1 dump('entering util.list.js\n');
3 if (typeof main == 'undefined') main = {};
4 util.list = function (id) {
6 this.node = document.getElementById(id);
8 this.row_count = { 'total' : 0, 'fleshed' : 0 };
10 if (!this.node) throw('Could not find element ' + id);
11 switch(this.node.nodeName) {
15 throw(this.node.nodeName + ' not yet supported'); break;
16 default: throw(this.node.nodeName + ' not supported'); break;
19 JSAN.use('util.error'); this.error = new util.error();
24 util.list.prototype = {
26 'init' : function (params) {
30 JSAN.use('util.widgets');
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;
37 if (typeof params.prebuilt != 'undefined') obj.prebuilt = params.prebuilt;
39 if (typeof params.columns == 'undefined') throw('util.list.init: No columns');
40 obj.columns = params.columns;
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;
49 '_init_tree' : function (params) {
53 this.treechildren = this.node.lastChild;
56 var treecols = document.createElement('treecols');
57 this.node.appendChild(treecols);
58 this.treecols = treecols;
60 for (var i = 0; i < this.columns.length; i++) {
61 var treecol = document.createElement('treecol');
62 for (var j in this.columns[i]) {
63 treecol.setAttribute(j,this.columns[i][j]);
65 treecols.appendChild(treecol);
66 treecol.addEventListener(
70 var sortDir = ev.target.getAttribute('sortDir') || 'desc';
71 if (sortDir == 'desc') sortDir = 'asc'; else sortDir = 'desc';
72 ev.target.setAttribute('sortDir',sortDir);
73 obj._sort_tree(ev.target,sortDir);
76 if (obj.row_count.total != obj.row_count.fleshed && (obj.row_count.total - obj.row_count.fleshed) > 50) {
77 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?');
80 setTimeout( do_it, 0 );
83 setTimeout( do_it, 0 );
88 var splitter = document.createElement('splitter');
89 splitter.setAttribute('class','tree-splitter');
90 treecols.appendChild(splitter);
93 var treechildren = document.createElement('treechildren');
94 this.node.appendChild(treechildren);
95 this.treechildren = treechildren;
97 if (typeof params.on_select == 'function') {
98 this.node.addEventListener(
104 if (typeof params.on_click == 'function') {
105 this.node.addEventListener(
112 this.node.addEventListener(
114 function(ev) { obj.detect_visible(); },
118 this.node.addEventListener(
120 function(ev) { obj.auto_retrieve(); },
123 this.node.addEventListener(
125 function(ev) { obj.auto_retrieve(); },
128 window.addEventListener(
130 function(ev) { obj.auto_retrieve(); },
133 /* FIXME -- find events on scrollbar to trigger this */
134 obj.detect_visible_polling();
136 var scrollbar = document.getAnonymousNodes( document.getAnonymousNodes(this.node)[1] )[1];
137 var slider = document.getAnonymousNodes( scrollbar )[2];
138 alert('scrollbar = ' + scrollbar.nodeName + ' grippy = ' + slider.nodeName);
139 scrollbar.addEventListener('click',function(){alert('sb click');},false);
140 scrollbar.addEventListener('command',function(){alert('sb command');},false);
141 scrollbar.addEventListener('scroll',function(){alert('sb scroll');},false);
142 slider.addEventListener('click',function(){alert('slider click');},false);
143 slider.addEventListener('command',function(){alert('slider command');},false);
144 slider.addEventListener('scroll',function(){alert('slider scroll');},false);
146 this.node.addEventListener('scroll',function(){ obj.auto_retrieve(); },false);
148 this.restores_columns(params);
151 '_init_listbox' : function (params) {
154 var listhead = document.createElement('listhead');
155 this.node.appendChild(listhead);
157 var listcols = document.createElement('listcols');
158 this.node.appendChild(listcols);
160 for (var i = 0; i < this.columns.length; i++) {
161 var listheader = document.createElement('listheader');
162 listhead.appendChild(listheader);
163 var listcol = document.createElement('listcol');
164 listcols.appendChild(listcol);
165 for (var j in this.columns[i]) {
166 listheader.setAttribute(j,this.columns[i][j]);
167 listcol.setAttribute(j,this.columns[i][j]);
173 'save_columns' : function (params) {
175 switch (this.node.nodeName) {
176 case 'tree' : this._save_columns_tree(params); break;
177 default: throw('NYI: Need .save_columns() for ' + this.node.nodeName); break;
181 '_save_columns_tree' : function (params) {
184 var id = obj.node.getAttribute('id'); if (!id) {
185 alert("FIXME: The columns for this list cannot be saved because the list has no id.");
189 var nl = obj.node.getElementsByTagName('treecol');
190 for (var i = 0; i < nl.length; i++) {
192 var col_id = col.getAttribute('id');
194 alert('FIXME: A column in this list does not have an id and cannot be saved');
197 var col_hidden = col.getAttribute('hidden');
198 var col_width = col.getAttribute('width');
199 var col_ordinal = col.getAttribute('ordinal');
200 my_cols[ col_id ] = { 'hidden' : col_hidden, 'width' : col_width, 'ordinal' : col_ordinal };
202 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
203 JSAN.use('util.file'); var file = new util.file('tree_columns_for_'+window.escape(id));
204 file.set_object(my_cols);
206 alert('Columns saved.');
208 obj.error.standard_unexpected_error_alert('_save_columns_tree',E);
212 'restores_columns' : function (params) {
214 switch (this.node.nodeName) {
215 case 'tree' : this._restores_columns_tree(params); break;
216 default: throw('NYI: Need .restores_columns() for ' + this.node.nodeName); break;
220 '_restores_columns_tree' : function (params) {
223 var id = obj.node.getAttribute('id'); if (!id) {
224 alert("FIXME: The columns for this list cannot be restored because the list has no id.");
228 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
229 JSAN.use('util.file'); var file = new util.file('tree_columns_for_'+window.escape(id));
230 if (file._file.exists()) {
231 var my_cols = file.get_object(); file.close();
232 var nl = obj.node.getElementsByTagName('treecol');
233 for (var i = 0; i < nl.length; i++) {
235 var col_id = col.getAttribute('id');
237 alert('FIXME: A column in this list does not have an id and cannot be saved');
240 if (typeof my_cols[col_id] != 'undefined') {
241 col.setAttribute('hidden',my_cols[col_id].hidden);
242 col.setAttribute('width',my_cols[col_id].width);
243 col.setAttribute('ordinal',my_cols[col_id].ordinal);
245 obj.error.sdump('D_ERROR','WARNING: Column ' + col_id + ' did not have a saved state.');
250 obj.error.standard_unexpected_error_alert('_restore_columns_tree',E);
254 'clear' : function (params) {
256 switch (this.node.nodeName) {
257 case 'tree' : this._clear_tree(params); break;
258 case 'listbox' : this._clear_listbox(params); break;
259 default: throw('NYI: Need .clear() for ' + this.node.nodeName); break;
261 this.error.sdump('D_LIST','Clearing list ' + this.node.getAttribute('id') + '\n');
262 this.row_count.total = 0;
263 this.row_count.fleshed = 0;
264 setTimeout( function() { obj.exec_on_all_fleshed(); }, 0 );
267 '_clear_tree' : function(params) {
269 if (obj.error.sdump_levels.D_LIST_DUMP_ON_CLEAR) {
270 obj.error.sdump('D_LIST_DUMP_ON_CLEAR',obj.dump());
272 if (obj.error.sdump_levels.D_LIST_DUMP_WITH_KEYS_ON_CLEAR) {
273 obj.error.sdump('D_LIST_DUMP_WITH_KEYS_ON_CLEAR',obj.dump_with_keys());
275 while (obj.treechildren.lastChild) obj.treechildren.removeChild( obj.treechildren.lastChild );
278 '_clear_listbox' : function(params) {
281 var nl = this.node.getElementsByTagName('listitem');
282 for (var i = 0; i < nl.length; i++) {
285 for (var i = 0; i < items.length; i++) {
286 this.node.removeChild(items[i]);
290 'append' : function (params) {
293 switch (this.node.nodeName) {
294 case 'tree' : rparams = this._append_to_tree(params); break;
295 case 'listbox' : rparams = this._append_to_listbox(params); break;
296 default: throw('NYI: Need .append() for ' + this.node.nodeName); break;
298 if (rparams && params.attributes) {
299 for (var i in params.attributes) {
300 rparams.my_node.setAttribute(i,params.attributes[i]);
303 this.row_count.total++;
304 if (this.row_count.fleshed == this.row_count.total) {
305 setTimeout( function() { obj.exec_on_all_fleshed(); }, 0 );
310 'refresh_row' : function (params) {
313 switch (this.node.nodeName) {
314 case 'tree' : rparams = this._refresh_row_in_tree(params); break;
315 default: throw('NYI: Need .refresh_row() for ' + this.node.nodeName); break;
317 if (rparams && params.attributes) {
318 for (var i in params.attributes) {
319 rparams.my_node.setAttribute(i,params.attributes[i]);
322 this.row_count.fleshed--;
327 '_append_to_tree' : function (params) {
331 if (typeof params.row == 'undefined') throw('util.list.append: Object must contain a row');
333 var s = ('util.list.append: params = ' + (params) + '\n');
335 var treechildren_node = this.treechildren;
337 if (params.node && params.node.nodeName == 'treeitem') {
338 params.node.setAttribute('container','true'); /* params.node.setAttribute('open','true'); */
339 if (params.node.lastChild.nodeName == 'treechildren') {
340 treechildren_node = params.node.lastChild;
342 treechildren_node = document.createElement('treechildren');
343 params.node.appendChild(treechildren_node);
347 var treeitem = document.createElement('treeitem');
348 treeitem.setAttribute('retrieve_id',params.retrieve_id);
349 if (typeof params.to_bottom != 'undefined') {
350 treechildren_node.appendChild( treeitem );
351 if (typeof params.no_auto_select == 'undefined') {
352 if (!obj.auto_select_pending) {
353 obj.auto_select_pending = true;
354 setTimeout(function() {
355 dump('auto-selecting\n');
356 var idx = Number(obj.node.view.rowCount)-1;
357 try { obj.node.view.selection.select(idx); } catch(E) { obj.error.sdump('D_ALERT','tree auto select: ' + E + '\n'); }
358 try { if (typeof params.on_select == 'function') params.on_select(); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, on_select: ' + E + '\n'); }
359 obj.auto_select_pending = false;
360 try { util.widgets.dispatch('flesh',obj.node.contentView.getItemAtIndex(idx).firstChild); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, flesh: ' + E + '\n'); }
365 if (treechildren_node.firstChild) {
366 treechildren_node.insertBefore( treeitem, treechildren_node.firstChild );
368 treechildren_node.appendChild( treeitem );
370 if (typeof params.no_auto_select == 'undefined') {
371 if (!obj.auto_select_pending) {
372 obj.auto_select_pending = true;
373 setTimeout(function() {
374 try { obj.node.view.selection.select(0); } catch(E) { obj.error.sdump('D_ALERT','tree auto select: ' + E + '\n'); }
375 try { if (typeof params.on_select == 'function') params.on_select(); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, on_select: ' + E + '\n'); }
376 obj.auto_select_pending = false;
377 try { util.widgets.dispatch('flesh',obj.node.contentView.getItemAtIndex(0).firstChild); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, flesh: ' + E + '\n'); }
382 var treerow = document.createElement('treerow');
383 treeitem.appendChild( treerow );
384 treerow.setAttribute('retrieve_id',params.retrieve_id);
386 s += ('tree = ' + this.node + ' treechildren = ' + treechildren_node + '\n');
387 s += ('treeitem = ' + treeitem + ' treerow = ' + treerow + '\n');
389 if (typeof params.retrieve_row == 'function' || typeof this.retrieve_row == 'function') {
391 obj.put_retrieving_label(treerow);
392 treerow.addEventListener(
396 if (treerow.getAttribute('retrieved') == 'true') return; /* already running */
398 treerow.setAttribute('retrieved','true');
400 //dump('fleshing = ' + params.retrieve_id + '\n');
402 function inc_fleshed() {
403 if (treerow.getAttribute('fleshed') == 'true') return; /* already fleshed */
404 treerow.setAttribute('fleshed','true');
405 obj.row_count.fleshed++;
406 if (obj.row_count.fleshed >= obj.row_count.total) {
407 setTimeout( function() { obj.exec_on_all_fleshed(); }, 0 );
411 params.row_node = treeitem;
412 params.on_retrieve = function(p) {
415 obj._map_row_to_treecell(p,treerow);
417 var idx = obj.node.contentView.getIndexOfItem( params.row_node );
418 dump('idx = ' + idx + '\n');
419 // if current row is selected, send another select event to re-sync data that the client code fetches on selects
420 if ( obj.node.view.selection.isSelected( idx ) ) {
421 dump('dispatching select event for on_retrieve for idx = ' + idx + '\n');
422 util.widgets.dispatch('select',obj.node);
425 alert('fixme2: ' + E);
429 if (typeof params.retrieve_row == 'function') {
431 params.retrieve_row( params );
433 } else if (typeof obj.retrieve_row == 'function') {
435 obj.retrieve_row( params );
447 util.widgets.dispatch('flesh',treerow);
452 obj.put_retrieving_label(treerow);
453 treerow.addEventListener(
456 //dump('fleshing anon\n');
457 if (treerow.getAttribute('fleshed') == 'true') return; /* already fleshed */
458 obj._map_row_to_treecell(params,treerow);
459 treerow.setAttribute('retrieved','true');
460 treerow.setAttribute('fleshed','true');
461 obj.row_count.fleshed++;
462 if (obj.row_count.fleshed >= obj.row_count.total) {
463 setTimeout( function() { obj.exec_on_all_fleshed(); }, 0 );
471 util.widgets.dispatch('flesh',treerow);
476 this.error.sdump('D_LIST',s);
480 if (obj.trim_list && obj.row_count.total >= obj.trim_list) {
482 //if (typeof params.to_bottom != 'undefined')
483 if (typeof params.to_top == 'undefined') {
484 treechildren_node.removeChild( treechildren_node.firstChild );
486 treechildren_node.removeChild( treechildren_node.lastChild );
492 setTimeout( function() { obj.auto_retrieve(); }, 0 );
494 params.my_node = treeitem;
498 '_refresh_row_in_tree' : function (params) {
502 if (typeof params.row == 'undefined') throw('util.list.refresh_row: Object must contain a row');
503 if (typeof params.my_node == 'undefined') throw('util.list.refresh_row: Object must contain a my_node');
504 if (params.my_node.nodeName != 'treeitem') throw('util.list.refresh_rwo: my_node must be a treeitem');
506 var s = ('util.list.refresh_row: params = ' + (params) + '\n');
508 var treeitem = params.my_node;
509 treeitem.setAttribute('retrieve_id',params.retrieve_id);
510 if (typeof params.to_bottom != 'undefined') {
511 if (typeof params.no_auto_select == 'undefined') {
512 if (!obj.auto_select_pending) {
513 obj.auto_select_pending = true;
514 setTimeout(function() {
515 dump('auto-selecting\n');
516 var idx = Number(obj.node.view.rowCount)-1;
517 try { obj.node.view.selection.select(idx); } catch(E) { obj.error.sdump('D_ALERT','tree auto select: ' + E + '\n'); }
518 try { if (typeof params.on_select == 'function') params.on_select(); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, on_select: ' + E + '\n'); }
519 obj.auto_select_pending = false;
520 try { util.widgets.dispatch('flesh',obj.node.contentView.getItemAtIndex(idx).firstChild); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, flesh: ' + E + '\n'); }
526 for (var i in treeitem.childNodes) if (treeitem.childNodes[i].nodeName == 'treerow') delete_me.push(treeitem.childNodes[i]);
527 for (var i = 0; i < delete_me.length; i++) treeitem.removeChild(delete_me[i]);
528 var treerow = document.createElement('treerow');
529 treeitem.appendChild( treerow );
530 treerow.setAttribute('retrieve_id',params.retrieve_id);
532 s += ('tree = ' + this.node + '\n');
533 s += ('treeitem = ' + treeitem + ' treerow = ' + treerow + '\n');
535 if (typeof params.retrieve_row == 'function' || typeof this.retrieve_row == 'function') {
537 obj.put_retrieving_label(treerow);
538 treerow.addEventListener(
542 if (treerow.getAttribute('retrieved') == 'true') return; /* already running */
544 treerow.setAttribute('retrieved','true');
546 //dump('fleshing = ' + params.retrieve_id + '\n');
548 function inc_fleshed() {
549 if (treerow.getAttribute('fleshed') == 'true') return; /* already fleshed */
550 treerow.setAttribute('fleshed','true');
551 obj.row_count.fleshed++;
552 if (obj.row_count.fleshed >= obj.row_count.total) {
553 setTimeout( function() { obj.exec_on_all_fleshed(); }, 0 );
557 params.row_node = treeitem;
558 params.on_retrieve = function(p) {
561 obj._map_row_to_treecell(p,treerow);
563 var idx = obj.node.contentView.getIndexOfItem( params.row_node );
564 dump('idx = ' + idx + '\n');
565 // if current row is selected, send another select event to re-sync data that the client code fetches on selects
566 if ( obj.node.view.selection.isSelected( idx ) ) {
567 dump('dispatching select event for on_retrieve for idx = ' + idx + '\n');
568 util.widgets.dispatch('select',obj.node);
571 alert('fixme2: ' + E);
575 if (typeof params.retrieve_row == 'function') {
577 params.retrieve_row( params );
579 } else if (typeof obj.retrieve_row == 'function') {
581 obj.retrieve_row( params );
593 util.widgets.dispatch('flesh',treerow);
598 obj.put_retrieving_label(treerow);
599 treerow.addEventListener(
602 //dump('fleshing anon\n');
603 if (treerow.getAttribute('fleshed') == 'true') return; /* already fleshed */
604 obj._map_row_to_treecell(params,treerow);
605 treerow.setAttribute('retrieved','true');
606 treerow.setAttribute('fleshed','true');
607 obj.row_count.fleshed++;
608 if (obj.row_count.fleshed >= obj.row_count.total) {
609 setTimeout( function() { obj.exec_on_all_fleshed(); }, 0 );
617 util.widgets.dispatch('flesh',treerow);
622 this.error.sdump('D_LIST',s);
626 if (obj.trim_list && obj.row_count.total >= obj.trim_list) {
628 //if (typeof params.to_bottom != 'undefined')
629 if (typeof params.to_top == 'undefined') {
630 treechildren_node.removeChild( treechildren_node.firstChild );
632 treechildren_node.removeChild( treechildren_node.lastChild );
638 setTimeout( function() { obj.auto_retrieve(); }, 0 );
640 JSAN.use('util.widgets'); util.widgets.dispatch('select',obj.node);
645 'put_retrieving_label' : function(treerow) {
650 dump('put_retrieving_label. columns = ' + js2JSON(obj.columns) + '\n');
651 while( obj.columns[cols_idx] && obj.columns[cols_idx].hidden && obj.columns[cols_idx].hidden == 'true') {
652 dump('\t' + cols_idx);
653 var treecell = document.createElement('treecell');
654 treerow.appendChild(treecell);
658 for (var i = 0; i < obj.columns.length; i++) {
659 var treecell = document.createElement('treecell'); treecell.setAttribute('label','Retrieving...');
660 treerow.appendChild(treecell);
663 dump('\t' + cols_idx + '\n');
670 'detect_visible' : function() {
673 //dump('detect_visible obj.node = ' + obj.node + '\n');
674 /* FIXME - this is a hack.. if the implementation of tree changes, this could break */
676 var scrollbar = document.getAnonymousNodes( document.getAnonymousNodes(obj.node)[1] )[1];
677 var curpos = scrollbar.getAttribute('curpos');
678 var maxpos = scrollbar.getAttribute('maxpos');
679 //alert('curpos = ' + curpos + ' maxpos = ' + maxpos + ' obj.curpos = ' + obj.curpos + ' obj.maxpos = ' + obj.maxpos + '\n');
680 if ((curpos != obj.curpos) || (maxpos != obj.maxpos)) {
681 if ( obj.auto_retrieve() > 0 ) {
682 obj.curpos = curpos; obj.maxpos = maxpos;
686 obj.error.sdump('D_XULRUNNER', 'List implementation changed? ' + E);
688 } catch(E) { obj.error.sdump('D_ERROR',E); }
691 'detect_visible_polling' : function() {
693 //alert('detect_visible_polling');
695 obj.detect_visible();
696 setTimeout(function() { try { obj.detect_visible_polling(); } catch(E) { alert(E); } },2000);
703 'auto_retrieve' : function(params) {
705 switch (this.node.nodeName) {
706 case 'tree' : obj._auto_retrieve_tree(params); break;
707 default: throw('NYI: Need .auto_retrieve() for ' + obj.node.nodeName); break;
711 '_auto_retrieve_tree' : function (params) {
713 if (!obj.auto_retrieve_in_progress) {
714 obj.auto_retrieve_in_progress = true;
718 //alert('auto_retrieve\n');
720 var startpos = obj.node.treeBoxObject.getFirstVisibleRow();
721 var endpos = obj.node.treeBoxObject.getLastVisibleRow();
722 if (startpos > endpos) endpos = obj.node.treeBoxObject.getPageLength();
723 //dump('startpos = ' + startpos + ' endpos = ' + endpos + '\n');
724 for (var i = startpos; i < endpos + 4; i++) {
726 //dump('trying index ' + i + '\n');
727 var item = obj.node.contentView.getItemAtIndex(i).firstChild;
728 if (item && item.getAttribute('retrieved') != 'true' ) {
729 //dump('\tgot an unfleshed item = ' + item + ' = ' + item.nodeName + '\n');
730 util.widgets.dispatch('flesh',item); count++;
733 //dump(i + ' : ' + E + '\n');
736 obj.auto_retrieve_in_progress = false;
738 } catch(E) { alert(E); }
744 'exec_on_all_fleshed' : function() {
747 if (obj.on_all_fleshed) {
748 if (typeof obj.on_all_fleshed == 'function') {
749 dump('exec_on_all_fleshed == function\n');
752 try { obj.on_all_fleshed(); } catch(E) { obj.error.standard_unexpected_error_alert('_full_retrieve_tree callback',obj.on_all_fleshed); }
755 } else if (typeof obj.on_all_fleshed.length != 'undefined') {
756 dump('exec_on_all_fleshed == array\n');
760 dump('exec_on_all_fleshed, processing on_all_fleshed array, length = ' + obj.on_all_fleshed.length + '\n');
761 var f = obj.on_all_fleshed.pop();
762 if (typeof f == 'function') {
763 try { f(); } catch(E) { obj.error.standard_unexpected_error_alert('_full_retrieve_tree callback',f); }
765 if (obj.on_all_fleshed.length > 0) arguments.callee();
767 obj.error.standard_unexpected_error_alert('exec_on_all_fleshed callback error',E);
772 obj.error.standard_unexpected_error_alert('unexpected on_all_fleshed object: ', obj.on_all_fleshed);
776 obj.error.standard_unexpected_error_alert('exec_on_all-fleshed error',E);
780 'full_retrieve' : function(params) {
782 switch (this.node.nodeName) {
783 case 'tree' : obj._full_retrieve_tree(params); break;
784 default: throw('NYI: Need .full_retrieve() for ' + obj.node.nodeName); break;
788 '_full_retrieve_tree' : function(params) {
791 if (obj.row_count.fleshed >= obj.row_count.total) {
792 dump('Full retrieve... tree seems to be in sync\n' + js2JSON(obj.row_count) + '\n');
793 obj.exec_on_all_fleshed();
795 dump('Full retrieve... syncing tree' + js2JSON(obj.row_count) + '\n');
796 JSAN.use('util.widgets');
797 var nodes = obj.treechildren.childNodes;
798 for (var i = 0; i < nodes.length; i++) {
799 util.widgets.dispatch('flesh',nodes[i].firstChild);
803 obj.error.standard_unexpected_error_alert('_full_retrieve_tree',E);
807 '_append_to_listbox' : function (params) {
811 if (typeof params.row == 'undefined') throw('util.list.append: Object must contain a row');
813 var s = ('util.list.append: params = ' + (params) + '\n');
815 var listitem = document.createElement('listitem');
817 s += ('listbox = ' + this.node + ' listitem = ' + listitem + '\n');
819 if (typeof params.retrieve_row == 'function' || typeof this.retrieve_row == 'function') {
823 listitem.setAttribute('retrieve_id',params.retrieve_id);
824 //FIXME//Make async and fire when row is visible in list
827 params.row_node = listitem;
828 params.on_retrieve = function(row) {
830 obj._map_row_to_listcell(params,listitem);
831 obj.node.appendChild( listitem );
832 util.widgets.dispatch('select',obj.node);
835 if (typeof params.retrieve_row == 'function') {
837 row = params.retrieve_row( params );
841 if (typeof obj.retrieve_row == 'function') {
843 row = obj.retrieve_row( params );
850 this._map_row_to_listcell(params,listitem);
851 this.node.appendChild( listitem );
854 this.error.sdump('D_LIST',s);
855 params.my_node = listitem;
860 '_map_row_to_treecell' : function(params,treerow) {
863 util.widgets.remove_children(treerow);
865 if (typeof params.map_row_to_column == 'function' || typeof this.map_row_to_column == 'function') {
867 for (var i = 0; i < this.columns.length; i++) {
868 var treecell = document.createElement('treecell');
870 if (params.skip_columns && (params.skip_columns.indexOf(i) != -1)) {
871 treecell.setAttribute('label',label);
872 treerow.appendChild( treecell );
873 s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
876 if (params.skip_all_columns_except && (params.skip_all_columns_except.indexOf(i) == -1)) {
877 treecell.setAttribute('label',label);
878 treerow.appendChild( treecell );
879 s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
883 if (typeof params.map_row_to_column == 'function') {
885 label = params.map_row_to_column(params.row,this.columns[i]);
887 } else if (typeof this.map_row_to_column == 'function') {
889 label = this.map_row_to_column(params.row,this.columns[i]);
892 treecell.setAttribute('label',label ? label : '');
893 treerow.appendChild( treecell );
894 s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
896 } else if (typeof params.map_row_to_columns == 'function' || typeof this.map_row_to_columns == 'function') {
900 if (typeof params.map_row_to_columns == 'function') {
902 labels = params.map_row_to_columns(params.row,this.columns);
904 } else if (typeof this.map_row_to_columns == 'function') {
906 labels = this.map_row_to_columns(params.row,this.columns);
909 for (var i = 0; i < labels.length; i++) {
910 var treecell = document.createElement('treecell');
911 treecell.setAttribute('label',typeof labels[i] == 'string' || typeof labels[i] == 'number' ? labels[i] : '');
912 treerow.appendChild( treecell );
913 s += ('treecell = ' + treecell + ' with label = ' + labels[i] + '\n');
918 throw('No row to column mapping function.');
920 this.error.sdump('D_LIST',s);
923 '_map_row_to_listcell' : function(params,listitem) {
926 for (var i = 0; i < this.columns.length; i++) {
928 if (typeof params.map_row_to_column == 'function') {
930 value = params.map_row_to_column(params.row,this.columns[i]);
934 if (typeof this.map_row_to_column == 'function') {
936 value = this.map_row_to_column(params.row,this.columns[i]);
939 if (typeof value == 'string' || typeof value == 'number') {
940 var listcell = document.createElement('listcell');
941 listcell.setAttribute('label',value);
942 listitem.appendChild(listcell);
943 s += ('listcell = ' + listcell + ' with label = ' + value + '\n');
945 listitem.appendChild(value);
946 s += ('listcell = ' + value + ' is really a ' + value.nodeName + '\n');
949 this.error.sdump('D_LIST',s);
952 'select_all' : function(params) {
954 switch(this.node.nodeName) {
955 case 'tree' : return this._select_all_from_tree(params); break;
956 default: throw('NYI: Need ._select_all_from_() for ' + this.node.nodeName); break;
960 '_select_all_from_tree' : function(params) {
962 this.node.view.selection.selectAll();
965 'retrieve_selection' : function(params) {
967 switch(this.node.nodeName) {
968 case 'tree' : return this._retrieve_selection_from_tree(params); break;
969 default: throw('NYI: Need ._retrieve_selection_from_() for ' + this.node.nodeName); break;
973 '_retrieve_selection_from_tree' : function(params) {
976 var start = new Object();
977 var end = new Object();
978 var numRanges = this.node.view.selection.getRangeCount();
979 for (var t=0; t<numRanges; t++){
980 this.node.view.selection.getRangeAt(t,start,end);
981 for (var v=start.value; v<=end.value; v++){
982 var i = this.node.contentView.getItemAtIndex(v);
989 'dump' : function(params) {
991 switch(this.node.nodeName) {
992 case 'tree' : return this._dump_tree(params); break;
993 default: throw('NYI: Need .dump() for ' + this.node.nodeName); break;
997 '_dump_tree' : function(params) {
1000 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
1002 var treeitem = this.treechildren.childNodes[i];
1003 var treerow = treeitem.firstChild;
1004 for (var j = 0; j < treerow.childNodes.length; j++) {
1005 row.push( treerow.childNodes[j].getAttribute('label') );
1012 'dump_with_keys' : function(params) {
1014 switch(this.node.nodeName) {
1015 case 'tree' : return this._dump_tree_with_keys(params); break;
1016 default: throw('NYI: Need .dump_with_keys() for ' + this.node.nodeName); break;
1021 '_dump_tree_with_keys' : function(params) {
1024 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
1026 var treeitem = this.treechildren.childNodes[i];
1027 var treerow = treeitem.firstChild;
1028 for (var j = 0; j < treerow.childNodes.length; j++) {
1029 row[ obj.columns[j].id ] = treerow.childNodes[j].getAttribute('label');
1036 'dump_csv' : function(params) {
1038 switch(this.node.nodeName) {
1039 case 'tree' : return this._dump_tree_csv(params); break;
1040 default: throw('NYI: Need .dump_csv() for ' + this.node.nodeName); break;
1045 '_dump_tree_csv' : function(params) {
1048 for (var j = 0; j < obj.columns.length; j++) {
1049 if (obj.node.treeBoxObject.columns.getColumnAt(j).element.getAttribute('hidden') == 'true') {
1052 if (dump) dump += ',';
1053 dump += '"' + obj.columns[j].label.replace(/"/g, '""') + '"';
1057 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
1059 var treeitem = this.treechildren.childNodes[i];
1060 var treerow = treeitem.firstChild;
1061 for (var j = 0; j < treerow.childNodes.length; j++) {
1062 if (obj.node.treeBoxObject.columns.getColumnAt(j).element.getAttribute('hidden') == 'true') {
1065 if (row) row += ',';
1066 row += '"' + treerow.childNodes[j].getAttribute('label').replace(/"/g, '""') + '"';
1069 dump += row + '\r\n';
1074 'dump_csv_to_clipboard' : function(params) {
1076 if (params && params.no_full_retrieve) {
1077 copy_to_clipboard( obj.dump_csv( params ) );
1079 obj.wrap_in_full_retrieve( function() { copy_to_clipboard( obj.dump_csv( params ) ); } );
1083 'print' : function(params) {
1084 if (!params) params = {};
1085 switch(this.node.nodeName) {
1086 case 'tree' : return this._print_tree(params); break;
1087 default: throw('NYI: Need ._print() for ' + this.node.nodeName); break;
1091 '_print_tree' : function(params) {
1094 JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.stash_retrieve();
1095 if (!params.staff && data.list.au && data.list.au[0]) {
1096 params.staff = data.list.au[0];
1098 if (!params.lib && data.list.au && data.list.au[0] && data.list.au[0].ws_ou() && data.hash.aou && data.hash.aou[ data.list.au[0].ws_ou() ]) {
1099 params.lib = data.hash.aou[ data.list.au[0].ws_ou() ];
1100 params.lib.children(null);
1102 if (params.template && data.print_list_templates[ params.template ]) {
1103 var template = data.print_list_templates[ params.template ];
1104 for (var i in template) params[i] = template[i];
1106 obj.wrap_in_full_retrieve(
1109 if (!params.list) params.list = obj.dump_with_keys();
1110 JSAN.use('util.print'); var print = new util.print();
1111 print.tree_list( params );
1112 if (typeof params.callback == 'function') params.callback();
1114 obj.error.standard_unexpected_error_alert('inner _print_tree',E);
1120 obj.error.standard_unexpected_error_alert('_print_tree',E);
1124 'dump_selected_with_keys' : function(params) {
1126 switch(this.node.nodeName) {
1127 case 'tree' : return this._dump_tree_selection_with_keys(params); break;
1128 default: throw('NYI: Need .dump_selection_with_keys() for ' + this.node.nodeName); break;
1133 '_dump_tree_selection_with_keys' : function(params) {
1136 var list = obj._retrieve_selection_from_tree();
1137 for (var i = 0; i < list.length; i++) {
1139 var treeitem = list[i];
1140 var treerow = treeitem.firstChild;
1141 for (var j = 0; j < treerow.childNodes.length; j++) {
1142 var value = treerow.childNodes[j].getAttribute('label');
1143 if (params.skip_hidden_columns) if (obj.node.treeBoxObject.columns.getColumnAt(j).element.getAttribute('hidden') == 'true') continue;
1144 var id = obj.columns[j].id; if (params.labels_instead_of_ids) id = obj.columns[j].label;
1152 'clipboard' : function() {
1155 var dump = obj.dump_selected_with_keys({'skip_hidden_columns':true,'labels_instead_of_ids':true});
1156 JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.stash_retrieve();
1157 data.list_clipboard = dump; data.stash('list_clipboard');
1158 JSAN.use('util.window'); var win = new util.window();
1159 win.open(urls.XUL_LIST_CLIPBOARD,'list_clipboard','chrome,resizable,modal');
1161 this.error.standard_unexpected_error_alert('clipboard',E);
1165 'dump_retrieve_ids' : function(params) {
1167 switch(this.node.nodeName) {
1168 case 'tree' : return this._dump_retrieve_ids_tree(params); break;
1169 default: throw('NYI: Need .dump_retrieve_ids() for ' + this.node.nodeName); break;
1173 '_dump_retrieve_ids_tree' : function(params) {
1176 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
1177 var treeitem = this.treechildren.childNodes[i];
1178 dump.push( treeitem.getAttribute('retrieve_id') );
1183 'wrap_in_full_retrieve' : function(f) {
1185 if (typeof obj.on_all_fleshed == 'function') { // legacy
1186 obj.on_all_fleshed = [ obj.on_all_fleshed ];
1188 if (! obj.on_all_fleshed) obj.on_all_fleshed = [];
1189 obj.on_all_fleshed.push(f);
1190 obj.full_retrieve();
1193 '_sort_tree' : function(col,sortDir) {
1196 if (obj.node.getAttribute('no_sort')) {
1200 for (var i = 0; i < obj.columns.length; i++) {
1201 if (obj.columns[i].id == col.id) col_pos = function(a){return a;}(i);
1203 obj.wrap_in_full_retrieve(
1206 JSAN.use('util.money');
1208 var treeitems = obj.treechildren.childNodes;
1209 for (var i = 0; i < treeitems.length; i++) {
1210 var treeitem = treeitems[i];
1211 var treerow = treeitem.firstChild;
1212 var treecell = treerow.childNodes[ col_pos ];
1213 value = ( { 'value' : treecell ? treecell.getAttribute('label') : '', 'node' : treeitem } );
1216 rows = rows.sort( function(a,b) {
1217 a = a.value; b = b.value;
1218 if (col.getAttribute('sort_type')) {
1219 switch(col.getAttribute('sort_type')) {
1221 a = Number(a); b = Number(b);
1224 a = util.money.dollars_float_to_cents_integer(a);
1225 b = util.money.dollars_float_to_cents_integer(b);
1227 case 'title' : /* special case for "a" and "the". doesn't use marc 245 indicator */
1228 a = String( a ).toUpperCase().replace( /^\s*(THE|A|AN)\s+/, '' );
1229 b = String( b ).toUpperCase().replace( /^\s*(THE|A|AN)\s+/, '' );
1232 a = String( a ).toUpperCase();
1233 b = String( b ).toUpperCase();
1237 if (typeof a == 'string' || typeof b == 'string') {
1238 a = String( a ).toUpperCase();
1239 b = String( b ).toUpperCase();
1242 if (a < b) return -1;
1243 if (a > b) return 1;
1246 if (sortDir == 'asc') rows = rows.reverse();
1247 while(obj.treechildren.lastChild) obj.treechildren.removeChild( obj.treechildren.lastChild );
1248 for (var i = 0; i < rows.length; i++) {
1249 obj.treechildren.appendChild( rows[i].node );
1252 obj.error.standard_unexpected_error_alert('sorting',E);
1257 obj.error.standard_unexpected_error_alert('pre sorting', E);
1262 dump('exiting util.list.js\n');