[imp] added many2manytags

bzr revid: nicolas.vanhoren@openerp.com-20120509154416-62lfzf4t7b9g58zi
This commit is contained in:
niv-openerp
2012-05-09 17:44:16 +02:00
6 changed files with 5237 additions and 88 deletions
+1
View File
@@ -29,6 +29,7 @@
"static/lib/jquery.deferred-queue/jquery.deferred-queue.js",
"static/lib/jquery.scrollTo/jquery.scrollTo-min.js",
"static/lib/jquery.tipsy/jquery.tipsy.js",
"static/lib/jquery.textext/jquery.textext.js",
"static/lib/json/json2.js",
"static/lib/qweb/qweb2.js",
"static/lib/underscore/underscore.js",
File diff suppressed because it is too large Load Diff
+24
View File
@@ -1461,6 +1461,30 @@
.openerp .oe_form .oe_form_field_datetime input {
min-width: 11em;
}
.openerp .oe_form .oe_form_field_many2manytags .text-wrap {
width: 100% !important;
}
.openerp .oe_form .oe_form_field_many2manytags .text-wrap textarea {
width: 100% !important;
}
.openerp .oe_form .oe_form_field_many2manytags .oe_form_field_many2manytags_box {
border-radius: 2px;
box-sizing: border-box;
position: relative;
float: left;
border: 1px solid #9daccc;
background: #e2e6f0;
color: black;
padding: 0px 3px 0px 3px;
margin: 0 2px 2px 0;
cursor: pointer;
height: 16px;
font: 11px "lucida grande", tahoma, verdana, arial, sans-serif;
}
.openerp .oe_form .oe_form_field_many2manytags .text-core .text-wrap .text-dropdown .text-list .text-suggestion em {
font-style: italic;
text-decoration: none;
}
.openerp .oe_form .oe_datepicker_container {
display: none;
}
+21
View File
@@ -1211,6 +1211,27 @@ $colour4: #8a89ba
padding-top: 4px
.oe_form_field_datetime input
min-width: 11em
.oe_form_field_many2manytags
.text-wrap
width: 100% !important
textarea
width: 100% !important
.oe_form_field_many2manytags_box
border-radius: 2px
box-sizing: border-box
position: relative
float: left
border: 1px solid #9DACCC
background: #E2E6F0
color: black
padding: 0px 3px 0px 3px
margin: 0 2px 2px 0
cursor: pointer
height: 16px
font: 11px "lucida grande", tahoma, verdana, arial, sans-serif
.text-core .text-wrap .text-dropdown .text-list .text-suggestion em
font-style: italic
text-decoration: none
.oe_datepicker_container
display: none
.oe_datepicker_root
+245 -88
View File
@@ -2304,17 +2304,113 @@ instance.web.form.dialog = function(content, options) {
return dialog.$element;
};
instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin, {
/**
* A mixin containing some useful methods to handle completion inputs.
*/
instance.web.form.CompletionFieldMixin = {
init: function() {
this.limit = 7;
this.orderer = new instance.web.DropMisordered();
},
/**
* Call this method to search using a string.
*/
get_search_result: function(search_val) {
var self = this;
var dataset = new instance.web.DataSet(this, this.field.relation, self.build_context());
return this.orderer.add(dataset.name_search(
search_val, self.build_domain(), 'ilike', this.limit + 1)).pipe(function(data) {
self.last_search = data;
// possible selections for the m2o
var values = _.map(data, function(x) {
return {
label: _.str.escapeHTML(x[1]),
value:x[1],
name:x[1],
id:x[0]
};
});
// search more... if more results that max
if (values.length > self.limit) {
values = values.slice(0, self.limit);
values.push({label: _t("<em>   Search More...</em>"), action: function() {
dataset.name_search(search_val, self.build_domain(), 'ilike'
, false, function(data) {
self._search_create_popup("search", data);
});
}});
}
// quick create
var raw_result = _(data.result).map(function(x) {return x[1];});
if (search_val.length > 0 && !_.include(raw_result, search_val)) {
values.push({label: _.str.sprintf(_t('<em>   Create "<strong>%s</strong>"</em>'),
$('<span />').text(search_val).html()), action: function() {
self._quick_create(search_val);
}});
}
// create...
values.push({label: _t("<em>   Create and Edit...</em>"), action: function() {
self._search_create_popup("form", undefined, {"default_name": search_val});
}});
return values;
});
},
_quick_create: function(name) {
var self = this;
var slow_create = function () {
self._search_create_popup("form", undefined, {"default_name": name});
};
if (self.get_definition_options().quick_create === undefined || self.get_definition_options().quick_create) {
new instance.web.DataSet(this, this.field.relation, self.build_context())
.name_create(name, function(data) {
self.add_id(data[0]);
}).fail(function(error, event) {
event.preventDefault();
slow_create();
});
} else
slow_create();
},
// all search/create popup handling
_search_create_popup: function(view, ids, context) {
var self = this;
var pop = new instance.web.form.SelectCreatePopup(this);
pop.select_element(
self.field.relation,
{
title: (view === 'search' ? _t("Search: ") : _t("Create: ")) + (this.string || this.name),
initial_ids: ids ? _.map(ids, function(x) {return x[0]}) : undefined,
initial_view: view,
disable_multiple_selection: true
},
self.build_domain(),
new instance.web.CompoundContext(self.build_context(), context || {})
);
pop.on_select_elements.add(function(element_ids) {
self.add_id(element_ids[0]);
});
},
/**
* To implement.
*/
add_id: function(id) {},
};
instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.ReinitializeFieldMixin,
instance.web.form.CompletionFieldMixin, {
template: "FieldMany2One",
init: function(field_manager, node) {
this._super(field_manager, node);
this.limit = 7;
instance.web.form.CompletionFieldMixin.init.call(this);
this.set({'value': false});
this.display_value = {};
this.last_search = [];
this.floating = false;
this.inhibit_on_change = false;
this.orderer = new instance.web.DropMisordered();
},
start: function() {
this._super();
@@ -2426,7 +2522,11 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.exten
var isSelecting = false;
// autocomplete
this.$input.autocomplete({
source: function(req, resp) { self.get_search_result(req, resp); },
source: function(req, resp) {
self.get_search_result(req.term).then(function(result) {
resp(result);
});
},
select: function(event, ui) {
isSelecting = true;
var item = ui.item;
@@ -2458,91 +2558,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.exten
isSelecting = false;
});
},
// autocomplete component content handling
get_search_result: function(request, response) {
var search_val = request.term;
var self = this;
var dataset = new instance.web.DataSet(this, this.field.relation, self.build_context());
this.orderer.add(dataset.name_search(
search_val, self.build_domain(), 'ilike', this.limit + 1)).then(function(data) {
self.last_search = data;
// possible selections for the m2o
var values = _.map(data, function(x) {
return {
label: _.str.escapeHTML(x[1]),
value:x[1],
name:x[1],
id:x[0]
};
});
// search more... if more results that max
if (values.length > self.limit) {
values = values.slice(0, self.limit);
values.push({label: _t("<em>   Search More...</em>"), action: function() {
dataset.name_search(search_val, self.build_domain(), 'ilike'
, false, function(data) {
self._search_create_popup("search", data);
});
}});
}
// quick create
var raw_result = _(data.result).map(function(x) {return x[1];});
if (search_val.length > 0 &&
!_.include(raw_result, search_val) &&
(!self.get("value") || self.floating)) {
values.push({label: _.str.sprintf(_t('<em>   Create "<strong>%s</strong>"</em>'),
$('<span />').text(search_val).html()), action: function() {
self._quick_create(search_val);
}});
}
// create...
values.push({label: _t("<em>   Create and Edit...</em>"), action: function() {
self._search_create_popup("form", undefined, {"default_name": search_val});
}});
response(values);
});
},
_quick_create: function(name) {
var self = this;
var slow_create = function () {
self._search_create_popup("form", undefined, {"default_name": name});
};
if (self.get_definition_options().quick_create === undefined || self.get_definition_options().quick_create) {
new instance.web.DataSet(this, this.field.relation, self.build_context())
.name_create(name, function(data) {
self.display_value = {};
self.display_value["" + data[0]] = data[1];
self.set({value: data[0]});
}).fail(function(error, event) {
event.preventDefault();
slow_create();
});
} else
slow_create();
},
// all search/create popup handling
_search_create_popup: function(view, ids, context) {
var self = this;
var pop = new instance.web.form.SelectCreatePopup(this);
pop.select_element(
self.field.relation,
{
title: (view === 'search' ? _t("Search: ") : _t("Create: ")) + (this.string || this.name),
initial_ids: ids ? _.map(ids, function(x) {return x[0]}) : undefined,
initial_view: view,
disable_multiple_selection: true
},
self.build_domain(),
new instance.web.CompoundContext(self.build_context(), context || {})
);
pop.on_select_elements.add(function(element_ids) {
self.set({value: element_ids[0]});
});
},
render_value: function(no_recurse) {
var self = this;
if (! this.get("value")) {
@@ -2595,6 +2611,10 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(_.exten
this._super(value_);
this.inhibit_on_change = false;
},
add_id: function(id) {
this.display_value = {};
this.set({value: id});
},
is_false: function() {
return ! this.get("value");
},
@@ -3036,6 +3056,142 @@ instance.web.form.One2ManyKanbanView = instance.web_kanban.KanbanView.extend({
});
}
instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(_.extend({}, instance.web.form.CompletionFieldMixin,
instance.web.form.ReinitializeFieldMixin, {
template: "FieldMany2ManyTags",
init: function() {
this._super.apply(this, arguments);
instance.web.form.CompletionFieldMixin.init.call(this);
this.set({"value": []});
this.display_orderer = new instance.web.DropMisordered();
},
start: function() {
this._super();
instance.web.form.ReinitializeFieldMixin.start.call(this);
this.on("change:value", this, this.render_value);
},
initialize_content: function() {
if (this.get("effective_readonly"))
return;
var self = this;
self. $text = $("textarea", this.$element);
self.$text.textext({
plugins : 'tags arrow autocomplete',
autocomplete: {
render: function(suggestion) {
return $('<span class="text-label"/>').
data('index', suggestion['index']).html(suggestion['label']);
}
},
ext: {
autocomplete: {
selectFromDropdown: function(a, b, c) {
$(this).trigger('hideDropdown');
var index = Number(this.selectedSuggestionElement().children().children().data('index'));
var data = self.search_result[index];
if (data.id) {
self.add_id(data.id);
} else {
data.action();
}
},
},
tags: {
isTagAllowed: function(tag) {
if (! tag.name)
return false;
return true;
},
removeTag: function(tag) {
var id = tag.data("id");
self.set({"value": _.without(self.get("value"), id)});
},
renderTag: function(stuff) {
return $.fn.textext.TextExtTags.prototype.renderTag.
call(this, stuff).data("id", stuff.id);
},
},
itemManager: {
itemToString: function(item) {
return item.name;
},
},
},
}).bind('getSuggestions', function(e, data) {
var _this = this;
var str = !!data ? data.query || '' : '';
self.get_search_result(str).then(function(result) {
self.search_result = result;
$(_this).trigger('setSuggestions', {result : _.map(result, function(el, i) {
return _.extend(el, {index:i});
})});
});
}).bind('tagClick', function(e, tag, value, callback) {
var pop = new instance.web.form.FormOpenPopup(self.view);
pop.show_element(
self.field.relation,
value.id,
self.build_context(),
{
title: _t("Open: ") + (self.string || self.name)
}
);
pop.on_write_completed.add_last(function() {
self.render_value();
});
});
self.tags = self.$text.textext()[0].tags();
},
set_value: function(value_) {
value_ = value_ || [];
if (value_.length >= 1 && value_[0] instanceof Array) {
value_ = value_[0][2];
}
this._super(value_);
},
get_value: function() {
var tmp = [commands.replace_with(this.get("value"))];
return tmp;
},
render_value: function() {
var self = this;
var dataset = new instance.web.DataSetStatic(this, this.field.relation, self.view.dataset.get_context());
var handle_names = function(data) {
var indexed = {};
_.each(data, function(el) {
indexed[el[0]] = el;
});
data = _.map(self.get("value"), function(el) { return indexed[el]; });
if (! self.get("effective_readonly")) {
self.tags.containerElement().children().remove();
$("textarea", self.$element).css("padding-left", "3px");
self.tags.addTags(_.map(data, function(el) {return {name: el[1], id:el[0]};}));
} else {
self.$element.html(QWeb.render("FieldMany2ManyTags.box", {elements: data}));
$(".oe_form_field_many2manytags_box", self.$element).click(function() {
var index = Number($(this).data("index"));
self.do_action({
type: 'ir.actions.act_window',
res_model: self.field.relation,
res_id: self.get("value")[index],
context: self.build_context(),
views: [[false, 'form']],
target: 'current'
});
});
}
};
if (! self.get('values') || self.get('values').length > 0) {
this.display_orderer.add(dataset.name_get(self.get("value"))).then(handle_names);
} else {
handle_names([]);
}
},
add_id: function(id) {
this.set({'value': _.uniq(this.get('value').concat([id]))});
},
}));
/*
* TODO niv: clean those deferred stuff, it could be better
*/
@@ -3823,6 +3979,7 @@ instance.web.form.widgets = new instance.web.Registry({
'selection' : 'instance.web.form.FieldSelection',
'many2one' : 'instance.web.form.FieldMany2One',
'many2many' : 'instance.web.form.FieldMany2Many',
'many2manytags' : 'instance.web.form.FieldMany2ManyTags',
'one2many' : 'instance.web.form.FieldOne2Many',
'one2many_list' : 'instance.web.form.FieldOne2Many',
'reference' : 'instance.web.form.FieldReference',
+16
View File
@@ -1047,6 +1047,22 @@
</span>
</t>
</t>
<t t-name="FieldMany2ManyTags">
<div class="oe_form_field_many2manytags">
<t t-if="! widget.get('effective_readonly')">
<textarea rows="1" style="width: 100%"></textarea>
</t>
</div>
</t>
<t t-name="FieldMany2ManyTags.box">
<t t-set="i" t-value="0"/>
<t t-foreach="elements" t-as="el">
<span class="oe_form_field_many2manytags_box" t-att-data-index="i">
<t t-esc="el[1]"/>
</span>
<t t-set="i" t-value="i + 1"/>
</t>
</t>
<t t-name="FieldReference">
<table class="oe_form_field_reference oe_frame oe_forms" border="0" cellpadding="0" cellspacing="0">
<tr>