Merge branch 'release-1.1.1'
This commit is contained in:
commit
b2009d7c45
CHANGELOG.txtREADME.mdgrunt.jspackage.json
src
containers
editable-container.csseditable-container.jseditable-inline.jseditable-poshytip.jseditable-tooltip.js
editable-form
element
inputs-ext/address
inputs
test
@ -1,5 +1,16 @@
|
||||
X-editable changelog
|
||||
=============================
|
||||
|
||||
|
||||
Version 1.1.1 Nov 30, 2012
|
||||
----------------------------
|
||||
[enh] 'showbuttons' option to hide buttons in form (vitalets)
|
||||
[enh] object can be passed in 'option' method to set several options at once (vitalets)
|
||||
[enh #20] toggle editable by 'dblclick' and 'mouseenter' (vitalets)
|
||||
[enh] added 'inputs-ext' directory with sample input 'address'. They will not be concatenated to main files (vitalets)
|
||||
[enh #13] 'onblur' option: to cancel, submit or ignore when user clicks outside the form (vitalets)
|
||||
[enh] 'ajaxOptions' parameter for advanced ajax configuration (vitalets)
|
||||
[enh] 'success' callback can return object to overwrite submitted value (vitalets)
|
||||
|
||||
|
||||
Version 1.1.0 Nov 27, 2012
|
||||
|
@ -7,7 +7,7 @@ It is a new life of [bootstrap-editable plugin](http://github.com/vitalets/boots
|
||||
See **http://vitalets.github.com/x-editable**
|
||||
|
||||
## Reporting issues
|
||||
When creating issues please provide jsFiddle example. You can just fork [this fiddle](http://jsfiddle.net/xBB5x/1/) as starting point.
|
||||
When creating issues please provide jsFiddle example. You can just fork [this fiddle](http://jsfiddle.net/xBB5x/5/) as starting point.
|
||||
Your feedback is very appreciated!
|
||||
|
||||
## Contribution
|
||||
@ -60,7 +60,7 @@ Or use grunt's _qunit_ task <code>grunt test</code>. For that you also need to [
|
||||
You will get distributive in **lib/dist** and updated docs in **gh-pages/*.html**.
|
||||
Do not edit **index.html** and **docs.html** directly! Instead look at [Handlebars](https://github.com/wycats/handlebars.js) templates in **generator/templates**.
|
||||
|
||||
6.Commit changes on <code>dev</code> branch and make pull request as usual.
|
||||
6.Commit changes on <code>dev</code> / <code>gh-pages-dev</code> branch and make pull request as usual.
|
||||
|
||||
Thanks for your support!
|
||||
|
||||
|
30
grunt.js
30
grunt.js
@ -151,7 +151,8 @@ module.exports = function(grunt) {
|
||||
'src/element/*.js',
|
||||
'src/inputs/*.js',
|
||||
'src/inputs/date/date.js',
|
||||
'src/inputs/dateui/dateui.js'
|
||||
'src/inputs/dateui/dateui.js',
|
||||
'src/inputs-ext/**/*.js'
|
||||
]
|
||||
},
|
||||
/*
|
||||
@ -192,29 +193,20 @@ module.exports = function(grunt) {
|
||||
flatten: true
|
||||
}
|
||||
},
|
||||
inputs_ext: {
|
||||
files: {
|
||||
'<%= dist %>/inputs-ext/': 'src/inputs-ext/**'
|
||||
},
|
||||
options: {
|
||||
basePath: 'inputs-ext'
|
||||
}
|
||||
},
|
||||
ui_datepicker: {
|
||||
files: {
|
||||
//copy jquery ui datepicker
|
||||
'<%= dist %>/jquery-editable/jquery-ui-datepicker/' : 'src/inputs/dateui/jquery-ui-datepicker/**'
|
||||
}
|
||||
}
|
||||
},
|
||||
yuidoc: {
|
||||
compile: {
|
||||
name: '<%= pkg.title || pkg.name %>',
|
||||
description: '<%= pkg.description %>',
|
||||
version: '<%= pkg.version %>',
|
||||
url: "<%= pkg.homepage %>",
|
||||
// logo: 'src/editable-form/img/loading.gif',
|
||||
options: {
|
||||
paths: "src/",
|
||||
ignorePaths: ['src/inputs/date/locales'],
|
||||
outdir: "../docs/",
|
||||
// theme: "simple",
|
||||
themedir: "../yuidoc-theme"
|
||||
//themedir: "../yuidoc-bootstrap-theme-master"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
//compress does not work properly for MAC OS (see https://github.com/vitalets/bootstrap-editable/issues/19)
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "X-editable",
|
||||
"title": "X-editable",
|
||||
"description": "In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"homepage": "http://github.com/vitalets/x-editable",
|
||||
"author": {
|
||||
"name": "Vitaliy Potapov",
|
||||
|
@ -5,4 +5,9 @@
|
||||
.editable-container.popover {
|
||||
/* width: 300px;*/ /* debug */
|
||||
width: auto; /* without this rule popover does not stretch */
|
||||
}
|
||||
|
||||
.editable-container.editable-inline {
|
||||
display: inline;
|
||||
vertical-align: middle;
|
||||
}
|
@ -27,7 +27,33 @@ Applied as jQuery method.
|
||||
//bind 'destroyed' listener to destroy container when element is removed from dom
|
||||
this.$element.on('destroyed', $.proxy(function(){
|
||||
this.destroy();
|
||||
}, this));
|
||||
}, this));
|
||||
|
||||
//attach document handlers (once)
|
||||
if(!$(document).data('editable-handlers-attached')) {
|
||||
//close all on escape
|
||||
$(document).on('keyup.editable', function (e) {
|
||||
if (e.which === 27) {
|
||||
$('.editable-open').editableContainer('hide');
|
||||
//todo: return focus on element
|
||||
}
|
||||
});
|
||||
|
||||
//close containers when click outside
|
||||
$(document).on('click.editable', function(e) {
|
||||
var $target = $(e.target);
|
||||
|
||||
//if click inside some editableContainer --> no nothing
|
||||
if($target.is('.editable-container') || $target.parents('.editable-container').length || $target.parents('.ui-datepicker-header').length) {
|
||||
return;
|
||||
} else {
|
||||
//close all open containers (except one)
|
||||
EditableContainer.prototype.closeOthers(e.target);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).data('editable-handlers-attached', true);
|
||||
}
|
||||
},
|
||||
|
||||
//split options on containerOptions and formOptions
|
||||
@ -93,11 +119,22 @@ Applied as jQuery method.
|
||||
/**
|
||||
Shows container with form
|
||||
@method show()
|
||||
@param {boolean} closeAll Wether to close all other editable containers when showing this one. Default true.
|
||||
**/
|
||||
show: function () {
|
||||
show: function (closeAll) {
|
||||
this.$element.addClass('editable-open');
|
||||
if(closeAll !== false) {
|
||||
//close all open containers (except this)
|
||||
this.closeOthers(this.$element[0]);
|
||||
}
|
||||
|
||||
this.innerShow();
|
||||
},
|
||||
|
||||
/* internal show method. To be overwritten in child classes */
|
||||
innerShow: function () {
|
||||
this.call('show');
|
||||
this.tip().addClass('editable-container');
|
||||
|
||||
this.initForm();
|
||||
this.tip().find(this.innerCss).empty().append(this.$form);
|
||||
this.$form.editableform('render');
|
||||
@ -108,10 +145,11 @@ Applied as jQuery method.
|
||||
@method hide()
|
||||
**/
|
||||
hide: function() {
|
||||
if(!this.tip() || !this.tip().is(':visible')) {
|
||||
if(!this.tip() || !this.tip().is(':visible') || !this.$element.hasClass('editable-open')) {
|
||||
return;
|
||||
}
|
||||
this.call('hide');
|
||||
this.$element.removeClass('editable-open');
|
||||
this.innerHide();
|
||||
/**
|
||||
Fired when container was hidden. It occurs on both save or cancel.
|
||||
|
||||
@ -121,15 +159,21 @@ Applied as jQuery method.
|
||||
this.$element.triggerHandler('hidden');
|
||||
},
|
||||
|
||||
/* internal hide method. To be overwritten in child classes */
|
||||
innerHide: function () {
|
||||
this.call('hide');
|
||||
},
|
||||
|
||||
/**
|
||||
Toggles container visibility (show / hide)
|
||||
@method toggle()
|
||||
@param {boolean} closeAll Wether to close all other editable containers when showing this one. Default true.
|
||||
**/
|
||||
toggle: function() {
|
||||
toggle: function(closeAll) {
|
||||
if(this.tip && this.tip().is(':visible')) {
|
||||
this.hide();
|
||||
} else {
|
||||
this.show();
|
||||
this.show(closeAll);
|
||||
}
|
||||
},
|
||||
|
||||
@ -210,6 +254,44 @@ Applied as jQuery method.
|
||||
**/
|
||||
destroy: function() {
|
||||
this.call('destroy');
|
||||
},
|
||||
|
||||
/*
|
||||
Closes other containers except one related to passed element.
|
||||
Other containers can be cancelled or submitted (depends on onblur option)
|
||||
*/
|
||||
closeOthers: function(element) {
|
||||
$('.editable-open').each(function(i, el){
|
||||
//do nothing with passed element
|
||||
if(el === element) {
|
||||
return;
|
||||
}
|
||||
|
||||
//otherwise cancel or submit all open containers
|
||||
var $el = $(el),
|
||||
ec = $el.data('editableContainer');
|
||||
|
||||
if(!ec) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(ec.options.onblur === 'cancel') {
|
||||
$el.data('editableContainer').hide();
|
||||
} else if(ec.options.onblur === 'submit') {
|
||||
$el.data('editableContainer').tip().find('form').submit();
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
Activates input of visible container (e.g. set focus)
|
||||
@method activate()
|
||||
**/
|
||||
activate: function() {
|
||||
if(this.tip && this.tip().is(':visible') && this.$form) {
|
||||
this.$form.data('editableform').input.activate();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
@ -248,7 +330,7 @@ Applied as jQuery method.
|
||||
//store constructor
|
||||
$.fn.editableContainer.Constructor = EditableContainer;
|
||||
|
||||
//defaults - must be redefined!
|
||||
//defaults
|
||||
$.fn.editableContainer.defaults = {
|
||||
/**
|
||||
Initial value of form input
|
||||
@ -275,7 +357,16 @@ Applied as jQuery method.
|
||||
@default true
|
||||
@private
|
||||
**/
|
||||
autohide: true
|
||||
autohide: true,
|
||||
/**
|
||||
Action when user clicks outside the container. Can be <code>cancel|submit|ignore</code>.
|
||||
Setting <code>ignore</code> allows to have several containers open.
|
||||
|
||||
@property onblur
|
||||
@type string
|
||||
@default 'cancel'
|
||||
**/
|
||||
onblur: 'cancel'
|
||||
};
|
||||
|
||||
/*
|
||||
@ -290,4 +381,4 @@ Applied as jQuery method.
|
||||
}
|
||||
};
|
||||
|
||||
}(window.jQuery));
|
||||
}(window.jQuery));
|
||||
|
@ -26,7 +26,7 @@
|
||||
return this.$form;
|
||||
},
|
||||
|
||||
show: function () {
|
||||
innerShow: function () {
|
||||
this.$element.hide();
|
||||
|
||||
if(this.$form) {
|
||||
@ -40,19 +40,13 @@
|
||||
this.$form.editableform('render');
|
||||
},
|
||||
|
||||
hide: function () {
|
||||
if(!this.tip() || !this.tip().is(':visible')) {
|
||||
return;
|
||||
}
|
||||
innerHide: function () {
|
||||
this.$form.hide(this.options.anim, $.proxy(function() {
|
||||
this.$element.show();
|
||||
//return focus on element
|
||||
if (this.options.enablefocus) {
|
||||
this.$element.focus();
|
||||
}
|
||||
|
||||
//trigger event
|
||||
this.$element.triggerHandler('hidden');
|
||||
}, this));
|
||||
},
|
||||
|
||||
|
@ -28,11 +28,10 @@
|
||||
this.call('update', $content);
|
||||
},
|
||||
|
||||
show: function () {
|
||||
innerShow: function () {
|
||||
this.$form.editableform('render');
|
||||
this.tip().addClass('editable-container');
|
||||
|
||||
this.call('show');
|
||||
this.tip().addClass('editable-container');
|
||||
this.$form.data('editableform').input.activate();
|
||||
},
|
||||
|
||||
|
@ -50,7 +50,7 @@
|
||||
return this.container()._find(this.container().element);
|
||||
},
|
||||
|
||||
show: function() {
|
||||
innerShow: function() {
|
||||
this.call('open');
|
||||
this.tip().addClass('editable-container');
|
||||
|
||||
@ -62,12 +62,8 @@
|
||||
this.$form.editableform('render');
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
if(!this.tip() || !this.tip().is(':visible')) {
|
||||
return;
|
||||
}
|
||||
innerHide: function() {
|
||||
this.call('close');
|
||||
this.$element.triggerHandler('hidden');
|
||||
},
|
||||
|
||||
setPosition: function() {
|
||||
|
@ -5,11 +5,8 @@ Editableform based on Twitter Bootstrap
|
||||
|
||||
$.extend($.fn.editableform.Constructor.prototype, {
|
||||
initTemplate: function() {
|
||||
this.$form = $($.fn.editableform.template);
|
||||
this.$form.find('.editable-error-block').addClass('help-block');
|
||||
|
||||
//buttons
|
||||
this.$form.find('div.editable-buttons').append($.fn.editableform.buttons);
|
||||
this.$form = $($.fn.editableform.template);
|
||||
this.$form.find('.editable-error-block').addClass('help-block');
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -4,10 +4,7 @@ Editableform based on jQuery UI
|
||||
(function ($) {
|
||||
|
||||
$.extend($.fn.editableform.Constructor.prototype, {
|
||||
initTemplate: function() {
|
||||
this.$form = $($.fn.editableform.template);
|
||||
|
||||
//buttons
|
||||
initButtons: function() {
|
||||
this.$form.find('.editable-buttons').append($.fn.editableform.buttons);
|
||||
this.$form.find('.editable-submit').button({
|
||||
icons: { primary: "ui-icon-check" },
|
||||
@ -17,7 +14,6 @@ Editableform based on jQuery UI
|
||||
icons: { primary: "ui-icon-closethick" },
|
||||
text: false
|
||||
}).removeAttr('title');
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -38,7 +38,8 @@
|
||||
.editableform-loading {
|
||||
background: url('img/loading.gif') center center no-repeat;
|
||||
height: 25px;
|
||||
width: auto;
|
||||
width: auto;
|
||||
min-width: 25px;
|
||||
}
|
||||
|
||||
.editable-inline .editableform-loading {
|
||||
|
@ -11,7 +11,7 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
||||
|
||||
var EditableForm = function (element, options) {
|
||||
this.options = $.extend({}, $.fn.editableform.defaults, options);
|
||||
this.$element = $(element); //div (usually), containing form. not form tag!
|
||||
this.$element = $(element); //div, containing form. Not form tag! Not editable-element.
|
||||
this.initInput();
|
||||
};
|
||||
|
||||
@ -34,9 +34,9 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
||||
},
|
||||
initTemplate: function() {
|
||||
this.$form = $($.fn.editableform.template);
|
||||
|
||||
//buttons
|
||||
this.$form.find('div.editable-buttons').append($.fn.editableform.buttons);
|
||||
},
|
||||
initButtons: function() {
|
||||
this.$form.find('.editable-buttons').append($.fn.editableform.buttons);
|
||||
},
|
||||
/**
|
||||
Renders editableform
|
||||
@ -47,8 +47,14 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
||||
this.$loading = $($.fn.editableform.loading);
|
||||
this.$element.empty().append(this.$loading);
|
||||
this.showLoading();
|
||||
|
||||
|
||||
//init form template and buttons
|
||||
this.initTemplate();
|
||||
if(this.options.showbuttons) {
|
||||
this.initButtons();
|
||||
} else {
|
||||
this.$form.find('.editable-buttons').remove();
|
||||
}
|
||||
|
||||
/**
|
||||
Fired when rendering starts
|
||||
@ -63,6 +69,11 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
||||
//input
|
||||
this.$form.find('div.editable-input').append(this.input.$input);
|
||||
|
||||
//automatically submit inputs when no buttons shown
|
||||
if(!this.options.showbuttons) {
|
||||
this.input.autosubmit();
|
||||
}
|
||||
|
||||
//"clear" link
|
||||
if(this.input.$clear) {
|
||||
this.$form.find('div.editable-input').append($('<div class="editable-clear">').append(this.input.$clear));
|
||||
@ -150,11 +161,10 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
||||
submit: function(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
|
||||
var error,
|
||||
//get value from input
|
||||
newValue = this.input.input2value(),
|
||||
newValueStr;
|
||||
newValue = this.input.input2value(), //get new value from input
|
||||
newValueStr;
|
||||
|
||||
//validation
|
||||
if (error = this.validate(newValue)) {
|
||||
@ -162,14 +172,14 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
||||
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*/
|
||||
/*jslint eqeq: false*/
|
||||
this.cancel();
|
||||
return;
|
||||
}
|
||||
@ -177,13 +187,20 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
||||
//sending data to server
|
||||
$.when(this.save(newValueStr))
|
||||
.done($.proxy(function(response) {
|
||||
var error;
|
||||
//call success callback. if it returns string --> show error
|
||||
if(error = this.options.success.call(this, response, newValue)) {
|
||||
this.error(error);
|
||||
//run success callback
|
||||
var res = typeof this.options.success === 'function' ? this.options.success.call(this, response, newValue) : null;
|
||||
|
||||
//if success callback returns string --> show error
|
||||
if(res && typeof res === 'string') {
|
||||
this.error(res);
|
||||
this.showForm();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//if success callback returns object like {newValue: <something>} --> use that value instead of submitted
|
||||
if(res && typeof res === 'object' && res.hasOwnProperty('newValue')) {
|
||||
newValue = res.newValue;
|
||||
}
|
||||
|
||||
//clear error message
|
||||
this.error(false);
|
||||
@ -212,7 +229,7 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
||||
save: function(value) {
|
||||
var pk = (typeof this.options.pk === 'function') ? this.options.pk.call(this) : this.options.pk,
|
||||
send = !!(typeof this.options.url === 'function' || (this.options.url && ((this.options.send === 'always') || (this.options.send === 'auto' && pk)))),
|
||||
params;
|
||||
params, ajaxOptions;
|
||||
|
||||
if (send) { //send to server
|
||||
this.showLoading();
|
||||
@ -236,12 +253,14 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
||||
if(typeof this.options.url === 'function') { //user's function
|
||||
return this.options.url.call(this, params);
|
||||
} else { //send ajax to server and return deferred object
|
||||
return $.ajax({
|
||||
ajaxOptions = $.extend({
|
||||
url : this.options.url,
|
||||
data : params,
|
||||
type : 'post',
|
||||
dataType: 'json'
|
||||
});
|
||||
}, this.options.ajaxOptions);
|
||||
|
||||
return $.ajax(ajaxOptions);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -339,7 +358,7 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
||||
/**
|
||||
Additional params for submit. Function can be used to calculate params dynamically
|
||||
@example
|
||||
params: function() {
|
||||
params: function(params) {
|
||||
return { a: 1 };
|
||||
}
|
||||
|
||||
@ -398,9 +417,13 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
||||
**/
|
||||
validate: null,
|
||||
/**
|
||||
Success callback. Called when value successfully sent on server and response status = 200.
|
||||
Can be used to process json response. If this function returns string - means error occured and string is shown as error message.
|
||||
|
||||
Success callback. Called when value successfully sent on server and **response status = 200**.
|
||||
Usefull to work with json response. For example, if your backend response can be <code>{success: true}</code>
|
||||
or <code>{success: false, msg: "server error"}</code> you can check it inside this callback.
|
||||
If it returns **string** - means error occured and string is shown as error message.
|
||||
If it returns **object like** <code>{newValue: <something>}</code> - it overwrites value, submitted by user.
|
||||
Otherwise newValue simply rendered into element.
|
||||
|
||||
@property success
|
||||
@type function
|
||||
@default null
|
||||
@ -409,7 +432,36 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
|
||||
if(!response.success) return response.msg;
|
||||
}
|
||||
**/
|
||||
success: function(response, newValue) {}
|
||||
success: function(response, newValue) {},
|
||||
/**
|
||||
Additional options for ajax request.
|
||||
List of values: http://api.jquery.com/jQuery.ajax
|
||||
|
||||
@property ajaxOptions
|
||||
@type object
|
||||
@default null
|
||||
**/
|
||||
ajaxOptions: null,
|
||||
/**
|
||||
Wether to show buttons or not.
|
||||
Form without buttons can be auto-submitted by input or by onblur = 'submit'.
|
||||
|
||||
@property showbuttons
|
||||
@type boolean
|
||||
@default true
|
||||
**/
|
||||
showbuttons: true
|
||||
|
||||
/*todo:
|
||||
Submit strategy. Can be <code>normal|never</code>
|
||||
<code>submitmode='never'</code> usefull for turning into classic form several inputs and submitting them together manually.
|
||||
Works pretty with <code>showbuttons=false</code>
|
||||
|
||||
@property submitmode
|
||||
@type string
|
||||
@default normal
|
||||
*/
|
||||
// submitmode: 'normal'
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -47,34 +47,32 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
this.value = this.input.html2value($.trim(this.$element.html()));
|
||||
isValueByText = true;
|
||||
} else {
|
||||
this.value = this.input.str2value($.trim(this.options.value));
|
||||
if(typeof this.options.value === 'string') {
|
||||
this.options.value = $.trim(this.options.value);
|
||||
}
|
||||
this.value = this.input.str2value(this.options.value);
|
||||
}
|
||||
|
||||
//attach handler to close any container on escape
|
||||
$(document).off('keyup.editable').on('keyup.editable', function (e) {
|
||||
if (e.which === 27) {
|
||||
$('.editable-container').find('.editable-cancel').click();
|
||||
}
|
||||
});
|
||||
|
||||
//attach handler to close container when click outside
|
||||
$(document).off('click.editable').on('click.editable', function(e) {
|
||||
var $target = $(e.target);
|
||||
//if click inside container --> do nothing
|
||||
if($target.is('.editable-container') || $target.parents('.editable-container').length || $target.parents('.ui-datepicker-header').length) {
|
||||
return;
|
||||
}
|
||||
//close all other containers
|
||||
$('.editable-container').find('.editable-cancel').click();
|
||||
});
|
||||
|
||||
//add 'editable' class
|
||||
this.$element.addClass('editable');
|
||||
|
||||
//attach click handler. In disabled mode it just prevent default action (useful for links)
|
||||
if(this.options.toggle === 'click') {
|
||||
//attach handler activating editable. In disabled mode it just prevent default action (useful for links)
|
||||
if(this.options.toggle !== 'manual') {
|
||||
this.$element.addClass('editable-click');
|
||||
this.$element.on('click.editable', $.proxy(this.click, this));
|
||||
this.$element.on(this.options.toggle + '.editable', $.proxy(function(e){
|
||||
e.preventDefault();
|
||||
//stop propagation not required anymore because in document click handler it checks event target
|
||||
//e.stopPropagation();
|
||||
|
||||
if(this.options.toggle === 'mouseenter') {
|
||||
//for hover only show container
|
||||
this.show();
|
||||
} else {
|
||||
//when toggle='click' we should not close all other containers as they will be closed automatically in document click listener
|
||||
var closeAll = (this.options.toggle !== 'click');
|
||||
this.toggle(closeAll);
|
||||
}
|
||||
}, this));
|
||||
} else {
|
||||
this.$element.attr('tabindex', -1); //do not stop focus on element when toggled manually
|
||||
}
|
||||
@ -115,7 +113,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
this.options.disabled = false;
|
||||
this.$element.removeClass('editable-disabled');
|
||||
this.handleEmpty();
|
||||
if(this.options.toggle === 'click') {
|
||||
if(this.options.toggle !== 'manual') {
|
||||
if(this.$element.attr('tabindex') === '-1') {
|
||||
this.$element.removeAttr('tabindex');
|
||||
}
|
||||
@ -151,10 +149,24 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
Sets new option
|
||||
|
||||
@method option(key, value)
|
||||
@param {string} key
|
||||
@param {mixed} value
|
||||
@param {string|object} key option name or object with several options
|
||||
@param {mixed} value option new value
|
||||
@example
|
||||
$('.editable').editable('option', 'pk', 2);
|
||||
**/
|
||||
option: function(key, value) {
|
||||
//set option(s) by object
|
||||
if(key && typeof key === 'object') {
|
||||
$.each(key, $.proxy(function(k, v){
|
||||
this.option($.trim(k), v);
|
||||
}, this));
|
||||
return;
|
||||
}
|
||||
|
||||
//set option by string
|
||||
this.options[key] = value;
|
||||
|
||||
//disabled
|
||||
if(key === 'disabled') {
|
||||
if(value) {
|
||||
this.disable();
|
||||
@ -163,12 +175,15 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.options[key] = value;
|
||||
|
||||
//value
|
||||
if(key === 'value') {
|
||||
this.setValue(value);
|
||||
}
|
||||
|
||||
//transfer new option to container!
|
||||
if(this.container) {
|
||||
this.container.option(key, value);
|
||||
this.container.option(key, value);
|
||||
}
|
||||
},
|
||||
|
||||
@ -193,21 +208,12 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
}
|
||||
},
|
||||
|
||||
click: function (e) {
|
||||
e.preventDefault();
|
||||
if(this.options.disabled) {
|
||||
return;
|
||||
}
|
||||
//stop propagation bacause document listen any click to hide all editableContainers
|
||||
e.stopPropagation();
|
||||
this.toggle();
|
||||
},
|
||||
|
||||
/**
|
||||
Shows container with form
|
||||
@method show()
|
||||
@param {boolean} closeAll Wether to close all other editable containers when showing this one. Default true.
|
||||
**/
|
||||
show: function () {
|
||||
show: function (closeAll) {
|
||||
if(this.options.disabled) {
|
||||
return;
|
||||
}
|
||||
@ -216,7 +222,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
if(!this.container) {
|
||||
var containerOptions = $.extend({}, this.options, {
|
||||
value: this.value,
|
||||
autohide: false //element itsef will show/hide container
|
||||
autohide: false //element will take care to show/hide container
|
||||
});
|
||||
this.$element.editableContainer(containerOptions);
|
||||
this.$element.on({
|
||||
@ -227,12 +233,9 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
} else if(this.container.tip().is(':visible')) {
|
||||
return;
|
||||
}
|
||||
|
||||
//hide all other editable containers. Required to work correctly with toggle = manual
|
||||
$('.editable-container').find('.editable-cancel').click();
|
||||
|
||||
//show container
|
||||
this.container.show();
|
||||
this.container.show(closeAll);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -247,18 +250,19 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
//return focus on element
|
||||
if (this.options.enablefocus && this.options.toggle === 'click') {
|
||||
this.$element.focus();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
Toggles container visibility (show / hide)
|
||||
@method toggle()
|
||||
@param {boolean} closeAll Wether to close all other editable containers when showing this one. Default true.
|
||||
**/
|
||||
toggle: function() {
|
||||
toggle: function(closeAll) {
|
||||
if(this.container && this.container.tip().is(':visible')) {
|
||||
this.hide();
|
||||
} else {
|
||||
this.show();
|
||||
this.show(closeAll);
|
||||
}
|
||||
},
|
||||
|
||||
@ -324,7 +328,17 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
this.handleEmpty();
|
||||
this.$element.triggerHandler('render', this);
|
||||
}, this));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
Activates input of visible container (e.g. set focus)
|
||||
@method activate()
|
||||
**/
|
||||
activate: function() {
|
||||
if(this.container) {
|
||||
this.container.activate();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* EDITABLE PLUGIN DEFINITION
|
||||
@ -459,7 +473,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
|
||||
$.fn.editable.defaults = {
|
||||
/**
|
||||
Type of input. Can be <code>text|textarea|select|date</code>
|
||||
Type of input. Can be <code>text|textarea|select|date|checklist</code> and more
|
||||
|
||||
@property type
|
||||
@type string
|
||||
@ -475,9 +489,10 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
**/
|
||||
disabled: false,
|
||||
/**
|
||||
How to toggle editable. Can be <code>click|manual</code>.
|
||||
When set to <code>manual</code> you should manually call <code>show/hide</code> methods of editable.
|
||||
Note: if you are calling <code>show</code> on **click** event you need to apply <code>e.stopPropagation()</code> because container has behavior to hide on any click outside.
|
||||
How to toggle editable. Can be <code>click|dblclick|mouseenter|manual</code>.
|
||||
When set to <code>manual</code> you should manually call <code>show/hide</code> methods of editable.
|
||||
**Note**: if you call <code>show</code> or <code>toggle</code> inside **click** handler of some DOM element,
|
||||
you need to apply <code>e.stopPropagation()</code> because containers are being closed on any click on document.
|
||||
|
||||
@example
|
||||
$('#edit-button').click(function(e) {
|
||||
@ -490,6 +505,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
@default 'click'
|
||||
**/
|
||||
toggle: 'click',
|
||||
|
||||
/**
|
||||
Text shown when element is empty.
|
||||
|
||||
@ -519,7 +535,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
**/
|
||||
enablefocus: false,
|
||||
/**
|
||||
Initial value of input
|
||||
Initial value of input. Taken from <code>data-value</code> or element's text.
|
||||
|
||||
@property value
|
||||
@type mixed
|
||||
|
9
src/inputs-ext/address/address.css
Normal file
9
src/inputs-ext/address/address.css
Normal file
@ -0,0 +1,9 @@
|
||||
.editable-address {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.editable-address span {
|
||||
width: 70px;
|
||||
display: inline-block;
|
||||
}
|
107
src/inputs-ext/address/address.js
Normal file
107
src/inputs-ext/address/address.js
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
Address editable input.
|
||||
Internally value stored as {city: "Moscow", street: "Lenina", building: "15"}
|
||||
|
||||
@class address
|
||||
@extends abstract
|
||||
@final
|
||||
@example
|
||||
<a href="#" id="address" data-type="address" data-pk="1">awesome</a>
|
||||
<script>
|
||||
$(function(){
|
||||
$('#address').editable({
|
||||
url: '/post',
|
||||
title: 'Enter city, street and building #',
|
||||
value: {
|
||||
city: "Moscow",
|
||||
street: "Lenina",
|
||||
building: "15"
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
**/
|
||||
(function ($) {
|
||||
var Address = function (options) {
|
||||
this.init('address', options, Address.defaults);
|
||||
};
|
||||
|
||||
$.fn.editableform.utils.inherit(Address, $.fn.editableform.types.abstract);
|
||||
|
||||
$.extend(Address.prototype, {
|
||||
render: function() {
|
||||
Address.superclass.render.call(this);
|
||||
|
||||
// this.$input.
|
||||
},
|
||||
|
||||
|
||||
value2html: function(value, element) {
|
||||
var html = value.city + ', ' + value.street + ' st., bld. ' + value.building;
|
||||
$(element).text(html);
|
||||
},
|
||||
|
||||
html2value: function(html) {
|
||||
/*
|
||||
you may write parsing method to get value by element's html
|
||||
e.g. "Moscow, st. Lenina, bld. 15" => {city: "Moscow", street: "Lenina", building: "15"}
|
||||
but for complex structures I do not recommend do that.
|
||||
Better always set value directly via javascript, e.g.
|
||||
editable({
|
||||
value: {
|
||||
city: "Moscow",
|
||||
street: "Lenina",
|
||||
building: "15"
|
||||
}
|
||||
});
|
||||
*/
|
||||
return null;
|
||||
},
|
||||
|
||||
/*
|
||||
method for converting data before sent on server.
|
||||
As jQuery correctly sends objects via ajax, you can just return value
|
||||
*/
|
||||
value2str: function(value) {
|
||||
return value;
|
||||
},
|
||||
|
||||
/*
|
||||
this is mainly for parsing value defined in data-value attribute.
|
||||
If you will always set value by javascript, no need to overwrite it
|
||||
*/
|
||||
str2value: function(str) {
|
||||
return str;
|
||||
},
|
||||
|
||||
value2input: function(value) {
|
||||
this.$input.find('input[name="city"]').val(value.city);
|
||||
this.$input.find('input[name="street"]').val(value.street);
|
||||
this.$input.find('input[name="building"]').val(value.building);
|
||||
},
|
||||
|
||||
input2value: function() {
|
||||
return {
|
||||
city: this.$input.find('input[name="city"]').val(),
|
||||
street: this.$input.find('input[name="street"]').val(),
|
||||
building: this.$input.find('input[name="building"]').val()
|
||||
};
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
//set focus on city
|
||||
this.$input.find('input[name="city"]').focus();
|
||||
}
|
||||
});
|
||||
|
||||
Address.defaults = $.extend({}, $.fn.editableform.types.abstract.defaults, {
|
||||
tpl: '<div><label><span>City: </span><input type="text" name="city" class="span2"></label></div>'+
|
||||
'<div><label><span>Street: </span><input type="text" name="street" class="span2"></label></div>'+
|
||||
'<div><label><span>Building: </span><input type="text" name="building" class="span1"></label></div>',
|
||||
|
||||
inputclass: 'editable-address'
|
||||
});
|
||||
|
||||
$.fn.editableform.types.address = Address;
|
||||
|
||||
}(window.jQuery));
|
@ -46,7 +46,7 @@ To create your own input you should inherit from this class.
|
||||
@param {DOMElement} element
|
||||
**/
|
||||
value2html: function(value, element) {
|
||||
var html = $('<div>').text(value).html();
|
||||
var html = this.escape(value);
|
||||
$(element).html(html);
|
||||
},
|
||||
|
||||
@ -120,7 +120,21 @@ To create your own input you should inherit from this class.
|
||||
**/
|
||||
clear: function() {
|
||||
this.$input.val(null);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
method to escape html.
|
||||
**/
|
||||
escape: function(str) {
|
||||
return $('<div>').text(str).html();
|
||||
},
|
||||
|
||||
/**
|
||||
attach handler to automatically submit form when value changed (usefull when buttons not shown)
|
||||
**/
|
||||
autosubmit: function() {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
Abstract.defaults = {
|
||||
|
@ -1,5 +1,6 @@
|
||||
/**
|
||||
List of checkboxes. Internally value stored as javascript array of values.
|
||||
List of checkboxes.
|
||||
Internally value stored as javascript array of values.
|
||||
|
||||
@class checklist
|
||||
@extends list
|
||||
@ -49,6 +50,8 @@ $(function(){
|
||||
|
||||
value2str: function(value) {
|
||||
return $.isArray(value) ? value.join($.trim(this.options.separator)) : '';
|
||||
//it is also possible to sent as array
|
||||
//return value;
|
||||
},
|
||||
|
||||
//parse separated string
|
||||
@ -68,11 +71,17 @@ $(function(){
|
||||
var $checks = this.$input.find('input[type="checkbox"]');
|
||||
$checks.removeAttr('checked');
|
||||
if($.isArray(value) && value.length) {
|
||||
$checks.each(function(i, el) {
|
||||
if($.inArray($(el).val(), value) !== -1) {
|
||||
$(el).attr('checked', 'checked');
|
||||
}
|
||||
});
|
||||
$checks.each(function(i, el) {
|
||||
var $el = $(el);
|
||||
// cannot use $.inArray as it performs strict comparison
|
||||
$.each(value, function(j, val){
|
||||
/*jslint eqeq: true*/
|
||||
if($el.val() == val) {
|
||||
/*jslint eqeq: false*/
|
||||
$el.attr('checked', 'checked');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@ -99,7 +108,19 @@ $(function(){
|
||||
html = this.options.limitText.replace('{checked}', $.isArray(value) ? value.length : 0).replace('{count}', this.sourceData.length);
|
||||
}
|
||||
$(element).html(html);
|
||||
}
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
this.$input.find('input[type="checkbox"]').first().focus();
|
||||
},
|
||||
|
||||
autosubmit: function() {
|
||||
this.$input.find('input[type="checkbox"]').on('keydown', function(e){
|
||||
if (e.which === 13) {
|
||||
$(this).closest('form').submit();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Checklist.defaults = $.extend({}, $.fn.editableform.types.list.defaults, {
|
||||
|
@ -95,7 +95,16 @@ $(function(){
|
||||
clear: function() {
|
||||
this.$input.data('datepicker').date = null;
|
||||
this.$input.find('.active').removeClass('active');
|
||||
}
|
||||
},
|
||||
|
||||
autosubmit: function() {
|
||||
this.$input.on('changeDate', function(e){
|
||||
var $form = $(this).closest('form');
|
||||
setTimeout(function() {
|
||||
$form.submit();
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
@ -112,7 +112,16 @@ $(function(){
|
||||
|
||||
clear: function() {
|
||||
this.$input.datepicker('setDate', null);
|
||||
}
|
||||
},
|
||||
|
||||
autosubmit: function() {
|
||||
this.$input.on('mouseup', 'table.ui-datepicker-calendar a.ui-state-default', function(e){
|
||||
var $form = $(this).closest('form');
|
||||
setTimeout(function() {
|
||||
$form.submit();
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
@ -45,7 +45,13 @@ $(function(){
|
||||
text = item.text;
|
||||
}
|
||||
Select.superclass.constructor.superclass.value2html(text, element);
|
||||
}
|
||||
},
|
||||
|
||||
autosubmit: function() {
|
||||
this.$input.on('change', function(){
|
||||
$(this).closest('form').submit();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Select.defaults = $.extend({}, $.fn.editableform.types.list.defaults, {
|
||||
|
@ -80,8 +80,7 @@ function getAssets(f, c, src, libs) {
|
||||
//core
|
||||
js.unshift(bootstrap+'js/bootstrap.js')
|
||||
css.unshift(bootstrap+'css/bootstrap.css');
|
||||
// css.push(bootstrap+'css/bootstrap.css');
|
||||
//css.unshift(bootstrap+'css/bootstrap-responsive.css');
|
||||
css.unshift(bootstrap+'css/bootstrap-responsive.css');
|
||||
|
||||
//editable
|
||||
js.push(forms+'editable-form-bootstrap.js');
|
||||
|
@ -287,7 +287,7 @@ $(function () {
|
||||
});
|
||||
|
||||
|
||||
test("option method", function () {
|
||||
test("option method (string and object)", function () {
|
||||
var e = $('<a href="#" data-url="post.php" data-name="text">abc</a>').appendTo('#qunit-fixture').editable(),
|
||||
e1 = $('<a href="#" data-pk="1" data-name="text1">abc</a>').appendTo('#qunit-fixture').editable(),
|
||||
url = 'abc';
|
||||
@ -296,6 +296,12 @@ $(function () {
|
||||
|
||||
equal(e.data('editable').options.pk, 2, 'pk set correctly');
|
||||
equal(e1.data('editable').options.pk, 2, 'pk2 set correctly');
|
||||
|
||||
$('#qunit-fixture a').editable('option', {pk: 3, value: 'abcd'});
|
||||
|
||||
equal(e.data('editable').options.pk, 3, 'pk set correctly (by object)');
|
||||
equal(e.data('editable').value, 'abcd', 'value set correctly (by object)');
|
||||
equal(e.text(), 'abcd', 'text set correctly (by object)');
|
||||
});
|
||||
|
||||
asyncTest("'submit' method: client and server validation", function () {
|
||||
|
@ -78,7 +78,7 @@
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
ok(p.is(':visible'), 'popover shown');
|
||||
ok(p.is(':visible'), 'popover shown');
|
||||
|
||||
//todo: for jqueryui phantomjs calcs wrong position. Need investigation
|
||||
if(!$.browser.webkit && fc.f !== 'jqueryui') {
|
||||
@ -90,41 +90,195 @@
|
||||
e.remove();
|
||||
});
|
||||
|
||||
test("should close all other containers on click on editable", function () {
|
||||
var e1 = $('<a href="#" data-pk="1" data-url="post.php" id="a">abc</a>').appendTo('#qunit-fixture').editable(),
|
||||
e2 = $('<a href="#" data-pk="1" data-url="post.php" id="b">abcd</a>').appendTo('#qunit-fixture').editable();
|
||||
|
||||
e1.click()
|
||||
var p1 = tip(e1);
|
||||
ok(p1.is(':visible'), 'popover1 visible');
|
||||
|
||||
e2.click()
|
||||
var p2 = tip(e2);
|
||||
ok(p2.is(':visible'), 'popover2 visible');
|
||||
ok(!p1.is(':visible'), 'popover1 closed');
|
||||
|
||||
p2.find('button[type=button]').click();
|
||||
ok(!p2.is(':visible'), 'popover2 closed');
|
||||
});
|
||||
|
||||
test("click outside container should hide it", function () {
|
||||
var e = $('<a href="#" data-pk="1" data-url="post.php" data-name="text1">abc</a>').appendTo('#qunit-fixture').editable(),
|
||||
e1 = $('<div>').appendTo('body');
|
||||
|
||||
test("onblur: cancel", function () {
|
||||
var oldValue = 'abc',
|
||||
newValue = 'cde',
|
||||
e = $('<a href="#" data-type="text" data-pk="1" data-url="post.php" id="a">'+oldValue+'</a>').appendTo('#qunit-fixture').editable({
|
||||
onblur: 'cancel',
|
||||
url: function() {}
|
||||
}),
|
||||
e2 = $('<a href="#" data-type="text" data-pk="1" data-url="post.php" id="b">abcd</a>').appendTo('#qunit-fixture').editable();
|
||||
|
||||
//click inside
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
ok(p.is(':visible'), 'popover shown');
|
||||
|
||||
ok(p.is(':visible'), 'popover1 visible');
|
||||
p.find('input').val(newValue);
|
||||
p.click();
|
||||
ok(p.is(':visible'), 'popover still shown');
|
||||
p.find('input').click();
|
||||
ok(p.is(':visible'), 'popover1 still visible');
|
||||
|
||||
//click outside
|
||||
p.find('input').val(newValue);
|
||||
$('#qunit-fixture').click();
|
||||
ok(!p.is(':visible'), 'popover1 closed');
|
||||
equal(e.data('editable').value, oldValue, 'old value exists');
|
||||
|
||||
e1.click();
|
||||
ok(!p.is(':visible'), 'popover closed');
|
||||
});
|
||||
//click on another editable
|
||||
e.click();
|
||||
p = tip(e);
|
||||
ok(p.is(':visible'), 'popover1 visible');
|
||||
p.find('input').val(newValue);
|
||||
e2.click();
|
||||
var p2 = tip(e2);
|
||||
ok(!p.is(':visible'), 'popover1 closed');
|
||||
ok(p2.is(':visible'), 'popover2 visible');
|
||||
equal(e.data('editable').value, oldValue, 'old value exists');
|
||||
e2.editable('hide');
|
||||
ok(!p2.is(':visible'), 'popover2 closed');
|
||||
|
||||
//call show method of another editable, closeAll = true (default)
|
||||
e.click();
|
||||
p = tip(e);
|
||||
ok(p.is(':visible'), 'popover1 visible');
|
||||
p.find('input').val(newValue);
|
||||
e2.editable('show');
|
||||
p2 = tip(e2);
|
||||
ok(!p.is(':visible'), 'popover1 closed');
|
||||
ok(p2.is(':visible'), 'popover2 visible');
|
||||
equal(e.data('editable').value, oldValue, 'old value exists');
|
||||
e2.editable('hide');
|
||||
ok(!p2.is(':visible'), 'popover2 closed');
|
||||
|
||||
//call show method of another editable, closeAll = false
|
||||
e.click();
|
||||
p = tip(e);
|
||||
ok(p.is(':visible'), 'popover1 visible');
|
||||
p.find('input').val(newValue);
|
||||
e2.editable('show', false);
|
||||
p2 = tip(e2);
|
||||
ok(p.is(':visible'), 'popover1 visible');
|
||||
ok(p2.is(':visible'), 'popover2 visible');
|
||||
|
||||
e.editable('hide');
|
||||
e2.editable('hide');
|
||||
ok(!p.is(':visible'), 'popover1 closed');
|
||||
ok(!p2.is(':visible'), 'popover2 closed');
|
||||
});
|
||||
|
||||
test("onblur: submit", function () {
|
||||
var oldValue = 'abc',
|
||||
newValue = 'cde',
|
||||
e = $('<a href="#" data-type="text" data-pk="1" data-url="post.php" id="a">'+oldValue+'</a>').appendTo('#qunit-fixture').editable({
|
||||
onblur: 'submit',
|
||||
url: function() {}
|
||||
}),
|
||||
e2 = $('<a href="#" data-type="text" data-pk="1" data-url="post.php" id="b">abcd</a>').appendTo('#qunit-fixture').editable();
|
||||
|
||||
//click inside
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
ok(p.is(':visible'), 'popover1 visible');
|
||||
p.find('input').val(newValue);
|
||||
p.click();
|
||||
p.find('input').click();
|
||||
ok(p.is(':visible'), 'popover1 still visible');
|
||||
|
||||
//click outside
|
||||
p.find('input').val(newValue);
|
||||
$('#qunit-fixture').click();
|
||||
ok(!p.is(':visible'), 'popover1 closed');
|
||||
equal(e.data('editable').value, newValue, 'new value saved');
|
||||
|
||||
//click on another editable
|
||||
e.click();
|
||||
p = tip(e);
|
||||
ok(p.is(':visible'), 'popover1 visible');
|
||||
p.find('input').val(oldValue);
|
||||
e2.click();
|
||||
var p2 = tip(e2);
|
||||
ok(!p.is(':visible'), 'popover1 closed');
|
||||
ok(p2.is(':visible'), 'popover2 visible');
|
||||
equal(e.data('editable').value, oldValue, 'old value re-saved');
|
||||
e2.editable('hide');
|
||||
ok(!p2.is(':visible'), 'popover2 closed');
|
||||
|
||||
//call show method of another editable, closeAll = true (default)
|
||||
e.click();
|
||||
p = tip(e);
|
||||
ok(p.is(':visible'), 'popover1 visible');
|
||||
p.find('input').val(newValue);
|
||||
e2.editable('show');
|
||||
p2 = tip(e2);
|
||||
ok(!p.is(':visible'), 'popover1 closed');
|
||||
ok(p2.is(':visible'), 'popover2 visible');
|
||||
equal(e.data('editable').value, newValue, 'new value saved');
|
||||
e2.editable('hide');
|
||||
ok(!p2.is(':visible'), 'popover2 closed');
|
||||
|
||||
//call show method of another editable, closeAll = false
|
||||
e.click();
|
||||
p = tip(e);
|
||||
ok(p.is(':visible'), 'popover1 visible');
|
||||
p.find('input').val(oldValue);
|
||||
e2.editable('show', false);
|
||||
p2 = tip(e2);
|
||||
ok(p.is(':visible'), 'popover1 visible');
|
||||
ok(p2.is(':visible'), 'popover2 visible');
|
||||
|
||||
e.editable('hide');
|
||||
e2.editable('hide');
|
||||
ok(!p.is(':visible'), 'popover1 closed');
|
||||
ok(!p2.is(':visible'), 'popover2 closed');
|
||||
});
|
||||
|
||||
test("onblur: ignore", function () {
|
||||
var oldValue = 'abc',
|
||||
newValue = 'cde',
|
||||
e = $('<a href="#" data-type="text" data-pk="1" data-url="post.php" id="a">'+oldValue+'</a>').appendTo('#qunit-fixture').editable({
|
||||
onblur: 'ignore',
|
||||
url: function() {}
|
||||
}),
|
||||
e2 = $('<a href="#" data-type="text" data-pk="1" data-url="post.php" id="b">abcd</a>').appendTo('#qunit-fixture').editable();
|
||||
|
||||
//click inside
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
ok(p.is(':visible'), 'popover1 visible');
|
||||
p.find('input').val(newValue);
|
||||
p.click();
|
||||
p.find('input').click();
|
||||
ok(p.is(':visible'), 'popover1 still visible');
|
||||
|
||||
//click outside
|
||||
p.find('input').val(newValue);
|
||||
$('#qunit-fixture').click();
|
||||
ok(p.is(':visible'), 'popover1 still visible');
|
||||
|
||||
//click on another editable
|
||||
e2.click();
|
||||
var p2 = tip(e2);
|
||||
ok(p.is(':visible'), 'popover1 still visible');
|
||||
ok(p2.is(':visible'), 'popover2 visible');
|
||||
e2.editable('hide');
|
||||
ok(!p2.is(':visible'), 'popover2 closed');
|
||||
|
||||
//call show method of another editable, closeAll = true (default)
|
||||
e2.editable('show');
|
||||
p2 = tip(e2);
|
||||
ok(p.is(':visible'), 'popover1 still visible');
|
||||
ok(p2.is(':visible'), 'popover2 visible');
|
||||
e2.editable('hide');
|
||||
ok(!p2.is(':visible'), 'popover2 closed');
|
||||
|
||||
//call show method of another editable, closeAll = false
|
||||
e2.editable('show', false);
|
||||
p2 = tip(e2);
|
||||
ok(p.is(':visible'), 'popover1 still visible');
|
||||
ok(p2.is(':visible'), 'popover2 visible');
|
||||
e2.editable('hide');
|
||||
ok(!p2.is(':visible'), 'popover2 closed');
|
||||
|
||||
e.editable('hide');
|
||||
ok(!p.is(':visible'), 'popover1 closed');
|
||||
});
|
||||
|
||||
|
||||
test("should not wrap buttons when parent has position:absolute", function () {
|
||||
var d = $('<div style="position: absolute; top: 200px">').appendTo(fx),
|
||||
e = $('<a href="#" data-pk="1" data-url="post.php" data-name="text1">abc</a>').appendTo(d).editable();
|
||||
e = $('<a href="#" data-pk="1" data-url="post.php" data-name="text1">abc</a>').appendTo(d).editable({
|
||||
showbuttons: true
|
||||
});
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
@ -132,7 +286,81 @@
|
||||
ok(p.find('button').offset().left > p.find('.editable-input').offset().left + p.find('.editable-input').width(), 'buttons left ok');
|
||||
|
||||
d.remove();
|
||||
});
|
||||
});
|
||||
|
||||
test("toggle: manual", function () {
|
||||
var e = $('<a href="#" id="a"></a>').appendTo('#qunit-fixture').editable({
|
||||
toggle: 'manual'
|
||||
});
|
||||
|
||||
e.click();
|
||||
ok(!e.data('editableContainer'), 'popover not visible after click');
|
||||
e.editable('show');
|
||||
var p = tip(e);
|
||||
ok(p.is(':visible'), 'shown manually');
|
||||
});
|
||||
|
||||
test("toggle: dblclick", function () {
|
||||
var e = $('<a href="#" id="a"></a>').appendTo('#qunit-fixture').editable({
|
||||
toggle: 'dblclick'
|
||||
}),
|
||||
p, p2,
|
||||
e2 = $('<a href="#" data-type="text" data-pk="1" data-url="post.php" id="b">abcd</a>').appendTo('#qunit-fixture').editable();
|
||||
|
||||
e.click();
|
||||
ok(!e.data('editableContainer'), 'popover not visible after click');
|
||||
|
||||
e2.click();
|
||||
p2 = tip(e2);
|
||||
ok(p2.is(':visible'), 'popover2 visible');
|
||||
|
||||
e.dblclick();
|
||||
p = tip(e);
|
||||
ok(p.is(':visible'), 'popover1 visible');
|
||||
ok(!p2.is(':visible'), 'popover2 closed');
|
||||
});
|
||||
|
||||
test("toggle: mouseenter", function () {
|
||||
var e = $('<a href="#" id="a"></a>').appendTo('#qunit-fixture').editable({
|
||||
toggle: 'mouseenter'
|
||||
}),
|
||||
p, p2,
|
||||
e2 = $('<a href="#" data-type="text" data-pk="1" data-url="post.php" id="b">abcd</a>').appendTo('#qunit-fixture').editable();
|
||||
|
||||
e.click();
|
||||
ok(!e.data('editableContainer'), 'popover not visible after click');
|
||||
|
||||
e.dblclick();
|
||||
ok(!e.data('editableContainer'), 'popover not visible after dblclick');
|
||||
|
||||
e2.click();
|
||||
p2 = tip(e2);
|
||||
ok(p2.is(':visible'), 'popover2 visible');
|
||||
|
||||
e.mouseenter();
|
||||
ok(e.data('editableContainer'), 'container defined');
|
||||
p = tip(e);
|
||||
ok(p.is(':visible'), 'popover1 visible');
|
||||
ok(!p2.is(':visible'), 'popover2 closed');
|
||||
|
||||
//hover once again --> container should stay open
|
||||
e.hover();
|
||||
p = tip(e);
|
||||
ok(p.is(':visible'), 'popover1 visible after second hover');
|
||||
});
|
||||
|
||||
test("showbuttons: false", function () {
|
||||
var e = $('<a href="#" id="a" data-type="text"></a>').appendTo('#qunit-fixture').editable({
|
||||
showbuttons: false
|
||||
});
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
ok(p.is(':visible'), 'popover visible');
|
||||
ok(!p.find('.editable-submit').length, 'submit not rendered');
|
||||
ok(!p.find('.editable-cancel').length, 'cancel not rendered');
|
||||
ok(!p.find('.editable-buttons').length, '.editable-buttons block not rendered');
|
||||
});
|
||||
|
||||
//unfortunatly, testing this feature does not always work in browsers. Tested manually.
|
||||
/*
|
||||
|
@ -450,5 +450,30 @@ $(function () {
|
||||
start();
|
||||
}, timeout);
|
||||
});
|
||||
|
||||
asyncTest("autosubmit when showbuttons=false", function () {
|
||||
expect(4);
|
||||
var e = $('<a href="#" data-type="select" data-value="2" data-url="post.php">customer</a>').appendTo(fx).editable({
|
||||
pk: 1,
|
||||
source: groups,
|
||||
showbuttons: false
|
||||
}),
|
||||
selected = 3;
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
equal(p.find('select').val(), e.data('editable').value, 'selected value correct');
|
||||
|
||||
p.find('select').val(selected);
|
||||
p.find('select').trigger('change');
|
||||
|
||||
setTimeout(function() {
|
||||
ok(!p.is(':visible'), 'popover closed');
|
||||
equal(e.data('editable').value, selected, 'new value saved')
|
||||
equal(e.text(), groups[selected], 'text shown correctly')
|
||||
e.remove();
|
||||
start();
|
||||
}, timeout);
|
||||
});
|
||||
|
||||
});
|
@ -39,18 +39,6 @@ $(function () {
|
||||
p.find('button[type=button]').click();
|
||||
ok(!p.is(':visible'), 'popover was removed');
|
||||
});
|
||||
|
||||
test("option 'toggle' = manual", function () {
|
||||
var e = $('<a href="#" id="a"></a>').appendTo('#qunit-fixture').editable({
|
||||
toggle: 'manual'
|
||||
});
|
||||
|
||||
e.click();
|
||||
ok(!e.data().editableContainer, 'popover not visible after click');
|
||||
e.editable('show');
|
||||
var p = tip(e);
|
||||
ok(p.is(':visible'), 'shown manually');
|
||||
});
|
||||
|
||||
asyncTest("should load correct value and save new entered text (and value)", function () {
|
||||
var v = 'ab<b>"',
|
||||
@ -211,7 +199,38 @@ $(function () {
|
||||
start();
|
||||
}, timeout);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
asyncTest("should show new value if success callback returns object", function () {
|
||||
var newText = 'cd<e>;"',
|
||||
e = $('<a href="#" data-pk="1" data-url="post.php" data-name="text1">abc</a>').appendTo(fx).editable({
|
||||
success: function(response, newValue) {
|
||||
equal(newValue, newText, 'value in success passed correctly');
|
||||
return {newValue: 'xyz'};
|
||||
}
|
||||
});
|
||||
|
||||
e.click()
|
||||
var p = tip(e);
|
||||
|
||||
ok(p.find('input[type=text]').length, 'input exists')
|
||||
p.find('input').val(newText);
|
||||
p.find('form').submit();
|
||||
|
||||
setTimeout(function() {
|
||||
ok(!p.is(':visible'), 'popover closed');
|
||||
equal(p.find('.editable-error-block').text(), '', 'no error msg');
|
||||
equal(e.data('editable').value, 'xyz', 'value ok');
|
||||
equal(e.text(), 'xyz', 'text ok');
|
||||
|
||||
p.find('button[type=button]').click();
|
||||
ok(!p.is(':visible'), 'popover was removed');
|
||||
e.remove();
|
||||
start();
|
||||
}, timeout);
|
||||
|
||||
});
|
||||
|
||||
|
||||
asyncTest("should submit all required params", function () {
|
||||
var e = $('<a href="#" data-pk="1" data-url="post-resp.php">abc</a>').appendTo(fx).editable({
|
||||
@ -256,6 +275,9 @@ $(function () {
|
||||
equal(resp.data.name, 'username', 'name ok');
|
||||
equal(resp.data.value, newText, 'value ok');
|
||||
equal(resp.data.q, 2, 'additional params ok');
|
||||
},
|
||||
ajaxOptions: {
|
||||
headers: {"myHeader": "123"}
|
||||
}
|
||||
}),
|
||||
newText = 'cd<e>;"'
|
||||
@ -272,8 +294,38 @@ $(function () {
|
||||
start();
|
||||
}, timeout);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
asyncTest("ajaxOptions", function () {
|
||||
var e = $('<a href="#" data-pk="1" data-url="post-options.php">abc</a>').appendTo(fx).editable({
|
||||
name: 'username',
|
||||
ajaxOptions: {
|
||||
dataType: 'html'
|
||||
}
|
||||
}),
|
||||
newText = 'cd<e>;"'
|
||||
|
||||
$.mockjax({
|
||||
url: 'post-options.php',
|
||||
response: function(settings) {
|
||||
equal(settings.dataType, 'html', 'dataType key ok');
|
||||
}
|
||||
});
|
||||
|
||||
e.click()
|
||||
var p = tip(e);
|
||||
|
||||
ok(p.find('input[type=text]').length, 'input exists')
|
||||
p.find('input').val(newText);
|
||||
p.find('form').submit();
|
||||
|
||||
setTimeout(function() {
|
||||
e.remove();
|
||||
start();
|
||||
}, timeout);
|
||||
|
||||
});
|
||||
|
||||
|
||||
asyncTest("submit to url defined as function", function () {
|
||||
expect(3);
|
||||
|
Loading…
x
Reference in New Issue
Block a user