Bug 25728: 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 = 'block';
69             } else if (lis[i].style.display == 'none') {
70                 // show
71                 lis[i].style.display = 'block';
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").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
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 textaeras = divs[i].getElementsByTagName('textarea');
214                     id_input = textaeras[0].getAttribute('id')+new_key;
215                     textaeras[0].setAttribute('id',id_input);
216                     textaeras[0].setAttribute('name',textaeras[0].getAttribute('name')+new_key);
217                 }
218             }
219             if( $(inputs[1]).hasClass('framework_plugin') ) {
220                 olddiv= original.getElementsByTagName('li')[i];
221                 oldcontrol= olddiv.getElementsByTagName('input')[1];
222                 AddEventHandlers( oldcontrol,inputs[1],id_input );
223             }
224
225             if (advancedMARCEditor == '0') {
226                 // when cloning a subfield, re set its label too.
227                 var labels = divs[i].getElementsByTagName('label');
228                 labels[0].setAttribute('for',id_input);
229             }
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').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         label.setAttribute('for',id_input);
385     }
386
387     // setting a new id for the parent div
388     var new_id  = original.getAttribute('id')+new_key;
389     clone.setAttribute('id',new_id);
390
391     try {
392         var anchors = clone.getElementsByTagName('a');
393         if(anchors.length){
394             for( i = 0 ,len = anchors.length ; i < len ; i++){
395                 if(anchors[i].getAttribute('class') == 'buttonPlus'){
396                     anchors[i].setAttribute('onclick',"CloneSubfield('" + new_id + "','" + advancedMARCEditor + "'); return false;");
397                 } else if (anchors[i].getAttribute('class') == 'buttonMinus') {
398                     anchors[i].setAttribute('onclick',"UnCloneField('" + new_id + "'); return false;");
399                 }
400             }
401         }
402     }
403     catch(e){
404         // do nothig if ButtonPlus & CloneButtonPlus don't exist.
405     }
406     // insert this line on the page
407     original.parentNode.insertBefore(clone,original.nextSibling);
408
409     //Restablish select2 for the cloned elements.
410     Select2Utils.initSelect2($(original).find('select'));
411     Select2Utils.initSelect2($(clone).find('select'));
412
413     // delete data of cloned subfield
414     clone.querySelectorAll('input.input_marceditor').value = "";
415 }
416
417 function AddEventHandlers (oldcontrol, newcontrol, newinputid ) {
418 // This function is a helper for CloneField and CloneSubfield.
419 // It adds the event handlers from oldcontrol to newcontrol.
420 // newinputid is the id attribute of the cloned controlling input field
421 // Note: This code depends on the jQuery data for events; this structure
422 // is moved to _data as of jQuery 1.8.
423     var ev= $(oldcontrol).data('events');
424     if(typeof ev != 'undefined') {
425         $.each(ev, function(prop,val) {
426             $.each(val, function(prop2,val2) {
427                 $(newcontrol).off( val2.type );
428                 $(newcontrol).on( val2.type, {id: newinputid}, val2.handler );
429             });
430         });
431     }
432 }
433
434 /**
435  * This function removes or clears unwanted subfields
436  */
437 function UnCloneField(index) {
438     var original = document.getElementById(index);
439     var canUnclone = false;
440     if ($(original).hasClass("tag")) {
441         // unclone a field, check if there will remain one field
442         var fieldCode = getFieldCode(index);
443         // tag divs with id begining with original field code
444         var cloneFields = $('.tag[id^="tag_'+fieldCode+'"]');
445         if (cloneFields.length > 1) {
446             canUnclone = true;
447         }
448     } else {
449         // unclone a subfield, check if there will remain one subfield
450         var subfieldCode = getFieldAndSubfieldCode(index);
451         // subfield divs of same field with id begining with original field and subfield field code
452         var cloneSubfields = $(original).parent().children('.subfield_line[id^="subfield'+subfieldCode+'"]');
453         if (cloneSubfields.length > 1) {
454             canUnclone = true;
455         }
456     }
457     if (canUnclone) {
458         // remove clone
459         original.parentNode.removeChild(original);
460     } else {
461         // clear inputs, but don't delete
462         $(":input.input_marceditor", original).each(function(){
463             // thanks to http://www.learningjquery.com/2007/08/clearing-form-data for
464             // hint about clearing selects correctly
465             var type = this.type;
466             var tag = this.tagName.toLowerCase();
467             if (type == 'text' || type == 'password' || tag == 'textarea') {
468                 this.value = "";
469             } else if (type == 'checkbox' || type == 'radio') {
470                 this.checked = false;
471             } else if (tag == 'select') {
472                 this.selectedIndex = -1;
473                 // required for Select2 to be able to update its control
474                 $(this).trigger('change');
475             }
476         });
477         $(":input.indicator", original).val("");
478     }
479 }
480
481 /**
482  * This function create a random number
483  */
484 function CreateKey(){
485     return parseInt(Math.random() * 100000);
486 }
487
488 /* Functions developed for additem.tt */
489
490 /**
491  * To clone a subfield.<br>
492  * @param original subfield div to clone
493  */
494 function CloneItemSubfield(original){
495     Select2Utils.removeSelect2($(original).find('select'));
496     var clone = original.cloneNode(true);
497     var new_key = CreateKey();
498
499     // set the attribute for the new 'li' subfields
500     var inputs     = clone.getElementsByTagName('input');
501     var selects    = clone.getElementsByTagName('select');
502     var textareas  = clone.getElementsByTagName('textarea');
503
504     // input (except hidden type)
505     var id_input = "";
506     for(var i=0,len=inputs.length; i<len ; i++ ){
507         if (inputs[i].getAttribute('type') != 'hidden') {
508             id_input = inputs[i].getAttribute('id')+new_key;
509             inputs[i].setAttribute('id',id_input);
510         }
511     }
512
513     // select
514     for( i=0,len=selects.length; i<len ; i++ ){
515         id_input = selects[i].getAttribute('id')+new_key;
516         selects[i].setAttribute('id',selects[i].getAttribute('id')+new_key);
517     }
518
519     // textarea
520     for( i=0,len=textareas.length; i<len ; i++ ){
521         id_input = textareas[i].getAttribute('id')+new_key;
522         textareas[i].setAttribute('id',textareas[i].getAttribute('id')+new_key);
523     }
524
525     // when cloning a subfield, reset its label too.
526     var label = clone.getElementsByTagName('label')[0];
527     label.setAttribute('for',id_input);
528
529     // setting a new if for the parent div
530     var new_id = original.getAttribute('id')+new_key;
531     clone.setAttribute('id',new_id);
532
533     // insert this line on the page
534     original.parentNode.insertBefore(clone,original.nextSibling);
535     Select2Utils.initSelect2($(original).find('select'));
536     Select2Utils.initSelect2($(clone).find('select'));
537 }
538
539 /**
540  * Check mandatory subfields of a cataloging form and adds <code>missing</code> class to those who are empty.<br>
541  * @param p the parent object of subfields to check
542  * @return the number of empty mandatory subfields
543  */
544 function CheckMandatorySubfields(p){
545     var total = 0;
546     $(p).find(".subfield_line input[name='mandatory'][value='1']").each(function(){
547         var editor = $(this).siblings("[name='field_value']");
548         if (!editor.val()) {
549             editor.addClass("missing");
550             total++;
551         }
552     });
553     return total;
554 }
555
556 function CheckImportantSubfields(p){
557     var total = 0;
558     $(p).find(".subfield_line input[name='important'][value='1']").each(function(i){
559         var editor = $(this).siblings("[name='field_value']");
560         if (!editor.val()) {
561             editor.addClass("missing");
562             total++;
563         }
564     });
565     return total;
566 }
567
568 $(document).ready(function() {
569     $("input.input_marceditor, input.indicator").addClass('noEnterSubmit');
570     $(document).ajaxSuccess(function() {
571         $("input.input_marceditor, input.indicator").addClass('noEnterSubmit');
572     });
573
574     if ( window.editor === undefined ) { // TODO This does not work with the advanced editor
575         Select2Utils.initSelect2($('.subfield_line select[data-category=""]')); // branches, itemtypes and cn_source
576         Select2Utils.initSelect2($('.subfield_line select[data-category!=""]'));
577     }
578
579     $("#add_new_av").on("submit", function(){
580         var category         = $(this).find('input[name="category"]').val();
581         var value            = $(this).find('input[name="value"]').val();
582         var description      = $(this).find('input[name="description"]').val();
583         var opac_description = $(this).find('input[name="opac_description"]').val();
584
585         var data = "category="+encodeURIComponent(category)
586             +"&value="+encodeURIComponent(value)
587             +"&description="+encodeURIComponent(description)
588             +"&opac_description="+encodeURIComponent(opac_description);
589
590         $.ajax({
591             type: "POST",
592             url: "/cgi-bin/koha/svc/authorised_values",
593             data: data,
594             success: function(response) {
595                 $('#avCreate').modal('hide');
596
597                 $(current_select2).append('<option selected value="'+response.value+'">'+response.description+'</option>');
598             },
599             error: function(err) {
600                 $("#avCreate .error").html(_("Something went wrong, maybe the value already exists?"))
601             }
602         });
603         return false;
604     });
605 });