Firefox Add-on: page mod include pattern won't match - firefox-addon

I'm trying to add global hotkey support to Spotify (and others). For this I have to execute a content script in the player app iframe, but no matter what pattern I try Firefox just won't execute my content script.
This is what I try to do:
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");
pageMod.PageMod({
include: /^https?:\/\/play\.spotify\.com\/apps\/player\/.+/,
attachTo: ["frame"],
contentScriptFile: [data.url("content.js")]
});
Has anyone any idea what could be wrong? How can I make it match?
See:
https://bitbucket.org/panzi/play-control/src/f1dbd217661c0f09d3615dce7b8b1cab9f8fbf70/browser-plugin/firefox/playcontrol-spotify/lib/main.js?at=default
The same thing for Chrome works perfectly well:
https://bitbucket.org/panzi/play-control/src/f1dbd217661c0f09d3615dce7b8b1cab9f8fbf70/browser-plugin/chrome/playcontrol-spotify/?at=default

I'm a regex noob, but in the doc examples, they don't use ^ even when the string starts with 'http'.
Try getting progressively more stringent to see which part of the regex it doesn't like. Throw an onAttach: console.log("pageMod attached"), in there to make sure it isn't being attached and something else isn't causing the problem.
/.*play\.spotify\.com\/apps\/player.*/ If this works, then either it doesn't like the beginning or the end. Try:
/https?:\/\/play\.spotify\.com\/apps\/player.*/
/^https?:\/\/play\.spotify\.com\/apps\/player.*/
.*play\.spotify\.com\/apps\/player\/.*/
.*play\.spotify\.com\/apps\/player\/.+/
If all of the above work, then your string should work too.

URL matching works the way I've written it. The bug was something else.

Related

How to prevent automatic hyperlink detection in the console of Firefox/Chrome developer tools?

