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