/[bfilter]/trunk/bfilter.js
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/bfilter.js

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 6 by dpavlin, Tue Sep 7 09:29:36 2004 UTC revision 30 by dpavlin, Fri Sep 24 16:58:08 2004 UTC
# Line 1  Line 1 
1  /*  /*
2     Fast filtering function using pre-sorted list elements     Fast filtering function using pre-sorted list elements
3     Dobrica Pavlinusic, dpavlin@rot13.org 2004-09-06     Dobrica Pavlinusic, dpavlin@rot13.org 2004-09-06
4       Matko Andjelinic, matko.andjelinic@gmail.com 2004-09-09 (contributed OO implementation)
5  */  */
6    
7  var debug = 0;  top.__bfilter_obj = new Array();
8    
 function bfilter_init() {  
         show_status();  
 }  
9    
10  var id_cache = Array();  function BFilter(arr) {
11            this.id_cache = Array();
12            // total number of hits
13            this.hits = 0;
14    
15            // store reference to this object for later (YAK)
16            this.obj_count = top.__bfilter_obj.length;
17            top.__bfilter_obj[this.obj_count] = this;
18    
19            // clear results html
20            this.results_html = '';
21    
22            // show results after 0.2s
23            this.timeout = 200;
24            this.timeout_handle = null;
25    
26            // this function is called for each result
27            this.result = function (arr) {
28                    this.results_html += '<li><a href="'+arr[1]+'">'+
29                            (this.hits % 2 == 0 ? '<span style="background: #e0e0e0;">' : '') +
30                            arr[0] +
31                            (this.hits % 2 == 0 ? '</span>' : '') +
32                            '</a></li>';
33                    return true;
34            }
35    
36            // this function is called when updating innerHTML with results
37            this.display = function () {
38                    if (this.results_html) {
39                            return '<ul>'+this.results_html+'</ul>';
40                    } else {
41                            return null;
42                    }
43            }
44    
45    
46            if (! arr) {
47                    this.debug("ERROR: can't search empty array");
48                    return;
49            }
50    
51            this.arr = arr;
52            this.debug("index has "+this.arr.length+" parts");
53    
54  function element_id(id) {          if (! arr.min_len) {
55          if (id_cache[id]) {                  this.results("ERROR: index structure problem");
56                  return id_cache[id];                  return;
57          } else {          } else {
58                  var el = document.getElementById(id);                  this.min_len = arr.min_len;
59            }
60    
61            this.debug("index part has "+this.min_len+" parts");
62    
63            this.show_status();
64    
65    }
66    
67    BFilter.prototype.element_id = function (id,no_alert) {
68            if (this.id_cache[id]) {
69                    return this.id_cache[id];
70            } else {
71                    var el = self.document.getElementById(id);
72                  if (el) {                  if (el) {
73                          id_cache[id] = el;                          this.id_cache[id] = el;
74                          return el;                          return el;
75                  } else {                  } else {
76                          alert("can't find element id: "+id);                          if (! no_alert) {
77                                    alert("can't find element id: "+id);
78                            } else {
79                                    // don't look it up again
80                                    this.id_cache[id] = null;
81                            }
82                  }                  }
83          }          }
84            return null;
85  }  }
86    
 // total number of hits  
 var hits = 0;  
