refactor containers: same render logic, fix tests
This commit is contained in:
parent
775deede07
commit
0ced7f87f5
src
containers
editable-form
element
test/unit
@ -26,6 +26,10 @@ Applied as jQuery method.
|
||||
//todo: what is in priority: data or js?
|
||||
this.options = $.extend({}, $.fn.editableContainer.defaults, $.fn.editableutils.getConfigData(this.$element), options);
|
||||
this.splitOptions();
|
||||
|
||||
//set scope of form callbacks to element
|
||||
this.formOptions.scope = this.$element[0];
|
||||
|
||||
this.initContainer();
|
||||
|
||||
//bind 'destroyed' listener to destroy container when element is removed from dom
|
||||
@ -82,13 +86,29 @@ Applied as jQuery method.
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
Returns jquery object of container
|
||||
@method tip()
|
||||
*/
|
||||
tip: function() {
|
||||
return this.container() ? this.container().$tip : null;
|
||||
},
|
||||
|
||||
/* returns container object */
|
||||
container: function() {
|
||||
return this.$element.data(this.containerName);
|
||||
},
|
||||
|
||||
call: function() {
|
||||
this.$element[this.containerName].apply(this.$element, arguments);
|
||||
},
|
||||
|
||||
initContainer: function(){
|
||||
this.call(this.containerOptions);
|
||||
},
|
||||
|
||||
initForm: function() {
|
||||
this.formOptions.scope = this.$element[0]; //set scope of form callbacks to element
|
||||
this.$form = $('<div>')
|
||||
renderForm: function() {
|
||||
this.$form
|
||||
.editableform(this.formOptions)
|
||||
.on({
|
||||
save: $.proxy(this.save, this), //click on submit button (value changed)
|
||||
@ -110,31 +130,16 @@ Applied as jQuery method.
|
||||
**/
|
||||
this.$element.triggerHandler('shown');
|
||||
}, this)
|
||||
});
|
||||
return this.$form;
|
||||
})
|
||||
.editableform('render');
|
||||
},
|
||||
|
||||
/*
|
||||
Returns jquery object of container
|
||||
@method tip()
|
||||
*/
|
||||
tip: function() {
|
||||
return this.container().$tip;
|
||||
},
|
||||
|
||||
container: function() {
|
||||
return this.$element.data(this.containerName);
|
||||
},
|
||||
|
||||
call: function() {
|
||||
this.$element[this.containerName].apply(this.$element, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
Shows container with form
|
||||
@method show()
|
||||
@param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
|
||||
**/
|
||||
**/
|
||||
/* Note: poshytip owerwrites this method totally! */
|
||||
show: function (closeAll) {
|
||||
this.$element.addClass('editable-open');
|
||||
if(closeAll !== false) {
|
||||
@ -142,16 +147,37 @@ Applied as jQuery method.
|
||||
this.closeOthers(this.$element[0]);
|
||||
}
|
||||
|
||||
//show container itself
|
||||
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');
|
||||
|
||||
/*
|
||||
Currently, form is re-rendered on every show.
|
||||
The main reason is that we dont know, what container will do with content when closed:
|
||||
remove(), detach() or just hide().
|
||||
|
||||
Detaching form itself before hide and re-insert before show is good solution,
|
||||
but visually it looks ugly, as container changes size before hide.
|
||||
*/
|
||||
|
||||
//if form already exist - delete previous data
|
||||
if(this.$form) {
|
||||
//todo: destroy prev data!
|
||||
//this.$form.destroy();
|
||||
}
|
||||
|
||||
this.$form = $('<div>');
|
||||
|
||||
//insert form into container body
|
||||
if(this.tip().is(this.innerCss)) {
|
||||
//for inline container
|
||||
this.tip().append(this.$form);
|
||||
} else {
|
||||
this.tip().find(this.innerCss).append(this.$form);
|
||||
}
|
||||
|
||||
//render form
|
||||
this.renderForm();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -163,8 +189,10 @@ Applied as jQuery method.
|
||||
if(!this.tip() || !this.tip().is(':visible') || !this.$element.hasClass('editable-open')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$element.removeClass('editable-open');
|
||||
this.innerHide();
|
||||
|
||||
/**
|
||||
Fired when container was hidden. It occurs on both save or cancel.
|
||||
|
||||
@ -182,9 +210,14 @@ Applied as jQuery method.
|
||||
this.$element.triggerHandler('hidden', reason);
|
||||
},
|
||||
|
||||
/* internal show method. To be overwritten in child classes */
|
||||
innerShow: function () {
|
||||
|
||||
},
|
||||
|
||||
/* internal hide method. To be overwritten in child classes */
|
||||
innerHide: function () {
|
||||
this.call('hide');
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
@ -193,7 +226,7 @@ Applied as jQuery method.
|
||||
@param {boolean} closeAll Whether to close all other editable containers when showing this one. Default true.
|
||||
**/
|
||||
toggle: function(closeAll) {
|
||||
if(this.tip && this.tip().is(':visible')) {
|
||||
if(this.container() && this.tip() && this.tip().is(':visible')) {
|
||||
this.hide();
|
||||
} else {
|
||||
this.show(closeAll);
|
||||
@ -261,11 +294,17 @@ Applied as jQuery method.
|
||||
@method destroy()
|
||||
**/
|
||||
destroy: function() {
|
||||
this.call('destroy');
|
||||
this.hide();
|
||||
this.innerDestroy();
|
||||
this.$element.off('destroyed');
|
||||
this.$element.removeData('editableContainer');
|
||||
},
|
||||
|
||||
/* to be overwritten in child classes */
|
||||
innerDestroy: function() {
|
||||
|
||||
},
|
||||
|
||||
/*
|
||||
Closes other containers except one related to passed element.
|
||||
Other containers can be cancelled or submitted (depends on onblur option)
|
||||
|
@ -8,49 +8,42 @@
|
||||
//extend methods
|
||||
$.extend($.fn.editableContainer.Inline.prototype, $.fn.editableContainer.Popup.prototype, {
|
||||
containerName: 'editableform',
|
||||
innerCss: null,
|
||||
innerCss: '.editable-inline',
|
||||
|
||||
initContainer: function(){
|
||||
//no init for container
|
||||
//only convert anim to miliseconds (int)
|
||||
//container is <span> element
|
||||
this.$tip = $('<span></span>').addClass('editable-inline');
|
||||
|
||||
//convert anim to miliseconds (int)
|
||||
if(!this.options.anim) {
|
||||
this.options.anim = 0;
|
||||
}
|
||||
},
|
||||
|
||||
splitOptions: function() {
|
||||
//all options are passed to form
|
||||
this.containerOptions = {};
|
||||
this.formOptions = this.options;
|
||||
},
|
||||
|
||||
tip: function() {
|
||||
return this.$form;
|
||||
return this.$tip;
|
||||
},
|
||||
|
||||
innerShow: function () {
|
||||
this.$element.hide();
|
||||
|
||||
if(this.$form) {
|
||||
this.$form.remove();
|
||||
}
|
||||
|
||||
this.initForm();
|
||||
this.tip().addClass('editable-container').addClass('editable-inline');
|
||||
this.$form.insertAfter(this.$element);
|
||||
this.$form.show(this.options.anim);
|
||||
this.$form.editableform('render');
|
||||
this.tip().insertAfter(this.$element).show();
|
||||
},
|
||||
|
||||
innerHide: function () {
|
||||
this.$form.hide(this.options.anim, $.proxy(function() {
|
||||
this.$tip.hide(this.options.anim, $.proxy(function() {
|
||||
this.$element.show();
|
||||
this.tip().empty().remove();
|
||||
}, this));
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
innerDestroy: function() {
|
||||
this.tip().remove();
|
||||
this.$element.off('destroyed');
|
||||
this.$element.removeData('editableContainer');
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -29,9 +29,25 @@
|
||||
this.call(this.containerOptions);
|
||||
|
||||
if(t) {
|
||||
//restore data('template')
|
||||
this.$element.data('template', t);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
/* show */
|
||||
innerShow: function () {
|
||||
this.call('show');
|
||||
},
|
||||
|
||||
/* hide */
|
||||
innerHide: function () {
|
||||
this.call('hide');
|
||||
},
|
||||
|
||||
/* destroy */
|
||||
innerDestroy: function() {
|
||||
this.call('destroy');
|
||||
},
|
||||
|
||||
setContainerOption: function(key, value) {
|
||||
this.container().options[key] = value;
|
||||
|
@ -20,20 +20,41 @@
|
||||
});
|
||||
|
||||
this.call(this.containerOptions);
|
||||
|
||||
var $content = $('<div>')
|
||||
.append($('<label>').text(this.options.title || this.$element.data( "title") || this.$element.data( "originalTitle")))
|
||||
.append(this.initForm());
|
||||
|
||||
this.call('update', $content);
|
||||
},
|
||||
|
||||
innerShow: function () {
|
||||
this.$form.editableform('render');
|
||||
/*
|
||||
Overwrite totally show() method as poshytip requires content is set before show
|
||||
*/
|
||||
show: function (closeAll) {
|
||||
this.$element.addClass('editable-open');
|
||||
if(closeAll !== false) {
|
||||
//close all open containers (except this)
|
||||
this.closeOthers(this.$element[0]);
|
||||
}
|
||||
|
||||
//render form
|
||||
this.$form = $('<div>');
|
||||
this.renderForm();
|
||||
|
||||
var $label = $('<label>').text(this.options.title || this.$element.data( "title") || this.$element.data( "originalTitle")),
|
||||
$content = $('<div>').append($label).append(this.$form);
|
||||
|
||||
this.call('update', $content);
|
||||
this.call('show');
|
||||
|
||||
this.tip().addClass('editable-container');
|
||||
this.$form.data('editableform').input.activate();
|
||||
},
|
||||
},
|
||||
|
||||
/* hide */
|
||||
innerHide: function () {
|
||||
this.call('hide');
|
||||
},
|
||||
|
||||
/* destroy */
|
||||
innerDestroy: function() {
|
||||
this.call('destroy');
|
||||
},
|
||||
|
||||
setPosition: function() {
|
||||
this.container().refresh(false);
|
||||
|
@ -47,25 +47,23 @@
|
||||
},
|
||||
|
||||
tip: function() {
|
||||
return this.container()._find(this.container().element);
|
||||
return this.container() ? this.container()._find(this.container().element) : null;
|
||||
},
|
||||
|
||||
innerShow: function() {
|
||||
this.call('open');
|
||||
this.tip().addClass('editable-container');
|
||||
|
||||
this.initForm();
|
||||
this.tip().find(this.innerCss)
|
||||
.empty()
|
||||
.append($('<label>').text(this.options.title || this.$element.data( "ui-tooltip-title") || this.$element.data( "originalTitle")))
|
||||
.append(this.$form);
|
||||
this.$form.editableform('render');
|
||||
var label = this.options.title || this.$element.data( "ui-tooltip-title") || this.$element.data( "originalTitle");
|
||||
this.tip().find(this.innerCss).empty().append($('<label>').text(label));
|
||||
},
|
||||
|
||||
innerHide: function() {
|
||||
this.call('close');
|
||||
},
|
||||
|
||||
innerDestroy: function() {
|
||||
/* tooltip destroys itself on hide */
|
||||
},
|
||||
|
||||
setPosition: function() {
|
||||
this.tip().position( $.extend({
|
||||
of: this.$element
|
||||
@ -102,11 +100,8 @@
|
||||
}
|
||||
|
||||
this.containerOptions.position = pos;
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
//jqueryui tooltip destroys itself
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}(window.jQuery));
|
@ -15,17 +15,14 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
||||
if(!this.options.scope) {
|
||||
this.options.scope = this;
|
||||
}
|
||||
this.initInput();
|
||||
//nothing shown after init
|
||||
};
|
||||
|
||||
EditableForm.prototype = {
|
||||
constructor: EditableForm,
|
||||
initInput: function() { //called once
|
||||
//take input from options or create new input instance
|
||||
this.input = this.options.input || $.fn.editableutils.createInput(this.options);
|
||||
if(!this.input) {
|
||||
return;
|
||||
}
|
||||
//take input from options (as it is created in editable-element)
|
||||
this.input = this.options.input;
|
||||
|
||||
//set initial value
|
||||
this.value = this.input.str2value(this.options.value);
|
||||
@ -54,6 +51,9 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
||||
this.$form.find('.editable-buttons').remove();
|
||||
}
|
||||
|
||||
//show loading state
|
||||
this.showLoading();
|
||||
|
||||
/**
|
||||
Fired when rendering starts
|
||||
@event rendering
|
||||
@ -61,8 +61,8 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
||||
**/
|
||||
this.$div.triggerHandler('rendering');
|
||||
|
||||
//show loading state
|
||||
this.showLoading();
|
||||
//init input
|
||||
this.initInput();
|
||||
|
||||
//append input to form
|
||||
this.input.prerender();
|
||||
@ -308,14 +308,17 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
||||
},
|
||||
|
||||
option: function(key, value) {
|
||||
this.options[key] = value;
|
||||
if(key in this.options) {
|
||||
this.options[key] = value;
|
||||
}
|
||||
|
||||
if(key === 'value') {
|
||||
this.setValue(value);
|
||||
}
|
||||
//pass to input
|
||||
if(this.input.option) {
|
||||
this.input.option(key, value);
|
||||
}
|
||||
// if(this.input && this.input.option) {
|
||||
// this.input.option(key, value);
|
||||
// }
|
||||
},
|
||||
|
||||
setValue: function(value, convertStr) {
|
||||
|
@ -183,12 +183,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
|
||||
//disabled
|
||||
if(key === 'disabled') {
|
||||
if(value) {
|
||||
this.disable();
|
||||
} else {
|
||||
this.enable();
|
||||
}
|
||||
return;
|
||||
return value ? this.disable() : this.enable();
|
||||
}
|
||||
|
||||
//value
|
||||
@ -199,12 +194,13 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
//transfer new option to container!
|
||||
if(this.container) {
|
||||
this.container.option(key, value);
|
||||
} else {
|
||||
//pass option to input directly
|
||||
if(this.input.option) {
|
||||
this.input.option(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
//pass option to input directly (as it points to the same in form)
|
||||
if(this.input.option) {
|
||||
this.input.option(key, value);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/*
|
||||
@ -354,13 +350,14 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
@method destroy()
|
||||
**/
|
||||
destroy: function() {
|
||||
if(this.options.toggle !== 'manual') {
|
||||
this.$element.removeClass('editable-click');
|
||||
this.$element.off(this.options.toggle + '.editable');
|
||||
}
|
||||
if(this.container) {
|
||||
this.container.destroy();
|
||||
}
|
||||
|
||||
if(this.options.toggle !== 'manual') {
|
||||
this.$element.removeClass('editable-click');
|
||||
this.$element.off(this.options.toggle + '.editable');
|
||||
}
|
||||
|
||||
this.$element.off("save.internal");
|
||||
|
||||
|
@ -40,45 +40,71 @@ $(function () {
|
||||
equal(settings.data.value, finalD, 'submitted value correct');
|
||||
}
|
||||
});
|
||||
|
||||
//testing func, run twice!
|
||||
var func = function() {
|
||||
var df = $.Deferred();
|
||||
|
||||
equal(frmt(e.data('editable').value, 'dd.mm.yyyy'), d, 'value correct');
|
||||
equal(frmt(e.data('editable').value, 'dd.mm.yyyy'), d, 'value correct');
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
ok(p.find('input').is(':visible'), 'input exists');
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
ok(p.find('input').is(':visible'), 'input exists');
|
||||
|
||||
equal(p.find('input').val(), d, 'date set correct');
|
||||
|
||||
//open picker
|
||||
p.find('img').click();
|
||||
var picker = p.find('input').datepicker('widget');
|
||||
|
||||
ok(picker.is(':visible'), 'picker shown');
|
||||
ok(picker.find('a.ui-state-active').is(':visible'), 'active day is visible');
|
||||
equal(picker.find('a.ui-state-active').text(), 15, 'day shown correct');
|
||||
equal(picker.find('.ui-datepicker-calendar > thead > tr > th').eq(0).find('span').text(), 'Mo', 'weekStart correct');
|
||||
equal(p.find('input').val(), d, 'date set correct');
|
||||
|
||||
//open picker
|
||||
p.find('img').click();
|
||||
|
||||
equal(p.find('input').length, 1, 'input is single');
|
||||
|
||||
var picker = p.find('input').datepicker('widget');
|
||||
|
||||
ok(picker.is(':visible'), 'picker shown');
|
||||
ok(picker.find('a.ui-state-active').is(':visible'), 'active day is visible');
|
||||
equal(picker.find('a.ui-state-active').text(), 15, 'day shown correct');
|
||||
equal(picker.find('.ui-datepicker-calendar > thead > tr > th').eq(0).find('span').text(), 'Mo', 'weekStart correct');
|
||||
|
||||
//set new day by picker
|
||||
picker.find('a.ui-state-active').parent().next().click();
|
||||
ok(!picker.is(':visible'), 'picker closed');
|
||||
//set new day by picker
|
||||
picker.find('a.ui-state-active').parent().next().click();
|
||||
ok(!picker.is(':visible'), 'picker closed');
|
||||
|
||||
equal(p.find('input').val(), nextD, 'next day set correct');
|
||||
|
||||
p.find('input').val(finalD).trigger('keyup');
|
||||
|
||||
equal(picker.find('a.ui-state-active').text(), 17, 'picker active date updated');
|
||||
|
||||
equal(p.find('input').val(), nextD, 'next day set correct');
|
||||
|
||||
p.find('input').val(finalD).trigger('keyup');
|
||||
//prevent page reload in case of error
|
||||
p.find('form').submit(function(e){
|
||||
if(!e.isDefaultPrevented()) {
|
||||
e.preventDefault();
|
||||
ok(false, 'form submit not prevented!');
|
||||
}
|
||||
})
|
||||
|
||||
//submit
|
||||
p.find('form').submit();
|
||||
|
||||
equal(picker.find('a.ui-state-active').text(), 17, 'picker active date updated');
|
||||
|
||||
//submit
|
||||
p.find('form').submit();
|
||||
|
||||
setTimeout(function() {
|
||||
ok(!p.is(':visible'), 'popover closed');
|
||||
ok(!picker.is(':visible'), 'picker closed');
|
||||
equal(frmt(e.data('editable').value, f), finalD, 'new date saved to value');
|
||||
equal(e.text(), finalD, 'new text shown');
|
||||
e.remove();
|
||||
start();
|
||||
}, timeout);
|
||||
setTimeout(function() {
|
||||
ok(!p.is(':visible'), 'popover closed');
|
||||
ok(!picker.is(':visible'), 'picker closed');
|
||||
equal(frmt(e.data('editable').value, f), finalD, 'new date saved to value');
|
||||
equal(e.text(), finalD, 'new text shown');
|
||||
df.resolve();
|
||||
}, timeout);
|
||||
|
||||
return df.promise();
|
||||
};
|
||||
|
||||
|
||||
$.when(func()).then(function() {
|
||||
e.editable('setValue', d, true);
|
||||
$.when(func()).then(function() {
|
||||
e.remove();
|
||||
start();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
@ -678,9 +678,12 @@ $(function () {
|
||||
p = tip(e);
|
||||
ok(p.find('select').length, 'select exists');
|
||||
equal(p.find('select').find('option').length, 2, 'new options loaded');
|
||||
equal(p.find('select').val(), 'a', 'selected value correct') ;
|
||||
|
||||
//disable below test as in ie select.val() return null
|
||||
// equal(p.find('select').val(), 'a', 'selected value correct') ;
|
||||
p.find('.editable-cancel').click();
|
||||
ok(!p.is(':visible'), 'popover was closed');
|
||||
|
||||
e.remove();
|
||||
start();
|
||||
}, timeout);
|
||||
|
Loading…
x
Reference in New Issue
Block a user