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