I have two joomla applications se up with exactly the same versions, the same global configuration settings, and I set up a test application with the following function to load a php into a div on a specific page..
function getDiv(str) {
var id = document.getElementById("appselector").value;
if (id == "") {
document.getElementById("scoffitcategoryedit").innerHTML = "";
return;
}
else {
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp3 = new XMLHttpRequest();
} else {
// code for IE6, IE5
xmlhttp3 = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp3.onreadystatechange = function() {
if (xmlhttp3.readyState == 4 && xmlhttp3.status == 200) {
document.getElementById("scoffitcategoryedit").innerHTML = xmlhttp3.responseText;
alert("WTF");
}
};
xmlhttp3.open("GET","index.php?option=com_jumi&fileid=23& format=raw&" + str + id, true);
xmlhttp3.send();
}
}
I know its a little long winded, but the problem is that the script works fine in one website, but not in the other. Both of them are loading the same versions of jquery (which as you can see I don't like using), and both have the same templates. The only clue I seem to have found is that when I have text links elsewhere on the site attached with query statements pointing to self (index.php?blastr=bla&drivelstr=drivel), the browser shows index.php/ prepended to the link mentioned above.
I debugged the script and in the non functioning website it hangs on the xmlhttp3.send line.
I know people espouse the beauty of jquery's load() function as a replacement for this, but I cant get it to work (probably because the templates are using jquery versions higher than 1.8.1 when it was deprecated). So i'd rather stick with base js.
Any ideas about this inconsistent behaviour ?
This should be a comment but can't yet :(
I would check your configuration file for this line:
public $live_site = '';
and see if there is something in the failing site besides ''.
I found out what it was, I must have actually installed two different versions of the Jumi application in my websites. one website had a file under components/com_jumi/views/application named view.raw.php while the other did not. This meant that the format=raw in the index.php string could not be interpreted and caused a null response.
I simply copied the file into the other website where it was missing and everything then worked fine. But thanks for the response.
Related
I'm trying to emulate drag and drop UI behaviour in a behat test. So far with no success, despite mink allegedly supporting that interaction.
Weirdly enough it was hard for me to find any relevant blog posts about the subjects. Ones I've found (this and http://www.pix-art.be/post/testing-drag-and-drop-with-behat-and-guzzle
) did not help me much. Especially the latter one.
Does anyone have any suggestions on how to approach the problem or has experience with actually testing that interaction?
you can find an working example in the ownCloud test code, it does move files into folders via drag-and-drop:
public function moveFileTo(
$name, $destination, Session $session, $maxRetries = STANDARD_RETRY_COUNT
) {
$toMoveFileRow = $this->findFileRowByName($name, $session);
$destinationFileRow = $this->findFileRowByName($destination, $session);
$this->initAjaxCounters($session);
$this->resetSumStartedAjaxRequests($session);
for ($retryCounter = 0; $retryCounter < $maxRetries; $retryCounter++) {
$toMoveFileRow->findFileLink()->dragTo(
$destinationFileRow->findFileLink()
);
$this->waitForAjaxCallsToStartAndFinish($session);
$countXHRRequests = $this->getSumStartedAjaxRequests($session);
if ($countXHRRequests === 0) {
\error_log("Error while moving file");
} else {
break;
}
}
if ($retryCounter > 0) {
$message
= "INFORMATION: retried to move file $retryCounter times";
echo $message;
\error_log($message);
}
}
from: https://github.com/owncloud/core/blob/47396de109965110276deb545a9bd09f375c9823/tests/acceptance/features/lib/FilesPageCRUD.php#L243
First it finds the NodeElement of the file that has to be moved, then then NodeElement of the destination and calls $fileToBeMovedElement->dragTo($destinationElement)
Because it proved to be flaky there is an retry loop around the dragTo function. To test if the drag-and-drop operation worked the code checks if any AJAX calls were set off or not (in this particular app this drag-and-drop operation sets off an WebDAV request)
"EXPORTED_SYMBOLS is not an array" Exception flagged when tried to use Components.utils.import("chrome://app/content/app1.js");.
I have a XUL application created and from one of the JS File(say app.js) I tried to include the other JS File as shown above.
Both app.js and app1.js are placed in content folder and also in chrome.manifest file following line is added
"content app content/"
In other JS File (app1.js), I have exported symbols like
var EXPORTED_SYMBOLS = ["Fooinstance"];
var Fooinstance = {
foo: function() {
...
}
}
In app.js,
Components.utils.import("chrome://app/content/app1.js");
// Error: chrome://app/content/app1.js - EXPORTED_SYMBOLS is not an array
...
Fooinstance.foo();
I am running this XUL app on XULRunner 17.0.1 win32 libraries.
I looked through the code in this link https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Using
It did not help and if I include it as resource it works however I do not want to include it as part of resource.
Could you someone point out what mistake would be ?
I had this same problem, and I solved it:
1) changing the file extension (.js) by .jsm
2) Adding a first line on your module exporting classes to share. EG:
var EXPORTED_SYMBOLS = ["Xobject"];
function Xobject(){
}
Xobject.prototype.stop = function() {
return 'stop';
}
Xobject.prototype.run = function() {
return 'running';
}
3) Calling this way
Components.utils.import('resource://gre/modules/Services.jsm' );
Components.utils.import("chrome://myFirstAddOn/content/Xobject.jsm");
var myXobject = new Xobject();
alert(myXobject.run());
Hope it help u
For anyone else getting this, another possible reason is a circular dependency. My case was a little different, but I had two JSM files each using Components.utils.import to import each other. Then I got this error in one of them.
I see that CasperJS has a "download" function and an "on resource received" callback but I do not see the contents of a resource in the callback, and I don't want to download the resource to the filesystem.
I want to grab the contents of the resource so that I can do something with it in my script. Is this possible with CasperJS or PhantomJS?
This problem has been in my way for the last couple of days. The proxy solution wasn't very clean in my environment so I found out where phantomjs's QTNetworking core put the resources when it caches them.
Long story short, here is my gist. You need the cache.js and mimetype.js files:
https://gist.github.com/bshamric/4717583
//for this to work, you have to call phantomjs with the cache enabled:
//usage: phantomjs --disk-cache=true test.js
var page = require('webpage').create();
var fs = require('fs');
var cache = require('./cache');
var mimetype = require('./mimetype');
//this is the path that QTNetwork classes uses for caching files for it's http client
//the path should be the one that has 16 folders labeled 0,1,2,3,...,F
cache.cachePath = '/Users/brandon/Library/Caches/Ofi Labs/PhantomJS/data7/';
var url = 'http://google.com';
page.viewportSize = { width: 1300, height: 768 };
//when the resource is received, go ahead and include a reference to it in the cache object
page.onResourceReceived = function(response) {
//I only cache images, but you can change this
if(response.contentType.indexOf('image') >= 0)
{
cache.includeResource(response);
}
};
//when the page is done loading, go through each cachedResource and do something with it,
//I'm just saving them to a file
page.onLoadFinished = function(status) {
for(index in cache.cachedResources) {
var file = cache.cachedResources[index].cacheFileNoPath;
var ext = mimetype.ext[cache.cachedResources[index].mimetype];
var finalFile = file.replace("."+cache.cacheExtension,"."+ext);
fs.write('saved/'+finalFile,cache.cachedResources[index].getContents(),'b');
}
};
page.open(url, function () {
page.render('saved/google.pdf');
phantom.exit();
});
Then when you call phantomjs, just make sure the cache is enabled:
phantomjs --disk-cache=true test.js
Some notes:
I wrote this for the purpose of getting the images on a page without using the proxy or taking a low res snapshot. QT uses compression on certain text file resources and you will have to deal with the decompression if you use this for text files. Also, I ran a quick test to pull in html resources and it didn't parse the http headers out of the result. But, this is useful to me, hopefully someone else will find it so, modify it if you have problems with a specific content type.
I've found that until the phantomjs matures a bit, according to the issue 158 http://code.google.com/p/phantomjs/issues/detail?id=158 this is a bit of a headache for them.
So you want to do it anyways? I've opted to go a bit higher to accomplish this and have grabbed PyMiProxy over at https://github.com/allfro/pymiproxy, downloaded, installed, set it up, took their example code and made this in proxy.py
from miproxy.proxy import RequestInterceptorPlugin, ResponseInterceptorPlugin, AsyncMitmProxy
from mimetools import Message
from StringIO import StringIO
class DebugInterceptor(RequestInterceptorPlugin, ResponseInterceptorPlugin):
def do_request(self, data):
data = data.replace('Accept-Encoding: gzip\r\n', 'Accept-Encoding:\r\n', 1);
return data
def do_response(self, data):
#print '<< %s' % repr(data[:100])
request_line, headers_alone = data.split('\r\n', 1)
headers = Message(StringIO(headers_alone))
print "Content type: %s" %(headers['content-type'])
if headers['content-type'] == 'text/x-comma-separated-values':
f = open('data.csv', 'w')
f.write(data)
print ''
return data
if __name__ == '__main__':
proxy = AsyncMitmProxy()
proxy.register_interceptor(DebugInterceptor)
try:
proxy.serve_forever()
except KeyboardInterrupt:
proxy.server_close()
Then I fire it up
python proxy.py
Next I execute phantomjs with the proxy specified...
phantomjs --ignore-ssl-errors=yes --cookies-file=cookies.txt --proxy=127.0.0.1:8080 --web-security=no myfile.js
You may want to turn your security on or such, it was needless for me currently as I'm scraping just one source. You should now see a bunch of text flowing through your proxy console and if it lands on something with the mime type of "text/x-comma-separated-values" it'll save it as data.csv. This will also save all the headers and everything, but if you've come this far I'm sure you can figure out how to pop those off.
One other detail, I've found that I've had to disable gzip encoding, I could use zlib and decompress data in gzip from my own apache webserver, but if it comes out of IIS or such the decompression will get errors and I'm not sure about that part of it.
So my power company won't offer me an API? Fine! We do it the hard way!
Did not realize I could grab the source from the document object like this:
casper.start(url, function() {
var js = this.evaluate(function() {
return document;
});
this.echo(js.all[0].outerHTML);
});
More info here.
You can use Casper.debugHTML() to print out contents of a HTML resource:
var casper = require('casper').create();
casper.start('http://google.com/', function() {
this.debugHTML();
});
casper.run();
You can also store the HTML contents in a var using casper.getPageContent(): http://casperjs.org/api.html#casper.getPageContent (available in lastest master)
I've been trying to send data from my background page to a content script in my chrome extension. i can't seem to get it to work. I've read a few posts online but they're not really clear and seem quite high level. I've got managed to get the oauth working using the Oauth contacts example on the Chrome samples. The authentication works, i can get the data and display it in an html page by opening a new tab.
I want to send this data to a content script.
i'm having a lot of trouble with this and would really appreciate if someone could outline the explicit steps you need to follow to send data from a bg page to a content script or even better some code. Any takers?
the code for my background page is below (i've excluded the oauth paramaeters and other )
` function onContacts(text, xhr) {
contacts = [];
var data = JSON.parse(text);
var realdata = data.contacts;
for (var i = 0, person; person = realdata.person[i]; i++) {
var contact = {
'name' : person['name'],
'emails' : person['email']
};
contacts.push(contact); //this array "contacts" is read by the
contacts.html page when opened in a new tab
}
chrome.tabs.create({ 'url' : 'contacts.html'}); sending data to new tab
//chrome.tabs.executeScript(null,{file: "contentscript.js"});
may be this may work?
};
function getContacts() {
oauth.authorize(function() {
console.log("on authorize");
setIcon();
var url = "http://mydataurl/";
oauth.sendSignedRequest(url, onContacts);
});
};
chrome.browserAction.onClicked.addListener(getContacts);`
As i'm not quite sure how to get the data into the content script i wont bother posting the multiple versions of my failed content scripts. if I could just get a sample on how to request the "contacts" array from my content script, and how to send the data from the bg page, that would be great!
You have two options getting the data into the content script:
Using Tab API:
http://code.google.com/chrome/extensions/tabs.html#method-executeScript
Using Messaging:
http://code.google.com/chrome/extensions/messaging.html
Using Tab API
I usually use this approach when my extension will just be used once in a while, for example, setting the image as my desktop wallpaper. People don't set a wallpaper every second, or every minute. They usually do it once a week or even day. So I just inject a content script to that page. It is pretty easy to do so, you can either do it by file or code as explained in the documentation:
chrome.tabs.executeScript(tab.id, {file: 'inject_this.js'}, function() {
console.log('Successfully injected script into the page');
});
Using Messaging
If you are constantly need information from your websites, it would be better to use messaging. There are two types of messaging, Long-lived and Single-requests. Your content script (that you define in the manifest) can listen for extension requests:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.method == 'ping')
sendResponse({ data: 'pong' });
else
sendResponse({});
});
And your background page could send a message to that content script through messaging. As shown below, it will get the currently selected tab and send a request to that page.
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {method: 'ping'}, function(response) {
console.log(response.data);
});
});
Depends on your extension which method to use. I have used both. For an extension that will be used like every second, every time, I use Messaging (Long-Lived). For an extension that will not be used every time, then you don't need the content script in every single page, you can just use the Tab API executeScript because it will just inject a content script whenever you need to.
Hope that helps! Do a search on Stackoverflow, there are many answers to content scripts and background pages.
To follow on Mohamed's point.
If you want to pass data from the background script to the content script at initialisation, you can generate another simple script that contains only JSON and execute it beforehand.
Is that what you are looking for?
Otherwise, you will need to use the message passing interface
In the background page:
// Subscribe to onVisited event, so that injectSite() is called once at every pageload.
chrome.history.onVisited.addListener(injectSite);
function injectSite(data) {
// get custom configuration for this URL in the background page.
var site_conf = getSiteConfiguration(data.url);
if (site_conf)
{
chrome.tabs.executeScript({ code: 'PARAMS = ' + JSON.stringify(site_conf) + ';' });
chrome.tabs.executeScript({ file: 'site_injection.js' });
}
}
In the content script page (site_injection.js)
// read config directly from background
console.log(PARAM.whatever);
I thought I'd update this answer for current and future readers.
According to the Chrome API, chrome.extension.onRequest is "[d]eprecated since Chrome 33. Please use runtime.onMessage."
See this tutorial from the Chrome API for code examples on the messaging API.
Also, there are similar (newer) SO posts, such as this one, which are more relevant for the time being.
I'm in the process of building my first Safari extension--a very simple one--but I've run into a couple of problems. The extension boils down to a single, injected script that attempts to bypass the native feed handler and redirect to an http:// URI. My issues so far are twofold:
The "whitelist" isn't working the way I'd expect. Since all feeds are shown under the "feed://" protocol, I've tried to capture that in the whitelist as "feed://*/*" (with nothing in the blacklist), but I end up in a request loop that I can't understand. If I set blacklist values of "http://*/*" and "https://*/*", everything works as expected.
I can't figure out how to access my settings from my injected script. The script creates a beforeload event handler, but can't access my settings using the safari.extension.settings path indicated in the documentation.
I haven't found anything in Apple's documentation to indicate that settings shouldn't be available from my script. Since extensions are such a new feature, even Google returns limited relevant results and most of those are from the official documentation.
What am I missing?
UPDATE
So I'm hoping that the documentation is incomplete because it's borderline abysmal, but I've learned a bit about settings. It turns out that, from injection scripts, the SafariExtensionSettings object isn't available. Injection scripts only have access to the SafariContentExtension object (which isn't useful at all), but it's aliased in exactly the same manner (safari.extension.settings)--bad idea, IMO. As stated in the injection script documentation:
Important: When you use safari.extension from within an injected script, you are not addressing the SafariExtension class. You are addressing the SafariContentExtension class.
You have to use the messaging system to talk to a global HTML file which has access to the settings. It's kind of loopy, but I have a message being sent to a global.html file that retrieves the settings and will send a message back to my injection script as soon as I figure out how to go about doing that.
Since I'm doing all of my work before the document loads, all of the methods I've found to send message back rely on a page object that I don't have.
Like everyone else at this point, I'm still climbing the learning curve, but here's how I've handled this problem:
I have a simple extension with no chrome and one injected end script (script.js). For the purpose of loading settings I've added a simple global page (proxy.html). When script.js is injected, it sends a getSettings message to proxy.html. proxy.html responds with a setSettings message, and script.js continues initialization.
The most helpful page I've found in the docs on this topic is Messages and Proxies.
proxy.html:
<!doctype html>
<html lang="en">
<head>
<script type="text/javascript">
safari.application.addEventListener( "message", function( e ) {
if( e.name === "getSettings" ) {
e.target.page.dispatchMessage( "setSettings", {
sort_keys: safari.extension.settings.getItem( "sort_keys" )
} );
}
}, false );
</script>
</head>
<body></body>
</html>
script.js:
( function() {
var settings, init = function() {
// do extension stuff
};
// listen for an incoming setSettings message
safari.self.addEventListener( "message", function( e ) {
if( e.name === "setSettings" ) {
settings = e.message;
init();
}
}, false );
// ask proxy.html for settings
safari.self.tab.dispatchMessage( "getSettings" );
}() )
EDIT: like you said in your initial post update, the injected script doesn't have the same kind of access that a global HTML page would have. This is my working solution, imagine you want to know the value of setting "foo" in the injected script:
Injected script code:
function getMessage(msgEvent) {
if (msgEvent.name == "settingValueIs")
alert("Value for asked setting is: " + msgEvent.message);
}
safari.self.tab.dispatchMessage("getSettingValue", "foo"); // ask for value
safari.self.addEventListener("message", getMessage, false); // wait for reply
Global HTML code:
function respondToMessage(messageEvent) {
if (messageEvent.name == "getSettingValue") {
// getItem("foo");
var value = safari.extension.settings.getItem(messageEvent.message);
// return value of foo to injected script
safari.application.activeBrowserWindow.activeTab.page.dispatchMessage("settingValueIs", value);
}
}
safari.application.addEventListener("message",respondToMessage,false);
Hope this helps !
Initial post: I'm having the same 2nd problem as you, I can't access my settings (or secureSettings) from an injected script. In my case the script is loaded after page load, but even that way I can't use safari.extension.settings.
The only way it works is with a toolbar/button, the HTML behind that element can getItem and setItem as expected.
My conclusion is that, for some reason, injected scripts can't access settings (actually, they don't even seem to have access to the safari element). Bug or intended feature, that's left to figure out.
It took me several days, but I think I found a workable solution using the canLoad() messaging method. My injection script retrieves settings by calling the global HTML page like this:
settings = safari.self.tab.canLoad( event );
My global HTML file, in turn, returns those settings as:
settings = {
'setting1': safari.extension.settings.getItem( 'setting1' )
}
msgEvent.message = settings;
It's still a bit more "hacky" than I'd like. I can't seem to simply return the settings object itself, so I have to compile a new object by retrieving each setting manually. Not ideal, but it does seem to be effective.
run into the same problem, but the answer is easier than you can imagine: include the script in your global html.
<!DOCTYPE HTML>
<script type="text/javascript" src="cleanup.js"></script>
<script>
…
</script>
then you can access the settings as described in documentation safari.extension.settings.myKey
you can also upvote #Travis, because I got the idea from his post
//EDIT:
actually I don't really know whats wrong. Calling the settings as the first command works, but not at a later time. Additionally it seems to corrupting my complete script after the 2. injection. Need verification if it's only in my (difficult?) script.
//EDIT2:
now I got it to work to get back the settings object via dispatchMessage()
in your injected.js
function gotSettings(msgEvent) {
if (msgEvent.name === "SETTINGS") {
setts = msgEvent.message;
alert(setts.mySetting1);
// run the programm
}
}
safari.self.addEventListener("message", gotSettings, false);
safari.self.tab.dispatchMessage("getSettings");
and in global.html
switch (event.name) {
case "getSettings":
// send the settings data
event.target.page.dispatchMessage("SETTINGS", safari.extension.settings);
relying on this apple documentation