diff --git a/substitutions/html/config.html b/substitutions/html/config.html index 69ecacf..c2f5c78 100644 --- a/substitutions/html/config.html +++ b/substitutions/html/config.html @@ -48,6 +48,19 @@

XKCD Substitutions

+
+

Use XKCD Font

+

To help you remember that the page is more awesome, this extension can write its substitutions in Randall's handwriting, just like the font on this page.

+
+
+ +
+
+
+

Website Blacklist

While this extension tries not to affect things like login forms or emails, due to the complex nature of websites this cannot be guaranteed. So there is a way to stop this extension working on specific sites.

diff --git a/substitutions/js/background.js b/substitutions/js/background.js index 541b7c0..855ff3c 100644 --- a/substitutions/js/background.js +++ b/substitutions/js/background.js @@ -79,6 +79,7 @@ var default_blacklisted_sites = [ "outlook.com", "xkcd.com" ]; +var default_use_font = true; var debug = false; @@ -113,7 +114,9 @@ function addMessage(request, sender, sendResponse) { if (debug) { console.log("message fire"); } chrome.storage.sync.get(null, function(result) { if (request === "config" && result["replacements"]) { - sendResponse(result["replacements"]); + sendResponse({"replacements": result["replacements"], + "useFont": result["useFont"], + "fontUrl": chrome.extension.getURL("fonts/xkcd.otf")}); } }); return true; @@ -137,6 +140,11 @@ function fixDataCorruption() { "blacklist": default_blacklisted_sites }); } + if (!result["useFont"]) { + chrome.storage.sync.set({ + "useFont": default_use_font + }); + } }); } diff --git a/substitutions/js/options.js b/substitutions/js/options.js index f249e6c..028fe01 100644 --- a/substitutions/js/options.js +++ b/substitutions/js/options.js @@ -16,6 +16,7 @@ function makeClean() { function saveOptions(e) { e.preventDefault; console.log("ping"); + var useFont = $("#use-font").prop("checked"); var blacklist = $("#website-blacklist").val().replace(/\s+/g, "").toLowerCase().split(","); var replacements = []; var originals = $('#replacements [name="origin"]'); @@ -30,7 +31,8 @@ function saveOptions(e) { }; chrome.storage.sync.set({ "blacklist": blacklist, - "replacements": replacements + "replacements": replacements, + "useFont": useFont }, function() { makeClean(); @@ -41,7 +43,8 @@ function saveOptions(e) { function reset(){ chrome.storage.sync.set({ "blacklist": default_blacklisted_sites, - "replacements": default_replacements + "replacements": default_replacements, + "useFont": default_use_font }, function() { makeClean(); @@ -53,7 +56,9 @@ function reset(){ function populateSettings() { $("#replacements").empty(); $("blacklist input").val(""); + $("#use-font").prop("checked", false); chrome.storage.sync.get(null, function(result) { + $("#use-font").prop("checked", result["useFont"]); $("#blacklist input").val(result["blacklist"].join(", ")); var replacements = result['replacements']; for (var i = 0; i < replacements.length; i++) { @@ -94,7 +99,9 @@ $(document).ready(function() { $("#refresh").on('click', populateSettings); - $("#reset").on('click', reset) + $("#reset").on('click', reset); + + $("#use-font").on('click', makeDirty); $("#blacklist").keypress(function(e) { if (e.which == 13) { diff --git a/substitutions/js/substitutions.js b/substitutions/js/substitutions.js index bd8023a..3471942 100644 --- a/substitutions/js/substitutions.js +++ b/substitutions/js/substitutions.js @@ -2,7 +2,8 @@ // Icon and idea are from www.xkcd.com/1288 chrome.runtime.sendMessage("config", function(response) { "use strict"; - // taken from http://stackoverflow.com/questions/17264639/replace-text-but-keep-case + + // Taken from http://stackoverflow.com/questions/17264639/replace-text-but-keep-case function matchCase(text, pattern) { var result = ''; for (var i = 0; i < text.length; i++) { @@ -16,40 +17,134 @@ chrome.runtime.sendMessage("config", function(response) { } return result; } - var substitute = (function() { - "use strict"; - var replacements, ignore, i, replacementsObject, original; - replacements = response; - replacementsObject = []; - for (i = replacements.length - 1; i >= 0; i--) { - original = new RegExp("\\b" + replacements[i][0] + "\\b", "gi"); - replacementsObject.push([original, replacements[i][1]]); - } - return function(node) { - var i; - var ignore = { - "STYLE": 0, - "SCRIPT": 0, - "NOSCRIPT": 0, - "IFRAME": 0, - "OBJECT": 0, - "INPUT": 0, - "FORM": 0, - "TEXTAREA": 0 - }; - if (node.parentElement.tagName in ignore) { - return; + + // Taken from Google's Closure library, goog.string.regExpEscape + function regExpEscape(s) { + return String(s) + .replace(/([-()\[\]{}+?*.$\^|,:#= 0; i--) { + replacementsMap[replacements[i][0].toLowerCase()] = replacements[i][1]; + } + var ignore = { + "STYLE": 0, + "SCRIPT": 0, + "NOSCRIPT": 0, + "IFRAME": 0, + "OBJECT": 0, + "INPUT": 0, + "FORM": 0, + "TEXTAREA": 0 + }; + + // Set up the functions we'll need to perform the iteration. + var node; + var iter; + + var filter = { + acceptNode: function(node) { + if (node.nodeType == Node.TEXT_NODE) { + // This is a text node that we should show to the + // filter. + return NodeFilter.FILTER_ACCEPT; + } + if (node.nodeType == Node.ELEMENT_NODE) { + // Fold to upper case before checking the tag name, + // since this may be XHTML etc. + if (node.tagName.toUpperCase() in ignore) { + // Ignore this element, and all its children. + return NodeFilter.FILTER_REJECT; + } + if (node.classList.contains("xkcdSubstitutionsExtensionSubbed")) { + // We've already changed this text. Note that some + // other extension or the page's own scripts may + // have made more changes to what we did, so don't + // fight back and forth, constantly changing the + // DOM. Instead, just skip this subtree entirely. + return NodeFilter.FILTER_REJECT; + } + } + // This is not a node we're interested in. Skip this node, + // but process its children. + return NodeFilter.FILTER_SKIP; } - for (i = replacementsObject.length - 1; i >= 0; i--) { - node.nodeValue = node.nodeValue.replace(replacementsObject[i][0], function(match) { - return matchCase(replacementsObject[i][1], match); - }); + }; + + function substitute(node) { + var replacementIdx; + var splitIdx; + + // Before starting, make sure there's something to substitute. + // Otherwise, we end up doing a lot of expensive tree modification + // for no reason. + if (!node.nodeValue.match(originalsRegexp)) { + return; + } + + // Prepare a document fragment to hold the result. + var docFrag = document.createDocumentFragment(); + + // Split the string into substring, where each substring either contains + // something we'll substitute, or something that we won't. We do this + // by using the capturing parentheses in originalsRegexp. + var splits = node.nodeValue.split(originalsRegexp); + for (splitIdx = 0; splitIdx < splits.length; splitIdx++) { + var splitString = splits[splitIdx]; + var splitStringLower = splitString.toLowerCase(); + var newNode; + if (splitStringLower in replacementsMap) { + // This is something that needs to be changed. + newNode = document.createElement("span"); + newNode.setAttribute("class", "xkcdSubstitutionsExtensionSubbed"); + newNode.setAttribute("title", splitString); + newNode.textContent = matchCase(replacementsMap[splitStringLower], + splitString); + } else { + // This is a stretch between stuff that needs changing. + newNode = document.createTextNode(splitString); } - }; - })(); + docFrag.appendChild(newNode); + } + + // Let the tree walker know that its place has changed: the old + // node it sent us is gone, and so we'll update its current place + // to refer to the last node we've processed. + iter.currentNode = docFrag.lastChild; + // Make the changes. + node.parentNode.replaceChild(docFrag, node); + } - var node, iter; - var iter = document.createNodeIterator(document.body, NodeFilter.SHOW_TEXT); + iter = document.createTreeWalker(document.body, + NodeFilter.SHOW_ELEMENT | + NodeFilter.SHOW_TEXT, + filter); while ((node = iter.nextNode())) { substitute(node); } diff --git a/substitutions/manifest.json b/substitutions/manifest.json index 2684325..d2d177e 100644 --- a/substitutions/manifest.json +++ b/substitutions/manifest.json @@ -16,6 +16,9 @@ ], "persistent": false }, + "web_accessible_resources": [ + "fonts/xkcd.otf" + ], "permissions": [ "tabs", "storage",