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