From af727561cf25c8195759c7d6523ce7887ed17b5a Mon Sep 17 00:00:00 2001 From: satyr Date: Thu, 18 Mar 2010 05:41:03 +0900 Subject: [PATCH] Added SkinFeedPlugin in place of SkinSvc, simplifying things greatly. --- ubiquity/builtin-feeds/builtincmds.js | 2 +- ubiquity/chrome/content/cmdlist.js | 25 +- ubiquity/chrome/content/header.js | 1 + ubiquity/chrome/content/settings.js | 124 ++++----- ubiquity/index.html | 2 + ubiquity/modules/nountypes.js | 6 +- ubiquity/modules/setup.js | 45 +--- ubiquity/modules/skin_feed_plugin.js | 240 +++++++++++++++++ ubiquity/modules/skinsvc.js | 375 -------------------------- 9 files changed, 315 insertions(+), 505 deletions(-) create mode 100644 ubiquity/modules/skin_feed_plugin.js delete mode 100755 ubiquity/modules/skinsvc.js diff --git a/ubiquity/builtin-feeds/builtincmds.js b/ubiquity/builtin-feeds/builtincmds.js index d28ec375..67caa820 100644 --- a/ubiquity/builtin-feeds/builtincmds.js +++ b/ubiquity/builtin-feeds/builtincmds.js @@ -159,7 +159,7 @@ CmdUtils.CreateCommand({ argument: noun_type_skin, execute: function chskin_execute({object: {data: skin}}) { if (skin) { - UbiquitySetup.createServices().skinService.changeSkin(skin.localUrl); + skin.pick(); Utils.tabs.reload(/^about:ubiquity\?settings\b/); } else Utils.focusUrlInBrowser(Settings); diff --git a/ubiquity/chrome/content/cmdlist.js b/ubiquity/chrome/content/cmdlist.js index 0fc0921d..fb43fb1e 100644 --- a/ubiquity/chrome/content/cmdlist.js +++ b/ubiquity/chrome/content/cmdlist.js @@ -66,6 +66,10 @@ var {escapeHtml} = Utils; var {feedManager, commandSource, messageService} = ( UbiquitySetup.createServices()); +function getFeeds(type) [ + feed for each (feed in feedManager["get" + type + "Feeds"]()) + if ("commands" in feed)]; + function A(url, text, className, attrs) { var a = document.createElement("a"); a.href = url; @@ -231,12 +235,11 @@ function fillTableRowForCmd(row, cmd, className) { function updateSubscribedCount() { $("#num-commands").html(commandSource.commandNames.length); - $("#num-subscribed-feeds").html(feedManager.getSubscribedFeeds().length); + $("#num-subscribed-feeds").text(getFeeds("Subscribed").length); } function updateUnsubscribedCount() { - $("#num-unsubscribed-feeds").html( - feedManager.getUnsubscribedFeeds().length); + $("#num-unsubscribed-feeds").text(getFeeds("Unsubscribed").length); } function buildTable() { @@ -267,10 +270,8 @@ function buildTable() { function addCmdToTable(cmd) { let aRow = $(""); let feedCell = $(""); - let feed = getFeedForCommand(feedManager, cmd); - if (feed) { - fillTableCellForFeed(feedCell, feed); - } + let feed = feedManager.getFeedForUrl(cmd.feedUri); + if (feed) fillTableCellForFeed(feedCell, feed); aRow.append(feedCell); fillTableRowForCmd(aRow, cmd); table.append(aRow); @@ -279,7 +280,7 @@ function buildTable() { updateSubscribedCount(); if (/^feed/.test(sortMode)) - (feedManager.getSubscribedFeeds() + (getFeeds("Subscribed") .sort(/date$/.test(sortMode) ? byDate : byTitle) .forEach(addFeedToTable)); else @@ -315,14 +316,6 @@ function sortCmdListBy(cmdList, key) { return cmdList.sort(key === "enabled" ? checksort : alphasort); } -function getFeedForCommand(feedManager, cmd) { - // This is a really hacky implementation -- it involves going through - // all feeds looking for one containing a command with a matching name. - for each (let feed in feedManager.getSubscribedFeeds()) - if (cmd.id in (feed.commands || {})) return feed; - return null; -} - // Bind this to checkbox "change". function onDisableOrEnableCmd() { // update the preferences, when the user toggles the active diff --git a/ubiquity/chrome/content/header.js b/ubiquity/chrome/content/header.js index b9061d14..0d4b1e86 100644 --- a/ubiquity/chrome/content/header.js +++ b/ubiquity/chrome/content/header.js @@ -45,6 +45,7 @@ Cu.import("resource://ubiquity/modules/localization_utils.js"); var L = LocalizationUtils.propertySelector( "chrome://ubiquity/locale/aboutubiquity.properties"); +var H = Utils.escapeHtml; var gPrefs = Utils.prefs; diff --git a/ubiquity/chrome/content/settings.js b/ubiquity/chrome/content/settings.js index 89179df9..2d85b8fc 100755 --- a/ubiquity/chrome/content/settings.js +++ b/ubiquity/chrome/content/settings.js @@ -42,7 +42,6 @@ Cu.import("resource://ubiquity/modules/prefkeys.js") const PREF_NFE = "extensions.ubiquity.doNounFirstExternals"; var {skinService, messageService} = UbiquitySetup.createServices(); -var {escapeHtml} = Utils; $(onDocumentLoad); @@ -117,107 +116,76 @@ function changeExternalCallSettings() { } function loadSkinList() { - var {CUSTOM_SKIN, currentSkin, skinList} = skinService; - var $list = $("#skin-list").empty(); - var i = 0; - for each (let skin in skinList) - if (skin.localUrl === CUSTOM_SKIN) - var customSkin = skin; - else - $list.append(createSkinElement(skin, i++)); - $list.append(createSkinElement(customSkin, i)); - checkSkin(currentSkin); - // If current skin is custom skin, auto-open the editor - if (currentSkin === CUSTOM_SKIN) - openSkinEditor(); + var {skins, currentSkin} = skinService; + var $list = $("#skin-list").empty(), id = -1; + for each (let skin in Utils.sortBy(skins, function(s) s.uri.spec)) + $list.append(createSkinElement(skin, ++id, skin === currentSkin)); + if (currentSkin === skinService.customSkin) openSkinEditor(); } -function createSkinElement(skin, id) { - var {localUrl: filepath, downloadUrl: origpath, metaData: skinMeta} = skin; - var skinId = "skin_" + id; - var skinEl = $( - '
' + - ('') + - '' + - '' + - '
'); +function createSkinElement(skin, id, current) { + var {metaData} = skin; + var $skin = $( + '
' + + ('') + + '
'); - //Add the name and onchange event - skinEl.find(".name").text(skinMeta.name); - skinEl.find("input").change(function onRadioChange() { - skinService.changeSkin(filepath); - }); + $skin.find(".name").text(metaData.name); + $skin.find("input").change(function onPick() { skin.pick() }); - if ("author" in skinMeta) - skinEl.find(".author").text(L("ubiquity.settings.skinauthor", - skinMeta.author)); - if ("email" in skinMeta) { - let ee = escapeHtml(skinMeta.email); - skinEl.find(".email")[0].innerHTML = "email: " + ee.link("mailto:" + ee); - } - if ("license" in skinMeta) - skinEl.find(".license").text(L("ubiquity.settings.skinlicense", - skinMeta.license)); - if ("homepage" in skinMeta) { - let eh = escapeHtml(skinMeta.homepage); - skinEl.find(".homepage")[0].innerHTML = eh.link(eh); - } + "author" in metaData && $("
", { + class: "author", + text: L("ubiquity.settings.skinauthor", metaData.author), + }).appendTo($skin); + "license" in metaData && $("
", { + class: "license", + text: L("ubiquity.settings.skinlicense", metaData.license), + }).appendTo($skin); + "email" in metaData && $("
", { + class: "email", + html: let (ee = H(metaData.email)) "email: " + ee.link("mailto:" + ee), + }).appendTo($skin); + "homepage" in metaData && $("
", { + class: "homepage", + html: let (eh = H(metaData.homepage)) eh.link(eh), + }).appendTo($skin); ($('') - .attr("href", "view-source:" + filepath) + .attr("href", "view-source:" + skin.viewSourceUri.spec) .text(L("ubiquity.settings.viewskinsource")) - .appendTo(skinEl)); - if (filepath !== origpath) ( + .appendTo($skin)); + + skin.isBuiltIn || ( $('') .text(L("ubiquity.settings.uninstallskin")) .click(function uninstall() { - var before = skinService.currentSkin; - skinService.uninstall(filepath); - var after = skinService.currentSkin; - if (before !== after) checkSkin(after); - skinEl.slideUp(); + if (skin === skinService.currentSkin) skinService.defaultSkin.pick(); + skin.purge(); + $skin.slideUp(); }) - .appendTo(skinEl.append(" "))); + .appendTo($skin.append(" "))); - return skinEl; -} - -function checkSkin(url) { - $("#skin-list input:radio").each(function radio() { - if (this.value === url) { - this.checked = true; - return false; - } - }); + return $skin; } function openSkinEditor() { $("#editor-div").show(); - $("#skin-editor").val(Utils.getLocalUrl(skinService.CUSTOM_SKIN)).focus(); + $("#skin-editor").val(skinService.customSkin.css).focus(); $("#edit-button").hide(); } function saveCustomSkin() { - try { - skinService.saveCustomSkin($("#skin-editor").val()); - } catch (e) { - messageService.displayMessage(L("ubiquity.settings.skinerror")); - Cu.reportError(e); - return; - } + var {customSkin} = skinService; + customSkin.css = $("#skin-editor").val(); messageService.displayMessage(L("ubiquity.settings.skinsaved")); - loadSkinList(); - if (skinService.currentSkin === skinService.CUSTOM_SKIN) - skinService.loadCurrentSkin(); + if (customSkin === skinService.currentSkin) customSkin.pick(); } function saveAs() { try { - skinService.saveAs($("#skin-editor").val(), "custom"); + skinService.saveAs($("#skin-editor").val(), "custom.css"); } catch (e) { messageService.displayMessage(L("ubiquity.settings.skinerror")); Cu.reportError(e); @@ -228,6 +196,6 @@ function saveAs() { function shareSkin() { var data = $("#skin-editor").val() - var name = Utils.trim((/@name[ \t]+(.+)/(data) || [, "ubiquity-skin"])[1]); + var name = ((/@name[ \t]+(.+)/(data) || [, "ubiquity-skin"])[1]).trim(); pasteToGist(name, data, "css"); } diff --git a/ubiquity/index.html b/ubiquity/index.html index f622a1ef..050eb7f2 100644 --- a/ubiquity/index.html +++ b/ubiquity/index.html @@ -42,6 +42,8 @@
  • Locked-Down Feed Plugin
  • +
  • SkinFeedPlugin
  • Parser 2
  • + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// = SkinFeedPlugin = +// The boss of {{{SkinFeed}}}s, aka {{{skinService}}}. + +var EXPORTED_SYMBOLS = ["SkinFeedPlugin"]; + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +Cu.import("resource://ubiquity/modules/utils.js"); +Cu.import("resource://ubiquity/modules/codesource.js"); +Cu.import("resource://ubiquity/modules/localization_utils.js"); + +const L = LocalizationUtils.propertySelector( + "chrome://ubiquity/locale/coreubiquity.properties"); +const SSS = (Cc["@mozilla.org/content/style-sheet-service;1"] + .getService(Ci.nsIStyleSheetService)); +const PREF_SKIN = "extensions.ubiquity.skin"; +const PREF_CUSTOM = "extensions.ubiquity.customCss"; +const PREF_REMOTE_TIMEOUT = "extensions.ubiquity.remoteUriTimeout"; +const URL_ROOT = "chrome://ubiquity/skin/skins/"; +const URL_CUSTOM = "ubiquity://custom-skin-css"; +const URL_DEFAULT = URL_ROOT + "experimental.css"; +const RE_LEAFNAME = /[^/]*$/; + +var gCurrentCssUri = Utils.uri("data:text/css,"); + +function SkinFeedPlugin(feedManager, msgService, webJsm) { + SFP._feedManager = feedManager; + SFP._msgService = msgService; + SFP._webJsm = webJsm; + feedManager.registerPlugin(SFP); + for each (let url in [ + URL_CUSTOM, URL_DEFAULT, URL_ROOT + "default.css", URL_ROOT + "old.css"]) + feedManager.addSubscribedFeed({ + type: "ubiquity-skin", + url: url, sourceUrl: url, title: url, + isBuiltIn: true, + canAutoUpdate: true, + }); + SFP.customSkin.__defineSetter__("css", function SF_setCustomCss(css) { + Utils.prefs.set(PREF_CUSTOM, css); + }); + SFP.currentSkin.pick(true); + return SFP; +} +var SFP = Utils.extend(SkinFeedPlugin.prototype, { + type: "ubiquity-skin", + notifyMessage: L("ubiquity.skinsvc.newskinfound"), + + makeFeed: function SFP_makeFeed(baseFeed, eventHub) + SkinFeed(baseFeed, eventHub, this._msgService), + onSubscribeClick: function SFP_onSubscribeClick(pageUrl, link) { + var cssUrl = link.href, me = this; + me._webJsm.jQuery.ajax({ + url: link.href, + dataType: "text", + success: function yay(css) { + me._feedManager.addSubscribedFeed({ + type: "ubiquity-skin", + url: cssUrl, sourceUrl: cssUrl, + title: url, + sourceCode: css, + canAutoUpdate: true, + }).getFeedForUrl(url).pick(); + Utils.tabs.reload(/^about:ubiquity\?settings\b/); + }, + error: Utils.log, + }); + }, + + // === {{{ SkinFeedPlugin.skins }}} === + // Installed {{{SkinFeed}}}s as array. + get skins SFP_getSkins() [ + feed for each (feed in this._feedManager.getSubscribedFeeds()) + if (feed.type === "ubiquity-skin")], + + // === {{{ SkinFeedPlugin.customSkin }}} === + get customSkin SFP_getCurrentSkin() + this._feedManager.getFeedForUrl(URL_CUSTOM), + + // === {{{ SkinFeedPlugin.defaultSkin }}} === + get defaultSkin SFP_getCurrentSkin() + this._feedManager.getFeedForUrl(URL_DEFAULT), + + // === {{{ SkinFeedPlugin.currentSkin }}} === + get currentSkin SFP_getCurrentSkin() ( + this._feedManager.getFeedForUrl(Utils.prefs.get(PREF_SKIN, URL_DEFAULT)) || + this.defaultSkin), + + // === {{{ SkinFeedPlugin.saveAs(cssText, defaultName) }}} === + // Saves {{{cssText}}} to a file and subscribes to it. + saveAs: function SFP_saveAs(cssText, defaultName) { + const {nsIFilePicker} = Ci; + var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); + fp.init(Utils.currentChromeWindow, + L("ubiquity.skinsvc.saveyourskin"), + nsIFilePicker.modeSave); + fp.defaultString = defaultName || ""; + fp.appendFilter("CSS (*.css)", "*.css"); + var rv = fp.show(); + if (rv !== nsIFilePicker.returnOK && + rv !== nsIFilePicker.returnReplace) return ""; + var {file, fileURL: {spec}} = fp; + try { + let fos = (Cc["@mozilla.org/network/file-output-stream;1"] + .createInstance(Ci.nsIFileOutputStream)); + fos.init(file, 0x02 | 0x08 | 0x20, 0644, 0); + fos.write(cssText, cssText.length); + fos.close(); + } catch (e) { + //errorToLocalize + e.message = + "Error writing Ubiquity skin to " + file.path + ": " + e.message; + Cu.reportError(e); + } + this.onSubscribeClick({title: RE_LEAFNAME(spec)[0], URL: spec}, spec); + this._feedManager.getFeedForUrl(spec).pick(); + return file.path; + }, + toString: function SFP_toString() "[object SkinFeedPlugin]", +}); + +// == SkinFeed == + +function SkinFeed(baseFeed, eventHub, msgService) Utils.extend({ + __proto__: baseFeed, + _msgService: msgService, + _codeSource: ( + RemoteUriCodeSource.isValidUri(baseFeed.uri) + ? new RemoteUriCodeSource(baseFeed, + Utils.prefs.get(PREF_REMOTE_TIMEOUT, 3e5)) + : new LocalUriCodeSource(baseFeed.uri.spec)), + _dataCache: null, +}, SkinFeed.prototype); +Utils.extend(SkinFeed.prototype, { + // === {{{ SkinFeed#css }}} === + // CSS code of this skin. Settable if custom. + get css SF_getCss() { + var code = this._codeSource.getCode(); + if (this._codeSource.updated) this._dataCache = null; + return code; + }, + + // === {{{ SkinFeed#dataUri }}} === + // Data URI object used to register this skin. + get dataUri SF_getDataUri() + Utils.uri("data:text/css,/*ubiquity-skin*/" + encodeURI(this.css)), + + // === {{{ SkinFeed#metaData }}} === + // Contents of the meta data block ({{{ =skin= ~ =/skin= }}}). + get metaData SF_getMetaData() { + if (this._dataCache) return this._dataCache; + var {css} = this, data = {name: this.title}; + var [, block] = /=skin=\s*([^]+)\s*=\/skin=/(css) || 0; + if (block) { + let re = /^[ \t]*@(\w+)[ \t]+(.+)/mg, m; + while ((m = re.exec(block))) data[m[1]] = m[2].trim(); + } + if (!("homepage" in data)) data.homepage = this.title; + return this._dataCache = data; + }, + + // === {{{ SkinFeed#pick(silently = false) }}} === + // Applies this skin. Won't notify user if {{{silently}}}. + pick: function SF_pick(silently) { + try { + (SSS.sheetRegistered(gCurrentCssUri, SSS.USER_SHEET) && + SSS.unregisterSheet(gCurrentCssUri, SSS.USER_SHEET)); + hackCssForBugs(gCurrentCssUri, SSS); + var {dataUri, uri} = this; + SSS.loadAndRegisterSheet(dataUri, SSS.USER_SHEET); + hackCssForBugs(dataUri, SSS, true); + gCurrentCssUri = dataUri; + Utils.prefs.set(PREF_SKIN, uri.spec); + } catch (e) { + this._msgService.displayMessage( + //errorToLocalize + "Error applying Ubiquity skin from " + uri.spec); + Cu.reportError(e); + } + silently || + this._msgService.displayMessage(L("ubiquity.skinsvc.skinchanged")); + return this; + }, + refresh: function SF_refresh() this, + toString: function SF_toString() "[object SkinFeed<" + this.uri.spec + ">]", +}); + +function hackCssForBugs(uri, registering) { + if (Utils.OS === "Darwin" && + uri.spec === URL_ROOT + "experimental.css") { + let hackUri = Utils.uri(URL_ROOT + "experimental-466hack.css"); + if (registering) + SSS.loadAndRegisterSheet(hackUri, SSS.USER_SHEET); + else if (SSS.sheetRegistered(hackUri, SSS.USER_SHEET)) + SSS.unregisterSheet(hackUri, SSS.USER_SHEET); + } +} + +Cu.import("resource://ubiquity/modules/ubiquity_protocol.js", null).setPath( + RE_LEAFNAME(URL_CUSTOM)[0], function customSkinUri() { + var css = Utils.prefs.get(PREF_CUSTOM); + if (!css) css = Utils.getLocalUrl(URL_ROOT + "custom.css"); + return "data:text/css," + encodeURI(css); + }); diff --git a/ubiquity/modules/skinsvc.js b/ubiquity/modules/skinsvc.js deleted file mode 100755 index e4e08abc..00000000 --- a/ubiquity/modules/skinsvc.js +++ /dev/null @@ -1,375 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Ubiquity. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2007 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Abimanyu Raja - * Satoshi Murakami - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -var EXPORTED_SYMBOLS = ["SkinSvc"]; - -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://ubiquity/modules/utils.js"); -Cu.import("resource://ubiquity/modules/dbutils.js"); -Cu.import("resource://ubiquity/modules/localization_utils.js"); - -const SKIN_ROOT = "chrome://ubiquity/skin/skins/"; -const SKIN_PREF = "extensions.ubiquity.skin"; - -var L = LocalizationUtils.propertySelector( - "chrome://ubiquity/locale/coreubiquity.properties"); - -var gConnection = connect(); -var gMetaDict = {}; - -function connect() DbUtils.connectLite( - "ubiquity_skin_memory", - { download_uri: "VARCHAR(256)", - local_uri : "VARCHAR(256)" }, - [let (path = SKIN_ROOT + name + ".css") [path, path] - for each (name in ["default", "experimental", "old", "custom"])]); - -function SkinSvc(webJsm, msgService) { - this._webJsm = webJsm; - this._msgService = msgService; -} - -SkinSvc.SkinProto = { - get metaData() SkinSvc.readMetaData(this), -}; - -SkinSvc.readMetaData = function SS_readMetaData( - {css, downloadUrl, localUrl, noCache}) { - if (!noCache && localUrl in gMetaDict) return gMetaDict[localUrl]; - var metaData = gMetaDict[localUrl] = {name: localUrl}; - css || (css = Utils.getLocalUrl(localUrl, "utf-8")); - //look for =skin= ~ =/skin= indicating metadata - var [, data] = /=skin=\s*([^]+)\s*=\/skin=/(css) || 0; - if (data) { - let re = /^[ \t]*@(\w+)[ \t]+(.+)/mg, m; - while ((m = re.exec(data))) metaData[m[1]] = m[2].trim(); - } - if (!("homepage" in metaData) && /^https?:/.test(downloadUrl)) - metaData.homepage = downloadUrl; - return metaData; -}; - -SkinSvc.reset = function SS_reset() { - var {databaseFile} = gConnection; - gConnection.close(); - databaseFile.exists() && databaseFile.remove(false); - gConnection = connect(); -}; - -SkinSvc.prototype = { - PREF: SKIN_PREF, - DEFAULT_SKIN: SKIN_ROOT + "experimental.css", - CUSTOM_SKIN : SKIN_ROOT + "custom.css", - - _createStatement: function SS__createStatement(sql) { - try { - return gConnection.createStatement(sql); - } catch (e) { - throw new Error(gConnection.lastErrorString); - } - }, - - _isLocalUrl: function SS__isLocalUrl(skinUrl) - /^(?:file|chrome)$/.test(Utils.url(skinUrl).scheme), - - //Navigate to chrome://ubiquity/skin/skins/ and get the folder - _getSkinFolder: function SS__getSkinFolder() { - var MY_ID = "ubiquity@labs.mozilla.com"; - var em = (Cc["@mozilla.org/extensions/manager;1"] - .getService(Ci.nsIExtensionManager)); - var file = (em.getInstallLocation(MY_ID) - .getItemFile(MY_ID, "chrome/skin/skins/default.css") - .parent); - return file; - }, - - // file: nsILocalFile / data: string - _writeToFile: function SS__writeToFile(file, data) { - try { - var foStream = (Cc["@mozilla.org/network/file-output-stream;1"] - .createInstance(Ci.nsIFileOutputStream)); - foStream.init(file, 0x02 | 0x08 | 0x20, 0644, 0); - foStream.write(data, data.length); - foStream.close(); - } catch (e) { - //errorToLocalize - Cu.reportError("Error writing Ubiquity skin to " + file.path + - "\n" + e); - } - }, - - _writeToLocalUrl: function SS__writeToLocalUrl(url, data) { - var file = this._getSkinFolder(); - file.append(url.slice(url.lastIndexOf("/") + 1)); - this._writeToFile(file, data); - SkinSvc.readMetaData({css: data, localUrl: url, noCache: true}); - }, - - _randomKey: function SS__randomKey() Math.random().toString(36).slice(-8), - - _hackCssForBug466: function SS__hackCssForBug466(cssPath, sss, action) { - if (cssPath.spec === "chrome://ubiquity/skin/skins/experimental.css" && - Utils.OS === "Darwin") { - let hackCss = - Utils.url("chrome://ubiquity/skin/skins/experimental-466hack.css"); - if (action === "register") - sss.loadAndRegisterSheet(hackCss, sss.USER_SHEET); - else if (sss.sheetRegistered(hackCss, sss.USER_SHEET)) - sss.unregisterSheet(hackCss, sss.USER_SHEET); - } - }, - - _hackCssForBug717: function SS__hackCssForBug717(cssPath, sss, action) { - if (cssPath.spec === "chrome://ubiquity/skin/skins/default.css" && - Utils.OS === "Darwin" && - let (VC = (Cc["@mozilla.org/xpcom/version-comparator;1"] - .getService(Ci.nsIVersionComparator)), - XULAI = (Cc["@mozilla.org/xre/app-info;1"] - .getService(Ci.nsIXULAppInfo)) - ) VC.compare(XULAI.version, "3.1") < 0) { - let hackCss = - Utils.url("chrome://ubiquity/skin/skins/default-717hack.css"); - if (action === "register") - sss.loadAndRegisterSheet(hackCss, sss.USER_SHEET); - else if (sss.sheetRegistered(hackCss, sss.USER_SHEET)) - sss.unregisterSheet(hackCss, sss.USER_SHEET); - } - }, - - //Check if the skin from this URL has already been installed - isInstalled: function SS_isInstalled(url) { - var selStmt = this._createStatement( - "SELECT COUNT(*) FROM ubiquity_skin_memory " + - "WHERE download_uri = ?1"); - selStmt.bindUTF8StringParameter(0, url); - var count = selStmt.executeStep() ? selStmt.getInt32(0) : 0; - selStmt.finalize(); - return count !== 0; - }, - - //Add a new skin record into the database - addSkin: function SS_addSkin(downloadUrl, localUrl) { - var insStmt = this._createStatement( - "INSERT INTO ubiquity_skin_memory VALUES (?1, ?2)"); - insStmt.bindUTF8StringParameter(0, downloadUrl); - insStmt.bindUTF8StringParameter(1, localUrl); - insStmt.execute(); - insStmt.finalize(); - }, - - deleteSkin: function SS_deleteSkin(url) { - var delStmt = this._createStatement( - "DELETE FROM ubiquity_skin_memory " + - "WHERE local_uri = ?1 OR download_uri = ?2"); - delStmt.bindUTF8StringParameter(0, url); - delStmt.bindUTF8StringParameter(1, url); - delStmt.execute(); - delStmt.finalize(); - }, - - //Unregister any current skins - //And load this new skin - loadSkin: function SS_loadSkin(newSkinPath) { - var sss = (Cc["@mozilla.org/content/style-sheet-service;1"] - .getService(Ci.nsIStyleSheetService)); - try { - // Remove the previous skin CSS - var oldCss = Utils.url(this.currentSkin); - if (sss.sheetRegistered(oldCss, sss.USER_SHEET)) - sss.unregisterSheet(oldCss, sss.USER_SHEET); - this._hackCssForBug466(oldCss, sss, "unregister"); - this._hackCssForBug717(oldCss, sss, "unregister"); - } catch (e) {} // do nothing - //Load the new skin CSS - var newCss = Utils.url(newSkinPath); - sss.loadAndRegisterSheet(newCss, sss.USER_SHEET); - Utils.prefs.setValue(SKIN_PREF, newSkinPath); - this._hackCssForBug466(newCss, sss, "register"); - this._hackCssForBug717(newCss, sss, "register"); - }, - - //Change the skin and notify - changeSkin: function SS_changeSkin(newSkinPath) { - try { - this.loadSkin(newSkinPath); - this._msgService.displayMessage(L("ubiquity.skinsvc.skinchanged")); - } catch (e) { - this.loadSkin(this.DEFAULT_SKIN); - //errorToLocalize - var msg = "Error applying Ubiquity skin from " + newSkinPath; - this._msgService.displayMessage(msg); - Cu.reportError(msg + " : " + e); - } - }, - - updateSkin: function SS_updateSkin(downloadUrl, localUrl) { - var self = this; - this._webJsm.jQuery.get(downloadUrl, null, function onSuccess(data) { - self._writeToLocalUrl(localUrl, data); - }, "text"); - }, - - updateAllSkins: function SS_updateAllSkins() { - //Only have to update/download remote skins - //Local skins are pointed at directly - for each (var skin in this.skinList) - if (skin.localUrl !== skin.downloadUrl) - this.updateSkin(skin.downloadUrl, skin.localUrl); - }, - - loadCurrentSkin: function SS_loadCurrentSkin() { - try { - this.loadSkin(this.currentSkin); - } catch (e) { - //If there's any error loading the current skin, - //load the default and tell the user about the failure - this.loadSkin(this.DEFAULT_SKIN); - //errorToLocalize - this._msgService.displayMessage( - "Loading your current skin failed. The default skin will be loaded."); - } - }, - - install: function SS_install(remote, local) { - this.addSkin(remote, local); - this.changeSkin(local); - Utils.tabs.reload(/^about:ubiquity\?settings\b/); - }, - - uninstall: function SS_uninstall(url) { - var {skinList} = this; - EACH_SKIN: { - for each (var {localUrl, downloadUrl} in skinList) - if (localUrl !== downloadUrl && - localUrl === url || downloadUrl === url) - break EACH_SKIN; - return; - } - this.deleteSkin(url); - var file = (Cc["@mozilla.org/network/protocol;1?name=file"] - .createInstance(Ci.nsIFileProtocolHandler) - .getFileFromURLSpec(localUrl)); - file.remove(false); - if (localUrl === this.currentSkin) - this.changeSkin(this.DEFAULT_SKIN); - }, - - saveCustomSkin: function SS_saveCustomSkin(cssText) { - this._writeToLocalUrl(this.CUSTOM_SKIN, cssText); - }, - - saveAs: function SS_saveAs(cssText, defaultName) { - const {nsIFilePicker} = Ci; - var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); - fp.init(Utils.currentChromeWindow, - L("ubiquity.skinsvc.saveyourskin"), - nsIFilePicker.modeSave); - fp.defaultString = defaultName || ""; - fp.appendFilter("CSS (*.css)", "*.css"); - var rv = fp.show(); - if (rv !== nsIFilePicker.returnOK && - rv !== nsIFilePicker.returnReplace) - return null; - this._writeToFile(fp.file, cssText); - var {spec} = fp.fileURL; - this.addSkin("data:,dev/null/" + this._randomKey(), spec); - this.changeSkin(spec); - SkinSvc.readMetaData({css: cssText, localUrl: spec, noCache: true}); - return fp.file.path; - }, - - get currentSkin SS_getCurrentSkin() - Utils.prefs.getValue(SKIN_PREF, this.DEFAULT_SKIN), - - get skinList SS_getSkinList() { - var list = []; - var selStmt = this._createStatement( - "SELECT local_uri, download_uri FROM ubiquity_skin_memory"); - while (selStmt.executeStep()) - list.push({ - localUrl: selStmt.getUTF8String(0), - downloadUrl: selStmt.getUTF8String(1), - __proto__: SkinSvc.SkinProto, - }); - selStmt.finalize(); - return list; - }, -}; - -SkinSvc.prototype.installToWindow = function installToWindow(window) { - var self = this; - function showNotification(targetDoc, skinUrl) { - Utils.notify({ - target: targetDoc, - label: L("ubiquity.skinsvc.newskinfound"), - value: "ubiquity_notify_skin_available", - priority: "INFO_MEDIUM", - buttons: [{ - accessKey: "I", - callback: onSubscribeClick, - label: L("ubiquity.skinsvc.installskin"), - }]}); - function onSubscribeClick(notification, button) { - if (self._isLocalUrl(skinUrl)) self.install(skinUrl, skinUrl); - else self._webJsm.jQuery.get(skinUrl, null, function onSuccess(data) { - //Navigate to chrome://ubiquity/skin/skins/ - var file = self._getSkinFolder(); - //Select a random name for the file - var filename = self._randomKey() + ".css"; - //Create the new file - file.append(filename); - file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0644); - //Write the downloaded CSS to the file - self._writeToFile(file, data); - var ios = (Cc["@mozilla.org/network/io-service;1"] - .getService(Ci.nsIIOService)); - var {spec} = ios.newFileURI(file); - //Add skin to DB and make it the current skin - self.install(skinUrl, spec); - SkinSvc.readMetaData({ - css: data, downloadUrl: skinUrl, localUrl: spec, noCache: true}); - }, "text"); - } - } - // Watch for any tags of the form - // on pages and install the skin for them if they exist. - window.addEventListener("DOMLinkAdded", function onLinkAdded({target}) { - if (target.rel === "ubiquity-skin" && !self.isInstalled(target.href)) - showNotification(target.ownerDocument, target.href); - }, false); -};