Merge lp:~openerp-dev/openerp-web/trunk-mass_mailing-v2-tde into lp:openerp-web
- trunk-mass_mailing-v2-tde
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenERP R&D Web Team | Pending | ||
Review via email: mp+211473@code.launchpad.net |
Commit message
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.
- 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
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> |