Bug 32307: Fix gallery when Coce is enabled
[koha.git] / koha-tmpl / opac-tmpl / bootstrap / js / autofill.js
1 /*
2  * Plugin dealing with the Google API based on jQuery autofill plugin
3  * https://plugins.jquery.com/autofill/
4  *
5  * Automatically fills form inputs with relevant data based on search result
6  * Modified for OPAC Suggestion form
7  */
8
9 (function ($) {
10     function typeString(o) {
11         if (typeof o != 'object')
12             return typeof o;
13
14         if (o === null)
15             return "null";
16
17         //object, array, function, date, regexp, string, number, boolean, error
18         var internalClass = Object.prototype.toString.call(o)
19             .match(/\[object\s(\w+)\]/)[1];
20
21         return internalClass.toLowerCase();
22     }
23
24     var AutoFiller = function (elm, fields, type) {
25         var self = this;
26         self.type = type;
27         self.$elm = $(elm);
28         self.fields = fields;
29
30         var MSG_UNDO_AUTOFILL_SUGGESTION =  __("Clear form");
31         var MSG_SEARCH_GOOGLE_BOOKS = __("Search Google Books");
32
33         /* decorate element as autofiller */
34         self.$undo = $('<input type="button" class="btn btn-info btn-sm" style="display:none;margin-left:5px;" value="' + MSG_UNDO_AUTOFILL_SUGGESTION + '" />');
35         self.$fillbtn = $('<input type="button" class="btn btn-primary btn-sm" value="' + MSG_SEARCH_GOOGLE_BOOKS + '" />');
36         self.$error = $('<span class="add-on" style="display:none;padding-left:5px;"></span>');
37         self.$elm.after(self.$error);
38         self.$elm.after(self.$undo);
39         self.$elm.after(self.$fillbtn);
40
41         for(var key in fields) {
42             if( fields.hasOwnProperty(key) && typeof fields[key] === 'object' ) {
43                 var $target = $('#' + self.fields[key].target);
44                 self.fields[key].$target = $target;
45             }
46         }
47
48         self.$fillbtn.click(function(){
49             /* clear fields first */
50             for(var key in self.fields) {
51                 var field = self.fields[key];
52                 field.$target.trigger('autofill-undo');
53             }
54             /* only allow forced update once every second */
55             if(Date.now() - self.lastupdate > 1000) {
56                 self.$elm.trigger('change');
57             }
58         });
59
60         self.$undo.click(function(){
61             for(var key in self.fields) {
62                 var field = self.fields[key];
63                 //field.$target.val("");
64                 field.$target.trigger('autofill-undo');
65             }
66             $(":input[type='text']").each(function(){
67                 $(this).val("");
68             });
69             self.$undo.hide();
70         });
71
72         self.$elm.change(function() {
73             self.lastupdate = Date.now();
74             self.$error.html('');
75             self.$error.hide();
76             /* give user some feedback that the request is in progress */
77             self.$fillbtn.fadeOut(1000).fadeIn(1000);
78             if ( self.$elm.val()) {
79                 var gAPI = 'https://www.googleapis.com/books/v1/volumes?q=';
80                 gAPI += self.$elm.val().replace(/\-/g, '');
81                 gAPI += '&maxResults=1';
82                 $.getJSON(gAPI, function (response) {
83                     if(response.totalItems == 0) {
84                         self.$error.html(__('Sorry, nothing found.'));
85                         self.$error.show();
86                         return;
87                     }
88
89                     var undos = 0;
90                     var item = response.items[0];
91                     for(var key in self.fields) {
92                         var filled = false;
93                         var value = eval('item.'+key);
94                         var field = self.fields[key];
95
96                         /* field handled by caller */
97                         if('handle' in field) {
98                             if(typeof field.handle === 'function')
99                                 field.handle(field.$target, value);
100
101                             continue; /* next please */
102                         }
103
104                         /* wouldn't know what to do with result unless we have a
105                         * target */
106                         if( ! field.$target )
107                             continue;
108
109                         /* format copyrightdate */
110                         if ( field.target == 'copyrightdate' ) {
111                             if ( value.indexOf('-') > -1 ) {
112                                 var hyphenIndex = value.indexOf('-');
113                                 var newval = value.slice(0, hyphenIndex);
114                                 value = newval;
115                             }
116                         }
117
118                         /* handle differently depending on datatype */
119                         switch(typeString(value)) {
120                             case 'array':
121                                 switch(field.$target.prop('nodeName').toUpperCase()) {
122                                     case 'TEXTAREA':
123                                         undos++;
124                                         field.$target.bind('autofill-undo', field.$target.text(), function(e){$(this).text(e.data);});
125                                         field.$target.text(value.join(', '));
126                                         break;
127                                     case 'INPUT':
128                                     default:
129                                         undos++;
130                                         field.$target.bind('autofill-undo', field.$target.val(), function(e){$(this).val(e.data);});
131                                         field.$target.val(value.join(', '));
132                                         break;
133                                 }
134                                 break;
135                             default:
136                                 switch(field.$target.prop('nodeName').toUpperCase()) {
137                                     case 'TEXTAREA':
138                                         undos++;
139                                         field.$target.bind('autofill-undo', field.$target.text(), function(e){$(this).text(e.data);});
140                                         field.$target.text(value);
141                                         break;
142                                     case 'SELECT':
143                                     case 'INPUT':
144                                     default:
145                                         undos++;
146                                         field.$target.bind('autofill-undo', field.$target.val(), function(e){$(this).val(e.data);});
147                                         field.$target.val(value);
148                                         break;
149                                 }
150                         }
151
152                         switch(field.effect) {
153                             case 'flash':
154                                 field.$target.fadeOut(500).fadeIn(500);
155                                 break;
156                         }
157                     }
158
159                     if(undos > 0)
160                         self.$undo.show();
161
162                 });
163                 }
164            });
165        };
166
167     /*
168      * @fields object: Google Books API item propreties map for
169      *                 mapping against a target element. Expected
170      *                 type:
171      *                 {
172      *                  GoogleBooksItem.property: {target: ELEM,
173      *                                             handle: function(target, value),
174      *                                             effect: jQuery effects,
175      *                                            }
176      *                 }
177      *
178      *                 "target" is optional and if specified alone (i.e no
179      *                 handle proprety) autofill will automaticly fill this
180      *                 target element with returned data.
181      *
182      *                 "handle" is optional and will be called when ajax request
183      *                 has finished and target is matched. Function specifies
184      *                 two arguments: target and value. Target is the target
185      *                 element specified by "target" and value is the value
186      *                 returned by Google Books API for the matched property.
187      *
188      *                 If a handle function is given, full control of result data
189      *                 is given to the handle function.
190      *
191      *                 "effect" is optional and specifies effect name of effect
192      *                 to use for the target once value has been set. Can be one of:
193      *
194      *                      - 'flash'
195      *
196      * @type string: defines the query type, default to input name
197      *               For example <input type="text" name="isbn"></input>
198      *               will search for isbn by default
199      *
200      * @EXAMPLE
201      *
202      *  $('#isbn').autofill({
203      *      'volumeInfo.title': {target: 'title', effect: 'flash'},
204      *      'volumeInfo.authors': {target: 'author'},
205      *      'volumeInfo.publisher': {target: 'publishercode'},
206      *      'selfLink': {handle: function(t,v){window.location=v;}}
207      *  });
208      * */
209     $.fn.autofill = function(fields, type) {
210         if(type === undefined) // default to input name
211             type = this.attr('name');
212
213         return this.each(function(i){
214             var plugin = $.data(this, "plugin_autofill");
215             if (plugin)
216                 plugin.destroy();
217
218             $.data(this, "plugin_autofill", new AutoFiller(this, fields, type));
219         });
220     };
221 }(jQuery));