From 79847d1d9295caf4abf2061b96a27f867ae4192f Mon Sep 17 00:00:00 2001 From: vitalets <noginsk@rambler.ru> Date: Wed, 28 Nov 2012 21:24:51 +0400 Subject: [PATCH] onblur option ready, need test --- src/containers/editable-container.js | 133 +++++++++++++++++++++++++-- src/containers/editable-inline.js | 10 +- src/containers/editable-poshytip.js | 5 +- src/containers/editable-tooltip.js | 8 +- src/element/editable-element.js | 32 ++----- 5 files changed, 140 insertions(+), 48 deletions(-) diff --git a/src/containers/editable-container.js b/src/containers/editable-container.js index 8cc64c2..0228d55 100644 --- a/src/containers/editable-container.js +++ b/src/containers/editable-container.js @@ -27,7 +27,73 @@ 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 element = e.target, + $target = $(e.target), + $clickedContainer = $target.is('.editable-container') ? $target : $target.closest('.editable-container'); + + //if click inside some editableContainer --> find corresponding element + if($clickedContainer.length) { + $('.editable-open').each(function(i, el){ + if($(el).data('editableContainer').tip()[0] === $clickedContainer[0]) { + element = el; + return false; + } + }); + } + + //close all open containers (except one) + EditableContainer.prototype.closeOthers(element); + + /* $('.editable-open').each(function(){ + //if click target is editable element --> do nothing with el + if(this === e.target) { + return; + } + + var $el = $(this), + ec = $el.data('editableContainer'); + + //if click in some editableContainer and current el is it's owner --> do nothing with el + if($clickedContainer.length && ec.tip()[0] === $clickedContainer[0]) { + return; + } + + //otherwise cancel or submit el's container + if(ec.options.onblur === 'cancel') { + $el.data('editableContainer').hide(); + } else if(ec.options.onblur === 'submit') { + $el.data('editableContainer').tip().find('form').submit(); + } + }); */ + + //if click inside container --> do nothing + // if($target.is('.editable-container') || $target.parents('.editable-container').length || $target.parents('.ui-datepicker-header').length) { + /* + 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(); + */ + }); + + $(document).data('editable-handlers-attached', true); + } }, //split options on containerOptions and formOptions @@ -93,11 +159,22 @@ Applied as jQuery method. /** Shows container with form @method show() + @param {boolean} multi if true - other editable containers will not be closed. Default false. **/ - show: function () { + show: function (multi) { + this.$element.addClass('editable-open'); + if(!multi) { + //close all open containers (except one) + 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 +185,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,6 +199,11 @@ 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() @@ -210,6 +293,34 @@ 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(); + } + }); + } }; @@ -248,7 +359,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 +386,15 @@ Applied as jQuery method. @default true @private **/ - autohide: true + autohide: true, + /** + Action when click outside container. Can be <code>cancel|submit|ignore</code> + + @property onblur + @type string + @default cancel + **/ + onblur: 'cancel' }; /* diff --git a/src/containers/editable-inline.js b/src/containers/editable-inline.js index 92c5455..df585a6 100644 --- a/src/containers/editable-inline.js +++ b/src/containers/editable-inline.js @@ -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)); }, diff --git a/src/containers/editable-poshytip.js b/src/containers/editable-poshytip.js index 5cbd427..3488ec9 100644 --- a/src/containers/editable-poshytip.js +++ b/src/containers/editable-poshytip.js @@ -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(); }, diff --git a/src/containers/editable-tooltip.js b/src/containers/editable-tooltip.js index dcfa261..4fbc842 100644 --- a/src/containers/editable-tooltip.js +++ b/src/containers/editable-tooltip.js @@ -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() { diff --git a/src/element/editable-element.js b/src/element/editable-element.js index f51afec..1a3dd78 100644 --- a/src/element/editable-element.js +++ b/src/element/editable-element.js @@ -50,24 +50,6 @@ Makes editable any HTML element on the page. Applied as jQuery method. this.value = this.input.str2value($.trim(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'); @@ -199,15 +181,16 @@ Makes editable any HTML element on the page. Applied as jQuery method. return; } //stop propagation bacause document listen any click to hide all editableContainers - e.stopPropagation(); + //e.stopPropagation(); this.toggle(); }, /** Shows container with form @method show() + @param {boolean} multi if true - other editable containers will not be closed. Default false. **/ - show: function () { + show: function (multi) { if(this.options.disabled) { return; } @@ -216,7 +199,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({ @@ -229,10 +212,11 @@ Makes editable any HTML element on the page. Applied as jQuery method. } //hide all other editable containers. Required to work correctly with toggle = manual - $('.editable-container').find('.editable-cancel').click(); + //temp + //$('.editable-container').find('.editable-cancel').click(); //show container - this.container.show(); + this.container.show(multi); }, /** @@ -247,7 +231,7 @@ 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(); - } + } }, /**