diff options
author | Kris Maglione <maglione.k@gmail.com> | 2011-02-17 15:23:17 -0500 |
---|---|---|
committer | Kris Maglione <maglione.k@gmail.com> | 2011-02-17 15:23:17 -0500 |
commit | a54573522acb5afcdaacf370ec19aec2d858d236 (patch) | |
tree | 82372893e3b0da8d03de61f421e0bdaac4982069 /common | |
parent | 589849c06d4a7b6751f685a38debf3d7f882c619 (diff) | |
download | pentadactyl-a54573522acb5afcdaacf370ec19aec2d858d236.tar.gz |
Replace XPath-based hint paths with CSS selectors. Needs cleanup and validation.
--HG--
extra : rebase_source : 83035481bf697b7b57e17e516b0dfc61329164c6
Diffstat (limited to 'common')
-rw-r--r-- | common/content/dactyl.js | 3 | ||||
-rw-r--r-- | common/content/help.xsl | 4 | ||||
-rw-r--r-- | common/content/hints.js | 71 | ||||
-rw-r--r-- | common/locale/en-US/options.xml | 50 | ||||
-rw-r--r-- | common/modules/io.jsm | 3 | ||||
-rw-r--r-- | common/modules/options.jsm | 50 | ||||
-rw-r--r-- | common/modules/util.jsm | 20 |
7 files changed, 129 insertions, 72 deletions
diff --git a/common/content/dactyl.js b/common/content/dactyl.js index 763e07d5..cfca1372 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -1382,6 +1382,9 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { dactyl.echoerr(template.linkifyHelp(error.message)); else dactyl.beep(); + + if (!error.noTrace) + util.reportError(error); return; } if (error.result == Cr.NS_BINDING_ABORTED) diff --git a/common/content/help.xsl b/common/content/help.xsl index ac166064..0f5ae9b5 100644 --- a/common/content/help.xsl +++ b/common/content/help.xsl @@ -231,7 +231,9 @@ <xsl:template match="dactyl:default[not(@type='plain')]" mode="help-2"> <xsl:variable name="type" select="preceding-sibling::dactyl:type[1] | following-sibling::dactyl:type[1]"/> - <span dactyl:highlight="HelpDefault">(default:<xsl:text> </xsl:text> + <span dactyl:highlight="HelpDefault"> + <xsl:copy-of select="@*"/> + <xsl:text>(default: </xsl:text> <xsl:choose> <xsl:when test="$type = 'string'"> <span dactyl:highlight="HelpString" delim="'"><xsl:apply-templates mode="help-1"/></span> diff --git a/common/content/hints.js b/common/content/hints.js index a473e6c9..9538f4fe 100644 --- a/common/content/hints.js +++ b/common/content/hints.js @@ -271,7 +271,7 @@ var HintSession = Class("HintSession", CommandMode, { return true; } - let body = doc.body || util.evaluateXPath(["body"], doc).snapshotItem(0); + let body = doc.body || doc.querySelector("body"); if (body) { let fragment = util.xmlToDom(<div highlight="hints"/>, doc); body.appendChild(fragment); @@ -281,7 +281,7 @@ var HintSession = Class("HintSession", CommandMode, { let baseNodeAbsolute = util.xmlToDom(<span highlight="Hint" style="display: none"/>, doc); let mode = this.hintMode; - let res = util.evaluateXPath(mode.xpath, doc, true); + let res = mode.matcher(doc); let start = this.pageHints.length; for (let elem in res) { @@ -670,6 +670,29 @@ var HintSession = Class("HintSession", CommandMode, { }, }); +function compileMatcher(list) { + let xpath = [], css = []; + for (let elem in values(list)) + if (/^xpath:/.test(elem)) + xpath.push(elem.substr(6)); + else + css.push(elem); + + return update( + function matcher(node) { + if (matcher.xpath) + for (let elem in util.evaluateXPath(matcher.xpath, node)) + yield elem; + + if (matcher.css) + for (let [, elem] in iter(node.querySelectorAll(matcher.css))) + yield elem; + }, { + css: css.join(", "), + xpath: xpath.join(" | ") + }); +} + var Hints = Module("hints", { init: function init() { this.resizeTimer = Timer(100, 500, function () { @@ -682,8 +705,8 @@ var Hints = Module("hints", { events.listen(appContent, "scroll", this.resizeTimer.closure.tell, false); const Mode = Hints.Mode; - Mode.defaultValue("tags", function () function () options["hinttags"]); - Mode.prototype.__defineGetter__("xpath", function () + Mode.defaultValue("tags", function () function () options.get("hinttags").matcher); + Mode.prototype.__defineGetter__("matcher", function () options.get("extendedhinttags").getKey(this.name, this.tags())); this.modes = {}; @@ -1162,23 +1185,41 @@ var Hints = Module("hints", { }, options: function () { function xpath(arg) util.makeXPath(arg); + options.add(["extendedhinttags", "eht"], - "XPath strings of hintable elements for extended hint modes", + "XPath or CSS selector strings of hintable elements for extended hint modes", "regexpmap", { - "[iI]": xpath(["img"]), - "[asOTivVWy]": xpath(["{a,area}[@href]", "{img,iframe}[@src]"]), - "[f]": xpath(["body"]), - "[F]": xpath(["body", "code", "div", "html", "p", "pre", "span"]), - "[S]": xpath(["input[not(@type='hidden')]", "textarea", "button", "select"]) + "[iI]": "img", + "[asOTivVWy]": ["a[href]", "area[href]", "img[src]", "iframe[src]"], + "[f]": "body", + "[F]": ["body", "code", "div", "html", "p", "pre", "span"], + "[S]": ["input:not([type=hidden])", "textarea", "button", "select"] }, - { validator: Option.validateXPath }); + { + keepQuotes: true, + getKey: function (val, default_) + let (res = array.nth(this.value, function (re) re.test(val), 0)) + res ? res.matcher : default_, + setter: function (vals) { + for (let value in values(vals)) + value.matcher = compileMatcher(Option.splitList(value.result)); + return vals; + }, + validator: Option.validateXPath + }); options.add(["hinttags", "ht"], "XPath string of hintable elements activated by 'f' and 'F'", - "string", xpath(["input[not(@type='hidden')]", "a", "area", "iframe", "textarea", "button", "select", - "*[@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or " + - "@tabindex or @role='link' or @role='button']"]), - { validator: Option.validateXPath }); + "stringlist", "input:not([type=hidden]),a,area,iframe,textarea,button,select," + + "[onclick],[onmouseover],[onmousedown],[onmouseup],[oncommand]," + + "[tabindex],[role=link],[role=button]", + { + setter: function (values) { + this.matcher = compileMatcher(values); + return values; + }, + validator: Option.validateXPath + }); options.add(["hintkeys", "hk"], "The keys used to label and select hints", diff --git a/common/locale/en-US/options.xml b/common/locale/en-US/options.xml index 5e98816e..9247a5c2 100644 --- a/common/locale/en-US/options.xml +++ b/common/locale/en-US/options.xml @@ -1,14 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="dactyl://content/help.xsl"?> -<!DOCTYPE document SYSTEM "dactyl://content/dtd" [ - <!ENTITY hinttags "//*[@onclick or @onmouseover or @onmousedown or - @onmouseup or @oncommand or @role='link'] | - //input[not(@type='hidden')] | //xhtml:input[not(@type='hidden')] | - //a | //xhtml:a | //area | //xhtml:area | - //button | //xhtml:button | //iframe | //xhtml:iframe | - //select | //xhtml:select | //textarea | //xhtml:textarea"> -]> +<!DOCTYPE document SYSTEM "dactyl://content/dtd"> <document name="options" @@ -631,26 +624,19 @@ <item> <tags>'eht' 'extendedhinttags'</tags> - <spec>'extendedhinttags' 'eht'</spec> <strut/> + <spec>'extendedhinttags'</spec> <type>regexpmap</type> - <default>[iI]:'//img | //xhtml:img', - [OTivVWy]:'//a[@href] | //xhtml:a[@href] | - //area[@href] | //xhtml:area[@href] | - //img[@src] | //xhtml:img[@src] | - //iframe[@src] | //xhtml:iframe[@src]', - [F]:'//div | //xhtml:div | //span | //xhtml:span | - //p | //xhtml:p | //body | //xhtml:body | - //html | //xhtml:html' - [S]:'//input[not(@type=''hidden'')] | - //xhtml:input[not(@type=''hidden'')] | - //textarea | //xhtml:textarea | - //button | //xhtml:button | - //select | //xhtml:select'</default> - <description> - <p> - Defines specialized XPath expressions for arbitrary - <t>extended-hints</t> modes. If no matches are found, the value of + <default style="display: block;">[asOTivVWy]:a[href],area[href],img[src],iframe[src], + [f]:body, + [F]:body,code,div,html,p,pre,span, + [iI]:img, + [S]:button,'input:not([type=hidden])',select,textarea</default> + <description> + <p> + Defines specialized CSS selectors or XPath expressions for arbitrary + <t>extended-hints</t> modes. The syntax is the same as for + <o>hinttags</o>. If no matches are found, the value of <o>hinttags</o> is used. </p> </description> @@ -855,12 +841,16 @@ <tags>'ht' 'hinttags'</tags> <strut/> <spec>'hinttags' 'ht'</spec> - <type>string</type> - <default>&hinttags;</default> + <type>stringlist</type> + <default style="display: block;">a,area,button,iframe,input:not([type=hidden]),select,textarea, + [onclick],[onmouseover],[onmousedown],[onmouseup],[oncommand], + [tabindex],[role=link],[role=button]</default> <description> <p> - The XPath string used to select elements for - <link topic="hints">hinting</link>. Can be overridden for + A list of CSS selectors or XPath expressions used to select elements + for <link topic="hints">hinting</link>. Values beginning with the + string <str>xpath:</str> are treated as XPath expressions, while any + other values are treated as CSS selectors. Can be overridden for individual <t>extended-hints</t> modes with the <o>extendedhinttags</o> option. </p> diff --git a/common/modules/io.jsm b/common/modules/io.jsm index 71c72ba2..ef18759f 100644 --- a/common/modules/io.jsm +++ b/common/modules/io.jsm @@ -205,8 +205,7 @@ var IO = Module("io", { return context; } catch (e) { - if (!(e instanceof FailedAssertion)) - dactyl.reportError(e); + dactyl.reportError(e); let message = "Sourcing file: " + (e.echoerr || file.path + ": " + e); if (!params.silent) dactyl.echoerr(message); diff --git a/common/modules/options.jsm b/common/modules/options.jsm index 74e1347f..7a9452fc 100644 --- a/common/modules/options.jsm +++ b/common/modules/options.jsm @@ -415,18 +415,23 @@ var Option = Class("Option", { }, parseRegexp: function (value, result, flags) { + let keepQuotes = this && this.keepQuotes; if (isArray(flags)) // Called by Array.map result = flags = undefined; + if (flags == null) + flags = this && this.regexpFlags || ""; + let [, bang, val] = /^(!?)(.*)/.exec(value); let re = RegExp(Option.dequote(val), flags); re.bang = bang; re.result = result !== undefined ? result : !bang; - re.toString = function () Option.unparseRegexp(this); + re.toString = function () Option.unparseRegexp(this, keepQuotes); return re; }, - unparseRegexp: function (re) re.bang + Option.quote(util.regexp.getSource(re), /^!|:/) + - (typeof re.result === "boolean" ? "" : ":" + Option.quote(re.result)), + + unparseRegexp: function (re, quoted) re.bang + Option.quote(util.regexp.getSource(re), /^!|:/) + + (typeof re.result === "boolean" ? "" : ":" + (quoted ? re.result : Option.quote(re.result))), parseSite: function parseSite(pattern, result, rest) { if (isArray(rest)) // Called by Array.map @@ -500,23 +505,25 @@ var Option = Class("Option", { return [key, Option.dequote(v.substr(count + 1))]; })), - regexpmap: function (value) - Option.splitList(value, true).map(function (v) { - let [count, re, quote] = Commands.parseArg(v, /:/, true); - let val = Option.dequote(v.substr(count + 1)); - if (count === v.length) - [val, re] = [re, ".?"]; - return Option.parseRegexp(re, val, this.regexpFlags); - }, this), - - sitemap: function (value) - Option.splitList(value, true).map(function (v) { - let [count, re, quote] = Commands.parseArg(v, /:/, true); - let val = Option.dequote(v.substr(count + 1)); - if (count === v.length) - [val, re] = [re, "*"]; - return Option.parseSite(re, val); - }, this) + regexpmap: function (value) Option.parse.list.call(this, value, Option.parseRegexp), + + sitemap: function (value) Option.parse.list.call(this, value, Option.parseSite), + + list: function (value, parse) let (prev = null) + array.compact(Option.splitList(value, true).map(function (v) { + let [count, filter, quote] = Commands.parseArg(v, /:/, true); + + let val = v.substr(count + 1); + if (!this.keepQuotes) + val = Option.dequote(val); + + if (v.length > count) + return prev = parse.call(this, filter, val); + else { + util.assert(prev, "Syntax error", false); + prev.result += "," + v; + } + }, this)) }, testValues: { @@ -549,7 +556,7 @@ var Option = Class("Option", { return res; }, - quote: function quote(str, re) + quote: function quote(str, re) isArray(str) ? str.map(function (s) quote(s, re)).join(",") : Commands.quoteArg[/[\s|"'\\,]|^$/.test(str) || re && re.test && re.test(str) ? (/[\b\f\n\r\t]/.test(str) ? '"' : "'") : ""](str, re), @@ -683,6 +690,7 @@ var Option = Class("Option", { }, validateXPath: function (values) { + return true; // For now. let evaluator = services.XPathEvaluator(); return this.testValues(values, function (value) evaluator.createExpression(value, util.evaluateXPath.resolver)); diff --git a/common/modules/util.jsm b/common/modules/util.jsm index 32fe8af7..d41024b6 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -22,7 +22,18 @@ var XUL = Namespace("xul", "http://www.mozilla.org/keymaster/gatekeeper/there.is var NS = Namespace("dactyl", "http://vimperator.org/namespaces/liberator"); default xml namespace = XHTML; -var FailedAssertion = Class("FailedAssertion", ErrorBase); +var FailedAssertion = Class("FailedAssertion", ErrorBase, { + init: function init(message, level, noTrace) { + if (noTrace !== undefined) + this.noTrace = noTrace; + init.supercall(this, message, level); + }, + + level: 3, + + noTrace: true +}); + var Point = Struct("x", "y"); var wrapCallback = function wrapCallback(fn) { @@ -144,9 +155,9 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * @param {string} message The message to present to the * user on failure. */ - assert: function (condition, message) { + assert: function (condition, message, quiet) { if (!condition) - throw FailedAssertion(message, 1); + throw FailedAssertion(message, 1, quiet === undefined ? true : quiet); }, /** @@ -1417,6 +1428,9 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), errors: Class.memoize(function () []), maxErrors: 15, reportError: function (error) { + if (error.noTrace) + return; + if (Cu.reportError) Cu.reportError(error); |