Merge branch 'release-1.3.0'

This commit is contained in:
vitalets
2012-12-10 22:50:47 +04:00
36 changed files with 9898 additions and 218 deletions

@ -2,6 +2,21 @@ X-editable changelog
============================= =============================
Version 1.3.0 Dec 10, 2012
----------------------------
[enh] added html5 inputs support: password, email, url, tel, number, range (vitalets)
[bug #43] fix for bootstrap 2.2.2 (vitalets)
[enh #41] 'abstract' class renamed to 'abstractinput' as abstract is reserved word (vitalets)
[enh #40] 'params' option defined as function overwrites original ajax data instead of appending (vitalets)
[bug] datepicker: error when click on arrows after clear date (vitalets)
[enh] 'hidden' event: added possible value of reason param - 'nochange'. Occurs when form is submitted but value was not changed (vitalets)
[enh] 'submit' method changed: error-callback's parameter simplified (vitalets)
[enh] 'submit' method changed: now when response 200 OK it does not set pk automatically (vitalets)
[enh] 'submit' method changed: removed dataType='json'. Use 'ajaxOptions' to specify dataType if needed (vitalets)
[enh] removed default ajax dataType='json'. Use 'ajaxOptions' to specify dataType if needed (vitalets)
[enh] select: do not show 'sourceError' in element during autotext execution (vitalets)
Version 1.2.0 Dec 6, 2012 Version 1.2.0 Dec 6, 2012
---------------------------- ----------------------------
[enh #36] 'submit' method: added 'ajaxOptions' property to modify ajax request (vitalets) [enh #36] 'submit' method: added 'ajaxOptions' property to modify ajax request (vitalets)

@ -42,7 +42,8 @@ function getFiles() {
inputs+'text.js', inputs+'text.js',
inputs+'textarea.js', inputs+'textarea.js',
inputs+'select.js', inputs+'select.js',
inputs+'checklist.js' inputs+'checklist.js',
inputs+'html5types.js'
]; ];
//common css files //common css files

@ -2,7 +2,7 @@
"name": "X-editable", "name": "X-editable",
"title": "X-editable", "title": "X-editable",
"description": "In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery", "description": "In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery",
"version": "1.2.0", "version": "1.3.0",
"homepage": "http://github.com/vitalets/x-editable", "homepage": "http://github.com/vitalets/x-editable",
"author": { "author": {
"name": "Vitaliy Potapov", "name": "Vitaliy Potapov",

@ -8,7 +8,8 @@
} }
.editable-container.editable-inline { .editable-container.editable-inline {
display: inline; /* display: inline; */ /* display: inline does not correctly work with show()/hide() in jquery <= 1.7.2 */
display: inline-block;
vertical-align: middle; vertical-align: middle;
} }

@ -80,9 +80,8 @@ Applied as jQuery method.
.editableform(this.formOptions) .editableform(this.formOptions)
.on({ .on({
save: $.proxy(this.save, this), save: $.proxy(this.save, this),
cancel: $.proxy(function(){ cancel: $.proxy(function(){ this.hide('cancel'); }, this),
this.hide('cancel'); nochange: $.proxy(function(){ this.hide('nochange'); }, this),
}, this),
show: $.proxy(this.setPosition, this), //re-position container every time form is shown (occurs each time after loading state) show: $.proxy(this.setPosition, this), //re-position container every time form is shown (occurs each time after loading state)
rendering: $.proxy(this.setPosition, this), //this allows to place container correctly when loading shown rendering: $.proxy(this.setPosition, this), //this allows to place container correctly when loading shown
rendered: $.proxy(function(){ rendered: $.proxy(function(){
@ -146,7 +145,7 @@ Applied as jQuery method.
/** /**
Hides container with form Hides container with form
@method hide() @method hide()
@param {string} reason Reason caused hiding. Can be <code>save|cancel|onblur|undefined (=manual)</code> @param {string} reason Reason caused hiding. Can be <code>save|cancel|onblur|nochange|undefined (=manual)</code>
**/ **/
hide: function(reason) { hide: function(reason) {
if(!this.tip() || !this.tip().is(':visible') || !this.$element.hasClass('editable-open')) { if(!this.tip() || !this.tip().is(':visible') || !this.$element.hasClass('editable-open')) {
@ -159,7 +158,7 @@ Applied as jQuery method.
@event hidden @event hidden
@param {object} event event object @param {object} event event object
@param {string} reason Reason caused hiding. Can be <code>save|cancel|onblur|undefined (=manual)</code> @param {string} reason Reason caused hiding. Can be <code>save|cancel|onblur|nochange|undefined (=manual)</code>
@example @example
$('#username').on('hidden', function(e, reason) { $('#username').on('hidden', function(e, reason) {
if(reason === 'save' || reason === 'cancel') { if(reason === 'save' || reason === 'cancel') {

@ -8,7 +8,8 @@
//extend methods //extend methods
$.extend($.fn.editableContainer.Constructor.prototype, { $.extend($.fn.editableContainer.Constructor.prototype, {
containerName: 'popover', containerName: 'popover',
innerCss: '.popover-content p', //for compatibility with bootstrap <= 2.2.1 (content inserted into <p> instead of directly .popover-content)
innerCss: $($.fn.popover.defaults.template).find('p').length ? '.popover-content p' : '.popover-content',
initContainer: function(){ initContainer: function(){
$.extend(this.containerOptions, { $.extend(this.containerOptions, {

@ -53,6 +53,7 @@
max-width: 300px; max-width: 300px;
margin: 5px 0 0 0; margin: 5px 0 0 0;
width: auto; width: auto;
white-space: normal;
} }
/*add padding for jquery ui*/ /*add padding for jquery ui*/

@ -179,11 +179,16 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
return; return;
} }
//if value not changed --> cancel //if value not changed --> trigger 'nochange' event and return
/*jslint eqeq: true*/ /*jslint eqeq: true*/
if (!this.options.savenochange && this.input.value2str(newValue) == this.input.value2str(this.value)) { if (!this.options.savenochange && this.input.value2str(newValue) == this.input.value2str(this.value)) {
/*jslint eqeq: false*/ /*jslint eqeq: false*/
this.cancel(); /**
Fired when value not changed but form is submitted. Requires savenochange = false.
@event nochange
@param {Object} event event object
**/
this.$div.triggerHandler('nochange');
return; return;
} }
@ -259,7 +264,7 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
//additional params //additional params
if(typeof this.options.params === 'function') { if(typeof this.options.params === 'function') {
$.extend(params, this.options.params.call(this.options.scope, params)); params = this.options.params.call(this.options.scope, params);
} else { } else {
//try parse json in single quotes (from data-params attribute) //try parse json in single quotes (from data-params attribute)
this.options.params = $.fn.editableutils.tryParseJson(this.options.params, true); this.options.params = $.fn.editableutils.tryParseJson(this.options.params, true);
@ -273,8 +278,7 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
return $.ajax($.extend({ return $.ajax($.extend({
url : this.options.url, url : this.options.url,
data : params, data : params,
type : 'post', type : 'POST'
dataType: 'json'
}, this.options.ajaxOptions)); }, this.options.ajaxOptions));
} }
} }
@ -371,10 +375,13 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
**/ **/
url:null, url:null,
/** /**
Additional params for submit. Function can be used to calculate params dynamically Additional params for submit. If defined as <code>object</code> - it is **appended** to original ajax data (pk, name and value).
If defined as <code>function</code> - returned object **overwrites** original ajax data.
@example @example
params: function(params) { params: function(params) {
return { a: 1 }; //originally params contain pk, name and value
params.a = 1;
return params;
} }
@property params @property params
@ -447,7 +454,7 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
if(!response.success) return response.msg; if(!response.success) return response.msg;
} }
**/ **/
success: function(response, newValue) {}, success: null,
/** /**
Additional options for ajax request. Additional options for ajax request.
List of values: http://api.jquery.com/jQuery.ajax List of values: http://api.jquery.com/jQuery.ajax

@ -250,9 +250,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
value: this.value value: this.value
}); });
this.$element.editableContainer(containerOptions); this.$element.editableContainer(containerOptions);
this.$element.on({ this.$element.on("save.internal", $.proxy(this.save, this));
save: $.proxy(this.save, this)
});
this.container = this.$element.data('editableContainer'); this.container = this.$element.data('editableContainer');
} else if(this.container.tip().is(':visible')) { } else if(this.container.tip().is(':visible')) {
return; return;
@ -422,16 +420,17 @@ Makes editable any HTML element on the page. Applied as jQuery method.
return result; return result;
/** /**
This method collects values from several editable elements and submit them all to server. This method collects values from several editable elements and submit them all to server.
It is designed mainly for <a href="#newrecord">creating new records</a>. Internally it runs client-side validation for all fields and submits only in case of success.
See <a href="#newrecord">creating new records</a> for details.
@method submit(options) @method submit(options)
@param {object} options @param {object} options
@param {object} options.url url to submit data @param {object} options.url url to submit data
@param {object} options.data additional data to submit @param {object} options.data additional data to submit
@param {object} options.ajaxOptions additional ajax options @param {object} options.ajaxOptions additional ajax options
@param {function} options.error(obj) error handler (called on both client-side and server-side validation errors) @param {function} options.error(obj) error handler
@param {function} options.success(obj) success handler @param {function} options.success(obj,config) success handler
@returns {Object} jQuery object @returns {Object} jQuery object
**/ **/
case 'submit': //collects value, validate and submit to server for creating new record case 'submit': //collects value, validate and submit to server for creating new record
@ -449,22 +448,13 @@ Makes editable any HTML element on the page. Applied as jQuery method.
$.ajax($.extend({ $.ajax($.extend({
url: config.url, url: config.url,
data: values, data: values,
type: 'POST', type: 'POST'
dataType: 'json'
}, config.ajaxOptions)) }, config.ajaxOptions))
.success(function(response) { .success(function(response) {
//successful response //successful response 200 OK
if(typeof response === 'object' && response.id) { if(typeof config.success === 'function') {
$elems.editable('option', 'pk', response.id); config.success.call($elems, response, config);
$elems.removeClass('editable-unsaved'); }
if(typeof config.success === 'function') {
config.success.apply($elems, arguments);
}
} else { //server-side validation error
if(typeof config.error === 'function') {
config.error.apply($elems, arguments);
}
}
}) })
.error(function(){ //ajax error .error(function(){ //ajax error
if(typeof config.error === 'function') { if(typeof config.error === 'function') {
@ -473,7 +463,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
}); });
} else { //client-side validation error } else { //client-side validation error
if(typeof config.error === 'function') { if(typeof config.error === 'function') {
config.error.call($elems, {errors: errors}); config.error.call($elems, errors);
} }
} }
return this; return this;
@ -577,4 +567,4 @@ Makes editable any HTML element on the page. Applied as jQuery method.
display: null display: null
}; };
}(window.jQuery)); }(window.jQuery));

@ -3,7 +3,7 @@ Address editable input.
Internally value stored as {city: "Moscow", street: "Lenina", building: "15"} Internally value stored as {city: "Moscow", street: "Lenina", building: "15"}
@class address @class address
@extends abstract @extends abstractinput
@final @final
@example @example
<a href="#" id="address" data-type="address" data-pk="1">awesome</a> <a href="#" id="address" data-type="address" data-pk="1">awesome</a>
@ -26,14 +26,24 @@ $(function(){
this.init('address', options, Address.defaults); this.init('address', options, Address.defaults);
}; };
$.fn.editableutils.inherit(Address, $.fn.editabletypes.abstract); //inherit from Abstract input
$.fn.editableutils.inherit(Address, $.fn.editabletypes.abstractinput);
$.extend(Address.prototype, { $.extend(Address.prototype, {
render: function() { /**
Address.superclass.render.call(this); Renders input from tpl
},
@method render()
**/
render: function() {
Address.superclass.render.call(this);
},
//standard way to show value in element. Used only if display option not defined. /**
Default method to show value in element. Can be overwritten by display option.
@method value2html(value, element)
**/
value2html: function(value, element) { value2html: function(value, element) {
if(!value) { if(!value) {
$(element).empty(); $(element).empty();
@ -43,12 +53,17 @@ $(function(){
$(element).html(html); $(element).html(html);
}, },
/**
Gets value from element's html
@method html2value(html)
**/
html2value: function(html) { html2value: function(html) {
/* /*
you may write parsing method to get value by element's 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"} e.g. "Moscow, st. Lenina, bld. 15" => {city: "Moscow", street: "Lenina", building: "15"}
but for complex structures I do not recommend do that. but for complex structures it's not recommended.
Better always set value directly via javascript, e.g. Better set value directly via javascript, e.g.
editable({ editable({
value: { value: {
city: "Moscow", city: "Moscow",
@ -60,10 +75,12 @@ $(function(){
return null; return null;
}, },
/* /**
converts value to string. Converts value to string.
It is used in internal comparing (not for sending to server). It is used in internal comparing (not for sending to server).
*/
@method value2str(value)
**/
value2str: function(value) { value2str: function(value) {
var str = ''; var str = '';
if(value) { if(value) {
@ -75,19 +92,35 @@ $(function(){
}, },
/* /*
this is mainly for parsing value defined in data-value attribute. Converts string to value. Used for reading value from 'data-value' attribute.
If you will always set value by javascript, no need to overwrite it
@method str2value(str)
*/ */
str2value: function(str) { str2value: function(str) {
/*
this is mainly for parsing value defined in data-value attribute.
If you will always set value by javascript, no need to overwrite it
*/
return str; return str;
}, },
/**
Sets value of input.
@method value2input(value)
@param {mixed} value
**/
value2input: function(value) { value2input: function(value) {
this.$input.find('input[name="city"]').val(value.city); this.$input.find('input[name="city"]').val(value.city);
this.$input.find('input[name="street"]').val(value.street); this.$input.find('input[name="street"]').val(value.street);
this.$input.find('input[name="building"]').val(value.building); this.$input.find('input[name="building"]').val(value.building);
}, },
/**
Returns value of input.
@method input2value()
**/
input2value: function() { input2value: function() {
return { return {
city: this.$input.find('input[name="city"]').val(), city: this.$input.find('input[name="city"]').val(),
@ -95,14 +128,31 @@ $(function(){
building: this.$input.find('input[name="building"]').val() building: this.$input.find('input[name="building"]').val()
}; };
}, },
/**
Activates input: sets focus on the first field.
@method activate()
**/
activate: function() { activate: function() {
//set focus on city
this.$input.find('input[name="city"]').focus(); this.$input.find('input[name="city"]').focus();
} },
/**
Attaches handler to submit form in case of 'showbuttons=false' mode
@method autosubmit()
**/
autosubmit: function() {
this.$input.find('input[type="text"]').keydown(function (e) {
if (e.which === 13) {
$(this).closest('form').submit();
}
});
}
}); });
Address.defaults = $.extend({}, $.fn.editabletypes.abstract.defaults, { Address.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
tpl: '<div><label><span>City: </span><input type="text" name="city" class="input-small"></label></div>'+ tpl: '<div><label><span>City: </span><input type="text" name="city" class="input-small"></label></div>'+
'<div><label><span>Street: </span><input type="text" name="street" class="input-small"></label></div>'+ '<div><label><span>Street: </span><input type="text" name="street" class="input-small"></label></div>'+
'<div><label><span>Building: </span><input type="text" name="building" class="input-mini"></label></div>', '<div><label><span>Building: </span><input type="text" name="building" class="input-mini"></label></div>',

@ -1,17 +1,18 @@
/** /**
Abstract editable input class. AbstractInput - base class for all editable inputs.
To create your own input you should inherit from this class. It defines interface to be implemented by any input type.
To create your own input you can inherit from this class.
@class abstract @class abstractinput
**/ **/
(function ($) { (function ($) {
//types //types
$.fn.editabletypes = {}; $.fn.editabletypes = {};
var Abstract = function () { }; var AbstractInput = function () { };
Abstract.prototype = { AbstractInput.prototype = {
/** /**
Initializes input Initializes input
@ -26,7 +27,7 @@ To create your own input you should inherit from this class.
}, },
/** /**
Renders input. Can return jQuery deferred object. Renders input from tpl. Can return jQuery deferred object.
@method render() @method render()
**/ **/
@ -64,7 +65,7 @@ To create your own input you should inherit from this class.
}, },
/** /**
Converts value to string (for comparering) Converts value to string (for internal compare). For submitting to server used value2submit().
@method value2str(value) @method value2str(value)
@param {mixed} value @param {mixed} value
@ -150,7 +151,7 @@ To create your own input you should inherit from this class.
} }
}; };
Abstract.defaults = { AbstractInput.defaults = {
/** /**
HTML template of input. Normally you should not change it. HTML template of input. Normally you should not change it.
@ -177,6 +178,6 @@ To create your own input you should inherit from this class.
name: null name: null
}; };
$.extend($.fn.editabletypes, {abstract: Abstract}); $.extend($.fn.editabletypes, {abstractinput: AbstractInput});
}(window.jQuery)); }(window.jQuery));

@ -286,7 +286,7 @@
startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity, startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity, endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity, endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
currentDate = this.date.valueOf(), currentDate = this.date && this.date.valueOf(),
today = new Date(); today = new Date();
this.picker.find('.datepicker-days thead th:eq(1)') this.picker.find('.datepicker-days thead th:eq(1)')
.text(dates[this.language].months[month]+' '+year); .text(dates[this.language].months[month]+' '+year);
@ -321,7 +321,7 @@
prevMonth.getUTCDate() == today.getDate()) { prevMonth.getUTCDate() == today.getDate()) {
clsName += ' today'; clsName += ' today';
} }
if (prevMonth.valueOf() == currentDate) { if (currentDate && prevMonth.valueOf() == currentDate) {
clsName += ' active'; clsName += ' active';
} }
if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate) { if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate) {
@ -334,14 +334,14 @@
prevMonth.setUTCDate(prevMonth.getUTCDate()+1); prevMonth.setUTCDate(prevMonth.getUTCDate()+1);
} }
this.picker.find('.datepicker-days tbody').empty().append(html.join('')); this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
var currentYear = this.date.getUTCFullYear(); var currentYear = this.date && this.date.getUTCFullYear();
var months = this.picker.find('.datepicker-months') var months = this.picker.find('.datepicker-months')
.find('th:eq(1)') .find('th:eq(1)')
.text(year) .text(year)
.end() .end()
.find('span').removeClass('active'); .find('span').removeClass('active');
if (currentYear == year) { if (currentYear && currentYear == year) {
months.eq(this.date.getUTCMonth()).addClass('active'); months.eq(this.date.getUTCMonth()).addClass('active');
} }
if (year < startYear || year > endYear) { if (year < startYear || year > endYear) {

@ -4,7 +4,7 @@ Description and examples: http://vitalets.github.com/bootstrap-datepicker.
For localization you can include js file from here: https://github.com/eternicode/bootstrap-datepicker/tree/master/js/locales For localization you can include js file from here: https://github.com/eternicode/bootstrap-datepicker/tree/master/js/locales
@class date @class date
@extends abstract @extends abstractinput
@final @final
@example @example
<a href="#" id="dob" data-type="date" data-pk="1" data-url="/post" data-original-title="Select date">15/05/1984</a> <a href="#" id="dob" data-type="date" data-pk="1" data-url="/post" data-original-title="Select date">15/05/1984</a>
@ -48,7 +48,7 @@ $(function(){
this.parsedViewFormat = this.dpg.parseFormat(this.options.viewformat); this.parsedViewFormat = this.dpg.parseFormat(this.options.viewformat);
}; };
$.fn.editableutils.inherit(Date, $.fn.editabletypes.abstract); $.fn.editableutils.inherit(Date, $.fn.editabletypes.abstractinput);
$.extend(Date.prototype, { $.extend(Date.prototype, {
render: function () { render: function () {
@ -112,7 +112,7 @@ $(function(){
}); });
Date.defaults = $.extend({}, $.fn.editabletypes.abstract.defaults, { Date.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
/** /**
@property tpl @property tpl
@default <div></div> @default <div></div>

@ -4,7 +4,7 @@ Description and examples: http://jqueryui.com/datepicker.
This input is also accessible as **date** type. Do not use it together with __bootstrap-datepicker__ as both apply <code>$().datepicker()</code> method. This input is also accessible as **date** type. Do not use it together with __bootstrap-datepicker__ as both apply <code>$().datepicker()</code> method.
@class dateui @class dateui
@extends abstract @extends abstractinput
@final @final
@example @example
<a href="#" id="dob" data-type="date" data-pk="1" data-url="/post" data-original-title="Select date">15/05/1984</a> <a href="#" id="dob" data-type="date" data-pk="1" data-url="/post" data-original-title="Select date">15/05/1984</a>
@ -46,7 +46,7 @@ $(function(){
this.options.datepicker.dateFormat = this.options.datepicker.format; this.options.datepicker.dateFormat = this.options.datepicker.format;
}; };
$.fn.editableutils.inherit(DateUI, $.fn.editabletypes.abstract); $.fn.editableutils.inherit(DateUI, $.fn.editabletypes.abstractinput);
$.extend(DateUI.prototype, { $.extend(DateUI.prototype, {
render: function () { render: function () {
@ -129,7 +129,7 @@ $(function(){
}); });
DateUI.defaults = $.extend({}, $.fn.editabletypes.abstract.defaults, { DateUI.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
/** /**
@property tpl @property tpl
@default <div></div> @default <div></div>

188
src/inputs/html5types.js Normal file

@ -0,0 +1,188 @@
/**
HTML5 input types.
Following types are supported:
* password
* email
* url
* tel
* number
* range
Learn more about html5 inputs:
http://www.w3.org/wiki/HTML5_form_additions
To check browser compatibility please see:
https://developer.mozilla.org/en-US/docs/HTML/Element/Input
@class html5types
@extends text
@final
@since 1.3.0
@example
<a href="#" id="email" data-type="email" data-pk="1">admin@example.com</a>
<script>
$(function(){
$('#email').editable({
url: '/post',
title: 'Enter email'
});
});
</script>
**/
/**
@property tpl
@default depends on type
**/
/*
Password
*/
(function ($) {
var Password = function (options) {
this.init('password', options, Password.defaults);
};
$.fn.editableutils.inherit(Password, $.fn.editabletypes.text);
$.extend(Password.prototype, {
//do not display password, show '[hidden]' instead
value2html: function(value, element) {
if(value) {
$(element).text('[hidden]');
} else {
$(element).empty();
}
},
//as password not displayed, should not set value by html
html2value: function(html) {
return null;
}
});
Password.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
tpl: '<input type="password">'
});
$.fn.editabletypes.password = Password;
}(window.jQuery));
/*
Email
*/
(function ($) {
var Email = function (options) {
this.init('email', options, Email.defaults);
};
$.fn.editableutils.inherit(Email, $.fn.editabletypes.text);
Email.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
tpl: '<input type="email">'
});
$.fn.editabletypes.email = Email;
}(window.jQuery));
/*
Url
*/
(function ($) {
var Url = function (options) {
this.init('url', options, Url.defaults);
};
$.fn.editableutils.inherit(Url, $.fn.editabletypes.text);
Url.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
tpl: '<input type="url">'
});
$.fn.editabletypes.url = Url;
}(window.jQuery));
/*
Tel
*/
(function ($) {
var Tel = function (options) {
this.init('tel', options, Tel.defaults);
};
$.fn.editableutils.inherit(Tel, $.fn.editabletypes.text);
Tel.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
tpl: '<input type="tel">'
});
$.fn.editabletypes.tel = Tel;
}(window.jQuery));
/*
Number
*/
(function ($) {
var NumberInput = function (options) {
this.init('number', options, NumberInput.defaults);
};
$.fn.editableutils.inherit(NumberInput, $.fn.editabletypes.text);
$.extend(NumberInput.prototype, {
render: function () {
NumberInput.superclass.render.call(this);
if (this.options.min !== null) {
this.$input.attr('min', this.options.min);
}
if (this.options.max !== null) {
this.$input.attr('max', this.options.max);
}
if (this.options.step !== null) {
this.$input.attr('step', this.options.step);
}
}
});
NumberInput.defaults = $.extend({}, $.fn.editabletypes.text.defaults, {
tpl: '<input type="number">',
inputclass: 'input-mini',
min: null,
max: null,
step: null
});
$.fn.editabletypes.number = NumberInput;
}(window.jQuery));
/*
Range (inherit from number)
*/
(function ($) {
var Range = function (options) {
this.init('range', options, Range.defaults);
};
$.fn.editableutils.inherit(Range, $.fn.editabletypes.number);
$.extend(Range.prototype, {
render: function () {
this.$input = $(this.options.tpl);
var $slider = this.$input.filter('input');
if(this.options.inputclass) {
$slider.addClass(this.options.inputclass);
}
if (this.options.min !== null) {
$slider.attr('min', this.options.min);
}
if (this.options.max !== null) {
$slider.attr('max', this.options.max);
}
if (this.options.step !== null) {
$slider.attr('step', this.options.step);
}
$slider.on('input', function(){
$(this).siblings('output').text($(this).val());
});
},
activate: function() {
this.$input.filter('input').focus();
}
});
Range.defaults = $.extend({}, $.fn.editabletypes.number.defaults, {
tpl: '<input type="range"><output style="width: 30px; display: inline-block"></output>',
inputclass: 'input-medium'
});
$.fn.editabletypes.range = Range;
}(window.jQuery));

@ -2,7 +2,7 @@
List - abstract class for inputs that have source option loaded from js array or via ajax List - abstract class for inputs that have source option loaded from js array or via ajax
@class list @class list
@extends abstract @extends abstractinput
**/ **/
(function ($) { (function ($) {
@ -10,7 +10,7 @@ List - abstract class for inputs that have source option loaded from js array or
}; };
$.fn.editableutils.inherit(List, $.fn.editabletypes.abstract); $.fn.editableutils.inherit(List, $.fn.editabletypes.abstractinput);
$.extend(List.prototype, { $.extend(List.prototype, {
render: function () { render: function () {
@ -45,7 +45,7 @@ List - abstract class for inputs that have source option loaded from js array or
} }
deferred.resolve(); deferred.resolve();
}, function () { }, function () {
List.superclass.value2html(this.options.sourceError, element); //do nothing with element
deferred.resolve(); deferred.resolve();
}); });
@ -237,7 +237,7 @@ List - abstract class for inputs that have source option loaded from js array or
}); });
List.defaults = $.extend({}, $.fn.editabletypes.abstract.defaults, { List.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
/** /**
Source data for list. If string - considered ajax url to load items. Otherwise should be an array. Source data for list. If string - considered ajax url to load items. Otherwise should be an array.
Array format is: <code>[{value: 1, text: "text"}, {...}]</code><br> Array format is: <code>[{value: 1, text: "text"}, {...}]</code><br>

@ -2,7 +2,7 @@
Text input Text input
@class text @class text
@extends abstract @extends abstractinput
@final @final
@example @example
<a href="#" id="username" data-type="text" data-pk="1">awesome</a> <a href="#" id="username" data-type="text" data-pk="1">awesome</a>
@ -20,7 +20,7 @@ $(function(){
this.init('text', options, Text.defaults); this.init('text', options, Text.defaults);
}; };
$.fn.editableutils.inherit(Text, $.fn.editabletypes.abstract); $.fn.editableutils.inherit(Text, $.fn.editabletypes.abstractinput);
$.extend(Text.prototype, { $.extend(Text.prototype, {
activate: function() { activate: function() {
@ -31,7 +31,7 @@ $(function(){
} }
}); });
Text.defaults = $.extend({}, $.fn.editabletypes.abstract.defaults, { Text.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
/** /**
@property tpl @property tpl
@default <input type="text"> @default <input type="text">

@ -2,7 +2,7 @@
Textarea input Textarea input
@class textarea @class textarea
@extends abstract @extends abstractinput
@final @final
@example @example
<a href="#" id="comments" data-type="textarea" data-pk="1">awesome comment!</a> <a href="#" id="comments" data-type="textarea" data-pk="1">awesome comment!</a>
@ -21,7 +21,7 @@ $(function(){
this.init('textarea', options, Textarea.defaults); this.init('textarea', options, Textarea.defaults);
}; };
$.fn.editableutils.inherit(Textarea, $.fn.editabletypes.abstract); $.fn.editableutils.inherit(Textarea, $.fn.editabletypes.abstractinput);
$.extend(Textarea.prototype, { $.extend(Textarea.prototype, {
render: function () { render: function () {
@ -66,7 +66,7 @@ $(function(){
} }
}); });
Textarea.defaults = $.extend({}, $.fn.editabletypes.abstract.defaults, { Textarea.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
/** /**
@property tpl @property tpl
@default <textarea></textarea> @default <textarea></textarea>
@ -84,7 +84,7 @@ $(function(){
@type string @type string
@default null @default null
**/ **/
placeholder: null placeholder: null
}); });
$.fn.editabletypes.textarea = Textarea; $.fn.editabletypes.textarea = Textarea;

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

6039
test/libs/bootstrap222/css/bootstrap.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

(image error) Size: 8.6 KiB

Binary file not shown.

After

(image error) Size: 12 KiB

2159
test/libs/bootstrap222/js/bootstrap.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -33,6 +33,7 @@ define(function () {
'inputs/textarea', 'inputs/textarea',
'inputs/select', 'inputs/select',
'inputs/checklist', 'inputs/checklist',
'inputs/html5types',
'inputs-ext/address/address'], 'inputs-ext/address/address'],
init: function(require) { init: function(require) {
loadCss(require.toUrl("./editable-form.css")); loadCss(require.toUrl("./editable-form.css"));
@ -44,6 +45,7 @@ define(function () {
'inputs/text': ['inputs/abstract'], 'inputs/text': ['inputs/abstract'],
'inputs/textarea': ['inputs/abstract'], 'inputs/textarea': ['inputs/abstract'],
'inputs/abstract': ['editable-form/editable-form-utils'], 'inputs/abstract': ['editable-form/editable-form-utils'],
'inputs/html5types': ['inputs/text'],
//bootstrap //bootstrap
'bootstrap/js/bootstrap': { 'bootstrap/js/bootstrap': {
@ -145,7 +147,8 @@ define(function () {
return { return {
baseUrl: baseUrl, baseUrl: baseUrl,
paths: { paths: {
"bootstrap": "../test/libs/bootstrap221", // "bootstrap": "../test/libs/bootstrap221",
"bootstrap": "../test/libs/bootstrap222",
"jqueryui": "../test/libs/jquery-ui-1.9.1.custom", "jqueryui": "../test/libs/jquery-ui-1.9.1.custom",
"poshytip": "../test/libs/poshytip", "poshytip": "../test/libs/poshytip",
"test": "../test" "test": "../test"

@ -4,30 +4,41 @@ var jqver = decodeURIComponent((new RegExp('[?|&]' + 'jquery' + '=' + '([^&;]+?)
require(["loader", jqurl], function(loader) { require(["loader", jqurl], function(loader) {
requirejs.config(loader.getConfig("../src")); var config = loader.getConfig("../src"),
params = loader.getParams();
//add test specific dependencies
config.shim['test/mocks'] = ['element/editable-element', 'test/libs/mockjax/jquery.mockjax'];
//as we need to keep order of tests, create shim dependencies automatically
addTests(config);
requirejs.config(config);
require(['element/editable-element', require(['test/unit/api'],
'test/libs/mockjax/jquery.mockjax'
],
function() { function() {
//disable effects //disable effects
$.fx.off = true; $.fx.off = true;
$.support.transition = false; $.support.transition = false;
var params = loader.getParams(); QUnit.load();
QUnit.start();
require([ });
function addTests(config) {
var tests = [
'test/mocks', 'test/mocks',
'test/unit/common', 'test/unit/common',
'test/unit/text', 'test/unit/text',
'test/unit/textarea', 'test/unit/textarea',
'test/unit/select', 'test/unit/select',
'test/unit/checklist', 'test/unit/checklist',
'test/unit/api', (params.f === 'bootstrap') ? 'test/unit/date' : 'test/unit/dateui',
(params.f === 'bootstrap') ? 'test/unit/date' : 'test/unit/dateui' 'test/unit/api'
], function() { ];
QUnit.load();
QUnit.start(); for(var i=0; i<tests.length-1; i++) {
}); config.shim[tests[i+1]] = [tests[i]];
}); }
}
}); });

@ -57,7 +57,7 @@ $(function () {
}); });
// useful functions // usefull functions
function tip(e) { function tip(e) {
return e.data('editableContainer').tip(); return e.data('editableContainer').tip();

@ -79,8 +79,8 @@ $(function () {
e.editable(); e.editable();
}); });
asyncTest("events: shown / hidden (reason: cancel, onblur, manual)", function () { asyncTest("events: shown / hidden (reason: cancel, onblur, nochange, manual)", function () {
expect(11); expect(15);
var val = '1', test_reason, var val = '1', test_reason,
e = $('<a href="#" data-pk="1" data-type="select" data-url="post.php" data-name="text" data-value="'+val+'"></a>').appendTo(fx); e = $('<a href="#" data-pk="1" data-type="select" data-url="post.php" data-name="text" data-value="'+val+'"></a>').appendTo(fx);
@ -113,6 +113,13 @@ $(function () {
e.parent().click(); e.parent().click();
ok(!p.is(':visible'), 'popover closed'); ok(!p.is(':visible'), 'popover closed');
test_reason = 'nochange'
e.click();
p = tip(e);
ok(p.is(':visible'), 'popover shown');
p.find('form').submit(); //submit value without changes
ok(!p.is(':visible'), 'popover closed');
test_reason = 'manual' test_reason = 'manual'
e.click(); e.click();
p = tip(e); p = tip(e);
@ -152,9 +159,8 @@ $(function () {
e.remove(); e.remove();
start(); start();
}, timeout); }, timeout);
}); });
test("show/hide/toggle methods", function () { test("show/hide/toggle methods", function () {
var e = $('<a href="#" data-pk="1" data-url="post.php" data-name="text1">abc</a>').appendTo('#qunit-fixture').editable(); var e = $('<a href="#" data-pk="1" data-url="post.php" data-name="text1">abc</a>').appendTo('#qunit-fixture').editable();
e.editable('show'); e.editable('show');
@ -212,16 +218,16 @@ $(function () {
equal(e.text(), 'abcd', 'text set correctly (by object)'); equal(e.text(), 'abcd', 'text set correctly (by object)');
}); });
asyncTest("'submit' method: client and server validation", function () { asyncTest("'submit' method: client and server validation errors", function () {
var ev1 = 'ev1', var ev1 = 'ev1',
ev2 = 'ev2', ev2 = 'ev2',
e1v = 'e1v', e1v = 'e1v',
e = $('<a href="#" class="new" data-type="text" data-url="post.php" data-name="text">'+ev1+'</a>').appendTo(fx).editable({ e = $('<a href="#" class="new-val" data-type="text" data-url="post.php" data-name="text">'+ev1+'</a>').appendTo(fx).editable({
validate: function(value) { validate: function(value) {
if(value == ev1) return 'invalid'; if(value == ev1) return 'invalid';
} }
}), }),
e1 = $('<a href="#" class="new" data-type="text" data-name="text1">'+e1v+'</a>').appendTo(fx).editable(); e1 = $('<a href="#" class="new-val" data-type="text" data-name="text1">'+e1v+'</a>').appendTo(fx).editable();
$.mockjax({ $.mockjax({
url: 'new-error.php', url: 'new-error.php',
@ -236,49 +242,71 @@ $(function () {
}; };
} }
}); });
$(fx).find('.new').editable('submit', { $.mockjax({
url: 'new.php', url: 'new.php',
error: function(data) { response: function(settings) {
ok(data.errors, 'errors defined'); ok(false, 'should not submit to new.php');
equal(data.errors.text, 'invalid', 'client validation error ok'); }
});
$(fx).find('.new-val').editable('submit', {
url: 'new.php',
error: function(errors) {
equal(errors.text, 'invalid', 'client validation error ok');
} }
}); });
//change value to pass client side validation //change value to pass client side validation
e.click(); e.click();
var p = tip(e); var p = tip(e);
p.find('input[type=text]').val(ev2); p.find('input[type=text]').val(ev2);
p.find('button[type=submit]').click(); p.find('button[type=submit]').click();
$(fx).find('.new').editable('submit', { $(fx).find('.new-val').editable('submit', {
url: 'new-error.php', url: 'new-error.php',
data: {a: 123}, data: {a: 123},
error: function(data) { success: function(data, config) {
equal(data.errors.text1, 'server-invalid', 'server validation error ok'); ok(data.errors, 'errors received from server');
e.remove(); ok(typeof config.error === 'function', 'config passed correctly');
e1.remove();
start(); if(data && data.id) {
//success
} else if(data && data.errors){
config.error.call(this, data.errors); //call error from success
}
},
error: function(errors) {
equal(errors.text1, 'server-invalid', 'server validation error ok');
}, },
ajaxOptions: { ajaxOptions: {
type: 'PUT' type: 'PUT',
dataType: 'json'
} }
}); });
setTimeout(function() {
e.remove();
e1.remove();
start();
}, timeout);
}); });
asyncTest("'submit' method: server error", function () { asyncTest("'submit' method: server error", function () {
expect(2);
var ev1 = 'ev1', var ev1 = 'ev1',
e1v = 'e1v', e1v = 'e1v',
e = $('<a href="#" class="new" data-type="text" data-url="post.php" data-name="text">'+ev1+'</a>').appendTo(fx).editable(), e = $('<a href="#" class="new-err" data-type="text" data-url="post.php" data-name="text">'+ev1+'</a>').appendTo(fx).editable(),
e1 = $('<a href="#" class="new" data-type="text" data-name="text1">'+e1v+'</a>').appendTo(fx).editable(); e1 = $('<a href="#" class="new-err" data-type="text" data-name="text1">'+e1v+'</a>').appendTo(fx).editable();
$(fx).find('.new').editable('submit', { $(fx).find('.new-err').editable('submit', {
url: 'error.php', url: 'error.php',
error: function(data) { error: function(data) {
ok(!data.errors, 'no client errors'); equal(this[0], $(fx).find('.new-err')[0], 'success context ok');
equal(this[1], $(fx).find('.new-err')[1], 'success context2 ok');
equal(data.status, 500, 'status 500 ok');
equal(data.responseText, 'customtext', 'server error ok'); equal(data.responseText, 'customtext', 'server error ok');
e.remove(); e.remove();
@ -290,7 +318,6 @@ $(function () {
}); });
asyncTest("'submit' method: success", function () { asyncTest("'submit' method: success", function () {
expect(7);
var ev1 = 'ev1', var ev1 = 'ev1',
e1v = 'e1v', e1v = 'e1v',
pk = 123, pk = 123,
@ -302,24 +329,23 @@ $(function () {
response: function(settings) { response: function(settings) {
equal(settings.data.text, ev1, 'first value ok'); equal(settings.data.text, ev1, 'first value ok');
equal(settings.data.text1, e1v, 'second value ok'); equal(settings.data.text1, e1v, 'second value ok');
this.responseText = {id: pk}; this.responseText = 'response-body';
} }
}); });
$(fx).find('.new').editable('submit', { $(fx).find('.new').editable('submit', {
url: 'new-success.php', url: 'new-success.php',
success: function(data) { success: function(data) {
equal(e.data('editable').options.pk, pk, 'pk1 ok'); equal(this[0], $(fx).find('.new')[0], 'success context ok');
ok(!e.hasClass('editable-changed'), 'no "editable-changed" class'); equal(this[1], $(fx).find('.new')[1], 'success context2 ok');
equal(data, 'response-body', 'response body ok');
equal(e1.data('editable').options.pk, pk, 'pk2 ok');
ok(!e1.hasClass('editable-changed'), 'no "editable-changed" class');
equal(data.id, pk, 'server result id ok');
e.remove(); e.remove();
e1.remove(); e1.remove();
start(); start();
},
error: function(errors) {
ok(false, 'error should not be called');
} }
}); });

@ -3,7 +3,8 @@ $(function () {
module("checklist", { module("checklist", {
setup: function(){ setup: function(){
sfx = $('#qunit-fixture'), sfx = $('#qunit-fixture'),
fx = $('#async-fixture'); fx = $('#async-fixture');
$.support.transition = false;
} }
}); });

@ -444,6 +444,81 @@
e.remove(); e.remove();
start(); start();
}, timeout); }, 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({
name: 'username',
params: {
q: 2
},
ajaxOptions: {
dataType: 'json'
},
success: function(resp) {
equal(resp.dataType, 'json', 'dataType ok');
equal(resp.data.pk, 1, 'pk ok');
equal(resp.data.name, 'username', 'name ok');
equal(resp.data.value, newText, 'value ok');
equal(resp.data.q, 2, 'additional params ok');
}
}),
newText = 'cd<e>;"'
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("params as function", function () {
var e = $('<a href="#" data-pk="1" data-url="post-params-func.php">abc</a>').appendTo(fx).editable({
name: 'username',
params: function(params) {
ok(this === e[0], 'scope is ok');
equal(params.pk, 1, 'params in func already have values (pk)');
return $.extend(params, {q: 2, pk: 3});
},
ajaxOptions: {
headers: {"myHeader": "123"}
}
}),
newText = 'cd<e>;"'
$.mockjax({
url: 'post-params-func.php',
response: function(settings) {
equal(settings.dataType, undefined, 'dataType undefined (correct)');
equal(settings.data.pk, 3, 'pk ok');
equal(settings.data.name, 'username', 'name ok');
equal(settings.data.value, newText, 'value ok');
equal(settings.data.q, 2, 'additional params 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);
});
}(jQuery)); }(jQuery));

@ -6,6 +6,7 @@ $(function () {
setup: function(){ setup: function(){
fx = $('#async-fixture'); fx = $('#async-fixture');
dpg = $.fn.datepicker.DPGlobal; dpg = $.fn.datepicker.DPGlobal;
$.support.transition = false;
} }
}); });

@ -5,6 +5,7 @@ $(function () {
module("dateui", { module("dateui", {
setup: function(){ setup: function(){
fx = $('#async-fixture'); fx = $('#async-fixture');
$.support.transition = false;
} }
}); });

@ -295,12 +295,12 @@ $(function () {
expect(4); expect(4);
//clear cache //clear cache
$(document).removeData('groups.php-name1'); $(document).removeData('groups-cache-sim.php-name1');
var req = 0; var req = 0;
$.mockjax({ $.mockjax({
url: 'groups-cache-sim.php', url: 'groups-cache-sim.php',
responseTime: 200, responseTime: 50,
response: function() { response: function() {
req++; req++;
this.responseText = groups; this.responseText = groups;
@ -312,7 +312,6 @@ $(function () {
e2 = $('<a href="#" data-type="select" data-pk="1" data-name="name1" data-value="3" data-url="post.php" data-source="groups-cache-sim.php"></a>').appendTo(fx).editable(); e2 = $('<a href="#" data-type="select" data-pk="1" data-name="name1" data-value="3" data-url="post.php" data-source="groups-cache-sim.php"></a>').appendTo(fx).editable();
setTimeout(function() { setTimeout(function() {
equal(req, 1, 'one request'); equal(req, 1, 'one request');
equal(e.text(), groups[1], 'text1 correct'); equal(e.text(), groups[1], 'text1 correct');
equal(e1.text(), groups[2], 'text2 correct'); equal(e1.text(), groups[2], 'text2 correct');
@ -330,7 +329,7 @@ $(function () {
expect(4); expect(4);
//clear cache //clear cache
$(document).removeData('groups.php-name1'); $(document).removeData('groups-cache-sim-err.php-name1');
var req = 0; var req = 0;
$.mockjax({ $.mockjax({
@ -342,17 +341,16 @@ $(function () {
} }
}); });
var e = $('<a href="#" data-type="select" data-pk="1" data-name="name1" data-value="1" data-autotext="always" data-url="post.php" data-source="groups-cache-sim-err.php">35</a>').appendTo(fx).editable(), var e = $('<a href="#" data-type="select" data-pk="1" data-name="name1" data-value="1" data-autotext="always" data-url="post.php" data-source="groups-cache-sim-err.php">11</a>').appendTo(fx).editable(),
e1 = $('<a href="#" data-type="select" data-pk="1" data-name="name1" data-value="2" data-autotext="always" data-url="post.php" data-source="groups-cache-sim-err.php">35</a>').appendTo(fx).editable(), e1 = $('<a href="#" data-type="select" data-pk="1" data-name="name1" data-value="2" data-autotext="always" data-url="post.php" data-source="groups-cache-sim-err.php">22</a>').appendTo(fx).editable(),
e2 = $('<a href="#" data-type="select" data-pk="1" data-name="name1" data-value="3" data-autotext="always" data-url="post.php" data-source="groups-cache-sim-err.php">6456</a>').appendTo(fx).editable(), e2 = $('<a href="#" data-type="select" data-pk="1" data-name="name1" data-value="3" data-autotext="always" data-url="post.php" data-source="groups-cache-sim-err.php"></a>').appendTo(fx).editable();
errText = $.fn.editabletypes.select.defaults.sourceError;
setTimeout(function() { setTimeout(function() {
equal(req, 1, 'one request'); equal(req, 1, 'one request');
equal(e.text(), errText, 'text1 correct'); equal(e.text(), '11', 'text1 correct');
equal(e1.text(), errText, 'text2 correct'); equal(e1.text(), '22', 'text2 correct');
equal(e2.text(), errText, 'text3 correct'); equal(e2.text(), $.fn.editable.defaults.emptytext, 'text3 correct');
e.remove(); e.remove();
e1.remove(); e1.remove();

@ -211,71 +211,6 @@ $(function () {
}); });
asyncTest("should submit all required params", function () {
var e = $('<a href="#" data-pk="1" data-url="post-resp.php">abc</a>').appendTo(fx).editable({
name: 'username',
params: {
q: 2
},
success: function(resp) {
equal(resp.dataType, 'json', 'dataType ok');
equal(resp.data.pk, 1, 'pk ok');
equal(resp.data.name, 'username', 'name ok');
equal(resp.data.value, newText, 'value ok');
equal(resp.data.q, 2, 'additional params ok');
}
}),
newText = 'cd<e>;"'
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("params as function", function () {
var e = $('<a href="#" data-pk="1" data-url="post-resp.php">abc</a>').appendTo(fx).editable({
name: 'username',
params: function(params) {
ok(this === e[0], 'scope is ok');
equal(params.pk, 1, 'params in func already have values (pk)');
return { q: 2, pk: 3 };
},
success: function(resp) {
equal(resp.dataType, 'json', 'dataType ok');
equal(resp.data.pk, 3, 'pk ok');
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>;"'
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("ajaxOptions", function () { asyncTest("ajaxOptions", function () {
var e = $('<a href="#" data-pk="1" data-url="post-options.php">abc</a>').appendTo(fx).editable({ var e = $('<a href="#" data-pk="1" data-url="post-options.php">abc</a>').appendTo(fx).editable({
@ -503,6 +438,67 @@ $(function () {
start(); start();
}, timeout); }, timeout);
}); });
test("password", function () {
var v = '123', v1 = '456';
var e = $('<a href="#" data-pk="1" data-name="name" data-value="'+v+'"></a>').appendTo('#qunit-fixture').editable({
type: 'password',
url: function(params) {
equal(params.value, v1, 'submitted value correct');
}
});
equal(e.text(), '[hidden]', 'text is hidden');
e.click()
var p = tip(e);
ok(p.is(':visible'), 'popover visible');
var $input = p.find('input[type="password"]');
ok($input.length, 'input exists');
equal($input.val(), v, 'input contains correct value');
$input.val(v1);
p.find('form').submit();
ok(!p.is(':visible'), 'popover closed');
equal(e.data('editable').value, v1, 'new value saved to value');
equal(e.text(), '[hidden]', 'new text shown');
});
test("html5 types", function () {
var types = ['email', 'url', 'tel', 'number', 'range'],
v = '12',
v1 = '45';
expect(8*types.length);
for(var i = 0; i< types.length; i++) {
var e = $('<a href="#" data-pk="1" data-name="name">'+v+'</a>').appendTo('#qunit-fixture').editable({
type: types[i],
url: function(params) {
equal(params.value, v1, 'submitted value correct');
}
});
equal(e.data('editable').value, v, 'value correct');
e.click()
var p = tip(e);
ok(p.is(':visible'), 'popover visible');
var $input = p.find('input[type='+types[i]+']');
ok($input.length, 'input exists');
equal($input.val(), v, 'input contain correct value');
$input.val(v1);
p.find('form').submit();
ok(!p.is(':visible'), 'popover closed');
equal(e.data('editable').value, v1, 'new value saved to value');
equal(e.text(), v1, 'new text shown');
}
});
}); });