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',params.row_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',params.row_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 );
659 'put_retrieving_label' : function(treerow) {
664 dump('put_retrieving_label. columns = ' + js2JSON(obj.columns) + '\n');
665 while( obj.columns[cols_idx] && obj.columns[cols_idx].hidden && obj.columns[cols_idx].hidden == 'true') {
666 dump('\t' + cols_idx);
667 var treecell = document.createElement('treecell');
668 treerow.appendChild(treecell);
672 for (var i = 0; i < obj.columns.length; i++) {
673 var treecell = document.createElement('treecell'); treecell.setAttribute('label','Retrieving...');
674 treerow.appendChild(treecell);
677 dump('\t' + cols_idx + '\n');
684 'detect_visible' : function() {
687 //dump('detect_visible obj.node = ' + obj.node + '\n');
688 /* FIXME - this is a hack.. if the implementation of tree changes, this could break */
690 var scrollbar = document.getAnonymousNodes( document.getAnonymousNodes(obj.node)[1] )[1];
691 var curpos = scrollbar.getAttribute('curpos');
692 var maxpos = scrollbar.getAttribute('maxpos');
693 //alert('curpos = ' + curpos + ' maxpos = ' + maxpos + ' obj.curpos = ' + obj.curpos + ' obj.maxpos = ' + obj.maxpos + '\n');
694 if ((curpos != obj.curpos) || (maxpos != obj.maxpos)) {
695 if ( obj.auto_retrieve() > 0 ) {
696 obj.curpos = curpos; obj.maxpos = maxpos;
700 obj.error.sdump('D_XULRUNNER', 'List implementation changed? ' + E);
702 } catch(E) { obj.error.sdump('D_ERROR',E); }
705 'detect_visible_polling' : function() {
707 //alert('detect_visible_polling');
709 obj.detect_visible();
710 setTimeout(function() { try { obj.detect_visible_polling(); } catch(E) { alert(E); } },2000);
717 'auto_retrieve' : function(params) {
719 switch (this.node.nodeName) {
720 case 'tree' : obj._auto_retrieve_tree(params); break;
721 default: throw('NYI: Need .auto_retrieve() for ' + obj.node.nodeName); break;
725 '_auto_retrieve_tree' : function (params) {
727 if (!obj.auto_retrieve_in_progress) {
728 obj.auto_retrieve_in_progress = true;
732 //alert('auto_retrieve\n');
734 var startpos = obj.node.treeBoxObject.getFirstVisibleRow();
735 var endpos = obj.node.treeBoxObject.getLastVisibleRow();
736 if (startpos > endpos) endpos = obj.node.treeBoxObject.getPageLength();
737 //dump('startpos = ' + startpos + ' endpos = ' + endpos + '\n');
738 for (var i = startpos; i < endpos + 4; i++) {
740 //dump('trying index ' + i + '\n');
741 var item = obj.node.contentView.getItemAtIndex(i).firstChild;
742 if (item && item.getAttribute('retrieved') != 'true' ) {
743 //dump('\tgot an unfleshed item = ' + item + ' = ' + item.nodeName + '\n');
744 util.widgets.dispatch('flesh',item); count++;
747 //dump(i + ' : ' + E + '\n');
750 obj.auto_retrieve_in_progress = false;
752 } catch(E) { alert(E); }
758 'full_retrieve' : function(params) {
760 switch (this.node.nodeName) {
761 case 'tree' : obj._full_retrieve_tree(params); break;
762 default: throw('NYI: Need .full_retrieve() for ' + obj.node.nodeName); break;
766 '_full_retrieve_tree' : function(params) {
769 if (obj.row_count.fleshed >= obj.row_count.total) {
770 dump('Full retrieve... tree seems to be in sync\n' + js2JSON(obj.row_count) + '\n');
771 if (typeof obj.on_all_fleshed == 'function') {
772 setTimeout( function() { obj.on_all_fleshed(); }, 0 );
774 dump('.full_retrieve called with no callback?' + '\n');
777 dump('Full retrieve... syncing tree' + js2JSON(obj.row_count) + '\n');
778 JSAN.use('util.widgets');
779 var nodes = obj.treechildren.childNodes;
780 for (var i = 0; i < nodes.length; i++) {
781 util.widgets.dispatch('flesh',nodes[i].firstChild);
785 obj.error.standard_unexpected_error_alert('_full_retrieve_tree',E);
789 '_append_to_listbox' : function (params) {
793 if (typeof params.row == 'undefined') throw('util.list.append: Object must contain a row');
795 var s = ('util.list.append: params = ' + (params) + '\n');
797 var listitem = document.createElement('listitem');
799 s += ('listbox = ' + this.node + ' listitem = ' + listitem + '\n');
801 if (typeof params.retrieve_row == 'function' || typeof this.retrieve_row == 'function') {
805 listitem.setAttribute('retrieve_id',params.retrieve_id);
806 //FIXME//Make async and fire when row is visible in list
809 params.row_node = listitem;
810 params.on_retrieve = function(row) {
812 obj._map_row_to_listcell(params,listitem);
813 obj.node.appendChild( listitem );
814 util.widgets.dispatch('select',params.row_node);
817 if (typeof params.retrieve_row == 'function') {
819 row = params.retrieve_row( params );
823 if (typeof obj.retrieve_row == 'function') {
825 row = obj.retrieve_row( params );
832 this._map_row_to_listcell(params,listitem);
833 this.node.appendChild( listitem );
836 this.error.sdump('D_LIST',s);
837 params.my_node = listitem;
842 '_map_row_to_treecell' : function(params,treerow) {
845 util.widgets.remove_children(treerow);
847 if (typeof params.map_row_to_column == 'function' || typeof this.map_row_to_column == 'function') {
849 for (var i = 0; i < this.columns.length; i++) {
850 var treecell = document.createElement('treecell');
852 if (params.skip_columns && (params.skip_columns.indexOf(i) != -1)) {
853 treecell.setAttribute('label',label);
854 treerow.appendChild( treecell );
855 s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
858 if (params.skip_all_columns_except && (params.skip_all_columns_except.indexOf(i) == -1)) {
859 treecell.setAttribute('label',label);
860 treerow.appendChild( treecell );
861 s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
865 if (typeof params.map_row_to_column == 'function') {
867 label = params.map_row_to_column(params.row,this.columns[i]);
869 } else if (typeof this.map_row_to_column == 'function') {
871 label = this.map_row_to_column(params.row,this.columns[i]);
874 treecell.setAttribute('label',label ? label : '');
875 treerow.appendChild( treecell );
876 s += ('treecell = ' + treecell + ' with label = ' + label + '\n');
878 } else if (typeof params.map_row_to_columns == 'function' || typeof this.map_row_to_columns == 'function') {
882 if (typeof params.map_row_to_columns == 'function') {
884 labels = params.map_row_to_columns(params.row,this.columns);
886 } else if (typeof this.map_row_to_columns == 'function') {
888 labels = this.map_row_to_columns(params.row,this.columns);
891 for (var i = 0; i < labels.length; i++) {
892 var treecell = document.createElement('treecell');
893 treecell.setAttribute('label',typeof labels[i] == 'string' || typeof labels[i] == 'number' ? labels[i] : '');
894 treerow.appendChild( treecell );
895 s += ('treecell = ' + treecell + ' with label = ' + labels[i] + '\n');
900 throw('No row to column mapping function.');
902 this.error.sdump('D_LIST',s);
905 '_map_row_to_listcell' : function(params,listitem) {
908 for (var i = 0; i < this.columns.length; i++) {
910 if (typeof params.map_row_to_column == 'function') {
912 value = params.map_row_to_column(params.row,this.columns[i]);
916 if (typeof this.map_row_to_column == 'function') {
918 value = this.map_row_to_column(params.row,this.columns[i]);
921 if (typeof value == 'string' || typeof value == 'number') {
922 var listcell = document.createElement('listcell');
923 listcell.setAttribute('label',value);
924 listitem.appendChild(listcell);
925 s += ('listcell = ' + listcell + ' with label = ' + value + '\n');
927 listitem.appendChild(value);
928 s += ('listcell = ' + value + ' is really a ' + value.nodeName + '\n');
931 this.error.sdump('D_LIST',s);
934 'select_all' : function(params) {
936 switch(this.node.nodeName) {
937 case 'tree' : return this._select_all_from_tree(params); break;
938 default: throw('NYI: Need ._select_all_from_() for ' + this.node.nodeName); break;
942 '_select_all_from_tree' : function(params) {
944 this.node.view.selection.selectAll();
947 'retrieve_selection' : function(params) {
949 switch(this.node.nodeName) {
950 case 'tree' : return this._retrieve_selection_from_tree(params); break;
951 default: throw('NYI: Need ._retrieve_selection_from_() for ' + this.node.nodeName); break;
955 '_retrieve_selection_from_tree' : function(params) {
958 var start = new Object();
959 var end = new Object();
960 var numRanges = this.node.view.selection.getRangeCount();
961 for (var t=0; t<numRanges; t++){
962 this.node.view.selection.getRangeAt(t,start,end);
963 for (var v=start.value; v<=end.value; v++){
964 var i = this.node.contentView.getItemAtIndex(v);
971 'dump' : function(params) {
973 switch(this.node.nodeName) {
974 case 'tree' : return this._dump_tree(params); break;
975 default: throw('NYI: Need .dump() for ' + this.node.nodeName); break;
979 '_dump_tree' : function(params) {
982 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
984 var treeitem = this.treechildren.childNodes[i];
985 var treerow = treeitem.firstChild;
986 for (var j = 0; j < treerow.childNodes.length; j++) {
987 row.push( treerow.childNodes[j].getAttribute('label') );
994 'dump_with_keys' : function(params) {
996 switch(this.node.nodeName) {
997 case 'tree' : return this._dump_tree_with_keys(params); break;
998 default: throw('NYI: Need .dump_with_keys() for ' + this.node.nodeName); break;
1003 '_dump_tree_with_keys' : function(params) {
1006 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
1008 var treeitem = this.treechildren.childNodes[i];
1009 var treerow = treeitem.firstChild;
1010 for (var j = 0; j < treerow.childNodes.length; j++) {
1011 row[ obj.columns[j].id ] = treerow.childNodes[j].getAttribute('label');
1018 'dump_csv' : function(params) {
1020 switch(this.node.nodeName) {
1021 case 'tree' : return this._dump_tree_csv(params); break;
1022 default: throw('NYI: Need .dump_csv() for ' + this.node.nodeName); break;
1027 '_dump_tree_csv' : function(params) {
1030 for (var j = 0; j < obj.columns.length; j++) {
1031 if (obj.node.treeBoxObject.columns.getColumnAt(j).element.getAttribute('hidden') == 'true') {
1034 if (dump) dump += ',';
1035 dump += '"' + obj.columns[j].label.replace(/"/g, '""') + '"';
1039 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
1041 var treeitem = this.treechildren.childNodes[i];
1042 var treerow = treeitem.firstChild;
1043 for (var j = 0; j < treerow.childNodes.length; j++) {
1044 if (obj.node.treeBoxObject.columns.getColumnAt(j).element.getAttribute('hidden') == 'true') {
1047 if (row) row += ',';
1048 row += '"' + treerow.childNodes[j].getAttribute('label').replace(/"/g, '""') + '"';
1051 dump += row + '\r\n';
1056 'dump_selected_with_keys' : function(params) {
1058 switch(this.node.nodeName) {
1059 case 'tree' : return this._dump_tree_selection_with_keys(params); break;
1060 default: throw('NYI: Need .dump_selection_with_keys() for ' + this.node.nodeName); break;
1065 '_dump_tree_selection_with_keys' : function(params) {
1068 var list = obj._retrieve_selection_from_tree();
1069 for (var i = 0; i < list.length; i++) {
1071 var treeitem = list[i];
1072 var treerow = treeitem.firstChild;
1073 for (var j = 0; j < treerow.childNodes.length; j++) {
1074 var value = treerow.childNodes[j].getAttribute('label');
1075 if (params.skip_hidden_columns) if (obj.node.treeBoxObject.columns.getColumnAt(j).element.getAttribute('hidden') == 'true') continue;
1076 var id = obj.columns[j].id; if (params.labels_instead_of_ids) id = obj.columns[j].label;
1084 'clipboard' : function() {
1087 var dump = obj.dump_selected_with_keys({'skip_hidden_columns':true,'labels_instead_of_ids':true});
1088 JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.stash_retrieve();
1089 data.list_clipboard = dump; data.stash('list_clipboard');
1090 JSAN.use('util.window'); var win = new util.window();
1091 win.open(urls.XUL_LIST_CLIPBOARD,'list_clipboard','chrome,resizable,modal');
1093 this.error.standard_unexpected_error_alert('clipboard',E);
1097 'dump_retrieve_ids' : function(params) {
1099 switch(this.node.nodeName) {
1100 case 'tree' : return this._dump_retrieve_ids_tree(params); break;
1101 default: throw('NYI: Need .dump_retrieve_ids() for ' + this.node.nodeName); break;
1105 '_dump_retrieve_ids_tree' : function(params) {
1108 for (var i = 0; i < this.treechildren.childNodes.length; i++) {
1109 var treeitem = this.treechildren.childNodes[i];
1110 dump.push( treeitem.getAttribute('retrieve_id') );
1115 '_sort_tree' : function(col,sortDir) {
1118 if (obj.node.getAttribute('no_sort')) {
1121 if (obj.on_all_fleshed) {
1122 var r = window.confirm('This list is busy rendering/retrieving data. Abort current action and proceed?');
1123 if (r) {} else { return; }
1126 for (var i = 0; i < obj.columns.length; i++) {
1127 if (obj.columns[i].id == col.id) col_pos = function(a){return a;}(i);
1129 obj.on_all_fleshed = function() {
1131 JSAN.use('util.money');
1133 var treeitems = obj.treechildren.childNodes;
1134 for (var i = 0; i < treeitems.length; i++) {
1135 var treeitem = treeitems[i];
1136 var treerow = treeitem.firstChild;
1137 var treecell = treerow.childNodes[ col_pos ];
1138 value = ( { 'value' : treecell ? treecell.getAttribute('label') : '', 'node' : treeitem } );
1141 rows = rows.sort( function(a,b) {
1142 a = a.value; b = b.value;
1143 if (col.getAttribute('sort_type')) {
1144 switch(col.getAttribute('sort_type')) {
1146 a = Number(a); b = Number(b);
1149 a = util.money.dollars_float_to_cents_integer(a);
1150 b = util.money.dollars_float_to_cents_integer(b);
1152 case 'title' : /* special case for "a" and "the". doesn't use marc 245 indicator */
1153 a = String( a ).toUpperCase().replace( /^\s*(THE|A|AN)\s+/, '' );
1154 b = String( b ).toUpperCase().replace( /^\s*(THE|A|AN)\s+/, '' );
1157 a = String( a ).toUpperCase();
1158 b = String( b ).toUpperCase();
1162 if (typeof a == 'string' || typeof b == 'string') {
1163 a = String( a ).toUpperCase();
1164 b = String( b ).toUpperCase();
1167 if (a < b) return -1;
1168 if (a > b) return 1;
1171 if (sortDir == 'asc') rows = rows.reverse();
1172 while(obj.treechildren.lastChild) obj.treechildren.removeChild( obj.treechildren.lastChild );
1173 for (var i = 0; i < rows.length; i++) {
1174 obj.treechildren.appendChild( rows[i].node );
1177 obj.error.standard_unexpected_error_alert('sorting',E);
1179 setTimeout(function(){ obj.on_all_fleshed = null; },0);
1181 obj.full_retrieve();
1183 obj.error.standard_unexpected_error_alert('pre sorting', E);
1188 dump('exiting util.list.js\n');