[MERGE] Merge lp:~openerp-web.
bzr revid: bth@tinyerp.com-20120510055102-yoo8pbim46q5fp6d bzr revid: bth@tinyerp.com-20120514092121-7uz6efn91hkfuz93
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -1818,9 +1818,15 @@ class Reports(View):
|
||||
report = zlib.decompress(report)
|
||||
report_mimetype = self.TYPES_MAPPING.get(
|
||||
report_struct['format'], 'octet-stream')
|
||||
if 'name' not in action:
|
||||
reports = req.session.model('ir.actions.report.xml')
|
||||
res_id = reports.search([('report_name', '=',action['report_name']),],
|
||||
0, False, False, context)
|
||||
action['name'] = reports.read(res_id, ['name'], context)[0]['name']
|
||||
|
||||
return req.make_response(report,
|
||||
headers=[
|
||||
('Content-Disposition', 'attachment; filename="%s.%s"' % (action['report_name'], report_struct['format'])),
|
||||
('Content-Disposition', 'attachment; filename="%s.%s"' % (action['name'], report_struct['format'])),
|
||||
('Content-Type', report_mimetype),
|
||||
('Content-Length', len(report))],
|
||||
cookies={'fileToken': int(token)})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1118,8 +1118,6 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt
|
||||
// invisibility transfer
|
||||
var field_modifiers = JSON.parse($child.attr('modifiers') || '{}');
|
||||
var invisible = field_modifiers.invisible;
|
||||
field_modifiers.invisible = undefined;
|
||||
$child.attr('modifiers', JSON.stringify(field_modifiers));
|
||||
self.handle_common_properties($td, $("<dummy>").attr("modifiers", JSON.stringify({invisible: invisible})));
|
||||
|
||||
$tr.append($td.append($child));
|
||||
@@ -1371,17 +1369,27 @@ instance.web.form.InvisibilityChangerMixin = {
|
||||
instance.web.form.compute_domain(this._ic_invisible_modifier, this._ic_field_manager.fields);
|
||||
this.set({"invisible": result});
|
||||
});
|
||||
this.set({invisible: this._ic_invisible_modifier === true});
|
||||
this.set({invisible: this._ic_invisible_modifier === true, force_invisible: false});
|
||||
var check = function() {
|
||||
if (this.get("invisible") || this.get('force_invisible')) {
|
||||
this.set({"effective_invisible": true});
|
||||
} else {
|
||||
this.set({"effective_invisible": false});
|
||||
}
|
||||
};
|
||||
this.on('change:invisible', this, check);
|
||||
this.on('change:force_invisible', this, check);
|
||||
_.bind(check, this)();
|
||||
},
|
||||
start: function() {
|
||||
var check_visibility = function() {
|
||||
if (this.get("invisible")) {
|
||||
if (this.get("effective_invisible")) {
|
||||
this.$element.hide();
|
||||
} else {
|
||||
this.$element.show();
|
||||
}
|
||||
};
|
||||
this.on("change:invisible", this, check_visibility);
|
||||
this.on("change:effective_invisible", this, check_visibility);
|
||||
_.bind(check_visibility, this)();
|
||||
},
|
||||
};
|
||||
@@ -1827,7 +1835,6 @@ instance.web.form.FieldChar = instance.web.form.AbstractField.extend(_.extend({}
|
||||
init: function (field_manager, node) {
|
||||
this._super(field_manager, node);
|
||||
this.password = this.node.attrs.password === 'True' || this.node.attrs.password === '1';
|
||||
this.placeholder = this.node.attrs.placeholder || '';
|
||||
},
|
||||
initialize_content: function() {
|
||||
var self = this;
|
||||
@@ -2305,17 +2312,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();
|
||||
@@ -2427,7 +2530,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;
|
||||
@@ -2459,91 +2566,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")) {
|
||||
@@ -2596,6 +2619,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");
|
||||
},
|
||||
@@ -3037,6 +3064,154 @@ 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();
|
||||
this._drop_shown = false;
|
||||
},
|
||||
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() {
|
||||
$(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();
|
||||
});
|
||||
}).bind('hideDropdown', function() {
|
||||
self._drop_shown = false;
|
||||
}).bind('hideDropdown', function() {
|
||||
self._drop_shown = true;
|
||||
});
|
||||
self.tags = self.$text.textext()[0].tags();
|
||||
$("textarea", this.$element).focusout(function() {
|
||||
$("textarea", this.$element).val("");
|
||||
}).keydown(function(e) {
|
||||
if (event.keyCode === 9 && self._drop_shown) {
|
||||
self.$text.textext()[0].autocomplete().selectFromDropdown();
|
||||
}
|
||||
});
|
||||
},
|
||||
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
|
||||
*/
|
||||
@@ -3824,6 +3999,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',
|
||||
|
||||
@@ -917,7 +917,7 @@
|
||||
t-att-tabindex="widget.node.attrs.tabindex"
|
||||
t-att-autofocus="widget.node.attrs.autofocus"
|
||||
t-attf-class="field_char #{widget.is_field_number ? 'oe-number' : ''}"
|
||||
t-att-placeholder="widget.placeholder"
|
||||
t-att-placeholder="widget.node.attrs.placeholder"
|
||||
/><img class="oe_field_translate oe_input_icon" t-if="widget.field.translate" t-att-src='_s + "/web/static/src/img/icons/terp-translate.png"' width="16" height="16" border="0"/>
|
||||
</div>
|
||||
</t>
|
||||
@@ -934,6 +934,7 @@
|
||||
t-att-id="widget.id_for_label"
|
||||
t-att-tabindex="widget.node.attrs.tabindex"
|
||||
t-att-autofocus="widget.node.attrs.autofocus"
|
||||
t-att-placeholder="widget.node.attrs.placeholder"
|
||||
/>
|
||||
</td>
|
||||
<td width="16">
|
||||
@@ -959,6 +960,7 @@
|
||||
t-att-id="widget.id_for_label"
|
||||
t-att-tabindex="widget.node.attrs.tabindex"
|
||||
t-att-autofocus="widget.node.attrs.autofocus"
|
||||
t-att-placeholder="widget.node.attrs.placeholder"
|
||||
/>
|
||||
</td>
|
||||
<td width="16">
|
||||
@@ -982,6 +984,7 @@
|
||||
class="field_text"
|
||||
t-att-tabindex="widget.node.attrs.tabindex"
|
||||
t-att-autofocus="widget.node.attrs.autofocus"
|
||||
t-att-placeholder="widget.node.attrs.placeholder"
|
||||
></textarea>
|
||||
<img class="oe_field_translate oe_input_icon" t-if="widget.field.translate"
|
||||
t-att-src='_s + "/web/static/src/img/icons/terp-translate.png"' width="16" height="16" border="0"/>
|
||||
@@ -992,6 +995,7 @@
|
||||
<input type="text" class="oe_datepicker_container" disabled="disabled" style="display: none;"/>
|
||||
<input type="text"
|
||||
t-att-name="widget.name"
|
||||
t-att-placeholder="widget.getParent().node.attrs.placeholder"
|
||||
t-attf-class="oe_datepicker_master field_#{widget.type_of_date} oe_form_field_#{widget.type_of_date}"
|
||||
/><img class="oe_input_icon oe_datepicker_trigger" t-att-src='_s + "/web/static/src/img/ui/field_calendar.png"'
|
||||
title="Select date" width="16" height="16" border="0"/>
|
||||
@@ -1024,6 +1028,7 @@
|
||||
t-att-id="widget.id_for_label"
|
||||
t-att-tabindex="widget.node.attrs.tabindex"
|
||||
t-att-autofocus="widget.node.attrs.autofocus"
|
||||
t-att-placeholder="widget.node.attrs.placeholder"
|
||||
/>
|
||||
<span class="oe-m2o-drop-down-button">
|
||||
<img t-att-src='_s + "/web/static/src/img/down-arrow.png"' /></span>
|
||||
@@ -1042,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>
|
||||
|
||||
@@ -224,6 +224,30 @@
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
.openerp .oe_kanban_add {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: url(/web_kanban/static/src/img/plus-icon.png) no-repeat;
|
||||
}
|
||||
|
||||
.openerp .oe_kanban_quick_create {
|
||||
/* apply block formatting context */
|
||||
overflow: hidden;
|
||||
}
|
||||
.openerp .oe_kanban_quick_create input {
|
||||
display: block;
|
||||
/* margins within width */
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
.openerp .oe_kanban_quick_create button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* Custom colors are also present in kanban.js */
|
||||
/* Custom color#0 */
|
||||
.openerp .oe_kanban_color_0 .oe_kanban_color_bglight {
|
||||
|
||||
@@ -348,6 +348,12 @@ instance.web_kanban.KanbanGroup = instance.web.OldWidget.extend({
|
||||
self.view.compute_groups_width();
|
||||
return false;
|
||||
});
|
||||
this.$element.find('.oe_kanban_add').click(function () {
|
||||
if (self.quick) { return; }
|
||||
self.quick = new instance.web_kanban.QuickCreate(this)
|
||||
.on('added', self, self.proxy('quick_add'));
|
||||
self.quick.appendTo(self.$element.find('.oe_kanban_group_header'));
|
||||
});
|
||||
this.$records.find('.oe_kanban_show_more').click(this.do_show_more);
|
||||
if (this.state.folded) {
|
||||
this.do_toggle_fold();
|
||||
@@ -370,12 +376,17 @@ instance.web_kanban.KanbanGroup = instance.web.OldWidget.extend({
|
||||
'offset': self.dataset_offset += self.view.limit
|
||||
}).then(this.do_add_records);
|
||||
},
|
||||
do_add_records: function(records) {
|
||||
do_add_records: function(records, prepend) {
|
||||
var self = this;
|
||||
_.each(records, function(record) {
|
||||
var rec = new instance.web_kanban.KanbanRecord(self, record);
|
||||
rec.insertBefore(self.$records.find('.oe_kanban_show_more'));
|
||||
self.records.push(rec);
|
||||
if (!prepend) {
|
||||
rec.insertBefore(self.$records.find('.oe_kanban_show_more'));
|
||||
self.records.push(rec);
|
||||
} else {
|
||||
rec.prependTo(self.$records);
|
||||
self.records.unshift(rec);
|
||||
}
|
||||
});
|
||||
this.$records.find('.oe_kanban_show_more').toggle(this.records.length < this.dataset.size())
|
||||
.find('.oe_kanban_remaining').text(this.dataset.size() - this.records.length);
|
||||
@@ -398,6 +409,36 @@ instance.web_kanban.KanbanGroup = instance.web.OldWidget.extend({
|
||||
self.view.dataset.write(record.id, { sequence : index });
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Handles user event from nested quick creation view
|
||||
*
|
||||
* @param {String} name name to give to the new record
|
||||
*/
|
||||
quick_add: function (name) {
|
||||
var context = {};
|
||||
context['default_' + this.view.group_by] = this.value;
|
||||
// FIXME: what if name_create fails?
|
||||
new instance.web.Model(this.dataset.model).call(
|
||||
'name_create', [name], {context: new instance.web.CompoundContext(
|
||||
this.dataset.get_context(), context)})
|
||||
.then(this.proxy('quick_created'))
|
||||
},
|
||||
/**
|
||||
* Handles a non-erroneous response from name_create
|
||||
*
|
||||
* @param {(Id, String)} record name_get format for the newly created record
|
||||
*/
|
||||
quick_created: function (record) {
|
||||
var id = record[0], self = this;
|
||||
this.quick.destroy();
|
||||
delete this.quick;
|
||||
new instance.web.Model(this.dataset.model).call(
|
||||
'read', [[id], this.view.fields_keys], {})
|
||||
.then(function (records) {
|
||||
self.view.dataset.ids.push(id);
|
||||
self.do_add_records(records, 'prepend');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -603,6 +644,30 @@ instance.web_kanban.KanbanRecord = instance.web.OldWidget.extend({
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Quick creation view.
|
||||
*
|
||||
* Triggers a single event "added" with a single parameter "name", which is the
|
||||
* name entered by the user
|
||||
*
|
||||
* @class
|
||||
* @type {*}
|
||||
*/
|
||||
instance.web_kanban.QuickCreate = instance.web.Widget.extend({
|
||||
template: 'KanbanView.quick_create',
|
||||
|
||||
start: function () {
|
||||
var self = this;
|
||||
var $input = this.$element.find('input');
|
||||
$input.focus();
|
||||
this.$element.on('submit', function () {
|
||||
self.trigger('added', $input.val());
|
||||
return false;
|
||||
});
|
||||
return this._super();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<t t-if="widget.view.group_by">
|
||||
<div class="oe_kanban_group_header">
|
||||
<div class="oe_kanban_fold_icon"></div>
|
||||
<div class="oe_kanban_add"></div>
|
||||
<div class="oe_fold_column">
|
||||
<div t-attf-class="oe_kanban_group_title #{widget.undefined_title ? 'oe_kanban_group_title_undefined' : ''}">
|
||||
<t t-esc="widget.title"/>
|
||||
@@ -62,4 +63,8 @@
|
||||
</tr>
|
||||
</table>
|
||||
</t>
|
||||
<form t-name="KanbanView.quick_create" class="oe_kanban_quick_create">
|
||||
<input/>
|
||||
<button type="submit">Add</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user