From 9c48c5aefad070e01d410775178648e618a4f9c1 Mon Sep 17 00:00:00 2001
From: renato <renato@rezo.net>
Date: Fri, 18 May 2007 19:05:54 +0000
Subject: [PATCH] escape special chars in regexs and avoid looping the browser
 on some conditions

---
 dist/javascript/SearchHighlight.js | 451 +++++++++++++++--------------
 1 file changed, 226 insertions(+), 225 deletions(-)

diff --git a/dist/javascript/SearchHighlight.js b/dist/javascript/SearchHighlight.js
index 36df841b74..5c3ae5dc87 100644
--- a/dist/javascript/SearchHighlight.js
+++ b/dist/javascript/SearchHighlight.js
@@ -1,225 +1,226 @@
-/**
- * SearchHighlight plugin for jQuery
- * 
- * Thanks to Scott Yang <http://scott.yang.id.au/>
- * for the original idea and some code
- *    
- * @author Renato Formato <renatoformato@virgilio.it> 
- *  
- * @version 0.32
- *
- *  Options
- *  - exact (string, default:"exact") 
- *    "exact" : find and highlight the exact words.
- *    "whole" : find partial matches but highlight whole words
- *    "partial": find and highlight partial matches
- *     
- *  - style_name (string, default:'hilite')
- *    The class given to the span wrapping the matched words.
- *     
- *  - style_name_suffix (boolean, default:true)
- *    If true a different number is added to style_name for every different matched word.
- *     
- *  - debug_referrer (string, default:null)
- *    Set a referrer for debugging purpose.
- *     
- *  - engines (array of regex, default:null)
- *    Add a new search engine regex to highlight searches coming from new search engines.
- *    The first element is the regex to match the domain.
- *    The second element is the regex to match the query string. 
- *    Ex: [/^http:\/\/my\.site\.net/i,/search=([^&]+)/i]        
- *            
- *  - startHighlightComment (string, default:null)
- *    The text of a comment that starts a block enabled for highlight.
- *    If null all the document is enabled for highlight.
- *        
- *  - stopHighlightComment (string, default:null)  
- *    The text of a comment that ends a block enabled for highlight.
- *    If null all the document is enabled for highlight. 
- */
-
-(function($){
-  jQuery.fn.SearchHighlight = function(options) {
-    var ref = options.debug_referrer || document.referrer;
-    if(!ref && options.keys==undefined) return this;
-    
-    SearchHighlight.options = $.extend({exact:"exact",style_name:'hilite',style_name_suffix:true},options);
-    
-    if(options.engines) SearchHighlight.engines.unshift(options.engines);  
-    var q = options.keys!=undefined?options.keys.split(/[\s,\+\.]+/):SearchHighlight.decodeURL(ref,SearchHighlight.engines);
-    if(q && q.join("")) {
-      SearchHighlight.buildReplaceTools(q);
-      return this.each(function(){
-        var el = this;
-        if(el==document) el = $("body")[0];
-        SearchHighlight.hiliteElement(el, q); 
-      })
-    } else return this;
-  }    
-
-  var SearchHighlight = {
-    options: {},
-    regex: [],
-    engines: [
-    [/^http:\/\/(www\.)?google\./i, /q=([^&]+)/i],                            // Google
-    [/^http:\/\/(www\.)?search\.yahoo\./i, /p=([^&]+)/i],                     // Yahoo
-    [/^http:\/\/(www\.)?search\.msn\./i, /q=([^&]+)/i],                       // MSN
-    [/^http:\/\/(www\.)?search\.live\./i, /query=([^&]+)/i],                  // MSN Live
-    [/^http:\/\/(www\.)?search\.aol\./i, /userQuery=([^&]+)/i],               // AOL
-    [/^http:\/\/(www\.)?ask\.com/i, /q=([^&]+)/i],                            // Ask.com
-    [/^http:\/\/(www\.)?altavista\./i, /q=([^&]+)/i],                         // AltaVista
-    [/^http:\/\/(www\.)?feedster\./i, /q=([^&]+)/i],                          // Feedster
-    [/^http:\/\/(www\.)?search\.lycos\./i, /q=([^&]+)/i],                     // Lycos
-    [/^http:\/\/(www\.)?alltheweb\./i, /q=([^&]+)/i],                         // AllTheWeb
-    [/^http:\/\/(www\.)?technorati\.com/i, /([^\?\/]+)(?:\?.*)$/i],           // Technorati
-    ],
-    subs: {},
-    decodeURL: function(URL,reg) {
-      URL = decodeURIComponent(URL);
-      var query = null;
-      $.each(reg,function(i,n){
-        if(n[0].test(URL)) {
-          var match = URL.match(n[1]);
-          if(match) {
-            query = match[1];
-            return false;
-          }
-        }
-      })
-      
-      if (query) {
-      query = query.replace(/(\'|")/, '\$1');
-      query = query.split(/[\s,\+\.]+/);
-      }
-      
-      return query;
-    },
-		regexAccent : [
-      [/[\xC0-\xC5\u0100-\u0105]/ig,'a'],
-      [/[\xC7\u0106-\u010D]/ig,'c'],
-      [/[\xC8-\xCB]/ig,'e'],
-      [/[\xCC-\xCF]/ig,'i'],
-      [/\xD1/ig,'n'],
-      [/[\xD2-\xD6\xD8]/ig,'o'],
-      [/[\u015A-\u0161]/ig,'s'],
-      [/[\u0162-\u0167]/ig,'t'],
-      [/[\xD9-\xDC]/ig,'u'],
-      [/\xFF/ig,'y'],
-      [/[\x91\x92\u2018\u2019]/ig,'\'']
-    ],
-    matchAccent : /[\x91\x92\xC0-\xC5\xC7-\xCF\xD1-\xD6\xD8-\xDC\xFF\u0100-\u010D\u015A-\u0167\u2018\u2019]/ig,  
-		replaceAccent: function(q) {
-		  SearchHighlight.matchAccent.lastIndex = 0;
-      if(SearchHighlight.matchAccent.test(q)) {
-        for(var i=0,l=SearchHighlight.regexAccent.length;i<l;i++)
-          q = q.replace(SearchHighlight.regexAccent[i][0],SearchHighlight.regexAccent[i][1]);
-      }
-      return q;
-    },
-    buildReplaceTools : function(query) {
-        re = new Array();
-        for (var i = 0, l=query.length; i < l; i ++) {
-            query[i] = SearchHighlight.replaceAccent(query[i].toLowerCase());
-            re.push(query[i]);
-        }
-        
-        var regex = re.join("|");
-        switch(SearchHighlight.options.exact) {
-          case "exact":
-            regex = '\\b(?:'+regex+')\\b';
-            break;
-          case "whole":
-            regex = '\\b\\w*('+regex+')\\w*\\b';
-            break;
-        }    
-        SearchHighlight.regex = new RegExp(regex, "gi");
-        
-        for (var i = 0, l = query.length; i < l; i ++) {
-            SearchHighlight.subs[query[i]] = SearchHighlight.options.style_name+
-              (SearchHighlight.options.style_name_suffix?i+1:''); 
-        }        
-    },
-    nosearch: /s(?:cript|tyle)|textarea/i,
-    hiliteElement: function(el, query) {
-        var startIndex, endIndex, comment = false, opt = SearchHighlight.options;
-        if(!opt.startHighlightComment || !opt.stopHighlightComment)
-          return SearchHighlight.hiliteTree(0,el.childNodes.length,el,query);
-        if($.browser.msie) {
-          var item = el.firstChild, i = 0, parents = [], startComment = false;
-          while(item) {
-            if(item.nodeType==8) {
-              if($.trim(item.data)==opt.startHighlightComment) {
-                comment = startComment = true;
-                startIndex= i+1;
-              } else if($.trim(item.data)==opt.stopHighlightComment) {
-                endIndex = i;
-                SearchHighlight.hiliteTree(startIndex,endIndex,item.parentNode,query);
-                startComment = false;
-              }
-            }
-            var next = item.nextSibling, back, child;
-            if(!startComment && (child = item.firstChild)) {
-              if(next)
-                parents.push([next,i+1]);
-              item = child;
-              i = 0;
-            } else {
-              if(!(item = next)) {
-                if(back = parents.pop()) {
-                  item = back[0];
-                  i =  back[1];
-                }
-              } else i++;
-            }
-          }
-        } else {
-          var walker = document.createTreeWalker(el,NodeFilter.SHOW_COMMENT,null,false), currComment;
-          while(currComment = walker.nextNode()) {
-            if($.trim(currComment.data)==opt.startHighlightComment) {
-              comment = true;
-              el = currComment.parentNode;
-              startIndex = 0;
-              endIndex = el.childNodes.length;
-              while(el.childNodes[startIndex]!=currComment) startIndex++;
-              startIndex++;
-            } else if($.trim(currComment.data)==opt.stopHighlightComment) {
-              while(el.childNodes[endIndex-1]!=currComment) endIndex--;
-              SearchHighlight.hiliteTree(startIndex,endIndex,el,query);
-            }
-          }
-        }
-        if(!comment) SearchHighlight.hiliteTree(0,el.childNodes.length,el,query);
-    },
-    hiliteTree : function(startIndex,endIndex,el,query) {
-        var matchIndex = SearchHighlight.options.exact=="whole"?1:0;
-        for(;startIndex<endIndex;startIndex++) {
-          var item = el.childNodes[startIndex];
-          if ( item.nodeType != 8 ) {//comment node
-  				  //text node
-            if(item.nodeType==3) {
-              var text = item.data, textNoAcc = SearchHighlight.replaceAccent(text);
-              var newtext="",match,index=0;
-              SearchHighlight.regex.lastIndex = 0;
-              while(match = SearchHighlight.regex.exec(textNoAcc)) {
-                newtext += text.substr(index,match.index-index)+'<span class="'+
-                SearchHighlight.subs[match[matchIndex].toLowerCase()]+'">'+text.substr(match.index,match[0].length)+"</span>";
-                index = match.index+match[0].length;
-              }
-              if(newtext) {
-                //add ther last part of the text
-                newtext += text.substring(index);
-                var repl = $.merge([],$("<span>"+newtext+"</span>")[0].childNodes);
-                endIndex += repl.length-1;
-                startIndex += repl.length-1;
-                $(item).before(repl).remove();
-              }                
-            } else {
-              if(item.nodeType==1 && item.nodeName.search(SearchHighlight.nosearch)==-1)
-                SearchHighlight.hiliteTree(0,item.childNodes.length,item,query);
-            }	
-          }
-        }    
-    }
-    
-  };
-})(jQuery)
+/**
+ * SearchHighlight plugin for jQuery
+ * 
+ * Thanks to Scott Yang <http://scott.yang.id.au/>
+ * for the original idea and some code
+ *    
+ * @author Renato Formato <renatoformato@virgilio.it> 
+ *  
+ * @version 0.32
+ *
+ *  Options
+ *  - exact (string, default:"exact") 
+ *    "exact" : find and highlight the exact words.
+ *    "whole" : find partial matches but highlight whole words
+ *    "partial": find and highlight partial matches
+ *     
+ *  - style_name (string, default:'hilite')
+ *    The class given to the span wrapping the matched words.
+ *     
+ *  - style_name_suffix (boolean, default:true)
+ *    If true a different number is added to style_name for every different matched word.
+ *     
+ *  - debug_referrer (string, default:null)
+ *    Set a referrer for debugging purpose.
+ *     
+ *  - engines (array of regex, default:null)
+ *    Add a new search engine regex to highlight searches coming from new search engines.
+ *    The first element is the regex to match the domain.
+ *    The second element is the regex to match the query string. 
+ *    Ex: [/^http:\/\/my\.site\.net/i,/search=([^&]+)/i]        
+ *            
+ *  - startHighlightComment (string, default:null)
+ *    The text of a comment that starts a block enabled for highlight.
+ *    If null all the document is enabled for highlight.
+ *        
+ *  - stopHighlightComment (string, default:null)  
+ *    The text of a comment that ends a block enabled for highlight.
+ *    If null all the document is enabled for highlight. 
+ */
+
+(function($){
+  jQuery.fn.SearchHighlight = function(options) {
+    var ref = options.debug_referrer || document.referrer;
+    if(!ref && options.keys==undefined) return this;
+    
+    SearchHighlight.options = $.extend({exact:"exact",style_name:'hilite',style_name_suffix:true},options);
+    
+    if(options.engines) SearchHighlight.engines.unshift(options.engines);  
+    var q = options.keys!=undefined?options.keys.toLowerCase().split(/[\s,\+\.]+/):SearchHighlight.decodeURL(ref,SearchHighlight.engines);
+    if(q && q.join("")) {
+      SearchHighlight.buildReplaceTools(q);
+      return this.each(function(){
+        var el = this;
+        if(el==document) el = $("body")[0];
+        SearchHighlight.hiliteElement(el, q); 
+      })
+    } else return this;
+  }    
+
+  var SearchHighlight = {
+    options: {},
+    regex: [],
+    engines: [
+    [/^http:\/\/(www\.)?google\./i, /q=([^&]+)/i],                            // Google
+    [/^http:\/\/(www\.)?search\.yahoo\./i, /p=([^&]+)/i],                     // Yahoo
+    [/^http:\/\/(www\.)?search\.msn\./i, /q=([^&]+)/i],                       // MSN
+    [/^http:\/\/(www\.)?search\.live\./i, /query=([^&]+)/i],                  // MSN Live
+    [/^http:\/\/(www\.)?search\.aol\./i, /userQuery=([^&]+)/i],               // AOL
+    [/^http:\/\/(www\.)?ask\.com/i, /q=([^&]+)/i],                            // Ask.com
+    [/^http:\/\/(www\.)?altavista\./i, /q=([^&]+)/i],                         // AltaVista
+    [/^http:\/\/(www\.)?feedster\./i, /q=([^&]+)/i],                          // Feedster
+    [/^http:\/\/(www\.)?search\.lycos\./i, /q=([^&]+)/i],                     // Lycos
+    [/^http:\/\/(www\.)?alltheweb\./i, /q=([^&]+)/i],                         // AllTheWeb
+    [/^http:\/\/(www\.)?technorati\.com/i, /([^\?\/]+)(?:\?.*)$/i],           // Technorati
+    ],
+    subs: {},
+    decodeURL: function(URL,reg) {
+      URL = decodeURIComponent(URL);
+      var query = null;
+      $.each(reg,function(i,n){
+        if(n[0].test(URL)) {
+          var match = URL.match(n[1]);
+          if(match) {
+            query = match[1].toLowerCase();
+            return false;
+          }
+        }
+      })
+      
+      if (query) {
+      query = query.replace(/(\'|")/, '\$1');
+      query = query.split(/[\s,\+\.]+/);
+      }
+      
+      return query;
+    },
+		regexAccent : [
+      [/[\xC0-\xC5\u0100-\u0105]/ig,'a'],
+      [/[\xC7\u0106-\u010D]/ig,'c'],
+      [/[\xC8-\xCB]/ig,'e'],
+      [/[\xCC-\xCF]/ig,'i'],
+      [/\xD1/ig,'n'],
+      [/[\xD2-\xD6\xD8]/ig,'o'],
+      [/[\u015A-\u0161]/ig,'s'],
+      [/[\u0162-\u0167]/ig,'t'],
+      [/[\xD9-\xDC]/ig,'u'],
+      [/\xFF/ig,'y'],
+      [/[\x91\x92\u2018\u2019]/ig,'\'']
+    ],
+    matchAccent : /[\x91\x92\xC0-\xC5\xC7-\xCF\xD1-\xD6\xD8-\xDC\xFF\u0100-\u010D\u015A-\u0167\u2018\u2019]/ig,  
+		replaceAccent: function(q) {
+		  SearchHighlight.matchAccent.lastIndex = 0;
+      if(SearchHighlight.matchAccent.test(q)) {
+        for(var i=0,l=SearchHighlight.regexAccent.length;i<l;i++)
+          q = q.replace(SearchHighlight.regexAccent[i][0],SearchHighlight.regexAccent[i][1]);
+      }
+      return q;
+    },
+    escapeRegEx : /((?:\\{2})*)([[\]{}*?|])/g, //the special chars . and + are already gone at this point because they are considered split chars
+    buildReplaceTools : function(query) {
+        var re = [], regex;
+        $.each(query,function(i,n){
+            if(n = SearchHighlight.replaceAccent(n).replace(SearchHighlight.escapeRegEx,"$1\\$2"))
+              re.push(n);        
+        });
+        
+        regex = re.join("|");
+        switch(SearchHighlight.options.exact) {
+          case "exact":
+            regex = '\\b(?:'+regex+')\\b';
+            break;
+          case "whole":
+            regex = '\\b\\w*('+regex+')\\w*\\b';
+            break;
+        }    
+        SearchHighlight.regex = new RegExp(regex, "gi");
+        
+        $.each(re,function(i,n){
+            SearchHighlight.subs[n] = SearchHighlight.options.style_name+
+              (SearchHighlight.options.style_name_suffix?i+1:''); 
+        });       
+    },
+    nosearch: /s(?:cript|tyle)|textarea/i,
+    hiliteElement: function(el, query) {
+        var startIndex, endIndex, comment = false, opt = SearchHighlight.options;
+        if(!opt.startHighlightComment || !opt.stopHighlightComment)
+          return SearchHighlight.hiliteTree(0,el.childNodes.length,el,query);
+        if($.browser.msie) {
+          var item = el.firstChild, i = 0, parents = [], startComment = false;
+          while(item) {
+            if(item.nodeType==8) {
+              if($.trim(item.data)==opt.startHighlightComment) {
+                comment = startComment = true;
+                startIndex= i+1;
+              } else if($.trim(item.data)==opt.stopHighlightComment) {
+                endIndex = i;
+                SearchHighlight.hiliteTree(startIndex,endIndex,item.parentNode,query);
+                startComment = false;
+              }
+            }
+            var next = item.nextSibling, back, child;
+            if(!startComment && (child = item.firstChild)) {
+              if(next)
+                parents.push([next,i+1]);
+              item = child;
+              i = 0;
+            } else {
+              if(!(item = next)) {
+                if(back = parents.pop()) {
+                  item = back[0];
+                  i =  back[1];
+                }
+              } else i++;
+            }
+          }
+        } else {
+          var walker = document.createTreeWalker(el,NodeFilter.SHOW_COMMENT,null,false), currComment;
+          while(currComment = walker.nextNode()) {
+            if($.trim(currComment.data)==opt.startHighlightComment) {
+              comment = true;
+              el = currComment.parentNode;
+              startIndex = 0;
+              endIndex = el.childNodes.length;
+              while(el.childNodes[startIndex]!=currComment) startIndex++;
+              startIndex++;
+            } else if($.trim(currComment.data)==opt.stopHighlightComment) {
+              while(el.childNodes[endIndex-1]!=currComment) endIndex--;
+              SearchHighlight.hiliteTree(startIndex,endIndex,el,query);
+            }
+          }
+        }
+        if(!comment) SearchHighlight.hiliteTree(0,el.childNodes.length,el,query);
+    },
+    hiliteTree : function(startIndex,endIndex,el,query) {
+        var matchIndex = SearchHighlight.options.exact=="whole"?1:0;
+        for(;startIndex<endIndex;startIndex++) {
+          var item = el.childNodes[startIndex];
+          if ( item.nodeType != 8 ) {//comment node
+  				  //text node
+            if(item.nodeType==3) {
+              var text = item.data, textNoAcc = SearchHighlight.replaceAccent(text);
+              var newtext="",match,index=0;
+              SearchHighlight.regex.lastIndex = 0;
+              while(match = SearchHighlight.regex.exec(textNoAcc)) {
+                newtext += text.substr(index,match.index-index)+'<span class="'+
+                SearchHighlight.subs[match[matchIndex].toLowerCase()]+'">'+text.substr(match.index,match[0].length)+"</span>";
+                index = match.index+match[0].length;
+              }
+              if(newtext) {
+                //add the last part of the text
+                newtext += text.substring(index);
+                var repl = $.merge([],$("<span>"+newtext+"</span>")[0].childNodes);
+                endIndex += repl.length-1;
+                startIndex += repl.length-1;
+                $(item).before(repl).remove();
+              }                
+            } else {
+              if(item.nodeType==1 && item.nodeName.search(SearchHighlight.nosearch)==-1)
+                SearchHighlight.hiliteTree(0,item.childNodes.length,item,query);
+            }	
+          }
+        }    
+    }
+    
+  };
+})(jQuery)
-- 
GitLab