diff --git a/common/components/protocols.js b/common/components/protocols.js index 3566f3d4..ef2af7c7 100644 --- a/common/components/protocols.js +++ b/common/components/protocols.js @@ -94,98 +94,11 @@ function Liberator() { this.wrappedJSObject = this; - this.__defineGetter__("helpNamespaces", function () this.NAMESPACES ? this.NAMESPACES.slice() : null); - this.__defineSetter__("helpNamespaces", function (namespaces) { - if (!this.NAMESPACES) - parseHelpTags(namespaces); - }); - - function xpath(doc, expression) - { - let result = doc.evaluate(expression, doc, - function lookupNamespaceURI(prefix) ({ - xhtml: "http://www.w3.org/1999/xhtml", - liberator: "http://vimperator.org/namespaces/liberator", - }[prefix] || null), - 5, null); - result.__iterator__ = function () { let elem; while ((elem = this.iterateNext())) yield elem; }; - return result; - } - - this.httpGet = httpGet; - function httpGet(url) - { - try - { - let xmlhttp = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); - xmlhttp.open("GET", url, false); - xmlhttp.send(null); - return xmlhttp; - } - catch (e) {} - } - const self = this; this.HELP_TAGS = {}; this.FILE_MAP = {}; this.OVERLAY_MAP = {}; - this.NAMESPACES = null; - var HELP_FILES = null; - - function XSLTProcessor(sheet) - { - let xslt = Cc["@mozilla.org/document-transformer;1?type=xslt"].createInstance(Ci.nsIXSLTProcessor); - xslt.importStylesheet(httpGet(sheet).responseXML); - return xslt; - } - - function findHelpFile(file) - { - let result = []; - for each (let namespace in self.NAMESPACES) - { - let url = ["chrome://", namespace, "/locale/", file, ".xml"].join(""); - let res = httpGet(url); - if (res) - { - if (res.responseXML.documentElement.localName == "document") - self.FILE_MAP[file] = url; - if (res.responseXML.documentElement.localName == "overlay") - self.OVERLAY_MAP[file] = url; - if (res.responseXML.documentElement.localName == "document") - result = [url, res.responseXML]; - } - } - return result; - } - - function parseHelpTags(namespaces) - { - HELP_FILES = []; - self.NAMESPACES = Array.slice(namespaces); - - findHelpFile("all"); - - const XSLT = XSLTProcessor("chrome://liberator/content/help.xsl"); - self.HELP_TAGS.all = "all"; - for each (let namespace in self.NAMESPACES) - { - let files = xpath( - httpGet("chrome://" + namespace + "/locale/all.xml").responseXML, - "//liberator:include/@href"); - for each (let file in files) - { - let [url, doc] = findHelpFile(file.value); - if (!doc) - continue; - self.FILE_MAP[file.value] = url; - doc = XSLT.transformToDocument(doc); - for (let elem in xpath(doc, "//liberator:tag/text()")) - self.HELP_TAGS[elem.textContent] = file.value; - HELP_FILES.push(file.value); - } - } - } + this.NAMESPACES = []; } Liberator.prototype = { contractID: "@mozilla.org/network/protocol;1?name=liberator", @@ -203,6 +116,13 @@ Liberator.prototype = { } }, + init: function (obj) + { + for each (let prop in ["HELP_TAGS", "FILE_MAP", "OVERLAY_MAP", "NAMESPACES"]) + for (let [k, v] in Iterator(obj[prop])) + this[prop][k] = v + }, + scheme: "liberator", defaultPort: -1, allowPort: function (port, scheme) false, diff --git a/common/content/buffer.js b/common/content/buffer.js index 6e57c834..537a2448 100644 --- a/common/content/buffer.js +++ b/common/content/buffer.js @@ -389,7 +389,7 @@ function Buffer() //{{{ let xpath = ["input[not(@type) or @type='text' or @type='password' or @type='file']", "textarea[not(@disabled) and not(@readonly)]"]; - let elements = [m for (m in buffer.evaluateXPath(xpath))].filter(function (match) { + let elements = [m for (m in util.evaluateXPath(xpath))].filter(function (match) { let computedStyle = util.computedStyle(match); return computedStyle.visibility != "hidden" && computedStyle.display != "none"; }); @@ -802,7 +802,7 @@ function Buffer() //{{{ } let nFeed = 0; - for (let link in buffer.evaluateXPath(["link[@href and (@rel='feed' or (@rel='alternate' and @type))]"], doc)) + for (let link in util.evaluateXPath(["link[@href and (@rel='feed' or (@rel='alternate' and @type))]"], doc)) { let rel = link.rel.toLowerCase(); let feed = { title: link.title, href: link.href, type: link.type || "" }; @@ -1012,48 +1012,6 @@ function Buffer() //{{{ */ addPageInfoSection: addPageInfoSection, - /** - * Evaluates an XPath expression in the current or provided - * document. It provides the xhtml, xhtml2 and liberator XML - * namespaces. The result may be used as an iterator. - * - * @param {string} expression The XPath expression to evaluate. - * @param {Document} doc The document to evaluate the expression in. - * @default The current document. - * @param {Node} elem The context element. - * @default doc - * @param {boolean} asIterator Whether to return the results as an - * XPath iterator. - */ - evaluateXPath: function (expression, doc, elem, asIterator) - { - if (!doc) - doc = window.content.document; - if (!elem) - elem = doc; - if (util.isArray(expression)) - expression = util.makeXPath(expression); - - let result = doc.evaluate(expression, elem, - function lookupNamespaceURI(prefix) - { - return { - xhtml: "http://www.w3.org/1999/xhtml", - xhtml2: "http://www.w3.org/2002/06/xhtml2", - liberator: NS.uri - }[prefix] || null; - }, - asIterator ? XPathResult.ORDERED_NODE_ITERATOR_TYPE : XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, - null - ); - - 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 result; - }, - /** * Returns the currently selected word. If the selection is * null, it tries to guess the word that the caret is @@ -1162,7 +1120,7 @@ function Buffer() //{{{ return true; } - let res = buffer.evaluateXPath(options.get("hinttags").defaultValue, frame.document); + let res = util.evaluateXPath(options.get("hinttags").defaultValue, frame.document); for (let [, regex] in Iterator(regexes)) { for (let i in util.range(res.snapshotLength, 0, -1)) diff --git a/common/content/hints.js b/common/content/hints.js index 9a1c40c1..211dae11 100644 --- a/common/content/hints.js +++ b/common/content/hints.js @@ -164,7 +164,7 @@ function Hints() //{{{ if (elem.id) { // TODO: (possibly) do some guess work for label-like objects - let label = buffer.evaluateXPath("//label[@for='" + elem.id + "']", doc).snapshotItem(0); + let label = util.evaluateXPath("//label[@for='" + elem.id + "']", doc).snapshotItem(0); if (label) return [label.textContent.toLowerCase(), true]; } @@ -284,7 +284,7 @@ function Hints() //{{{ let baseNodeAbsolute = util.xmlToDom(, doc); let elem, text, span, rect, showText; - let res = buffer.evaluateXPath(hintMode.tags(), doc, null, true); + let res = util.evaluateXPath(hintMode.tags(), doc, null, true); let fragment = util.xmlToDom(
, doc); let start = pageHints.length; @@ -440,7 +440,7 @@ function Hints() //{{{ // FIXME: Broken for imgspans. for (let [, { doc: doc }] in Iterator(docs)) { - for (let elem in buffer.evaluateXPath("//*[@liberator:highlight and @number]", doc)) + for (let elem in util.evaluateXPath("//*[@liberator:highlight and @number]", doc)) { let group = elem.getAttributeNS(NS.uri, "highlight"); css.push(highlight.selector(group) + "[number='" + elem.getAttribute("number") + "'] { " + elem.style.cssText + " }"); @@ -466,7 +466,7 @@ function Hints() //{{{ for (let [,{ doc: doc, start: start, end: end }] in Iterator(docs)) { - for (let elem in buffer.evaluateXPath("//*[@liberator:highlight='hints']", doc)) + for (let elem in util.evaluateXPath("//*[@liberator:highlight='hints']", doc)) elem.parentNode.removeChild(elem); for (let i in util.range(start, end + 1)) { @@ -778,7 +778,7 @@ function Hints() //{{{ { try { - buffer.evaluateXPath(val, document.implementation.createDocument("", "", null)); + util.evaluateXPath(val, document.implementation.createDocument("", "", null)); return true; } catch (e) diff --git a/common/content/liberator.js b/common/content/liberator.js index 96006379..42aca866 100644 --- a/common/content/liberator.js +++ b/common/content/liberator.js @@ -638,7 +638,7 @@ const liberator = (function () //{{{ toolbox = document.getElementById("navigator-toolbox"); if (toolbox) { - function findToolbar(name) buffer.evaluateXPath( + function findToolbar(name) util.evaluateXPath( "./*[@toolbarname=" + util.escapeString(name, "'") + "]", document, toolbox).snapshotItem(0); @@ -859,7 +859,7 @@ const liberator = (function () //{{{ completion.toolbar = function toolbar(context) { context.title = ["Toolbar"]; context.keys = { text: function (item) item.getAttribute("toolbarname"), description: function () "" }; - context.completions = buffer.evaluateXPath("./*[@toolbarname]", document, toolbox); + context.completions = util.evaluateXPath("./*[@toolbarname]", document, toolbox); }; completion.window = function window(context) { @@ -1377,6 +1377,73 @@ const liberator = (function () //{{{ return null; }, + /** + * @private + * Initialize the help system. + */ + initHelp: function () + { + if (services.get("liberator:").NAMESPACES.length) + return; + + let namespaces = [config.name.toLowerCase(), "liberator"]; + let tagMap = {}; + let fileMap = {}; + let overlayMap = {}; + function XSLTProcessor(sheet) + { + let xslt = Cc["@mozilla.org/document-transformer;1?type=xslt"].createInstance(Ci.nsIXSLTProcessor); + xslt.importStylesheet(util.httpGet(sheet).responseXML); + return xslt; + } + + function findHelpFile(file) + { + let result = []; + for (let [, namespace] in Iterator(namespaces)) + { + let url = ["chrome://", namespace, "/locale/", file, ".xml"].join(""); + let res = util.httpGet(url); + if (res) + { + if (res.responseXML.documentElement.localName == "document") + fileMap[file] = url; + if (res.responseXML.documentElement.localName == "overlay") + overlayMap[file] = url; + if (res.responseXML.documentElement.localName == "document") + result = [url, res.responseXML]; + } + } + return result; + } + + findHelpFile("all"); + tagMap.all = "all"; + + const XSLT = XSLTProcessor("chrome://liberator/content/help.xsl"); + for (let [, namespace] in Iterator(namespaces)) + { + let files = util.evaluateXPath( + "//liberator:include/@href", + util.httpGet("chrome://" + namespace + "/locale/all.xml").responseXML); + for (let file in files) + { + let [url, doc] = findHelpFile(file.value); + if (!doc) + continue; + fileMap[file.value] = url; + doc = XSLT.transformToDocument(doc); + for (let elem in util.evaluateXPath("//liberator:tag/text()", doc)) + tagMap[elem.textContent] = file.value; + } + } + + services.get("liberator:").init({ + HELP_TAGS: tagMap, FILE_MAP: fileMap, + OVERLAY_MAP: overlayMap, NAMESPACES: namespaces + }); + }, + /** * Opens the help page containing the specified topic if it * exists. @@ -1726,7 +1793,7 @@ const liberator = (function () //{{{ let start = Date.now(); liberator.log("Initializing liberator object...", 0); - services.get("liberator:").helpNamespaces = [config.name.toLowerCase(), "liberator"]; + liberator.initHelp(); config.features.push(getPlatformFeature()); diff --git a/common/content/ui.js b/common/content/ui.js index 4d6eec9b..70363bd8 100644 --- a/common/content/ui.js +++ b/common/content/ui.js @@ -1949,7 +1949,7 @@ function ItemList(id) //{{{ divNodes.noCompletions.style.display = haveCompletions ? "none" : "block"; - completionElements = buffer.evaluateXPath("//xhtml:div[@liberator:highlight='CompItem']", doc); + completionElements = util.evaluateXPath("//xhtml:div[@liberator:highlight='CompItem']", doc); return true; } diff --git a/common/content/util.js b/common/content/util.js index d2d2c9b0..38152b1a 100644 --- a/common/content/util.js +++ b/common/content/util.js @@ -365,6 +365,48 @@ const util = { //{{{ } }, + /** + * Evaluates an XPath expression in the current or provided + * document. It provides the xhtml, xhtml2 and liberator XML + * namespaces. The result may be used as an iterator. + * + * @param {string} expression The XPath expression to evaluate. + * @param {Document} doc The document to evaluate the expression in. + * @default The current document. + * @param {Node} elem The context element. + * @default doc + * @param {boolean} asIterator Whether to return the results as an + * XPath iterator. + */ + evaluateXPath: function (expression, doc, elem, asIterator) + { + if (!doc) + doc = window.content.document; + if (!elem) + elem = doc; + if (util.isArray(expression)) + expression = util.makeXPath(expression); + + let result = doc.evaluate(expression, elem, + function lookupNamespaceURI(prefix) + { + return { + xhtml: "http://www.w3.org/1999/xhtml", + xhtml2: "http://www.w3.org/2002/06/xhtml2", + liberator: NS.uri + }[prefix] || null; + }, + asIterator ? XPathResult.ORDERED_NODE_ITERATOR_TYPE : XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, + null + ); + + 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 result; + }, + /** * The identity function. * diff --git a/common/locale/en-US/autocommands.xml b/common/locale/en-US/autocommands.xml index b99cef10..ed8d49ed 100644 --- a/common/locale/en-US/autocommands.xml +++ b/common/locale/en-US/autocommands.xml @@ -89,7 +89,7 @@

-:autocmd LocationChange .* :set editor=gvim -f +:autocmd LocationChange .* :set editor=gvim -f :autocmd LocationChange mail\\.google\\.com :set editor=gvim -f -c 'set ft=mail'