pull/2/head
gorhill 8 years ago
parent 2ef2505507
commit 9a26274b11

@ -51,6 +51,33 @@ vAPI.modernFirefox = Services.appinfo.ID === '{ec8030f7-c20a-464f-9b0e-13a3a9e97
/******************************************************************************/
var deferUntil = function(testFn, mainFn, details) {
if ( typeof details !== 'object' ) {
details = {};
}
var now = 0;
var next = details.next || 200;
var until = details.until || 2000;
var check = function() {
if ( testFn() === true || now >= until ) {
mainFn();
return;
}
now += next;
vAPI.setTimeout(check, next);
};
if ( 'sync' in details && details.sync === true ) {
check();
} else {
vAPI.setTimeout(check, 1);
}
};
/******************************************************************************/
vAPI.app = {
name: 'uMatrix',
version: location.hash.slice(1)
@ -558,7 +585,6 @@ vAPI.storage = (function() {
// This must be executed/setup early.
var winWatcher = (function() {
var chromeWindowType = vAPI.thunderbird ? 'mail:3pane' : 'navigator:browser';
var windowToIdMap = new Map();
var windowIdGenerator = 1;
var api = {
@ -566,6 +592,24 @@ var winWatcher = (function() {
onCloseWindow: null
};
// https://github.com/gorhill/uMatrix/issues/586
// This is necessary hack because on SeaMonkey 2.40, for unknown reasons
// private windows do not have the attribute `windowtype` set to
// `navigator:browser`. As a fallback, the code here will also test whether
// the id attribute is `main-window`.
api.toBrowserWindow = function(win) {
var docElement = win && win.document && win.document.documentElement;
if ( !docElement ) {
return null;
}
if ( vAPI.thunderbird ) {
return docElement.getAttribute('windowtype') === 'mail:3pane' ? win : null;
}
return docElement.getAttribute('windowtype') === 'navigator:browser' ||
docElement.getAttribute('id') === 'main-window' ?
win : null;
};
api.getWindows = function() {
return windowToIdMap.keys();
};
@ -575,7 +619,7 @@ var winWatcher = (function() {
};
api.getCurrentWindow = function() {
return Services.wm.getMostRecentWindow(chromeWindowType) || null;
return this.toBrowserWindow(Services.wm.getMostRecentWindow(null));
};
var addWindow = function(win) {
@ -761,7 +805,7 @@ vAPI.tabs.get = function(tabId, callback) {
return browser;
}
if ( !browser ) {
if ( !browser || !browser.currentURI ) {
callback();
return;
}
@ -1224,56 +1268,12 @@ var tabWatcher = (function() {
});
};
var attachToTabBrowserLater = function(details) {
details.tryCount = details.tryCount ? details.tryCount + 1 : 1;
if ( details.tryCount > 8 ) {
return false;
}
vAPI.setTimeout(function(details) {
attachToTabBrowser(details.window, details.tryCount);
},
200,
details
);
return true;
};
var attachToTabBrowser = function(window, tryCount) {
// Let's just be extra-paranoiac regarding whether all is right before
// trying to attach outself to the browser window.
var document = window && window.document;
var docElement = document && document.documentElement;
var wintype = docElement && docElement.getAttribute('windowtype');
if ( wintype !== 'navigator:browser' ) {
attachToTabBrowserLater({ window: window, tryCount: tryCount });
return;
}
// https://github.com/gorhill/uBlock/issues/906
// This might have been the cause. Will see.
if ( document.readyState !== 'complete' ) {
attachToTabBrowserLater({ window: window, tryCount: tryCount });
return;
}
// On some platforms, the tab browser isn't immediately available,
// try waiting a bit if this happens.
// https://github.com/gorhill/uBlock/issues/763
// Not getting a tab browser should not prevent from attaching ourself
// to the window.
var tabBrowser = getTabBrowser(window);
if (
tabBrowser === null &&
attachToTabBrowserLater({ window: window, tryCount: tryCount })
) {
return;
}
var attachToTabBrowser = function(window) {
if ( typeof vAPI.toolbarButton.attachToNewWindow === 'function' ) {
vAPI.toolbarButton.attachToNewWindow(window);
}
var tabBrowser = getTabBrowser(window);
if ( tabBrowser === null ) {
return;
}
@ -1291,7 +1291,6 @@ var tabWatcher = (function() {
// not set when a tab is opened as a result of session restore -- it is
// set *after* the event is fired in such case.
if ( tabContainer ) {
//tabContainer.addEventListener('TabOpen', onOpen);
tabContainer.addEventListener('TabShow', onShow);
tabContainer.addEventListener('TabClose', onClose);
// when new window is opened TabSelect doesn't run on the selected tab?
@ -1299,8 +1298,32 @@ var tabWatcher = (function() {
}
};
// https://github.com/gorhill/uBlock/issues/906
// Ensure the environment is ready before trying to attaching.
var canAttachToTabBrowser = function(window) {
var document = window && window.document;
if ( !document || document.readyState !== 'complete' ) {
return false;
}
// On some platforms, the tab browser isn't immediately available,
// try waiting a bit if this happens.
// https://github.com/gorhill/uBlock/issues/763
// Not getting a tab browser should not prevent from attaching ourself
// to the window.
var tabBrowser = getTabBrowser(window);
if ( tabBrowser === null ) {
return false;
}
return winWatcher.toBrowserWindow(window) !== null;
};
var onWindowLoad = function(win) {
attachToTabBrowser(win);
deferUntil(
canAttachToTabBrowser.bind(null, win),
attachToTabBrowser.bind(null, win)
);
};
var onWindowUnload = function(win) {
@ -1313,7 +1336,6 @@ var tabWatcher = (function() {
var tabContainer = tabBrowser.tabContainer;
if ( tabContainer ) {
//tabContainer.removeEventListener('TabOpen', onOpen);
tabContainer.removeEventListener('TabShow', onShow);
tabContainer.removeEventListener('TabClose', onClose);
tabContainer.removeEventListener('TabSelect', onSelect);
@ -2316,59 +2338,11 @@ vAPI.toolbarButton = {
tbb.id = 'umatrix-legacy-button'; // NOTE: must match legacy-toolbar-button.css
tbb.viewId = tbb.id + '-panel';
var sss = null;
var styleSheetUri = null;
var addLegacyToolbarButtonLater = function(details) {
details.tryCount = details.tryCount ? details.tryCount + 1 : 1;
if ( details.tryCount > 8 ) {
return false;
}
vAPI.setTimeout(function(details) {
addLegacyToolbarButton(details.window, details.tryCount);
},
200,
details
);
return true;
};
var addLegacyToolbarButton = function(window, tryCount) {
var createToolbarButton = function(window) {
var document = window.document;
// https://github.com/gorhill/uMatrix/issues/357
// Already installed?
if ( document.getElementById(tbb.id) !== null ) {
return;
}
var toolbox = document.getElementById('navigator-toolbox') ||
document.getElementById('mail-toolbox');
if (
toolbox === null &&
addLegacyToolbarButtonLater({ window: window, tryCount: tryCount })
) {
return;
}
// palette might take a little longer to appear on some platforms,
// give it a small delay and try again.
var palette = toolbox.palette;
if (
palette === null &&
addLegacyToolbarButtonLater({ window: window, tryCount: tryCount })
) {
return;
}
var navbar = document.getElementById('nav-bar');
if (
navbar === null &&
addLegacyToolbarButtonLater({ window: window, tryCount: tryCount })
) {
return;
}
var toolbarButton = document.createElement('toolbarbutton');
toolbarButton.setAttribute('id', tbb.id);
// type = panel would be more accurate, but doesn't look as good
@ -2387,21 +2361,49 @@ vAPI.toolbarButton = {
toolbarButtonPanel.addEventListener('popuphiding', tbb.onViewHiding);
toolbarButton.appendChild(toolbarButtonPanel);
if ( palette !== null && palette.querySelector('#' + tbb.id) === null ) {
palette.appendChild(toolbarButton);
}
return toolbarButton;
};
var addLegacyToolbarButton = function(window) {
// uMatrix's stylesheet lazily added.
if ( styleSheetUri === null ) {
var sss = Cc["@mozilla.org/content/style-sheet-service;1"]
.getService(Ci.nsIStyleSheetService);
styleSheetUri = Services.io.newURI(vAPI.getURL("css/legacy-toolbar-button.css"), null, null);
tbb.closePopup = function() {
// `hidePopup` reported as not existing while testing legacy button
// on FF 41.0.2.
// https://bugzilla.mozilla.org/show_bug.cgi?id=1151796
if ( typeof toolbarButtonPanel.hidePopup === 'function' ) {
toolbarButtonPanel.hidePopup();
// Register global so it works in all windows, including palette
if ( !sss.sheetRegistered(styleSheetUri, sss.AUTHOR_SHEET) ) {
sss.loadAndRegisterSheet(styleSheetUri, sss.AUTHOR_SHEET);
}
};
}
var document = window.document;
// https://github.com/gorhill/uMatrix/issues/357
// Already installed?
if ( document.getElementById(tbb.id) !== null ) {
return;
}
var toolbox = document.getElementById('navigator-toolbox') ||
document.getElementById('mail-toolbox');
if ( toolbox === null ) {
return;
}
// Find the place to put the button
var toolbars = toolbox.externalToolbars.slice();
var toolbarButton = createToolbarButton(window);
// https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/toolbarpalette
var palette = toolbox.palette;
if ( palette && palette.querySelector('#' + tbb.id) === null ) {
palette.appendChild(toolbarButton);
}
// Find the place to put the button.
// Pale Moon: `toolbox.externalToolbars` can be undefined. Seen while
// testing popup test number 3:
// http://raymondhill.net/ublock/popup.html
var toolbars = toolbox.externalToolbars ? toolbox.externalToolbars.slice() : [];
for ( var child of toolbox.children ) {
if ( child.localName === 'toolbar' ) {
toolbars.push(child);
@ -2418,6 +2420,11 @@ vAPI.toolbarButton = {
if ( index === -1 ) {
continue;
}
// This can occur with Pale Moon:
// "TypeError: toolbar.insertItem is not a function"
if ( typeof toolbar.insertItem !== 'function' ) {
continue;
}
// Found our button on this toolbar - but where on it?
var before = null;
for ( var i = index + 1; i < currentset.length; i++ ) {
@ -2426,6 +2433,7 @@ vAPI.toolbarButton = {
break;
}
}
// https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Method/insertItem
toolbar.insertItem(tbb.id, before);
break;
}
@ -2440,6 +2448,7 @@ vAPI.toolbarButton = {
// No button yet so give it a default location. If forcing the button,
// just put in in the palette rather than on any specific toolbar (who
// knows what toolbars will be available or visible!)
var navbar = document.getElementById('nav-bar');
if ( navbar !== null && !vAPI.localStorage.getBool('legacyToolbarButtonAdded') ) {
// https://github.com/gorhill/uBlock/issues/264
// Find a child customizable palette, if any.
@ -2451,9 +2460,34 @@ vAPI.toolbarButton = {
}
};
var canAddLegacyToolbarButton = function(window) {
var document = window.document;
if (
!document ||
document.readyState !== 'complete' ||
document.getElementById('nav-bar') === null
) {
return false;
}
var toolbox = document.getElementById('navigator-toolbox') ||
document.getElementById('mail-toolbox');
return toolbox !== null && !!toolbox.palette;
};
var onPopupCloseRequested = function({target}) {
if ( typeof tbb.closePopup === 'function' ) {
tbb.closePopup(target);
var document = target.ownerDocument;
if ( !document ) {
return;
}
var toolbarButtonPanel = document.getElementById(tbb.viewId);
if ( toolbarButtonPanel === null ) {
return;
}
// `hidePopup` reported as not existing while testing legacy button
// on FF 41.0.2.
// https://bugzilla.mozilla.org/show_bug.cgi?id=1151796
if ( typeof toolbarButtonPanel.hidePopup === 'function' ) {
toolbarButtonPanel.hidePopup();
}
};
@ -2480,7 +2514,10 @@ vAPI.toolbarButton = {
};
tbb.attachToNewWindow = function(win) {
addLegacyToolbarButton(win);
deferUntil(
canAddLegacyToolbarButton.bind(null, win),
addLegacyToolbarButton.bind(null, win)
);
};
tbb.init = function() {
@ -2489,14 +2526,6 @@ vAPI.toolbarButton = {
onPopupCloseRequested
);
sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
styleSheetUri = Services.io.newURI(vAPI.getURL("css/legacy-toolbar-button.css"), null, null);
// Register global so it works in all windows, including palette
if ( !sss.sheetRegistered(styleSheetUri, sss.AUTHOR_SHEET) ) {
sss.loadAndRegisterSheet(styleSheetUri, sss.AUTHOR_SHEET);
}
cleanupTasks.push(shutdown);
};
})();
@ -3028,43 +3057,84 @@ vAPI.contextMenu.remove = function() {
/******************************************************************************/
/******************************************************************************/
var optionsObserver = {
addonId: 'uMatrix@raymondhill.net',
register: function() {
Services.obs.addObserver(this, 'addon-options-displayed', false);
cleanupTasks.push(this.unregister.bind(this));
var optionsObserver = (function() {
var addonId = 'uMatrix@raymondhill.net';
var browser = tabWatcher.currentBrowser();
if ( browser && browser.currentURI && browser.currentURI.spec === 'about:addons' ) {
this.observe(browser.contentDocument, 'addon-enabled', this.addonId);
var commandHandler = function() {
switch ( this.id ) {
case 'showDashboardButton':
vAPI.tabs.open({ url: 'dashboard.html', index: -1 });
break;
case 'showLoggerButton':
vAPI.tabs.open({ url: 'logger-ui.html', index: -1 });
break;
default:
break;
}
},
unregister: function() {
Services.obs.removeObserver(this, 'addon-options-displayed');
},
};
setupOptionsButton: function(doc, id, page) {
var setupOptionsButton = function(doc, id) {
var button = doc.getElementById(id);
if ( button === null ) {
return;
}
button.addEventListener('command', function() {
vAPI.tabs.open({ url: page, index: -1 });
});
button.addEventListener('command', commandHandler);
button.label = vAPI.i18n(id);
},
};
observe: function(doc, topic, addonId) {
if ( addonId !== this.addonId ) {
return;
var setupOptionsButtons = function(doc) {
setupOptionsButton(doc, 'showDashboardButton');
setupOptionsButton(doc, 'showLoggerButton');
};
var observer = {
observe: function(doc, topic, id) {
if ( id !== addonId ) {
return;
}
setupOptionsButtons(doc);
}
};
this.setupOptionsButton(doc, 'showDashboardButton', 'dashboard.html');
this.setupOptionsButton(doc, 'showLoggerButton', 'logger-ui.html');
}
};
// https://github.com/gorhill/uBlock/issues/948
// Older versions of Firefox can throw here when looking up `currentURI`.
var canInit = function() {
try {
var tabBrowser = tabWatcher.currentBrowser();
return tabBrowser &&
tabBrowser.currentURI &&
tabBrowser.currentURI.spec === 'about:addons' &&
tabBrowser.contentDocument &&
tabBrowser.contentDocument.readyState === 'complete';
} catch (ex) {
}
};
// Manually add the buttons if the `about:addons` page is already opened.
var init = function() {
if ( canInit() ) {
setupOptionsButtons(tabWatcher.currentBrowser().contentDocument);
}
};
var unregister = function() {
Services.obs.removeObserver(observer, 'addon-options-displayed');
};
var register = function() {
Services.obs.addObserver(observer, 'addon-options-displayed', false);
cleanupTasks.push(unregister);
deferUntil(canInit, init, { next: 463 });
};
return {
register: register,
unregister: unregister
};
})();
optionsObserver.register();

Loading…
Cancel
Save