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 cr.exportPath('settings'); | 5 cr.exportPath('settings'); |
6 | 6 |
7 /** | 7 /** |
8 * A data structure used by callers to combine the results of multiple search | 8 * A data structure used by callers to combine the results of multiple search |
9 * requests. | 9 * requests. |
10 * | 10 * |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 * Finds all previous highlighted nodes under |node| (both within self and | 60 * Finds all previous highlighted nodes under |node| (both within self and |
61 * children's Shadow DOM) and replaces the highlights (yellow rectangle and | 61 * children's Shadow DOM) and replaces the highlights (yellow rectangle and |
62 * search bubbles) with the original text node. | 62 * search bubbles) with the original text node. |
63 * TODO(dpapad): Consider making this a private method of TopLevelSearchTask. | 63 * TODO(dpapad): Consider making this a private method of TopLevelSearchTask. |
64 * @param {!Node} node | 64 * @param {!Node} node |
65 * @private | 65 * @private |
66 */ | 66 */ |
67 function findAndRemoveHighlights_(node) { | 67 function findAndRemoveHighlights_(node) { |
68 var wrappers = node.querySelectorAll('* /deep/ .' + WRAPPER_CSS_CLASS); | 68 var wrappers = node.querySelectorAll('* /deep/ .' + WRAPPER_CSS_CLASS); |
69 | 69 |
70 for (var i = 0; i < wrappers.length; i++ ) { | 70 for (var i = 0; i < wrappers.length; i++) { |
71 var wrapper = wrappers[i]; | 71 var wrapper = wrappers[i]; |
72 var originalNode = wrapper.querySelector( | 72 var originalNode = |
73 '.' + ORIGINAL_CONTENT_CSS_CLASS); | 73 wrapper.querySelector('.' + ORIGINAL_CONTENT_CSS_CLASS); |
74 wrapper.parentElement.replaceChild(originalNode.firstChild, wrapper); | 74 wrapper.parentElement.replaceChild(originalNode.firstChild, wrapper); |
75 } | 75 } |
76 | 76 |
77 var searchBubbles = node.querySelectorAll( | 77 var searchBubbles = |
78 '* /deep/ .' + SEARCH_BUBBLE_CSS_CLASS); | 78 node.querySelectorAll('* /deep/ .' + SEARCH_BUBBLE_CSS_CLASS); |
79 for (var j = 0; j < searchBubbles.length; j++) | 79 for (var j = 0; j < searchBubbles.length; j++) |
80 searchBubbles[j].remove(); | 80 searchBubbles[j].remove(); |
81 } | 81 } |
82 | 82 |
83 /** | 83 /** |
84 * Applies the highlight UI (yellow rectangle) around all matches in |node|. | 84 * Applies the highlight UI (yellow rectangle) around all matches in |node|. |
85 * @param {!Node} node The text node to be highlighted. |node| ends up | 85 * @param {!Node} node The text node to be highlighted. |node| ends up |
86 * being removed from the DOM tree. | 86 * being removed from the DOM tree. |
87 * @param {!Array<string>} tokens The string tokens after splitting on the | 87 * @param {!Array<string>} tokens The string tokens after splitting on the |
88 * relevant regExp. Even indices hold text that doesn't need highlighting, | 88 * relevant regExp. Even indices hold text that doesn't need highlighting, |
(...skipping 17 matching lines...) Expand all Loading... |
106 span.style.display = 'none'; | 106 span.style.display = 'none'; |
107 span.appendChild(node); | 107 span.appendChild(node); |
108 wrapper.appendChild(span); | 108 wrapper.appendChild(span); |
109 | 109 |
110 for (var i = 0; i < tokens.length; ++i) { | 110 for (var i = 0; i < tokens.length; ++i) { |
111 if (i % 2 == 0) { | 111 if (i % 2 == 0) { |
112 wrapper.appendChild(document.createTextNode(tokens[i])); | 112 wrapper.appendChild(document.createTextNode(tokens[i])); |
113 } else { | 113 } else { |
114 var span = document.createElement('span'); | 114 var span = document.createElement('span'); |
115 span.classList.add(HIT_CSS_CLASS); | 115 span.classList.add(HIT_CSS_CLASS); |
116 span.style.backgroundColor = '#ffeb3b'; // --var(--paper-yellow-500) | 116 span.style.backgroundColor = '#ffeb3b'; // --var(--paper-yellow-500) |
117 span.textContent = tokens[i]; | 117 span.textContent = tokens[i]; |
118 wrapper.appendChild(span); | 118 wrapper.appendChild(span); |
119 } | 119 } |
120 } | 120 } |
121 } | 121 } |
122 | 122 |
123 /** | 123 /** |
124 * Traverses the entire DOM (including Shadow DOM), finds text nodes that | 124 * Traverses the entire DOM (including Shadow DOM), finds text nodes that |
125 * match the given regular expression and applies the highlight UI. It also | 125 * match the given regular expression and applies the highlight UI. It also |
126 * ensures that <settings-section> instances become visible if any matches | 126 * ensures that <settings-section> instances become visible if any matches |
127 * occurred under their subtree. | 127 * occurred under their subtree. |
128 * | 128 * |
129 * @param {!settings.SearchRequest} request | 129 * @param {!settings.SearchRequest} request |
130 * @param {!Node} root The root of the sub-tree to be searched | 130 * @param {!Node} root The root of the sub-tree to be searched |
131 * @private | 131 * @private |
132 */ | 132 */ |
133 function findAndHighlightMatches_(request, root) { | 133 function findAndHighlightMatches_(request, root) { |
134 var foundMatches = false; | 134 var foundMatches = false; |
135 function doSearch(node) { | 135 function doSearch(node) { |
136 if (node.nodeName == 'TEMPLATE' && node.hasAttribute('route-path') && | 136 if (node.nodeName == 'TEMPLATE' && node.hasAttribute('route-path') && |
137 !node.if && !node.hasAttribute(SKIP_SEARCH_CSS_ATTRIBUTE)) { | 137 !node.if && !node.hasAttribute(SKIP_SEARCH_CSS_ATTRIBUTE)) { |
138 request.queue_.addRenderTask(new RenderTask(request, node)); | 138 request.queue_.addRenderTask(new RenderTask(request, node)); |
139 return; | 139 return; |
140 } | 140 } |
141 | 141 |
142 if (IGNORED_ELEMENTS.has(node.nodeName)) | 142 if (IGNORED_ELEMENTS.has(node.nodeName)) |
143 return; | 143 return; |
144 | 144 |
145 if (node instanceof HTMLElement) { | 145 if (node instanceof HTMLElement) { |
146 var element = /** @type {HTMLElement} */(node); | 146 var element = /** @type {HTMLElement} */ (node); |
147 if (element.hasAttribute(SKIP_SEARCH_CSS_ATTRIBUTE) || | 147 if (element.hasAttribute(SKIP_SEARCH_CSS_ATTRIBUTE) || |
148 element.hasAttribute('hidden') || | 148 element.hasAttribute('hidden') || element.style.display == 'none') { |
149 element.style.display == 'none') { | |
150 return; | 149 return; |
151 } | 150 } |
152 } | 151 } |
153 | 152 |
154 if (node.nodeType == Node.TEXT_NODE) { | 153 if (node.nodeType == Node.TEXT_NODE) { |
155 var textContent = node.nodeValue.trim(); | 154 var textContent = node.nodeValue.trim(); |
156 if (textContent.length == 0) | 155 if (textContent.length == 0) |
157 return; | 156 return; |
158 | 157 |
159 if (request.regExp.test(textContent)) { | 158 if (request.regExp.test(textContent)) { |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 * @param {!Node} node | 234 * @param {!Node} node |
236 * @param {string} rawQuery | 235 * @param {string} rawQuery |
237 * @private | 236 * @private |
238 */ | 237 */ |
239 function revealParentSection_(node, rawQuery) { | 238 function revealParentSection_(node, rawQuery) { |
240 var associatedControl = null; | 239 var associatedControl = null; |
241 // Find corresponding SETTINGS-SECTION parent and make it visible. | 240 // Find corresponding SETTINGS-SECTION parent and make it visible. |
242 var parent = node; | 241 var parent = node; |
243 while (parent && parent.nodeName !== 'SETTINGS-SECTION') { | 242 while (parent && parent.nodeName !== 'SETTINGS-SECTION') { |
244 parent = parent.nodeType == Node.DOCUMENT_FRAGMENT_NODE ? | 243 parent = parent.nodeType == Node.DOCUMENT_FRAGMENT_NODE ? |
245 parent.host : parent.parentNode; | 244 parent.host : |
| 245 parent.parentNode; |
246 if (parent.nodeName == 'SETTINGS-SUBPAGE') { | 246 if (parent.nodeName == 'SETTINGS-SUBPAGE') { |
247 // TODO(dpapad): Cast to SettingsSubpageElement here. | 247 // TODO(dpapad): Cast to SettingsSubpageElement here. |
248 associatedControl = assert( | 248 associatedControl = assert( |
249 parent.associatedControl, | 249 parent.associatedControl, |
250 'An associated control was expected for SETTINGS-SUBPAGE ' + | 250 'An associated control was expected for SETTINGS-SUBPAGE ' + |
251 parent.pageTitle + ', but was not found.'); | 251 parent.pageTitle + ', but was not found.'); |
252 } | 252 } |
253 } | 253 } |
254 if (parent) | 254 if (parent) |
255 parent.hiddenBySearch = false; | 255 parent.hiddenBySearch = false; |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 */ | 437 */ |
438 onEmpty: function(onEmptyCallback) { | 438 onEmpty: function(onEmptyCallback) { |
439 this.onEmptyCallback_ = onEmptyCallback; | 439 this.onEmptyCallback_ = onEmptyCallback; |
440 }, | 440 }, |
441 | 441 |
442 /** | 442 /** |
443 * @return {!Task|undefined} | 443 * @return {!Task|undefined} |
444 * @private | 444 * @private |
445 */ | 445 */ |
446 popNextTask_: function() { | 446 popNextTask_: function() { |
447 return this.queues_.high.shift() || | 447 return this.queues_.high.shift() || this.queues_.middle.shift() || |
448 this.queues_.middle.shift() || | |
449 this.queues_.low.shift(); | 448 this.queues_.low.shift(); |
450 }, | 449 }, |
451 | 450 |
452 /** @private */ | 451 /** @private */ |
453 consumePending_: function() { | 452 consumePending_: function() { |
454 if (this.running_) | 453 if (this.running_) |
455 return; | 454 return; |
456 | 455 |
457 while (1) { | 456 while (1) { |
458 var task = this.popNextTask_(); | 457 var task = this.popNextTask_(); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
528 | 527 |
529 /** | 528 /** |
530 * @return {?RegExp} | 529 * @return {?RegExp} |
531 * @private | 530 * @private |
532 */ | 531 */ |
533 generateRegExp_: function() { | 532 generateRegExp_: function() { |
534 var regExp = null; | 533 var regExp = null; |
535 | 534 |
536 // Generate search text by escaping any characters that would be | 535 // Generate search text by escaping any characters that would be |
537 // problematic for regular expressions. | 536 // problematic for regular expressions. |
538 var searchText = this.rawQuery_.trim().replace( | 537 var searchText = |
539 SearchRequest.SANITIZE_REGEX_, '\\$&'); | 538 this.rawQuery_.trim().replace(SearchRequest.SANITIZE_REGEX_, '\\$&'); |
540 if (searchText.length > 0) | 539 if (searchText.length > 0) |
541 regExp = new RegExp('(' + searchText + ')', 'i'); | 540 regExp = new RegExp('(' + searchText + ')', 'i'); |
542 | 541 |
543 return regExp; | 542 return regExp; |
544 }, | 543 }, |
545 | 544 |
546 /** | 545 /** |
547 * @param {string} rawQuery | 546 * @param {string} rawQuery |
548 * @return {boolean} Whether this SearchRequest refers to an identical | 547 * @return {boolean} Whether this SearchRequest refers to an identical |
549 * query. | 548 * query. |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
629 function setSearchManagerForTesting(searchManager) { | 628 function setSearchManagerForTesting(searchManager) { |
630 SearchManagerImpl.instance_ = searchManager; | 629 SearchManagerImpl.instance_ = searchManager; |
631 } | 630 } |
632 | 631 |
633 return { | 632 return { |
634 getSearchManager: getSearchManager, | 633 getSearchManager: getSearchManager, |
635 setSearchManagerForTesting: setSearchManagerForTesting, | 634 setSearchManagerForTesting: setSearchManagerForTesting, |
636 SearchRequest: SearchRequest, | 635 SearchRequest: SearchRequest, |
637 }; | 636 }; |
638 }); | 637 }); |
OLD | NEW |