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

Legend:
Removed from v.8  
changed lines
  Added in v.32

  ViewVC Help
Powered by ViewVC 1.1.26