Merge lp:~openerp-dev/openerp-web/trunk-mass_mailing-v2-tde into lp:openerp-web

Proposed by Thibault Delavallée (OpenERP)
Status: Merged
Merged at revision: 3976
Proposed branch: lp:~openerp-dev/openerp-web/trunk-mass_mailing-v2-tde
Merge into: lp:openerp-web
Diff against target: 387 lines (+184/-22)
5 files modified
addons/web/static/src/css/base.css (+10/-2)
addons/web/static/src/css/base.sass (+7/-1)
addons/web/static/src/js/view_form.js (+127/-8)
addons/web/static/src/js/view_list.js (+2/-2)
addons/web/static/src/xml/base.xml (+38/-9)
To merge this branch: bzr merge lp:~openerp-dev/openerp-web/trunk-mass_mailing-v2-tde
Reviewer Review Type Date Requested Status
OpenERP R&D Web Team Pending
Review via email: mp+211473@code.launchpad.net

Description of the change

[ADD] web: form: added FieldCharDomain widget. This widget works on a char field and is used to manage a domain. It allows to select records in a list view and to store the domain in the field, without having to deal with the complexity of writing domains.

[ADD] web: form: added FieldBarChart widget. This widget works on char field and display a serialized list of values as a barchart. This is used in stat buttons, like percent pie or stat info, to display a summary of some data on form view.

[IMP] web: some fixes and improvements in the stat buttons.

[IMP] web: list view: buttons in list view can now be text button, not only icon-based buttons. Icons are so v6 and not swag.

To post a comment you must log in.
3960. By Thibault Delavallée (OpenERP)

[IMP] sidebar in list view: context should be the one of the dataset, allowing context propagation, not
void default context.

3961. By Thibault Delavallée (OpenERP)

[MERGE] Sync with trunk

3962. By Thibault Delavallée (OpenERP)

[IMP] list_view: allow displaying string-based buttons in list view
and not only img-based buttons.

3963. By Thibault Delavallée (OpenERP)

[MERGE] Sync with trunk

3964. By Thibault Delavallée (OpenERP)

[IMP] view_form: Many2One: when choosing not to have the possibility
of creating values in a many2one, also avoid displaying an 'error displayer'
that allow to create a new record.

3965. By Thibault Delavallée (OpenERP)

[MERGE] Sync with trunk

3966. By Thibault Delavallée (OpenERP)

[MERGE] Sync with trunk

3967. By Thibault Delavallée (OpenERP)

[MERGE] Sync with trunk

3968. By Thibault Delavallée (OpenERP)

[IMP] web: stat buttons: some CSS fixes + added barchart button
that display a barchart. Whoo.

3969. By Thibault Delavallée (OpenERP)

[FIX] web: fixed fieldbarchart, now accepting JSON; fixed statinfo, now properly managing values

3970. By Thibault Delavallée (OpenERP)

[MERGE] Sync with trunk to have last fixes

3971. By Thibault Delavallée (OpenERP)

[MERGE] Sync with trunk

3972. By Thibault Delavallée (OpenERP)

[MERGE] Sync with trunk

3973. By Thibault Delavallée (OpenERP)

[MERGE] Sync with trunk

3974. By Thibault Delavallée (OpenERP)

[REV] Reverted changes about sidebar as we now have
a widget to handle things like selection in a list view.

3975. By Thibault Delavallée (OpenERP)

[FIX] web: fixed iamge buttons taking 2 lines

3976. By Thibault Delavallée (OpenERP)

[ADD] web: form: added char domain widget coming from mass_mailing. This widget
is used to compute the number of records according ot a domain, and to allow
selecting documents.

3977. By Thibault Delavallée (OpenERP)

[FIX] chardomain field: fixed button action

3978. By Thibault Delavallée (OpenERP)

