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_WARN','tree auto select: ' + E + '\n'); }
358 try { if (typeof params.on_select == 'function') params.on_select(); } catch(E) { obj.error.sdump('D_WARN','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_WARN','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_WARN','tree auto select: ' + E + '\n'); }
375 try { if (typeof params.on_select == 'function') params.on_select(); } catch(E) { obj.error.sdump('D_WARN','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_WARN','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_WARN','tree auto select: ' + E + '\n'); }
518 try { if (typeof params.on_select == 'function') params.on_select(); } catch(E) { obj.error.sdump('D_WARN','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_WARN','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 (typeof params == 'undefined') params = {};
1077 if (params.no_full_retrieve) {
1078 copy_to_clipboard( obj.dump_csv( params ) );
1080 obj.wrap_in_full_retrieve( function() { copy_to_clipboard( obj.dump_csv( params ) ); } );
1084 'dump_csv_to_printer' : function(params) {
1086 JSAN.use('util.print'); var print = new util.print();
1087 if (typeof params == 'undefined') params = {};
1088 if (params.no_full_retrieve) {
1089 print.simple( obj.dump_csv( params ), {'content_type':'text/plain'} );
1091 obj.wrap_in_full_retrieve(
1093 print.simple( obj.dump_csv( params ), {'content_type':'text/plain'} );
1099 'dump_csv_to_file' : function(params) {
1101 JSAN.use('util.file'); var f = new util.file();
1102 if (typeof params == 'undefined') params = {};
1103 if (params.no_full_retrieve) {
1104 params.data = obj.dump_csv( params );
1105 params.not_json = true;
1106 if (!params.title) params.title = 'Save List CSV As';
1107 f.export_file( params );
1109 obj.wrap_in_full_retrieve(
1111 params.data = obj.dump_csv( params );
1112 params.not_json = true;
1113 if (!params.title) params.title = 'Save List CSV As';
1114 f.export_file( params );
1120 'print' : function(params) {
1121 if (!params) params = {};
1122 switch(this.node.nodeName) {
1123 case 'tree' : return this._print_tree(params); break;
1124 default: throw('NYI: Need ._print() for ' + this.node.nodeName); break;
1128 '_print_tree' : function(params) {
1131 JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.stash_retrieve();
1132 if (!params.staff && data.list.au && data.list.au[0]) {
1133 params.staff = data.list.au[0];
1135 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() ]) {
1136 params.lib = data.hash.aou[ data.list.au[0].ws_ou() ];
1137 params.lib.children(null);
1139 if (params.template && data.print_list_templates[ params.template ]) {
1140 var template = data.print_list_templates[ params.template ];
1141 for (var i in template) params[i] = template[i];
1143 obj.wrap_in_full_retrieve(
1146 if (!params.list) params.list = obj.dump_with_keys();
1147 JSAN.use('util.print'); var print = new util.print();
1148 print.tree_list( params );
1149 if (typeof params.callback == 'function') params.callback();
1151 obj.error.standard_unexpected_error_alert('inner _print_tree',E);
1157 obj.error.standard_unexpected_error_alert('_print_tree',E);
1161 'dump_selected_with_keys' : function(params) {
1163 switch(this.node.nodeName) {
1164 case 'tree' : return this._dump_tree_selection_with_keys(params); break;
1165 default: throw('NYI: Need .dump_selection_with_keys() for ' + this.node.nodeName); break;
1170 '_dump_tree_selection_with_keys' : function(params) {
1173 var list = obj._retrieve_selection_from_tree();
1174 for (var i = 0; i < list.length; i++) {
1176 var treeitem = list[i];
1177 var treerow = treeitem.firstChild;
1178 for (var j = 0; j < treerow.childNodes.length; j++) {
1179 var value = treerow.childNodes[j].getAttribute('label');
1180 if (params.skip_hidden_columns) if (obj.node.treeBoxObject.columns.getColumnAt(j).element.getAttribute('hidden') == 'true') continue;
1181 var id = obj.columns[j].id; if (params.labels_instead_of_ids) id = obj.columns[j].label;
1189 'clipboard' : function() {
1192 var dump = obj.dump_selected_with_keys({'skip_hidden_columns':true,'labels_instead_of_ids':true});
1193 JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.stash_retrieve();
1194 data.list_clipboard = dump; data.stash('list_clipboard');
1195 JSAN.use('util.window'); var win = new util.window();
1196 win.open(urls.XUL_LIST_CLIPBOARD,'list_clipboard','chrome,resizable,modal');
1197 window.focus(); // sometimes the main window will lower after a clipboard action
1199 this.error.standard_unexpected_error_alert('clipboard',E);
1203 'dump_retrieve_ids' : function(params) {
1205 switch(this.node.nodeName) {
1206 case 'tree' : return this._dump_retrieve_ids_tree(params); break;
1207 default: throw('NYI: Need .dump_retrieve_ids() for ' + this.node.nodeName); break;
1211 '_dump_retrieve_ids_tree' : function(params) {
1214 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
1215 var treeitem = this.treechildren.childNodes[i];
1216 dump.push( treeitem.getAttribute('retrieve_id') );
1221 'wrap_in_full_retrieve' : function(f) {
1223 if (typeof obj.on_all_fleshed == 'function') { // legacy
1224 obj.on_all_fleshed = [ obj.on_all_fleshed ];
1226 if (! obj.on_all_fleshed) obj.on_all_fleshed = [];
1227 obj.on_all_fleshed.push(f);
1228 obj.full_retrieve();
1231 '_sort_tree' : function(col,sortDir) {
1234 if (obj.node.getAttribute('no_sort')) {
1238 for (var i = 0; i < obj.columns.length; i++) {
1239 if (obj.columns[i].id == col.id) col_pos = function(a){return a;}(i);
1241 obj.wrap_in_full_retrieve(
1244 JSAN.use('util.money');
1246 var treeitems = obj.treechildren.childNodes;
1247 for (var i = 0; i < treeitems.length; i++) {
1248 var treeitem = treeitems[i];
1249 var treerow = treeitem.firstChild;
1250 var treecell = treerow.childNodes[ col_pos ];
1251 value = ( { 'value' : treecell ? treecell.getAttribute('label') : '', 'node' : treeitem } );
1254 rows = rows.sort( function(a,b) {
1255 a = a.value; b = b.value;
1256 if (col.getAttribute('sort_type')) {
1257 switch(col.getAttribute('sort_type')) {
1259 a = Number(a); b = Number(b);
1262 a = util.money.dollars_float_to_cents_integer(a);
1263 b = util.money.dollars_float_to_cents_integer(b);
1265 case 'title' : /* special case for "a" and "the". doesn't use marc 245 indicator */
1266 a = String( a ).toUpperCase().replace( /^\s*(THE|A|AN)\s+/, '' );
1267 b = String( b ).toUpperCase().replace( /^\s*(THE|A|AN)\s+/, '' );
1270 a = String( a ).toUpperCase();
1271 b = String( b ).toUpperCase();
1275 if (typeof a == 'string' || typeof b == 'string') {
1276 a = String( a ).toUpperCase();
1277 b = String( b ).toUpperCase();
1280 if (a < b) return -1;
1281 if (a > b) return 1;
1284 if (sortDir == 'asc') rows = rows.reverse();
1285 while(obj.treechildren.lastChild) obj.treechildren.removeChild( obj.treechildren.lastChild );
1286 for (var i = 0; i < rows.length; i++) {
1287 obj.treechildren.appendChild( rows[i].node );
1290 obj.error.standard_unexpected_error_alert('sorting',E);
1295 obj.error.standard_unexpected_error_alert('pre sorting', E);
1300 dump('exiting util.list.js\n');