Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | # -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
michael@0 | 2 | # This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | # License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
michael@0 | 5 | |
michael@0 | 6 | const gXPInstallObserver = { |
michael@0 | 7 | _findChildShell: function (aDocShell, aSoughtShell) |
michael@0 | 8 | { |
michael@0 | 9 | if (aDocShell == aSoughtShell) |
michael@0 | 10 | return aDocShell; |
michael@0 | 11 | |
michael@0 | 12 | var node = aDocShell.QueryInterface(Components.interfaces.nsIDocShellTreeItem); |
michael@0 | 13 | for (var i = 0; i < node.childCount; ++i) { |
michael@0 | 14 | var docShell = node.getChildAt(i); |
michael@0 | 15 | docShell = this._findChildShell(docShell, aSoughtShell); |
michael@0 | 16 | if (docShell == aSoughtShell) |
michael@0 | 17 | return docShell; |
michael@0 | 18 | } |
michael@0 | 19 | return null; |
michael@0 | 20 | }, |
michael@0 | 21 | |
michael@0 | 22 | _getBrowser: function (aDocShell) |
michael@0 | 23 | { |
michael@0 | 24 | for (let browser of gBrowser.browsers) { |
michael@0 | 25 | if (this._findChildShell(browser.docShell, aDocShell)) |
michael@0 | 26 | return browser; |
michael@0 | 27 | } |
michael@0 | 28 | return null; |
michael@0 | 29 | }, |
michael@0 | 30 | |
michael@0 | 31 | observe: function (aSubject, aTopic, aData) |
michael@0 | 32 | { |
michael@0 | 33 | var brandBundle = document.getElementById("bundle_brand"); |
michael@0 | 34 | var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo); |
michael@0 | 35 | var win = installInfo.originatingWindow; |
michael@0 | 36 | var shell = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor) |
michael@0 | 37 | .getInterface(Components.interfaces.nsIWebNavigation) |
michael@0 | 38 | .QueryInterface(Components.interfaces.nsIDocShell); |
michael@0 | 39 | var browser = this._getBrowser(shell); |
michael@0 | 40 | if (!browser) |
michael@0 | 41 | return; |
michael@0 | 42 | const anchorID = "addons-notification-icon"; |
michael@0 | 43 | var messageString, action; |
michael@0 | 44 | var brandShortName = brandBundle.getString("brandShortName"); |
michael@0 | 45 | |
michael@0 | 46 | var notificationID = aTopic; |
michael@0 | 47 | // Make notifications persist a minimum of 30 seconds |
michael@0 | 48 | var options = { |
michael@0 | 49 | timeout: Date.now() + 30000 |
michael@0 | 50 | }; |
michael@0 | 51 | |
michael@0 | 52 | switch (aTopic) { |
michael@0 | 53 | case "addon-install-disabled": |
michael@0 | 54 | notificationID = "xpinstall-disabled" |
michael@0 | 55 | |
michael@0 | 56 | if (gPrefService.prefIsLocked("xpinstall.enabled")) { |
michael@0 | 57 | messageString = gNavigatorBundle.getString("xpinstallDisabledMessageLocked"); |
michael@0 | 58 | buttons = []; |
michael@0 | 59 | } |
michael@0 | 60 | else { |
michael@0 | 61 | messageString = gNavigatorBundle.getString("xpinstallDisabledMessage"); |
michael@0 | 62 | |
michael@0 | 63 | action = { |
michael@0 | 64 | label: gNavigatorBundle.getString("xpinstallDisabledButton"), |
michael@0 | 65 | accessKey: gNavigatorBundle.getString("xpinstallDisabledButton.accesskey"), |
michael@0 | 66 | callback: function editPrefs() { |
michael@0 | 67 | gPrefService.setBoolPref("xpinstall.enabled", true); |
michael@0 | 68 | } |
michael@0 | 69 | }; |
michael@0 | 70 | } |
michael@0 | 71 | |
michael@0 | 72 | PopupNotifications.show(browser, notificationID, messageString, anchorID, |
michael@0 | 73 | action, null, options); |
michael@0 | 74 | break; |
michael@0 | 75 | case "addon-install-blocked": |
michael@0 | 76 | messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarning", |
michael@0 | 77 | [brandShortName, installInfo.originatingURI.host]); |
michael@0 | 78 | |
michael@0 | 79 | let secHistogram = Components.classes["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry).getHistogramById("SECURITY_UI"); |
michael@0 | 80 | action = { |
michael@0 | 81 | label: gNavigatorBundle.getString("xpinstallPromptAllowButton"), |
michael@0 | 82 | accessKey: gNavigatorBundle.getString("xpinstallPromptAllowButton.accesskey"), |
michael@0 | 83 | callback: function() { |
michael@0 | 84 | secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_ADDON_ASKING_PREVENTED_CLICK_THROUGH); |
michael@0 | 85 | installInfo.install(); |
michael@0 | 86 | } |
michael@0 | 87 | }; |
michael@0 | 88 | |
michael@0 | 89 | secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_ADDON_ASKING_PREVENTED); |
michael@0 | 90 | PopupNotifications.show(browser, notificationID, messageString, anchorID, |
michael@0 | 91 | action, null, options); |
michael@0 | 92 | break; |
michael@0 | 93 | case "addon-install-started": |
michael@0 | 94 | var needsDownload = function needsDownload(aInstall) { |
michael@0 | 95 | return aInstall.state != AddonManager.STATE_DOWNLOADED; |
michael@0 | 96 | } |
michael@0 | 97 | // If all installs have already been downloaded then there is no need to |
michael@0 | 98 | // show the download progress |
michael@0 | 99 | if (!installInfo.installs.some(needsDownload)) |
michael@0 | 100 | return; |
michael@0 | 101 | notificationID = "addon-progress"; |
michael@0 | 102 | messageString = gNavigatorBundle.getString("addonDownloading"); |
michael@0 | 103 | messageString = PluralForm.get(installInfo.installs.length, messageString); |
michael@0 | 104 | options.installs = installInfo.installs; |
michael@0 | 105 | options.contentWindow = browser.contentWindow; |
michael@0 | 106 | options.sourceURI = browser.currentURI; |
michael@0 | 107 | options.eventCallback = function(aEvent) { |
michael@0 | 108 | if (aEvent != "removed") |
michael@0 | 109 | return; |
michael@0 | 110 | options.contentWindow = null; |
michael@0 | 111 | options.sourceURI = null; |
michael@0 | 112 | }; |
michael@0 | 113 | PopupNotifications.show(browser, notificationID, messageString, anchorID, |
michael@0 | 114 | null, null, options); |
michael@0 | 115 | break; |
michael@0 | 116 | case "addon-install-failed": |
michael@0 | 117 | // TODO This isn't terribly ideal for the multiple failure case |
michael@0 | 118 | for (let install of installInfo.installs) { |
michael@0 | 119 | let host = (installInfo.originatingURI instanceof Ci.nsIStandardURL) && |
michael@0 | 120 | installInfo.originatingURI.host; |
michael@0 | 121 | if (!host) |
michael@0 | 122 | host = (install.sourceURI instanceof Ci.nsIStandardURL) && |
michael@0 | 123 | install.sourceURI.host; |
michael@0 | 124 | |
michael@0 | 125 | let error = (host || install.error == 0) ? "addonError" : "addonLocalError"; |
michael@0 | 126 | if (install.error != 0) |
michael@0 | 127 | error += install.error; |
michael@0 | 128 | else if (install.addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED) |
michael@0 | 129 | error += "Blocklisted"; |
michael@0 | 130 | else |
michael@0 | 131 | error += "Incompatible"; |
michael@0 | 132 | |
michael@0 | 133 | messageString = gNavigatorBundle.getString(error); |
michael@0 | 134 | messageString = messageString.replace("#1", install.name); |
michael@0 | 135 | if (host) |
michael@0 | 136 | messageString = messageString.replace("#2", host); |
michael@0 | 137 | messageString = messageString.replace("#3", brandShortName); |
michael@0 | 138 | messageString = messageString.replace("#4", Services.appinfo.version); |
michael@0 | 139 | |
michael@0 | 140 | PopupNotifications.show(browser, notificationID, messageString, anchorID, |
michael@0 | 141 | action, null, options); |
michael@0 | 142 | } |
michael@0 | 143 | break; |
michael@0 | 144 | case "addon-install-complete": |
michael@0 | 145 | var needsRestart = installInfo.installs.some(function(i) { |
michael@0 | 146 | return i.addon.pendingOperations != AddonManager.PENDING_NONE; |
michael@0 | 147 | }); |
michael@0 | 148 | |
michael@0 | 149 | if (needsRestart) { |
michael@0 | 150 | messageString = gNavigatorBundle.getString("addonsInstalledNeedsRestart"); |
michael@0 | 151 | action = { |
michael@0 | 152 | label: gNavigatorBundle.getString("addonInstallRestartButton"), |
michael@0 | 153 | accessKey: gNavigatorBundle.getString("addonInstallRestartButton.accesskey"), |
michael@0 | 154 | callback: function() { |
michael@0 | 155 | Application.restart(); |
michael@0 | 156 | } |
michael@0 | 157 | }; |
michael@0 | 158 | } |
michael@0 | 159 | else { |
michael@0 | 160 | messageString = gNavigatorBundle.getString("addonsInstalled"); |
michael@0 | 161 | action = null; |
michael@0 | 162 | } |
michael@0 | 163 | |
michael@0 | 164 | messageString = PluralForm.get(installInfo.installs.length, messageString); |
michael@0 | 165 | messageString = messageString.replace("#1", installInfo.installs[0].name); |
michael@0 | 166 | messageString = messageString.replace("#2", installInfo.installs.length); |
michael@0 | 167 | messageString = messageString.replace("#3", brandShortName); |
michael@0 | 168 | |
michael@0 | 169 | // Remove notificaion on dismissal, since it's possible to cancel the |
michael@0 | 170 | // install through the addons manager UI, making the "restart" prompt |
michael@0 | 171 | // irrelevant. |
michael@0 | 172 | options.removeOnDismissal = true; |
michael@0 | 173 | |
michael@0 | 174 | PopupNotifications.show(browser, notificationID, messageString, anchorID, |
michael@0 | 175 | action, null, options); |
michael@0 | 176 | break; |
michael@0 | 177 | } |
michael@0 | 178 | } |
michael@0 | 179 | }; |
michael@0 | 180 | |
michael@0 | 181 | var LightWeightThemeWebInstaller = { |
michael@0 | 182 | handleEvent: function (event) { |
michael@0 | 183 | switch (event.type) { |
michael@0 | 184 | case "InstallBrowserTheme": |
michael@0 | 185 | case "PreviewBrowserTheme": |
michael@0 | 186 | case "ResetBrowserThemePreview": |
michael@0 | 187 | // ignore requests from background tabs |
michael@0 | 188 | if (event.target.ownerDocument.defaultView.top != content) |
michael@0 | 189 | return; |
michael@0 | 190 | } |
michael@0 | 191 | switch (event.type) { |
michael@0 | 192 | case "InstallBrowserTheme": |
michael@0 | 193 | this._installRequest(event); |
michael@0 | 194 | break; |
michael@0 | 195 | case "PreviewBrowserTheme": |
michael@0 | 196 | this._preview(event); |
michael@0 | 197 | break; |
michael@0 | 198 | case "ResetBrowserThemePreview": |
michael@0 | 199 | this._resetPreview(event); |
michael@0 | 200 | break; |
michael@0 | 201 | case "pagehide": |
michael@0 | 202 | case "TabSelect": |
michael@0 | 203 | this._resetPreview(); |
michael@0 | 204 | break; |
michael@0 | 205 | } |
michael@0 | 206 | }, |
michael@0 | 207 | |
michael@0 | 208 | get _manager () { |
michael@0 | 209 | var temp = {}; |
michael@0 | 210 | Cu.import("resource://gre/modules/LightweightThemeManager.jsm", temp); |
michael@0 | 211 | delete this._manager; |
michael@0 | 212 | return this._manager = temp.LightweightThemeManager; |
michael@0 | 213 | }, |
michael@0 | 214 | |
michael@0 | 215 | _installRequest: function (event) { |
michael@0 | 216 | var node = event.target; |
michael@0 | 217 | var data = this._getThemeFromNode(node); |
michael@0 | 218 | if (!data) |
michael@0 | 219 | return; |
michael@0 | 220 | |
michael@0 | 221 | if (this._isAllowed(node)) { |
michael@0 | 222 | this._install(data); |
michael@0 | 223 | return; |
michael@0 | 224 | } |
michael@0 | 225 | |
michael@0 | 226 | var allowButtonText = |
michael@0 | 227 | gNavigatorBundle.getString("lwthemeInstallRequest.allowButton"); |
michael@0 | 228 | var allowButtonAccesskey = |
michael@0 | 229 | gNavigatorBundle.getString("lwthemeInstallRequest.allowButton.accesskey"); |
michael@0 | 230 | var message = |
michael@0 | 231 | gNavigatorBundle.getFormattedString("lwthemeInstallRequest.message", |
michael@0 | 232 | [node.ownerDocument.location.host]); |
michael@0 | 233 | var buttons = [{ |
michael@0 | 234 | label: allowButtonText, |
michael@0 | 235 | accessKey: allowButtonAccesskey, |
michael@0 | 236 | callback: function () { |
michael@0 | 237 | LightWeightThemeWebInstaller._install(data); |
michael@0 | 238 | } |
michael@0 | 239 | }]; |
michael@0 | 240 | |
michael@0 | 241 | this._removePreviousNotifications(); |
michael@0 | 242 | |
michael@0 | 243 | var notificationBox = gBrowser.getNotificationBox(); |
michael@0 | 244 | var notificationBar = |
michael@0 | 245 | notificationBox.appendNotification(message, "lwtheme-install-request", "", |
michael@0 | 246 | notificationBox.PRIORITY_INFO_MEDIUM, |
michael@0 | 247 | buttons); |
michael@0 | 248 | notificationBar.persistence = 1; |
michael@0 | 249 | }, |
michael@0 | 250 | |
michael@0 | 251 | _install: function (newLWTheme) { |
michael@0 | 252 | var previousLWTheme = this._manager.currentTheme; |
michael@0 | 253 | |
michael@0 | 254 | var listener = { |
michael@0 | 255 | onEnabling: function(aAddon, aRequiresRestart) { |
michael@0 | 256 | if (!aRequiresRestart) |
michael@0 | 257 | return; |
michael@0 | 258 | |
michael@0 | 259 | let messageString = gNavigatorBundle.getFormattedString("lwthemeNeedsRestart.message", |
michael@0 | 260 | [aAddon.name], 1); |
michael@0 | 261 | |
michael@0 | 262 | let action = { |
michael@0 | 263 | label: gNavigatorBundle.getString("lwthemeNeedsRestart.button"), |
michael@0 | 264 | accessKey: gNavigatorBundle.getString("lwthemeNeedsRestart.accesskey"), |
michael@0 | 265 | callback: function () { |
michael@0 | 266 | Application.restart(); |
michael@0 | 267 | } |
michael@0 | 268 | }; |
michael@0 | 269 | |
michael@0 | 270 | let options = { |
michael@0 | 271 | timeout: Date.now() + 30000 |
michael@0 | 272 | }; |
michael@0 | 273 | |
michael@0 | 274 | PopupNotifications.show(gBrowser.selectedBrowser, "addon-theme-change", |
michael@0 | 275 | messageString, "addons-notification-icon", |
michael@0 | 276 | action, null, options); |
michael@0 | 277 | }, |
michael@0 | 278 | |
michael@0 | 279 | onEnabled: function(aAddon) { |
michael@0 | 280 | LightWeightThemeWebInstaller._postInstallNotification(newLWTheme, previousLWTheme); |
michael@0 | 281 | } |
michael@0 | 282 | }; |
michael@0 | 283 | |
michael@0 | 284 | AddonManager.addAddonListener(listener); |
michael@0 | 285 | this._manager.currentTheme = newLWTheme; |
michael@0 | 286 | AddonManager.removeAddonListener(listener); |
michael@0 | 287 | }, |
michael@0 | 288 | |
michael@0 | 289 | _postInstallNotification: function (newTheme, previousTheme) { |
michael@0 | 290 | function text(id) { |
michael@0 | 291 | return gNavigatorBundle.getString("lwthemePostInstallNotification." + id); |
michael@0 | 292 | } |
michael@0 | 293 | |
michael@0 | 294 | var buttons = [{ |
michael@0 | 295 | label: text("undoButton"), |
michael@0 | 296 | accessKey: text("undoButton.accesskey"), |
michael@0 | 297 | callback: function () { |
michael@0 | 298 | LightWeightThemeWebInstaller._manager.forgetUsedTheme(newTheme.id); |
michael@0 | 299 | LightWeightThemeWebInstaller._manager.currentTheme = previousTheme; |
michael@0 | 300 | } |
michael@0 | 301 | }, { |
michael@0 | 302 | label: text("manageButton"), |
michael@0 | 303 | accessKey: text("manageButton.accesskey"), |
michael@0 | 304 | callback: function () { |
michael@0 | 305 | BrowserOpenAddonsMgr("addons://list/theme"); |
michael@0 | 306 | } |
michael@0 | 307 | }]; |
michael@0 | 308 | |
michael@0 | 309 | this._removePreviousNotifications(); |
michael@0 | 310 | |
michael@0 | 311 | var notificationBox = gBrowser.getNotificationBox(); |
michael@0 | 312 | var notificationBar = |
michael@0 | 313 | notificationBox.appendNotification(text("message"), |
michael@0 | 314 | "lwtheme-install-notification", "", |
michael@0 | 315 | notificationBox.PRIORITY_INFO_MEDIUM, |
michael@0 | 316 | buttons); |
michael@0 | 317 | notificationBar.persistence = 1; |
michael@0 | 318 | notificationBar.timeout = Date.now() + 20000; // 20 seconds |
michael@0 | 319 | }, |
michael@0 | 320 | |
michael@0 | 321 | _removePreviousNotifications: function () { |
michael@0 | 322 | var box = gBrowser.getNotificationBox(); |
michael@0 | 323 | |
michael@0 | 324 | ["lwtheme-install-request", |
michael@0 | 325 | "lwtheme-install-notification"].forEach(function (value) { |
michael@0 | 326 | var notification = box.getNotificationWithValue(value); |
michael@0 | 327 | if (notification) |
michael@0 | 328 | box.removeNotification(notification); |
michael@0 | 329 | }); |
michael@0 | 330 | }, |
michael@0 | 331 | |
michael@0 | 332 | _previewWindow: null, |
michael@0 | 333 | _preview: function (event) { |
michael@0 | 334 | if (!this._isAllowed(event.target)) |
michael@0 | 335 | return; |
michael@0 | 336 | |
michael@0 | 337 | var data = this._getThemeFromNode(event.target); |
michael@0 | 338 | if (!data) |
michael@0 | 339 | return; |
michael@0 | 340 | |
michael@0 | 341 | this._resetPreview(); |
michael@0 | 342 | |
michael@0 | 343 | this._previewWindow = event.target.ownerDocument.defaultView; |
michael@0 | 344 | this._previewWindow.addEventListener("pagehide", this, true); |
michael@0 | 345 | gBrowser.tabContainer.addEventListener("TabSelect", this, false); |
michael@0 | 346 | |
michael@0 | 347 | this._manager.previewTheme(data); |
michael@0 | 348 | }, |
michael@0 | 349 | |
michael@0 | 350 | _resetPreview: function (event) { |
michael@0 | 351 | if (!this._previewWindow || |
michael@0 | 352 | event && !this._isAllowed(event.target)) |
michael@0 | 353 | return; |
michael@0 | 354 | |
michael@0 | 355 | this._previewWindow.removeEventListener("pagehide", this, true); |
michael@0 | 356 | this._previewWindow = null; |
michael@0 | 357 | gBrowser.tabContainer.removeEventListener("TabSelect", this, false); |
michael@0 | 358 | |
michael@0 | 359 | this._manager.resetPreview(); |
michael@0 | 360 | }, |
michael@0 | 361 | |
michael@0 | 362 | _isAllowed: function (node) { |
michael@0 | 363 | var pm = Services.perms; |
michael@0 | 364 | |
michael@0 | 365 | var uri = node.ownerDocument.documentURIObject; |
michael@0 | 366 | return pm.testPermission(uri, "install") == pm.ALLOW_ACTION; |
michael@0 | 367 | }, |
michael@0 | 368 | |
michael@0 | 369 | _getThemeFromNode: function (node) { |
michael@0 | 370 | return this._manager.parseTheme(node.getAttribute("data-browsertheme"), |
michael@0 | 371 | node.baseURI); |
michael@0 | 372 | } |
michael@0 | 373 | } |
michael@0 | 374 | |
michael@0 | 375 | /* |
michael@0 | 376 | * Listen for Lightweight Theme styling changes and update the browser's theme accordingly. |
michael@0 | 377 | */ |
michael@0 | 378 | let LightweightThemeListener = { |
michael@0 | 379 | _modifiedStyles: [], |
michael@0 | 380 | |
michael@0 | 381 | init: function () { |
michael@0 | 382 | XPCOMUtils.defineLazyGetter(this, "styleSheet", function() { |
michael@0 | 383 | for (let i = document.styleSheets.length - 1; i >= 0; i--) { |
michael@0 | 384 | let sheet = document.styleSheets[i]; |
michael@0 | 385 | if (sheet.href == "chrome://browser/skin/browser-lightweightTheme.css") |
michael@0 | 386 | return sheet; |
michael@0 | 387 | } |
michael@0 | 388 | }); |
michael@0 | 389 | |
michael@0 | 390 | Services.obs.addObserver(this, "lightweight-theme-styling-update", false); |
michael@0 | 391 | Services.obs.addObserver(this, "lightweight-theme-optimized", false); |
michael@0 | 392 | if (document.documentElement.hasAttribute("lwtheme")) |
michael@0 | 393 | this.updateStyleSheet(document.documentElement.style.backgroundImage); |
michael@0 | 394 | }, |
michael@0 | 395 | |
michael@0 | 396 | uninit: function () { |
michael@0 | 397 | Services.obs.removeObserver(this, "lightweight-theme-styling-update"); |
michael@0 | 398 | Services.obs.removeObserver(this, "lightweight-theme-optimized"); |
michael@0 | 399 | }, |
michael@0 | 400 | |
michael@0 | 401 | /** |
michael@0 | 402 | * Append the headerImage to the background-image property of all rulesets in |
michael@0 | 403 | * browser-lightweightTheme.css. |
michael@0 | 404 | * |
michael@0 | 405 | * @param headerImage - a string containing a CSS image for the lightweight theme header. |
michael@0 | 406 | */ |
michael@0 | 407 | updateStyleSheet: function(headerImage) { |
michael@0 | 408 | if (!this.styleSheet) |
michael@0 | 409 | return; |
michael@0 | 410 | this.substituteRules(this.styleSheet.cssRules, headerImage); |
michael@0 | 411 | }, |
michael@0 | 412 | |
michael@0 | 413 | substituteRules: function(ruleList, headerImage, existingStyleRulesModified = 0) { |
michael@0 | 414 | let styleRulesModified = 0; |
michael@0 | 415 | for (let i = 0; i < ruleList.length; i++) { |
michael@0 | 416 | let rule = ruleList[i]; |
michael@0 | 417 | if (rule instanceof Ci.nsIDOMCSSGroupingRule) { |
michael@0 | 418 | // Add the number of modified sub-rules to the modified count |
michael@0 | 419 | styleRulesModified += this.substituteRules(rule.cssRules, headerImage, existingStyleRulesModified + styleRulesModified); |
michael@0 | 420 | } else if (rule instanceof Ci.nsIDOMCSSStyleRule) { |
michael@0 | 421 | if (!rule.style.backgroundImage) |
michael@0 | 422 | continue; |
michael@0 | 423 | let modifiedIndex = existingStyleRulesModified + styleRulesModified; |
michael@0 | 424 | if (!this._modifiedStyles[modifiedIndex]) |
michael@0 | 425 | this._modifiedStyles[modifiedIndex] = { backgroundImage: rule.style.backgroundImage }; |
michael@0 | 426 | |
michael@0 | 427 | rule.style.backgroundImage = this._modifiedStyles[modifiedIndex].backgroundImage + ", " + headerImage; |
michael@0 | 428 | styleRulesModified++; |
michael@0 | 429 | } else { |
michael@0 | 430 | Cu.reportError("Unsupported rule encountered"); |
michael@0 | 431 | } |
michael@0 | 432 | } |
michael@0 | 433 | return styleRulesModified; |
michael@0 | 434 | }, |
michael@0 | 435 | |
michael@0 | 436 | // nsIObserver |
michael@0 | 437 | observe: function (aSubject, aTopic, aData) { |
michael@0 | 438 | if ((aTopic != "lightweight-theme-styling-update" && aTopic != "lightweight-theme-optimized") || |
michael@0 | 439 | !this.styleSheet) |
michael@0 | 440 | return; |
michael@0 | 441 | |
michael@0 | 442 | if (aTopic == "lightweight-theme-optimized" && aSubject != window) |
michael@0 | 443 | return; |
michael@0 | 444 | |
michael@0 | 445 | let themeData = JSON.parse(aData); |
michael@0 | 446 | if (!themeData) |
michael@0 | 447 | return; |
michael@0 | 448 | this.updateStyleSheet("url(" + themeData.headerURL + ")"); |
michael@0 | 449 | }, |
michael@0 | 450 | }; |