Bug 27128: (bug 25728 follow-up) Don't prefill av's code
[koha.git] / koha-tmpl / intranet-tmpl / prog / js / cataloging.js
1 /* exported openAuth ExpandField CloneField CloneSubfield UnCloneField CloneItemSubfield CheckMandatorySubfields */
2
3 /*
4  * Unified file for catalogue edition
5  */
6
7 /* Functions developed for addbiblio.tt and authorities.tt */
8
9 // returns the fieldcode based upon tag div id
10 function getFieldCode(tagDivId){
11     // format : tag_<tagnumber>_...
12     return tagDivId.substr(3+1,3);
13 }
14
15 //returns the field and subfieldcode based upon subfield div id
16 function getFieldAndSubfieldCode(subfieldDivId){
17     // format : subfield<tagnumber><subfieldnumber>...
18     return subfieldDivId.substr(8,3+1);
19 }
20
21 //returns the subfieldcode based upon subfieldid writing
22 function getSubfieldCode(tagsubfieldid){
23     // 3 : tag +3 : tagnumber +4 : number of _ +8 subfield -1 begins at 0
24     return tagsubfieldid.substr(3+3+4+8-1,1);
25 }
26
27 // Take the base of tagsubfield information (removing the subfieldcodes and subfieldindexes)
28 // returns the filter
29 function getTagInputnameFilter(tagsubfieldid){
30     var tagsubfield=tagsubfieldid.substr(0,tagsubfieldid.lastIndexOf("_"));
31     var tagcode=tagsubfield.substr(tagsubfield.lastIndexOf("_"));
32     tagsubfield=tagsubfield.substr(0,tagsubfield.lastIndexOf("_"));
33     tagsubfield=tagsubfield.substr(0,tagsubfield.lastIndexOf("_"));
34     tagsubfield=tagsubfield+"_."+tagcode;
35     return tagsubfield;
36 }
37
38 // if source is "auth", we are editing an authority otherwise it is a biblio
39 function openAuth(tagsubfieldid,authtype,source) {
40     // let's take the base of tagsubfield information (removing the indexes and the codes
41     var element=document.getElementById(tagsubfieldid);
42     var tagsubfield=getTagInputnameFilter(tagsubfieldid);
43     var elementsubfcode=getSubfieldCode(element.name);
44     var mainmainstring=element.value;
45     var mainstring = new Array();
46     var inputs = element.parentNode.parentNode.getElementsByTagName("input");
47
48     for (var myindex =0; myindex<inputs.length;myindex++){
49         if (inputs[myindex].name && inputs[myindex].name.match(tagsubfield)){
50             var subfieldcode=getSubfieldCode(inputs[myindex].name);
51             if (isNaN(parseInt(subfieldcode)) && inputs[myindex].value != "" && subfieldcode!=elementsubfcode){
52                 mainstring.push(inputs[myindex].value);
53             }
54         }
55     }
56     mainstring = mainstring.join(' ');
57     window.open("../authorities/auth_finder.pl?source="+source+"&authtypecode="+authtype+"&index="+tagsubfieldid+"&value_mainstr="+encodeURIComponent(mainmainstring)+"&value_main="+encodeURIComponent(mainstring), "_blank",'width=700,height=550,toolbar=false,scrollbars=yes');
58 }
59
60 function ExpandField(index) {
61     var original = document.getElementById(index); //original <li>
62     var lis = original.getElementsByTagName('li');
63     for(var i=0,lislen = lis.length ; i<lislen ; i++){   // foreach li
64         if(lis[i].hasAttribute('id') == 0 ) {continue; } // li element is specific to Select2
65         if(lis[i].getAttribute('id').match(/^subfield/)){  // if it s a subfield
66             if (!lis[i].style.display) {
67                 // first time => show all subfields
68                 lis[i].style.display = 'flex';
69             } else if (lis[i].style.display == 'none') {
70                 // show
71                 lis[i].style.display = 'flex';
72             } else {
73                 // hide
74                 lis[i].style.display = 'none';
75             }
76         }
77     }
78 }
79
80 var current_select2;
81 var Select2Utils = {
82     removeSelect2: function(selects) {
83         if ($.fn.select2) {
84             $(selects).each(function(){
85                 $(this).select2('destroy');
86             });
87         }
88     },
89
90     initSelect2: function(selects) {
91         if ($.fn.select2) {
92             if ( window.CAN_user_parameters_manage_auth_values === undefined || ! CAN_user_parameters_manage_auth_values ) {
93                 $(selects).select2().on("select2:clear", function () {
94                     $(this).on("select2:opening.cancelOpen", function (evt) {
95                         evt.preventDefault();
96                         $(this).off("select2:opening.cancelOpen");
97                     });
98                 });
99             } else {
100                 $(selects).each(function(){
101                     if ( !$(this).data("category") ) {
102                         $(this).select2().on("select2:clear", function () {
103                             $(this).on("select2:opening.cancelOpen", function (evt) {
104                                 evt.preventDefault();
105                                 $(this).off("select2:opening.cancelOpen");
106                             });
107                         });
108                     } else {
109                         $(this).select2({
110                             tags: true,
111                             createTag: function (tag) {
112                                 return {
113                                     id: tag.term,
114                                     text: tag.term,
115                                     newTag: true
116                                 };
117                             },
118                             templateResult: function(state) {
119                                 if (state.newTag) {
120                                     return state.text + " " + __("(select to create)");
121                                 }
122                                 return state.text;
123                             }
124                         }).on("select2:select", function(e) {
125                             if(e.params.data.newTag){
126                                 current_select2 = this;
127                                 var category = $(this).data("category");
128                                 $("#avCreate #new_av_category").html(category);
129                                 $("#avCreate input[name='category']").val(category);
130                                 $("#avCreate input[name='value']").val('');
131                                 $("#avCreate input[name='description']").val(e.params.data.text);
132
133                                 $(this).val($(this).find("option:first").val()).trigger('change');
134                                 $('#avCreate').modal({show:true});
135                             }
136                         }).on("select2:clear", function () {
137                             $(this).on("select2:opening.cancelOpen", function (evt) {
138                                 evt.preventDefault();
139
140                                 $(this).off("select2:opening.cancelOpen");
141                             });
142                         });
143                     }
144                 });
145             }
146         }
147     }
148 };
149
150 /**
151  * To clone a field
152  * @param hideMarc '0' for false, '1' for true
153  * @param advancedMARCEditor '0' for false, '1' for true
154  */
155 function CloneField(index, hideMarc, advancedMARCEditor) {
156     var original = document.getElementById(index); //original <li>
157     Select2Utils.removeSelect2($(original).find('select'));
158
159     var clone = original.cloneNode(true);
160     var new_key = CreateKey();
161     var new_id  = original.getAttribute('id')+new_key;
162
163     clone.setAttribute('id',new_id); // setting a new id for the parent li
164
165     var divs = Array.from(clone.getElementsByTagName('li')).concat(Array.from(clone.getElementsByTagName('div')));
166
167     // if hide_marc, indicators are hidden fields
168     // setting a new name for the new indicator
169     for(var i=0; i < 2; i++) {
170         var indicator = clone.getElementsByTagName('input')[i];
171         indicator.setAttribute('name',indicator.getAttribute('name')+new_key);
172     }
173
174     // settings all subfields
175     var divslen = divs.length;
176     for( i=0; i < divslen ; i++ ){      // foreach div/li
177         if( divs[i].getAttribute("id") && divs[i].getAttribute("id").match(/^subfield/)){  // if it s a subfield
178
179             // set the attribute for the new 'li' subfields
180             divs[i].setAttribute('id',divs[i].getAttribute('id')+new_key);
181
182             var inputs   = divs[i].getElementsByTagName('input');
183             var id_input = "";
184             var olddiv;
185             var oldcontrol;
186
187             for( j = 0 ; j < inputs.length ; j++ ) {
188                 if(inputs[j].getAttribute("id") && inputs[j].getAttribute("id").match(/^tag_/) ){
189                     inputs[j].value = "";
190                 }
191             }
192             var textareas = divs[i].getElementsByTagName('textarea');
193             for( j = 0 ; j < textareas.length ; j++ ) {
194                 if(textareas[j].getAttribute("id") && textareas[j].getAttribute("id").match(/^tag_/) ){
195                     textareas[j].value = "";
196                 }
197             }
198             if( inputs.length > 0 ){
199                 inputs[0].setAttribute('id',inputs[0].getAttribute('id')+new_key);
200                 inputs[0].setAttribute('name',inputs[0].getAttribute('name')+new_key);
201
202                 try {
203                     id_input = inputs[1].getAttribute('id')+new_key;
204                     inputs[1].setAttribute('id',id_input);
205                     inputs[1].setAttribute('name',inputs[1].getAttribute('name')+new_key);
206                 } catch(e) {
207                     try{ // it s a select if it is not an input
208                         var selects = divs[i].getElementsByTagName('select');
209                         id_input = selects[0].getAttribute('id')+new_key;
210                         selects[0].setAttribute('id',id_input);
211                         selects[0].setAttribute('name',selects[0].getAttribute('name')+new_key);
212                     }catch(e2){ // it is a textarea if it s not a select or an input
213                         var textareas = divs[i].getElementsByTagName('textarea');
214                         if( textareas.length > 0 ){
215                             id_input = textareas[0].getAttribute('id')+new_key;
216                             textareas[0].setAttribute('id',id_input);
217                             textareas[0].setAttribute('name',textareas[0].getAttribute('name')+new_key);
218                         }
219                     }
220                 }
221                 if( $(inputs[1]).hasClass('framework_plugin') ) {
222                     olddiv= original.getElementsByTagName('li')[i];
223                     oldcontrol= olddiv.getElementsByTagName('input')[1];
224                     AddEventHandlers( oldcontrol,inputs[1],id_input );
225                 }
226             }
227             // when cloning a subfield, re set its label too.
228             var labels = divs[i].getElementsByTagName('label');
229             labels[0].setAttribute('for', id_input);
230
231             // setting its '+' and '-' buttons
232             try {
233                 var anchors = divs[i].getElementsByTagName('a');
234                 for (var j = 0; j < anchors.length; j++) {
235                     if(anchors[j].getAttribute('class') == 'buttonPlus'){
236                         anchors[j].setAttribute('onclick',"CloneSubfield('" + divs[i].getAttribute('id') + "','" + advancedMARCEditor + "'); return false;");
237                     } else if (anchors[j].getAttribute('class') == 'buttonMinus') {
238                         anchors[j].setAttribute('onclick',"UnCloneField('" + divs[i].getAttribute('id') + "'); return false;");
239                     }
240                 }
241             }
242             catch(e){
243                 // do nothig if ButtonPlus & CloneButtonPlus don t exist.
244             }
245
246             // button ...
247             var spans=0;
248             try {
249                 spans = divs[i].getElementsByTagName('a');
250             } catch(e) {
251                 // no spans
252             }
253             if(spans){
254                 var buttonDot;
255                 if(!CloneButtonPlus){ // it s impossible to have  + ... (buttonDot AND buttonPlus)
256                     buttonDot = spans[0];
257                     if(buttonDot){
258                         // 2 possibilities :
259                         try{
260                             if( $(buttonDot).hasClass('framework_plugin') ) {
261                                 olddiv= original.getElementsByTagName('li')[i];
262                                 oldcontrol= olddiv.getElementsByTagName('a')[0];
263                                 AddEventHandlers(oldcontrol,buttonDot,id_input);
264                             }
265                             try {
266                                 // do not copy the script section.
267                                 var script = spans[0].getElementsByTagName('script')[0];
268                                 spans[0].removeChild(script);
269                             } catch(e) {
270                                 // do nothing if there is no script
271                             }
272                         } catch(e){
273                             //
274                         }
275                     }
276                 }
277             }
278
279         } else { // it's a indicator div
280             if ( divs[i].getAttribute("id") && divs[i].getAttribute('id').match(/^div_indicator/)) {
281
282                 // setting a new id for the indicator div
283                 divs[i].setAttribute('id',divs[i].getAttribute('id')+new_key);
284
285                 inputs = divs[i].getElementsByTagName('input');
286                 inputs[0].setAttribute('id',inputs[0].getAttribute('id')+new_key);
287                 inputs[1].setAttribute('id',inputs[1].getAttribute('id')+new_key);
288
289                 var CloneButtonPlus;
290                 try {
291                     anchors = divs[i].getElementsByTagName('a');
292                     for ( j = 0; j < anchors.length; j++) {
293                         if (anchors[j].getAttribute('class') == 'buttonPlus') {
294                             anchors[j].setAttribute('onclick',"CloneField('" + new_id + "','" + hideMarc + "','" + advancedMARCEditor + "'); return false;");
295                         } else if (anchors[j].getAttribute('class') == 'buttonMinus') {
296                             anchors[j].setAttribute('onclick',"UnCloneField('" + new_id + "'); return false;");
297                         } else if (anchors[j].getAttribute('class') == 'expandfield') {
298                             anchors[j].setAttribute('onclick',"ExpandField('" + new_id + "'); return false;");
299                         }
300                     }
301                 }
302                 catch(e){
303                     // do nothig CloneButtonPlus doesn't exist.
304                 }
305
306             }
307         }
308     }
309
310     // insert this line on the page
311     original.parentNode.insertBefore(clone,original.nextSibling);
312
313     $("ul.sortable_subfield", clone).sortable();
314
315     Select2Utils.initSelect2($(original).find('select'));
316     Select2Utils.initSelect2($(clone).find('select'));
317 }
318
319
320 /**
321  * To clone a subfield
322  * @param index
323  * @param advancedMARCEditor '0' for false, '1' for true
324  */
325 function CloneSubfield(index, advancedMARCEditor){
326     var original = document.getElementById(index); //original <div>
327     Select2Utils.removeSelect2($(original).find('select'));
328     var clone = original.cloneNode(true);
329     var new_key = CreateKey();
330     // set the attribute for the new 'li' subfields
331     var inputs     = clone.getElementsByTagName('input');
332     var selects    = clone.getElementsByTagName('select');
333     var textareas  = clone.getElementsByTagName('textarea');
334     var linkid;
335     var oldcontrol;
336
337     // input
338     var id_input = "";
339     for(var i=0,len=inputs.length; i<len ; i++ ){
340         id_input = inputs[i].getAttribute('id')+new_key;
341         inputs[i].setAttribute('id',id_input);
342         inputs[i].setAttribute('name',inputs[i].getAttribute('name')+new_key);
343         if(inputs[i].getAttribute("id") && inputs[i].getAttribute("id").match(/^tag_/) ){
344             inputs[i].value = "";
345         }
346         linkid = id_input;
347     }
348
349     // Plugin input
350     if( $(inputs[1]).hasClass('framework_plugin') ) {
351         oldcontrol= original.getElementsByTagName('input')[1];
352         AddEventHandlers( oldcontrol, inputs[1], linkid );
353     }
354
355     // select
356     for(i=0,len=selects.length; i<len ; i++ ){
357         id_input = selects[i].getAttribute('id')+new_key;
358         selects[i].setAttribute('id',selects[i].getAttribute('id')+new_key);
359         selects[i].setAttribute('name',selects[i].getAttribute('name')+new_key);
360         linkid = id_input;
361     }
362
363     // textarea
364     for( i=0,len=textareas.length; i<len ; i++ ){
365         id_input = textareas[i].getAttribute('id')+new_key;
366         textareas[i].setAttribute('id',textareas[i].getAttribute('id')+new_key);
367         textareas[i].setAttribute('name',textareas[i].getAttribute('name')+new_key);
368         if(textareas[i].getAttribute("id") && textareas[i].getAttribute("id").match(/^tag_/) ){
369             textareas[i].value = "";
370         }
371         linkid = id_input;
372     }
373
374     // Handle click event on buttonDot for plugin
375     var links  = clone.getElementsByTagName('a');
376     if( $(links[0]).hasClass('framework_plugin') ) {
377         oldcontrol= original.getElementsByTagName('a')[0];
378         AddEventHandlers( oldcontrol, links[0], linkid );
379     }
380
381     if(advancedMARCEditor == '0') {
382         // when cloning a subfield, reset its label too.
383         var label = clone.getElementsByTagName('label')[0];
384         if( label ){
385             label.setAttribute('for',id_input);
386         }
387     }
388
389     // setting a new id for the parent div
390     var new_id  = original.getAttribute('id')+new_key;
391     clone.setAttribute('id',new_id);
392
393     try {
394         var anchors = clone.getElementsByTagName('a');
395         if(anchors.length){
396             for( i = 0 ,len = anchors.length ; i < len ; i++){
397                 if(anchors[i].getAttribute('class') == 'buttonPlus'){
398                     anchors[i].setAttribute('onclick',"CloneSubfield('" + new_id + "','" + advancedMARCEditor + "'); return false;");
399                 } else if (anchors[i].getAttribute('class') == 'buttonMinus') {
400                     anchors[i].setAttribute('onclick',"UnCloneField('" + new_id + "'); return false;");
401                 }
402             }
403         }
404     }
405     catch(e){
406         // do nothig if ButtonPlus & CloneButtonPlus don't exist.
407     }
408     // insert this line on the page
409     original.parentNode.insertBefore(clone,original.nextSibling);
410
411     //Restablish select2 for the cloned elements.
412     Select2Utils.initSelect2($(original).find('select'));
413     Select2Utils.initSelect2($(clone).find('select'));
414
415     // delete data of cloned subfield
416     clone.querySelectorAll('input.input_marceditor').value = "";
417 }
418
419 function AddEventHandlers (oldcontrol, newcontrol, newinputid ) {
420 // This function is a helper for CloneField and CloneSubfield.
421 // It adds the event handlers from oldcontrol to newcontrol.
422 // newinputid is the id attribute of the cloned controlling input field
423 // Note: This code depends on the jQuery data for events; this structure
424 // is moved to _data as of jQuery 1.8.
425     var ev= $(oldcontrol).data('events');
426     if(typeof ev != 'undefined') {
427         $.each(ev, function(prop,val) {
428             $.each(val, function(prop2,val2) {
429                 $(newcontrol).off( val2.type );
430                 $(newcontrol).on( val2.type, {id: newinputid}, val2.handler );
431             });
432         });
433     }
434 }
435
436 /**
437  * This function removes or clears unwanted subfields
438  */
439 function UnCloneField(index) {
440     var original = document.getElementById(index);
441     var canUnclone = false;
442     if ($(original).hasClass("tag")) {
443         // unclone a field, check if there will remain one field
444         var fieldCode = getFieldCode(index);
445         // tag divs with id begining with original field code
446         var cloneFields = $('.tag[id^="tag_'+fieldCode+'"]');
447         if (cloneFields.length > 1) {
448             canUnclone = true;
449         }
450     } else {
451         // unclone a subfield, check if there will remain one subfield
452         var subfieldCode = getFieldAndSubfieldCode(index);
453         // subfield divs of same field with id begining with original field and subfield field code
454         var cloneSubfields = $(original).parent().children('.subfield_line[id^="subfield'+subfieldCode+'"]');
455         if (cloneSubfields.length > 1) {
456             canUnclone = true;
457         }
458     }
459     if (canUnclone) {
460         // remove clone
461         original.parentNode.removeChild(original);
462     } else {
463         // clear inputs, but don't delete
464         $(":input.input_marceditor", original).each(function(){
465             // thanks to http://www.learningjquery.com/2007/08/clearing-form-data for
466             // hint about clearing selects correctly
467             var type = this.type;
468             var tag = this.tagName.toLowerCase();
469             if (type == 'text' || type == 'password' || tag == 'textarea') {
470                 this.value = "";
471             } else if (type == 'checkbox' || type == 'radio') {
472                 this.checked = false;
473             } else if (tag == 'select') {
474                 this.selectedIndex = -1;
475                 // required for Select2 to be able to update its control
476                 $(this).trigger('change');
477             }
478         });
479         $(":input.indicator", original).val("");
480     }
481 }
482
483 /**
484  * This function create a random number
485  */
486 function CreateKey(){
487     return parseInt(Math.random() * 100000);
488 }
489
490 /* Functions developed for additem.tt */
491
492 /**
493  * To clone a subfield.<br>
494  * @param original subfield div to clone
495  */
496 function CloneItemSubfield(original){
497     Select2Utils.removeSelect2($(original).find('select'));
498     var clone = original.cloneNode(true);
499     var new_key = CreateKey();
500
501     // set the attribute for the new 'li' subfields
502     var inputs     = clone.getElementsByTagName('input');
503     var selects    = clone.getElementsByTagName('select');
504     var textareas  = clone.getElementsByTagName('textarea');
505
506     // input (except hidden type)
507     var id_input = "";
508     for(var i=0,len=inputs.length; i<len ; i++ ){
509         if (inputs[i].getAttribute('type') != 'hidden') {
510             id_input = inputs[i].getAttribute('id')+new_key;
511             inputs[i].setAttribute('id',id_input);
512         }
513     }
514
515     // select
516     for( i=0,len=selects.length; i<len ; i++ ){
517         id_input = selects[i].getAttribute('id')+new_key;
518         selects[i].setAttribute('id',selects[i].getAttribute('id')+new_key);
519     }
520
521     // textarea
522     for( i=0,len=textareas.length; i<len ; i++ ){
523         id_input = textareas[i].getAttribute('id')+new_key;
524         textareas[i].setAttribute('id',textareas[i].getAttribute('id')+new_key);
525     }
526
527     // when cloning a subfield, reset its label too.
528     var label = clone.getElementsByTagName('label')[0];
529     label.setAttribute('for',id_input);
530
531     // setting a new if for the parent div
532     var new_id = original.getAttribute('id')+new_key;
533     clone.setAttribute('id',new_id);
534
535     // insert this line on the page
536     original.parentNode.insertBefore(clone,original.nextSibling);
537     Select2Utils.initSelect2($(original).find('select'));
538     Select2Utils.initSelect2($(clone).find('select'));
539 }
540
541 /**
542  * Check mandatory subfields of a cataloging form and adds <code>missing</code> class to those who are empty.<br>
543  * @param p the parent object of subfields to check
544  * @return the number of empty mandatory subfields
545  */
546 function CheckMandatorySubfields(p){
547     var total = 0;
548     $(p).find(".subfield_line input[name='mandatory'][value='1']").each(function(){
549         var editor = $(this).siblings("[name='field_value']");
550         if (!editor.val()) {
551             editor.addClass("missing");
552             total++;
553         }
554     });
555     return total;
556 }
557
558 function CheckImportantSubfields(p){
559     var total = 0;
560     $(p).find(".subfield_line input[name='important'][value='1']").each(function(i){
561         var editor = $(this).siblings("[name='field_value']");
562         if (!editor.val()) {
563             editor.addClass("missing");
564             total++;
565         }
566     });
567     return total;
568 }
569
570 $(document).ready(function() {
571     $("input.input_marceditor, input.indicator").addClass('noEnterSubmit');
572     $(document).ajaxSuccess(function() {
573         $("input.input_marceditor, input.indicator").addClass('noEnterSubmit');
574     });
575
576     if ( window.editor === undefined ) { // TODO This does not work with the advanced editor
577         Select2Utils.initSelect2($('.subfield_line select[data-category=""]')); // branches, itemtypes and cn_source
578         Select2Utils.initSelect2($('.subfield_line select[data-category!=""]'));
579     }
580
581     $("#add_new_av").on("submit", function(){
582         var category         = $(this).find('input[name="category"]').val();
583         var value            = $(this).find('input[name="value"]').val();
584         var description      = $(this).find('input[name="description"]').val();
585         var opac_description = $(this).find('input[name="opac_description"]').val();
586
587         var data = "category="+encodeURIComponent(category)
588             +"&value="+encodeURIComponent(value)
589             +"&description="+encodeURIComponent(description)
590             +"&opac_description="+encodeURIComponent(opac_description);
591
592         $.ajax({
593             type: "POST",
594             url: "/cgi-bin/koha/svc/authorised_values",
595             data: data,
596             success: function(response) {
597                 $('#avCreate').modal('hide');
598
599                 $(current_select2).append('<option selected value="'+response.value+'">'+response.description+'</option>');
600             },
601             error: function(err) {
602                 $("#avCreate .error").html(_("Something went wrong, maybe the value already exists?"))
603             }
604         });
605         return false;
606     });
607 });