optimized for speed - OK for nodes, but 4000+ persons is still one second per keystro...
[plewww.git] / plekit / table / table.js
1 /* $Id$ */
2
3 /* when a table gets paginated, displays context info */
4 function plekit_table_paginator (opts,table_id) {
5
6   if(!("currentPage" in opts)) { return; }
7     
8   var p = document.createElement('p');
9   var table=$(table_id);
10   var t = $(table_id+'-fdtablePaginaterWrapTop');
11   var b = $(table_id+'-fdtablePaginaterWrapBottom');
12
13   /* when there's no visible entry, the pagination code removes the wrappers */
14   if ( (!t) || (!b) ) return;
15
16   /* get how many entries are matching:
17      opts.visibleRows only holds the contents of the current page
18      so we store the number of matching entries in the table 'matching' attribute
19   */
20   var totalMatches = opts.totalRows;
21   var matching=table['matching'];
22   if (matching) totalMatches = matching;
23
24   var label;
25
26   var matches_text;
27   if (totalMatches != opts.totalRows) {
28     matches_text = totalMatches + "/" + opts.totalRows;
29   } else {
30     matches_text = opts.totalRows;
31   }
32   var first = ((opts.currentPage-1) * opts.rowsPerPage) +1;
33   var last = Math.min((opts.currentPage * opts.rowsPerPage),totalMatches);
34   var items_text = "Items [" + first + " - " + last + "] of " + matches_text;
35   var page_text = "Page " + opts.currentPage + " of " + Math.ceil(totalMatches / opts.rowsPerPage);
36   label = items_text + " -- " + page_text;
37
38   p.className = "paginationText";    
39   p.appendChild(document.createTextNode(label));
40
41   /*  t.insertBefore(p.cloneNode(true), t.firstChild); */
42   b.appendChild(p);
43 }
44
45
46 /* locates a table from its id and alters the classname to reflect new table size */
47 function plekit_pagesize_set (table_id,size_id,def_size) {
48   var table=document.getElementById(table_id);
49   var size_area=document.getElementById(size_id);
50   if ( ! size_area.value ) {
51     size_area.value=def_size;
52   }
53   var size=size_area.value;
54   table.className=table.className.replace(/paginate-\d+/,"paginate-"+size); 
55   tablePaginater.init(table_id);
56 }
57
58 function plekit_pagesize_reset(table_id, size_id, size) {
59   var table=document.getElementById(table_id);
60   var size_area=document.getElementById(size_id);
61   size_area.value=size;
62   table.className=table.className.replace(/paginate-\d+/,"paginate-"+size); 
63   tablePaginater.init(table_id);
64 }
65   
66 /* set or clear the ' invisibleRow' in the tr's classname, according to visible */
67 function plekit_table_row_visible (row,visible) {
68   var cn=row.className;
69   /* clear */
70   cn=cn.replace(" invisibleRow","");
71   if (! visible) cn += " invisibleRow";
72   row.className=cn;
73 }
74
75 // Working around MSIE...
76 if ('undefined' == typeof Node)
77     Node = { ELEMENT_NODE: 1, TEXT_NODE: 3 };
78
79 // Extract actual text from a DOM node (remove internal tags and so on)
80 function getInnerText(node) {
81         var result = '';
82         if (Node.TEXT_NODE == node.nodeType)
83                 return node.nodeValue;
84         if (Node.ELEMENT_NODE != node.nodeType)
85                 return '';
86         for (var index = 0; index < node.childNodes.length; ++index)
87                 result += getInnerText(node.childNodes.item(index));
88         return result;
89 } // getInnerText
90
91 // cache in the <tr> node the concatenation of the innerTexts of its cells
92 function plekit_tr_text (tr) {
93   // if cached, use it
94   if (tr['text_to_match']) return tr['text_to_match'];
95   // otherwise compute it
96   var text="";
97   var cells=tr.cells;
98   for (var i=0; i<cells.length; i++) 
99     text += getInnerText(cells[i]) + " ";
100   text = text.strip().toLowerCase();
101   tr['text_to_match'] = text;
102   return text;
103 }
104
105 /* scan the table, and mark as visible 
106    the rows that match (either AND or OR the patterns) */
107 function plekit_table_filter (table_id,pattern_id,and_id) {
108   var table=$(table_id);
109   var css='#'+table_id+'>tbody';
110   var rows = $$(css)[0].rows;
111   var pattern_area = $(pattern_id);
112   var pattern_text = pattern_area.value;
113   var matching_entries=0;
114   var and_button=$(and_id);
115   var and_if_true=and_button.checked;
116
117   // canonicalize white spaces 
118   pattern_text = pattern_text.replace(/^\s+/, '').replace(/\s+$/, '').replace(/\s+/g,' ');
119   
120   if (pattern_text.indexOf ("&") != -1) {
121     pattern_text = pattern_text.replace(/&/," ");
122     pattern_area.value=pattern_text;
123     and_button.checked=true;
124     return;
125   } else if (pattern_text.indexOf ("|") != -1 ) {
126     pattern_text = pattern_text.replace(/\|/," ");
127     pattern_area.value=pattern_text;
128     and_button.checked=false;
129     return;
130   }
131     
132   var match_attempts=0;
133   var start=(new Date).getTime();
134
135   // if we're running with the same pattern
136   var previous_pattern=table['previous_pattern'];
137   var previous_mode=table['previous_mode'];
138   if ( (previous_pattern == pattern_text) && (previous_mode == and_if_true) ) {
139     window.console.log ('no change in pattern');
140     return;
141   }
142
143   // re compile all patterns 
144   var pattern_texts = pattern_text.strip().split(" ");
145   var searches=new Array();
146   var patterns=new Array();
147   for (var i=0; i < pattern_texts.length; i++) {
148     window.console.log ('compiled ' + i + '-th pattern = [' + pattern_texts[i] + ']');
149     // ignore case
150     searches[i]=pattern_texts[i].toLowerCase();
151     patterns[i]=new RegExp(pattern_texts[i],"i");
152   }
153
154   // scan rows, elaborate 'visible'
155   window.console.log ('we have ' + rows.length + ' rows');
156   for (var row_index = 0; row_index < rows.length ; row_index++) {
157     var tr=rows[row_index];
158     var visible=false;
159     
160     /*empty pattern */
161     if (patterns.length == 0) {
162       visible=true;
163     } else if (and_if_true) {
164       /* AND mode: all patterns must match */
165       visible=true;
166       var against=plekit_tr_text (tr);
167       for (var search_index=0; search_index<searches.length; search_index++) {
168         var search=searches[search_index];
169         match_attempts++;
170         if ( against.search(search) < 0) {
171           visible=false;
172           break;          
173         }
174       }
175     } else {
176       /* OR mode: any match is good enough */
177       visible=false;
178       var against = plekit_tr_text(tr);
179       for (var search_index=0; search_index < searches.length; search_index++) {
180         var search=searches[search_index];
181         match_attempts++;
182         if (against.search(search) >= 0) {
183           visible=true;
184           break;
185         }
186       }
187     }
188
189     plekit_table_row_visible(tr,visible);
190     if (visible) matching_entries +=1;
191   }
192   // save for next run
193   table['previous_pattern']=pattern_text;
194   table['previous_mode']=and_if_true;
195   
196   var end=(new Date).getTime();
197   var match_ms=end-start;
198
199   // optimize useless calls to init, by comparing # of matching entries
200   var previous_matching=table['previous_matching'];
201   if (matching_entries == previous_matching) {
202     window.console.log ('same # of matching entries - skipped redisplay');
203     window.console.log ("plekit_table_filter: " + 
204                         match_attempts + " matches - " +
205                         matching_entries + " lines - " 
206                         + "match=" + match_ms + " ms");
207     return;
208   }
209   
210   table['matching']=matching_entries;
211   table['match_attempts']=match_attempts;
212   tablePaginater.init(table_id);
213   var end2=(new Date).getTime();
214   var paginate_ms=end2-end;
215   window.console.log ("plekit_table_filter: " + 
216                       match_attempts + " matches - " +
217                       matching_entries + " lines - " 
218                       + "match=" + match_ms + " ms - "
219                       + "paginate=" + paginate_ms + " ms");
220   
221 }
222
223 function plekit_table_filter_reset (table_id, pattern_id,and_id) {
224   /* reset pattern */
225   document.getElementById(pattern_id).value="";
226   plekit_table_filter (table_id, pattern_id,and_id);
227 }