mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-22 22:57:58 +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,
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAACoAAAAqCAYAAADFw8lbAAAABGdBTUEAALGOfPtRkwAAACBjSFJN
|
||||||
|
AAB6JQAAgIMAAPn/AACA6AAAdTAAAOpgAAA6lwAAF2+XqZnUAAANkklEQVR4nGL8//8/w1AAAAHE
|
||||||
|
QqF+ZiAWyKntl3/9/oPkp09fhIF8Rqjcfz4+njdiYhIvJtdl3gPyPwHxP3ItAgggRjJDVNw3qdTp
|
||||||
|
7qNnHr/+/FXm4ODgFeDh4eBgY2NBdui7Tx9//wCC799/fubkZL+nLCe1ffO87j1AuTekWggQQKQ6
|
||||||
|
VNrIJznv05evVhIiImLSEsL8fHwCHHx8fKw8XGxM7CxMTMiKf/759+/r50//Pn799fvz27ffbz19
|
||||||
|
/un9+48vBQX5j53bMreHFAcDBBCxDmXxjCuOunH3YbK8lJicsoKigKSECIcgvwCLgCAfEx8XFyMb
|
||||||
|
OzvYPDR9/3/9/Mnw6du3/x/ef/r3/uOHP/cePv9x497dd89ePH9kqqc9ExjCq4Hq/hJyAEAAEeNQ
|
||||||
|
ERWHiKnA6NUx0NISV5AW5REXF2eVEBZk5OPjYmSHOJCBg4UVpwE//vxm+PrpO8O3nz/+gxz98uWL
|
||||||
|
31duPPxy8MTZ55xcrJfvHFiRwQBJwzgBQAARcqiUtFnwHEU5SU1DPW1RBSkJDjlpCSYhfj5GDg5I
|
||||||
|
LHMwMzMwszEzsDNgz5fffv2E+FaEj4GVhQ0Yuj8ZPnz89v/1q+d/D5y7+WPngcOv37x5de3FmW0J
|
||||||
|
DHiSAkAA4XOoBNCR8zVV5LX1gY7UUpRgk5GRYYKFoAA3JAQ5gPmHnYkNqwE///1iEBcSYACmSYbr
|
||||||
|
1x8yHD57huH8pZsM7z9+YxDk52Lwdnf4d/rq3Z+bdx14DUwKV4GOjcPlWIAAwlU8cShah8wCOlIL
|
||||||
|
5EgDDWU2MVFBJh5ONmAIMjFw80AcC3IgExskWYJCCx0oCgsxfPz2l6Ft2lKGdZu3Mjx5/YHhByMb
|
||||||
|
w29mdoZ/bOwMWnoGTJ52VuzADCd64vx1LWDAzH56am04UOsvdLMAAgibQxmBObsBGAoaQEeKAB3J
|
||||||
|
LiUmCo5qbpBDoSGI7EBmVhYGNkbUmAGF4sOnLxhyKloY9h4/z8AmKMrALaHEIMLFC5b//u0zw6XH
|
||||||
|
rxj8HI2YjA102f8zc4i++/BeE2h3PbBEqEZ3FEAAMaELAAtvQ2DR52xpaCAGjG6sjmTnYgc7kIOT
|
||||||
|
CyjOAcxILAxMzKwMwLISjEGOBJYQDBGZ5WBHCqtqMogoajJwQh0JAh+//GR48uo12BxFaWkmLVUF
|
||||||
|
didLE/GXrz44l7RO1UJ3F0AAoTuUdd/xMwUGWtpSykoKXBKiUkzYHAkCMAeyszHBMbBkAOOX7z4x
|
||||||
|
lDZ0M5y4dptBUMOQgV1QAljAMYMxKCRfvHrDwMbBzsDFwwWODQFeFgYZCREmdXV1Ln0dTZkNuw83
|
||||||
|
MkBqPTgACCCUqE8u7bYQEhDUU1WR5ZOVEGHm5uNkBKVJZEeCDIY5EARADkMH05ZsBIekjKoWUA8w
|
||||||
|
FP9Aisl3nz4z6KpKM8Q5mDEYaykA9XIx/P7yFVhi/GUQ4eFk/CElwWKip8H/4NF9ldSqfvPZbYXH
|
||||||
|
YGYCBBCyQ5nOX78RYqipISIiJMwOLCOZQGUjF1KaJMaRR89dZ1i6fCU4TXLxiwBFIGn39YcvDMH2
|
||||||
|
JgyNSX4MnMDi7Ovnb2DxL79/Ac3nBNrzi4Gf7x+TvKwku6aGuujxcxfjgdLHYQYABBBy1EsCsYmM
|
||||||
|
rAQPsDBnBudwYCwDMynYkaC0BMowTEDHw6IYG1i+fgfD3dfvGERklBj+MrGA8dMXb8GO7MoIZPgH
|
||||||
|
rKlevvvA8BsYyCAMK9qADQVwkSciKMisqSjLA8wnoHQqDDMXIIDgDg3PqdeXEJMUgoYmI6ggBxXi
|
||||||
|
IINgOZuFnQur42Dg7MVbDDv27GXgFxRjAOYcsNiLZy8ZgG0CcEgy/IaELg8rG7iMRQcg+3g42BmB
|
||||||
|
NR8bsC0hFJXXZgSTAwgguENfv32jDjSQm4uTnRlYqIPLHlhogn0MjHJWpr8MvFy4q8qDx0/AQxME
|
||||||
|
3gFD7tuHtww5PnZg/svPH8FRDQtJdMeCQpWbi4NRgIeLRVxCjPvF66caMDmAAIKlUZZfv344A1tB
|
||||||
|
nMAGBhMr039ItQiNFlBoQgzCHt0g8OzlO4ZNe08APQeMLVZ2sCO/f/vEwM7HwzBlyyGG+SvWMvz/
|
||||||
|
8ovh/9c3DH6BXgylBRkMT58/wzAHlNw42NmZJAV5Oe4/eKgKDcx/AAEEdygDIycnsKnGAmwFMcKK
|
||||||
|
IxBATpsMf4D1Ngs7Vofevv+A4dT5iwycIjLg3A1yJFzu0lVgk+MTw//vvxgYv35kUDd/w8DLBmlD
|
||||||
|
Y0sCXOwcjOzcfKzAtq4aNDB/AQQQzKEgV7Ows3EyAl3MCEubyAAU7QwsuEN0776jDN/fvGPgkFIG
|
||||||
|
O/L3b0TLjYmfj4EBhEFB8/ETMMOIAFtUmG0MkJ3/wQ5hYgS1b0HWQt3GABBAyLmekQGzPcnw+88v
|
||||||
|
cK2DD4Cqyumzl4DZzEzsKI5EBv++fweGzR+GX3//oDgOhtEAIxsLM9w9AAGEXI7+Z4AVesiG//rP
|
||||||
|
8PX7D2DU8zLgCs+d+48yvHlwj4FR35bhxz9glLJyMPz79B7YDnoLjm4U8PUlw+e3xnjTO5J74H0s
|
||||||
|
gACCORQk8BtE/2H4//8nwx9GDgaEDz99+czwE9iO/AysmUBVJzqYv2oTMGh4GZj4BCGGvXnFAMyV
|
||||||
|
DFFxAQzADMrw4+s3hMd/fmYwMdZnAHZJsLoOaDfYkX9/g6szkC/B0QMQQDCH/mJj/f/129fPvxmw
|
||||||
|
hCosWn5++QDECHEBXiGGY+fPMJzYdRjYxFaGCP7+wfD/5RuGCO8gBmDvEyz0/dMPFPN+/f0BLvRx
|
||||||
|
tWN//PwL7Gf9+MnO9Oc0kAt2OUAAwUOUnZVj0/sPX/S/ff/y98dPfmZ+NmB6AlZtKADKB+VUsCWs
|
||||||
|
jAz1E+aBxZjFxcCO/AcsRxkFBRgCPayBZS8jw5Nn77A6BlS/AxMthh1/f/1lAPaz/r598/6HgIDI
|
||||||
|
XVjAAQQQPDMpSAhfffH+/edvP37/AfZx/v/4xcyADkAOBGFQzaKoKMnQP30Rw9n9wLJTSRuu5v/7
|
||||||
|
DwwedsYMpoY6DC9fvwcX8OgYnNdADkRzJMjsH3//gvpVf1+9efMF6KbrMDmAAII7dHpX1d2P7z4A
|
||||||
|
266ffgI7Yv+gaQVuAAiI8/IzSIqKMvAK8DPUtU1maO6axgBsn0GKH1BovHwFLIZ4GBJDvRn4udgY
|
||||||
|
3n/7iRqK2HM3wpNAa758//UP2Pn78e7Tx7dAN92EyQEEEHKuf/vv/89ND569UJCSFOYW/snHxMH2
|
||||||
|
C1w8gEIQBI5evsZw6/YdhtXb9jKcOHQK2GMTZGDkkYAUOyDw8QtDUlIQg5u1PsObV+/hjiMWADuC
|
||||||
|
/z99+vbn2p2nn/k42bcxIPVMAQII2aH/1GWlD9198DRCTUmeX0jgCzMHOw8zqPCXUZZk2LzrCENS
|
||||||
|
XCrDG2C+YOQRY2CUUmFgYEOUr/8fP2cwNlNkKM2KAfM/f/0FrruJBR9/fGP48PX3/8cv3vx48OjR
|
||||||
|
SwtD7a0MSBkbIIBQWvjAoL7w4/v7VbfuPQSmgY9/vn7/9R+cBIBVJ9N/oAs5+RgYFTQZmGRl4NHN
|
||||||
|
8Os32JFSylIMnbXVDBrAtPvs6WuSHPnjxy8GkF3vPn76fe7y9ffAwndzT3X2LWQ1AAGE3rn7baSj
|
||||||
|
teXC1dt+kmKiPFycPPxAMWZgT5KRh18IrOA/sB7/C8SIoPjCYKCrwtDfU83gYKIB7haTAkDpHxTl
|
||||||
|
Hz78+Hv55t3P127dfORjZbCUAW30BCCAMDp3QJ/c4Gf/M+HslWvPHj178e3Nh+9/n7/9yCAuKszA
|
||||||
|
LyEKdhgjsDEsys3BYCAnwZCdFcawbn4Xg4OBItyRxIYmyJFfgZ08YJT/u/fs+dd9R048VRTlntBU
|
||||||
|
lXsfXS1AAOEagOB0CM3KVVZQTDTQ15ZWkpLkUpYXYj50/AzD03ffGICNawZFSQEGbSVFcDEFqmVe
|
||||||
|
vPhAkiNB0f3x5x9gLfPj34PnL76t3br/6fs3j5cd37SwgwFSS6IAgADCN1LCD3RsJtCxCUDHSoIc
|
||||||
|
a2KgzAwsdhhBBTkIvH/3HdwYJgf8+PXnPzAk/959+BTkyOdAR64EOrILKPUVm3qAAMI3kPvxwOpp
|
||||||
|
04GO/f/z7//YXz9+SgHFeKQl+ViAvUd4qwZWdIEArNEEK3eRiyZYTwEK/n/4/OfPucu3v2zbvf/Z
|
||||||
|
1y9v1wAd2Y3LkSAAEEDEjObx+cbmBPxlFcg10laW0dZQ5tNUkmYTExJk5uXlZQS3U4kEP3/9+w9M
|
||||||
|
739v3n/+69Cp859Onjn/WJCTYfLmxVPW4XMkCAAEELHjo6zZJbWG9159axIUEJZXUZIT1lVX5lZV
|
||||||
|
EGNTlJYEllTwEMYYH4XRwK7Kv8t3Hv86dvbS19MXbr799PH5A31FqbqpPc3nGIgYHwUIIFJHnPlj
|
||||||
|
Mkqs3n77X8TFxy8lJSYqqCAlwSUnLcEiJS7ADOzCICeL/x8+fvvz8t3Hv8DS4zewbP4OrEzeA8vp
|
||||||
|
Z1L8nH1LZvSABheITuAAAUTOGD7IIXzAENb8+OV7+cdfjKC+NzcbFy/QnRzc7MyM4E4VMF3//P7r
|
||||||
|
x9df3z5/+f7j71dgkfdWQpi/CxiCoIYGqGokyWKAACJ3sgEGQHUoqAPPX1zVIPzj198SKB8EvnGw
|
||||||
|
Mff0tjWAxjtBFT+ohYJR7BALAAKIUofSDQAEEEbNNFgBQIABABWRKc05F+/jAAAAAElFTkSuQmCC
|
||||||
|
`,
|
||||||
|
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