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 'register_all_fleshed_callback' : function(f) {
50 this.on_all_fleshed = f;
53 '_init_tree' : function (params) {
57 this.treechildren = this.node.lastChild;
60 var treecols = document.createElement('treecols');
61 this.node.appendChild(treecols);
62 this.treecols = treecols;
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]);
69 treecols.appendChild(treecol);
70 treecol.addEventListener(
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);
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?');
84 setTimeout( do_it, 0 );
87 setTimeout( do_it, 0 );
92 var splitter = document.createElement('splitter');
93 splitter.setAttribute('class','tree-splitter');
94 treecols.appendChild(splitter);
97 var treechildren = document.createElement('treechildren');
98 this.node.appendChild(treechildren);
99 this.treechildren = treechildren;
101 if (typeof params.on_select == 'function') {
102 this.node.addEventListener(
108 if (typeof params.on_click == 'function') {
109 this.node.addEventListener(
116 this.node.addEventListener(
118 function(ev) { obj.detect_visible(); },
122 this.node.addEventListener(
124 function(ev) { obj.auto_retrieve(); },
127 this.node.addEventListener(
129 function(ev) { obj.auto_retrieve(); },
132 window.addEventListener(
134 function(ev) { obj.auto_retrieve(); },
137 /* FIXME -- find events on scrollbar to trigger this */
138 obj.detect_visible_polling();
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);
150 this.node.addEventListener('scroll',function(){ obj.auto_retrieve(); },false);
152 this.restores_columns(params);
155 '_init_listbox' : function (params) {
158 var listhead = document.createElement('listhead');
159 this.node.appendChild(listhead);
161 var listcols = document.createElement('listcols');
162 this.node.appendChild(listcols);
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]);
177 'save_columns' : function (params) {
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;
185 '_save_columns_tree' : function (params) {
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.");
193 var nl = obj.node.getElementsByTagName('treecol');
194 for (var i = 0; i < nl.length; i++) {
196 var col_id = col.getAttribute('id');
198 alert('FIXME: A column in this list does not have an id and cannot be saved');
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 };
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);
210 alert('Columns saved.');
212 obj.error.standard_unexpected_error_alert('_save_columns_tree',E);
216 'restores_columns' : function (params) {
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;
224 '_restores_columns_tree' : function (params) {
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.");
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++) {
239 var col_id = col.getAttribute('id');
241 alert('FIXME: A column in this list does not have an id and cannot be saved');
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);
249 obj.error.sdump('D_ERROR','WARNING: Column ' + col_id + ' did not have a saved state.');
254 obj.error.standard_unexpected_error_alert('_restore_columns_tree',E);
258 'clear' : function (params) {
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;
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 );
273 '_clear_tree' : function(params) {
275 if (obj.error.sdump_levels.D_LIST_DUMP_ON_CLEAR) {
276 obj.error.sdump('D_LIST_DUMP_ON_CLEAR',obj.dump());
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());
281 while (obj.treechildren.lastChild) obj.treechildren.removeChild( obj.treechildren.lastChild );
284 '_clear_listbox' : function(params) {
287 var nl = this.node.getElementsByTagName('listitem');
288 for (var i = 0; i < nl.length; i++) {
291 for (var i = 0; i < items.length; i++) {
292 this.node.removeChild(items[i]);
296 'append' : function (params) {
299 switch (this.node.nodeName) {
300 case 'tree' : rparams = this._append_to_tree(params); break;
301 case 'listbox' : rparams = this._append_to_listbox(params); break;
302 default: throw('NYI: Need .append() for ' + this.node.nodeName); break;
304 if (rparams && params.attributes) {
305 for (var i in params.attributes) {
306 rparams.my_node.setAttribute(i,params.attributes[i]);
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 );
318 'refresh_row' : function (params) {
321 switch (this.node.nodeName) {
322 case 'tree' : rparams = this._refresh_row_in_tree(params); break;
323 default: throw('NYI: Need .refresh_row() for ' + this.node.nodeName); break;
325 if (rparams && params.attributes) {
326 for (var i in params.attributes) {
327 rparams.my_node.setAttribute(i,params.attributes[i]);
330 this.row_count.fleshed--;
335 '_append_to_tree' : function (params) {
339 if (typeof params.row == 'undefined') throw('util.list.append: Object must contain a row');
341 var s = ('util.list.append: params = ' + (params) + '\n');
343 var treechildren_node = this.treechildren;
345 if (params.node && params.node.nodeName == 'treeitem') {
346 params.node.setAttribute('container','true'); /* params.node.setAttribute('open','true'); */
347 if (params.node.lastChild.nodeName == 'treechildren') {
348 treechildren_node = params.node.lastChild;
350 treechildren_node = document.createElement('treechildren');
351 params.node.appendChild(treechildren_node);
355 var treeitem = document.createElement('treeitem');
356 treeitem.setAttribute('retrieve_id',params.retrieve_id);
357 if (typeof params.to_bottom != 'undefined') {
358 treechildren_node.appendChild( treeitem );
359 if (typeof params.no_auto_select == 'undefined') {
360 if (!obj.auto_select_pending) {
361 obj.auto_select_pending = true;
362 setTimeout(function() {
363 dump('auto-selecting\n');
364 var idx = Number(obj.node.view.rowCount)-1;
365 try { obj.node.view.selection.select(idx); } catch(E) { obj.error.sdump('D_ALERT','tree auto select: ' + E + '\n'); }
366 try { if (typeof params.on_select == 'function') params.on_select(); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, on_select: ' + E + '\n'); }
367 obj.auto_select_pending = false;
368 try { util.widgets.dispatch('flesh',obj.node.contentView.getItemAtIndex(idx).firstChild); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, flesh: ' + E + '\n'); }
373 if (treechildren_node.firstChild) {
374 treechildren_node.insertBefore( treeitem, treechildren_node.firstChild );
376 treechildren_node.appendChild( treeitem );
378 if (typeof params.no_auto_select == 'undefined') {
379 if (!obj.auto_select_pending) {
380 obj.auto_select_pending = true;
381 setTimeout(function() {
382 try { obj.node.view.selection.select(0); } catch(E) { obj.error.sdump('D_ALERT','tree auto select: ' + E + '\n'); }
383 try { if (typeof params.on_select == 'function') params.on_select(); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, on_select: ' + E + '\n'); }
384 obj.auto_select_pending = false;
385 try { util.widgets.dispatch('flesh',obj.node.contentView.getItemAtIndex(0).firstChild); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, flesh: ' + E + '\n'); }
390 var treerow = document.createElement('treerow');
391 treeitem.appendChild( treerow );
392 treerow.setAttribute('retrieve_id',params.retrieve_id);
394 s += ('tree = ' + this.node + ' treechildren = ' + treechildren_node + '\n');
395 s += ('treeitem = ' + treeitem + ' treerow = ' + treerow + '\n');
397 if (typeof params.retrieve_row == 'function' || typeof this.retrieve_row == 'function') {
399 obj.put_retrieving_label(treerow);
400 treerow.addEventListener(
404 if (treerow.getAttribute('retrieved') == 'true') return; /* already running */
406 treerow.setAttribute('retrieved','true');
408 //dump('fleshing = ' + params.retrieve_id + '\n');
410 function inc_fleshed() {
411 if (treerow.getAttribute('fleshed') == 'true') return; /* already fleshed */
412 treerow.setAttribute('fleshed','true');
413 obj.row_count.fleshed++;
414 if (obj.row_count.fleshed >= obj.row_count.total) {
415 if (typeof obj.on_all_fleshed == 'function') {
416 setTimeout( function() { obj.on_all_fleshed(); }, 0 );
421 params.row_node = treeitem;
422 params.on_retrieve = function(p) {
425 obj._map_row_to_treecell(p,treerow);
427 var idx = obj.node.contentView.getIndexOfItem( params.row_node );
428 dump('idx = ' + idx + '\n');
429 // if current row is selected, send another select event to re-sync data that the client code fetches on selects
430 if ( obj.node.view.selection.isSelected( idx ) ) {
431 dump('dispatching select event for on_retrieve for idx = ' + idx + '\n');
432 util.widgets.dispatch('select',obj.node);
435 alert('fixme2: ' + E);
439 if (typeof params.retrieve_row == 'function') {
441 params.retrieve_row( params );
443 } else if (typeof obj.retrieve_row == 'function') {
445 obj.retrieve_row( params );
457 util.widgets.dispatch('flesh',treerow);
462 obj.put_retrieving_label(treerow);
463 treerow.addEventListener(
466 //dump('fleshing anon\n');
467 if (treerow.getAttribute('fleshed') == 'true') return; /* already fleshed */
468 obj._map_row_to_treecell(params,treerow);
469 treerow.setAttribute('retrieved','true');
470 treerow.setAttribute('fleshed','true');
471 obj.row_count.fleshed++;
472 if (obj.row_count.fleshed >= obj.row_count.total) {
473 if (typeof obj.on_all_fleshed == 'function') {
474 setTimeout( function() { obj.on_all_fleshed(); }, 0 );
483 util.widgets.dispatch('flesh',treerow);
488 this.error.sdump('D_LIST',s);
492 if (obj.trim_list && obj.row_count.total >= obj.trim_list) {
494 //if (typeof params.to_bottom != 'undefined')
495 if (typeof params.to_top == 'undefined') {
496 treechildren_node.removeChild( treechildren_node.firstChild );
498 treechildren_node.removeChild( treechildren_node.lastChild );
504 setTimeout( function() { obj.auto_retrieve(); }, 0 );
506 params.my_node = treeitem;
510 '_refresh_row_in_tree' : function (params) {
514 if (typeof params.row == 'undefined') throw('util.list.refresh_row: Object must contain a row');
515 if (typeof params.my_node == 'undefined') throw('util.list.refresh_row: Object must contain a my_node');
516 if (params.my_node.nodeName != 'treeitem') throw('util.list.refresh_rwo: my_node must be a treeitem');
518 var s = ('util.list.refresh_row: params = ' + (params) + '\n');
520 var treeitem = params.my_node;
521 treeitem.setAttribute('retrieve_id',params.retrieve_id);
522 if (typeof params.to_bottom != 'undefined') {
523 if (typeof params.no_auto_select == 'undefined') {
524 if (!obj.auto_select_pending) {
525 obj.auto_select_pending = true;
526 setTimeout(function() {
527 dump('auto-selecting\n');
528 var idx = Number(obj.node.view.rowCount)-1;
529 try { obj.node.view.selection.select(idx); } catch(E) { obj.error.sdump('D_ALERT','tree auto select: ' + E + '\n'); }
530 try { if (typeof params.on_select == 'function') params.on_select(); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, on_select: ' + E + '\n'); }
531 obj.auto_select_pending = false;
532 try { util.widgets.dispatch('flesh',obj.node.contentView.getItemAtIndex(idx).firstChild); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, flesh: ' + E + '\n'); }
538 for (var i in treeitem.childNodes) if (treeitem.childNodes[i].nodeName == 'treerow') delete_me.push(treeitem.childNodes[i]);
539 for (var i = 0; i < delete_me.length; i++) treeitem.removeChild(delete_me[i]);
540 var treerow = document.createElement('treerow');
541 treeitem.appendChild( treerow );
542 treerow.setAttribute('retrieve_id',params.retrieve_id);
544 s += ('tree = ' + this.node + '\n');
545 s += ('treeitem = ' + treeitem + ' treerow = ' + treerow + '\n');
547 if (typeof params.retrieve_row == 'function' || typeof this.retrieve_row == 'function') {
549 obj.put_retrieving_label(treerow);
550 treerow.addEventListener(
554 if (treerow.getAttribute('retrieved') == 'true') return; /* already running */
556 treerow.setAttribute('retrieved','true');
558 //dump('fleshing = ' + params.retrieve_id + '\n');
560 function inc_fleshed() {
561 if (treerow.getAttribute('fleshed') == 'true') return; /* already fleshed */
562 treerow.setAttribute('fleshed','true');
563 obj.row_count.fleshed++;
564 if (obj.row_count.fleshed >= obj.row_count.total) {
565 if (typeof obj.on_all_fleshed == 'function') {
566 setTimeout( function() { obj.on_all_fleshed(); }, 0 );
571 params.row_node = treeitem;
572 params.on_retrieve = function(p) {
575 obj._map_row_to_treecell(p,treerow);
577 var idx = obj.node.contentView.getIndexOfItem( params.row_node );
578 dump('idx = ' + idx + '\n');
579 // if current row is selected, send another select event to re-sync data that the client code fetches on selects
580 if ( obj.node.view.selection.isSelected( idx ) ) {
581 dump('dispatching select event for on_retrieve for idx = ' + idx + '\n');
582 util.widgets.dispatch('select',obj.node);
585 alert('fixme2: ' + E);
589 if (typeof params.retrieve_row == 'function') {
591 params.retrieve_row( params );
593 } else if (typeof obj.retrieve_row == 'function') {
595 obj.retrieve_row( params );
607 util.widgets.dispatch('flesh',treerow);
612 obj.put_retrieving_label(treerow);
613 treerow.addEventListener(
616 //dump('fleshing anon\n');
617 if (treerow.getAttribute('fleshed') == 'true') return; /* already fleshed */
618 obj._map_row_to_treecell(params,treerow);
619 treerow.setAttribute('retrieved','true');
620 treerow.setAttribute('fleshed','true');
621 obj.row_count.fleshed++;
622 if (obj.row_count.fleshed >= obj.row_count.total) {
623 if (typeof obj.on_all_fleshed == 'function') {
624 setTimeout( function() { obj.on_all_fleshed(); }, 0 );
633 util.widgets.dispatch('flesh',treerow);
638 this.error.sdump('D_LIST',s);
642 if (obj.trim_list && obj.row_count.total >= obj.trim_list) {
644 //if (typeof params.to_bottom != 'undefined')
645 if (typeof params.to_top == 'undefined') {
646 treechildren_node.removeChild( treechildren_node.firstChild );
648 treechildren_node.removeChild( treechildren_node.lastChild );
654 setTimeout( function() { obj.auto_retrieve(); }, 0 );
656 JSAN.use('util.widgets'); util.widgets.dispatch('select',obj.node);
661 'put_retrieving_label' : function(treerow) {
666 dump('put_retrieving_label. columns = ' + js2JSON(obj.columns) + '\n');
667 while( obj.columns[cols_idx] && obj.columns[cols_idx].hidden && obj.columns[cols_idx].hidden == 'true') {
668 dump('\t' + cols_idx);
669 var treecell = document.createElement('treecell');
670 treerow.appendChild(treecell);
674 for (var i = 0; i < obj.columns.length; i++) {
675 var treecell = document.createElement('treecell'); treecell.setAttribute('label','Retrieving...');
676 treerow.appendChild(treecell);
679 dump('\t' + cols_idx + '\n');
686 'detect_visible' : function() {
689 //dump('detect_visible obj.node = ' + obj.node + '\n');
690 /* FIXME - this is a hack.. if the implementation of tree changes, this could break */
692 var scrollbar = document.getAnonymousNodes( document.getAnonymousNodes(obj.node)[1] )[1];
693 var curpos = scrollbar.getAttribute('curpos');
694 var maxpos = scrollbar.getAttribute('maxpos');
695 //alert('curpos = ' + curpos + ' maxpos = ' + maxpos + ' obj.curpos = ' + obj.curpos + ' obj.maxpos = ' + obj.maxpos + '\n');
696 if ((curpos != obj.curpos) || (maxpos != obj.maxpos)) {
697 if ( obj.auto_retrieve() > 0 ) {
698 obj.curpos = curpos; obj.maxpos = maxpos;
702 obj.error.sdump('D_XULRUNNER', 'List implementation changed? ' + E);
704 } catch(E) { obj.error.sdump('D_ERROR',E); }
707 'detect_visible_polling' : function() {
709 //alert('detect_visible_polling');
711 obj.detect_visible();
712 setTimeout(function() { try { obj.detect_visible_polling(); } catch(E) { alert(E); } },2000);
719 'auto_retrieve' : function(params) {
721 switch (this.node.nodeName) {
722 case 'tree' : obj._auto_retrieve_tree(params); break;
723 default: throw('NYI: Need .auto_retrieve() for ' + obj.node.nodeName); break;
727 '_auto_retrieve_tree' : function (params) {
729 if (!obj.auto_retrieve_in_progress) {
730 obj.auto_retrieve_in_progress = true;
734 //alert('auto_retrieve\n');
736 var startpos = obj.node.treeBoxObject.getFirstVisibleRow();
737 var endpos = obj.node.treeBoxObject.getLastVisibleRow();
738 if (startpos > endpos) endpos = obj.node.treeBoxObject.getPageLength();
739 //dump('startpos = ' + startpos + ' endpos = ' + endpos + '\n');
740 for (var i = startpos; i < endpos + 4; i++) {
742 //dump('trying index ' + i + '\n');
743 var item = obj.node.contentView.getItemAtIndex(i).firstChild;
744 if (item && item.getAttribute('retrieved') != 'true' ) {
745 //dump('\tgot an unfleshed item = ' + item + ' = ' + item.nodeName + '\n');
746 util.widgets.dispatch('flesh',item); count++;
749 //dump(i + ' : ' + E + '\n');
752 obj.auto_retrieve_in_progress = false;
754 } catch(E) { alert(E); }
760 'full_retrieve' : function(params) {
762 switch (this.node.nodeName) {
763 case 'tree' : obj._full_retrieve_tree(params); break;
764 default: throw('NYI: Need .full_retrieve() for ' + obj.node.nodeName); break;
768 '_full_retrieve_tree' : function(params) {
771 if (obj.row_count.fleshed >= obj.row_count.total) {
772 dump('Full retrieve... tree seems to be in sync\n' + js2JSON(obj.row_count) + '\n');
773 if (typeof obj.on_all_fleshed == 'function') {
776 try { obj.on_all_fleshed(); } catch(E) { obj.error.standard_unexpected_error_alert('_full_retrieve_tree callback',obj.on_all_fleshed); }
779 } else if (typeof obj.on_all_fleshed.length != 'undefined') {
782 var f = obj.on_all_fleshed.pop();
783 if (typeof f == 'function') {
784 try { f(); } catch(E) { obj.error.standard_unexpected_error_alert('_full_retrieve_tree callback',f); }
786 obj.error.standard_unexpected_error_alert('_full_retrieve_tree callback: expected a function',f);
788 if (obj.on_all_fleshed.length > 0) arguments.callee();
792 dump('.full_retrieve called with no callback?' + '\n');
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 'dump_selected_with_keys' : function(params) {
1085 switch(this.node.nodeName) {
1086 case 'tree' : return this._dump_tree_selection_with_keys(params); break;
1087 default: throw('NYI: Need .dump_selection_with_keys() for ' + this.node.nodeName); break;
1092 '_dump_tree_selection_with_keys' : function(params) {
1095 var list = obj._retrieve_selection_from_tree();
1096 for (var i = 0; i < list.length; i++) {
1098 var treeitem = list[i];
1099 var treerow = treeitem.firstChild;
1100 for (var j = 0; j < treerow.childNodes.length; j++) {
1101 var value = treerow.childNodes[j].getAttribute('label');
1102 if (params.skip_hidden_columns) if (obj.node.treeBoxObject.columns.getColumnAt(j).element.getAttribute('hidden') == 'true') continue;
1103 var id = obj.columns[j].id; if (params.labels_instead_of_ids) id = obj.columns[j].label;
1111 'clipboard' : function() {
1114 var dump = obj.dump_selected_with_keys({'skip_hidden_columns':true,'labels_instead_of_ids':true});
1115 JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.stash_retrieve();
1116 data.list_clipboard = dump; data.stash('list_clipboard');
1117 JSAN.use('util.window'); var win = new util.window();
1118 win.open(urls.XUL_LIST_CLIPBOARD,'list_clipboard','chrome,resizable,modal');
1120 this.error.standard_unexpected_error_alert('clipboard',E);
1124 'dump_retrieve_ids' : function(params) {
1126 switch(this.node.nodeName) {
1127 case 'tree' : return this._dump_retrieve_ids_tree(params); break;
1128 default: throw('NYI: Need .dump_retrieve_ids() for ' + this.node.nodeName); break;
1132 '_dump_retrieve_ids_tree' : function(params) {
1135 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
1136 var treeitem = this.treechildren.childNodes[i];
1137 dump.push( treeitem.getAttribute('retrieve_id') );
1142 'wrap_in_full_retrieve' : function(f) {
1144 if (typeof obj.on_all_fleshed == 'function') { // legacy
1145 obj.on_all_fleshed = [ obj.on_all_fleshed ];
1147 if (! obj.on_all_fleshed) obj.on_all_fleshed = [];
1148 obj.on_all_fleshed.push(f);
1149 obj.full_retrieve();
1152 '_sort_tree' : function(col,sortDir) {
1155 if (obj.node.getAttribute('no_sort')) {
1158 if (obj.on_all_fleshed) {
1159 var r = window.confirm('This list is busy rendering/retrieving data. Abort current action and proceed?');
1160 if (r) {} else { return; }
1163 for (var i = 0; i < obj.columns.length; i++) {
1164 if (obj.columns[i].id == col.id) col_pos = function(a){return a;}(i);
1166 obj.on_all_fleshed = function() {
1168 JSAN.use('util.money');
1170 var treeitems = obj.treechildren.childNodes;
1171 for (var i = 0; i < treeitems.length; i++) {
1172 var treeitem = treeitems[i];
1173 var treerow = treeitem.firstChild;
1174 var treecell = treerow.childNodes[ col_pos ];
1175 value = ( { 'value' : treecell ? treecell.getAttribute('label') : '', 'node' : treeitem } );
1178 rows = rows.sort( function(a,b) {
1179 a = a.value; b = b.value;
1180 if (col.getAttribute('sort_type')) {
1181 switch(col.getAttribute('sort_type')) {
1183 a = Number(a); b = Number(b);
1186 a = util.money.dollars_float_to_cents_integer(a);
1187 b = util.money.dollars_float_to_cents_integer(b);
1189 case 'title' : /* special case for "a" and "the". doesn't use marc 245 indicator */
1190 a = String( a ).toUpperCase().replace( /^\s*(THE|A|AN)\s+/, '' );
1191 b = String( b ).toUpperCase().replace( /^\s*(THE|A|AN)\s+/, '' );
1194 a = String( a ).toUpperCase();
1195 b = String( b ).toUpperCase();
1199 if (typeof a == 'string' || typeof b == 'string') {
1200 a = String( a ).toUpperCase();
1201 b = String( b ).toUpperCase();
1204 if (a < b) return -1;
1205 if (a > b) return 1;
1208 if (sortDir == 'asc') rows = rows.reverse();
1209 while(obj.treechildren.lastChild) obj.treechildren.removeChild( obj.treechildren.lastChild );
1210 for (var i = 0; i < rows.length; i++) {
1211 obj.treechildren.appendChild( rows[i].node );
1214 obj.error.standard_unexpected_error_alert('sorting',E);
1216 setTimeout(function(){ obj.on_all_fleshed = null; },0);
1218 obj.full_retrieve();
1220 obj.error.standard_unexpected_error_alert('pre sorting', E);
1225 dump('exiting util.list.js\n');