Add autocompletion on M2O form widgets
review15051002
This commit is contained in:
1 parent
5ea18e2c19
commit
52899110ee
7 files changed
+146
-20
No files matched your search
+3
-1
@@ -18,7 +18,9 @@
|
||||
"jquery": "~2.1.1",
|
||||
"bootstrap": "~3.3.1",
|
||||
"moment": "~2.9.0",
|
||||
"eonasdan-bootstrap-datetimepicker": "~4.0.0"
|
||||
"eonasdan-bootstrap-datetimepicker": "~4.0.0",
|
||||
"typeahead.js": "~0.10.5",
|
||||
"typeahead.js-bootstrap3.less": "~0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"qunit": "~1.17.1"
|
||||
|
||||
@@ -10,8 +10,10 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<script type="text/javascript" src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="bower_components/moment/min/moment.min.js"></script>
|
||||
<script type="text/javascript" src="bower_components/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js"></script>
|
||||
<script type="text/javascript" src="bower_components/typeahead.js/dist/typeahead.bundle.js"></script>
|
||||
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">
|
||||
<link rel="stylesheet" href="bower_components/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css">
|
||||
<link rel="stylesheet" href="bower_components/typeahead.js-bootstrap3.less/typeahead.css"/>
|
||||
<link rel="stylesheet" href="offcanvas.css">
|
||||
<script type="text/javascript" src="dist/sao.min.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="dist/sao.min.css"
|
||||
|
||||
@@ -2514,4 +2514,49 @@
|
||||
}
|
||||
});
|
||||
Sao.common.processing = new Sao.common.Processing();
|
||||
|
||||
Sao.common.get_completion = function(entry, source, match_selected,
|
||||
search, create) {
|
||||
entry.attr('autocomplete', 'off');
|
||||
entry.typeahead({
|
||||
'minLength': 1,
|
||||
'highlight': true
|
||||
}, {
|
||||
'source': source,
|
||||
'displayKey': 'rec_name'
|
||||
});
|
||||
entry.on('typeahead:selected', match_selected);
|
||||
};
|
||||
Sao.common.update_completion = function(entry, record, field, model,
|
||||
domain) {
|
||||
var prm = jQuery.Deferred();
|
||||
var update = function(search_text, domain) {
|
||||
if (entry.typeahead('val') != search_text) {
|
||||
return prm.reject();
|
||||
}
|
||||
if (!search_text || !model) {
|
||||
return prm.reject();
|
||||
}
|
||||
if (domain === undefined) {
|
||||
domain = field.get_domain(record);
|
||||
}
|
||||
var context = field.get_context(record);
|
||||
domain = [['rec_name', 'ilike', '%' + search_text + '%'], domain];
|
||||
|
||||
var sao_model = new Sao.Model(model);
|
||||
var search_prm = sao_model.execute('search_read', [domain, 0,
|
||||
Sao.config.limit, null, ['rec_name']], context);
|
||||
search_prm.then(function(results) {
|
||||
if (entry.typeahead('val') != search_text) {
|
||||
return prm.reject();
|
||||
}
|
||||
// TODO search & create
|
||||
prm.resolve(results);
|
||||
}, prm.reject);
|
||||
};
|
||||
|
||||
var search_text = entry.typeahead('val');
|
||||
window.setTimeout(update, 300, search_text, domain);
|
||||
return prm.promise();
|
||||
};
|
||||
}());
|
||||
+1
-1
@@ -1975,7 +1975,7 @@
|
||||
var store_rec_name = function(rec_name) {
|
||||
record._values[this.name + '.rec_name'] = rec_name;
|
||||
}.bind(this);
|
||||
if (ref_model && ref_id >= 0) {
|
||||
if (ref_model && ref_id !== null && ref_id >= 0) {
|
||||
if (!rec_name && ref_id >= 0) {
|
||||
Sao.rpc({
|
||||
'method': 'model.' + ref_model + '.read',
|
||||
|
||||
@@ -175,3 +175,7 @@
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.tt-hint {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
+2
-2
@@ -42,7 +42,7 @@
|
||||
'<div class="container-fluid">' +
|
||||
'<div class="navbar-header">' +
|
||||
'<button type="button" class="navbar-toggle collapsed" ' +
|
||||
'data-toggle="collapse" ' +
|
||||
'data-toggle="collapse" ' +
|
||||
'data-target="#navbar-' + this.id + '">' +
|
||||
'<span class="sr-only">Toggle navigation</span>' +
|
||||
'<span class="icon-bar"></span>' +
|
||||
@@ -401,7 +401,7 @@
|
||||
test_modified = true;
|
||||
}
|
||||
var reload = function() {
|
||||
this.screen.cancel_current().then(function() {
|
||||
return this.screen.cancel_current().then(function() {
|
||||
this.screen.save_tree_state(false);
|
||||
if (this.screen.current_view.view_type != 'form') {
|
||||
this.screen.search_filter(
|
||||
|
||||
+89
-16
@@ -2249,7 +2249,12 @@
|
||||
'class': 'glyphicon glyphicon-search'
|
||||
})).appendTo(buttons);
|
||||
this.but_open.click(this.edit.bind(this));
|
||||
// TODO autocompletion
|
||||
if (!attributes.completion || attributes.completion == "1") {
|
||||
Sao.common.get_completion(this.entry,
|
||||
this._update_completion.bind(this),
|
||||
this._completion_match_selected.bind(this));
|
||||
this.wid_completion = true;
|
||||
}
|
||||
this._readonly = false;
|
||||
},
|
||||
get_screen: function() {
|
||||
@@ -2268,16 +2273,77 @@
|
||||
if (jQuery.isEmptyObject(value)) {
|
||||
value = '';
|
||||
}
|
||||
this.entry.val(value);
|
||||
this.value(value);
|
||||
},
|
||||
// This function is required because once typeahead is activated on an
|
||||
// entry then .val() function should not be used anymore.
|
||||
// In order to keep the same semantics as .val() we use the same
|
||||
// signature
|
||||
value: function(value) {
|
||||
if (this.wid_completion) {
|
||||
if (!arguments.length) {
|
||||
return this.entry.typeahead('val');
|
||||
} else {
|
||||
return this.entry.typeahead('val', value);
|
||||
}
|
||||
} else {
|
||||
if (!arguments.length) {
|
||||
return this.entry.val();
|
||||
} else {
|
||||
return this.entry.val(value);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
get_text: function() {
|
||||
var record = this.record();
|
||||
if (record) {
|
||||
return record.field_get_client(this.field_name);
|
||||
}
|
||||
return '';
|
||||
},
|
||||
_set_completion: function() {
|
||||
this.entry.data('search', this.read_access());
|
||||
this.entry.data('create', this.create_access());
|
||||
},
|
||||
_update_completion: function(query, process) {
|
||||
var record = this.record();
|
||||
if (!record) {
|
||||
return;
|
||||
}
|
||||
var field = this.field();
|
||||
var value = field.get(record);
|
||||
if (this.has_target(value)) {
|
||||
var id = this.id_from_value(value);
|
||||
if ((id !== undefined) && (id > 0)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var model = this.get_model();
|
||||
|
||||
var prm = Sao.common.update_completion(this.entry, record, field,
|
||||
model);
|
||||
prm.done(process);
|
||||
},
|
||||
_completion_match_selected: function(event_, selected_item, name) {
|
||||
this.record().field_set_client(this.field_name,
|
||||
this.value_from_id(selected_item.id,
|
||||
selected_item.rec_name), true);
|
||||
},
|
||||
display: function(record, field) {
|
||||
var screen_record = this.record();
|
||||
if ((screen_record && record) && (screen_record.id != record.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var text_value, value;
|
||||
Sao.View.Form.Many2One._super.display.call(this, record, field);
|
||||
|
||||
this._set_button_sensitive();
|
||||
this._set_completion();
|
||||
|
||||
if (!record) {
|
||||
this.entry.val('');
|
||||
this.value('');
|
||||
return;
|
||||
}
|
||||
this.set_text(field.get_client(record));
|
||||
@@ -2362,7 +2428,7 @@
|
||||
var dom;
|
||||
var domain = this.field().get_domain(record);
|
||||
var context = this.field().get_context(record);
|
||||
var text = this.entry.val();
|
||||
var text = this.value();
|
||||
callback = function(result) {
|
||||
if (!jQuery.isEmptyObject(result)) {
|
||||
var value = this.value_from_id(result[0][0],
|
||||
@@ -2428,10 +2494,10 @@
|
||||
this.activate();
|
||||
} else if (this.has_target(this.record().field_get(
|
||||
this.field_name)) && editable) {
|
||||
var value = this.record().field_get_client(this.field_name);
|
||||
if ((value != this.entry.val()) ||
|
||||
var value = this.get_text();
|
||||
if ((value != this.value()) ||
|
||||
~delete_keys.indexOf(event_.which)) {
|
||||
this.entry.val('');
|
||||
this.value('');
|
||||
this.record().field_set_client(this.field_name,
|
||||
this.value_from_id(null, ''));
|
||||
}
|
||||
@@ -2447,7 +2513,7 @@
|
||||
var sao_model = new Sao.Model(model);
|
||||
|
||||
if (model && !this.has_target(value)) {
|
||||
var text = this.entry.val();
|
||||
var text = this.value();
|
||||
if (!this._readonly && (text ||
|
||||
this.field().get_state_attrs(this.record())
|
||||
.required)) {
|
||||
@@ -2462,7 +2528,7 @@
|
||||
this.record().field_set_client(this.field_name,
|
||||
value, true);
|
||||
} else {
|
||||
this.entry.val('');
|
||||
this.value('');
|
||||
}
|
||||
};
|
||||
var parser = new Sao.common.DomainParser();
|
||||
@@ -2529,6 +2595,13 @@
|
||||
}
|
||||
return [this.get_model(), [id, str]];
|
||||
},
|
||||
get_text: function() {
|
||||
var record = this.record();
|
||||
if (record) {
|
||||
return record.field_get_client(this.field_name)[1];
|
||||
}
|
||||
return '';
|
||||
},
|
||||
get_model: function() {
|
||||
return this.select.val();
|
||||
},
|
||||
@@ -2553,7 +2626,7 @@
|
||||
this.select.prop('disabled', this.entry.prop('disabled'));
|
||||
},
|
||||
select_changed: function() {
|
||||
this.entry.val('');
|
||||
this.value('');
|
||||
var model = this.get_model();
|
||||
var value;
|
||||
if (model) {
|
||||
@@ -2566,11 +2639,11 @@
|
||||
set_value: function(record, field) {
|
||||
var value;
|
||||
if (!this.get_model()) {
|
||||
value = this.entry.val();
|
||||
value = this.value();
|
||||
if (jQuery.isEmptyObject(value)) {
|
||||
field.set_client(record, this.field_name, null);
|
||||
field.set_client(record, null);
|
||||
} else {
|
||||
field.set_client(record, this.field_name, ['', value]);
|
||||
field.set_client(record, ['', value]);
|
||||
}
|
||||
} else {
|
||||
value = field.get_client(record, this.field_name);
|
||||
@@ -2583,9 +2656,9 @@
|
||||
name = '';
|
||||
}
|
||||
if ((model != this.get_model()) ||
|
||||
(name != this.entry.val())) {
|
||||
field.set_client(record, this.field_name, null);
|
||||
this.entry.val('');
|
||||
(name != this.value())) {
|
||||
field.set_client(record, null);
|
||||
this.value('');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user