1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-11-16 23:42:39 +01:00

Safari: rework of toolbar icon update mechanism -- leaner, faster

This commit is contained in:
Chris 2015-05-01 03:02:32 -06:00
parent b6902d2c70
commit 0217f1cc8b

View File

@ -457,18 +457,160 @@
/******************************************************************************/
// reload the popup when it's opened
safari.application.addEventListener("popover", function(event) {
var w = event.target.contentWindow, body = w.document.body, child;
while(child = body.firstChild) {
body.removeChild(child);
}
w.location.reload();
}, true);
/******************************************************************************/
var ICON_URLS = {
"on": vAPI.getURL("img/browsericons/safari-icon16.png"),
"off": vAPI.getURL("img/browsericons/safari-icon16-off.png")
};
var IconState = function(badge, img, icon) {
this.badge = badge;
// ^ a number -- the badge 'value'
this.img = img;
// ^ a string -- 'on' or 'off'
this.active = false;
// ^ is this IconState active for rendering?
this.icon = typeof icon !== "undefined" ? icon : null;
// ^ the corresponding browser toolbar-icon object
this.dirty = (1 << 1) | (1 << 0);
/* ^ bitmask AB: two bits, A and B
where A is whether img has changed and needs render
and B is whether badge has changed and needs render */
};
var iconStateForTabId = {}; // {tabId: IconState}
var getIconForWindow = function(whichWindow) {
// do we already have the right icon cached?
if(typeof whichWindow.uBlockIcon !== "undefined") {
return whichWindow.uBlockIcon;
}
// iterate through the icons to find the one which
// belongs to this window (whichWindow)
var items = safari.extension.toolbarItems;
for(var i = 0; i < items.length; i++) {
if(items[i].browserWindow === whichWindow) {
return (whichWindow.uBlockIcon = items[i]);
}
}
};
safari.application.addEventListener("activate", function(event) {
if(!(event.target instanceof SafariBrowserTab)) {
return;
}
// when a tab is activated...
var tab = event.target;
if(tab.browserWindow !== tab.oldBrowserWindow) {
// looks like tab is now associated with a new window
tab.oldBrowserWindow = tab.browserWindow;
// so, unvalidate icon
tab.uBlockKnowsIcon = false;
}
var tabId = vAPI.tabs.getTabId(tab),
state = iconStateForTabId[tabId];
if(typeof state === "undefined") {
state = iconStateForTabId[tabId] = new IconState(0, "on");
// need to get the icon for this newly-encountered tab...
// uBlockKnowsIcon should be undefined here, so in theory
// we don't need this -- but to be sure,
// go ahead and explicitly unvalidate
tab.uBlockKnowsIcon = false;
}
if(!tab.uBlockKnowsIcon) {
// need to find the icon for this tab's window
state.icon = getIconForWindow(tab.browserWindow);
tab.uBlockKnowsIcon = true;
}
state.active = true;
// force re-render since we probably switched tabs
state.dirty = (1 << 1) | (1 << 0);
renderIcon(state);
}, true);
safari.application.addEventListener("deactivate", function(event) {
if(!(event.target instanceof SafariBrowserTab)) {
return;
}
// when a tab is deactivated...
var tabId = vAPI.tabs.getTabId(event.target),
state = iconStateForTabId[tabId];
if(typeof state === "undefined") {
return;
}
// mark its iconState as inactive so we don't visually
// render changes for now
state.active = false;
}, true);
var renderIcon = function(iconState) {
if(iconState.dirty === 0) {
// quit if we don't need to touch the "DOM"
return;
}
var icon = iconState.icon;
icon.badge = iconState.badge;
// only update the image if needed:
if(iconState.dirty & 1) {
icon.image = ICON_URLS[iconState.img];
}
iconState.dirty = 0;
};
vAPI.setIcon = function(tabId, iconStatus, badge) {
badge = badge || 0;
var state = iconStateForTabId[tabId];
if(typeof state === "undefined") {
state = iconStateForTabId[tabId] = new IconState(badge, iconStatus);
}
else {
state.dirty = ((state.badge !== badge) << 1) | ((state.img !== iconStatus) << 0);
state.badge = badge;
state.img = iconStatus;
}
if(state.active === true) {
renderIcon(state);
}
};
/******************************************************************************/
// bind tabs to unique IDs
(function() {
var wins = safari.application.browserWindows,
i = wins.length,
j;
while(i --) {
j = wins[i].tabs.length;
j,
curTab,
curTabId,
curWindow;
while(i--) {
curWindow = wins[i];
j = curWindow.tabs.length;
while(j--) {
vAPI.tabs.stack[vAPI.tabs.stackId++] = wins[i].tabs[j];
curTab = wins[i].tabs[j], curTabId = vAPI.tabs.stackId++;
iconStateForTabId[curTabId] = new IconState(0, "on", getIconForWindow(curWindow));
curTab.uBlockKnowsIcon = true;
if(curWindow.activeTab === curTab) {
iconStateForTabId[curTabId].active = true;
}
vAPI.tabs.stack[curTabId] = curTab;
}
}
})();
@ -499,74 +641,12 @@
vAPI.tabs.onClosed(tabId);
}
delete vAPI.tabIconState[tabId];
delete vAPI.tabs.stack[tabId];
delete iconStateForTabId[tabId];
}
}, true);
/******************************************************************************/
vAPI.toolbarItem = false;
var getIconForWindow = function(target) {
var items = safari.extension.toolbarItems;
for(var i = 0, n = items.length; i < n; i++) {
if(items[i].browserWindow === target) {
return items[i];
}
}
};
safari.application.addEventListener("activate", function(event) {
var target = event.target;
if(target instanceof SafariBrowserTab) {
vAPI.updateIcon(vAPI.tabs.getTabId(target));
}
else if(target instanceof SafariBrowserWindow) {
vAPI.toolbarItem = getIconForWindow(target);
}
}, true);
/******************************************************************************/
// reload the popup when it's opened
safari.application.addEventListener("popover", function(event) {
var w = event.target.contentWindow, body = w.document.body, child;
while(child = body.firstChild) {
body.removeChild(child);
}
w.location.reload();
}, true);
/******************************************************************************/
function TabIconState() {}
TabIconState.prototype.badge = 0;
TabIconState.prototype.img = "";
vAPI.tabIconState = { /*tabId: {badge: 0, img: suffix}*/ };
vAPI.updateIcon = function(tabId) {
var icon = vAPI.toolbarItem;
if(icon === false) {
icon = getIconForWindow(vAPI.tabs.stack[tabId].browserWindow);
}
var state = vAPI.tabIconState[tabId];
if(typeof state === "undefined") {
state = vAPI.tabIconState[tabId] = new TabIconState();
}
icon.badge = state.badge;
icon.image = vAPI.getURL("img/browsericons/safari-icon16" + state.img + ".png");
};
vAPI.setIcon = function(tabId, iconStatus, badge) {
var state = vAPI.tabIconState[tabId];
if(typeof state === "undefined") {
state = vAPI.tabIconState[tabId] = new TabIconState();
}
state.badge = badge || 0;
state.img = (iconStatus === "on" ? "" : "-off");
vAPI.updateIcon(tabId);
};
/******************************************************************************/
vAPI.messaging = {
listeners: {},
defaultHandler: null,