diff --git a/common/content/buffer.js b/common/content/buffer.js index 23989362..0350c852 100644 --- a/common/content/buffer.js +++ b/common/content/buffer.js @@ -26,8 +26,16 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + const Point = new Struct("x", "y"); +/** + * A class to manage the primary web content buffer. The name comes + * from vim's term, 'buffer', which signifies instances of open + * files. + * @instance buffer + */ function Buffer() //{{{ { //////////////////////////////////////////////////////////////////////////////// @@ -808,6 +816,10 @@ function Buffer() //{{{ return { + /** + * The alternative stylesheets for the current buffer. Only + * returns stylesheets for the 'screen' media type. + */ get alternateStyleSheets() { let stylesheets = window.getAllStyleSheets(window.content); @@ -817,9 +829,18 @@ function Buffer() //{{{ ); }, + /** + * @property {Object} A map of page info sections to their + * content generating functions. + */ get pageInfo() pageInfo, - // 0 if loading, 1 if loaded or 2 if load failed + /** + * Returns whether the buffer is loaded. Values may be: + * 0 - Loading. + * 1 - Fully loaded. + * 2 - Load failed. + */ get loaded() { if (window.content.document.pageIsFullyLoaded !== undefined) @@ -832,7 +853,10 @@ function Buffer() //{{{ window.content.document.pageIsFullyLoaded = value; }, - // used to keep track of the right field for "gi" + /** + * The last focused input field in the buffer. Used by the + * "gi" key binding. + */ get lastInputField() { if (window.content.document.lastInputField) @@ -845,6 +869,9 @@ function Buffer() //{{{ window.content.document.lastInputField = value; }, + /** + * The current top-level document's URL. + */ get URL() { return window.content.document.location.href; @@ -855,6 +882,10 @@ function Buffer() //{{{ return window.content.innerHeight; }, + /** + * The current browser's text zoom level, as a percentage with + * 100 as 'normal'. Only affects text size. + */ get textZoom() { return getBrowser().markupDocumentViewer.textZoom * 100; @@ -864,6 +895,11 @@ function Buffer() //{{{ setZoom(value, false); }, + /** + * The current browser's text zoom level, as a percentage with + * 100 as 'normal'. Affects text size, as well as image size + * and block size. + */ get fullZoom() { return getBrowser().markupDocumentViewer.fullZoom * 100; @@ -873,14 +909,37 @@ function Buffer() //{{{ setZoom(value, true); }, + /** + * The current document's title. + */ get title() { return window.content.document.title; }, + /** + * + * @param {string} option The section's value in 'pageinfo'. + * @param {string} title The heading for this section's + * output. + * @param {function} fn The function to generate this + * section's output. + */ addPageInfoSection: addPageInfoSection, - // returns an XPathResult object + /** + * Evaluates an XPath expression in the current or provided + * document. It provides the xhtml 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) @@ -891,15 +950,10 @@ function Buffer() //{{{ let result = doc.evaluate(expression, elem, function lookupNamespaceURI(prefix) { - switch (prefix) - { - case "xhtml": - return "http://www.w3.org/1999/xhtml"; - case "liberator": - return NS.uri; - default: - return null; - } + return { + xhtml: "http://www.w3.org/1999/xhtml", + liberator: NS.uri + }[prefix] || null; }, asIterator ? XPathResult.ORDERED_NODE_ITERATOR_TYPE : XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null @@ -912,9 +966,13 @@ function Buffer() //{{{ return result; }, - // in contrast to vim, returns the selection if one is made, - // otherwise tries to guess the current word under the text cursor - // NOTE: might change the selection + /** + * Returns the currently selected word. If the selection is + * null, it tries to guess the word that the caret is + * positioned in. + * + * NOTE: might change the selection + */ // FIXME: getSelection() doesn't always preserve line endings, see: // https://www.mozdev.org/bugs/show_bug.cgi?id=19303 getCurrentWord: function () @@ -936,8 +994,13 @@ function Buffer() //{{{ return String(selection); }, - // more advanced than a simple elem.focus() as it also works for iframes - // and image maps + /** + * Focuses the given element. In contrast to a simple + * elem.focus() call, this function works for iframes and + * image maps. + * + * @param {Node} elem The element to focus. + */ // TODO: merge with followLink()? focusElement: function (elem) { @@ -962,6 +1025,17 @@ function Buffer() //{{{ elem.dispatchEvent(evt); }, + /** + * Try to guess links the like of "next" and "prev". Though it + * has a singularly horrendous name, it turns out to be quite + * useful. + * + * @param {string} rel The relationship to look for. Looks for + * links with matching @rel or @rev attributes, and, + * failing that, looks for an option named rel + + * "pattern", and finds the last link matching that + * RegExp. + */ followDocumentRelationship: function (rel) { let regexps = options.get(rel + "pattern").values @@ -1018,7 +1092,13 @@ function Buffer() //{{{ liberator.beep(); }, - // artificially "clicks" a link in order to open it + /** + * Fakes a click on a link. + * + * @param {Node} elem The element to click. + * @param {number} where Where to open the link. See + * {@link liberator.open}. + */ followLink: function (elem, where) { let doc = elem.ownerDocument; @@ -1066,6 +1146,9 @@ function Buffer() //{{{ }); }, + /** + * The current document's selection controller. + */ get selectionController() getBrowser().docShell .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsISelectionDisplay) @@ -1090,11 +1173,19 @@ function Buffer() //{{{ } }, + /** + * Scrolls to the bottom of the current buffer. + */ scrollBottom: function () { scrollToPercentiles(-1, 100); }, + /** + * Scrolls the window laterally cols columns. + * + * @param {number} cols The number of columns to scroll. + */ scrollColumns: function (cols) { let win = findScrollableWindow(); @@ -1106,11 +1197,19 @@ function Buffer() //{{{ win.scrollBy(COL_WIDTH * cols, 0); }, + /** + * Scrolls the buffer to its rightmost position. + */ scrollEnd: function () { scrollToPercentiles(100, -1); }, + /** + * Scrolls the buffer vertically lines rows. + * + * @param {number} lines The number of lines to scroll. + */ scrollLines: function (lines) { let win = findScrollableWindow(); @@ -1118,6 +1217,11 @@ function Buffer() //{{{ win.scrollByLines(lines); }, + /** + * Scrolls the buffer vertically pages pages. + * + * @param {number} pages The number of pages to scroll. + */ scrollPages: function (pages) { let win = findScrollableWindow(); @@ -1139,16 +1243,25 @@ function Buffer() //{{{ win.scrollBy(0, win.innerHeight / 2 * direction); }, + /** + * Scrolls the current buffer vertically to percentage + */ scrollToPercentile: function (percentage) { scrollToPercentiles(-1, percentage); }, + /** + * Scrolls the current buffer laterally to its leftmost. + */ scrollStart: function () { scrollToPercentiles(0, -1); }, + /** + * Scrolls the current buffer vertically to its top. + */ scrollTop: function () { scrollToPercentiles(-1, 0); @@ -1310,6 +1423,9 @@ function Buffer() //{{{ //}}} }; //}}} +/** + * @instance marks + */ function Marks() //{{{ { //////////////////////////////////////////////////////////////////////////////// diff --git a/common/content/commands.js b/common/content/commands.js index 7486d344..d357918d 100644 --- a/common/content/commands.js +++ b/common/content/commands.js @@ -26,6 +26,8 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + // Do NOT create instances of this class yourself, use the helper method // commands.add() instead function Command(specs, description, action, extraInfo) //{{{ @@ -147,6 +149,9 @@ Command.prototype = { }; //}}} +/** + * @instance commands + */ function Commands() //{{{ { //////////////////////////////////////////////////////////////////////////////// diff --git a/common/content/completion.js b/common/content/completion.js index f9ddee03..2c119f95 100644 --- a/common/content/completion.js +++ b/common/content/completion.js @@ -26,6 +26,8 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + /** * Creates a new completion context. * @@ -647,6 +649,9 @@ CompletionContext.prototype = { } }; //}}} +/** + * @instance completion + */ function Completion() //{{{ { //////////////////////////////////////////////////////////////////////////////// diff --git a/common/content/editor.js b/common/content/editor.js index 6219a4ea..5c9ffedb 100644 --- a/common/content/editor.js +++ b/common/content/editor.js @@ -26,9 +26,14 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + // command names taken from: // http://developer.mozilla.org/en/docs/Editor_Embedding_Guide +/** + * @instance editor + */ function Editor() //{{{ { //////////////////////////////////////////////////////////////////////////////// diff --git a/common/content/events.js b/common/content/events.js index c477cb80..3009eee6 100644 --- a/common/content/events.js +++ b/common/content/events.js @@ -26,6 +26,11 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + +/** + * @instance autocommands + */ function AutoCommands() //{{{ { //////////////////////////////////////////////////////////////////////////////// @@ -277,6 +282,9 @@ function AutoCommands() //{{{ //}}} }; //}}} +/** + * @instance events + */ function Events() //{{{ { //////////////////////////////////////////////////////////////////////////////// diff --git a/common/content/find.js b/common/content/find.js index 923426f5..72c77388 100644 --- a/common/content/find.js +++ b/common/content/find.js @@ -26,6 +26,8 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + // TODO: proper backwards search - implement our own component? // : implement our own highlighter? // : frameset pages @@ -37,6 +39,9 @@ the terms of any one of the MPL, the GPL or the LGPL. // : incremental searches shouldn't permanently update search modifiers // make sure you only create this object when the "liberator" object is ready +/** + * @instance search + */ function Search() //{{{ { //////////////////////////////////////////////////////////////////////////////// diff --git a/common/content/hints.js b/common/content/hints.js index 90c7e14f..38f36436 100644 --- a/common/content/hints.js +++ b/common/content/hints.js @@ -26,6 +26,11 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + +/** + * @instance hints + */ function Hints() //{{{ { //////////////////////////////////////////////////////////////////////////////// diff --git a/common/content/io.js b/common/content/io.js index 136b2b13..ba62b137 100644 --- a/common/content/io.js +++ b/common/content/io.js @@ -27,6 +27,8 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + plugins.contexts = {}; function Script(file) { @@ -52,6 +54,9 @@ function Script(file) Script.prototype = plugins; // TODO: why are we passing around strings rather than file objects? +/** + * @instance io + */ function IO() //{{{ { //////////////////////////////////////////////////////////////////////////////// @@ -838,7 +843,7 @@ lookup: } else if (/\.css$/.test(filename)) { - storage.styles.registerSheet(uri.spec, !silent, true); + storage.styles.registerSheet(uri.spec, true); } else { diff --git a/common/content/liberator.js b/common/content/liberator.js index 54780d85..1e32d051 100644 --- a/common/content/liberator.js +++ b/common/content/liberator.js @@ -26,6 +26,8 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; diff --git a/common/content/mappings.js b/common/content/mappings.js index 7e35b115..d409ba79 100644 --- a/common/content/mappings.js +++ b/common/content/mappings.js @@ -26,6 +26,8 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + // Do NOT create instances of this class yourself, use the helper method // mappings.add() instead function Map(modes, cmds, description, action, extraInfo) //{{{ @@ -76,6 +78,9 @@ Map.prototype = { }; //}}} +/** + * @instance mappings + */ function Mappings() //{{{ { //////////////////////////////////////////////////////////////////////////////// diff --git a/common/content/modes.js b/common/content/modes.js index 0159dd24..e79a67f4 100644 --- a/common/content/modes.js +++ b/common/content/modes.js @@ -26,6 +26,8 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + const modes = (function () //{{{ { //////////////////////////////////////////////////////////////////////////////// diff --git a/common/content/options.js b/common/content/options.js index 6373dcb6..a1844a5f 100644 --- a/common/content/options.js +++ b/common/content/options.js @@ -26,6 +26,8 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + // do NOT create instances of this class yourself, use the helper method // options.add() instead function Option(names, description, type, defaultValue, extraInfo) //{{{ @@ -293,6 +295,9 @@ Option.validateCompleter = function (values) function (value) res.some(function (item) item[0] == value)); }; //}}} +/** + * @instance options + */ function Options() //{{{ { //////////////////////////////////////////////////////////////////////////////// diff --git a/common/content/style.js b/common/content/style.js index 62c14ef2..d2ef4d57 100644 --- a/common/content/style.js +++ b/common/content/style.js @@ -6,6 +6,19 @@ it under any or all of those licenseses. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + +/** + * @constant + * @property {string} The default highlighting rules. They have the + * form: + * rule ::= selector space css + * selector ::= group + * | group "," css-selector + * | group "," css-selector "," scope + * group ::= groupname + * | groupname css-selector + */ // Highlights.prototype.CSS = .toString(); +/** + * A class to manage highlighting rules. The parameters are the + * standard paramaters for any {@link Storage} object. + * + * @author Kris Maglione + */ function Highlights(name, store, serial) { var self = this; @@ -161,25 +180,35 @@ function Highlights(name, store, serial) .replace(";!important;", ";", "g"); // Seeming Spidermonkey bug css = style.selector + " { " + css + " }"; - let error = styles.addSheet(style.selector, style.filter, css, true, force); + let error = styles.addSheet(style.selector, style.filter, css, true); if (error) return error; style.value = newStyle; highlight[style.class] = style; }; + /** + * Gets a CSS selector given a highlight group. + */ this.selector = function (class) { let [, hl, rest] = class.match(/^(\w*)(.*)/); return "[liberator|highlight~=" + hl + "]" + rest }; + /** + * Clears all highlighting rules. Rules with default values are + * reset. + */ this.clear = function () { for (let [k, v] in Iterator(highlight)) this.set(k, null, true); }; + /** + * Reloads the values in {@link #CSS}. + */ this.reload = function () { this.CSS.replace(/\{((?:.|\n)*?)\}/g, function (_, _1) _1.replace(/\n\s*/g, " ")) @@ -203,6 +232,13 @@ function Highlights(name, store, serial) }; } +/** + * Manages named and unnamed user stylesheets, which apply to both + * chrome and content pages. The parameters are the standard + * paramaters for any {@link Storage} object. + * + * @author Kris Maglione + */ function Styles(name, store, serial) { /* Can't reference liberator or Components inside Styles -- @@ -233,7 +269,20 @@ function Styles(name, store, serial) this.__defineGetter__("systemNames", function () Iterator(systemNames)); this.__defineGetter__("userNames", function () Iterator(userNames)); - this.addSheet = function (name, filter, css, system, force) + /** + * Add a new stylesheet. + * + * @param {string} name The name given to the stylesheet by + * which it may be later referenced. + * @param {string} filter The sites to which this sheet will + * apply. Can be a domain name or a URL. Any URL ending in + * "*" is matched as a prefix. + * @param {string} css The CSS to be applied. + * @param {boolean} system Declares whether this is a system or + * user sheet. System sheets are used internally by + * @liberator. + */ + this.addSheet = function (name, filter, css, system) { let sheets = system ? systemSheets : userSheets; let names = system ? systemNames : userNames; @@ -249,7 +298,7 @@ function Styles(name, store, serial) sheet.ref = []; try { - this.registerSheet(cssUri(wrapCSS(sheet)), !force); + this.registerSheet(cssUri(wrapCSS(sheet))); this.registerAgentSheet(cssUri(wrapCSS(sheet))) } catch (e) @@ -266,6 +315,10 @@ function Styles(name, store, serial) return null; }; + /** + * Find sheets matching the parameters. See {@link #addSheet} + * for parameters. + */ this.findSheets = function (name, filter, css, index, system) { let sheets = system ? systemSheets : userSheets; @@ -284,6 +337,12 @@ function Styles(name, store, serial) return matches.map(function (i) sheets[i]); }; + /** + * Remove a stylesheet. See {@link #addSheet} for parameters. + * In cases where filter is supplied, the given filters + * are removed from matching sheets. If any remain, the sheet is + * left in place. + */ this.removeSheet = function (name, filter, css, index, system) { let self = this; @@ -326,11 +385,15 @@ function Styles(name, store, serial) return matches.length; }; - this.registerSheet = function (uri, doCheckSyntax, reload) + /** + * Register a user stylesheet at the given URI. + * + * @param {string} uri The UrI of the sheet to register. + * @param {boolean} reload Whether to reload any sheets that are + * already registered. + */ + this.registerSheet = function (uri, reload) { - //dump (uri + "\n\n"); - if (doCheckSyntax) - checkSyntax(uri); if (reload) this.unregisterSheet(uri); uri = ios.newURI(uri, null, null); @@ -338,6 +401,9 @@ function Styles(name, store, serial) sss.loadAndRegisterSheet(uri, sss.USER_SHEET); }; + /** + * Unregister a sheet at the given URI. + */ this.unregisterSheet = function (uri) { uri = ios.newURI(uri, null, null); @@ -346,6 +412,10 @@ function Styles(name, store, serial) }; // FIXME + /** + * Register an agent stylesheet. + * @deprecated + */ this.registerAgentSheet = function (uri) { this.unregisterAgentSheet(uri); @@ -353,6 +423,10 @@ function Styles(name, store, serial) sss.loadAndRegisterSheet(uri, sss.AGENT_SHEET); }; + /** + * Unregister an agent stylesheet. + * @deprecated + */ this.unregisterAgentSheet = function (uri) { uri = ios.newURI(uri, null, null); @@ -373,65 +447,6 @@ function Styles(name, store, serial) .join(", "); return namespace + "@-moz-document " + selectors + "{\n" + css + "\n}\n"; } - - let queryinterface = XPCOMUtils.generateQI([Ci.nsIConsoleListener]); - /* What happens if more than one thread tries to use this? */ - let testDoc = document.implementation.createDocument(XHTML, "doc", null); - function checkSyntax(uri) - { - let errors = []; - let listener = { - QueryInterface: queryinterface, - observe: function (message) - { - try - { - message = message.QueryInterface(Ci.nsIScriptError); - if (message.sourceName == uri) - errors.push(message); - } - catch (e) {} - } - }; - - try - { - consoleService.registerListener(listener); - if (testDoc.documentElement.firstChild) - testDoc.documentElement.removeChild(testDoc.documentElement.firstChild); - testDoc.documentElement.appendChild(util.xmlToDom( - , testDoc)); - - while (true) - { - try - { - // Throws NS_ERROR_DOM_INVALID_ACCESS_ERR if not finished loading - testDoc.styleSheets[0].cssRules.length; - break; - } - catch (e) - { - if (e.name != "NS_ERROR_DOM_INVALID_ACCESS_ERR") - return [e.toString()]; - sleep(10); - } - } - } - finally - { - consoleService.unregisterListener(listener); - } - if (errors.length) - { - let err = new Error("", errors[0].sourceName.replace(/^(chrome-data:text\/css,).*/, "$1..."), errors[0].lineNumber); - err.name = "CSSError"; - err.message = errors.reduce(function (msg, e) msg + "; " + e.lineNumber + ": " + e.errorMessage, - errors.shift().errorMessage); - err.echoerr = err.fileName + ":" + err.lineNumber + ": " + err.message; - throw err; - } - } } let (array = util.Array) { @@ -440,8 +455,16 @@ let (array = util.Array) }; } +/** + * @property {Styles} + */ const styles = storage.newObject("styles", Styles, false); + +/** + * @property {Highlights} + */ const highlight = storage.newObject("highlight", Highlights, false); + highlight.CSS = Highlights.prototype.CSS; highlight.reload(); diff --git a/common/content/tabs.js b/common/content/tabs.js index 4e8512f2..fd3c6a24 100644 --- a/common/content/tabs.js +++ b/common/content/tabs.js @@ -26,6 +26,8 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + // TODO: many methods do not work with Thunderbird correctly yet function Tabs() //{{{ diff --git a/common/content/template.js b/common/content/template.js index 7b937537..0f7a08a3 100644 --- a/common/content/template.js +++ b/common/content/template.js @@ -1,3 +1,6 @@ + +/** @scope modules */ + const template = { add: function add(a, b) a + b, join: function join(c) function (a, b) a + c + b, diff --git a/common/content/ui.js b/common/content/ui.js index eb3e6c9f..717dbe37 100644 --- a/common/content/ui.js +++ b/common/content/ui.js @@ -26,6 +26,8 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + /* * This class is used for prompting of user input and echoing of messages * diff --git a/common/content/util.js b/common/content/util.js index d6499e57..3d3995f4 100644 --- a/common/content/util.js +++ b/common/content/util.js @@ -26,6 +26,8 @@ the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. }}} ***** END LICENSE BLOCK *****/ +/** @scope modules */ + const XHTML = "http://www.w3.org/1999/xhtml"; const NS = Namespace("liberator", "http://vimperator.org/namespaces/liberator"); default xml namespace = XHTML;