Advertisement
Guest User

jquery.jeditable-1.7.1.js

a guest
Apr 4th, 2014
211
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement