686 lines
24 KiB
JavaScript
686 lines
24 KiB
JavaScript
|
/*
|
||
|
* BestInPlace (for jQuery)
|
||
|
* version: 3.0.0.alpha (2014)
|
||
|
*
|
||
|
* By Bernat Farrero based on the work of Jan Varwig.
|
||
|
* Examples at http://bernatfarrero.com
|
||
|
*
|
||
|
* Licensed under the MIT:
|
||
|
* http://www.opensource.org/licenses/mit-license.php
|
||
|
*
|
||
|
* @requires jQuery
|
||
|
*
|
||
|
* Usage:
|
||
|
*
|
||
|
* Attention.
|
||
|
* The format of the JSON object given to the select inputs is the following:
|
||
|
* [["key", "value"],["key", "value"]]
|
||
|
* The format of the JSON object given to the checkbox inputs is the following:
|
||
|
* ["falseValue", "trueValue"]
|
||
|
|
||
|
*/
|
||
|
//= require jquery.autosize
|
||
|
|
||
|
function BestInPlaceEditor(e) {
|
||
|
'use strict';
|
||
|
this.element = e;
|
||
|
this.initOptions();
|
||
|
this.bindForm();
|
||
|
this.initPlaceHolder();
|
||
|
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
|
||
|
}
|
||
|
|
||
|
BestInPlaceEditor.prototype = {
|
||
|
// Public Interface Functions //////////////////////////////////////////////
|
||
|
|
||
|
activate: function () {
|
||
|
'use strict';
|
||
|
var to_display;
|
||
|
if (this.isPlaceHolder()) {
|
||
|
to_display = "";
|
||
|
} else if (this.original_content) {
|
||
|
to_display = this.original_content;
|
||
|
} else {
|
||
|
switch (this.formType) {
|
||
|
case 'input':
|
||
|
case 'textarea':
|
||
|
if (this.display_raw) {
|
||
|
to_display = this.element.html().replace(/&/gi, '&');
|
||
|
}
|
||
|
else {
|
||
|
var value = this.element.data('bipValue');
|
||
|
if (typeof value === 'undefined') {
|
||
|
to_display = '';
|
||
|
} else if (typeof value === 'string') {
|
||
|
to_display = this.element.data('bipValue').replace(/&/gi, '&');
|
||
|
} else {
|
||
|
to_display = this.element.data('bipValue');
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 'select':
|
||
|
to_display = this.element.html();
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.oldValue = this.isPlaceHolder() ? "" : this.element.html();
|
||
|
this.display_value = to_display;
|
||
|
jQuery(this.activator).unbind("click", this.clickHandler);
|
||
|
this.activateForm();
|
||
|
this.element.trigger(jQuery.Event("best_in_place:activate"));
|
||
|
},
|
||
|
|
||
|
abort: function () {
|
||
|
'use strict';
|
||
|
this.activateText(this.oldValue);
|
||
|
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
|
||
|
this.element.trigger(jQuery.Event("best_in_place:abort"));
|
||
|
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
|
||
|
},
|
||
|
|
||
|
abortIfConfirm: function () {
|
||
|
'use strict';
|
||
|
if (!this.useConfirm) {
|
||
|
this.abort();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (confirm(BestInPlaceEditor.defaults.locales[''].confirmMessage)) {
|
||
|
this.abort();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
update: function () {
|
||
|
'use strict';
|
||
|
var editor = this,
|
||
|
value = this.getValue();
|
||
|
|
||
|
// Avoid request if no change is made
|
||
|
if (this.formType in {"input": 1, "textarea": 1} && value === this.oldValue) {
|
||
|
this.abort();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
editor.ajax({
|
||
|
"type": this.requestMethod(),
|
||
|
"dataType": BestInPlaceEditor.defaults.ajaxDataType,
|
||
|
"data": editor.requestData(),
|
||
|
"success": function (data, status, xhr) {
|
||
|
editor.loadSuccessCallback(data, status, xhr);
|
||
|
},
|
||
|
"error": function (request, error) {
|
||
|
editor.loadErrorCallback(request, error);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
|
||
|
switch (this.formType) {
|
||
|
case "select":
|
||
|
this.previousCollectionValue = value;
|
||
|
|
||
|
// search for the text for the span
|
||
|
$.each(this.values, function(index, arr){ if (String(arr[0]) === String(value)) editor.element.html(arr[1]); });
|
||
|
break;
|
||
|
|
||
|
case "checkbox":
|
||
|
$.each(this.values, function(index, arr){ if (String(arr[0]) === String(value)) editor.element.html(arr[1]); });
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
if (value !== "") {
|
||
|
if (this.display_raw) {
|
||
|
editor.element.html(value);
|
||
|
} else {
|
||
|
editor.element.text(value);
|
||
|
}
|
||
|
} else {
|
||
|
editor.element.html(this.placeHolder);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
editor.element.data('bipValue', value);
|
||
|
editor.element.attr('data-bip-value', value);
|
||
|
|
||
|
editor.element.trigger(jQuery.Event("best_in_place:update"));
|
||
|
|
||
|
|
||
|
},
|
||
|
|
||
|
activateForm: function () {
|
||
|
'use strict';
|
||
|
alert(BestInPlaceEditor.defaults.locales[''].uninitializedForm);
|
||
|
},
|
||
|
|
||
|
activateText: function (value) {
|
||
|
'use strict';
|
||
|
this.element.html(value);
|
||
|
if (this.isPlaceHolder()) {
|
||
|
this.element.html(this.placeHolder);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// Helper Functions ////////////////////////////////////////////////////////
|
||
|
|
||
|
initOptions: function () {
|
||
|
// Try parent supplied info
|
||
|
'use strict';
|
||
|
var self = this;
|
||
|
self.element.parents().each(function () {
|
||
|
var $parent = jQuery(this);
|
||
|
self.url = self.url || $parent.data("bipUrl");
|
||
|
self.activator = self.activator || $parent.data("bipActivator");
|
||
|
self.okButton = self.okButton || $parent.data("bipOkButton");
|
||
|
self.okButtonClass = self.okButtonClass || $parent.data("bipOkButtonClass");
|
||
|
self.cancelButton = self.cancelButton || $parent.data("bipCancelButton");
|
||
|
self.cancelButtonClass = self.cancelButtonClass || $parent.data("bipCancelButtonClass");
|
||
|
self.skipBlur = self.skipBlur || $parent.data("bipSkipBlur");
|
||
|
});
|
||
|
|
||
|
// Load own attributes (overrides all others)
|
||
|
self.url = self.element.data("bipUrl") || self.url || document.location.pathname;
|
||
|
self.collection = self.element.data("bipCollection") || self.collection;
|
||
|
self.formType = self.element.data("bipType") || "input";
|
||
|
self.objectName = self.element.data("bipObject") || self.objectName;
|
||
|
self.attributeName = self.element.data("bipAttribute") || self.attributeName;
|
||
|
self.activator = self.element.data("bipActivator") || self.element;
|
||
|
self.okButton = self.element.data("bipOkButton") || self.okButton;
|
||
|
self.okButtonClass = self.element.data("bipOkButtonClass") || self.okButtonClass || BestInPlaceEditor.defaults.okButtonClass;
|
||
|
self.cancelButton = self.element.data("bipCancelButton") || self.cancelButton;
|
||
|
self.cancelButtonClass = self.element.data("bipCancelButtonClass") || self.cancelButtonClass || BestInPlaceEditor.defaults.cancelButtonClass;
|
||
|
self.skipBlur = self.element.data("bipSkipBlur") || self.skipBlur || BestInPlaceEditor.defaults.skipBlur;
|
||
|
self.isNewObject = self.element.data("bipNewObject");
|
||
|
self.dataExtraPayload = self.element.data("bipExtraPayload");
|
||
|
|
||
|
// Fix for default values of 0
|
||
|
if (self.element.data("bipPlaceholder") == null) {
|
||
|
self.placeHolder = BestInPlaceEditor.defaults.locales[''].placeHolder;
|
||
|
} else {
|
||
|
self.placeHolder = self.element.data("bipPlaceholder");
|
||
|
}
|
||
|
|
||
|
self.inner_class = self.element.data("bipInnerClass");
|
||
|
self.html_attrs = self.element.data("bipHtmlAttrs");
|
||
|
self.original_content = self.element.data("bipOriginalContent") || self.original_content;
|
||
|
|
||
|
// if set the input won't be satinized
|
||
|
self.display_raw = self.element.data("bip-raw");
|
||
|
|
||
|
self.useConfirm = self.element.data("bip-confirm");
|
||
|
|
||
|
if (self.formType === "select" || self.formType === "checkbox") {
|
||
|
self.values = self.collection;
|
||
|
self.collectionValue = self.element.data("bipValue") || self.collectionValue;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
bindForm: function () {
|
||
|
'use strict';
|
||
|
this.activateForm = BestInPlaceEditor.forms[this.formType].activateForm;
|
||
|
this.getValue = BestInPlaceEditor.forms[this.formType].getValue;
|
||
|
},
|
||
|
|
||
|
|
||
|
initPlaceHolder: function () {
|
||
|
'use strict';
|
||
|
// TODO add placeholder for select and checkbox
|
||
|
if (this.element.html() === "") {
|
||
|
this.element.addClass('bip-placeholder');
|
||
|
this.element.html(this.placeHolder);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
isPlaceHolder: function () {
|
||
|
'use strict';
|
||
|
// TODO: It only work when form is deactivated.
|
||
|
// Condition will fail when form is activated
|
||
|
return this.element.html() === "" || this.element.html() === this.placeHolder;
|
||
|
},
|
||
|
|
||
|
getValue: function () {
|
||
|
'use strict';
|
||
|
alert(BestInPlaceEditor.defaults.locales[''].uninitializedForm);
|
||
|
},
|
||
|
|
||
|
// Trim and Strips HTML from text
|
||
|
sanitizeValue: function (s) {
|
||
|
'use strict';
|
||
|
return jQuery.trim(s);
|
||
|
},
|
||
|
|
||
|
requestMethod: function() {
|
||
|
'use strict';
|
||
|
return this.isNewObject ? 'post' : BestInPlaceEditor.defaults.ajaxMethod;
|
||
|
},
|
||
|
|
||
|
/* Generate the data sent in the POST request */
|
||
|
requestData: function () {
|
||
|
'use strict';
|
||
|
// To prevent xss attacks, a csrf token must be defined as a meta attribute
|
||
|
var csrf_token = jQuery('meta[name=csrf-token]').attr('content'),
|
||
|
csrf_param = jQuery('meta[name=csrf-param]').attr('content');
|
||
|
|
||
|
var data = {}
|
||
|
data['_method'] = this.requestMethod()
|
||
|
|
||
|
data[this.objectName] = this.dataExtraPayload || {}
|
||
|
|
||
|
data[this.objectName][this.attributeName] = this.getValue()
|
||
|
|
||
|
if (csrf_param !== undefined && csrf_token !== undefined) {
|
||
|
data[csrf_param] = csrf_token
|
||
|
}
|
||
|
return jQuery.param(data);
|
||
|
},
|
||
|
|
||
|
ajax: function (options) {
|
||
|
'use strict';
|
||
|
options.url = this.url;
|
||
|
options.beforeSend = function (xhr) {
|
||
|
xhr.setRequestHeader("Accept", "application/json");
|
||
|
};
|
||
|
return jQuery.ajax(options);
|
||
|
},
|
||
|
|
||
|
// Handlers ////////////////////////////////////////////////////////////////
|
||
|
|
||
|
loadSuccessCallback: function (data, status, xhr) {
|
||
|
'use strict';
|
||
|
data = jQuery.trim(data);
|
||
|
//Update original content with current text.
|
||
|
if (this.display_raw) {
|
||
|
this.original_content = this.element.html();
|
||
|
} else {
|
||
|
this.original_content = this.element.text();
|
||
|
}
|
||
|
|
||
|
if (data && data !== "") {
|
||
|
var response = jQuery.parseJSON(data);
|
||
|
if (response !== null && response.hasOwnProperty("display_as")) {
|
||
|
this.element.data('bip-original-content', this.element.text());
|
||
|
this.element.html(response.display_as);
|
||
|
}
|
||
|
if (this.isNewObject && response && response[this.objectName]) {
|
||
|
if (response[this.objectName]["id"]) {
|
||
|
this.isNewObject = false
|
||
|
this.url += "/" + response[this.objectName]["id"] // in REST a POST /thing url should become PUT /thing/123
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
this.element.toggleClass('bip-placeholder', this.isPlaceHolder());
|
||
|
|
||
|
this.element.trigger(jQuery.Event("best_in_place:success"), [data, status, xhr]);
|
||
|
this.element.trigger(jQuery.Event("ajax:success"), [data, status, xhr]);
|
||
|
|
||
|
// Binding back after being clicked
|
||
|
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
|
||
|
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
|
||
|
|
||
|
if (this.collectionValue !== null && this.formType === "select") {
|
||
|
this.collectionValue = this.previousCollectionValue;
|
||
|
this.previousCollectionValue = null;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
loadErrorCallback: function (request, error) {
|
||
|
'use strict';
|
||
|
this.activateText(this.oldValue);
|
||
|
|
||
|
this.element.trigger(jQuery.Event("best_in_place:error"), [request, error]);
|
||
|
this.element.trigger(jQuery.Event("ajax:error"), request, error);
|
||
|
|
||
|
// Binding back after being clicked
|
||
|
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
|
||
|
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
|
||
|
},
|
||
|
|
||
|
clickHandler: function (event) {
|
||
|
'use strict';
|
||
|
event.preventDefault();
|
||
|
event.data.editor.activate();
|
||
|
},
|
||
|
|
||
|
setHtmlAttributes: function () {
|
||
|
'use strict';
|
||
|
var formField = this.element.find(this.formType);
|
||
|
|
||
|
if (this.html_attrs) {
|
||
|
var attrs = this.html_attrs;
|
||
|
$.each(attrs, function (key, val) {
|
||
|
formField.attr(key, val);
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
placeButtons: function (output, field) {
|
||
|
'use strict';
|
||
|
if (field.okButton) {
|
||
|
output.append(
|
||
|
jQuery(document.createElement('input'))
|
||
|
.attr('type', 'submit')
|
||
|
.attr('class', field.okButtonClass)
|
||
|
.attr('value', field.okButton)
|
||
|
);
|
||
|
}
|
||
|
if (field.cancelButton) {
|
||
|
output.append(
|
||
|
jQuery(document.createElement('input'))
|
||
|
.attr('type', 'button')
|
||
|
.attr('class', field.cancelButtonClass)
|
||
|
.attr('value', field.cancelButton)
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
// Button cases:
|
||
|
// If no buttons, then blur saves, ESC cancels
|
||
|
// If just Cancel button, then blur saves, ESC or clicking Cancel cancels (careful of blur event!)
|
||
|
// If just OK button, then clicking OK saves (careful of blur event!), ESC or blur cancels
|
||
|
// If both buttons, then clicking OK saves, ESC or clicking Cancel or blur cancels
|
||
|
BestInPlaceEditor.forms = {
|
||
|
"input": {
|
||
|
activateForm: function () {
|
||
|
'use strict';
|
||
|
var output = jQuery(document.createElement('form'))
|
||
|
.addClass('form_in_place')
|
||
|
.attr('action', 'javascript:void(0);')
|
||
|
.attr('style', 'display:inline');
|
||
|
var input_elt = jQuery(document.createElement('input'))
|
||
|
.attr('type', 'text')
|
||
|
.attr('name', this.attributeName)
|
||
|
.val(this.display_value);
|
||
|
|
||
|
// Add class to form input
|
||
|
if (this.inner_class) {
|
||
|
input_elt.addClass(this.inner_class);
|
||
|
}
|
||
|
|
||
|
output.append(input_elt);
|
||
|
this.placeButtons(output, this);
|
||
|
|
||
|
this.element.html(output);
|
||
|
this.setHtmlAttributes();
|
||
|
|
||
|
this.element.find("input[type='text']")[0].select();
|
||
|
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.input.submitHandler);
|
||
|
if (this.cancelButton) {
|
||
|
this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.input.cancelButtonHandler);
|
||
|
}
|
||
|
if (!this.okButton) {
|
||
|
this.element.find("input[type='text']").bind('blur', {editor: this}, BestInPlaceEditor.forms.input.inputBlurHandler);
|
||
|
}
|
||
|
this.element.find("input[type='text']").bind('keyup', {editor: this}, BestInPlaceEditor.forms.input.keyupHandler);
|
||
|
this.blurTimer = null;
|
||
|
this.userClicked = false;
|
||
|
},
|
||
|
|
||
|
getValue: function () {
|
||
|
'use strict';
|
||
|
return this.sanitizeValue(this.element.find("input").val());
|
||
|
},
|
||
|
|
||
|
// When buttons are present, use a timer on the blur event to give precedence to clicks
|
||
|
inputBlurHandler: function (event) {
|
||
|
'use strict';
|
||
|
if (event.data.editor.okButton) {
|
||
|
event.data.editor.blurTimer = setTimeout(function () {
|
||
|
if (!event.data.editor.userClicked) {
|
||
|
event.data.editor.abort();
|
||
|
}
|
||
|
}, 500);
|
||
|
} else {
|
||
|
if (event.data.editor.cancelButton) {
|
||
|
event.data.editor.blurTimer = setTimeout(function () {
|
||
|
if (!event.data.editor.userClicked) {
|
||
|
event.data.editor.update();
|
||
|
}
|
||
|
}, 500);
|
||
|
} else {
|
||
|
event.data.editor.update();
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
submitHandler: function (event) {
|
||
|
'use strict';
|
||
|
event.data.editor.userClicked = true;
|
||
|
clearTimeout(event.data.editor.blurTimer);
|
||
|
event.data.editor.update();
|
||
|
},
|
||
|
|
||
|
cancelButtonHandler: function (event) {
|
||
|
'use strict';
|
||
|
event.data.editor.userClicked = true;
|
||
|
clearTimeout(event.data.editor.blurTimer);
|
||
|
event.data.editor.abort();
|
||
|
event.stopPropagation(); // Without this, click isn't handled
|
||
|
},
|
||
|
|
||
|
keyupHandler: function (event) {
|
||
|
'use strict';
|
||
|
if (event.keyCode === 27) {
|
||
|
event.data.editor.abort();
|
||
|
event.stopImmediatePropagation();
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
"select": {
|
||
|
activateForm: function () {
|
||
|
'use strict';
|
||
|
var output = jQuery(document.createElement('form'))
|
||
|
.attr('action', 'javascript:void(0)')
|
||
|
.attr('style', 'display:inline'),
|
||
|
selected = '',
|
||
|
select_elt = jQuery(document.createElement('select'))
|
||
|
.attr('class', this.inner_class !== null ? this.inner_class : ''),
|
||
|
currentCollectionValue = this.collectionValue,
|
||
|
key, value,
|
||
|
a = this.values;
|
||
|
|
||
|
$.each(a, function(index, arr){
|
||
|
key = arr[0];
|
||
|
value = arr[1];
|
||
|
var option_elt = jQuery(document.createElement('option'))
|
||
|
.val(key)
|
||
|
.html(value);
|
||
|
|
||
|
if (currentCollectionValue) {
|
||
|
if (String(key) === String(currentCollectionValue)) option_elt.attr('selected', 'selected');
|
||
|
}
|
||
|
select_elt.append(option_elt);
|
||
|
});
|
||
|
output.append(select_elt);
|
||
|
|
||
|
this.element.html(output);
|
||
|
this.setHtmlAttributes();
|
||
|
this.element.find("select").bind('change', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
|
||
|
this.element.find("select").bind('blur', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
|
||
|
this.element.find("select").bind('keyup', {editor: this}, BestInPlaceEditor.forms.select.keyupHandler);
|
||
|
this.element.find("select")[0].focus();
|
||
|
|
||
|
// automatically click on the select so you
|
||
|
// don't have to click twice
|
||
|
try {
|
||
|
var e = document.createEvent("MouseEvents");
|
||
|
e.initMouseEvent("mousedown", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
||
|
this.element.find("select")[0].dispatchEvent(e);
|
||
|
}
|
||
|
catch(e) {
|
||
|
// browser doesn't support this, e.g. IE8
|
||
|
}
|
||
|
},
|
||
|
|
||
|
getValue: function () {
|
||
|
'use strict';
|
||
|
return this.sanitizeValue(this.element.find("select").val());
|
||
|
},
|
||
|
|
||
|
blurHandler: function (event) {
|
||
|
'use strict';
|
||
|
event.data.editor.update();
|
||
|
},
|
||
|
|
||
|
keyupHandler: function (event) {
|
||
|
'use strict';
|
||
|
if (event.keyCode === 27) {
|
||
|
event.data.editor.abort();
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
"checkbox": {
|
||
|
activateForm: function () {
|
||
|
'use strict';
|
||
|
this.collectionValue = !this.getValue();
|
||
|
this.setHtmlAttributes();
|
||
|
this.update();
|
||
|
},
|
||
|
|
||
|
getValue: function () {
|
||
|
'use strict';
|
||
|
return this.collectionValue;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
"textarea": {
|
||
|
activateForm: function () {
|
||
|
'use strict';
|
||
|
// grab width and height of text
|
||
|
var width = this.element.css('width');
|
||
|
var height = this.element.css('height');
|
||
|
|
||
|
// construct form
|
||
|
var output = jQuery(document.createElement('form'))
|
||
|
.addClass('form_in_place')
|
||
|
.attr('action', 'javascript:void(0);')
|
||
|
.attr('style', 'display:inline');
|
||
|
var textarea_elt = jQuery(document.createElement('textarea'))
|
||
|
.attr('name', this.attributeName)
|
||
|
.val(this.sanitizeValue(this.display_value));
|
||
|
|
||
|
if (this.inner_class !== null) {
|
||
|
textarea_elt.addClass(this.inner_class);
|
||
|
}
|
||
|
|
||
|
output.append(textarea_elt);
|
||
|
|
||
|
this.placeButtons(output, this);
|
||
|
|
||
|
this.element.html(output);
|
||
|
this.setHtmlAttributes();
|
||
|
|
||
|
// set width and height of textarea
|
||
|
jQuery(this.element.find("textarea")[0]).css({'min-width': width, 'min-height': height});
|
||
|
jQuery(this.element.find("textarea")[0]).autosize();
|
||
|
|
||
|
this.element.find("textarea")[0].focus();
|
||
|
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.textarea.submitHandler);
|
||
|
|
||
|
if (this.cancelButton) {
|
||
|
this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.textarea.cancelButtonHandler);
|
||
|
}
|
||
|
|
||
|
if (!this.skipBlur) {
|
||
|
this.element.find("textarea").bind('blur', {editor: this}, BestInPlaceEditor.forms.textarea.blurHandler);
|
||
|
}
|
||
|
this.element.find("textarea").bind('keyup', {editor: this}, BestInPlaceEditor.forms.textarea.keyupHandler);
|
||
|
this.blurTimer = null;
|
||
|
this.userClicked = false;
|
||
|
},
|
||
|
|
||
|
getValue: function () {
|
||
|
'use strict';
|
||
|
return this.sanitizeValue(this.element.find("textarea").val());
|
||
|
},
|
||
|
|
||
|
// When buttons are present, use a timer on the blur event to give precedence to clicks
|
||
|
blurHandler: function (event) {
|
||
|
'use strict';
|
||
|
if (event.data.editor.okButton) {
|
||
|
event.data.editor.blurTimer = setTimeout(function () {
|
||
|
if (!event.data.editor.userClicked) {
|
||
|
event.data.editor.abortIfConfirm();
|
||
|
}
|
||
|
}, 500);
|
||
|
} else {
|
||
|
if (event.data.editor.cancelButton) {
|
||
|
event.data.editor.blurTimer = setTimeout(function () {
|
||
|
if (!event.data.editor.userClicked) {
|
||
|
event.data.editor.update();
|
||
|
}
|
||
|
}, 500);
|
||
|
} else {
|
||
|
event.data.editor.update();
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
submitHandler: function (event) {
|
||
|
'use strict';
|
||
|
event.data.editor.userClicked = true;
|
||
|
clearTimeout(event.data.editor.blurTimer);
|
||
|
event.data.editor.update();
|
||
|
},
|
||
|
|
||
|
cancelButtonHandler: function (event) {
|
||
|
'use strict';
|
||
|
event.data.editor.userClicked = true;
|
||
|
clearTimeout(event.data.editor.blurTimer);
|
||
|
event.data.editor.abortIfConfirm();
|
||
|
event.stopPropagation(); // Without this, click isn't handled
|
||
|
},
|
||
|
|
||
|
keyupHandler: function (event) {
|
||
|
'use strict';
|
||
|
if (event.keyCode === 27) {
|
||
|
event.data.editor.abortIfConfirm();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
BestInPlaceEditor.defaults = {
|
||
|
locales: {},
|
||
|
ajaxMethod: "put", //TODO Change to patch when support to 3.2 is dropped
|
||
|
ajaxDataType: 'text',
|
||
|
okButtonClass: '',
|
||
|
cancelButtonClass: '',
|
||
|
skipBlur: false
|
||
|
};
|
||
|
|
||
|
// Default locale
|
||
|
BestInPlaceEditor.defaults.locales[''] = {
|
||
|
confirmMessage: "Are you sure you want to discard your changes?",
|
||
|
uninitializedForm: "The form was not properly initialized. getValue is unbound",
|
||
|
placeHolder: '-'
|
||
|
};
|
||
|
|
||
|
jQuery.fn.best_in_place = function () {
|
||
|
'use strict';
|
||
|
function setBestInPlace(element) {
|
||
|
if (!element.data('bestInPlaceEditor')) {
|
||
|
element.data('bestInPlaceEditor', new BestInPlaceEditor(element));
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
jQuery(this.context).delegate(this.selector, 'click', function () {
|
||
|
var el = jQuery(this);
|
||
|
if (setBestInPlace(el)) {
|
||
|
el.click();
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.each(function () {
|
||
|
setBestInPlace(jQuery(this));
|
||
|
});
|
||
|
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
|
||
|
|