]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/xul/staff_client/chrome/content/util/list.js
change default list behavior back to append to bottom, and change checkout specifical...
[working/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         this.row_count = { 'total' : 0, 'fleshed' : 0 };
9
10         if (!this.node) throw('Could not find element ' + id);
11         switch(this.node.nodeName) {
12                 case 'listbox' : 
13                 case 'tree' : break;
14                 case 'richlistbox' :
15                         throw(this.node.nodeName + ' not yet supported'); break;
16                 default: throw(this.node.nodeName + ' not supported'); break;
17         }
18
19         JSAN.use('util.error'); this.error = new util.error();
20
21         return this;
22 };
23
24 util.list.prototype = {
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.map_row_to_columns == 'function') obj.map_row_to_columns = params.map_row_to_columns;
34                 if (typeof params.retrieve_row == 'function') obj.retrieve_row = params.retrieve_row;
35
36                 obj.prebuilt = false;
37                 if (typeof params.prebuilt != 'undefined') obj.prebuilt = params.prebuilt;
38
39                 if (typeof params.columns == 'undefined') throw('util.list.init: No columns');
40                 obj.columns = params.columns;
41
42                 switch(obj.node.nodeName) {
43                         case 'tree' : obj._init_tree(params); break;
44                         case 'listbox' : obj._init_listbox(params); break;
45                         default: throw('NYI: Need ._init() for ' + obj.node.nodeName); break;
46                 }
47         },
48
49         'register_all_fleshed_callback' : function(f) {
50                 this.on_all_fleshed = f;
51         },
52
53         '_init_tree' : function (params) {
54                 var obj = this;
55                 if (this.prebuilt) {
56                 
57                         this.treechildren = this.node.lastChild;        
58                 
59                 } else {
60                         var treecols = document.createElement('treecols');
61                         this.node.appendChild(treecols);
62                         this.treecols = treecols;
63
64                         for (var i = 0; i < this.columns.length; i++) {
65                                 var treecol = document.createElement('treecol');
66                                 for (var j in this.columns[i]) {
67                                         treecol.setAttribute(j,this.columns[i][j]);
68                                 }
69                                 treecols.appendChild(treecol);
70                                 treecol.addEventListener(
71                                         'click', 
72                                         function(ev) {
73                                                 function do_it() {
74                                                         var sortDir = ev.target.getAttribute('sortDir') || 'desc';
75                                                         if (sortDir == 'desc') sortDir = 'asc'; else sortDir = 'desc';
76                                                         ev.target.setAttribute('sortDir',sortDir);
77                                                         obj._sort_tree(ev.target,sortDir);
78                                                 }
79
80                                                 if (obj.row_count.total != obj.row_count.fleshed && (obj.row_count.total - obj.row_count.fleshed) > 50) {
81                                                         var r = window.confirm('WARNING: Only ' + obj.row_count.fleshed + ' out of ' + obj.row_count.total + ' rows in this list have been retrieved for immediate viewing.  Sorting this list requires that all these rows be retrieved, and this may take some time and lag the staff client.  Would you like to proceed?');
82
83                                                         if (r) {
84                                                                 setTimeout( do_it, 0 );
85                                                         }
86                                                 } else {
87                                                                 setTimeout( do_it, 0 );
88                                                 }
89                                         },
90                                         false
91                                 );
92                                 var splitter = document.createElement('splitter');
93                                 splitter.setAttribute('class','tree-splitter');
94                                 treecols.appendChild(splitter);
95                         }
96
97                         var treechildren = document.createElement('treechildren');
98                         this.node.appendChild(treechildren);
99                         this.treechildren = treechildren;
100                 }
101                 if (typeof params.on_select == 'function') {
102                         this.node.addEventListener(
103                                 'select',
104                                 params.on_select,
105                                 false
106                         );
107                 }
108                 if (typeof params.on_click == 'function') {
109                         this.node.addEventListener(
110                                 'click',
111                                 params.on_click,
112                                 false
113                         );
114                 }
115                 /*
116                 this.node.addEventListener(
117                         'mousemove',
118                         function(ev) { obj.detect_visible(); },
119                         false
120                 );
121                 */
122                 this.node.addEventListener(
123                         'keypress',
124                         function(ev) { obj.auto_retrieve(); },
125                         false
126                 );
127                 this.node.addEventListener(
128                         'click',
129                         function(ev) { obj.auto_retrieve(); },
130                         false
131                 );
132                 window.addEventListener(
133                         'resize',
134                         function(ev) { obj.auto_retrieve(); },
135                         false
136                 );
137                 /* FIXME -- find events on scrollbar to trigger this */
138                 obj.detect_visible_polling();   
139                 /*
140                 var scrollbar = document.getAnonymousNodes( document.getAnonymousNodes(this.node)[1] )[1];
141                 var slider = document.getAnonymousNodes( scrollbar )[2];
142                 alert('scrollbar = ' + scrollbar.nodeName + ' grippy = ' + slider.nodeName);
143                 scrollbar.addEventListener('click',function(){alert('sb click');},false);
144                 scrollbar.addEventListener('command',function(){alert('sb command');},false);
145                 scrollbar.addEventListener('scroll',function(){alert('sb scroll');},false);
146                 slider.addEventListener('click',function(){alert('slider click');},false);
147                 slider.addEventListener('command',function(){alert('slider command');},false);
148                 slider.addEventListener('scroll',function(){alert('slider scroll');},false);
149                 */
150                 this.node.addEventListener('scroll',function(){ obj.auto_retrieve(); },false);
151
152                 this.restores_columns(params);
153         },
154
155         '_init_listbox' : function (params) {
156                 if (this.prebuilt) {
157                 } else {
158                         var listhead = document.createElement('listhead');
159                         this.node.appendChild(listhead);
160
161                         var listcols = document.createElement('listcols');
162                         this.node.appendChild(listcols);
163
164                         for (var i = 0; i < this.columns.length; i++) {
165                                 var listheader = document.createElement('listheader');
166                                 listhead.appendChild(listheader);
167                                 var listcol = document.createElement('listcol');
168                                 listcols.appendChild(listcol);
169                                 for (var j in this.columns[i]) {
170                                         listheader.setAttribute(j,this.columns[i][j]);
171                                         listcol.setAttribute(j,this.columns[i][j]);
172                                 };
173                         }
174                 }
175         },
176
177         'save_columns' : function (params) {
178                 var obj = this;
179                 switch (this.node.nodeName) {
180                         case 'tree' : this._save_columns_tree(params); break;
181                         default: throw('NYI: Need .save_columns() for ' + this.node.nodeName); break;
182                 }
183         },
184
185         '_save_columns_tree' : function (params) {
186                 var obj = this;
187                 try {
188                         var id = obj.node.getAttribute('id'); if (!id) {
189                                 alert("FIXME: The columns for this list cannot be saved because the list has no id.");
190                                 return;
191                         }
192                         var my_cols = {};
193                         var nl = obj.node.getElementsByTagName('treecol');
194                         for (var i = 0; i < nl.length; i++) {
195                                 var col = nl[i];
196                                 var col_id = col.getAttribute('id');
197                                 if (!col_id) {
198                                         alert('FIXME: A column in this list does not have an id and cannot be saved');
199                                         continue;
200                                 }
201                                 var col_hidden = col.getAttribute('hidden'); 
202                                 var col_width = col.getAttribute('width'); 
203                                 var col_ordinal = col.getAttribute('ordinal'); 
204                                 my_cols[ col_id ] = { 'hidden' : col_hidden, 'width' : col_width, 'ordinal' : col_ordinal };
205                         }
206                         netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
207                         JSAN.use('util.file'); var file = new util.file('tree_columns_for_'+window.escape(id));
208                         file.set_object(my_cols);
209                         file.close();
210                         alert('Columns saved.');
211                 } catch(E) {
212                         obj.error.standard_unexpected_error_alert('_save_columns_tree',E);
213                 }
214         },
215
216         'restores_columns' : function (params) {
217                 var obj = this;
218                 switch (this.node.nodeName) {
219                         case 'tree' : this._restores_columns_tree(params); break;
220                         default: throw('NYI: Need .restores_columns() for ' + this.node.nodeName); break;
221                 }
222         },
223
224         '_restores_columns_tree' : function (params) {
225                 var obj = this;
226                 try {
227                         var id = obj.node.getAttribute('id'); if (!id) {
228                                 alert("FIXME: The columns for this list cannot be restored because the list has no id.");
229                                 return;
230                         }
231
232                         netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
233                         JSAN.use('util.file'); var file = new util.file('tree_columns_for_'+window.escape(id));
234                         if (file._file.exists()) {
235                                 var my_cols = file.get_object(); file.close();
236                                 var nl = obj.node.getElementsByTagName('treecol');
237                                 for (var i = 0; i < nl.length; i++) {
238                                         var col = nl[i];
239                                         var col_id = col.getAttribute('id');
240                                         if (!col_id) {
241                                                 alert('FIXME: A column in this list does not have an id and cannot be saved');
242                                                 continue;
243                                         }
244                                         if (typeof my_cols[col_id] != 'undefined') {
245                                                 col.setAttribute('hidden',my_cols[col_id].hidden); 
246                                                 col.setAttribute('width',my_cols[col_id].width); 
247                                                 col.setAttribute('ordinal',my_cols[col_id].ordinal); 
248                                         } else {
249                                                 obj.error.sdump('D_ERROR','WARNING: Column ' + col_id + ' did not have a saved state.');
250                                         }
251                                 }
252                         }
253                 } catch(E) {
254                         obj.error.standard_unexpected_error_alert('_restore_columns_tree',E);
255                 }
256         },
257
258         'clear' : function (params) {
259                 var obj = this;
260                 switch (this.node.nodeName) {
261                         case 'tree' : this._clear_tree(params); break;
262                         case 'listbox' : this._clear_listbox(params); break;
263                         default: throw('NYI: Need .clear() for ' + this.node.nodeName); break;
264                 }
265                 this.error.sdump('D_LIST','Clearing list ' + this.node.getAttribute('id') + '\n');
266                 this.row_count.total = 0;
267                 this.row_count.fleshed = 0;
268                 if (typeof obj.on_all_fleshed == 'function') {
269                         setTimeout( function() { obj.on_all_fleshed(); }, 0 );
270                 }
271         },
272
273         '_clear_tree' : function(params) {
274                 var obj = this;
275                 if (obj.error.sdump_levels.D_LIST_DUMP_ON_CLEAR) {
276                         obj.error.sdump('D_LIST_DUMP_ON_CLEAR',obj.dump());
277                 }
278                 if (obj.error.sdump_levels.D_LIST_DUMP_WITH_KEYS_ON_CLEAR) {
279                         obj.error.sdump('D_LIST_DUMP_WITH_KEYS_ON_CLEAR',obj.dump_with_keys());
280                 }
281                 while (obj.treechildren.lastChild) obj.treechildren.removeChild( obj.treechildren.lastChild );
282         },
283
284         '_clear_listbox' : function(params) {
285                 var obj = this;
286                 var items = [];
287                 var nl = this.node.getElementsByTagName('listitem');
288                 for (var i = 0; i < nl.length; i++) {
289                         items.push( nl[i] );
290                 }
291                 for (var i = 0; i < items.length; i++) {
292                         this.node.removeChild(items[i]);
293                 }
294         },
295
296         'append' : function (params) {
297                 var rnode;
298                 var obj = this;
299                 switch (this.node.nodeName) {
300                         case 'tree' : rnode = this._append_to_tree(params); break;
301                         case 'listbox' : rnode = this._append_to_listbox(params); break;
302                         default: throw('NYI: Need .append() for ' + this.node.nodeName); break;
303                 }
304                 if (rnode && params.attributes) {
305                         for (var i in params.attributes) {
306                                 rnode.setAttribute(i,params.attributes[i]);
307                         }
308                 }
309                 this.row_count.total++;
310                 if (this.row_count.fleshed == this.row_count.total) {
311                         if (typeof this.on_all_fleshed == 'function') {
312                                 setTimeout( function() { obj.on_all_fleshed(); }, 0 );
313                         }
314                 }
315                 return rnode;
316         },
317
318         '_append_to_tree' : function (params) {
319
320                 var obj = this;
321
322                 if (typeof params.row == 'undefined') throw('util.list.append: Object must contain a row');
323
324                 var s = ('util.list.append: params = ' + (params) + '\n');
325
326                 var treechildren_node = this.treechildren;
327
328                 if (params.node && params.node.nodeName == 'treeitem') {
329                         params.node.setAttribute('container','true'); /* params.node.setAttribute('open','true'); */
330                         if (params.node.lastChild.nodeName == 'treechildren') {
331                                 treechildren_node = params.node.lastChild;
332                         } else {
333                                 treechildren_node = document.createElement('treechildren');
334                                 params.node.appendChild(treechildren_node);
335                         }
336                 }
337
338                 var treeitem = document.createElement('treeitem');
339                 treeitem.setAttribute('retrieve_id',params.retrieve_id);
340                 //if (typeof params.to_bottom != 'undefined') {
341                 if (typeof params.to_top == 'undefined') {
342                         treechildren_node.appendChild( treeitem );
343                 } else {
344                         if (treechildren_node.firstChild) {
345                                 treechildren_node.insertBefore( treeitem, treechildren_node.firstChild );
346                         } else {
347                                 treechildren_node.appendChild( treeitem );
348                         }
349                 }
350                 var treerow = document.createElement('treerow');
351                 treeitem.appendChild( treerow );
352                 treerow.setAttribute('retrieve_id',params.retrieve_id);
353
354                 s += ('tree = ' + this.node + '  treechildren = ' + treechildren_node + '\n');
355                 s += ('treeitem = ' + treeitem + '  treerow = ' + treerow + '\n');
356
357                 if (typeof params.retrieve_row == 'function' || typeof this.retrieve_row == 'function') {
358
359                         obj.put_retrieving_label(treerow);
360                         treerow.addEventListener(
361                                 'flesh',
362                                 function() {
363
364                                         if (treerow.getAttribute('retrieved') == 'true') return; /* already running */
365
366                                         treerow.setAttribute('retrieved','true');
367
368                                         //dump('fleshing = ' + params.retrieve_id + '\n');
369
370                                         function inc_fleshed() {
371                                                 if (treerow.getAttribute('fleshed') == 'true') return; /* already fleshed */
372                                                 treerow.setAttribute('fleshed','true');
373                                                 obj.row_count.fleshed++;
374                                                 if (obj.row_count.fleshed == obj.row_count.total) {
375                                                         if (typeof obj.on_all_fleshed == 'function') {
376                                                                 setTimeout( function() { obj.on_all_fleshed(); }, 0 );
377                                                         }
378                                                 }
379                                         }
380
381                                         params.row_node = treeitem;
382                                         params.on_retrieve = function(p) {
383                                                 try {
384                                                         p.row = params.row;
385                                                         obj._map_row_to_treecell(p,treerow);
386                                                         inc_fleshed();
387                                                 } catch(E) {
388                                                         alert('fixme2: ' + E);
389                                                 }
390                                         }
391
392                                         if (typeof params.retrieve_row == 'function') {
393
394                                                 params.retrieve_row( params );
395
396                                         } else if (typeof obj.retrieve_row == 'function') {
397
398                                                         obj.retrieve_row( params );
399
400                                         } else {
401                                         
402                                                         inc_fleshed();
403                                         }
404                                 },
405                                 false
406                         );
407                         /*
408                         setTimeout(
409                                 function() {
410                                         util.widgets.dispatch('flesh',treerow);
411                                 }, 0
412                         );
413                         */
414                 } else {
415                         obj.put_retrieving_label(treerow);
416                         treerow.addEventListener(
417                                 'flesh',
418                                 function() {
419                                         //dump('fleshing anon\n');
420                                         if (treerow.getAttribute('fleshed') == 'true') return; /* already fleshed */
421                                         obj._map_row_to_treecell(params,treerow);
422                                         treerow.setAttribute('retrieved','true');
423                                         treerow.setAttribute('fleshed','true');
424                                         obj.row_count.fleshed++;
425                                         if (obj.row_count.fleshed == obj.row_count.total) {
426                                                 if (typeof obj.on_all_fleshed == 'function') {
427                                                         setTimeout( function() { obj.on_all_fleshed(); }, 0 );
428                                                 }
429                                         }
430                                 },
431                                 false
432                         );
433                         /*
434                         setTimeout(
435                                 function() {
436                                         util.widgets.dispatch('flesh',treerow);
437                                 }, 0
438                         );
439                         */
440                 }
441                 this.error.sdump('D_LIST',s);
442
443                         try {
444
445                                 if (obj.trim_list && obj.row_count.total >= obj.trim_list) {
446                                         // Remove oldest row
447                                         //if (typeof params.to_bottom != 'undefined') {
448                                         if (typeof params.to_top == 'undefined') {
449                                                 treechildren_node.removeChild( treechildren_node.firstChild );
450                                         } else {
451                                                 treechildren_node.removeChild( treechildren_node.lastChild );
452                                         }
453                                 }
454                         } catch(E) {
455                         }
456
457                 setTimeout( function() { obj.auto_retrieve(); }, 0 );
458
459                 return treeitem;
460         },
461
462         'put_retrieving_label' : function(treerow) {
463                 var obj = this;
464                 try {
465                         /*
466                         var cols_idx = 0;
467                         dump('put_retrieving_label.  columns = ' + js2JSON(obj.columns) + '\n');
468                         while( obj.columns[cols_idx] && obj.columns[cols_idx].hidden && obj.columns[cols_idx].hidden == 'true') {
469                                 dump('\t' + cols_idx);
470                                 var treecell = document.createElement('treecell');
471                                 treerow.appendChild(treecell);
472                                 cols_idx++;
473                         }
474                         */
475                         for (var i = 0; i < obj.columns.length; i++) {
476                         var treecell = document.createElement('treecell'); treecell.setAttribute('label','Retrieving...');
477                         treerow.appendChild(treecell);
478                         }
479                         /*
480                         dump('\t' + cols_idx + '\n');
481                         */
482                 } catch(E) {
483                         alert(E);
484                 }
485         },
486
487         'detect_visible' : function() {
488                 var obj = this;
489                 try {
490                         //dump('detect_visible  obj.node = ' + obj.node + '\n');
491                         /* FIXME - this is a hack.. if the implementation of tree changes, this could break */
492                         try {
493                                 var scrollbar = document.getAnonymousNodes( document.getAnonymousNodes(obj.node)[1] )[1];
494                                 var curpos = scrollbar.getAttribute('curpos');
495                                 var maxpos = scrollbar.getAttribute('maxpos');
496                                 //alert('curpos = ' + curpos + ' maxpos = ' + maxpos + ' obj.curpos = ' + obj.curpos + ' obj.maxpos = ' + obj.maxpos + '\n');
497                                 if ((curpos != obj.curpos) || (maxpos != obj.maxpos)) {
498                                         if ( obj.auto_retrieve() > 0 ) {
499                                                 obj.curpos = curpos; obj.maxpos = maxpos;
500                                         }
501                                 }
502                         } catch(E) {
503                                 obj.error.sdump('D_XULRUNNER', 'List implementation changed? ' + E);
504                         }
505                 } catch(E) { obj.error.sdump('D_ERROR',E); }
506         },
507
508         'detect_visible_polling' : function() {
509                 try {
510                         //alert('detect_visible_polling');
511                         var obj = this;
512                         obj.detect_visible();
513                         setTimeout(function() { try { obj.detect_visible_polling(); } catch(E) { alert(E); } },2000);
514                 } catch(E) {
515                         alert(E);
516                 }
517         },
518
519
520         'auto_retrieve' : function(params) {
521                 var obj = this;
522                 switch (this.node.nodeName) {
523                         case 'tree' : obj._auto_retrieve_tree(params); break;
524                         default: throw('NYI: Need .auto_retrieve() for ' + obj.node.nodeName); break;
525                 }
526         },
527
528         '_auto_retrieve_tree' : function (params) {
529                 var obj = this;
530                 if (!obj.auto_retrieve_in_progress) {
531                         obj.auto_retrieve_in_progress = true;
532                         setTimeout(
533                                 function() {
534                                         try {
535                                                         //alert('auto_retrieve\n');
536                                                         var count = 0;
537                                                         var startpos = obj.node.treeBoxObject.getFirstVisibleRow();
538                                                         var endpos = obj.node.treeBoxObject.getLastVisibleRow();
539                                                         if (startpos > endpos) endpos = obj.node.treeBoxObject.getPageLength();
540                                                         //dump('startpos = ' + startpos + ' endpos = ' + endpos + '\n');
541                                                         for (var i = startpos; i < endpos + 4; i++) {
542                                                                 try {
543                                                                         //dump('trying index ' + i + '\n');
544                                                                         var item = obj.node.contentView.getItemAtIndex(i).firstChild;
545                                                                         if (item && item.getAttribute('retrieved') != 'true' ) {
546                                                                                 //dump('\tgot an unfleshed item = ' + item + ' = ' + item.nodeName + '\n');
547                                                                                 util.widgets.dispatch('flesh',item); count++;
548                                                                         }
549                                                                 } catch(E) {
550                                                                         //dump(i + ' : ' + E + '\n');
551                                                                 }
552                                                         }
553                                                         obj.auto_retrieve_in_progress = false;
554                                                         return count;
555                                         } catch(E) { alert(E); }
556                                 }, 1
557                         );
558                 }
559         },
560
561         'full_retrieve' : function(params) {
562                 var obj = this;
563                 switch (this.node.nodeName) {
564                         case 'tree' : obj._full_retrieve_tree(params); break;
565                         default: throw('NYI: Need .full_retrieve() for ' + obj.node.nodeName); break;
566                 }
567         },
568
569         '_full_retrieve_tree' : function(params) {
570                 var obj = this;
571                 try {
572                         if (obj.row_count.total == obj.row_count.fleshed) {
573                                 //alert('Full retrieve... tree seems to be in sync\n' + js2JSON(obj.row_count));
574                                 if (typeof obj.on_all_fleshed == 'function') {
575                                         setTimeout( function() { obj.on_all_fleshed(); }, 0 );
576                                 } else {
577                                         alert('.full_retrieve called with no callback?');
578                                 }
579                         } else {
580                                 //alert('Full retrieve... syncing tree' + js2JSON(obj.row_count));
581                                 JSAN.use('util.widgets');
582                                 var nodes = obj.treechildren.childNodes;
583                                 for (var i = 0; i < nodes.length; i++) {
584                                         util.widgets.dispatch('flesh',nodes[i].firstChild);
585                                 }
586                         }
587                 } catch(E) {
588                         obj.error.standard_unexpected_error_alert('_full_retrieve_tree',E);
589                 }
590         },
591
592         '_append_to_listbox' : function (params) {
593
594                 var obj = this;
595
596                 if (typeof params.row == 'undefined') throw('util.list.append: Object must contain a row');
597
598                 var s = ('util.list.append: params = ' + (params) + '\n');
599
600                 var listitem = document.createElement('listitem');
601
602                 s += ('listbox = ' + this.node + '  listitem = ' + listitem + '\n');
603
604                 if (typeof params.retrieve_row == 'function' || typeof this.retrieve_row == 'function') {
605
606                         setTimeout(
607                                 function() {
608                                         listitem.setAttribute('retrieve_id',params.retrieve_id);
609                                         //FIXME//Make async and fire when row is visible in list
610                                         var row;
611
612                                         params.row_node = listitem;
613                                         params.on_retrieve = function(row) {
614                                                 params.row = row;
615                                                 obj._map_row_to_listcell(params,listitem);
616                                                 obj.node.appendChild( listitem );
617                                         }
618
619                                         if (typeof params.retrieve_row == 'function') {
620
621                                                 row = params.retrieve_row( params );
622
623                                         } else {
624
625                                                 if (typeof obj.retrieve_row == 'function') {
626
627                                                         row = obj.retrieve_row( params );
628
629                                                 }
630                                         }
631                                 }, 0
632                         );
633                 } else {
634                         this._map_row_to_listcell(params,listitem);
635                         this.node.appendChild( listitem );
636                 }
637
638                 this.error.sdump('D_LIST',s);
639                 return listitem;
640
641         },
642
643         '_map_row_to_treecell' : function(params,treerow) {
644                 var obj = this;
645                 var s = '';
646                 util.widgets.remove_children(treerow);
647
648                 if (typeof params.map_row_to_column == 'function' || typeof this.map_row_to_column == 'function') {
649
650                         for (var i = 0; i < this.columns.length; i++) {
651                                 var treecell = document.createElement('treecell');
652                                 var label = '';
653                                 if (params.skip_columns && (params.skip_columns.indexOf(i) != -1)) {
654                                         treecell.setAttribute('label',label);
655                                         treerow.appendChild( treecell );
656                                         s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
657                                         continue;
658                                 }
659                                 if (params.skip_all_columns_except && (params.skip_all_columns_except.indexOf(i) == -1)) {
660                                         treecell.setAttribute('label',label);
661                                         treerow.appendChild( treecell );
662                                         s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
663                                         continue;
664                                 }
665         
666                                 if (typeof params.map_row_to_column == 'function')  {
667         
668                                         label = params.map_row_to_column(params.row,this.columns[i]);
669         
670                                 } else if (typeof this.map_row_to_column == 'function') {
671         
672                                         label = this.map_row_to_column(params.row,this.columns[i]);
673         
674                                 }
675                                 treecell.setAttribute('label',label ? label : '');
676                                 treerow.appendChild( treecell );
677                                 s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
678                         }
679                 } else if (typeof params.map_row_to_columns == 'function' || typeof this.map_row_to_columns == 'function') {
680
681                         var labels = [];
682
683                         if (typeof params.map_row_to_columns == 'function') {
684
685                                 labels = params.map_row_to_columns(params.row,this.columns);
686
687                         } else if (typeof this.map_row_to_columns == 'function') {
688
689                                 labels = this.map_row_to_columns(params.row,this.columns);
690
691                         }
692                         for (var i = 0; i < labels.length; i++) {
693                                 var treecell = document.createElement('treecell');
694                                 treecell.setAttribute('label',typeof labels[i] == 'string' || typeof labels[i] == 'number' ? labels[i] : '');
695                                 treerow.appendChild( treecell );
696                                 s += ('treecell = ' + treecell + ' with label = ' + labels[i] + '\n');
697                         }
698
699                 } else {
700
701                         throw('No row to column mapping function.');
702                 }
703                 this.error.sdump('D_LIST',s);
704         },
705
706         '_map_row_to_listcell' : function(params,listitem) {
707                 var obj = this;
708                 var s = '';
709                 for (var i = 0; i < this.columns.length; i++) {
710                         var value = '';
711                         if (typeof params.map_row_to_column == 'function')  {
712
713                                 value = params.map_row_to_column(params.row,this.columns[i]);
714
715                         } else {
716
717                                 if (typeof this.map_row_to_column == 'function') {
718
719                                         value = this.map_row_to_column(params.row,this.columns[i]);
720                                 }
721                         }
722                         if (typeof value == 'string' || typeof value == 'number') {
723                                 var listcell = document.createElement('listcell');
724                                 listcell.setAttribute('label',value);
725                                 listitem.appendChild(listcell);
726                                 s += ('listcell = ' + listcell + ' with label = ' + value + '\n');
727                         } else {
728                                 listitem.appendChild(value);
729                                 s += ('listcell = ' + value + ' is really a ' + value.nodeName + '\n');
730                         }
731                 }
732                 this.error.sdump('D_LIST',s);
733         },
734
735         'select_all' : function(params) {
736                 var obj = this;
737                 switch(this.node.nodeName) {
738                         case 'tree' : return this._select_all_from_tree(params); break;
739                         default: throw('NYI: Need ._select_all_from_() for ' + this.node.nodeName); break;
740                 }
741         },
742
743         '_select_all_from_tree' : function(params) {
744                 var obj = this;
745                 this.node.view.selection.selectAll();
746         },
747
748         'retrieve_selection' : function(params) {
749                 var obj = this;
750                 switch(this.node.nodeName) {
751                         case 'tree' : return this._retrieve_selection_from_tree(params); break;
752                         default: throw('NYI: Need ._retrieve_selection_from_() for ' + this.node.nodeName); break;
753                 }
754         },
755
756         '_retrieve_selection_from_tree' : function(params) {
757                 var obj = this;
758                 var list = [];
759                 var start = new Object();
760                 var end = new Object();
761                 var numRanges = this.node.view.selection.getRangeCount();
762                 for (var t=0; t<numRanges; t++){
763                         this.node.view.selection.getRangeAt(t,start,end);
764                         for (var v=start.value; v<=end.value; v++){
765                                 var i = this.node.contentView.getItemAtIndex(v);
766                                 list.push( i );
767                         }
768                 }
769                 return list;
770         },
771
772         'dump' : function(params) {
773                 var obj = this;
774                 switch(this.node.nodeName) {
775                         case 'tree' : return this._dump_tree(params); break;
776                         default: throw('NYI: Need .dump() for ' + this.node.nodeName); break;
777                 }
778         },
779
780         '_dump_tree' : function(params) {
781                 var obj = this;
782                 var dump = [];
783                 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
784                         var row = [];
785                         var treeitem = this.treechildren.childNodes[i];
786                         var treerow = treeitem.firstChild;
787                         for (var j = 0; j < treerow.childNodes.length; j++) {
788                                 row.push( treerow.childNodes[j].getAttribute('label') );
789                         }
790                         dump.push( row );
791                 }
792                 return dump;
793         },
794
795         'dump_with_keys' : function(params) {
796                 var obj = this;
797                 switch(this.node.nodeName) {
798                         case 'tree' : return this._dump_tree_with_keys(params); break;
799                         default: throw('NYI: Need .dump_with_keys() for ' + this.node.nodeName); break;
800                 }
801
802         },
803
804         '_dump_tree_with_keys' : function(params) {
805                 var obj = this;
806                 var dump = [];
807                 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
808                         var row = {};
809                         var treeitem = this.treechildren.childNodes[i];
810                         var treerow = treeitem.firstChild;
811                         for (var j = 0; j < treerow.childNodes.length; j++) {
812                                 row[ obj.columns[j].id ] = treerow.childNodes[j].getAttribute('label');
813                         }
814                         dump.push( row );
815                 }
816                 return dump;
817         },
818
819         'dump_csv' : function(params) {
820                 var obj = this;
821                 switch(this.node.nodeName) {
822                         case 'tree' : return this._dump_tree_csv(params); break;
823                         default: throw('NYI: Need .dump_csv() for ' + this.node.nodeName); break;
824                 }
825
826         },
827
828         '_dump_tree_csv' : function(params) {
829                 var obj = this;
830                 var dump = '';
831                 for (var j = 0; j < obj.columns.length; j++) {
832                         if (obj.node.treeBoxObject.columns.getColumnAt(j).element.getAttribute('hidden') == 'true') {
833                                 /* skip */
834                         } else {
835                                 if (dump) dump += ',';
836                                 dump += '"' + obj.columns[j].label.replace(/"/g, '""') + '"';
837                         }
838                 }
839                 dump += '\r\n';
840                 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
841                         var row = '';
842                         var treeitem = this.treechildren.childNodes[i];
843                         var treerow = treeitem.firstChild;
844                         for (var j = 0; j < treerow.childNodes.length; j++) {
845                                 if (obj.node.treeBoxObject.columns.getColumnAt(j).element.getAttribute('hidden') == 'true') {
846                                         /* skip */
847                                 } else {
848                                         if (row) row += ',';
849                                         row += '"' + treerow.childNodes[j].getAttribute('label').replace(/"/g, '""') + '"';
850                                 }
851                         }
852                         dump +=  row + '\r\n';
853                 }
854                 return dump;
855         },
856
857         'dump_selected_with_keys' : function(params) {
858                 var obj = this;
859                 switch(this.node.nodeName) {
860                         case 'tree' : return this._dump_tree_selection_with_keys(params); break;
861                         default: throw('NYI: Need .dump_selection_with_keys() for ' + this.node.nodeName); break;
862                 }
863
864         },
865
866         '_dump_tree_selection_with_keys' : function(params) {
867                 var obj = this;
868                 var dump = [];
869                 var list = obj._retrieve_selection_from_tree();
870                 for (var i = 0; i < list.length; i++) {
871                         var row = {};
872                         var treeitem = list[i];
873                         var treerow = treeitem.firstChild;
874                         for (var j = 0; j < treerow.childNodes.length; j++) {
875                                 var value = treerow.childNodes[j].getAttribute('label');
876                                 if (params.skip_hidden_columns) if (obj.node.treeBoxObject.columns.getColumnAt(j).element.getAttribute('hidden') == 'true') continue;
877                                 var id = obj.columns[j].id; if (params.labels_instead_of_ids) id = obj.columns[j].label;
878                                 row[ id ] = value;
879                         }
880                         dump.push( row );
881                 }
882                 return dump;
883         },
884
885         'clipboard' : function() {
886                 try {
887                         var obj = this;
888                         var dump = obj.dump_selected_with_keys({'skip_hidden_columns':true,'labels_instead_of_ids':true});
889                         JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.stash_retrieve();
890                         data.list_clipboard = dump; data.stash('list_clipboard');
891                         JSAN.use('util.window'); var win = new util.window();
892                         win.open(urls.XUL_LIST_CLIPBOARD,'list_clipboard','chrome,resizable,modal');
893                 } catch(E) {
894                         this.error.standard_unexpected_error_alert('clipboard',E);
895                 }
896         },
897
898         'dump_retrieve_ids' : function(params) {
899                 var obj = this;
900                 switch(this.node.nodeName) {
901                         case 'tree' : return this._dump_retrieve_ids_tree(params); break;
902                         default: throw('NYI: Need .dump_retrieve_ids() for ' + this.node.nodeName); break;
903                 }
904         },
905
906         '_dump_retrieve_ids_tree' : function(params) {
907                 var obj = this;
908                 var dump = [];
909                 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
910                         var treeitem = this.treechildren.childNodes[i];
911                         dump.push( treeitem.getAttribute('retrieve_id') );
912                 }
913                 return dump;
914         },
915
916         '_sort_tree' : function(col,sortDir) {
917                 var obj = this;
918                 try {
919                         if (obj.node.getAttribute('no_sort')) {
920                                 return;
921                         }
922                         if (obj.on_all_fleshed) {
923                                 var r = window.confirm('This list is busy rendering/retrieving data.  Abort current action and proceed?');
924                                 if (r) {} else { return; }
925                         }
926                         var col_pos;
927                         for (var i = 0; i < obj.columns.length; i++) { 
928                                 if (obj.columns[i].id == col.id) col_pos = function(a){return a;}(i); 
929                         }
930                         obj.on_all_fleshed = function() {
931                                         try {
932                                                 JSAN.use('util.money');
933                                                 var rows = [];
934                                                 var treeitems = obj.treechildren.childNodes;
935                                                 for (var i = 0; i < treeitems.length; i++) {
936                                                         var treeitem = treeitems[i];
937                                                         var treerow = treeitem.firstChild;
938                                                         var treecell = treerow.childNodes[ col_pos ];
939                                                         value = ( { 'value' : treecell ? treecell.getAttribute('label') : '', 'node' : treeitem } );
940                                                         rows.push( value );
941                                                 }
942                                                 rows = rows.sort( function(a,b) { 
943                                                         a = a.value; b = b.value; 
944                                                         if (col.getAttribute('sort_type')) {
945                                                                 switch(col.getAttribute('sort_type')) {
946                                                                         case 'number' :
947                                                                                 a = Number(a); b = Number(b);
948                                                                         break;
949                                                                         case 'money' :
950                                                                                 a = util.money.dollars_float_to_cents_integer(a);
951                                                                                 b = util.money.dollars_float_to_cents_integer(b);
952                                                                         break;
953                                                                         case 'title' : /* special case for "a" and "the".  doesn't use marc 245 indicator */
954                                                                                 a = String( a ).toUpperCase().replace( /^\s*(THE|A|AN)\s+/, '' );
955                                                                                 b = String( b ).toUpperCase().replace( /^\s*(THE|A|AN)\s+/, '' );
956                                                                         break;
957                                                                         default:
958                                                                                 a = String( a ).toUpperCase();
959                                                                                 b = String( b ).toUpperCase();
960                                                                         break;
961                                                                 }
962                                                         } else {
963                                                                 if (typeof a == 'string' || typeof b == 'string') {
964                                                                         a = String( a ).toUpperCase();
965                                                                         b = String( b ).toUpperCase();
966                                                                 }
967                                                         }
968                                                         if (a < b) return -1; 
969                                                         if (a > b) return 1; 
970                                                         return 0; 
971                                                 } );
972                                                 if (sortDir == 'asc') rows = rows.reverse();
973                                                 while(obj.treechildren.lastChild) obj.treechildren.removeChild( obj.treechildren.lastChild );
974                                                 for (var i = 0; i < rows.length; i++) {
975                                                         obj.treechildren.appendChild( rows[i].node );
976                                                 }
977                                         } catch(E) {
978                                                 obj.error.standard_unexpected_error_alert('sorting',E); 
979                                         }
980                                         setTimeout(function(){ obj.on_all_fleshed = null; },0);
981                                 }
982                         obj.full_retrieve();
983                 } catch(E) {
984                         obj.error.standard_unexpected_error_alert('pre sorting', E);
985                 }
986         },
987
988 }
989 dump('exiting util.list.js\n');