diff --git a/common/content/bookmarks.js b/common/content/bookmarks.js index 140ac3cc..79e19360 100644 --- a/common/content/bookmarks.js +++ b/common/content/bookmarks.js @@ -6,8 +6,6 @@ // given in the LICENSE.txt file included with this file. "use strict"; -var DEFAULT_FAVICON = "chrome://mozapps/skin/places/defaultFavicon.png"; - // also includes methods for dealing with keywords and search engines var Bookmarks = Module("bookmarks", { init: function () { diff --git a/common/content/hints.js b/common/content/hints.js index d4774167..2f4f7230 100644 --- a/common/content/hints.js +++ b/common/content/hints.js @@ -19,9 +19,8 @@ var HintSession = Class("HintSession", CommandMode, { this.forceOpen = opts.forceOpen || dactyl.forceOpen; - // Hack. - if (!opts.window && modes.main == modes.OUTPUT_MULTILINE) - opts.window = commandline.widgets.multilineOutput.contentWindow; + if (!opts.window) + opts.window = modes.getStack(0).params.window; this.hintMode = hints.modes[mode]; dactyl.assert(this.hintMode); @@ -760,7 +759,7 @@ var Hints = Module("hints", { this.addMode("V", "View hint source in external editor", function (elem, loc) buffer.viewSource(loc, true)); this.addMode("y", "Yank hint location", function (elem, loc) dactyl.clipboardWrite(loc, true)); this.addMode("Y", "Yank hint description", function (elem) dactyl.clipboardWrite(elem.textContent || "", true)); - this.addMode("c", "Open context menu", function (elem) buffer.openContextMenu(elem)); + this.addMode("c", "Open context menu", function (elem) DOM(elem).contextmenu()); this.addMode("i", "Show image", function (elem) dactyl.open(elem.src)); this.addMode("I", "Show image in a new tab", function (elem) dactyl.open(elem.src, dactyl.NEW_TAB)); diff --git a/common/content/history.js b/common/content/history.js index d898041a..30d5935c 100644 --- a/common/content/history.js +++ b/common/content/history.js @@ -36,12 +36,12 @@ var History = Module("history", { let root = services.history.executeQuery(query, options).root; root.containerOpen = true; try { - let items = iter(util.range(0, root.childCount)).map(function (i) { + var items = iter(util.range(0, root.childCount)).map(function (i) { let node = root.getChild(i); return { url: node.uri, title: node.title, - icon: node.icon ? node.icon : DEFAULT_FAVICON + icon: node.icon ? node.icon : BookmarkCache.DEFAULT_FAVICON }; }).toArray(); } diff --git a/common/modules/bookmarkcache.jsm b/common/modules/bookmarkcache.jsm index 1d984af0..175ce1ad 100644 --- a/common/modules/bookmarkcache.jsm +++ b/common/modules/bookmarkcache.jsm @@ -227,6 +227,8 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), { } } }, { + DEFAULT_FAVICON: "chrome://mozapps/skin/places/defaultFavicon.png", + getAnnotation: function getAnnotation(item, anno) services.annotation.itemHasAnnotation(item, anno) ? services.annotation.getItemAnnotation(item, anno) : null, diff --git a/common/content/buffer.js b/common/modules/buffer.jsm similarity index 82% rename from common/content/buffer.js rename to common/modules/buffer.jsm index a1a2782f..a59de322 100644 --- a/common/content/buffer.js +++ b/common/modules/buffer.jsm @@ -4,9 +4,17 @@ // // This work is licensed for reuse under an MIT license. Details are // given in the LICENSE.txt file included with this file. -"use strict"; +try {"use strict"; -/** @scope modules */ +Components.utils.import("resource://dactyl/bootstrap.jsm"); +defineModule("buffer", { + exports: ["Buffer", "buffer"], + require: ["prefs", "services", "util"] +}, this); + +this.lazyRequire("finder", ["RangeFind"]); +this.lazyRequire("template", ["template"]); +this.lazyRequire("overlay", ["overlay"]); /** * A class to manage the primary web content buffer. The name comes @@ -14,24 +22,33 @@ * files. * @instance buffer */ -var Buffer = Module("buffer", { +var Buffer = Module("Buffer", { + Local: function Local(dactyl, modules, window) ({ + get win() { + return window.content; + + let win = services.focus.focusedWindow; + if (!win || win == window || util.topWindow(win) != window) + return window.content + if (win.top == window) + return win; + return win.top; + } + }), + init: function init(win) { if (win) this.win = win; - else - this.__defineGetter__("win", function () content); }, - addPageInfoSection: deprecated("Buffer.addPageInfoSection", - { get: function addPageInfoSection() Buffer.closure.addPageInfoSection }), + get addPageInfoSection() Buffer.closure.addPageInfoSection, - pageInfo: deprecated("Buffer.pageInfo", - { get: function pageInfo() Buffer.pageInfo }), + get pageInfo() Buffer.pageInfo, // called when the active document is scrolled _updateBufferPosition: function _updateBufferPosition() { - statusline.updateBufferPosition(); - commandline.clear(true); + this.modules.statusline.updateBufferPosition(); + this.modules.commandline.clear(true); }, /** @@ -39,7 +56,8 @@ var Buffer = Module("buffer", { * buffer. Only returns style sheets for the 'screen' media type. */ get alternateStyleSheets() { - let stylesheets = window.getAllStyleSheets(this.focusedFrame); + let stylesheets = array.flatten( + this.allFrames().map(function (w) Array.slice(w.document.styleSheets))); return stylesheets.filter( function (stylesheet) /^(screen|all|)$/i.test(stylesheet.media.mediaText) && !/^\s*$/.test(stylesheet.title) @@ -47,18 +65,22 @@ var Buffer = Module("buffer", { }, climbUrlPath: function climbUrlPath(count) { - let url = buffer.documentURI.clone(); + let { dactyl } = this.modules; + + let url = this.documentURI.clone(); dactyl.assert(url instanceof Ci.nsIURL); while (count-- && url.path != "/") url.path = url.path.replace(/[^\/]+\/*$/, ""); - dactyl.assert(!url.equals(buffer.documentURI)); + dactyl.assert(!url.equals(this.documentURI)); dactyl.open(url.spec); }, incrementURL: function incrementURL(count) { - let matches = buffer.uri.spec.match(/(.*?)(\d+)(\D*)$/); + let { dactyl } = this.modules; + + let matches = this.uri.spec.match(/(.*?)(\d+)(\D*)$/); dactyl.assert(matches); let oldNum = matches[2]; @@ -85,10 +107,11 @@ var Buffer = Module("buffer", { * tab. */ get localStore() { - let doc = content.document; + let { doc } = this; + let store = overlay.getData(doc, "buffer", null); - if (!store || !buffer.localStorePrototype.isPrototypeOf(store)) - store = overlay.setData(doc, "buffer", Object.create(buffer.localStorePrototype)); + if (!store || !this.localStorePrototype.isPrototypeOf(store)) + store = overlay.setData(doc, "buffer", Object.create(this.localStorePrototype)); return store.instance = store; }, @@ -115,6 +138,13 @@ var Buffer = Module("buffer", { */ get doc() this.win.document, + get docShell() util.docShell(this.win), + + get modules() this.topWindow.dactyl.modules, + set modules(val) {}, + + topWindow: Class.Memoize(function () util.topWindow(this.win)), + /** * @property {nsIURI} The current top-level document's URI. */ @@ -136,20 +166,25 @@ var Buffer = Module("buffer", { */ get pageHeight() this.win.innerHeight, + get contentViewer() this.docShell.contentViewer + .QueryInterface(Components.interfaces.nsIMarkupDocumentViewer), + /** * @property {number} The current browser's zoom level, as a * percentage with 100 as 'normal'. */ - get zoomLevel() config.browser.markupDocumentViewer[this.fullZoom ? "fullZoom" : "textZoom"] * 100, + get zoomLevel() this.contentViewer[this.fullZoom ? "fullZoom" : "textZoom"] * 100, set zoomLevel(value) { this.setZoom(value, this.fullZoom); }, /** * @property {boolean} Whether the current browser is using full * zoom, as opposed to text zoom. */ - get fullZoom() ZoomManager.useFullZoom, + get fullZoom() this.ZoomManager.useFullZoom, set fullZoom(value) { this.setZoom(this.zoomLevel, value); }, + get ZoomManager() this.topWindow.ZoomManager, + /** * @property {string} The current document's title. */ @@ -187,13 +222,14 @@ var Buffer = Module("buffer", { allFrames: function allFrames(win, focusedFirst) { let frames = []; (function rec(frame) { - if (true || frame.document.body instanceof HTMLBodyElement) + if (true || frame.document.body instanceof Ci.nsIDOMHTMLBodyElement) frames.push(frame); Array.forEach(frame.frames, rec); })(win || this.win); + if (focusedFirst) - return frames.filter(function (f) f === buffer.focusedFrame).concat( - frames.filter(function (f) f !== buffer.focusedFrame)); + return frames.filter(function (f) f === this.focusedFrame).concat( + frames.filter(function (f) f !== this.focusedFrame)); return frames; }, @@ -226,9 +262,11 @@ var Buffer = Module("buffer", { * @returns {boolean} */ focusAllowed: function focusAllowed(elem) { - if (elem instanceof Window && !Editor.getEditor(elem)) + if (elem instanceof Ci.nsIDOMWindow && !DOM(elem).isEditable) return true; + let { options } = this.modules; + let doc = elem.ownerDocument || elem.document || elem; switch (options.get("strictfocus").getKey(doc.documentURIObject || util.newURI(doc.documentURI), "moderate")) { case "despotic": @@ -250,28 +288,33 @@ var Buffer = Module("buffer", { * @param {Node} elem The element to focus. */ focusElement: function focusElement(elem) { + let { dactyl } = this.modules; + let win = elem.ownerDocument && elem.ownerDocument.defaultView || elem; overlay.setData(elem, "focus-allowed", true); overlay.setData(win.document, "focus-allowed", true); - if (isinstance(elem, [HTMLFrameElement, HTMLIFrameElement])) + if (isinstance(elem, [Ci.nsIDOMHTMLFrameElement, + Ci.nsIDOMHTMLIFrameElement])) elem = elem.contentWindow; + if (elem.document) overlay.setData(elem.document, "focus-allowed", true); - if (elem instanceof HTMLInputElement && elem.type == "file") { + if (elem instanceof Ci.nsIDOMHTMLInputElement && elem.type == "file") { Buffer.openUploadPrompt(elem); this.lastInputField = elem; } else { - if (isinstance(elem, [HTMLInputElement, XULTextBoxElement])) + if (isinstance(elem, [Ci.nsIDOMHTMLInputElement, + Ci.nsIDOMXULTextBoxElement])) var flags = services.focus.FLAG_BYMOUSE; else flags = services.focus.FLAG_SHOWRING; if (!overlay.getData(elem, "had-focus", false) && elem.value && - elem instanceof HTMLInputElement && + elem instanceof Ci.nsIDOMHTMLInputElement && Editor.getEditor(elem) && elem.selectionStart != null && elem.selectionStart == elem.selectionEnd) @@ -279,7 +322,7 @@ var Buffer = Module("buffer", { dactyl.focus(elem, flags); - if (elem instanceof Window) { + if (elem instanceof Ci.nsIDOMWindow) { let sel = elem.getSelection(); if (sel && !sel.rangeCount) sel.addRange(RangeFind.endpoint( @@ -297,7 +340,7 @@ var Buffer = Module("buffer", { } // for imagemap - if (elem instanceof HTMLAreaElement) { + if (elem instanceof Ci.nsIDOMHTMLAreaElement) { try { let [x, y] = elem.getAttribute("coords").split(",").map(parseFloat); @@ -326,6 +369,8 @@ var Buffer = Module("buffer", { * @param {string} path The CSS to use for the search. @optional */ findLink: function findLink(rel, regexps, count, follow, path) { + let { dactyl, options } = this.modules; + let selector = path || options.get("hinttags").stringDefaultValue; function followFrame(frame) { @@ -368,6 +413,8 @@ var Buffer = Module("buffer", { }, followDocumentRelationship: deprecated("buffer.findLink", function followDocumentRelationship(rel) { + let { options } = this.modules; + this.findLink(rel, options[rel + "pattern"], 0, true); }), @@ -379,25 +426,31 @@ var Buffer = Module("buffer", { * {@link dactyl.open}. */ followLink: function followLink(elem, where) { + let { dactyl } = this.modules; + let doc = elem.ownerDocument; let win = doc.defaultView; let { left: offsetX, top: offsetY } = elem.getBoundingClientRect(); - if (isinstance(elem, [HTMLFrameElement, HTMLIFrameElement])) + if (isinstance(elem, [Ci.nsIDOMHTMLFrameElement, + Ci.nsIDOMHTMLIFrameElement])) return this.focusElement(elem); - if (isinstance(elem, HTMLLinkElement)) + + if (isinstance(elem, Ci.nsIDOMHTMLLinkElement)) return dactyl.open(elem.href, where); - if (elem instanceof HTMLAreaElement) { // for imagemap + if (elem instanceof Ci.nsIDOMHTMLAreaElement) { // for imagemap let coords = elem.getAttribute("coords").split(","); offsetX = Number(coords[0]) + 1; offsetY = Number(coords[1]) + 1; } - else if (elem instanceof HTMLInputElement && elem.type == "file") { + else if (elem instanceof Ci.nsIDOMHTMLInputElement && elem.type == "file") { Buffer.openUploadPrompt(elem); return; } + let { dactyl } = this.modules; + let ctrlKey = false, shiftKey = false; switch (dactyl.forceTarget || where) { case dactyl.NEW_TAB: @@ -442,11 +495,7 @@ var Buffer = Module("buffer", { * * @param {Node} elem The context element. */ - openContextMenu: function openContextMenu(elem) { - document.popupNode = elem; - let menu = document.getElementById("contentAreaContextMenu"); - menu.showPopup(elem, -1, -1, "context", "bottomleft", "topleft"); - }, + openContextMenu: deprecated("DOM#contextmenu", function openContextMenu(elem) DOM(elem).contextmenu()), /** * Saves a page link to disk. @@ -454,12 +503,16 @@ var Buffer = Module("buffer", { * @param {HTMLAnchorElement} elem The page link to save. */ saveLink: function saveLink(elem) { + let { completion, dactyl, io } = modules; + + let self = this; let doc = elem.ownerDocument; let uri = util.newURI(elem.href || elem.src, null, util.newURI(elem.baseURI)); let referrer = util.newURI(doc.documentURI, doc.characterSet); try { - window.urlSecurityCheck(uri.spec, doc.nodePrincipal); + services.security.checkLoadURIWithPrincipal(doc.nodePrincipal, uri, + services.security.STANDARD); io.CommandFileMode(_("buffer.prompt.saveLink") + " ", { onSubmit: function (path) { @@ -475,7 +528,7 @@ var Buffer = Module("buffer", { util.assert(false, _("save.invalidDestination", e.name)); } - buffer.saveURI(uri, file); + self.saveURI(uri, file); }, completer: function (context) completion.savePage(context, elem) @@ -497,6 +550,7 @@ var Buffer = Module("buffer", { persist.persistFlags = persist.PERSIST_FLAGS_FROM_CACHE | persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES; + let window = this.topWindow; let downloadListener = new window.DownloadListener(window, services.Transfer(uri, File(file).URI, "", null, null, null, persist)); @@ -504,7 +558,7 @@ var Buffer = Module("buffer", { persist.progressListener = update(Object.create(downloadListener), { onStateChange: util.wrapCallback(function onStateChange(progress, request, flags, status) { if (callback && (flags & Ci.nsIWebProgressListener.STATE_STOP) && status == 0) - dactyl.trapErrors(callback, self, uri, file, progress, request, flags, status); + util.trapErrors(callback, self, uri, file, progress, request, flags, status); return onStateChange.superapply(this, arguments); }) @@ -544,6 +598,8 @@ var Buffer = Module("buffer", { Buffer.scrollToPosition(this.findScrollable(0, vertical == null), horizontal, vertical), _scrollByScrollSize: function _scrollByScrollSize(count, direction) { + let { options } = this.modules; + if (count > 0) options["scroll"] = count; this.scrollByScrollSize(direction); @@ -558,6 +614,8 @@ var Buffer = Module("buffer", { * @optional */ scrollByScrollSize: function scrollByScrollSize(direction, count) { + let { options } = this.modules; + direction = direction ? 1 : -1; count = count || 1; @@ -580,9 +638,9 @@ var Buffer = Module("buffer", { */ findScrollable: function findScrollable(dir, horizontal) { function find(elem) { - while (elem && !(elem instanceof Element) && elem.parentNode) + while (elem && !(elem instanceof Ci.nsIDOMElement) && elem.parentNode) elem = elem.parentNode; - for (; elem instanceof Element; elem = elem.parentNode) + for (; elem instanceof Ci.nsIDOMElement; elem = elem.parentNode) if (Buffer.isScrollable(elem, dir, horizontal)) break; @@ -605,20 +663,22 @@ var Buffer = Module("buffer", { if (elem) elem = find(elem); - if (!(elem instanceof Element)) { + if (!(elem instanceof Ci.nsIDOMElement)) { let doc = this.findScrollableWindow().document; elem = find(doc.body || doc.getElementsByTagName("body")[0] || doc.documentElement); } let doc = this.focusedFrame.document; - return dactyl.assert(elem || doc.body || doc.documentElement); + return util.assert(elem || doc.body || doc.documentElement); }, /** * Find the best candidate scrollable frame in the current buffer. */ findScrollableWindow: function findScrollableWindow() { - let win = window.document.commandDispatcher.focusedWindow; + let { document } = this.topWindow; + + let win = document.commandDispatcher.focusedWindow; if (win && (win.scrollMaxX > 0 || win.scrollMaxY > 0)) return win; @@ -648,12 +708,14 @@ var Buffer = Module("buffer", { * @param {boolean} offScreen If true, include only off-screen elements. @optional */ findJump: function findJump(arg, count, reverse, offScreen) { + let { options } = this.modules; + const FUDGE = 10; marks.push(); let path = options["jumptags"][arg]; - dactyl.assert(path, _("error.invalidArgument", arg)); + util.assert(path, _("error.invalidArgument", arg)); let distance = reverse ? function (rect) -rect.top : function (rect) rect.top; let elems = [[e, distance(e.getBoundingClientRect())] for (e in path.matcher(this.focusedFrame.document))] @@ -661,10 +723,10 @@ var Buffer = Module("buffer", { .sort(function (a, b) a[1] - b[1]) if (offScreen && !reverse) - elems = elems.filter(function (e) e[1] > this, window.innerHeight); + elems = elems.filter(function (e) e[1] > this, this.topWindow.innerHeight); let idx = Math.min((count || 1) - 1, elems.length); - dactyl.assert(idx in elems); + util.assert(idx in elems); let elem = elems[idx][0]; elem.scrollIntoView(true); @@ -683,7 +745,9 @@ var Buffer = Module("buffer", { * count skips backwards. */ shiftFrameFocus: function shiftFrameFocus(count) { - if (!(this.doc instanceof HTMLDocument)) + let { dactyl } = this.modules; + + if (!(this.doc instanceof Ci.nsIDOMHTMLDocument)) return; let frames = this.allFrames(); @@ -692,7 +756,7 @@ var Buffer = Module("buffer", { return; // remove all hidden frames - frames = frames.filter(function (frame) !(frame.document.body instanceof HTMLFrameSetElement)) + frames = frames.filter(function (frame) !(frame.document.body instanceof Ci.nsIDOMHTMLFrameSetElement)) .filter(function (frame) !frame.frameElement || let (rect = frame.frameElement.getBoundingClientRect()) rect.width && rect.height); @@ -731,6 +795,8 @@ var Buffer = Module("buffer", { * @param {Node} elem The element to query. */ showElementInfo: function showElementInfo(elem) { + let { dactyl } = this.modules; + dactyl.echo(<>Element:
{util.objectToString(elem, true)}, commandline.FORCE_MULTILINE); }, @@ -742,6 +808,8 @@ var Buffer = Module("buffer", { * @default The value of 'pageinfo'. */ showPageInfo: function showPageInfo(verbose, sections) { + let { commandline, dactyl, options } = this.modules; + let self = this; // Ctrl-g single line output @@ -766,17 +834,19 @@ var Buffer = Module("buffer", { return template.table(title, action.call(self, true)); },
); - dactyl.echo(list, commandline.FORCE_MULTILINE); + commandline.commandOutput(list); }, /** * Stops loading and animations in the current content. */ stop: function stop() { + let { config } = this.modules; + if (config.stop) config.stop(); else - config.browser.mCurrentBrowser.stop(); + this.docShell.stop(this.docShell.STOP_ALL); }, /** @@ -785,8 +855,10 @@ var Buffer = Module("buffer", { */ viewSelectionSource: function viewSelectionSource() { // copied (and tuned somewhat) from browser.jar -> nsContextMenu.js + let { document, window } = this.topWindow; + let win = document.commandDispatcher.focusedWindow; - if (win == window) + if (win == this.topWindow) win = this.focusedFrame; let charset = win ? "charset=" + win.document.characterSet : null; @@ -814,6 +886,10 @@ var Buffer = Module("buffer", { * @param {boolean} useExternalEditor View the source in the external editor. */ viewSource: function viewSource(loc, useExternalEditor) { + let { dactyl, options } = this.modules; + + let window = this.topWindow; + let doc = this.focusedFrame.document; if (isObject(loc)) { @@ -837,7 +913,7 @@ var Buffer = Module("buffer", { let sh = history.session; if (sh[sh.index].URI.spec == url) - window.getWebNavigation().gotoIndex(sh.index); + this.docShell.gotoIndex(sh.index); else dactyl.open(url, { hide: true }); } @@ -938,22 +1014,31 @@ var Buffer = Module("buffer", { * closed range [Buffer.ZOOM_MIN, Buffer.ZOOM_MAX]. */ setZoom: function setZoom(value, fullZoom) { - dactyl.assert(value >= Buffer.ZOOM_MIN || value <= Buffer.ZOOM_MAX, - _("zoom.outOfRange", Buffer.ZOOM_MIN, Buffer.ZOOM_MAX)); + let { dactyl, statusline } = this.modules; + let { ZoomManager } = this; - if (fullZoom !== undefined) + util.assert(value >= Buffer.ZOOM_MIN || value <= Buffer.ZOOM_MAX, + _("zoom.outOfRange", Buffer.ZOOM_MIN, Buffer.ZOOM_MAX)); + + if (fullZoom === undefined) + fullZoom = ZoomManager.useFullZoom; + else ZoomManager.useFullZoom = fullZoom; + + value /= 100; try { - ZoomManager.zoom = value / 100; + this.contentViewer.textZoom = fullZoom ? 1 : value; + this.contentViewer.fullZoom = !fullZoom ? 1 : value; } catch (e if e == Cr.NS_ERROR_ILLEGAL_VALUE) { return dactyl.echoerr(_("zoom.illegal")); } - if ("FullZoom" in window) - FullZoom._applySettingToPref(); + if (fullZoom && services.has("contentPrefs")) + services.contentPrefs.setPref(this.uri, "browser.content.full-zoom", + value); - statusline.updateZoomLevel(value, ZoomManager.useFullZoom); + statusline.updateZoomLevel(); }, /** @@ -970,6 +1055,8 @@ var Buffer = Module("buffer", { * extreme in the given direction. */ bumpZoomLevel: function bumpZoomLevel(steps, fullZoom) { + let { ZoomManager } = this; + if (fullZoom === undefined) fullZoom = ZoomManager.useFullZoom; @@ -977,20 +1064,20 @@ var Buffer = Module("buffer", { let cur = values.indexOf(ZoomManager.snap(ZoomManager.zoom)); let i = Math.constrain(cur + steps, 0, values.length - 1); - dactyl.assert(i != cur || fullZoom != ZoomManager.useFullZoom); + util.assert(i != cur || fullZoom != ZoomManager.useFullZoom); this.setZoom(Math.round(values[i] * 100), fullZoom); }, getAllFrames: deprecated("buffer.allFrames", "allFrames"), - scrollTop: deprecated("buffer.scrollToPercent", function scrollTop() buffer.scrollToPercent(null, 0)), - scrollBottom: deprecated("buffer.scrollToPercent", function scrollBottom() buffer.scrollToPercent(null, 100)), - scrollStart: deprecated("buffer.scrollToPercent", function scrollStart() buffer.scrollToPercent(0, null)), - scrollEnd: deprecated("buffer.scrollToPercent", function scrollEnd() buffer.scrollToPercent(100, null)), - scrollColumns: deprecated("buffer.scrollHorizontal", function scrollColumns(cols) buffer.scrollHorizontal("columns", cols)), - scrollPages: deprecated("buffer.scrollHorizontal", function scrollPages(pages) buffer.scrollVertical("pages", pages)), + scrollTop: deprecated("buffer.scrollToPercent", function scrollTop() this.scrollToPercent(null, 0)), + scrollBottom: deprecated("buffer.scrollToPercent", function scrollBottom() this.scrollToPercent(null, 100)), + scrollStart: deprecated("buffer.scrollToPercent", function scrollStart() this.scrollToPercent(0, null)), + scrollEnd: deprecated("buffer.scrollToPercent", function scrollEnd() this.scrollToPercent(100, null)), + scrollColumns: deprecated("buffer.scrollHorizontal", function scrollColumns(cols) this.scrollHorizontal("columns", cols)), + scrollPages: deprecated("buffer.scrollHorizontal", function scrollPages(pages) this.scrollVertical("pages", pages)), scrollTo: deprecated("Buffer.scrollTo", function scrollTo(x, y) this.win.scrollTo(x, y)), - textZoom: deprecated("buffer.zoomValue/buffer.fullZoom", function textZoom() config.browser.markupDocumentViewer.textZoom * 100) + textZoom: deprecated("buffer.zoomValue/buffer.fullZoom", function textZoom() this.contentViewer.markupDocumentViewer.textZoom * 100) }, { PageInfo: Struct("PageInfo", "name", "title", "action") .localize("title"), @@ -1011,9 +1098,9 @@ var Buffer = Module("buffer", { }, Scrollable: function Scrollable(elem) { - if (elem instanceof Element) + if (elem instanceof Ci.nsIDOMElement) return elem; - if (isinstance(elem, [Window, Document])) + if (isinstance(elem, [Ci.nsIDOMWindow, Ci.nsIDOMDocument])) return { __proto__: elem.documentElement || elem.ownerDocument.documentElement, @@ -1034,11 +1121,13 @@ var Buffer = Module("buffer", { return elem; }, - ZOOM_MIN: Class.Memoize(function () prefs.get("zoom.minPercent")), - ZOOM_MAX: Class.Memoize(function () prefs.get("zoom.maxPercent")), + get ZOOM_MIN() prefs.get("zoom.minPercent"), + get ZOOM_MAX() prefs.get("zoom.maxPercent"), - setZoom: deprecated("buffer.setZoom", function setZoom() buffer.setZoom.apply(buffer, arguments)), - bumpZoomLevel: deprecated("buffer.bumpZoomLevel", function bumpZoomLevel() buffer.bumpZoomLevel.apply(buffer, arguments)), + setZoom: deprecated("buffer.setZoom", function setZoom() + let ({ buffer } = overlay.activeModules) buffer.setZoom.apply(buffer, arguments)), + bumpZoomLevel: deprecated("buffer.bumpZoomLevel", function bumpZoomLevel() + let ({ buffer } = overlay.activeModules) buffer.bumpZoomLevel.apply(buffer, arguments)), /** * Returns the currently selected word in *win*. If the selection is @@ -1047,12 +1136,14 @@ var Buffer = Module("buffer", { * @returns {string} */ currentWord: function currentWord(win, select) { + let { options } = this.modules; + let selection = win.getSelection(); if (selection.rangeCount == 0) return ""; let range = selection.getRangeAt(0).cloneRange(); - if (range.collapsed && range.startContainer instanceof Text) { + if (range.collapsed && range.startContainer instanceof Ci.nsIDOMText) { let re = options.get("iskeyword").regexp; Editor.extendRange(range, true, re, true); Editor.extendRange(range, false, re, true); @@ -1068,7 +1159,8 @@ var Buffer = Module("buffer", { let url = node.href || node.src || node.documentURI; let currExt = url.replace(/^.*?(?:\.([a-z0-9]+))?$/i, "$1").toLowerCase(); - if (isinstance(node, [Document, HTMLImageElement])) { + if (isinstance(node, [Ci.nsIDOMDocument, + Ci.nsIDOMHTMLImageElement])) { let type = node.contentType || node.QueryInterface(Ci.nsIImageLoadingContent) .getRequest(0).mimeType; @@ -1090,7 +1182,7 @@ var Buffer = Module("buffer", { if (node.alt) names.push([node.alt, /*L*/"Alternate Text"]); - if (!isinstance(node, Document) && node.textContent) + if (!isinstance(node, Ci.nsIDOMDocument) && node.textContent) names.push([node.textContent, /*L*/"Link Text"]); names.push([decodeURIComponent(url.replace(/.*?([^\/]*)\/*$/, "$1")), "File Name"]); @@ -1100,8 +1192,10 @@ var Buffer = Module("buffer", { .replace(re, ext), title]); }, - findScrollableWindow: deprecated("buffer.findScrollableWindow", function findScrollableWindow() buffer.findScrollableWindow.apply(buffer, arguments)), - findScrollable: deprecated("buffer.findScrollable", function findScrollable() buffer.findScrollable.apply(buffer, arguments)), + findScrollableWindow: deprecated("buffer.findScrollableWindow", function findScrollableWindow() + let ({ buffer } = overlay.activeModules) buffer.findScrollableWindow.apply(buffer, arguments)), + findScrollable: deprecated("buffer.findScrollable", function findScrollable() + let ({ buffer } = overlay.activeModules) buffer.findScrollable.apply(buffer, arguments)), isScrollable: function isScrollable(elem, dir, horizontal) { if (!DOM(elem).isScrollable(horizontal ? "horizontal" : "vertical")) @@ -1143,6 +1237,10 @@ var Buffer = Module("buffer", { * {@link marks.push}. @optional */ scrollTo: function scrollTo(elem, left, top, reason) { + let doc = elem.ownerDocument || elem.document || elem; + + let { buffer, marks, options } = util.topWindow(doc.defaultView).dactyl.modules; + if (~[elem, elem.document, elem.ownerDocument].indexOf(buffer.focusedFrame.document)) marks.push(reason); @@ -1161,6 +1259,8 @@ var Buffer = Module("buffer", { * marks. */ smoothScrollTo: function smoothScrollTo(node, x, y) { + let { options } = overlay.activeModules; + let time = options["scrolltime"]; let steps = options["scrollsteps"]; @@ -1212,7 +1312,7 @@ var Buffer = Module("buffer", { else throw Error(); - dactyl.assert(number < 0 ? elem.scrollLeft > 0 : elem.scrollLeft < elem.scrollWidth - elem.clientWidth); + util.assert(number < 0 ? elem.scrollLeft > 0 : elem.scrollLeft < elem.scrollWidth - elem.clientWidth); let left = node.dactylScrollDestX !== undefined ? node.dactylScrollDestX : elem.scrollLeft; node.dactylScrollDestX = undefined; @@ -1221,7 +1321,7 @@ var Buffer = Module("buffer", { }, /** - * Scrolls the currently given element vertically. + * Scrolls the given element vertically. * * @param {Element} elem The element to scroll. * @param {string} unit The increment by which to scroll. @@ -1244,7 +1344,7 @@ var Buffer = Module("buffer", { else throw Error(); - dactyl.assert(number < 0 ? elem.scrollTop > 0 : elem.scrollTop < elem.scrollHeight - elem.clientHeight); + util.assert(number < 0 ? elem.scrollTop > 0 : elem.scrollTop < elem.scrollHeight - elem.clientHeight); let top = node.dactylScrollDestY !== undefined ? node.dactylScrollDestY : elem.scrollTop; node.dactylScrollDestY = undefined; @@ -1319,10 +1419,12 @@ var Buffer = Module("buffer", { }, openUploadPrompt: function openUploadPrompt(elem) { + let { io } = overlay.activeModules; + io.CommandFileMode(_("buffer.prompt.uploadFile") + " ", { onSubmit: function onSubmit(path) { let file = io.File(path); - dactyl.assert(file.exists()); + util.assert(file.exists()); DOM(elem).val(file.path).change(); } @@ -1330,184 +1432,7 @@ var Buffer = Module("buffer", { } }, { init: function init(dactyl, modules, window) { - - Buffer.addPageInfoSection("e", "Search Engines", function (verbose) { - - let n = 1; - let nEngines = 0; - for (let { document: doc } in values(this.allFrames())) { - let engines = DOM("link[href][rel=search][type='application/opensearchdescription+xml']", doc); - nEngines += engines.length; - - if (verbose) - for (let link in engines) - yield [link.title || /*L*/ "Engine " + n++, - {link.href}]; - } - - if (!verbose && nEngines) - yield nEngines + /*L*/" engine" + (nEngines > 1 ? "s" : ""); - }); - - Buffer.addPageInfoSection("f", "Feeds", function (verbose) { - const feedTypes = { - "application/rss+xml": "RSS", - "application/atom+xml": "Atom", - "text/xml": "XML", - "application/xml": "XML", - "application/rdf+xml": "XML" - }; - - function isValidFeed(data, principal, isFeed) { - if (!data || !principal) - return false; - - if (!isFeed) { - var type = data.type && data.type.toLowerCase(); - type = type.replace(/^\s+|\s*(?:;.*)?$/g, ""); - - isFeed = ["application/rss+xml", "application/atom+xml"].indexOf(type) >= 0 || - // really slimy: general XML types with magic letters in the title - type in feedTypes && /\brss\b/i.test(data.title); - } - - if (isFeed) { - try { - window.urlSecurityCheck(data.href, principal, - Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL); - } - catch (e) { - isFeed = false; - } - } - - if (type) - data.type = type; - - return isFeed; - } - - let nFeed = 0; - for (let [i, win] in Iterator(this.allFrames())) { - let doc = win.document; - - for (let link in DOM("link[href][rel=feed], link[href][rel=alternate][type]", doc)) { - let rel = link.rel.toLowerCase(); - let feed = { title: link.title, href: link.href, type: link.type || "" }; - if (isValidFeed(feed, doc.nodePrincipal, rel == "feed")) { - nFeed++; - let type = feedTypes[feed.type] || "RSS"; - if (verbose) - yield [feed.title, template.highlightURL(feed.href, true) +  ({type})]; - } - } - - } - - if (!verbose && nFeed) - yield nFeed + /*L*/" feed" + (nFeed > 1 ? "s" : ""); - }); - - Buffer.addPageInfoSection("g", "General Info", function (verbose) { - let doc = this.focusedFrame.document; - - // get file size - const ACCESS_READ = Ci.nsICache.ACCESS_READ; - let cacheKey = doc.documentURI; - - for (let proto in array.iterValues(["HTTP", "FTP"])) { - try { - var cacheEntryDescriptor = services.cache.createSession(proto, 0, true) - .openCacheEntry(cacheKey, ACCESS_READ, false); - break; - } - catch (e) {} - } - - let pageSize = []; // [0] bytes; [1] kbytes - if (cacheEntryDescriptor) { - pageSize[0] = util.formatBytes(cacheEntryDescriptor.dataSize, 0, false); - pageSize[1] = util.formatBytes(cacheEntryDescriptor.dataSize, 2, true); - if (pageSize[1] == pageSize[0]) - pageSize.length = 1; // don't output "xx Bytes" twice - } - - let lastModVerbose = new Date(doc.lastModified).toLocaleString(); - let lastMod = new Date(doc.lastModified).toLocaleFormat("%x %X"); - - if (lastModVerbose == "Invalid Date" || new Date(doc.lastModified).getFullYear() == 1970) - lastModVerbose = lastMod = null; - - if (!verbose) { - if (pageSize[0]) - yield (pageSize[1] || pageSize[0]) + /*L*/" bytes"; - yield lastMod; - return; - } - - yield ["Title", doc.title]; - yield ["URL", template.highlightURL(doc.location.href, true)]; - - let ref = "referrer" in doc && doc.referrer; - if (ref) - yield ["Referrer", template.highlightURL(ref, true)]; - - if (pageSize[0]) - yield ["File Size", pageSize[1] ? pageSize[1] + " (" + pageSize[0] + ")" - : pageSize[0]]; - - yield ["Mime-Type", doc.contentType]; - yield ["Encoding", doc.characterSet]; - yield ["Compatibility", doc.compatMode == "BackCompat" ? "Quirks Mode" : "Full/Almost Standards Mode"]; - if (lastModVerbose) - yield ["Last Modified", lastModVerbose]; - }); - - this.addPageInfoSection("m", "Meta Tags", function (verbose) { - if (!verbose) - return []; - - // get meta tag data, sort and put into pageMeta[] - let metaNodes = this.focusedFrame.document.getElementsByTagName("meta"); - - return Array.map(metaNodes, function (node) [(node.name || node.httpEquiv), template.highlightURL(node.content)]) - .sort(function (a, b) util.compareIgnoreCase(a[0], b[0])); - }); - - let identity = window.gIdentityHandler; - this.addPageInfoSection("s", "Security", function (verbose) { - if (!verbose || !identity) - return; // For now - - // Modified from Firefox - function location(data) array.compact([ - data.city, data.state, data.country - ]).join(", "); - - switch (statusline.security) { - case "secure": - case "extended": - var data = identity.getIdentityData(); - - yield ["Host", identity.getEffectiveHost()]; - - if (statusline.security === "extended") - yield ["Owner", data.subjectOrg]; - else - yield ["Owner", _("pageinfo.s.ownerUnverified", data.subjectOrg)]; - - if (location(data).length) - yield ["Location", location(data)]; - - yield ["Verified by", data.caOrg]; - - if (identity._overrideService.hasMatchingOverride(identity._lastLocation.hostname, - (identity._lastLocation.port || 443), - data.cert, {}, {})) - yield ["User exception", /*L*/"true"]; - break; - } - }); + init.superapply(this, arguments); dactyl.commands["buffer.viewSource"] = function (event) { let elem = event.originalTarget; @@ -1515,10 +1440,12 @@ var Buffer = Module("buffer", { if (elem.hasAttribute("column")) obj.column = elem.getAttribute("column"); - buffer.viewSource(obj); + modules.buffer.viewSource(obj); }; }, commands: function initCommands(dactyl, modules, window) { + let { buffer, commands, config, options } = modules; + commands.add(["frameo[nly]"], "Show only the current frame's page", function (args) { @@ -1583,7 +1510,7 @@ var Buffer = Module("buffer", { { argCount: "?", completer: function (context) { - completion.optionValue(context, "pageinfo", "+", ""); + modules.completion.optionValue(context, "pageinfo", "+", ""); context.title = ["Page Info"]; } }); @@ -1605,13 +1532,13 @@ var Buffer = Module("buffer", { }, { argCount: "?", - completer: function (context) completion.alternateStyleSheet(context), + completer: function (context) modules.completion.alternateStyleSheet(context), literal: 0 }); commands.add(["re[load]"], "Reload the current web page", - function (args) { tabs.reload(config.browser.mCurrentTab, args.bang); }, + function (args) { modules.tabs.reload(config.browser.mCurrentTab, args.bang); }, { argCount: "0", bang: true @@ -1621,7 +1548,9 @@ var Buffer = Module("buffer", { commands.add(["sav[eas]", "w[rite]"], "Save current document to disk", function (args) { - let doc = content.document; + let { commandline, io } = modules; + let { doc, win } = buffer; + let chosenData = null; let filename = args[0]; @@ -1666,9 +1595,9 @@ var Buffer = Module("buffer", { prefs.set("browser.download.lastDir", io.cwd.path); try { - var contentDisposition = content.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils) - .getDocumentMetadata("content-disposition"); + var contentDisposition = win.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils) + .getDocumentMetadata("content-disposition"); } catch (e) {} @@ -1681,12 +1610,14 @@ var Buffer = Module("buffer", { argCount: "?", bang: true, completer: function (context) { + let { buffer, completion } = modules; + if (context.filter[0] == "!") return; if (/^>>/.test(context.filter)) context.advance(/^>>\s*/.exec(context.filter)[0].length); - completion.savePage(context, content.document); + completion.savePage(context, buffer.doc); context.fork("file", 0, completion, "file"); }, literal: 0 @@ -1703,7 +1634,7 @@ var Buffer = Module("buffer", { { argCount: "?", bang: true, - completer: function (context) completion.url(context, "bhf") + completer: function (context) modules.completion.url(context, "bhf") }); commands.add(["zo[om]"], @@ -1731,6 +1662,8 @@ var Buffer = Module("buffer", { }); }, completion: function initCompletion(dactyl, modules, window) { + let { CompletionContext, buffer, completion } = modules; + completion.alternateStyleSheet = function alternateStylesheet(context) { context.title = ["Stylesheet", "Location"]; @@ -1745,6 +1678,8 @@ var Buffer = Module("buffer", { }; completion.buffer = function buffer(context, visible) { + let { tabs } = modules; + let filter = context.filter.toLowerCase(); let defItem = { parent: { getTitle: function () "" } }; @@ -1799,7 +1734,7 @@ var Buffer = Module("buffer", { tab: tab, id: i, url: url, - icon: tab.image || DEFAULT_FAVICON + icon: tab.image || BookmarkCache.DEFAULT_FAVICON }; }); }, vals); @@ -1813,9 +1748,13 @@ var Buffer = Module("buffer", { }; }, events: function initEvents(dactyl, modules, window) { + let { buffer, config, events } = modules; + events.listen(config.browser, "scroll", buffer.closure._updateBufferPosition, false); }, mappings: function initMappings(dactyl, modules, window) { + let { Events, buffer, ex, mappings, modes, options, tabs } = modules; + mappings.add([modes.NORMAL], ["y", ""], "Yank current location to the clipboard", function () { dactyl.clipboardWrite(buffer.uri.spec, true); }); @@ -1932,8 +1871,10 @@ var Buffer = Module("buffer", { mappings.add([modes.NORMAL], [""], "Scroll down a full page", function (args) { - if (isinstance((services.focus.focusedWindow || content).document.activeElement, - [HTMLInputElement, HTMLButtonElement, Ci.nsIDOMXULButtonElement])) + if (isinstance((services.focus.focusedWindow || buffer.win).document.activeElement, + [Ci.nsIDOMHTMLInputElement, + Ci.nsIDOMHTMLButtonElement, + Ci.nsIDOMXULButtonElement])) return Events.PASS; buffer.scrollVertical("pages", Math.max(args.count, 1)); @@ -2014,7 +1955,8 @@ var Buffer = Module("buffer", { let elements = array.flatten(frames.map(function (win) [m for (m in DOM.XPath(xpath, win.document))])) .filter(function (elem) { - if (isinstance(elem, [HTMLFrameElement, HTMLIFrameElement])) + if (isinstance(elem, [Ci.nsIDOMHTMLFrameElement, + Ci.nsIDOMHTMLIFrameElement])) return Editor.getEditor(elem.contentWindow); elem = DOM(elem); @@ -2144,6 +2086,8 @@ var Buffer = Module("buffer", { function () { buffer.showPageInfo(true); }); }, options: function initOptions(dactyl, modules, window) { + let { Option, buffer, completion, config, options } = modules; + options.add(["encoding", "enc"], "The current buffer's character encoding", "string", "UTF-8", @@ -2156,9 +2100,9 @@ var Buffer = Module("buffer", { // Stolen from browser.jar/content/browser/browser.js, more or less. try { - config.browser.docShell.QueryInterface(Ci.nsIDocCharset).charset = val; - PlacesUtils.history.setCharsetForURI(getWebNavigation().currentURI, val); - window.getWebNavigation().reload(Ci.nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE); + buffer.docShell.QueryInterface(Ci.nsIDocCharset).charset = val; + window.PlacesUtils.history.setCharsetForURI(buffer.uri, val); + buffer.docShell.reload(Ci.nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE); } catch (e) { dactyl.reportError(e); } return null; @@ -2300,10 +2244,197 @@ var Buffer = Module("buffer", { "Show current website without styling defined by the author", "boolean", false, { - setter: function (value) config.browser.markupDocumentViewer.authorStyleDisabled = value, - getter: function () config.browser.markupDocumentViewer.authorStyleDisabled + setter: function (value) buffer.contentViewer.authorStyleDisabled = value, + getter: function () buffer.contentViewer.authorStyleDisabled }); } }); +Buffer.addPageInfoSection("e", "Search Engines", function (verbose) { + let n = 1; + let nEngines = 0; + + for (let { document: doc } in values(this.allFrames())) { + let engines = DOM("link[href][rel=search][type='application/opensearchdescription+xml']", doc); + nEngines += engines.length; + + if (verbose) + for (let link in engines) + yield [link.title || /*L*/ "Engine " + n++, + {link.href}]; + } + + if (!verbose && nEngines) + yield nEngines + /*L*/" engine" + (nEngines > 1 ? "s" : ""); +}); + +Buffer.addPageInfoSection("f", "Feeds", function (verbose) { + const feedTypes = { + "application/rss+xml": "RSS", + "application/atom+xml": "Atom", + "text/xml": "XML", + "application/xml": "XML", + "application/rdf+xml": "XML" + }; + + function isValidFeed(data, principal, isFeed) { + if (!data || !principal) + return false; + + if (!isFeed) { + var type = data.type && data.type.toLowerCase(); + type = type.replace(/^\s+|\s*(?:;.*)?$/g, ""); + + isFeed = ["application/rss+xml", "application/atom+xml"].indexOf(type) >= 0 || + // really slimy: general XML types with magic letters in the title + type in feedTypes && /\brss\b/i.test(data.title); + } + + if (isFeed) { + try { + services.security.checkLoadURIStrWithPrincipal(principal, data.href, + services.security.DISALLOW_INHERIT_PRINCIPAL); + } + catch (e) { + isFeed = false; + } + } + + if (type) + data.type = type; + + return isFeed; + } + + let nFeed = 0; + for (let [i, win] in Iterator(this.allFrames())) { + let doc = win.document; + + for (let link in DOM("link[href][rel=feed], link[href][rel=alternate][type]", doc)) { + let rel = link.rel.toLowerCase(); + let feed = { title: link.title, href: link.href, type: link.type || "" }; + if (isValidFeed(feed, doc.nodePrincipal, rel == "feed")) { + nFeed++; + let type = feedTypes[feed.type] || "RSS"; + if (verbose) + yield [feed.title, template.highlightURL(feed.href, true) +  ({type})]; + } + } + + } + + if (!verbose && nFeed) + yield nFeed + /*L*/" feed" + (nFeed > 1 ? "s" : ""); +}); + +Buffer.addPageInfoSection("g", "General Info", function (verbose) { + let doc = this.focusedFrame.document; + + // get file size + const ACCESS_READ = Ci.nsICache.ACCESS_READ; + let cacheKey = doc.documentURI; + + for (let proto in array.iterValues(["HTTP", "FTP"])) { + try { + var cacheEntryDescriptor = services.cache.createSession(proto, 0, true) + .openCacheEntry(cacheKey, ACCESS_READ, false); + break; + } + catch (e) {} + } + + let pageSize = []; // [0] bytes; [1] kbytes + if (cacheEntryDescriptor) { + pageSize[0] = util.formatBytes(cacheEntryDescriptor.dataSize, 0, false); + pageSize[1] = util.formatBytes(cacheEntryDescriptor.dataSize, 2, true); + if (pageSize[1] == pageSize[0]) + pageSize.length = 1; // don't output "xx Bytes" twice + } + + let lastModVerbose = new Date(doc.lastModified).toLocaleString(); + let lastMod = new Date(doc.lastModified).toLocaleFormat("%x %X"); + + if (lastModVerbose == "Invalid Date" || new Date(doc.lastModified).getFullYear() == 1970) + lastModVerbose = lastMod = null; + + if (!verbose) { + if (pageSize[0]) + yield (pageSize[1] || pageSize[0]) + /*L*/" bytes"; + yield lastMod; + return; + } + + yield ["Title", doc.title]; + yield ["URL", template.highlightURL(doc.location.href, true)]; + + let ref = "referrer" in doc && doc.referrer; + if (ref) + yield ["Referrer", template.highlightURL(ref, true)]; + + if (pageSize[0]) + yield ["File Size", pageSize[1] ? pageSize[1] + " (" + pageSize[0] + ")" + : pageSize[0]]; + + yield ["Mime-Type", doc.contentType]; + yield ["Encoding", doc.characterSet]; + yield ["Compatibility", doc.compatMode == "BackCompat" ? "Quirks Mode" : "Full/Almost Standards Mode"]; + if (lastModVerbose) + yield ["Last Modified", lastModVerbose]; +}); + +Buffer.addPageInfoSection("m", "Meta Tags", function (verbose) { + if (!verbose) + return []; + + // get meta tag data, sort and put into pageMeta[] + let metaNodes = this.focusedFrame.document.getElementsByTagName("meta"); + + return Array.map(metaNodes, function (node) [(node.name || node.httpEquiv), template.highlightURL(node.content)]) + .sort(function (a, b) util.compareIgnoreCase(a[0], b[0])); +}); + +Buffer.addPageInfoSection("s", "Security", function (verbose) { + let { statusline } = this.modules + + let identity = this.topWindow.gIdentityHandler; + + if (!verbose || !identity) + return; // For now + + // Modified from Firefox + function location(data) array.compact([ + data.city, data.state, data.country + ]).join(", "); + + switch (statusline.security) { + case "secure": + case "extended": + var data = identity.getIdentityData(); + + yield ["Host", identity.getEffectiveHost()]; + + if (statusline.security === "extended") + yield ["Owner", data.subjectOrg]; + else + yield ["Owner", _("pageinfo.s.ownerUnverified", data.subjectOrg)]; + + if (location(data).length) + yield ["Location", location(data)]; + + yield ["Verified by", data.caOrg]; + + if (identity._overrideService.hasMatchingOverride(identity._lastLocation.hostname, + (identity._lastLocation.port || 443), + data.cert, {}, {})) + yield ["User exception", /*L*/"true"]; + break; + } +}); + +} catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); } + +endModule(); + // vim: set fdm=marker sw=4 ts=4 et: diff --git a/common/modules/config.jsm b/common/modules/config.jsm index 094b7bdd..75c854fe 100644 --- a/common/modules/config.jsm +++ b/common/modules/config.jsm @@ -107,6 +107,7 @@ var ConfigBase = Class("ConfigBase", { global: ["addons", "base", "io", + "buffer", "cache", "commands", "completion", @@ -136,7 +137,6 @@ var ConfigBase = Class("ConfigBase", { "commandline", "abbreviations", "autocommands", - "buffer", "editor", "events", "hints", diff --git a/common/modules/dom.jsm b/common/modules/dom.jsm index 482b0214..c21fddb5 100644 --- a/common/modules/dom.jsm +++ b/common/modules/dom.jsm @@ -318,7 +318,7 @@ var DOM = Class("DOM", { }), }), - get rect() this[0].getBoundingClientRect(), + get rect() this[0] ? this[0].getBoundingClientRect() : {}, get viewport() { let r = this.rect; @@ -760,7 +760,7 @@ var DOM = Class("DOM", { dispatch: function dispatch(event, params, extraProps) { this.canceled = false; return this.each(function (elem) { - let evt = DOM.Event(this.document, event, params); + let evt = DOM.Event(this.document, event, params, elem); if (!DOM.Event.dispatch(elem, evt, extraProps)) this.canceled = true; }, this); @@ -825,7 +825,7 @@ var DOM = Class("DOM", { * @param {Object} opts The pseudo-event. @optional */ Event: Class("Event", { - init: function Event(doc, type, opts) { + init: function Event(doc, type, opts, target) { const DEFAULTS = { HTML: { type: type, bubbles: true, cancelable: false @@ -842,8 +842,12 @@ var DOM = Class("DOM", { bubbles: true, cancelable: true, view: doc.defaultView, detail: 1, - screenX: 0, screenY: 0, - clientX: 0, clientY: 0, + get screenX() this.view.mozInnerScreenX + + Math.max(0, this.clientX + (DOM(target || opts.target).rect.left || 0)), + get screenY() this.view.mozInnerScreenY + + Math.max(0, this.clientY + (DOM(target || opts.target).rect.top || 0)), + clientX: 0, + clientY: 0, ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, button: 0, relatedTarget: null @@ -854,13 +858,12 @@ var DOM = Class("DOM", { var t = this.constructor.types[type] || ""; var evt = doc.createEvent(t + "Events"); - let defaults = DEFAULTS[t || "HTML"]; - update(defaults, this.constructor.defaults[type]); + let params = DEFAULTS[t || "HTML"]; + let args = Object.keys(params); + update(params, this.constructor.defaults[type], + iter.toObject([k, opts[k]] for (k in opts) if (k in params))); - let args = Object.keys(defaults) - .map(function (k) k in opts ? opts[k] : defaults[k]) - - evt["init" + t + "Event"].apply(evt, args); + evt["init" + t + "Event"].apply(evt, args.map(function (k) params[k])); return evt; } }, { @@ -1203,7 +1206,8 @@ var DOM = Class("DOM", { types: Class.Memoize(function () iter( { Mouse: "click mousedown mouseout mouseover mouseup " + - "popupshowing popupshown popuphiding popuphidden", + "popupshowing popupshown popuphiding popuphidden " + + "contextmenu", Key: "keydown keypress keyup", "": "change command dactyl-input input submit " + "load unload pageshow pagehide DOMContentLoaded" diff --git a/common/modules/finder.jsm b/common/modules/finder.jsm index d5922096..a0d88aeb 100644 --- a/common/modules/finder.jsm +++ b/common/modules/finder.jsm @@ -741,8 +741,7 @@ var RangeFind = Class("RangeFind", { this.range = range; this.document = range.startContainer.ownerDocument; this.window = this.document.defaultView; - this.docShell = this.window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell); + this.docShell = util.docShell(this.window); if (this.selection == null) return false; diff --git a/common/modules/help.jsm b/common/modules/help.jsm index 7e460576..641086b7 100644 --- a/common/modules/help.jsm +++ b/common/modules/help.jsm @@ -215,7 +215,7 @@ var Help = Module("Help", { }, flush: function flush(entries, time) { - cache.flushEntry("help", time); + cache.flushEntry("help.json", time); for (let entry in values(Array.concat(entries || []))) cache.flushEntry(entry, time); diff --git a/common/modules/services.jsm b/common/modules/services.jsm index a3009779..97e25646 100644 --- a/common/modules/services.jsm +++ b/common/modules/services.jsm @@ -36,6 +36,7 @@ var Services = Module("Services", { this.add("clipboardHelper", "@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper"); this.add("commandLineHandler", "@mozilla.org/commandlinehandler/general-startup;1?type=dactyl"); this.add("console", "@mozilla.org/consoleservice;1", "nsIConsoleService"); + this.add("contentPrefs", "@mozilla.org/content-pref/service;1", "nsIContentPrefService"); this.add("dactyl", "@dactyl.googlecode.com/extra/utils", "dactylIUtils"); this.add("dactyl:", this.PROTOCOL + "dactyl"); this.add("debugger", "@mozilla.org/js/jsd/debugger-service;1", "jsdIDebuggerService"); @@ -63,6 +64,7 @@ var Services = Module("Services", { this.add("resource:", this.PROTOCOL + "resource", ["nsIProtocolHandler", "nsIResProtocolHandler"]); this.add("runtime", "@mozilla.org/xre/runtime;1", ["nsIXULAppInfo", "nsIXULRuntime"]); this.add("rdf", "@mozilla.org/rdf/rdf-service;1", "nsIRDFService"); + this.add("security", "@mozilla.org/scriptsecuritymanager;1", "nsIScriptSecurityManager"); this.add("sessionStore", "@mozilla.org/browser/sessionstore;1", "nsISessionStore"); this.add("spell", "@mozilla.org/spellchecker/engine;1", "mozISpellCheckingEngine"); this.add("stringBundle", "@mozilla.org/intl/stringbundle;1", "nsIStringBundleService"); diff --git a/common/modules/util.jsm b/common/modules/util.jsm index 1e21f3fc..32223597 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -505,6 +505,17 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), dequote: function dequote(pattern, chars) pattern.replace(/\\(.)/, function (m0, m1) chars.indexOf(m1) >= 0 ? m1 : m0), + /** + * Returns the nsIDocShell for the given window. + * + * @param {Window} win The window for which to get the docShell. + * @returns {nsIDocShell} + */ + + docShell: function docShell(win) + win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell), + /** * Prints a message to the console. If *msg* is an object it is pretty * printed.