Hints を 弄ってみた
気になった点を修正するつもりが、かなり修正しちゃった…
- tags の 引数に 対象 window を 渡す
- tags の 返り値が Array 構造 OK(length と 数字 属性があれば なんでも良いはず)
- tags が Generator に 対応
- 画面外や非表示のframeを処理しないように修正
- スクリーンに一部分が表示されているフレームは 表示部位のみhints対象として処理
なので、 tags に
function(win) win.document.querySelectorAll("a")
function(win) [win.document.body]
function(win){ for(let [,e] in Iterator(win.document.querySelectorAll("a"))){ //xpath じゃ不可能な フィルター判定 yield e; } }
また下二つは、多分パフォーマンスにつながると思います。
シビアな位置だと 表示されないことがあるかもしれませんので、
フィードバックしていただけたらと思います。
//_hints-generate-ext.js (function(){ let name = "Hints.prototype._generate"; if(!userContext[name]) userContext[name]=Hints.prototype._generate; function evalFunc(src, obj) liberator.eval(["(function()",src,")()"].join(" "),obj) Hints.prototype._generate = evalFunc(_generate.toString(), Hints.prototype._generate); function _generate(win,screen) { if (!win) win = window.content; if(!screen) screen = {top:0,left:0,height:win.innerHeight,width:win.innerWidth}; let doc = win.document; let [offsetX, offsetY] = this._getContainerOffsets(doc); let baseNodeAbsolute = util.xmlToDom(<span highlight="Hint"/>, doc); function _isVisibleFromElement(elem) _isVisible(elem.getBoundingClientRect()) function _isVisible(rect){ return ( !rect || rect.top > screen.height || rect.bottom < screen.top || rect.left > screen.width || rect.right < screen.left ) ? false: true; } let res = this._hintMode.tags(win); if (typeof res == "string") { res = function (tags) {var it = util.evaluateXPath(tags, doc, null, true);var elem;while ((elem = it.iterateNext())) {yield elem;}}(res); } else if ("length" in res) { res = util.Array.itervalues(res); } let fragment = util.xmlToDom(<div highlight="hints"/>, doc); let start = this._pageHints.length; let elem; for(let elem in res){ let hint = { elem: elem, showText: false }; // TODO: for iframes, this calculation is wrong if(!_isVisibleFromElement(elem)) continue; rect = elem.getClientRects()[0]; if (!rect) continue; let computedStyle = doc.defaultView.getComputedStyle(elem, null); if (computedStyle.getPropertyValue("visibility") != "visible" || computedStyle.getPropertyValue("display") == "none") continue; if (elem instanceof HTMLInputElement || elem instanceof HTMLSelectElement || elem instanceof HTMLTextAreaElement) [hint.text, hint.showText] = this._getInputHint(elem, doc); else hint.text = elem.textContent.toLowerCase(); hint.span = baseNodeAbsolute.cloneNode(true); let leftPos = Math.max((rect.left + offsetX), offsetX); let topPos = Math.max((rect.top + offsetY), offsetY); if (elem instanceof HTMLAreaElement) [leftPos, topPos] = this._getAreaOffset(elem, leftPos, topPos); hint.span.style.left = leftPos + "px"; hint.span.style.top = topPos + "px"; fragment.appendChild(hint.span); this._pageHints.push(hint); } let body = doc.body || util.evaluateXPath(["body"], doc).snapshotItem(0); if (body) { body.appendChild(fragment); this._docs.push({ doc: doc, start: start, end: this._pageHints.length - 1 }); } for(let frame in util.Array.itervalues(win.frames)){ elem = frame.frameElement; if(elem.getClientRects().length === 0) continue; rect = elem.getBoundingClientRect(); if(!_isVisible(rect)) continue; this._generate(frame, { top : Math.max(0, - rect.top), left : Math.max(0, - rect.left), height: Math.min(frame.innerHeight, screen.height - rect.top), width: Math.min(frame.innerWidth, screen.width - rect.left) }); } return true; } })();