Fix linting problems and more readable code
This commit is contained in:
parent
970d48b17a
commit
560f5b666e
479
apply.js
479
apply.js
|
@ -1,3 +1,4 @@
|
|||
/*jshint undef:false*/
|
||||
var g_disableAll = false;
|
||||
var g_styleElements = {};
|
||||
var iframeObserver;
|
||||
|
@ -7,289 +8,311 @@ initObserver();
|
|||
requestStyles();
|
||||
|
||||
function requestStyles() {
|
||||
// If this is a Stylish page (Edit Style or Manage Styles),
|
||||
// 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 bg = chrome.extension.getBackgroundPage();
|
||||
if (bg && bg.getStyles) {
|
||||
// apply styles immediately, then proceed with a normal request that will update the icon
|
||||
bg.getStyles(request, applyStyles);
|
||||
}
|
||||
}
|
||||
chrome.runtime.sendMessage(request, applyStyles);
|
||||
// If this is a Stylish page (Edit Style or Manage Styles),
|
||||
// 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 bg = chrome.extension.getBackgroundPage();
|
||||
if (bg && bg.getStyles) {
|
||||
// apply styles immediately, then proceed with a normal request that will update the icon
|
||||
bg.getStyles(request, applyStyles);
|
||||
}
|
||||
}
|
||||
chrome.runtime.sendMessage(request, applyStyles);
|
||||
}
|
||||
|
||||
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
|
||||
// Also handle special request just for the pop-up
|
||||
switch (request.method == "updatePopup" ? request.reason : request.method) {
|
||||
case "styleDeleted":
|
||||
removeStyle(request.id, document);
|
||||
break;
|
||||
case "styleUpdated":
|
||||
if (request.style.enabled) {
|
||||
retireStyle(request.style.id);
|
||||
// fallthrough to "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);
|
||||
}
|
||||
break;
|
||||
case "styleApply":
|
||||
applyStyles(request.styles);
|
||||
break;
|
||||
case "styleReplaceAll":
|
||||
replaceAll(request.styles, document);
|
||||
break;
|
||||
case "styleDisableAll":
|
||||
disableAll(request.disableAll);
|
||||
break;
|
||||
}
|
||||
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);
|
||||
break;
|
||||
case "styleUpdated":
|
||||
if (request.style.enabled) {
|
||||
retireStyle(request.style.id);
|
||||
styleAdded();
|
||||
} else {
|
||||
removeStyle(request.style.id, document);
|
||||
}
|
||||
break;
|
||||
case "styleAdded":
|
||||
styleAdded();
|
||||
break;
|
||||
case "styleApply":
|
||||
applyStyles(request.styles);
|
||||
break;
|
||||
case "styleReplaceAll":
|
||||
replaceAll(request.styles, document);
|
||||
break;
|
||||
case "styleDisableAll":
|
||||
disableAll(request.disableAll);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
function disableAll(disable) {
|
||||
if (!disable === !g_disableAll) {
|
||||
return;
|
||||
}
|
||||
g_disableAll = disable;
|
||||
if (g_disableAll) {
|
||||
iframeObserver.disconnect();
|
||||
}
|
||||
if (!disable === !g_disableAll) {
|
||||
return;
|
||||
}
|
||||
g_disableAll = disable;
|
||||
if (g_disableAll) {
|
||||
iframeObserver.disconnect();
|
||||
}
|
||||
|
||||
disableSheets(g_disableAll, document);
|
||||
disableSheets(g_disableAll, document);
|
||||
|
||||
if (!g_disableAll && document.readyState != "loading") {
|
||||
iframeObserver.start();
|
||||
}
|
||||
if (!g_disableAll && document.readyState != "loading") {
|
||||
iframeObserver.start();
|
||||
}
|
||||
|
||||
function disableSheets(disable, doc) {
|
||||
Array.prototype.forEach.call(doc.styleSheets, function(stylesheet) {
|
||||
if (stylesheet.ownerNode.classList.contains("stylish")) {
|
||||
stylesheet.disabled = disable;
|
||||
}
|
||||
});
|
||||
getDynamicIFrames(doc).forEach(function(iframe) {
|
||||
if (!disable) {
|
||||
// update the IFRAME if it was created while the observer was disconnected
|
||||
addDocumentStylesToIFrame(iframe);
|
||||
}
|
||||
disableSheets(disable, iframe.contentDocument);
|
||||
});
|
||||
}
|
||||
function disableSheets(disable, doc) {
|
||||
Array.prototype.forEach.call(doc.styleSheets, function (stylesheet) {
|
||||
if (stylesheet.ownerNode.classList.contains("stylish")) {
|
||||
stylesheet.disabled = disable;
|
||||
}
|
||||
});
|
||||
getDynamicIFrames(doc).forEach(function (iframe) {
|
||||
if (!disable) {
|
||||
// update the IFRAME if it was created while the observer was disconnected
|
||||
addDocumentStylesToIFrame(iframe);
|
||||
}
|
||||
disableSheets(disable, iframe.contentDocument);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function removeStyle(id, doc) {
|
||||
var e = doc.getElementById("stylish-" + id);
|
||||
delete g_styleElements["stylish-" + id];
|
||||
if (e) {
|
||||
e.remove();
|
||||
}
|
||||
if (doc == document && Object.keys(g_styleElements).length == 0) {
|
||||
iframeObserver.disconnect();
|
||||
}
|
||||
getDynamicIFrames(doc).forEach(function(iframe) {
|
||||
removeStyle(id, iframe.contentDocument);
|
||||
});
|
||||
var e = doc.getElementById("stylish-" + id);
|
||||
delete g_styleElements["stylish-" + id];
|
||||
if (e) {
|
||||
e.remove();
|
||||
}
|
||||
if (doc == document && Object.keys(g_styleElements).length === 0) {
|
||||
iframeObserver.disconnect();
|
||||
}
|
||||
getDynamicIFrames(doc).forEach(function (iframe) {
|
||||
removeStyle(id, iframe.contentDocument);
|
||||
});
|
||||
}
|
||||
|
||||
// to avoid page flicker when the style is updated
|
||||
// instead of removing it immediately we rename its ID and queue it
|
||||
// to be deleted in applyStyles after a new version is fetched and applied
|
||||
function retireStyle(id, doc) {
|
||||
var deadID = "ghost-" + id;
|
||||
if (!doc) {
|
||||
doc = document;
|
||||
retiredStyleIds.push(deadID);
|
||||
delete g_styleElements["stylish-" + id];
|
||||
// in case something went wrong and new style was never applied
|
||||
setTimeout(removeStyle.bind(null, deadID, doc), 1000);
|
||||
}
|
||||
var e = doc.getElementById("stylish-" + id);
|
||||
if (e) {
|
||||
e.id = "stylish-" + deadID;
|
||||
}
|
||||
getDynamicIFrames(doc).forEach(function(iframe) {
|
||||
retireStyle(id, iframe.contentDocument);
|
||||
});
|
||||
var deadID = "ghost-" + id;
|
||||
if (!doc) {
|
||||
doc = document;
|
||||
retiredStyleIds.push(deadID);
|
||||
delete g_styleElements["stylish-" + id];
|
||||
// in case something went wrong and new style was never applied
|
||||
setTimeout(removeStyle.bind(null, deadID, doc), 1000);
|
||||
}
|
||||
var e = doc.getElementById("stylish-" + id);
|
||||
if (e) {
|
||||
e.id = "stylish-" + deadID;
|
||||
}
|
||||
getDynamicIFrames(doc).forEach(function (iframe) {
|
||||
retireStyle(id, iframe.contentDocument);
|
||||
});
|
||||
}
|
||||
|
||||
function applyStyles(styleHash) {
|
||||
if (!styleHash) { // Chrome is starting up
|
||||
requestStyles();
|
||||
return;
|
||||
}
|
||||
if ("disableAll" in styleHash) {
|
||||
disableAll(styleHash.disableAll);
|
||||
delete styleHash.disableAll;
|
||||
}
|
||||
if (!styleHash) { // Chrome is starting up
|
||||
requestStyles();
|
||||
return;
|
||||
}
|
||||
if ("disableAll" in styleHash) {
|
||||
disableAll(styleHash.disableAll);
|
||||
delete styleHash.disableAll;
|
||||
}
|
||||
|
||||
for (var styleId in styleHash) {
|
||||
applySections(styleId, styleHash[styleId]);
|
||||
}
|
||||
for (var styleId in styleHash) {
|
||||
applySections(styleId, styleHash[styleId]);
|
||||
}
|
||||
|
||||
if (Object.keys(g_styleElements).length) {
|
||||
// when site response is application/xml Chrome displays our style elements
|
||||
// under document.documentElement as plain text so we need to move them into HEAD
|
||||
// (which already is autogenerated at this moment for the xml response)
|
||||
if (document.head && document.head.firstChild && document.head.firstChild.id == "xml-viewer-style") {
|
||||
for (var id in g_styleElements) {
|
||||
document.head.appendChild(document.getElementById(id));
|
||||
}
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
addDocumentStylesToAllIFrames();
|
||||
iframeObserver.start();
|
||||
});
|
||||
}
|
||||
if (Object.keys(g_styleElements).length) {
|
||||
// when site response is application/xml Chrome displays our style elements
|
||||
// under document.documentElement as plain text so we need to move them into HEAD
|
||||
// (which already is autogenerated at this moment for the xml response)
|
||||
if (document.head && document.head.firstChild && document.head.firstChild.id == "xml-viewer-style") {
|
||||
for (var id in g_styleElements) {
|
||||
document.head.appendChild(document.getElementById(id));
|
||||
}
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
addDocumentStylesToAllIFrames();
|
||||
iframeObserver.start();
|
||||
});
|
||||
}
|
||||
|
||||
if (retiredStyleIds.length) {
|
||||
setTimeout(function() {
|
||||
while (retiredStyleIds.length) {
|
||||
removeStyle(retiredStyleIds.shift(), document);
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
if (retiredStyleIds.length) {
|
||||
setTimeout(function () {
|
||||
while (retiredStyleIds.length) {
|
||||
removeStyle(retiredStyleIds.shift(), document);
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function applySections(styleId, sections) {
|
||||
var styleElement = document.getElementById("stylish-" + styleId);
|
||||
// Already there.
|
||||
if (styleElement) {
|
||||
return;
|
||||
}
|
||||
if (document.documentElement instanceof SVGSVGElement) {
|
||||
// SVG document, make an SVG style element.
|
||||
styleElement = document.createElementNS("http://www.w3.org/2000/svg", "style");
|
||||
} else {
|
||||
// This will make an HTML style element. If there's SVG embedded in an HTML document, this works on the SVG too.
|
||||
styleElement = document.createElement("style");
|
||||
}
|
||||
styleElement.setAttribute("id", "stylish-" + styleId);
|
||||
styleElement.setAttribute("class", "stylish");
|
||||
styleElement.setAttribute("type", "text/css");
|
||||
styleElement.appendChild(document.createTextNode(sections.map(function(section) {
|
||||
return section.code;
|
||||
}).join("\n")));
|
||||
addStyleElement(styleElement, document);
|
||||
g_styleElements[styleElement.id] = styleElement;
|
||||
var styleElement = document.getElementById("stylish-" + styleId);
|
||||
// Already there.
|
||||
if (styleElement) {
|
||||
return;
|
||||
}
|
||||
if (document.documentElement instanceof SVGSVGElement) {
|
||||
// SVG document, make an SVG style element.
|
||||
styleElement = document.createElementNS("http://www.w3.org/2000/svg", "style");
|
||||
} else {
|
||||
// This will make an HTML style element. If there's SVG embedded in an HTML document, this works on the SVG too.
|
||||
styleElement = document.createElement("style");
|
||||
}
|
||||
styleElement.setAttribute("id", "stylish-" + styleId);
|
||||
styleElement.setAttribute("class", "stylish");
|
||||
styleElement.setAttribute("type", "text/css");
|
||||
styleElement.appendChild(document.createTextNode(sections.map(function (section) {
|
||||
return section.code;
|
||||
}).join("\n")));
|
||||
addStyleElement(styleElement, document);
|
||||
g_styleElements[styleElement.id] = styleElement;
|
||||
}
|
||||
|
||||
function addStyleElement(styleElement, doc) {
|
||||
if (!doc.documentElement || doc.getElementById(styleElement.id)) {
|
||||
return;
|
||||
}
|
||||
doc.documentElement.appendChild(doc.importNode(styleElement, true))
|
||||
.disabled = g_disableAll;
|
||||
getDynamicIFrames(doc).forEach(function(iframe) {
|
||||
if (iframeIsLoadingSrcDoc(iframe)) {
|
||||
addStyleToIFrameSrcDoc(iframe, styleElement);
|
||||
} else {
|
||||
addStyleElement(styleElement, iframe.contentDocument);
|
||||
}
|
||||
});
|
||||
if (!doc.documentElement || doc.getElementById(styleElement.id)) {
|
||||
return;
|
||||
}
|
||||
doc.documentElement.appendChild(doc.importNode(styleElement, true))
|
||||
.disabled = g_disableAll;
|
||||
getDynamicIFrames(doc).forEach(function (iframe) {
|
||||
if (iframeIsLoadingSrcDoc(iframe)) {
|
||||
addStyleToIFrameSrcDoc(iframe, styleElement);
|
||||
} else {
|
||||
addStyleElement(styleElement, iframe.contentDocument);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addDocumentStylesToIFrame(iframe) {
|
||||
var doc = iframe.contentDocument;
|
||||
var srcDocIsLoading = iframeIsLoadingSrcDoc(iframe);
|
||||
for (var id in g_styleElements) {
|
||||
if (srcDocIsLoading) {
|
||||
addStyleToIFrameSrcDoc(iframe, g_styleElements[id]);
|
||||
} else {
|
||||
addStyleElement(g_styleElements[id], doc);
|
||||
}
|
||||
}
|
||||
var doc = iframe.contentDocument;
|
||||
var srcDocIsLoading = iframeIsLoadingSrcDoc(iframe);
|
||||
for (var id in g_styleElements) {
|
||||
if (srcDocIsLoading) {
|
||||
addStyleToIFrameSrcDoc(iframe, g_styleElements[id]);
|
||||
} else {
|
||||
addStyleElement(g_styleElements[id], doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addDocumentStylesToAllIFrames() {
|
||||
getDynamicIFrames(document).forEach(addDocumentStylesToIFrame);
|
||||
getDynamicIFrames(document).forEach(addDocumentStylesToIFrame);
|
||||
}
|
||||
|
||||
// Only dynamic iframes get the parent document's styles. Other ones should get styles based on their own URLs.
|
||||
function getDynamicIFrames(doc) {
|
||||
return Array.prototype.filter.call(doc.getElementsByTagName('iframe'), iframeIsDynamic);
|
||||
return Array.prototype.filter.call(doc.getElementsByTagName('iframe'), iframeIsDynamic);
|
||||
}
|
||||
|
||||
function iframeIsDynamic(f) {
|
||||
var href;
|
||||
try {
|
||||
href = f.contentDocument.location.href;
|
||||
} catch (ex) {
|
||||
// Cross-origin, so it's not a dynamic iframe
|
||||
return false;
|
||||
}
|
||||
return href == document.location.href || href.indexOf("about:") == 0;
|
||||
var href;
|
||||
try {
|
||||
href = f.contentDocument.location.href;
|
||||
} catch (ex) {
|
||||
// Cross-origin, so it's not a dynamic iframe
|
||||
return false;
|
||||
}
|
||||
return href == document.location.href || href.indexOf("about:") === 0;
|
||||
}
|
||||
|
||||
function iframeIsLoadingSrcDoc(f) {
|
||||
return f.srcdoc && f.contentDocument.all.length <= 3;
|
||||
// 3 nodes or less in total (html, head, body) == new empty iframe about to be overwritten by its 'srcdoc'
|
||||
return f.srcdoc && f.contentDocument.all.length <= 3;
|
||||
// 3 nodes or less in total (html, head, body) == new empty iframe about to be overwritten by its 'srcdoc'
|
||||
}
|
||||
|
||||
function addStyleToIFrameSrcDoc(iframe, styleElement) {
|
||||
if (g_disableAll) {
|
||||
return;
|
||||
}
|
||||
iframe.srcdoc += styleElement.outerHTML;
|
||||
// make sure the style is added in case srcdoc was malformed
|
||||
setTimeout(addStyleElement.bind(null, styleElement, iframe.contentDocument), 100);
|
||||
if (g_disableAll) {
|
||||
return;
|
||||
}
|
||||
iframe.srcdoc += styleElement.outerHTML;
|
||||
// make sure the style is added in case srcdoc was malformed
|
||||
setTimeout(addStyleElement.bind(null, styleElement, iframe.contentDocument), 100);
|
||||
}
|
||||
|
||||
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"; });
|
||||
}
|
||||
getDynamicIFrames(doc).forEach(function(iframe) {
|
||||
replaceAll(newStyles, iframe.contentDocument, pass2);
|
||||
});
|
||||
if (doc == document && !pass2) {
|
||||
g_styleElements = {};
|
||||
applyStyles(newStyles);
|
||||
replaceAll(newStyles, doc, true);
|
||||
}
|
||||
if (pass2) {
|
||||
oldStyles.forEach(function(style) { style.remove(); });
|
||||
}
|
||||
var oldStyles = [].slice.call(doc.querySelectorAll("STYLE.stylish" + (pass2 ? "[id$='-ghost']" : "")));
|
||||
if (!pass2) {
|
||||
oldStyles.forEach(function (style) {
|
||||
style.id += "-ghost";
|
||||
});
|
||||
}
|
||||
getDynamicIFrames(doc).forEach(function (iframe) {
|
||||
replaceAll(newStyles, iframe.contentDocument, pass2);
|
||||
});
|
||||
if (doc == document && !pass2) {
|
||||
g_styleElements = {};
|
||||
applyStyles(newStyles);
|
||||
replaceAll(newStyles, doc, true);
|
||||
}
|
||||
if (pass2) {
|
||||
oldStyles.forEach(function (style) {
|
||||
style.remove();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Observe dynamic IFRAMEs being added
|
||||
function initObserver() {
|
||||
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)
|
||||
addDocumentStylesToAllIFrames();
|
||||
return;
|
||||
}
|
||||
// move the check out of current execution context
|
||||
// because some same-domain (!) iframes fail to load when their "contentDocument" is accessed (!)
|
||||
// namely gmail's old chat iframe talkgadget.google.com
|
||||
setTimeout(process.bind(null, mutations), 0);
|
||||
});
|
||||
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)
|
||||
addDocumentStylesToAllIFrames();
|
||||
return;
|
||||
}
|
||||
// move the check out of current execution context
|
||||
// because some same-domain (!) iframes fail to load when their "contentDocument" is accessed (!)
|
||||
// namely gmail's old chat iframe talkgadget.google.com
|
||||
setTimeout(process.bind(null, mutations), 0);
|
||||
});
|
||||
|
||||
function process(mutations) {
|
||||
for (var m = 0, ml = mutations.length; m < ml; m++) {
|
||||
var mutation = mutations[m];
|
||||
if (mutation.type === "childList") {
|
||||
for (var n = 0, nodes = mutation.addedNodes, nl = nodes.length; n < nl; n++) {
|
||||
var node = nodes[n];
|
||||
if (node.localName === "iframe" && iframeIsDynamic(node)) {
|
||||
addDocumentStylesToIFrame(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function process(mutations) {
|
||||
for (var m = 0, ml = mutations.length; m < ml; m++) {
|
||||
var mutation = mutations[m];
|
||||
if (mutation.type === "childList") {
|
||||
for (var n = 0, nodes = mutation.addedNodes, nl = nodes.length; n < nl; n++) {
|
||||
var node = nodes[n];
|
||||
if (node.localName === "iframe" && iframeIsDynamic(node)) {
|
||||
addDocumentStylesToIFrame(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iframeObserver.start = function() {
|
||||
// will be ignored by browser if already observing
|
||||
iframeObserver.observe(document, {childList: true, subtree: true});
|
||||
}
|
||||
iframeObserver.start = function () {
|
||||
// will be ignored by browser if already observing
|
||||
iframeObserver.observe(document, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
};
|
||||
}
|
296
background.js
296
background.js
|
@ -1,9 +1,12 @@
|
|||
/*jshint undef:false*/
|
||||
var frameIdMessageable;
|
||||
runTryCatch(function() {
|
||||
chrome.tabs.sendMessage(0, {}, {frameId: 0}, function() {
|
||||
var clearError = chrome.runtime.lastError;
|
||||
frameIdMessageable = true;
|
||||
});
|
||||
runTryCatch(function () {
|
||||
chrome.tabs.sendMessage(0, {}, {
|
||||
frameId: 0
|
||||
}, function () {
|
||||
var clearError = chrome.runtime.lastError;
|
||||
frameIdMessageable = true;
|
||||
});
|
||||
});
|
||||
|
||||
// This happens right away, sometimes so fast that the content script isn't even ready. That's
|
||||
|
@ -11,159 +14,204 @@ runTryCatch(function() {
|
|||
chrome.webNavigation.onCommitted.addListener(webNavigationListener.bind(this, "styleApply"));
|
||||
// Not supported in Firefox - https://bugzilla.mozilla.org/show_bug.cgi?id=1239349
|
||||
if ("onHistoryStateUpdated" in chrome.webNavigation) {
|
||||
chrome.webNavigation.onHistoryStateUpdated.addListener(webNavigationListener.bind(this, "styleReplaceAll"));
|
||||
chrome.webNavigation.onHistoryStateUpdated.addListener(webNavigationListener.bind(this, "styleReplaceAll"));
|
||||
}
|
||||
chrome.webNavigation.onBeforeNavigate.addListener(webNavigationListener.bind(this, null));
|
||||
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (data.frameId == 0) {
|
||||
updateIcon({id: data.tabId, url: data.url}, styleHash);
|
||||
}
|
||||
});
|
||||
// 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) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
if (info.status == "loading" && info.url) {
|
||||
if (info.url.indexOf('#') > 0) {
|
||||
tabUrlHasHash[tabId] = true;
|
||||
} else if (tabUrlHasHash[tabId]) {
|
||||
delete tabUrlHasHash[tabId];
|
||||
} else {
|
||||
// do nothing since the tab neither had # before nor has # now
|
||||
return;
|
||||
}
|
||||
webNavigationListener("styleReplaceAll", {tabId: tabId, frameId: 0, url: info.url});
|
||||
}
|
||||
chrome.tabs.onUpdated.addListener(function (tabId, info, tab) {
|
||||
if (info.status == "loading" && info.url) {
|
||||
if (info.url.indexOf('#') > 0) {
|
||||
tabUrlHasHash[tabId] = true;
|
||||
} else if (tabUrlHasHash[tabId]) {
|
||||
delete tabUrlHasHash[tabId];
|
||||
} else {
|
||||
// do nothing since the tab neither had # before nor has # now
|
||||
return;
|
||||
}
|
||||
webNavigationListener("styleReplaceAll", {
|
||||
tabId: tabId,
|
||||
frameId: 0,
|
||||
url: info.url
|
||||
});
|
||||
}
|
||||
});
|
||||
chrome.tabs.onRemoved.addListener(function(tabId, info) {
|
||||
delete tabUrlHasHash[tabId];
|
||||
chrome.tabs.onRemoved.addListener(function (tabId, info) {
|
||||
delete tabUrlHasHash[tabId];
|
||||
});
|
||||
|
||||
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) {
|
||||
updateIcon(sender.tab, styles);
|
||||
}
|
||||
return true;
|
||||
case "saveStyle":
|
||||
saveStyle(request, sendResponse);
|
||||
return true;
|
||||
case "invalidateCache":
|
||||
if (typeof invalidateCache != "undefined") {
|
||||
invalidateCache(false);
|
||||
}
|
||||
break;
|
||||
case "healthCheck":
|
||||
getDatabase(function() { sendResponse(true); }, function() { sendResponse(false); });
|
||||
return true;
|
||||
case "openURL":
|
||||
openURL(request);
|
||||
break;
|
||||
case "styleDisableAll":
|
||||
chrome.contextMenus.update("disableAll", {checked: request.disableAll});
|
||||
break;
|
||||
case "prefChanged":
|
||||
if (request.prefName == "show-badge") {
|
||||
chrome.contextMenus.update("show-badge", {checked: request.value});
|
||||
}
|
||||
break;
|
||||
}
|
||||
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) {
|
||||
updateIcon(sender.tab, styles);
|
||||
}
|
||||
return true;
|
||||
case "saveStyle":
|
||||
saveStyle(request, sendResponse);
|
||||
return true;
|
||||
case "invalidateCache":
|
||||
if (typeof invalidateCache != "undefined") {
|
||||
invalidateCache(false);
|
||||
}
|
||||
break;
|
||||
case "healthCheck":
|
||||
getDatabase(function () {
|
||||
sendResponse(true);
|
||||
}, function () {
|
||||
sendResponse(false);
|
||||
});
|
||||
return true;
|
||||
case "openURL":
|
||||
openURL(request);
|
||||
break;
|
||||
case "styleDisableAll":
|
||||
chrome.contextMenus.update("disableAll", {
|
||||
checked: request.disableAll
|
||||
});
|
||||
break;
|
||||
case "prefChanged":
|
||||
if (request.prefName == "show-badge") {
|
||||
chrome.contextMenus.update("show-badge", {
|
||||
checked: request.value
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Not available in Firefox - https://bugzilla.mozilla.org/show_bug.cgi?id=1240350
|
||||
if ("commands" in chrome) {
|
||||
chrome.commands.onCommand.addListener(function(command) {
|
||||
switch (command) {
|
||||
case "openManage":
|
||||
openURL({url: chrome.extension.getURL("manage.html")});
|
||||
break;
|
||||
case "styleDisableAll":
|
||||
disableAllStylesToggle();
|
||||
chrome.contextMenus.update("disableAll", {checked: prefs.get("disableAll")});
|
||||
break;
|
||||
}
|
||||
});
|
||||
chrome.commands.onCommand.addListener(function (command) {
|
||||
switch (command) {
|
||||
case "openManage":
|
||||
openURL({
|
||||
url: chrome.extension.getURL("manage.html")
|
||||
});
|
||||
break;
|
||||
case "styleDisableAll":
|
||||
disableAllStylesToggle();
|
||||
chrome.contextMenus.update("disableAll", {
|
||||
checked: prefs.get("disableAll")
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 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() {
|
||||
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 });
|
||||
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 });
|
||||
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;
|
||||
});
|
||||
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;
|
||||
});
|
||||
});
|
||||
|
||||
chrome.contextMenus.onClicked.addListener(function(info, tab) {
|
||||
if (info.menuItemId == "disableAll") {
|
||||
disableAllStylesToggle(info.checked);
|
||||
} else {
|
||||
prefs.set(info.menuItemId, info.checked);
|
||||
}
|
||||
chrome.contextMenus.onClicked.addListener(function (info, tab) {
|
||||
if (info.menuItemId == "disableAll") {
|
||||
disableAllStylesToggle(info.checked);
|
||||
} else {
|
||||
prefs.set(info.menuItemId, info.checked);
|
||||
}
|
||||
});
|
||||
|
||||
function disableAllStylesToggle(newState) {
|
||||
if (newState === undefined || newState === null) {
|
||||
newState = !prefs.get("disableAll");
|
||||
}
|
||||
prefs.set("disableAll", newState);
|
||||
if (newState === undefined || newState === null) {
|
||||
newState = !prefs.get("disableAll");
|
||||
}
|
||||
prefs.set("disableAll", 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) {
|
||||
// If there's only one tab in this window, it's been dragged to new window
|
||||
prefs.set("openEditInWindow", win.tabs.length == 1);
|
||||
});
|
||||
}
|
||||
});
|
||||
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);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function openURL(options) {
|
||||
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) {});
|
||||
} else {
|
||||
delete options.method;
|
||||
getActiveTab(function(tab) {
|
||||
// re-use an active new tab page
|
||||
chrome.tabs[tab.url == "chrome://newtab/" ? "update" : "create"](options);
|
||||
});
|
||||
}
|
||||
});
|
||||
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) {});
|
||||
} else {
|
||||
delete options.method;
|
||||
getActiveTab(function (tab) {
|
||||
// re-use an active new tab page
|
||||
chrome.tabs[tab.url == "chrome://newtab/" ? "update" : "create"](options);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var codeMirrorThemes;
|
||||
getCodeMirrorThemes(function(themes) {
|
||||
codeMirrorThemes = themes;
|
||||
getCodeMirrorThemes(function (themes) {
|
||||
codeMirrorThemes = themes;
|
||||
});
|
9937
csslint/csslint.js
9937
csslint/csslint.js
File diff suppressed because it is too large
Load Diff
249
install.js
249
install.js
|
@ -1,136 +1,155 @@
|
|||
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];
|
||||
// maybe an update is needed
|
||||
// use the md5 if available
|
||||
var md5Url = getMeta("stylish-md5-url");
|
||||
if (md5Url && installedStyle.md5Url && installedStyle.originalMd5) {
|
||||
getResource(md5Url, function(md5) {
|
||||
if (md5 == installedStyle.originalMd5) {
|
||||
sendEvent("styleAlreadyInstalledChrome", {updateUrl: installedStyle.updateUrl});
|
||||
} else {
|
||||
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});
|
||||
}
|
||||
var json = JSON.parse(code);
|
||||
if (json.sections.length == installedStyle.sections.length) {
|
||||
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});
|
||||
return;
|
||||
};
|
||||
}
|
||||
sendEvent("styleCanBeUpdatedChrome", {updateUrl: installedStyle.updateUrl});
|
||||
});
|
||||
}
|
||||
}
|
||||
/*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];
|
||||
// maybe an update is needed
|
||||
// use the md5 if available
|
||||
var md5Url = getMeta("stylish-md5-url");
|
||||
if (md5Url && installedStyle.md5Url && installedStyle.originalMd5) {
|
||||
getResource(md5Url, function (md5) {
|
||||
if (md5 == installedStyle.originalMd5) {
|
||||
sendEvent("styleAlreadyInstalledChrome", {
|
||||
updateUrl: installedStyle.updateUrl
|
||||
});
|
||||
} else {
|
||||
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
|
||||
});
|
||||
}
|
||||
var json = JSON.parse(code);
|
||||
if (json.sections.length == installedStyle.sections.length) {
|
||||
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
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
sendEvent("styleCanBeUpdatedChrome", {
|
||||
updateUrl: installedStyle.updateUrl
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function sectionsAreEqual(a, b) {
|
||||
if (a.code != b.code) {
|
||||
return false;
|
||||
}
|
||||
return ["urls", "urlPrefixes", "domains", "regexps"].every(function(attribute) {
|
||||
return arraysAreEqual(a[attribute], b[attribute]);
|
||||
});
|
||||
if (a.code != b.code) {
|
||||
return false;
|
||||
}
|
||||
return ["urls", "urlPrefixes", "domains", "regexps"].every(function (attribute) {
|
||||
return arraysAreEqual(a[attribute], b[attribute]);
|
||||
});
|
||||
}
|
||||
|
||||
function arraysAreEqual(a, b) {
|
||||
// treat empty array and undefined as equivalent
|
||||
if (typeof a == "undefined")
|
||||
return (typeof b == "undefined") || (b.length == 0);
|
||||
if (typeof b == "undefined")
|
||||
return (typeof a == "undefined") || (a.length == 0);
|
||||
if (a.length != b.length) {
|
||||
return false;
|
||||
}
|
||||
return a.every(function(entry) {
|
||||
return b.indexOf(entry) != -1;
|
||||
});
|
||||
// treat empty array and undefined as equivalent
|
||||
if (typeof a == "undefined")
|
||||
return (typeof b == "undefined") || (b.length === 0);
|
||||
if (typeof b == "undefined")
|
||||
return (typeof a == "undefined") || (a.length === 0);
|
||||
if (a.length != b.length) {
|
||||
return false;
|
||||
}
|
||||
return a.every(function (entry) {
|
||||
return b.indexOf(entry) != -1;
|
||||
});
|
||||
}
|
||||
|
||||
function sendEvent(type, data) {
|
||||
if (typeof data == "undefined") {
|
||||
data = null;
|
||||
}
|
||||
var stylishEvent = new CustomEvent(type, {detail: data});
|
||||
document.dispatchEvent(stylishEvent);
|
||||
if (typeof data == "undefined") {
|
||||
data = null;
|
||||
}
|
||||
var stylishEvent = new CustomEvent(type, {
|
||||
detail: data
|
||||
});
|
||||
document.dispatchEvent(stylishEvent);
|
||||
}
|
||||
|
||||
document.addEventListener("stylishInstallChrome", function() {
|
||||
getResource(getMeta("stylish-description"), function(name) {
|
||||
if (confirm(chrome.i18n.getMessage('styleInstall', [name]))) {
|
||||
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) {
|
||||
sendEvent("styleInstalledChrome");
|
||||
});
|
||||
});
|
||||
getResource(getMeta("stylish-install-ping-url-chrome"));
|
||||
}
|
||||
});
|
||||
document.addEventListener("stylishInstallChrome", function () {
|
||||
getResource(getMeta("stylish-description"), function (name) {
|
||||
if (confirm(chrome.i18n.getMessage('styleInstall', [name]))) {
|
||||
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) {
|
||||
sendEvent("styleInstalledChrome");
|
||||
});
|
||||
});
|
||||
getResource(getMeta("stylish-install-ping-url-chrome"));
|
||||
}
|
||||
});
|
||||
}, false);
|
||||
|
||||
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) {
|
||||
var json = JSON.parse(code);
|
||||
json.method = "saveStyle";
|
||||
json.id = style.id;
|
||||
chrome.runtime.sendMessage(json, function() {
|
||||
sendEvent("styleInstalledChrome");
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
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) {
|
||||
var json = JSON.parse(code);
|
||||
json.method = "saveStyle";
|
||||
json.id = style.id;
|
||||
chrome.runtime.sendMessage(json, function () {
|
||||
sendEvent("styleInstalledChrome");
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}, false);
|
||||
|
||||
|
||||
function getMeta(name) {
|
||||
var e = document.querySelector("link[rel='" + name + "']");
|
||||
return e ? e.getAttribute("href") : null;
|
||||
var e = document.querySelector("link[rel='" + name + "']");
|
||||
return e ? e.getAttribute("href") : null;
|
||||
}
|
||||
|
||||
function getResource(url, callback) {
|
||||
if (url.indexOf("#") == 0) {
|
||||
if (callback) {
|
||||
callback(document.getElementById(url.substring(1)).innerText);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4 && callback) {
|
||||
if (xhr.status >= 400) {
|
||||
callback(null);
|
||||
} else {
|
||||
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.send(parts[1]);
|
||||
} else {
|
||||
xhr.open("GET", url, true);
|
||||
xhr.send();
|
||||
}
|
||||
if (url.indexOf("#") === 0) {
|
||||
if (callback) {
|
||||
callback(document.getElementById(url.substring(1)).innerText);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == 4 && callback) {
|
||||
if (xhr.status >= 400) {
|
||||
callback(null);
|
||||
} else {
|
||||
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.send(parts[1]);
|
||||
} else {
|
||||
xhr.open("GET", url, true);
|
||||
xhr.send();
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
887
manage.js
887
manage.js
|
@ -1,3 +1,4 @@
|
|||
/*jshint undef:false*/
|
||||
var lastUpdatedStyleId = null;
|
||||
var installed;
|
||||
|
||||
|
@ -5,519 +6,551 @@ 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);
|
||||
return;
|
||||
}
|
||||
if (!installed) {
|
||||
// "getStyles" message callback is invoked before document is loaded,
|
||||
// postpone the action until DOMContentLoaded is fired
|
||||
document.stylishStyles = styles;
|
||||
return;
|
||||
}
|
||||
styles.sort(function(a, b) { return a.name.localeCompare(b.name)});
|
||||
styles.map(createStyleElement).forEach(function(e) {
|
||||
installed.appendChild(e);
|
||||
});
|
||||
if (history.state) {
|
||||
window.scrollTo(0, history.state.scrollY);
|
||||
}
|
||||
if (!styles) { // Chrome is starting up
|
||||
chrome.runtime.sendMessage({
|
||||
method: "getStyles"
|
||||
}, showStyles);
|
||||
return;
|
||||
}
|
||||
if (!installed) {
|
||||
// "getStyles" message callback is invoked before document is loaded,
|
||||
// postpone the action until DOMContentLoaded is fired
|
||||
document.stylishStyles = styles;
|
||||
return;
|
||||
}
|
||||
styles.sort(function (a, b) {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
styles.map(createStyleElement).forEach(function (e) {
|
||||
installed.appendChild(e);
|
||||
});
|
||||
if (history.state) {
|
||||
window.scrollTo(0, history.state.scrollY);
|
||||
}
|
||||
}
|
||||
|
||||
function createStyleElement(style) {
|
||||
var e = template.style.cloneNode(true);
|
||||
e.setAttribute("class", style.enabled ? "enabled" : "disabled");
|
||||
e.setAttribute("style-id", style.id);
|
||||
if (style.updateUrl) {
|
||||
e.setAttribute("style-update-url", style.updateUrl);
|
||||
}
|
||||
if (style.md5Url) {
|
||||
e.setAttribute("style-md5-url", style.md5Url);
|
||||
}
|
||||
if (style.originalMd5) {
|
||||
e.setAttribute("style-original-md5", style.originalMd5);
|
||||
}
|
||||
var e = template.style.cloneNode(true);
|
||||
e.setAttribute("class", style.enabled ? "enabled" : "disabled");
|
||||
e.setAttribute("style-id", style.id);
|
||||
if (style.updateUrl) {
|
||||
e.setAttribute("style-update-url", style.updateUrl);
|
||||
}
|
||||
if (style.md5Url) {
|
||||
e.setAttribute("style-md5-url", style.md5Url);
|
||||
}
|
||||
if (style.originalMd5) {
|
||||
e.setAttribute("style-original-md5", style.originalMd5);
|
||||
}
|
||||
|
||||
var styleName = e.querySelector(".style-name");
|
||||
styleName.appendChild(document.createTextNode(style.name));
|
||||
if (style.url) {
|
||||
var homepage = template.styleHomepage.cloneNode(true)
|
||||
homepage.setAttribute("href", style.url);
|
||||
styleName.appendChild(document.createTextNode(" " ));
|
||||
styleName.appendChild(homepage);
|
||||
}
|
||||
var domains = [];
|
||||
var urls = [];
|
||||
var urlPrefixes = [];
|
||||
var regexps = [];
|
||||
function add(array, property) {
|
||||
style.sections.forEach(function(section) {
|
||||
if (section[property]) {
|
||||
section[property].filter(function(value) {
|
||||
return array.indexOf(value) == -1;
|
||||
}).forEach(function(value) {
|
||||
array.push(value);
|
||||
});;
|
||||
}
|
||||
});
|
||||
}
|
||||
add(domains, 'domains');
|
||||
add(urls, 'urls');
|
||||
add(urlPrefixes, 'urlPrefixes');
|
||||
add(regexps, 'regexps');
|
||||
var appliesToToShow = [];
|
||||
if (domains)
|
||||
appliesToToShow = appliesToToShow.concat(domains);
|
||||
if (urls)
|
||||
appliesToToShow = appliesToToShow.concat(urls);
|
||||
if (urlPrefixes)
|
||||
appliesToToShow = appliesToToShow.concat(urlPrefixes.map(function(u) { return u + "*"; }));
|
||||
if (regexps)
|
||||
appliesToToShow = appliesToToShow.concat(regexps.map(function(u) { return "/" + u + "/"; }));
|
||||
var appliesToString = "";
|
||||
var showAppliesToExtra = false;
|
||||
if (appliesToToShow.length == "")
|
||||
appliesToString = t('appliesToEverything');
|
||||
else if (appliesToToShow.length <= 10)
|
||||
appliesToString = appliesToToShow.join(", ");
|
||||
else {
|
||||
appliesToString = appliesToToShow.slice(0, 10).join(", ");
|
||||
showAppliesToExtra = true;
|
||||
}
|
||||
e.querySelector(".applies-to").appendChild(document.createTextNode(t('appliesDisplay', [appliesToString])));
|
||||
if (showAppliesToExtra) {
|
||||
e.querySelector(".applies-to").appendChild(appliesToExtraTemplate.cloneNode(true));
|
||||
}
|
||||
var editLink = e.querySelector(".style-edit-link");
|
||||
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 openWindow = left && shift && !ctrl;
|
||||
var openBackgroundTab = (middle && !shift) || (left && ctrl && !shift);
|
||||
var openForegroundTab = (middle && shift) || (left && ctrl && shift);
|
||||
var url = event.target.href || event.target.parentNode.href;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (openWindow || openBackgroundTab || openForegroundTab) {
|
||||
if (openWindow) {
|
||||
var options = prefs.get("windowPosition");
|
||||
options.url = url;
|
||||
chrome.windows.create(options);
|
||||
} else {
|
||||
chrome.runtime.sendMessage({
|
||||
method: "openURL",
|
||||
url: url,
|
||||
active: openForegroundTab
|
||||
});
|
||||
}
|
||||
} else {
|
||||
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(".check-update").addEventListener("click", doCheckUpdate, false);
|
||||
e.querySelector(".update").addEventListener("click", doUpdate, false);
|
||||
e.querySelector(".delete").addEventListener("click", doDelete, false);
|
||||
return e;
|
||||
var styleName = e.querySelector(".style-name");
|
||||
styleName.appendChild(document.createTextNode(style.name));
|
||||
if (style.url) {
|
||||
var homepage = template.styleHomepage.cloneNode(true);
|
||||
homepage.setAttribute("href", style.url);
|
||||
styleName.appendChild(document.createTextNode(" "));
|
||||
styleName.appendChild(homepage);
|
||||
}
|
||||
var domains = [];
|
||||
var urls = [];
|
||||
var urlPrefixes = [];
|
||||
var regexps = [];
|
||||
|
||||
function add(array, property) {
|
||||
style.sections.forEach(function (section) {
|
||||
if (section[property]) {
|
||||
section[property].filter(function (value) {
|
||||
return array.indexOf(value) == -1;
|
||||
}).forEach(function (value) {
|
||||
array.push(value);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
add(domains, 'domains');
|
||||
add(urls, 'urls');
|
||||
add(urlPrefixes, 'urlPrefixes');
|
||||
add(regexps, 'regexps');
|
||||
var appliesToToShow = [];
|
||||
if (domains)
|
||||
appliesToToShow = appliesToToShow.concat(domains);
|
||||
if (urls)
|
||||
appliesToToShow = appliesToToShow.concat(urls);
|
||||
if (urlPrefixes)
|
||||
appliesToToShow = appliesToToShow.concat(urlPrefixes.map(function (u) {
|
||||
return u + "*";
|
||||
}));
|
||||
if (regexps)
|
||||
appliesToToShow = appliesToToShow.concat(regexps.map(function (u) {
|
||||
return "/" + u + "/";
|
||||
}));
|
||||
var appliesToString = "";
|
||||
var showAppliesToExtra = false;
|
||||
if (appliesToToShow.length === "")
|
||||
appliesToString = t('appliesToEverything');
|
||||
else if (appliesToToShow.length <= 10)
|
||||
appliesToString = appliesToToShow.join(", ");
|
||||
else {
|
||||
appliesToString = appliesToToShow.slice(0, 10).join(", ");
|
||||
showAppliesToExtra = true;
|
||||
}
|
||||
e.querySelector(".applies-to").appendChild(document.createTextNode(t('appliesDisplay', [appliesToString])));
|
||||
if (showAppliesToExtra) {
|
||||
e.querySelector(".applies-to").appendChild(appliesToExtraTemplate.cloneNode(true));
|
||||
}
|
||||
var editLink = e.querySelector(".style-edit-link");
|
||||
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 openWindow = left && shift && !ctrl;
|
||||
var openBackgroundTab = (middle && !shift) || (left && ctrl && !shift);
|
||||
var openForegroundTab = (middle && shift) || (left && ctrl && shift);
|
||||
var url = event.target.href || event.target.parentNode.href;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (openWindow || openBackgroundTab || openForegroundTab) {
|
||||
if (openWindow) {
|
||||
var options = prefs.get("windowPosition");
|
||||
options.url = url;
|
||||
chrome.windows.create(options);
|
||||
} else {
|
||||
chrome.runtime.sendMessage({
|
||||
method: "openURL",
|
||||
url: url,
|
||||
active: openForegroundTab
|
||||
});
|
||||
}
|
||||
} else {
|
||||
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(".check-update").addEventListener("click", doCheckUpdate, false);
|
||||
e.querySelector(".update").addEventListener("click", doUpdate, false);
|
||||
e.querySelector(".delete").addEventListener("click", doDelete, false);
|
||||
return e;
|
||||
}
|
||||
|
||||
function enable(event, enabled) {
|
||||
var id = getId(event);
|
||||
enableStyle(id, enabled);
|
||||
var id = getId(event);
|
||||
enableStyle(id, enabled);
|
||||
}
|
||||
|
||||
function doDelete() {
|
||||
if (!confirm(t('deleteStyleConfirm'))) {
|
||||
return;
|
||||
}
|
||||
var id = getId(event);
|
||||
deleteStyle(id);
|
||||
if (!confirm(t('deleteStyleConfirm'))) {
|
||||
return;
|
||||
}
|
||||
var id = getId(event);
|
||||
deleteStyle(id);
|
||||
}
|
||||
|
||||
function getId(event) {
|
||||
return getStyleElement(event).getAttribute("style-id");
|
||||
return getStyleElement(event).getAttribute("style-id");
|
||||
}
|
||||
|
||||
function getStyleElement(event) {
|
||||
var e = event.target;
|
||||
while (e) {
|
||||
if (e.hasAttribute("style-id")) {
|
||||
return e;
|
||||
}
|
||||
e = e.parentNode;
|
||||
}
|
||||
return null;
|
||||
var e = event.target;
|
||||
while (e) {
|
||||
if (e.hasAttribute("style-id")) {
|
||||
return e;
|
||||
}
|
||||
e = e.parentNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
|
||||
switch (request.method) {
|
||||
case "styleUpdated":
|
||||
handleUpdate(request.style);
|
||||
break;
|
||||
case "styleAdded":
|
||||
installed.appendChild(createStyleElement(request.style));
|
||||
break;
|
||||
case "styleDeleted":
|
||||
handleDelete(request.id);
|
||||
break;
|
||||
}
|
||||
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
||||
switch (request.method) {
|
||||
case "styleUpdated":
|
||||
handleUpdate(request.style);
|
||||
break;
|
||||
case "styleAdded":
|
||||
installed.appendChild(createStyleElement(request.style));
|
||||
break;
|
||||
case "styleDeleted":
|
||||
handleDelete(request.id);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
function handleUpdate(style) {
|
||||
var element = createStyleElement(style);
|
||||
installed.replaceChild(element, installed.querySelector("[style-id='" + style.id + "']"));
|
||||
if (style.id == lastUpdatedStyleId) {
|
||||
lastUpdatedStyleId = null;
|
||||
element.className = element.className += " update-done";
|
||||
element.querySelector(".update-note").innerHTML = t('updateCompleted');
|
||||
};
|
||||
var element = createStyleElement(style);
|
||||
installed.replaceChild(element, installed.querySelector("[style-id='" + style.id + "']"));
|
||||
if (style.id == lastUpdatedStyleId) {
|
||||
lastUpdatedStyleId = null;
|
||||
element.className = element.className += " update-done";
|
||||
element.querySelector(".update-note").innerHTML = t('updateCompleted');
|
||||
}
|
||||
}
|
||||
|
||||
function handleDelete(id) {
|
||||
var node = installed.querySelector("[style-id='" + id + "']");
|
||||
if (node) {
|
||||
installed.removeChild(node);
|
||||
}
|
||||
var node = installed.querySelector("[style-id='" + id + "']");
|
||||
if (node) {
|
||||
installed.removeChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
function doCheckUpdate(event) {
|
||||
checkUpdate(getStyleElement(event));
|
||||
checkUpdate(getStyleElement(event));
|
||||
}
|
||||
|
||||
function applyUpdateAll() {
|
||||
var btnApply = document.getElementById("apply-all-updates");
|
||||
btnApply.disabled = true;
|
||||
setTimeout(function() {
|
||||
btnApply.style.display = "none";
|
||||
btnApply.disabled = false;
|
||||
}, 1000);
|
||||
var btnApply = document.getElementById("apply-all-updates");
|
||||
btnApply.disabled = true;
|
||||
setTimeout(function () {
|
||||
btnApply.style.display = "none";
|
||||
btnApply.disabled = false;
|
||||
}, 1000);
|
||||
|
||||
Array.prototype.forEach.call(document.querySelectorAll(".can-update .update"), function(button) {
|
||||
button.click();
|
||||
});
|
||||
Array.prototype.forEach.call(document.querySelectorAll(".can-update .update"), function (button) {
|
||||
button.click();
|
||||
});
|
||||
}
|
||||
|
||||
function checkUpdateAll() {
|
||||
var btnCheck = document.getElementById("check-all-updates");
|
||||
var btnApply = document.getElementById("apply-all-updates");
|
||||
var noUpdates = document.getElementById("update-all-no-updates");
|
||||
var btnCheck = document.getElementById("check-all-updates");
|
||||
var btnApply = document.getElementById("apply-all-updates");
|
||||
var noUpdates = document.getElementById("update-all-no-updates");
|
||||
|
||||
btnCheck.disabled = true;
|
||||
btnApply.classList.add("hidden");
|
||||
noUpdates.classList.add("hidden");
|
||||
btnCheck.disabled = true;
|
||||
btnApply.classList.add("hidden");
|
||||
noUpdates.classList.add("hidden");
|
||||
|
||||
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) {
|
||||
if (success) {
|
||||
++updatableCount;
|
||||
}
|
||||
if (--toCheckCount == 0) {
|
||||
btnCheck.disabled = false;
|
||||
if (updatableCount) {
|
||||
btnApply.classList.remove("hidden");
|
||||
} else {
|
||||
noUpdates.classList.remove("hidden");
|
||||
setTimeout(function() {
|
||||
noUpdates.classList.add("hidden");
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
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) {
|
||||
if (success) {
|
||||
++updatableCount;
|
||||
}
|
||||
if (--toCheckCount === 0) {
|
||||
btnCheck.disabled = false;
|
||||
if (updatableCount) {
|
||||
btnApply.classList.remove("hidden");
|
||||
} else {
|
||||
noUpdates.classList.remove("hidden");
|
||||
setTimeout(function () {
|
||||
noUpdates.classList.add("hidden");
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function checkUpdate(element, callback) {
|
||||
element.querySelector(".update-note").innerHTML = t('checkingForUpdate');
|
||||
element.className = element.className.replace("checking-update", "").replace("no-update", "").replace("can-update", "") + " checking-update";
|
||||
var id = element.getAttribute("style-id");
|
||||
var url = element.getAttribute("style-update-url");
|
||||
var md5Url = element.getAttribute("style-md5-url");
|
||||
var originalMd5 = element.getAttribute("style-original-md5");
|
||||
element.querySelector(".update-note").innerHTML = t('checkingForUpdate');
|
||||
element.className = element.className.replace("checking-update", "").replace("no-update", "").replace("can-update", "") + " checking-update";
|
||||
var id = element.getAttribute("style-id");
|
||||
var url = element.getAttribute("style-update-url");
|
||||
var md5Url = element.getAttribute("style-md5-url");
|
||||
var originalMd5 = element.getAttribute("style-original-md5");
|
||||
|
||||
function handleSuccess(forceUpdate, serverJson) {
|
||||
chrome.runtime.sendMessage({method: "getStyles", id: id}, function(styles) {
|
||||
var style = styles[0];
|
||||
var needsUpdate = false;
|
||||
if (!forceUpdate && codeIsEqual(style.sections, serverJson.sections)) {
|
||||
handleNeedsUpdate("no", id, serverJson);
|
||||
} else {
|
||||
handleNeedsUpdate("yes", id, serverJson);
|
||||
needsUpdate = true;
|
||||
}
|
||||
if (callback) {
|
||||
callback(needsUpdate);
|
||||
}
|
||||
});
|
||||
}
|
||||
function handleSuccess(forceUpdate, serverJson) {
|
||||
chrome.runtime.sendMessage({
|
||||
method: "getStyles",
|
||||
id: id
|
||||
}, function (styles) {
|
||||
var style = styles[0];
|
||||
var needsUpdate = false;
|
||||
if (!forceUpdate && codeIsEqual(style.sections, serverJson.sections)) {
|
||||
handleNeedsUpdate("no", id, serverJson);
|
||||
} else {
|
||||
handleNeedsUpdate("yes", id, serverJson);
|
||||
needsUpdate = true;
|
||||
}
|
||||
if (callback) {
|
||||
callback(needsUpdate);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleFailure(status) {
|
||||
if (status == 0) {
|
||||
handleNeedsUpdate(t('updateCheckFailServerUnreachable'), id, null);
|
||||
} else {
|
||||
handleNeedsUpdate(t('updateCheckFailBadResponseCode', [status]), id, null);
|
||||
}
|
||||
if (callback) {
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
function handleFailure(status) {
|
||||
if (status === 0) {
|
||||
handleNeedsUpdate(t('updateCheckFailServerUnreachable'), id, null);
|
||||
} else {
|
||||
handleNeedsUpdate(t('updateCheckFailBadResponseCode', [status]), id, null);
|
||||
}
|
||||
if (callback) {
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!md5Url || !originalMd5) {
|
||||
checkUpdateFullCode(url, false, handleSuccess, handleFailure)
|
||||
} else {
|
||||
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);
|
||||
} else {
|
||||
handleNeedsUpdate("no", id, null);
|
||||
if (callback) {
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
}, handleFailure);
|
||||
}
|
||||
if (!md5Url || !originalMd5) {
|
||||
checkUpdateFullCode(url, false, handleSuccess, handleFailure);
|
||||
} else {
|
||||
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);
|
||||
} else {
|
||||
handleNeedsUpdate("no", id, null);
|
||||
if (callback) {
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
}, handleFailure);
|
||||
}
|
||||
}
|
||||
|
||||
function checkUpdateFullCode(url, forceUpdate, successCallback, failureCallback) {
|
||||
download(url, function(responseText) {
|
||||
successCallback(forceUpdate, JSON.parse(responseText));
|
||||
}, failureCallback);
|
||||
download(url, function (responseText) {
|
||||
successCallback(forceUpdate, JSON.parse(responseText));
|
||||
}, failureCallback);
|
||||
}
|
||||
|
||||
function checkUpdateMd5(originalMd5, md5Url, successCallback, failureCallback) {
|
||||
download(md5Url, function(responseText) {
|
||||
if (responseText.length != 32) {
|
||||
failureCallback(-1);
|
||||
return;
|
||||
}
|
||||
successCallback(responseText != originalMd5);
|
||||
}, failureCallback);
|
||||
download(md5Url, function (responseText) {
|
||||
if (responseText.length != 32) {
|
||||
failureCallback(-1);
|
||||
return;
|
||||
}
|
||||
successCallback(responseText != originalMd5);
|
||||
}, failureCallback);
|
||||
}
|
||||
|
||||
function download(url, successCallback, failureCallback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function (aEvt) {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
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.send(parts[1]);
|
||||
} else {
|
||||
xhr.open("GET", url, true);
|
||||
xhr.send();
|
||||
}
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function (aEvt) {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
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.send(parts[1]);
|
||||
} else {
|
||||
xhr.open("GET", url, true);
|
||||
xhr.send();
|
||||
}
|
||||
}
|
||||
|
||||
function handleNeedsUpdate(needsUpdate, id, serverJson) {
|
||||
var e = document.querySelector("[style-id='" + id + "']");
|
||||
e.className = e.className.replace("checking-update", "");
|
||||
switch (needsUpdate) {
|
||||
case "yes":
|
||||
e.className += " can-update";
|
||||
e.updatedCode = serverJson;
|
||||
e.querySelector(".update-note").innerHTML = '';
|
||||
break;
|
||||
case "no":
|
||||
e.className += " no-update";
|
||||
e.querySelector(".update-note").innerHTML = t('updateCheckSucceededNoUpdate');
|
||||
break;
|
||||
default:
|
||||
e.className += " no-update";
|
||||
e.querySelector(".update-note").innerHTML = needsUpdate;
|
||||
}
|
||||
var e = document.querySelector("[style-id='" + id + "']");
|
||||
e.className = e.className.replace("checking-update", "");
|
||||
switch (needsUpdate) {
|
||||
case "yes":
|
||||
e.className += " can-update";
|
||||
e.updatedCode = serverJson;
|
||||
e.querySelector(".update-note").innerHTML = '';
|
||||
break;
|
||||
case "no":
|
||||
e.className += " no-update";
|
||||
e.querySelector(".update-note").innerHTML = t('updateCheckSucceededNoUpdate');
|
||||
break;
|
||||
default:
|
||||
e.className += " no-update";
|
||||
e.querySelector(".update-note").innerHTML = needsUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
function doUpdate(event) {
|
||||
var element = getStyleElement(event);
|
||||
var element = getStyleElement(event);
|
||||
|
||||
var updatedCode = element.updatedCode;
|
||||
// update everything but name
|
||||
delete updatedCode.name;
|
||||
updatedCode.id = element.getAttribute('style-id');
|
||||
updatedCode.method = "saveStyle";
|
||||
var updatedCode = element.updatedCode;
|
||||
// update everything but name
|
||||
delete updatedCode.name;
|
||||
updatedCode.id = element.getAttribute('style-id');
|
||||
updatedCode.method = "saveStyle";
|
||||
|
||||
// updating the UI will be handled by the general update listener
|
||||
lastUpdatedStyleId = updatedCode.id;
|
||||
chrome.runtime.sendMessage(updatedCode, function () {});
|
||||
// updating the UI will be handled by the general update listener
|
||||
lastUpdatedStyleId = updatedCode.id;
|
||||
chrome.runtime.sendMessage(updatedCode, function () {});
|
||||
}
|
||||
|
||||
function codeIsEqual(a, b) {
|
||||
if (a.length != b.length) {
|
||||
return false;
|
||||
}
|
||||
var properties = ["code", "urlPrefixes", "urls", "domains", "regexps"];
|
||||
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) {
|
||||
return jsonEquals(a[i], b[j], property);
|
||||
});
|
||||
if (allEquals) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
if (a.length != b.length) {
|
||||
return false;
|
||||
}
|
||||
var properties = ["code", "urlPrefixes", "urls", "domains", "regexps"];
|
||||
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) {
|
||||
return jsonEquals(a[i], b[j], property);
|
||||
});
|
||||
if (allEquals) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function jsonEquals(a, b, property) {
|
||||
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))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (typeA == "undefined") {
|
||||
return true;
|
||||
}
|
||||
if (typeA == "array") {
|
||||
if (aProp.length != bProp.length) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < aProp.length; i++) {
|
||||
if (bProp.indexOf(aProp[i]) == -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (typeA == "string") {
|
||||
return aProp == 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))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (typeA == "undefined") {
|
||||
return true;
|
||||
}
|
||||
if (typeA == "array") {
|
||||
if (aProp.length != bProp.length) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < aProp.length; i++) {
|
||||
if (bProp.indexOf(aProp[i]) == -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (typeA == "string") {
|
||||
return aProp == bProp;
|
||||
}
|
||||
}
|
||||
|
||||
function searchStyles(immediately) {
|
||||
var query = document.getElementById("search").value.toLocaleLowerCase();
|
||||
if (query == (searchStyles.lastQuery || "")) {
|
||||
return;
|
||||
}
|
||||
searchStyles.lastQuery = query;
|
||||
if (immediately) {
|
||||
doSearch();
|
||||
} else {
|
||||
clearTimeout(searchStyles.timeout);
|
||||
searchStyles.timeout = setTimeout(doSearch, 100);
|
||||
}
|
||||
function doSearch() {
|
||||
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";
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function isMatchingText(text) {
|
||||
return text.toLocaleLowerCase().indexOf(query) >= 0;
|
||||
}
|
||||
var query = document.getElementById("search").value.toLocaleLowerCase();
|
||||
if (query == (searchStyles.lastQuery || "")) {
|
||||
return;
|
||||
}
|
||||
searchStyles.lastQuery = query;
|
||||
if (immediately) {
|
||||
doSearch();
|
||||
} else {
|
||||
clearTimeout(searchStyles.timeout);
|
||||
searchStyles.timeout = setTimeout(doSearch, 100);
|
||||
}
|
||||
|
||||
function doSearch() {
|
||||
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";
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function isMatchingText(text) {
|
||||
return text.toLocaleLowerCase().indexOf(query) >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
function onFilterChange (className, event) {
|
||||
installed.classList.toggle(className, event.target.checked);
|
||||
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});
|
||||
node.addEventListener("change", onFilterChange.bind(undefined, className), false);
|
||||
onFilterChange(className, {
|
||||
target: node
|
||||
});
|
||||
}
|
||||
|
||||
function importStyles (e) {
|
||||
var file = e.target.files[0];
|
||||
var reader = new FileReader();
|
||||
var styles = [];
|
||||
function importStyles(e) {
|
||||
var file = e.target.files[0];
|
||||
var reader = new FileReader();
|
||||
var styles = [];
|
||||
|
||||
function save () {
|
||||
var style = styles.shift();
|
||||
if (style) {
|
||||
delete style.id;
|
||||
saveStyle(style, save);
|
||||
}
|
||||
else {
|
||||
window.location.reload()
|
||||
}
|
||||
}
|
||||
|
||||
reader.onloadend = function (evt) {
|
||||
try {
|
||||
styles = JSON.parse(evt.target.result);
|
||||
save();
|
||||
function save() {
|
||||
var style = styles.shift();
|
||||
if (style) {
|
||||
delete style.id;
|
||||
saveStyle(style, save);
|
||||
} else {
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
window.alert(e.message);
|
||||
|
||||
reader.onloadend = function (evt) {
|
||||
try {
|
||||
styles = JSON.parse(evt.target.result);
|
||||
save();
|
||||
} catch (e) {
|
||||
window.alert(e.message);
|
||||
}
|
||||
};
|
||||
reader.onerror = function (e) {
|
||||
window.alert(e.message);
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
||||
function selectAll() {
|
||||
document.execCommand('selectAll');
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
installed = document.getElementById("installed");
|
||||
if (document.stylishStyles) {
|
||||
showStyles(document.stylishStyles);
|
||||
delete document.stylishStyles;
|
||||
}
|
||||
};
|
||||
reader.onerror = function (e) {
|
||||
window.alert(e.message);
|
||||
}
|
||||
reader.readAsText(file)
|
||||
}
|
||||
|
||||
function selectAll () {
|
||||
document.execCommand('selectAll');
|
||||
}
|
||||
document.getElementById("check-all-updates").addEventListener("click", checkUpdateAll);
|
||||
document.getElementById("apply-all-updates").addEventListener("click", applyUpdateAll);
|
||||
document.getElementById("search").addEventListener("input", searchStyles);
|
||||
searchStyles(true); // re-apply filtering on history Back
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
installed = document.getElementById("installed");
|
||||
if (document.stylishStyles) {
|
||||
showStyles(document.stylishStyles);
|
||||
delete document.stylishStyles;
|
||||
}
|
||||
document.querySelector('input[type=file]').addEventListener('change', importStyles);
|
||||
document.querySelector('#import pre').addEventListener('click', selectAll);
|
||||
|
||||
document.getElementById("check-all-updates").addEventListener("click", checkUpdateAll);
|
||||
document.getElementById("apply-all-updates").addEventListener("click", applyUpdateAll);
|
||||
document.getElementById("search").addEventListener("input", searchStyles);
|
||||
searchStyles(true); // re-apply filtering on history Back
|
||||
|
||||
document.querySelector('input[type=file]').addEventListener('change', importStyles);
|
||||
document.querySelector('#import pre').addEventListener('click', selectAll);
|
||||
|
||||
setupLivePrefs([
|
||||
setupLivePrefs([
|
||||
"manage.onlyEnabled",
|
||||
"manage.onlyEdited",
|
||||
"show-badge",
|
||||
"popup.stylesFirst"
|
||||
]);
|
||||
initFilter("enabled-only", document.getElementById("manage.onlyEnabled"));
|
||||
initFilter("edited-only", document.getElementById("manage.onlyEdited"));
|
||||
initFilter("enabled-only", document.getElementById("manage.onlyEnabled"));
|
||||
initFilter("edited-only", document.getElementById("manage.onlyEdited"));
|
||||
|
||||
});
|
177
messaging.js
177
messaging.js
|
@ -1,90 +1,117 @@
|
|||
/*jshint undef:false*/
|
||||
function notifyAllTabs(request) {
|
||||
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});
|
||||
chrome.runtime.sendMessage(reqPopup);
|
||||
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
|
||||
});
|
||||
chrome.runtime.sendMessage(reqPopup);
|
||||
}
|
||||
|
||||
function updateIcon(tab, styles) {
|
||||
// while NTP is still loading only process the request for its main frame with a real url
|
||||
// (but when it's loaded we should process style toggle requests from popups, for example)
|
||||
if (tab.url == "chrome://newtab/" && tab.status != "complete") {
|
||||
return;
|
||||
}
|
||||
if (styles) {
|
||||
// check for not-yet-existing tabs e.g. omnibox instant search
|
||||
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) {
|
||||
styles.length = 0;
|
||||
for (var id in styles) {
|
||||
styles.length += id.match(/^\d+$/) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
stylesReceived(styles);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
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);
|
||||
} else {
|
||||
chrome.runtime.sendMessage({method: "getStyles", matchUrl: url, enabled: true}, stylesReceived);
|
||||
}
|
||||
});
|
||||
// while NTP is still loading only process the request for its main frame with a real url
|
||||
// (but when it's loaded we should process style toggle requests from popups, for example)
|
||||
if (tab.url == "chrome://newtab/" && tab.status != "complete") {
|
||||
return;
|
||||
}
|
||||
if (styles) {
|
||||
// check for not-yet-existing tabs e.g. omnibox instant search
|
||||
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) {
|
||||
styles.length = 0;
|
||||
for (var id in styles) {
|
||||
styles.length += id.match(/^\d+$/) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
stylesReceived(styles);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
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);
|
||||
} else {
|
||||
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" : "";
|
||||
chrome.browserAction.setIcon({
|
||||
path: {
|
||||
// Material Design 2016 new size is 16px
|
||||
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",
|
||||
},
|
||||
tabId: tab.id
|
||||
}, 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]});
|
||||
}
|
||||
});
|
||||
//console.log("Tab " + tab.id + " (" + tab.url + ") badge text set to '" + t + "'.");
|
||||
}
|
||||
function stylesReceived(styles) {
|
||||
var disableAll = "disableAll" in styles ? styles.disableAll : prefs.get("disableAll");
|
||||
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",
|
||||
// Chromium forks or non-chromium browsers may still use the traditional 19px
|
||||
19: "19" + postfix + ".png",
|
||||
38: "38" + postfix + ".png",
|
||||
},
|
||||
tabId: tab.id
|
||||
}, 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]
|
||||
});
|
||||
}
|
||||
});
|
||||
//console.log("Tab " + tab.id + " (" + tab.url + ") badge text set to '" + t + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
function getActiveTab(callback) {
|
||||
chrome.tabs.query({currentWindow: true, active: true}, function(tabs) {
|
||||
callback(tabs[0]);
|
||||
});
|
||||
chrome.tabs.query({
|
||||
currentWindow: true,
|
||||
active: true
|
||||
}, function (tabs) {
|
||||
callback(tabs[0]);
|
||||
});
|
||||
}
|
||||
|
||||
function getActiveTabRealURL(callback) {
|
||||
getActiveTab(function(tab) {
|
||||
getTabRealURL(tab, callback);
|
||||
});
|
||||
getActiveTab(function (tab) {
|
||||
getTabRealURL(tab, callback);
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
frame && callback(frame.url);
|
||||
});
|
||||
}
|
||||
if (tab.url != "chrome://newtab/") {
|
||||
callback(tab.url);
|
||||
} else {
|
||||
chrome.webNavigation.getFrame({
|
||||
tabId: tab.id,
|
||||
frameId: 0,
|
||||
processId: -1
|
||||
}, function (frame) {
|
||||
frame && callback(frame.url);
|
||||
});
|
||||
}
|
||||
}
|
330
popup.js
330
popup.js
|
@ -1,209 +1,235 @@
|
|||
/*jshint undef:false*/
|
||||
var writeStyleTemplate = document.createElement("a");
|
||||
writeStyleTemplate.className = "write-style-link";
|
||||
|
||||
var installed = document.getElementById("installed");
|
||||
|
||||
if (!prefs.get("popup.stylesFirst")) {
|
||||
document.body.insertBefore(document.querySelector("body > .actions"), installed);
|
||||
document.body.insertBefore(document.querySelector("body > .actions"), installed);
|
||||
}
|
||||
|
||||
getActiveTabRealURL(updatePopUp);
|
||||
|
||||
function updatePopUp(url) {
|
||||
var urlWillWork = /^(file|http|https|ftps?|chrome\-extension):/.exec(url);
|
||||
if (!urlWillWork) {
|
||||
document.body.classList.add("blocked");
|
||||
document.getElementById("unavailable").style.display = "block";
|
||||
return;
|
||||
}
|
||||
var urlWillWork = /^(file|http|https|ftps?|chrome\-extension):/.exec(url);
|
||||
if (!urlWillWork) {
|
||||
document.body.classList.add("blocked");
|
||||
document.getElementById("unavailable").style.display = "block";
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
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
|
||||
var writeStyleLinks = [],
|
||||
container = document.createElement('span');
|
||||
container.id = "match";
|
||||
// Write new style links
|
||||
var writeStyleLinks = [],
|
||||
container = document.createElement('span');
|
||||
container.id = "match";
|
||||
|
||||
// For this 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]
|
||||
));
|
||||
urlLink.title = "url-prefix(\"$\")".replace("$", url);
|
||||
writeStyleLinks.push(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);
|
||||
}
|
||||
// For this 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]
|
||||
));
|
||||
urlLink.title = "url-prefix(\"$\")".replace("$", url);
|
||||
writeStyleLinks.push(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);
|
||||
}
|
||||
|
||||
// For domain
|
||||
var domains = getDomains(url)
|
||||
domains.forEach(function(domain) {
|
||||
// Don't include TLD
|
||||
if (domains.length > 1 && domain.indexOf(".") == -1) {
|
||||
return;
|
||||
}
|
||||
var domainLink = writeStyleTemplate.cloneNode(true);
|
||||
domainLink.href = "edit.html?domain=" + encodeURIComponent(domain);
|
||||
domainLink.appendChild(document.createTextNode(domain));
|
||||
domainLink.title = "domain(\"$\")".replace("$", domain);
|
||||
domainLink.setAttribute("subdomain", domain.substring(0, domain.indexOf(".")));
|
||||
writeStyleLinks.push(domainLink);
|
||||
});
|
||||
// For domain
|
||||
var domains = getDomains(url);
|
||||
domains.forEach(function (domain) {
|
||||
// Don't include TLD
|
||||
if (domains.length > 1 && domain.indexOf(".") == -1) {
|
||||
return;
|
||||
}
|
||||
var domainLink = writeStyleTemplate.cloneNode(true);
|
||||
domainLink.href = "edit.html?domain=" + encodeURIComponent(domain);
|
||||
domainLink.appendChild(document.createTextNode(domain));
|
||||
domainLink.title = "domain(\"$\")".replace("$", domain);
|
||||
domainLink.setAttribute("subdomain", domain.substring(0, domain.indexOf(".")));
|
||||
writeStyleLinks.push(domainLink);
|
||||
});
|
||||
|
||||
var writeStyle = document.querySelector("#write-style");
|
||||
writeStyleLinks.forEach(function(link, index) {
|
||||
link.addEventListener("click", openLinkInTabOrWindow, false);
|
||||
container.appendChild(link);
|
||||
});
|
||||
if (prefs.get("popup.breadcrumbs")) {
|
||||
container.classList.add("breadcrumbs");
|
||||
container.appendChild(container.removeChild(container.firstChild));
|
||||
}
|
||||
writeStyle.appendChild(container);
|
||||
var writeStyle = document.querySelector("#write-style");
|
||||
writeStyleLinks.forEach(function (link, index) {
|
||||
link.addEventListener("click", openLinkInTabOrWindow, false);
|
||||
container.appendChild(link);
|
||||
});
|
||||
if (prefs.get("popup.breadcrumbs")) {
|
||||
container.classList.add("breadcrumbs");
|
||||
container.appendChild(container.removeChild(container.firstChild));
|
||||
}
|
||||
writeStyle.appendChild(container);
|
||||
}
|
||||
|
||||
function showStyles(styles) {
|
||||
var enabledFirst = prefs.get("popup.enabledFirst");
|
||||
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) {
|
||||
installed.innerHTML = "<div class='entry' id='no-styles'>" + t('noStylesForSite') + "</div>";
|
||||
}
|
||||
styles.map(createStyleElement).forEach(function(e) {
|
||||
installed.appendChild(e);
|
||||
});
|
||||
var enabledFirst = prefs.get("popup.enabledFirst");
|
||||
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) {
|
||||
installed.innerHTML = "<div class='entry' id='no-styles'>" + t('noStylesForSite') + "</div>";
|
||||
}
|
||||
styles.map(createStyleElement).forEach(function (e) {
|
||||
installed.appendChild(e);
|
||||
});
|
||||
}
|
||||
|
||||
function createStyleElement(style) {
|
||||
var e = template.style.cloneNode(true);
|
||||
var checkbox = e.querySelector(".checker");
|
||||
checkbox.id = "style-" + style.id;
|
||||
checkbox.checked = style.enabled;
|
||||
var e = template.style.cloneNode(true);
|
||||
var checkbox = e.querySelector(".checker");
|
||||
checkbox.id = "style-" + style.id;
|
||||
checkbox.checked = style.enabled;
|
||||
|
||||
e.setAttribute("class", "entry " + (style.enabled ? "enabled" : "disabled"));
|
||||
e.setAttribute("style-id", style.id);
|
||||
var styleName = e.querySelector(".style-name");
|
||||
styleName.appendChild(document.createTextNode(style.name));
|
||||
styleName.setAttribute("for", "style-" + style.id);
|
||||
styleName.checkbox = checkbox;
|
||||
var editLink = e.querySelector(".style-edit-link");
|
||||
editLink.setAttribute("href", editLink.getAttribute("href") + style.id);
|
||||
editLink.addEventListener("click", openLinkInTabOrWindow, false);
|
||||
e.setAttribute("class", "entry " + (style.enabled ? "enabled" : "disabled"));
|
||||
e.setAttribute("style-id", style.id);
|
||||
var styleName = e.querySelector(".style-name");
|
||||
styleName.appendChild(document.createTextNode(style.name));
|
||||
styleName.setAttribute("for", "style-" + style.id);
|
||||
styleName.checkbox = checkbox;
|
||||
var editLink = e.querySelector(".style-edit-link");
|
||||
editLink.setAttribute("href", editLink.getAttribute("href") + style.id);
|
||||
editLink.addEventListener("click", openLinkInTabOrWindow, false);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
e.querySelector(".delete").addEventListener("click", function() { doDelete(event, false); }, false);
|
||||
return e;
|
||||
e.querySelector(".delete").addEventListener("click", function () {
|
||||
doDelete(event, false);
|
||||
}, false);
|
||||
return e;
|
||||
}
|
||||
|
||||
function enable(event, enabled) {
|
||||
var id = getId(event);
|
||||
enableStyle(id, enabled);
|
||||
var id = getId(event);
|
||||
enableStyle(id, enabled);
|
||||
}
|
||||
|
||||
function doDelete() {
|
||||
// Opera can't do confirms in popups
|
||||
if (getBrowser() != "Opera") {
|
||||
if (!confirm(t('deleteStyleConfirm'))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var id = getId(event);
|
||||
deleteStyle(id);
|
||||
// Opera can't do confirms in popups
|
||||
if (getBrowser() != "Opera") {
|
||||
if (!confirm(t('deleteStyleConfirm'))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var id = getId(event);
|
||||
deleteStyle(id);
|
||||
}
|
||||
|
||||
function getBrowser() {
|
||||
if (navigator.userAgent.indexOf("OPR") > -1) {
|
||||
return "Opera";
|
||||
}
|
||||
return "Chrome";
|
||||
if (navigator.userAgent.indexOf("OPR") > -1) {
|
||||
return "Opera";
|
||||
}
|
||||
return "Chrome";
|
||||
}
|
||||
|
||||
function getId(event) {
|
||||
var e = event.target;
|
||||
while (e) {
|
||||
if (e.hasAttribute("style-id")) {
|
||||
return e.getAttribute("style-id");
|
||||
}
|
||||
e = e.parentNode;
|
||||
}
|
||||
return null;
|
||||
var e = event.target;
|
||||
while (e) {
|
||||
if (e.hasAttribute("style-id")) {
|
||||
return e.getAttribute("style-id");
|
||||
}
|
||||
e = e.parentNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function openLinkInTabOrWindow(event) {
|
||||
event.preventDefault();
|
||||
if (prefs.get("openEditInWindow", false)) {
|
||||
var options = {url: event.target.href}
|
||||
var wp = prefs.get("windowPosition", {});
|
||||
for (var k in wp) options[k] = wp[k];
|
||||
chrome.windows.create(options);
|
||||
} else {
|
||||
openLink(event);
|
||||
}
|
||||
close();
|
||||
event.preventDefault();
|
||||
if (prefs.get("openEditInWindow", false)) {
|
||||
var options = {
|
||||
url: event.target.href
|
||||
};
|
||||
var wp = prefs.get("windowPosition", {});
|
||||
for (var k in wp) options[k] = wp[k];
|
||||
chrome.windows.create(options);
|
||||
} else {
|
||||
openLink(event);
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
function openLink(event) {
|
||||
event.preventDefault();
|
||||
chrome.runtime.sendMessage({method: "openURL", url: event.target.href});
|
||||
close();
|
||||
event.preventDefault();
|
||||
chrome.runtime.sendMessage({
|
||||
method: "openURL",
|
||||
url: event.target.href
|
||||
});
|
||||
close();
|
||||
}
|
||||
|
||||
function handleUpdate(style) {
|
||||
var styleElement = installed.querySelector("[style-id='" + style.id + "']");
|
||||
if (styleElement) {
|
||||
installed.replaceChild(createStyleElement(style), styleElement);
|
||||
} else {
|
||||
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";
|
||||
installed.appendChild(createStyleElement(style));
|
||||
}
|
||||
});
|
||||
}
|
||||
var styleElement = installed.querySelector("[style-id='" + style.id + "']");
|
||||
if (styleElement) {
|
||||
installed.replaceChild(createStyleElement(style), styleElement);
|
||||
} else {
|
||||
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";
|
||||
installed.appendChild(createStyleElement(style));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleDelete(id) {
|
||||
var styleElement = installed.querySelector("[style-id='" + id + "']");
|
||||
if (styleElement) {
|
||||
installed.removeChild(styleElement);
|
||||
}
|
||||
var styleElement = installed.querySelector("[style-id='" + id + "']");
|
||||
if (styleElement) {
|
||||
installed.removeChild(styleElement);
|
||||
}
|
||||
}
|
||||
|
||||
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
|
||||
if (request.method == "updatePopup") {
|
||||
switch (request.reason) {
|
||||
case "styleAdded":
|
||||
case "styleUpdated":
|
||||
handleUpdate(request.style);
|
||||
break;
|
||||
case "styleDeleted":
|
||||
handleDelete(request.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
||||
if (request.method == "updatePopup") {
|
||||
switch (request.reason) {
|
||||
case "styleAdded":
|
||||
case "styleUpdated":
|
||||
handleUpdate(request.style);
|
||||
break;
|
||||
case "styleDeleted":
|
||||
handleDelete(request.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
["find-styles-link", "open-manage-link"].forEach(function(id) {
|
||||
document.getElementById(id).addEventListener("click", openLink, false);
|
||||
["find-styles-link", "open-manage-link"].forEach(function (id) {
|
||||
document.getElementById(id).addEventListener("click", openLink, false);
|
||||
});
|
||||
|
||||
document.getElementById("disableAll").addEventListener("change", function(event) {
|
||||
installed.classList.toggle("disabled", prefs.get("disableAll"));
|
||||
document.getElementById("disableAll").addEventListener("change", function (event) {
|
||||
installed.classList.toggle("disabled", prefs.get("disableAll"));
|
||||
});
|
||||
setupLivePrefs(["disableAll"]);
|
|
@ -1,169 +1,193 @@
|
|||
/*jshint undef:false*/
|
||||
var webSqlStorage = {
|
||||
|
||||
migrate: function() {
|
||||
if (typeof openDatabase == "undefined") {
|
||||
// No WebSQL - no migration!
|
||||
return;
|
||||
}
|
||||
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)
|
||||
os.add(s);
|
||||
});
|
||||
// While this was running, the styles were loaded from the (empty) indexed db
|
||||
setTimeout(function() {
|
||||
invalidateCache(true);
|
||||
}, 500);
|
||||
});
|
||||
}, null);
|
||||
},
|
||||
migrate: function () {
|
||||
if (typeof openDatabase == "undefined") {
|
||||
// No WebSQL - no migration!
|
||||
return;
|
||||
}
|
||||
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);
|
||||
os.add(s);
|
||||
});
|
||||
// While this was running, the styles were loaded from the (empty) indexed db
|
||||
setTimeout(function () {
|
||||
invalidateCache(true);
|
||||
}, 500);
|
||||
});
|
||||
}, null);
|
||||
},
|
||||
|
||||
cleanStyle: function(s) {
|
||||
delete s.id;
|
||||
s.sections.forEach(function(section) {
|
||||
delete section.id;
|
||||
["urls", "urlPrefixes", "domains", "regexps"].forEach(function(property) {
|
||||
if (!section[property]) {
|
||||
section[property] = [];
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
cleanStyle: function (s) {
|
||||
delete s.id;
|
||||
s.sections.forEach(function (section) {
|
||||
delete section.id;
|
||||
["urls", "urlPrefixes", "domains", "regexps"].forEach(function (property) {
|
||||
if (!section[property]) {
|
||||
section[property] = [];
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
getStyles: function(callback) {
|
||||
webSqlStorage.getDatabase(function(db) {
|
||||
if (!db) {
|
||||
callback([]);
|
||||
return;
|
||||
}
|
||||
db.readTransaction(function (t) {
|
||||
var where = "";
|
||||
var params = [];
|
||||
getStyles: function (callback) {
|
||||
webSqlStorage.getDatabase(function (db) {
|
||||
if (!db) {
|
||||
callback([]);
|
||||
return;
|
||||
}
|
||||
db.readTransaction(function (t) {
|
||||
var where = "";
|
||||
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;
|
||||
for (var i = 0; i < r.rows.length; i++) {
|
||||
var values = r.rows.item(i);
|
||||
var metaName = null;
|
||||
switch (values.metaName) {
|
||||
case null:
|
||||
break;
|
||||
case "url":
|
||||
metaName = "urls";
|
||||
break;
|
||||
case "url-prefix":
|
||||
metaName = "urlPrefixes";
|
||||
break;
|
||||
case "domain":
|
||||
var metaName = "domains";
|
||||
break;
|
||||
case "regexps":
|
||||
var metaName = "regexps";
|
||||
break;
|
||||
default:
|
||||
var 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: []};
|
||||
styles.push(currentStyle);
|
||||
}
|
||||
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) {
|
||||
if (currentSection[metaName]) {
|
||||
currentSection[metaName].push(metaValue);
|
||||
} else {
|
||||
currentSection[metaName] = [metaValue];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
callback(styles);
|
||||
}, reportError);
|
||||
}, reportError);
|
||||
}, reportError);
|
||||
},
|
||||
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 = [],
|
||||
currentStyle = null,
|
||||
currentSection = null,
|
||||
metaName;
|
||||
for (var i = 0; i < r.rows.length; i++) {
|
||||
var values = r.rows.item(i);
|
||||
metaName = null;
|
||||
switch (values.metaName) {
|
||||
case null:
|
||||
break;
|
||||
case "url":
|
||||
metaName = "urls";
|
||||
break;
|
||||
case "url-prefix":
|
||||
metaName = "urlPrefixes";
|
||||
break;
|
||||
case "domain":
|
||||
metaName = "domains";
|
||||
break;
|
||||
case "regexps":
|
||||
metaName = "regexps";
|
||||
break;
|
||||
default:
|
||||
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: []
|
||||
};
|
||||
styles.push(currentStyle);
|
||||
}
|
||||
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) {
|
||||
if (currentSection[metaName]) {
|
||||
currentSection[metaName].push(metaValue);
|
||||
} else {
|
||||
currentSection[metaName] = [metaValue];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
callback(styles);
|
||||
}, reportError);
|
||||
}, reportError);
|
||||
}, reportError);
|
||||
},
|
||||
|
||||
getDatabase: function(ready, error) {
|
||||
try {
|
||||
stylishDb = openDatabase('stylish', '', 'Stylish Styles', 5*1024*1024);
|
||||
} catch (ex) {
|
||||
error();
|
||||
throw ex;
|
||||
}
|
||||
if (stylishDb.version == "") {
|
||||
// It didn't already exist, we have nothing to migrate.
|
||||
ready(null);
|
||||
return;
|
||||
}
|
||||
if (stylishDb.version == "1.0") {
|
||||
webSqlStorage.dbV11(stylishDb, error, ready);
|
||||
} else if (stylishDb.version == "1.1") {
|
||||
webSqlStorage.dbV12(stylishDb, error, ready);
|
||||
} else if (stylishDb.version == "1.2") {
|
||||
webSqlStorage.dbV13(stylishDb, error, ready);
|
||||
} else if (stylishDb.version == "1.3") {
|
||||
webSqlStorage.dbV14(stylishDb, error, ready);
|
||||
} else if (stylishDb.version == "1.4") {
|
||||
webSqlStorage.dbV15(stylishDb, error, ready);
|
||||
} else {
|
||||
ready(stylishDb);
|
||||
}
|
||||
},
|
||||
getDatabase: function (ready, error) {
|
||||
try {
|
||||
stylishDb = openDatabase('stylish', '', 'Stylish Styles', 5 * 1024 * 1024);
|
||||
} catch (ex) {
|
||||
error();
|
||||
throw ex;
|
||||
}
|
||||
if (stylishDb.version === "") {
|
||||
// It didn't already exist, we have nothing to migrate.
|
||||
ready(null);
|
||||
return;
|
||||
}
|
||||
if (stylishDb.version == "1.0") {
|
||||
webSqlStorage.dbV11(stylishDb, error, ready);
|
||||
} else if (stylishDb.version == "1.1") {
|
||||
webSqlStorage.dbV12(stylishDb, error, ready);
|
||||
} else if (stylishDb.version == "1.2") {
|
||||
webSqlStorage.dbV13(stylishDb, error, ready);
|
||||
} else if (stylishDb.version == "1.3") {
|
||||
webSqlStorage.dbV14(stylishDb, error, ready);
|
||||
} else if (stylishDb.version == "1.4") {
|
||||
webSqlStorage.dbV15(stylishDb, error, ready);
|
||||
} else {
|
||||
ready(stylishDb);
|
||||
}
|
||||
},
|
||||
|
||||
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)});
|
||||
},
|
||||
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);
|
||||
});
|
||||
},
|
||||
|
||||
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);');
|
||||
t.executeSql('INSERT INTO sections (style_id, code) SELECT id, code FROM styles;');
|
||||
// switch meta to sections
|
||||
t.executeSql('DROP INDEX style_meta_style_id;');
|
||||
t.executeSql('CREATE TABLE section_meta (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, section_id INTEGER NOT NULL, name TEXT NOT NULL, value TEXT NOT NULL);');
|
||||
t.executeSql('INSERT INTO section_meta (section_id, name, value) SELECT s.id, sm.name, sm.value FROM sections s INNER JOIN style_meta sm ON sm.style_id = s.style_id;');
|
||||
t.executeSql('CREATE INDEX section_meta_section_id ON section_meta (section_id);');
|
||||
t.executeSql('DROP TABLE style_meta;');
|
||||
// drop extra fields from styles table
|
||||
t.executeSql('CREATE TABLE newstyles (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, url TEXT, updateUrl TEXT, md5Url TEXT, name TEXT NOT NULL, enabled INTEGER NOT NULL);');
|
||||
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)});
|
||||
},
|
||||
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);');
|
||||
t.executeSql('INSERT INTO sections (style_id, code) SELECT id, code FROM styles;');
|
||||
// switch meta to sections
|
||||
t.executeSql('DROP INDEX style_meta_style_id;');
|
||||
t.executeSql('CREATE TABLE section_meta (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, section_id INTEGER NOT NULL, name TEXT NOT NULL, value TEXT NOT NULL);');
|
||||
t.executeSql('INSERT INTO section_meta (section_id, name, value) SELECT s.id, sm.name, sm.value FROM sections s INNER JOIN style_meta sm ON sm.style_id = s.style_id;');
|
||||
t.executeSql('CREATE INDEX section_meta_section_id ON section_meta (section_id);');
|
||||
t.executeSql('DROP TABLE style_meta;');
|
||||
// drop extra fields from styles table
|
||||
t.executeSql('CREATE TABLE newstyles (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, url TEXT, updateUrl TEXT, md5Url TEXT, name TEXT NOT NULL, enabled INTEGER NOT NULL);');
|
||||
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);
|
||||
});
|
||||
},
|
||||
|
||||
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)});
|
||||
},
|
||||
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);
|
||||
});
|
||||
},
|
||||
|
||||
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)});
|
||||
},
|
||||
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);
|
||||
});
|
||||
},
|
||||
|
||||
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); });
|
||||
}
|
||||
}
|
||||
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);
|
||||
});
|
||||
}
|
||||
};
|
1025
storage.js
1025
storage.js
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user