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]);
334 '_append_to_tree' : function (params) {
338 if (typeof params.row == 'undefined') throw('util.list.append: Object must contain a row');
340 var s = ('util.list.append: params = ' + (params) + '\n');
342 var treechildren_node = this.treechildren;
344 if (params.node && params.node.nodeName == 'treeitem') {
345 params.node.setAttribute('container','true'); /* params.node.setAttribute('open','true'); */
346 if (params.node.lastChild.nodeName == 'treechildren') {
347 treechildren_node = params.node.lastChild;
349 treechildren_node = document.createElement('treechildren');
350 params.node.appendChild(treechildren_node);
354 var treeitem = document.createElement('treeitem');
355 treeitem.setAttribute('retrieve_id',params.retrieve_id);
356 if (typeof params.to_bottom != 'undefined') {
357 treechildren_node.appendChild( treeitem );
358 if (typeof params.no_auto_select == 'undefined') {
359 if (!obj.auto_select_pending) {
360 obj.auto_select_pending = true;
361 setTimeout(function() {
362 dump('auto-selecting\n');
363 var idx = Number(obj.node.view.rowCount)-1;
364 try { obj.node.view.selection.select(idx); } catch(E) { obj.error.sdump('D_ALERT','tree auto select: ' + E + '\n'); }
365 try { if (typeof params.on_select == 'function') params.on_select(); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, on_select: ' + E + '\n'); }
366 obj.auto_select_pending = false;
367 try { util.widgets.dispatch('flesh',obj.node.contentView.getItemAtIndex(idx).firstChild); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, flesh: ' + E + '\n'); }
372 if (treechildren_node.firstChild) {
373 treechildren_node.insertBefore( treeitem, treechildren_node.firstChild );
375 treechildren_node.appendChild( treeitem );
377 if (typeof params.no_auto_select == 'undefined') {
378 if (!obj.auto_select_pending) {
379 obj.auto_select_pending = true;
380 setTimeout(function() {
381 try { obj.node.view.selection.select(0); } catch(E) { obj.error.sdump('D_ALERT','tree auto select: ' + E + '\n'); }
382 try { if (typeof params.on_select == 'function') params.on_select(); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, on_select: ' + E + '\n'); }
383 obj.auto_select_pending = false;
384 try { util.widgets.dispatch('flesh',obj.node.contentView.getItemAtIndex(0).firstChild); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, flesh: ' + E + '\n'); }
389 var treerow = document.createElement('treerow');
390 treeitem.appendChild( treerow );
391 treerow.setAttribute('retrieve_id',params.retrieve_id);
393 s += ('tree = ' + this.node + ' treechildren = ' + treechildren_node + '\n');
394 s += ('treeitem = ' + treeitem + ' treerow = ' + treerow + '\n');
396 if (typeof params.retrieve_row == 'function' || typeof this.retrieve_row == 'function') {
398 obj.put_retrieving_label(treerow);
399 treerow.addEventListener(
403 if (treerow.getAttribute('retrieved') == 'true') return; /* already running */
405 treerow.setAttribute('retrieved','true');
407 //dump('fleshing = ' + params.retrieve_id + '\n');
409 function inc_fleshed() {
410 if (treerow.getAttribute('fleshed') == 'true') return; /* already fleshed */
411 treerow.setAttribute('fleshed','true');
412 obj.row_count.fleshed++;
413 if (obj.row_count.fleshed == obj.row_count.total) {
414 if (typeof obj.on_all_fleshed == 'function') {
415 setTimeout( function() { obj.on_all_fleshed(); }, 0 );
420 params.row_node = treeitem;
421 params.on_retrieve = function(p) {
424 obj._map_row_to_treecell(p,treerow);
426 var idx = obj.node.contentView.getIndexOfItem( params.row_node );
427 dump('idx = ' + idx + '\n');
428 // if current row is selected, send another select event to re-sync data that the client code fetches on selects
429 if ( obj.node.view.selection.isSelected( idx ) ) {
430 dump('dispatching select event for on_retrieve for idx = ' + idx + '\n');
431 util.widgets.dispatch('select',params.row_node);
434 alert('fixme2: ' + E);
438 if (typeof params.retrieve_row == 'function') {
440 params.retrieve_row( params );
442 } else if (typeof obj.retrieve_row == 'function') {
444 obj.retrieve_row( params );
456 util.widgets.dispatch('flesh',treerow);
461 obj.put_retrieving_label(treerow);
462 treerow.addEventListener(
465 //dump('fleshing anon\n');
466 if (treerow.getAttribute('fleshed') == 'true') return; /* already fleshed */
467 obj._map_row_to_treecell(params,treerow);
468 treerow.setAttribute('retrieved','true');
469 treerow.setAttribute('fleshed','true');
470 obj.row_count.fleshed++;
471 if (obj.row_count.fleshed == obj.row_count.total) {
472 if (typeof obj.on_all_fleshed == 'function') {
473 setTimeout( function() { obj.on_all_fleshed(); }, 0 );
482 util.widgets.dispatch('flesh',treerow);
487 this.error.sdump('D_LIST',s);
491 if (obj.trim_list && obj.row_count.total >= obj.trim_list) {
493 //if (typeof params.to_bottom != 'undefined')
494 if (typeof params.to_top == 'undefined') {
495 treechildren_node.removeChild( treechildren_node.firstChild );
497 treechildren_node.removeChild( treechildren_node.lastChild );
503 setTimeout( function() { obj.auto_retrieve(); }, 0 );
505 params.my_node = treeitem;
509 '_refresh_row_in_tree' : function (params) {
513 if (typeof params.row == 'undefined') throw('util.list.refresh_row: Object must contain a row');
514 if (typeof params.my_node == 'undefined') throw('util.list.refresh_row: Object must contain a my_node');
515 if (params.my_node.nodeName != 'treeitem') throw('util.list.refresh_rwo: my_node must be a treeitem');
517 var s = ('util.list.refresh_row: params = ' + (params) + '\n');
519 var treeitem = params.my_node;
520 treeitem.setAttribute('retrieve_id',params.retrieve_id);
521 if (typeof params.to_bottom != 'undefined') {
522 if (typeof params.no_auto_select == 'undefined') {
523 if (!obj.auto_select_pending) {
524 obj.auto_select_pending = true;
525 setTimeout(function() {
526 dump('auto-selecting\n');
527 var idx = Number(obj.node.view.rowCount)-1;
528 try { obj.node.view.selection.select(idx); } catch(E) { obj.error.sdump('D_ALERT','tree auto select: ' + E + '\n'); }
529 try { if (typeof params.on_select == 'function') params.on_select(); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, on_select: ' + E + '\n'); }
530 obj.auto_select_pending = false;
531 try { util.widgets.dispatch('flesh',obj.node.contentView.getItemAtIndex(idx).firstChild); } catch(E) { obj.error.sdump('D_ALERT','tree auto select, flesh: ' + E + '\n'); }
537 for (var i in treeitem.childNodes) if (treeitem.childNodes[i].nodeName == 'treerow') delete_me.push(treeitem.childNodes[i]);
538 for (var i = 0; i < delete_me.length; i++) treeitem.removeChild(delete_me[i]);
539 var treerow = document.createElement('treerow');
540 treeitem.appendChild( treerow );
541 treerow.setAttribute('retrieve_id',params.retrieve_id);
543 s += ('tree = ' + this.node + '\n');
544 s += ('treeitem = ' + treeitem + ' treerow = ' + treerow + '\n');
546 if (typeof params.retrieve_row == 'function' || typeof this.retrieve_row == 'function') {
548 obj.put_retrieving_label(treerow);
549 treerow.addEventListener(
553 if (treerow.getAttribute('retrieved') == 'true') return; /* already running */
555 treerow.setAttribute('retrieved','true');
557 //dump('fleshing = ' + params.retrieve_id + '\n');
559 function inc_fleshed() {
560 if (treerow.getAttribute('fleshed') == 'true') return; /* already fleshed */
561 treerow.setAttribute('fleshed','true');
562 obj.row_count.fleshed++;
563 if (obj.row_count.fleshed == obj.row_count.total) {
564 if (typeof obj.on_all_fleshed == 'function') {
565 setTimeout( function() { obj.on_all_fleshed(); }, 0 );
570 params.row_node = treeitem;
571 params.on_retrieve = function(p) {
574 obj._map_row_to_treecell(p,treerow);
576 var idx = obj.node.contentView.getIndexOfItem( params.row_node );
577 dump('idx = ' + idx + '\n');
578 // if current row is selected, send another select event to re-sync data that the client code fetches on selects
579 if ( obj.node.view.selection.isSelected( idx ) ) {
580 dump('dispatching select event for on_retrieve for idx = ' + idx + '\n');
581 util.widgets.dispatch('select',params.row_node);
584 alert('fixme2: ' + E);
588 if (typeof params.retrieve_row == 'function') {
590 params.retrieve_row( params );
592 } else if (typeof obj.retrieve_row == 'function') {
594 obj.retrieve_row( params );
606 util.widgets.dispatch('flesh',treerow);
611 obj.put_retrieving_label(treerow);
612 treerow.addEventListener(
615 //dump('fleshing anon\n');
616 if (treerow.getAttribute('fleshed') == 'true') return; /* already fleshed */
617 obj._map_row_to_treecell(params,treerow);
618 treerow.setAttribute('retrieved','true');
619 treerow.setAttribute('fleshed','true');
620 obj.row_count.fleshed++;
621 if (obj.row_count.fleshed == obj.row_count.total) {
622 if (typeof obj.on_all_fleshed == 'function') {
623 setTimeout( function() { obj.on_all_fleshed(); }, 0 );
632 util.widgets.dispatch('flesh',treerow);
637 this.error.sdump('D_LIST',s);
641 if (obj.trim_list && obj.row_count.total >= obj.trim_list) {
643 //if (typeof params.to_bottom != 'undefined')
644 if (typeof params.to_top == 'undefined') {
645 treechildren_node.removeChild( treechildren_node.firstChild );
647 treechildren_node.removeChild( treechildren_node.lastChild );
653 setTimeout( function() { obj.auto_retrieve(); }, 0 );
658 'put_retrieving_label' : function(treerow) {
663 dump('put_retrieving_label. columns = ' + js2JSON(obj.columns) + '\n');
664 while( obj.columns[cols_idx] && obj.columns[cols_idx].hidden && obj.columns[cols_idx].hidden == 'true') {
665 dump('\t' + cols_idx);
666 var treecell = document.createElement('treecell');
667 treerow.appendChild(treecell);
671 for (var i = 0; i < obj.columns.length; i++) {
672 var treecell = document.createElement('treecell'); treecell.setAttribute('label','Retrieving...');
673 treerow.appendChild(treecell);
676 dump('\t' + cols_idx + '\n');
683 'detect_visible' : function() {
686 //dump('detect_visible obj.node = ' + obj.node + '\n');
687 /* FIXME - this is a hack.. if the implementation of tree changes, this could break */
689 var scrollbar = document.getAnonymousNodes( document.getAnonymousNodes(obj.node)[1] )[1];
690 var curpos = scrollbar.getAttribute('curpos');
691 var maxpos = scrollbar.getAttribute('maxpos');
692 //alert('curpos = ' + curpos + ' maxpos = ' + maxpos + ' obj.curpos = ' + obj.curpos + ' obj.maxpos = ' + obj.maxpos + '\n');
693 if ((curpos != obj.curpos) || (maxpos != obj.maxpos)) {
694 if ( obj.auto_retrieve() > 0 ) {
695 obj.curpos = curpos; obj.maxpos = maxpos;
699 obj.error.sdump('D_XULRUNNER', 'List implementation changed? ' + E);
701 } catch(E) { obj.error.sdump('D_ERROR',E); }
704 'detect_visible_polling' : function() {
706 //alert('detect_visible_polling');
708 obj.detect_visible();
709 setTimeout(function() { try { obj.detect_visible_polling(); } catch(E) { alert(E); } },2000);
716 'auto_retrieve' : function(params) {
718 switch (this.node.nodeName) {
719 case 'tree' : obj._auto_retrieve_tree(params); break;
720 default: throw('NYI: Need .auto_retrieve() for ' + obj.node.nodeName); break;
724 '_auto_retrieve_tree' : function (params) {
726 if (!obj.auto_retrieve_in_progress) {
727 obj.auto_retrieve_in_progress = true;
731 //alert('auto_retrieve\n');
733 var startpos = obj.node.treeBoxObject.getFirstVisibleRow();
734 var endpos = obj.node.treeBoxObject.getLastVisibleRow();
735 if (startpos > endpos) endpos = obj.node.treeBoxObject.getPageLength();
736 //dump('startpos = ' + startpos + ' endpos = ' + endpos + '\n');
737 for (var i = startpos; i < endpos + 4; i++) {
739 //dump('trying index ' + i + '\n');
740 var item = obj.node.contentView.getItemAtIndex(i).firstChild;
741 if (item && item.getAttribute('retrieved') != 'true' ) {
742 //dump('\tgot an unfleshed item = ' + item + ' = ' + item.nodeName + '\n');
743 util.widgets.dispatch('flesh',item); count++;
746 //dump(i + ' : ' + E + '\n');
749 obj.auto_retrieve_in_progress = false;
751 } catch(E) { alert(E); }
757 'full_retrieve' : function(params) {
759 switch (this.node.nodeName) {
760 case 'tree' : obj._full_retrieve_tree(params); break;
761 default: throw('NYI: Need .full_retrieve() for ' + obj.node.nodeName); break;
765 '_full_retrieve_tree' : function(params) {
768 if (obj.row_count.total == obj.row_count.fleshed) {
769 //alert('Full retrieve... tree seems to be in sync\n' + js2JSON(obj.row_count));
770 if (typeof obj.on_all_fleshed == 'function') {
771 setTimeout( function() { obj.on_all_fleshed(); }, 0 );
773 alert('.full_retrieve called with no callback?');
776 //alert('Full retrieve... syncing tree' + js2JSON(obj.row_count));
777 JSAN.use('util.widgets');
778 var nodes = obj.treechildren.childNodes;
779 for (var i = 0; i < nodes.length; i++) {
780 util.widgets.dispatch('flesh',nodes[i].firstChild);
784 obj.error.standard_unexpected_error_alert('_full_retrieve_tree',E);
788 '_append_to_listbox' : function (params) {
792 if (typeof params.row == 'undefined') throw('util.list.append: Object must contain a row');
794 var s = ('util.list.append: params = ' + (params) + '\n');
796 var listitem = document.createElement('listitem');
798 s += ('listbox = ' + this.node + ' listitem = ' + listitem + '\n');
800 if (typeof params.retrieve_row == 'function' || typeof this.retrieve_row == 'function') {
804 listitem.setAttribute('retrieve_id',params.retrieve_id);
805 //FIXME//Make async and fire when row is visible in list
808 params.row_node = listitem;
809 params.on_retrieve = function(row) {
811 obj._map_row_to_listcell(params,listitem);
812 obj.node.appendChild( listitem );
813 util.widgets.dispatch('select',params.row_node);
816 if (typeof params.retrieve_row == 'function') {
818 row = params.retrieve_row( params );
822 if (typeof obj.retrieve_row == 'function') {
824 row = obj.retrieve_row( params );
831 this._map_row_to_listcell(params,listitem);
832 this.node.appendChild( listitem );
835 this.error.sdump('D_LIST',s);
836 params.my_node = listitem;
841 '_map_row_to_treecell' : function(params,treerow) {
844 util.widgets.remove_children(treerow);
846 if (typeof params.map_row_to_column == 'function' || typeof this.map_row_to_column == 'function') {
848 for (var i = 0; i < this.columns.length; i++) {
849 var treecell = document.createElement('treecell');
851 if (params.skip_columns && (params.skip_columns.indexOf(i) != -1)) {
852 treecell.setAttribute('label',label);
853 treerow.appendChild( treecell );
854 s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
857 if (params.skip_all_columns_except && (params.skip_all_columns_except.indexOf(i) == -1)) {
858 treecell.setAttribute('label',label);
859 treerow.appendChild( treecell );
860 s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
864 if (typeof params.map_row_to_column == 'function') {
866 label = params.map_row_to_column(params.row,this.columns[i]);
868 } else if (typeof this.map_row_to_column == 'function') {
870 label = this.map_row_to_column(params.row,this.columns[i]);
873 treecell.setAttribute('label',label ? label : '');
874 treerow.appendChild( treecell );
875 s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
877 } else if (typeof params.map_row_to_columns == 'function' || typeof this.map_row_to_columns == 'function') {
881 if (typeof params.map_row_to_columns == 'function') {
883 labels = params.map_row_to_columns(params.row,this.columns);
885 } else if (typeof this.map_row_to_columns == 'function') {
887 labels = this.map_row_to_columns(params.row,this.columns);
890 for (var i = 0; i < labels.length; i++) {
891 var treecell = document.createElement('treecell');
892 treecell.setAttribute('label',typeof labels[i] == 'string' || typeof labels[i] == 'number' ? labels[i] : '');
893 treerow.appendChild( treecell );
894 s += ('treecell = ' + treecell + ' with label = ' + labels[i] + '\n');
899 throw('No row to column mapping function.');
901 this.error.sdump('D_LIST',s);
904 '_map_row_to_listcell' : function(params,listitem) {
907 for (var i = 0; i < this.columns.length; i++) {
909 if (typeof params.map_row_to_column == 'function') {
911 value = params.map_row_to_column(params.row,this.columns[i]);
915 if (typeof this.map_row_to_column == 'function') {
917 value = this.map_row_to_column(params.row,this.columns[i]);
920 if (typeof value == 'string' || typeof value == 'number') {
921 var listcell = document.createElement('listcell');
922 listcell.setAttribute('label',value);
923 listitem.appendChild(listcell);
924 s += ('listcell = ' + listcell + ' with label = ' + value + '\n');
926 listitem.appendChild(value);
927 s += ('listcell = ' + value + ' is really a ' + value.nodeName + '\n');
930 this.error.sdump('D_LIST',s);
933 'select_all' : function(params) {
935 switch(this.node.nodeName) {
936 case 'tree' : return this._select_all_from_tree(params); break;
937 default: throw('NYI: Need ._select_all_from_() for ' + this.node.nodeName); break;
941 '_select_all_from_tree' : function(params) {
943 this.node.view.selection.selectAll();
946 'retrieve_selection' : function(params) {
948 switch(this.node.nodeName) {
949 case 'tree' : return this._retrieve_selection_from_tree(params); break;
950 default: throw('NYI: Need ._retrieve_selection_from_() for ' + this.node.nodeName); break;
954 '_retrieve_selection_from_tree' : function(params) {
957 var start = new Object();
958 var end = new Object();
959 var numRanges = this.node.view.selection.getRangeCount();
960 for (var t=0; t<numRanges; t++){
961 this.node.view.selection.getRangeAt(t,start,end);
962 for (var v=start.value; v<=end.value; v++){
963 var i = this.node.contentView.getItemAtIndex(v);
970 'dump' : function(params) {
972 switch(this.node.nodeName) {
973 case 'tree' : return this._dump_tree(params); break;
974 default: throw('NYI: Need .dump() for ' + this.node.nodeName); break;
978 '_dump_tree' : function(params) {
981 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
983 var treeitem = this.treechildren.childNodes[i];
984 var treerow = treeitem.firstChild;
985 for (var j = 0; j < treerow.childNodes.length; j++) {
986 row.push( treerow.childNodes[j].getAttribute('label') );
993 'dump_with_keys' : function(params) {
995 switch(this.node.nodeName) {
996 case 'tree' : return this._dump_tree_with_keys(params); break;
997 default: throw('NYI: Need .dump_with_keys() for ' + this.node.nodeName); break;
1002 '_dump_tree_with_keys' : function(params) {
1005 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
1007 var treeitem = this.treechildren.childNodes[i];
1008 var treerow = treeitem.firstChild;
1009 for (var j = 0; j < treerow.childNodes.length; j++) {
1010 row[ obj.columns[j].id ] = treerow.childNodes[j].getAttribute('label');
1017 'dump_csv' : function(params) {
1019 switch(this.node.nodeName) {
1020 case 'tree' : return this._dump_tree_csv(params); break;
1021 default: throw('NYI: Need .dump_csv() for ' + this.node.nodeName); break;
1026 '_dump_tree_csv' : function(params) {
1029 for (var j = 0; j < obj.columns.length; j++) {
1030 if (obj.node.treeBoxObject.columns.getColumnAt(j).element.getAttribute('hidden') == 'true') {
1033 if (dump) dump += ',';
1034 dump += '"' + obj.columns[j].label.replace(/"/g, '""') + '"';
1038 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
1040 var treeitem = this.treechildren.childNodes[i];
1041 var treerow = treeitem.firstChild;
1042 for (var j = 0; j < treerow.childNodes.length; j++) {
1043 if (obj.node.treeBoxObject.columns.getColumnAt(j).element.getAttribute('hidden') == 'true') {
1046 if (row) row += ',';
1047 row += '"' + treerow.childNodes[j].getAttribute('label').replace(/"/g, '""') + '"';
1050 dump += row + '\r\n';
1055 'dump_selected_with_keys' : function(params) {
1057 switch(this.node.nodeName) {
1058 case 'tree' : return this._dump_tree_selection_with_keys(params); break;
1059 default: throw('NYI: Need .dump_selection_with_keys() for ' + this.node.nodeName); break;
1064 '_dump_tree_selection_with_keys' : function(params) {
1067 var list = obj._retrieve_selection_from_tree();
1068 for (var i = 0; i < list.length; i++) {
1070 var treeitem = list[i];
1071 var treerow = treeitem.firstChild;
1072 for (var j = 0; j < treerow.childNodes.length; j++) {
1073 var value = treerow.childNodes[j].getAttribute('label');
1074 if (params.skip_hidden_columns) if (obj.node.treeBoxObject.columns.getColumnAt(j).element.getAttribute('hidden') == 'true') continue;
1075 var id = obj.columns[j].id; if (params.labels_instead_of_ids) id = obj.columns[j].label;
1083 'clipboard' : function() {
1086 var dump = obj.dump_selected_with_keys({'skip_hidden_columns':true,'labels_instead_of_ids':true});
1087 JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.stash_retrieve();
1088 data.list_clipboard = dump; data.stash('list_clipboard');
1089 JSAN.use('util.window'); var win = new util.window();
1090 win.open(urls.XUL_LIST_CLIPBOARD,'list_clipboard','chrome,resizable,modal');
1092 this.error.standard_unexpected_error_alert('clipboard',E);
1096 'dump_retrieve_ids' : function(params) {
1098 switch(this.node.nodeName) {
1099 case 'tree' : return this._dump_retrieve_ids_tree(params); break;
1100 default: throw('NYI: Need .dump_retrieve_ids() for ' + this.node.nodeName); break;
1104 '_dump_retrieve_ids_tree' : function(params) {
1107 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
1108 var treeitem = this.treechildren.childNodes[i];
1109 dump.push( treeitem.getAttribute('retrieve_id') );
1114 '_sort_tree' : function(col,sortDir) {
1117 if (obj.node.getAttribute('no_sort')) {
1120 if (obj.on_all_fleshed) {
1121 var r = window.confirm('This list is busy rendering/retrieving data. Abort current action and proceed?');
1122 if (r) {} else { return; }
1125 for (var i = 0; i < obj.columns.length; i++) {
1126 if (obj.columns[i].id == col.id) col_pos = function(a){return a;}(i);
1128 obj.on_all_fleshed = function() {
1130 JSAN.use('util.money');
1132 var treeitems = obj.treechildren.childNodes;
1133 for (var i = 0; i < treeitems.length; i++) {
1134 var treeitem = treeitems[i];
1135 var treerow = treeitem.firstChild;
1136 var treecell = treerow.childNodes[ col_pos ];
1137 value = ( { 'value' : treecell ? treecell.getAttribute('label') : '', 'node' : treeitem } );
1140 rows = rows.sort( function(a,b) {
1141 a = a.value; b = b.value;
1142 if (col.getAttribute('sort_type')) {
1143 switch(col.getAttribute('sort_type')) {
1145 a = Number(a); b = Number(b);
1148 a = util.money.dollars_float_to_cents_integer(a);
1149 b = util.money.dollars_float_to_cents_integer(b);
1151 case 'title' : /* special case for "a" and "the". doesn't use marc 245 indicator */
1152 a = String( a ).toUpperCase().replace( /^\s*(THE|A|AN)\s+/, '' );
1153 b = String( b ).toUpperCase().replace( /^\s*(THE|A|AN)\s+/, '' );
1156 a = String( a ).toUpperCase();
1157 b = String( b ).toUpperCase();
1161 if (typeof a == 'string' || typeof b == 'string') {
1162 a = String( a ).toUpperCase();
1163 b = String( b ).toUpperCase();
1166 if (a < b) return -1;
1167 if (a > b) return 1;
1170 if (sortDir == 'asc') rows = rows.reverse();
1171 while(obj.treechildren.lastChild) obj.treechildren.removeChild( obj.treechildren.lastChild );
1172 for (var i = 0; i < rows.length; i++) {
1173 obj.treechildren.appendChild( rows[i].node );
1176 obj.error.standard_unexpected_error_alert('sorting',E);
1178 setTimeout(function(){ obj.on_all_fleshed = null; },0);
1180 obj.full_retrieve();
1182 obj.error.standard_unexpected_error_alert('pre sorting', E);
1187 dump('exiting util.list.js\n');