[MERGE] many2one and many2many

bzr revid: nicolas.vanhoren@openerp.com-20110513142038-wa87m5kbfviqstvr
This commit is contained in:
niv-openerp 2011-05-13 16:20:38 +02:00
commit ce6efa372a
12 changed files with 351 additions and 9 deletions

View File

@ -357,6 +357,28 @@ class DataSet(openerpweb.Controller):
reads = Model.read(ids, fields or False, request.context)
reads.sort(key=lambda obj: ids.index(obj['id']))
return reads
@openerpweb.jsonrequest
def read(self, request, model, ids, fields=False):
return self.do_search_read(request, model, ids, fields)
def search_read(self, request, model, ids, fields=False):
""" Performs a read()
:param request: a JSON-RPC request object
:type request: openerpweb.JsonRequest
:param str model: the name of the model to search on
:param ids: the ids of the records
:type ids: [?]
:param fields: a list of the fields to return in the result records
:type fields: [str]
:returns: a list of result records
:rtype: list
"""
Model = request.session.model(model)
reads = Model.read(ids, fields or False, request.context)
reads.sort(key=lambda obj: ids.index(obj['id']))
return reads
@openerpweb.jsonrequest
def get(self, request, model, ids, fields=False):
@ -424,6 +446,12 @@ class DataSet(openerpweb.Controller):
m = req.session.model(model)
r = m.default_get(fields, context)
return {'result': r}
@openerpweb.jsonrequest
def name_search(self, req, model, search_str, domain=[], context={}):
m = req.session.model(model)
r = m.name_search(search_str+'%', domain, '=ilike', context)
return {'result': r}
class DataGroup(openerpweb.Controller):
_cp_path = "/base/group"

View File

@ -28,6 +28,7 @@
<script type="text/javascript" src="/base/static/src/js/form.js"></script>
<script type="text/javascript" src="/base/static/src/js/list.js"></script>
<script type="text/javascript" src="/base/static/src/js/search.js"></script>
<script type="text/javascript" src="/base/static/src/js/m2o.js"></script>
<link rel="stylesheet" type="text/css" media="screen" href="/base/static/lib/jquery.ui/css/smoothness/jquery-ui-1.8.9.custom.css" />
<link rel="stylesheet" type="text/css" media="screen" href="/base/static/lib/jquery.ui.notify/css/ui.notify.css" />

View File

@ -825,3 +825,12 @@ body.openerp {
border-color: #828282;
}
/* Many2one Autosearch */
.openerp .ui_combo {
height: 20px;
margin-right: 1px;
top: 4px;
width: 22px;
}
/* ------------- End autocomplete ------- */

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 B

View File

@ -126,6 +126,7 @@ openerp.base = function(instance) {
openerp.base.views(instance);
openerp.base.search(instance);
openerp.base.list(instance);
openerp.base.m2o(instance);
openerp.base.form(instance);
};

View File

