@@ -3,8 +3,8 @@ var ELEMENT_NODE_TYPE = 1;
33var TEXT_NODE_TYPE = 3 ;
44var UNEXPANDABLE = / ( s c r i p t | s t y l e | s v g | a u d i o | c a n v a s | f i g u r e | v i d e o | s e l e c t | i n p u t | t e x t a r e a ) / i;
55var HIGHLIGHT_TAG = 'highlight-tag' ;
6- var HIGHLIGHT_CLASS = 'chrome-regex-search- highlighted' ;
7- var SELECTED_CLASS = 'chrome-regex-search- selected' ;
6+ var HIGHLIGHT_CLASS = 'highlighted' ;
7+ var SELECTED_CLASS = 'selected' ;
88var DEFAULT_MAX_RESULTS = 500 ;
99var DEFAULT_HIGHLIGHT_COLOR = '#ffff00' ;
1010var DEFAULT_SELECTED_COLOR = '#ff9900' ;
@@ -14,7 +14,6 @@ var DEFAULT_CASE_INSENSITIVE = false;
1414
1515/*** VARIABLES ***/
1616var searchInfo ;
17- var finder ;
1817/*** VARIABLES ***/
1918
2019/*** LIBRARY FUNCTIONS ***/
@@ -35,7 +34,7 @@ function initSearchInfo(pattern) {
3534 searchInfo = {
3635 regexString : pattern ,
3736 selectedIndex : 0 ,
38- highlights : [ ] ,
37+ highlightedNodes : [ ] ,
3938 length : 0
4039 }
4140}
@@ -51,30 +50,58 @@ function returnSearchInfo(cause) {
5150 } ) ;
5251}
5352
53+ /* Check if the given node is a text node */
54+ function isTextNode ( node ) {
55+ return node && node . nodeType === TEXT_NODE_TYPE ;
56+ }
57+
58+ /* Check if the given node is an expandable node that will yield text nodes */
59+ function isExpandable ( node ) {
60+ return node && node . nodeType === ELEMENT_NODE_TYPE && node . childNodes &&
61+ ! UNEXPANDABLE . test ( node . tagName ) && node . visible ( ) ;
62+ }
63+
5464/* Highlight all text that matches regex */
5565function highlight ( regex , highlightColor , selectedColor , textColor , maxResults ) {
56- finder = findAndReplaceDOMText (
57- document . body ,
58- {
59- find : regex ,
60- wrap : "span" ,
61- wrapClass : HIGHLIGHT_CLASS ,
62- filterElements : function ( element ) {
63- /* Check if the element is visible */
64- /* https://stackoverflow.com/a/21696585 */
65- return element . offsetParent !== null || element === document . body ;
66- } ,
67- preset : "prose"
66+ function highlightRecursive ( node ) {
67+ if ( searchInfo . length >= maxResults ) {
68+ return ;
6869 }
69- )
70- searchInfo . highlights = finder . elements ;
71- searchInfo . length = finder . elements . length ;
70+ if ( isTextNode ( node ) ) {
71+ var index = node . data . search ( regex ) ;
72+ if ( index >= 0 && node . data . length > 0 ) {
73+ var matchedText = node . data . match ( regex ) [ 0 ] ;
74+ var matchedTextNode = node . splitText ( index ) ;
75+ matchedTextNode . splitText ( matchedText . length ) ;
76+ var spanNode = document . createElement ( HIGHLIGHT_TAG ) ;
77+ spanNode . className = HIGHLIGHT_CLASS ;
78+ spanNode . style . backgroundColor = highlightColor ;
79+ spanNode . style . color = textColor ;
80+ spanNode . appendChild ( matchedTextNode . cloneNode ( true ) ) ;
81+ matchedTextNode . parentNode . replaceChild ( spanNode , matchedTextNode ) ;
82+ searchInfo . highlightedNodes . push ( spanNode ) ;
83+ searchInfo . length += 1 ;
84+ return 1 ;
85+ }
86+ } else if ( isExpandable ( node ) ) {
87+ var children = node . childNodes ;
88+ for ( var i = 0 ; i < children . length ; ++ i ) {
89+ var child = children [ i ] ;
90+ i += highlightRecursive ( child ) ;
91+ }
92+ }
93+ return 0 ;
94+ }
95+ highlightRecursive ( document . getElementsByTagName ( 'body' ) [ 0 ] ) ;
7296} ;
7397
7498/* Remove all highlights from page */
7599function removeHighlight ( ) {
76- if ( finder ) {
77- finder . revert ( ) ;
100+ while ( node = document . body . querySelector ( HIGHLIGHT_TAG + '.' + HIGHLIGHT_CLASS ) ) {
101+ node . outerHTML = node . innerHTML ;
102+ }
103+ while ( node = document . body . querySelector ( HIGHLIGHT_TAG + '.' + SELECTED_CLASS ) ) {
104+ node . outerHTML = node . innerHTML ;
78105 }
79106} ;
80107
@@ -85,41 +112,22 @@ function scrollToElement(element) {
85112 window . scrollTo ( 0 , Math . max ( top , window . pageYOffset - ( window . innerHeight / 2 ) ) ) ;
86113}
87114
88- /* Select first regex match after selection on page */
115+ /* Select first regex match on page */
89116function selectFirstNode ( selectedColor ) {
90- if ( searchInfo . highlights . length === 0 ) {
91- return ;
92- }
93-
94- function selectIndex ( index ) {
95- searchInfo . selectedIndex = index ;
96- searchInfo . highlights [ index ] . forEach ( ( e ) => { e . className = SELECTED_CLASS ; } ) ;
97- scrollToElement ( searchInfo . highlights [ index ] [ 0 ] ) ;
98- }
99-
100- if ( getSelection ( ) . anchorNode ) {
101- function path ( e ) {
102- return e . parentNode === null ? [ ] : path ( e . parentNode ) . concat ( [ Array . prototype . indexOf . call ( e . parentNode . childNodes , e ) ] ) ;
103- }
104-
105- var selection = path ( getSelection ( ) . anchorNode )
106- var index = searchInfo . highlights . findIndex ( ( h ) => path ( h [ 0 ] ) > selection ) ;
107- if ( index !== - 1 ) {
108- selectIndex ( index ) ;
109- return ;
110- }
117+ var length = searchInfo . length ;
118+ if ( length > 0 ) {
119+ searchInfo . highlightedNodes [ 0 ] . className = SELECTED_CLASS ;
120+ searchInfo . highlightedNodes [ 0 ] . style . backgroundColor = selectedColor ;
121+ scrollToElement ( searchInfo . highlightedNodes [ 0 ] ) ;
111122 }
112-
113- selectIndex ( 0 ) ;
114123}
115124
116125/* Helper for selecting a regex matched element */
117126function selectNode ( highlightedColor , selectedColor , getNext ) {
118127 var length = searchInfo . length ;
119128 if ( length > 0 ) {
120- searchInfo . highlights [ searchInfo . selectedIndex ] . forEach ( function ( n ) {
121- n . className = HIGHLIGHT_CLASS ;
122- } ) ;
129+ searchInfo . highlightedNodes [ searchInfo . selectedIndex ] . className = HIGHLIGHT_CLASS ;
130+ searchInfo . highlightedNodes [ searchInfo . selectedIndex ] . style . backgroundColor = highlightedColor ;
123131 if ( getNext ) {
124132 if ( searchInfo . selectedIndex === length - 1 ) {
125133 searchInfo . selectedIndex = 0 ;
@@ -133,11 +141,10 @@ function selectNode(highlightedColor, selectedColor, getNext) {
133141 searchInfo . selectedIndex -= 1 ;
134142 }
135143 }
136- searchInfo . highlights [ searchInfo . selectedIndex ] . forEach ( function ( n ) {
137- n . className = SELECTED_CLASS ;
138- } ) ;
144+ searchInfo . highlightedNodes [ searchInfo . selectedIndex ] . className = SELECTED_CLASS ;
145+ searchInfo . highlightedNodes [ searchInfo . selectedIndex ] . style . backgroundColor = selectedColor ;
139146 returnSearchInfo ( 'selectNode' ) ;
140- scrollToElement ( searchInfo . highlights [ searchInfo . selectedIndex ] [ 0 ] ) ;
147+ scrollToElement ( searchInfo . highlightedNodes [ searchInfo . selectedIndex ] ) ;
141148 }
142149}
143150/* Forward cycle through regex matched elements */
@@ -174,7 +181,7 @@ function search(regexString, configurationChanged) {
174181 function ( result ) {
175182 initSearchInfo ( regexString ) ;
176183 if ( result . caseInsensitive ) {
177- regex = new RegExp ( regexString , 'gi ' ) ;
184+ regex = new RegExp ( regexString , 'i ' ) ;
178185 }
179186 highlight ( regex , result . highlightColor , result . selectedColor , result . textColor , result . maxResults ) ;
180187 selectFirstNode ( result . selectedColor ) ;
@@ -245,17 +252,4 @@ chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
245252
246253/*** INIT ***/
247254initSearchInfo ( ) ;
248-
249- chrome . storage . local . get ( {
250- 'highlightColor' : DEFAULT_HIGHLIGHT_COLOR ,
251- 'selectedColor' : DEFAULT_SELECTED_COLOR ,
252- 'textColor' : DEFAULT_TEXT_COLOR ,
253- } , function ( result ) {
254- var css = document . createElement ( "style" ) ;
255- css . type = "text/css" ;
256- css . innerHTML =
257- "." + HIGHLIGHT_CLASS + " { background: " + result . highlightColor + "; color: " + result . textColor + " }\n" +
258- "." + SELECTED_CLASS + " { background: " + result . selectedColor + "; color: " + result . textColor + " }" ;
259- document . body . appendChild ( css ) ;
260- } ) ;
261255/*** INIT ***/
0 commit comments