]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/xul/staff_client/chrome/content/util/list.js
for already fleshed trees
[Evergreen.git] / Open-ILS / xul / staff_client / chrome / content / util / list.js
1 dump('entering util.list.js\n');
2
3 if (typeof main == 'undefined') main = {};
4 util.list = function (id) {
5
6         this.node = document.getElementById(id);
7
8         if (!this.node) throw('Could not find element ' + id);
9         switch(this.node.nodeName) {
10                 case 'listbox' : 
11                 case 'tree' : break;
12                 case 'richlistbox' :
13                         throw(this.node.nodeName + ' not yet supported'); break;
14                 default: throw(this.node.nodeName + ' not supported'); break;
15         }
16
17         JSAN.use('util.error'); this.error = new util.error();
18
19         return this;
20 };
21
22 util.list.prototype = {
23
24         'row_count' : { 'total' : 0, 'fleshed' : 0, 'all_fleshed' : true },
25
26         'init' : function (params) {
27
28                 var obj = this;
29
30                 JSAN.use('util.widgets');
31
32                 if (typeof params.map_row_to_column == 'function') obj.map_row_to_column = params.map_row_to_column;
33                 if (typeof params.retrieve_row == 'function') obj.retrieve_row = params.retrieve_row;
34
35                 obj.prebuilt = false;
36                 if (typeof params.prebuilt != 'undefined') obj.prebuilt = params.prebuilt;
37
38                 if (typeof params.columns == 'undefined') throw('util.list.init: No columns');
39                 obj.columns = params.columns;
40
41                 switch(obj.node.nodeName) {
42                         case 'tree' : obj._init_tree(params); break;
43                         case 'listbox' : obj._init_listbox(params); break;
44                         default: throw('NYI: Need ._init() for ' + obj.node.nodeName); break;
45                 }
46
47                 obj.row_count.watch(
48                         'all_fleshed',
49                         function(a,b,c) {
50                                 if (c) {
51                                         if (typeof obj.on_all_fleshed == 'function') {
52                                                 obj.on_all_fleshed(a,b,c);
53                                         }
54                                 }
55                         }
56                 );
57         },
58
59         '_init_tree' : function (params) {
60                 var obj = this;
61                 if (this.prebuilt) {
62                 
63                         this.treechildren = this.node.lastChild;        
64                 
65                 } else {
66                         var treecols = document.createElement('treecols');
67                         this.node.appendChild(treecols);
68
69                         for (var i = 0; i < this.columns.length; i++) {
70                                 var treecol = document.createElement('treecol');
71                                 for (var j in this.columns[i]) {
72                                         treecol.setAttribute(j,this.columns[i][j]);
73                                 }
74                                 treecols.appendChild(treecol);
75                                 var splitter = document.createElement('splitter');
76                                 splitter.setAttribute('class','tree-splitter');
77                                 treecols.appendChild(splitter);
78                         }
79
80                         var treechildren = document.createElement('treechildren');
81                         this.node.appendChild(treechildren);
82                         this.treechildren = treechildren;
83                 }
84                 if (typeof params.on_select == 'function') {
85                         this.node.addEventListener(
86                                 'select',
87                                 params.on_select,
88                                 false
89                         );
90                 }
91                 if (typeof params.on_click == 'function') {
92                         this.node.addEventListener(
93                                 'click',
94                                 params.on_click,
95                                 false
96                         );
97                 }
98                 /*
99                 this.node.addEventListener(
100                         'mousemove',
101                         function(ev) { obj.detect_visible(); },
102                         false
103                 );
104                 */
105                 this.node.addEventListener(
106                         'keypress',
107                         function(ev) { obj.auto_retrieve(); },
108                         false
109                 );
110                 this.node.addEventListener(
111                         'click',
112                         function(ev) { obj.auto_retrieve(); },
113                         false
114                 );
115                 window.addEventListener(
116                         'resize',
117                         function(ev) { obj.auto_retrieve(); },
118                         false
119                 );
120                 /* FIXME -- find events on scrollbar to trigger this */
121                 //obj.detect_visible_polling(); 
122                 /*
123                 var scrollbar = document.getAnonymousNodes( document.getAnonymousNodes(this.node)[1] )[1];
124                 var slider = document.getAnonymousNodes( scrollbar )[2];
125                 alert('scrollbar = ' + scrollbar.nodeName + ' grippy = ' + slider.nodeName);
126                 scrollbar.addEventListener('click',function(){alert('sb click');},false);
127                 scrollbar.addEventListener('command',function(){alert('sb command');},false);
128                 scrollbar.addEventListener('scroll',function(){alert('sb scroll');},false);
129                 slider.addEventListener('click',function(){alert('slider click');},false);
130                 slider.addEventListener('command',function(){alert('slider command');},false);
131                 slider.addEventListener('scroll',function(){alert('slider scroll');},false);
132                 */
133                 this.node.addEventListener('scroll',function(){ obj.auto_retrieve(); },false);
134         },
135
136         '_init_listbox' : function (params) {
137                 if (this.prebuilt) {
138                 } else {
139                         var listhead = document.createElement('listhead');
140                         this.node.appendChild(listhead);
141
142                         var listcols = document.createElement('listcols');
143                         this.node.appendChild(listcols);
144
145                         for (var i = 0; i < this.columns.length; i++) {
146                                 var listheader = document.createElement('listheader');
147                                 listhead.appendChild(listheader);
148                                 var listcol = document.createElement('listcol');
149                                 listcols.appendChild(listcol);
150                                 for (var j in this.columns[i]) {
151                                         listheader.setAttribute(j,this.columns[i][j]);
152                                         listcol.setAttribute(j,this.columns[i][j]);
153                                 };
154                         }
155                 }
156         },
157
158         'clear' : function (params) {
159                 switch (this.node.nodeName) {
160                         case 'tree' : this._clear_tree(params); break;
161                         case 'listbox' : this._clear_listbox(params); break;
162                         default: throw('NYI: Need .clear() for ' + this.node.nodeName); break;
163                 }
164                 this.error.sdump('D_LIST','Clearing list ' + this.node.getAttribute('id') + '\n');
165                 this.row_count.total = 0;
166                 this.row_count.fleshed = 0;
167                 this.row_count.all_fleshed = true;
168         },
169
170         '_clear_tree' : function(params) {
171                 var obj = this;
172                 if (obj.error.sdump_levels.D_LIST_DUMP_ON_CLEAR) {
173                         obj.error.sdump('D_LIST_DUMP_ON_CLEAR',obj.dump());
174                 }
175                 if (obj.error.sdump_levels.D_LIST_DUMP_WITH_KEYS_ON_CLEAR) {
176                         obj.error.sdump('D_LIST_DUMP_WITH_KEYS_ON_CLEAR',obj.dump_with_keys());
177                 }
178                 while (obj.treechildren.lastChild) obj.treechildren.removeChild( obj.treechildren.lastChild );
179         },
180
181         '_clear_listbox' : function(params) {
182                 var items = [];
183                 var nl = this.node.getElementsByTagName('listitem');
184                 for (var i = 0; i < nl.length; i++) {
185                         items.push( nl[i] );
186                 }
187                 for (var i = 0; i < items.length; i++) {
188                         this.node.removeChild(items[i]);
189                 }
190         },
191
192         'append' : function (params) {
193                 var rnode;
194                 switch (this.node.nodeName) {
195                         case 'tree' : rnode = this._append_to_tree(params); break;
196                         case 'listbox' : rnode = this._append_to_listbox(params); break;
197                         default: throw('NYI: Need .append() for ' + this.node.nodeName); break;
198                 }
199                 if (rnode && params.attributes) {
200                         for (var i in params.attributes) {
201                                 rnode.setAttribute(i,params.attributes[i]);
202                         }
203                 }
204                 this.row_count.total++;
205                 if (this.row_count.fleshed == this.row_count.total) {
206                         this.row_count.all_fleshed = true;
207                 } else {
208                         this.row_count.all_fleshed = false;
209                 }
210                 return rnode;
211         },
212
213         '_append_to_tree' : function (params) {
214
215                 var obj = this;
216
217                 if (typeof params.row == 'undefined') throw('util.list.append: Object must contain a row');
218
219                 var s = ('util.list.append: params = ' + (params) + '\n');
220
221                 var treechildren_node = this.treechildren;
222
223                 if (params.node && params.node.nodeName == 'treeitem') {
224                         params.node.setAttribute('container','true'); /* params.node.setAttribute('open','true'); */
225                         if (params.node.lastChild.nodeName == 'treechildren') {
226                                 treechildren_node = params.node.lastChild;
227                         } else {
228                                 treechildren_node = document.createElement('treechildren');
229                                 params.node.appendChild(treechildren_node);
230                         }
231                 }
232
233                 var treeitem = document.createElement('treeitem');
234                 treeitem.setAttribute('retrieve_id',params.retrieve_id);
235                 treechildren_node.appendChild( treeitem );
236                 var treerow = document.createElement('treerow');
237                 treeitem.appendChild( treerow );
238                 treerow.setAttribute('retrieve_id',params.retrieve_id);
239
240                 s += ('tree = ' + this.node + '  treechildren = ' + treechildren_node + '\n');
241                 s += ('treeitem = ' + treeitem + '  treerow = ' + treerow + '\n');
242
243                 if (typeof params.retrieve_row == 'function' || typeof this.retrieve_row == 'function') {
244
245                         obj.put_retrieving_label(treerow);
246                         treerow.addEventListener(
247                                 'flesh',
248                                 function() {
249                                         //dump('fleshing = ' + params.retrieve_id + '\n');
250
251                                         params.row_node = treeitem;
252                                         params.on_retrieve = function(p) {
253                                                 try {
254                                                         p.row = params.row;
255                                                         obj._map_row_to_treecell(p,treerow);
256                                                         treerow.setAttribute('fleshed','true');
257                                                         obj.row_count.fleshed++;
258                                                         if (obj.row_count.fleshed == obj.row_count.total) {
259                                                                 obj.row_count.all_fleshed = true;
260                                                         } else {
261                                                                 obj.row_count.all_fleshed = false;
262                                                         }
263                                                 } catch(E) {
264                                                         alert('fixme2: ' + E);
265                                                 }
266                                         }
267
268                                         if (typeof params.retrieve_row == 'function') {
269
270                                                 params.retrieve_row( params );
271
272                                         } else {
273
274                                                 if (typeof obj.retrieve_row == 'function') {
275
276                                                         obj.retrieve_row( params );
277
278                                                 }
279                                         }
280
281                                         treerow.setAttribute('retrieved','true');
282                                 },
283                                 false
284                         );
285                         /*
286                         setTimeout(
287                                 function() {
288                                         util.widgets.dispatch('flesh',treerow);
289                                 }, 0
290                         );
291                         */
292                 } else {
293                         obj.put_retrieving_label(treerow);
294                         treerow.addEventListener(
295                                 'flesh',
296                                 function() {
297                                         //dump('fleshing anon\n');
298                                         obj._map_row_to_treecell(params,treerow);
299                                         treerow.setAttribute('retrieved','true');
300                                         treerow.setAttribute('fleshed','true');
301                                         obj.row_count.fleshed++;
302                                         if (obj.row_count.fleshed == obj.row_count.total) {
303                                                 obj.row_count.all_fleshed = true;
304                                         } else {
305                                                 obj.row_count.all_fleshed = false;
306                                         }
307                                 },
308                                 false
309                         );
310                         /*
311                         setTimeout(
312                                 function() {
313                                         util.widgets.dispatch('flesh',treerow);
314                                 }, 0
315                         );
316                         */
317                 }
318                 this.error.sdump('D_LIST',s);
319
320                 setTimeout( function() { obj.auto_retrieve(); }, 0 );
321
322                 return treeitem;
323         },
324
325         'put_retrieving_label' : function(treerow) {
326                 var obj = this;
327                 try {
328                         /*
329                         var cols_idx = 0;
330                         dump('put_retrieving_label.  columns = ' + js2JSON(obj.columns) + '\n');
331                         while( obj.columns[cols_idx] && obj.columns[cols_idx].hidden && obj.columns[cols_idx].hidden == 'true') {
332                                 dump('\t' + cols_idx);
333                                 var treecell = document.createElement('treecell');
334                                 treerow.appendChild(treecell);
335                                 cols_idx++;
336                         }
337                         */
338                         for (var i = 0; i < obj.columns.length; i++) {
339                         var treecell = document.createElement('treecell'); treecell.setAttribute('label','Retrieving...');
340                         treerow.appendChild(treecell);
341                         }
342                         /*
343                         dump('\t' + cols_idx + '\n');
344                         */
345                 } catch(E) {
346                         alert(E);
347                 }
348         },
349
350         'detect_visible' : function() {
351                 try {
352                         var obj = this;
353                         //dump('detect_visible  obj.node = ' + obj.node + '\n');
354                         /* FIXME - this is a hack.. if the implementation of tree changes, this could break */
355                         var scrollbar = document.getAnonymousNodes( document.getAnonymousNodes(obj.node)[1] )[1];
356                         var curpos = scrollbar.getAttribute('curpos');
357                         var maxpos = scrollbar.getAttribute('maxpos');
358                         //alert('curpos = ' + curpos + ' maxpos = ' + maxpos + ' obj.curpos = ' + obj.curpos + ' obj.maxpos = ' + obj.maxpos + '\n');
359                         if ((curpos != obj.curpos) || (maxpos != obj.maxpos)) {
360                                 if ( obj.auto_retrieve() > 0 ) {
361                                         obj.curpos = curpos; obj.maxpos = maxpos;
362                                 }
363                         }
364                 } catch(E) { alert(E); }
365         },
366
367         'detect_visible_polling' : function() {
368                 try {
369                         //alert('detect_visible_polling');
370                         var obj = this;
371                         obj.detect_visible();
372                         setTimeout(function() { try { obj.detect_visible_polling(); } catch(E) { alert(E); } },2000);
373                 } catch(E) {
374                         alert(E);
375                 }
376         },
377
378
379         'auto_retrieve' : function(params) {
380                 var obj = this;
381                 switch (this.node.nodeName) {
382                         case 'tree' : obj._auto_retrieve_tree(params); break;
383                         default: throw('NYI: Need .auto_retrieve() for ' + obj.node.nodeName); break;
384                 }
385         },
386
387         '_auto_retrieve_tree' : function (params) {
388                 var obj = this;
389                 if (!obj.auto_retrieve_in_progress) {
390                         obj.auto_retrieve_in_progress = true;
391                         setTimeout(
392                                 function() {
393                                         try {
394                                                         //alert('auto_retrieve\n');
395                                                         var count = 0;
396                                                         var startpos = obj.node.treeBoxObject.getFirstVisibleRow();
397                                                         var endpos = obj.node.treeBoxObject.getLastVisibleRow();
398                                                         if (startpos > endpos) endpos = obj.node.treeBoxObject.getPageLength();
399                                                         //dump('startpos = ' + startpos + ' endpos = ' + endpos + '\n');
400                                                         for (var i = startpos; i < endpos + 2; i++) {
401                                                                 try {
402                                                                         //dump('trying index ' + i + '\n');
403                                                                         var item = obj.node.contentView.getItemAtIndex(i).firstChild;
404                                                                         if (item && item.getAttribute('retrieved') != 'true' ) {
405                                                                                 //dump('\tgot an unfleshed item = ' + item + ' = ' + item.nodeName + '\n');
406                                                                                 util.widgets.dispatch('flesh',item); count++;
407                                                                         }
408                                                                 } catch(E) {
409                                                                         //dump(i + ' : ' + E + '\n');
410                                                                 }
411                                                         }
412                                                         obj.auto_retrieve_in_progress = false;
413                                                         return count;
414                                         } catch(E) { alert(E); }
415                                 }, 1
416                         );
417                 }
418         },
419
420         'full_retrieve' : function(params) {
421                 var obj = this;
422                 switch (this.node.nodeName) {
423                         case 'tree' : obj._full_retrieve_tree(params); break;
424                         default: throw('NYI: Need .full_retrieve() for ' + obj.node.nodeName); break;
425                 }
426         },
427
428         '_full_retrieve_tree' : function(params) {
429                 var obj = this;
430                 if (obj.all_fleshed) {
431                         obj.all_fleshed = false; obj.all_fleshed = true;
432                 } else {
433                         var nodes = obj.treechildren.childNodes;
434                         for (var i = 0; i < nodes.length; i++) util.widgets.dispatch('flesh',nodes[i]);
435                 }
436         },
437
438         '_append_to_listbox' : function (params) {
439
440                 var obj = this;
441
442                 if (typeof params.row == 'undefined') throw('util.list.append: Object must contain a row');
443
444                 var s = ('util.list.append: params = ' + (params) + '\n');
445
446                 var listitem = document.createElement('listitem');
447
448                 s += ('listbox = ' + this.node + '  listitem = ' + listitem + '\n');
449
450                 if (typeof params.retrieve_row == 'function' || typeof this.retrieve_row == 'function') {
451
452                         setTimeout(
453                                 function() {
454                                         listitem.setAttribute('retrieve_id',params.retrieve_id);
455                                         //FIXME//Make async and fire when row is visible in list
456                                         var row;
457
458                                         params.row_node = listitem;
459                                         params.on_retrieve = function(row) {
460                                                 params.row = row;
461                                                 obj._map_row_to_listcell(params,listitem);
462                                                 obj.node.appendChild( listitem );
463                                         }
464
465                                         if (typeof params.retrieve_row == 'function') {
466
467                                                 row = params.retrieve_row( params );
468
469                                         } else {
470
471                                                 if (typeof obj.retrieve_row == 'function') {
472
473                                                         row = obj.retrieve_row( params );
474
475                                                 }
476                                         }
477                                 }, 0
478                         );
479                 } else {
480                         this._map_row_to_listcell(params,listitem);
481                         this.node.appendChild( listitem );
482                 }
483
484                 this.error.sdump('D_LIST',s);
485                 return listitem;
486
487         },
488
489         '_map_row_to_treecell' : function(params,treerow) {
490                 var s = '';
491                 util.widgets.remove_children(treerow);
492                 for (var i = 0; i < this.columns.length; i++) {
493                         var treecell = document.createElement('treecell');
494                         var label = '';
495                         if (params.skip_columns && (params.skip_columns.indexOf(i) != -1)) {
496                                 treecell.setAttribute('label',label);
497                                 treerow.appendChild( treecell );
498                                 s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
499                                 continue;
500                         }
501                         if (params.skip_all_columns_except && (params.skip_all_columns_except.indexOf(i) == -1)) {
502                                 treecell.setAttribute('label',label);
503                                 treerow.appendChild( treecell );
504                                 s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
505                                 continue;
506                         }
507                         if (typeof params.map_row_to_column == 'function')  {
508
509                                 label = params.map_row_to_column(params.row,this.columns[i]);
510
511                         } else {
512
513                                 if (typeof this.map_row_to_column == 'function') {
514
515                                         label = this.map_row_to_column(params.row,this.columns[i]);
516
517                                 } else {
518
519                                         throw('No map_row_to_column function');
520
521                                 }
522                         }
523                         treecell.setAttribute('label',label);
524                         treerow.appendChild( treecell );
525                         s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
526                 }
527                 this.error.sdump('D_LIST',s);
528         },
529
530         '_map_row_to_listcell' : function(params,listitem) {
531                 var s = '';
532                 for (var i = 0; i < this.columns.length; i++) {
533                         var value = '';
534                         if (typeof params.map_row_to_column == 'function')  {
535
536                                 value = params.map_row_to_column(params.row,this.columns[i]);
537
538                         } else {
539
540                                 if (typeof this.map_row_to_column == 'function') {
541
542                                         value = this.map_row_to_column(params.row,this.columns[i]);
543                                 }
544                         }
545                         if (typeof value == 'string' || typeof value == 'number') {
546                                 var listcell = document.createElement('listcell');
547                                 listcell.setAttribute('label',value);
548                                 listitem.appendChild(listcell);
549                                 s += ('listcell = ' + listcell + ' with label = ' + value + '\n');
550                         } else {
551                                 listitem.appendChild(value);
552                                 s += ('listcell = ' + value + ' is really a ' + value.nodeName + '\n');
553                         }
554                 }
555                 this.error.sdump('D_LIST',s);
556         },
557
558         'retrieve_selection' : function(params) {
559                 switch(this.node.nodeName) {
560                         case 'tree' : return this._retrieve_selection_from_tree(params); break;
561                         default: throw('NYI: Need ._retrieve_selection_from_() for ' + this.node.nodeName); break;
562                 }
563         },
564
565         '_retrieve_selection_from_tree' : function(params) {
566                 var list = [];
567                 var start = new Object();
568                 var end = new Object();
569                 var numRanges = this.node.view.selection.getRangeCount();
570                 for (var t=0; t<numRanges; t++){
571                         this.node.view.selection.getRangeAt(t,start,end);
572                         for (var v=start.value; v<=end.value; v++){
573                                 var i = this.node.contentView.getItemAtIndex(v);
574                                 list.push( i );
575                         }
576                 }
577                 return list;
578         },
579
580         'dump' : function(params) {
581                 switch(this.node.nodeName) {
582                         case 'tree' : return this._dump_tree(params); break;
583                         default: throw('NYI: Need .dump() for ' + this.node.nodeName); break;
584                 }
585         },
586
587         '_dump_tree' : function(params) {
588                 var dump = [];
589                 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
590                         var row = [];
591                         var treeitem = this.treechildren.childNodes[i];
592                         var treerow = treeitem.firstChild;
593                         for (var j = 0; j < treerow.childNodes.length; j++) {
594                                 row.push( treerow.childNodes[j].getAttribute('label') );
595                         }
596                         dump.push( row );
597                 }
598                 return dump;
599         },
600
601         'dump_with_keys' : function(params) {
602                 switch(this.node.nodeName) {
603                         case 'tree' : return this._dump_tree_with_keys(params); break;
604                         default: throw('NYI: Need .dump_with_keys() for ' + this.node.nodeName); break;
605                 }
606
607         },
608
609         '_dump_tree_with_keys' : function(params) {
610                 var obj = this;
611                 var dump = [];
612                 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
613                         var row = {};
614                         var treeitem = this.treechildren.childNodes[i];
615                         var treerow = treeitem.firstChild;
616                         for (var j = 0; j < treerow.childNodes.length; j++) {
617                                 row[ obj.columns[j].id ] = treerow.childNodes[j].getAttribute('label');
618                         }
619                         dump.push( row );
620                 }
621                 return dump;
622         },
623
624         'dump_retrieve_ids' : function(params) {
625                 switch(this.node.nodeName) {
626                         case 'tree' : return this._dump_retrieve_ids_tree(params); break;
627                         default: throw('NYI: Need .dump_retrieve_ids() for ' + this.node.nodeName); break;
628                 }
629         },
630
631         '_dump_retrieve_ids_tree' : function(params) {
632                 var dump = [];
633                 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
634                         var treeitem = this.treechildren.childNodes[i];
635                         dump.push( treeitem.getAttribute('retrieve_id') );
636                 }
637                 return dump;
638         },
639
640 }
641 dump('exiting util.list.js\n');