diff --git a/Readme.md b/Readme.md
index 7b853a8..d94b2a2 100644
--- a/Readme.md
+++ b/Readme.md
@@ -1,12 +1,12 @@
Re-Pagination
===
-This add-on is mostly a rewrite of the old re-pagination/antipagination extension for Firefox.
-Lev assigned ownership over to this project, so that this incarnation is now the official one.
+This add-on is an update of the old re-pagination/antipagination extension for Firefox 57+.
+Nils Maier has not assigned ownership over to this project, so this is still a fork.
Features
===
-* Fully restartless
-* Should prevent some |jank|ing compared to the original extension
+* WebExtension compatible with Firefox Quantum
+* Compatible with more sites
* All, limited and slideshow
diff --git a/_locales/de/messages.json b/_locales/de/messages.json
new file mode 100644
index 0000000..8477d08
--- /dev/null
+++ b/_locales/de/messages.json
@@ -0,0 +1,85 @@
+{
+ "displaySubmenu_label": {
+ "message": "Untermenü anzeigen"
+ },
+ "displaySubmenu_desc": {
+ "message": "Wenn diese Option aktiviert ist (Standard), dann wird Re-Pagination als Untermenü angezeigt anstatt die verschiedenen Aktionen direkt im Kontextmenü anzuzeigen."
+ },
+ "showslideshow_label": {
+ "message": "'Slide-Show' Menüeintrag anzeigen"
+ },
+ "showalldomain_label": {
+ "message": "'Alle Tabs der aktuellen Domain' Menüeintrag anzeigen"
+ },
+ "loglevel_label": {
+ "message": "Protokoll Stufe"
+ },
+ "loglevel_desc": {
+ "message": "Die Nachrichten werden in der Fehlerkonsole protokolliert. Man sollte diese Einstellung auf 'Keine Protokollierung' belassen, wenn nicht anders angewiesen."
+ },
+ "loglevel_none_label": {
+ "message": "Keine Protokollierung"
+ },
+ "loglevel_error_label": {
+ "message": "Fehler protokollieren"
+ },
+ "loglevel_info_label": {
+ "message": "Fehler und Infos protokollieren"
+ },
+ "loglevel_debug_label": {
+ "message": "Alles protokollieren!"
+ },
+ "menu_label": {
+ "message": "Re-Pagination"
+ },
+ "repagination_nolimit": {
+ "message": "Alle laden"
+ },
+ "repagination_nolimit_domain": {
+ "message": "'Alle Tabs der aktuellen Domain'"
+ },
+ "repagination_limit": {
+ "message": "Begrenzt"
+ },
+ "repagination_slide": {
+ "message": "Slide-Show"
+ },
+ "repagination_slide_0": {
+ "message": "Sofort"
+ },
+ "repagination_slide_1": {
+ "message": "1 Sekunde"
+ },
+ "repagination_slide_60": {
+ "message": "1 Minute"
+ },
+ "repagination_stop": {
+ "message": "Stoppen!"
+ },
+ "repagination_limit_x": {
+ "message": "$1 Seiten"
+ },
+ "repagination_slide_120": {
+ "message": "2 Minuten"
+ },
+ "repagination_slide_x": {
+ "message": "$1 Sekunden"
+ },
+
+ "repagination_limited": {
+ "message": "($1 of $2) Re-Pagination arbeitet..."
+ },
+ "repagination_unlimited": {
+ "message": "($1) Re-Pagination arbeitet..."
+ },
+ "repagination_running": {
+ "message": "Re-Pagination arbeitet..."
+ },
+
+ "extensionName": {
+ "message": "Re-Pagination"
+ },
+ "extensionDescription": {
+ "message": "Alle fortlaufenden Seiten in einem einzigem Tab auf einmal laden"
+ }
+}
\ No newline at end of file
diff --git a/_locales/en/messages.json b/_locales/en/messages.json
new file mode 100644
index 0000000..5d54487
--- /dev/null
+++ b/_locales/en/messages.json
@@ -0,0 +1,83 @@
+{
+ "displaySubmenu_label": {
+ "message": "Display submenu"
+ },
+ "displaySubmenu_desc": {
+ "message": "When this option is enabled (default), then Re-Pagination will be displayed as a submenu instead of displaying the various actions directly within the context menu."
+ },
+ "showslideshow_label": {
+ "message": "Show 'Slideshow' menu item"
+ },
+ "showalldomain_label": {
+ "message": "Show 'All tabs for current domain' menu item"
+ },
+ "loglevel_label": {
+ "message": "Log level"
+ },
+ "loglevel_desc": {
+ "message": "The messages will be logged to the Error Console. You should leave this at 'No Logging' unless instructed otherwise"
+ },
+ "loglevel_none_label": {
+ "message": "No Logging"
+ },
+ "loglevel_error_label": {
+ "message": "Log Errors"
+ },
+ "loglevel_info_label": {
+ "message": "Log Errors and Infos"
+ },
+ "loglevel_debug_label": {
+ "message": "Log Everything!"
+ },
+ "menu_label": {
+ "message": "Re-Pagination"
+ },
+ "repagination_nolimit": {
+ "message": "Load all"
+ },
+ "repagination_nolimit_domain": {
+ "message": "All tabs for current domain"
+ },
+ "repagination_limit": {
+ "message": "Limited"
+ },
+ "repagination_limit_x": {
+ "message": "$1 pages"
+ },
+ "repagination_slide": {
+ "message": "Slideshow"
+ },
+ "repagination_slide_0": {
+ "message": "Immediately"
+ },
+ "repagination_slide_1": {
+ "message": "1 second"
+ },
+ "repagination_slide_x": {
+ "message": "$1 seconds"
+ },
+ "repagination_slide_60": {
+ "message": "1 minute"
+ },
+ "repagination_slide_120": {
+ "message": "2 minutes"
+ },
+ "repagination_stop": {
+ "message": "Stop!"
+ },
+ "repagination_limited": {
+ "message": "($1 of $2) Re-Pagination is running..."
+ },
+ "repagination_unlimited": {
+ "message": "($1) Re-Pagination is running..."
+ },
+ "repagination_running": {
+ "message": "Re-Pagination is running..."
+ },
+ "extensionName": {
+ "message": "Re-Pagination"
+ },
+ "extensionDescription": {
+ "message": "Load all consecutive pages in a single tab at once."
+ }
+}
\ No newline at end of file
diff --git a/bootstrap.js b/bootstrap.js
deleted file mode 100644
index eeda145..0000000
--- a/bootstrap.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-const global = this;
-
-function install() {}
-function uninstall() {}
-function startup(data) {
- Components.utils.import("chrome://repagination/content/loader.jsm");
- _setupLoader(data, function real_startup() {
- require("main");
- });
-}
-function shutdown(reason) {
- if (reason === APP_SHUTDOWN) {
- // No need to cleanup; stuff will vanish anyway
- return;
- }
- unload("shutdown");
-}
-
-/* vim: set et ts=2 sw=2 : */
diff --git a/build.py b/build.py
index 91f86ed..2411991 100644
--- a/build.py
+++ b/build.py
@@ -10,15 +10,11 @@
from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED
resources = [
- "install.rdf",
- "chrome.manifest",
- "*.xul",
- "locale/*/*.dtd",
- "locale/*/*.properties",
- "defaults/preferences/prefs.js",
- "icon.png", "icon64.png",
+ "manifest.json",
+ "_locales/*/messages.json",
+ "icon.png", "icon32.png", "icon64.png",
"LICENSE.txt",
- "content-script.js"
+ "*.js", "options.html"
]
destination = "repagination.xpi"
@@ -34,26 +30,7 @@ def Minor():
yield
-def get_js_requires(scripts):
- known = set()
- scripts = list(scripts)
- for script in scripts:
- with open(script) as sp:
- for line in sp:
- m = re.search(r"(?:r|lazyR)equire\((['\"])(.+?)\1", line)
- if not m:
- continue
- m = m.group(2) + ".js"
- if m in known:
- continue
- known.add(m)
- scripts += m,
- return set(scripts)
-
-
def get_files(resources):
- for r in get_js_requires(("bootstrap.js", "loader.jsm")):
- yield r
for r in resources:
if os.path.isfile(r):
yield r
@@ -73,9 +50,9 @@ def __exit__(self, type, value, traceback):
self.close()
-if os.path.exists(destination):
- print >>sys.stderr, destination, "is in the way"
- sys.exit(1)
+# if os.path.exists(destination):
+ # print >>sys.stderr, destination, "is in the way"
+ # sys.exit(1)
with Minor(), ZipOutFile(destination) as zp:
for f in sorted(get_files(resources), key=str.lower):
diff --git a/chrome.manifest b/chrome.manifest
deleted file mode 100644
index f574b5b..0000000
--- a/chrome.manifest
+++ /dev/null
@@ -1,4 +0,0 @@
-content repagination ./
-
-locale repagination en-US locale/en-US/
-locale repagination de locale/de/
diff --git a/content-script.js b/content-script.js
index 0e36fbd..b263df9 100644
--- a/content-script.js
+++ b/content-script.js
@@ -3,131 +3,58 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
-/* global
- addMessageListener,
- content,
- removeMessageListener,
- sendAsyncMessage,
- sendSyncMessage
-*/
-
-(function() {
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-let {Services, Promise} = Cu.import("resource://gre/modules/Services.jsm", {});
-let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
-
-const [LOG_DEBUG, LOG_INFO, LOG_ERROR] = [0, 1, 2];
-const log = function(level, message, exception) {
- sendAsyncMessage("repagination:log", {
- level: level,
- message: message,
- exception: exception && {
- message: exception.message,
- fileName: exception.fileName,
- lineNumber: exception.lineNumber,
- stack: exception.stack
- }
- });
-};
+{
+console.log("Framescript loaded!");
+let port = browser.runtime.connect();
-const _ = function() {
- return sendSyncMessage("repagination:_", {
- arguments: Array.map(arguments, e => e.toString())
- })[0];
-};
+var focusElement = null;
-const getFirstSnapshot = (doc, node, query) =>
- doc.evaluate(query, node, null, 7, null).snapshotItem(0);
+let _ = function () {
+ let args = Array.from(arguments).map(e => e.toString());
+ return browser.i18n.getMessage(args[0], args.slice(1));
+}
-const checkSameOrigin = (node, tryLoadUri) => {
- try {
- if (!(tryLoadUri instanceof Ci.nsIURI)) {
- tryLoadUri = Services.io.newURI(tryLoadUri, null, null);
- }
- if (tryLoadUri.schemeIs("data")) {
- return true;
- }
- let pr = node.nodePrincipal;
- pr = Cc["@mozilla.org/scriptsecuritymanager;1"].
- getService(Ci.nsIScriptSecurityManager).
- getAppCodebasePrincipal(pr.URI,
- pr.appId,
- pr.isInBrowserElement);
- if (pr.checkMayLoad.length == 3) {
- pr.checkMayLoad(tryLoadUri, false, false);
- }
- else {
- pr.checkMayLoad(tryLoadUri, false);
- }
- return true;
- }
- catch (ex) {
- log(LOG_DEBUG, "denied load of " + (tryLoadUri.spec || tryLoadUri), ex);
- return false;
- }
-};
+let equalLinks = (left, right) =>
+ left.pathname === right.pathname &&
+ left.search === right.search &&
+ left.host === right.host &&
+ left.protocol === right.protocol;
-const createFrame = (window, src, allowScripts, loadFun) => {
- log(LOG_INFO, "creating frame for " + src);
- if (!checkSameOrigin(window.document, src)) {
- throw new Error("same origin mismatch; frame creation denied");
- }
- let frame = window.document.createElement("iframe");
- frame.setAttribute("sandbox", "allow-scripts");
- frame.style.display = "none";
- window.document.body.appendChild(frame);
- let docShell = frame.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShell);
- docShell.allowImages = false;
- docShell.allowPlugins = false;
- docShell.allowJavascript = allowScripts;
-
- frame.addEventListener("load", function loadHandler() {
- frame.removeEventListener("load", loadHandler, false);
- log(LOG_INFO, "frame loaded, going to process");
- try {
- loadFun(frame);
- }
- catch (ex) {
- log(LOG_ERROR, "failed to invoke callback on frame", ex);
- }
- }, false);
- frame.src = src;
+let getFirstSnapshot = (doc, node, query) =>
+ doc.evaluate(query, node, null, 7, null).snapshotItem(0);
+let createPageRequest = (srcurl, allowScripts, loadFun) => {
let errorCount = 0;
- let errorHandler = function() {
- log(LOG_INFO, "frame err'ed out");
- if (++errorCount > 5) {
- frame.removeEventListener("error", errorHandler, false);
- frame.removeEventListener("abort", errorHandler, false);
- log(LOG_ERROR, "frame err'ed out, giving up");
- try {
- loadFun(frame);
- }
- catch (ex) {
- log(LOG_ERROR, "failed to invoke callback on frame", ex);
+ function sendRequest() {
+ var xhr = new XMLHttpRequest();
+ xhr.onload = function() {
+ if (xhr.status == 200) {
+ console.info("XHR loaded, going to process");
+ try {
+ loadFun(xhr.responseXML);
+ }
+ catch (ex) {
+ console.error("failed to invoke callback on XHR", ex);
+ }
+ } else if (++errorCount <= 5) {
+ console.info("XHR err'ed out, retrying");
+ setTimeout(function(){ sendRequest(); }, 500 * (2**errorCount));
+ } else {
+ console.error("XHR err'ed out, giving up");
}
- return;
- }
- if (frame.history) {
- frame.history.reload();
- }
- else {
- frame.src = src;
}
- };
- frame.addEventListener("error", errorHandler, false);
- frame.addEventListener("abort", errorHandler, false);
-
- return frame;
+ xhr.open('GET', srcurl);
+ xhr.responseType = "document";
+ xhr.send();
+ }
+ sendRequest();
};
-const Repaginator = function Repaginator(focusElement, count, allowScripts, yielding) {
+let Repaginator = function Repaginator(count, allowScripts, yielding) {
this.pageLimit = count || 0;
this.allowScripts = allowScripts;
this.yielding = yielding;
- this.init(focusElement);
+ this.init();
};
Repaginator.prototype = {
slideshow: false,
@@ -136,7 +63,7 @@ Repaginator.prototype = {
pageCount: 0,
attemptToIncrement: true,
- init: function R_init(focusElement) {
+ init: function R_init() {
// find anchor
(function findInitialAnchor() {
for (let parent = focusElement; parent; parent = parent.parentNode) {
@@ -147,17 +74,22 @@ Repaginator.prototype = {
}
throw new Error("No focus element");
})();
-
- this._window = focusElement.ownerDocument.defaultView;
},
buildQuery: function R_buildQuery(el) {
- function escapeXStr(str) {
- return str.replace(/'/g, "\\'");
+ function escapeXStr(mystr) {
+ return mystr.replace(/'/g, "\\'");
}
this.query = "";
(function buildQuery() {
+ // Homestuck hack
+ if(el.href && el.href.includes("mspaintadventures.com")) {
+ this.query = "//center[position() = 1]/table[position() = 1]/tbody[position() = 1]/tr[position() = 2]/td[position() = 1]/table[position() = 1]/tbody[position() = 1]/tr[position() = 1]/td[position() = 1]/table[position() = 1]/tbody[position() = 1]/tr[position() = 2]/td[position() = 1]/center[position() = 1]/table[position() = 1]/tbody[position() = 1]/tr[position() = 6]/td[position() = 1]/table[position() = 1]/tbody[position() = 1]/tr[position() = 1]/td[position() = 1]/font[position() = 1]/a[position() = 1]";
+ this.numberToken = /(\[@href='.*)(\d+)(.*?'\])/;
+ return;
+ }
+
// See if the anchor has an ID
// Note: cannot use the id() xpath function here, as there might
// be duplicate ids
@@ -177,7 +109,7 @@ Repaginator.prototype = {
this.query = "/html/head//link[@rel='" + escapeXStr(rel) + "']";
// no point in checking for numbers
this.attemptToIncrement = false;
- log(LOG_DEBUG, "using link[@rel]");
+ console.log("using link[@rel]");
return;
}
}
@@ -191,55 +123,87 @@ Repaginator.prototype = {
break;
}
if (pn.id) {
- log(LOG_DEBUG, "got id: " + pn.id);
+ console.log("got id: " + pn.id);
pieces.unshift("//" + pn.localName + "[@id='" +
escapeXStr(pn.id) + "']");
break; // one id is enough
}
if (pn.className) {
- log(LOG_DEBUG, "got class: " + pn.className);
+ console.log("got class: " + pn.className);
pieces.unshift("//" + pn.localName + "[@class='" +
escapeXStr(pn.className) + "']");
+ break;
}
}
this.query = pieces.join("");
- log(LOG_DEBUG, "findPathPrefix result: " + this.query);
+ console.log("findPathPrefix result: " + this.query);
}).call(this);
// find the anchor
(function findAnchor() {
let text = el.textContent;
- // First: try the node text
+ // See if there is rel=next or rel=prev
+ let rel = (el.getAttribute("rel") || "").trim();
+ if (rel && (rel.includes("next") || rel.includes("prev"))) {
+ this.query += "//a[@rel='" + escapeXStr(rel) + "']";
+ // no point in checking for numbers
+ this.attemptToIncrement = false;
+ console.log("using a[@rel]");
+ return;
+ }
+
+ // Try the node text
if (text.trim()) {
this.query += "//a[.='" + escapeXStr(text) + "']";
this.numberToken = /(a\[.='.*?)(\d+)(.*?\])/;
- log(LOG_DEBUG, "using text");
+ console.log("using text");
return;
}
- // Second: see if it has a child with a @src we may use
- let srcEl = getFirstSnapshot(el.ownerDocument, el, "child::*[@src]");
+ // See if it has a descendant with a @src we may use
+ let srcEl = getFirstSnapshot(el.ownerDocument, el, "descendant::*[@src]");
if (srcEl) {
let src = srcEl.getAttribute("src") || "";
if (src.trim()) {
this.query += "//" + srcEl.localName + "[@src='" + escapeXStr(src) +
"']/ancestor::a";
this.numberToken = /(\[@src='.*?)(\d+)(.*?'\])/;
- log(LOG_DEBUG, "using @src");
+ console.log("using @src");
return;
}
}
- // Third: See if there is a child with a @value we may use
- srcEl = getFirstSnapshot(el.ownerDocument, el, "child::*[@value]");
+ // See if there is a descendant with a @value we may use
+ srcEl = getFirstSnapshot(el.ownerDocument, el, "descendant::*[@value]");
if (srcEl) {
let val = srcEl.getAttribute("value") || "";
if (val.trim()) {
this.query += "//" + srcEl.localName + "[@value='" +
escapeXStr(val) + "']/ancestor::a";
this.numberToken = /(\[@value='.*?)(\d+)(.*?'\])/;
- log(LOG_DEBUG, "using @value");
+ console.log("using @value");
+ return;
+ }
+ }
+
+ // See if there is a class we may use
+ if (el.className) {
+ this.query += "//a[@class='" + escapeXStr(el.className) + "']";
+ this.numberToken = /(\[@class='.*?)(\d+)(.*?'\])/;
+ console.log("using a[@class]");
+ return;
+ }
+
+ // See if there is a descendant with an id we may use
+ srcEl = getFirstSnapshot(el.ownerDocument, el, "descendant::*[@id]");
+ if (srcEl) {
+ let val = srcEl.getAttribute("id") || "";
+ if (val.trim()) {
+ this.query += "//" + srcEl.localName + "[@id='" +
+ escapeXStr(val) + "']/ancestor::a";
+ this.numberToken = /(\[@value='.*?)(\d+)(.*?'\])/;
+ console.log("using descendant class");
return;
}
}
@@ -251,73 +215,45 @@ Repaginator.prototype = {
// We're after the last result
this.query = "(" + this.query + ")[last()]";
- log(LOG_INFO, "query: " + this.query);
+ console.info("query: " + this.query);
},
setTitle: function R_setTitle() {
- let wnd = this._window;
- if (!wnd) {
- return;
- }
- if (!this._title) {
- this._title = wnd.document.title;
- }
if (this.pageLimit) {
- wnd.document.title =
+ document.title =
_("repagination_limited", this.pageCount, this.pageLimit);
}
else if (this.pageCount > 0) {
- wnd.document.title = _("repagination_unlimited", this.pageCount);
+ document.title = _("repagination_unlimited", this.pageCount);
}
else {
- wnd.document.title = _("repagination_running");
+ document.title = _("repagination_running");
}
},
- restoreTitle: function R_restoreTitle() {
- let wnd = this._window;
- if (this._title && wnd) {
- wnd.document.title = this._title;
+ finished: function R_finished() {
+ port.postMessage({msg: "finished"});
+ stop();
+ // restore title
+ if("_title" in this) {
+ document.title = this._title;
delete this._title;
}
},
- unregister: function R_unregister() {
- sendAsyncMessage("repagination:unregister", {id: this.frameId});
- if (this._window) {
- this._window.document.body.removeAttribute("repagination");
- this._window.removeEventListener("beforeunload", this.unload, true);
- }
- },
repaginate: function R_repaginate() {
+ this._title = document.title;
this.setTitle();
- let wnd = this._window;
- if (!wnd) {
- log(LOG_INFO, "window is gone!");
- return;
- }
- this.frameId = wnd.QueryInterface(Ci.nsIInterfaceRequestor).
- getInterface(Ci.nsIDOMWindowUtils).
- outerWindowID;
- sendAsyncMessage("repagination:register", {id: this.frameId});
- this.unload = () => {
- log(LOG_DEBUG, "unload");
- this.unregister();
- };
- wnd.addEventListener("beforeunload", this.unload, true);
-
try {
- let node = wnd.document.evaluate(
- this.query, wnd.document, null, 9, null).singleNodeValue;
+ let node = document.evaluate(
+ this.query, document, null, 9, null).singleNodeValue;
if (!node) {
throw new Error("no node");
}
- wnd.document.body.setAttribute("repagination", "true");
- createFrame(wnd, node.href, this.allowScripts, frame => {
- this.loadNext(frame, 0);
+ document.body.setAttribute("repagination", "true");
+ createPageRequest(node.href, this.allowScripts, frame => {
+ this.loadNext(node.href, frame, 0);
});
- }
- catch (ex) {
- this.unregister();
- this.restoreTitle();
- log(LOG_ERROR, "repaginate failed", ex);
+ } catch (ex) {
+ this.finished();
+ console.error("repaginate failed", ex);
}
},
incrementQuery: function R_incrementQuery() {
@@ -325,283 +261,176 @@ Repaginator.prototype = {
return pre + (parseInt(num, 10) + 1) + post;
});
},
- loadNext: function R_loadNext(element, delay) {
- if (!this.yielding) {
- if (delay > 0) {
- log(LOG_DEBUG, "delaying (sto) " + delay);
- content.setTimeout(() => this.loadNext(element, 0), delay);
- return;
- }
-
- try {
- for (let f in this._loadNext_gen.bind(this, element)()) {
- if (!f) {
- break;
- }
- }
- }
- catch (ex) {
- log(LOG_ERROR, "failed to process loadNext (non-yielding)", ex);
- }
+ loadNext: function R_loadNext(src, element, delay) {
+ if (delay > 0) {
+ console.log("delaying (sto) " + delay);
+ setTimeout(() => this.loadNext(src, element, 0), delay);
return;
}
- Task.spawn(function*() {
- try {
- if (delay > 0) {
- yield new Promise(r => {
- log(LOG_DEBUG, "delaying " + delay);
- content.setTimeout(() => {
- log(LOG_DEBUG, "invoke " + delay);
- r();
- }, delay);
- });
- }
- let gen = this._loadNext_gen(element);
- let deadline = +(new Date()) + 60;
- for (let r in gen) {
- if (!r) {
- break;
- }
- if (deadline < +(new Date())) {
- yield new Promise(r => {
- content.setTimeout(() => r(), 0);
- });
- deadline = +(new Date()) + 60;
- }
- }
- }
- catch (ex) {
- log(LOG_ERROR, "failed to iterate loadNext", ex);
- }
- }.bind(this));
+ try {
+ this._loadNext_gen.bind(this, src, element)();
+ } catch (ex) {
+ console.error("failed to process loadNext (non-yielding)", ex);
+ this.finished();
+ }
+ return;
},
- _loadNext_gen: function R__loadNext_gen(element) {
+ _loadNext_gen: function R__loadNext_gen(src, element) {
+ let ownerDoc = document;
+
try {
- let ownerDoc = element.ownerDocument;
- if (!ownerDoc || !this._window) {
- yield true;
- this.unregister();
- this.restoreTitle();
- log(LOG_INFO, "gone, giving up!");
- return;
+ if (!ownerDoc.body.hasAttribute("repagination")) {
+ throw new Error("not running");
}
- try {
- if (!ownerDoc.body.hasAttribute("repagination")) {
- throw new Error("not running");
- }
-
- var doc = element.contentDocument;
- if (!checkSameOrigin(ownerDoc, doc.defaultView.location)) {
- throw new Error("not in the same origin anymore");
- }
- this.pageCount++;
-
- // Remove scripts from frame
- // The scripts should already be present in the parent (first page)
- // Duplicate scripts would cause more havoc (performance-wise) than
- // behaviour failures due to missing scripts
- // Note: This is NOT a security mechanism, but a performance thing.
- Array.forEach(doc.querySelectorAll("script"),
- s => s.parentNode.removeChild(s));
- Array.forEach(doc.querySelectorAll("noscript"),
- s => s.parentNode.removeChild(s));
-
- yield true;
-
- // Do the dirty deed
- // Note: same-origin checked; see above
- if (this.slideshow) {
- log(LOG_INFO, "replacing content (slideshow)");
- ownerDoc.body.innerHTML = doc.body.innerHTML;
- ownerDoc.body.setAttribute("repagination", "true");
- }
- else {
- log(LOG_INFO, "inserting content (normal)");
- // Remove non-same-origin iframes, such as ad iframes
- // Otherwise we might create a shitload of (nearly) identical frames
- // which might even kill the browser
- if (!this.pageLimit || this.pageLimit > 10) {
- log(LOG_INFO, "removing non-same-origin iframes to avoid dupes");
- let host = ownerDoc.defaultView.location.hostName;
- Array.forEach(doc.querySelectorAll("iframe"), function(f) {
- if (f.contentWindow.location.hostname != host) {
- f.parentNode.removeChild(f);
- }
- });
- yield true;
- }
- for (let c = doc.body.firstChild; c; c = c.nextSibling) {
- ownerDoc.body.appendChild(ownerDoc.importNode(c, true));
- yield true;
- }
+ var doc = element;
+ this.pageCount++;
+
+ // Remove scripts from frame
+ // The scripts should already be present in the parent (first page)
+ // Duplicate scripts would cause more havoc (performance-wise) than
+ // behaviour failures due to missing scripts
+ // Note: This is NOT a security mechanism, but a performance thing.
+ doc.querySelectorAll("script").forEach(s => s.parentNode.removeChild(s));
+ doc.querySelectorAll("style").forEach(s => s.parentNode.removeChild(s));
+
+ // Do the dirty deed
+ if (this.slideshow) {
+ console.info("replacing content (slideshow)");
+ // this should be safe since innerHTML returns serialized HTML
+ ownerDoc.body.innerHTML = doc.body.innerHTML;
+ ownerDoc.body.setAttribute("repagination", "true");
+ }
+ else {
+ console.info("inserting content (normal)");
+ // Remove non-same-origin iframes, such as ad iframes
+ // Otherwise we might create a shitload of (nearly) identical frames
+ // which might even kill the browser
+ if (!this.pageLimit || this.pageLimit > 10) {
+ console.info("removing non-same-origin iframes to avoid dupes");
+ let host = ownerDoc.defaultView.location.hostName;
+ doc.querySelectorAll("iframe").forEach(function(f) {
+ var url = new URL(f.src, ownerDoc.defaultView.location.href);
+ if (url.hostname != host) {
+ f.parentNode.removeChild(f);
+ }
+ });
}
-
- // Synthesize load events to trigger other add-ons and
- // page scripts.
- if (ownerDoc.defaultView) {
- log(LOG_DEBUG, "about to fire load events");
-
- let levt = ownerDoc.createEvent("Events");
- levt.initEvent("DOMContentLoaded", true, true);
- ownerDoc.defaultView.dispatchEvent(levt);
- log(LOG_DEBUG, "fired DOMContentLoaded");
-
- levt = ownerDoc.createEvent("Events");
- levt.initEvent("load", true, true);
- ownerDoc.defaultView.dispatchEvent(levt);
- log(LOG_DEBUG, "fired load");
+ for (let c = doc.body.firstChild; c; c = c.nextSibling) {
+ ownerDoc.body.appendChild(ownerDoc.importNode(c, true));
}
- yield true;
+ }
- if (this.pageLimit && this.pageCount >= this.pageLimit) {
- throw new Error("done");
- }
+ if (this.pageLimit && this.pageCount >= this.pageLimit) {
+ throw new Error("done");
+ }
- let savedQuery;
- if (this.attemptToIncrement) {
- log(LOG_DEBUG, "attempting to increment query");
- let nq = this.incrementQuery();
- if (nq == this.query) {
- log(LOG_DEBUG, "query did not increment");
- this.attemptToIncrement = false;
- }
- else {
- log(LOG_DEBUG, "query did increment");
- savedQuery = this.query;
- this.query = nq;
- }
- }
- let node = doc.evaluate(this.query, doc, null, 9, null).singleNodeValue;
- let loc = (doc.location || {}).href || null;
- if (this.attemptToIncrement && (!node || node.href == loc)) {
- log(LOG_DEBUG, "no result after incrementing; restoring");
- log(LOG_DEBUG, "inc:" + this.query + " orig:" + savedQuery);
- this.query = savedQuery;
- node = doc.evaluate(this.query, doc, null, 9, null).singleNodeValue;
+ let savedQuery;
+ if (this.attemptToIncrement) {
+ console.log("attempting to increment query");
+ let nq = this.incrementQuery();
+ if (nq == this.query) {
+ console.log("query did not increment");
this.attemptToIncrement = false;
}
- if (!node) {
- throw new Error("no next node found for query: " + this.query);
- }
- if (loc && loc == node.href) {
- throw new Error("location did not change for query" + this.query);
+ else {
+ console.log("query did increment");
+ savedQuery = this.query;
+ this.query = nq;
}
-
- this.setTitle();
- log(LOG_INFO, "next please");
- createFrame(ownerDoc.defaultView, node.href, this.allowScripts,
- frame => {
- if (!this._window || this._window.closed) {
- log(LOG_DEBUG, "self is gone by now");
- this.unregister();
- this.restoreTitle();
- return;
- }
- if (this.slideshow && this.seconds) {
- log(LOG_INFO, "slideshow; delay: " + this.seconds * 1000);
- this.loadNext(frame, this.seconds * 1000);
- }
- else {
- log(LOG_INFO, "regular; no-delay");
- this.loadNext(frame, 0);
- }
- });
}
- catch (ex) {
- log(LOG_INFO, "loadNext complete", ex);
- this.unregister();
- this.restoreTitle();
+ let node = doc.evaluate(this.query, doc, null, 9, null).singleNodeValue;
+ let loc = src || null;
+ if (this.attemptToIncrement && (!node || node.href == loc)) {
+ console.log("no result after incrementing; restoring");
+ console.log("inc:" + this.query + " orig:" + savedQuery);
+ this.query = savedQuery;
+ node = doc.evaluate(this.query, doc, null, 9, null).singleNodeValue;
+ this.attemptToIncrement = false;
+ }
+ if (!node) {
+ throw new Error("no next node found for query: " + this.query);
+ }
+ let nexturl = node.href.toString();
+ if (loc && loc == nexturl) {
+ throw new Error("location did not change for query" + this.query);
}
+ if (equalLinks(node,window.location)) {
+ throw new Error("loop back to first item");
+ }
+
+ this.setTitle();
+ console.info("next please: " + nexturl);
+ createPageRequest(nexturl, this.allowScripts, frame => {
+ if (this.slideshow && this.seconds) {
+ console.info("slideshow; delay: " + this.seconds * 1000);
+ this.loadNext(nexturl, frame, this.seconds * 1000);
+ }
+ else {
+ console.info("regular; no-delay");
+ this.loadNext(nexturl, frame, 0);
+ }
+ });
}
- finally {
- element.parentElement.removeChild(element);
+ catch (ex) {
+ console.log(ex);
+ console.info("loadNext complete");
+ this.finished();
}
}
};
Object.seal(Repaginator.prototype);
-const Slideshow = function Slideshow(focusElement, seconds, allowScripts, yielding) {
+let Slideshow = function Slideshow(seconds, allowScripts, yielding) {
this.seconds = seconds || 0;
this.slideshow = true;
this.allowScripts = allowScripts;
this.yielding = yielding;
- this.init(focusElement);
- this.buildQuery(focusElement);
+ this.init();
};
Slideshow.prototype = Repaginator.prototype;
-const fe = () => {
- let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
- let focusedWindow = {};
- let elt = fm.getFocusedElementForWindow(content, true, focusedWindow);
- return elt;
-};
-
-const repaginate = m => {
- let {num, slideshow, allowScripts, yielding} = m.data;
+let repaginate = (target, num, slideshow, allowScripts, yielding) => {
try {
let Ctor = slideshow ? Slideshow : Repaginator;
let rep;
- if ("query" in m.data) {
- let el = getFirstSnapshot(content.document, content.document,
- m.data.query);
- if (!el) {
- log(LOG_DEBUG, "did not find explicit query element");
- return;
- }
- rep = new Ctor(el, num, allowScripts, yielding);
- rep.query = m.data.query;
- }
- else {
- let el = fe();
- rep = new Ctor(fe(), num, allowScripts, yielding);
- rep.buildQuery(el);
- }
+ focusElement = browser.menus.getTargetElement(target);
+ rep = new Ctor(num, allowScripts, yielding);
+ rep.buildQuery(focusElement);
rep.repaginate();
+ } catch (ex) {
+ console.error("Failed to run repaginate", ex);
}
- catch (ex) {
- log(LOG_ERROR, "Failed to run repaginate", ex);
- }
-};
-
-const query = () => {
- let el = fe();
- let rv = new Repaginator(el);
- rv.buildQuery(el);
- sendAsyncMessage("repagination:query", rv.query);
};
-const stop = () => {
+let stop = () => {
try {
- if (!content) {
- return;
- }
- let body = content.document.getElementsByTagName("body")[0];
+ let body = document.body;
if (body) {
body.removeAttribute("repagination");
}
+ } catch (ex) {
+ console.error("failed to stop repagination", ex);
}
- catch (ex) {
- log(LOG_ERROR, "failed to stop repagination", ex);
- }
-};
-
-const shutdown = () => {
- removeMessageListener("repagination:normal", repaginate);
- removeMessageListener("repagination:query", query);
- removeMessageListener("repagination:stop", stop);
- removeMessageListener("repagination:shutdown", shutdown);
};
-addMessageListener("repagination:normal", repaginate);
-addMessageListener("repagination:query", query);
-addMessageListener("repagination:stop", stop);
-addMessageListener("repagination:shutdown", shutdown);
-
-log(LOG_DEBUG, "Framescript loaded!");
+port.onMessage.addListener(msg => {
+ switch (msg.msg) {
+ case "normal": repaginate(msg.target, msg.num, msg.slideshow, msg.allowScripts, msg.yielding); break;
+ case "stop" : stop(); break;
+ }
+});
-})(); // "module"
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1370368
+window.addEventListener('pagehide', function(event) {
+ stop();
+ try {
+ port.disconnect();
+ } catch (ex) {
+ console.log(ex)
+ }
+});
+}
/* vim: set et ts=2 sw=2 : */
diff --git a/defaults/preferences/prefs.js b/defaults/preferences/prefs.js
deleted file mode 100644
index 68093cc..0000000
--- a/defaults/preferences/prefs.js
+++ /dev/null
@@ -1,6 +0,0 @@
-pref("extensions.{6072cb90-a0bd-11da-a746-0800200c9a66}.submenu", true);
-pref("extensions.{6072cb90-a0bd-11da-a746-0800200c9a66}.loglevel", 0x7fffffff);
-pref("extensions.{6072cb90-a0bd-11da-a746-0800200c9a66}.showalldomain", false);
-pref("extensions.{6072cb90-a0bd-11da-a746-0800200c9a66}.showslideshow", true);
-pref("extensions.{6072cb90-a0bd-11da-a746-0800200c9a66}.yielding", false);
-pref("extensions.{6072cb90-a0bd-11da-a746-0800200c9a66}.allowscripts", true);
diff --git a/install.rdf b/install.rdf
deleted file mode 100644
index 770e4af..0000000
--- a/install.rdf
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
- {6072cb90-a0bd-11da-a746-0800200c9a66}
- Re-Pagination
- Load all consecutive pages in a single tab at once.
- 2016.08.03
-
- true
- true
- 2
-
- chrome://repagination/content/options.xul
- 2
-
- Nils Maier
- Nils Maier
- Lev, Omar
-
-
-
-
- {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
- 40.0
- 50.*
-
-
-
-
-
- {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}
- 2.35
- 2.47.*
-
-
-
-
diff --git a/loader.jsm b/loader.jsm
deleted file mode 100644
index 6a7da1a..0000000
--- a/loader.jsm
+++ /dev/null
@@ -1,242 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-var EXPORTED_SYMBOLS = ["BASE_PATH", "require", "unload", "_setupLoader"];
-
-var {
- classes: Cc,
- interfaces: Ci,
- utils: Cu,
- results: Cr,
- Constructor: ctor,
- manager: Cm
-} = Components;
-
-var weak = Cu.getWeakReference.bind(Cu);
-var reportError = Cu.reportError.bind(Cu);
-
-Cm.QueryInterface(Ci.nsIComponentRegistrar);
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-var lazy = XPCOMUtils.defineLazyGetter;
-
-// hide our internals
-// Since require() uses .scriptloader, the loaded require scopes will have
-// access to the named stuff within this module scope, but we actually want
-// them to have access to certain stuff.
-(function setup_scope(exports) {
- Services = exports.Services = Object.create(Services);
- let dlsg = XPCOMUtils.defineLazyServiceGetter.bind(XPCOMUtils, Services);
- dlsg("catman", "@mozilla.org/categorymanager;1", "nsICategoryManager");
- dlsg("clipbrd", "@mozilla.org/widget/clipboard;1", "nsIClipboard");
- dlsg("drags", "@mozilla.org/widget/dragservice;1", "nsIDragService");
- dlsg("eps", "@mozilla.org/uriloader/external-protocol-service;1",
- "nsIExternalProtocolService");
- dlsg("fixups", "@mozilla.org/docshell/urifixup;1", "nsIURIFixup");
- dlsg("memrm", "@mozilla.org/memory-reporter-manager;1",
- "nsIMemoryReporterManager");
- dlsg("mime", "@mozilla.org/uriloader/external-helper-app-service;1",
- "nsIMIMEService");
- dlsg("mimeheader", "@mozilla.org/network/mime-hdrparam;1",
- "nsIMIMEHeaderParam");
- dlsg("sysprincipal", "@mozilla.org/systemprincipal;1", "nsIPrincipal");
- dlsg("uuid", "@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
-
- const Instances = exports.Instances = {
- get: function I_get(symbol, contract, iface, initializer) {
- if (!(symbol in this)) {
- this.register(symbol, contract, iface, initializer);
- }
- return this[symbol];
- },
- register: function I_register(symbol, contract, iface, initializer) {
- if (symbol in this) {
- let msg = "Symbol " + symbol + " already in Instances";
- log(LOG_ERROR, msg);
- throw new Error(msg);
- }
- if (initializer) {
- lazy(this, symbol, () => ctor(contract, iface, initializer));
- lazy(this, symbol + "_p", () => ctor(contract, iface));
- }
- else {
- lazy(this, symbol, () => ctor(contract, iface));
- lazy(this, symbol.toLowerCase(), () => new (ctor(contract, iface))());
- }
- }
- };
-
- const {SELF_PATH, BASE_PATH} = (function() {
- let rv;
- try { throw new Error("narf"); }
- catch (ex) {
- rv = {
- SELF_PATH: ex.fileName,
- BASE_PATH: /^(.+\/).*?$/.exec(ex.fileName)[1]
- };
- }
- return rv;
- })();
- exports.BASE_PATH = BASE_PATH;
-
- // logging stubs
- var log = function() {}; // stub
- var LOG_DEBUG = 0, LOG_INFO = 0, LOG_ERROR = 0;
-
- var _unloaders = [];
- let _runUnloader = function _runUnloader(fn) {
- try {
- fn();
- }
- catch (ex) {
- log(LOG_ERROR, "unloader failed", ex);
- }
- };
- exports.unload = function unload(fn) {
- if (fn == "shutdown") {
- log(LOG_INFO, "shutdown");
- for (let i = _unloaders.length; ~(--i);) {
- _runUnloader(_unloaders[i]);
- }
- _unloaders.splice(0);
- return;
- }
-
- // add an unloader
- if (typeof(fn) != "function") {
- throw new Error("unloader is not a function");
- }
- _unloaders.push(fn);
- return function() {
- _runUnloader(fn);
- _unloaders = _unloaders.filter(c => c != fn);
- };
- };
-
- const _registry = new Map();
- exports.require = function require(mod) {
- mod = BASE_PATH + mod + ".js";
-
- // already loaded?
- let scope = _registry.get(mod);
- if (scope) {
- return scope.exports;
- }
-
- // try to load the mod
- log(LOG_DEBUG, "going to load: " + mod);
- scope = Object.create(exports);
- scope.exports = Object.create(null);
- try {
- scope = Cu.Sandbox(Services.sysprincipal, {
- sandboxName: mod,
- sandboxPrototype: scope,
- wantXRays: false
- });
- Services.scriptloader.loadSubScript(mod, scope, "utf-8");
- }
- catch (ex) {
- log(LOG_ERROR, "failed to load " + mod, ex);
- throw ex;
- }
-
- _registry.set(mod, scope);
- log(LOG_DEBUG, "loaded module: " + mod);
-
- return scope.exports;
- };
-
- exports.lazyRequire = function lazyRequire(mod) {
- function lazyBind(props, prop) {
- log(LOG_DEBUG, "lazily binding " + props + " for module " + mod);
- let m = require(mod);
- for (let [,p] in new Iterator(props)) {
- delete this[p];
- this[p] = m[p];
- }
- return this[prop];
- }
-
- // Already loaded?
- let scope = _registry.get(mod);
- if (scope) {
- return scope.exports;
- }
-
- let props = Array.slice(arguments, 1);
- let rv = {};
- let binder = lazyBind.bind(rv, props);
- for (let [,p] in new Iterator(props)) {
- let _p = p;
- lazy(rv, _p, () => binder(_p));
- }
- return rv;
- };
-
- unload(function() {
- for (let [mod, scope] of _registry) {
- _registry.delete(mod);
- Cu.nukeSandbox(scope);
- }
- if (_registry.clear) {
- _registry.clear();
- }
- // unload ourselves
- Cu.unload(SELF_PATH);
- });
-
- exports._setupLoader = function _setupLoader(data, callback) {
- delete exports._setupLoader;
-
- let _am = {};
- Cu.import("resource://gre/modules/AddonManager.jsm", _am);
- _am.AddonManager.getAddonByID(data.id, function loader_startup(addon) {
- exports.ADDON = addon;
- unload(() => delete exports.ADDON);
-
- let logging;
- try {
- logging = require("sdk/logging");
- for (let [k,v] in new Iterator(logging)) {
- exports[k] = v;
- }
-
- let prefs = require("sdk/preferences");
- exports.prefs = prefs.prefs;
- exports.globalPrefs = prefs.globalPrefs;
-
- try {
- prefs.prefs.observe("loglevel",
- (p, v) => logging.setLogLevel(v),
- logging.LOG_NONE);
- }
- catch (ex) {
- logging.log(logging.LOG_ERROR, "failed to set log level", ex);
- }
- }
- catch (ex) {
- // probably do not have a working log() yet
- reportError(ex);
- return;
- }
-
- try {
- if (callback) {
- logging.log(logging.LOG_DEBUG, "loader: running callback");
- callback();
- }
- }
- catch (ex) {
- logging.log(logging.LOG_ERROR, "callback failed!", ex);
- }
- logging.log(logging.LOG_DEBUG, "loader: done");
- });
- };
-
-})(this);
-
-/* vim: set et ts=2 sw=2 : */
diff --git a/locale/de/options.dtd b/locale/de/options.dtd
deleted file mode 100644
index 932c656..0000000
--- a/locale/de/options.dtd
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/locale/de/repagination.dtd b/locale/de/repagination.dtd
deleted file mode 100644
index e6c5a21..0000000
--- a/locale/de/repagination.dtd
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/locale/de/repagination.properties b/locale/de/repagination.properties
deleted file mode 100644
index cd3e05c..0000000
--- a/locale/de/repagination.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-pages.label=%S Seiten
-minutes.label=%S Minuten
-seconds.label=%S Sekunden
-
-repagination_limited=(%S of %S) Re-Pagination arbeitet...
-repagination_unlimited=(%S) Re-Pagination arbeitet...
-repagination_running=Re-Pagination arbeitet...
-
-extensions.{6072cb90-a0bd-11da-a746-0800200c9a66}.name=Re-Pagination
-extensions.{6072cb90-a0bd-11da-a746-0800200c9a66}.description=Alle fortlaufenden Seiten in einem einzigem Tab auf einmal laden
-extensions.{6072cb90-a0bd-11da-a746-0800200c9a66}.translator.1=Nils Maier
diff --git a/locale/en-US/options.dtd b/locale/en-US/options.dtd
deleted file mode 100644
index 6100f15..0000000
--- a/locale/en-US/options.dtd
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/locale/en-US/repagination.dtd b/locale/en-US/repagination.dtd
deleted file mode 100644
index 61a26ec..0000000
--- a/locale/en-US/repagination.dtd
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/locale/en-US/repagination.properties b/locale/en-US/repagination.properties
deleted file mode 100644
index cdb1b4a..0000000
--- a/locale/en-US/repagination.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-pages.label=%S pages
-minutes.label=%S minutes
-seconds.label=%S seconds
-
-repagination_limited=(%S of %S) Re-Pagination is running...
-repagination_unlimited=(%S) Re-Pagination is running...
-repagination_running=Re-Pagination is running...
-
-extensions.{6072cb90-a0bd-11da-a746-0800200c9a66}.name=Re-Pagination
-extensions.{6072cb90-a0bd-11da-a746-0800200c9a66}.description=Load all consecutive pages in a single tab at once.
-extensions.{6072cb90-a0bd-11da-a746-0800200c9a66}.translator.1=Nils Maier
diff --git a/main.js b/main.js
index 4ee8a04..6767e66 100644
--- a/main.js
+++ b/main.js
@@ -3,271 +3,205 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
-const {registerOverlay, unloadWindow} = require("sdk/windows");
-
+const PORTS = {};
+const PENDING = {};
const RUNNING = new Set();
-const globalMM = Cc["@mozilla.org/globalmessagemanager;1"].
- getService(Ci.nsIMessageListenerManager);
-function registerRunning(m) {
- RUNNING.add(m.data.id);
- log(LOG_DEBUG, `added ${m.data.id} to running`);
+function onError(error) {
+ console.error(error);
}
-function unregisterRunning(m) {
- RUNNING.delete(m.data.id);
- log(LOG_DEBUG, `removed ${m.data.id} from running`);
+const MENU = {
+ NOLIMIT: 'REPAGINATION_NOLIMIT',
+ LIMIT: 'REPAGINATION_LIMIT',
+ SLIDE: 'REPAGINATION_SLIDE',
+ STOP: 'REPAGINATION_STOP'
}
-globalMM.addMessageListener("repagination:register", registerRunning);
-globalMM.addMessageListener("repagination:unregister", unregisterRunning);
-unload(() => {
- globalMM.removeMessageListener("repagination:register", registerRunning);
- globalMM.removeMessageListener("repagination:unregister", unregisterRunning);
-});
-
-/* globals _ */
-lazy(this, "_", function() {
- let bundle = require("sdk/strings").
- getBundle("chrome://repagination/locale/repagination.properties");
- return function() {
- return bundle.getString.apply(bundle, arguments);
- };
-});
-
-function checkSameOrigin(principal, tryLoadUri) {
- try {
- if (!(tryLoadUri instanceof Ci.nsIURI)) {
- tryLoadUri = Services.io.newURI(tryLoadUri, null, null);
- }
- if (tryLoadUri.schemeIs("data")) {
- return true;
- }
- principal.checkMayLoad(tryLoadUri, false, true);
- return true;
- }
- catch (ex) {
- log(LOG_DEBUG, "denied load of " + (tryLoadUri.spec || tryLoadUri), ex);
- return false;
+
+function onCreated(n) {
+ if (browser.runtime.lastError) {
+ console.error("Error creating menu item: %o", browser.runtime.lastError);
}
}
-function main(window, document) {
- const $ = id => document.getElementById(id);
- const $$$ = q => document.querySelectorAll(q);
+function createMenu(prefs) {
+ let c = ["link"]; // ContextTypes for most menu items
+
+ browser.menus.create({
+ id: MENU.NOLIMIT,
+ title: browser.i18n.getMessage("repagination_nolimit"),
+ contexts: c
+ }, onCreated);
+
+ let limits = [5,10,25,50,100];
+
+ for(let j in limits) {
+ let i = limits[j];
+ browser.menus.create({
+ id: MENU.LIMIT + "_" + i,
+ title: browser.i18n.getMessage("repagination_limit_x",[i]),
+ contexts: c
+ }, onCreated);
- function repaginate(num, slideshow) {
- log(LOG_INFO, "repaginate: " + num + "/" + slideshow);
- try {
- let mm = window.gBrowser.selectedBrowser.messageManager;
- mm.sendAsyncMessage("repagination:normal", {
- num: num,
- slideshow: slideshow,
- allowScripts: prefs.get("allowscripts", true),
- yielding: prefs.yielding
- });
- }
- catch (ex) {
- log(LOG_ERROR, "failed to run repaginate", ex);
- }
}
- function repaginate_domain() {
- log(LOG_INFO, "repaginate_domain");
- try {
- let mm = window.gBrowser.selectedBrowser.messageManager;
- let queried = m => {
- mm.removeMessageListener("repagination:query", queried);
- log(LOG_DEBUG, "recv query " + m.data);
- if (!m.data) {
- return;
- }
- const host = window.gBrowser.selectedBrowser.currentURI.host;
- for (let i = 0; i < window.gBrowser.browsers.length; ++i) {
- let browser = window.gBrowser.getBrowserAtIndex(i);
- if (!browser) {
- continue;
- }
- if (browser.currentURI.host != host) {
- continue;
- }
- browser.messageManager.sendAsyncMessage("repagination:normal", {
- num: 0,
- slideshow: false,
- allowScripts: prefs.get("allowscripts", true),
- yielding: prefs.yielding,
- query: m.data
- });
- }
- };
- mm.addMessageListener("repagination:query", queried);
- mm.sendAsyncMessage("repagination:query");
- }
- catch (ex) {
- log(LOG_ERROR, "failed to run repaginate_domain", ex);
+ if(prefs.slideshows) {
+ browser.menus.create({
+ id: MENU.SLIDE,
+ title: browser.i18n.getMessage("repagination_slide"),
+ contexts: c
+ }, onCreated);
+
+ let slides = [0,1,2,4,5,10,15,30,60,120];
+
+ for(let j in slides) {
+ let i = slides[j];
+ browser.menus.create({
+ id: MENU.SLIDE + "_" + i,
+ parentId: MENU.SLIDE,
+ title: ([0,1,60,120].indexOf(i) != -1) ? browser.i18n.getMessage("repagination_slide_" + i) : browser.i18n.getMessage("repagination_slide_x",[i]),
+ contexts: c
+ }, onCreated);
}
}
- function stop() {
- log(LOG_INFO, "stop");
- let mm = window.gBrowser.selectedBrowser.messageManager;
- mm.sendAsyncMessage("repagination:stop");
+ updStop();
+}
+
+var added = false;
+
+function updStop() {
+ if(RUNNING.size > 0 && !added) {
+ browser.menus.create({
+ id: MENU.STOP,
+ title: browser.i18n.getMessage("repagination_stop"),
+ contexts: ["all"]
+ }, onCreated);
+ added = true;
+ } else if(added) {
+ browser.menus.remove(MENU.STOP);
+ added = false;
}
+}
- function onAll() { repaginate(); }
- function onAllDomain() { repaginate_domain(); }
- function onStop() { stop(); }
- function onLimitCommand(evt) {
- let t = evt.target;
- if (t.localName != "menuitem") {
- return;
- }
- repaginate(parseInt(t.getAttribute("value"), 10));
+var defaultSettings = {
+ slideshows: false,
+ exists: true // special pref to restore defaults
+};
+
+function prefReset(newSettings, areaName) {
+ console.log("prefs changed")
+ if (areaName == "local" && ("exists" in newSettings)) {
+ browser.menus.removeAll();
+ console.log("recreating menu")
+ browser.storage.local.get().then(initSettings, onError);
}
- function onSlideCommand(evt) {
- let t = evt.target;
- if (t.localName != "menuitem") {
- return;
- }
- repaginate(parseInt(t.getAttribute("value"), 10), true);
+}
+
+function initSettings(prefs) {
+ if (!("exists" in prefs) || !prefs.exists) {
+ browser.storage.onChanged.removeListener(prefReset);
+ browser.storage.local.set(defaultSettings);
+ browser.storage.onChanged.addListener(prefReset);
+ prefs = defaultSettings;
}
- log(LOG_INFO, "main called!");
-
- let frameToLog = m => log(m.data.level, m.data.message, m.data.exception);
- let frameL10N = m => {
- return _.apply(null, m.data.arguments);
- };
- window.messageManager.addMessageListener("repagination:log", frameToLog);
- window.messageManager.addMessageListener("repagination:_", frameL10N);
- let fs = "chrome://repagination/content/content-script.js?" + (+new Date());
- window.messageManager.loadFrameScript(fs, true);
- unloadWindow(window, () => {
- window.messageManager.broadcastAsyncMessage("repagination:shutdown");
- window.messageManager.removeMessageListener("repagination:log", frameToLog);
- window.messageManager.removeMessageListener("repagination:_", frameL10N);
- window.messageManager.removeDelayedFrameScript(fs);
- });
+ createMenu(prefs);
+}
- // finish the localization
- let nodes = $$$(":-moz-any(#repagination_limit, " +
- "#repagination_menu_limit) menuitem");
- for (let n of nodes) {
- n.setAttribute("label", _("pages.label", n.getAttribute("value")));
- }
- nodes = $$$(":-moz-any(#repagination_slide, #repagination_menu_slide) " +
- "menuitem:not([label])");
- for (let n of nodes) {
- let s = parseInt(n.getAttribute("value"), 10);
- if (s < 60) {
- n.setAttribute("label", _("seconds.label", s));
- }
- else {
- n.setAttribute("label", _("minutes.label", parseInt(s / 60, 10)));
- }
- }
- let contextMenu = $("contentAreaContextMenu");
-
- let menuCascaded = {
- menu: $("repagination_menu"),
- allMenu: $("repagination_menu_nolimit"),
- allDomainMenu: $("repagination_menu_nolimit_domain"),
- stopMenu: $("repagination_menu_stop"),
- limitMenu: $("repagination_menu_limit"),
- slideMenu: $("repagination_menu_slide")
- };
- let menuPlain = {
- menu: {},
- allMenu: $("repagination_nolimit"),
- allDomainMenu: $("repagination_nolimit_domain"),
- stopMenu: $("repagination_stop"),
- limitMenu: $("repagination_limit"),
- slideMenu: $("repagination_slide")
- };
- let menuCurrent;
-
- prefs.observe("submenu", function(pref, value) {
- menuCurrent = value ? menuCascaded : menuPlain;
- let menuDisabled = value ? menuPlain : menuCascaded;
- for (let [,mi] in new Iterator(menuDisabled)) {
- mi.hidden = true;
+function myinit(prefs) {
+ initSettings(prefs);
+
+ function process(info, tab) {
+ let str = info.menuItemId;
+
+ if(str == MENU.STOP) {
+ console.info("stop");
+ PORTS[tab].postMessage({
+ msg: "stop"
+ });
+ return;
}
- }, true);
- let onContextMenu = function onContextMenu() {
- function setMenuHidden(hidden) {
- log(LOG_DEBUG, "set menu hidden = " + hidden);
- for (let [,mi] in new Iterator(menuCurrent)) {
- mi.hidden = hidden;
- }
- menuCurrent.slideMenu.hidden =
- menuCurrent.slideMenu.hidden || !prefs.showslideshow;
- menuCurrent.allDomainMenu.hidden =
- menuCurrent.allDomainMenu.hidden || !prefs.showalldomain;
+ let num, slideshow;
+ if(str == MENU.NOLIMIT) {
+ num = 0;
+ slideshow = false;
+ } else if(str.startsWith(MENU.LIMIT)) {
+ // https://stackoverflow.com/questions/5555518/split-variable-from-last-slash-jquery
+ num = parseInt(str.substring(str.lastIndexOf("_") + 1, str.length), 10);
+ slideshow = false;
+ } else if(str.startsWith(MENU.SLIDE)) {
+ num = parseInt(str.substring(str.lastIndexOf("_") + 1, str.length), 10);
+ slideshow = true;
}
- let {gContextMenu} = window;
- log(LOG_DEBUG, `context menu showing for ${gContextMenu.frameOuterWindowID}!`);
+ console.info("repaginate: " + num + "/" + slideshow);
try {
- if (gContextMenu.onLink && /^https?$/.test(gContextMenu.linkURI.scheme)) {
- setMenuHidden(!checkSameOrigin(gContextMenu.principal,
- gContextMenu.linkURL));
- if (!RUNNING.has(gContextMenu.frameOuterWindowID)) {
- menuCurrent.stopMenu.hidden = true;
- }
- return;
- }
+ PORTS[tab].postMessage({
+ msg: "normal",
+ target: info.targetElementId,
+ num: num,
+ slideshow: slideshow,
+ allowScripts: prefs.allowScripts,
+ yielding: prefs.yielding
+ });
+ RUNNING.add(tab);
+ updStop();
+ } catch (ex) {
+ console.log(ex);
+ console.error("failed to run repaginate");
+ delete PORTS[tabid];
+ delete PENDING[tabid];
+ RUNNING.delete(tabid);
}
- catch (ex) {
- log(LOG_ERROR, "failed to setup menu (onLink)", ex);
+ }
+
+ // We lazily inject the main content script in a vague hope for efficiency
+ // We use ports for messaging but have to store the messages until the port is opened.
+
+ browser.menus.onClicked.addListener((info, tab) => {
+ console.log(info, tab);
+ if(tab.id in PORTS) {
+ process(info, tab.id);
+ } else {
+ console.log("injecting " + tab.id);
+ browser.tabs.executeScript(tab.id, { file: "content-script.js" } );
+ PENDING[tab.id] = info;
}
- try {
- setMenuHidden(true);
- if (RUNNING.has(gContextMenu.frameOuterWindowID)) {
- menuCurrent.menu.hidden = menuCurrent.stopMenu.hidden = false;
+ });
+
+
+ browser.runtime.onConnect.addListener(function(port) {
+ let tabid = port.sender.tab.id;
+ PORTS[tabid] = port;
+ port.onDisconnect.addListener((p) => {
+ delete PORTS[tabid];
+ delete PENDING[tabid];
+ RUNNING.delete(tabid);
+ updStop();
+ });
+ port.onMessage.addListener(msg => {
+ switch (msg.msg) {
+ case "finished":
+ RUNNING.delete(tabid);
+ updStop();
+ break;
}
+ });
+
+ if (port.sender.tab.id in PENDING) {
+ var info = PENDING[port.sender.tab.id];
+ delete PENDING[port.sender.tab.id];
+ process(info, port.sender.tab.id);
}
- catch (ex) {
- log(LOG_ERROR, "failed to setup menu (plain)", ex);
- }
- };
-
- contextMenu.addEventListener("popupshowing", onContextMenu, true);
- menuCascaded.allMenu.addEventListener("command", onAll, true);
- menuPlain.allMenu.addEventListener("command", onAll, true);
- menuCascaded.allDomainMenu.addEventListener("command", onAllDomain, true);
- menuPlain.allDomainMenu.addEventListener("command", onAllDomain, true);
- menuCascaded.stopMenu.addEventListener("command", onStop, true);
- menuPlain.stopMenu.addEventListener("command", onStop, true);
- menuCascaded.limitMenu.addEventListener("command", onLimitCommand, true);
- menuPlain.limitMenu.addEventListener("command", onLimitCommand, true);
- menuCascaded.slideMenu.addEventListener("command", onSlideCommand, true);
- menuPlain.slideMenu.addEventListener("command", onSlideCommand, true);
- unloadWindow(window, function() {
- contextMenu.removeEventListener("popuphowing", onContextMenu, true);
- menuCascaded.allMenu.removeEventListener("command", onAll, true);
- menuPlain.allMenu.removeEventListener("command", onAll, true);
- menuCascaded.allDomainMenu.removeEventListener("command", onAllDomain,
- true);
- menuPlain.allDomainMenu.removeEventListener("command", onAllDomain, true);
- menuCascaded.stopMenu.removeEventListener("command", onStop, true);
- menuPlain.stopMenu.removeEventListener("command", onStop, true);
- menuCascaded.limitMenu.removeEventListener("command", onLimitCommand, true);
- menuPlain.limitMenu.removeEventListener("command", onLimitCommand, true);
- menuCascaded.slideMenu.removeEventListener("command", onSlideCommand, true);
- menuPlain.slideMenu.removeEventListener("command", onSlideCommand, true);
- contextMenu = menuPlain = menuCascaded = null;
});
- log(LOG_INFO, "all good!");
}
-registerOverlay(
- "repagination.xul",
- "chrome://browser/content/browser.xul",
- main
-);
-registerOverlay(
- "repagination.xul",
- "chrome://navigator/content/navigator.xul",
- main
-);
+
+browser.storage.local.get().then(myinit, onError);
+
+browser.storage.onChanged.addListener(prefReset);
+
+console.info("all good!");
/* vim: set et ts=2 sw=2 : */
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000..640435a
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,34 @@
+{
+ "manifest_version": 2,
+ "name": "__MSG_extensionName__",
+ "version": "2020.5.27",
+ "description": "__MSG_extensionDescription__",
+ "homepage_url": "https://github.com/Mathnerd314/repagination/",
+
+ "default_locale": "en",
+ "options_ui": {
+ "page": "options.html",
+ "browser_style": true
+ },
+ "icons": { "32": "icon32.png",
+ "48": "icon.png",
+ "64": "icon64.png"},
+
+ "applications": {
+ "gecko": {
+ "id": "repagination-fork-mathnerd314@github.com",
+ "strict_min_version": "63.0"
+ }
+ },
+
+ "background": {
+ "scripts": ["main.js"]
+ },
+
+ "permissions": [
+ "activeTab",
+ "storage",
+ "menus",
+ ""
+ ]
+}
diff --git a/options.html b/options.html
new file mode 100644
index 0000000..10acd23
--- /dev/null
+++ b/options.html
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+Credits
+
+- Original developer: Omar Lev
+- Developer, translator: Nils Maier
+- Current maintainer: Mathnerd314
+
+
\ No newline at end of file
diff --git a/options.js b/options.js
new file mode 100644
index 0000000..3af0b55
--- /dev/null
+++ b/options.js
@@ -0,0 +1,19 @@
+/* see also main.js */
+
+/*
+Update the options UI with the settings values retrieved from storage,
+or the default settings if the stored settings are empty.
+*/
+function updateUI(restoredSettings) {
+ document.getElementById("slideshows").checked = restoredSettings.slideshows || false;
+}
+
+function onError(e) {
+ console.error(e);
+}
+
+browser.storage.local.get().then(updateUI, onError);
+
+document.getElementById("slideshows").onchange = function setSlideshows() {
+ browser.storage.local.set({ exists: true, slideshows: document.getElementById("slideshows").checked});
+};
diff --git a/options.xul b/options.xul
deleted file mode 100644
index 91391d6..0000000
--- a/options.xul
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/repagination.xul b/repagination.xul
deleted file mode 100644
index 579d1d3..0000000
--- a/repagination.xul
+++ /dev/null
@@ -1,75 +0,0 @@
-
-
-
-
diff --git a/sdk/cothreads.js b/sdk/cothreads.js
deleted file mode 100644
index 139701a..0000000
--- a/sdk/cothreads.js
+++ /dev/null
@@ -1,244 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-// Note: only used for dispatching CoThreads to the mainThread event loop
-const ThreadManager = Cc["@mozilla.org/thread-manager;1"].
- getService(Ci.nsIThreadManager);
-const MainThread = ThreadManager.mainThread;
-
-const CoThreadBase = {
- _idx: 0,
- _ran: false,
- _finishFunc: null,
-
- init: function CoThreadBase_init(func, yieldEvery, thisCtx) {
- this._thisCtx = thisCtx ? thisCtx : this;
-
- // default to 1
- this._yieldEvery = typeof yieldEvery == 'number' ?
- Math.floor(yieldEvery) :
- 1;
- if (yieldEvery < 1) {
- throw Cr.NS_ERROR_INVALID_ARG;
- }
-
- if (typeof func != 'function' && !(func instanceof Function)) {
- throw Cr.NS_ERROR_INVALID_ARG;
- }
- this._func = func;
- this.init = function() {};
- },
-
- start: function CoThreadBase_run(finishFunc) {
- if (this._ran) {
- throw new Error("You cannot run a CoThread/CoThreadListWalker instance " +
- "more than once.");
- }
- this._finishFunc = finishFunc;
- this._ran = true;
- MainThread.dispatch(this, 0);
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsICancelable,
- Ci.nsIRunnable]),
-
- _terminated: false,
-
- run: function CoThreadBase_run() {
- if (this._terminated) {
- return;
- }
-
- let y = this._yieldEvery;
- let g = this._generator;
- let f = this._func;
- let ctx = this._thisCtx;
- let callf = this._callf;
- const isStar = !('send' in g);
- try {
- for (let i = 0; i < y; ++i) {
- let next = g.next();
- if (isStar) {
- if (next.done) {
- throw "complete";
- }
- next = next.value;
- }
- if (!callf(ctx, next, this._idx++, f)) {
- throw 'complete';
- }
- }
- if (!this._terminated) {
- MainThread.dispatch(this, 0);
- }
- }
- catch (ex) {
- this.cancel();
- }
- },
-
- cancel: function CoThreadBase_cancel() {
- if (this._terminated) {
- return;
- }
- this._terminated = true;
- if (this._finishFunc) {
- this._finishFunc.call(this._thisCtx);
- }
- }
-};
-
-/**
- * Constructs a new CoThread (aka. pseudo-thread).
- * A CoThread will repeatedly call a specified function, but "breaking"
- * the operation temporarily after a certain amount of calls,
- * so that the main thread gets a chance to process any outstanding
- * events.
- *
- * Example:
- * new CoThread(
- * // What to do with each item?
- * // Print it!
- * function(count) document.write(count + "
") || (count < 30000),
- * // When to turn over Control?
- * // Each 1000 items
- * 1000
- * ).start();
- *
- * @param {Function} func Function to be called. Is passed call count as
- * argument. Returning false will cancel the operation.
- * @param {Number} yieldEvery Optional. After how many items control should be
- * turned over to the main thread
- * @param {Object} thisCtx Optional. The function will be called in the scope of
- * this object (or if omitted in the scope of the
- * CoThread instance)
- */
-exports.CoThread = function CoThread(func, yieldEvery, thisCtx) {
- this.init(func, yieldEvery, thisCtx);
- // fake generator so we may use a common implementation. ;)
- this._generator = (function() {
- for(;;) {
- yield null;
- }
- })();
-};
-
-exports.CoThread.prototype = Object.create(CoThreadBase, {
- _callf: {
- value: function CoThread__callf(ctx, i, idx, fn) {
- return fn.call(ctx, idx);
- },
- enumerable: true
- }
-});
-
-/**
- * Constructs a new CoThreadInterleaved (aka. pseudo-thread).
- * The CoThread will process a interleaved function (generator)
- *
- * Example:
- * new CoThread(
- * function(count) {
- * do_some();
- * yield true;
- * do_more();
- * yield true;
- * if (!do_even_more()) {
- * return;
- * }
- * do_last();
- * },
- * // When to turn over Control?
- * // Each 2 items
- * 2
- * ).start();
- *
- * @param {Function} func Function to be called. Is passed call count as
- * argument. Returning false will cancel the operation.
- * @param {Number} yieldEvery Optional. After how many items control should be
- * turned over to the main thread
- * @param {Object} thisCtx Optional. The function will be called in the scope of
- * this object (or if omitted in the scope of the
- * CoThread instance)
- */
-exports.CoThreadInterleaved = function CoThreadInterleaved(generator,
- yieldEvery,
- thisCtx) {
- this.init(() => true, yieldEvery, thisCtx);
- this._generator = generator;
-};
-exports.CoThreadInterleaved.prototype = Object.create(CoThreadBase, {
- _callf: {
- value: () => true,
- enumerable: true
- }
-});
-
-/**
- * Constructs a new CoThreadListWalker (aka. pseudo-thread).
- * A CoThreadListWalker will walk a specified list and call a specified function
- * on each item, but "breaking" the operation temporarily after a
- * certain amount of processed items, so that the main thread may
- * process any outstanding events.
- *
- * Example:
- * new CoThreadListWalker(
- * // What to do with each item?
- * // Print it!
- * function(item, idx) {
- * return document.write(item + "/" + idx + "
") || true;
-* },
- * // What items?
- * // 0 - 29999
- * (function() { for (let i = 0; i < 30000; ++i) yield i; })(),
- * // When to turn over Control?
- * // Each 1000 items
- * 1000,
- * null,
- * ).start(function() alert('done'));
- *
- * @param {Function} func Function to be called on each item. Is passed item
- * and index as arguments. Returning false will cancel
- * the operation.
- * @param {Array/Generator} arrayOrGenerator Array or Generator object to be
- * used as the input list
- * @param {Number} yieldEvery Optional. After how many items control should be
- * turned over to the main thread
- * @param {Object} thisCtx Optional. The function will be called in the scope of
- * this object (or if omitted in the scope of the
- * CoThread instance)
- */
-exports.CoThreadListWalker = function CoThreadListWalker(func, arrayOrGenerator,
- yieldEvery, thisCtx) {
- this.init(func, yieldEvery, thisCtx);
-
- if (arrayOrGenerator instanceof Array || 'length' in arrayOrGenerator) {
- // make a generator
- this._generator = (function*() {
- for (let i of arrayOrGenerator) {
- yield i;
- }
- })();
- }
- else {
- this._generator = arrayOrGenerator;
- }
-
- if (this._lastFunc && (typeof func != 'function' &&
- !(func instanceof Function))) {
- throw Cr.NS_ERROR_INVALID_ARG;
- }
-};
-
-exports.CoThreadListWalker.prototype = Object.create(CoThreadBase, {
- _callf: {
- value: function CoThreadListWalker__callf(ctx, item, idx, fn) {
- return fn.call(ctx, item, idx);
- },
- enumerable: true
- }
-});
-
-/* vim: set et ts=2 sw=2 : */
diff --git a/sdk/logging.js b/sdk/logging.js
deleted file mode 100644
index e17ce79..0000000
--- a/sdk/logging.js
+++ /dev/null
@@ -1,146 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-const global = this;
-
-Instances.register("ScriptError",
- "@mozilla.org/scripterror;1",
- "nsIScriptError",
- "init");
-
-var UNKNOWN_STACK = {
- stackMsg: "",
- sourceName: "unknown",
- sourceLine: "",
- lineNumber: 0,
- columnNumber: 0
-};
-Object.freeze(UNKNOWN_STACK);
-
-function prepareStack(stack) {
- if (!stack || !(stack instanceof Ci.nsIStackFrame)) {
- stack = Components.stack;
- for (let i = 0; stack && i < 2; ++i) {
- stack = stack.caller;
- }
- if (!stack) {
- return UNKNOWN_STACK;
- }
- }
- let rv = {};
- rv.sourceName = stack.filename;
- rv.sourceLine = stack.sourceLine;
- rv.lineNumber = stack.lineNumber;
- let message = [];
- for (let i = 0; stack && i < 6; ++i, stack = stack.caller) {
- if (stack.lineNumber) {
- message.push("\t" + (stack.name || "[anonymous]") + "() @ " +
- stack.filename + ":" + stack.lineNumber);
- }
- else {
- message.push("\t[native @ " + (stack.languageName || "???" ) + "]");
- }
- }
- rv.stackMsg = message.join("\n");
- rv.prototype = UNKNOWN_STACK;
- return rv;
-}
-
-const {
- errorFlag,
- warningFlag
-} = Ci.nsIScriptError;
-
-Object.defineProperties(exports, {
- LOG_DEBUG: {value: 0, enumerable: true},
- LOG_INFO: {value: 1, enumerable: true},
- LOG_ERROR: {value: 2, enumerable: true},
- LOG_NONE: {value: 0x7FFFFFFF},
- PREFIX: {get: () => prefix},
- setLogLevel: {value: l => global.level = l}
-});
-
-var prefix = ADDON.name;
-global.level = exports.LOG_NONE;
-
-exports.log = function(level, message, exception) {
- try {
- if (global.level > level) {
- return;
- }
-
- if (message instanceof Ci.nsIScriptError ||
- message instanceof Ci.nsIException || message.fileName) {
- exception = message;
- message = exception.message;
- }
- else if (exception) {
- message = message + " [Exception: " + exception.message + "]";
- }
-
- let {
- stackMsg,
- sourceName,
- sourceLine,
- lineNumber,
- columnNumber
- } = prepareStack((exception && exception.location) || null);
-
- if (stackMsg) {
- message += "\n" + stackMsg;
- }
-
- let category = "component javascript";
-
- if (exception) {
- if (exception instanceof Ci.nsIScriptError) {
- sourceName = exception.sourceName;
- sourceLine = exception.sourceLine;
- lineNumber = exception.lineNumber;
- columnNumber = exception.columnNumber;
- category = exception.category;
- }
- else if (exception instanceof Ci.nsIException) {
- sourceName = exception.filename;
- lineNumber = exception.lineNumber;
- }
- else {
- sourceName = exception.fileName || sourceName;
- lineNumber = exception.lineNumber || lineNumber;
- }
- }
-
- let levelMsg;
- switch (level) {
- case exports.LOG_ERROR:
- levelMsg = "error";
- break;
- case exports.LOG_INFO:
- levelMsg = "info";
- break;
- default:
- levelMsg = "debug";
- }
-
- message = global.prefix + " (" + levelMsg + ") - " + message;
-
- const scriptError = new Instances.ScriptError(
- message,
- sourceName,
- sourceLine,
- lineNumber,
- columnNumber,
- level >= exports.LOG_ERROR ? errorFlag : warningFlag,
- category);
- Services.console.logMessage(scriptError);
- }
- catch (ex) {
- reportError("failed to log");
- reportError(ex);
- reportError(exception || message);
- }
-};
-
-/* vim: set et ts=2 sw=2 : */
diff --git a/sdk/observers.js b/sdk/observers.js
deleted file mode 100644
index c29e307..0000000
--- a/sdk/observers.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-const manager = {
- topics: Object.create(null),
- observe: function observe(subject, topic, data) {
- let observers = this.topics[topic];
- if (!observers) {
- return;
- }
- for (let i = observers.length; ~(--i);) {
- try {
- observers[i].call(null, subject, topic, data);
- }
- catch (ex) {
- log(LOG_ERROR, "observer threw", ex);
- }
- }
- },
- add: function add(topic, cb) {
- try {
- this.topics[topic].push(cb);
- }
- catch (ex) {
- this.topics[topic] = [cb];
- Services.obs.addObserver(this, topic, false);
- }
- },
- remove: function remove(topic, cb) {
- let observers = this.topics[topic];
- if (!observers) {
- log(LOG_ERROR,
- "tried to remove a non-existant observer for topic: " + topic);
- return;
- }
- observers = this.topics[topic] = observers.filter(fn => fn != cb);
- if (!observers.length) {
- delete this.topics[topic];
- Services.obs.removeObserver(this, topic, false);
- }
- },
- teardown: function teardown() {
- for (let k in this.topics) {
- this.topics[k].splice(0);
- delete this.topics[k];
- Services.obs.removeObserver(this, k, false);
- }
- }
-};
-unload(() => manager.teardown());
-
-Object.defineProperties(exports, {
- add: {value: (topic, cb) => manager.add(topic, cb)},
- remove: {value: (topic, cb) => manager.remove(topic, cb)}
-});
-
-/* vim: set et ts=2 sw=2 : */
diff --git a/sdk/preferences.js b/sdk/preferences.js
deleted file mode 100644
index 9ae7523..0000000
--- a/sdk/preferences.js
+++ /dev/null
@@ -1,177 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-/* This implementation was heavily inspired by the add-on SDK stuff ;)
- *
- * TODO:
- * - Implement enumerate/getChildren
- */
-
-try {
- Instances.register("SupportsString", "@mozilla.org/supports-string;1", "nsISupportsString");
-}
-catch (ex) {
- // ignore
-}
-
-const {
- PREF_INVALID: INVALID,
- PREF_STRING: STR,
- PREF_INT: INT,
- PREF_BOOL: BOOL
-} = Ci.nsIPrefBranch;
-
-function createProxy(branch) {
- return new Proxy(branch, {
- get: function(receiver, name) {
- if (name in branch) {
- log(LOG_DEBUG, "prefproxy: returning plain " + name);
- return branch[name];
- }
- log(LOG_DEBUG, "prefproxy: returning pref " + branch.branch + name);
- return branch.get(name);
- },
- set: function(receiver, name, value) {
- if (name in branch) {
- throw new Error("Cannot use this name as a preference");
- }
- log(LOG_DEBUG, "prefproxy: setting pref " + branch.branch + name);
- branch.set(name, value);
- },
- delete: function(name) {
- if (name in branch) {
- throw new Error("Cannot use this name as a preference");
- }
- branch.delete(name);
- },
- has: function(name) {
- if (name in branch) {
- throw new Error("Cannot use this name as a preference");
- }
- log(LOG_DEBUG, "prefproxy: has pref " + branch.branch + name);
- return branch.has(name);
- }
- });
-}
-
-function Branch(branch) {
- if (typeof(branch) == "string") {
- if (!/\.$|^$/.test(branch)) {
- branch += ".";
- }
- branch = Services.prefs.getBranch(branch);
- if ("nsIPrefBranch2" in Ci) {
- branch.QueryInterface(Ci.nsIPrefBranch2);
- }
- }
- this.branch = branch.root;
-
- let getType = this.getType = pref => branch.getPrefType(pref);
- this.has = pref => getType(pref) != INVALID;
- this.isChanged = pref => branch.prefHasUserValue(pref);
- this.isDefault = pref => !this[pref].isChanged();
- let get = this.get = function(pref, defaultValue) {
- switch (getType(pref)) {
- case STR:
- return branch.getComplexValue(pref, Ci.nsISupportsString).data;
- case INT:
- return branch.getIntPref(pref);
- case BOOL:
- return branch.getBoolPref(pref);
- default:
- if (typeof(defaultValue) != "undefined") {
- return defaultValue;
- }
- log(LOG_DEBUG, "creating subbranch for " + branch.root + pref);
- return createProxy(new Branch(branch.root + pref));
- }
- };
- this.set = function(pref, value) {
- if (value === null || value === undefined) {
- log(LOG_DEBUG, "ignoring null value for pref " + pref);
- return;
- }
- switch (value.constructor.name) {
- case "Number":
- if (!isFinite(value)) {
- let msg = "attempt to set an invalid number to pref " + branch.root +
- pref + ": " + value;
- log(LOG_DEBUG, msg);
- throw new Error(msg);
- }
- if (value % 1) {
- log(LOG_DEBUG, "coercing float to int before setting pref " +
- branch.root + pref + ": " + value);
- value = parseInt(value);
- }
- branch.setIntPref(pref, value);
- break;
-
- case "Boolean":
- branch.setBoolPref(pref, value);
- break;
-
- default:
- log(LOG_DEBUG, "coercing object into string before setting pref " +
- branch.root + pref);
- value = value.toString();
- // fall through
-
- case "String":
- {
- let str = new Instances.SupportsString();
- str.data = value;
- branch.setComplexValue(pref, Ci.nsISupportsString, str);
- }
- break;
- }
- };
- this.delete = function(pref) {
- branch.clearUserPref(pref);
- };
- this.observe = function(pref, callback, defaultValue) {
- let obs = {
- observe: function(s, t, d) {
- [s, t, d] = [s, t, d];
- callback(pref, get(pref, defaultValue));
- }
- };
- branch.addObserver(pref, obs, false);
- unload(() => branch.removeObserver(pref, obs));
- obs.observe();
- };
-}
-
-(function setDefaultPrefs() {
- let branch = new Branch(Services.prefs.getDefaultBranch(""));
- let scope = {
- pref: (key, val) => {
- try {
- branch.set(key, val);
- }
- catch (ex) {
- Cu.reportError(ex);
- }
- }
- };
- try {
- Services.scriptloader.loadSubScript(BASE_PATH +
- "defaults/preferences/prefs.js", scope);
- }
- // errors here should not kill addon
- catch (ex) {
- log(LOG_ERROR, "failed to setup default preferences", ex);
- }
-})();
-
-var globalPrefs = createProxy(new Branch(""));
-var prefs = globalPrefs.extensions[ADDON.id];
-
-Object.defineProperties(exports, {
- prefs: {get: () => prefs, enumerable: true},
- globalPrefs: {value: globalPrefs, enumerable: true}
-});
-
-/* vim: set et ts=2 sw=2 : */
diff --git a/sdk/request.js b/sdk/request.js
deleted file mode 100644
index 3be32cb..0000000
--- a/sdk/request.js
+++ /dev/null
@@ -1,119 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-Cu.importGlobalProperties(["XMLHttpRequest", "Blob", "File"]);
-
-exports.Blob = Blob;
-exports.File = File;
-exports.xhr = exports.XMLHttpRequest = XMLHttpRequest;
-
-function Callbacks(underlay) {
- try {
- this.underlay = underlay.QueryInterface(Ci.nsIInterfaceRequestor);
- }
- catch (ex) {
- this.underlay = null;
- }
-}
-Callbacks.prototype = {
- badHost: null,
- getInterface: function(iid) {
- try {
- return this.QueryInterface(iid);
- }
- catch (ex) {
- if (this.underlay) {
- return this.underlay.getInterface(iid);
- }
- throw ex;
- }
- },
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIBadCertListener2, Ci.nsIInterfaceRequestor]),
- notifyCertProblem: function(si, status, host) {
- this.badHost = host;
- return false;
- }
-};
-
-exports.request = (method, url, data, options) => {
- options = options || {};
- return new Promise((resolve, reject) => {
- let req = new XMLHttpRequest();
- let cbs = null;
- try {
- url = url.spec || url;
- if (method == "POST" && !data) {
- let [u, ...pieces] = url.split("?");
- url = u;
- data = pieces.length && pieces.join("?") || null;
- }
- req.timeout = options.timeout || 10000;
- if (options.mime) {
- req.overrideMimeType(options.mime);
- }
- if (options.type) {
- req.responseType = options.type;
- }
- else {
- req.responseType = "json";
- }
- if (options.setup) {
- options.setup(req);
- }
- req.addEventListener("loadend", function end() {
- req.removeEventListener("loadend", end, false);
- try {
- if (req.status < 100 || req.status >= 400) {
- if (cbs && cbs.badHost) {
- throw new Error(`${cbs.badHost} has an invalid TLS Certificate`);
- }
- throw new Error("Bad response");
- }
- log(LOG_DEBUG, `request to ${url} resolved`);
- resolve(req);
- }
- catch (ex) {
- log(LOG_DEBUG, `request to ${url} rejected ${ex}`);
- reject(ex);
- }
- }, false);
- log(LOG_DEBUG, `Making request to ${url} w/ data ${data}`);
- req.open(method, url);
- if (req.channel) {
- try {
- cbs = new Callbacks(req.channel.notificationCallbacks);
- req.channel.notificationCallbacks = cbs;
- }
- catch (ex) {
- log(LOG_DEBUG, "Failed to set callbacks", ex);
- }
- if (req.channel instanceof Ci.nsIHttpChannel) {
- if (options.cookies) {
- for (let n of Object.keys(options.cookies)) {
- req.channel.setRequestHeader("Cookie", `${encodeURIComponent(n)}=${encodeURIComponent(options.cookies[n])}`, true);
- }
- }
- if (options.headers) {
- for (let n of Object.keys(options.headers)) {
- let h = options.headers[n];
- let merge = true;
- if (Array.isArray(h)) {
- merge = !!h[1];
- h = h[0];
- }
- req.channel.setRequestHeader(n, h, merge);
- }
- }
- }
- }
- req.send(data || null);
- }
- catch (ex) {
- reject(ex);
- }
- });
-};
-
-/* vim: set et ts=2 sw=2 : */
diff --git a/sdk/strings.js b/sdk/strings.js
deleted file mode 100644
index 68bbfa6..0000000
--- a/sdk/strings.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-var bundleFlush = null;
-
-function Bundle(uri) {
- lazy(this, "_bundle", function() {
- if (!bundleFlush) {
- bundleFlush = unload(() => Services.strings.flushBundles());
- }
- log(LOG_DEBUG, `loading bundle ${uri}`);
- return Services.strings.createBundle(uri);
- });
- this._dict = Object.create(null);
-}
-Bundle.prototype = {
- getString: function getString(id /*, args */) {
- try {
- if (arguments.length > 1) {
- let args = Array.slice(arguments, 1);
- return this._bundle.formatStringFromName(id, args, args.length);
- }
- return this._bundle.GetStringFromName(id);
- }
- catch (ex) {
- log(LOG_ERROR, "invalid string bundle id: " + id, ex);
- throw ex;
- }
- }
-};
-
-Object.defineProperty(exports, "getBundle", {value: uri => {
- let bundle = new Bundle(uri);
- let rv = bundle.getString.bind(bundle);
- rv.getString = rv;
- return rv;
-}});
-
-/* vim: set et ts=2 sw=2 : */
diff --git a/sdk/timers.js b/sdk/timers.js
deleted file mode 100644
index 99c9417..0000000
--- a/sdk/timers.js
+++ /dev/null
@@ -1,90 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-Instances.register("Timer", "@mozilla.org/timer;1", "nsITimer", "init");
-
-const {
- TYPE_ONE_SHOT,
- TYPE_REPEATING_SLACK
-} = Ci.nsITimer;
-
-const CLAMP = globalPrefs.dom.min_timeout_value;
-
-function uuid() {
- return Services.uuid.generateUUID().toString();
-}
-
-let timers = Object.create(Object.prototype, {
- create: {value: function(type, func, delay, args) {
- let id = uuid();
- let timer = new Instances.Timer({
- observe: function() {
- log(LOG_DEBUG, "timer " + id + "fired delay: " + delay +
- " type:" + type);
- try {
- func.apply(null, args);
- }
- finally {
- if (type == TYPE_ONE_SHOT) {
- delete this[id];
- }
- }
- }
- }, delay, type);
- this[id] = timer;
- log(LOG_DEBUG, "timer " + id + " created delay: " + delay +
- " type:" + type);
- return id;
- }},
- destroy: {value: function(id) {
- if (id in this) {
- try {
- this[id].cancel();
- } catch (ex) {}
- delete this[id];
- log(LOG_DEBUG, "timer " + id + " destroyed");
- }
- }}
-});
-unload(function unload_timers() {
- for (let [id,timer] in new Iterator(timers)) {
- try {
- timer.cancel();
- } catch (ex) {}
- delete timers[id];
- }
-});
-
-Object.defineProperties(exports, {
- createTimeout: {
- value: function createTimeout(func, delay /*, ... */) {
- let args = Array.slice(2);
- return timers.create(TYPE_ONE_SHOT, func, Math.max(delay, CLAMP), args);
- },
- enumerable: true
- },
- createInterval: {
- value: function createInterval(func, delay /*, ... */) {
- let args = Array.slice(2);
- return timers.create(TYPE_REPEATING_SLACK, func,
- Math.max(delay, CLAMP), args);
- },
- enumerable: true
- },
- defer: {
- value: function defer(func /*. ... */) {
- let args = Array.slice(1);
- return timers.create(TYPE_ONE_SHOT, func, 0, args);
- },
- enumerable: true
- },
- destroy: {
- value: id => timers.destroy(id),
- enumerable: true
- }
-});
-Object.freeze(exports);
-
-/* vim: set et ts=2 sw=2 : */
diff --git a/sdk/windows.js b/sdk/windows.js
deleted file mode 100644
index 429d697..0000000
--- a/sdk/windows.js
+++ /dev/null
@@ -1,222 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-Instances.register("XHR",
- "@mozilla.org/xmlextras/xmlhttprequest;1",
- "nsIXMLHttpRequest");
-
-/**
- * Specialized unloader that will trigger whenever either the window gets
- * unloaded or the add-on is shut down
- */
-exports.unloadWindow = function unloadWindow(window, fn) {
- let handler = unload(function() {
- window.removeEventListener('unload', handler, false);
- try {
- fn();
- }
- catch (ex) {
- log(LOG_ERROR, "failed to run window unloader", ex);
- }
- });
- window.addEventListener('unload', handler, false);
-};
-
-/**
- * Apply a callback to each open and new browser windows.
- */
-exports.watchWindows = function watchWindows(location, callback) {
- // Wrap the callback in a function that ignores failures
- function watcher(window) {
- log(LOG_DEBUG, "watchwindows watcher");
- try {
- callback(window, window.document);
- }
- catch(ex) {
- log(LOG_ERROR, "window watcher failed", ex);
- }
- }
-
- // Wait for the window to finish loading before running the callback
- function runOnLoad(window) {
- // Listen for one load event before checking the window type
- window.addEventListener("load", function runOnLoad_load() {
- window.removeEventListener("load", runOnLoad_load, false);
-
- // Now that the window has loaded, only handle requested windows
- if (window.location == location) {
- watcher(window);
- }
- else {
- log(LOG_DEBUG, "skipping window: " + window.location +
- " as another location was requested: " + location);
- }
- }, false);
- }
-
- // Add functionality to existing windows
- let windows = Services.wm.getEnumerator(null);
- while (windows.hasMoreElements()) {
- // Only run the watcher immediately if the browser is completely loaded
- let window = windows.getNext();
- if (window.document.readyState == "complete") {
- if (window.location == location) {
- watcher(window);
- }
- else {
- log(LOG_DEBUG, "skipping early window: " + window.location +
- " as another location was requested: " + location);
- }
- }
- // Wait for the window to load before continuing
- else {
- runOnLoad(window);
- }
- }
-
- // Watch for new browser windows opening then wait for it to load
- function windowWatcher(subject, topic) {
- if (topic == "domwindowopened") {
- runOnLoad(subject);
- }
- }
- Services.ww.registerNotification(windowWatcher);
-
- // Make sure to stop watching for windows if we're unloading
- unload(() => Services.ww.unregisterNotification(windowWatcher));
-};
-
-/**
- * Register a new overlay (XUL)
- */
-exports.registerOverlay = function registerOverlay(src, location, callback) {
- function inject(xul, window, document) {
- function $(id) {
- return document.getElementById(id);
- }
- function $$(q) {
- return document.querySelector(q);
- }
-
- // loadOverlay for the poor
- function addNode(target, node) {
- // helper: insert according to position
- function insertX(nn, attr, callback) {
- if (!nn.hasAttribute(attr)) {
- return false;
- }
- let places = nn.getAttribute(attr)
- .split(',')
- .map(p => p.trim())
- .filter(p => !!p);
- for (let p of places) {
- let pn = $$('#' + target.id + ' > #' + p);
- if (!pn) {
- continue;
- }
- callback(pn);
- return true;
- }
- return false;
- }
-
- // bring the node to be inserted into the document
- let nn = document.importNode(node, true);
-
- // try to insert according to insertafter/before
- if (insertX(nn, 'insertafter',
- pn => pn.parentNode.insertBefore(nn, pn.nextSibling)) ||
- insertX(nn, 'insertbefore',
- pn => pn.parentNode.insertBefore(nn, pn))) {
- }
- // just append
- else {
- target.appendChild(nn);
- }
- return nn;
- }
- log(LOG_DEBUG, "gonna stuff: " + src + " into: " + location);
-
- try {
- // store unloaders for all elements inserted
- let unloaders = [];
-
- // Add all overlays
- for (let id in xul) {
- let target = $(id);
- if (!target) {
- log(LOG_INFO, "no target for " + id + ", not inserting");
- continue;
- }
-
- // insert all children
- for (let n = xul[id].firstChild; n; n = n.nextSibling) {
- if (n.nodeType != n.ELEMENT_NODE) {
- continue;
- }
- let nn = addNode(target, n);
- unloaders.push(() => nn.parentNode.removeChild(nn));
- }
- }
- // install per-window unloader
- if (unloaders.length) {
- exports.unloadWindow(window, () => unloaders.forEach(u => u()));
- }
-
- callback && callback(window, document);
- }
- catch (ex) {
- log(LOG_ERROR, "failed to inject xul", ex);
- }
- }
-
- let _r = new Instances.XHR();
- _r.onload = function() {
- log(LOG_DEBUG, "loaded: " + src);
- let document = _r.responseXML;
-
- // clean the document a bit
- let emptyNodes = document.evaluate(
- "//text()[normalize-space(.) = '']", document, null, 7, null);
- for (let i = 0, e = emptyNodes.snapshotLength; i < e; ++i) {
- let n = emptyNodes.snapshotItem(i);
- n.parentNode.removeChild(n);
- }
-
- // prepare all elements to be inserted
- let xul = {};
- for (let n = document.documentElement.firstChild; n; n = n.nextSibling) {
- if (n.nodeType != n.ELEMENT_NODE || !n.hasAttribute("id")) {
- continue;
- }
- let id = n.getAttribute("id");
- xul[id] = n;
- }
- if (!Object.keys(xul).length) {
- log(LOG_INFO, "There is only XUL ... but there wasn't");
- return;
- }
- exports.watchWindows(location, inject.bind(null, xul));
- };
- _r.onerror = _r.onabort = function() {
- log(LOG_ERROR, "Failed to load " + src);
- }
- _r.overrideMimeType("application/xml");
- _r.open("GET", BASE_PATH + src);
- // Elevate the request, so DTDs will work. Not a security issue since we
- // always load from BASE_PATH, and that is our privileged chrome package.
- // This is no different than regular overlays.
- let sec = Cc['@mozilla.org/scriptsecuritymanager;1'].
- getService(Ci.nsIScriptSecurityManager);
- try {
- _r.channel.owner = sec.getSystemPrincipal();
- }
- catch (ex) {
- log(LOG_ERROR, "Failed to set system principal");
- }
- _r.send();
-};
-
-/* vim: set et ts=2 sw=2 : */