1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2026-01-06 16:34:14 +01:00

Major documentation updates and formatting fixes, and many, many other changes thanks to an MQ glitch, including:

* Significant completion speed improvements
 * Significantly improve startup speed, in large part by lazily
   instantiating Options and Commands, lazily installing highlight
   stylesheets, etc.
 * Update logos and icons, fix atrocious about page
 * Fix Teledactyl
 * JavaScript completion now avoids accessing property values
 * Add Option#persist to define which options are saved with :mkp
 * Add new Dactyl component which holds add-on-specific configuration
   information and removes need for separate components for each dactyl
   host
 * Several fixes for latest nightlies
 * Significant code cleanup and many bug fixes

--HG--
rename : muttator/AUTHORS => teledactyl/AUTHORS
rename : muttator/Donors => teledactyl/Donors
rename : muttator/Makefile => teledactyl/Makefile
rename : muttator/NEWS => teledactyl/NEWS
rename : muttator/TODO => teledactyl/TODO
rename : muttator/chrome.manifest => teledactyl/chrome.manifest
rename : muttator/components/commandline-handler.js => teledactyl/components/commandline-handler.js
rename : muttator/components/protocols.js => teledactyl/components/protocols.js
rename : muttator/content/addressbook.js => teledactyl/content/addressbook.js
rename : muttator/content/compose/compose.js => teledactyl/content/compose/compose.js
rename : muttator/content/compose/compose.xul => teledactyl/content/compose/compose.xul
rename : muttator/content/compose/dactyl.dtd => teledactyl/content/compose/dactyl.dtd
rename : muttator/content/compose/dactyl.xul => teledactyl/content/compose/dactyl.xul
rename : muttator/content/config.js => teledactyl/content/config.js
rename : muttator/content/dactyl.dtd => teledactyl/content/dactyl.dtd
rename : muttator/content/logo.png => teledactyl/content/logo.png
rename : muttator/content/mail.js => teledactyl/content/mail.js
rename : muttator/content/muttator.xul => teledactyl/content/pentadactyl.xul
rename : muttator/contrib/vim/Makefile => teledactyl/contrib/vim/Makefile
rename : muttator/contrib/vim/ftdetect/muttator.vim => teledactyl/contrib/vim/ftdetect/muttator.vim
rename : muttator/contrib/vim/mkvimball.txt => teledactyl/contrib/vim/mkvimball.txt
rename : muttator/contrib/vim/syntax/muttator.vim => teledactyl/contrib/vim/syntax/muttator.vim
rename : muttator/install.rdf => teledactyl/install.rdf
rename : muttator/locale/en-US/Makefile => teledactyl/locale/en-US/Makefile
rename : muttator/locale/en-US/all.xml => teledactyl/locale/en-US/all.xml
rename : muttator/locale/en-US/autocommands.xml => teledactyl/locale/en-US/autocommands.xml
rename : muttator/locale/en-US/gui.xml => teledactyl/locale/en-US/gui.xml
rename : muttator/locale/en-US/intro.xml => teledactyl/locale/en-US/intro.xml
rename : muttator/skin/icon.png => teledactyl/skin/icon.png
This commit is contained in:
Kris Maglione
2010-09-17 06:21:33 -04:00
parent bfbb4b1313
commit 1557b70f45
125 changed files with 4409 additions and 3969 deletions

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2009 by Kris Maglione <maglione.k@gmail.com>
// Copyright (c) 2009-2010 by Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
@@ -11,6 +11,74 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
let objproto = Object.prototype;
let hasOwnProperty = objproto.hasOwnProperty;
if (!Object.create)
Object.create = function (proto, props) {
let obj = { __proto__: proto };
for (let k in properties(props || {}))
Object.defineProperty(obj, k, props[k]);
return obj;
};
if (!Object.defineProperty)
Object.defineProperty = function (obj, prop, desc) {
let value = desc.value;
if ("value" in desc)
if (desc.writable && !objproto.__lookupGetter__.call(obj, prop)
&& !objproto.__lookupSetter__.call(obj, prop))
obj[prop] = value;
else {
objproto.__defineGetter__.call(obj, prop, function () value);
if (desc.writable)
objproto.__defineSetter__.call(obj, prop, function (val) { value = val; });
}
if ("get" in desc)
objproto.__defineGetter__.call(obj, prop, desc.get);
if ("set" in desc)
objproto.__defineSetter__.call(obj, prop, desc.set);
}
if (!Object.getOwnPropertyDescriptor)
Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(obj, prop) {
if (!hasOwnProperty.call(obj, prop))
return undefined;
let desc = {
configurable: true,
enumerable: objproto.propertyIsEnumerable.call(obj, prop),
};
var get = obj.__lookupGetter__(prop),
set = obj.__lookupSetter__(prop);
if (!get && !set) {
desc.value = obj[prop];
desc.writable = true;
}
if (get)
desc.get = get;
if (set)
desc.set = set;
return desc;
}
if (!Object.getOwnPropertyNames)
Object.getOwnPropertyNames = function getOwnPropertyNames(obj) {
// This is an ugly and unfortunately necessary hack.
if (hasOwnProperty.call(obj, "__iterator__")) {
var oldIter = obj.__iterator__;
delete obj.__iterator__;
}
let res = [k for (k in obj) if (hasOwnProperty.call(obj, k))];
if (oldIter !== undefined) {
obj.__iterator__ = oldIter;
res.push("__iterator__");
}
return res;
};
if (!Object.getPrototypeOf)
Object.getPrototypeOf = function (obj) obj.__proto__;
if (!Object.keys)
Object.keys = function (obj)
Object.getOwnPropertyNames(obj).filter(function (k) objproto.propertyIsEnumerable.call(obj, k));
let use = {};
let loaded = {};
let currentModule;
@@ -30,17 +98,21 @@ function defmodule(name, module, params) {
}
currentModule = module;
}
defmodule.loadLog = [];
// Object.defineProperty(defmodule.loadLog, "push", { value: function (val) { dump(val + "\n"); this[this.length] = val } });
Object.defineProperty(defmodule.loadLog, "push", { value: function (val) { dump(val + "\n"); this[this.length] = val } });
defmodule.modules = [];
defmodule.times = {};
defmodule.time = function (major, minor, func, self) {
defmodule.times = { all: 0 };
defmodule.time = function time(major, minor, func, self) {
let time = Date.now();
let res = func.apply(self, Array.slice(arguments, 4));
let delta = Date.now() - time;
defmodule.times.all += delta;
defmodule.times[major] = (defmodule.times[major] || 0) + delta;
if (minor)
if (minor) {
defmodule.times[":" + minor] = (defmodule.times[":" + minor] || 0) + delta;
defmodule.times[major + ":" + minor] = (defmodule.times[major + ":" + minor] || 0) + delta;
}
return res;
}
@@ -66,12 +138,12 @@ defmodule("base", this, {
// sed -n 's/^(const|function) ([a-zA-Z0-9_]+).*/ "\2",/p' base.jsm | sort | fmt
exports: [
"Cc", "Ci", "Class", "Cr", "Cu", "Module", "Object", "Runnable",
"Struct", "StructBase", "Timer", "XPCOMUtils", "allkeys", "array",
"call", "callable", "curry", "debuggerProperties", "defmodule", "dict",
"Struct", "StructBase", "Timer", "UTF8", "XPCOMUtils", "array",
"call", "callable", "curry", "debuggerProperties", "defmodule",
"endmodule", "extend", "foreach", "isarray", "isgenerator",
"isinstance", "isobject", "isstring", "issubclass", "iter", "keys",
"memoize", "properties", "requiresMainThread", "set", "update",
"values",
"isinstance", "isobject", "isstring", "issubclass", "iter", "iterall",
"keys", "memoize", "properties", "requiresMainThread", "set",
"update", "values",
],
use: ["services"]
});
@@ -83,33 +155,13 @@ function Runnable(self, func, args) {
};
}
function allkeys(obj) {
let ret = {};
try {
for (; obj; obj = obj.__proto__) {
services.get("debugger").wrapValue(obj).getProperties(ret, {});
for (let prop in values(ret.value))
yield prop.name.stringValue;
}
return;
}
catch (e) {}
let __iterator__ = obj.__iterator__;
try {
if ("__iterator__" in obj) {
yield "__iterator__";
delete obj.__iterator__;
}
for (let k in obj)
yield k;
}
finally {
if (__iterator__)
obj.__iterator__ = __iterator__;
}
}
/**
* Returns a list of all of the top-level properties of an object, by
* way of the debugger.
*
* @param {object} obj
* @returns [jsdIProperty]
*/
function debuggerProperties(obj) {
if (loaded.services && services.get("debugger").isOn) {
let ret = {};
@@ -118,58 +170,89 @@ function debuggerProperties(obj) {
}
}
let hasOwnProperty = Object.prototype.hasOwnProperty;
if (!Object.keys)
Object.keys = function keys(obj) [k for (k in obj) if (hasOwnProperty.call(obj, k))];
if (!Object.getOwnPropertyNames)
Object.getOwnPropertyNames = function getOwnPropertyNames(obj) {
let res = debuggerProperties(obj);
if (res)
return [prop.name.stringValue for (prop in values(res))];
return Object.keys(obj);
}
function properties(obj, prototypes) {
/**
* Iterates over the names of all of the top-level properties of an
* object or, if prototypes is given, all of the properties in the
* prototype chain below the top. Uses the debugger if possible.
*
* @param {object} obj The object to inspect.
* @param {boolean} properties Whether to inspect the prototype chain
* @default false
* @returns {Generator}
*/
function properties(obj, prototypes, debugger_) {
let orig = obj;
let seen = {};
for (; obj; obj = prototypes && obj.__proto__) {
try {
var iter = values(Object.getOwnPropertyNames(obj));
var iter = (!debugger_ || !services.get("debugger").isOn) && values(Object.getOwnPropertyNames(obj));
}
catch (e) {
catch (e) {}
if (!iter)
iter = (prop.name.stringValue for (prop in values(debuggerProperties(obj))));
}
for (let key in iter)
if (!prototypes || !set.add(seen, key) && obj != orig)
yield key
}
}
/**
* Iterates over all of the top-level, iterable property names of an
* object.
*
* @param {object} obj The object to inspect.
* @returns {Generator}
*/
function keys(obj) {
for (var k in obj)
if (hasOwnProperty.call(obj, k))
yield k;
}
/**
* Iterates over all of the top-level, iterable property values of an
* object.
*
* @param {object} obj The object to inspect.
* @returns {Generator}
*/
function values(obj) {
for (var k in obj)
if (hasOwnProperty.call(obj, k))
yield obj[k];
}
/**
* Iterates over an iterable object and calls a callback for each
* element.
*
* @param {object} iter The iterator.
* @param {function} fn The callback.
* @param {object} self The this object for 'fn'.
*/
function foreach(iter, fn, self) {
for (let val in iter)
fn.call(self, val);
}
function dict(ary) {
var obj = {};
for (var i = 0; i < ary.length; i++) {
var val = ary[i];
obj[val[0]] = val[1];
}
return obj;
/**
* Iterates over each iterable argument in turn, yielding each value.
*
* @returns {Generator}
*/
function iterall() {
for (let i = 0; i < arguments.length; i++)
for (let j in Iterator(arguments[i]))
yield j;
}
/**
* Utility for managing sets of strings. Given an array, returns an
* object with one key for each value thereof.
*
* @param {[string]} ary @optional
* @returns {object}
*/
function set(ary) {
let obj = {};
if (ary)
@@ -177,33 +260,86 @@ function set(ary) {
obj[ary[i]] = true;
return obj;
}
/**
* Adds an element to a set and returns true if the element was
* previously contained.
*
* @param {object} set The set.
* @param {string} key The key to add.
* @returns boolean
*/
set.add = function (set, key) {
let res = this.has(set, key);
set[key] = true;
return res;
}
/**
* Returns true if the given set contains the given key.
*
* @param {object} set The set.
* @param {string} key The key to check.
* @returns {boolean}
*/
set.has = function (set, key) hasOwnProperty.call(set, key);
set.remove = function (set, key) { delete set[key]; }
/**
* Returns a new set containing the members of the first argument which
* do not exist in any of the other given arguments.
*
* @param {object} set The set.
* @returns {object}
*/
set.subtract = function (set) {
set = update({}, set);
for (let i = 1; i < arguments.length; i++)
for (let k in keys(arguments[i]))
delete set[k];
return set;
}
/**
* Removes an element from a set and returns true if the element was
* previously contained.
*
* @param {object} set The set.
* @param {string} key The key to remove.
* @returns boolean
*/
set.remove = function (set, key) {
let res = set.has(set, key);
delete set[key];
return res;
}
/**
* Iterates over an arbitrary object. The following iterators types are
* supported, and work as a user would expect:
*
* • nsIDOMNodeIterator
* • mozIStorageStatement
*
* Additionally, the following array-like objects yield a tuple of the
* form [index, element] for each contained element:
*
* • nsIDOMHTMLCollection
* • nsIDOMNodeList
*
* and the following likewise yield one element of the form
* [name, element] for each contained element:
*
* • nsIDOMNamedNodeMap
*
* Duck typing is implemented for the any other type. If the object
* contains the "enumerator" property, iter is called on that. If the
* property is a function, it is called first. If it contains the
* property "getNext" along with either "hasMoreItems" or "hasMore", it
* is iterated over appropriately.
*
* For all other cases, this function behaves exactly like the Iterator
* function.
*
* @param {object} obj
* @returns {Generator}
*/
function iter(obj) {
if (obj instanceof Ci.nsISimpleEnumerator)
return (function () {
while (obj.hasMoreElements())
yield obj.getNext();
})();
if (isinstance(obj, [Ci.nsIStringEnumerator, Ci.nsIUTF8StringEnumerator]))
return (function () {
while (obj.hasMore())
yield obj.getNext();
})();
if (isinstance(obj, Ci.nsIDOMNodeIterator))
return (function () {
try {
while (true)
yield obj.nextNode();
}
catch (e) {}
})();
if (isinstance(obj, [Ci.nsIDOMHTMLCollection, Ci.nsIDOMNodeList]))
return array.iteritems(obj);
if (obj instanceof Ci.nsIDOMNamedNodeMap)
@@ -217,14 +353,51 @@ function iter(obj) {
yield obj.row;
obj.reset();
})(obj);
if ("getNext" in obj) {
if ("hasMoreElements" in obj)
return (function () {
while (obj.hasMoreElements())
yield obj.getNext();
})();
if ("hasMore" in obj)
return (function () {
while (obj.hasMore())
yield obj.getNext();
})();
}
if ("enumerator" in obj) {
if (callable(obj.enumerator))
return iter(obj.enumerator());
return iter(obj.enumerator);
}
return Iterator(obj);
}
/**
* Returns true if both arguments are functions and
* (targ() instaneof src) would also return true.
*
* @param {function} targ
* @param {function} src
* @returns {boolean}
*/
function issubclass(targ, src) {
return src === targ ||
targ && typeof targ === "function" && targ.prototype instanceof src;
}
/**
* Returns true if targ is an instance or src. If src is an array,
* returns true if targ is an instance of any element of src. If src is
* the object form of a primitive type, returns true if targ is a
* non-boxed version of the type, i.e., if (typeof targ == "string"),
* isinstance(targ, String) is true. Finally, if src is a string,
* returns true if ({}.toString.call(targ) == "[object <src>]").
*
* @param {object} targ The object to check.
* @param {object|string|[object|string]} src The types to check targ against.
* @returns {boolean}
*/
function isinstance(targ, src) {
const types = {
boolean: Boolean,
@@ -234,8 +407,8 @@ function isinstance(targ, src) {
}
src = Array.concat(src);
for (var i = 0; i < src.length; i++) {
if (typeof src[i] == "string") {
if (Object.prototype.toString.call(targ) == "[object " + src[i] + "]")
if (typeof src[i] === "string") {
if (objproto.toString.call(targ) === "[object " + src[i] + "]")
return true;
}
else {
@@ -249,9 +422,10 @@ function isinstance(targ, src) {
return false;
}
function isobject(obj) {
return typeof obj === "object" && obj != null;
}
/**
* Returns true if obj is a non-null object.
*/
function isobject(obj) typeof obj === "object" && obj != null;
/**
* Returns true if and only if its sole argument is an
@@ -259,9 +433,8 @@ function isobject(obj) {
* any window, frame, namespace, or execution context, which
* is not the case when using (obj instanceof Array).
*/
function isarray(val) {
return Object.prototype.toString.call(val) == "[object Array]";
}
const isarray = Array.isArray ||
function isarray(val) objproto.toString.call(val) == "[object Array]";
/**
* Returns true if and only if its sole argument is an
@@ -269,9 +442,7 @@ function isarray(val) {
* functions containing the 'yield' statement and generator
* statements such as (x for (x in obj)).
*/
function isgenerator(val) {
return Object.prototype.toString.call(val) == "[object Generator]";
}
function isgenerator(val) objproto.toString.call(val) == "[object Generator]";
/**
* Returns true if and only if its sole argument is a String,
@@ -280,28 +451,30 @@ function isgenerator(val) {
* namespace, or execution context, which is not the case when
* using (obj instanceof String) or (typeof obj == "string").
*/
function isstring(val) {
return Object.prototype.toString.call(val) == "[object String]";
}
function isstring(val) objproto.toString.call(val) == "[object String]";
/**
* Returns true if and only if its sole argument may be called
* as a function. This includes classes and function objects.
*/
function callable(val) {
return typeof val === "function";
}
function callable(val) typeof val === "function";
function call(fn) {
fn.apply(arguments[1], Array.slice(arguments, 2));
return fn;
}
/**
* Memoizes an object property value.
*
* @param {object} obj The object to add the property to.
* @param {string} key The property name.
* @param {function} getter The function which will return the initial
* value of the property.
*/
function memoize(obj, key, getter) {
obj.__defineGetter__(key, function () {
delete obj[key];
return obj[key] = getter(obj, key);
});
obj.__defineGetter__(key, function ()
Class.replaceProperty(this, key, getter.call(this, key)));
}
/**
@@ -390,24 +563,15 @@ function update(target) {
for (let i = 1; i < arguments.length; i++) {
let src = arguments[i];
Object.getOwnPropertyNames(src || {}).forEach(function (k) {
var get = src.__lookupGetter__(k),
set = src.__lookupSetter__(k);
if (!get && !set) {
var v = src[k];
target[k] = v;
if (target.__proto__ && callable(v)) {
v.superapply = function (self, args) {
return target.__proto__[k].apply(self, args);
};
v.supercall = function (self) {
return v.superapply(self, Array.slice(arguments, 1));
};
}
let desc = Object.getOwnPropertyDescriptor(src, k);
if (desc.value && callable(desc.value) && Object.getPrototypeOf(target)) {
let func = desc.value;
desc.value.superapply = function (self, args)
Object.getPrototypeOf(target)[k].apply(self, args);
desc.value.supercall = function (self)
func.superapply(self, Array.slice(arguments, 1));
}
if (get)
target.__defineGetter__(k, get);
if (set)
target.__defineSetter__(k, set);
Object.defineProperty(target, k, desc);
});
}
return target;
@@ -424,14 +588,19 @@ function update(target) {
* @param {Object} overrides @optional
*/
function extend(subclass, superclass, overrides) {
subclass.prototype = { __proto__: superclass.prototype };
subclass.superclass = superclass;
try {
subclass.prototype = Object.create(superclass.prototype);
}
catch(e) {
dump(e + "\n" + String.replace(e.stack, /^/gm, " ") + "\n\n");
}
update(subclass.prototype, overrides);
subclass.superclass = superclass.prototype;
subclass.prototype.constructor = subclass;
subclass.prototype.__class__ = subclass;
subclass.prototype._class_ = subclass;
if (superclass.prototype.constructor === Object.prototype.constructor)
if (superclass.prototype.constructor === objproto.constructor)
superclass.prototype.constructor = superclass;
}
@@ -459,22 +628,6 @@ function extend(subclass, superclass, overrides) {
* @returns {function} The constructor for the resulting class.
*/
function Class() {
function constructor() {
let self = {
__proto__: Constructor.prototype,
constructor: Constructor,
get closure() {
delete this.closure;
function closure(fn) function () fn.apply(self, arguments);
for (let k in this)
if (!this.__lookupGetter__(k) && callable(this[k]))
closure[k] = closure(self[k]);
return this.closure = closure;
}
};
var res = self.init.apply(self, arguments);
return res !== undefined ? res : self;
}
var args = Array.slice(arguments);
if (isstring(args[0]))
@@ -483,21 +636,43 @@ function Class() {
if (callable(args[0]))
superclass = args.shift();
var Constructor = eval("(function " + (name || superclass.name).replace(/\W/g, "_") +
String.substr(constructor, 20) + ")");
Constructor.__proto__ = superclass;
Constructor.name = name || superclass.name;
var Constructor = eval(String.replace(<![CDATA[
(function constructor() {
let self = Object.create(Constructor.prototype, {
constructor: { value: Constructor },
closure: {
configurable: true,
get: function () {
function closure(fn) function () fn.apply(self, arguments);
for (let k in iterall(properties(this),
properties(this, true)))
if (!this.__lookupGetter__(k) && callable(this[k]))
closure[k] = closure(self[k]);
Object.defineProperty(this, "closure", { value: closure });
return closure;
}
}
});
var res = self.init.apply(self, arguments);
return res !== undefined ? res : self;
})]]>,
"constructor", (name || superclass.classname).replace(/\W/g, "_")));
Constructor.classname = name || superclass.classname || superclass.name;
if (!("init" in superclass.prototype)) {
var superc = superclass;
if ("init" in superclass.prototype)
Constructor.__proto__ = superclass;
else {
let superc = superclass;
superclass = function Shim() {};
extend(superclass, superc, {
init: superc
});
superclass.__proto__ = superc;
}
extend(Constructor, superclass, args[0]);
update(Constructor, args[1]);
Constructor.__proto__ = superclass;
args = args.slice(2);
Array.forEach(args, function (obj) {
if (callable(obj))
@@ -506,18 +681,11 @@ function Class() {
});
return Constructor;
}
if (Object.defineProperty)
Class.replaceProperty = function (obj, prop, value) {
Object.defineProperty(obj, prop, { configurable: true, enumerable: true, value: value, writable: true });
return value;
};
else
Class.replaceProperty = function (obj, prop, value) {
obj.__defineGetter__(prop, function () value);
obj.__defineSetter__(prop, function (val) { value = val; });
return value;
};
Class.toString = function () "[class " + this.name + "]";
Class.replaceProperty = function (obj, prop, value) {
Object.defineProperty(obj, prop, { configurable: true, enumerable: true, value: value, writable: true });
return value;
};
Class.toString = function () "[class " + this.classname + "]";
Class.prototype = {
/**
* Initializes new instances of this class. Called automatically
@@ -525,7 +693,7 @@ Class.prototype = {
*/
init: function () {},
toString: function () "[instance " + this.constructor.name + "]",
toString: function () "[instance " + this.constructor.classname + "]",
/**
* Executes 'callback' after 'timeout' milliseconds. The value of
@@ -558,9 +726,9 @@ function Module(name, prototype) {
let init = callable(prototype) ? 4 : 3;
const module = Class.apply(Class, Array.slice(arguments, 0, init));
let instance = module();
module.name = name.toLowerCase();
module.classname = name.toLowerCase();
instance.INIT = arguments[init] || {};
currentModule[module.name] = instance;
currentModule[module.classname] = instance;
defmodule.modules.push(instance);
return module;
}
@@ -597,7 +765,7 @@ else
*/
function Struct() {
let args = Array.slice(arguments);
const Struct = Class("Struct", Struct_Base, {
const Struct = Class("Struct", StructBase, {
length: args.length,
members: args
});
@@ -607,7 +775,7 @@ function Struct() {
});
return Struct;
}
let Struct_Base = Class("StructBase", Array, {
let StructBase = Class("StructBase", Array, {
init: function () {
for (let i = 0; i < arguments.length; i++)
if (arguments[i] != undefined)
@@ -639,7 +807,7 @@ let Struct_Base = Class("StructBase", Array, {
*/
defaultValue: function (key, val) {
let i = this.prototype.members.indexOf(key);
this.prototype.__defineGetter__(i, function () (this[i] = val.call(this), this[i])); // Kludge for FF 3.0
this.prototype.__defineGetter__(i, function () (this[i] = val.call(this)));
this.prototype.__defineSetter__(i, function (value)
Class.replaceProperty(this, i, value));
}
@@ -700,10 +868,26 @@ const Timer = Class("Timer", {
}
});
/**
* Returns the UTF-8 encoded value of a string mis-encoded into
* ISO-8859-1.
*
* @param {string} str
* @returns {string}
*/
function UTF8(str) {
try {
return decodeURIComponent(escape(str))
}
catch (e) {
return str
}
}
/**
* Array utility methods.
*/
const array = Class("util.Array", Array, {
const array = Class("array", Array, {
init: function (ary) {
if (isinstance(ary, ["Iterator", "Generator"]))
ary = [k for (k in ary)];
@@ -714,23 +898,19 @@ const array = Class("util.Array", Array, {
__proto__: ary,
__iterator__: function () this.iteritems(),
__noSuchMethod__: function (meth, args) {
var res = array[meth].apply(null, [this.__proto__].concat(args));
var res = array[meth].apply(null, [this.array].concat(args));
if (isarray(res))
return array(res);
return res;
},
toString: function () this.__proto__.toString(),
concat: function () this.__proto__.concat.apply(this.__proto__, arguments),
array: ary,
toString: function () this.array.toString(),
concat: function () this.array.concat.apply(this.array, arguments),
filter: function () this.__noSuchMethod__("filter", Array.slice(arguments)),
map: function () this.__noSuchMethod__("map", Array.slice(arguments))
};
}
}, {
isinstance: function isinstance(obj) {
return Object.prototype.toString.call(obj) == "[object Array]";
},
/**
* Converts an array to an object. As in lisp, an assoc is an
* array of key-value pairs, which maps directly to an object,
@@ -834,6 +1014,6 @@ const array = Class("util.Array", Array, {
endmodule();
// catch(e){dump(e.fileName+":"+e.lineNumber+": "+e+"\n");}
// catch(e){dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack);}
// vim: set fdm=marker sw=4 ts=4 et ft=javascript:

View File

@@ -7,7 +7,7 @@
Components.utils.import("resource://dactyl/base.jsm");
defmodule("bookmarkcache", this, {
exports: ["Bookmark", "BookmarkCache", "Keyword", "bookmarkcache"],
require: ["services", "util"]
require: ["services", "storage", "util"]
});
@@ -26,11 +26,10 @@ const name = "bookmark-cache";
const BookmarkCache = Module("BookmarkCache", {
init: function init() {
bookmarks.addObserver(this, false);
},
__iterator__: function () (val for ([, val] in Iterator(self.bookmarks))),
__iterator__: function () (val for ([, val] in Iterator(this.bookmarks))),
get bookmarks() Class.replaceProperty(this, "bookmarks", this.load()),
@@ -38,9 +37,9 @@ const BookmarkCache = Module("BookmarkCache", {
.map(function (s) bookmarks[s]),
_deleteBookmark: function deleteBookmark(id) {
let length = bookmarks.length;
bookmarks = bookmarks.filter(function (item) item.id != id);
return bookmarks.length < length;
let length = this.bookmarks.length;
this.bookmarks = this.bookmarks.filter(function (item) item.id != id);
return this.bookmarks.length < length;
},
_loadBookmark: function loadBookmark(node) {
@@ -118,7 +117,7 @@ const BookmarkCache = Module("BookmarkCache", {
onItemMoved: function onItemMoved() {},
onItemAdded: function onItemAdded(itemId, folder, index) {
if (bookmarks.getItemType(itemId) == bookmarks.TYPE_BOOKMARK) {
if (self.isBookmark(itemId)) {
if (this.isBookmark(itemId)) {
let bmark = this._loadBookmark(this.readBookmark(itemId));
this.bookmarks.push(bmark);
storage.fireEvent(name, "add", bmark);

View File

@@ -8,22 +8,40 @@ Components.utils.import("resource://dactyl/base.jsm");
defmodule("highlight", this, {
exports: ["Highlight", "Highlights", "highlight"],
require: ["services", "styles"],
use: ["template"]
use: ["template", "util"]
});
const Highlight = Struct("class", "selector", "filter", "default", "value", "base");
const Highlight = Struct("class", "selector", "sites",
"default", "value", "agent",
"base", "baseClass", "style");
Highlight.liveProperty = function (name, prop) {
let i = this.prototype.members.indexOf(name);
this.prototype.__defineGetter__(name, function () this[i]);
this.prototype.__defineSetter__(name, function (val) {
this[i] = val;
this.style[prop || name] = this[prop || name];
});
}
Highlight.liveProperty("agent");
Highlight.liveProperty("value", "css");
Highlight.liveProperty("selector", "css");
Highlight.liveProperty("sites");
Highlight.liveProperty("style", "css");
Highlight.defaultValue("filter", function ()
this.base ? this.base.filter :
["chrome://dactyl/*",
"dactyl:*",
"file://*"].concat(highlight.styleableChrome).join(","));
Highlight.defaultValue("baseClass", function () /^(\w*)/.exec(this.class)[0]);
Highlight.defaultValue("selector", function () highlight.selector(this.class));
Highlight.defaultValue("sites", function ()
this.base ? this.base.sites
: ["chrome://dactyl/*", "dactyl:*", "file://*"].concat(
highlight.styleableChrome));
Highlight.defaultValue("style", function ()
styles.addSheet(true, "highlight:" + this.class, this.sites, this.css, this.agent, true));
Highlight.defaultValue("value", function () this.default);
Highlight.defaultValue("base", function () {
let base = /^(\w*)/.exec(this.class)[0];
return (base != this.class && base in highlight.highlight) ? highlight.highlight[base] : null;
});
Highlight.prototype.__defineGetter__("base", function ()
this.baseClass != this.class && highlight.highlight[this.baseClass] || null);
Highlight.prototype.__defineGetter__("css", function ()
this.selector + "{" + this.value + "}");
Highlight.prototype.toString = function ()
"Highlight(" + this.class + ")\n\t"
+ [k + ": " + String.quote(v) for ([k, v] in this)]
@@ -38,12 +56,47 @@ Highlight.prototype.toString = function ()
const Highlights = Module("Highlight", {
init: function () {
this.highlight = {};
this.loaded = {};
},
keys: function keys() Object.keys(this.highlight).sort(),
__iterator__: function () values(this.highlight),
_create: function (agent, args) {
let obj = Highlight.apply(Highlight, args);
if (!isarray(obj[2]))
obj[2] = obj[2].split(",");
obj[5] = agent;
let old = this.highlight[obj.class];
this.highlight[obj.class] = obj;
// This *must* come before any other property changes.
if (old)
obj.style = old.style;
if (/^[>+ ]/.test(obj.selector))
obj.selector = this.selector(obj.class) + obj.selector;
if (old && old.value != old.default)
obj.value = old.style;
if (!old && obj.base && obj.base.enabled)
obj.style.enabled = true;
else
this.loaded.__defineSetter__(obj.class, function () {
delete this[obj.class];
this[obj.class] = true;
if (obj.class === obj.baseClass)
for (let h in highlight)
if (h.baseClass === obj.class)
this[h.class] = true;
obj.style.enabled = true;
});
return obj;
},
get: function (k) this.highlight[k],
set: function (key, newStyle, force, append) {
let [, class_, selectors] = key.match(/^([a-zA-Z_-]+)(.*)/);
@@ -51,35 +104,40 @@ const Highlights = Module("Highlight", {
if (!(class_ in this.highlight))
return "Unknown highlight keyword: " + class_;
let style = this.highlight[key] || Highlight(key);
let highlight = this.highlight[key] || this._create(false, [key]);
if (append)
newStyle = (style.value || "").replace(/;?\s*$/, "; " + newStyle);
newStyle = (highlight.value || "").replace(/;?\s*$/, "; " + newStyle);
if (/^\s*$/.test(newStyle))
newStyle = null;
if (newStyle == null) {
if (style.default == null) {
styles.removeSheet(true, style.selector);
delete this.highlight[style.class];
if (highlight.default == null) {
highlight.style.enabled = false;
delete this.loaded[highlight.class];
delete this.highlight[highlight.class];
return null;
}
newStyle = style.default;
newStyle = highlight.default;
}
if (!style.loaded || style.value != newStyle) {
styles.removeSheet(true, style.selector);
let css = newStyle.replace(/(?:!\s*important\s*)?(?:;?\s*$|;)/g, "!important;")
.replace(";!important;", ";", "g"); // Seeming Spidermonkey bug
if (!/^\s*(?:!\s*important\s*)?;*\s*$/.test(css)) {
css = style.selector + " { " + css + " }";
highlight.value = newStyle;
if (force)
highlight.style.enabled = true;
this.highlight[highlight.class] = highlight;
return highlight;
},
styles.addSheet(true, "highlight:" + style.class, style.filter, css, true);
style.loaded = true;
}
}
style.value = newStyle;
this.highlight[style.class] = style;
return null;
/**
* Highlights a node with the given group, and ensures that said
* group is loaded.
*
* @param {Node} node
* @param {string} group
*/
highlightNode: function (node, group) {
node.setAttributeNS(NS.uri, "highlight", group);
for each (let h in group.split(" "))
this.loaded[h] = true;
},
/**
@@ -104,30 +162,69 @@ const Highlights = Module("Highlight", {
this.set(k, null, true);
},
groupRegexp: RegExp(String.replace(<![CDATA[
^
(\s* (?:\S|\s\S)+ \s+)
\{ ([^}]*) \}
\s*
$
]]>, /\s*/g, ""), "gm"),
sheetRegexp: RegExp(String.replace(<![CDATA[
^\s*
!? \*?
( (?:[^;\s]|\s\S)+ )
(?:; ( (?:[^;\s]|\s\S)+ )? )?
(?:; ( (?:[^ \s]|\s\S)+ ) )?
\s* (.*)
$
]]>, /\s*/g, "")),
/**
* Bulk loads new CSS rules.
* Bulk loads new CSS rules, in the format of,
*
* Rules ::= Rule | Rule "\n" Rule
* Rule ::= Bang? Star? MatchSpec Space Space* Css
* | Comment
* Comment ::= Space* "//" *
* Bang ::= "!"
* Star ::= "*"
* MatchSpec ::= Class
* | Class ";" Selector
* | Class ";" Selector ";" Sites
* CSS ::= CSSLine | "{" CSSLines "}"
* CSSLines ::= CSSLine | CSSLine "\n" CSSLines
*
* Where Class is the name of the sheet, Selector is the CSS
* selector for the style, Site is the comma-separated list of site
* filters to apply the style to.
*
* If Selector is not provided, it defaults to [dactyl|highlight~={Class}].
* If it is provided and begins with any of "+", ">" or " ", it is
* appended to the default.
*
* If Sites is not provided, it defaults to the chrome documents of
* the main application window, dactyl help files, and any other
* dactyl-specific documents.
*
* If Star is provided, the style is applied as an agent sheet.
*
* The new styles are lazily activated unless Bang or 'eager' is
* provided. See {@link Util#xmlToDom}.
*
* @param {string} css The rules to load. See {@link Highlights#css}.
* @param {boolean} eager When true, load all provided rules immediately.
*/
loadCSS: function (css) {
css.replace(/^(\s*\S*\s+)\{((?:.|\n)*?)\}\s*$/gm, function (_, _1, _2) _1 + " " + _2.replace(/\n\s*/g, " "))
.split("\n").filter(function (s) /\S/.test(s))
.forEach(function (style) {
style = Highlight.apply(Highlight,
Array.slice(style.match(/^\s*((?:[^,\s]|\s\S)+)(?:,((?:[^,\s]|\s\S)+)?)?(?:,((?:[^,\s]|\s\S)+))?\s*(.*)$/),
1));
if (/^[>+ ]/.test(style.selector))
style.selector = this.selector(style.class) + style.selector;
loadCSS: function (css, eager) {
String.replace(css, this.groupRegexp, function (m, m1, m2) m1 + " " + m2.replace(/\n\s*/g, " "))
.split("\n").filter(function (s) /\S/.test(s) && !/^\s*\/\//.test(s))
.forEach(function (highlight) {
let old = this.highlight[style.class];
if (!old)
this.highlight[style.class] = style;
else if (old.value == old.default)
old.value = style.value;
}, this);
for (let [class_, hl] in Iterator(this.highlight))
if (hl.value == hl.default)
this.set(class_);
let bang = eager || /^\s*!/.test(highlight);
let star = /^\s*!?\*/.test(highlight);
highlight = this._create(star, this.sheetRegexp.exec(highlight).slice(1));
if (bang)
highlight.style.enabled = true;
}, this);
}
}, {
}, {
@@ -181,11 +278,8 @@ const Highlights = Module("Highlight", {
if (!key || h.class.indexOf(key) > -1))));
else if (!key && clear)
highlight.clear();
else {
let error = highlight.set(key, css, clear, "-append" in args);
if (error)
dactyl.echoerr(error);
}
else
highlight.set(key, css, clear, "-append" in args);
},
{
// TODO: add this as a standard highlight completion function?
@@ -221,7 +315,7 @@ const Highlights = Module("Highlight", {
completion.colorScheme = function colorScheme(context) {
context.title = ["Color Scheme", "Runtime Path"];
context.keys = { text: function (f) f.leafName.replace(/\.vimp$/, ""), description: ".parent.path" };
context.completions = util.Array.flatten(
context.completions = array.flatten(
modules.io.getRuntimeDirectories("colors").map(
function (dir) dir.readDirectory().filter(
function (file) /\.vimp$/.test(file.leafName))))
@@ -232,6 +326,12 @@ const Highlights = Module("Highlight", {
context.title = ["Highlight Group", "Value"];
context.completions = [[v.class, v.value] for (v in highlight)];
};
},
javascript: function (dactyl, modules, window) {
modules.JavaScript.setCompleter(["get", "set"].map(function (m) highlight[m]),
[ function (context, obj, args) Iterator(highlight.highlight) ]);
modules.JavaScript.setCompleter(["highlightNode"].map(function (m) highlight[m]),
[ null, function (context, obj, args) Iterator(highlight.highlight) ]);
}
});

View File

@@ -69,7 +69,7 @@ const Sanitizer = Module("sanitizer", tmp.Sanitizer, {
services.get("permissions").remove(util.createURI(p.host), p.type);
services.get("permissions").add(util.createURI(p.host), p.type, 0);
}
for (let p in iter(services.get("contentprefs").getPrefs(util.createURI(host)).enumerator))
for (let p in iter(services.get("contentprefs").getPrefs(util.createURI(host))))
services.get("contentprefs").removePref(util.createURI(host), p.QueryInterface(Ci.nsIProperty).name);
}
else {
@@ -185,12 +185,12 @@ const Sanitizer = Module("sanitizer", tmp.Sanitizer, {
prefToArg: function (pref) pref.replace(/.*\./, "").toLowerCase(),
iterCookies: function iterCookies(host) {
for (let c in iter(services.get("cookies").enumerator))
for (let c in iter(services.get("cookies")))
if (!host || util.isSubdomain(c.QueryInterface(Ci.nsICookie2).rawHost, host))
yield c;
},
iterPermissions: function iterPermissions(host) {
for (let p in iter(services.get("permissions").enumerator))
for (let p in iter(services.get("permissions")))
if (p.QueryInterface(Ci.nsIPermission) && (!host || util.isSubdomain(p.host, host)))
yield p;
}

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
// Copyright (c) 2008-2020 by Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
@@ -9,6 +9,9 @@ defmodule("services", this, {
exports: ["Services", "services"]
});
/**
* A lazily-instantiated XPCOM class and service cache.
*/
const Services = Module("Services", {
init: function () {
this.classes = {};
@@ -33,12 +36,13 @@ const Services = Module("Services", {
this.add("json", "@mozilla.org/dom/json;1", Ci.nsIJSON, "createInstance");
this.add("livemark", "@mozilla.org/browser/livemark-service;2", Ci.nsILivemarkService);
this.add("observer", "@mozilla.org/observer-service;1", Ci.nsIObserverService);
this.add("pref", "@mozilla.org/preferences-service;1", [Ci.nsIPrefBranch, Ci.nsIPrefBranch2, Ci.nsIPrefService]);
this.add("pref", "@mozilla.org/preferences-service;1", [Ci.nsIPrefBranch2, Ci.nsIPrefService]);
this.add("privateBrowsing", "@mozilla.org/privatebrowsing;1", Ci.nsIPrivateBrowsingService);
this.add("profile", "@mozilla.org/toolkit/profile-service;1", Ci.nsIToolkitProfileService);
this.add("runtime", "@mozilla.org/xre/runtime;1", [Ci.nsIXULAppInfo, Ci.nsIXULRuntime]);
this.add("rdf", "@mozilla.org/rdf/rdf-service;1", Ci.nsIRDFService);
this.add("sessionStore", "@mozilla.org/browser/sessionstore;1", Ci.nsISessionStore);
this.add("stringBundle", "@mozilla.org/intl/stringbundle;1", Ci.nsIStringBundleService);
this.add("stylesheet", "@mozilla.org/content/style-sheet-service;1", Ci.nsIStyleSheetService);
this.add("subscriptLoader", "@mozilla.org/moz/jssubscript-loader;1", Ci.mozIJSSubScriptLoader);
this.add("tagging", "@mozilla.org/browser/tagging-service;1", Ci.nsITaggingService);
@@ -103,19 +107,19 @@ const Services = Module("Services", {
return this.classes[name] = function () self._create(class_, ifaces, "createInstance");
},
/**
* Returns a new instance of the cached class with the specified name.
*
* @param {string} name The class's cache key.
*/
create: function (name) this.classes[name](),
/**
* Returns the cached service with the specified name.
*
* @param {string} name The service's cache key.
*/
get: function (name) this.services[name],
/**
* Returns a new instance of the cached class with the specified name.
*
* @param {string} name The class's cache key.
*/
create: function (name) this.classes[name]()
}, {
}, {
init: function (dactyl, modules) {

View File

@@ -1,24 +1,7 @@
/***** BEGIN LICENSE BLOCK ***** {{{
Copyright ©2008-2009 by Kris Maglione <maglione.k at Gmail>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
}}} ***** END LICENSE BLOCK *****/
// Copyright (c) 2008-2010 by Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
"use strict";
const myObject = Object;
@@ -98,38 +81,6 @@ const StoreBase = Class("StoreBase", {
save: function () { savePref(this); },
});
const ObjectStore = Class("ObjectStore", StoreBase, {
_constructor: myObject,
clear: function () {
this._object = {};
this.fireEvent("clear");
},
get: function get(key, default_) key in this._object ? this._object[key] : this.set(key, default_),
keys: function keys() Object.keys(this._object),
remove: function remove(key) {
var ret = this._object[key];
delete this._object[key];
this.fireEvent("remove", key);
},
set: function set(key, val) {
var defined = key in this._object;
var orig = this._object[key];
this._object[key] = val;
if (!defined)
this.fireEvent("add", key);
else if (orig != val)
this.fireEvent("change", key);
return val;
},
__iterator__: function () Iterator(this._object),
});
const ArrayStore = Class("ArrayStore", StoreBase, {
_constructor: Array,
@@ -176,12 +127,51 @@ const ArrayStore = Class("ArrayStore", StoreBase, {
__iterator__: function () Iterator(this._object),
});
const ObjectStore = Class("ObjectStore", StoreBase, {
_constructor: myObject,
clear: function () {
this._object = {};
this.fireEvent("clear");
},
get: function get(key, default_)
key in this._object ? this._object[key] :
arguments.length > 1 ? this.set(key, default_) :
undefined,
keys: function keys() Object.keys(this._object),
remove: function remove(key) {
var ret = this._object[key];
delete this._object[key];
this.fireEvent("remove", key);
},
set: function set(key, val) {
var defined = key in this._object;
var orig = this._object[key];
this._object[key] = val;
if (!defined)
this.fireEvent("add", key);
else if (orig != val)
this.fireEvent("change", key);
return val;
},
__iterator__: function () Iterator(this._object),
});
var keys = {};
var observers = {};
const Storage = Module("Storage", {
alwaysReload: {},
newObject: function newObject(key, constructor, params) {
if (params == null || !isobject(params))
throw Error("Invalid argument type");
if (!(key in keys) || params.reload || this.alwaysReload[key]) {
if (key in this && !(params.reload || this.alwaysReload[key]))
throw Error();
@@ -198,7 +188,7 @@ const Storage = Module("Storage", {
},
newArray: function newArray(key, options) {
return this.newObject(key, ArrayStore, { type: Array, __proto__: options });
return this.newObject(key, ArrayStore, update({ type: Array }, options));
},
addObserver: function addObserver(key, callback, ref) {
@@ -295,7 +285,7 @@ const File = Class("File", {
let file = services.create("file");
if (path instanceof Ci.nsIFile)
file = path;
file = path.QueryInterface(Ci.nsIFile);
else if (/file:\/\//.test(path))
file = services.create("file:").getFileFromURLSpec(path);
else {
@@ -317,9 +307,8 @@ const File = Class("File", {
iterDirectory: function () {
if (!this.isDirectory())
throw Error("Not a directory");
let entries = this.directoryEntries;
while (entries.hasMoreElements())
yield File(entries.getNext().QueryInterface(Ci.nsIFile));
for (let file in iter(this.directoryEntries))
yield File(file);
},
/**
@@ -409,6 +398,8 @@ const File = Class("File", {
if (!perms)
perms = parseInt('0644', 8);
if (!this.exists()) // OCREAT won't creat the directory
this.create(this.NORMAL_FILE_TYPE, perms);
ofstream.init(this, mode, perms, 0);
let ocstream = getStream(0);
@@ -567,8 +558,8 @@ const File = Class("File", {
replacePathSep: function (path) path.replace("/", File.PATH_SEP, "g")
});
// catch(e){dump(e.fileName+":"+e.lineNumber+": "+e+"\n");}
endmodule();
// catch(e){dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack);}
// vim: set fdm=marker sw=4 sts=4 et ft=javascript:

View File

@@ -7,7 +7,8 @@
Components.utils.import("resource://dactyl/base.jsm");
defmodule("styles", this, {
exports: ["Style", "Styles", "styles"],
require: ["services", "util"]
require: ["services", "util"],
use: ["template"]
});
const sss = services.get("stylesheet");
@@ -17,6 +18,35 @@ const namespace = "@namespace html " + XHTML.uri.quote() + ";\n" +
"@namespace dactyl " + NS.uri.quote() + ";\n";
const Sheet = Struct("name", "id", "sites", "css", "system", "agent");
Sheet.liveProperty = function (name) {
let i = this.prototype.members.indexOf(name);
this.prototype.__defineGetter__(name, function () this[i]);
this.prototype.__defineSetter__(name, function (val) {
this[i] = val;
this.enabled = this.enabled;
});
}
Sheet.liveProperty("agent");
Sheet.liveProperty("css");
Sheet.liveProperty("sites");
Sheet.prototype.__defineGetter__("uri", function () cssUri(this.fullCSS));
Sheet.prototype.__defineGetter__("enabled", function () this._enabled);
Sheet.prototype.__defineSetter__("enabled", function (on) {
if (on != this._enabled || this.uri != this._uri) {
if (on)
this.enabled = false;
else if (!this._uri)
return;
let meth = on ? "registerSheet" : "unregisterSheet";
styles[meth](on ? this.uri : this._uri,
on ? this.agent : this._agent);
this._agent = this.agent;
this._enabled = Boolean(on);
this._uri = this.uri;
}
});
Sheet.prototype.__defineGetter__("fullCSS", function wrapCSS() {
let filter = this.sites;
let css = this.css;
@@ -29,23 +59,8 @@ Sheet.prototype.__defineGetter__("fullCSS", function wrapCSS() {
: "domain")
+ '("' + part.replace(/"/g, "%22").replace(/\*$/, "") + '")')
.join(", ");
return "/* Dactyl style #" + this.id + " */ " + namespace + " @-moz-document " + selectors + "{\n" + css + "\n}\n";
});
Sheet.prototype.__defineGetter__("css", function () this[3]);
Sheet.prototype.__defineSetter__("css", function (val) {
this.enabled = false;
this[3] = val;
this.enabled = true;
return val;
});
Sheet.prototype.__defineGetter__("enabled", function () this._enabled);
Sheet.prototype.__defineSetter__("enabled", function (on) {
this._enabled = Boolean(on);
let meth = on ? "registerSheet" : "unregisterSheet";
styles[meth](cssUri(this.fullCSS));
if (this.agent)
styles[meth](cssUri(this.fullCSS), true);
return "/* Dactyl style #" + this.id + (this.agent ? " (agent)" : "") + " */ "
+ namespace + " @-moz-document " + selectors + "{\n" + css + "\n}\n";
});
/**
@@ -64,7 +79,7 @@ const Styles = Module("Styles", {
this.systemNames = {};
},
get sites() array(this.userSheets).map(function (s) s.sites).flatten().uniq().__proto__,
get sites() array(this.userSheets).map(function (s) s.sites).flatten().uniq().array,
__iterator__: function () Iterator(this.userSheets.concat(this.systemSheets)),
@@ -81,25 +96,27 @@ const Styles = Module("Styles", {
* "*" is matched as a prefix.
* @param {string} css The CSS to be applied.
*/
addSheet: function addSheet(system, name, filter, css, agent) {
addSheet: function addSheet(system, name, filter, css, agent, lazy) {
let sheets = system ? this.systemSheets : this.userSheets;
let names = system ? this.systemNames : this.userNames;
if (name && name in names)
this.removeSheet(system, name);
let sheet = Sheet(name, this._id++, filter.split(",").filter(util.identity), String(css), null, system, agent);
if (!isarray(filter))
filter = filter.split(",");
if (name && name in names) {
var sheet = names[name];
sheet.filter = filter;
sheet.css = String(css);
}
else
sheet = Sheet(name, this._id++, filter.filter(util.identity), String(css), system, agent);
try {
if (!lazy)
sheet.enabled = true;
}
catch (e) {
return e.echoerr || e;
}
sheets.push(sheet);
if (name)
names[name] = sheet;
return null;
return sheet;
},
/**
@@ -129,14 +146,13 @@ const Styles = Module("Styles", {
*/
findSheets: function findSheets(system, name, filter, css, index) {
let sheets = system ? this.systemSheets : this.userSheets;
let names = system ? this.systemNames : this.userNames;
// Grossly inefficient.
let matches = [k for ([k, v] in Iterator(sheets))];
if (index)
matches = String(index).split(",").filter(function (i) i in sheets);
if (name)
matches = matches.filter(function (i) sheets[i] == names[name]);
matches = matches.filter(function (i) sheets[i].name == name);
if (css)
matches = matches.filter(function (i) sheets[i].css == css);
if (filter)
@@ -178,18 +194,18 @@ const Styles = Module("Styles", {
return null;
for (let [, sheet] in Iterator(matches.reverse())) {
sheet.enabled = false;
if (name)
delete names[name];
if (sheets.indexOf(sheet) > -1)
sheets.splice(sheets.indexOf(sheet), 1);
/* Re-add if we're only changing the site filter. */
if (filter) {
let sites = sheet.sites.filter(function (f) f != filter);
if (sites.length)
this.addSheet(system, name, sites.join(","), css, sheet.agent);
if (sites.length) {
sheet.sites = sites;
continue;
}
}
sheet.enabled = false;
if (sheet.name)
delete names[sheet.name];
if (sheets.indexOf(sheet) > -1)
sheets.splice(sheets.indexOf(sheet), 1);
}
return matches.length;
},
@@ -256,7 +272,7 @@ const Styles = Module("Styles", {
["min-width: 1em; text-align: center; color: red; font-weight: bold;",
"padding: 0 1em 0 1ex; vertical-align: top;",
"padding: 0 1em 0 0; vertical-align: top;"],
([sheet.enabled ? "" : "\u00d7",
([sheet.enabled ? "" : UTF8("×"),
key,
sheet.sites.join(","),
sheet.css]
@@ -271,9 +287,7 @@ const Styles = Module("Styles", {
css = sheet.css + " " + css;
}
}
let err = styles.addSheet(false, name, filter, css);
if (err)
dactyl.echoerr(err);
styles.addSheet(false, name, filter, css);
}
},
{
@@ -377,4 +391,6 @@ const Styles = Module("Styles", {
endmodule();
// catch(e){dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack);}
// vim:se fdm=marker sw=4 ts=4 et ft=javascript:

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k at Gmail>
// Copyright (c) 2008-2010 by Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
@@ -40,6 +40,8 @@ const Template = Module("Template", {
if (typeof xml == "xml")
return xml;
try {
XML.ignoreWhitespace = false;
XML.prettyPrinting = false;
return new XMLList(xml);
}
catch (e) {}
@@ -48,7 +50,7 @@ const Template = Module("Template", {
bookmarkDescription: function (item, text)
<>
<a href={item.item.url} highlight="URL">{text}</a>&#160;
<a href={item.item.url} highlight="URL">{text || ""}</a>&#xa0;
{
!(item.extra && item.extra.length) ? "" :
<span class="extra-info">
@@ -72,8 +74,8 @@ const Template = Module("Template", {
var desc = item[1] || "";
}
else {
var text = this.process[0].call(this, item, item.text);
var desc = this.process[1].call(this, item, item.description);
var text = this.processor[0].call(this, item, item.result);
var desc = this.processor[1].call(this, item, item.description);
}
// <e4x>
@@ -82,8 +84,8 @@ const Template = Module("Template", {
- from pushing the baseline down and enlarging
- the row.
-->
<li highlight="CompResult">{text}&#160;</li>
<li highlight="CompDesc">{desc}&#160;</li>
<li highlight="CompResult">{text}&#xa0;</li>
<li highlight="CompDesc">{desc}&#xa0;</li>
</div>;
// </e4x>
},

View File

@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2009 by Doug Kearns <dougkearns@gmail.com>
// Copyright (c) 2008-2009 by Kris Maglione <maglione.k@gmail.com>
// Copyright (c) 2008-2010 by Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
@@ -10,7 +10,7 @@ Components.utils.import("resource://dactyl/base.jsm");
defmodule("util", this, {
exports: ["Math", "NS", "Util", "XHTML", "XUL", "util"],
require: ["services"],
use: ["template"]
use: ["highlight", "template"]
});
const XHTML = Namespace("html", "http://www.w3.org/1999/xhtml");
@@ -206,7 +206,7 @@ const Util = Module("Util", {
function rec(acc) {
if (acc.length == patterns.length)
res.push(array(substrings).zip(acc).flatten().join(""));
else
else
for (let [, pattern] in Iterator(patterns[acc.length]))
rec(acc.concat(pattern));
}
@@ -295,12 +295,12 @@ const Util = Module("Util", {
null
);
return {
__proto__: result,
__iterator__: asIterator
? function () { let elem; while ((elem = this.iterateNext())) yield elem; }
: function () { for (let i = 0; i < this.snapshotLength; i++) yield this.snapshotItem(i); }
}
return Object.create(result, {
__iterator__: {
value: asIterator ? function () { let elem; while ((elem = this.iterateNext())) yield elem; }
: function () { for (let i = 0; i < this.snapshotLength; i++) yield this.snapshotItem(i); }
}
});
},
extend: function extend(dest) {
@@ -388,18 +388,17 @@ const Util = Module("Util", {
try {
let xmlhttp = services.create("xmlhttp");
xmlhttp.mozBackgroundRequest = true;
if (callback) {
if (callback)
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4)
callback(xmlhttp);
};
}
xmlhttp.open("GET", url, !!callback);
xmlhttp.send(null);
return xmlhttp;
}
catch (e) {
util.dactyl.log("Error opening " + String.quote(url) + ": " + e, 1);
util.dactyl.log("Error opening " + String.quote(url) + ": " + e, 1);
return null;
}
},
@@ -460,9 +459,9 @@ const Util = Module("Util", {
* @returns {string}
*/
makeXPath: function makeXPath(nodes) {
return util.Array(nodes).map(util.debrace).flatten()
.map(function (node) [node, "xhtml:" + node]).flatten()
.map(function (node) "//" + node).join(" | ");
return array(nodes).map(util.debrace).flatten()
.map(function (node) [node, "xhtml:" + node]).flatten()
.map(function (node) "//" + node).join(" | ");
},
/**
@@ -480,18 +479,6 @@ const Util = Module("Util", {
return ary;
},
/**
* Memoize the lookup of a property in an object.
*
* @param {object} obj The object to alter.
* @param {string} key The name of the property to memoize.
* @param {function} getter A function of zero to two arguments which
* will return the property's value. <b>obj</b> is
* passed as the first argument, <b>key</b> as the
* second.
*/
memoize: memoize,
newThread: function () services.get("threadManager").newThread(0),
/**
@@ -524,34 +511,47 @@ const Util = Module("Util", {
if (object === null)
return "null\n";
if (typeof object != "object")
if (typeof object !== "object")
return false;
const NAMESPACES = util.Array.toObject([
[NS, 'dactyl'],
[XHTML, 'html'],
[XUL, 'xul']
]);
if (object instanceof Ci.nsIDOMElement) {
const NAMESPACES = array.toObject([
[NS, "dactyl"],
[XHTML, "html"],
[XUL, "xul"]
]);
let elem = object;
if (elem.nodeType == elem.TEXT_NODE)
return elem.data;
function namespaced(node) {
var ns = NAMESPACES[node.namespaceURI];
if (ns)
return ns + ":" + node.localName;
return node.localName.toLowerCase();
var ns = NAMESPACES[node.namespaceURI] || /^(?:(.*?):)?/.exec(node.name)[0];
if (!ns)
return node.localName;
if (color)
return <><span highlight="HelpXMLNamespace">{ns}</span>{node.localName}</>
return ns + ":" + node.localName;
}
try {
let hasChildren = elem.firstChild && (!/^\s*$/.test(elem.firstChild) || elem.firstChild.nextSibling)
if (color)
return <span highlight="HelpXMLBlock"><span highlight="HelpXMLTagStart">&lt;{
namespaced(elem)} {
template.map(array.itervalues(elem.attributes),
function (attr)
<span highlight="HelpXMLAttribute">{namespaced(attr)}</span> +
<span highlight="HelpXMLString">{attr.value}</span>,
<> </>)
}{ hasChildren ? "/>" : ">"
}</span>{ !hasChildren ? "" :
<>...</> +
<span highlight="HtmlTagEnd">&lt;{namespaced(elem)}></span>
}</span>;
let tag = "<" + [namespaced(elem)].concat(
[namespaced(a) + "=" + template.highlight(a.value, true)
for ([i, a] in util.Array.iteritems(elem.attributes))]).join(" ");
if (!elem.firstChild || /^\s*$/.test(elem.firstChild) && !elem.firstChild.nextSibling)
tag += '/>';
else
tag += '>...</' + namespaced(elem) + '>';
return tag;
for ([i, a] in array.iteritems(elem.attributes))]).join(" ");
return tag + (hasChildren ? "/>" : ">...</" + namespaced(elem) + ">");
}
catch (e) {
return {}.toString.call(elem);
@@ -562,13 +562,15 @@ const Util = Module("Util", {
var obj = String(object);
}
catch (e) {
obj = "[Object]";
obj = Object.prototype.toString.call(obj);
}
obj = template.highlightFilter(util.clip(obj, 150), "\n", !color ? function () "^J" : function () <span highlight="NonText">^J</span>);
let string = <><span highlight="Title Object">{obj}</span>::<br/>&#xa;</>;
let string = <><span highlight="Title Object">{obj}</span>::<br/>&#x0a;</>;
let keys = [];
try { // window.content often does not want to be queried with "var i in object"
// window.content often does not want to be queried with "var i in object"
try {
let hasValue = !("__iterator__" in object || isinstance(object, ["Generator", "Iterator"]));
if (object.dactyl && object.modules && object.modules.modules == object.modules) {
object = Iterator(object);
@@ -593,7 +595,7 @@ const Util = Module("Util", {
i = parseInt(i);
else if (/^[A-Z_]+$/.test(i))
i = "";
keys.push([i, <>{key}{noVal ? "" : <>: {value}</>}<br/>&#xa;</>]);
keys.push([i, <>{key}{noVal ? "" : <>: {value}</>}<br/>&#x0a;</>]);
}
}
catch (e) {}
@@ -672,7 +674,6 @@ const Util = Module("Util", {
selectionController: function (win)
win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsISelectionDisplay)
.QueryInterface(Ci.nsISelectionController),
@@ -714,6 +715,7 @@ const Util = Module("Util", {
* string.
*
* util.split("a, b, c, d, e", /, /, 3) -> ["a", "b", "c, d, e"]
*
* @param {string} str The string to split.
* @param {RegExp|string} re The regular expression on which to split the string.
* @param {number} limit The maximum number of elements to return.
@@ -775,7 +777,9 @@ const Util = Module("Util", {
},
/**
* Converts an E4X XML literal to a DOM node.
* Converts an E4X XML literal to a DOM node. Any attribute named
* highlight is present, it is transformed into dactyl:highlight,
* and the named highlight groups are guaranteed to be loaded.
*
* @param {Node} node
* @param {Document} doc
@@ -797,7 +801,14 @@ const Util = Module("Util", {
case "element":
let domnode = doc.createElementNS(node.namespace(), node.localName());
for each (let attr in node.@*)
domnode.setAttributeNS(attr.name() == "highlight" ? NS.uri : attr.namespace(), attr.name(), String(attr));
if (attr.name() != "highlight")
domnode.setAttributeNS(attr.namespace(), attr.name(), String(attr));
else {
domnode.setAttributeNS(NS.uri, "highlight", String(attr));
for each (let h in String.split(attr, " "))
highlight.loaded[h] = true;
}
for each (let child in node.*)
domnode.appendChild(xmlToDom(child, doc, nodes));
if (nodes && node.@key)
@@ -816,9 +827,7 @@ const Util = Module("Util", {
* @singleton
*/
const GlobalMath = Math;
var Math = {
__proto__: GlobalMath,
var Math = update(Object.create(GlobalMath), {
/**
* Returns the specified <b>value</b> constrained to the range <b>min</b> -
* <b>max</b>.
@@ -829,9 +838,9 @@ var Math = {
* @returns {number}
*/
constrain: function constrain(value, min, max) Math.min(Math.max(min, value), max)
};
});
// catch(e){dump(e.fileName+":"+e.lineNumber+": "+e+"\n");}
// catch(e){dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack);}
endmodule();