Merge 4cc455ec1d
into 7904cf9b6f
This commit is contained in:
commit
92590f0326
49
apply.js
49
apply.js
|
@ -1,3 +1,4 @@
|
||||||
|
/*jshint undef:false*/
|
||||||
var g_disableAll = false;
|
var g_disableAll = false;
|
||||||
var g_styleElements = {};
|
var g_styleElements = {};
|
||||||
var iframeObserver;
|
var iframeObserver;
|
||||||
|
@ -11,8 +12,13 @@ function requestStyles() {
|
||||||
// we'll request the styles directly to minimize delay and flicker,
|
// we'll request the styles directly to minimize delay and flicker,
|
||||||
// unless Chrome still starts up and the background page isn't fully loaded.
|
// unless Chrome still starts up and the background page isn't fully loaded.
|
||||||
// (Note: in this case the function may be invoked again from applyStyles.)
|
// (Note: in this case the function may be invoked again from applyStyles.)
|
||||||
var request = {method: "getStyles", matchUrl: location.href, enabled: true, asHash: true};
|
var request = {
|
||||||
if (location.href.indexOf(chrome.extension.getURL("")) == 0) {
|
method: "getStyles",
|
||||||
|
matchUrl: location.href,
|
||||||
|
enabled: true,
|
||||||
|
asHash: true
|
||||||
|
};
|
||||||
|
if (location.href.indexOf(chrome.extension.getURL("")) === 0) {
|
||||||
var bg = chrome.extension.getBackgroundPage();
|
var bg = chrome.extension.getBackgroundPage();
|
||||||
if (bg && bg.getStyles) {
|
if (bg && bg.getStyles) {
|
||||||
// apply styles immediately, then proceed with a normal request that will update the icon
|
// apply styles immediately, then proceed with a normal request that will update the icon
|
||||||
|
@ -24,6 +30,18 @@ function requestStyles() {
|
||||||
|
|
||||||
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
||||||
// Also handle special request just for the pop-up
|
// Also handle special request just for the pop-up
|
||||||
|
function styleAdded() {
|
||||||
|
if (request.style.enabled) {
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
method: "getStyles",
|
||||||
|
matchUrl: location.href,
|
||||||
|
enabled: true,
|
||||||
|
id: request.style.id,
|
||||||
|
asHash: true
|
||||||
|
}, applyStyles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (request.method == "updatePopup" ? request.reason : request.method) {
|
switch (request.method == "updatePopup" ? request.reason : request.method) {
|
||||||
case "styleDeleted":
|
case "styleDeleted":
|
||||||
removeStyle(request.id, document);
|
removeStyle(request.id, document);
|
||||||
|
@ -31,15 +49,13 @@ chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
|
||||||
case "styleUpdated":
|
case "styleUpdated":
|
||||||
if (request.style.enabled) {
|
if (request.style.enabled) {
|
||||||
retireStyle(request.style.id);
|
retireStyle(request.style.id);
|
||||||
// fallthrough to "styleAdded"
|
styleAdded();
|
||||||
} else {
|
} else {
|
||||||
removeStyle(request.style.id, document);
|
removeStyle(request.style.id, document);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case "styleAdded":
|
case "styleAdded":
|
||||||
if (request.style.enabled) {
|
styleAdded();
|
||||||
chrome.runtime.sendMessage({method: "getStyles", matchUrl: location.href, enabled: true, id: request.style.id, asHash: true}, applyStyles);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "styleApply":
|
case "styleApply":
|
||||||
applyStyles(request.styles);
|
applyStyles(request.styles);
|
||||||
|
@ -90,7 +106,7 @@ function removeStyle(id, doc) {
|
||||||
if (e) {
|
if (e) {
|
||||||
e.remove();
|
e.remove();
|
||||||
}
|
}
|
||||||
if (doc == document && Object.keys(g_styleElements).length == 0) {
|
if (doc == document && Object.keys(g_styleElements).length === 0) {
|
||||||
iframeObserver.disconnect();
|
iframeObserver.disconnect();
|
||||||
}
|
}
|
||||||
getDynamicIFrames(doc).forEach(function (iframe) {
|
getDynamicIFrames(doc).forEach(function (iframe) {
|
||||||
|
@ -224,7 +240,7 @@ function iframeIsDynamic(f) {
|
||||||
// Cross-origin, so it's not a dynamic iframe
|
// Cross-origin, so it's not a dynamic iframe
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return href == document.location.href || href.indexOf("about:") == 0;
|
return href == document.location.href || href.indexOf("about:") === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function iframeIsLoadingSrcDoc(f) {
|
function iframeIsLoadingSrcDoc(f) {
|
||||||
|
@ -244,7 +260,9 @@ function addStyleToIFrameSrcDoc(iframe, styleElement) {
|
||||||
function replaceAll(newStyles, doc, pass2) {
|
function replaceAll(newStyles, doc, pass2) {
|
||||||
var oldStyles = [].slice.call(doc.querySelectorAll("STYLE.stylish" + (pass2 ? "[id$='-ghost']" : "")));
|
var oldStyles = [].slice.call(doc.querySelectorAll("STYLE.stylish" + (pass2 ? "[id$='-ghost']" : "")));
|
||||||
if (!pass2) {
|
if (!pass2) {
|
||||||
oldStyles.forEach(function(style) { style.id += "-ghost"; });
|
oldStyles.forEach(function (style) {
|
||||||
|
style.id += "-ghost";
|
||||||
|
});
|
||||||
}
|
}
|
||||||
getDynamicIFrames(doc).forEach(function (iframe) {
|
getDynamicIFrames(doc).forEach(function (iframe) {
|
||||||
replaceAll(newStyles, iframe.contentDocument, pass2);
|
replaceAll(newStyles, iframe.contentDocument, pass2);
|
||||||
|
@ -255,7 +273,9 @@ function replaceAll(newStyles, doc, pass2) {
|
||||||
replaceAll(newStyles, doc, true);
|
replaceAll(newStyles, doc, true);
|
||||||
}
|
}
|
||||||
if (pass2) {
|
if (pass2) {
|
||||||
oldStyles.forEach(function(style) { style.remove(); });
|
oldStyles.forEach(function (style) {
|
||||||
|
style.remove();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,6 +310,9 @@ function initObserver() {
|
||||||
|
|
||||||
iframeObserver.start = function () {
|
iframeObserver.start = function () {
|
||||||
// will be ignored by browser if already observing
|
// will be ignored by browser if already observing
|
||||||
iframeObserver.observe(document, {childList: true, subtree: true});
|
iframeObserver.observe(document, {
|
||||||
}
|
childList: true,
|
||||||
|
subtree: true
|
||||||
|
});
|
||||||
|
};
|
||||||
}
|
}
|
100
background.js
100
background.js
|
@ -1,6 +1,9 @@
|
||||||
|
/*jshint undef:false*/
|
||||||
var frameIdMessageable;
|
var frameIdMessageable;
|
||||||
runTryCatch(function () {
|
runTryCatch(function () {
|
||||||
chrome.tabs.sendMessage(0, {}, {frameId: 0}, function() {
|
chrome.tabs.sendMessage(0, {}, {
|
||||||
|
frameId: 0
|
||||||
|
}, function () {
|
||||||
var clearError = chrome.runtime.lastError;
|
var clearError = chrome.runtime.lastError;
|
||||||
frameIdMessageable = true;
|
frameIdMessageable = true;
|
||||||
});
|
});
|
||||||
|
@ -14,21 +17,34 @@ if ("onHistoryStateUpdated" in chrome.webNavigation) {
|
||||||
chrome.webNavigation.onHistoryStateUpdated.addListener(webNavigationListener.bind(this, "styleReplaceAll"));
|
chrome.webNavigation.onHistoryStateUpdated.addListener(webNavigationListener.bind(this, "styleReplaceAll"));
|
||||||
}
|
}
|
||||||
chrome.webNavigation.onBeforeNavigate.addListener(webNavigationListener.bind(this, null));
|
chrome.webNavigation.onBeforeNavigate.addListener(webNavigationListener.bind(this, null));
|
||||||
|
|
||||||
function webNavigationListener(method, data) {
|
function webNavigationListener(method, data) {
|
||||||
// Until Chrome 41, we can't target a frame with a message
|
// Until Chrome 41, we can't target a frame with a message
|
||||||
// (https://developer.chrome.com/extensions/tabs#method-sendMessage)
|
// (https://developer.chrome.com/extensions/tabs#method-sendMessage)
|
||||||
// so a style affecting a page with an iframe will affect the main page as well.
|
// so a style affecting a page with an iframe will affect the main page as well.
|
||||||
// Skip doing this for frames in pre-41 to prevent page flicker.
|
// Skip doing this for frames in pre-41 to prevent page flicker.
|
||||||
if (data.frameId != 0 && !frameIdMessageable) {
|
if (data.frameId !== 0 && !frameIdMessageable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getStyles({matchUrl: data.url, enabled: true, asHash: true}, function(styleHash) {
|
getStyles({
|
||||||
|
matchUrl: data.url,
|
||||||
|
enabled: true,
|
||||||
|
asHash: true
|
||||||
|
}, function (styleHash) {
|
||||||
if (method) {
|
if (method) {
|
||||||
chrome.tabs.sendMessage(data.tabId, {method: method, styles: styleHash},
|
chrome.tabs.sendMessage(data.tabId, {
|
||||||
frameIdMessageable ? {frameId: data.frameId} : undefined);
|
method: method,
|
||||||
|
styles: styleHash
|
||||||
|
},
|
||||||
|
frameIdMessageable ? {
|
||||||
|
frameId: data.frameId
|
||||||
|
} : undefined);
|
||||||
}
|
}
|
||||||
if (data.frameId == 0) {
|
if (data.frameId === 0) {
|
||||||
updateIcon({id: data.tabId, url: data.url}, styleHash);
|
updateIcon({
|
||||||
|
id: data.tabId,
|
||||||
|
url: data.url
|
||||||
|
}, styleHash);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -45,7 +61,11 @@ chrome.tabs.onUpdated.addListener(function(tabId, info, tab) {
|
||||||
// do nothing since the tab neither had # before nor has # now
|
// do nothing since the tab neither had # before nor has # now
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
webNavigationListener("styleReplaceAll", {tabId: tabId, frameId: 0, url: info.url});
|
webNavigationListener("styleReplaceAll", {
|
||||||
|
tabId: tabId,
|
||||||
|
frameId: 0,
|
||||||
|
url: info.url
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
chrome.tabs.onRemoved.addListener(function (tabId, info) {
|
chrome.tabs.onRemoved.addListener(function (tabId, info) {
|
||||||
|
@ -57,9 +77,7 @@ chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
|
||||||
case "getStyles":
|
case "getStyles":
|
||||||
var styles = getStyles(request, sendResponse);
|
var styles = getStyles(request, sendResponse);
|
||||||
// check if this is a main content frame style enumeration
|
// check if this is a main content frame style enumeration
|
||||||
if (request.matchUrl && !request.id
|
if (request.matchUrl && !request.id && sender && sender.tab && sender.frameId === 0 && sender.tab.url == request.matchUrl) {
|
||||||
&& sender && sender.tab && sender.frameId == 0
|
|
||||||
&& sender.tab.url == request.matchUrl) {
|
|
||||||
updateIcon(sender.tab, styles);
|
updateIcon(sender.tab, styles);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -72,17 +90,25 @@ chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "healthCheck":
|
case "healthCheck":
|
||||||
getDatabase(function() { sendResponse(true); }, function() { sendResponse(false); });
|
getDatabase(function () {
|
||||||
|
sendResponse(true);
|
||||||
|
}, function () {
|
||||||
|
sendResponse(false);
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
case "openURL":
|
case "openURL":
|
||||||
openURL(request);
|
openURL(request);
|
||||||
break;
|
break;
|
||||||
case "styleDisableAll":
|
case "styleDisableAll":
|
||||||
chrome.contextMenus.update("disableAll", {checked: request.disableAll});
|
chrome.contextMenus.update("disableAll", {
|
||||||
|
checked: request.disableAll
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case "prefChanged":
|
case "prefChanged":
|
||||||
if (request.prefName == "show-badge") {
|
if (request.prefName == "show-badge") {
|
||||||
chrome.contextMenus.update("show-badge", {checked: request.value});
|
chrome.contextMenus.update("show-badge", {
|
||||||
|
checked: request.value
|
||||||
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -94,11 +120,15 @@ if ("commands" in chrome) {
|
||||||
chrome.commands.onCommand.addListener(function (command) {
|
chrome.commands.onCommand.addListener(function (command) {
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case "openManage":
|
case "openManage":
|
||||||
openURL({url: chrome.extension.getURL("manage.html")});
|
openURL({
|
||||||
|
url: chrome.extension.getURL("manage.html")
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case "styleDisableAll":
|
case "styleDisableAll":
|
||||||
disableAllStylesToggle();
|
disableAllStylesToggle();
|
||||||
chrome.contextMenus.update("disableAll", {checked: prefs.get("disableAll")});
|
chrome.contextMenus.update("disableAll", {
|
||||||
|
checked: prefs.get("disableAll")
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -108,13 +138,23 @@ if ("commands" in chrome) {
|
||||||
// upon encountering the unsupported parameter value "browser_action", so we have to catch it.
|
// upon encountering the unsupported parameter value "browser_action", so we have to catch it.
|
||||||
runTryCatch(function () {
|
runTryCatch(function () {
|
||||||
chrome.contextMenus.create({
|
chrome.contextMenus.create({
|
||||||
id: "show-badge", title: chrome.i18n.getMessage("menuShowBadge"),
|
id: "show-badge",
|
||||||
type: "checkbox", contexts: ["browser_action"], checked: prefs.get("show-badge")
|
title: chrome.i18n.getMessage("menuShowBadge"),
|
||||||
}, function() { var clearError = chrome.runtime.lastError });
|
type: "checkbox",
|
||||||
|
contexts: ["browser_action"],
|
||||||
|
checked: prefs.get("show-badge")
|
||||||
|
}, function () {
|
||||||
|
var clearError = chrome.runtime.lastError;
|
||||||
|
});
|
||||||
chrome.contextMenus.create({
|
chrome.contextMenus.create({
|
||||||
id: "disableAll", title: chrome.i18n.getMessage("disableAllStyles"),
|
id: "disableAll",
|
||||||
type: "checkbox", contexts: ["browser_action"], checked: prefs.get("disableAll")
|
title: chrome.i18n.getMessage("disableAllStyles"),
|
||||||
}, function() { var clearError = chrome.runtime.lastError });
|
type: "checkbox",
|
||||||
|
contexts: ["browser_action"],
|
||||||
|
checked: prefs.get("disableAll")
|
||||||
|
}, function () {
|
||||||
|
var clearError = chrome.runtime.lastError;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
chrome.contextMenus.onClicked.addListener(function (info, tab) {
|
chrome.contextMenus.onClicked.addListener(function (info, tab) {
|
||||||
|
@ -139,8 +179,10 @@ getDatabase(function() {}, reportError);
|
||||||
var editFullUrl = chrome.extension.getURL("edit.html");
|
var editFullUrl = chrome.extension.getURL("edit.html");
|
||||||
chrome.tabs.onAttached.addListener(function (tabId, data) {
|
chrome.tabs.onAttached.addListener(function (tabId, data) {
|
||||||
chrome.tabs.get(tabId, function (tabData) {
|
chrome.tabs.get(tabId, function (tabData) {
|
||||||
if (tabData.url.indexOf(editFullUrl) == 0) {
|
if (tabData.url.indexOf(editFullUrl) === 0) {
|
||||||
chrome.windows.get(tabData.windowId, {populate: true}, function(win) {
|
chrome.windows.get(tabData.windowId, {
|
||||||
|
populate: true
|
||||||
|
}, function (win) {
|
||||||
// If there's only one tab in this window, it's been dragged to new window
|
// If there's only one tab in this window, it's been dragged to new window
|
||||||
prefs.set("openEditInWindow", win.tabs.length == 1);
|
prefs.set("openEditInWindow", win.tabs.length == 1);
|
||||||
});
|
});
|
||||||
|
@ -149,10 +191,16 @@ chrome.tabs.onAttached.addListener(function(tabId, data) {
|
||||||
});
|
});
|
||||||
|
|
||||||
function openURL(options) {
|
function openURL(options) {
|
||||||
chrome.tabs.query({currentWindow: true, url: options.url}, function(tabs) {
|
chrome.tabs.query({
|
||||||
|
currentWindow: true,
|
||||||
|
url: options.url
|
||||||
|
}, function (tabs) {
|
||||||
// switch to an existing tab with the requested url
|
// switch to an existing tab with the requested url
|
||||||
if (tabs.length) {
|
if (tabs.length) {
|
||||||
chrome.tabs.highlight({windowId: tabs[0].windowId, tabs: tabs[0].index}, function (window) {});
|
chrome.tabs.highlight({
|
||||||
|
windowId: tabs[0].windowId,
|
||||||
|
tabs: tabs[0].index
|
||||||
|
}, function (window) {});
|
||||||
} else {
|
} else {
|
||||||
delete options.method;
|
delete options.method;
|
||||||
getActiveTab(function (tab) {
|
getActiveTab(function (tab) {
|
||||||
|
|
310
edit.js
310
edit.js
|
@ -1,5 +1,5 @@
|
||||||
"use strict";
|
/*jshint undef:false*/
|
||||||
|
(function () {
|
||||||
var styleId = null;
|
var styleId = null;
|
||||||
var dirty = {}; // only the actually dirty items here
|
var dirty = {}; // only the actually dirty items here
|
||||||
var editors = []; // array of all CodeMirror instances
|
var editors = []; // array of all CodeMirror instances
|
||||||
|
@ -7,8 +7,18 @@ var saveSizeOnClose;
|
||||||
var useHistoryBack; // use browser history back when "back to manage" is clicked
|
var useHistoryBack; // use browser history back when "back to manage" is clicked
|
||||||
|
|
||||||
// direct & reverse mapping of @-moz-document keywords and internal property names
|
// direct & reverse mapping of @-moz-document keywords and internal property names
|
||||||
var propertyToCss = {urls: "url", urlPrefixes: "url-prefix", domains: "domain", regexps: "regexp"};
|
var propertyToCss = {
|
||||||
var CssToProperty = {"url": "urls", "url-prefix": "urlPrefixes", "domain": "domains", "regexp": "regexps"};
|
urls: "url",
|
||||||
|
urlPrefixes: "url-prefix",
|
||||||
|
domains: "domain",
|
||||||
|
regexps: "regexp"
|
||||||
|
};
|
||||||
|
var CssToProperty = {
|
||||||
|
"url": "urls",
|
||||||
|
"url-prefix": "urlPrefixes",
|
||||||
|
"domain": "domains",
|
||||||
|
"regexp": "regexps"
|
||||||
|
};
|
||||||
|
|
||||||
// make querySelectorAll enumeration code readable
|
// make querySelectorAll enumeration code readable
|
||||||
["forEach", "some", "indexOf", "map"].forEach(function (method) {
|
["forEach", "some", "indexOf", "map"].forEach(function (method) {
|
||||||
|
@ -28,15 +38,26 @@ Array.prototype.rotate = function(amount) { // negative amount == rotate left
|
||||||
var r = this.slice(-amount, this.length);
|
var r = this.slice(-amount, this.length);
|
||||||
Array.prototype.push.apply(r, this.slice(0, this.length - r.length));
|
Array.prototype.push.apply(r, this.slice(0, this.length - r.length));
|
||||||
return r;
|
return r;
|
||||||
}
|
};
|
||||||
|
|
||||||
Object.defineProperty(Array.prototype, "last", {get: function() { return this[this.length - 1]; }});
|
Object.defineProperty(Array.prototype, "last", {
|
||||||
|
get: function () {
|
||||||
|
return this[this.length - 1];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// reroute handling to nearest editor when keypress resolves to one of these commands
|
// reroute handling to nearest editor when keypress resolves to one of these commands
|
||||||
var hotkeyRerouter = {
|
var hotkeyRerouter = {
|
||||||
commands: {
|
commands: {
|
||||||
save: true, jumpToLine: true, nextEditor: true, prevEditor: true,
|
save: true,
|
||||||
find: true, findNext: true, findPrev: true, replace: true, replaceAll: true
|
jumpToLine: true,
|
||||||
|
nextEditor: true,
|
||||||
|
prevEditor: true,
|
||||||
|
find: true,
|
||||||
|
findNext: true,
|
||||||
|
findPrev: true,
|
||||||
|
replace: true,
|
||||||
|
replaceAll: true
|
||||||
},
|
},
|
||||||
setState: function (enable) {
|
setState: function (enable) {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
|
@ -45,11 +66,11 @@ var hotkeyRerouter = {
|
||||||
},
|
},
|
||||||
eventHandler: function (event) {
|
eventHandler: function (event) {
|
||||||
var keyName = CodeMirror.keyName(event);
|
var keyName = CodeMirror.keyName(event);
|
||||||
if ("handled" == CodeMirror.lookupKey(keyName, CodeMirror.getOption("keyMap"), handleCommand)
|
if ("handled" == CodeMirror.lookupKey(keyName, CodeMirror.getOption("keyMap"), handleCommand) || "handled" == CodeMirror.lookupKey(keyName, CodeMirror.defaults.extraKeys, handleCommand)) {
|
||||||
|| "handled" == CodeMirror.lookupKey(keyName, CodeMirror.defaults.extraKeys, handleCommand)) {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCommand(command) {
|
function handleCommand(command) {
|
||||||
if (hotkeyRerouter.commands[command] === true) {
|
if (hotkeyRerouter.commands[command] === true) {
|
||||||
CodeMirror.commands[command](getEditorInSight(event.target));
|
CodeMirror.commands[command](getEditorInSight(event.target));
|
||||||
|
@ -98,7 +119,7 @@ function setCleanItem(node, isClean) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isCleanGlobal() {
|
function isCleanGlobal() {
|
||||||
var clean = Object.keys(dirty).length == 0;
|
var clean = Object.keys(dirty).length === 0;
|
||||||
setDirtyClass(document.body, !clean);
|
setDirtyClass(document.body, !clean);
|
||||||
document.getElementById("save-button").disabled = clean;
|
document.getElementById("save-button").disabled = clean;
|
||||||
return clean;
|
return clean;
|
||||||
|
@ -110,7 +131,9 @@ function setCleanGlobal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCleanSection(section) {
|
function setCleanSection(section) {
|
||||||
section.querySelectorAll(".style-contributor").forEach(function(node) { setCleanItem(node, true) });
|
section.querySelectorAll(".style-contributor").forEach(function (node) {
|
||||||
|
setCleanItem(node, true);
|
||||||
|
});
|
||||||
|
|
||||||
// #header section has no codemirror
|
// #header section has no codemirror
|
||||||
var cm = section.CodeMirror;
|
var cm = section.CodeMirror;
|
||||||
|
@ -132,7 +155,10 @@ function initCodeMirror() {
|
||||||
foldGutter: true,
|
foldGutter: true,
|
||||||
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"],
|
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"],
|
||||||
matchBrackets: true,
|
matchBrackets: true,
|
||||||
lint: {getAnnotations: CodeMirror.lint.css, delay: prefs.get("editor.lintDelay")},
|
lint: {
|
||||||
|
getAnnotations: CodeMirror.lint.css,
|
||||||
|
delay: prefs.get("editor.lintDelay")
|
||||||
|
},
|
||||||
lintReportDelay: prefs.get("editor.lintReportDelay"),
|
lintReportDelay: prefs.get("editor.lintReportDelay"),
|
||||||
styleActiveLine: true,
|
styleActiveLine: true,
|
||||||
theme: "default",
|
theme: "default",
|
||||||
|
@ -145,11 +171,17 @@ function initCodeMirror() {
|
||||||
|
|
||||||
// additional commands
|
// additional commands
|
||||||
CM.commands.jumpToLine = jumpToLine;
|
CM.commands.jumpToLine = jumpToLine;
|
||||||
CM.commands.nextEditor = function(cm) { nextPrevEditor(cm, 1) };
|
CM.commands.nextEditor = function (cm) {
|
||||||
CM.commands.prevEditor = function(cm) { nextPrevEditor(cm, -1) };
|
nextPrevEditor(cm, 1);
|
||||||
|
};
|
||||||
|
CM.commands.prevEditor = function (cm) {
|
||||||
|
nextPrevEditor(cm, -1);
|
||||||
|
};
|
||||||
CM.commands.save = save;
|
CM.commands.save = save;
|
||||||
CM.commands.blockComment = function (cm) {
|
CM.commands.blockComment = function (cm) {
|
||||||
cm.blockComment(cm.getCursor("from"), cm.getCursor("to"), {fullLines: false});
|
cm.blockComment(cm.getCursor("from"), cm.getCursor("to"), {
|
||||||
|
fullLines: false
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// "basic" keymap only has basic keys by design, so we skip it
|
// "basic" keymap only has basic keys by design, so we skip it
|
||||||
|
@ -177,7 +209,7 @@ function initCodeMirror() {
|
||||||
if (isWindowsOS) {
|
if (isWindowsOS) {
|
||||||
// "pcDefault" keymap on Windows should have F3/Shift-F3
|
// "pcDefault" keymap on Windows should have F3/Shift-F3
|
||||||
if (!extraKeysCommands.findNext) {
|
if (!extraKeysCommands.findNext) {
|
||||||
CM.keyMap.pcDefault["F3"] = "findNext";
|
CM.keyMap.pcDefault.F3 = "findNext";
|
||||||
}
|
}
|
||||||
if (!extraKeysCommands.findPrev) {
|
if (!extraKeysCommands.findPrev) {
|
||||||
CM.keyMap.pcDefault["Shift-F3"] = "findPrev";
|
CM.keyMap.pcDefault["Shift-F3"] = "findPrev";
|
||||||
|
@ -185,8 +217,14 @@ function initCodeMirror() {
|
||||||
|
|
||||||
// try to remap non-interceptable Ctrl-(Shift-)N/T/W hotkeys
|
// try to remap non-interceptable Ctrl-(Shift-)N/T/W hotkeys
|
||||||
["N", "T", "W"].forEach(function (char) {
|
["N", "T", "W"].forEach(function (char) {
|
||||||
[{from: "Ctrl-", to: ["Alt-", "Ctrl-Alt-"]},
|
[{
|
||||||
{from: "Shift-Ctrl-", to: ["Ctrl-Alt-", "Shift-Ctrl-Alt-"]} // Note: modifier order in CM is S-C-A
|
from: "Ctrl-",
|
||||||
|
to: ["Alt-", "Ctrl-Alt-"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "Shift-Ctrl-",
|
||||||
|
to: ["Ctrl-Alt-", "Shift-Ctrl-Alt-"]
|
||||||
|
} // Note: modifier order in CM is S-C-A
|
||||||
].forEach(function (remap) {
|
].forEach(function (remap) {
|
||||||
var oldKey = remap.from + char;
|
var oldKey = remap.from + char;
|
||||||
Object.keys(CM.keyMap).forEach(function (keyMapName) {
|
Object.keys(CM.keyMap).forEach(function (keyMapName) {
|
||||||
|
@ -211,17 +249,17 @@ function initCodeMirror() {
|
||||||
// user option values
|
// user option values
|
||||||
CM.getOption = function (o) {
|
CM.getOption = function (o) {
|
||||||
return CodeMirror.defaults[o];
|
return CodeMirror.defaults[o];
|
||||||
}
|
};
|
||||||
CM.setOption = function (o, v) {
|
CM.setOption = function (o, v) {
|
||||||
CodeMirror.defaults[o] = v;
|
CodeMirror.defaults[o] = v;
|
||||||
editors.forEach(function (editor) {
|
editors.forEach(function (editor) {
|
||||||
editor.setOption(o, v);
|
editor.setOption(o, v);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
CM.prototype.getSection = function () {
|
CM.prototype.getSection = function () {
|
||||||
return this.display.wrapper.parentNode;
|
return this.display.wrapper.parentNode;
|
||||||
}
|
};
|
||||||
|
|
||||||
// preload the theme so that CodeMirror can calculate its metrics in DOMContentLoaded->setupLivePrefs()
|
// preload the theme so that CodeMirror can calculate its metrics in DOMContentLoaded->setupLivePrefs()
|
||||||
var theme = prefs.get("editor.theme");
|
var theme = prefs.get("editor.theme");
|
||||||
|
@ -230,7 +268,9 @@ function initCodeMirror() {
|
||||||
// initialize global editor controls
|
// initialize global editor controls
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
function optionsHtmlFromArray(options) {
|
function optionsHtmlFromArray(options) {
|
||||||
return options.map(function(opt) { return "<option>" + opt + "</option>"; }).join("");
|
return options.map(function (opt) {
|
||||||
|
return "<option>" + opt + "</option>";
|
||||||
|
}).join("");
|
||||||
}
|
}
|
||||||
var themeControl = document.getElementById("editor.theme");
|
var themeControl = document.getElementById("editor.theme");
|
||||||
var bg = chrome.extension.getBackgroundPage();
|
var bg = chrome.extension.getBackgroundPage();
|
||||||
|
@ -248,7 +288,9 @@ function initCodeMirror() {
|
||||||
document.getElementById("options").addEventListener("change", acmeEventListener, false);
|
document.getElementById("options").addEventListener("change", acmeEventListener, false);
|
||||||
setupLivePrefs(
|
setupLivePrefs(
|
||||||
document.querySelectorAll("#options *[data-option][id^='editor.']")
|
document.querySelectorAll("#options *[data-option][id^='editor.']")
|
||||||
.map(function(option) { return option.id })
|
.map(function (option) {
|
||||||
|
return option.id;
|
||||||
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -324,9 +366,8 @@ function setupCodeMirror(textarea, index) {
|
||||||
resizeGrip.addEventListener("mousedown", function (e) {
|
resizeGrip.addEventListener("mousedown", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var cm = e.target.parentNode.CodeMirror;
|
var cm = e.target.parentNode.CodeMirror;
|
||||||
var minHeight = cm.defaultTextHeight()
|
var minHeight = cm.defaultTextHeight() + cm.display.lineDiv.offsetParent.offsetTop /* .CodeMirror-lines padding */ + cm.display.wrapper.offsetHeight - cm.display.wrapper.scrollHeight /* borders */ ;
|
||||||
+ cm.display.lineDiv.offsetParent.offsetTop /* .CodeMirror-lines padding */
|
|
||||||
+ cm.display.wrapper.offsetHeight - cm.display.wrapper.scrollHeight /* borders */;
|
|
||||||
function resize(e) {
|
function resize(e) {
|
||||||
cm.setSize(null, Math.max(minHeight, cm.display.wrapper.scrollHeight + e.movementY));
|
cm.setSize(null, Math.max(minHeight, cm.display.wrapper.scrollHeight + e.movementY));
|
||||||
}
|
}
|
||||||
|
@ -337,13 +378,13 @@ function setupCodeMirror(textarea, index) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// resizeGrip has enough space when scrollbars.horiz is visible
|
// resizeGrip has enough space when scrollbars.horiz is visible
|
||||||
if (cm.display.scrollbars.horiz.style.display != "") {
|
if (cm.display.scrollbars.horiz.style.display !== "") {
|
||||||
cm.display.scrollbars.vert.style.marginBottom = "0";
|
cm.display.scrollbars.vert.style.marginBottom = "0";
|
||||||
}
|
}
|
||||||
// resizeGrip space adjustment in case a long line was entered/deleted by a user
|
// resizeGrip space adjustment in case a long line was entered/deleted by a user
|
||||||
new MutationObserver(function (mutations) {
|
new MutationObserver(function (mutations) {
|
||||||
var hScrollbar = mutations[0].target;
|
var hScrollbar = mutations[0].target;
|
||||||
var hScrollbarVisible = hScrollbar.style.display != "";
|
var hScrollbarVisible = hScrollbar.style.display !== "";
|
||||||
var vScrollbar = hScrollbar.parentNode.CodeMirror.display.scrollbars.vert;
|
var vScrollbar = hScrollbar.parentNode.CodeMirror.display.scrollbars.vert;
|
||||||
vScrollbar.style.marginBottom = hScrollbarVisible ? "0" : "";
|
vScrollbar.style.marginBottom = hScrollbarVisible ? "0" : "";
|
||||||
}).observe(cm.display.scrollbars.horiz, {
|
}).observe(cm.display.scrollbars.horiz, {
|
||||||
|
@ -386,7 +427,9 @@ document.addEventListener("wheel", function(event) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
chrome.tabs.query({currentWindow: true}, function(tabs) {
|
chrome.tabs.query({
|
||||||
|
currentWindow: true
|
||||||
|
}, function (tabs) {
|
||||||
var windowId = tabs[0].windowId;
|
var windowId = tabs[0].windowId;
|
||||||
if (prefs.get("openEditInWindow")) {
|
if (prefs.get("openEditInWindow")) {
|
||||||
if (tabs.length == 1 && window.history.length == 1) {
|
if (tabs.length == 1 && window.history.length == 1) {
|
||||||
|
@ -435,10 +478,10 @@ window.onbeforeunload = function() {
|
||||||
}
|
}
|
||||||
updateLintReport(null, 0);
|
updateLintReport(null, 0);
|
||||||
return confirm(t('styleChangesNotSaved'));
|
return confirm(t('styleChangesNotSaved'));
|
||||||
}
|
};
|
||||||
|
|
||||||
function addAppliesTo(list, name, value) {
|
function addAppliesTo(list, name, value) {
|
||||||
var showingEverything = list.querySelector(".applies-to-everything") != null;
|
var showingEverything = list.querySelector(".applies-to-everything") !== null;
|
||||||
// blow away "Everything" if it's there
|
// blow away "Everything" if it's there
|
||||||
if (showingEverything) {
|
if (showingEverything) {
|
||||||
list.removeChild(list.firstChild);
|
list.removeChild(list.firstChild);
|
||||||
|
@ -458,7 +501,9 @@ function addAppliesTo(list, name, value) {
|
||||||
} else {
|
} else {
|
||||||
e = template.appliesToEverything.cloneNode(true);
|
e = template.appliesToEverything.cloneNode(true);
|
||||||
}
|
}
|
||||||
e.querySelector(".add-applies-to").addEventListener("click", function() {addAppliesTo(this.parentNode.parentNode)}, false);
|
e.querySelector(".add-applies-to").addEventListener("click", function () {
|
||||||
|
addAppliesTo(this.parentNode.parentNode);
|
||||||
|
}, false);
|
||||||
list.appendChild(e);
|
list.appendChild(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,18 +536,19 @@ function addSection(event, section) {
|
||||||
appliesTo.addEventListener("change", onChange);
|
appliesTo.addEventListener("change", onChange);
|
||||||
appliesTo.addEventListener("input", onChange);
|
appliesTo.addEventListener("input", onChange);
|
||||||
|
|
||||||
var sections = document.getElementById("sections");
|
var sections = document.getElementById("sections"),
|
||||||
|
cm;
|
||||||
if (event) {
|
if (event) {
|
||||||
var clickedSection = getSectionForChild(event.target);
|
var clickedSection = getSectionForChild(event.target);
|
||||||
sections.insertBefore(div, clickedSection.nextElementSibling);
|
sections.insertBefore(div, clickedSection.nextElementSibling);
|
||||||
var newIndex = getSections().indexOf(clickedSection) + 1;
|
var newIndex = getSections().indexOf(clickedSection) + 1;
|
||||||
var cm = setupCodeMirror(codeElement, newIndex);
|
cm = setupCodeMirror(codeElement, newIndex);
|
||||||
makeSectionVisible(cm);
|
makeSectionVisible(cm);
|
||||||
cm.focus()
|
cm.focus();
|
||||||
renderLintReport();
|
renderLintReport();
|
||||||
} else {
|
} else {
|
||||||
sections.appendChild(div);
|
sections.appendChild(div);
|
||||||
var cm = setupCodeMirror(codeElement);
|
cm = setupCodeMirror(codeElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
div.CodeMirror = cm;
|
div.CodeMirror = cm;
|
||||||
|
@ -561,7 +607,7 @@ function setupGlobalSearch() {
|
||||||
findNext: CodeMirror.commands.findNext,
|
findNext: CodeMirror.commands.findNext,
|
||||||
findPrev: CodeMirror.commands.findPrev,
|
findPrev: CodeMirror.commands.findPrev,
|
||||||
replace: CodeMirror.commands.replace
|
replace: CodeMirror.commands.replace
|
||||||
}
|
};
|
||||||
var originalOpenDialog = CodeMirror.prototype.openDialog;
|
var originalOpenDialog = CodeMirror.prototype.openDialog;
|
||||||
var originalOpenConfirm = CodeMirror.prototype.openConfirm;
|
var originalOpenConfirm = CodeMirror.prototype.openConfirm;
|
||||||
|
|
||||||
|
@ -585,7 +631,7 @@ function setupGlobalSearch() {
|
||||||
query: newState.query,
|
query: newState.query,
|
||||||
overlay: newState.overlay,
|
overlay: newState.overlay,
|
||||||
annotate: cm.showMatchesOnScrollbar(newState.query, shouldIgnoreCase(newState.query))
|
annotate: cm.showMatchesOnScrollbar(newState.query, shouldIgnoreCase(newState.query))
|
||||||
}
|
};
|
||||||
cm.addOverlay(newState.overlay);
|
cm.addOverlay(newState.overlay);
|
||||||
return cm.state.search;
|
return cm.state.search;
|
||||||
}
|
}
|
||||||
|
@ -596,7 +642,9 @@ function setupGlobalSearch() {
|
||||||
// invoke 'callback' and bind 'this' to the original callback
|
// invoke 'callback' and bind 'this' to the original callback
|
||||||
originalOpenDialog.call(cm, template.innerHTML, callback.bind(cb), opt);
|
originalOpenDialog.call(cm, template.innerHTML, callback.bind(cb), opt);
|
||||||
};
|
};
|
||||||
setTimeout(function() { cm.openDialog = originalOpenDialog; }, 0);
|
setTimeout(function () {
|
||||||
|
cm.openDialog = originalOpenDialog;
|
||||||
|
}, 0);
|
||||||
refocusMinidialog(cm);
|
refocusMinidialog(cm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,7 +672,7 @@ function setupGlobalSearch() {
|
||||||
updateState(cm, curState);
|
updateState(cm, curState);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (CodeMirror.cmpPos(curState.posFrom, curState.posTo) == 0) {
|
if (CodeMirror.cmpPos(curState.posFrom, curState.posTo) === 0) {
|
||||||
findNext(activeCM);
|
findNext(activeCM);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -640,11 +688,9 @@ function setupGlobalSearch() {
|
||||||
var pos = activeCM.getCursor(reverse ? "from" : "to");
|
var pos = activeCM.getCursor(reverse ? "from" : "to");
|
||||||
activeCM.setSelection(activeCM.getCursor()); // clear the selection, don't move the cursor
|
activeCM.setSelection(activeCM.getCursor()); // clear the selection, don't move the cursor
|
||||||
|
|
||||||
var rxQuery = typeof state.query == "object"
|
var rxQuery = typeof state.query == "object" ? state.query : stringAsRegExp(state.query, shouldIgnoreCase(state.query) ? "i" : "");
|
||||||
? state.query : stringAsRegExp(state.query, shouldIgnoreCase(state.query) ? "i" : "");
|
|
||||||
|
|
||||||
if (document.activeElement && document.activeElement.name == "applies-value"
|
if (document.activeElement && document.activeElement.name == "applies-value" && searchAppliesTo(activeCM)) {
|
||||||
&& searchAppliesTo(activeCM)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (var i = 0, cm = activeCM; i < editors.length; i++) {
|
for (var i = 0, cm = activeCM; i < editors.length; i++) {
|
||||||
|
@ -689,7 +735,7 @@ function setupGlobalSearch() {
|
||||||
// works only outside of current event handlers chain, hence timeout=0
|
// works only outside of current event handlers chain, hence timeout=0
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
input.setSelectionRange(end, end);
|
input.setSelectionRange(end, end);
|
||||||
input.setSelectionRange(match.index, end)
|
input.setSelectionRange(match.index, end);
|
||||||
}, 0);
|
}, 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -742,6 +788,7 @@ function setupGlobalSearch() {
|
||||||
};
|
};
|
||||||
originalCommand.replace(cm, all);
|
originalCommand.replace(cm, all);
|
||||||
}
|
}
|
||||||
|
|
||||||
function doConfirm(cm) {
|
function doConfirm(cm) {
|
||||||
var wrapAround = false;
|
var wrapAround = false;
|
||||||
var origPos = cm.getCursor();
|
var origPos = cm.getCursor();
|
||||||
|
@ -750,7 +797,9 @@ function setupGlobalSearch() {
|
||||||
return function () {
|
return function () {
|
||||||
makeSectionVisible(cm);
|
makeSectionVisible(cm);
|
||||||
cm.openConfirm = overrideConfirm;
|
cm.openConfirm = overrideConfirm;
|
||||||
setTimeout(function() { cm.openConfirm = originalOpenConfirm; }, 0);
|
setTimeout(function () {
|
||||||
|
cm.openConfirm = originalOpenConfirm;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
var pos = cm.getCursor();
|
var pos = cm.getCursor();
|
||||||
callback();
|
callback();
|
||||||
|
@ -758,13 +807,13 @@ function setupGlobalSearch() {
|
||||||
wrapAround |= cmp <= 0;
|
wrapAround |= cmp <= 0;
|
||||||
|
|
||||||
var dlg = cm.getWrapperElement().querySelector(".CodeMirror-dialog");
|
var dlg = cm.getWrapperElement().querySelector(".CodeMirror-dialog");
|
||||||
if (!dlg || cmp == 0 || wrapAround && CodeMirror.cmpPos(cm.getCursor(), origPos) >= 0) {
|
if (!dlg || cmp === 0 || wrapAround && CodeMirror.cmpPos(cm.getCursor(), origPos) >= 0) {
|
||||||
if (dlg) {
|
if (dlg) {
|
||||||
dlg.remove();
|
dlg.remove();
|
||||||
}
|
}
|
||||||
doReplace();
|
doReplace();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
originalOpenConfirm.call(cm, template.replaceConfirm.innerHTML, ovrCallbacks, opt);
|
originalOpenConfirm.call(cm, template.replaceConfirm.innerHTML, ovrCallbacks, opt);
|
||||||
};
|
};
|
||||||
|
@ -790,7 +839,9 @@ function jumpToLine(cm) {
|
||||||
if (m) {
|
if (m) {
|
||||||
cm.setCursor(m[1] - 1, m[2] ? m[2] - 1 : cur.ch);
|
cm.setCursor(m[1] - 1, m[2] ? m[2] - 1 : cur.ch);
|
||||||
}
|
}
|
||||||
}, {value: cur.line+1});
|
}, {
|
||||||
|
value: cur.line + 1
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function refocusMinidialog(cm) {
|
function refocusMinidialog(cm) {
|
||||||
|
@ -822,11 +873,19 @@ function getEditorInSight(nearbyElement) {
|
||||||
}
|
}
|
||||||
if (!cm || offscreenDistance(cm) > 0) {
|
if (!cm || offscreenDistance(cm) > 0) {
|
||||||
var sorted = editors
|
var sorted = editors
|
||||||
.map(function(cm, index) { return {cm: cm, distance: offscreenDistance(cm), index: index} })
|
.map(function (cm, index) {
|
||||||
.sort(function(a, b) { return a.distance - b.distance || a.index - b.index });
|
return {
|
||||||
|
cm: cm,
|
||||||
|
distance: offscreenDistance(cm),
|
||||||
|
index: index
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort(function (a, b) {
|
||||||
|
return a.distance - b.distance || a.index - b.index;
|
||||||
|
});
|
||||||
cm = sorted[0].cm;
|
cm = sorted[0].cm;
|
||||||
if (sorted[0].distance > 0) {
|
if (sorted[0].distance > 0) {
|
||||||
makeSectionVisible(cm)
|
makeSectionVisible(cm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cm;
|
return cm;
|
||||||
|
@ -845,7 +904,7 @@ function getEditorInSight(nearbyElement) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateLintReport(cm, delay) {
|
function updateLintReport(cm, delay) {
|
||||||
if (delay == 0) {
|
if (delay === 0) {
|
||||||
// immediately show pending csslint messages in onbeforeunload and save
|
// immediately show pending csslint messages in onbeforeunload and save
|
||||||
update.call(cm);
|
update.call(cm);
|
||||||
return;
|
return;
|
||||||
|
@ -866,7 +925,7 @@ function updateLintReport(cm, delay) {
|
||||||
var state = cm.state.lint;
|
var state = cm.state.lint;
|
||||||
clearTimeout(state.reportTimeout);
|
clearTimeout(state.reportTimeout);
|
||||||
state.reportTimeout = setTimeout(update.bind(cm), state.options.delay + 100);
|
state.reportTimeout = setTimeout(update.bind(cm), state.options.delay + 100);
|
||||||
state.postponeNewIssues = delay == undefined || delay == null;
|
state.postponeNewIssues = delay === undefined || delay === null;
|
||||||
|
|
||||||
function update() { // this == cm
|
function update() { // this == cm
|
||||||
var scope = this ? [this] : editors;
|
var scope = this ? [this] : editors;
|
||||||
|
@ -876,7 +935,7 @@ function updateLintReport(cm, delay) {
|
||||||
var state = cm.state.lint;
|
var state = cm.state.lint;
|
||||||
var oldMarkers = state.markedLast || {};
|
var oldMarkers = state.markedLast || {};
|
||||||
var newMarkers = {};
|
var newMarkers = {};
|
||||||
var html = state.marked.length == 0 ? "" : "<tbody>" +
|
var html = state.marked.length === 0 ? "" : "<tbody>" +
|
||||||
state.marked.map(function (mark) {
|
state.marked.map(function (mark) {
|
||||||
var info = mark.__annotation;
|
var info = mark.__annotation;
|
||||||
var isActiveLine = info.from.line == cm.getCursor().line;
|
var isActiveLine = info.from.line == cm.getCursor().line;
|
||||||
|
@ -915,9 +974,19 @@ function updateLintReport(cm, delay) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeHtml(html) {
|
function escapeHtml(html) {
|
||||||
var chars = {"&": "&", "<": "<", ">": ">", '"': '"', "'": ''', "/": '/'};
|
var chars = {
|
||||||
return html.replace(/[&<>"'\/]/g, function(char) { return chars[char] });
|
"&": "&",
|
||||||
|
"<": "<",
|
||||||
|
">": ">",
|
||||||
|
'"': '"',
|
||||||
|
"'": ''',
|
||||||
|
"/": '/'
|
||||||
|
};
|
||||||
|
return html.replace(/[&<>"'\/]/g, function (char) {
|
||||||
|
return chars[char];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -986,6 +1055,7 @@ function beautify(event) {
|
||||||
script.src = "beautify/beautify-css.js";
|
script.src = "beautify/beautify-css.js";
|
||||||
script.onload = doBeautify;
|
script.onload = doBeautify;
|
||||||
}
|
}
|
||||||
|
|
||||||
function doBeautify() {
|
function doBeautify() {
|
||||||
var tabs = prefs.get("editor.indentWithTabs");
|
var tabs = prefs.get("editor.indentWithTabs");
|
||||||
var options = prefs.get("editor.beautify");
|
var options = prefs.get("editor.beautify");
|
||||||
|
@ -1061,7 +1131,9 @@ function init() {
|
||||||
var params = getParams();
|
var params = getParams();
|
||||||
if (!params.id) { // match should be 2 - one for the whole thing, one for the parentheses
|
if (!params.id) { // match should be 2 - one for the whole thing, one for the parentheses
|
||||||
// This is an add
|
// This is an add
|
||||||
var section = {code: ""}
|
var section = {
|
||||||
|
code: ""
|
||||||
|
};
|
||||||
for (var i in CssToProperty) {
|
for (var i in CssToProperty) {
|
||||||
if (params[i]) {
|
if (params[i]) {
|
||||||
section[CssToProperty[i]] = [params[i]];
|
section[CssToProperty[i]] = [params[i]];
|
||||||
|
@ -1069,7 +1141,7 @@ function init() {
|
||||||
}
|
}
|
||||||
addSection(null, section);
|
addSection(null, section);
|
||||||
// default to enabled
|
// default to enabled
|
||||||
document.getElementById("enabled").checked = true
|
document.getElementById("enabled").checked = true;
|
||||||
tE("heading", "addStyleTitle");
|
tE("heading", "addStyleTitle");
|
||||||
initHooks();
|
initHooks();
|
||||||
return;
|
return;
|
||||||
|
@ -1077,8 +1149,12 @@ function init() {
|
||||||
// This is an edit
|
// This is an edit
|
||||||
tE("heading", "editStyleHeading", null, false);
|
tE("heading", "editStyleHeading", null, false);
|
||||||
requestStyle();
|
requestStyle();
|
||||||
|
|
||||||
function requestStyle() {
|
function requestStyle() {
|
||||||
chrome.runtime.sendMessage({method: "getStyles", id: params.id}, function callback(styles) {
|
chrome.runtime.sendMessage({
|
||||||
|
method: "getStyles",
|
||||||
|
id: params.id
|
||||||
|
}, function callback(styles) {
|
||||||
if (!styles) { // Chrome is starting up and shows edit.html
|
if (!styles) { // Chrome is starting up and shows edit.html
|
||||||
requestStyle();
|
requestStyle();
|
||||||
return;
|
return;
|
||||||
|
@ -1095,8 +1171,12 @@ function initWithStyle(style) {
|
||||||
document.getElementById("enabled").checked = style.enabled;
|
document.getElementById("enabled").checked = style.enabled;
|
||||||
document.getElementById("url").href = style.url;
|
document.getElementById("url").href = style.url;
|
||||||
// if this was done in response to an update, we need to clear existing sections
|
// if this was done in response to an update, we need to clear existing sections
|
||||||
getSections().forEach(function(div) { div.remove(); });
|
getSections().forEach(function (div) {
|
||||||
var queue = style.sections.length ? style.sections : [{code: ""}];
|
div.remove();
|
||||||
|
});
|
||||||
|
var queue = style.sections.length ? style.sections : [{
|
||||||
|
code: ""
|
||||||
|
}];
|
||||||
var queueStart = new Date().getTime();
|
var queueStart = new Date().getTime();
|
||||||
// after 100ms the sections will be added asynchronously
|
// after 100ms the sections will be added asynchronously
|
||||||
while (new Date().getTime() - queueStart <= 100 && queue.length) {
|
while (new Date().getTime() - queueStart <= 100 && queue.length) {
|
||||||
|
@ -1146,7 +1226,10 @@ function initHooks() {
|
||||||
|
|
||||||
function maximizeCodeHeight(sectionDiv, isLast) {
|
function maximizeCodeHeight(sectionDiv, isLast) {
|
||||||
var cm = sectionDiv.CodeMirror;
|
var cm = sectionDiv.CodeMirror;
|
||||||
var stats = maximizeCodeHeight.stats = maximizeCodeHeight.stats || {totalHeight: 0, deltas: []};
|
var stats = maximizeCodeHeight.stats = maximizeCodeHeight.stats || {
|
||||||
|
totalHeight: 0,
|
||||||
|
deltas: []
|
||||||
|
};
|
||||||
if (!stats.cmActualHeight) {
|
if (!stats.cmActualHeight) {
|
||||||
stats.cmActualHeight = getComputedHeight(cm.display.wrapper);
|
stats.cmActualHeight = getComputedHeight(cm.display.wrapper);
|
||||||
}
|
}
|
||||||
|
@ -1180,7 +1263,9 @@ function maximizeCodeHeight(sectionDiv, isLast) {
|
||||||
if (available <= 0) {
|
if (available <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var totalDelta = stats.deltas.reduce(function(sum, d) { return sum + d; }, 0);
|
var totalDelta = stats.deltas.reduce(function (sum, d) {
|
||||||
|
return sum + d;
|
||||||
|
}, 0);
|
||||||
var q = available / totalDelta;
|
var q = available / totalDelta;
|
||||||
var baseHeight = stats.cmActualHeight - stats.sectionMarginTop;
|
var baseHeight = stats.cmActualHeight - stats.sectionMarginTop;
|
||||||
stats.deltas.forEach(function (delta, index) {
|
stats.deltas.forEach(function (delta, index) {
|
||||||
|
@ -1199,7 +1284,7 @@ function updateTitle() {
|
||||||
|
|
||||||
function validate() {
|
function validate() {
|
||||||
var name = document.getElementById("name").value;
|
var name = document.getElementById("name").value;
|
||||||
if (name == "") {
|
if (name === "") {
|
||||||
return t("styleMissingName");
|
return t("styleMissingName");
|
||||||
}
|
}
|
||||||
// validate the regexps
|
// validate the regexps
|
||||||
|
@ -1259,7 +1344,7 @@ function getSectionsHashes() {
|
||||||
getSections().forEach(function (div) {
|
getSections().forEach(function (div) {
|
||||||
var meta = getMeta(div);
|
var meta = getMeta(div);
|
||||||
var code = div.CodeMirror.getValue();
|
var code = div.CodeMirror.getValue();
|
||||||
if (/^\s*$/.test(code) && Object.keys(meta).length == 0) {
|
if (/^\s*$/.test(code) && Object.keys(meta).length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
meta.code = code;
|
meta.code = code;
|
||||||
|
@ -1269,7 +1354,12 @@ function getSectionsHashes() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMeta(e) {
|
function getMeta(e) {
|
||||||
var meta = {urls: [], urlPrefixes: [], domains: [], regexps: []};
|
var meta = {
|
||||||
|
urls: [],
|
||||||
|
urlPrefixes: [],
|
||||||
|
domains: [],
|
||||||
|
regexps: []
|
||||||
|
};
|
||||||
e.querySelector(".applies-to-list").childNodes.forEach(function (li) {
|
e.querySelector(".applies-to-list").childNodes.forEach(function (li) {
|
||||||
if (li.className == template.appliesToEverything.className) {
|
if (li.className == template.appliesToEverything.className) {
|
||||||
return;
|
return;
|
||||||
|
@ -1297,7 +1387,9 @@ function saveComplete(style) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMozillaFormat() {
|
function showMozillaFormat() {
|
||||||
var popup = showCodeMirrorPopup(t("styleToMozillaFormatTitle"), "", {readOnly: true});
|
var popup = showCodeMirrorPopup(t("styleToMozillaFormatTitle"), "", {
|
||||||
|
readOnly: true
|
||||||
|
});
|
||||||
popup.codebox.setValue(toMozillaFormat());
|
popup.codebox.setValue(toMozillaFormat());
|
||||||
popup.codebox.execCommand("selectAll");
|
popup.codebox.execCommand("selectAll");
|
||||||
}
|
}
|
||||||
|
@ -1317,10 +1409,10 @@ function toMozillaFormat() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function fromMozillaFormat() {
|
function fromMozillaFormat() {
|
||||||
var popup = showCodeMirrorPopup(t("styleFromMozillaFormatPrompt"), tHTML("<div>\
|
var popup = showCodeMirrorPopup(t("styleFromMozillaFormatPrompt"), tHTML("<div>" +
|
||||||
<button name='import-append' i18n-text='importAppendLabel' i18n-title='importAppendTooltip'></button>\
|
"<button name='import-append' i18n-text='importAppendLabel' i18n-title='importAppendTooltip'></button>" +
|
||||||
<button name='import-replace' i18n-text='importReplaceLabel' i18n-title='importReplaceTooltip'></button>\
|
"<button name='import-replace' i18n-text='importReplaceLabel' i18n-title='importReplaceTooltip'></button>" +
|
||||||
</div>").innerHTML);
|
"</div>").innerHTML);
|
||||||
|
|
||||||
var contents = popup.querySelector(".contents");
|
var contents = popup.querySelector(".contents");
|
||||||
contents.insertBefore(popup.codebox.display.wrapper, contents.firstElementChild);
|
contents.insertBefore(popup.codebox.display.wrapper, contents.firstElementChild);
|
||||||
|
@ -1340,15 +1432,26 @@ function fromMozillaFormat() {
|
||||||
var replaceOldStyle = this.name == "import-replace";
|
var replaceOldStyle = this.name == "import-replace";
|
||||||
popup.querySelector(".close-icon").click();
|
popup.querySelector(".close-icon").click();
|
||||||
var mozStyle = trimNewLines(popup.codebox.getValue());
|
var mozStyle = trimNewLines(popup.codebox.getValue());
|
||||||
var parser = new exports.css.Parser(), lines = mozStyle.split("\n");
|
var parser = new exports.css.Parser(),
|
||||||
var sectionStack = [{code: "", start: {line: 1, col: 1}}];
|
lines = mozStyle.split("\n");
|
||||||
var errors = "", oldSectionCount = editors.length;
|
var sectionStack = [{
|
||||||
|
code: "",
|
||||||
|
start: {
|
||||||
|
line: 1,
|
||||||
|
col: 1
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
var errors = "",
|
||||||
|
oldSectionCount = editors.length;
|
||||||
var firstAddedCM;
|
var firstAddedCM;
|
||||||
|
|
||||||
parser.addListener("startdocument", function (e) {
|
parser.addListener("startdocument", function (e) {
|
||||||
var outerText = getRange(sectionStack.last.start, (--e.col, e));
|
var outerText = getRange(sectionStack.last.start, (--e.col, e));
|
||||||
var gapComment = outerText.match(/(\/\*[\s\S]*?\*\/)[\s\n]*$/);
|
var gapComment = outerText.match(/(\/\*[\s\S]*?\*\/)[\s\n]*$/);
|
||||||
var section = {code: "", start: backtrackTo(this, exports.css.Tokens.LBRACE, "end")};
|
var section = {
|
||||||
|
code: "",
|
||||||
|
start: backtrackTo(this, exports.css.Tokens.LBRACE, "end")
|
||||||
|
};
|
||||||
// move last comment before @-moz-document inside the section
|
// move last comment before @-moz-document inside the section
|
||||||
if (gapComment && !gapComment[1].match(/\/\*\s*AGENT_SHEET\s*\*\//)) {
|
if (gapComment && !gapComment[1].match(/\/\*\s*AGENT_SHEET\s*\*\//)) {
|
||||||
section.code = gapComment[1] + "\n";
|
section.code = gapComment[1] + "\n";
|
||||||
|
@ -1378,7 +1481,10 @@ function fromMozillaFormat() {
|
||||||
|
|
||||||
parser.addListener("endstylesheet", function () {
|
parser.addListener("endstylesheet", function () {
|
||||||
// add nonclosed outer sections (either broken or the last global one)
|
// add nonclosed outer sections (either broken or the last global one)
|
||||||
var endOfText = {line: lines.length, col: lines.last.length + 1};
|
var endOfText = {
|
||||||
|
line: lines.length,
|
||||||
|
col: lines.last.length + 1
|
||||||
|
};
|
||||||
sectionStack.last.code += getRange(sectionStack.last.start, endOfText);
|
sectionStack.last.code += getRange(sectionStack.last.start, endOfText);
|
||||||
sectionStack.forEach(doAddSection);
|
sectionStack.forEach(doAddSection);
|
||||||
|
|
||||||
|
@ -1410,6 +1516,7 @@ function fromMozillaFormat() {
|
||||||
"\n" + lines[end.line - 1].substring(0, end.col - 1));
|
"\n" + lines[end.line - 1].substring(0, end.col - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function doAddSection(section) {
|
function doAddSection(section) {
|
||||||
if (!firstAddedCM) {
|
if (!firstAddedCM) {
|
||||||
if (!initFirstSection(section)) {
|
if (!initFirstSection(section)) {
|
||||||
|
@ -1432,25 +1539,34 @@ function fromMozillaFormat() {
|
||||||
}
|
}
|
||||||
if (replaceOldStyle) {
|
if (replaceOldStyle) {
|
||||||
editors.slice(0).reverse().forEach(function (cm) {
|
editors.slice(0).reverse().forEach(function (cm) {
|
||||||
removeSection({target: cm.getSection().firstElementChild});
|
removeSection({
|
||||||
|
target: cm.getSection().firstElementChild
|
||||||
|
});
|
||||||
});
|
});
|
||||||
} else if (!editors.last.getValue()) {
|
} else if (!editors.last.getValue()) {
|
||||||
// nuke the last blank section
|
// nuke the last blank section
|
||||||
if (editors.last.getSection().querySelector(".applies-to-everything")) {
|
if (editors.last.getSection().querySelector(".applies-to-everything")) {
|
||||||
removeSection({target: editors.last.getSection()});
|
removeSection({
|
||||||
|
target: editors.last.getSection()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function backtrackTo(parser, tokenType, startEnd) {
|
function backtrackTo(parser, tokenType, startEnd) {
|
||||||
var tokens = parser._tokenStream._lt;
|
var tokens = parser._tokenStream._lt;
|
||||||
for (var i = tokens.length - 2; i >= 0; --i) {
|
for (var i = tokens.length - 2; i >= 0; --i) {
|
||||||
if (tokens[i].type == tokenType) {
|
if (tokens[i].type == tokenType) {
|
||||||
return {line: tokens[i][startEnd+"Line"], col: tokens[i][startEnd+"Col"]};
|
return {
|
||||||
|
line: tokens[i][startEnd + "Line"],
|
||||||
|
col: tokens[i][startEnd + "Col"]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function trimNewLines(s) {
|
function trimNewLines(s) {
|
||||||
return s.replace(/^[\s\n]+/, "").replace(/[\s\n]+$/, "");
|
return s.replace(/^[\s\n]+/, "").replace(/[\s\n]+$/, "");
|
||||||
}
|
}
|
||||||
|
@ -1471,9 +1587,19 @@ function showToMozillaHelp() {
|
||||||
function showKeyMapHelp() {
|
function showKeyMapHelp() {
|
||||||
var keyMap = mergeKeyMaps({}, prefs.get("editor.keyMap"), CodeMirror.defaults.extraKeys);
|
var keyMap = mergeKeyMaps({}, prefs.get("editor.keyMap"), CodeMirror.defaults.extraKeys);
|
||||||
var keyMapSorted = Object.keys(keyMap)
|
var keyMapSorted = Object.keys(keyMap)
|
||||||
.map(function(key) { return {key: key, cmd: keyMap[key]} })
|
.map(function (key) {
|
||||||
.concat([{key: "Shift-Ctrl-Wheel", cmd: "scrollWindow"}])
|
return {
|
||||||
.sort(function(a, b) { return a.cmd < b.cmd || (a.cmd == b.cmd && a.key < b.key) ? -1 : 1 });
|
key: key,
|
||||||
|
cmd: keyMap[key]
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.concat([{
|
||||||
|
key: "Shift-Ctrl-Wheel",
|
||||||
|
cmd: "scrollWindow"
|
||||||
|
}])
|
||||||
|
.sort(function (a, b) {
|
||||||
|
return a.cmd < b.cmd || (a.cmd == b.cmd && a.key < b.key) ? -1 : 1;
|
||||||
|
});
|
||||||
showHelp(t("cm_keyMap") + ": " + prefs.get("editor.keyMap"),
|
showHelp(t("cm_keyMap") + ": " + prefs.get("editor.keyMap"),
|
||||||
'<table class="keymap-list">' +
|
'<table class="keymap-list">' +
|
||||||
'<thead><tr><th><input placeholder="' + t("helpKeyMapHotkey") + '" type="search"></th>' +
|
'<thead><tr><th><input placeholder="' + t("helpKeyMapHotkey") + '" type="search"></th>' +
|
||||||
|
@ -1506,6 +1632,7 @@ function showKeyMapHelp() {
|
||||||
this.value = normalizedKey.replace("-dummy", "");
|
this.value = normalizedKey.replace("-dummy", "");
|
||||||
filterTable(event);
|
filterTable(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterTable(event) {
|
function filterTable(event) {
|
||||||
var input = event.target;
|
var input = event.target;
|
||||||
var query = stringAsRegExp(input.value, "gi");
|
var query = stringAsRegExp(input.value, "gi");
|
||||||
|
@ -1520,6 +1647,7 @@ function showKeyMapHelp() {
|
||||||
cell.innerHTML = cell.textContent;
|
cell.innerHTML = cell.textContent;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeKeyMaps(merged) {
|
function mergeKeyMaps(merged) {
|
||||||
[].slice.call(arguments, 1).forEach(function (keyMap) {
|
[].slice.call(arguments, 1).forEach(function (keyMap) {
|
||||||
if (typeof keyMap == "string") {
|
if (typeof keyMap == "string") {
|
||||||
|
@ -1589,14 +1717,21 @@ function showCodeMirrorPopup(title, html, options) {
|
||||||
foldGutter: true,
|
foldGutter: true,
|
||||||
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"],
|
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"],
|
||||||
matchBrackets: true,
|
matchBrackets: true,
|
||||||
lint: {getAnnotations: CodeMirror.lint.css, delay: 0},
|
lint: {
|
||||||
|
getAnnotations: CodeMirror.lint.css,
|
||||||
|
delay: 0
|
||||||
|
},
|
||||||
styleActiveLine: true,
|
styleActiveLine: true,
|
||||||
theme: prefs.get("editor.theme"),
|
theme: prefs.get("editor.theme"),
|
||||||
keyMap: prefs.get("editor.keyMap")
|
keyMap: prefs.get("editor.keyMap")
|
||||||
}, options));
|
}, options));
|
||||||
popup.codebox.focus();
|
popup.codebox.focus();
|
||||||
popup.codebox.on("focus", function() { hotkeyRerouter.setState(false) });
|
popup.codebox.on("focus", function () {
|
||||||
popup.codebox.on("blur", function() { hotkeyRerouter.setState(true) });
|
hotkeyRerouter.setState(false);
|
||||||
|
});
|
||||||
|
popup.codebox.on("blur", function () {
|
||||||
|
hotkeyRerouter.setState(true);
|
||||||
|
});
|
||||||
return popup;
|
return popup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1642,3 +1777,4 @@ function getComputedHeight(el) {
|
||||||
return el.getBoundingClientRect().height +
|
return el.getBoundingClientRect().height +
|
||||||
parseFloat(compStyle.marginTop) + parseFloat(compStyle.marginBottom);
|
parseFloat(compStyle.marginTop) + parseFloat(compStyle.marginBottom);
|
||||||
}
|
}
|
||||||
|
}());
|
|
@ -1,3 +1,4 @@
|
||||||
|
/*jshint undef:false*/
|
||||||
healthCheck();
|
healthCheck();
|
||||||
|
|
||||||
function healthCheck() {
|
function healthCheck() {
|
||||||
|
|
49
install.js
49
install.js
|
@ -1,5 +1,9 @@
|
||||||
chrome.runtime.sendMessage({method: "getStyles", url: getMeta("stylish-id-url") || location.href}, function(response) {
|
/*jshint undef:false*/
|
||||||
if (response.length == 0) {
|
chrome.runtime.sendMessage({
|
||||||
|
method: "getStyles",
|
||||||
|
url: getMeta("stylish-id-url") || location.href
|
||||||
|
}, function (response) {
|
||||||
|
if (response.length === 0) {
|
||||||
sendEvent("styleCanBeInstalledChrome");
|
sendEvent("styleCanBeInstalledChrome");
|
||||||
} else {
|
} else {
|
||||||
var installedStyle = response[0];
|
var installedStyle = response[0];
|
||||||
|
@ -9,16 +13,22 @@ chrome.runtime.sendMessage({method: "getStyles", url: getMeta("stylish-id-url")
|
||||||
if (md5Url && installedStyle.md5Url && installedStyle.originalMd5) {
|
if (md5Url && installedStyle.md5Url && installedStyle.originalMd5) {
|
||||||
getResource(md5Url, function (md5) {
|
getResource(md5Url, function (md5) {
|
||||||
if (md5 == installedStyle.originalMd5) {
|
if (md5 == installedStyle.originalMd5) {
|
||||||
sendEvent("styleAlreadyInstalledChrome", {updateUrl: installedStyle.updateUrl});
|
sendEvent("styleAlreadyInstalledChrome", {
|
||||||
|
updateUrl: installedStyle.updateUrl
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
sendEvent("styleCanBeUpdatedChrome", {updateUrl: installedStyle.updateUrl});
|
sendEvent("styleCanBeUpdatedChrome", {
|
||||||
|
updateUrl: installedStyle.updateUrl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
getResource(getMeta("stylish-code-chrome"), function (code) {
|
getResource(getMeta("stylish-code-chrome"), function (code) {
|
||||||
// this would indicate a failure (a style with settings?).
|
// this would indicate a failure (a style with settings?).
|
||||||
if (code == null) {
|
if (code === null) {
|
||||||
sendEvent("styleCanBeUpdatedChrome", {updateUrl: installedStyle.updateUrl});
|
sendEvent("styleCanBeUpdatedChrome", {
|
||||||
|
updateUrl: installedStyle.updateUrl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
var json = JSON.parse(code);
|
var json = JSON.parse(code);
|
||||||
if (json.sections.length == installedStyle.sections.length) {
|
if (json.sections.length == installedStyle.sections.length) {
|
||||||
|
@ -28,11 +38,15 @@ chrome.runtime.sendMessage({method: "getStyles", url: getMeta("stylish-id-url")
|
||||||
});
|
});
|
||||||
})) {
|
})) {
|
||||||
// everything's the same
|
// everything's the same
|
||||||
sendEvent("styleAlreadyInstalledChrome", {updateUrl: installedStyle.updateUrl});
|
sendEvent("styleAlreadyInstalledChrome", {
|
||||||
|
updateUrl: installedStyle.updateUrl
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
sendEvent("styleCanBeUpdatedChrome", {updateUrl: installedStyle.updateUrl});
|
}
|
||||||
|
sendEvent("styleCanBeUpdatedChrome", {
|
||||||
|
updateUrl: installedStyle.updateUrl
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,9 +64,9 @@ function sectionsAreEqual(a, b) {
|
||||||
function arraysAreEqual(a, b) {
|
function arraysAreEqual(a, b) {
|
||||||
// treat empty array and undefined as equivalent
|
// treat empty array and undefined as equivalent
|
||||||
if (typeof a == "undefined")
|
if (typeof a == "undefined")
|
||||||
return (typeof b == "undefined") || (b.length == 0);
|
return (typeof b == "undefined") || (b.length === 0);
|
||||||
if (typeof b == "undefined")
|
if (typeof b == "undefined")
|
||||||
return (typeof a == "undefined") || (a.length == 0);
|
return (typeof a == "undefined") || (a.length === 0);
|
||||||
if (a.length != b.length) {
|
if (a.length != b.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +79,9 @@ function sendEvent(type, data) {
|
||||||
if (typeof data == "undefined") {
|
if (typeof data == "undefined") {
|
||||||
data = null;
|
data = null;
|
||||||
}
|
}
|
||||||
var stylishEvent = new CustomEvent(type, {detail: data});
|
var stylishEvent = new CustomEvent(type, {
|
||||||
|
detail: data
|
||||||
|
});
|
||||||
document.dispatchEvent(stylishEvent);
|
document.dispatchEvent(stylishEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +102,10 @@ document.addEventListener("stylishInstallChrome", function() {
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
document.addEventListener("stylishUpdateChrome", function () {
|
document.addEventListener("stylishUpdateChrome", function () {
|
||||||
chrome.runtime.sendMessage({method: "getStyles", url: getMeta("stylish-id-url") || location.href}, function(response) {
|
chrome.runtime.sendMessage({
|
||||||
|
method: "getStyles",
|
||||||
|
url: getMeta("stylish-id-url") || location.href
|
||||||
|
}, function (response) {
|
||||||
var style = response[0];
|
var style = response[0];
|
||||||
if (confirm(chrome.i18n.getMessage('styleUpdate', [style.name]))) {
|
if (confirm(chrome.i18n.getMessage('styleUpdate', [style.name]))) {
|
||||||
getResource(getMeta("stylish-code-chrome"), function (code) {
|
getResource(getMeta("stylish-code-chrome"), function (code) {
|
||||||
|
@ -108,7 +127,7 @@ function getMeta(name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getResource(url, callback) {
|
function getResource(url, callback) {
|
||||||
if (url.indexOf("#") == 0) {
|
if (url.indexOf("#") === 0) {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback(document.getElementById(url.substring(1)).innerText);
|
callback(document.getElementById(url.substring(1)).innerText);
|
||||||
}
|
}
|
||||||
|
@ -123,7 +142,7 @@ function getResource(url, callback) {
|
||||||
callback(xhr.responseText);
|
callback(xhr.responseText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
if (url.length > 2000) {
|
if (url.length > 2000) {
|
||||||
var parts = url.split("?");
|
var parts = url.split("?");
|
||||||
xhr.open("POST", parts[0], true);
|
xhr.open("POST", parts[0], true);
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
/*jshint undef:false*/
|
||||||
var template = {};
|
var template = {};
|
||||||
tDocLoader();
|
tDocLoader();
|
||||||
|
|
||||||
function t(key, params) {
|
function t(key, params) {
|
||||||
var s = chrome.i18n.getMessage(key, params)
|
var s = chrome.i18n.getMessage(key, params);
|
||||||
if (s == "") {
|
if (s === "") {
|
||||||
throw "Missing string '" + key + "'.";
|
throw "Missing string '" + key + "'.";
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
|
@ -44,7 +45,7 @@ function tNodeList(nodes) {
|
||||||
for (var a = node.attributes.length - 1; a >= 0; a--) {
|
for (var a = node.attributes.length - 1; a >= 0; a--) {
|
||||||
var attr = node.attributes[a];
|
var attr = node.attributes[a];
|
||||||
var name = attr.nodeName;
|
var name = attr.nodeName;
|
||||||
if (name.indexOf("i18n-") != 0) {
|
if (name.indexOf("i18n-") !== 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
name = name.substr(5); // "i18n-".length
|
name = name.substr(5); // "i18n-".length
|
||||||
|
|
101
manage.js
101
manage.js
|
@ -1,3 +1,4 @@
|
||||||
|
/*jshint undef:false*/
|
||||||
var lastUpdatedStyleId = null;
|
var lastUpdatedStyleId = null;
|
||||||
var installed;
|
var installed;
|
||||||
|
|
||||||
|
@ -5,11 +6,15 @@ var appliesToExtraTemplate = document.createElement("span");
|
||||||
appliesToExtraTemplate.className = "applies-to-extra";
|
appliesToExtraTemplate.className = "applies-to-extra";
|
||||||
appliesToExtraTemplate.innerHTML = " " + t('appliesDisplayTruncatedSuffix');
|
appliesToExtraTemplate.innerHTML = " " + t('appliesDisplayTruncatedSuffix');
|
||||||
|
|
||||||
chrome.runtime.sendMessage({method: "getStyles"}, showStyles);
|
chrome.runtime.sendMessage({
|
||||||
|
method: "getStyles"
|
||||||
|
}, showStyles);
|
||||||
|
|
||||||
function showStyles(styles) {
|
function showStyles(styles) {
|
||||||
if (!styles) { // Chrome is starting up
|
if (!styles) { // Chrome is starting up
|
||||||
chrome.runtime.sendMessage({method: "getStyles"}, showStyles);
|
chrome.runtime.sendMessage({
|
||||||
|
method: "getStyles"
|
||||||
|
}, showStyles);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!installed) {
|
if (!installed) {
|
||||||
|
@ -18,7 +23,9 @@ function showStyles(styles) {
|
||||||
document.stylishStyles = styles;
|
document.stylishStyles = styles;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
styles.sort(function(a, b) { return a.name.localeCompare(b.name)});
|
styles.sort(function (a, b) {
|
||||||
|
return a.name.localeCompare(b.name);
|
||||||
|
});
|
||||||
styles.map(createStyleElement).forEach(function (e) {
|
styles.map(createStyleElement).forEach(function (e) {
|
||||||
installed.appendChild(e);
|
installed.appendChild(e);
|
||||||
});
|
});
|
||||||
|
@ -44,7 +51,7 @@ function createStyleElement(style) {
|
||||||
var styleName = e.querySelector(".style-name");
|
var styleName = e.querySelector(".style-name");
|
||||||
styleName.appendChild(document.createTextNode(style.name));
|
styleName.appendChild(document.createTextNode(style.name));
|
||||||
if (style.url) {
|
if (style.url) {
|
||||||
var homepage = template.styleHomepage.cloneNode(true)
|
var homepage = template.styleHomepage.cloneNode(true);
|
||||||
homepage.setAttribute("href", style.url);
|
homepage.setAttribute("href", style.url);
|
||||||
styleName.appendChild(document.createTextNode(" "));
|
styleName.appendChild(document.createTextNode(" "));
|
||||||
styleName.appendChild(homepage);
|
styleName.appendChild(homepage);
|
||||||
|
@ -53,6 +60,7 @@ function createStyleElement(style) {
|
||||||
var urls = [];
|
var urls = [];
|
||||||
var urlPrefixes = [];
|
var urlPrefixes = [];
|
||||||
var regexps = [];
|
var regexps = [];
|
||||||
|
|
||||||
function add(array, property) {
|
function add(array, property) {
|
||||||
style.sections.forEach(function (section) {
|
style.sections.forEach(function (section) {
|
||||||
if (section[property]) {
|
if (section[property]) {
|
||||||
|
@ -60,7 +68,7 @@ function createStyleElement(style) {
|
||||||
return array.indexOf(value) == -1;
|
return array.indexOf(value) == -1;
|
||||||
}).forEach(function (value) {
|
}).forEach(function (value) {
|
||||||
array.push(value);
|
array.push(value);
|
||||||
});;
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -74,12 +82,16 @@ function createStyleElement(style) {
|
||||||
if (urls)
|
if (urls)
|
||||||
appliesToToShow = appliesToToShow.concat(urls);
|
appliesToToShow = appliesToToShow.concat(urls);
|
||||||
if (urlPrefixes)
|
if (urlPrefixes)
|
||||||
appliesToToShow = appliesToToShow.concat(urlPrefixes.map(function(u) { return u + "*"; }));
|
appliesToToShow = appliesToToShow.concat(urlPrefixes.map(function (u) {
|
||||||
|
return u + "*";
|
||||||
|
}));
|
||||||
if (regexps)
|
if (regexps)
|
||||||
appliesToToShow = appliesToToShow.concat(regexps.map(function(u) { return "/" + u + "/"; }));
|
appliesToToShow = appliesToToShow.concat(regexps.map(function (u) {
|
||||||
|
return "/" + u + "/";
|
||||||
|
}));
|
||||||
var appliesToString = "";
|
var appliesToString = "";
|
||||||
var showAppliesToExtra = false;
|
var showAppliesToExtra = false;
|
||||||
if (appliesToToShow.length == "")
|
if (appliesToToShow.length === "")
|
||||||
appliesToString = t('appliesToEverything');
|
appliesToString = t('appliesToEverything');
|
||||||
else if (appliesToToShow.length <= 10)
|
else if (appliesToToShow.length <= 10)
|
||||||
appliesToString = appliesToToShow.join(", ");
|
appliesToString = appliesToToShow.join(", ");
|
||||||
|
@ -95,8 +107,10 @@ function createStyleElement(style) {
|
||||||
editLink.setAttribute("href", editLink.getAttribute("href") + style.id);
|
editLink.setAttribute("href", editLink.getAttribute("href") + style.id);
|
||||||
editLink.addEventListener("click", function (event) {
|
editLink.addEventListener("click", function (event) {
|
||||||
if (!event.altKey) {
|
if (!event.altKey) {
|
||||||
var left = event.button == 0, middle = event.button == 1,
|
var left = event.button === 0,
|
||||||
shift = event.shiftKey, ctrl = event.ctrlKey;
|
middle = event.button == 1,
|
||||||
|
shift = event.shiftKey,
|
||||||
|
ctrl = event.ctrlKey;
|
||||||
var openWindow = left && shift && !ctrl;
|
var openWindow = left && shift && !ctrl;
|
||||||
var openBackgroundTab = (middle && !shift) || (left && ctrl && !shift);
|
var openBackgroundTab = (middle && !shift) || (left && ctrl && !shift);
|
||||||
var openForegroundTab = (middle && shift) || (left && ctrl && shift);
|
var openForegroundTab = (middle && shift) || (left && ctrl && shift);
|
||||||
|
@ -116,7 +130,9 @@ function createStyleElement(style) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
history.replaceState({scrollY: window.scrollY}, document.title);
|
history.replaceState({
|
||||||
|
scrollY: window.scrollY
|
||||||
|
}, document.title);
|
||||||
getActiveTab(function (tab) {
|
getActiveTab(function (tab) {
|
||||||
sessionStorageHash("manageStylesHistory").set(tab.id, url);
|
sessionStorageHash("manageStylesHistory").set(tab.id, url);
|
||||||
location.href = url;
|
location.href = url;
|
||||||
|
@ -124,8 +140,12 @@ function createStyleElement(style) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
e.querySelector(".enable").addEventListener("click", function(event) { enable(event, true); }, false);
|
e.querySelector(".enable").addEventListener("click", function (event) {
|
||||||
e.querySelector(".disable").addEventListener("click", function(event) { enable(event, false); }, false);
|
enable(event, true);
|
||||||
|
}, false);
|
||||||
|
e.querySelector(".disable").addEventListener("click", function (event) {
|
||||||
|
enable(event, false);
|
||||||
|
}, false);
|
||||||
e.querySelector(".check-update").addEventListener("click", doCheckUpdate, false);
|
e.querySelector(".check-update").addEventListener("click", doCheckUpdate, false);
|
||||||
e.querySelector(".update").addEventListener("click", doUpdate, false);
|
e.querySelector(".update").addEventListener("click", doUpdate, false);
|
||||||
e.querySelector(".delete").addEventListener("click", doDelete, false);
|
e.querySelector(".delete").addEventListener("click", doDelete, false);
|
||||||
|
@ -181,7 +201,7 @@ function handleUpdate(style) {
|
||||||
lastUpdatedStyleId = null;
|
lastUpdatedStyleId = null;
|
||||||
element.className = element.className += " update-done";
|
element.className = element.className += " update-done";
|
||||||
element.querySelector(".update-note").innerHTML = t('updateCompleted');
|
element.querySelector(".update-note").innerHTML = t('updateCompleted');
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDelete(id) {
|
function handleDelete(id) {
|
||||||
|
@ -225,7 +245,7 @@ function checkUpdateAll() {
|
||||||
if (success) {
|
if (success) {
|
||||||
++updatableCount;
|
++updatableCount;
|
||||||
}
|
}
|
||||||
if (--toCheckCount == 0) {
|
if (--toCheckCount === 0) {
|
||||||
btnCheck.disabled = false;
|
btnCheck.disabled = false;
|
||||||
if (updatableCount) {
|
if (updatableCount) {
|
||||||
btnApply.classList.remove("hidden");
|
btnApply.classList.remove("hidden");
|
||||||
|
@ -249,7 +269,10 @@ function checkUpdate(element, callback) {
|
||||||
var originalMd5 = element.getAttribute("style-original-md5");
|
var originalMd5 = element.getAttribute("style-original-md5");
|
||||||
|
|
||||||
function handleSuccess(forceUpdate, serverJson) {
|
function handleSuccess(forceUpdate, serverJson) {
|
||||||
chrome.runtime.sendMessage({method: "getStyles", id: id}, function(styles) {
|
chrome.runtime.sendMessage({
|
||||||
|
method: "getStyles",
|
||||||
|
id: id
|
||||||
|
}, function (styles) {
|
||||||
var style = styles[0];
|
var style = styles[0];
|
||||||
var needsUpdate = false;
|
var needsUpdate = false;
|
||||||
if (!forceUpdate && codeIsEqual(style.sections, serverJson.sections)) {
|
if (!forceUpdate && codeIsEqual(style.sections, serverJson.sections)) {
|
||||||
|
@ -265,7 +288,7 @@ function checkUpdate(element, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFailure(status) {
|
function handleFailure(status) {
|
||||||
if (status == 0) {
|
if (status === 0) {
|
||||||
handleNeedsUpdate(t('updateCheckFailServerUnreachable'), id, null);
|
handleNeedsUpdate(t('updateCheckFailServerUnreachable'), id, null);
|
||||||
} else {
|
} else {
|
||||||
handleNeedsUpdate(t('updateCheckFailBadResponseCode', [status]), id, null);
|
handleNeedsUpdate(t('updateCheckFailBadResponseCode', [status]), id, null);
|
||||||
|
@ -276,7 +299,7 @@ function checkUpdate(element, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!md5Url || !originalMd5) {
|
if (!md5Url || !originalMd5) {
|
||||||
checkUpdateFullCode(url, false, handleSuccess, handleFailure)
|
checkUpdateFullCode(url, false, handleSuccess, handleFailure);
|
||||||
} else {
|
} else {
|
||||||
checkUpdateMd5(originalMd5, md5Url, function (needsUpdate) {
|
checkUpdateMd5(originalMd5, md5Url, function (needsUpdate) {
|
||||||
if (needsUpdate) {
|
if (needsUpdate) {
|
||||||
|
@ -313,12 +336,12 @@ function download(url, successCallback, failureCallback) {
|
||||||
xhr.onreadystatechange = function (aEvt) {
|
xhr.onreadystatechange = function (aEvt) {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState == 4) {
|
||||||
if (xhr.status == 200) {
|
if (xhr.status == 200) {
|
||||||
successCallback(xhr.responseText)
|
successCallback(xhr.responseText);
|
||||||
} else {
|
} else {
|
||||||
failureCallback(xhr.status);
|
failureCallback(xhr.status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
if (url.length > 2000) {
|
if (url.length > 2000) {
|
||||||
var parts = url.split("?");
|
var parts = url.split("?");
|
||||||
xhr.open("POST", parts[0], true);
|
xhr.open("POST", parts[0], true);
|
||||||
|
@ -387,11 +410,13 @@ function codeIsEqual(a, b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function jsonEquals(a, b, property) {
|
function jsonEquals(a, b, property) {
|
||||||
var aProp = a[property], typeA = getType(aProp);
|
var aProp = a[property],
|
||||||
var bProp = b[property], typeB = getType(bProp);
|
typeA = getType(aProp);
|
||||||
|
var bProp = b[property],
|
||||||
|
typeB = getType(bProp);
|
||||||
if (typeA != typeB) {
|
if (typeA != typeB) {
|
||||||
// consider empty arrays equivalent to lack of property
|
// consider empty arrays equivalent to lack of property
|
||||||
if ((typeA == "undefined" || (typeA == "array" && aProp.length == 0)) && (typeB == "undefined" || (typeB == "array" && bProp.length == 0))) {
|
if ((typeA == "undefined" || (typeA == "array" && aProp.length === 0)) && (typeB == "undefined" || (typeB == "array" && bProp.length === 0))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -427,8 +452,11 @@ function searchStyles(immediately) {
|
||||||
clearTimeout(searchStyles.timeout);
|
clearTimeout(searchStyles.timeout);
|
||||||
searchStyles.timeout = setTimeout(doSearch, 100);
|
searchStyles.timeout = setTimeout(doSearch, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
function doSearch() {
|
function doSearch() {
|
||||||
chrome.runtime.sendMessage({method: "getStyles"}, function(styles) {
|
chrome.runtime.sendMessage({
|
||||||
|
method: "getStyles"
|
||||||
|
}, function (styles) {
|
||||||
styles.forEach(function (style) {
|
styles.forEach(function (style) {
|
||||||
var el = document.querySelector("[style-id='" + style.id + "']");
|
var el = document.querySelector("[style-id='" + style.id + "']");
|
||||||
if (el) {
|
if (el) {
|
||||||
|
@ -437,17 +465,21 @@ function searchStyles(immediately) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMatchingStyle(style) {
|
function isMatchingStyle(style) {
|
||||||
return style.sections.some(function (section) {
|
return style.sections.some(function (section) {
|
||||||
return Object.keys(section).some(function (key) {
|
return Object.keys(section).some(function (key) {
|
||||||
var value = section[key];
|
var value = section[key];
|
||||||
switch (typeof value) {
|
switch (typeof value) {
|
||||||
case "string": return isMatchingText(value);
|
case "string":
|
||||||
case "object": return value.some(isMatchingText);
|
return isMatchingText(value);
|
||||||
|
case "object":
|
||||||
|
return value.some(isMatchingText);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMatchingText(text) {
|
function isMatchingText(text) {
|
||||||
return text.toLocaleLowerCase().indexOf(query) >= 0;
|
return text.toLocaleLowerCase().indexOf(query) >= 0;
|
||||||
}
|
}
|
||||||
|
@ -456,9 +488,12 @@ function searchStyles(immediately) {
|
||||||
function onFilterChange(className, event) {
|
function onFilterChange(className, event) {
|
||||||
installed.classList.toggle(className, event.target.checked);
|
installed.classList.toggle(className, event.target.checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
function initFilter(className, node) {
|
function initFilter(className, node) {
|
||||||
node.addEventListener("change", onFilterChange.bind(undefined, className), false);
|
node.addEventListener("change", onFilterChange.bind(undefined, className), false);
|
||||||
onFilterChange(className, {target: node});
|
onFilterChange(className, {
|
||||||
|
target: node
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function importStyles(e) {
|
function importStyles(e) {
|
||||||
|
@ -471,9 +506,8 @@ function importStyles (e) {
|
||||||
if (style) {
|
if (style) {
|
||||||
delete style.id;
|
delete style.id;
|
||||||
saveStyle(style, save);
|
saveStyle(style, save);
|
||||||
}
|
} else {
|
||||||
else {
|
window.location.reload();
|
||||||
window.location.reload()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,15 +515,14 @@ function importStyles (e) {
|
||||||
try {
|
try {
|
||||||
styles = JSON.parse(evt.target.result);
|
styles = JSON.parse(evt.target.result);
|
||||||
save();
|
save();
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
|
||||||
window.alert(e.message);
|
window.alert(e.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
reader.onerror = function (e) {
|
reader.onerror = function (e) {
|
||||||
window.alert(e.message);
|
window.alert(e.message);
|
||||||
}
|
};
|
||||||
reader.readAsText(file)
|
reader.readAsText(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectAll() {
|
function selectAll() {
|
||||||
|
|
49
messaging.js
49
messaging.js
|
@ -1,5 +1,8 @@
|
||||||
|
/*jshint undef:false*/
|
||||||
function notifyAllTabs(request) {
|
function notifyAllTabs(request) {
|
||||||
chrome.windows.getAll({populate: true}, function(windows) {
|
chrome.windows.getAll({
|
||||||
|
populate: true
|
||||||
|
}, function (windows) {
|
||||||
windows.forEach(function (win) {
|
windows.forEach(function (win) {
|
||||||
win.tabs.forEach(function (tab) {
|
win.tabs.forEach(function (tab) {
|
||||||
chrome.tabs.sendMessage(tab.id, request);
|
chrome.tabs.sendMessage(tab.id, request);
|
||||||
|
@ -8,7 +11,10 @@ function notifyAllTabs(request) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// notify all open popups
|
// notify all open popups
|
||||||
var reqPopup = shallowMerge({}, request, {method: "updatePopup", reason: request.method});
|
var reqPopup = shallowMerge({}, request, {
|
||||||
|
method: "updatePopup",
|
||||||
|
reason: request.method
|
||||||
|
});
|
||||||
chrome.runtime.sendMessage(reqPopup);
|
chrome.runtime.sendMessage(reqPopup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,21 +43,30 @@ function updateIcon(tab, styles) {
|
||||||
getTabRealURL(tab, function (url) {
|
getTabRealURL(tab, function (url) {
|
||||||
// if we have access to this, call directly. a page sending a message to itself doesn't seem to work right.
|
// if we have access to this, call directly. a page sending a message to itself doesn't seem to work right.
|
||||||
if (typeof getStyles != "undefined") {
|
if (typeof getStyles != "undefined") {
|
||||||
getStyles({matchUrl: url, enabled: true}, stylesReceived);
|
getStyles({
|
||||||
|
matchUrl: url,
|
||||||
|
enabled: true
|
||||||
|
}, stylesReceived);
|
||||||
} else {
|
} else {
|
||||||
chrome.runtime.sendMessage({method: "getStyles", matchUrl: url, enabled: true}, stylesReceived);
|
chrome.runtime.sendMessage({
|
||||||
|
method: "getStyles",
|
||||||
|
matchUrl: url,
|
||||||
|
enabled: true
|
||||||
|
}, stylesReceived);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function stylesReceived(styles) {
|
function stylesReceived(styles) {
|
||||||
var disableAll = "disableAll" in styles ? styles.disableAll : prefs.get("disableAll");
|
var disableAll = "disableAll" in styles ? styles.disableAll : prefs.get("disableAll");
|
||||||
var postfix = styles.length == 0 || disableAll ? "w" : "";
|
var postfix = styles.length === 0 || disableAll ? "w" : "";
|
||||||
chrome.browserAction.setIcon({
|
chrome.browserAction.setIcon({
|
||||||
path: {
|
path: {
|
||||||
// Material Design 2016 new size is 16px
|
// Material Design 2016 new size is 16px
|
||||||
16: "16" + postfix + ".png", 32: "32" + postfix + ".png",
|
16: "16" + postfix + ".png",
|
||||||
|
32: "32" + postfix + ".png",
|
||||||
// Chromium forks or non-chromium browsers may still use the traditional 19px
|
// Chromium forks or non-chromium browsers may still use the traditional 19px
|
||||||
19: "19" + postfix + ".png", 38: "38" + postfix + ".png",
|
19: "19" + postfix + ".png",
|
||||||
|
38: "38" + postfix + ".png",
|
||||||
},
|
},
|
||||||
tabId: tab.id
|
tabId: tab.id
|
||||||
}, function () {
|
}, function () {
|
||||||
|
@ -59,8 +74,13 @@ function updateIcon(tab, styles) {
|
||||||
// e.g. 'windowPosition' pref updated in edit.js::window.onbeforeunload
|
// e.g. 'windowPosition' pref updated in edit.js::window.onbeforeunload
|
||||||
if (!chrome.runtime.lastError) {
|
if (!chrome.runtime.lastError) {
|
||||||
var t = prefs.get("show-badge") && styles.length ? ("" + styles.length) : "";
|
var t = prefs.get("show-badge") && styles.length ? ("" + styles.length) : "";
|
||||||
chrome.browserAction.setBadgeText({text: t, tabId: tab.id});
|
chrome.browserAction.setBadgeText({
|
||||||
chrome.browserAction.setBadgeBackgroundColor({color: disableAll ? "#aaa" : [0, 0, 0, 0]});
|
text: t,
|
||||||
|
tabId: tab.id
|
||||||
|
});
|
||||||
|
chrome.browserAction.setBadgeBackgroundColor({
|
||||||
|
color: disableAll ? "#aaa" : [0, 0, 0, 0]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//console.log("Tab " + tab.id + " (" + tab.url + ") badge text set to '" + t + "'.");
|
//console.log("Tab " + tab.id + " (" + tab.url + ") badge text set to '" + t + "'.");
|
||||||
|
@ -68,7 +88,10 @@ function updateIcon(tab, styles) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveTab(callback) {
|
function getActiveTab(callback) {
|
||||||
chrome.tabs.query({currentWindow: true, active: true}, function(tabs) {
|
chrome.tabs.query({
|
||||||
|
currentWindow: true,
|
||||||
|
active: true
|
||||||
|
}, function (tabs) {
|
||||||
callback(tabs[0]);
|
callback(tabs[0]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -83,7 +106,11 @@ function getTabRealURL(tab, callback) {
|
||||||
if (tab.url != "chrome://newtab/") {
|
if (tab.url != "chrome://newtab/") {
|
||||||
callback(tab.url);
|
callback(tab.url);
|
||||||
} else {
|
} else {
|
||||||
chrome.webNavigation.getFrame({tabId: tab.id, frameId: 0, processId: -1}, function(frame) {
|
chrome.webNavigation.getFrame({
|
||||||
|
tabId: tab.id,
|
||||||
|
frameId: 0,
|
||||||
|
processId: -1
|
||||||
|
}, function (frame) {
|
||||||
frame && callback(frame.url);
|
frame && callback(frame.url);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
62
popup.js
62
popup.js
|
@ -1,3 +1,4 @@
|
||||||
|
/*jshint undef:false*/
|
||||||
var writeStyleTemplate = document.createElement("a");
|
var writeStyleTemplate = document.createElement("a");
|
||||||
writeStyleTemplate.className = "write-style-link";
|
writeStyleTemplate.className = "write-style-link";
|
||||||
|
|
||||||
|
@ -17,7 +18,10 @@ function updatePopUp(url) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
chrome.runtime.sendMessage({method: "getStyles", matchUrl: url}, showStyles);
|
chrome.runtime.sendMessage({
|
||||||
|
method: "getStyles",
|
||||||
|
matchUrl: url
|
||||||
|
}, showStyles);
|
||||||
document.querySelector("#find-styles a").href = "https://userstyles.org/styles/browse/all/" + encodeURIComponent("file" === urlWillWork[1] ? "file:" : url);
|
document.querySelector("#find-styles a").href = "https://userstyles.org/styles/browse/all/" + encodeURIComponent("file" === urlWillWork[1] ? "file:" : url);
|
||||||
|
|
||||||
// Write new style links
|
// Write new style links
|
||||||
|
@ -29,22 +33,28 @@ function updatePopUp(url) {
|
||||||
var urlLink = writeStyleTemplate.cloneNode(true);
|
var urlLink = writeStyleTemplate.cloneNode(true);
|
||||||
urlLink.href = "edit.html?url-prefix=" + encodeURIComponent(url);
|
urlLink.href = "edit.html?url-prefix=" + encodeURIComponent(url);
|
||||||
urlLink.appendChild(document.createTextNode( // switchable; default="this URL"
|
urlLink.appendChild(document.createTextNode( // switchable; default="this URL"
|
||||||
!prefs.get("popup.breadcrumbs.usePath")
|
!prefs.get("popup.breadcrumbs.usePath") ? t("writeStyleForURL").replace(/ /g, "\u00a0") : /\/\/[^/]+\/(.*)/.exec(url)[1]
|
||||||
? t("writeStyleForURL").replace(/ /g, "\u00a0")
|
|
||||||
: /\/\/[^/]+\/(.*)/.exec(url)[1]
|
|
||||||
));
|
));
|
||||||
urlLink.title = "url-prefix(\"$\")".replace("$", url);
|
urlLink.title = "url-prefix(\"$\")".replace("$", url);
|
||||||
writeStyleLinks.push(urlLink);
|
writeStyleLinks.push(urlLink);
|
||||||
document.querySelector("#write-style").appendChild(urlLink)
|
document.querySelector("#write-style").appendChild(urlLink);
|
||||||
if (prefs.get("popup.breadcrumbs")) { // switchable; default=enabled
|
if (prefs.get("popup.breadcrumbs")) { // switchable; default=enabled
|
||||||
urlLink.addEventListener("mouseenter", function(event) { this.parentNode.classList.add("url()") }, false);
|
urlLink.addEventListener("mouseenter", function (event) {
|
||||||
urlLink.addEventListener("focus", function(event) { this.parentNode.classList.add("url()") }, false);
|
this.parentNode.classList.add("url()");
|
||||||
urlLink.addEventListener("mouseleave", function(event) { this.parentNode.classList.remove("url()") }, false);
|
}, false);
|
||||||
urlLink.addEventListener("blur", function(event) { this.parentNode.classList.remove("url()") }, false);
|
urlLink.addEventListener("focus", function (event) {
|
||||||
|
this.parentNode.classList.add("url()");
|
||||||
|
}, false);
|
||||||
|
urlLink.addEventListener("mouseleave", function (event) {
|
||||||
|
this.parentNode.classList.remove("url()");
|
||||||
|
}, false);
|
||||||
|
urlLink.addEventListener("blur", function (event) {
|
||||||
|
this.parentNode.classList.remove("url()");
|
||||||
|
}, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For domain
|
// For domain
|
||||||
var domains = getDomains(url)
|
var domains = getDomains(url);
|
||||||
domains.forEach(function (domain) {
|
domains.forEach(function (domain) {
|
||||||
// Don't include TLD
|
// Don't include TLD
|
||||||
if (domains.length > 1 && domain.indexOf(".") == -1) {
|
if (domains.length > 1 && domain.indexOf(".") == -1) {
|
||||||
|
@ -76,7 +86,7 @@ function showStyles(styles) {
|
||||||
if (enabledFirst && a.enabled !== b.enabled) return !(a.enabled < b.enabled) ? -1 : 1;
|
if (enabledFirst && a.enabled !== b.enabled) return !(a.enabled < b.enabled) ? -1 : 1;
|
||||||
return a.name.localeCompare(b.name);
|
return a.name.localeCompare(b.name);
|
||||||
});
|
});
|
||||||
if (styles.length == 0) {
|
if (styles.length === 0) {
|
||||||
installed.innerHTML = "<div class='entry' id='no-styles'>" + t('noStylesForSite') + "</div>";
|
installed.innerHTML = "<div class='entry' id='no-styles'>" + t('noStylesForSite') + "</div>";
|
||||||
}
|
}
|
||||||
styles.map(createStyleElement).forEach(function (e) {
|
styles.map(createStyleElement).forEach(function (e) {
|
||||||
|
@ -100,13 +110,24 @@ function createStyleElement(style) {
|
||||||
editLink.setAttribute("href", editLink.getAttribute("href") + style.id);
|
editLink.setAttribute("href", editLink.getAttribute("href") + style.id);
|
||||||
editLink.addEventListener("click", openLinkInTabOrWindow, false);
|
editLink.addEventListener("click", openLinkInTabOrWindow, false);
|
||||||
|
|
||||||
styleName.addEventListener("click", function() { this.checkbox.click(); event.preventDefault(); });
|
styleName.addEventListener("click", function () {
|
||||||
|
this.checkbox.click();
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
// clicking the checkbox will toggle it, and this will run after that happens
|
// clicking the checkbox will toggle it, and this will run after that happens
|
||||||
checkbox.addEventListener("click", function() { enable(event, event.target.checked); }, false);
|
checkbox.addEventListener("click", function () {
|
||||||
e.querySelector(".enable").addEventListener("click", function() { enable(event, true); }, false);
|
enable(event, event.target.checked);
|
||||||
e.querySelector(".disable").addEventListener("click", function() { enable(event, false); }, false);
|
}, false);
|
||||||
|
e.querySelector(".enable").addEventListener("click", function () {
|
||||||
|
enable(event, true);
|
||||||
|
}, false);
|
||||||
|
e.querySelector(".disable").addEventListener("click", function () {
|
||||||
|
enable(event, false);
|
||||||
|
}, false);
|
||||||
|
|
||||||
e.querySelector(".delete").addEventListener("click", function() { doDelete(event, false); }, false);
|
e.querySelector(".delete").addEventListener("click", function () {
|
||||||
|
doDelete(event, false);
|
||||||
|
}, false);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +168,9 @@ function getId(event) {
|
||||||
function openLinkInTabOrWindow(event) {
|
function openLinkInTabOrWindow(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (prefs.get("openEditInWindow", false)) {
|
if (prefs.get("openEditInWindow", false)) {
|
||||||
var options = {url: event.target.href}
|
var options = {
|
||||||
|
url: event.target.href
|
||||||
|
};
|
||||||
var wp = prefs.get("windowPosition", {});
|
var wp = prefs.get("windowPosition", {});
|
||||||
for (var k in wp) options[k] = wp[k];
|
for (var k in wp) options[k] = wp[k];
|
||||||
chrome.windows.create(options);
|
chrome.windows.create(options);
|
||||||
|
@ -159,7 +182,10 @@ function openLinkInTabOrWindow(event) {
|
||||||
|
|
||||||
function openLink(event) {
|
function openLink(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
chrome.runtime.sendMessage({method: "openURL", url: event.target.href});
|
chrome.runtime.sendMessage({
|
||||||
|
method: "openURL",
|
||||||
|
url: event.target.href
|
||||||
|
});
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/*jshint undef:false*/
|
||||||
var webSqlStorage = {
|
var webSqlStorage = {
|
||||||
|
|
||||||
migrate: function () {
|
migrate: function () {
|
||||||
|
@ -10,7 +11,7 @@ var webSqlStorage = {
|
||||||
var tx = db.transaction(["styles"], "readwrite");
|
var tx = db.transaction(["styles"], "readwrite");
|
||||||
var os = tx.objectStore("styles");
|
var os = tx.objectStore("styles");
|
||||||
styles.forEach(function (s) {
|
styles.forEach(function (s) {
|
||||||
webSqlStorage.cleanStyle(s)
|
webSqlStorage.cleanStyle(s);
|
||||||
os.add(s);
|
os.add(s);
|
||||||
});
|
});
|
||||||
// While this was running, the styles were loaded from the (empty) indexed db
|
// While this was running, the styles were loaded from the (empty) indexed db
|
||||||
|
@ -44,12 +45,13 @@ var webSqlStorage = {
|
||||||
var params = [];
|
var params = [];
|
||||||
|
|
||||||
t.executeSql('SELECT DISTINCT s.*, se.id section_id, se.code, sm.name metaName, sm.value metaValue FROM styles s LEFT JOIN sections se ON se.style_id = s.id LEFT JOIN section_meta sm ON sm.section_id = se.id WHERE 1' + where + ' ORDER BY s.id, se.id, sm.id', params, function (t, r) {
|
t.executeSql('SELECT DISTINCT s.*, se.id section_id, se.code, sm.name metaName, sm.value metaValue FROM styles s LEFT JOIN sections se ON se.style_id = s.id LEFT JOIN section_meta sm ON sm.section_id = se.id WHERE 1' + where + ' ORDER BY s.id, se.id, sm.id', params, function (t, r) {
|
||||||
var styles = [];
|
var styles = [],
|
||||||
var currentStyle = null;
|
currentStyle = null,
|
||||||
var currentSection = null;
|
currentSection = null,
|
||||||
|
metaName;
|
||||||
for (var i = 0; i < r.rows.length; i++) {
|
for (var i = 0; i < r.rows.length; i++) {
|
||||||
var values = r.rows.item(i);
|
var values = r.rows.item(i);
|
||||||
var metaName = null;
|
metaName = null;
|
||||||
switch (values.metaName) {
|
switch (values.metaName) {
|
||||||
case null:
|
case null:
|
||||||
break;
|
break;
|
||||||
|
@ -60,22 +62,34 @@ var webSqlStorage = {
|
||||||
metaName = "urlPrefixes";
|
metaName = "urlPrefixes";
|
||||||
break;
|
break;
|
||||||
case "domain":
|
case "domain":
|
||||||
var metaName = "domains";
|
metaName = "domains";
|
||||||
break;
|
break;
|
||||||
case "regexps":
|
case "regexps":
|
||||||
var metaName = "regexps";
|
metaName = "regexps";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
var metaName = values.metaName + "s";
|
metaName = values.metaName + "s";
|
||||||
}
|
}
|
||||||
var metaValue = values.metaValue;
|
var metaValue = values.metaValue;
|
||||||
if (currentStyle == null || currentStyle.id != values.id) {
|
if (currentStyle === null || currentStyle.id != values.id) {
|
||||||
currentStyle = {id: values.id, url: values.url, updateUrl: values.updateUrl, md5Url: values.md5Url, name: values.name, enabled: values.enabled == "true", originalMd5: values.originalMd5, sections: []};
|
currentStyle = {
|
||||||
|
id: values.id,
|
||||||
|
url: values.url,
|
||||||
|
updateUrl: values.updateUrl,
|
||||||
|
md5Url: values.md5Url,
|
||||||
|
name: values.name,
|
||||||
|
enabled: values.enabled == "true",
|
||||||
|
originalMd5: values.originalMd5,
|
||||||
|
sections: []
|
||||||
|
};
|
||||||
styles.push(currentStyle);
|
styles.push(currentStyle);
|
||||||
}
|
}
|
||||||
if (values.section_id != null) {
|
if (values.section_id !== null) {
|
||||||
if (currentSection == null || currentSection.id != values.section_id) {
|
if (currentSection === null || currentSection.id != values.section_id) {
|
||||||
currentSection = {id: values.section_id, code: values.code};
|
currentSection = {
|
||||||
|
id: values.section_id,
|
||||||
|
code: values.code
|
||||||
|
};
|
||||||
currentStyle.sections.push(currentSection);
|
currentStyle.sections.push(currentSection);
|
||||||
}
|
}
|
||||||
if (metaName && metaValue) {
|
if (metaName && metaValue) {
|
||||||
|
@ -100,7 +114,7 @@ var webSqlStorage = {
|
||||||
error();
|
error();
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
if (stylishDb.version == "") {
|
if (stylishDb.version === "") {
|
||||||
// It didn't already exist, we have nothing to migrate.
|
// It didn't already exist, we have nothing to migrate.
|
||||||
ready(null);
|
ready(null);
|
||||||
return;
|
return;
|
||||||
|
@ -125,7 +139,9 @@ var webSqlStorage = {
|
||||||
t.executeSql('CREATE TABLE styles (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, url TEXT, updateUrl TEXT, md5Url TEXT, name TEXT NOT NULL, code TEXT NOT NULL, enabled INTEGER NOT NULL, originalCode TEXT NULL);');
|
t.executeSql('CREATE TABLE styles (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, url TEXT, updateUrl TEXT, md5Url TEXT, name TEXT NOT NULL, code TEXT NOT NULL, enabled INTEGER NOT NULL, originalCode TEXT NULL);');
|
||||||
t.executeSql('CREATE TABLE style_meta (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, style_id INTEGER NOT NULL, name TEXT NOT NULL, value TEXT NOT NULL);');
|
t.executeSql('CREATE TABLE style_meta (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, style_id INTEGER NOT NULL, name TEXT NOT NULL, value TEXT NOT NULL);');
|
||||||
t.executeSql('CREATE INDEX style_meta_style_id ON style_meta (style_id);');
|
t.executeSql('CREATE INDEX style_meta_style_id ON style_meta (style_id);');
|
||||||
}, error, function() { webSqlStorage.dbV12(d, error, done)});
|
}, error, function () {
|
||||||
|
webSqlStorage.dbV12(d, error, done);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
dbV12: function (d, error, done) {
|
dbV12: function (d, error, done) {
|
||||||
|
@ -144,7 +160,9 @@ var webSqlStorage = {
|
||||||
t.executeSql('INSERT INTO newstyles (id, url, updateUrl, md5Url, name, enabled) SELECT id, url, updateUrl, md5Url, name, enabled FROM styles;');
|
t.executeSql('INSERT INTO newstyles (id, url, updateUrl, md5Url, name, enabled) SELECT id, url, updateUrl, md5Url, name, enabled FROM styles;');
|
||||||
t.executeSql('DROP TABLE styles;');
|
t.executeSql('DROP TABLE styles;');
|
||||||
t.executeSql('ALTER TABLE newstyles RENAME TO styles;');
|
t.executeSql('ALTER TABLE newstyles RENAME TO styles;');
|
||||||
}, error, function() { webSqlStorage.dbV13(d, error, done)});
|
}, error, function () {
|
||||||
|
webSqlStorage.dbV13(d, error, done);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
dbV13: function (d, error, done) {
|
dbV13: function (d, error, done) {
|
||||||
|
@ -152,18 +170,24 @@ var webSqlStorage = {
|
||||||
// clear out orphans
|
// clear out orphans
|
||||||
t.executeSql('DELETE FROM section_meta WHERE section_id IN (SELECT sections.id FROM sections LEFT JOIN styles ON styles.id = sections.style_id WHERE styles.id IS NULL);');
|
t.executeSql('DELETE FROM section_meta WHERE section_id IN (SELECT sections.id FROM sections LEFT JOIN styles ON styles.id = sections.style_id WHERE styles.id IS NULL);');
|
||||||
t.executeSql('DELETE FROM sections WHERE id IN (SELECT sections.id FROM sections LEFT JOIN styles ON styles.id = sections.style_id WHERE styles.id IS NULL);');
|
t.executeSql('DELETE FROM sections WHERE id IN (SELECT sections.id FROM sections LEFT JOIN styles ON styles.id = sections.style_id WHERE styles.id IS NULL);');
|
||||||
}, error, function() { webSqlStorage.dbV14(d, error, done)});
|
}, error, function () {
|
||||||
|
webSqlStorage.dbV14(d, error, done);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
dbV14: function (d, error, done) {
|
dbV14: function (d, error, done) {
|
||||||
d.changeVersion(d.version, '1.4', function (t) {
|
d.changeVersion(d.version, '1.4', function (t) {
|
||||||
t.executeSql('UPDATE styles SET url = null WHERE url = "undefined";');
|
t.executeSql('UPDATE styles SET url = null WHERE url = "undefined";');
|
||||||
}, error, function() { webSqlStorage.dbV15(d, error, done)});
|
}, error, function () {
|
||||||
|
webSqlStorage.dbV15(d, error, done);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
dbV15: function (d, error, done) {
|
dbV15: function (d, error, done) {
|
||||||
d.changeVersion(d.version, '1.5', function (t) {
|
d.changeVersion(d.version, '1.5', function (t) {
|
||||||
t.executeSql('ALTER TABLE styles ADD COLUMN originalMd5 TEXT NULL;');
|
t.executeSql('ALTER TABLE styles ADD COLUMN originalMd5 TEXT NULL;');
|
||||||
}, error, function() { done(d); });
|
}, error, function () {
|
||||||
}
|
done(d);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
};
|
177
storage.js
177
storage.js
|
@ -1,3 +1,4 @@
|
||||||
|
/*jshint undef:false*/
|
||||||
function getDatabase(ready, error) {
|
function getDatabase(ready, error) {
|
||||||
var dbOpenRequest = window.indexedDB.open("stylish", 2);
|
var dbOpenRequest = window.indexedDB.open("stylish", 2);
|
||||||
dbOpenRequest.onsuccess = function (e) {
|
dbOpenRequest.onsuccess = function (e) {
|
||||||
|
@ -10,16 +11,21 @@ function getDatabase(ready, error) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
dbOpenRequest.onupgradeneeded = function (event) {
|
dbOpenRequest.onupgradeneeded = function (event) {
|
||||||
if (event.oldVersion == 0) {
|
if (event.oldVersion === 0) {
|
||||||
var os = event.target.result.createObjectStore("styles", {keyPath: 'id', autoIncrement: true});
|
var os = event.target.result.createObjectStore("styles", {
|
||||||
|
keyPath: 'id',
|
||||||
|
autoIncrement: true
|
||||||
|
});
|
||||||
webSqlStorage.migrate();
|
webSqlStorage.migrate();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var cachedStyles = null,
|
||||||
|
request;
|
||||||
|
|
||||||
var cachedStyles = null;
|
|
||||||
function getStyles(options, callback) {
|
function getStyles(options, callback) {
|
||||||
if (cachedStyles != null) {
|
if (cachedStyles !== null) {
|
||||||
callback(filterStyles(cachedStyles, options));
|
callback(filterStyles(cachedStyles, options));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -30,8 +36,8 @@ function getStyles(options, callback) {
|
||||||
os.openCursor().onsuccess = function (event) {
|
os.openCursor().onsuccess = function (event) {
|
||||||
var cursor = event.target.result;
|
var cursor = event.target.result;
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
var s = cursor.value
|
var s = cursor.value;
|
||||||
s.id = cursor.key
|
s.id = cursor.key;
|
||||||
all.push(cursor.value);
|
all.push(cursor.value);
|
||||||
cursor.continue();
|
cursor.continue();
|
||||||
} else {
|
} else {
|
||||||
|
@ -45,7 +51,9 @@ function getStyles(options, callback) {
|
||||||
function invalidateCache(andNotify) {
|
function invalidateCache(andNotify) {
|
||||||
cachedStyles = null;
|
cachedStyles = null;
|
||||||
if (andNotify) {
|
if (andNotify) {
|
||||||
chrome.runtime.sendMessage({method: "invalidateCache"});
|
chrome.runtime.sendMessage({
|
||||||
|
method: "invalidateCache"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,26 +63,28 @@ function filterStyles(styles, options) {
|
||||||
var id = "id" in options ? Number(options.id) : null;
|
var id = "id" in options ? Number(options.id) : null;
|
||||||
var matchUrl = "matchUrl" in options ? options.matchUrl : null;
|
var matchUrl = "matchUrl" in options ? options.matchUrl : null;
|
||||||
|
|
||||||
if (enabled != null) {
|
if (enabled !== null) {
|
||||||
styles = styles.filter(function (style) {
|
styles = styles.filter(function (style) {
|
||||||
return style.enabled == enabled;
|
return style.enabled == enabled;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (url != null) {
|
if (url !== null) {
|
||||||
styles = styles.filter(function (style) {
|
styles = styles.filter(function (style) {
|
||||||
return style.url == url;
|
return style.url == url;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (id != null) {
|
if (id !== null) {
|
||||||
styles = styles.filter(function (style) {
|
styles = styles.filter(function (style) {
|
||||||
return style.id == id;
|
return style.id == id;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (matchUrl != null) {
|
if (matchUrl !== null) {
|
||||||
// Return as a hash from style to applicable sections? Can only be used with matchUrl.
|
// Return as a hash from style to applicable sections? Can only be used with matchUrl.
|
||||||
var asHash = "asHash" in options ? options.asHash : false;
|
var asHash = "asHash" in options ? options.asHash : false;
|
||||||
if (asHash) {
|
if (asHash) {
|
||||||
var h = {disableAll: prefs.get("disableAll", false)};
|
var h = {
|
||||||
|
disableAll: prefs.get("disableAll", false)
|
||||||
|
};
|
||||||
styles.forEach(function (style) {
|
styles.forEach(function (style) {
|
||||||
var applicableSections = getApplicableSections(style, matchUrl);
|
var applicableSections = getApplicableSections(style, matchUrl);
|
||||||
if (applicableSections.length > 0) {
|
if (applicableSections.length > 0) {
|
||||||
|
@ -98,7 +108,7 @@ function saveStyle(o, callback) {
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
if (o.id) {
|
if (o.id) {
|
||||||
var request = os.get(Number(o.id));
|
request = os.get(Number(o.id));
|
||||||
request.onsuccess = function (event) {
|
request.onsuccess = function (event) {
|
||||||
var style = request.result;
|
var style = request.result;
|
||||||
for (var prop in o) {
|
for (var prop in o) {
|
||||||
|
@ -109,7 +119,10 @@ function saveStyle(o, callback) {
|
||||||
}
|
}
|
||||||
request = os.put(style);
|
request = os.put(style);
|
||||||
request.onsuccess = function (event) {
|
request.onsuccess = function (event) {
|
||||||
notifyAllTabs({method: "styleUpdated", style: style});
|
notifyAllTabs({
|
||||||
|
method: "styleUpdated",
|
||||||
|
style: style
|
||||||
|
});
|
||||||
invalidateCache(true);
|
invalidateCache(true);
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback(style);
|
callback(style);
|
||||||
|
@ -139,13 +152,16 @@ function saveStyle(o, callback) {
|
||||||
o.enabled = true;
|
o.enabled = true;
|
||||||
}
|
}
|
||||||
// Make sure it's not null - that makes indexeddb sad
|
// Make sure it's not null - that makes indexeddb sad
|
||||||
delete o["id"];
|
delete o.id;
|
||||||
var request = os.add(o);
|
request = os.add(o);
|
||||||
request.onsuccess = function (event) {
|
request.onsuccess = function (event) {
|
||||||
invalidateCache(true);
|
invalidateCache(true);
|
||||||
// Give it the ID that was generated
|
// Give it the ID that was generated
|
||||||
o.id = event.target.result;
|
o.id = event.target.result;
|
||||||
notifyAllTabs({method: "styleAdded", style: o});
|
notifyAllTabs({
|
||||||
|
method: "styleAdded",
|
||||||
|
style: o
|
||||||
|
});
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback(o);
|
callback(o);
|
||||||
}
|
}
|
||||||
|
@ -154,9 +170,15 @@ function saveStyle(o, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function enableStyle(id, enabled) {
|
function enableStyle(id, enabled) {
|
||||||
saveStyle({id: id, enabled: enabled}, function(style) {
|
saveStyle({
|
||||||
|
id: id,
|
||||||
|
enabled: enabled
|
||||||
|
}, function (style) {
|
||||||
handleUpdate(style);
|
handleUpdate(style);
|
||||||
notifyAllTabs({method: "styleUpdated", style: style});
|
notifyAllTabs({
|
||||||
|
method: "styleUpdated",
|
||||||
|
style: style
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,16 +186,20 @@ function deleteStyle(id) {
|
||||||
getDatabase(function (db) {
|
getDatabase(function (db) {
|
||||||
var tx = db.transaction(["styles"], "readwrite");
|
var tx = db.transaction(["styles"], "readwrite");
|
||||||
var os = tx.objectStore("styles");
|
var os = tx.objectStore("styles");
|
||||||
var request = os.delete(Number(id));
|
request = os.delete(Number(id));
|
||||||
request.onsuccess = function (event) {
|
request.onsuccess = function (event) {
|
||||||
handleDelete(id);
|
handleDelete(id);
|
||||||
invalidateCache(true);
|
invalidateCache(true);
|
||||||
notifyAllTabs({method: "styleDeleted", id: id});
|
notifyAllTabs({
|
||||||
|
method: "styleDeleted",
|
||||||
|
id: id
|
||||||
|
});
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function reportError() {
|
function reportError() {
|
||||||
|
var i;
|
||||||
for (i in arguments) {
|
for (i in arguments) {
|
||||||
if ("message" in arguments[i]) {
|
if ("message" in arguments[i]) {
|
||||||
//alert(arguments[i].message);
|
//alert(arguments[i].message);
|
||||||
|
@ -190,7 +216,7 @@ function fixBoolean(b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDomains(url) {
|
function getDomains(url) {
|
||||||
if (url.indexOf("file:") == 0) {
|
if (url.indexOf("file:") === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
var d = /.*?:\/*([^\/:]+)/.exec(url)[1];
|
var d = /.*?:\/*([^\/:]+)/.exec(url)[1];
|
||||||
|
@ -213,6 +239,7 @@ function getType(o) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var namespacePattern = /^\s*(@namespace[^;]+;\s*)+$/;
|
var namespacePattern = /^\s*(@namespace[^;]+;\s*)+$/;
|
||||||
|
|
||||||
function getApplicableSections(style, url) {
|
function getApplicableSections(style, url) {
|
||||||
var sections = style.sections.filter(function (section) {
|
var sections = style.sections.filter(function (section) {
|
||||||
return sectionAppliesToUrl(section, url);
|
return sectionAppliesToUrl(section, url);
|
||||||
|
@ -226,14 +253,14 @@ function getApplicableSections(style, url) {
|
||||||
|
|
||||||
function sectionAppliesToUrl(section, url) {
|
function sectionAppliesToUrl(section, url) {
|
||||||
// only http, https, file, and chrome-extension allowed
|
// only http, https, file, and chrome-extension allowed
|
||||||
if (url.indexOf("http") != 0 && url.indexOf("file") != 0 && url.indexOf("chrome-extension") != 0 && url.indexOf("ftp") != 0) {
|
if (url.indexOf("http") !== 0 && url.indexOf("file") !== 0 && url.indexOf("chrome-extension") !== 0 && url.indexOf("ftp") !== 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// other extensions can't be styled
|
// other extensions can't be styled
|
||||||
if (url.indexOf("chrome-extension") == 0 && url.indexOf(chrome.extension.getURL("")) != 0) {
|
if (url.indexOf("chrome-extension") === 0 && url.indexOf(chrome.extension.getURL("")) !== 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (section.urls.length == 0 && section.domains.length == 0 && section.urlPrefixes.length == 0 && section.regexps.length == 0) {
|
if (section.urls.length === 0 && section.domains.length === 0 && section.urlPrefixes.length === 0 && section.regexps.length === 0) {
|
||||||
//console.log(section.id + " is global");
|
//console.log(section.id + " is global");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -242,7 +269,7 @@ function sectionAppliesToUrl(section, url) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (section.urlPrefixes.some(function (prefix) {
|
if (section.urlPrefixes.some(function (prefix) {
|
||||||
return url.indexOf(prefix) == 0;
|
return url.indexOf(prefix) === 0;
|
||||||
})) {
|
})) {
|
||||||
//console.log(section.id + " applies to " + url + " due to URL prefix rules");
|
//console.log(section.id + " applies to " + url + " due to URL prefix rules");
|
||||||
return true;
|
return true;
|
||||||
|
@ -261,7 +288,9 @@ function sectionAppliesToUrl(section, url) {
|
||||||
if (regexp[regexp.length - 1] != "$") {
|
if (regexp[regexp.length - 1] != "$") {
|
||||||
regexp += "$";
|
regexp += "$";
|
||||||
}
|
}
|
||||||
var re = runTryCatch(function() { return new RegExp(regexp) });
|
var re = runTryCatch(function () {
|
||||||
|
return new RegExp(regexp);
|
||||||
|
});
|
||||||
if (re) {
|
if (re) {
|
||||||
return (re).test(url);
|
return (re).test(url);
|
||||||
} else {
|
} else {
|
||||||
|
@ -282,8 +311,9 @@ function isCheckbox(el) {
|
||||||
// js engine can't optimize the entire function if it contains try-catch
|
// js engine can't optimize the entire function if it contains try-catch
|
||||||
// so we should keep it isolated from normal code in a minimal wrapper
|
// so we should keep it isolated from normal code in a minimal wrapper
|
||||||
function runTryCatch(func) {
|
function runTryCatch(func) {
|
||||||
try { return func() }
|
try {
|
||||||
catch(e) {}
|
return func();
|
||||||
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accepts an array of pref names (values are fetched via prefs.get)
|
// Accepts an array of pref names (values are fetched via prefs.get)
|
||||||
|
@ -301,10 +331,14 @@ function setupLivePrefs(IDs) {
|
||||||
updateElement(request.prefName);
|
updateElement(request.prefName);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function updateElement(id) {
|
function updateElement(id) {
|
||||||
var el = document.getElementById(id);
|
var el = document.getElementById(id);
|
||||||
el[isCheckbox(el) ? "checked" : "value"] = prefs.get(id);
|
el[isCheckbox(el) ? "checked" : "value"] = prefs.get(id);
|
||||||
el.dispatchEvent(new Event("change", {bubbles: true, cancelable: true}));
|
el.dispatchEvent(new Event("change", {
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true
|
||||||
|
}));
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,7 +383,9 @@ var prefs = chrome.extension.getBackgroundPage().prefs || new function Prefs() {
|
||||||
|
|
||||||
var syncTimeout; // see broadcast() function below
|
var syncTimeout; // see broadcast() function below
|
||||||
|
|
||||||
Object.defineProperty(this, "readOnlyValues", {value: {}});
|
Object.defineProperty(this, "readOnlyValues", {
|
||||||
|
value: {}
|
||||||
|
});
|
||||||
|
|
||||||
Prefs.prototype.get = function (key, defaultValue) {
|
Prefs.prototype.get = function (key, defaultValue) {
|
||||||
if (key in values) {
|
if (key in values) {
|
||||||
|
@ -377,32 +413,47 @@ var prefs = chrome.extension.getBackgroundPage().prefs || new function Prefs() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Prefs.prototype.remove = function(key) { me.set(key, undefined) };
|
Prefs.prototype.remove = function (key) {
|
||||||
|
me.set(key, undefined);
|
||||||
|
};
|
||||||
|
|
||||||
Prefs.prototype.broadcast = function (key, value, options) {
|
Prefs.prototype.broadcast = function (key, value, options) {
|
||||||
var message = {method: "prefChanged", prefName: key, value: value};
|
var message = {
|
||||||
|
method: "prefChanged",
|
||||||
|
prefName: key,
|
||||||
|
value: value
|
||||||
|
};
|
||||||
notifyAllTabs(message);
|
notifyAllTabs(message);
|
||||||
chrome.runtime.sendMessage(message);
|
chrome.runtime.sendMessage(message);
|
||||||
if (key == "disableAll") {
|
if (key == "disableAll") {
|
||||||
notifyAllTabs({method: "styleDisableAll", disableAll: value});
|
notifyAllTabs({
|
||||||
|
method: "styleDisableAll",
|
||||||
|
disableAll: value
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (!options || !options.noSync) {
|
if (!options || !options.noSync) {
|
||||||
clearTimeout(syncTimeout);
|
clearTimeout(syncTimeout);
|
||||||
syncTimeout = setTimeout(function () {
|
syncTimeout = setTimeout(function () {
|
||||||
getSync().set({"settings": values});
|
getSync().set({
|
||||||
|
"settings": values
|
||||||
|
});
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.keys(defaults).forEach(function (key) {
|
Object.keys(defaults).forEach(function (key) {
|
||||||
me.set(key, defaults[key], {noBroadcast: true});
|
me.set(key, defaults[key], {
|
||||||
|
noBroadcast: true
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
getSync().get("settings", function (result) {
|
getSync().get("settings", function (result) {
|
||||||
var synced = result.settings;
|
var synced = result.settings;
|
||||||
for (var key in defaults) {
|
for (var key in defaults) {
|
||||||
if (synced && (key in synced)) {
|
if (synced && (key in synced)) {
|
||||||
me.set(key, synced[key], {noSync: true});
|
me.set(key, synced[key], {
|
||||||
|
noSync: true
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
var value = tryMigrating(key);
|
var value = tryMigrating(key);
|
||||||
if (value !== undefined) {
|
if (value !== undefined) {
|
||||||
|
@ -414,16 +465,21 @@ var prefs = chrome.extension.getBackgroundPage().prefs || new function Prefs() {
|
||||||
|
|
||||||
chrome.storage.onChanged.addListener(function (changes, area) {
|
chrome.storage.onChanged.addListener(function (changes, area) {
|
||||||
if (area == "sync" && "settings" in changes) {
|
if (area == "sync" && "settings" in changes) {
|
||||||
var synced = changes.settings.newValue;
|
var synced = changes.settings.newValue,
|
||||||
|
key;
|
||||||
if (synced) {
|
if (synced) {
|
||||||
for (key in defaults) {
|
for (key in defaults) {
|
||||||
if (key in synced) {
|
if (key in synced) {
|
||||||
me.set(key, synced[key], {noSync: true});
|
me.set(key, synced[key], {
|
||||||
|
noSync: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// user manually deleted our settings, we'll recreate them
|
// user manually deleted our settings, we'll recreate them
|
||||||
getSync().set({"settings": values});
|
getSync().set({
|
||||||
|
"settings": values
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -450,16 +506,22 @@ var prefs = chrome.extension.getBackgroundPage().prefs || new function Prefs() {
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
};
|
}();
|
||||||
|
|
||||||
function getCodeMirrorThemes(callback) {
|
function getCodeMirrorThemes(callback) {
|
||||||
chrome.runtime.getPackageDirectoryEntry(function (rootDir) {
|
chrome.runtime.getPackageDirectoryEntry(function (rootDir) {
|
||||||
rootDir.getDirectory("codemirror/theme", {create: false}, function(themeDir) {
|
rootDir.getDirectory("codemirror/theme", {
|
||||||
|
create: false
|
||||||
|
}, function (themeDir) {
|
||||||
themeDir.createReader().readEntries(function (entries) {
|
themeDir.createReader().readEntries(function (entries) {
|
||||||
var themes = [chrome.i18n.getMessage("defaultTheme")];
|
var themes = [chrome.i18n.getMessage("defaultTheme")];
|
||||||
entries
|
entries
|
||||||
.filter(function(entry) { return entry.isFile })
|
.filter(function (entry) {
|
||||||
.sort(function(a, b) { return a.name < b.name ? -1 : 1 })
|
return entry.isFile;
|
||||||
|
})
|
||||||
|
.sort(function (a, b) {
|
||||||
|
return a.name < b.name ? -1 : 1;
|
||||||
|
})
|
||||||
.forEach(function (entry) {
|
.forEach(function (entry) {
|
||||||
themes.push(entry.name.replace(/\.css$/, ""));
|
themes.push(entry.name.replace(/\.css$/, ""));
|
||||||
});
|
});
|
||||||
|
@ -474,14 +536,24 @@ function getCodeMirrorThemes(callback) {
|
||||||
function sessionStorageHash(name) {
|
function sessionStorageHash(name) {
|
||||||
var hash = {
|
var hash = {
|
||||||
value: {},
|
value: {},
|
||||||
set: function(k, v) { this.value[k] = v; this.updateStorage(); },
|
set: function (k, v) {
|
||||||
unset: function(k) { delete this.value[k]; this.updateStorage(); },
|
this.value[k] = v;
|
||||||
|
this.updateStorage();
|
||||||
|
},
|
||||||
|
unset: function (k) {
|
||||||
|
delete this.value[k];
|
||||||
|
this.updateStorage();
|
||||||
|
},
|
||||||
updateStorage: function () {
|
updateStorage: function () {
|
||||||
sessionStorage[this.name] = JSON.stringify(this.value);
|
sessionStorage[this.name] = JSON.stringify(this.value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
try { hash.value = JSON.parse(sessionStorage[name]); } catch(e) {}
|
try {
|
||||||
Object.defineProperty(hash, "name", {value: name});
|
hash.value = JSON.parse(sessionStorage[name]);
|
||||||
|
} catch (e) {}
|
||||||
|
Object.defineProperty(hash, "name", {
|
||||||
|
value: name
|
||||||
|
});
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -544,7 +616,10 @@ function defineReadonlyProperty(obj, key, value) {
|
||||||
if (typeof copy == "object") {
|
if (typeof copy == "object") {
|
||||||
Object.freeze(copy);
|
Object.freeze(copy);
|
||||||
}
|
}
|
||||||
Object.defineProperty(obj, key, {value: copy, configurable: true})
|
Object.defineProperty(obj, key, {
|
||||||
|
value: copy,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Polyfill, can be removed when Firefox gets this - https://bugzilla.mozilla.org/show_bug.cgi?id=1220494
|
// Polyfill, can be removed when Firefox gets this - https://bugzilla.mozilla.org/show_bug.cgi?id=1220494
|
||||||
|
@ -565,5 +640,5 @@ function getSync() {
|
||||||
}
|
}
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user