diff --git a/common/content/buffer.js b/common/content/buffer.js index b299c373..a8ba504d 100644 --- a/common/content/buffer.js +++ b/common/content/buffer.js @@ -519,10 +519,22 @@ const Buffer = Module("buffer", { } else { elem.focus(); - if (elem instanceof Window && elem.getSelection() && !elem.getSelection().rangeCount) - elem.getSelection().addRange(RangeFind.endpoint( - RangeFind.nodeRange(elem.document.body || elem.document.documentElement), - true)); + if (elem instanceof Window) { + let sel = elem.getSelection(); + if (sel && !sel.rangeCount) + sel.addRange(RangeFind.endpoint( + RangeFind.nodeRange(elem.document.body || elem.document.documentElement), + true)); + } + else { + let range = RangeFind.nodeRange(elem); + let sel = (elem.ownerDocument || elem).defaultView.getSelection(); + if (!sel.rangeCount || !RangeFind.intersects(range, sel.getRangeAt(0))) { + range.collapse(true); + sel.removeAllRanges(); + sel.addRange(range); + } + } // for imagemap if (elem instanceof HTMLAreaElement) { @@ -1109,9 +1121,13 @@ const Buffer = Module("buffer", { return elem; } + var elem = buffer.focusedFrame.document.activeElement; + if (elem == elem.ownerDocument.body) + elem = null; + let sel = buffer.focusedFrame.getSelection(); - if (sel && sel.rangeCount) - var elem = find(sel.getRangeAt(0).startContainer); + if (!elem && sel && sel.rangeCount) + elem = find(sel.getRangeAt(0).startContainer); if (!(elem instanceof Element)) { let doc = Buffer.findScrollableWindow().document; diff --git a/common/content/finder.js b/common/content/finder.js index 96600f2d..8ed0f1eb 100644 --- a/common/content/finder.js +++ b/common/content/finder.js @@ -642,6 +642,9 @@ const RangeFind = Class("RangeFind", { contains: function (range, r) range.compareBoundaryPoints(range.START_TO_END, r) >= 0 && range.compareBoundaryPoints(range.END_TO_START, r) <= 0, + intersects: function (range, r) + r.compareBoundaryPoints(range.START_TO_END, range) >= 0 && + r.compareBoundaryPoints(range.END_TO_START, range) <= 0, endpoint: function (range, before) { range = range.cloneRange(); range.collapse(before); diff --git a/common/content/hints.js b/common/content/hints.js index b570d131..a06d4f29 100644 --- a/common/content/hints.js +++ b/common/content/hints.js @@ -48,11 +48,12 @@ const Hints = Module("hints", { options.get("extendedhinttags").getKey(this.name, this.tags())); this._hintModes = {}; - this.addMode(";", "Focus hint", function (elem) buffer.focusElement(elem)); + this.addMode(";", "Focus hint", buffer.closure.focusElement); this.addMode("?", "Show information for hint", function (elem) buffer.showElementInfo(elem)); this.addMode("s", "Save hint", function (elem) buffer.saveLink(elem, true)); this.addMode("a", "Save hint with prompt", function (elem) buffer.saveLink(elem, false)); this.addMode("f", "Focus frame", function (elem) elem.ownerDocument.defaultView.focus(), function () ["body"]); + this.addMode("F", "Focus frame or pseudo-frame", buffer.closure.focusElement, null, isScrollable); this.addMode("o", "Follow hint", function (elem) buffer.followLink(elem, dactyl.CURRENT_TAB)); this.addMode("t", "Follow hint in a new tab", function (elem) buffer.followLink(elem, dactyl.NEW_TAB)); this.addMode("b", "Follow hint in a background tab", function (elem) buffer.followLink(elem, dactyl.NEW_BACKGROUND_TAB)); @@ -68,6 +69,9 @@ const Hints = Module("hints", { this.addMode("c", "Open context menu", function (elem) buffer.openContextMenu(elem)); 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)); + + function isScrollable(elem) isinstance(elem, [HTMLFrameElement, HTMLIFrameElement]) || + Buffer.isScrollable(elem, 0, true) || Buffer.isScrollable(elem, 0, false); }, /** @@ -285,7 +289,10 @@ const Hints = Module("hints", { let baseNodeAbsolute = util.xmlToDom(, doc); - let res = util.evaluateXPath(this._hintMode.xpath, doc, null, true); + let mode = this._hintMode; + let res = util.evaluateXPath(mode.xpath, doc, null, true); + if (mode.filter) + res = let (orig = res) (e for (e in orig) if (mode.filter(e))); let fragment = util.xmlToDom(
, doc); let start = this._pageHints.length; @@ -1078,7 +1085,7 @@ const Hints = Module("hints", { return -1; }, - Mode: Struct("name", "prompt", "action", "tags") + Mode: Struct("name", "prompt", "action", "tags", "filter") }, { mappings: function () { var myModes = config.browserModes; @@ -1105,13 +1112,13 @@ const Hints = Module("hints", { util.makeXPath(["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']"]); + function xpath(arg) Option.quote(util.makeXPath(arg)); options.add(["extendedhinttags", "eht"], "XPath string of hintable elements activated by ';'", - "regexpmap", "[iI]:" + Option.quote(util.makeXPath(["img"])) + - ",[OTivVWy]:" + Option.quote(util.makeXPath( - ["{a,area}[@href]", "{img,iframe}[@src]"])) + - ",[S]:" + Option.quote(util.makeXPath( - ["input[not(@type='hidden')]", "textarea", "button", "select"])), + "regexpmap", "[iI]:" + xpath(["img"]) + + ",[OTivVWy]:" + xpath(["{a,area}[@href]", "{img,iframe}[@src]"]) + + ",[F]:" + xpath(["div", "span", "p", "body", "html"]) + + ",[S]:" + xpath(["input[not(@type='hidden')]", "textarea", "button", "select"]), { validator: Option.validateXPath }); options.add(["hinttags", "ht"], diff --git a/common/locale/en-US/hints.xml b/common/locale/en-US/hints.xml index df356602..a893a3fa 100644 --- a/common/locale/en-US/hints.xml +++ b/common/locale/en-US/hints.xml @@ -97,6 +97,7 @@
  • s to save its destination
  • a to save its destination (prompting for save location)
  • f to focus a frame
  • +
  • f to focus a frame or pseudo-frame
  • o to open its location in the current tab
  • t to open its location in a new tab
  • b to open its location in a new background tab
  • diff --git a/common/locale/en-US/options.xml b/common/locale/en-US/options.xml index 824b8a9c..4ec5915d 100644 --- a/common/locale/en-US/options.xml +++ b/common/locale/en-US/options.xml @@ -612,6 +612,11 @@ //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 |