Something that drives me nuts in the developper tools of Chrome (106) and Firefox (105) is the fact that whenever some text logged to the console via console.log(text) happens to contain a hyperlink, this link is not only turned clickable (I can live with it even when I usually prefer to have just plain text) but is abbreviated, if it is a long link. So when I want to control what precise link is in some variable, I cannot just write e.g. console.log(img.src), because some of the interesting information of the link is hidden.
You can try yourself with
var href = 'https://stackoverflow.com/search?q=%5Bgoogle-chrome-devtools%5D+%5Bconsole.log%5D+%5Bfirefox-developer-tools%5D+%5Bhyperlink%5D+automatic+detection&someMoreStuffTomakeTheLinkLonger';
console.log(href);
In both, Firefox and Chrome, the output for me contains some '...', e.g. in Firefox I obtain as output:
https://stackoverflow.com/search?q=%5Bgoogle-chrome-devtools…link%5D+automatic+detection&someMoreStuffTomakeTheLinkLonger
thus hiding the part after "-devtools". (Chrome hides a slightly different part). The console is mostly a debugging tool. I log things because I want to see them, not hide them. I always need to either hover with the mouse and wait for the tooltip (doesn't allow me to copy fractions of the link) or to right click copy the link and paste it somewhere where I can see it completely. Or take a substring to remove the "https://" in the front. But note that the variable isn't necessarily a single hyperlink, but can be any text containing several such hyperlinks. I didn't find a way to force console.log to just print plain text all content. Did anybody meet this problem as well and find a workaround?
I made this a community wiki answer, because the main insight is not from myself but from the comments. Feel free to improve.
The console.log() function allows several arguments, which allows also a formatted output similar to printf in some languages. The possibilities of formatting can be found in the documentation of console.log() on MDN. In any case, this formatted output provides a solution at least for Chrome, as #wOxxOm pointed out in the comments:
console.log('%O', href) // works in Chrome
This is rather surprising, because %O is described at MDN as
"Outputs a JavaScript object. Clicking the object name opens more information about it in the inspector".
It seems there is no 'clicking' in Chrome when the object is a string.
There is also %s for string output, but this just gives the standard behavior of replacing links in both browsers. And for Firefox none of the above two formatting options works. There one really has to replace the protocol "https://" by something that is not recognized as link. A space behind ':' seems enough, so "https: //". It turns out, that one can also insert a formatting string "https:%c//", which can even be empty, and thus yield an output which is the complete link and can be copied as well:
console.log(href.replace(/(https?:)/, "$1%c"), ""); // works in Firefox
In particular the FF solution is cumbersome, and there might also be several links within one console-output. So it is useful to define one's own log-function (or if one prefers, redefine console.log, but note the remark at the end)
function isChrome() {...} // use your favorite Chrome detection here
function isFirefox() {...} // use your favorite Firefox detection here
function plainLog() {
const msg = arguments[0];
if (isChrome() && arguments.length == 1 && typeof msg == "string") {
return console.log("%O", msg);
}
if (isFirefox() && arguments.length == 1 && typeof msg == "string") {
const emptyStyle = ""; // serves only as a separator, such that FF doesn't recognize the link anymore
const reg = /(https?:)\/\//g;
const emptyStyles = []; // we need to insert one empty Style for every found link
const matches = msg.matchAll(reg);
for (let match of matches) {
emptyStyles.push(emptyStyle);
}
return console.log(msg.replace(reg, '$1%c//'), ...emptyStyles);
}
return console.log(...arguments);
}
For browser detection isChrome() and isFirefox() see e.g. here on SO.
One can of course extend the redefinition also to the other console functions (console.info, console.warn, etc.)
The downside of the redefinition of console.log is that usually every output of the console shows also the last entry of the call stack as a practical link to the source of the logging. But due to the redefintion, this link is now always to the same place, namely the file and line number where plainLog() is defined and calls console.log(), instead of the place where the new log command plainLog() was called. This new problem is described on SO here, but the solution (see comment) is again a bit involved and also not completely satisfying to serve as a replacement for the built-in console.log . So if links appear only rarely in the logging, it's probably better to switch to the redefined plainLog() only for these links.

.NET/MVC4/Jquery Mobile/Knockout/Chrome/iPhone extra # character in URL

Okay, if I could offer a bounty for this I would - I offer virtual karma.
As mentioned in the title I have an .NET/MVC4/Jquery Mobile/Knockout website. On the index page there is a button
<button data-bind="click: getResults" data-theme="f">Search</button>
which calls a javascript function
$.mobile.navigate("/results?option1=a&option2=b", { transition: amw.transitions.slide });
This works great on all browsers and devices except Chrome/iPhone. As far as I can tell the version of Chrome or iOS does not matter. The resulting URL in the address bar is
iPhone/Chrome: http://www.mywebsite.com/#/results?option1=a&option2=b
Other Devices: http://www.mywebsite.com/results?option1=a&option2=b
I have put alerts throughout jQuery mobile to try and figure out what is going on (if someone knows a way to debug chrome on iOS let me know) and I cannot see where the extra # is being added.
This may not seem like a big deal but the url ends up being passed on to a downstream service that really does not like the extra #.
I can put in a hack at the call to the service to strip out the # but I would really like to figure out what is happening.
The only suspect line I can find in jQuery mobile (1.3.0) is line #2298
// if the hash is included in the data make sure the shape
// is consistent for comparison
if( data.hash && data.hash.indexOf( "#" ) === -1) {
data.hash = "#" + data.hash;
}
But I am not sure what this does or why it would occour only on Chrome/iPhone.
so StackOverflow people - what is going on?
Thanks.

"document" in mozilla extension js modules?

I am building Firefox extension, that creates single XMPP chat connection, that can be accessed from all tabs and windows, so I figured, that only way to to this, is to create connection in javascript module and include it on every browser window. Correct me if I am wrong...
EDIT: I am building traditional extension with xul overlays, not using sdk, and talking about those modules: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules
So I copied Strophe.js into js module. Strophe.js uses code like this:
/*_Private_ function that creates a dummy XML DOM document to serve as
* an element and text node generator.
*/
[---]
if (document.implementation.createDocument === undefined) {
doc = this._getIEXmlDom();
doc.appendChild(doc.createElement('strophe'));
} else {
doc = document.implementation
.createDocument('jabber:client', 'strophe', null);
}
and later uses doc.createElement() to create xml(or html?) nodes.
All worked fine, but in module I got error "Error: ReferenceError: document is not defined".
How to get around this?
(Larger piece of exact code: http://pastebin.com/R64gYiKC )
Use the hiddenDOMwindow
Cu.import("resource://gre/modules/Services.jsm");
var doc = Services.appShell.hiddenDOMWindow.document;
It sounds like you might not be correctly attaching your content script to the worker page. Make sure that you're using something like tabs.attach() to attach one or more content scripts to the worker page (see documentation here).
Otherwise you may need to wait for the DOM to load, waiting for the entire page to load
window.onload = function ()
{
Javascript code goes here
}
Should take at least diagnose that issue (even if the above isn't the best method to use in production). But if I had to wager, I'd say that you're not attaching the content script.

jQueryUI's .tabs is clashing with Apache Rewrite

I have an Apache write that works everywhere except on pages that are using 'tabs'.
For some reason, the tabs are loading as if they are full pages loaded through AJAX (ran through the index.php as the rewrite instructs - but it shouldn't be rewriting an # anchor link I would think...)
Is there a way that I can stop it from doing this? It's weird because not only is it treating the # link as a real URL, it's adding -33,000px to the <html> via inline style, so this is what it looks like AFTER I disable it in the inspection tool. Otherwise it's just black and extremely long.
I should add that this was not an issue until I added <base href="/folder/"> to fix an issue with it not rewriting sub-directories properly. Before, it still did the rewrite and rendered the page correctly.
Update
This is definitely a <base> and jQueryUI's .tabs clashing. When I removed the rewrite and use the long URL it continuously clones them. The rewrite saved it from rewriting past 12 times or so.
mod_rewrite does also look at the fragment identifiers, but you can tell it not to in a RewriteCond.
The following only allows a URI that doesn't end with a fragment identifier.
RewriteCond %{REQUEST_URI} !(#(.*))$
Thanks to this bug report I found a solution.
$.fn.__tabs = $.fn.tabs;
$.fn.tabs = function (a, b, c, d, e, f) {
var base = location.href.replace(/#.*$/, '');
$('ul>li>a[href^="#"]', this).each(function () {
var href = $(this).attr('href');
$(this).attr('href', base + href);
});
$(this).__tabs(a, b, c, d, e, f);
};
//$('#the-object').tabs();
Apparently at 1.8 it worked, at 1.9 it went loopy. This adds the base href to the link, fixing the issue.
Apparently this is partly due to a bug in jQueryUI tabs
The Bug Report
I'm not sure I can wrap my head around this, but it is working in IE and not in Chrome/Firefox... Guess I'll try a plug-in.

Developing a Firefox plugin/addon that invokes "Save As" from FF's own set of functions

I have a basic FF addon that polls for something in the DOM of the page in window.document. When it sees it, it is supposed to save the page. That's the hard part. I don't want to replicate the functionality of "save complete" I just want to call the pre-existing functionality from the plugin/addon at the right moment.
Is this an XPCom thing? Or is it pure JavaScript via the relevant APIs ?
iMacros for Firefox can invoke Save-as (without popping the associated dialog), but I can't see how.
Can anyone advise as to how to call deeper Firefox functions like this?
Thanks, - Paul
PS - I really love Mozilla Archive Format, with MHT and Faithful Save but I think it is replicating functionality again. My alternative is to invoke it's function, but that's as opaque to me as the firefox native one.
You can use nsIWebBrowserPersist.saveDocument() for this:
var persist = Cc["#mozilla.org/embedding/browser/nsWebBrowserPersist;1"].
createInstance(Ci.nsIWebBrowserPersist);
var localPath = Cc["#mozilla.org/file/local;1"].
createInstance(Ci.nsILocalFile);
localPath.initWithPath(pathToLocalDirectory);
var localFile = localPath.clone();
localFile.append("mylocalfile.html");
persist.saveDocument(document, localFile, localPath, null, 0, 0);
The key is the third parameter which specifies where the linked URIs should be stored. See http://mxr.mozilla.org/mozilla2.0/source/embedding/components/webbrowserpersist/public/nsIWebBrowserPersist.idl#256 for complete documentation.

Resources