[MERGE] Sync with trunk

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'addons/web/static/src/css/base.css'
2--- addons/web/static/src/css/base.css 2014-04-11 13:29:34 +0000
3+++ addons/web/static/src/css/base.css 2014-04-16 08:29:33 +0000
4@@ -1,4 +1,4 @@
5-@charset "UTF-8";
6+@charset "utf-8";
7 @font-face {
8 font-family: "mnmliconsRegular";
9 src: url("/web/static/src/font/mnmliconsv21-webfont.eot") format("eot");
10@@ -352,9 +352,17 @@
11 width: 37px;
12 text-align: center;
13 }
14+.openerp .oe_button_box .oe_stat_button .oe_form_field_percent_pie {
15+ width: 42px;
16+}
17+.openerp .oe_button_box .oe_stat_button .oe_form_field_bar_chart {
18+ width: 42px;
19+}
20 .openerp .oe_button_box .oe_stat_button svg {
21 width: 38px;
22 height: 38px;
23+ display: inline;
24+ vertical-align: middle;
25 }
26 .openerp .oe_avatar > img {
27 max-height: 90px;
28@@ -2768,7 +2776,7 @@
29 padding: 3px 6px;
30 white-space: pre-line;
31 }
32-.openerp .oe_list_content > tbody > tr > td > button, .openerp .oe_list_content > tbody > tr > th > button {
33+.openerp .oe_list_content > tbody > tr > td > button.btn_img, .openerp .oe_list_content > tbody > tr > th > button.btn_img {
34 border: none;
35 background: transparent;
36 padding: 0;
37
38=== modified file 'addons/web/static/src/css/base.sass'
39--- addons/web/static/src/css/base.sass 2014-04-11 13:29:34 +0000
40+++ addons/web/static/src/css/base.sass 2014-04-16 08:29:33 +0000
41@@ -362,9 +362,15 @@
42 padding: 0px 3px
43 width: 37px
44 text-align: center
45+ .oe_form_field_percent_pie
46+ width: 42px
47+ .oe_form_field_bar_chart
48+ width: 42px
49 svg
50 width: 38px
51 height: 38px
52+ display: inline
53+ vertical-align: middle
54 .oe_avatar
55 > img
56 max-height: 90px
57@@ -2241,7 +2247,7 @@
58 padding: 3px 6px
59 white-space: pre-line
60 > td, > th
61- > button
62+ > button.btn_img
63 border: none
64 background: transparent
65 padding: 0
66
67=== modified file 'addons/web/static/src/js/view_form.js'
68--- addons/web/static/src/js/view_form.js 2014-04-15 14:29:10 +0000
69+++ addons/web/static/src/js/view_form.js 2014-04-16 08:29:33 +0000
70@@ -2438,6 +2438,76 @@
71 }
72 });
73
74+instance.web.form.FieldCharDomain = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, {
75+ init: function(field_manager, node) {
76+ this._super.apply(this, arguments);
77+ },
78+ start: function() {
79+ var self = this;
80+ this._super.apply(this, arguments);
81+ this.on("change:effective_readonly", this, function () {
82+ this.display_field();
83+ this.render_value();
84+ });
85+ this.display_field();
86+ return this._super();
87+ },
88+ render_value: function() {
89+ this.$('button.select_records').css('visibility', this.get('effective_readonly') ? 'hidden': '');
90+ },
91+ set_value: function(value_) {
92+ var self = this;
93+ this.set('value', value_ || false);
94+ this.display_field();
95+ },
96+ display_field: function() {
97+ var self = this;
98+ this.$el.html(instance.web.qweb.render("FieldCharDomain", {widget: this}));
99+ if (this.get('value')) {
100+ var domain = instance.web.pyeval.eval('domain', this.get('value'));
101+ var relation = this.getParent().fields.mailing_model.get('value')[0];
102+ var ds = new instance.web.DataSetStatic(self, relation, self.build_context());
103+ ds.call('search_count', [domain]).then(function (results) {
104+ $('.oe_domain_count', self.$el).text(results + ' records selected');
105+ $('button span', self.$el).text(' Change selection');
106+ });
107+ } else {
108+ $('.oe_domain_count', this.$el).text('0 record selected');
109+ $('button span', this.$el).text(' Select records');
110+ };
111+ this.$('.select_records').on('click', self.on_click);
112+ },
113+ on_click: function(ev) {
114+ var self = this;
115+ var model = this.options.model || this.field_manager.get_field_value(this.options.model_field);
116+ this.pop = new instance.web.form.SelectCreatePopup(this);
117+ this.pop.select_element(
118+ model, {title: 'Select records...'},
119+ [], this.build_context());
120+ this.pop.on("elements_selected", self, function(element_ids) {
121+ if (this.pop.$('input.oe_list_record_selector').prop('checked')) {
122+ var search_data = this.pop.searchview.build_search_data();
123+ var domain_done = instance.web.pyeval.eval_domains_and_contexts({
124+ domains: search_data.domains,
125+ contexts: search_data.contexts,
126+ group_by_seq: search_data.groupbys || []
127+ }).then(function (results) {
128+ return results.domain;
129+ });
130+ }
131+ else {
132+ var domain = ["id", "in", element_ids];
133+ var domain_done = $.Deferred().resolve(domain);
134+ }
135+ $.when(domain_done).then(function (domain) {
136+ var domain = self.pop.dataset.domain.concat(domain || []);
137+ self.set_value(JSON.stringify(domain))
138+ });
139+ });
140+ event.preventDefault();
141+ },
142+});
143+
144 instance.web.DateTimeWidget = instance.web.Widget.extend({
145 template: "web.datepicker",
146 jqueryui_object: 'datetimepicker',
147@@ -2833,10 +2903,10 @@
148
149 svg.innerHTML = "";
150 nv.addGraph(function() {
151- var size=43;
152+ var width = 42, height = 42;
153 var chart = nv.models.pieChart()
154- .width(size)
155- .height(size)
156+ .width(width)
157+ .height(height)
158 .margin({top: 0, right: 0, bottom: 0, left: 0})
159 .donut(true)
160 .showLegend(false)
161@@ -2849,11 +2919,11 @@
162 .datum([{'x': 'value', 'y': value}, {'x': 'complement', 'y': 100 - value}])
163 .transition()
164 .call(chart)
165- .attr({width:size, height:size});
166+ .attr('style', 'width: ' + width + 'px; height:' + height + 'px;');
167
168 d3.select(svg)
169 .append("text")
170- .attr({x: size/2, y: size/2 + 3, 'text-anchor': 'middle'})
171+ .attr({x: width/2, y: height/2 + 3, 'text-anchor': 'middle'})
172 .style({"font-size": "10px", "font-weight": "bold"})
173 .text(formatted_value);
174
175@@ -2863,6 +2933,43 @@
176 }
177 });
178
179+/**
180+ The FieldBarChart expectsa list of values (indeed)
181+*/
182+instance.web.form.FieldBarChart = instance.web.form.AbstractField.extend({
183+ template: 'FieldBarChart',
184+
185+ render_value: function() {
186+ var value = JSON.parse(this.get('value'));
187+ var svg = this.$('svg')[0];
188+ svg.innerHTML = "";
189+ nv.addGraph(function() {
190+ var width = 34, height = 34;
191+ var chart = nv.models.discreteBarChart()
192+ .x(function (d) { return d.tooltip })
193+ .y(function (d) { return d.value })
194+ .width(width)
195+ .height(height)
196+ .margin({top: 0, right: 0, bottom: 0, left: 0})
197+ .tooltips(false)
198+ .showValues(false)
199+ .transitionDuration(350)
200+ .showXAxis(false)
201+ .showYAxis(false);
202+
203+ d3.select(svg)
204+ .datum([{key: 'values', values: value}])
205+ .transition()
206+ .call(chart)
207+ .attr('style', 'width: ' + (width + 4) + 'px; height: ' + (height + 8) + 'px;');
208+
209+ nv.utils.windowResize(chart.update);
210+
211+ return chart;
212+ });
213+
214+ }
215+});
216
217
218 instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, {
219@@ -3419,7 +3526,7 @@
220 }
221 self.floating = false;
222 }
223- if (used && self.get("value") === false && ! self.no_ed) {
224+ if (used && self.get("value") === false && ! self.no_ed && (self.options.no_create === false || self.options.no_create === undefined)) {
225 self.ed_def.reject();
226 self.uned_def.reject();
227 self.ed_def = $.Deferred();
228@@ -5919,20 +6026,30 @@
229 display a simple string "<value of field> <label of the field>"
230 */
231 instance.web.form.StatInfo = instance.web.form.AbstractField.extend({
232+ is_field_number: true,
233 init: function() {
234 this._super.apply(this, arguments);
235- this.set("value", 0);
236+ this.internal_set_value(0);
237+ },
238+ set_value: function(value_) {
239+ if (value_ === false || value_ === undefined) {
240+ value_ = 0;
241+ }
242+ this._super.apply(this, [value_]);
243 },
244 render_value: function() {
245 var options = {
246 value: this.get("value") || 0,
247- text: this.string,
248 };
249+ if (! this.node.attrs.nolabel) {
250+ options.text = this.string
251+ }
252 this.$el.html(QWeb.render("StatInfo", options));
253 },
254
255 });
256
257+
258 /**
259 * Registry of form fields, called by :js:`instance.web.FormView`.
260 *
261@@ -5946,6 +6063,7 @@
262 'url' : 'instance.web.form.FieldUrl',
263 'text' : 'instance.web.form.FieldText',
264 'html' : 'instance.web.form.FieldTextHtml',
265+ 'char_domain': 'instance.web.form.FieldCharDomain',
266 'date' : 'instance.web.form.FieldDate',
267 'datetime' : 'instance.web.form.FieldDatetime',
268 'selection' : 'instance.web.form.FieldSelection',
269@@ -5961,6 +6079,7 @@
270 'boolean' : 'instance.web.form.FieldBoolean',
271 'float' : 'instance.web.form.FieldFloat',
272 'percentpie': 'instance.web.form.FieldPercentPie',
273+ 'barchart': 'instance.web.form.FieldBarChart',
274 'integer': 'instance.web.form.FieldFloat',
275 'float_time': 'instance.web.form.FieldFloat',
276 'progressbar': 'instance.web.form.FieldProgressBar',
277
278=== modified file 'addons/web/static/src/js/view_list.js'
279--- addons/web/static/src/js/view_list.js 2014-04-02 09:23:10 +0000
280+++ addons/web/static/src/js/view_list.js 2014-04-16 08:29:33 +0000
281@@ -2261,8 +2261,8 @@
282 attrs = this.modifiers_for(row_data);
283 }
284 if (attrs.invisible) { return ''; }
285-
286- return QWeb.render('ListView.row.button', {
287+ var template = this.icon && 'ListView.row.button' || 'ListView.row.text_button';
288+ return QWeb.render(template, {
289 widget: this,
290 prefix: instance.session.prefix,
291 disabled: attrs.readonly
292
293=== modified file 'addons/web/static/src/xml/base.xml'
294--- addons/web/static/src/xml/base.xml 2014-04-11 13:29:34 +0000
295+++ addons/web/static/src/xml/base.xml 2014-04-16 08:29:33 +0000
296@@ -612,10 +612,16 @@
297 <div class="oe_sidebar">
298 <t t-foreach="widget.sections" t-as="section">
299 <div class="oe_form_dropdown_section">
300- <button class="oe_dropdown_toggle oe_dropdown_arrow">
301+ <button class="oe_dropdown_toggle oe_dropdown_arrow" t-if="section.name != 'buttons'">
302 <t t-if="section.name == 'files'" t-raw="widget.items[section.name].length || ''"/>
303 <t t-esc="section.label"/>
304 </button>
305+ <t t-if="section.name == 'buttons'" t-foreach="widget.items[section.name]" t-as="item" t-att-class="item.classname">
306+ <button t-att-title="item.title or ''" t-att-data-section="section.name" t-att-data-index="item_index" t-att-href="item.url"
307+ target="_blank" class="oe_sidebar_button oe_highlight">
308+ <t t-raw="item.label"/>
309+ </button>
310+ </t>
311 <ul class="oe_dropdown_menu">
312 <li t-foreach="widget.items[section.name]" t-as="item" t-att-class="item.classname">
313 <t t-if="section.name == 'files'">
314@@ -792,11 +798,16 @@
315 </span>
316 </t>
317 </t>
318+<button t-name="ListView.row.text_button" type="button"
319+ t-att-title="widget.string" t-att-disabled="disabled || undefined"
320+ t-att-class="disabled ? 'oe_list_button_disabled btn' : 'btn'">
321+ <t t-esc="widget.string"/>
322+</button>
323 <button t-name="ListView.row.button" type="button"
324 t-att-title="widget.string" t-att-disabled="disabled || undefined"
325- t-att-class="disabled ? 'oe_list_button_disabled' : undefined"
326- ><img t-attf-src="#{prefix}/web/static/src/img/icons/#{widget.icon}.png"
327- t-att-alt="widget.string"/></button>
328+ t-att-class="disabled ? 'oe_list_button_disabled btn_img' : 'btn_img'"
329+ ><img t-attf-src="#{prefix}/web/static/src/img/icons/#{widget.icon}.png"
330+ t-att-alt="widget.string"/></button>
331 <t t-extend="ListView.row">
332 <!-- adds back padding to row being rendered after edition, if necessary
333 (if not deletable add back padding), otherwise the row being added is
334@@ -1069,6 +1080,16 @@
335 </t>
336 </div>
337 </t>
338+<t t-name="FieldCharDomain">
339+ <div class="oe_form_field">
340+ <span class="oe_domain_count"/>
341+ <button class="oe_button oe_link select_records" type="button"
342+ t-att-style="widget.node.attrs.style"
343+ t-att-accesskey="widget.node.attrs.accesskey">
344+ <span class="fa fa-arrow-right"/>
345+ </button>
346+ </div>
347+</t>
348 <t t-name="web.datepicker">
349 <span>
350 <t t-set="placeholder" t-value="widget.getParent().node and widget.getParent().node.attrs.placeholder"/>
351@@ -1209,9 +1230,16 @@
352 </span>
353 </t>
354 <t t-name="FieldPercentPie">
355- <span class="oe_form_field oe_form_field_percent_pie" t-att-style="widget.node.attrs.style">
356- <svg></svg>
357- </span>
358+ <div class="oe_form_field oe_form_field_percent_pie" t-att-style="widget.node.attrs.style">
359+ <svg></svg>
360+ <span t-if="widget.string"><t t-esc="widget.string"/></span>
361+ </div>
362+</t>
363+<t t-name="FieldBarChart">
364+ <div class="oe_form_field oe_form_field_bar_chart" t-att-style="widget.node.attrs.style">
365+ <svg></svg>
366+ <span t-if="widget.string"><t t-esc="widget.string"/></span>
367+ </div>
368 </t>
369 <t t-name="FieldStatus">
370 <ul t-att-class="'oe_form_field_status ' + (widget.options.clickable ? 'oe_form_status_clickable' : 'oe_form_status')" t-att-style="widget.node.attrs.style"/>
371@@ -1382,7 +1410,7 @@
372 t-att-autofocus="widget.node.attrs.autofocus"
373 t-att-accesskey="widget.node.attrs.accesskey">
374 <img t-if="!widget.is_stat_button and widget.node.attrs.icon " t-att-src="_s + widget.node.attrs.icon" width="16" height="16"/>
375- <div t-if="widget.is_stat_button" class="stat_button_icon"><t t-if="widget.icon" t-raw="widget.icon"/></div>
376+ <div t-if="widget.is_stat_button and widget.icon" class="stat_button_icon"><t t-raw="widget.icon"/></div>
377 <span t-if="widget.string and !widget.is_stat_button"><t t-esc="widget.string"/></span>
378 <div t-if="widget.string and widget.is_stat_button"><t t-esc="widget.string"/></div>
379 </button>
380@@ -1958,5 +1986,6 @@
381 <a href="javascript:void(0)"><t t-esc="text"/></a>
382 </t>
383 <t t-name="StatInfo">
384- <strong><t t-esc="value"/></strong><br/><t t-esc="text"/></t>
385+ <strong><t t-esc="value"/></strong>
386+ <t t-esc="text"/></t>
387 </templates>