Fix linting problems and more readable code
This commit is contained in:
parent
970d48b17a
commit
560f5b666e
73
apply.js
73
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
|
||||
|
@ -22,8 +28,20 @@ function requestStyles() {
|
|||
chrome.runtime.sendMessage(request, applyStyles);
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
|
@ -69,12 +85,12 @@ function disableAll(disable) {
|
|||
}
|
||||
|
||||
function disableSheets(disable, doc) {
|
||||
Array.prototype.forEach.call(doc.styleSheets, function(stylesheet) {
|
||||
Array.prototype.forEach.call(doc.styleSheets, function (stylesheet) {
|
||||
if (stylesheet.ownerNode.classList.contains("stylish")) {
|
||||
stylesheet.disabled = disable;
|
||||
}
|
||||
});
|
||||
getDynamicIFrames(doc).forEach(function(iframe) {
|
||||
getDynamicIFrames(doc).forEach(function (iframe) {
|
||||
if (!disable) {
|
||||
// update the IFRAME if it was created while the observer was disconnected
|
||||
addDocumentStylesToIFrame(iframe);
|
||||
|
@ -90,10 +106,10 @@ 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) {
|
||||
getDynamicIFrames(doc).forEach(function (iframe) {
|
||||
removeStyle(id, iframe.contentDocument);
|
||||
});
|
||||
}
|
||||
|
@ -114,7 +130,7 @@ function retireStyle(id, doc) {
|
|||
if (e) {
|
||||
e.id = "stylish-" + deadID;
|
||||
}
|
||||
getDynamicIFrames(doc).forEach(function(iframe) {
|
||||
getDynamicIFrames(doc).forEach(function (iframe) {
|
||||
retireStyle(id, iframe.contentDocument);
|
||||
});
|
||||
}
|
||||
|
@ -142,14 +158,14 @@ function applyStyles(styleHash) {
|
|||
document.head.appendChild(document.getElementById(id));
|
||||
}
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
addDocumentStylesToAllIFrames();
|
||||
iframeObserver.start();
|
||||
});
|
||||
}
|
||||
|
||||
if (retiredStyleIds.length) {
|
||||
setTimeout(function() {
|
||||
setTimeout(function () {
|
||||
while (retiredStyleIds.length) {
|
||||
removeStyle(retiredStyleIds.shift(), document);
|
||||
}
|
||||
|
@ -173,7 +189,7 @@ function applySections(styleId, sections) {
|
|||
styleElement.setAttribute("id", "stylish-" + styleId);
|
||||
styleElement.setAttribute("class", "stylish");
|
||||
styleElement.setAttribute("type", "text/css");
|
||||
styleElement.appendChild(document.createTextNode(sections.map(function(section) {
|
||||
styleElement.appendChild(document.createTextNode(sections.map(function (section) {
|
||||
return section.code;
|
||||
}).join("\n")));
|
||||
addStyleElement(styleElement, document);
|
||||
|
@ -186,7 +202,7 @@ function addStyleElement(styleElement, doc) {
|
|||
}
|
||||
doc.documentElement.appendChild(doc.importNode(styleElement, true))
|
||||
.disabled = g_disableAll;
|
||||
getDynamicIFrames(doc).forEach(function(iframe) {
|
||||
getDynamicIFrames(doc).forEach(function (iframe) {
|
||||
if (iframeIsLoadingSrcDoc(iframe)) {
|
||||
addStyleToIFrameSrcDoc(iframe, styleElement);
|
||||
} else {
|
||||
|
@ -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,9 +260,11 @@ 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) {
|
||||
getDynamicIFrames(doc).forEach(function (iframe) {
|
||||
replaceAll(newStyles, iframe.contentDocument, pass2);
|
||||
});
|
||||
if (doc == document && !pass2) {
|
||||
|
@ -255,13 +273,15 @@ function replaceAll(newStyles, doc, pass2) {
|
|||
replaceAll(newStyles, doc, true);
|
||||
}
|
||||
if (pass2) {
|
||||
oldStyles.forEach(function(style) { style.remove(); });
|
||||
oldStyles.forEach(function (style) {
|
||||
style.remove();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Observe dynamic IFRAMEs being added
|
||||
function initObserver() {
|
||||
iframeObserver = new MutationObserver(function(mutations) {
|
||||
iframeObserver = new MutationObserver(function (mutations) {
|
||||
if (mutations.length > 1000) {
|
||||
// use a much faster method for very complex pages with 100,000 mutations
|
||||
// (observer usually receives 1k-10k mutations per call)
|
||||
|
@ -288,8 +308,11 @@ function initObserver() {
|
|||
}
|
||||
}
|
||||
|
||||
iframeObserver.start = function() {
|
||||
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
|
||||
});
|
||||
};
|
||||
}
|
124
background.js
124
background.js
|
@ -1,6 +1,9 @@
|
|||
/*jshint undef:false*/
|
||||
var frameIdMessageable;
|
||||
runTryCatch(function() {
|
||||
chrome.tabs.sendMessage(0, {}, {frameId: 0}, function() {
|
||||
runTryCatch(function () {
|
||||
chrome.tabs.sendMessage(0, {}, {
|
||||
frameId: 0
|
||||
}, function () {
|
||||
var clearError = chrome.runtime.lastError;
|
||||
frameIdMessageable = true;
|
||||
});
|
||||
|
@ -14,28 +17,41 @@ 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// catch direct URL hash modifications not invoked via HTML5 history API
|
||||
var tabUrlHasHash = {};
|
||||
chrome.tabs.onUpdated.addListener(function(tabId, info, tab) {
|
||||
chrome.tabs.onUpdated.addListener(function (tabId, info, tab) {
|
||||
if (info.status == "loading" && info.url) {
|
||||
if (info.url.indexOf('#') > 0) {
|
||||
tabUrlHasHash[tabId] = true;
|
||||
|
@ -45,21 +61,23 @@ 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) {
|
||||
chrome.tabs.onRemoved.addListener(function (tabId, info) {
|
||||
delete tabUrlHasHash[tabId];
|
||||
});
|
||||
|
||||
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
|
||||
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
||||
switch (request.method) {
|
||||
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;
|
||||
}
|
||||
|
@ -91,14 +117,18 @@ chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
|
|||
|
||||
// Not available in Firefox - https://bugzilla.mozilla.org/show_bug.cgi?id=1240350
|
||||
if ("commands" in chrome) {
|
||||
chrome.commands.onCommand.addListener(function(command) {
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
@ -106,18 +136,28 @@ if ("commands" in chrome) {
|
|||
|
||||
// contextMenus API is present in ancient Chrome but it throws an exception
|
||||
// upon encountering the unsupported parameter value "browser_action", so we have to catch it.
|
||||
runTryCatch(function() {
|
||||
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) {
|
||||
chrome.contextMenus.onClicked.addListener(function (info, tab) {
|
||||
if (info.menuItemId == "disableAll") {
|
||||
disableAllStylesToggle(info.checked);
|
||||
} else {
|
||||
|
@ -133,14 +173,16 @@ function disableAllStylesToggle(newState) {
|
|||
}
|
||||
|
||||
// Get the DB so that any first run actions will be performed immediately when the background page loads.
|
||||
getDatabase(function() {}, reportError);
|
||||
getDatabase(function () {}, reportError);
|
||||
|
||||
// When an edit page gets attached or detached, remember its state so we can do the same to the next one to open.
|
||||
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) {
|
||||
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 there's only one tab in this window, it's been dragged to new window
|
||||
prefs.set("openEditInWindow", win.tabs.length == 1);
|
||||
});
|
||||
|
@ -149,13 +191,19 @@ 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) {
|
||||
getActiveTab(function (tab) {
|
||||
// re-use an active new tab page
|
||||
chrome.tabs[tab.url == "chrome://newtab/" ? "update" : "create"](options);
|
||||
});
|
||||
|
@ -164,6 +212,6 @@ function openURL(options) {
|
|||
}
|
||||
|
||||
var codeMirrorThemes;
|
||||
getCodeMirrorThemes(function(themes) {
|
||||
getCodeMirrorThemes(function (themes) {
|
||||
codeMirrorThemes = themes;
|
||||
});
|
9937
csslint/csslint.js
9937
csslint/csslint.js
File diff suppressed because it is too large
Load Diff
79
install.js
79
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];
|
||||
|
@ -7,32 +11,42 @@ chrome.runtime.sendMessage({method: "getStyles", url: getMeta("stylish-id-url")
|
|||
// use the md5 if available
|
||||
var md5Url = getMeta("stylish-md5-url");
|
||||
if (md5Url && installedStyle.md5Url && installedStyle.originalMd5) {
|
||||
getResource(md5Url, function(md5) {
|
||||
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) {
|
||||
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) {
|
||||
if (json.sections.every(function(section) {
|
||||
return installedStyle.sections.some(function(installedSection) {
|
||||
if (json.sections.every(function (section) {
|
||||
return installedStyle.sections.some(function (installedSection) {
|
||||
return sectionsAreEqual(section, installedSection);
|
||||
});
|
||||
})) {
|
||||
// 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
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +56,7 @@ function sectionsAreEqual(a, b) {
|
|||
if (a.code != b.code) {
|
||||
return false;
|
||||
}
|
||||
return ["urls", "urlPrefixes", "domains", "regexps"].every(function(attribute) {
|
||||
return ["urls", "urlPrefixes", "domains", "regexps"].every(function (attribute) {
|
||||
return arraysAreEqual(a[attribute], b[attribute]);
|
||||
});
|
||||
}
|
||||
|
@ -50,13 +64,13 @@ 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;
|
||||
}
|
||||
return a.every(function(entry) {
|
||||
return a.every(function (entry) {
|
||||
return b.indexOf(entry) != -1;
|
||||
});
|
||||
}
|
||||
|
@ -65,18 +79,20 @@ 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);
|
||||
}
|
||||
|
||||
document.addEventListener("stylishInstallChrome", function() {
|
||||
getResource(getMeta("stylish-description"), function(name) {
|
||||
document.addEventListener("stylishInstallChrome", function () {
|
||||
getResource(getMeta("stylish-description"), function (name) {
|
||||
if (confirm(chrome.i18n.getMessage('styleInstall', [name]))) {
|
||||
getResource(getMeta("stylish-code-chrome"), function(code) {
|
||||
getResource(getMeta("stylish-code-chrome"), function (code) {
|
||||
// check for old style json
|
||||
var json = JSON.parse(code);
|
||||
json.method = "saveStyle";
|
||||
chrome.runtime.sendMessage(json, function(response) {
|
||||
chrome.runtime.sendMessage(json, function (response) {
|
||||
sendEvent("styleInstalledChrome");
|
||||
});
|
||||
});
|
||||
|
@ -85,15 +101,18 @@ document.addEventListener("stylishInstallChrome", function() {
|
|||
});
|
||||
}, false);
|
||||
|
||||
document.addEventListener("stylishUpdateChrome", function() {
|
||||
chrome.runtime.sendMessage({method: "getStyles", url: getMeta("stylish-id-url") || location.href}, function(response) {
|
||||
document.addEventListener("stylishUpdateChrome", function () {
|
||||
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) {
|
||||
getResource(getMeta("stylish-code-chrome"), function (code) {
|
||||
var json = JSON.parse(code);
|
||||
json.method = "saveStyle";
|
||||
json.id = style.id;
|
||||
chrome.runtime.sendMessage(json, function() {
|
||||
chrome.runtime.sendMessage(json, function () {
|
||||
sendEvent("styleInstalledChrome");
|
||||
});
|
||||
});
|
||||
|
@ -108,14 +127,14 @@ function getMeta(name) {
|
|||
}
|
||||
|
||||
function getResource(url, callback) {
|
||||
if (url.indexOf("#") == 0) {
|
||||
if (url.indexOf("#") === 0) {
|
||||
if (callback) {
|
||||
callback(document.getElementById(url.substring(1)).innerText);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function() {
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4 && callback) {
|
||||
if (xhr.status >= 400) {
|
||||
callback(null);
|
||||
|
@ -123,11 +142,11 @@ function getResource(url, callback) {
|
|||
callback(xhr.responseText);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (url.length > 2000) {
|
||||
var parts = url.split("?");
|
||||
xhr.open("POST", parts[0], true);
|
||||
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
|
||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
xhr.send(parts[1]);
|
||||
} else {
|
||||
xhr.open("GET", url, 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
|
||||
|
|
153
manage.js
153
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,8 +23,10 @@ function showStyles(styles) {
|
|||
document.stylishStyles = styles;
|
||||
return;
|
||||
}
|
||||
styles.sort(function(a, b) { return a.name.localeCompare(b.name)});
|
||||
styles.map(createStyleElement).forEach(function(e) {
|
||||
styles.sort(function (a, b) {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
styles.map(createStyleElement).forEach(function (e) {
|
||||
installed.appendChild(e);
|
||||
});
|
||||
if (history.state) {
|
||||
|
@ -44,23 +51,24 @@ 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(document.createTextNode(" "));
|
||||
styleName.appendChild(homepage);
|
||||
}
|
||||
var domains = [];
|
||||
var urls = [];
|
||||
var urlPrefixes = [];
|
||||
var regexps = [];
|
||||
|
||||
function add(array, property) {
|
||||
style.sections.forEach(function(section) {
|
||||
style.sections.forEach(function (section) {
|
||||
if (section[property]) {
|
||||
section[property].filter(function(value) {
|
||||
section[property].filter(function (value) {
|
||||
return array.indexOf(value) == -1;
|
||||
}).forEach(function(value) {
|
||||
}).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(", ");
|
||||
|
@ -93,10 +105,12 @@ function createStyleElement(style) {
|
|||
}
|
||||
var editLink = e.querySelector(".style-edit-link");
|
||||
editLink.setAttribute("href", editLink.getAttribute("href") + style.id);
|
||||
editLink.addEventListener("click", function(event) {
|
||||
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,16 +130,22 @@ function createStyleElement(style) {
|
|||
});
|
||||
}
|
||||
} else {
|
||||
history.replaceState({scrollY: window.scrollY}, document.title);
|
||||
getActiveTab(function(tab) {
|
||||
history.replaceState({
|
||||
scrollY: window.scrollY
|
||||
}, document.title);
|
||||
getActiveTab(function (tab) {
|
||||
sessionStorageHash("manageStylesHistory").set(tab.id, url);
|
||||
location.href = url;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
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);
|
||||
|
@ -160,7 +180,7 @@ function getStyleElement(event) {
|
|||
return null;
|
||||
}
|
||||
|
||||
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
|
||||
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
||||
switch (request.method) {
|
||||
case "styleUpdated":
|
||||
handleUpdate(request.style);
|
||||
|
@ -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) {
|
||||
|
@ -198,12 +218,12 @@ function doCheckUpdate(event) {
|
|||
function applyUpdateAll() {
|
||||
var btnApply = document.getElementById("apply-all-updates");
|
||||
btnApply.disabled = true;
|
||||
setTimeout(function() {
|
||||
setTimeout(function () {
|
||||
btnApply.style.display = "none";
|
||||
btnApply.disabled = false;
|
||||
}, 1000);
|
||||
|
||||
Array.prototype.forEach.call(document.querySelectorAll(".can-update .update"), function(button) {
|
||||
Array.prototype.forEach.call(document.querySelectorAll(".can-update .update"), function (button) {
|
||||
button.click();
|
||||
});
|
||||
}
|
||||
|
@ -220,18 +240,18 @@ function checkUpdateAll() {
|
|||
var elements = document.querySelectorAll("[style-update-url]");
|
||||
var toCheckCount = elements.length;
|
||||
var updatableCount = 0;
|
||||
Array.prototype.forEach.call(elements, function(element) {
|
||||
checkUpdate(element, function(success) {
|
||||
Array.prototype.forEach.call(elements, function (element) {
|
||||
checkUpdate(element, function (success) {
|
||||
if (success) {
|
||||
++updatableCount;
|
||||
}
|
||||
if (--toCheckCount == 0) {
|
||||
if (--toCheckCount === 0) {
|
||||
btnCheck.disabled = false;
|
||||
if (updatableCount) {
|
||||
btnApply.classList.remove("hidden");
|
||||
} else {
|
||||
noUpdates.classList.remove("hidden");
|
||||
setTimeout(function() {
|
||||
setTimeout(function () {
|
||||
noUpdates.classList.add("hidden");
|
||||
}, 10000);
|
||||
}
|
||||
|
@ -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,9 +299,9 @@ function checkUpdate(element, callback) {
|
|||
}
|
||||
|
||||
if (!md5Url || !originalMd5) {
|
||||
checkUpdateFullCode(url, false, handleSuccess, handleFailure)
|
||||
checkUpdateFullCode(url, false, handleSuccess, handleFailure);
|
||||
} else {
|
||||
checkUpdateMd5(originalMd5, md5Url, function(needsUpdate) {
|
||||
checkUpdateMd5(originalMd5, md5Url, function (needsUpdate) {
|
||||
if (needsUpdate) {
|
||||
// If the md5 shows a change we will update regardless of whether the code looks different
|
||||
checkUpdateFullCode(url, true, handleSuccess, handleFailure);
|
||||
|
@ -293,13 +316,13 @@ function checkUpdate(element, callback) {
|
|||
}
|
||||
|
||||
function checkUpdateFullCode(url, forceUpdate, successCallback, failureCallback) {
|
||||
download(url, function(responseText) {
|
||||
download(url, function (responseText) {
|
||||
successCallback(forceUpdate, JSON.parse(responseText));
|
||||
}, failureCallback);
|
||||
}
|
||||
|
||||
function checkUpdateMd5(originalMd5, md5Url, successCallback, failureCallback) {
|
||||
download(md5Url, function(responseText) {
|
||||
download(md5Url, function (responseText) {
|
||||
if (responseText.length != 32) {
|
||||
failureCallback(-1);
|
||||
return;
|
||||
|
@ -313,16 +336,16 @@ 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);
|
||||
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
|
||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
xhr.send(parts[1]);
|
||||
} else {
|
||||
xhr.open("GET", url, true);
|
||||
|
@ -371,7 +394,7 @@ function codeIsEqual(a, b) {
|
|||
for (var i = 0; i < a.length; i++) {
|
||||
var found = false;
|
||||
for (var j = 0; j < b.length; j++) {
|
||||
var allEquals = properties.every(function(property) {
|
||||
var allEquals = properties.every(function (property) {
|
||||
return jsonEquals(a[i], b[j], property);
|
||||
});
|
||||
if (allEquals) {
|
||||
|
@ -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,9 +452,12 @@ function searchStyles(immediately) {
|
|||
clearTimeout(searchStyles.timeout);
|
||||
searchStyles.timeout = setTimeout(doSearch, 100);
|
||||
}
|
||||
|
||||
function doSearch() {
|
||||
chrome.runtime.sendMessage({method: "getStyles"}, function(styles) {
|
||||
styles.forEach(function(style) {
|
||||
chrome.runtime.sendMessage({
|
||||
method: "getStyles"
|
||||
}, function (styles) {
|
||||
styles.forEach(function (style) {
|
||||
var el = document.querySelector("[style-id='" + style.id + "']");
|
||||
if (el) {
|
||||
el.style.display = !query || isMatchingText(style.name) || isMatchingStyle(style) ? "" : "none";
|
||||
|
@ -437,43 +465,49 @@ function searchStyles(immediately) {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
function isMatchingStyle(style) {
|
||||
return style.sections.some(function(section) {
|
||||
return Object.keys(section).some(function(key) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
function onFilterChange (className, event) {
|
||||
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) {
|
||||
function importStyles(e) {
|
||||
var file = e.target.files[0];
|
||||
var reader = new FileReader();
|
||||
var styles = [];
|
||||
|
||||
function save () {
|
||||
function save() {
|
||||
var style = styles.shift();
|
||||
if (style) {
|
||||
delete style.id;
|
||||
saveStyle(style, save);
|
||||
}
|
||||
else {
|
||||
window.location.reload()
|
||||
} else {
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,22 +515,21 @@ 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 () {
|
||||
function selectAll() {
|
||||
document.execCommand('selectAll');
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
installed = document.getElementById("installed");
|
||||
if (document.stylishStyles) {
|
||||
showStyles(document.stylishStyles);
|
||||
|
|
61
messaging.js
61
messaging.js
|
@ -1,14 +1,20 @@
|
|||
/*jshint undef:false*/
|
||||
function notifyAllTabs(request) {
|
||||
chrome.windows.getAll({populate: true}, function(windows) {
|
||||
windows.forEach(function(win) {
|
||||
win.tabs.forEach(function(tab) {
|
||||
chrome.windows.getAll({
|
||||
populate: true
|
||||
}, function (windows) {
|
||||
windows.forEach(function (win) {
|
||||
win.tabs.forEach(function (tab) {
|
||||
chrome.tabs.sendMessage(tab.id, request);
|
||||
updateIcon(tab);
|
||||
});
|
||||
});
|
||||
});
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -20,7 +26,7 @@ function updateIcon(tab, styles) {
|
|||
}
|
||||
if (styles) {
|
||||
// check for not-yet-existing tabs e.g. omnibox instant search
|
||||
chrome.tabs.get(tab.id, function() {
|
||||
chrome.tabs.get(tab.id, function () {
|
||||
if (!chrome.runtime.lastError) {
|
||||
// for 'styles' asHash:true fake the length by counting numeric ids manually
|
||||
if (styles.length === undefined) {
|
||||
|
@ -34,33 +40,47 @@ function updateIcon(tab, styles) {
|
|||
});
|
||||
return;
|
||||
}
|
||||
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 (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() {
|
||||
}, function () {
|
||||
// if the tab was just closed an error may occur,
|
||||
// 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,13 +88,16 @@ 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]);
|
||||
});
|
||||
}
|
||||
|
||||
function getActiveTabRealURL(callback) {
|
||||
getActiveTab(function(tab) {
|
||||
getActiveTab(function (tab) {
|
||||
getTabRealURL(tab, callback);
|
||||
});
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
78
popup.js
78
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,23 +33,29 @@ 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)
|
||||
domains.forEach(function(domain) {
|
||||
var domains = getDomains(url);
|
||||
domains.forEach(function (domain) {
|
||||
// Don't include TLD
|
||||
if (domains.length > 1 && domain.indexOf(".") == -1) {
|
||||
return;
|
||||
|
@ -59,7 +69,7 @@ function updatePopUp(url) {
|
|||
});
|
||||
|
||||
var writeStyle = document.querySelector("#write-style");
|
||||
writeStyleLinks.forEach(function(link, index) {
|
||||
writeStyleLinks.forEach(function (link, index) {
|
||||
link.addEventListener("click", openLinkInTabOrWindow, false);
|
||||
container.appendChild(link);
|
||||
});
|
||||
|
@ -72,14 +82,14 @@ function updatePopUp(url) {
|
|||
|
||||
function showStyles(styles) {
|
||||
var enabledFirst = prefs.get("popup.enabledFirst");
|
||||
styles.sort(function(a, b) {
|
||||
styles.sort(function (a, b) {
|
||||
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) {
|
||||
styles.map(createStyleElement).forEach(function (e) {
|
||||
installed.appendChild(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();
|
||||
}
|
||||
|
||||
|
@ -168,7 +194,7 @@ function handleUpdate(style) {
|
|||
if (styleElement) {
|
||||
installed.replaceChild(createStyleElement(style), styleElement);
|
||||
} else {
|
||||
getActiveTabRealURL(function(url) {
|
||||
getActiveTabRealURL(function (url) {
|
||||
if (chrome.extension.getBackgroundPage().getApplicableSections(style, url).length) {
|
||||
// a new style for the current url is installed
|
||||
document.getElementById("unavailable").style.display = "none";
|
||||
|
@ -185,7 +211,7 @@ function handleDelete(id) {
|
|||
}
|
||||
}
|
||||
|
||||
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
|
||||
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
||||
if (request.method == "updatePopup") {
|
||||
switch (request.reason) {
|
||||
case "styleAdded":
|
||||
|
@ -199,11 +225,11 @@ chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
|
|||
}
|
||||
});
|
||||
|
||||
["find-styles-link", "open-manage-link"].forEach(function(id) {
|
||||
["find-styles-link", "open-manage-link"].forEach(function (id) {
|
||||
document.getElementById(id).addEventListener("click", openLink, false);
|
||||
});
|
||||
|
||||
document.getElementById("disableAll").addEventListener("change", function(event) {
|
||||
document.getElementById("disableAll").addEventListener("change", function (event) {
|
||||
installed.classList.toggle("disabled", prefs.get("disableAll"));
|
||||
});
|
||||
setupLivePrefs(["disableAll"]);
|
|
@ -1,31 +1,32 @@
|
|||
/*jshint undef:false*/
|
||||
var webSqlStorage = {
|
||||
|
||||
migrate: function() {
|
||||
migrate: function () {
|
||||
if (typeof openDatabase == "undefined") {
|
||||
// No WebSQL - no migration!
|
||||
return;
|
||||
}
|
||||
webSqlStorage.getStyles(function(styles) {
|
||||
getDatabase(function(db) {
|
||||
webSqlStorage.getStyles(function (styles) {
|
||||
getDatabase(function (db) {
|
||||
var tx = db.transaction(["styles"], "readwrite");
|
||||
var os = tx.objectStore("styles");
|
||||
styles.forEach(function(s) {
|
||||
webSqlStorage.cleanStyle(s)
|
||||
styles.forEach(function (s) {
|
||||
webSqlStorage.cleanStyle(s);
|
||||
os.add(s);
|
||||
});
|
||||
// While this was running, the styles were loaded from the (empty) indexed db
|
||||
setTimeout(function() {
|
||||
setTimeout(function () {
|
||||
invalidateCache(true);
|
||||
}, 500);
|
||||
});
|
||||
}, null);
|
||||
},
|
||||
|
||||
cleanStyle: function(s) {
|
||||
cleanStyle: function (s) {
|
||||
delete s.id;
|
||||
s.sections.forEach(function(section) {
|
||||
s.sections.forEach(function (section) {
|
||||
delete section.id;
|
||||
["urls", "urlPrefixes", "domains", "regexps"].forEach(function(property) {
|
||||
["urls", "urlPrefixes", "domains", "regexps"].forEach(function (property) {
|
||||
if (!section[property]) {
|
||||
section[property] = [];
|
||||
}
|
||||
|
@ -33,8 +34,8 @@ var webSqlStorage = {
|
|||
});
|
||||
},
|
||||
|
||||
getStyles: function(callback) {
|
||||
webSqlStorage.getDatabase(function(db) {
|
||||
getStyles: function (callback) {
|
||||
webSqlStorage.getDatabase(function (db) {
|
||||
if (!db) {
|
||||
callback([]);
|
||||
return;
|
||||
|
@ -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) {
|
||||
|
@ -93,14 +107,14 @@ var webSqlStorage = {
|
|||
}, reportError);
|
||||
},
|
||||
|
||||
getDatabase: function(ready, error) {
|
||||
getDatabase: function (ready, error) {
|
||||
try {
|
||||
stylishDb = openDatabase('stylish', '', 'Stylish Styles', 5*1024*1024);
|
||||
stylishDb = openDatabase('stylish', '', 'Stylish Styles', 5 * 1024 * 1024);
|
||||
} catch (ex) {
|
||||
error();
|
||||
throw ex;
|
||||
}
|
||||
if (stylishDb.version == "") {
|
||||
if (stylishDb.version === "") {
|
||||
// It didn't already exist, we have nothing to migrate.
|
||||
ready(null);
|
||||
return;
|
||||
|
@ -120,15 +134,17 @@ var webSqlStorage = {
|
|||
}
|
||||
},
|
||||
|
||||
dbV11: function(d, error, done) {
|
||||
dbV11: function (d, error, done) {
|
||||
d.changeVersion(d.version, '1.1', function (t) {
|
||||
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) {
|
||||
dbV12: function (d, error, done) {
|
||||
d.changeVersion(d.version, '1.2', function (t) {
|
||||
// add section table
|
||||
t.executeSql('CREATE TABLE sections (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, style_id INTEGER NOT NULL, code TEXT NOT NULL);');
|
||||
|
@ -144,26 +160,34 @@ 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) {
|
||||
dbV13: function (d, error, done) {
|
||||
d.changeVersion(d.version, '1.3', function (t) {
|
||||
// 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) {
|
||||
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) {
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
267
storage.js
267
storage.js
|
@ -1,37 +1,43 @@
|
|||
/*jshint undef:false*/
|
||||
function getDatabase(ready, error) {
|
||||
var dbOpenRequest = window.indexedDB.open("stylish", 2);
|
||||
dbOpenRequest.onsuccess = function(e) {
|
||||
dbOpenRequest.onsuccess = function (e) {
|
||||
ready(e.target.result);
|
||||
};
|
||||
dbOpenRequest.onerror = function(event) {
|
||||
dbOpenRequest.onerror = function (event) {
|
||||
console.log(event.target.errorCode);
|
||||
if (error) {
|
||||
error(event);
|
||||
}
|
||||
};
|
||||
dbOpenRequest.onupgradeneeded = function(event) {
|
||||
if (event.oldVersion == 0) {
|
||||
var os = event.target.result.createObjectStore("styles", {keyPath: 'id', autoIncrement: true});
|
||||
dbOpenRequest.onupgradeneeded = function (event) {
|
||||
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;
|
||||
}
|
||||
getDatabase(function(db) {
|
||||
getDatabase(function (db) {
|
||||
var tx = db.transaction(["styles"], "readonly");
|
||||
var os = tx.objectStore("styles");
|
||||
var all = [];
|
||||
os.openCursor().onsuccess = function(event) {
|
||||
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,27 +63,29 @@ function filterStyles(styles, options) {
|
|||
var id = "id" in options ? Number(options.id) : null;
|
||||
var matchUrl = "matchUrl" in options ? options.matchUrl : null;
|
||||
|
||||
if (enabled != null) {
|
||||
styles = styles.filter(function(style) {
|
||||
if (enabled !== null) {
|
||||
styles = styles.filter(function (style) {
|
||||
return style.enabled == enabled;
|
||||
});
|
||||
}
|
||||
if (url != null) {
|
||||
styles = styles.filter(function(style) {
|
||||
if (url !== null) {
|
||||
styles = styles.filter(function (style) {
|
||||
return style.url == url;
|
||||
});
|
||||
}
|
||||
if (id != null) {
|
||||
styles = styles.filter(function(style) {
|
||||
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)};
|
||||
styles.forEach(function(style) {
|
||||
var h = {
|
||||
disableAll: prefs.get("disableAll", false)
|
||||
};
|
||||
styles.forEach(function (style) {
|
||||
var applicableSections = getApplicableSections(style, matchUrl);
|
||||
if (applicableSections.length > 0) {
|
||||
h[style.id] = applicableSections;
|
||||
|
@ -83,7 +93,7 @@ function filterStyles(styles, options) {
|
|||
});
|
||||
return h;
|
||||
}
|
||||
styles = styles.filter(function(style) {
|
||||
styles = styles.filter(function (style) {
|
||||
var applicableSections = getApplicableSections(style, matchUrl);
|
||||
return applicableSections.length > 0;
|
||||
});
|
||||
|
@ -92,14 +102,14 @@ function filterStyles(styles, options) {
|
|||
}
|
||||
|
||||
function saveStyle(o, callback) {
|
||||
getDatabase(function(db) {
|
||||
getDatabase(function (db) {
|
||||
var tx = db.transaction(["styles"], "readwrite");
|
||||
var os = tx.objectStore("styles");
|
||||
|
||||
// Update
|
||||
if (o.id) {
|
||||
var request = os.get(Number(o.id));
|
||||
request.onsuccess = function(event) {
|
||||
request = os.get(Number(o.id));
|
||||
request.onsuccess = function (event) {
|
||||
var style = request.result;
|
||||
for (var prop in o) {
|
||||
if (prop == "id") {
|
||||
|
@ -108,8 +118,11 @@ function saveStyle(o, callback) {
|
|||
style[prop] = o[prop];
|
||||
}
|
||||
request = os.put(style);
|
||||
request.onsuccess = function(event) {
|
||||
notifyAllTabs({method: "styleUpdated", style: style});
|
||||
request.onsuccess = function (event) {
|
||||
notifyAllTabs({
|
||||
method: "styleUpdated",
|
||||
style: style
|
||||
});
|
||||
invalidateCache(true);
|
||||
if (callback) {
|
||||
callback(style);
|
||||
|
@ -121,14 +134,14 @@ function saveStyle(o, callback) {
|
|||
|
||||
// Create
|
||||
// Set optional things to null if they're undefined
|
||||
["updateUrl", "md5Url", "url", "originalMd5"].filter(function(att) {
|
||||
["updateUrl", "md5Url", "url", "originalMd5"].filter(function (att) {
|
||||
return !(att in o);
|
||||
}).forEach(function(att) {
|
||||
}).forEach(function (att) {
|
||||
o[att] = null;
|
||||
});
|
||||
// Set other optional things to empty array if they're undefined
|
||||
o.sections.forEach(function(section) {
|
||||
["urls", "urlPrefixes", "domains", "regexps"].forEach(function(property) {
|
||||
o.sections.forEach(function (section) {
|
||||
["urls", "urlPrefixes", "domains", "regexps"].forEach(function (property) {
|
||||
if (!section[property]) {
|
||||
section[property] = [];
|
||||
}
|
||||
|
@ -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);
|
||||
request.onsuccess = function(event) {
|
||||
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,26 +170,36 @@ 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
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function deleteStyle(id) {
|
||||
getDatabase(function(db) {
|
||||
getDatabase(function (db) {
|
||||
var tx = db.transaction(["styles"], "readwrite");
|
||||
var os = tx.objectStore("styles");
|
||||
var request = os.delete(Number(id));
|
||||
request.onsuccess = function(event) {
|
||||
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,8 +239,9 @@ function getType(o) {
|
|||
}
|
||||
|
||||
var namespacePattern = /^\s*(@namespace[^;]+;\s*)+$/;
|
||||
|
||||
function getApplicableSections(style, url) {
|
||||
var sections = style.sections.filter(function(section) {
|
||||
var sections = style.sections.filter(function (section) {
|
||||
return sectionAppliesToUrl(section, url);
|
||||
});
|
||||
// ignore if it's just namespaces
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -241,19 +268,19 @@ function sectionAppliesToUrl(section, url) {
|
|||
//console.log(section.id + " applies to " + url + " due to URL rules");
|
||||
return true;
|
||||
}
|
||||
if (section.urlPrefixes.some(function(prefix) {
|
||||
return url.indexOf(prefix) == 0;
|
||||
if (section.urlPrefixes.some(function (prefix) {
|
||||
return url.indexOf(prefix) === 0;
|
||||
})) {
|
||||
//console.log(section.id + " applies to " + url + " due to URL prefix rules");
|
||||
return true;
|
||||
}
|
||||
if (section.domains.length > 0 && getDomains(url).some(function(domain) {
|
||||
if (section.domains.length > 0 && getDomains(url).some(function (domain) {
|
||||
return section.domains.indexOf(domain) != -1;
|
||||
})) {
|
||||
//console.log(section.id + " applies due to " + url + " due to domain rules");
|
||||
return true;
|
||||
}
|
||||
if (section.regexps.some(function(regexp) {
|
||||
if (section.regexps.some(function (regexp) {
|
||||
// we want to match the full url, so add ^ and $ if not already present
|
||||
if (regexp[0] != "^") {
|
||||
regexp = "^" + regexp;
|
||||
|
@ -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,29 +311,34 @@ 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)
|
||||
// and establishes a two-way connection between the document elements and the actual prefs
|
||||
function setupLivePrefs(IDs) {
|
||||
var localIDs = {};
|
||||
IDs.forEach(function(id) {
|
||||
IDs.forEach(function (id) {
|
||||
localIDs[id] = true;
|
||||
updateElement(id).addEventListener("change", function() {
|
||||
updateElement(id).addEventListener("change", function () {
|
||||
prefs.set(this.id, isCheckbox(this) ? this.checked : this.value);
|
||||
});
|
||||
});
|
||||
chrome.runtime.onMessage.addListener(function(request) {
|
||||
chrome.runtime.onMessage.addListener(function (request) {
|
||||
if (request.prefName in localIDs) {
|
||||
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,9 +383,11 @@ 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) {
|
||||
Prefs.prototype.get = function (key, defaultValue) {
|
||||
if (key in values) {
|
||||
return values[key];
|
||||
}
|
||||
|
@ -364,11 +400,11 @@ var prefs = chrome.extension.getBackgroundPage().prefs || new function Prefs() {
|
|||
console.warn("No default preference for '%s'", key);
|
||||
};
|
||||
|
||||
Prefs.prototype.getAll = function(key) {
|
||||
Prefs.prototype.getAll = function (key) {
|
||||
return deepCopy(values);
|
||||
};
|
||||
|
||||
Prefs.prototype.set = function(key, value, options) {
|
||||
Prefs.prototype.set = function (key, value, options) {
|
||||
var oldValue = deepCopy(values[key]);
|
||||
values[key] = value;
|
||||
defineReadonlyProperty(this.readOnlyValues, key, value);
|
||||
|
@ -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};
|
||||
Prefs.prototype.broadcast = function (key, value, options) {
|
||||
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});
|
||||
syncTimeout = setTimeout(function () {
|
||||
getSync().set({
|
||||
"settings": values
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
Object.keys(defaults).forEach(function(key) {
|
||||
me.set(key, defaults[key], {noBroadcast: true});
|
||||
Object.keys(defaults).forEach(function (key) {
|
||||
me.set(key, defaults[key], {
|
||||
noBroadcast: true
|
||||
});
|
||||
});
|
||||
|
||||
getSync().get("settings", function(result) {
|
||||
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) {
|
||||
|
@ -412,18 +463,23 @@ 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) {
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -443,24 +499,30 @@ var prefs = chrome.extension.getBackgroundPage().prefs || new function Prefs() {
|
|||
case "object":
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
console.log("Cannot migrate from localStorage %s = '%s': %o", key, value, e);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
};
|
||||
}();
|
||||
|
||||
function getCodeMirrorThemes(callback) {
|
||||
chrome.runtime.getPackageDirectoryEntry(function(rootDir) {
|
||||
rootDir.getDirectory("codemirror/theme", {create: false}, function(themeDir) {
|
||||
themeDir.createReader().readEntries(function(entries) {
|
||||
chrome.runtime.getPackageDirectoryEntry(function (rootDir) {
|
||||
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 })
|
||||
.forEach(function(entry) {
|
||||
.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$/, ""));
|
||||
});
|
||||
if (callback) {
|
||||
|
@ -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(); },
|
||||
updateStorage: function() {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -494,7 +566,7 @@ function deepCopy(obj) {
|
|||
}
|
||||
}
|
||||
|
||||
function deepMerge(target, obj1 /* plus any number of object arguments */) {
|
||||
function deepMerge(target, obj1 /* plus any number of object arguments */ ) {
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
var obj = arguments[i];
|
||||
for (var k in obj) {
|
||||
|
@ -512,7 +584,7 @@ function deepMerge(target, obj1 /* plus any number of object arguments */) {
|
|||
return target;
|
||||
}
|
||||
|
||||
function shallowMerge(target, obj1 /* plus any number of object arguments */) {
|
||||
function shallowMerge(target, obj1 /* plus any number of object arguments */ ) {
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
var obj = arguments[i];
|
||||
for (var k in obj) {
|
||||
|
@ -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
|
||||
|
@ -554,10 +629,10 @@ function getSync() {
|
|||
}
|
||||
crappyStorage = {};
|
||||
return {
|
||||
get: function(key, callback) {
|
||||
get: function (key, callback) {
|
||||
callback(crappyStorage[key] || {});
|
||||
},
|
||||
set: function(source, callback) {
|
||||
set: function (source, callback) {
|
||||
for (var property in source) {
|
||||
if (source.hasOwnProperty(property)) {
|
||||
crappyStorage[property] = source[property];
|
||||
|
@ -565,5 +640,5 @@ function getSync() {
|
|||
}
|
||||
callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user