87    
88  function show_status(status) {  BFilter.prototype.show_status = function (status) {
89          var html;          var html;
90          if (hits > 0) {          if (this.hits > 0) {
91                  html = "shown "+hits+" entries";                  html = "shown "+this.hits+" entries";
92          } else {          } else {
93                  html = "no results";                  html = "no results";
94          }          }
95          if (! status) {          if (! status) {
96                  html = "Enter "+min_len+" letter"+(min_len == 1 ? '' : 's')+" to filter entries";                  html = "Enter "+this.min_len+" letter"+(this.min_len == 1 ? '' : 's')+" to filter entries";
97                  status = "";                  status = "";
98          }          }
99    
100          var el = element_id("status");          var el = this.element_id("status");
101          el.innerHTML = html+status+"\n";          el.innerHTML = html+status+"\n";
102  }  }
103    
104  var wait = 0;  BFilter.prototype.results = function (html,clean) {
   
 function results(html,clean) {  
105    
106          if (! html) { html = ""; }          if (! html) { html = ""; }
107    
108          // results_div.style.cursor = 'wait'; // 'auto'          // results_div.style.cursor = 'wait'; // 'auto'
109          var results_div = element_id("results");          var results_div = this.element_id("results");
110          if (clean) {          if (clean) {
111                  results_div.innerHTML = html+"\n";                  results_div.innerHTML = html;
112                    this.results_html = '';
113          } else {          } else {
114                  results_div.innerHTML += html+"\n";                  html = this.display();
115                    if (html) results_div.innerHTML += html;
116          }          }
117  }  }
118    
119    
120    BFilter.prototype.debug = function (html) {
121    
122            //return;
123    
124            // check if debugging is on
125            if (! html) { return 1; }
126    
127            var debug_div = this.element_id("debug",1);
128            if (! debug_div) { return null; }
129    
130            debug_div.innerHTML += html + "<br>\n";
131    
132            return null;
133    }
134    
135    
136  // modified binary search to find first element with substring  // modified binary search to find first element with substring
137  function binarySearch(arr, find) {  BFilter.prototype.binarySearch = function (arr, user_filter) {
138          if (!arr || typeof (find) == "undefined" || !arr.length) {          if (!arr || typeof (user_filter) == "undefined" || !arr.length) {
139                  return null;                  return null;
140          }          }
141          var low = 0;          var low = 0;
# Line 72  function binarySearch(arr, find) { Line 146  function binarySearch(arr, find) {
146                  var mid = (low + high) / 2;                  var mid = (low + high) / 2;
147                  var aTry = (mid < 1) ? 0 : parseInt(mid);                  var aTry = (mid < 1) ? 0 : parseInt(mid);
148                    
149                  var curr = arr[aTry].substr(0,find.length).toLowerCase();                  var curr = arr[aTry][0].substr(0,user_filter.length).toLowerCase();
150                  if (debug) { results("low="+low+" high="+high+" lastTry="+lastTry+" "+aTry+": "+curr+"<br>"); }                  this.debug("low="+low+" high="+high+" lastTry="+lastTry+" "+aTry+": "+curr);
151                  if (curr < find) {                  if (curr < user_filter) {
152                          low = aTry + 1;                          low = aTry + 1;
153                          continue;                          continue;
154                  }                  }
155                  if (curr > find) {                  if (curr > user_filter) {
156                          high = aTry - 1;                          high = aTry - 1;
157                          continue;                          continue;
158                  }                  }
159                  if (curr == find) {                  if (curr == user_filter) {
160                          high = aTry - 1;                          high = aTry - 1;
161                          lastTry = aTry;                          lastTry = aTry;
162                          continue;                          continue;
163                  }                  }
164                  return aTry;                  return aTry;
165          }          }
166          if (debug) { results("lastTry="+lastTry+"<br>"); }          this.debug("lastTry="+lastTry);
167    
168          if (typeof (lastTry) != "undefined") {          if (typeof (lastTry) != "undefined") {
169                  return lastTry;                  return lastTry;
# Line 98  function binarySearch(arr, find) { Line 172  function binarySearch(arr, find) {
172          }          }
173  }  }
174    
175  function bfilter(document, id, find, arr) {  BFilter.prototype.filter = function (user_filter) {
176            this.debug("set timeout for "+this.obj_count+" to "+this.timeout);
177            if (this.timeout_handle) {
178                    clearTimeout(this.timeout_handle);
179                    this.timeout_handle = null;
180            }
181            this.timeout_handle=setTimeout("top.__bfilter_obj["+this.obj_count+"].show_filter('"+user_filter.replace(/'/,"\\'")+"');", this.timeout);
182            return true;
183    }
184    
185    BFilter.prototype.show_filter = function (user_filter) {
186    
187          results('',1);          if (this.timeout_handle) {
188          hits = 0;                  clearTimeout(this.timeout_handle);
189                    this.timeout_handle = null;
190                    this.debug("timeout cleared");
191            }
192    
193            this.results('',1);
194            this.hits = 0;
195    
196          if (find.length < min_len) {          if (user_filter.length < this.min_len) {
197                  show_status();                  this.show_status();
198                  return;                  return;
199          }          }
200    
201          if (debug) { results("filter: '"+find+"'<br>"); }          this.debug("filter: '"+user_filter+"'");
202    
203          var find_lc = find.toLowerCase();          var user_filter_lc = user_filter.toLowerCase();
204    
205          var part = find_lc.substr(0,min_len);          var part = user_filter_lc.substr(0,this.min_len);
206    
207          // no part found          // no part found
208          if (! arr[part]) {          if (! this.arr[part]) {
209                  show_status(" for <em>"+find+"</em><br>");                  this.show_status(" for <em>"+user_filter+"</em><br>");
210                    this.debug("no part "+part);
211                  return;                  return;
212          }          }
213    
214          // start anim icon          // start anim icon
215          //results("<img  src=\"pie.gif\">&nbsp;Please wait, filtering...\n",1);          //results("<img  src=\"pie.gif\">&nbsp;Please wait, filtering...\n",1);
216    
217            var i;
218    
219          // full part? (optimization)          // full part? (optimization)
220          if (find.length == min_len) {          if (user_filter.length == this.min_len) {
221                  var html = '';                  for (i = 0; i < this.arr[part].length; i++) {
222                  for (var i = 0; i < arr[part].length; i++) {                          this.result(this.arr[part][i]);
223                          html += "<li>";                          this.hits++;
                         if (debug) { $html += i+": "; }  
                         html += arr[part][i]+"</li>\n";  
                         hits++;  
224                  }                  }
225                  results(html);                  this.results();
226          } else {          } else {
227    
228                  var from = binarySearch(arr[part], find_lc);                  var from = this.binarySearch(this.arr[part], user_filter_lc);
229    
230                  if (from != null) {                  if (from != null) {
231                                    
232                          if (debug) { results("loop "+from+" ... "+arr[part].length)+"<br>\n"; }                          this.debug("loop "+from+" ... "+this.arr[part].length);
   
                         var html = '';  
233    
234                          for(var i = from ; i < arr[part].length ; i++) {                          for(i = from ; i < this.arr[part].length ; i++) {
235                                  if (arr[part][i].substring(0,find.length).toLowerCase() != find_lc) {                                  if (this.arr[part][i][0].substring(0,user_filter.length).toLowerCase() != user_filter_lc) {
236                                            this.debug("loop exit at "+i);
237                                          break;                                          break;
238                                  }                                  }
239                                  if (debug) { html += i+": "; }                                  this.result(this.arr[part][i]);
240                                  html += arr[part][i]+"<br>\n";                                  this.hits++;
                                 hits++;  
241                          }                          }
242    
243                          results(html);                          this.results();
244                  }                  }
245    
246          }          }
247    
248          show_status(" for <em>"+find+"</em>");          this.show_status(" for <em>"+user_filter+"</em>");
249    
250  }  }
251    

Legend:
Removed from v.6  
changed lines
  Added in v.30

  ViewVC Help
Powered by ViewVC 1.1.26