diff options
author | anekos | 2008-08-27 10:50:30 +0000 |
---|---|---|
committer | anekos | 2008-08-27 10:50:30 +0000 |
commit | cefd3cc73211721934819213d3dcb49b128f9df3 (patch) | |
tree | 204da83c23da7680bbbc3fc3e1d76b5619045d0c /migemized_find.js | |
parent | d3b3936580f269b9cc9c4f9b634aa3edc426ff8d (diff) | |
download | vimperator-plugins-cefd3cc73211721934819213d3dcb49b128f9df3.tar.bz2 |
問題なくなったっぽい?
・フレームに対応
・MF.storageのバグ修正
git-svn-id: http://svn.coderepos.org/share/lang/javascript/vimperator-plugins/trunk@18317 d0d07461-0603-4401-acd4-de1884942a52
Diffstat (limited to 'migemized_find.js')
-rw-r--r-- | migemized_find.js | 234 |
1 files changed, 157 insertions, 77 deletions
diff --git a/migemized_find.js b/migemized_find.js index 255e91c..d865388 100644 --- a/migemized_find.js +++ b/migemized_find.js @@ -2,7 +2,7 @@ // @name Migemized Find // @description-ja デフォルトのドキュメント内検索をミゲマイズする。 // @license Creative Commons 2.1 (Attribution + Share Alike) -// @version 1.0 +// @version 1.2 // ==/VimperatorPlugin== // // Usage: @@ -31,10 +31,27 @@ y: (elem.offsetTop || 0) + parent.y } } - let delayCallTimer = null; + function slashArray (ary, center) { + let head = [], tail = []; + let current = head; + for (let i = 0; i < ary.length; i++) { + let it = ary[i]; + if (it == center) + current = tail; + else + current.push(it); + } + return [head, tail]; + } let MF = { + // 定数 + MODE_NORMAL: 0, + MODE_REGEXP: 1, + MODE_MIGEMO: 2, + lastSearchText: null, + lastSearchExpr: null, previousSearchText: null, lastDirection: null, @@ -42,21 +59,18 @@ get document function () content.document, - get storage function () (this.buffer.__migemized_find_storage || (this.buffer.__migemized_find_storage = {})), + // タブ毎に状態を保存するために、変数を用意 + get storage function () (gBrowser.mCurrentTab.__migemized_find_storage || (gBrowser.mCurrentTab.__migemized_find_storage = {})), - get defaultRange function () { - let range = this.document.createRange(); - range.selectNodeContents(this.document.body); + makeBodyRange: function (frame) { + let range = frame.document.createRange(); + range.selectNodeContents(frame.document.body); return range; }, get highlightRemover function () (this.storage.highlightRemover || function () void(0)), set highlightRemover function (fun) (this.storage.highlightRemover = fun), - MODE_NORMAL: 0, - MODE_REGEXP: 1, - MODE_MIGEMO: 2, - // 検索文字列から検索モードと検索文字列を得る。 searchTextToRegExpString: function (str) { let [head, tail] = [str[0], str.slice(1)]; @@ -74,17 +88,17 @@ this.highlightRemover = null; }, - highlightRange: function (range, setRemover) { + highlight: function (target, setRemover) { let span = this.document.createElement('span'); let spanStyle = 'background-color: lightblue; color: black; border: dotted 3px blue;'; span.setAttribute('style', spanStyle); - range.surroundContents(span); + target.range.surroundContents(span); let scroll = function () { let pos = getPosition(span); - content.scroll(pos.x - (content.innerWidth / 2), - pos.y - (content.innerHeight / 2)); + target.frame.scroll(pos.x - (target.frame.innerWidth / 2), + pos.y - (target.frame.innerHeight / 2)); }; setTimeout(scroll, 0); @@ -105,115 +119,181 @@ }, find: function (str, backwards, range, start, end) { - if (!range) - range = this.defaultRange; + if (!range) + range = this.makeBodyRange(this.currentFrames[0]); - if (!start) { - start = range.startContainer.ownerDocument.createRange(); - start.setStartBefore(range.startContainer); - } - if (!end) { - end = range.endContainer.ownerDocument.createRange(); - end.setEndAfter(range.endContainer); - } + if (!start) { + start = range.startContainer.ownerDocument.createRange(); + start.setStartBefore(range.startContainer); + } + if (!end) { + end = range.endContainer.ownerDocument.createRange(); + end.setEndAfter(range.endContainer); + } - if (backwards) - [start, end] = [end, start]; + // 検索方向に合わせて、開始終了位置を交換 + if (backwards) + [start, end] = [end, start]; - try { - return XMigemoCore.regExpFind(str, 'i', range, start, end, backwards); - } catch (e) { - return false; - } + try { + return XMigemoCore.regExpFind(str, 'i', range, start, end, backwards); + } catch (e) { + return false; + } }, findFirst: function (str, backwards) { - let f = function () { - this.lastDirection = backwards; - this.lastSearchText = str = this.searchTextToRegExpString(str); - - let result = this.storage.lastResult = this.find(str, backwards); - - this.removeHighlight(); - if (result) - this.highlightRange(result, true); - - return result; - }; + this.lastDirection = backwards; + this.lastSearchText = str; + this.lastSearchExpr = str = this.searchTextToRegExpString(str); + + let result, frames = this.currentFrames; + if (backwards) + frames = frames.reverse(); + + for each (let frame in frames) { + let ret = this.find(str, backwards, this.makeBodyRange(frame)); + if (ret) { + result = this.storage.lastResult = { + frame: frame, + range: ret, + }; + break; + } + } - if (delayCallTimer) - clearTimeout(delayCallTimer); + this.removeHighlight(); + if (result) + this.highlight(result, true); - delayCallTimer = setTimeout(function () f.call(MF), 300); + return result; }, findAgain: function (reverse) { + let backwards = !!(!this.lastDirection ^ !reverse); + let last = this.storage.lastResult; + let currentFrames = this.currentFrames; + + // 前回の結果がないので、(初め|最後)のフレームを対象にする + // findFirst と"似た"挙動になる + if (!last) { + let idx = backwards ? frames.length - 1 + : 0; + last = {frame: frames[idx], range: this.makeBodyRange(frames[idx])}; + } + this.removeHighlight(); - let str = this.lastSearchText; - let range = this.defaultRange; - let last = this.storage.lastResult; - let backwards = !!(!this.lastDirection ^ !reverse); + let str = this.lastSearchExpr; let start, end; - if (last) { - if (backwards) { - end = last.cloneRange(); - end.setEnd(last.startContainer, last.startOffset); - } else { - start = last.cloneRange(); - start.setStart(last.endContainer, last.endOffset); + if (backwards) { + end = last.range.cloneRange(); + end.setEnd(last.range.startContainer, last.range.startOffset); + } else { + start = last.range.cloneRange(); + start.setStart(last.range.endContainer, last.range.endOffset); + } + + let result; + let ret = this.find(str, backwards, this.makeBodyRange(last.frame), start, end); + + if (ret) { + result = {frame: last.frame, range: ret}; + } else { + // 見つからなかったので、ほかのフレームから検索 + let [head, tail] = slashArray(currentFrames, last.frame); + let next = backwards ? head.reverse().concat(tail.reverse()) + : tail.concat(head); + for each (let frame in next) { + let r = this.find(str, backwards, this.makeBodyRange(frame)); + if (r) { + result = {frame: frame, range: r}; + break; + } } } - let result = this.storage.lastResult = this.find(str, backwards, range, start, end); - if (!result) - result = this.storage.lastResult = this.find(str, backwards, range); + this.storage.lastResult = result; if (result) - this.highlightRange(result, true); - else - liberator.echoerr('not found: ' + str); + this.highlight(result, true); return result; }, + + submit: function () { + this.previousSearchText = this.lastSearchText; + }, + + cancel: function () { + this.lastSearchText = MF.previousSearchText; + }, + + get currentFrames function () { + let result = []; + (function (frame) { + // ボディがない物は検索対象外なので外す + if (frame.document.body.localName.toLowerCase() == 'body') + result.push(frame); + for (let i = 0; i < frame.frames.length; i++) + arguments.callee(frame.frames[i]); + })(content); + return result; + }, }; - let original = {}; + + // 前のタイマーを削除するために保存しておく + let delayCallTimer = null; let migemized = { find: function find (str, backwards) { - MF.findFirst(str, backwards); + // 短時間に何回も検索をしないように遅延させる + let f = function () MF.findFirst(str, backwards); + if (delayCallTimer) + clearTimeout(delayCallTimer); + delayCallTimer = setTimeout(function () f(), 300); }, findAgain: function findAgain (reverse) { MF.findAgain(reverse); + if (!MF.storage.lastResult) + liberator.echoerr('not found: ' + MF.lastSearchText); }, searchSubmitted: function searchSubmitted (command, forcedBackward) { + MF.submit(); if (!MF.storage.lastResult) liberator.echoerr('not found: ' + MF.lastSearchText); - MF.previousSearchText = MF.lastSearchText; }, searchCanceled: function searchCanceled () { - MF.lastSearchText = MF.previousSearchText; + MF.cancel(); }, }; - for (let name in migemized) - original[name] = liberator.search[name]; - function set (funcs) { - for (let name in funcs) - liberator.search[name] = funcs[name]; + // オリジナルの状態に戻せるように保存しておく + { + let original = {}; + + for (let name in migemized) + original[name] = liberator.search[name]; + + function set (funcs) { + for (let name in funcs) + liberator.search[name] = funcs[name]; + } + + set(migemized); + + MF.install = function () set(migemized); + MF.uninstall = function () set(original); } - set(migemized); - liberator.plugins.migemizedFind = { - install: function () set(migemized), - uninstall: function () set(original), - }; + // 外から使えるように + liberator.plugins.migemizedFind = MF; }catch(e){liberator.log(e);}})(); |