init
This commit is contained in:
16
src/editable-form/editable-form-bootstrap.js
Normal file
16
src/editable-form/editable-form-bootstrap.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Editable-form Bootstrap engine
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
//form template
|
||||
$.fn.editableform.template = '<form class="form-inline editableform"><div class="control-group">' +
|
||||
' <button type="submit" class="btn btn-primary"><i class="icon-ok icon-white"></i></button> <button type="button" class="btn clearfix"><i class="icon-ban-circle"></i></button>' +
|
||||
'<div style="clear:both"><span class="help-block editable-error-block"></span></div>' +
|
||||
'</div></form>';
|
||||
|
||||
//error classes
|
||||
$.fn.editableform.errorGroupClass = 'error';
|
||||
$.fn.editableform.errorBlockClass = null;
|
||||
|
||||
}(window.jQuery));
|
32
src/editable-form/editable-form-jqueryui.js
Normal file
32
src/editable-form/editable-form-jqueryui.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Editable-form jQuery UI engine
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
$.extend($.fn.editableform.Constructor.prototype, {
|
||||
initTemplate: function() {
|
||||
this.$form = $($.fn.editableform.template);
|
||||
|
||||
//init buttons
|
||||
this.$form.find('button[type=submit]').button({
|
||||
icons: { primary: "ui-icon-check" },
|
||||
text: false
|
||||
});
|
||||
this.$form.find('button[type=button]').button({
|
||||
icons: { primary: "ui-icon-cancel" },
|
||||
text: false
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//form template
|
||||
$.fn.editableform.template = '<form class="editableform"><div class="control-group">' +
|
||||
' <button type="submit" style="height: 24px">submit</button> <button type="button" style="height: 24px">cancel</button></div>' +
|
||||
'<div class="editable-error-block"></div>' +
|
||||
'</form>';
|
||||
|
||||
//error classes
|
||||
$.fn.editableform.errorGroupClass = null;
|
||||
$.fn.editableform.errorBlockClass = 'ui-state-error';
|
||||
|
||||
}(window.jQuery));
|
105
src/editable-form/editable-form-utils.js
Normal file
105
src/editable-form/editable-form-utils.js
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* EditableForm utils
|
||||
*/
|
||||
(function ($) {
|
||||
$.extend($.fn.editableform, {
|
||||
utils: {
|
||||
/**
|
||||
* classic JS inheritance function
|
||||
*/
|
||||
inherit: function (Child, Parent) {
|
||||
var F = function() { };
|
||||
F.prototype = Parent.prototype;
|
||||
Child.prototype = new F();
|
||||
Child.prototype.constructor = Child;
|
||||
Child.superclass = Parent.prototype;
|
||||
},
|
||||
|
||||
/**
|
||||
* set caret position in input
|
||||
* see http://stackoverflow.com/questions/499126/jquery-set-cursor-position-in-text-area
|
||||
*/
|
||||
setCursorPosition: function(elem, pos) {
|
||||
if (elem.setSelectionRange) {
|
||||
elem.setSelectionRange(pos, pos);
|
||||
} else if (elem.createTextRange) {
|
||||
var range = elem.createTextRange();
|
||||
range.collapse(true);
|
||||
range.moveEnd('character', pos);
|
||||
range.moveStart('character', pos);
|
||||
range.select();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* function to parse JSON in *single* quotes. (jquery automatically parse only double quotes)
|
||||
* That allows such code as: <a data-source="{'a': 'b', 'c': 'd'}">
|
||||
* safe = true --> means no exception will be thrown
|
||||
* for details see http://stackoverflow.com/questions/7410348/how-to-set-json-format-to-html5-data-attributes-in-the-jquery
|
||||
*/
|
||||
tryParseJson: function(s, safe) {
|
||||
if (typeof s === 'string' && s.length && s.match(/^\{.*\}$/)) {
|
||||
if (safe) {
|
||||
try {
|
||||
/*jslint evil: true*/
|
||||
s = (new Function('return ' + s))();
|
||||
/*jslint evil: false*/
|
||||
} catch (e) {} finally {
|
||||
return s;
|
||||
}
|
||||
} else {
|
||||
/*jslint evil: true*/
|
||||
s = (new Function('return ' + s))();
|
||||
/*jslint evil: false*/
|
||||
}
|
||||
}
|
||||
return s;
|
||||
},
|
||||
|
||||
/**
|
||||
* slice object by specified keys
|
||||
*/
|
||||
sliceObj: function(obj, keys, caseSensitive /* default: false */) {
|
||||
var key, keyLower, newObj = {};
|
||||
|
||||
if (!$.isArray(keys) || !keys.length) {
|
||||
return newObj;
|
||||
}
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
key = keys[i];
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
newObj[key] = obj[key];
|
||||
}
|
||||
|
||||
if(caseSensitive === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//when getting data-* attributes via $.data() it's converted to lowercase.
|
||||
//details: http://stackoverflow.com/questions/7602565/using-data-attributes-with-jquery
|
||||
//workaround is code below.
|
||||
keyLower = key.toLowerCase();
|
||||
if (obj.hasOwnProperty(keyLower)) {
|
||||
newObj[key] = obj[keyLower];
|
||||
}
|
||||
}
|
||||
|
||||
return newObj;
|
||||
},
|
||||
|
||||
/**
|
||||
* exclude complex objects from $.data() before pass to config
|
||||
*/
|
||||
getConfigData: function($element) {
|
||||
var data = {};
|
||||
$.each($element.data(), function(k, v) {
|
||||
if(typeof v !== 'object' || (v && typeof v === 'object' && v.constructor === Object)) {
|
||||
data[k] = v;
|
||||
}
|
||||
});
|
||||
return data;
|
||||
}
|
||||
}
|
||||
});
|
||||
}(window.jQuery));
|
43
src/editable-form/editable-form.css
Normal file
43
src/editable-form/editable-form.css
Normal file
@@ -0,0 +1,43 @@
|
||||
.editableform,
|
||||
.editableform div.control-group {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.editableform-loading {
|
||||
background: url('img/loading.gif') center center no-repeat;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.editable-inline .editableform-loading {
|
||||
background-position: left 5px;
|
||||
}
|
||||
|
||||
.editable-error-block {
|
||||
max-width: 300px;
|
||||
margin-top: 3px;
|
||||
margin-bottom: 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.editable-error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.editableform input,
|
||||
.editableform select,
|
||||
.editableform textarea {
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* for inline datepicker do not to inherit from table (bootstrap) */
|
||||
.table-striped .editableform table td, .editableform table th {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.table-striped .editableform table tr:nth-child(2n+1) td,
|
||||
.table-striped .editableform table tr:nth-child(2n+1) th {
|
||||
background-color: transparent;
|
||||
}
|
250
src/editable-form/editable-form.js
Normal file
250
src/editable-form/editable-form.js
Normal file
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* Editable-form plugin
|
||||
* Form with single input element, two buttons and automatic loader, shown on init/submit
|
||||
* Plugin applied to DIV tag and show form inside
|
||||
* Input must be one of following types:
|
||||
* - text
|
||||
* - textarea
|
||||
* - select
|
||||
* - date
|
||||
* - <your input here>
|
||||
*
|
||||
* EVENTS:
|
||||
* - render
|
||||
* - resize
|
||||
* - save
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
var EditableForm = function (element, options) {
|
||||
this.options = $.extend({}, $.fn.editableform.defaults, options);
|
||||
this.$container = $(element); //div, containing form
|
||||
this.initInput();
|
||||
};
|
||||
|
||||
EditableForm.prototype = {
|
||||
constructor: EditableForm,
|
||||
initInput: function() {
|
||||
var TypeConstructor, typeOptions;
|
||||
|
||||
//create input of specified type
|
||||
if(typeof $.fn.editableform.types[this.options.type] === 'function') {
|
||||
TypeConstructor = $.fn.editableform.types[this.options.type];
|
||||
typeOptions = $.fn.editableform.utils.sliceObj(this.options, Object.keys(TypeConstructor.defaults));
|
||||
this.input = new TypeConstructor(typeOptions);
|
||||
} else {
|
||||
$.error('Unknown type: '+ this.options.type);
|
||||
return;
|
||||
}
|
||||
|
||||
this.value = this.input.str2value(this.options.value);
|
||||
},
|
||||
initTemplate: function() {
|
||||
this.$form = $($.fn.editableform.template);
|
||||
},
|
||||
render: function() {
|
||||
this.$loading = $(this.options.loading);
|
||||
this.$container.empty().append(this.$loading);
|
||||
this.showLoading();
|
||||
|
||||
this.initTemplate();
|
||||
|
||||
this.$container.triggerHandler('rendering');
|
||||
|
||||
//render input
|
||||
$.when(this.input.render())
|
||||
.then($.proxy(function () {
|
||||
this.$form.find('div.control-group').prepend(this.input.$input);
|
||||
this.$form.find('button[type=button]').click($.proxy(this.cancel, this));
|
||||
this.$container.append(this.$form);
|
||||
if(this.input.error) {
|
||||
this.error(this.input.error);
|
||||
this.$form.find('button[type=submit]').attr('disabled', true);
|
||||
this.input.$input.attr('disabled', true);
|
||||
} else {
|
||||
this.error(false);
|
||||
this.input.$input.removeAttr('disabled');
|
||||
this.$form.find('button[type=submit]').removeAttr('disabled');
|
||||
this.input.value2input(this.value);
|
||||
this.$form.submit($.proxy(this.submit, this));
|
||||
}
|
||||
this.showForm();
|
||||
}, this));
|
||||
},
|
||||
cancel: function() {
|
||||
this.$container.triggerHandler('cancel');
|
||||
},
|
||||
showLoading: function() {
|
||||
var fw, fh, iw, ih;
|
||||
//set loading size equal to form
|
||||
if(this.$form) {
|
||||
fh = this.$form.outerHeight() || 0;
|
||||
fw = this.$form.outerWidth() || 0;
|
||||
ih = (this.input && this.input.$input.outerHeight()) || 0;
|
||||
iw = (this.input && this.input.$input.outerWidth()) || 0;
|
||||
if(fh || ih) {
|
||||
this.$loading.height(fh > ih ? fh : ih);
|
||||
}
|
||||
if(fw || iw) {
|
||||
this.$loading.width(fw > iw ? fw : iw);
|
||||
}
|
||||
this.$form.hide();
|
||||
}
|
||||
this.$loading.show();
|
||||
},
|
||||
|
||||
showForm: function() {
|
||||
this.$loading.hide();
|
||||
this.$form.show();
|
||||
this.input.activate();
|
||||
this.$container.triggerHandler('show');
|
||||
},
|
||||
|
||||
error: function(msg) {
|
||||
var $group = this.$form.find('.control-group'),
|
||||
$block = this.$form.find('.editable-error-block');
|
||||
|
||||
if(msg === false) {
|
||||
$group.removeClass($.fn.editableform.errorGroupClass);
|
||||
$block.removeClass($.fn.editableform.errorBlockClass).empty().hide();
|
||||
} else {
|
||||
$group.addClass($.fn.editableform.errorGroupClass);
|
||||
$block.addClass($.fn.editableform.errorBlockClass).text(msg).show();
|
||||
}
|
||||
},
|
||||
|
||||
submit: function(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
var error,
|
||||
//get value from input
|
||||
newValue = this.input.input2value(),
|
||||
newValueStr;
|
||||
|
||||
//validation
|
||||
if (error = this.validate(newValue)) {
|
||||
this.error(error);
|
||||
this.showForm();
|
||||
return;
|
||||
}
|
||||
|
||||
//value as string
|
||||
newValueStr = this.input.value2str(newValue);
|
||||
|
||||
//if value not changed --> cancel
|
||||
/*jslint eqeq: true*/
|
||||
if (newValueStr == this.input.value2str(this.value)) {
|
||||
/*jslint eqeq: false*/
|
||||
this.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
//sending data to server
|
||||
$.when(this.save(newValueStr))
|
||||
.done($.proxy(function(response) {
|
||||
this.error(false);
|
||||
this.value = newValue;
|
||||
this.$container.triggerHandler('save', {newValue: newValue, response: response});
|
||||
}, this))
|
||||
.fail($.proxy(function(xhr) {
|
||||
this.error(xhr.responseText || xhr.statusText || 'Unknown error!');
|
||||
this.showForm();
|
||||
}, this));
|
||||
},
|
||||
|
||||
save: function(value) {
|
||||
var pk = (typeof this.options.pk === 'function') ? this.options.pk.call(this) : this.options.pk,
|
||||
send = !!((this.options.url !== undefined) && (this.options.url !== null) && ((this.options.send === 'always') || (this.options.send === 'auto' && pk))),
|
||||
params;
|
||||
|
||||
if (send) { //send to server
|
||||
this.showLoading();
|
||||
|
||||
//try parse json in single quotes
|
||||
this.options.params = $.fn.editableform.utils.tryParseJson(this.options.params, true);
|
||||
|
||||
params = $.extend({}, this.options.params, {
|
||||
name: this.options.name || '',
|
||||
value: value,
|
||||
pk: pk
|
||||
});
|
||||
|
||||
//send ajax to server and return deferred object
|
||||
return $.ajax({
|
||||
url : (typeof this.options.url === 'function') ? this.options.url.call(this) : this.options.url,
|
||||
data : params,
|
||||
type : 'post',
|
||||
dataType: 'json'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
validate: function (value) {
|
||||
if (value === undefined) {
|
||||
value = this.value;
|
||||
}
|
||||
if (typeof this.options.validate === 'function') {
|
||||
return this.options.validate.call(this, value);
|
||||
}
|
||||
},
|
||||
|
||||
option: function(key, value) {
|
||||
this.options[key] = value;
|
||||
}
|
||||
};
|
||||
|
||||
//jquery plugin definition
|
||||
$.fn.editableform = function (option) {
|
||||
var args = arguments;
|
||||
return this.each(function () {
|
||||
var $this = $(this),
|
||||
data = $this.data('editableform'),
|
||||
options = typeof option === 'object' && option;
|
||||
if (!data) {
|
||||
$this.data('editableform', (data = new EditableForm(this, options)));
|
||||
}
|
||||
|
||||
if (typeof option === 'string') { //call method
|
||||
data[option].apply(data, Array.prototype.slice.call(args, 1));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
//keep link to constructor to allow inheritance
|
||||
$.fn.editableform.Constructor = EditableForm;
|
||||
|
||||
//defaults
|
||||
$.fn.editableform.defaults = {
|
||||
/* see also defaults for input */
|
||||
type: 'text',
|
||||
url:null,
|
||||
params:null,
|
||||
name: null,
|
||||
pk: null,
|
||||
value: null, //initial value
|
||||
send: 'auto', //always|auto|never
|
||||
loading: '<div class="editableform-loading"></div>',
|
||||
validate: null
|
||||
};
|
||||
|
||||
/*
|
||||
Note: following params could redefined in engine: bootstrap or jqueryui:
|
||||
Classes 'control-group' and 'editable-error-block' must always present!
|
||||
*/
|
||||
$.fn.editableform.template = '<form class="form-inline editableform"><div class="control-group">' +
|
||||
' <button type="submit">Ok</button> <button type="button">Cancel</button></div>' +
|
||||
'<div class="editable-error-block"></div>' +
|
||||
'</form>';
|
||||
|
||||
//error class attahced to control-group
|
||||
$.fn.editableform.errorGroupClass = null;
|
||||
//error class attahced to editable-error-block
|
||||
$.fn.editableform.errorBlockClass = 'editable-error';
|
||||
|
||||
|
||||
//input types
|
||||
$.fn.editableform.types = {};
|
||||
$.fn.editableform.utils = {};
|
||||
|
||||
}(window.jQuery));
|
BIN
src/editable-form/img/loading.gif
Normal file
BIN
src/editable-form/img/loading.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
Reference in New Issue
Block a user