pax_global_header00006660000000000000000000000064132726314170014520gustar00rootroot0000000000000052 comment=5d5c901b12299cf05e59766d8f89c6830a31e61a tinyjsd-1.2+git1/000077500000000000000000000000001327263141700137065ustar00rootroot00000000000000tinyjsd-1.2+git1/.eslintrc.js000066400000000000000000000027001327263141700161440ustar00rootroot00000000000000module.exports = { "rules": { "linebreak-style": [ 2, "unix" ], "semi": [ 2, "always" ], "strict": [2, "global"], "no-unused-vars": 0, "no-empty": 0, "comma-dangle": 2, "consistent-return": 2, "block-scoped-var": 2, "dot-notation": 2, "no-alert": 0, "no-caller": 2, "no-case-declarations": 2, "no-div-regex": 2, "no-labels": 2, "no-empty-pattern": 2, "no-eq-null": 2, "no-eval": 0, "no-extend-native": 2, "no-extra-bind": 2, "no-fallthrough": 2, "no-floating-decimal": 2, "no-implicit-coercion": 2, "no-implied-eval": 2, "no-invalid-this": 0, "no-iterator": 2, "no-labels": 2, "no-lone-blocks": 2, "no-loop-func": 2, "no-multi-str": 2, "no-native-reassign": 2, "no-new-func": 2, "no-new-wrappers": 2, "no-new": 2, "no-octal-escape": 2, "no-process-env": 2, "no-proto": 2, "no-redeclare": [2, { "builtinGlobals": true }], "no-return-assign": 2, "no-script-url": 0, "no-self-compare": 2, "no-sequences": 2, "no-unused-expressions": 2, "no-useless-call": 2, "no-useless-concat": 2, "no-useless-escape": 1, "no-void": 2, "no-with": 2, "radix": 2, "wrap-iife": [2, "inside"], "yoda": 2, // TODO: //"eqeqeq": 2, }, "env": { "es6": true, "browser": true, "node": true, }, "extends": "eslint:recommended" }; tinyjsd-1.2+git1/Makefile000066400000000000000000000002021327263141700153400ustar00rootroot00000000000000all: eslint *.js content/*/*.js content/*/*.jsm rm -f ../tinyjsd-master.xpi zip -rD ../tinyjsd-master.xpi * --exclude Makefile tinyjsd-1.2+git1/bootstrap.js000066400000000000000000000025621327263141700162660ustar00rootroot00000000000000/*global Components: false */ /* 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 Cu = Components.utils; /* global APP_STARTUP: false, APP_SHUTDOWN: false */ function install() {} function uninstall() {} function startup(data, reason) { const { TinyjsdFactory } = Cu.import("chrome://tinyJsd/content/modules/tinyjsdFactory.jsm", {}); const { TinyjsdOverlays } = Cu.import("chrome://tinyJsd/content/modules/tinyjsd-overlays.jsm", {}); TinyjsdFactory.startup(reason, data); TinyjsdOverlays.startup(reason, data); // to communicate with WebExtension API: // data.webExtension.startup().then(api => { // }); } function shutdown(data, reason) { if (reason === APP_SHUTDOWN) return; const { TinyjsdFactory } = Cu.import("chrome://tinyJsd/content/modules/tinyjsdFactory.jsm", {}); const { TinyjsdOverlays } = Cu.import("chrome://tinyJsd/content/modules/tinyjsd-overlays.jsm", {}); TinyjsdFactory.shutdown(reason, data); TinyjsdOverlays.shutdown(reason, data); Cu.unload("chrome://tinyJsd/content/modules/tinyjsd-overlays.jsm"); Cu.unload("chrome://tinyJsd/content/modules/tinyjsdCommon.jsm"); Cu.unload("chrome://tinyJsd/content/modules/tinyjsdFactory.jsm"); } tinyjsd-1.2+git1/chrome.manifest000066400000000000000000000002131327263141700167070ustar00rootroot00000000000000content tinyjsd content/ skin tinyjsd classic/1.0 skin/ skin tinyjsd modern/1.0 skin/ locale tinyjsd en-US locale/en-US/ tinyjsd-1.2+git1/content/000077500000000000000000000000001327263141700153605ustar00rootroot00000000000000tinyjsd-1.2+git1/content/modules/000077500000000000000000000000001327263141700170305ustar00rootroot00000000000000tinyjsd-1.2+git1/content/modules/tinyjsd-overlays.jsm000066400000000000000000000367631327263141700231100ustar00rootroot00000000000000/*global Components: false*/ /* * 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 = ["TinyjsdOverlays"]; const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; const APP_SHUTDOWN = 2; Cu.importGlobalProperties(["XMLHttpRequest"]); const { Services, Promise } = Cu.import("resource://gre/modules/Services.jsm", {}); const BASE_PATH = "chrome://tinyjsd/content/ui/"; const MY_ADDON_ID = "tinyjsd"; // Overlays to load at startup/enabling const LOAD_OVERLAYS = { // Thunderbird & SeaMonkey (Mail) "chrome://messenger/content/messenger.xul": ["tinyjsd-overlay.xul"], "chrome://messenger/content/messageWindow.xul": ["tinyjsd-overlay.xul"], // SeaMonkey (Browser) "chrome://navigator/content/navigator.xul": ["tinyjsd-overlay.xul"], // Komodo "chrome://komodo/content/komodo.xul": ["tinyjsd-overlay.xul"] }; function DEBUG_LOG(str) { //dump(str + "\n"); } function ERROR_LOG(str) { //dump(str + "\n"); } var WindowListener = { setupUI: function(window, overlayDefs) { DEBUG_LOG("overlays.jsm: setupUI(" + window.document.location.href + ")\n"); loadOverlay(window, overlayDefs, 0); }, tearDownUI: function(window) { let document = window.document; // unload UI elements let s = document.querySelectorAll("[overlay_source='" + MY_ADDON_ID + "']"); for (let i = 0; i < s.length; i++) { let p = s[i].parentNode; p.removeChild(s[i]); } let e = new Event("unload-" + MY_ADDON_ID); window.dispatchEvent(e); // unload CSS s = document.querySelectorAll("overlayed_css[source='" + MY_ADDON_ID + "']"); for (let i = 0; i < s.length; i++) { unloadCSS(s[i].getAttribute("href"), window); let p = s[i].parentNode; p.removeChild(s[i]); } }, // nsIWindowMediatorListener functions onOpenWindow: function(xulWindow) { // A new window has opened let domWindow = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow); // Wait for it to finish loading domWindow.addEventListener("load", function listener() { domWindow.removeEventListener("load", listener, false); for (let w in LOAD_OVERLAYS) { // If this is a relevant window then setup its UI if (domWindow.document.location.href.startsWith(w)) WindowListener.setupUI(domWindow, LOAD_OVERLAYS[w]); } }, false); }, onCloseWindow: function(xulWindow) {}, onWindowTitleChange: function(xulWindow, newTitle) {} }; var TinyjsdOverlays = { startup: function(reason) { let wm = Cc["@mozilla.org/appshell/window-mediator;1"]. getService(Ci.nsIWindowMediator); // Get the list of browser windows already open let windows = wm.getEnumerator(null); while (windows.hasMoreElements()) { let domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow); for (let w in LOAD_OVERLAYS) { // If this is a relevant window then setup its UI if (domWindow.document.location.href.startsWith(w)) WindowListener.setupUI(domWindow, LOAD_OVERLAYS[w]); } } // Wait for any new browser windows to open wm.addListener(WindowListener); }, shutdown: function(reason) { // When the application is shutting down we normally don't have to clean // up any UI changes made if (reason == APP_SHUTDOWN) return; let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator); // Get the list of browser windows already open let windows = wm.getEnumerator(null); while (windows.hasMoreElements()) { let domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow); WindowListener.tearDownUI(domWindow); // If this is a window opened by the addon, then close it if (domWindow.document.location.href.startsWith(BASE_PATH)) domWindow.close(); } // Stop listening for any new browser windows to open wm.removeListener(WindowListener); } }; function getAppId() { return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).ID; } /** * Register a new overlay (XUL) * @param xul: DOM-tre - source XUL to register * @param window: Object - target window * @param document: Object - document in target window */ /** * Load XUL into window * @param srcUrl: String - URL of XUL to load * @param window: Object - target window * @param document: Object - document in target window */ function insertXul(srcUrl, window, document, callback) { function injectDOM(xul) { function $(id) { return document.getElementById(id); } function $$(q) { return document.querySelector(q); } function getToolbarNthTag(toolbar, tagName, elemIndex) { if (elemIndex >= 0) { let s = new RegExp("^" + tagName + "[0-9]+$"); let node = toolbar.firstChild; let n = -1; while (node) { if (node.id.search(s) === 0) n++; if (n == elemIndex) return node; node = node.nextSibling; } } return null; } /** * get toolbar element for separator, spacer and spring */ function getToolbarElem(toolbar, currentset, index) { if (currentset[index] && (currentset[index].search(/^(separator|spacer|spring)$/) === 0)) { let target = currentset[index]; let foundIndex = -1; // find the n-th separator/spacer/spring for (let i = 0; i < index + 1; i++) { if (currentset[i] === target) ++foundIndex; } return getToolbarNthTag(toolbar, target, foundIndex); } return null; } /** * Add a button at the correct place on a toolbar. * Buttons are always added to the toolbar palette. Whether or not the button is added to the * toolbar depends on: * 1. if it's in the currentset of the toolbar (i.e. added previously) * 2. if it's defined a default button and the button has never been added to the toolbar before * * @param palette: Object - the toolbar palette containing all buttons (also invisible ones) * @param toolbarButton Object - the button to add * @param toolbarId String - the ID of the toolbar where the button shall be added * */ function addToolbarButton(palette, toolbarButton, toolbarId) { DEBUG_LOG("overlays.jsm: adding button '" + toolbarButton.id + " to " + toolbarId + "'\n"); let toolbar = $(toolbarId); let buttonId = toolbarButton.id; let firstRun = false; let currentset = toolbar.getAttribute("currentset").split(/,/); if (toolbar.getAttribute("currentset").length === 0) { currentset = toolbar.getAttribute("defaultset").split(/,/); } toolbarButton.setAttribute("overlay_source", MY_ADDON_ID); palette.appendChild(toolbarButton); let index = currentset.indexOf(buttonId); if (index >= 0) { // button was added before let before = null; for (let i = index + 1; i < currentset.length; i++) { if (currentset[i].search(/^(separator|spacer|spring)$/) < 0) { before = $(currentset[i]); } else { before = getToolbarElem(toolbar, currentset, i); } if (before) break; } toolbar.insertItem(buttonId, before); } } // loadOverlay for the poor function addNode(target, node) { // helper: insert according to position function insertX(nn, attr, callbackFunc) { if (!nn.hasAttribute(attr)) { return false; } let places = nn.getAttribute(attr) .split(',') .map(p => p.trim()) .filter(p => Boolean(p)); for (let p of places) { let pn = $$('#' + target.id + ' > #' + p); if (!pn) { continue; } if (callbackFunc) callbackFunc(pn); return true; } return false; } node.setAttribute("overlay_source", MY_ADDON_ID); // 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; } DEBUG_LOG("overlays.jsm: injectDOM: gonna stuff: " + srcUrl + " into: " + document.location.href + "\n"); try { // store unloaders for all elements inserted let unloaders = []; // Add all overlays for (let id in xul) { let target = $(id); if (!target) { if (xul[id].tagName === "toolbarpalette") { let toolboxId = xul[id].getAttribute("targetToolbox"); let toolbarId = xul[id].getAttribute("targetToolbar"); let defaultSet = xul[id].getAttribute("targetToolbarDefaultset"); if (!toolboxId) { DEBUG_LOG("overlays.jsm: injectDOM: cannot overlay toolbarpalette " + id + ": no target toolbox defined\n"); continue; } if (!toolbarId) { DEBUG_LOG("overlays.jsm: injectDOM: cannot overlay toolbarpalette " + id + ": no target toolbar defined\n"); continue; } if (defaultSet) { let toolbar = $(toolbarId); if (toolbar) { toolbar.setAttribute("defaultset", defaultSet); } } let toolbox = $(toolboxId); let palette = toolbox.palette; let c = xul[id].children; while (c.length > 0) { // added toolbar buttons are removed from the palette's children if (c[0].tagName && c[0].tagName === "toolbarbutton") { addToolbarButton(palette, c[0], toolbarId); } } } else { DEBUG_LOG("overlays.jsm: injectDOM: no target for " + id + ", not inserting\n"); } continue; } // insert all children for (let n of xul[id].children) { if (n.nodeType != n.ELEMENT_NODE) { continue; } let nn = addNode(target, n); unloaders.push(() => nn.parentNode.removeChild(nn)); } } } catch (ex) { ERROR_LOG("overlays.jsm: injectDOM: failed to inject xul " + ex.toString()); } } DEBUG_LOG("overlays.jsm: insertXul(" + srcUrl + ")\n"); let xmlReq = new XMLHttpRequest(); xmlReq.onload = function() { DEBUG_LOG("loaded: " + srcUrl + "\n"); let document = xmlReq.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) { continue; } if (n.tagName === "script" || n.tagName === "link") { continue; } if (!n.hasAttribute("id")) { DEBUG_LOG("overlays.jsm: insertXul: no ID for " + n.tagName + "\n"); continue; } let id = n.getAttribute("id"); if (id in xul) { DEBUG_LOG("overlays.jsm: insertXul: duplicate ID: " + id + "\n"); continue; } xul[id] = n; } if (!Object.keys(xul).length) { ERROR_LOG("No element to overlay found. Maybe a parsing error?\n"); return; } injectDOM(xul, window, document); // load css into window let css = document.getElementsByTagName("link"); for (let i = 0; i < css.length; i++) { let rel = css[i].getAttribute("rel"); if (rel && rel === "stylesheet") { loadCss(css[i].getAttribute("href"), window); } } // load scripts into window let sc = document.getElementsByTagName("script"); for (let i = 0; i < sc.length; i++) { let src = sc[i].getAttribute("src"); if (src) { loadScript(src, window); } } if (callback) { callback(0); } }; xmlReq.onerror = xmlReq.onabort = function() { ERROR_LOG("Failed to load " + srcUrl + "\n"); callback(0); }; xmlReq.overrideMimeType("application/xml"); xmlReq.open("GET", BASE_PATH + srcUrl); // 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 { xmlReq.channel.owner = sec.getSystemPrincipal(); } catch (ex) { ERROR_LOG("Failed to set system principal\n"); } xmlReq.send(); } function loadOverlay(window, overlayDefs, index) { DEBUG_LOG("overlays.jsm: loadOverlay(" + index + ")\n"); try { if (index < overlayDefs.length) { let overlayDef = overlayDefs[index]; let document = window.document; let url = overlayDef; if (typeof(overlayDef) !== "string") { url = overlayDef.url; if (overlayDef.application.substr(0, 1) === "!") { if (overlayDef.application.indexOf(getAppId()) > 0) { DEBUG_LOG("overlays.jsm: loadOverlay: skipping " + url + "\n"); loadOverlay(window, overlayDefs, index + 1); return; } } else if (overlayDef.application.indexOf(getAppId()) < 0) { DEBUG_LOG("overlays.jsm: loadOverlay: skipping " + url + "\n"); loadOverlay(window, overlayDefs, index + 1); return; } } let observer = function(result) { loadOverlay(window, overlayDefs, index + 1); }; insertXul(url, window, document, observer); } else { DEBUG_LOG("overlays.jsm: loadOverlay: completed\n"); let e = new Event("load-" + MY_ADDON_ID); window.dispatchEvent(e); DEBUG_LOG("overlays.jsm: loadOverlay: event completed\n"); } } catch (ex) { ERROR_LOG("overlays.jsm: could not overlay for " + window.document.location.href + ":\n" + ex.toString() + "\n"); } } function unloadCSS(url, targetWindow) { let domWindowUtils = targetWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); domWindowUtils.removeSheetUsingURIString(url, 1); } function loadCss(url, targetWindow) { try { let domWindowUtils = targetWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); domWindowUtils.loadSheetUsingURIString(url, 1); let document = targetWindow.document; let e = document.createElement("overlayed_css"); e.setAttribute("href", url); e.setAttribute("source", MY_ADDON_ID); let node = document.firstChild; while (node && (!node.tagName)) { node = node.nextSibling; } if (node) node.appendChild(e); } catch (ex) { ERROR_LOG("Error while loading CSS " + url + ":\n" + ex.message + "\n"); } } function loadScript(url, targetWindow) { let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader); try { loader.loadSubScript(url, targetWindow); } catch (ex) { ERROR_LOG("Error while loading script " + url + ":\n" + ex.message + "\n"); } } tinyjsd-1.2+git1/content/modules/tinyjsdCommon.jsm000066400000000000000000000175611327263141700224120ustar00rootroot00000000000000/* 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/. */ /* global Components: false */ 'use strict'; const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; const CC = Components.Constructor; Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/jsdebugger.jsm"); var EXPORTED_SYMBOLS = ["TinyjsdCommon", "JsdConsole"]; // addDebuggerToGlobal only allows adding the Debugger object to a global. The // this object is not guaranteed to be a global (in particular on B2G, due to // compartment sharing), so add the Debugger object to a sandbox instead. var sandbox = Cu.Sandbox(CC('@mozilla.org/systemprincipal;1', 'nsIPrincipal')()); Cu.evalInSandbox( "Components.utils.import('resource://gre/modules/jsdebugger.jsm');" + "addDebuggerToGlobal(this);", sandbox ); // hold the Debugger object for TinyJSD. var dbg = sandbox.Debugger(); const NS_SCRIPTABLEINPUTSTREAM_CONTRACTID = "@mozilla.org/scriptableinputstream;1"; const NS_IOSERVICE_CONTRACTID = "@mozilla.org/network/io-service;1"; var gConsoleCallback = null; var gRegistrationCompleted = false; var JsdConsole = { log: function(str) { if (gConsoleCallback) gConsoleCallback.log(str); return ""; }, clear: function(str) { if (gConsoleCallback) gConsoleCallback.clear(); return ""; }, getJsd: function() { if (gConsoleCallback) return gConsoleCallback.tinyjsd; return undefined; }, /** * open new window * @param url - String: url to open in new window * @param name - String: window name * @param features - String: window features * @param args - Array of String and/or number: window.arguments */ openWindow: function(url, name, features, args) { let wwatch = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher); let ma = null; let sup = null; if (args) { ma = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); if (typeof args === "string") { sup = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); sup.data = args; ma.appendElement(sup, false); } else if (Array.isArray(args)) { for (let i = 0; i < args.length; i++) { sup = null; switch (typeof args[i]) { case "string": sup = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); break; case "number": if (Math.floor(args[i]) == args[i]) { sup = Cc["@mozilla.org/supports-PRInt64;1"].createInstance(Ci.nsISupportsPRInt64); } else { sup = Cc["@mozilla.org/supports-float;1"].createInstance(Ci.nsISupportsFloat); } break; } if (sup) { sup.data = args[i]; ma.appendElement(sup, false); } } } } wwatch.openWindow(null, url, name, features, ma); } }; var TinyjsdCommon = { _cb: null, _tmpLog: "", _jsUnit: null, _scriptHook: null, _newObjectListener: null, _startupPhase: false, scriptStack: [], URL_OK: RegExp("^(file|chrome|resource|jar):", "i"), setTimeout: function(callbackFunction, sleepTimeMs) { var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); timer.initWithCallback(callbackFunction, sleepTimeMs, Ci.nsITimer.TYPE_ONE_SHOT); return timer; }, setLines: function(count) { var cb = this._cb; this.setTimeout(function __cb() { cb(count, false); }, 0); }, // register callback that gets called after a script has finished loading registerCb: function(func) { this._cb = func; }, logData: function(str) { if (gConsoleCallback) { gConsoleCallback.log(str); } else { this._tmpLog += str; } }, registerLogging: function(obj) { gConsoleCallback = obj; this.logData(this._tmpLog); }, // activate tracking of creation of new global objects enableDebugger: function() { if (gRegistrationCompleted) return; var self = this; let oArr = dbg.findAllGlobals(); for (let i in oArr) { try { dbg.addDebuggee(oArr[i]); } catch (ex) {} } gRegistrationCompleted = true; dbg.onNewGlobalObject = function(o) { this.addDebuggee(o); if (self._newObjectListener) { self._newObjectListener(o); } }; }, addNewObjectListener: function(func) { this._newObjectListener = func; }, removeNewObjectListener: function() { this._newObjectListener = null; }, stopDebugging: function() { this.removeNewObjectListener(); gConsoleCallback = null; dbg.onError = undefined; dbg.onExceptionUnwind = undefined; dbg.onEnterFrame = undefined; dbg.onDebuggerStatement = undefined; dbg.uncaughtExceptionHook = null; dbg.onNewScript = undefined; }, enableJsUnit: function(scriptFile) { this._jsUnit = scriptFile; }, jsUnitEnabled: function() { return this._jsUnit ? true : false; }, getJsUnitMainFile: function() { return this._jsUnit; }, resolveJetpackPath: function(uriPath) { function getJarPath(aPath) { if (aPath.toLowerCase().search(/\.(jar|xpi)!/) > 0) { if (aPath.search(/^([a-z]+:\/|jar:)/) < 0) aPath = "jar:/" + aPath; } return aPath; } let path = uriPath; // detect SDK Addons let i = path.indexOf(" -> "); if (i > 0) { path = path.substr(i + 4); if (path.search(TinyjsdCommon.URL_OK) == 0 || path.startsWith("/")) { return getJarPath(path); } } return getJarPath(uriPath); }, readFile: function(filePath) { // filePath: URL (String) var ioServ = Cc[NS_IOSERVICE_CONTRACTID].getService(Ci.nsIIOService); if (!ioServ) throw Components.results.NS_ERROR_FAILURE; var fileChannel = ioServ.newChannel(filePath, "UTF-8", null); var rawInStream = fileChannel.open(); var scriptableInStream = Cc[NS_SCRIPTABLEINPUTSTREAM_CONTRACTID].createInstance(Ci.nsIScriptableInputStream); scriptableInStream.init(rawInStream); var available = scriptableInStream.available(); var fileContents = scriptableInStream.read(available); scriptableInStream.close(); return fileContents; }, getConditionalBp: function(funcname, funcbody) { return "var " + funcname + " = function _jsdEval (callCount, recursionDepth) {" + funcbody + "}\n"; }, compileConditionalBp: function(funcname, funcbody) { let fnc = this.getConditionalBp(funcname, funcbody); return eval(fnc); }, getDebugger: function() { return dbg; }, getProperty: function(aObj, aKey) { let root = aObj; try { do { if (typeof(aObj.getOwnPropertyDescriptor) == "function") { const desc = aObj.getOwnPropertyDescriptor(aKey); if (desc) { if ("value" in desc) { return desc.value; } // Call the getter if it's safe. return this.hasSafeGetter(desc) ? desc.get.call(root).return : undefined; } } aObj = aObj.proto; } while (aObj); } catch (e) { // If anything goes wrong report the error and return undefined. return "Exception: " + e.toString(); } return undefined; }, hasSafeGetter: function(aDesc) { let fn = aDesc.get; return fn && fn.callable && fn.class == "Function" && fn.script === undefined; }, setStartupPhase: function() { this._startupPhase = true; }, startupCompleted: function() { if (this._startupPhase) { this._startupPhase = false; let insp = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector); insp.exitNestedEventLoop(); } } }; tinyjsd-1.2+git1/content/modules/tinyjsdFactory.jsm000066400000000000000000000313271327263141700225650ustar00rootroot00000000000000/* * 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/. */ /* global Components: false, dump: false */ /* eslint no-invalid-this: 0 */ "use strict"; var EXPORTED_SYMBOLS = ["TinyjsdFactory"]; Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); /* global XPCOMUtils: false */ Components.utils.import("chrome://tinyJsd/content/modules/tinyjsdCommon.jsm"); /* global TinyjsdCommon: false */ Components.utils.import("resource://gre/modules/Services.jsm"); /* global Services: false */ const TinyjsdProtocolHandler_CID = Components.ID("{830e9d02-9dd2-4913-a596-a43a347acd49}"); const TinyjsdProtocolHandler_CONTRACTID = "@mozilla.org/network/protocol;1?name=tinyjsd"; const NS_TINYJSD_CLINE_SERVICE_CID = Components.ID("{7854d457-a141-4bf7-9bbc-f65b5f94f566}"); const NS_SIMPLEURI_CONTRACTID = "@mozilla.org/network/simple-uri;1"; const NS_STRING_INPUT_STREAM_CONTRACTID = "@mozilla.org/io/string-input-stream;1"; const NS_INPUT_STREAM_CHNL_CONTRACTID = "@mozilla.org/network/input-stream-channel;1"; const NS_IOSERVICE_CONTRACTID = "@mozilla.org/network/io-service;1"; const NS_CLINE_SERVICE_CONTRACTID = "@mozilla.org/commandlinehandler/general-startup;1?type=tinyjsd"; const { classes: Cc, interfaces: Ci, manager: Cm, results: Cr, utils: Cu, Constructor: CC } = Components; Cm.QueryInterface(Ci.nsIComponentRegistrar); function DEBUG_LOG(str) { // dump("tinyjsd-service.js: " + str + "\n"); } function dispatch(callbackFunction, sleepTimeMs) { DEBUG_LOG("dispatch: " + sleepTimeMs); var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); timer.initWithCallback(callbackFunction, sleepTimeMs, Ci.nsITimer.TYPE_ONE_SHOT); return timer; } function dispatchEvent(callbackFunction, sleepTimeMs) { DEBUG_LOG("dispatchEvent: f=" + callbackFunction.name + "\n"); // object for dispatching callback back to main thread var mainEvent = function(cbFunc, sleepTime) { this.cbFunction = cbFunc; this.sleepTime = sleepTime; }; mainEvent.prototype = { QueryInterface: function(iid) { if (iid.equals(Ci.nsIRunnable) || iid.equals(Ci.nsISupports)) { return this; } throw Components.results.NS_ERROR_NO_INTERFACE; }, run: function() { DEBUG_LOG("dispatchEvent running mainEvent\n"); if (this.sleepTime) { dispatch(this.cbFunction, this.sleepTime); } else this.cbFunction(); }, notify: function() { DEBUG_LOG("dispatchEvent got notified\n"); if (this.sleepTime) { dispatch(this.cbFunction, this.sleepTime); } else this.cbFunction(); } }; var event = new mainEvent(callbackFunction, sleepTimeMs); var tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager); // dispatch the event to the main thread tm.mainThread.dispatch(event, Ci.nsIThread.DISPATCH_NORMAL); return event; } function TinyjsdProtocolHandler() {} TinyjsdProtocolHandler.prototype = { classDescription: "TinyJSD Protocol Handler", classID: TinyjsdProtocolHandler_CID, contractID: TinyjsdProtocolHandler_CONTRACTID, scheme: "tinyjsd", defaultPort: -1, protocolFlags: Ci.nsIProtocolHandler.URI_INHERITS_SECURITY_CONTEXT | Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE | Ci.nsIProtocolHandler.URI_NORELATIVE | Ci.nsIProtocolHandler.URI_NOAUTH | Ci.nsIProtocolHandler.URI_OPENING_EXECUTES_SCRIPT, QueryInterface: XPCOMUtils.generateQI(["nsIProtocolHandler"]), loadCssFile: function() { var ioServ = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); if (!ioServ) throw Components.results.NS_ERROR_FAILURE; var chromeRegistry = Components.classes["@mozilla.org/chrome/chrome-registry;1"] .getService(Components.interfaces.nsIChromeRegistry); var chromeURI = ioServ.newURI("chrome://tinyjsd/skin/sourceCodeContent.css", "utf-8", null); var fileUri = chromeRegistry.convertChromeURL(chromeURI); var fileChannel = ioServ.newChannelFromURI(chromeURI); var rawInStream = fileChannel.open(); var scriptableInStream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream); scriptableInStream.init(rawInStream); var available = scriptableInStream.available(); var fileContents = scriptableInStream.read(available); scriptableInStream.close(); return fileContents; }, newURI: function(aSpec, originCharset, aBaseURI) { DEBUG_LOG("newURI(): " + aSpec); if (!aSpec.startsWith("tinyjsd:")) { throw Components.results.NS_ERROR_FAILURE; } var uri = Cc[NS_SIMPLEURI_CONTRACTID].createInstance(Ci.nsIURI); try { // Gecko < 57 uri.spec = aSpec; } catch (x) { aSpec = aSpec.substr(8); let i = aSpec.indexOf("?"); try { // Gecko < 60 uri.scheme = "tinyjsd"; if (i >= 0) { uri.query = aSpec.substr(i + 1); uri.pathQueryRef = aSpec.substr(0, i); } else { uri.pathQueryRef = aSpec; } } catch (ex) { // Gecko >= 60 uri = uri.mutate().setScheme("tinyjsd").finalize(); if (i >= 0) { uri = uri.mutate().setQuery(aSpec.substr(i + 1)).finalize(); uri = uri.mutate().setPathQueryRef(aSpec.substr(0, i)).finalize(); } else { uri = uri.mutate().setPathQueryRef(aSpec).finalize(); } } } return uri; }, repeatChar: function(char, count) { count = Math.max(count || 0, 0); return new Array(count + 1).join(char); }, padding: function(str, count, char) { if (Math.abs(count) <= str.length) { return str; } var m = Math.max((Math.abs(count) - str.length) || 0, 0); var pad = Array(m + 1).join(String(char || ' ').charAt(0)); return (count < 0) ? pad + str : str + pad; }, escapeHtml: function _escapeHtml(str) { // HTML sanitizing following // https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/DOM_Building_and_HTML_Insertion#innerHTML_with_HTML_Escaping return str.replace(/&/g, "&") .replace(/"/g, """) .replace(//g, ">"); }, newStringChannel: function(uriPath, contentType, contentCharset) { try { let url = unescape(uriPath); let ioServ = Cc[NS_IOSERVICE_CONTRACTID].getService(Ci.nsIIOService); let channel = ioServ.newChannel(url, null, null); let origStream = channel.open(); let targetURI = ioServ.newURI(unescape(uriPath), null, null); let sci = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream); sci.init(origStream); let data = sci.read(origStream.available()); sci.close(); DEBUG_LOG("data count: " + data.length); let srcHtml = '\n'; srcHtml += '\n\n'; let srcLines = data.split(/\r?\n/); let padChars = String(srcLines.length).length; let i; for (i = 0; i < srcLines.length; i++) { srcHtml += ' ' + this.escapeHtml(srcLines[i]) + '\n'; } srcHtml += '\n'; let inputStream = Cc[NS_STRING_INPUT_STREAM_CONTRACTID].createInstance(Ci.nsIStringInputStream); inputStream.setData(srcHtml, srcHtml.length); if (!contentCharset || contentCharset.length == 0) { let netUtil = ioServ.QueryInterface(Ci.nsINetUtil); let newCharset = {}; let hadCharset = {}; let mimeType; try { // Gecko >= 43 mimeType = netUtil.parseResponseContentType(contentType, newCharset, hadCharset); } catch (ex) { // Gecko < 43 mimeType = netUtil.parseContentType(contentType, newCharset, hadCharset); } contentCharset = newCharset.value; } let isc = Cc[NS_INPUT_STREAM_CHNL_CONTRACTID].createInstance(Ci.nsIInputStreamChannel); isc.setURI(targetURI); isc.contentStream = inputStream; let chan = isc.QueryInterface(Ci.nsIChannel); if (contentType && contentType.length > 0) chan.contentType = contentType; if (contentCharset && contentCharset.length > 0) chan.contentCharset = contentCharset; TinyjsdCommon.setLines(srcLines.length); return chan; } catch (ex) { DEBUG_LOG("ERROR in newStringChannel: " + ex); let ioServ = Cc[NS_IOSERVICE_CONTRACTID].getService(Ci.nsIIOService); let targetURI = ioServ.newURI(unescape(uriPath), null, null); let srcHtml = ' %brandDTD; %tinyJsdDTD; ]>