[FIX] handling of focus on m2o fields (in editable list row)
* Throw out focusin/focusout: the m2o widget's completion list is created at the page top (body) so the editable listview can't generically handle arbitrary widgets via mere focusin/focusout. * Move responsibility of focus/blur events to the form view and its widgets. * Events could not just be named ``focus`` and ``blur`` due to usage of jquery's event system: jquery will automatically call a method of the event's name if it exists on the object, which conflicts with .web.form.Field#focus and leads to an infinite loop (as Field#focus focuses the field's root element, which triggers the focus event, which calls the focus method,...) => form-* and widget-*, can be switched back in trunk * m2o mess kind-of complex, basically: - the core input and the menu button behave as blur/focus triggers - when the autocompletion list is clicked, it will temporarily remove the focus from the input (blurring it), and put it back later... on a timer. Issue is the timer, we don't want to rely on having a bigger timer (as later revisions of the library may change our timings and it's iffy to rely on timers conserving order perfectly); on the other hand we know the focus *will* come back to the input eventually. So we can just avoid propagating blur iif the blur is the consequence of having clicked on the completion list. - roughly the same thing happens when clicking on $drop_down (after fixing the handling of its final focus to be consistent, as $drop_down would not re-focus the input if it was *closing* the completion list) - pretty sure the menu thing does *not work at all*, but I don't have the courage of fixing it before committing this part. Date/datetime widget remains to be handled, basically the core focus handling is the same as in e.g. a charfield *but* needs to handle (and ignore) loss of focus from clicking inside the picker widget. Expecting the level of suck to reach unknown heights. bzr revid: xmo@openerp.com-20120619072518-lsrhzij5asxt2aea
This commit is contained in:
parent
70b0af1375
commit
0516533c16
|
@ -80,6 +80,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
|
|||
this.sidebar.stop();
|
||||
}
|
||||
_.each(this.widgets, function(w) {
|
||||
$(w).unbind('.formBlur');
|
||||
w.stop();
|
||||
});
|
||||
this._super();
|
||||
|
@ -100,6 +101,8 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
|
|||
this.$element.html(this.rendered);
|
||||
_.each(this.widgets, function(w) {
|
||||
w.start();
|
||||
$(w).bind('widget-focus.formBlur', self.proxy('widgetFocused'))
|
||||
.bind('widget-blur.formBlur', self.proxy('widgetBlurred'));
|
||||
});
|
||||
this.$form_header = this.$element.find('.oe_form_header:first');
|
||||
this.$form_header.find('div.oe_form_pager button[data-pager-action]').click(function() {
|
||||
|
@ -130,6 +133,21 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
|
|||
this.has_been_loaded.resolve();
|
||||
},
|
||||
|
||||
widgetFocused: function() {
|
||||
if (this.__blur_timeout) {
|
||||
clearTimeout(this.__blur_timeout);
|
||||
delete this.__blur_timeout;
|
||||
}
|
||||
},
|
||||
widgetBlurred: function() {
|
||||
var self = this;
|
||||
// clear timeout, if any
|
||||
this.widgetFocused();
|
||||
this.__blur_timeout = setTimeout(function () {
|
||||
$(self).trigger('form-blur');
|
||||
}, 0);
|
||||
},
|
||||
|
||||
do_load_state: function(state, warm) {
|
||||
if (state.id && this.datarecord.id != state.id) {
|
||||
if (!this.dataset.get_id_index(state.id)) {
|
||||
|
@ -926,6 +944,13 @@ openerp.web.form.Widget = openerp.web.OldWidget.extend(/** @lends openerp.web.fo
|
|||
|
||||
this.width = this.node.attrs.width;
|
||||
},
|
||||
setupFocus: function ($e) {
|
||||
var self = this;
|
||||
$e.bind({
|
||||
focus: function () { $(self).trigger('widget-focus'); },
|
||||
blur: function () { $(self).trigger('widget-blur'); }
|
||||
});
|
||||
},
|
||||
start: function() {
|
||||
this.$element = this.view.$element.find(
|
||||
'.' + this.element_class.replace(/[^\r\n\f0-9A-Za-z_-]/g, "\\$&"));
|
||||
|
@ -1212,10 +1237,12 @@ openerp.web.form.WidgetButton = openerp.web.form.Widget.extend({
|
|||
},
|
||||
start: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find("button").click(this.on_click);
|
||||
var $button = this.$element.find('button');
|
||||
$button.click(this.on_click);
|
||||
if (this.help || openerp.connection.debug) {
|
||||
this.do_attach_tooltip();
|
||||
}
|
||||
this.setupFocus($button);
|
||||
},
|
||||
on_click: function() {
|
||||
var self = this;
|
||||
|
@ -1329,11 +1356,13 @@ openerp.web.form.WidgetLabel = openerp.web.form.Widget.extend({
|
|||
if (this['for'] && (this['for'].help || openerp.connection.debug)) {
|
||||
this.do_attach_tooltip(self['for']);
|
||||
}
|
||||
this.$element.find("label").dblclick(function() {
|
||||
var $label = this.$element.find('label');
|
||||
$label.dblclick(function() {
|
||||
var widget = self['for'] || self;
|
||||
openerp.log(widget.element_class , widget);
|
||||
window.w = widget;
|
||||
});
|
||||
this.setupFocus($label);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1460,7 +1489,9 @@ openerp.web.form.FieldChar = openerp.web.form.Field.extend({
|
|||
},
|
||||
start: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find('input').change(this.on_ui_change);
|
||||
var $input = this.$element.find('input');
|
||||
$input.change(this.on_ui_change);
|
||||
this.setupFocus($input);
|
||||
},
|
||||
set_value: function(value) {
|
||||
this._super.apply(this, arguments);
|
||||
|
@ -1501,7 +1532,9 @@ openerp.web.form.FieldEmail = openerp.web.form.FieldChar.extend({
|
|||
template: 'FieldEmail',
|
||||
start: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find('button').click(this.on_button_clicked);
|
||||
var $button = this.$element.find('button');
|
||||
$button.click(this.on_button_clicked);
|
||||
this.setupFocus($button);
|
||||
},
|
||||
on_button_clicked: function() {
|
||||
if (!this.value || !this.is_valid()) {
|
||||
|
@ -1516,7 +1549,9 @@ openerp.web.form.FieldUrl = openerp.web.form.FieldChar.extend({
|
|||
template: 'FieldUrl',
|
||||
start: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find('button').click(this.on_button_clicked);
|
||||
var $button = this.$element.find('button');
|
||||
$button.click(this.on_button_clicked);
|
||||
this.setupFocus($button);
|
||||
},
|
||||
on_button_clicked: function() {
|
||||
if (!this.value) {
|
||||
|
@ -1641,6 +1676,7 @@ openerp.web.form.FieldDatetime = openerp.web.form.Field.extend({
|
|||
this.datewidget = this.build_widget();
|
||||
this.datewidget.on_change.add_last(this.on_ui_change);
|
||||
this.datewidget.appendTo(this.$element);
|
||||
// FIXME: handle focus on datetime field
|
||||
},
|
||||
set_value: function(value) {
|
||||
this._super(value);
|
||||
|
@ -1671,8 +1707,10 @@ openerp.web.form.FieldText = openerp.web.form.Field.extend({
|
|||
template: 'FieldText',
|
||||
start: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find('textarea').change(this.on_ui_change);
|
||||
var $textarea = this.$element.find('textarea');
|
||||
$textarea.change(this.on_ui_change);
|
||||
this.resized = false;
|
||||
this.setupFocus($textarea);
|
||||
},
|
||||
set_value: function(value) {
|
||||
this._super.apply(this, arguments);
|
||||
|
@ -1733,7 +1771,9 @@ openerp.web.form.FieldBoolean = openerp.web.form.Field.extend({
|
|||
start: function() {
|
||||
var self = this;
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find('input').click(self.on_ui_change);
|
||||
var $input = this.$element.find('input');
|
||||
$input.click(self.on_ui_change);
|
||||
this.setupFocus($input);
|
||||
},
|
||||
set_value: function(value) {
|
||||
this._super.apply(this, arguments);
|
||||
|
@ -1803,7 +1843,8 @@ openerp.web.form.FieldSelection = openerp.web.form.Field.extend({
|
|||
// row
|
||||
var ischanging = false;
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find('select')
|
||||
var $select = this.$element.find('select');
|
||||
$select
|
||||
.change(this.on_ui_change)
|
||||
.change(function () { ischanging = true; })
|
||||
.click(function () { ischanging = false; })
|
||||
|
@ -1812,6 +1853,7 @@ openerp.web.form.FieldSelection = openerp.web.form.Field.extend({
|
|||
e.stopPropagation();
|
||||
ischanging = false;
|
||||
});
|
||||
this.setupFocus($select);
|
||||
},
|
||||
set_value: function(value) {
|
||||
value = value === null ? false : value;
|
||||
|
@ -1983,8 +2025,8 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
|
|||
} else {
|
||||
self.$input.autocomplete("search");
|
||||
}
|
||||
self.$input.focus();
|
||||
}
|
||||
self.$input.focus();
|
||||
});
|
||||
var anyoneLoosesFocus = function() {
|
||||
if (!self.$input.is(":focus") &&
|
||||
|
@ -2022,6 +2064,7 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
|
|||
minLength: 0,
|
||||
delay: 0
|
||||
});
|
||||
|
||||
// used to correct a bug when selecting an element by pushing 'enter' in an editable list
|
||||
this.$input.keyup(function(e) {
|
||||
if (e.which === 13) {
|
||||
|
@ -2030,6 +2073,23 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
|
|||
}
|
||||
isSelecting = false;
|
||||
});
|
||||
|
||||
var picking_completion = false;
|
||||
this.$input.autocomplete('widget').add(this.$drop_down)
|
||||
.mousedown(function () {
|
||||
picking_completion = true;
|
||||
});
|
||||
this.$input.add(this.$menu_btn).bind({
|
||||
blur: function () {
|
||||
if (!picking_completion) {
|
||||
$(self).trigger('widget-blur');
|
||||
}
|
||||
picking_completion = false;
|
||||
},
|
||||
focus: function () {
|
||||
$(self).trigger('widget-focus');
|
||||
}
|
||||
})
|
||||
},
|
||||
// autocomplete component content handling
|
||||
get_search_result: function(request, response) {
|
||||
|
@ -2666,28 +2726,13 @@ openerp.web.form.One2ManyList = openerp.web.ListView.List.extend({
|
|||
render_row_as_form: function () {
|
||||
var self = this;
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
self.setup_save_on_row_blur();
|
||||
$(self.edition_form).bind('form-blur', function () {
|
||||
if (!self.edition_form.widget_is_stopped) {
|
||||
self.view.ensure_saved();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
setup_save_on_row_blur: function () {
|
||||
var self = this;
|
||||
var form = this.edition_form;
|
||||
this.edition_form.$element.bind({
|
||||
focusout: function () {
|
||||
self._save_row_timeout = setTimeout(function () {
|
||||
if (form.widget_is_stopped) {
|
||||
// Saved or cancelled already, maybe?
|
||||
return;
|
||||
}
|
||||
self.view.ensure_saved();
|
||||
}, 0);
|
||||
},
|
||||
focusin: function () {
|
||||
clearTimeout(self._save_row_timeout);
|
||||
delete self._save_row_timeout;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
openerp.web.form.One2ManyFormView = openerp.web.FormView.extend({
|
||||
|
@ -3207,9 +3252,14 @@ openerp.web.form.FieldReference = openerp.web.form.Field.extend({
|
|||
}
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
this._super();
|
||||
this.selection.start();
|
||||
this.m2o.start();
|
||||
$(this.selection).add($(this.m2o)).bind({
|
||||
'focus': function () { $(self).trigger('widget-focus'); },
|
||||
'blur': function () { $(self).trigger('widget-blur'); }
|
||||
})
|
||||
},
|
||||
is_valid: function() {
|
||||
return this.required === false || typeof(this.get_value()) === 'string';
|
||||
|
|
Loading…
Reference in New Issue