Add datatables-1.9.4 and jquery-1.10.2 libraries
[proteocache.git] / webapp / resources / datatables-1.9.4 / examples / examples_support / jquery.jeditable.js
1 /*
2  * Jeditable - jQuery in place edit plugin
3  *
4  * Copyright (c) 2006-2009 Mika Tuupola, Dylan Verheul
5  *
6  * Licensed under the MIT license:
7  *   http://www.opensource.org/licenses/mit-license.php
8  *
9  * Project home:
10  *   http://www.appelsiini.net/projects/jeditable
11  *
12  * Based on editable by Dylan Verheul <dylan_at_dyve.net>:
13  *    http://www.dyve.net/jquery/?editable
14  *
15  */
16
17 /**
18   * Version 1.7.1
19   *
20   * ** means there is basic unit tests for this parameter. 
21   *
22   * @name  Jeditable
23   * @type  jQuery
24   * @param String  target             (POST) URL or function to send edited content to **
25   * @param Hash    options            additional options 
26   * @param String  options[method]    method to use to send edited content (POST or PUT) **
27   * @param Function options[callback] Function to run after submitting edited content **
28   * @param String  options[name]      POST parameter name of edited content
29   * @param String  options[id]        POST parameter name of edited div id
30   * @param Hash    options[submitdata] Extra parameters to send when submitting edited content.
31   * @param String  options[type]      text, textarea or select (or any 3rd party input type) **
32   * @param Integer options[rows]      number of rows if using textarea ** 
33   * @param Integer options[cols]      number of columns if using textarea **
34   * @param Mixed   options[height]    'auto', 'none' or height in pixels **
35   * @param Mixed   options[width]     'auto', 'none' or width in pixels **
36   * @param String  options[loadurl]   URL to fetch input content before editing **
37   * @param String  options[loadtype]  Request type for load url. Should be GET or POST.
38   * @param String  options[loadtext]  Text to display while loading external content.
39   * @param Mixed   options[loaddata]  Extra parameters to pass when fetching content before editing.
40   * @param Mixed   options[data]      Or content given as paramameter. String or function.**
41   * @param String  options[indicator] indicator html to show when saving
42   * @param String  options[tooltip]   optional tooltip text via title attribute **
43   * @param String  options[event]     jQuery event such as 'click' of 'dblclick' **
44   * @param String  options[submit]    submit button value, empty means no button **
45   * @param String  options[cancel]    cancel button value, empty means no button **
46   * @param String  options[cssclass]  CSS class to apply to input form. 'inherit' to copy from parent. **
47   * @param String  options[style]     Style to apply to input form 'inherit' to copy from parent. **
48   * @param String  options[select]    true or false, when true text is highlighted ??
49   * @param String  options[placeholder] Placeholder text or html to insert when element is empty. **
50   * @param String  options[onblur]    'cancel', 'submit', 'ignore' or function ??
51   *             
52   * @param Function options[onsubmit] function(settings, original) { ... } called before submit
53   * @param Function options[onreset]  function(settings, original) { ... } called before reset
54   * @param Function options[onerror]  function(settings, original, xhr) { ... } called on error
55   *             
56   * @param Hash    options[ajaxoptions]  jQuery Ajax options. See docs.jquery.com.
57   *             
58   */
59
60 (function($) {
61
62     $.fn.editable = function(target, options) {
63             
64         if ('disable' == target) {
65             $(this).data('disabled.editable', true);
66             return;
67         }
68         if ('enable' == target) {
69             $(this).data('disabled.editable', false);
70             return;
71         }
72         if ('destroy' == target) {
73             $(this)
74                 .unbind($(this).data('event.editable'))
75                 .removeData('disabled.editable')
76                 .removeData('event.editable');
77             return;
78         }
79         
80         var settings = $.extend({}, $.fn.editable.defaults, {target:target}, options);
81         
82         /* setup some functions */
83         var plugin   = $.editable.types[settings.type].plugin || function() { };
84         var submit   = $.editable.types[settings.type].submit || function() { };
85         var buttons  = $.editable.types[settings.type].buttons 
86                     || $.editable.types['defaults'].buttons;
87         var content  = $.editable.types[settings.type].content 
88                     || $.editable.types['defaults'].content;
89         var element  = $.editable.types[settings.type].element 
90                     || $.editable.types['defaults'].element;
91         var reset    = $.editable.types[settings.type].reset 
92                     || $.editable.types['defaults'].reset;
93         var callback = settings.callback || function() { };
94         var onedit   = settings.onedit   || function() { }; 
95         var onsubmit = settings.onsubmit || function() { };
96         var onreset  = settings.onreset  || function() { };
97         var onerror  = settings.onerror  || reset;
98           
99         /* show tooltip */
100         if (settings.tooltip) {
101             $(this).attr('title', settings.tooltip);
102         }
103         
104         settings.autowidth  = 'auto' == settings.width;
105         settings.autoheight = 'auto' == settings.height;
106         
107         return this.each(function() {
108                         
109             /* save this to self because this changes when scope changes */
110             var self = this;  
111                    
112             /* inlined block elements lose their width and height after first edit */
113             /* save them for later use as workaround */
114             var savedwidth  = $(self).width();
115             var savedheight = $(self).height();
116             
117             /* save so it can be later used by $.editable('destroy') */
118             $(this).data('event.editable', settings.event);
119             
120             /* if element is empty add something clickable (if requested) */
121             if (!$.trim($(this).html())) {
122                 $(this).html(settings.placeholder);
123             }
124             
125             $(this).bind(settings.event, function(e) {
126                 
127                 /* abort if disabled for this element */
128                 if (true === $(this).data('disabled.editable')) {
129                     return;
130                 }
131                 
132                 /* prevent throwing an exeption if edit field is clicked again */
133                 if (self.editing) {
134                     return;
135                 }
136                 
137                 /* abort if onedit hook returns false */
138                 if (false === onedit.apply(this, [settings, self])) {
139                    return;
140                 }
141                 
142                 /* prevent default action and bubbling */
143                 e.preventDefault();
144                 e.stopPropagation();
145                 
146                 /* remove tooltip */
147                 if (settings.tooltip) {
148                     $(self).removeAttr('title');
149                 }
150                 
151                 /* figure out how wide and tall we are, saved width and height */
152                 /* are workaround for http://dev.jquery.com/ticket/2190 */
153                 if (0 == $(self).width()) {
154                     //$(self).css('visibility', 'hidden');
155                     settings.width  = savedwidth;
156                     settings.height = savedheight;
157                 } else {
158                     if (settings.width != 'none') {
159                         settings.width = 
160                             settings.autowidth ? $(self).width()  : settings.width;
161                     }
162                     if (settings.height != 'none') {
163                         settings.height = 
164                             settings.autoheight ? $(self).height() : settings.height;
165                     }
166                 }
167                 //$(this).css('visibility', '');
168                 
169                 /* remove placeholder text, replace is here because of IE */
170                 if ($(this).html().toLowerCase().replace(/(;|")/g, '') == 
171                     settings.placeholder.toLowerCase().replace(/(;|")/g, '')) {
172                         $(this).html('');
173                 }
174                                 
175                 self.editing    = true;
176                 self.revert     = $(self).html();
177                 $(self).html('');
178
179                 /* create the form object */
180                 var form = $('<form />');
181                 
182                 /* apply css or style or both */
183                 if (settings.cssclass) {
184                     if ('inherit' == settings.cssclass) {
185                         form.attr('class', $(self).attr('class'));
186                     } else {
187                         form.attr('class', settings.cssclass);
188                     }
189                 }
190
191                 if (settings.style) {
192                     if ('inherit' == settings.style) {
193                         form.attr('style', $(self).attr('style'));
194                         /* IE needs the second line or display wont be inherited */
195                         form.css('display', $(self).css('display'));                
196                     } else {
197                         form.attr('style', settings.style);
198                     }
199                 }
200
201                 /* add main input element to form and store it in input */
202                 var input = element.apply(form, [settings, self]);
203
204                 /* set input content via POST, GET, given data or existing value */
205                 var input_content;
206                 
207                 if (settings.loadurl) {
208                     var t = setTimeout(function() {
209                         input.disabled = true;
210                         content.apply(form, [settings.loadtext, settings, self]);
211                     }, 100);
212
213                     var loaddata = {};
214                     loaddata[settings.id] = self.id;
215                     if ($.isFunction(settings.loaddata)) {
216                         $.extend(loaddata, settings.loaddata.apply(self, [self.revert, settings]));
217                     } else {
218                         $.extend(loaddata, settings.loaddata);
219                     }
220                     $.ajax({
221                        type : settings.loadtype,
222                        url  : settings.loadurl,
223                        data : loaddata,
224                        async : false,
225                        success: function(result) {
226                           window.clearTimeout(t);
227                           input_content = result;
228                           input.disabled = false;
229                        }
230                     });
231                 } else if (settings.data) {
232                     input_content = settings.data;
233                     if ($.isFunction(settings.data)) {
234                         input_content = settings.data.apply(self, [self.revert, settings]);
235                     }
236                 } else {
237                     input_content = self.revert; 
238                 }
239                 content.apply(form, [input_content, settings, self]);
240
241                 input.attr('name', settings.name);
242         
243                 /* add buttons to the form */
244                 buttons.apply(form, [settings, self]);
245          
246                 /* add created form to self */
247                 $(self).append(form);
248          
249                 /* attach 3rd party plugin if requested */
250                 plugin.apply(form, [settings, self]);
251
252                 /* focus to first visible form element */
253                 $(':input:visible:enabled:first', form).focus();
254
255                 /* highlight input contents when requested */
256                 if (settings.select) {
257                     input.select();
258                 }
259         
260                 /* discard changes if pressing esc */
261                 input.keydown(function(e) {
262                     if (e.keyCode == 27) {
263                         e.preventDefault();
264                         //self.reset();
265                         reset.apply(form, [settings, self]);
266                     }
267                 });
268
269                 /* discard, submit or nothing with changes when clicking outside */
270                 /* do nothing is usable when navigating with tab */
271                 var t;
272                 if ('cancel' == settings.onblur) {
273                     input.blur(function(e) {
274                         /* prevent canceling if submit was clicked */
275                         t = setTimeout(function() {
276                             reset.apply(form, [settings, self]);
277                         }, 500);
278                     });
279                 } else if ('submit' == settings.onblur) {
280                     input.blur(function(e) {
281                         /* prevent double submit if submit was clicked */
282                         t = setTimeout(function() {
283                             form.submit();
284                         }, 200);
285                     });
286                 } else if ($.isFunction(settings.onblur)) {
287                     input.blur(function(e) {
288                         settings.onblur.apply(self, [input.val(), settings]);
289                     });
290                 } else {
291                     input.blur(function(e) {
292                       /* TODO: maybe something here */
293                     });
294                 }
295
296                 form.submit(function(e) {
297
298                     if (t) { 
299                         clearTimeout(t);
300                     }
301
302                     /* do no submit */
303                     e.preventDefault(); 
304             
305                     /* call before submit hook. */
306                     /* if it returns false abort submitting */                    
307                     if (false !== onsubmit.apply(form, [settings, self])) { 
308                         /* custom inputs call before submit hook. */
309                         /* if it returns false abort submitting */
310                         if (false !== submit.apply(form, [settings, self])) { 
311
312                           /* check if given target is function */
313                           if ($.isFunction(settings.target)) {
314                               var str = settings.target.apply(self, [input.val(), settings]);
315                               $(self).html(str);
316                               self.editing = false;
317                               callback.apply(self, [self.innerHTML, settings]);
318                               /* TODO: this is not dry */                              
319                               if (!$.trim($(self).html())) {
320                                   $(self).html(settings.placeholder);
321                               }
322                           } else {
323                               /* add edited content and id of edited element to POST */
324                               var submitdata = {};
325                               submitdata[settings.name] = input.val();
326                               submitdata[settings.id] = self.id;
327                               /* add extra data to be POST:ed */
328                               if ($.isFunction(settings.submitdata)) {
329                                   $.extend(submitdata, settings.submitdata.apply(self, [self.revert, settings]));
330                               } else {
331                                   $.extend(submitdata, settings.submitdata);
332                               }
333
334                               /* quick and dirty PUT support */
335                               if ('PUT' == settings.method) {
336                                   submitdata['_method'] = 'put';
337                               }
338
339                               /* show the saving indicator */
340                               $(self).html(settings.indicator);
341                               
342                               /* defaults for ajaxoptions */
343                               var ajaxoptions = {
344                                   type    : 'POST',
345                                   data    : submitdata,
346                                   dataType: 'html',
347                                   url     : settings.target,
348                                   success : function(result, status) {
349                                       if (ajaxoptions.dataType == 'html') {
350                                         $(self).html(result);
351                                       }
352                                       self.editing = false;
353                                       callback.apply(self, [result, settings]);
354                                       if (!$.trim($(self).html())) {
355                                           $(self).html(settings.placeholder);
356                                       }
357                                   },
358                                   error   : function(xhr, status, error) {
359                                       onerror.apply(form, [settings, self, xhr]);
360                                   }
361                               };
362                               
363                               /* override with what is given in settings.ajaxoptions */
364                               $.extend(ajaxoptions, settings.ajaxoptions);   
365                               $.ajax(ajaxoptions);          
366                               
367                             }
368                         }
369                     }
370                     
371                     /* show tooltip again */
372                     $(self).attr('title', settings.tooltip);
373                     
374                     return false;
375                 });
376             });
377             
378             /* privileged methods */
379             this.reset = function(form) {
380                 /* prevent calling reset twice when blurring */
381                 if (this.editing) {
382                     /* before reset hook, if it returns false abort reseting */
383                     if (false !== onreset.apply(form, [settings, self])) { 
384                         $(self).html(self.revert);
385                         self.editing   = false;
386                         if (!$.trim($(self).html())) {
387                             $(self).html(settings.placeholder);
388                         }
389                         /* show tooltip again */
390                         if (settings.tooltip) {
391                             $(self).attr('title', settings.tooltip);                
392                         }
393                     }                    
394                 }
395             };            
396         });
397
398     };
399
400
401     $.editable = {
402         types: {
403             defaults: {
404                 element : function(settings, original) {
405                     var input = $('<input type="hidden"></input>');                
406                     $(this).append(input);
407                     return(input);
408                 },
409                 content : function(string, settings, original) {
410                     $(':input:first', this).val(string);
411                 },
412                 reset : function(settings, original) {
413                   original.reset(this);
414                 },
415                 buttons : function(settings, original) {
416                     var form = this;
417                     if (settings.submit) {
418                         /* if given html string use that */
419                         if (settings.submit.match(/>$/)) {
420                             var submit = $(settings.submit).click(function() {
421                                 if (submit.attr("type") != "submit") {
422                                     form.submit();
423                                 }
424                             });
425                         /* otherwise use button with given string as text */
426                         } else {
427                             var submit = $('<button type="submit" />');
428                             submit.html(settings.submit);                            
429                         }
430                         $(this).append(submit);
431                     }
432                     if (settings.cancel) {
433                         /* if given html string use that */
434                         if (settings.cancel.match(/>$/)) {
435                             var cancel = $(settings.cancel);
436                         /* otherwise use button with given string as text */
437                         } else {
438                             var cancel = $('<button type="cancel" />');
439                             cancel.html(settings.cancel);
440                         }
441                         $(this).append(cancel);
442
443                         $(cancel).click(function(event) {
444                             //original.reset();
445                             if ($.isFunction($.editable.types[settings.type].reset)) {
446                                 var reset = $.editable.types[settings.type].reset;                                                                
447                             } else {
448                                 var reset = $.editable.types['defaults'].reset;                                
449                             }
450                             reset.apply(form, [settings, original]);
451                             return false;
452                         });
453                     }
454                 }
455             },
456             text: {
457                 element : function(settings, original) {
458                     var input = $('<input />');
459                     if (settings.width  != 'none') { input.width(settings.width);  }
460                     if (settings.height != 'none') { input.height(settings.height); }
461                     /* https://bugzilla.mozilla.org/show_bug.cgi?id=236791 */
462                     //input[0].setAttribute('autocomplete','off');
463                     input.attr('autocomplete','off');
464                     $(this).append(input);
465                     return(input);
466                 }
467             },
468             textarea: {
469                 element : function(settings, original) {
470                     var textarea = $('<textarea />');
471                     if (settings.rows) {
472                         textarea.attr('rows', settings.rows);
473                     } else if (settings.height != "none") {
474                         textarea.height(settings.height);
475                     }
476                     if (settings.cols) {
477                         textarea.attr('cols', settings.cols);
478                     } else if (settings.width != "none") {
479                         textarea.width(settings.width);
480                     }
481                     $(this).append(textarea);
482                     return(textarea);
483                 }
484             },
485             select: {
486                element : function(settings, original) {
487                     var select = $('<select />');
488                     $(this).append(select);
489                     return(select);
490                 },
491                 content : function(data, settings, original) {
492                     /* If it is string assume it is json. */
493                     if (String == data.constructor) {      
494                         eval ('var json = ' + data);
495                     } else {
496                     /* Otherwise assume it is a hash already. */
497                         var json = data;
498                     }
499                     for (var key in json) {
500                         if (!json.hasOwnProperty(key)) {
501                             continue;
502                         }
503                         if ('selected' == key) {
504                             continue;
505                         } 
506                         var option = $('<option />').val(key).append(json[key]);
507                         $('select', this).append(option);    
508                     }                    
509                     /* Loop option again to set selected. IE needed this... */ 
510                     $('select', this).children().each(function() {
511                         if ($(this).val() == json['selected'] || 
512                             $(this).text() == $.trim(original.revert)) {
513                                 $(this).attr('selected', 'selected');
514                         }
515                     });
516                 }
517             }
518         },
519
520         /* Add new input type */
521         addInputType: function(name, input) {
522             $.editable.types[name] = input;
523         }
524     };
525
526     // publicly accessible defaults
527     $.fn.editable.defaults = {
528         name       : 'value',
529         id         : 'id',
530         type       : 'text',
531         width      : 'auto',
532         height     : 'auto',
533         event      : 'click.editable',
534         onblur     : 'cancel',
535         loadtype   : 'GET',
536         loadtext   : 'Loading...',
537         placeholder: 'Click to edit',
538         loaddata   : {},
539         submitdata : {},
540         ajaxoptions: {}
541     };
542
543 })(jQuery);