refactoring brapi json responses
[sgn.git] / js / CXGN / List.js
blobc5cb8dbd5e3f02d1b6ec6baee414db18efa682ee
2 /*
4 =head1 NAME
6 CXGN.List - a javascript library to implement the lists on the SGN platform
8 =head1 DESCRIPTION
10 There are two important list functions in this library, listed below. All other functions should be considered private and/or deprecated.
13 * addToListMenu(listMenuDiv, dataDiv)
15 this function will generate a select of all available lists and allow the content to be added to a list (from a search, etc). The first parameter is the id of the div tag where the menu should be drawn. The second parameter is the div that contains the data to be added. This can be a textfield, a div or span tag, or a multiple select tag.
17 * pasteListMenu(divName, menuDiv, buttonName)
19 this will generate an html select box of all the lists, and a "paste" button, to paste into a textarea (typically). The divName is the id of the textarea, the menuDiv is the id where the paste menu should be placed.
22 Public List object functions
24 * listSelect(divName, types)
26 will create an html select with id and name 'divName'. Optionally, a list of types can be specified that will limit the menu to the respective types.
28 Usage:
29 You have to instantiate the list object first:
31 var lo = new CXGN.List(); var s = lo.listSelect('myseldiv', [ 'trials' ]);
34 * validate(list_id, type, non_interactive)
36 * transform(list_id, new_type)
39 =head1 AUTHOR
41 Lukas Mueller <lam87@cornell.edu>
43 =cut
47 //JSAN.use('jqueryui');
49 if (!CXGN) CXGN = function () { };
51 CXGN.List = function () {
52     this.list = [];
56 CXGN.List.prototype = {
58     // Return the data as a straight list
59     //
60     getList: function(list_id) {
61         var list;
63         jQuery.ajax( {
64             url: '/list/contents/'+list_id,
65             async: false,
66             success: function(response) {
67                 if (response.error) {
68                     //document.write(response.error);
69                 }
70                 else {
71                     list = response;
72                 }
73             },
74             error: function(response) {
75                 alert("An error occurred.");
76             }
77         });
78         return list;
80     },
83     // this function also returns some metadata about
84     // list, namely its type.
85     //
86     getListData: function(list_id) {
87         var list;
89         jQuery.ajax( {
90             url: '/list/data',
91             async: false,
92             data: { 'list_id': list_id },
93             success: function(response) {
94                 if (response.error) {
95                     alert(response.error);
96                 }
97                 else {
98                     list = response;
99                 }
100             }
101         });
103         return list;
104     },
106     getListType: function(list_id) {
107         var type;
109         jQuery.ajax( {
110             url: '/list/type/'+list_id,
111             async: false,
112             success: function(response) {
113                 if (response.error) {
114                     alert(response.error);
115                 }
116                 else {
117                     type = response.list_type;
118                     return type;
119                 }
120             },
121             error: function () {
122                 alert('An error occurred. Cannot determine type. ');
123             }
125         });
126         return type;
127     },
129     setListType: function(list_id, type) {
131         jQuery.ajax( {
132             url: '/list/type/'+list_id+'/'+type,
133             async: false,
134             success: function(response) {
135                 if (response.error) {
136                     alert(response.error);
137                 }
138                 else {
139                     //alert('Type of list '+list_id+' set to '+type);
140                 }
141             }
142         });
143     },
146     allListTypes: function() {
147         var types;
148         jQuery.ajax( {
149             url: '/list/alltypes',
150             async: false,
151             success: function(response) {
152                 if (response.error) {
153                     alert(response.error);
154                 }
155                 else {
156                     types = response;
157                 }
158             }
159         });
160         return types;
162     },
164     typesHtmlSelect: function(list_id, html_select_id, selected) {
165         var types = this.allListTypes();
166         var html = '<select class="form-control" id="'+html_select_id+'" onchange="javascript:changeListType(\''+html_select_id+'\', '+list_id+');" >';
167         html += '<option name="null">(none)</option>';
168         for (var i=0; i<types.length; i++) {
169             var selected_html = '';
170             if (types[i][1] == selected) {
171                 selected_html = ' selected="selected" ';
172             }
173             html += '<option name="'+types[i][1]+'"'+selected_html+'>'+types[i][1]+'</option>';
174         }
175         html += '</select>';
176         return html;
177     },
179     newList: function(name) {
180         var oldListId = this.existsList(name);
181         var newListId = 0;
183         if (name == '') {
184             alert('Please provide a name for the new list.');
185             return 0;
186         }
188         if (oldListId === null) {
189             jQuery.ajax( {
190                 url: '/list/new',
191                 async: false,
192                 data: { 'name': name },
193                 success: function(response) {
194                     if (response.error) {
195                         alert(response.error);
196                     }
197                     else {
198                         newListId=response.list_id;
199                     }
200                 }
201             });
202             return newListId;
203         }
204         else {
205             alert('A list with name "'+ name + '" already exists. Please choose another list name.');
206             return 0;
207         }
208         alert("An error occurred. Cannot create new list right now.");
209         return 0;
210     },
212     availableLists: function(list_type) {
213         var lists = [];
214         jQuery.ajax( {
215             url: '/list/available',
216             data: { 'type': list_type },
217             async: false,
218             success: function(response) {
219                 if (response.error) {
220                     //alert(response.error);  //do not alert here
221                 }
222                 lists = response;
223             },
224             error: function(response) {
225                 alert("An error occurred");
226             }
227         });
228         return lists;
229     },
231     publicLists: function(list_type) {
232         var lists = [];
233         jQuery.ajax( {
234             url: '/list/available_public',
235             data: { 'type': list_type },
236             async: false,
237             success: function(response) {
238                 if (response.error) {
239                     alert(response.error);
240                 }
241                 lists = response;
242             },
243             error: function(response) {
244                 alert("An error occurred");
245             }
246         });
247         return lists;
248     },
250     //return the newly created list_item_id or 0 if nothing was added
251     //(due to duplicates)
252     addItem: function(list_id, item) {
253         var exists_item_id = this.existsItem(list_id,item);
254         if (exists_item_id ===0 ) {
255             jQuery.ajax( {
256                 async: false,
257                 url: '/list/item/add',
258                 data:  { 'list_id': list_id, 'element': item },
259                 success: function(response) {
260                     if (response.error) {
261                         alert(response.error);
262                         return 0;
263                     }
264                 }
265             });
266             var new_list_item_id = this.existsItem(list_id,item);
267             return new_list_item_id;
268         }
269         else { return 0; }
270     },
272     addBulk: function(list_id, items) {
273         var elements = items.join("\t");
275         var count;
276         jQuery.ajax( {
277             async: false,
278             method: 'POST',
279             url: '/list/add/bulk',
280             data:  { 'list_id': list_id, 'elements': elements },
281             success: function(response) {
282                 if (response.error) {
283                     alert(response.error);
284                 }
285                 else {
286                     if (response.duplicates) {
287                         alert("The following items are already in the list and were not added: "+response.duplicates.join(", "));
288                     }
289                     count = response.success;
290                 }
291             },
292             error: function(response) {
293                 alert("ERROR: "+response);
294             }
295         });
296         return count;
297     },
299     removeItem: function(list_id, item_id) {
300         jQuery.ajax( {
301             async: false,
302             url: '/list/item/remove',
303             data: { 'list_id': list_id, 'item_id': item_id }
304         });
305     },
307     updateItem: function(list_id, item_id, content) {
308         jQuery.ajax( {
309             async: false,
310             url: '/list/item/update',
311             data: { 'list_id': list_id, 'item_id': item_id, 'content':content }
312         });
313     },
315     deleteList: function(list_id) {
316         jQuery.ajax( {
317             url: '/list/delete',
318             async: false,
319             data: { 'list_id': list_id }
320         });
321     },
323     renderLists: function(div) {
324         var lists = this.availableLists();
325         var html = '';
326         html = html + '<div class="input-group"><input id="add_list_input" type="text" class="form-control" placeholder="Create New List" /><span class="input-group-btn"><button class="btn btn-primary" type="button" id="add_list_button" value="new list">New List</button></span></div><br/>';
328         if (lists.length===0) {
329             html = html + "None";
330             jQuery('#'+div+'_div').html(html);
331         }
333         html += '<table class="table table-hover table-condensed">';
334         html += '<thead><tr><th>&nbsp;</th><th>List Name</th><th>Count</th><th>Type</th><th colspan="4">Actions</th></tr></thead><tbody>';
335         for (var i = 0; i < lists.length; i++) {
336             html += '<tr><td><input type="checkbox" id="list_select_checkbox_'+lists[i][0]+'" name="list_select_checkbox" value="'+lists[i][0]+'"/></td>';
337             html += '<td><b>'+lists[i][1]+'</b></td>';
338             html += '<td>'+lists[i][3]+'</td>';
339             html += '<td>'+lists[i][5]+'</td>';
340             html += '<td><a title="View" id="view_list_'+lists[i][1]+'" href="javascript:showListItems(\'list_item_dialog\','+lists[i][0]+')"><span class="glyphicon glyphicon-th-list"></span></a></td>';
341             html += '<td><a title="Delete" id="delete_list_'+lists[i][1]+'" href="javascript:deleteList('+lists[i][0]+')"><span class="glyphicon glyphicon-remove"></span></a></td>';
342             html += '<td><a target="_blank" title="Download" id="download_list_'+lists[i][1]+'" href="/list/download?list_id='+lists[i][0]+'"><span class="glyphicon glyphicon-arrow-down"></span></a></td>';
343             if (lists[i][6] == 0){
344                 html += '<td><a title="Make Public" id="share_list_'+lists[i][1]+'" href="javascript:togglePublicList('+lists[i][0]+')"><span class="glyphicon glyphicon-share-alt"></span></a></td></tr>';
345             } else if (lists[i][6] == 1){
346                 html += '<td><a title="Make Private" id="share_list_'+lists[i][1]+'" href="javascript:togglePublicList('+lists[i][0]+')"><span class="glyphicon glyphicon-ban-circle"></span></a></td></tr>';
347             }
348         }
349         html = html + '</tbody></table>';
350         html += '<div id="list_group_select_action"></div>';
352         jQuery('#'+div+'_div').html(html);
354         jQuery('#add_list_button').click(function() {
355             var lo = new CXGN.List();
357             var name = jQuery('#add_list_input').val();
359             lo.newList(name);
360             lo.renderLists(div);
361         });
363         jQuery('#view_public_lists_button').click(function() {
364             jQuery('#public_list_dialog').modal('show');
365             var lo = new CXGN.List();
366             lo.renderPublicLists('public_list_dialog_div');
367         });
369         jQuery("input[name='list_select_checkbox']").click(function() {
370             var total=jQuery("input[name='list_select_checkbox']:checked").length;
371             var list_group_select_action_html='';
372             if (total == 0) {
373                 list_group_select_action_html += '';
374             } else {
375                 var selected = [];
376                 jQuery("input:checkbox:checked").each(function() {
377                     selected.push(jQuery(this).attr('value'));
378                 });
380                 list_group_select_action_html = '<hr><div class="row well well-sm"><div class="col-sm-4">For Selected Lists:</div><div class="col-sm-8">';
381                 if (total == 1) {
382                     list_group_select_action_html += '<a id="delete_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:deleteSelectedListGroup(['+selected+'])">Delete</a>&nbsp;<a id="make_public_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:makePublicSelectedListGroup(['+selected+'])">Make Public</a>&nbsp;<a id="make_private_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:makePrivateSelectedListGroup(['+selected+'])">Make Private</a>';
383                 } else if (total > 1) {
384                     list_group_select_action_html += '<a id="delete_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:deleteSelectedListGroup(['+selected+'])">Delete</a>&nbsp;<a id="make_public_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:makePublicSelectedListGroup(['+selected+'])">Make Public</a>&nbsp;<a id="make_private_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:makePrivateSelectedListGroup(['+selected+'])">Make Private</a><br/><br/><div class="input-group input-group-sm"><input type="text" class="form-control" id="new_combined_list_name" placeholder="New List Name"><span class="input-group-btn"><a id="combine_selected_list_group" class="btn btn-primary btn-sm" style="color:white" href="javascript:combineSelectedListGroup(['+selected+'])">Combine</a></span></div>';
385                 }
386                 list_group_select_action_html += '</div></div>';
387             }
388             jQuery("#list_group_select_action").html(list_group_select_action_html);
389         });
390     },
392     renderPublicLists: function(div) {
393         var lists = this.publicLists();
394         var html = '';
396         html += '<table id="public_list_data_table" class="table table-hover table-condensed">';
397         html += '<thead><tr><th>List Name</th><th>Count</th><th>Type</th><th>Actions</th><th>&nbsp;</th><th>&nbsp;</th></tr></thead><tbody>';
398         for (var i = 0; i < lists.length; i++) {
399             html += '<tr><td><b>'+lists[i][1]+'</b></td>';
400             html += '<td>'+lists[i][3]+'</td>';
401             html += '<td>'+lists[i][5]+'</td>';
402             html += '<td><a title="View" id="view_public_list_'+lists[i][1]+'" href="javascript:showPublicListItems(\'list_item_dialog\','+lists[i][0]+')"><span class="glyphicon glyphicon-th-list"></span></a></td>';
403             html += '<td><a target="_blank" title="Download" id="download_public_list_'+lists[i][1]+'" href="/list/download?list_id='+lists[i][0]+'"><span class="glyphicon glyphicon-arrow-down"></span></a></td>';
404             html += '<td><a title="Copy to Your Lists" id="copy_public_list_'+lists[i][1]+'" href="javascript:copyPublicList('+lists[i][0]+')"><span class="glyphicon glyphicon-plus"></span></a></td>';
405         }
406         html = html + '</tbody></table>';
408         jQuery('#'+div).html(html);
410         jQuery('#public_list_data_table').DataTable({
411             "destroy": true,
412             "columnDefs": [   { "orderable": false, "targets": [3,4,5] }  ]
413         });
414     },
416     listNameById: function(list_id) {
417         lists = this.availableLists();
418         for (var n=0; n<lists.length; n++) {
419             if (lists[n][0] == list_id) { return lists[n][1]; }
420         }
421     },
423     publicListNameById: function(list_id) {
424         lists = this.publicLists();
425         for (var n=0; n<lists.length; n++) {
426             if (lists[n][0] == list_id) { return lists[n][1]; }
427         }
428     },
430     renderItems: function(div, list_id) {
432         var list_data = this.getListData(list_id);
433         var items = list_data.elements;
434         var list_type = list_data.type_name;
435         var list_name = this.listNameById(list_id);
437         var html = '';
438         html += '<table class="table"><tr><td>List ID</td><td id="list_id_div">'+list_id+'</td></tr>';
439         html += '<tr><td>List name:<br/><input type="button" class="btn btn-primary btn-xs" id="updateNameButton" value="Update" /></td>';
440         html += '<td><input class="form-control" type="text" id="updateNameField" size="10" value="'+list_name+'" /></td></tr>';
441         html += '<tr><td>Type:<br/><input id="list_item_dialog_validate" type="button" class="btn btn-primary btn-xs" value="Validate" onclick="javascript:validateList('+list_id+',\'type_select\')" /></td><td>'+this.typesHtmlSelect(list_id, 'type_select', list_type)+'</td></tr>';
442         html += '<tr><td>Add New Items:<br/><button class="btn btn-primary btn-xs" type="button" id="dialog_add_list_item_button" value="Add">Add</button></td><td><textarea id="dialog_add_list_item" type="text" class="form-control" placeholder="Add Item To List" /></textarea></td></tr></table>';
444         html += '<table id="list_item_dialog_datatable" class="table table-condensed table-hover table-bordered"><thead style="display: none;"><tr><th><b>List items</b> ('+items.length+')</th><th>&nbsp;</th></tr></thead><tbody>';
446         for(var n=0; n<items.length; n++) {
447             html = html +'<tr><td id="list_item_toggle_edit_div_'+items[n][0]+'" ><div name="list_item_toggle_edit" data-listitemdiv="list_item_toggle_edit_div_'+items[n][0]+'" data-listitemid="'+items[n][0]+'" data-listitemname="'+items[n][1]+'" >'+ items[n][1] + '</div></td><td><input id="'+items[n][0]+'" type="button" class="btn btn-default btn-xs" value="Remove" /></td></tr>';
448         }
449         html += '</tbody></table>';
451         jQuery('#'+div+'_div').html(html);
453         jQuery('#list_item_dialog_datatable').DataTable({
454             destroy: true,
455             scrollY:        '30vh',
456             scrollCollapse: true,
457             paging:         false,
458         });
460         for (var n=0; n<items.length; n++) {
461             var list_item_id = items[n][0];
463             jQuery('#'+items[n][0]).click(
464                 function() {
465                     var lo = new CXGN.List();
466                     var i = lo.availableLists();
468                     lo.removeItem(list_id, this.id );
469                     lo.renderItems(div, list_id);
470                     lo.renderLists('list_dialog');
471                 });
472         }
474         jQuery('#dialog_add_list_item_button').click(
475             function() {
476                 addMultipleItemsToList('dialog_add_list_item', list_id);
477                 var lo = new CXGN.List();
478                 lo.renderItems(div, list_id);
479             }
480         );
482         jQuery('#updateNameButton').click(
483             function() {
484                 var lo = new CXGN.List();
485                 var new_name =  jQuery('#updateNameField').val();
486                 var list_id = jQuery('#list_id_div').html();
487                 lo.updateName(list_id, new_name);
488                 alert("Changed name to "+new_name+" for list id "+list_id);
489             }
490         );
492         jQuery('div[name="list_item_toggle_edit"]').click(function() {
493             var list_item_id = jQuery(this).data('listitemid');
494             var list_item_name = jQuery(this).data('listitemname');
495             var list_item_div = jQuery(this).data('listitemdiv');
496             var list_item_edit_html = '<div class="input-group"><input type="text" class="form-control" value="'+list_item_name+'" placeholder="'+list_item_name+'" id="list_item_edit_input_'+list_item_id+'" data-listitemid="'+list_item_id+'" /><span class="input-group-btn"><button class="btn btn-default" type="button" name="list_item_edit_submit" data-inputid="list_item_edit_input_'+list_item_id+'">Ok</button></span></div>';
497             jQuery("#"+list_item_div).empty().html(list_item_edit_html);
498         });
500         jQuery(document).on('click', 'button[name="list_item_edit_submit"]', function() {
501             var lo = new CXGN.List();
502             var list_id = jQuery('#list_id_div').html();
503             var input_id = jQuery(this).data('inputid');
504             lo.updateItem(list_id, jQuery("#"+input_id).data('listitemid'), jQuery("#"+input_id).val());
505             lo.renderItems(div, list_id);
506         });
507     },
509     renderPublicItems: function(div, list_id) {
510         var list_data = this.getListData(list_id);
511         var items = list_data.elements;
512         var list_type = list_data.type_name;
513         var list_name = this.publicListNameById(list_id);
515         var html = '';
516         html += '<table class="table"><tr><td>List ID</td><td id="list_id_div">'+list_id+'</td></tr>';
517         html += '<tr><td>List name:</td>';
518         html += '<td>'+list_name+'</td></tr>';
519         html += '<tr><td>Type:</td><td>'+list_type+'</td></tr>';
520         html += '</table>';
521         html += '<table id="public_list_item_dialog_datatable" class="table table-condensed table-hover table-bordered"><thead style="display: none;"><tr><th><b>List items</b> ('+items.length+')</th></tr></thead><tbody>';
522         for(var n=0; n<items.length; n++) {
523             html = html +'<tr><td>'+ items[n][1] + '</td></tr>';
524         }
525         html += '</tbody></table>';
527         jQuery('#'+div+'_div').html(html);
529         jQuery('#public_list_item_dialog_datatable').DataTable({
530             destroy: true,
531             scrollY:        '30vh',
532             scrollCollapse: true,
533             paging:         false,
534         });
535     },
537     existsList: function(name) {
538         var list_id = 0;
539         jQuery.ajax( {
540             url: '/list/exists',
541             async: false,
542             data: { 'name': name },
543             success: function(response) {
544                 list_id = response.list_id;
545             }
546         });
547         return list_id;
548     },
550     existsItem: function(list_id, name) {
551         var list_item_id =0;
552         jQuery.ajax( {
553             url: '/list/exists_item',
554             async: false,
555             data: { 'list_id' : list_id, 'name':name },
556             success: function(response) {
557                 list_item_id = response.list_item_id;
558             }
559         });
560         return list_item_id;
561     },
563     addToList: function(list_id, text) {
564         if (! text) {
565             return;
566         }
567         var list = text.split("\n");
568         var duplicates = [];
570         var info = this.addBulk(list_id, list);
572         return info;
574     },
576     addCrossProgenyToList: function(list_id, text) {
577         if (! text) {
578             return;
579         }
580         var list = text.split("\n");
581         list = list.filter(function(n){ return n != '' });
582         console.log(list);
583         var addeditems;
584         jQuery.ajax( {
585             url: '/list/add_cross_progeny',
586             async: false,
587             data: { 'list_id':list_id, 'cross_id_list' : JSON.stringify(list) },
588             success: function(response) {
589                 console.log(response);
590                 addeditems = response.success.count;
591             }
592         });
593         //var info = this.addBulk(list_id, list);
595         return addeditems;
596     },
598     /* listSelect: Creates an html select with lists of requested types.
600        Parameters:
601          div_name: The div_name where the select should appear
602          types: a list of list types that should be listed in the menu
603          add_empty_element: text. if present, add an empty element with the
604            provided text as description
605     */
607     listSelect: function(div_name, types, empty_element, refresh) {
608         var lists = new Array();
610         if (types) {
611             for (var n=0; n<types.length; n++) {
612                 var more = this.availableLists(types[n]);
613                 if (more) {
614                     for (var i=0; i<more.length; i++) {
615                         lists.push(more[i]);
616                     }
617                 }
618             }
619         }
620         else {
621             lists = this.availableLists();
622         }
624         var html = '<select class="form-control input-sm" id="'+div_name+'_list_select" name="'+div_name+'_list_select" >';
625         if (empty_element) {
626             html += '<option value="">'+empty_element+'</option>\n';
627         }
628         for (var n=0; n<lists.length; n++) {
629             html += '<option value='+lists[n][0]+'>'+lists[n][1]+'</option>';
630         }
631   if (refresh) {
632     if (types.length > 1) { types = types.join(',') };
633           html = '<div class="input-group">'+html+'</select><span class="input-group-btn"><button class="btn btn-default" type="button" id="'+div_name+'_list_refresh" title="Refresh lists" onclick="refreshListSelect(\''+div_name+'_list_select\',\''+types+'\',\'Options refreshed.\')"><span class="glyphicon glyphicon-refresh" aria-hidden="true"></span></button></span></div>';
634     return html;
635   }
636   else {
637     html = html + '</select>';
638         return html;
639   }
642     updateName: function(list_id, new_name) {
643         jQuery.ajax( {
644             url: '/list/name/update',
645             async: false,
646             data: { 'name' : new_name, 'list_id' : list_id },
647             success: function(response) {
648                 if (response.error) {
649                     alert(response.error);
650                     return;
651                 }
652                 else {
653                     alert("The name of the list was changed to "+new_name);
654                 }
655             },
656             error: function(response) { alert("An error occurred."); }
657         });
658         this.renderLists('list_dialog');
659     },
661     validate: function(list_id, type, non_interactive) {
662         var missing = new Array();
663         var error = 0;
664         jQuery.ajax( {
665             url: '/list/validate/'+list_id+'/'+type,
666             async: false,
667             success: function(response) {
668                 //console.log(response);
669                 if (response.error) {
670                     alert(response.error);
671                 } else {
672                     missing = response.missing;
673                 }
674             },
675             error: function(response) {
676                 alert("An error occurred while validating the list "+list_id);
677                 error=1;
678             }
679         });
681         if (error === 1 ) { return; }
683         if (missing.length==0) {
684             if (!non_interactive) { alert("This list passed validation."); }
685             return 1;
686         } else {
688             if (type == 'accessions') {
689                 jQuery("#validate_accession_error_display tbody").html('');
691                 var missing_accessions_html = "<div class='well well-sm'><h3>Add the missing accessions to a list</h3><div id='validate_stock_missing_accessions' style='display:none'></div><div id='validate_stock_add_missing_accessions'></div><hr><h4>Go to <a href='/breeders/accessions'>Manage Accessions</a> to add these new accessions.</h4></div><br/>";
694                 jQuery("#validate_stock_add_missing_accessions_html").html(missing_accessions_html);
696                 var missing_accessions_vals = '';
697                 for(var i=0; i<missing.length; i++) {
698                     missing_accessions_vals = missing_accessions_vals + missing[i] + '\n';
699                 }
701                 jQuery("#validate_stock_missing_accessions").html(missing_accessions_vals);
702                 addToListMenu('validate_stock_add_missing_accessions', 'validate_stock_missing_accessions', {
703                     selectText: true,
704                     listType: 'accessions'
705                 });
707                 jQuery("#validate_accession_error_display tbody").append(missing.join(","));
708                 jQuery('#validate_accession_error_display').modal("show");
710                 //alert("List validation failed. Elements not found: "+ missing.join(","));
711                 //return 0;
712             } else {
713                 alert('List did not pass validation because of these items: '+missing.join(", "));
714             }
715             return;
716         }
717     },
719     transform: function(list_id, transform_name) {
720         var transformed = new CXGN.List();
721         var ajaxResponse = [];
722         jQuery.ajax( {
723             url: '/list/transform/'+list_id+'/'+transform_name,
724             async: false,
725             success: function(response) {
726                 if (response.error) {
727                     alert(response.error);
728                 }
729                 else {
730                     ajaxResponse = response;
731                     //console.log("transformed="+ajaxResponse);
732                 }
733             },
734             error: function(response) { alert("An error occurred while validating the list "+list_id); }
735         });
736         return ajaxResponse.transform;
737     },
739     transform2Ids: function(list_id, data) {
740         if (data === undefined) var data = this.getListData(list_id);
741         //console.log("data ="+JSON.stringify(data));
742         var list_type = data.type_name;
744         var new_type;
745         switch (list_type)
746         {
747           case "traits":
748               new_type = 'traits_2_trait_ids';
749               break;
750           case "locations":
751               new_type = 'locations_2_location_ids';
752               break;
753           case "trials":
754           case "breeding_programs":
755               new_type = 'projects_2_project_ids';
756               break;
757           case "accessions":
758               new_type = 'accessions_2_accession_ids';
759               break;
760           case "plots":
761               new_type = 'plots_2_plot_ids';
762               break;
763           default:
764               return { 'error' : "cannot convert the list because of unknown type" };
765         }
766         //if (window.console) console.log("new type = "+new_type);
767         var transformed = this.transform(list_id, new_type);
768         //if (window.console) console.log("transformed="+JSON.stringify(transformed));
769         return transformed;
771     }
774 function setUpLists() {
775     jQuery("button[name='lists_link']").click(
776         function() { show_lists(); }
777     );
781 function show_lists() {
782     jQuery('#list_dialog').modal("show");
784     var l = new CXGN.List();
785     l.renderLists('list_dialog');
788 /* deprecated */
789 function pasteListMenu (div_name, menu_div, button_name) {
790     var lo = new CXGN.List();
792     var html='';
794     if (button_name === undefined) {
795         button_name = 'paste';
796     }
798     html = lo.listSelect(div_name);
799     html = html + '<button class="btn btn-info btn-sm" type="button" value="'+button_name+'" onclick="javascript:pasteList(\''+div_name+'\')" >'+button_name+'</button>';
801     jQuery('#'+menu_div).html(html);
804 function pasteList(div_name) {
805     var lo = new CXGN.List();
806     var list_id = jQuery('#'+div_name+'_list_select').val();
807         console.log(list_id);
808     var list = lo.getList(list_id);
809         console.log(list);
810     // textify list
811     var list_text = '';
812     for (var n=0; n<list.length; n++) {
813       list_text = list_text + list[n]+"\r\n";
814     }
815         console.log(list_text);
816     jQuery('#'+div_name).val(list_text);
817   }
819   /* refreshListSelect: refreshes an html select with lists of requested types.
821      Parameters:
822        div_name: The div_name where the select should appear
823        types: a list of list types that should be listed in the menu
824        add_empty_element: text. if present, add an empty element with the
825          provided text as description
826   */
828   function refreshListSelect(div_name, types, empty_element) {
829     var lo = new CXGN.List();
830     var lists = new Array();
831     var types = types.split(",");
832     //console.log("types = "+types);
833     if (types.length > 0) {
834         for (var n=0; n<types.length; n++) {
835           //console.log("retrieving lists of type: "+types[n]+"\n");
836           var more = lo.availableLists(types[n]);
837           if (more) {
838             for (var i=0; i<more.length; i++) {
839               lists.push(more[i]);
840             }
841           }
842         }
843     }
844     else {
845         lists = lo.availableLists();
846     }
848     var html;
849     if (empty_element) {
850         html += '<option value="">'+empty_element+'</option>\n';
851           }
852     for (var n=0; n<lists.length; n++) {
853         html += '<option value='+lists[n][0]+'>'+lists[n][1]+'</option>';
854     }
855     jQuery('#'+div_name).html(html);
857   }
860   addToListMenu
862   Parameters:
863   * listMenuDiv - the name of the div where the menu will be displayed
864   * dataDiv - the div from which the data will be copied (can be a div, textarea, or html select
865   * options - optional hash with the following keys:
866     - selectText: if the dataDiv is an html select and selectText is true, the text and not the value will be copied into the list
867     - listType: the type of lists to display in the menu
868     - typesSourceDiv: obtain the type from this source div
873 function addToListMenu(listMenuDiv, dataDiv, options) {
874     var lo = new CXGN.List();
876     var html;
877     var selectText;
878     var listType;
879     var typeSourceDiv;
880     var type;
881     var addition_type;
883     if (options) {
884         if (options.selectText) {
885             selectText = options.selectText;
886         }
887         if (options.typeSourceDiv) {
888             var sourcetype = getData(options.typeSourceDiv, selectText);
889             if (sourcetype) {
890                 type = sourcetype.replace(/(\n|\r)+$/, '');
891             }
892         }
893         if (options.listType) {
894             type = options.listType;
895         }
896         if (options.additionType) {
897             addition_type = options.additionType;
898         }
899     }
901     html = '<div class="row"><div class="col-sm-6" style="margin-right:0px; padding-right:0px;"><input class="form-control input-sm" type="text" id="'+dataDiv+'_new_list_name" placeholder="New list..." />';
902     html += '</div><div class="col-sm-6" style="margin-left:0px; padding-left:0px; margin-right:0px; padding-right:0px;"><input type="hidden" id="'+dataDiv+'_addition_type" value="'+addition_type+'" /><input type="hidden" id="'+dataDiv+'_list_type" value="'+type+'" />';
903     html += '<input class="btn btn-primary btn-sm" id="'+dataDiv+'_add_to_new_list" type="button" value="add to new list" /></div></div><br />';
905     html += '<div class="row"><div class="col-sm-6" style="margin-right:0px; padding-right:0px;">'+lo.listSelect(dataDiv, [ type ]);
907     html += '</div><div class="col-sm-6" style="margin-left:0px; padding-left:0px; margin-right:0px; padding-right:0px;"><input class="btn btn-primary btn-sm" id="'+dataDiv+'_button" type="button" value="add to list" /></div></div>';
909     jQuery('#'+listMenuDiv).html(html);
911     var list_id = 0;
913     jQuery('#'+dataDiv+'_add_to_new_list').click( function() {
914         var lo = new CXGN.List();
915         var new_name = jQuery('#'+dataDiv+'_new_list_name').val();
916         var type = jQuery('#'+dataDiv+'_list_type').val();
917         var addition_type = jQuery('#'+dataDiv+'_addition_type').val();
919         var data = getData(dataDiv, selectText);
920         list_id = lo.newList(new_name);
921         if (list_id > 0) {
922             var elementsAdded;
923             if (addition_type == 'cross_progeny') {
924                 elementsAdded = lo.addCrossProgenyToList(list_id, data);
925             } else {
926                 elementsAdded = lo.addToList(list_id, data);
927             }
928             if (type) {
929                 lo.setListType(list_id, type);
930             }
931             alert("Added "+elementsAdded+" list elements to list "+new_name+" and set type to "+type);
932         }
933     });
935     jQuery('#'+dataDiv+'_button').click(
936         function() {
937             var data = getData(dataDiv, selectText);
938             list_id = jQuery('#'+dataDiv+'_list_select').val();
939             var lo = new CXGN.List();
940             var elementsAdded = lo.addToList(list_id, data);
942             alert("Added "+elementsAdded+" list elements");
943             return list_id;
944         }
945     );
951 function getData(id, selectText) {
952     var divType = jQuery("#"+id).get(0).tagName;
953     var data;
955     if (divType == 'DIV' || divType =='SPAN' || divType === undefined) {
956         data = jQuery('#'+id).html();
957     }
958     if (divType == 'SELECT' && selectText) {
959         if (jQuery.browser.msie) {
960             // Note: MS IE unfortunately removes all whitespace
961             // in the jQuery().text() call. Program it out...
962             //
963             var selectbox = document.getElementById(id);
964             var datalist = new Array();
965             for (var n=0; n<selectbox.length; n++) {
966                 if (selectbox.options[n].selected) {
967                     var x=selectbox.options[n].text;
968                     datalist.push(x);
969                 }
970             }
971             data = datalist.join("\n");
972             //alert("data:"+data);
974         }
975         else {
976             data = jQuery('#'+id+" option:selected").text();
977         }
979     }
980     if (divType == 'SELECT' && ! selectText) {
981         var return_data = jQuery('#'+id).val();
983         if (return_data instanceof Array) {
984             data = return_data.join("\n");
985         }
986         else {
987             data = return_data;
988         }
989     }
990     if (divType == 'TEXTAREA') {
991         data = jQuery('textarea#'+id).val();
992     }
993     return data;
997 /* deprecated */
998 function addTextToListMenu(div) {
999     var lo = new CXGN.List();
1000     var html = lo.listSelect(div);
1001     html = html + '<input id="'+div+'_button" type="button" value="add to list" />';
1003     document.write(html);
1005     jQuery('#'+div+'_button').click(
1006         function() {
1007             var text = jQuery('textarea#div').val();
1008             var list_id = jQuery('#'+div+'_list_select').val();
1009             lo.addToList(list_id, text);
1010             lo.renderLists('list_dialog');
1011         }
1012     );
1015 /* deprecated */
1016 function addSelectToListMenu(div) {
1017     var lo = new CXGN.List();
1018     var html = lo.listSelect(div);
1019     html = html + '<input id="'+div+'_button" type="button" value="add to list" />';
1021     document.write(html);
1023     jQuery('#'+div+'_button').click(
1024         function() {
1025             var selected_items = jQuery('#'+div).val();
1026             var list_id = jQuery('#'+div+'_list_select').val();
1027             addArrayToList(selected_items, list_id);
1028             lo.renderLists('list_dialog');
1029         }
1030     );
1034 /* deprecated */
1035 // add the text in a div to a list
1036 function addDivToList(div_name) {
1037     var list_id = jQuery('#'+div_name+'_list_select').val();
1038     var lo = new CXGN.List();
1039     var list = jQuery('#'+div_name).val();
1040     var items = list.split("\n");
1042     for(var n=0; n<items.length; n++) {
1043         var added = lo.addItem(list_id, items[n]);
1044         if (added > 0) { }
1045     }
1048 /* deprecated */
1049 function addTextToList(div, list_id) {
1050     var lo = new CXGN.List();
1051     var item = jQuery('#'+div).val();
1052     var id = lo.addItem(list_id, item);
1053     if (id == 0) {
1054         alert('Item "'+item+'" was not added because it already exists');
1055     }
1056     lo.renderLists('list_dialog');
1059 /* deprecated */
1060 function addMultipleItemsToList(div, list_id) {
1061     var lo = new CXGN.List();
1062     var content = jQuery('#'+div).val();
1063     if (content == '') {
1064         alert("No items - Please enter items to add to the list.");
1065 return;
1066     }
1067 //    var items = content.split("\n");
1069   //  var duplicates = new Array();
1070     var items = content.split("\n");
1071     lo.addBulk(list_id, items);
1072    // for (var n=0; n<items.length; n++) {
1073 //      var id = lo.addItem(list_id, items[n]);
1074 //      if (id == 0) {
1075 //          duplicates.push(items[n]);
1076 //      }
1077   //  }
1078     //if (duplicates.length >0) {
1079 //      alert("The following items were not added because they are already in the list: "+ duplicates.join(", "));
1080   //  }
1081 //lo.renderLists('list_dialog');
1084 /* deprecated */
1085 function addArrayToList(items, list_id) {
1086 var lo = new CXGN.List();
1087    var duplicates = new Array();
1088     for (var n=0; n<items.length; n++) {
1089         var id = lo.addItem(list_id, items[n]);
1090         if (id == 0) {
1091             duplicates.push(items[n]);
1092         }
1093     }
1094     if (duplicates.length >0) {
1095         alert("The following items were not added because they are already in the list: "+ duplicates.join(", "));
1096     }
1099 function deleteList(list_id) {
1100     var lo = new CXGN.List();
1101     var list_name = lo.listNameById(list_id);
1102     if (confirm('Delete list "'+list_name+'"? (ID='+list_id+'). This cannot be undone.')) {
1103         lo.deleteList(list_id);
1104         lo.renderLists('list_dialog');
1105         alert('Deleted list '+list_name);
1106     }
1109 function togglePublicList(list_id) {
1110     jQuery.ajax({
1111         "url": "/list/public/toggle",
1112         "type": "POST",
1113         "data": {'list_id': list_id},
1114         success: function(r) {
1115             var lo = new CXGN.List();
1116             if (r.error) {
1117                 alert(r.error);
1118             } else if (r.r == 1) {
1119                 alert("List set to Private");
1120             } else if (r.r == 0) {
1121                 alert("List set to Public");
1122             }
1123             lo.renderLists('list_dialog');
1124         },
1125         error: function() {
1126             alert("Error Setting List to Public! List May Not Exist.");
1127         }
1128     });
1129     var lo = new CXGN.List();
1130     lo.renderLists('list_dialog');
1133 function makePublicList(list_id) {
1134     jQuery.ajax({
1135         "url": "/list/public/true",
1136         "type": "POST",
1137         "data": {'list_id': list_id},
1138         success: function(r) {
1139             var lo = new CXGN.List();
1140             if (r.error) {
1141                 alert(r.error);
1142             }
1143         },
1144         error: function() {
1145             alert("Error Setting List to Public! List May Not Exist.");
1146         }
1147     });
1150 function makePrivateList(list_id) {
1151     jQuery.ajax({
1152         "url": "/list/public/false",
1153         "type": "POST",
1154         "data": {'list_id': list_id},
1155         success: function(r) {
1156             var lo = new CXGN.List();
1157             if (r.error) {
1158                 alert(r.error);
1159             }
1160         },
1161         error: function() {
1162             alert("Error Setting List to Private! List May Not Exist.");
1163         }
1164     });
1167 function copyPublicList(list_id) {
1168     jQuery.ajax({
1169         "url": "/list/public/copy",
1170         "type": "POST",
1171         "data": {'list_id': list_id},
1172         success: function(r) {
1173             if (r.error) {
1174                 alert(r.error);
1175             } else if (r.success == 'true') {
1176                 alert("Public List Copied to Your Lists.");
1177             }
1178         },
1179         error: function() {
1180             alert("Error Copying Public List! List May Not Exist.");
1181         }
1182     });
1183     var lo = new CXGN.List();
1184     lo.renderLists('list_dialog');
1187 function deleteItemLink(list_item_id) {
1188     var lo = new CXGN.List();
1189     lo.deleteItem(list_item_id);
1190     lo.renderLists('list_dialog');
1193 function working_modal_show() {
1194     jQuery("#working_modal").modal('show');
1197 function working_modal_hide() {
1198     jQuery("#working_modal").modal('hide');
1201 function showListItems(div, list_id) {
1202     working_modal_show();
1203     var l = new CXGN.List();
1204     l.renderItems(div, list_id);
1205     jQuery('#'+div).modal("show");
1206     working_modal_hide();
1209 function showPublicListItems(div, list_id) {
1210     var l = new CXGN.List();
1211     jQuery('#'+div).modal("show");
1212     l.renderPublicItems(div, list_id);
1215 function addNewList(div_id) {
1216     var lo = new CXGN.List();
1217     var name = jQuery('#'+div_id).val();
1219     if (name == '') {
1220         alert("Please specify a name for the list.");
1221         return;
1222     }
1224     var list_id = lo.existsList(name);
1225     if (list_id > 0) {
1226         alert('The list '+name+' already exists. Please choose another name.');
1227         return;
1228     }
1229     lo.newList(name);
1230     lo.renderLists('list_item_dialog');
1233 function changeListType(html_select_id, list_id) {
1234     var type = jQuery('#'+html_select_id).val();
1235     var l = new CXGN.List();
1236     l.setListType(list_id, type);
1237     l.renderLists('list_dialog');
1241    validateList - check if all the elements in a list are of the correct type
1243    Parameters:
1244    * list_id: the id of the list
1245    * html_select_id: the id of the html select containing the type list
1249 function validateList(list_id, html_select_id) {
1250     var lo = new CXGN.List();
1251     var type = jQuery('#'+html_select_id).val();
1252     lo.validate(list_id, type);
1255 function deleteSelectedListGroup(list_ids) {
1256     var arrayLength = list_ids.length;
1257     if (confirm('Delete the selected lists? This cannot be undone.')) {
1258         for (var i=0; i<arrayLength; i++) {
1259             var lo = new CXGN.List();
1260             lo.deleteList(list_ids[i]);
1261         }
1262         lo.renderLists('list_dialog');
1263     }
1266 function makePublicSelectedListGroup(list_ids) {
1267     var arrayLength = list_ids.length;
1268     if (confirm('Make selected lists public?')) {
1269         for (var i=0; i<arrayLength; i++) {
1270             makePublicList(list_ids[i]);
1271         }
1272         var lo = new CXGN.List();
1273         lo.renderLists('list_dialog');
1274     }
1277 function makePrivateSelectedListGroup(list_ids) {
1278     var arrayLength = list_ids.length;
1279     if (confirm('Make selected lists private?')) {
1280         for (var i=0; i<arrayLength; i++) {
1281             makePrivateList(list_ids[i]);
1282         }
1283         var lo = new CXGN.List();
1284         lo.renderLists('list_dialog');
1285     }
1288 function combineSelectedListGroup(list_ids) {
1289     var arrayLength = list_ids.length;
1290     var list_name = jQuery('#new_combined_list_name').val();
1291     if (confirm('Combine selected lists into a new list called '+list_name+'?')) {
1292         var arrayItems = [];
1293         var lo = new CXGN.List();
1294         var first_list_type = lo.getListType(list_ids[0]);
1295         var same_list_types = true;
1296         for (var i=0; i<arrayLength; i++) {
1297             var list_type = lo.getListType(list_ids[i]);
1298             if (list_type != first_list_type) {
1299                 same_list_types = false;
1300                 if (!confirm('Are you sure you want to combine these list types: '+first_list_type+' and '+list_type)) {
1301                     return;
1302                 }
1303             }
1304         }
1305         var new_list_id = lo.newList(list_name);
1306         if (same_list_types == true) {
1307             lo.setListType(new_list_id, first_list_type);
1308         }
1309         for (var i=0; i<arrayLength; i++) {
1310             list = lo.getListData(list_ids[i]);
1311             var numElements = list.elements.length;
1312             for (var j=0; j<numElements; j++) {
1313                 arrayItems.push(list.elements[j][1]);
1314             }
1315         }
1316         lo.addBulk(new_list_id, arrayItems);
1317         lo.renderLists('list_dialog');
1318     }