| 37 | | lastSearchText: null, |
| 38 | | previousSearchText: null, |
| 39 | | lastDirection: null, |
| 40 | | |
| 41 | | get buffer function () liberator.buffer, |
| 42 | | |
| 43 | | get document function () content.document, |
| 44 | | |
| 45 | | get storage function () (this.buffer.__migemized_find_storage || (this.buffer.__migemized_find_storage = {})), |
| 46 | | |
| 47 | | get defaultRange function () { |
| 48 | | let range = this.document.createRange(); |
| 49 | | range.selectNodeContents(this.document.body); |
| 50 | | return range; |
| 51 | | }, |
| 52 | | |
| 53 | | get highlightRemover function () (this.storage.highlightRemover || function () void(0)), |
| 54 | | set highlightRemover function (fun) (this.storage.highlightRemover = fun), |
| 55 | | |
| | 48 | // 定数 |
| | 52 | |
| | 53 | lastSearchText: null, |
| | 54 | lastSearchExpr: null, |
| | 55 | previousSearchText: null, |
| | 56 | lastDirection: null, |
| | 57 | |
| | 58 | get buffer function () liberator.buffer, |
| | 59 | |
| | 60 | get document function () content.document, |
| | 61 | |
| | 62 | // タブ毎に状態を保存するために、変数を用意 |
| | 63 | get storage function () (gBrowser.mCurrentTab.__migemized_find_storage || (gBrowser.mCurrentTab.__migemized_find_storage = {})), |
| | 64 | |
| | 65 | makeBodyRange: function (frame) { |
| | 66 | let range = frame.document.createRange(); |
| | 67 | range.selectNodeContents(frame.document.body); |
| | 68 | return range; |
| | 69 | }, |
| | 70 | |
| | 71 | get highlightRemover function () (this.storage.highlightRemover || function () void(0)), |
| | 72 | set highlightRemover function (fun) (this.storage.highlightRemover = fun), |
| 108 | | if (!range) |
| 109 | | range = this.defaultRange; |
| 110 | | |
| 111 | | if (!start) { |
| 112 | | start = range.startContainer.ownerDocument.createRange(); |
| 113 | | start.setStartBefore(range.startContainer); |
| | 122 | if (!range) |
| | 123 | range = this.makeBodyRange(this.currentFrames[0]); |
| | 124 | |
| | 125 | if (!start) { |
| | 126 | start = range.startContainer.ownerDocument.createRange(); |
| | 127 | start.setStartBefore(range.startContainer); |
| | 128 | } |
| | 129 | if (!end) { |
| | 130 | end = range.endContainer.ownerDocument.createRange(); |
| | 131 | end.setEndAfter(range.endContainer); |
| | 132 | } |
| | 133 | |
| | 134 | // 検索方向に合わせて、開始終了位置を交換 |
| | 135 | if (backwards) |
| | 136 | [start, end] = [end, start]; |
| | 137 | |
| | 138 | try { |
| | 139 | return XMigemoCore.regExpFind(str, 'i', range, start, end, backwards); |
| | 140 | } catch (e) { |
| | 141 | return false; |
| | 142 | } |
| | 143 | }, |
| | 144 | |
| | 145 | findFirst: function (str, backwards) { |
| | 146 | this.lastDirection = backwards; |
| | 147 | this.lastSearchText = str; |
| | 148 | this.lastSearchExpr = str = this.searchTextToRegExpString(str); |
| | 149 | |
| | 150 | let result, frames = this.currentFrames; |
| | 151 | if (backwards) |
| | 152 | frames = frames.reverse(); |
| | 153 | |
| | 154 | for each (let frame in frames) { |
| | 155 | let ret = this.find(str, backwards, this.makeBodyRange(frame)); |
| | 156 | if (ret) { |
| | 157 | result = this.storage.lastResult = { |
| | 158 | frame: frame, |
| | 159 | range: ret, |
| | 160 | }; |
| | 161 | break; |
| 115 | | if (!end) { |
| 116 | | end = range.endContainer.ownerDocument.createRange(); |
| 117 | | end.setEndAfter(range.endContainer); |
| | 163 | } |
| | 164 | |
| | 165 | this.removeHighlight(); |
| | 166 | if (result) |
| | 167 | this.highlight(result, true); |
| | 168 | |
| | 169 | return result; |
| | 170 | }, |
| | 171 | |
| | 172 | findAgain: function (reverse) { |
| | 173 | let backwards = !!(!this.lastDirection ^ !reverse); |
| | 174 | let last = this.storage.lastResult; |
| | 175 | let currentFrames = this.currentFrames; |
| | 176 | |
| | 177 | // 前回の結果がないので、(初め|最後)のフレームを対象にする |
| | 178 | // findFirst と"似た"挙動になる |
| | 179 | if (!last) { |
| | 180 | let idx = backwards ? frames.length - 1 |
| | 181 | : 0; |
| | 182 | last = {frame: frames[idx], range: this.makeBodyRange(frames[idx])}; |
| | 183 | } |
| | 184 | |
| | 185 | this.removeHighlight(); |
| | 186 | |
| | 187 | let str = this.lastSearchExpr; |
| | 188 | let start, end; |
| | 189 | |
| | 190 | if (backwards) { |
| | 191 | end = last.range.cloneRange(); |
| | 192 | end.setEnd(last.range.startContainer, last.range.startOffset); |
| | 193 | } else { |
| | 194 | start = last.range.cloneRange(); |
| | 195 | start.setStart(last.range.endContainer, last.range.endOffset); |
| | 196 | } |
| | 197 | |
| | 198 | let result; |
| | 199 | let ret = this.find(str, backwards, this.makeBodyRange(last.frame), start, end); |
| | 200 | |
| | 201 | if (ret) { |
| | 202 | result = {frame: last.frame, range: ret}; |
| | 203 | } else { |
| | 204 | // 見つからなかったので、ほかのフレームから検索 |
| | 205 | let [head, tail] = slashArray(currentFrames, last.frame); |
| | 206 | let next = backwards ? head.reverse().concat(tail.reverse()) |
| | 207 | : tail.concat(head); |
| | 208 | for each (let frame in next) { |
| | 209 | let r = this.find(str, backwards, this.makeBodyRange(frame)); |
| | 210 | if (r) { |
| | 211 | result = {frame: frame, range: r}; |
| | 212 | break; |
| | 213 | } |
| 119 | | |
| 120 | | if (backwards) |
| 121 | | [start, end] = [end, start]; |
| 122 | | |
| 123 | | try { |
| 124 | | return XMigemoCore.regExpFind(str, 'i', range, start, end, backwards); |
| 125 | | } catch (e) { |
| 126 | | return false; |
| 127 | | } |
| 128 | | }, |
| 129 | | |
| 130 | | findFirst: function (str, backwards) { |
| 131 | | let f = function () { |
| 132 | | this.lastDirection = backwards; |
| 133 | | this.lastSearchText = str = this.searchTextToRegExpString(str); |
| 134 | | |
| 135 | | let result = this.storage.lastResult = this.find(str, backwards); |
| 136 | | |
| 137 | | this.removeHighlight(); |
| 138 | | if (result) |
| 139 | | this.highlightRange(result, true); |
| 140 | | |
| 141 | | return result; |
| 142 | | }; |
| 143 | | |
| | 215 | } |
| | 216 | |
| | 217 | this.storage.lastResult = result; |
| | 218 | |
| | 219 | if (result) |
| | 220 | this.highlight(result, true); |
| | 221 | |
| | 222 | return result; |
| | 223 | }, |
| | 224 | |
| | 225 | submit: function () { |
| | 226 | this.previousSearchText = this.lastSearchText; |
| | 227 | }, |
| | 228 | |
| | 229 | cancel: function () { |
| | 230 | this.lastSearchText = MF.previousSearchText; |
| | 231 | }, |
| | 232 | |
| | 233 | get currentFrames function () { |
| | 234 | let result = []; |
| | 235 | (function (frame) { |
| | 236 | // ボディがない物は検索対象外なので外す |
| | 237 | if (frame.document.body.localName.toLowerCase() == 'body') |
| | 238 | result.push(frame); |
| | 239 | for (let i = 0; i < frame.frames.length; i++) |
| | 240 | arguments.callee(frame.frames[i]); |
| | 241 | })(content); |
| | 242 | return result; |
| | 243 | }, |
| | 244 | }; |
| | 245 | |
| | 246 | |
| | 247 | // 前のタイマーを削除するために保存しておく |
| | 248 | let delayCallTimer = null; |
| | 249 | |
| | 250 | let migemized = { |
| | 251 | find: function find (str, backwards) { |
| | 252 | // 短時間に何回も検索をしないように遅延させる |
| | 253 | let f = function () MF.findFirst(str, backwards); |
| 146 | | |
| 147 | | delayCallTimer = setTimeout(function () f.call(MF), 300); |
| 148 | | }, |
| 149 | | |
| 150 | | findAgain: function (reverse) { |
| 151 | | this.removeHighlight(); |
| 152 | | |
| 153 | | let str = this.lastSearchText; |
| 154 | | let range = this.defaultRange; |
| 155 | | let last = this.storage.lastResult; |
| 156 | | let backwards = !!(!this.lastDirection ^ !reverse); |
| 157 | | let start, end; |
| 158 | | |
| 159 | | if (last) { |
| 160 | | if (backwards) { |
| 161 | | end = last.cloneRange(); |
| 162 | | end.setEnd(last.startContainer, last.startOffset); |
| 163 | | } else { |
| 164 | | start = last.cloneRange(); |
| 165 | | start.setStart(last.endContainer, last.endOffset); |
| 166 | | } |
| 167 | | } |
| 168 | | |
| 169 | | let result = this.storage.lastResult = this.find(str, backwards, range, start, end); |
| 170 | | if (!result) |
| 171 | | result = this.storage.lastResult = this.find(str, backwards, range); |
| 172 | | |
| 173 | | if (result) |
| 174 | | this.highlightRange(result, true); |
| 175 | | else |
| 176 | | liberator.echoerr('not found: ' + str); |
| 177 | | |
| 178 | | return result; |
| 179 | | }, |
| 180 | | }; |
| 181 | | |
| 182 | | let original = {}; |
| 183 | | |
| 184 | | let migemized = { |
| 185 | | find: function find (str, backwards) { |
| 186 | | MF.findFirst(str, backwards); |
| | 256 | delayCallTimer = setTimeout(function () f(), 300); |