[FIX] arrow keys handling in editable listview field when field is not a text-based input
* Correctly handle HTMLInputElement#selectionStart throwing an error (checkbox and radio) * Correctly handle elements without a selectionStart at all (select) => should ~always let the go-to-other-field behavior go through bzr revid: xmo@openerp.com-20120726123819-74n1gl01p6befgkp
This commit is contained in:
parent
66a7dc6359
commit
bf4c39cdf1
|
@ -425,26 +425,64 @@ openerp.web.list_editable = function (instance) {
|
|||
keyup_ESCAPE: function () {
|
||||
return this.cancel_edition();
|
||||
},
|
||||
/**
|
||||
* Gets the selection range (start, end) for the provided element,
|
||||
* returns ``null`` if it can't get a range.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_text_selection_range: function (el) {
|
||||
if (el.selectionStart !== undefined) {
|
||||
var selectionStart;
|
||||
try {
|
||||
selectionStart = el.selectionStart;
|
||||
} catch (e) {
|
||||
// radio or checkbox throw on selectionStart access
|
||||
return null;
|
||||
}
|
||||
if (selectionStart !== undefined) {
|
||||
return {
|
||||
start: el.selectionStart,
|
||||
start: selectionStart,
|
||||
end: el.selectionEnd
|
||||
};
|
||||
} else if(document.body.createTextRange) {
|
||||
} else if (document.body.createTextRange) {
|
||||
throw new Error("Implement text range handling for MSIE");
|
||||
var sel = document.body.createTextRange();
|
||||
if (sel.parentElement() === el) {
|
||||
|
||||
}
|
||||
}
|
||||
// Element without selection ranges (select, div/@contenteditable)
|
||||
return null;
|
||||
},
|
||||
_text_cursor: function (el) {
|
||||
var selection = this._text_selection_range(el);
|
||||
if (selection.start !== selection.end) {
|
||||
if (!selection) {
|
||||
return null;
|
||||
}
|
||||
return selection.start;
|
||||
if (selection.start !== selection.end) {
|
||||
return {position: null, collapsed: false};
|
||||
}
|
||||
return {position: selection.start, collapsed: true};
|
||||
},
|
||||
/**
|
||||
* Checks if the cursor is at the start of the provided el
|
||||
*
|
||||
* @param {HTMLInputElement | HTMLTextAreaElement}
|
||||
* @returns {Boolean}
|
||||
* @private
|
||||
*/
|
||||
_at_start: function (cursor, el) {
|
||||
return cursor.collapsed && (cursor.position === 0);
|
||||
},
|
||||
/**
|
||||
* Checks if the cursor is at the end of the provided el
|
||||
*
|
||||
* @param {HTMLInputElement | HTMLTextAreaElement}
|
||||
* @returns {Boolean}
|
||||
* @private
|
||||
*/
|
||||
_at_end: function (cursor, el) {
|
||||
return cursor.collapsed && (cursor.position === el.value.length);
|
||||
},
|
||||
/**
|
||||
* @param DOMEvent event
|
||||
|
@ -454,10 +492,11 @@ openerp.web.list_editable = function (instance) {
|
|||
*/
|
||||
_key_move_record: function (event, record_direction, is_valid_move) {
|
||||
if (!this.editor.is_editing('edit')) { return $.when(); }
|
||||
// FIXME: assumes editable widgets are input-type elements
|
||||
var index = this._text_cursor(event.target);
|
||||
// If selecting or not at the start of the input
|
||||
if (!is_valid_move(event.target, index)) { return $.when(); }
|
||||
var cursor = this._text_cursor(event.target);
|
||||
// if text-based input (has a cursor)
|
||||
// and selecting (not collapsed) or not at a field boundary
|
||||
// don't move to the next record
|
||||
if (cursor && !is_valid_move(event.target, cursor)) { return $.when(); }
|
||||
|
||||
event.preventDefault();
|
||||
var source_field = $(event.target).closest('[data-fieldname]')
|
||||
|
@ -466,13 +505,15 @@ openerp.web.list_editable = function (instance) {
|
|||
|
||||
},
|
||||
keydown_UP: function (e) {
|
||||
return this._key_move_record(e, 'pred', function (el, index) {
|
||||
return index === 0;
|
||||
var self = this;
|
||||
return this._key_move_record(e, 'pred', function (el, cursor) {
|
||||
return self._at_start(cursor, el);
|
||||
});
|
||||
},
|
||||
keydown_DOWN: function (e) {
|
||||
return this._key_move_record(e, 'succ', function (el, index) {
|
||||
return index === el.value.length;
|
||||
var self = this;
|
||||
return this._key_move_record(e, 'succ', function (el, cursor) {
|
||||
return self._at_end(cursor, el);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -480,8 +521,8 @@ openerp.web.list_editable = function (instance) {
|
|||
// If the cursor is at the beginning of the field
|
||||
var source_field = $(e.target).closest('[data-fieldname]')
|
||||
.attr('data-fieldname');
|
||||
var index = this._text_cursor(e.target);
|
||||
if (index !== 0) { return $.when(); }
|
||||
var cursor = this._text_cursor(e.target);
|
||||
if (cursor && !this._at_start(cursor, e.target)) { return $.when(); }
|
||||
|
||||
var fields_order = this.editor.form.fields_order;
|
||||
var field_index = _(fields_order).indexOf(source_field);
|
||||
|
@ -504,8 +545,8 @@ openerp.web.list_editable = function (instance) {
|
|||
// looking for new fields at the right
|
||||
var source_field = $(e.target).closest('[data-fieldname]')
|
||||
.attr('data-fieldname');
|
||||
var index = this._text_cursor(e.target);
|
||||
if (index !== e.target.value.length) { return $.when(); }
|
||||
var cursor = this._text_cursor(e.target);
|
||||
if (cursor && !this._at_end(cursor, e.target)) { return $.when(); }
|
||||
|
||||
var fields_order = this.editor.form.fields_order;
|
||||
var field_index = _(fields_order).indexOf(source_field);
|
||||
|
|
Loading…
Reference in New Issue