| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview Objects related to incremental search. | 6 * @fileoverview Objects related to incremental search. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 goog.provide('ISearch'); | 9 goog.provide('ISearch'); |
| 10 goog.provide('ISearchHandler'); | 10 goog.provide('ISearchHandler'); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 | 38 |
| 39 /** | 39 /** |
| 40 * Called when search result node changes. | 40 * Called when search result node changes. |
| 41 * @param {!AutomationNode} node The new search result. | 41 * @param {!AutomationNode} node The new search result. |
| 42 */ | 42 */ |
| 43 onSearchResultChanged: function(node) {} | 43 onSearchResultChanged: function(node) {} |
| 44 }; | 44 }; |
| 45 | 45 |
| 46 /** | 46 /** |
| 47 * Controls an incremental search. | 47 * Controls an incremental search. |
| 48 * @param {!AutomationNode} initialNode | 48 * @param {!cursors.Cursor} cursor |
| 49 * @constructor | 49 * @constructor |
| 50 */ | 50 */ |
| 51 ISearch = function(initialNode) { | 51 ISearch = function(cursor) { |
| 52 if (!cursor.node) |
| 53 throw 'Incremental search started from invalid range.'; |
| 54 |
| 52 var leaf = AutomationUtil.findNodePre( | 55 var leaf = AutomationUtil.findNodePre( |
| 53 initialNode, Dir.FORWARD, AutomationPredicate.leaf) || initialNode; | 56 cursor.node, Dir.FORWARD, AutomationPredicate.leaf) || cursor.node; |
| 54 | 57 |
| 55 /** @type {!AutomationNode} @private */ | 58 /** @type {!cursors.Cursor} */ |
| 56 this.node_ = leaf; | 59 this.cursor = cursors.Cursor.fromNode(leaf); |
| 57 | 60 |
| 58 /** | 61 /** |
| 59 * This tracks the id of a search that is in progress. | 62 * This tracks the id of a search that is in progress. |
| 60 * @type {number} @private | 63 * @type {number} @private |
| 61 */ | 64 */ |
| 62 this.pendingSearchId_ = 0; | 65 this.pendingSearchId_ = 0; |
| 63 | 66 |
| 64 // Global exports. | 67 // Global exports. |
| 65 /** Exported for this background script. */ | 68 /** Exported for this background script. */ |
| 66 cvox.ChromeVox = chrome.extension.getBackgroundPage()['cvox']['ChromeVox']; | 69 cvox.ChromeVox = chrome.extension.getBackgroundPage()['cvox']['ChromeVox']; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 83 searchStr = searchStr.toLocaleLowerCase(); | 86 searchStr = searchStr.toLocaleLowerCase(); |
| 84 // Keep things responsive by chunking cursor moves up into discrete | 87 // Keep things responsive by chunking cursor moves up into discrete |
| 85 // blocks. We can, if needed, simulate getting interrupted by the enter key. | 88 // blocks. We can, if needed, simulate getting interrupted by the enter key. |
| 86 var currentSearchId = ++this.pendingSearchId_; | 89 var currentSearchId = ++this.pendingSearchId_; |
| 87 var move = function(curNode) { | 90 var move = function(curNode) { |
| 88 var cur = cursors.Cursor.fromNode(curNode); | 91 var cur = cursors.Cursor.fromNode(curNode); |
| 89 var prev = cur; | 92 var prev = cur; |
| 90 cur = | 93 cur = |
| 91 cur.move(cursors.Unit.NODE, cursors.Movement.DIRECTIONAL, dir); | 94 cur.move(cursors.Unit.NODE, cursors.Movement.DIRECTIONAL, dir); |
| 92 if (prev.equals(cur)) { | 95 if (prev.equals(cur)) { |
| 93 this.handler_.onSearchReachedBoundary(this.node_); | 96 this.handler_.onSearchReachedBoundary(this.cursor.node); |
| 94 return; | 97 return; |
| 95 } | 98 } |
| 96 | 99 |
| 97 if (cur.getText().toLocaleLowerCase().indexOf(searchStr) != -1) { | 100 if (cur.getText().toLocaleLowerCase().indexOf(searchStr) != -1) { |
| 98 this.node_ = cur.node; | 101 this.cursor = cur; |
| 99 this.handler_.onSearchResultChanged(this.node_); | 102 this.handler_.onSearchResultChanged(this.cursor.node); |
| 100 return; | 103 return; |
| 101 } | 104 } |
| 102 if (this.pendingSearchId_ == currentSearchId) | 105 if (this.pendingSearchId_ == currentSearchId) |
| 103 window.setTimeout(move.bind(this, cur.node), 0); | 106 window.setTimeout(move.bind(this, cur.node), 0); |
| 104 }; | 107 }; |
| 105 window.setTimeout(move.bind(this, this.node_), 0); | 108 window.setTimeout(move.bind(this, this.cursor.node), 0); |
| 106 } | 109 } |
| 107 }; | 110 }; |
| 108 | 111 |
| 109 /** | 112 /** |
| 110 * @param {Element} input | 113 * @param {Element} input |
| 111 * @constructor | 114 * @constructor |
| 112 * @implements {ISearchHandler} | 115 * @implements {ISearchHandler} |
| 113 */ | 116 */ |
| 114 ISearchUI = function(input) { | 117 ISearchUI = function(input) { |
| 115 /** @type {ChromeVoxState} @private */ | 118 /** @type {ChromeVoxState} @private */ |
| 116 this.background_ = | 119 this.background_ = |
| 117 chrome.extension.getBackgroundPage()['ChromeVoxState']['instance']; | 120 chrome.extension.getBackgroundPage()['ChromeVoxState']['instance']; |
| 118 this.iSearch_ = new ISearch(this.background_.currentRange.start.node); | 121 this.iSearch_ = new ISearch(this.background_.currentRange.start); |
| 119 this.input_ = input; | 122 this.input_ = input; |
| 120 this.dir_ = Dir.FORWARD; | 123 this.dir_ = Dir.FORWARD; |
| 121 this.iSearch_.handler = this; | 124 this.iSearch_.handler = this; |
| 122 | 125 |
| 123 this.onKeyDown = this.onKeyDown.bind(this); | 126 this.onKeyDown = this.onKeyDown.bind(this); |
| 124 this.onTextInput = this.onTextInput.bind(this); | 127 this.onTextInput = this.onTextInput.bind(this); |
| 125 | 128 |
| 126 input.addEventListener('keydown', this.onKeyDown, true); | 129 input.addEventListener('keydown', this.onKeyDown, true); |
| 127 input.addEventListener('textInput', this.onTextInput, true); | 130 input.addEventListener('textInput', this.onTextInput, true); |
| 128 }; | 131 }; |
| 129 | 132 |
| 130 /** | 133 /** |
| 131 * @param {Element} input | 134 * @param {Element} input |
| 132 * @return {ISearchUI} | 135 * @return {ISearchUI} |
| 133 */ | 136 */ |
| 134 ISearchUI.get = function(input) { | 137 ISearchUI.init = function(input) { |
| 135 if (ISearchUI.instance_) | 138 if (ISearchUI.instance_) |
| 136 ISearchUI.instance_.destroy(); | 139 ISearchUI.instance_.destroy(); |
| 140 |
| 141 if (!input) |
| 142 return null; |
| 143 |
| 137 ISearchUI.instance_ = new ISearchUI(input); | 144 ISearchUI.instance_ = new ISearchUI(input); |
| 138 input.focus(); | 145 input.focus(); |
| 146 input.select(); |
| 139 return ISearchUI.instance_; | 147 return ISearchUI.instance_; |
| 140 }; | 148 }; |
| 141 | 149 |
| 142 ISearchUI.prototype = { | 150 ISearchUI.prototype = { |
| 143 /** | 151 /** |
| 144 * Listens to key down events. | 152 * Listens to key down events. |
| 145 * @param {Event} evt | 153 * @param {Event} evt |
| 146 * @return {boolean} | 154 * @return {boolean} |
| 147 */ | 155 */ |
| 148 onKeyDown: function(evt) { | 156 onKeyDown: function(evt) { |
| 149 switch (evt.key) { | 157 switch (evt.key) { |
| 150 case 'ArrowUp': | 158 case 'ArrowUp': |
| 151 this.dir_ = Dir.BACKWARD; | 159 this.dir_ = Dir.BACKWARD; |
| 152 break; | 160 break; |
| 153 case 'ArrowDown': | 161 case 'ArrowDown': |
| 154 this.dir_ = Dir.FORWARD; | 162 this.dir_ = Dir.FORWARD; |
| 155 break; | 163 break; |
| 156 case 'Escape': | 164 case 'Escape': |
| 157 this.pendingSearchId_ = 0; | 165 this.pendingSearchId_ = 0; |
| 158 Panel.closeMenusAndRestoreFocus(); | 166 Panel.closeMenusAndRestoreFocus(); |
| 159 return false; | 167 return false; |
| 160 case 'Enter': | 168 case 'Enter': |
| 161 this.pendingSearchId_ = 0; | 169 this.pendingSearchId_ = 0; |
| 170 Panel.setPendingCallback(function() { |
| 171 var node = this.iSearch_.cursor.node; |
| 172 if (!node) |
| 173 return; |
| 174 chrome.extension.getBackgroundPage().ChromeVoxState.instance[ |
| 175 'navigateToRange']( |
| 176 cursors.Range.fromNode(node)); |
| 177 }.bind(this)); |
| 162 Panel.closeMenusAndRestoreFocus(); | 178 Panel.closeMenusAndRestoreFocus(); |
| 163 return false; | 179 return false; |
| 164 default: | 180 default: |
| 165 this.pendingSearchId_ = 0; | 181 this.pendingSearchId_ = 0; |
| 166 return false; | 182 return false; |
| 167 } | 183 } |
| 168 this.iSearch_.search(this.input_.value, this.dir_); | 184 this.iSearch_.search(this.input_.value, this.dir_); |
| 169 evt.preventDefault(); | 185 evt.preventDefault(); |
| 170 evt.stopPropagation(); | 186 evt.stopPropagation(); |
| 171 return false; | 187 return false; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 this.iSearch_.handler_ = null; | 229 this.iSearch_.handler_ = null; |
| 214 this.iSearch_ = null; | 230 this.iSearch_ = null; |
| 215 var input = this.input_; | 231 var input = this.input_; |
| 216 this.input_ = null; | 232 this.input_ = null; |
| 217 input.removeEventListener('keydown', this.onKeyDown, true); | 233 input.removeEventListener('keydown', this.onKeyDown, true); |
| 218 input.removeEventListener('textInput', this.onTextInput, true); | 234 input.removeEventListener('textInput', this.onTextInput, true); |
| 219 } | 235 } |
| 220 }; | 236 }; |
| 221 | 237 |
| 222 }); // goog.scope | 238 }); // goog.scope |
| OLD | NEW |