mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-23 08:28:01 +01:00
Add plugins.
This commit is contained in:
1310
plugins/aardvark.js
Executable file
1310
plugins/aardvark.js
Executable file
File diff suppressed because it is too large
Load Diff
51
plugins/curl.js
Executable file
51
plugins/curl.js
Executable file
@@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
var INFO =
|
||||
["plugin", { name: "curl",
|
||||
version: "0.3",
|
||||
href: "http://dactyl.sf.net/pentadactyl/plugins#curl-plugin",
|
||||
summary: "Curl command-line generator",
|
||||
xmlns: "dactyl" },
|
||||
["author", { email: "maglione.k@gmail.com" },
|
||||
"Kris Maglione"],
|
||||
["license", { href: "http://opensource.org/licenses/mit-license.php" },
|
||||
"MIT"],
|
||||
["project", { name: "Pentadactyl", "min-version": "1.0" }],
|
||||
["p", {},
|
||||
"This plugin provides a means to generate a ", ["tt", {}, "curl(1)"], " ",
|
||||
"command-line from the data in a given form."],
|
||||
["item", {},
|
||||
["tags", {}, ";C"],
|
||||
["strut"],
|
||||
["spec", {}, ";C"],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"Generates a curl command-line from the data in the selected form. ",
|
||||
"The command includes the data from each form element, along with ",
|
||||
"the current User-Agent string and the cookies for the current ",
|
||||
"page."]]]];
|
||||
|
||||
hints.addMode('C', "Generate curl command for a form", function(elem) {
|
||||
if (elem.form)
|
||||
var { url, postData, elements } = DOM(elem).formData;
|
||||
else
|
||||
var url = elem.getAttribute("href");
|
||||
|
||||
if (!url || /^javascript:/.test(url))
|
||||
return;
|
||||
|
||||
url = util.newURI(url, null,
|
||||
elem.ownerDocument.documentURIObject).spec;
|
||||
|
||||
let { shellEscape } = util.closure;
|
||||
|
||||
dactyl.clipboardWrite(["curl"].concat(
|
||||
[].concat(
|
||||
[["--form-string", shellEscape(datum)] for (datum of (elements || []))],
|
||||
postData != null && !elements.length ? [["-d", shellEscape("")]] : [],
|
||||
[["-H", shellEscape("Cookie: " + elem.ownerDocument.cookie)],
|
||||
["-A", shellEscape(navigator.userAgent)],
|
||||
[shellEscape(url)]]
|
||||
).map(function(e) e.join(" ")).join(" \\\n ")).join(" "), true);
|
||||
});
|
||||
|
||||
/* vim:se sts=4 sw=4 et: */
|
||||
468
plugins/flashblock.js
Executable file
468
plugins/flashblock.js
Executable file
@@ -0,0 +1,468 @@
|
||||
"use strict";
|
||||
var INFO =
|
||||
["plugin", { name: "flashblock",
|
||||
version: "1.3",
|
||||
href: "http://dactyl.sf.net/pentadactyl/plugins#flashblock-plugin",
|
||||
summary: "Flash Blocker",
|
||||
xmlns: "dactyl" },
|
||||
["author", { email: "maglione.k@gmail.com" },
|
||||
"Kris Maglione"],
|
||||
["license", { href: "http://opensource.org/licenses/mit-license.php" },
|
||||
"MIT"],
|
||||
["project", { name: "Pentadactyl", "min-version": "1.0" }],
|
||||
["p", {},
|
||||
"This plugin provides the same features as the ever popular FlashBlock ",
|
||||
"Firefox add-on. Place holders are substituted for flash animations and ",
|
||||
"embedded videos. When clicked, the original embedded content is ",
|
||||
"restored. Additionally, this plugin provides options to control which ",
|
||||
"sites can play animations without restrictions and triggers to toggle ",
|
||||
"the playing of animations on the current page."],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "'fb' 'flashblock'"],
|
||||
["spec", {}, "'flashblock' 'fb'"],
|
||||
["type", {}, "boolean"],
|
||||
["default", {}, "true"],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"Controls the blocking of flash animations. When true, place ",
|
||||
"holders are substituted for flash animations on untrusted sites."]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "'fbw' 'fbwhitelist'"],
|
||||
["spec", {}, "'fbwhitelist' 'fbw'"],
|
||||
["type", {}, "sitelist"],
|
||||
["default", {}, ""],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"Controls which sites may play flash animations without user ",
|
||||
"intervention. See ", ["ex", {}, ":mk" + config.name.toLowerCase() + "rc"], "."]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, ":flashplay :flp"],
|
||||
["strut"],
|
||||
["spec", {}, ":flashplay"],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"Plays any blocked flash animations on the current page."]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, ":flashstop :fls"],
|
||||
["strut"],
|
||||
["spec", {}, ":flashstop"],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"Stops any currently playing flash animations on the current ",
|
||||
"page."]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, ":flashtoggle :flt"],
|
||||
["strut"],
|
||||
["spec", {}, ":flashtoggle"],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"Toggles the playing of all animations on the current page. If ",
|
||||
"any flash animations are currently blocked, all may begin ",
|
||||
"playing. Otherwise, all animations are stopped."],
|
||||
|
||||
["example", {},
|
||||
["ex", {}, ":map"], " -silent ",
|
||||
["k", { name: "A-p", link: "false" }],
|
||||
" ", ["ex", {}, ":flashtoggle"],
|
||||
["k", { name: "CR" }]]]]];
|
||||
|
||||
group.options.add(["flashblock", "fb"],
|
||||
"Enable blocking of flash animations",
|
||||
"boolean", true,
|
||||
{ setter: reload });
|
||||
group.options.add(["fbwhitelist", "fbw"],
|
||||
"Sites which may run flash animations without prompting",
|
||||
"sitelist", "",
|
||||
{
|
||||
completer: context => completion.visibleHosts(context),
|
||||
privateData: true,
|
||||
setter: reload,
|
||||
validator: () => true,
|
||||
});
|
||||
|
||||
["Play", "Stop"].forEach(action => {
|
||||
group.commands.add(["flash" + action, "fl" + action[0]].map(String.toLowerCase),
|
||||
action + " all flash animations on the current page",
|
||||
function () { postMessage(content, "flashblock" + action) },
|
||||
{ argCount: "0" }, true);
|
||||
});
|
||||
|
||||
group.commands.add(["flashtoggle", "flt"],
|
||||
"Toggle playing of flash animations on the current page",
|
||||
function () {
|
||||
if (buffer.allFrames().some(w => DOM("pseudoembed", w.document).length))
|
||||
commands.get("flashplay").action();
|
||||
else
|
||||
commands.get("flashstop").action();
|
||||
},
|
||||
{ argCount: "0" }, true);
|
||||
|
||||
group.mappings.add([modes.NORMAL], ["<Leader>fbwhitelist"],
|
||||
"Add the current site to the flash whitelist",
|
||||
function () { whitelist.op("+", whitelist.parse(content.location.hostname)) });
|
||||
group.mappings.add([modes.NORMAL], ["<Leader>fbWhitelist"],
|
||||
"Toggle the current site in the flash whitelist",
|
||||
function () {
|
||||
let host = content.location.hostname;
|
||||
if (!removeHost(host))
|
||||
whitelist.op("+", whitelist.parse(host));
|
||||
});
|
||||
|
||||
var enabled = options.get("flashblock");
|
||||
var whitelist = options.get("fbwhitelist");
|
||||
function postMessage(content, message) {
|
||||
buffer.allFrames(content).forEach(f => { f.postMessage(message, "*"); });
|
||||
}
|
||||
function reload(values) {
|
||||
//for (let [,t] in tabs.browsers)
|
||||
// t.contentWindow.postMessage("flashblockReload", "*");
|
||||
postMessage(gBrowser.mCurrentBrowser.contentWindow, "flashblockReload");
|
||||
return values;
|
||||
}
|
||||
|
||||
function removeHost(host) {
|
||||
let len = whitelist.value.length;
|
||||
let uri = util.createURI(host);
|
||||
whitelist.value = whitelist.value.filter(f => !f(uri));
|
||||
return whitelist.value.length != len;
|
||||
}
|
||||
|
||||
function onUnload() {
|
||||
group.events.unlisten(null);
|
||||
}
|
||||
group.events.listen(window, "flashblockCheckLoad",
|
||||
function checkLoadFlash(event) {
|
||||
if(!enabled.value || whitelist.getKey(event.target.documentURIObject))
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}, true, true);
|
||||
|
||||
var data = {
|
||||
bindings: "dactyl://data/text/xml," + encodeURIComponent('<?xml version="1.0"?>' +
|
||||
String.raw`
|
||||
<bindings
|
||||
xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:xbl="http://www.mozilla.org/xbl"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<binding id="flash">
|
||||
<implementation>
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
var myDocument = XPCNativeWrapper(document);
|
||||
var myWindow = XPCNativeWrapper(window);
|
||||
|
||||
function copyAttribs(to, from) {
|
||||
Array.map(from.attributes, function(attrib) {
|
||||
to.setAttribute(attrib.name, attrib.value);
|
||||
});
|
||||
}
|
||||
function capitalize(str) { return str[0].toUpperCase() + str.substr(1) };
|
||||
|
||||
function Placeholder(embed) {
|
||||
var self = this;
|
||||
this.embed = embed;
|
||||
|
||||
if (!document.flashblockStyle) {
|
||||
var head = document.getElementsByTagName("head")[0];
|
||||
var node = document.createElement("style");
|
||||
node.setAttribute("type", "text/css");
|
||||
head.insertBefore(node, head.firstChild);
|
||||
document.flashblockStyle = node.sheet;
|
||||
}
|
||||
|
||||
document.flashblockIdx = (document.flashblockIdx || 0) + 1;
|
||||
this.idx = document.flashblockIdx;
|
||||
embed.setAttribute("flashblock", this.idx);
|
||||
|
||||
document.flashblockStyle.insertRule("pseudoembed[flashblock='" + this.idx + "'] {}", 0);
|
||||
this.style = document.flashblockStyle.cssRules[0].style;
|
||||
|
||||
this.div = myDocument.createElement('pseudoembed');
|
||||
this.div.addEventListener("click", function() { self.showEmbed(true) }, true);
|
||||
this.div.flashblockEmbed = embed;
|
||||
}
|
||||
Placeholder.prototype = {
|
||||
showEmbed: function(clicked) {
|
||||
this.embed.clicked = clicked;
|
||||
if (this.embed.parentNode)
|
||||
return;
|
||||
copyAttribs(this.embed, this.div);
|
||||
this.div.parentNode.replaceChild(this.embed, this.div);
|
||||
},
|
||||
hideEmbed: function() {
|
||||
let parent = this.embed.parentNode;
|
||||
if (!parent)
|
||||
return;
|
||||
|
||||
this.div.setAttribute("embedtype", this.embed.localName);
|
||||
copyAttribs(this.div, this.embed);
|
||||
|
||||
['width', 'height'].forEach(function(dimen) {
|
||||
this.style[dimen] = "";
|
||||
if (this.embed[dimen])
|
||||
if (/%$/.test(this.embed[dimen]))
|
||||
this.style[dimen] = this.embed[dimen];
|
||||
else
|
||||
this.style[dimen] = parseInt(this.embed[dimen]) + "px";
|
||||
}, this);
|
||||
|
||||
let style = myWindow.getComputedStyle(parent, "");
|
||||
if (style.getPropertyValue("text-align") == "center") {
|
||||
this.style.marginRight = "auto";
|
||||
this.style.marginLeft = "auto";
|
||||
}
|
||||
|
||||
parent.replaceChild(this.div, this.embed);
|
||||
}
|
||||
}
|
||||
|
||||
var parent = this.parentNode
|
||||
var self = this;
|
||||
if (!this.getAttribute("flashblock"))
|
||||
this.setAttribute("flashblock", true);
|
||||
if (this.placeholder || parent.placeholder)
|
||||
return;
|
||||
this.placeholder = new Placeholder(self);
|
||||
|
||||
function checkReplace(e) {
|
||||
if (!e || e.data == "flashblockReload") {
|
||||
if (self.clicked)
|
||||
return;
|
||||
let event = myDocument.createEvent("UIEvents");
|
||||
event.initEvent("flashblockCheckLoad", true, true);
|
||||
myDocument.dispatchEvent(event);
|
||||
if (event.getPreventDefault())
|
||||
self.placeholder.showEmbed();
|
||||
else
|
||||
self.placeholder.hideEmbed();
|
||||
}
|
||||
else if (e.data == "flashblockPlay")
|
||||
self.placeholder.showEmbed(true);
|
||||
else if (e.data == "flashblockStop")
|
||||
self.placeholder.hideEmbed();
|
||||
}
|
||||
checkReplace();
|
||||
myWindow.addEventListener("message", checkReplace, false);
|
||||
|
||||
// if(this.src == this.ownerDocument.location)
|
||||
// myWindow.location = 'dactyl://data/application/xhtml+xml,' + encodeURIComponent('<?xml version="1.0" encoding="UTF-8"?>' +
|
||||
// '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">' +
|
||||
// <html xmlns="http://www.w3.org/1999/xhtml">
|
||||
// <head><title></title></head>
|
||||
// <body>{new XML(parent.innerHTML)}</body>
|
||||
// </html>);
|
||||
]]>
|
||||
</constructor>
|
||||
</implementation>
|
||||
</binding>
|
||||
</bindings>
|
||||
`),
|
||||
flash: `data:image/png;base64,
|
||||
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
|
||||
`,
|
||||
play: `data:image/png;base64,
|
||||
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
|
||||
AAMACHALg12qSjsAAAAASUVORK5CYII
|
||||
`,
|
||||
};
|
||||
|
||||
var CSS =
|
||||
/*
|
||||
* Flash Click to View by Ted Mielczarek (luser_mozilla@perilith.com)
|
||||
* Original code by Jesse Ruderman (jruderman@hmc.edu)
|
||||
* taken from http://www.squarefree.com/userstyles/xbl.html
|
||||
*
|
||||
* Change XBL binding for <object> tags, click to view flash
|
||||
*/
|
||||
String.literal`
|
||||
|
||||
pseudoembed {
|
||||
display: inline-block;
|
||||
min-width: 32px !important;
|
||||
min-height: 32px !important;
|
||||
border: 1px solid #dfdfdf;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
-moz-box-sizing: border-box;
|
||||
background: url("${data.play}") no-repeat center;
|
||||
}
|
||||
pseudoembed:hover {
|
||||
background-image: url("${data.flash}");
|
||||
}
|
||||
|
||||
video,
|
||||
object[classid*=":D27CDB6E-AE6D-11cf-96B8-444553540000"],
|
||||
object[codebase*="swflash.cab"],
|
||||
object[data*=".swf"],
|
||||
embed[type="application/x-shockwave-flash"],
|
||||
embed[src*=".swf"],
|
||||
object[type="application/x-shockwave-flash"],
|
||||
object[src*=".swf"] {
|
||||
-moz-binding: url("{bindings}") !important;
|
||||
}
|
||||
|
||||
/// TODO: Could do better.
|
||||
/// NoScript is incredibly annoying. The binding can't execute JS on
|
||||
/// untrusted sites.
|
||||
video:not([flashblock]),
|
||||
object[classid*=":D27CDB6E-AE6D-11cf-96B8-444553540000"]:not([flashblock]),
|
||||
object[codebase*="swflash.cab"]:not([flashblock]),
|
||||
object[data*=".swf"]:not([flashblock]),
|
||||
embed[type="application/x-shockwave-flash"]:not([flashblock]),
|
||||
embed[src*=".swf"]:not([flashblock]),
|
||||
object[type="application/x-shockwave-flash"]:not([flashblock]),
|
||||
object[src*=".swf"]:not([flashblock]) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/// Java identifiers.
|
||||
/// TODO: Make this work.
|
||||
/// applet,
|
||||
/// object[classid*=":8AD9C840-044E-11D1-B3E9-00805F499D93"],
|
||||
/// object[classid^="clsid:CAFEEFAC-"],
|
||||
/// object[classid^="java:"],
|
||||
/// object[type="application/x-java-applet"],
|
||||
/// embed[classid*=":8AD9C840-044E-11D1-B3E9-00805F499D93"],
|
||||
/// embed[classid^="clsid:CAFEEFAC-"],
|
||||
/// embed[classid^="java:"],
|
||||
/// embed[type="application/x-java-applet"]
|
||||
/// {
|
||||
/// -moz-binding: url("{bindings}") !important;
|
||||
/// }
|
||||
`.replace(/\/\/\/.*/gm, "");
|
||||
|
||||
styles.system.add("flashblock", "*", CSS);
|
||||
data = null;
|
||||
CSS = null;
|
||||
|
||||
/* vim:se sts=4 sw=4 et: */
|
||||
152
plugins/http-headers.js
Executable file
152
plugins/http-headers.js
Executable file
@@ -0,0 +1,152 @@
|
||||
"use strict";
|
||||
isGlobalModule = true;
|
||||
|
||||
var INFO =
|
||||
["plugin", { name: "http-headers",
|
||||
version: "0.7",
|
||||
href: "http://dactyl.sf.net/pentadactyl/plugins#http-headers-plugin",
|
||||
summary: "HTTP header info",
|
||||
xmlns: "dactyl" },
|
||||
["author", { email: "maglione.k@gmail.com" },
|
||||
"Kris Maglione"],
|
||||
["license", { href: "http://opensource.org/licenses/mit-license.php" },
|
||||
"MIT"],
|
||||
["project", { name: "Pentadactyl", "min-version": "1.0" }],
|
||||
|
||||
["p", {},
|
||||
"Adds request and response headers to the <ex>:pageinfo</ex> ",
|
||||
"command, with the keys ", ["em", {}, "h"], " and ", ["em", {}, "H"], " respectively. ",
|
||||
"See also ", ["o", {}, "pageinfo"], "."],
|
||||
|
||||
["example", {}, ["ex", {}, ":pageinfo hH"]]];
|
||||
|
||||
var { Buffer } = require("buffer");
|
||||
|
||||
var Controller = Class("Controller", XPCOM(Ci.nsIController), {
|
||||
init: function (command, data) {
|
||||
this.command = command;
|
||||
this.update(data);
|
||||
},
|
||||
get wrappedJSObject() { return this; },
|
||||
supportsCommand: function (cmd) { return cmd === this.command; },
|
||||
});
|
||||
|
||||
var HttpObserver = Class("HttpObserver",
|
||||
XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference, Ci.nsIWebProgressListener]), {
|
||||
|
||||
init: function init() {
|
||||
util.addObserver(this);
|
||||
},
|
||||
|
||||
cleanup: function cleanup() {
|
||||
this.observe.unregister();
|
||||
},
|
||||
|
||||
extractHeaders: function extractHeaders(request, type) {
|
||||
let major = {}, minor = {};
|
||||
request.QueryInterface(Ci.nsIHttpChannelInternal)["get" + type + "Version"](major, minor);
|
||||
|
||||
let headers = [[type.toUpperCase(), "HTTP/" + major.value + "." + minor.value]];
|
||||
request["visit" + type + "Headers"]({
|
||||
visitHeader: function (header, value) {
|
||||
headers.push([header, value]);
|
||||
}
|
||||
});
|
||||
return headers;
|
||||
},
|
||||
|
||||
getHeaders: function getHeaders(win, request) {
|
||||
request.QueryInterface(Ci.nsIChannel);
|
||||
|
||||
let headers = overlay.getData(win.document, "headers", Object);
|
||||
if ("response" in headers)
|
||||
return;
|
||||
|
||||
if (win && /^https?$/.test(request.URI.scheme)) {
|
||||
if (request instanceof Ci.nsIHttpChannel)
|
||||
request.QueryInterface(Ci.nsIHttpChannel);
|
||||
else {
|
||||
request.QueryInterface(Ci.nsIMultiPartChannel);
|
||||
request.baseChannel.QueryInterface(Ci.nsIHttpChannel);
|
||||
}
|
||||
|
||||
headers.request = this.extractHeaders(request, "Request");
|
||||
headers.request[0][1] = request.requestMethod + " " +
|
||||
request.URI.path + " " + headers.request[0][1];
|
||||
|
||||
try {
|
||||
headers.response = this.extractHeaders(request, "Response");
|
||||
headers.response[0][1] += " " + request.responseStatus + " " +
|
||||
request.responseStatusText;
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
let controller = this.getController(win);
|
||||
if (controller)
|
||||
win.controllers.removeController(controller);
|
||||
win.controllers.appendController(Controller("dactyl-headers", { headers: headers, url: win.document.documentURI }));
|
||||
}
|
||||
},
|
||||
|
||||
observers: {
|
||||
"http-on-examine-response": util.wrapCallback(function onExamineResponse(request, data) {
|
||||
request.QueryInterface(Ci.nsIChannel).QueryInterface(Ci.nsIHttpChannel).QueryInterface(Ci.nsIRequest);
|
||||
|
||||
if (request.loadFlags & request.LOAD_DOCUMENT_URI) {
|
||||
try {
|
||||
var win = request.notificationCallbacks.getInterface(Ci.nsIDOMWindow);
|
||||
}
|
||||
catch (e) {
|
||||
return;
|
||||
}
|
||||
this.getHeaders(win, request);
|
||||
try {
|
||||
webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
|
||||
}
|
||||
catch (e) {}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onStateChange: util.wrapCallback(function(webProgress, request, stateFlags, status) {
|
||||
if ((stateFlags & this.STATE_START) && (stateFlags & this.STATE_IS_DOCUMENT))
|
||||
this.getHeaders(webProgress.DOMWindow, request);
|
||||
else if ((stateFlags & this.STATE_STOP) && (stateFlags & this.STATE_IS_DOCUMENT)) {
|
||||
this.getHeaders(webProgress.DOMWindow, request);
|
||||
try {
|
||||
webProgress.removeProgressListener(this);
|
||||
} catch (e) {}
|
||||
}
|
||||
}),
|
||||
|
||||
getController: function getController(win) {
|
||||
for (let i of util.range(0, win.controllers.getControllerCount())) {
|
||||
let controller = win.controllers.getControllerAt(i);
|
||||
if (controller.supportsCommand("dactyl-headers") && controller.wrappedJSObject instanceof Controller)
|
||||
return controller.wrappedJSObject;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let observer = HttpObserver();
|
||||
let onUnload = observer.closure.cleanup;
|
||||
|
||||
function* iterHeaders(buffer, type) {
|
||||
let win = buffer.focusedFrame;
|
||||
let store = win.document[overlay.id];
|
||||
if (!store || !store.headers)
|
||||
store = observer.getController(win);
|
||||
|
||||
if (store)
|
||||
for (let [k, v] of values(store.headers[type] || []))
|
||||
yield [k, v];
|
||||
}
|
||||
|
||||
iter({ h: "Request", H: "Response" }).forEach(function ([key, name]) {
|
||||
Buffer.addPageInfoSection(key, name + " Headers", function (verbose) {
|
||||
if (verbose)
|
||||
return iterHeaders(this, name.toLowerCase())
|
||||
});
|
||||
});
|
||||
|
||||
/* vim:se sts=4 sw=4 et: */
|
||||
147
plugins/jscompletion.js
Executable file
147
plugins/jscompletion.js
Executable file
@@ -0,0 +1,147 @@
|
||||
"use strict";
|
||||
var INFO =
|
||||
["plugin", { name: "jscompletion",
|
||||
version: "1.0.4",
|
||||
href: "http://dactyl.sf.net/pentadactyl/plugins#jscompletion-plugin",
|
||||
summary: "JavaScript completion enhancements",
|
||||
xmlns: "dactyl" },
|
||||
["author", { email: "maglione.k@gmail.com" },
|
||||
"Kris Maglione"],
|
||||
["license", { href: "http://people.freebsd.org/~phk/" },
|
||||
"BEER-WARE"],
|
||||
["project", { name: "Pentadactyl", "min-version": "1.0" }],
|
||||
["p", {},
|
||||
"This plugin provides advanced completion functions for ",
|
||||
"DOM functions, eval, and some other special functions. ",
|
||||
"For instance, ",
|
||||
"", ["ex", {}, ':js content.document.getElementById("',
|
||||
["k", { name: "Tab", link: "c_<Tab>" }], ], " ",
|
||||
"should provide you with a list of all element IDs ",
|
||||
"present on the current web page. Many other DOM ",
|
||||
"methods are provided, along with their namespaced variants."]];
|
||||
|
||||
function evalXPath(xpath, doc, namespace) {
|
||||
let res = doc.evaluate(xpath, doc,
|
||||
function getNamespace(prefix) {
|
||||
return {
|
||||
html: "http://www.w3.org/1999/xhtml",
|
||||
dactyl: NS,
|
||||
ns: namespace
|
||||
}[prefix];
|
||||
},
|
||||
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
|
||||
null
|
||||
);
|
||||
return function* () {
|
||||
for (let i = 0; i < res.snapshotLength; i++)
|
||||
yield res.snapshotItem(i);
|
||||
}();
|
||||
}
|
||||
|
||||
let NAMESPACES = [
|
||||
["http://purl.org/atom/ns#", "Atom 0.3"],
|
||||
["http://www.w3.org/2005/Atom", "Atom 1.0"],
|
||||
[NS, "Dactyl"],
|
||||
["http://www.w3.org/2005/Atom", "RSS"],
|
||||
["http://www.w3.org/2000/svg", "SVG"],
|
||||
["http://www.mozilla.org/xbl", "XBL"],
|
||||
["http://www.w3.org/1999/xhtml", "XHTML 1.0"],
|
||||
["http://www.w3.org/2002/06/xhtml2", "XHTML 2.0"],
|
||||
["http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "XUL"]
|
||||
];
|
||||
|
||||
function addCompleter(names, fn) {
|
||||
for (let name of util.debrace(names))
|
||||
javascript.completers[name] = fn;
|
||||
}
|
||||
function* uniq(iter) {
|
||||
let seen = new RealSet()
|
||||
for (let val of iter)
|
||||
if (!seen.add(val))
|
||||
yield val;
|
||||
}
|
||||
|
||||
addCompleter("__lookup{Getter,Setter}__", function (context, func, obj, args) {
|
||||
if (args.length == 1)
|
||||
context.completions =
|
||||
[[k, obj[func](k)] for (k of properties(obj))].concat(
|
||||
[[k, obj[func](k)] for (k of properties(obj, true))]).filter(
|
||||
([k, v]) => v);
|
||||
});
|
||||
|
||||
addCompleter("eval", function (context, func, obj, args) {
|
||||
if (args.length > 1)
|
||||
return [];
|
||||
if (!context.cache.js) {
|
||||
context.cache.js = JavaScript();
|
||||
context.cache.context = CompletionContext("");
|
||||
}
|
||||
let ctxt = context.cache.context;
|
||||
context.keys = { text: "text", description: "description" };
|
||||
ctxt.filter = context.filter;
|
||||
context.cache.js.complete(ctxt);
|
||||
context.advance(ctxt.offset);
|
||||
context.completions = ctxt.allItems.items;
|
||||
});
|
||||
|
||||
addCompleter("getOwnPropertyDescriptor", function (context, func, obj, args) {
|
||||
context.anchored = false;
|
||||
context.keys = { text: util.identity, description: () => "" };
|
||||
if (args.length == 2)
|
||||
return properties(args[0]);
|
||||
});
|
||||
|
||||
addCompleter("getElementById", function (context, func, doc, args) {
|
||||
context.anchored = false;
|
||||
if (args.length == 1) {
|
||||
context.keys = { text: e => e.getAttribute("id"), description: util.objectToString };
|
||||
context.generate = () => evalXPath("//*[@id]", doc);
|
||||
}
|
||||
});
|
||||
|
||||
function addCompleterNS(names, fn) {
|
||||
addCompleter(names + "{,NS}", function checkNS(context, func, obj, args) {
|
||||
context.anchored = false;
|
||||
context.keys = { text: util.identity, description: () => "" };
|
||||
let isNS = /NS$/.test(func);
|
||||
if (isNS && args.length == 1)
|
||||
return NAMESPACES;
|
||||
let prefix = isNS ? "ns:" : "";
|
||||
return fn(context, func, obj, args, prefix, isNS && args.shift());
|
||||
});
|
||||
}
|
||||
|
||||
addCompleterNS("getElementsByClassName", function (context, func, doc, args, prefix, namespace) {
|
||||
if (args.length == 1) {
|
||||
let iter = evalXPath("//@" + prefix + "class", doc, namespace);
|
||||
return array(e.value.split(" ") for (e of iter)).flatten().uniq().array;
|
||||
}
|
||||
});
|
||||
|
||||
addCompleterNS("{getElementsByTagName,createElement}", function (context, func, doc, args, prefix, namespace) {
|
||||
if (args.length == 1) {
|
||||
let iter = evalXPath("//" + prefix + "*", doc, namespace);
|
||||
return uniq(e.localName.toLowerCase() for (e of iter));
|
||||
}
|
||||
});
|
||||
|
||||
addCompleterNS("getElementsByAttribute", function (context, func, doc, args, prefix, namespace) {
|
||||
switch (args.length) {
|
||||
case 1:
|
||||
let iter = evalXPath("//@" + prefix + "*", doc, namespace);
|
||||
return uniq(e.name for (e of iter));
|
||||
case 2:
|
||||
iter = evalXPath("//@" + prefix + args[0], doc, namespace);
|
||||
return uniq(e.value for (e of iter));
|
||||
}
|
||||
});
|
||||
|
||||
addCompleterNS("{get,set,remove}Attribute", function (context, func, node, args, prefix, namespace) {
|
||||
context.keys = { text: 0, description: 1 };
|
||||
if (args.length == 1)
|
||||
return [[a.localName, a.value]
|
||||
for (a of array.iterValues(node.attributes))
|
||||
if (!namespace || a.namespaceURI == namespace)];
|
||||
});
|
||||
|
||||
/* vim:se sts=4 sw=4 et: */
|
||||
483
plugins/noscript.js
Executable file
483
plugins/noscript.js
Executable file
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
* Copyright ©2010-2014 Kris Maglione <maglione.k at Gmail>
|
||||
* Distributable under the terms of the MIT license.
|
||||
*
|
||||
* Documentation is at the tail of this file.
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
if (!("noscriptOverlay" in window)) {
|
||||
if (!userContext.noscriptIgnoreMissing)
|
||||
dactyl.echoerr("This plugin requires the NoScript add-on.");
|
||||
throw Finished();
|
||||
}
|
||||
|
||||
/*
|
||||
* this.globalJS ? !this.alwaysBlockUntrustedContent || !this.untrustedSites.matches(s)
|
||||
* : this.jsPolicySites.matches(s) && !this.untrustedSites.matches(s) && !this.isForbiddenByHttpsStatus(s));
|
||||
*/
|
||||
|
||||
function getSites() {
|
||||
// This logic comes directly from NoScript. To my mind, it's insane.
|
||||
const ns = services.noscript;
|
||||
const global = options["script"];
|
||||
const groups = { allowed: ns.jsPolicySites, temp: ns.tempSites, untrusted: ns.untrustedSites };
|
||||
const show = RealSet(options["noscript-list"]);
|
||||
const sites = window.noscriptOverlay.getSites();
|
||||
|
||||
const blockUntrusted = global && ns.alwaysBlockUntrustedContent;
|
||||
|
||||
let res = [];
|
||||
for (let site of array.iterValues(Array.concat(sites.topSite, sites))) {
|
||||
let ary = [];
|
||||
|
||||
let untrusted = groups.untrusted.matches(site);
|
||||
let matchingSite = null;
|
||||
if (!untrusted)
|
||||
matchingSite = groups.allowed.matches(site) || blockUntrusted && site;
|
||||
|
||||
let enabled = Boolean(matchingSite);
|
||||
if (site == sites.topSite && !ns.dom.getDocShellForWindow(content).allowJavascript)
|
||||
enabled = false;
|
||||
|
||||
let hasPort = /:\d+$/.test(site);
|
||||
|
||||
if (enabled && !global || untrusted) {
|
||||
if (!enabled || global)
|
||||
matchingSite = untrusted;
|
||||
|
||||
if (hasPort && ns.ignorePorts)
|
||||
if (site = groups.allowed.matches(site.replace(/:\d+$/, "")))
|
||||
matchingSite = site;
|
||||
ary.push(matchingSite);
|
||||
}
|
||||
else {
|
||||
if ((!hasPort || ns.ignorePorts) && (show.has("full") || show.has("base"))) {
|
||||
let domain = !ns.isForbiddenByHttpsStatus(site) && ns.getDomain(site);
|
||||
if (domain && ns.isJSEnabled(domain) == enabled) {
|
||||
ary = util.subdomains(domain);
|
||||
if (!show.has("base") && ary.length > 1)
|
||||
ary = ary.slice(1);
|
||||
if (!show.has("full"))
|
||||
ary = ary.slice(0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (show.has("address") || ary.length == 0) {
|
||||
ary.push(site);
|
||||
|
||||
if (hasPort && ns.ignorePorts) {
|
||||
site = site.replace(/:\d+$/, "");
|
||||
if (!groups.allowed.matches(site))
|
||||
ary.push(site);
|
||||
}
|
||||
}
|
||||
}
|
||||
res = res.concat(ary);
|
||||
}
|
||||
|
||||
let seen = RealSet();
|
||||
return res.filter(function (h) {
|
||||
let res = !seen.has(h);
|
||||
seen.add(h);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
function getObjects() {
|
||||
let sites = noscriptOverlay.getSites();
|
||||
let general = [], specific = [];
|
||||
for (let group of values(sites.pluginExtras))
|
||||
for (let obj of array.iterValues(group)) {
|
||||
if (!obj.placeholder && (ns.isAllowedObject(obj.url, obj.mime) || obj.tag))
|
||||
continue;
|
||||
specific.push(obj.mime + "@" + obj.url);
|
||||
general.push("*@" + obj.url);
|
||||
general.push("*@" + obj.site);
|
||||
}
|
||||
sites = buffer.allFrames().map(f => f.location.host);
|
||||
for (let filter of values(options["noscript-objects"])) {
|
||||
let host = util.getHost(util.split(filter, /@/, 2)[1]);
|
||||
if (sites.some(s => s == host))
|
||||
specific.push(filter);
|
||||
}
|
||||
let seen = RealSet();
|
||||
return specific.concat(general).filter(function (site) {
|
||||
let res = !seen.has(site);
|
||||
seen.add(site);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
var onUnload = overlay.overlayObject(gBrowser, {
|
||||
// Extend NoScript's bookmarklet handling hack to the command-line
|
||||
// Modified from NoScript's own wrapper.
|
||||
loadURIWithFlags: function loadURIWithFlags(url) {
|
||||
let args = arguments;
|
||||
let load = () => loadURIWithFlags.superapply(gBrowser, args);
|
||||
|
||||
if (!commandline.command || !util.isDactyl(Components.stack.caller))
|
||||
return load();
|
||||
|
||||
try {
|
||||
for (let [cmd, args] of commands.parseCommands(commandline.command))
|
||||
var origURL = args.literalArg;
|
||||
|
||||
let isJS = url => /^(?:data|javascript):/i.test(url);
|
||||
let allowJS = prefs.get("noscript.allowURLBarJS", true);
|
||||
|
||||
if (isJS(origURL) && allowJS) {
|
||||
if (services.noscript.executeJSURL(origURL, load))
|
||||
return;
|
||||
}
|
||||
else if (url != origURL && isJS(url)) {
|
||||
if(services.noscript.handleBookmark(url, load))
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
util.reportError(e);
|
||||
}
|
||||
return load();
|
||||
}
|
||||
});
|
||||
|
||||
highlight.loadCSS(String.raw`
|
||||
NoScriptAllowed color: green;
|
||||
NoScriptBlocked color: #444; font-style: italic;
|
||||
NoScriptTemp color: blue;
|
||||
NoScriptUntrusted color: #c00; font-style: italic;
|
||||
`);
|
||||
|
||||
let groupProto = {};
|
||||
["temp", "jsPolicy", "untrusted"].forEach(function (group) {
|
||||
memoize(groupProto, group,
|
||||
function () {
|
||||
return services.noscript[group + "Sites"].matches(this.site);
|
||||
});
|
||||
});
|
||||
let groupDesc = {
|
||||
NoScriptTemp: "Temporarily allowed",
|
||||
NoScriptAllowed: "Allowed permanently",
|
||||
NoScriptUntrusted: "Untrusted",
|
||||
NoScriptBlocked: "Blocked"
|
||||
};
|
||||
|
||||
function splitContext(context, list) {
|
||||
for (let [name, title, filter] of values(list)) {
|
||||
let ctxt = context.split(name);
|
||||
ctxt.title = [title];
|
||||
ctxt.filters.push(filter);
|
||||
}
|
||||
}
|
||||
|
||||
completion.noscriptObjects = function (context) {
|
||||
let whitelist = options.get("noscript-objects").set;
|
||||
context = context.fork();
|
||||
context.compare = CompletionContext.Sort.unsorted;
|
||||
context.generate = getObjects;
|
||||
context.keys = {
|
||||
text: util.identity,
|
||||
description: key => whitelist.has(key) ? "Allowed" : "Forbidden"
|
||||
};
|
||||
splitContext(context, getObjects, [
|
||||
["forbidden", "Forbidden objects", item => !whitelist.has(item.item)],
|
||||
["allowed", "Allowed objects", item => whitelist.has(item.item)]]);
|
||||
};
|
||||
completion.noscriptSites = function (context) {
|
||||
context.compare = CompletionContext.Sort.unsorted;
|
||||
context.generate = getSites;
|
||||
context.keys = {
|
||||
text: util.identity,
|
||||
description: site => groupDesc[this.highlight] +
|
||||
(this.groups.untrusted && this.highlight != "NoScriptUntrusted" ? " (untrusted)" : ""),
|
||||
|
||||
highlight: function (site) {
|
||||
return this.groups.temp ? "NoScriptTemp" :
|
||||
this.groups.jsPolicy ? "NoScriptAllowed" :
|
||||
this.groups.untrusted ? "NoScriptUntrusted" :
|
||||
"NoScriptBlocked";
|
||||
},
|
||||
groups: site => ({ site: site, __proto__: groupProto })
|
||||
};
|
||||
splitContext(context, [
|
||||
["normal", "Active sites", item => item.groups.jsPolicy || !item.groups.untrusted],
|
||||
["untrusted", "Untrusted sites", item => !item.groups.jsPolicy && item.groups.untrusted]]);
|
||||
context.maxItems = 100;
|
||||
}
|
||||
|
||||
services.add("noscript", "@maone.net/noscript-service;1");
|
||||
|
||||
var PrefBase = "noscript.";
|
||||
var Pref = Struct("text", "pref", "description");
|
||||
let prefs = {
|
||||
forbid: [
|
||||
["bookmarklet", "forbidBookmarklets", "Forbid bookmarklets"],
|
||||
["collapse", "collapseObject", "Collapse forbidden objects"],
|
||||
["flash", "forbidFlash", "Block Adobe® Flash® animations"],
|
||||
["fonts", "forbidFonts", "Forbid remote font loading"],
|
||||
["frame", "forbidFrames", "Block foreign <frame> elements"],
|
||||
["iframe", "forbidIFrames", "Block foreign <iframe> elements"],
|
||||
["java", "forbidJava", "Block Java™ applets"],
|
||||
["media", "forbidMedia", "Block <audio> and <video> elements"],
|
||||
["placeholder", "showPlaceholder", "Replace forbidden objects with a placeholder"],
|
||||
["plugins", "forbidPlugins", "Forbid other plugins"],
|
||||
["refresh", "forbidMetaRefresh", "Block <meta> page directions"],
|
||||
["silverlight", "forbidSilverlight", "Block Microsoft® Silverlight™ objects"],
|
||||
["trusted", "contentBlocker", "Block media and plugins even on trusted sites"],
|
||||
["webbug", "blockNSWB", "Block “web bug” tracking images"],
|
||||
["xslt", "forbidXSLT", "Forbid XSLT stylesheets"]
|
||||
],
|
||||
list: [
|
||||
["address", "showAddress", "Show the full address (http://www.google.com)"],
|
||||
["base", "showBaseDomain", "Show the base domain (google.com)"],
|
||||
["full", "showDomain", "Show the full domain (www.google.com)"]
|
||||
]
|
||||
};
|
||||
for (let [k, v] of iter(prefs))
|
||||
prefs[k] = array(v).map(v => [v[0], Pref.fromArray(v.map(UTF8))]).toObject();
|
||||
|
||||
function getPref(pref) { return modules.prefs.get(PrefBase + pref); }
|
||||
function setPref(pref, val) { return modules.prefs.set(PrefBase + pref, val); }
|
||||
|
||||
prefs.complete = group => context => {
|
||||
context.keys = { text: "text", description: "description" };
|
||||
context.completions = values(prefs[group]);
|
||||
};
|
||||
prefs.get = function (group) { return [p.text for (p of values(this[group])) if (getPref(p.pref))]; };
|
||||
prefs.set = function (group, val) {
|
||||
for (let p of values(this[group]))
|
||||
setPref(p.pref, val.indexOf(p.text) >= 0);
|
||||
return val;
|
||||
}
|
||||
prefs.descs = function prefDescs(group) {
|
||||
return ["dl", {},
|
||||
template.map(values(this[group]), pref =>
|
||||
[["dt", {}, pref.text], ["dd", {}, pref.description]])];
|
||||
};
|
||||
|
||||
function groupParams(group) {
|
||||
return {
|
||||
getter: () => prefs.get(group),
|
||||
completer: prefs.complete(group),
|
||||
setter: val => prefs.set(group, val),
|
||||
initialValue: true,
|
||||
persist: false
|
||||
};
|
||||
}
|
||||
group.options.add(["noscript-forbid", "nsf"],
|
||||
"The set of permissions forbidden to untrusted sites",
|
||||
"stringlist", "",
|
||||
groupParams("forbid"));
|
||||
group.options.add(["noscript-list", "nsl"],
|
||||
"The set of domains to show in the menu and completion list",
|
||||
"stringlist", "",
|
||||
groupParams("list"));
|
||||
|
||||
group.options.add(["script"],
|
||||
"Whether NoScript is enabled",
|
||||
"boolean", false,
|
||||
{
|
||||
getter: () => services.noscript.jsEnabled,
|
||||
setter: (val) => services.noscript.jsEnabled = val,
|
||||
initialValue: true,
|
||||
persist: false
|
||||
});
|
||||
|
||||
[
|
||||
{
|
||||
names: ["noscript-sites", "nss"],
|
||||
description: "The list of sites allowed to execute scripts",
|
||||
action: (add, sites) => sites.length && noscriptOverlay.safeAllow(sites, add, false, -1),
|
||||
completer: (context) => completion.noscriptSites(context),
|
||||
has: (val) => hasOwnProperty(services.noscript.jsPolicySites.sitesMap, val) &&
|
||||
!hasOwnProperty(services.noscript.tempSites.sitesMap, val),
|
||||
get set() {
|
||||
return RealSet(k for (k in services.noscript.jsPolicySites.sitesMap))
|
||||
.difference(RealSet(k for (k in services.noscript.tempSites.sitesMap)))
|
||||
}
|
||||
}, {
|
||||
names: ["noscript-tempsites", "nst"],
|
||||
description: "The list of sites temporarily allowed to execute scripts",
|
||||
action: (add, sites) => sites.length && noscriptOverlay.safeAllow(sites, add, true, -1),
|
||||
completer: (context) => completion.noscriptSites(context),
|
||||
get set() { return RealSet(k for (k in services.noscript.tempSites.sitesMap)) },
|
||||
}, {
|
||||
names: ["noscript-untrusted", "nsu"],
|
||||
description: "The list of untrusted sites",
|
||||
action: (add, sites) => sites.length && services.noscript.setUntrusted(sites, add),
|
||||
completer: (context) => completion.noscriptSites(context),
|
||||
get set() { return RealSet(k for (k in services.noscript.untrustedSites.sitesMap)) },
|
||||
}, {
|
||||
names: ["noscript-objects", "nso"],
|
||||
description: "The list of allowed objects",
|
||||
get set() { return RealSet(array.flatten(
|
||||
[Array.concat(v).map(function (v) { return v + "@" + this; }, k)
|
||||
for ([k, v] of iter(services.noscript.objectWhitelist))])) },
|
||||
action: function (add, patterns) {
|
||||
for (let pattern of values(patterns)) {
|
||||
let [mime, site] = util.split(pattern, /@/, 2);
|
||||
if (add)
|
||||
services.noscript.allowObject(site, mime);
|
||||
else {
|
||||
let list = services.noscript.objectWhitelist[site];
|
||||
if (list) {
|
||||
if (list == "*") {
|
||||
delete services.noscript.objectWhitelist[site];
|
||||
services.noscript.objectWhitelistLen--;
|
||||
}
|
||||
else {
|
||||
let types = list.filter(type => type != mime);
|
||||
services.noscript.objectWhitelistLen -= list.length - types.length;
|
||||
services.noscript.objectWhitelist[site] = types;
|
||||
if (!types.length)
|
||||
delete services.noscript.objectWhitelist[site];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
services.noscript.reloadAllowedObjects(config.browser.selectedBrowser);
|
||||
},
|
||||
completer: context => completion.noscriptObjects(context)
|
||||
}
|
||||
].forEach(function (params) {
|
||||
group.options.add(params.names, params.description,
|
||||
"stringlist", "",
|
||||
{
|
||||
completer: function (context) {
|
||||
context.anchored = false;
|
||||
if (params.completer)
|
||||
params.completer(context)
|
||||
},
|
||||
domains: params.domains || (values => values),
|
||||
has: params.has || bind("has", params.set),
|
||||
initialValue: true,
|
||||
getter: params.getter || (() => Array.from(params.set)),
|
||||
setter: function (values) {
|
||||
let newset = RealSet(values);
|
||||
let current = params.set;
|
||||
let value = this.value;
|
||||
params.action(true, values.filter(site => !current.has(site)))
|
||||
params.action(false, value.filter(site => !newset.has(site)));
|
||||
return this.value;
|
||||
},
|
||||
persist: false,
|
||||
privateData: true,
|
||||
validator: params.validator || (() => true),
|
||||
})
|
||||
});
|
||||
|
||||
var INFO =
|
||||
["plugin", { name: "noscript",
|
||||
version: "0.9",
|
||||
href: "http://dactyl.sf.net/pentadactyl/plugins#noscript-plugin",
|
||||
summary: "NoScript integration",
|
||||
xmlns: "dactyl" },
|
||||
["author", { email: "maglione.k@gmail.com" }, "Kris Maglione"],
|
||||
["license", { href: "http://opensource.org/licenses/mit-license.php" }, "MIT"],
|
||||
["project", { name: "Pentadactyl", "min-version": "1.0" }],
|
||||
|
||||
["p", {},
|
||||
"This plugin provides tight integration with the NoScript add-on. ",
|
||||
"In addition to commands and options to control the behavior of ",
|
||||
"NoScript, this plugin also provides integration with both the ",
|
||||
config.appName, " and ", config.host, " sanitization systems sorely ",
|
||||
"lacking in the add-on itself. Namely, when data for a domain is ",
|
||||
"purged, all of its associated NoScript permissions are purged as ",
|
||||
"well, and temporary permissions are purged along with session ",
|
||||
"data."],
|
||||
|
||||
["note", {},
|
||||
"As most options provided by this script directly alter NoScript ",
|
||||
"preferences, which are persistent, their values are automatically ",
|
||||
"preserved across restarts."],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "'script' 'noscript'"],
|
||||
["strut", {}],
|
||||
["spec", {}, "'script'"],
|
||||
["type", {}, "boolean"],
|
||||
["default", {}, "noscript"],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"When on, all sites are allowed to execute scripts and ",
|
||||
"load plugins. When off, only specifically allowed sites ",
|
||||
"may do so."]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "'nsf' 'noscript-forbid'"],
|
||||
["spec", {}, "'noscript-forbid'"],
|
||||
["type", {}, "stringlist"],
|
||||
["default", {}, ""],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"The set of permissions forbidden to untrusted sites."],
|
||||
prefs.descs("forbid"),
|
||||
["p", {},
|
||||
"See also ", ["o", {}, "noscript-objects"], "."]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "'nsl' 'noscript-list'"],
|
||||
["spec", {}, "'noscript-list'"],
|
||||
["type", {}, "stringlist"],
|
||||
["default", {}, ""],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"The set of items to show in the main completion list and ",
|
||||
"NoScript menu."],
|
||||
prefs.descs("list")]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "'nso' 'noscript-objects'"],
|
||||
["spec", {}, "'noscript-objects'"],
|
||||
["type", {}, "stringlist"],
|
||||
["default", {}, ""],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"The list of objects which allowed to display. See also ",
|
||||
["o", {}, "noscript-forbid"], "."],
|
||||
["example", {},
|
||||
["ex", {}, ":map ", ["k", { name: "A-c", link: "false" }]], " ",
|
||||
["ex", {}, ":set nso!=", ["k", { name: "A-Tab", link: "c_<A-Tab>" }]]]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "'nss' 'noscript-sites'"],
|
||||
["spec", {}, "'noscript-sites'"],
|
||||
["type", {}, "stringlist"],
|
||||
["default", {}, ""],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"The list of sites which are permanently allowed to execute ",
|
||||
"scripts."],
|
||||
["example", {},
|
||||
["ex", {}, ":map ", ["k", { name: "A-s", link: "false" }]], " ",
|
||||
["ex", {}, ":set nss!=", ["k", { name: "A-Tab", link: "c_<A-Tab>" }]]]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "'nst' 'noscript-tempsites'"],
|
||||
["spec", {}, "'noscript-tempsites'"],
|
||||
["type", {}, "stringlist"],
|
||||
["default", {}, ""],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"The list of sites which are temporarily allowed to execute ",
|
||||
"scripts. The value is not preserved across application ",
|
||||
"restarts."],
|
||||
["example", {},
|
||||
["ex", {}, ":map ", ["k", { name: "A-S-s", link: "false" }]], " ",
|
||||
["ex", {}, ":set nst!=", ["k", { name: "A-Tab", link: "c_<A-Tab>" }]]]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "'nsu' 'noscript-untrusted'"],
|
||||
["spec", {}, "'noscript-untrusted'"],
|
||||
["type", {}, "stringlist"],
|
||||
["default", {}, ""],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"The list of untrusted sites which are not allowed to activate, ",
|
||||
"nor are listed in the main completion lists or NoScript menu."],
|
||||
["example", {},
|
||||
["ex", {}, ":map ", ["k", { name: "A-C-s", link: "false" }]], " ",
|
||||
["ex", {}, ":set nsu!=", ["k", { name: "A-Tab", link: "c_<A-Tab>" }]]]]]];
|
||||
|
||||
/* vim:se sts=4 sw=4 et: */
|
||||
177
plugins/tab-options.js
Executable file
177
plugins/tab-options.js
Executable file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <maglions.k at Gmail> wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return. Kris Maglione
|
||||
* ---------------------------------------------------------------------------
|
||||
* <phk@FreeBSD.ORG> wrote this license. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
||||
* ---------------------------------------------------------------------------
|
||||
*
|
||||
* Documentation is at the tail of this file.
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
let groupId = 0;
|
||||
let onUnload = overlay.overlayObject(gBrowser, {
|
||||
addTab: util.wrapCallback(function addTab(uri, params, charset, postData, ownerTab) {
|
||||
if (!isObject(params) || params instanceof Ci.nsIURI)
|
||||
params = { referrerURI: params, ownerTab: ownerTab };
|
||||
let currentTab = tabs.getTab();
|
||||
let tab = addTab.superapply(this, arguments);
|
||||
|
||||
if (!params.ownerTab && (params.referrerURI || params.relatedToCurrent))
|
||||
params.ownerTab = currentTab;
|
||||
if (params.ownerTab)
|
||||
tab.dactylOwner = Cu.getWeakReference(params.ownerTab);
|
||||
|
||||
tab.dactylGroup = browser.groupId++;
|
||||
if (params.ownerTab && (params.referrerURI || params.relatedToCurrent)) {
|
||||
if (params.ownerTab.dactylGroup == null)
|
||||
params.ownerTab.dactylGroup = tab.dactylGroup;
|
||||
tab.dactylGroup = params.ownerTab.dactylGroup;
|
||||
}
|
||||
|
||||
// This is a hack to deal with session restore.
|
||||
if (uri === "about:blank" && params.skipAnimation && Object.keys(params).length == 1)
|
||||
return tab;
|
||||
|
||||
let source = params.fromExternal ? "external" :
|
||||
params.referrerURI ? "link"
|
||||
: "orphan";
|
||||
let location = options["tabopen"][source];
|
||||
if (uri == null || location == null)
|
||||
return tab;
|
||||
|
||||
let visible = tabs.visibleTabs;
|
||||
let index = visible.indexOf(params.ownerTab || currentTab);
|
||||
if (/left$/.test(location))
|
||||
;
|
||||
else if (/right$/.test(location))
|
||||
index++;
|
||||
else if ("start" == location)
|
||||
index = 0;
|
||||
else if ("end" == location)
|
||||
index = visible.length;
|
||||
if ("groupleft" == location)
|
||||
while (index > 0 && visible[index].dactylGroup && visible[index].dactylGroup == currentTab.dactylGroup)
|
||||
index--;
|
||||
else if ("groupright" == location)
|
||||
while (index < visible.length && visible[index].dactylGroup && visible[index].dactylGroup == currentTab.dactylGroup)
|
||||
index++;
|
||||
config.browser.moveTabTo(tab, tabs.allTabs.concat(undefined).indexOf(visible[index]));
|
||||
|
||||
return tab;
|
||||
}),
|
||||
removeTab: util.wrapCallback(function removeTab(tab) {
|
||||
if (tab == tabs.getTab()) {
|
||||
let tabList = tabs.visibleTabs;
|
||||
let idx = tabList.indexOf(tab);
|
||||
for (let val of values(options["tabclose"])) {
|
||||
if (val == "opener" && tab.dactylOwner && tabs.allTabs.indexOf(tab.dactylOwner.get()) >= 0)
|
||||
tabs.select(tab.dactylOwner.get());
|
||||
else if (val == "previous" && tabs.alternate)
|
||||
tabs.select(tabs.alternate);
|
||||
else if (val == "left" && idx > 0)
|
||||
tabs.select(idx - 1);
|
||||
else if (val == "right" && idx < tabList.length - 1)
|
||||
tabs.select(idx + 1);
|
||||
else
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return removeTab.superapply(this, arguments);
|
||||
}),
|
||||
});
|
||||
|
||||
group.options.add(["tabclose", "tc"],
|
||||
"Tab closure options, in order of precedence",
|
||||
"stringlist", "left,opener,previous,right",
|
||||
{
|
||||
completer: context => [
|
||||
["left", "Select the tab to the left when closing"],
|
||||
["opener", UTF8("Select the tab’s opener, if available")],
|
||||
["previous", "Select the previously selected tab"],
|
||||
["right", "Select the tab to the right when closing"]
|
||||
]
|
||||
});
|
||||
group.options.add(["tabopen", "to"],
|
||||
"Placement options for new tabs",
|
||||
"stringmap", "link:right,orphan:groupright,external:end",
|
||||
{
|
||||
completer: function (context, extra) {
|
||||
if (extra.value == null)
|
||||
return [
|
||||
["external", "Tabs opened from an external application"],
|
||||
["link", "Tabs opened by clicking links and the like"],
|
||||
["orphan", "Tabs opened by any other means"]
|
||||
].filter(e => !hasOwnProperty(extra.values, e[0]));
|
||||
return [
|
||||
["end", "Open new tabs at the end of the tab bar"],
|
||||
["groupleft", "Open tabs to the left of the current group"],
|
||||
["groupright", "Open tabs to the right of the current group"],
|
||||
["left", "Open new tabs to the left of the current tab"],
|
||||
["right", "Open new tabs to the right of the current tab"],
|
||||
["start", "Open new tabs at the start of the tab bar"]
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
var INFO =
|
||||
["plugin", { name: "tab-options",
|
||||
version: "0.3",
|
||||
href: "http://dactyl.sf.net/pentadactyl/plugins#tab-options-plugin",
|
||||
summary: "Tab options",
|
||||
xmlns: "dactyl" },
|
||||
["author", { email: "maglione.k@gmail.com" }, "Kris Maglione"],
|
||||
["license", { href: "http://people.freebsd.org/~phk/" }, "BEER-WARE"],
|
||||
["project", { name: "Pentadactyl", "min-version": "1.0" }],
|
||||
["p", {},
|
||||
"Adds extended tab options, including relative placement of new",
|
||||
"tabs and more sensible focus changes after tab closure."],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "'tc' 'tabclose'"],
|
||||
["spec", {}, "'tabclose' 'tc'"],
|
||||
["type", {}, "stringlist"],
|
||||
["default", {}, options.get("tabclose").stringDefaultValue],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"Tab closure options, in order of precedence. The ",
|
||||
"first item for which a valid tab exists is used."],
|
||||
["dl", {},
|
||||
template.map(options.get("tabclose").completer(),
|
||||
([k, v]) =>
|
||||
[["dt", {}, k], ["dd", {}, v]])],
|
||||
["note", {},
|
||||
"This option does not affect the default mappings for ",
|
||||
["k", {}, "d"], "and ", ["k", {}, "D"],
|
||||
", which behave as documented."]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "'to' 'tabopen'"],
|
||||
["spec", {}, "'tabopen' 'to'"],
|
||||
["type", {}, "stringmap"],
|
||||
["default", {}, options.get("tabopen").stringDefaultValue],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"New tab placement options. The keys in the ",
|
||||
["t", {}, "stringmap"],
|
||||
"refer to the ways the tab was opened, while the values define ",
|
||||
"where such tabs are placed. The following keys are applicable:"],
|
||||
["dl", {},
|
||||
template.map(options.get("tabopen")
|
||||
.completer(null, { values: {} }),
|
||||
([k, v]) =>
|
||||
[["dt", {}, k], ["dd", {}, v]])],
|
||||
["p", {}, "As are the following values:"],
|
||||
["dl", {},
|
||||
template.map(options.get("tabopen")
|
||||
.completer(null, { value: "" }),
|
||||
([k, v]) =>
|
||||
[["dt", {}, k], ["dd", {}, v]])]]]
|
||||
];
|
||||
|
||||
/* vim:se sts=4 sw=4 et: */
|
||||
213
plugins/useragent.js
Executable file
213
plugins/useragent.js
Executable file
@@ -0,0 +1,213 @@
|
||||
"use strict";
|
||||
var INFO =
|
||||
["plugin", { name: "useragent",
|
||||
version: "0.3",
|
||||
href: "http://dactyl.sf.net/pentadactyl/plugins#useragent-plugin",
|
||||
summary: "User Agent Switcher",
|
||||
xmlns: "dactyl" },
|
||||
["author", { email: "maglione.k@gmail.com" },
|
||||
"Kris Maglione"],
|
||||
["license", { href: "http://opensource.org/licenses/mit-license.php" },
|
||||
"MIT"],
|
||||
["project", { name: "Pentadactyl", "min-version": "1.0" }],
|
||||
["p", {},
|
||||
"Ths plugin allows you to switch the browser's reported user-agent to a ",
|
||||
"number of preset values."],
|
||||
["item", {},
|
||||
["tags", {}, ":ua :useragent"],
|
||||
["spec", {}, ":useragent ", ["oa", {}, "name"], " ", ["oa", {}, "useragent"]],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"With zero or one arguments, list the currently defined ",
|
||||
"user-agent values."],
|
||||
|
||||
["p", {},
|
||||
"With two arguments, defines a new user-agent for use in the ",
|
||||
["o", {}, "useragent"], " option. When ", ["o", {}, "useragent"], " is set to ",
|
||||
"", ["oa", {}, "name"], ", the ", ["tt", {}, "User-Agent"], " value sent to web ",
|
||||
"servers, and the value returned by ",
|
||||
["tt", {}, "navigator.userAgent"], " will be ", ["oa", {}, "useragent"], ". ",
|
||||
"Additionally, the following options are available:"],
|
||||
|
||||
["dl", {},
|
||||
["dt", {}, "-appcodename"], ["dd", {}, "The value of ", ["tt", {}, "navigator.appCodeName"]],
|
||||
["dt", {}, "-appname"], ["dd", {}, "The value of ", ["tt", {}, "navigator.appName"]],
|
||||
["dt", {}, "-appversion"], ["dd", {}, "The value of ", ["tt", {}, "navigator.appVersion"]],
|
||||
["dt", {}, "-platform"], ["dd", {}, "The value of ", ["tt", {}, "navigator.platform"]],
|
||||
["dt", {}, "-vendor"], ["dd", {}, "The value of ", ["tt", {}, "navigator.vendor"]],
|
||||
["dt", {}, "-vendorsub"], ["dd", {}, "The value of ", ["tt", {}, "navigator.vendorsub"]]]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, ":deluseragent :delua"],
|
||||
["spec", {}, ":deluseragent ", ["a", {}, "name"]],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"Deletes a useragent created by ", ["ex", {}, ":useragent"], "."]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "'useragent' 'ua'"],
|
||||
["spec", {}, "'useragent' 'ua'"],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"Changes the User-Agent string sent to the web server and ",
|
||||
"returned by ", ["tt", {}, "navigator.userAgent"], ". If the value is the ",
|
||||
"name of a user-agent defined by ", ["ex", {}, ":useragent"], ", or one of ",
|
||||
"the predefined values, then the defined value is used. ",
|
||||
"Otherwise, the value itself is used."]]]];
|
||||
|
||||
let UserAgent, useragents;
|
||||
let init = function init_() {
|
||||
init = function () {};
|
||||
|
||||
UserAgent = Struct("name", "useragent", "appname", "appcodename",
|
||||
"appversion", "platform", "vendor", "vendorsub", "userset");
|
||||
|
||||
UserAgent.prototype.__defineGetter__("options", function () {
|
||||
return opts.slice(1).map(opt => [opt.name, this[opt.name]])
|
||||
.filter(opt => opt[1]);
|
||||
});
|
||||
|
||||
useragents = array([
|
||||
// From User Agent Switcher 0.7.2
|
||||
["ie-6", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
|
||||
"Mozilla", "Microsoft Internet Explorer", "4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
|
||||
"Win32"],
|
||||
["ie-7", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
|
||||
"Mozilla", "Microsoft Internet Explorer", "4.0 (compatible; MSIE 7.0; Windows NT 6.0)",
|
||||
"Win32"],
|
||||
["ie-8", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)",
|
||||
"Mozilla", "Microsoft Internet Explorer", "4.0 (compatible; MSIE 8.0; Windows NT 6.1)",
|
||||
"Win32"],
|
||||
["bot-googlebot-2.1", "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"],
|
||||
["bot-msnbot-1.1", "msnbot/1.1 (+http://search.msn.com/msnbot.htm)"],
|
||||
["bot-yahoo", "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)"],
|
||||
["iphone-3", "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16",
|
||||
"Mozilla", "Netscape", "5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16",
|
||||
"iPhone", "Apple Computer, Inc.", ""]
|
||||
]).map(ua => [ua[0], UserAgent.fromArray(ua)]).toObject();
|
||||
};
|
||||
|
||||
let Opt = Struct("name", "description", "pref", "names");
|
||||
Opt.defaultValue("names", function () { return ["-" + this.name]; });
|
||||
let opts = [
|
||||
["useragent", "The value of navigator.userAgent", "general.useragent.override"],
|
||||
["appcodename", "The value of navigator.appCodeName", "general.useragent.appName"],
|
||||
["appname", "The value of navigator.appName", "general.appname.override"],
|
||||
["appversion", "The value of navigator.appVersion", "general.appversion.override"],
|
||||
["platform", "The value of navigator.platform", "general.platform.override"],
|
||||
["vendor", "The value of navigator.vendor", "general.useragent.vendor"],
|
||||
["vendorsub", "The value of navigator.vendorsub", "general.useragent.vendorSub"]
|
||||
].map(Opt.fromArray, Opt);
|
||||
|
||||
group.options.add(["useragent", "ua"],
|
||||
"The current browser user-agent",
|
||||
"string", "default",
|
||||
{
|
||||
initValue: function () {},
|
||||
completer: function (context, args) {
|
||||
init();
|
||||
|
||||
context.title = ["Name", "User-Agent"];
|
||||
context.keys = { text: "name", description: "useragent" };
|
||||
context.completions = array(values(useragents)).concat(
|
||||
[{ name: "default", useragent: navigator.userAgent }]);
|
||||
},
|
||||
setter: function (value) {
|
||||
init();
|
||||
|
||||
let ua = useragents[value] ||
|
||||
(value == "default" ? UserAgent("default")
|
||||
: UserAgent("", value));
|
||||
for (let opt of values(opts)) {
|
||||
if (ua[opt.name])
|
||||
prefs.safeSet(opt.pref, ua[opt.name], "See the 'useragent' option");
|
||||
else
|
||||
prefs.safeReset(opt.pref, "See the 'useragent' option");
|
||||
}
|
||||
return value;
|
||||
},
|
||||
validator: () => true,
|
||||
});
|
||||
|
||||
group.commands.add(["useragent", "ua"],
|
||||
"Define a new useragent.",
|
||||
function (args) {
|
||||
init();
|
||||
|
||||
if (args.length < 2)
|
||||
commandline.commandOutput(template.tabular(["Name", "User-Agent"], ["padding-right: 1em; min-width: 8em;", "white-space: normal;"],
|
||||
[[ua.name,
|
||||
["",
|
||||
ua.useragent,
|
||||
!ua.options.length ? "" :
|
||||
["span", { highlight: "URLExtra" },
|
||||
" (",
|
||||
template.map(ua.options, (o) =>
|
||||
[["span", { highlight: "Key Normal" }, o[0]],
|
||||
"=",
|
||||
["span", { highlight: "String" }, o[1]]],
|
||||
"\u00a0"),
|
||||
")"]]
|
||||
]
|
||||
for (ua of values(useragents))
|
||||
if (!args[0] || ua.name.indexOf(args[0]) >= 0)]));
|
||||
else {
|
||||
dactyl.assert(args.bang || !Set.has(useragents, args[0]),
|
||||
"Useragent " + JSON.stringify(args[0]) + " already exists");
|
||||
useragents[args[0]] = UserAgent.fromArray(
|
||||
args.concat(opts.slice(1).map(
|
||||
(opt) => args[opt.names[0]])));
|
||||
useragents[args[0]].userset = true;
|
||||
}
|
||||
}, {
|
||||
bang: true,
|
||||
completer: function (context, args) {
|
||||
init();
|
||||
|
||||
if (args.completeArg == 1)
|
||||
context.completions = [[navigator.userAgent, "Default"]].concat(
|
||||
[[v.useragent, k] for ([k, v] of iter(useragents))]);
|
||||
},
|
||||
literal: 1,
|
||||
options: opts.slice(1).map((opt) => ({
|
||||
names: opt.names,
|
||||
description: opt.description,
|
||||
completer: (context, args) =>
|
||||
array(values(useragents)).map((ua) => ua[opt.name])
|
||||
.compact().uniq()
|
||||
.map((val) => [val, ""]).array,
|
||||
type: CommandOption.STRING
|
||||
})),
|
||||
serialize: function () {
|
||||
init();
|
||||
return [
|
||||
{
|
||||
command: this.name,
|
||||
arguments: [ua.name],
|
||||
bang: true,
|
||||
literalArg: ua.useragent,
|
||||
options: array(
|
||||
[opt.names[0], ua[opt.name]]
|
||||
for (opt of values(opts.slice(1)))
|
||||
if (ua[opt.name] != null)
|
||||
).toObject()
|
||||
}
|
||||
for (ua of values(useragents)) if (ua.userset)
|
||||
]
|
||||
}
|
||||
}, true);
|
||||
|
||||
group.commands.add(["deluseragent", "delua"],
|
||||
"Deletes a useragent.",
|
||||
function (args) {
|
||||
init();
|
||||
|
||||
dactyl.assert(Set.has(useragents, args[0]), "Invalid argument");
|
||||
if (options["useragent"] == args[0])
|
||||
options["useragent"] = "default";
|
||||
delete useragents[args[0]];
|
||||
}, {
|
||||
argCount: "1"
|
||||
}, true);
|
||||
|
||||
/* vim:se sts=4 sw=4 et: */
|
||||
209
plugins/xpcom.js
Executable file
209
plugins/xpcom.js
Executable file
@@ -0,0 +1,209 @@
|
||||
"use strict";
|
||||
var INFO =
|
||||
["plugin", { name: "xpcom",
|
||||
version: "0.4",
|
||||
href: "http://dactyl.sf.net/pentadactyl/plugins#xpcom-plugin",
|
||||
summary: "XPCOM development",
|
||||
xmlns: "dactyl" },
|
||||
["author", { email: "maglione.k@gmail.com" },
|
||||
"Kris Maglione"],
|
||||
["license", { href: "http://opensource.org/licenses/mit-license.php" },
|
||||
"MIT"],
|
||||
["project", { name: "Pentadactyl", "min-version": "1.0" }],
|
||||
|
||||
["p", {},
|
||||
"This plugin aids in the development of XPCOM-related code, and ",
|
||||
"in the exploration of extant XPCOM interfaces, classes, and ",
|
||||
"instances. All of the functions herein are exported to the ",
|
||||
"<em>userContext</em> and are thus available from the ",
|
||||
"<ex>:javascript</ex> command. Each of these functions provides ",
|
||||
"JavaScript completion for its arguments."],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "xpwrapper"],
|
||||
["spec", {}, "xpwrapper(<a>instance</a>, <oa>interface</oa>)"],
|
||||
["spec", {}, "xpwrapper(<a>string</a>)"],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"This function is the core of the plugin. It wraps XPCOM ",
|
||||
"objects so that their properties are more easily ",
|
||||
"accessible. When ", ["a", {}, "instance"], " alone is given, the ",
|
||||
"result contains one property for each interface that ",
|
||||
["a", {}, "instance"], " implements. Each of those properties, in ",
|
||||
"turn, returns ", ["a", {}, "instance"], " wrapped in a call to ",
|
||||
|
||||
["code", {}, "xpwrapper(", ["a", {}, "instance"], ", ", ["a", {}, "interface"], "),"],
|
||||
|
||||
"which contains only the properties of ", ["a", {}, "instance"], " ",
|
||||
"specified in ", ["a", {}, "interface"], ". Additionally, the ",
|
||||
"one-argument form contains the properties ", ["em", {}, "all"], "" ,
|
||||
"and ", ["em", {}, "wrappedJSObject"], ", the former of which ",
|
||||
"returns an object that implements all interfaces ",
|
||||
"provided by the instance, and the latter of which, when ",
|
||||
"applicable, is the raw JavaScript object that backs the ",
|
||||
"XPCOM instance."],
|
||||
|
||||
["p", {},
|
||||
"When ", ["a", {}, "string"], " is provided rather than an XPCOM ",
|
||||
"instance, the returned object contains all of the ",
|
||||
"properties specified by the interface with the given ",
|
||||
"name, each with an ", ["hl", { key: "Object" }, "undefined"], " value."]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "xpclasses"],
|
||||
["spec", {}, "xpclasses(", ["a", {}, "class"], ")"],
|
||||
["spec", {}, "xpclasses(", ["a", {}, "string"], ")"],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"When given an XPCOM instance as its first argument, ",
|
||||
"the result is exactly the same as the one argument form ",
|
||||
"of ", ["em", {}, "xpwrapper"], ". When given a string, returns the ",
|
||||
"", ["em", {}, "xpwrapper"], " for an instance of the provided ",
|
||||
"XPCOM contract ID."]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "xpproviders"],
|
||||
["strut"],
|
||||
["spec", {}, "xpproviders"],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"Presents, for each installed interface, a property for ",
|
||||
"each class that provides that interface. The properties ",
|
||||
"on both levels are lazily instantiated, so iterating ",
|
||||
"over the values of either level is not a good idea."],
|
||||
|
||||
["example", {},
|
||||
["ex", {}, ':js xpproviders.nsILocalFile["',
|
||||
["k", { name: "Tab", link: "c_<Tab>" }]]]]],
|
||||
|
||||
["item", {},
|
||||
["tags", {}, "xpservices"],
|
||||
["spec", {}, "xpservices(", ["a", {}, "class"], ")"],
|
||||
["spec", {}, "xpservices[", ["a", {}, "class"], "]"],
|
||||
["description", {},
|
||||
["p", {},
|
||||
"An object containing an ", ["t", {}, "xpwrapper"], " wrapped service for ",
|
||||
"each contract ID in ", ["em", {}, "Components.classes"], "."]]]];
|
||||
|
||||
function Completer(obj) {
|
||||
return [(context) => {
|
||||
context.anchored = false;
|
||||
return Object.keys(obj).map(k => [k, k]);
|
||||
}];
|
||||
}
|
||||
|
||||
userContext.xpwrapper = function xpwrapper(obj, iface) {
|
||||
let res = {};
|
||||
if (arguments.length == 2) {
|
||||
try {
|
||||
let shim = XPCOMShim([iface]);
|
||||
iter.forEach(properties(shim), function (prop) {
|
||||
res.__defineGetter__(prop, function () {
|
||||
let res = obj.QueryInterface(Ci[iface])[prop];
|
||||
if (callable(res)) {
|
||||
let fn = (...args) => res.apply(obj, args);
|
||||
fn.toString = () => res.toString();
|
||||
fn.toSource = () => res.toSource();
|
||||
return fn;
|
||||
}
|
||||
return res;
|
||||
})
|
||||
});
|
||||
}
|
||||
catch (e if e === Cr.NS_ERROR_NO_INTERFACE) {
|
||||
res = null
|
||||
}
|
||||
}
|
||||
else if (isString(obj))
|
||||
return xpwrapper({}, obj);
|
||||
else {
|
||||
for (let iface in Ci)
|
||||
if (Ci[iface] instanceof Ci.nsIJSIID)
|
||||
try {
|
||||
obj.QueryInterface(Ci[iface]);
|
||||
memoize(res, iface, iface => xpwrapper(obj, iface));
|
||||
}
|
||||
catch (e) {};
|
||||
|
||||
memoize(res, "all", function (iface) {
|
||||
try {
|
||||
for (let iface of Object.keys(Ci))
|
||||
obj instanceof Ci[iface];
|
||||
}
|
||||
catch (e) {}
|
||||
return obj;
|
||||
});
|
||||
if ("wrappedJSObject" in obj)
|
||||
memoize(res, "wrappedJSObject", () => obj.wrappedJSObject);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
memoize(userContext, "xpclasses", function () {
|
||||
function xpclasses(cls) {
|
||||
if (typeof cls == "string")
|
||||
cls = Cc[cls].createInstance();
|
||||
return userContext.xpwrapper(cls);
|
||||
}
|
||||
Object.keys(Cc).forEach(function (k) {
|
||||
xpclasses.__defineGetter__(k, () => xpclasses(k));
|
||||
});
|
||||
JavaScript.setCompleter([xpclasses], Completer(Cc));
|
||||
return xpclasses;
|
||||
});
|
||||
|
||||
memoize(userContext, "xpinterfaces", function () {
|
||||
function xpinterfaces(inst) {
|
||||
if (typeof inst == "string")
|
||||
inst = Cc[inst].createInstance();
|
||||
inst = inst.QueryInterface(Ci.nsIInterfaceRequestor);
|
||||
|
||||
let res = {};
|
||||
for (let iface in Ci)
|
||||
if (Ci[iface] instanceof Ci.nsIJSIID)
|
||||
try {
|
||||
inst.getInterface(Ci[iface]);
|
||||
memoize(res, iface, iface => userContext.xpwrapper(inst.getInterface(Ci[iface])));
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
return res;
|
||||
}
|
||||
return xpinterfaces;
|
||||
});
|
||||
|
||||
memoize(userContext, "xpservices", function () {
|
||||
function xpservices(cls) {
|
||||
if (typeof cls == "string")
|
||||
cls = Cc[cls].getService();
|
||||
return userContext.xpwrapper(cls);
|
||||
}
|
||||
Object.keys(Cc).forEach(function (k) {
|
||||
xpservices.__defineGetter__(k, () => xpservices(k));
|
||||
});
|
||||
JavaScript.setCompleter([xpservices], Completer(Cc));
|
||||
return xpservices;
|
||||
});
|
||||
|
||||
JavaScript.setCompleter([userContext.xpwrapper], Completer(Ci));
|
||||
|
||||
memoize(userContext, "xpproviders", function () {
|
||||
function xpproviders(iface) {
|
||||
iface = Ci[iface];
|
||||
let res = {};
|
||||
for (let cls in Cc)
|
||||
try {
|
||||
if (Cc[cls].getService() instanceof iface)
|
||||
memoize(res, cls, cls =>
|
||||
userContext.xpwrapper(Cc[cls].getService(), iface));
|
||||
}
|
||||
catch (e) {}
|
||||
return res;
|
||||
}
|
||||
for (let iface in Ci)
|
||||
memoize(xpproviders, iface, xpproviders);
|
||||
JavaScript.setCompleter([xpproviders], Completer(Ci));
|
||||
return xpproviders;
|
||||
});
|
||||
|
||||
/* vim:se sts=4 sw=4 et: */
|
||||
Reference in New Issue
Block a user