diff --git a/src/containers/editable-container.js b/src/containers/editable-container.js index 6c88750..9126688 100644 --- a/src/containers/editable-container.js +++ b/src/containers/editable-container.js @@ -23,8 +23,8 @@ Applied as jQuery method. innerCss: null, //tbd in child class init: function(element, options) { this.$element = $(element); - //todo: what is in priority: data or js? - this.options = $.extend({}, $.fn.editableContainer.defaults, $.fn.editableutils.getConfigData(this.$element), options); + //since 1.4.1 container do not use data-* directly as they already merged into options. + this.options = $.extend({}, $.fn.editableContainer.defaults, options); this.splitOptions(); //set scope of form callbacks to element diff --git a/src/editable-form/editable-form.js b/src/editable-form/editable-form.js index 50d52c1..efbeb63 100644 --- a/src/editable-form/editable-form.js +++ b/src/editable-form/editable-form.js @@ -11,7 +11,7 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc. var EditableForm = function (div, options) { this.options = $.extend({}, $.fn.editableform.defaults, options); - this.$div = $(div); //div, containing form. Not form tag! Not editable-element. + this.$div = $(div); //div, containing form. Not form tag. Not editable-element. if(!this.options.scope) { this.options.scope = this; } diff --git a/src/element/editable-element.js b/src/element/editable-element.js index 288e8d0..00e13c6 100644 --- a/src/element/editable-element.js +++ b/src/element/editable-element.js @@ -8,8 +8,13 @@ Makes editable any HTML element on the page. Applied as jQuery method. var Editable = function (element, options) { this.$element = $(element); - this.options = $.extend({}, $.fn.editable.defaults, $.fn.editableutils.getConfigData(this.$element), options); - this.init(); + //data-* has more priority over js options: because dynamically created elements may change data-* + this.options = $.extend({}, $.fn.editable.defaults, options, $.fn.editableutils.getConfigData(this.$element)); + if(this.options.selector) { + this.initLive(); + } else { + this.init(); + } }; Editable.prototype = { @@ -52,8 +57,10 @@ Makes editable any HTML element on the page. Applied as jQuery method. if(this.options.toggle !== 'manual') { this.$element.addClass('editable-click'); this.$element.on(this.options.toggle + '.editable', $.proxy(function(e){ + //prevent following link e.preventDefault(); - //stop propagation not required anymore because in document click handler it checks event target + + //stop propagation not required because in document click handler it checks event target //e.stopPropagation(); if(this.options.toggle === 'mouseenter') { @@ -95,6 +102,24 @@ Makes editable any HTML element on the page. Applied as jQuery method. }, this)); }, + /* + Initializes parent element for live editables + */ + initLive: function() { + //store selector + var selector = this.options.selector; + //modify options for child elements + this.options.selector = false; + this.options.autotext = 'never'; + //listen toggle events + this.$element.on(this.options.toggle + '.editable', selector, $.proxy(function(e){ + var $target = $(e.target); + if(!$target.data('editable')) { + $target.editable(this.options).trigger(e); + } + }, this)); + }, + /* Renders value into element's text. Can call custom display method from options. @@ -622,8 +647,8 @@ Makes editable any HTML element on the page. Applied as jQuery method. @property emptyclass @type string + @since 1.4.1 @default editable-empty - @since 1.4.1 **/ emptyclass: 'editable-empty', /** @@ -632,10 +657,35 @@ Makes editable any HTML element on the page. Applied as jQuery method. @property unsavedclass @type string + @since 1.4.1 @default editable-unsaved - @since 1.4.1 **/ - unsavedclass: 'editable-unsaved' + unsavedclass: 'editable-unsaved', + /** + If a css selector is provided, editable will be delegated to the specified targets. + Usefull for dynamically generated DOM elements. + **Please note**, that delegated targets can't use `emptytext` and `autotext` options, + as they are initialized after first click. + + @property selector + @type string + @since 1.4.1 + @default null + @example + <div id="user"> + <a href="#" data-name="username" data-type="text" title="Username">awesome</a> + <a href="#" data-name="group" data-type="select" data-source="/groups" data-value="1" title="Group">Operator</a> + </div> + + <script> + $('#user').editable({ + selector: 'a', + url: '/post', + pk: 1 + }); + </script> + **/ + selector: null }; }(window.jQuery)); diff --git a/test/unit/common.js b/test/unit/common.js index 316e593..92600a6 100644 --- a/test/unit/common.js +++ b/test/unit/common.js @@ -155,13 +155,13 @@ 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({ + e = $('<a href="#" data-type="text" data-pk="1" id="a">'+oldValue+'</a>').appendTo('#qunit-fixture').editable({ onblur: 'submit', - url: function() {} + send: 'never' }), e2 = $('<a href="#" data-type="text" data-pk="1" data-url="post.php" id="b">abcd</a>').appendTo('#qunit-fixture').editable(); @@ -179,7 +179,7 @@ $('#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); @@ -644,5 +644,57 @@ }); + test("`selector` option", function () { + var parent = $('<div><a href="#" id="a" data-type="text">123</a></div>').appendTo('#qunit-fixture').editable({ + selector: 'a', + url: 'post.php', + source: groups + }), + b = $('<a href="#" id="b" data-type="select" data-value="1"></a>'), + e = $('#a'), + selected = 2; + + ok(!e.hasClass('editable'), 'no editable class applied'); + + e.click(); + var p = tip(e); + + ok(e.hasClass('editable'), 'editable class applied'); + ok(e.data('editable'), 'data(editable) ok'); + ok(!e.data('editable').selector, 'selector cleared'); + equal(e.data('editable').options.url, 'post.php', 'url ok'); + equal(e.data('editable').options.type, 'text', 'type text ok'); + + ok(p.is(':visible'), 'popover visible'); + ok(p.find('input[type=text]').length, 'input exists'); + equal(p.find('input[type=text]').val(), '123', 'input contain correct value'); + + //dynamically add second element + b.appendTo(parent); + e = b; + + e.click(); + ok(!p.is(':visible'), 'first popover closed'); + + ok(e.data('editable'), 'data(editable) ok'); + ok(!e.data('editable').selector, 'selector cleared'); + equal(e.data('editable').options.url, 'post.php', 'url ok'); + equal(e.data('editable').options.type, 'select', 'type select ok'); + + p = tip(e); + ok(p.is(':visible'), 'second popover visible'); + + ok(p.find('select').length, 'select exists'); + equal(p.find('select').find('option').length, size, 'options loaded'); + equal(p.find('select').val(), e.data('editable').value, 'selected value correct'); + + p.find('select').val(selected); + p.find('form').submit(); + + ok(!p.is(':visible'), 'popover closed'); + equal(e.data('editable').value, selected, 'new value saved'); + equal(e.text(), groups[selected], 'new text shown'); + }); + }(jQuery)); \ No newline at end of file