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);
-};