diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c1d8d75..13df5c5 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -4,6 +4,7 @@ X-editable changelog Version 1.3.0 wip ---------------------------- +[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) diff --git a/grunt.js b/grunt.js index e7427c9..07c2d72 100644 --- a/grunt.js +++ b/grunt.js @@ -42,7 +42,8 @@ function getFiles() { inputs+'text.js', inputs+'textarea.js', inputs+'select.js', - inputs+'checklist.js' + inputs+'checklist.js', + inputs+'html5types.js' ]; //common css files diff --git a/src/inputs/abstract.js b/src/inputs/abstract.js index 9c4581b..22fd989 100644 --- a/src/inputs/abstract.js +++ b/src/inputs/abstract.js @@ -65,7 +65,7 @@ To create your own input you can 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) @param {mixed} value diff --git a/src/inputs/html5types.js b/src/inputs/html5types.js new file mode 100644 index 0000000..73ac47a --- /dev/null +++ b/src/inputs/html5types.js @@ -0,0 +1,180 @@ +/** +HTML5 input types. +Following types are supported: +- password +- email +- url +- tel +- number +- range + +To check browser compatibility please see: +http://www.wufoo.com/html5/ + +@class html5types +@extends text +@final +@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> +**/ + + +/* +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)); \ No newline at end of file diff --git a/src/inputs/textarea.js b/src/inputs/textarea.js index 72e431f..6a853b3 100644 --- a/src/inputs/textarea.js +++ b/src/inputs/textarea.js @@ -84,7 +84,7 @@ $(function(){ @type string @default null **/ - placeholder: null + placeholder: null }); $.fn.editabletypes.textarea = Textarea; diff --git a/test/loader.js b/test/loader.js index d961fa4..5ec827a 100644 --- a/test/loader.js +++ b/test/loader.js @@ -33,6 +33,7 @@ define(function () { 'inputs/textarea', 'inputs/select', 'inputs/checklist', + 'inputs/html5types', 'inputs-ext/address/address'], init: function(require) { loadCss(require.toUrl("./editable-form.css")); @@ -44,6 +45,7 @@ define(function () { 'inputs/text': ['inputs/abstract'], 'inputs/textarea': ['inputs/abstract'], 'inputs/abstract': ['editable-form/editable-form-utils'], + 'inputs/html5types': ['inputs/text'], //bootstrap 'bootstrap/js/bootstrap': { diff --git a/test/unit/text.js b/test/unit/text.js index e8e81fe..17d692c 100644 --- a/test/unit/text.js +++ b/test/unit/text.js @@ -438,6 +438,67 @@ $(function () { start(); }, 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'); + } + + }); }); \ No newline at end of file