@ -213,12 +213,12 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
context: this.context
}, callback);
},
create: function(data, callback) {
create: function(data, callback, error_callback) {
return this.rpc('/base/dataset/create', {
model: this.model,
data: data,
context: this.context
}, callback);
}, callback, error_callback);
},
write: function (id, data, callback) {
return this.rpc('/base/dataset/save', {
@ -243,6 +243,15 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
args: args
}, callback);
},
name_search: function (search_str, callback) {
search_str = search_str || '';
return this.rpc('/base/dataset/name_search', {
model: this.model,
search_str: search_str,
domain: this.domain || [],
context: this.context
}, callback);
},
exec_workflow: function (id, signal, callback) {
return this.rpc('/base/dataset/exec_workflow', {
model: this.model,

View File

@ -886,10 +886,33 @@ openerp.base.form.FieldSelection = openerp.base.form.Field.extend({
}
});
openerp.base.form.FieldMany2OneDatasSet = openerp.base.DataSetStatic.extend({
start: function() {
},
write: function (id, data, callback) {
this._super(id, data, callback);
},
});
openerp.base.form.FieldMany2OneViewManager = openerp.base.ViewManager.extend({
init: function(session, element_id, dataset, views) {
this._super(session, element_id, dataset, views);
}
});
openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
init: function(view, node) {
this._super(view, node);
this.template = "FieldMany2One";
this.is_field_m2o = true;
},
start: function() {
this.$element = $('#' + this.element_id);
this.dataset = new openerp.base.form.FieldMany2OneDatasSet(this.session, this.field.relation);
var views = [ [false,"list"], [false,"form"] ];
this.viewmanager = new openerp.base.form.FieldMany2OneViewManager(this.view.session, this.element_id, this.dataset, views);
new openerp.base.m2o(this.viewmanager, this.$element, this.field.relation, this.dataset, this.session)
this.$element.find('input').change(this.on_ui_change);
},
set_value: function(value) {
this._super.apply(this, arguments);
@ -899,6 +922,16 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
this.value = value[0];
}
this.$element.find('input').val(show_value);
this.$element.find('input').attr('m2o_id', this.value);
},
get_value: function() {
var val = this.$element.find('input').attr('m2o_id') || this.value
return val;
},
on_ui_change: function() {
this.touched = this.view.touched = true;
}
});
@ -959,6 +992,8 @@ openerp.base.form.FieldMany2Many = openerp.base.form.Field.extend({
this._super(view, node);
this.template = "FieldMany2Many";
this.list_id = _.uniqueId("many2many");
this.is_started = false;
this.is_setted = false;
},
start: function() {
this._super.apply(this, arguments);
@ -968,16 +1003,30 @@ openerp.base.form.FieldMany2Many = openerp.base.form.Field.extend({
var self = this;
this.list_view.m2m_field = this;
this.list_view.start();
var hack = {loaded: false};
this.list_view.on_loaded.add_last(function() {
if (! hack.loaded) {
self.is_started = true;
self.check_load();
hack.loaded = true;
}
});
},
set_value: function(value) {
if (value != false) {
this.dataset.ids = value;
this.dataset.count = value.length;
this.list_view.do_reload();
this.is_setted = true;
this.check_load();
}
},
get_value: function() {
return [[6,false,this.dataset.ids]];
},
check_load: function() {
if(this.is_started && this.is_setted) {
this.list_view.do_reload();
}
}
});
@ -1002,8 +1051,19 @@ openerp.base.form.Many2ManyListView = openerp.base.ListView.extend({
'context': this.dataset.context
}, this.do_fill_table);
},
do_add_record: function () {
// TODO: need to open a popup with search view
do_add_record: function (e) {
e.stopImmediatePropagation();
var pop = new openerp.base.form.Many2XSelectPopup(null, this.m2m_field.view.session);
pop.select_element(this.model);
var self = this;
pop.on_select_element.add(function(element_id) {
if(! _.detect(self.dataset.ids, function(x) {return x == element_id;})) {
self.dataset.ids.push(element_id);
self.dataset.count = self.dataset.ids.length;
self.do_reload();
}
pop.stop();
});
},
select_record: function(index) {
var id = this.rows[index].data.id.value;
@ -1023,6 +1083,97 @@ openerp.base.form.Many2ManyListView = openerp.base.ListView.extend({
}
});
openerp.base.form.Many2XSelectPopup = openerp.base.BaseWidget.extend({
identifier_prefix: "many2xselectpopup",
template: "Many2XSelectPopup",
select_element: function(model) {
this.model = model;
var html = this.render();
jQuery(html).dialog({title: '',
modal: true,
minWidth: 800});
this.start();
},
start: function() {
this._super();
this.dataset = new openerp.base.DataSetSearch(this.session, this.model);
this.setup_search_view();
},
setup_search_view: function() {
var self = this;
if (this.searchview) {
this.searchview.stop();
}
this.searchview = new openerp.base.SearchView(this, this.session, this.element_id + "_search",
this.dataset, false, {});
this.searchview.on_search.add(function(domains, contexts, groupbys) {
self.view_list.do_search.call(
self, domains, contexts, groupbys);
});
this.searchview.on_loaded.add_last(function () {
var $buttons = self.searchview.$element.find(".oe_search-view-buttons");
$buttons.append(QWeb.render("Many2XSelectPopup.search.buttons"));
var $nbutton = $buttons.find(".oe_many2xselectpopup-search-new");
$nbutton.click(function() {
self.new_object();
});
var $cbutton = $buttons.find(".oe_many2xselectpopup-search-close");
$cbutton.click(function() {
self.stop();
});
self.view_list = new openerp.base.form.Many2XPopupListView( null, self.session,
self.element_id + "_view_list", self.dataset, false);
self.view_list.popup = self;
self.view_list.do_show();
self.view_list.start();
var tmphack = {"loaded": false};
self.view_list.on_loaded.add_last(function() {
if ( !tmphack.loaded ) {
self.view_list.do_reload();
tmphack.loaded = true;
};
});
});
this.searchview.start();
},
on_select_element: function(element_id) {
},
new_object: function() {
var self = this;
this.searchview.hide();
this.view_list.$element.hide();
this.dataset.index = null;
this.view_form = new openerp.base.FormView({}, this.session,
this.element_id + "_view_form", this.dataset, false);
this.view_form.start();
this.view_form.on_loaded.add_last(function() {
var $buttons = self.view_form.$element.find(".oe_form_buttons");
$buttons.html(QWeb.render("Many2XSelectPopup.form.buttons"));
var $nbutton = $buttons.find(".oe_many2xselectpopup-form-save");
$nbutton.click(function() {
self.view_form.do_save();
});
var $cbutton = $buttons.find(".oe_many2xselectpopup-form-close");
$cbutton.click(function() {
self.stop();
});
});
this.view_form.on_created.add_last(function(r, success) {
if (r.result) {
var id = arguments[0].result;
self.on_select_element(id);
}
});
this.view_form.do_show();
}
});
openerp.base.form.Many2XPopupListView = openerp.base.ListView.extend({
switch_to_record: function(index) {
this.popup.on_select_element(this.dataset.ids[index]);
}
});
openerp.base.form.FieldReference = openerp.base.form.Field.extend({
init: function(view, node) {
this._super(view, node);

View File

@ -0,0 +1,121 @@
openerp.base.m2o = function(openerp){
openerp.base.m2o = openerp.base.Controller.extend({
init: function(view_manager, element_id, model, dataset, session){
this._super(element_id, model, dataset, session);
this.view_manager = view_manager
this.session = session;
this.element = element_id.find('input');
this.dataset = dataset;
var cache = {};
var lastXhr;
this.relation = model;
this.result_ids = []
var self = this
var $input = this.element.autocomplete({
source: function(request, response){
var search_val = request.term;
if (search_val in cache) {
response(cache[search_val]);
return;
}
//pass request to server
lastXhr = self.dataset.name_search(search_val, function(obj, status, xhr){
var result = obj.result
var values = [];
if (!result.length) {
values.push({'value': 'Create...', id: 'create'})
}
$.each(result, function(i, val){
values.push({
value: val[1],
id: val[0],
orig_val: val[1]
});
self.result_ids.push(result[i][0])
});
if (values.length > 10) {
values = values.slice(0, 10);
values.push({'value': 'More...', id: 'more'})
}
//process response
cache[search_val] = values;
response(values);
});
return;
},
select: function(event, ui){
ui.item.value = ui.item.orig_val? ui.item.orig_val : self.element.data( "autocomplete" ).term
if (ui.item.id == 'more') {
self.dataset.ids = self.result_ids;
self.dataset.count = self.dataset.ids.length;
self.dataset.domain = []
self.element.val('')
var pop = new openerp.base.form.Many2XSelectPopup(null, self.session);
pop.select_element(self.relation, self.dataset);
return;
}
if (ui.item.id == 'create') {
var val = self.element.val()
self.dataset.create({'name': ui.item.value},
function(r){}, function(r){
var element_id = _.uniqueId("act_window_dialog");
var dialog = jQuery('<div>',
{'id': element_id
}).dialog({
modal: true,
minWidth: 800
});
self.element.val('')
var event_form = new openerp.base.FormView(self.view_manager, self.session, element_id, self.dataset, false);
event_form.start();
});
$input.val(self.element.data( "autocomplete" ).term);
return true;
}
self.element.attr('m2o_id', ui.item.id);
},
minLength: 0,
focus: function(event, ui) {
if (ui.item.id == ('create')) {
return true;
}
ui.item.value = self.element.data("autocomplete").term.length ? self.element.val() + '[' + ui.item.orig_val.substring(self.element.data("autocomplete").term.length) + ']' : this.lastSearch
},
});
$("<div type='button' class='ui_combo'>&nbsp;</div>")
.attr("tabIndex", -1)
.attr("title", "Show All Items")
.insertAfter($input)
.button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
})
.removeClass("ui-corner-all")
.addClass("ui-corner-right ui-button-icon")
.click(function() {
// close if already visible
if ($input.autocomplete("widget").is(":visible")) {
$input.autocomplete( "close" );
return;
}
$(this).blur();
$input.autocomplete("search", "" );
$input.focus();
});
}
});
}

View File

@ -121,7 +121,10 @@ openerp.base.SearchView = openerp.base.Controller.extend({
'lines': lines,
'defaults': this.defaults
});
this.$element.html(render);
// We don't understand why the following commented line does not work in Chrome but
// the non-commented line does. As far as we investigated, only God knows.
//this.$element.html(render);
jQuery(render).appendTo(this.$element);
var f = this.$element.find('form');
this.$element.find('form')

View File

@ -257,7 +257,7 @@
<t t-foreach="row" t-as="td">
<td t-att-colspan="td.colspan gt 1 ? td.colspan : undefined"
t-att-width="td.width ? td.width : undefined"
t-att-nowrap="td.is_field_label ? 'true' : undefined"
t-att-nowrap="td.is_field_label or td.is_field_m2o? 'true' : undefined"
t-att-valign="td.table ? 'top' : undefined"
t-att-id="td.element_id"
t-att-class="'oe_form_' + (td.is_field_label ? 'label' : (td.field ? 'field_' + td.type : td.type))"
@ -350,7 +350,9 @@
t-att-name="widget.name"
t-att-id="widget.element_id + '_field'"
t-att-class="'field_' + widget.type"
t-att-type="widget.type"
style="width: 100%;"/>
</t>
<t t-name="FieldOne2Many">
<div t-att-id="widget.element_id">
@ -396,7 +398,7 @@
<h2 class="oe_view_title"><t t-esc="view.attrs['string']"/></h2>
<form>
<t t-call="SearchView.render_lines"/>
<div style="text-align:right;">
<div class="oe_search-view-buttons" style="text-align:right;">
<input type="submit" value="Search"/>
<input type="reset" value="Clear"/>
</div>
@ -504,7 +506,8 @@
<t t-set="expand" t-value="false"/>
<t t-set="label" t-value="'Custom Filters'"/>
<t t-set="content">
<div class="searchview_extended_groups_list"/>
<div class="searchview_extended_groups_list">
</div>
<button class="searchview_extended_add_group"
type="button"><span>Add group of conditions</span></button>
</t>
@ -584,4 +587,19 @@
</p>
</div>
</t>
<t t-name="Many2XSelectPopup">
<div t-att-id="element_id">
<div t-att-id="element_id + '_search'"></div>
<div t-att-id="element_id + '_view_list'"></div>
<div t-att-id="element_id + '_view_form'"></div>
</div>
</t>
<t t-name="Many2XSelectPopup.search.buttons">
<button type="button" class="oe_many2xselectpopup-search-new">New</button>
<button type="button" class="oe_many2xselectpopup-search-close">Close</button>
</t>
<t t-name="Many2XSelectPopup.form.buttons">
<button type="button" class="oe_many2xselectpopup-form-save">Save</button>
<button type="button" class="oe_many2xselectpopup-form-close">Close</button>
</t>
</templates>

View File

@ -22,6 +22,7 @@
<script src="/base/static/src/js/data.js"></script>
<script src="/base/static/src/js/views.js"></script>
<script src="/base/static/src/js/search.js"></script>
<script src="/base/static/src/js/m2o.js"></script>
<script src="/base/static/src/js/form.js"></script>
<script src="/base/static/src/js/list.js"></script>
<script type="text/javascript">