diff options
| author | Yogesh (OpenERP) <ysa@tinyerp.com> | 2011-11-15 10:31:59 +0530 |
|---|---|---|
| committer | Yogesh (OpenERP) <ysa@tinyerp.com> | 2011-11-15 10:31:59 +0530 |
| commit | 8d718eb7da01cbfb89d6886e62e40d5a26259ce7 (patch) | |
| tree | 8ad56aaa9f8581f2cbb1a84591ff853fd7c5a9a7 /addons/web/static/src | |
| parent | 4b250ebee88b70d0ded96174ec6d19cf3aa68592 (diff) | |
| parent | 95c31ad01cc762d1dcd9c4dfccdf2d21c5264d35 (diff) | |
[MERGE] Merge with trunk upto revision no 1469.
bzr revid: ysa@tinyerp.com-20111115050159-xn0kxam21tenh6wb
Diffstat (limited to 'addons/web/static/src')
| -rw-r--r-- | addons/web/static/src/css/base.css | 51 | ||||
| -rw-r--r-- | addons/web/static/src/js/core.js | 4 | ||||
| -rw-r--r-- | addons/web/static/src/js/data_import.js | 4 | ||||
| -rw-r--r-- | addons/web/static/src/js/formats.js | 101 | ||||
| -rw-r--r-- | addons/web/static/src/js/search.js | 145 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_form.js | 41 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_list.js | 14 | ||||
| -rw-r--r-- | addons/web/static/src/js/views.js | 79 | ||||
| -rw-r--r-- | addons/web/static/src/xml/base.xml | 129 |
9 files changed, 429 insertions, 139 deletions
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 01f4b11f4d3..c061353d113 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -26,7 +26,7 @@ body.openerp, .openerp textarea, .openerp input, .openerp select, .openerp optio margin: 0; } -.openerp .oe-number { +.openerp .oe-listview .oe-number { text-align: right !important; } .openerp .oe_hide { @@ -713,7 +713,26 @@ label.error { .openerp .oe-listview th { vertical-align: middle; text-align: left; + padding: 1px 2px; } +.openerp .oe-listview th.oe-record-selector, +.openerp .oe-listview td.oe-button, +.openerp .oe-listview td.oe-record-delete { + padding: 0 1px; +} + +/* Could use :not selectors if they were supported by MSIE8... */ +.openerp .oe-listview tbody td { + border-left: 1px solid #dadada; +} +.openerp .oe-listview tbody td:first-child, +.openerp .oe-listview tbody td.oe-button, +.openerp .oe-listview tbody td.oe-button+td, +.openerp .oe-listview tbody th.oe-record-selector+td, +.openerp .oe-listview tbody td.oe-record-delete { + border-left: none; +} + .openerp .oe-listview td.oe-record-delete { text-align: right; } @@ -825,6 +844,9 @@ label.error { background: none; border-width: 0; } +.openerp .oe_form_notebook .ui-tabs-panel { + padding: 4px; +} .openerp .oe_form_notebook ul.ui-tabs-nav { padding-left: 0; background: transparent; @@ -852,6 +874,17 @@ label.error { .openerp table.oe_frame { color: #4c4c4c; } +.openerp fieldset.oe_group_box { + border: 1px solid #AAAAAA; + moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + background: #F9F9F9; + padding: 4px; +} +.openerp fieldset.oe_group_box legend { + font-weight: bold; +} .openerp td.oe_form_frame_cell { padding: 2px; position: relative; @@ -875,6 +908,22 @@ label.error { .openerp label.oe_label_help { cursor: help; } +.openerp #tiptip_content { + font-size: 12px; +} +.openerp .oe_tooltip_string { + color: #FD5; + font-weight: bold; + font-size: 13px; +} +.openerp .oe_tooltip_technical { + padding: 0 0 4px 0; + margin: 5px 0 0 15px; + list-style: circle; +} +.openerp .oe_tooltip_technical_title { + font-weight: bold; +} .openerp .oe_forms label.oe_label, .openerp .oe_forms label.oe_label_help { margin: 3px 0 0 10px; diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index 0b49e1cc52d..369e1191665 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -993,7 +993,7 @@ openerp.web.TranslationDataBase = openerp.web.Class.extend(/** @lends openerp.we this.parameters = {"direction": 'ltr', "date_format": '%m/%d/%Y', "time_format": '%H:%M:%S', - "grouping": "[]", + "grouping": [], "decimal_point": ".", "thousands_sep": ","}; }, @@ -1009,6 +1009,8 @@ openerp.web.TranslationDataBase = openerp.web.Class.extend(/** @lends openerp.we }); if (translation_bundle.lang_parameters) { this.parameters = translation_bundle.lang_parameters; + this.parameters.grouping = py.eval( + this.parameters.grouping).toJSON(); } }, add_module_translation: function(mod) { diff --git a/addons/web/static/src/js/data_import.js b/addons/web/static/src/js/data_import.js index 355c6c1b493..d5e789ce3e7 100644 --- a/addons/web/static/src/js/data_import.js +++ b/addons/web/static/src/js/data_import.js @@ -70,8 +70,8 @@ openerp.web.DataImport = openerp.web.Dialog.extend({ height: 'auto', position: 'top', buttons: [ - {text: "Close", click: function() { self.stop(); }}, - {text: "Import File", click: function() { self.do_import(); }, 'class': 'oe-dialog-import-button'} + {text: _t("Close"), click: function() { self.stop(); }}, + {text: _t("Import File"), click: function() { self.do_import(); }, 'class': 'oe-dialog-import-button'} ], close: function(event, ui) { self.stop(); diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js index d5fcdd35b62..c4af2d0cf6b 100644 --- a/addons/web/static/src/js/formats.js +++ b/addons/web/static/src/js/formats.js @@ -1,7 +1,67 @@ openerp.web.formats = function(openerp) { +var _t = openerp.web._t; /** + * Intersperses ``separator`` in ``str`` at the positions indicated by + * ``indices``. + * + * ``indices`` is an array of relative offsets (from the previous insertion + * position, starting from the end of the string) at which to insert + * ``separator``. + * + * There are two special values: + * + * ``-1`` + * indicates the insertion should end now + * ``0`` + * indicates that the previous section pattern should be repeated (until all + * of ``str`` is consumed) + * + * @param {String} str + * @param {Array<Number>} indices + * @param {String} separator + * @returns {String} + */ +openerp.web.intersperse = function (str, indices, separator) { + separator = separator || ''; + var result = [], last = str.length; + + for(var i=0; i<indices.length; ++i) { + var section = indices[i]; + if (section === -1 || last <= 0) { + // Done with string, or -1 (stops formatting string) + break; + } else if(section === 0 && i === 0) { + // repeats previous section, which there is none => stop + break; + } else if (section === 0) { + // repeat previous section forever + //noinspection AssignmentToForLoopParameterJS + section = indices[--i]; + } + result.push(str.substring(last-section, last)); + last -= section; + } + + var s = str.substring(0, last); + if (s) { result.push(s); } + return result.reverse().join(separator); +}; +/** + * Insert "thousands" separators in the provided number (which is actually + * a string) + * + * @param {String} num + * @returns {String} + */ +openerp.web.insert_thousand_seps = function (num) { + var negative = num[0] === '-'; + num = (negative ? num.slice(1) : num); + return (negative ? '-' : '') + openerp.web.intersperse( + num, _t.database.parameters.grouping, _t.database.parameters.thousands_sep); +}; +/** * Formats a single atomic value based on a field descriptor * * @param {Object} value read from OpenERP @@ -22,13 +82,16 @@ openerp.web.format_value = function (value, descriptor, value_if_empty) { case -Infinity: return value_if_empty === undefined ? '' : value_if_empty; } + var l10n = _t.database.parameters; switch (descriptor.widget || descriptor.type) { case 'integer': - return _.sprintf('%d', value); + return openerp.web.insert_thousand_seps( + _.sprintf('%d', value)); case 'float': var precision = descriptor.digits ? descriptor.digits[1] : 2; - return _.sprintf('%.' + precision + 'f', value) - .replace('.', openerp.web._t.database.parameters.decimal_point); + var formatted = _.sprintf('%.' + precision + 'f', value).split('.'); + formatted[0] = openerp.web.insert_thousand_seps(formatted[0]); + return formatted.join(l10n.decimal_point); case 'float_time': return _.sprintf("%02d:%02d", Math.floor(value), @@ -43,29 +106,17 @@ openerp.web.format_value = function (value, descriptor, value_if_empty) { case 'datetime': if (typeof(value) == "string") value = openerp.web.auto_str_to_date(value); - try { - return value.toString(_.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate, - Date.CultureInfo.formatPatterns.longTime)); - } catch (e) { - return value.format("%m/%d/%Y %H:%M:%S"); - } - return value; + + return value.format(l10n.date_format + + ' ' + l10n.time_format); case 'date': if (typeof(value) == "string") value = openerp.web.auto_str_to_date(value); - try { - return value.toString(Date.CultureInfo.formatPatterns.shortDate); - } catch (e) { - return value.format("%m/%d/%Y"); - } + return value.format(l10n.date_format); case 'time': if (typeof(value) == "string") value = openerp.web.auto_str_to_date(value); - try { - return value.toString(Date.CultureInfo.formatPatterns.longTime); - } catch (e) { - return value.format("%H:%M:%S"); - } + return value.format(l10n.time_format); case 'selection': // Each choice is [value, label] var result = _(descriptor.selection).detect(function (choice) { @@ -79,6 +130,8 @@ openerp.web.format_value = function (value, descriptor, value_if_empty) { }; openerp.web.parse_value = function (value, descriptor, value_if_empty) { + var date_pattern = Date.normalizeFormat(_t.database.parameters.date_format), + time_pattern = Date.normalizeFormat(_t.database.parameters.time_format); switch (value) { case false: case "": @@ -119,8 +172,8 @@ openerp.web.parse_value = function (value, descriptor, value_if_empty) { case 'progressbar': return openerp.web.parse_value(value, {type: "float"}); case 'datetime': - var datetime = Date.parseExact(value, _.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate, - Date.CultureInfo.formatPatterns.longTime)); + var datetime = Date.parseExact( + value, (date_pattern + ' ' + time_pattern)); if (datetime !== null) return openerp.web.datetime_to_str(datetime); datetime = Date.parse(value); @@ -128,7 +181,7 @@ openerp.web.parse_value = function (value, descriptor, value_if_empty) { return openerp.web.datetime_to_str(datetime); throw new Error(value + " is not a valid datetime"); case 'date': - var date = Date.parseExact(value, Date.CultureInfo.formatPatterns.shortDate); + var date = Date.parseExact(value, date_pattern); if (date !== null) return openerp.web.date_to_str(date); date = Date.parse(value); @@ -136,7 +189,7 @@ openerp.web.parse_value = function (value, descriptor, value_if_empty) { return openerp.web.date_to_str(date); throw new Error(value + " is not a valid date"); case 'time': - var time = Date.parseExact(value, Date.CultureInfo.formatPatterns.longTime); + var time = Date.parseExact(value, time_pattern); if (time !== null) return openerp.web.time_to_str(time); time = Date.parse(value); diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 0ceab43f1fd..4fb5f02c690 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -1,5 +1,6 @@ openerp.web.search = function(openerp) { -var QWeb = openerp.web.qweb; +var QWeb = openerp.web.qweb, + _t = openerp.web._t; openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.SearchView# */{ template: "EmptyComponent", @@ -134,6 +135,12 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search } }, on_loaded: function(data) { + if (data.fields_view.type !== 'search' || + data.fields_view.arch.tag !== 'search') { + throw new Error(_.sprintf( + "Got non-search view after asking for a search view: type %s, arch root %s", + data.fields_view.type, data.fields_view.arch.tag)); + } var self = this, lines = this.make_widgets( data.fields_view['arch'].children, @@ -211,12 +218,12 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search var $dial = $(dial_html); $dial.dialog({ modal: true, - title: "Filter Entry", - buttons: { - Cancel: function() { + title: _t("Filter Entry"), + buttons: [ + {text: _t("Cancel"), click: function() { $(this).dialog("close"); - }, - OK: function() { + }}, + {text: _t("OK"), click: function() { $(this).dialog("close"); var name = $(this).find("input").val(); self.rpc('/web/searchview/save_filter', { @@ -227,8 +234,8 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search }).then(function() { self.reload_managed_filters(); }); - } - } + }} + ] }); } else { // manage_filters select.val("_filters"); @@ -337,7 +344,7 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search * @param {Array} errors a never-empty array of error objects */ on_invalid: function (errors) { - this.do_notify("Invalid Search", "triggered from search view"); + this.do_notify(_t("Invalid Search"), _t("triggered from search view")); }, do_clear: function () { this.$element.find('.filter_label, .filter_icon').removeClass('enabled'); @@ -349,7 +356,7 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search this.$element.find('table:last').hide(); $('.searchview_extended_groups_list').empty(); - setTimeout(this.on_clear); + setTimeout(this.on_clear, 0); }, /** * Triggered when the search view gets cleared @@ -418,8 +425,10 @@ openerp.web.search.Invalid = openerp.web.Class.extend( /** @lends openerp.web.se this.message = message; }, toString: function () { - return ('Incorrect value for field ' + this.field + - ': [' + this.value + '] is ' + this.message); + return _.sprintf( + _t("Incorrect value for field %(fieldname)s: [%(value)s] is %(message)s"), + {fieldname: this.field, value: this.value, message: this.message} + ); } }); openerp.web.search.Widget = openerp.web.Widget.extend( /** @lends openerp.web.search.Widget# */{ @@ -738,7 +747,7 @@ openerp.web.search.NumberField = openerp.web.search.Field.extend(/** @lends open * @extends openerp.web.search.NumberField */ openerp.web.search.IntegerField = openerp.web.search.NumberField.extend(/** @lends openerp.web.search.IntegerField# */{ - error_message: "not a valid integer", + error_message: _t("not a valid integer"), parse: function (value) { try { return openerp.web.parse_value(value, {'widget': 'integer'}); @@ -752,7 +761,7 @@ openerp.web.search.IntegerField = openerp.web.search.NumberField.extend(/** @len * @extends openerp.web.search.NumberField */ openerp.web.search.FloatField = openerp.web.search.NumberField.extend(/** @lends openerp.web.search.FloatField# */{ - error_message: "not a valid number", + error_message: _t("not a valid number"), parse: function (value) { try { return openerp.web.parse_value(value, {'widget': 'float'}); @@ -969,6 +978,12 @@ openerp.web.search.ExtendedSearch = openerp.web.OldWidget.extend({ this.rpc("/web/searchview/fields_get", {"model": this.model}, function(data) { self.fields = data.fields; + if (!('id' in self.fields)) { + self.fields.id = { + string: 'ID', + type: 'id' + } + } openerp.web.search.add_expand_listener(self.$element); self.$element.find('.searchview_extended_add_group').click(function (e) { self.add_group(); @@ -1153,73 +1168,78 @@ openerp.web.search.ExtendedSearchProposition = openerp.web.OldWidget.extend(/** } }); -openerp.web.search.ExtendedSearchProposition.Char = openerp.web.OldWidget.extend({ +openerp.web.search.ExtendedSearchProposition.Field = openerp.web.OldWidget.extend({ + start: function () { + this.$element = $("#" + this.element_id); + } +}); +openerp.web.search.ExtendedSearchProposition.Char = openerp.web.search.ExtendedSearchProposition.Field.extend({ template: 'SearchView.extended_search.proposition.char', identifier_prefix: 'extended-search-proposition-char', operators: [ - {value: "ilike", text: "contains"}, - {value: "not ilike", text: "doesn't contain"}, - {value: "=", text: "is equal to"}, - {value: "!=", text: "is not equal to"}, - {value: ">", text: "greater than"}, - {value: "<", text: "less than"}, - {value: ">=", text: "greater or equal than"}, - {value: "<=", text: "less or equal than"} + {value: "ilike", text: _t("contains")}, + {value: "not ilike", text: _t("doesn't contain")}, + {value: "=", text: _t("is equal to")}, + {value: "!=", text: _t("is not equal to")}, + {value: ">", text: _t("greater than")}, + {value: "<", text: _t("less than")}, + {value: ">=", text: _t("greater or equal than")}, + {value: "<=", text: _t("less or equal than")} ], get_value: function() { return this.$element.val(); } }); -openerp.web.search.ExtendedSearchProposition.DateTime = openerp.web.OldWidget.extend({ +openerp.web.search.ExtendedSearchProposition.DateTime = openerp.web.search.ExtendedSearchProposition.Field.extend({ template: 'SearchView.extended_search.proposition.empty', identifier_prefix: 'extended-search-proposition-datetime', operators: [ - {value: "=", text: "is equal to"}, - {value: "!=", text: "is not equal to"}, - {value: ">", text: "greater than"}, - {value: "<", text: "less than"}, - {value: ">=", text: "greater or equal than"}, - {value: "<=", text: "less or equal than"} + {value: "=", text: _t("is equal to")}, + {value: "!=", text: _t("is not equal to")}, + {value: ">", text: _t("greater than")}, + {value: "<", text: _t("less than")}, + {value: ">=", text: _t("greater or equal than")}, + {value: "<=", text: _t("less or equal than")} ], get_value: function() { return this.datewidget.get_value(); }, start: function() { - this.$element = $("#" + this.element_id); + this._super(); this.datewidget = new openerp.web.DateTimeWidget(this); this.datewidget.prependTo(this.$element); } }); -openerp.web.search.ExtendedSearchProposition.Date = openerp.web.OldWidget.extend({ +openerp.web.search.ExtendedSearchProposition.Date = openerp.web.search.ExtendedSearchProposition.Field.extend({ template: 'SearchView.extended_search.proposition.empty', identifier_prefix: 'extended-search-proposition-date', operators: [ - {value: "=", text: "is equal to"}, - {value: "!=", text: "is not equal to"}, - {value: ">", text: "greater than"}, - {value: "<", text: "less than"}, - {value: ">=", text: "greater or equal than"}, - {value: "<=", text: "less or equal than"} + {value: "=", text: _t("is equal to")}, + {value: "!=", text: _t("is not equal to")}, + {value: ">", text: _t("greater than")}, + {value: "<", text: _t("less than")}, + {value: ">=", text: _t("greater or equal than")}, + {value: "<=", text: _t("less or equal than")} ], get_value: function() { return this.datewidget.get_value(); }, start: function() { - this.$element = $("#" + this.element_id); + this._super(); this.datewidget = new openerp.web.DateWidget(this); this.datewidget.prependTo(this.$element); } }); -openerp.web.search.ExtendedSearchProposition.Integer = openerp.web.OldWidget.extend({ +openerp.web.search.ExtendedSearchProposition.Integer = openerp.web.search.ExtendedSearchProposition.Field.extend({ template: 'SearchView.extended_search.proposition.integer', identifier_prefix: 'extended-search-proposition-integer', operators: [ - {value: "=", text: "is equal to"}, - {value: "!=", text: "is not equal to"}, - {value: ">", text: "greater than"}, - {value: "<", text: "less than"}, - {value: ">=", text: "greater or equal than"}, - {value: "<=", text: "less or equal than"} + {value: "=", text: _t("is equal to")}, + {value: "!=", text: _t("is not equal to")}, + {value: ">", text: _t("greater than")}, + {value: "<", text: _t("less than")}, + {value: ">=", text: _t("greater or equal than")}, + {value: "<=", text: _t("less or equal than")} ], get_value: function() { try { @@ -1229,16 +1249,19 @@ openerp.web.search.ExtendedSearchProposition.Integer = openerp.web.OldWidget.ext } } }); -openerp.web.search.ExtendedSearchProposition.Float = openerp.web.OldWidget.extend({ +openerp.web.search.ExtendedSearchProposition.Id = openerp.web.search.ExtendedSearchProposition.Integer.extend({ + operators: [{value: "=", text: _t("is")}] +}); +openerp.web.search.ExtendedSearchProposition.Float = openerp.web.search.ExtendedSearchProposition.Field.extend({ template: 'SearchView.extended_search.proposition.float', identifier_prefix: 'extended-search-proposition-float', operators: [ - {value: "=", text: "is equal to"}, - {value: "!=", text: "is not equal to"}, - {value: ">", text: "greater than"}, - {value: "<", text: "less than"}, - {value: ">=", text: "greater or equal than"}, - {value: "<=", text: "less or equal than"} + {value: "=", text: _t("is equal to")}, + {value: "!=", text: _t("is not equal to")}, + {value: ">", text: _t("greater than")}, + {value: "<", text: _t("less than")}, + {value: ">=", text: _t("greater or equal than")}, + {value: "<=", text: _t("less or equal than")} ], get_value: function() { try { @@ -1248,12 +1271,12 @@ openerp.web.search.ExtendedSearchProposition.Float = openerp.web.OldWidget.exten } } }); -openerp.web.search.ExtendedSearchProposition.Selection = openerp.web.OldWidget.extend({ +openerp.web.search.ExtendedSearchProposition.Selection = openerp.web.search.ExtendedSearchProposition.Field.extend({ template: 'SearchView.extended_search.proposition.selection', identifier_prefix: 'extended-search-proposition-selection', operators: [ - {value: "=", text: "is"}, - {value: "!=", text: "is not"} + {value: "=", text: _t("is")}, + {value: "!=", text: _t("is not")} ], set_field: function(field) { this.field = field; @@ -1262,12 +1285,12 @@ openerp.web.search.ExtendedSearchProposition.Selection = openerp.web.OldWidget.e return this.$element.val(); } }); -openerp.web.search.ExtendedSearchProposition.Boolean = openerp.web.OldWidget.extend({ +openerp.web.search.ExtendedSearchProposition.Boolean = openerp.web.search.ExtendedSearchProposition.Field.extend({ template: 'SearchView.extended_search.proposition.boolean', identifier_prefix: 'extended-search-proposition-boolean', operators: [ - {value: "=", text: "is true"}, - {value: "!=", text: "is false"} + {value: "=", text: _t("is true")}, + {value: "!=", text: _t("is false")} ], get_value: function() { return true; @@ -1286,7 +1309,9 @@ openerp.web.search.custom_filters = new openerp.web.Registry({ 'integer': 'openerp.web.search.ExtendedSearchProposition.Integer', 'float': 'openerp.web.search.ExtendedSearchProposition.Float', 'boolean': 'openerp.web.search.ExtendedSearchProposition.Boolean', - 'selection': 'openerp.web.search.ExtendedSearchProposition.Selection' + 'selection': 'openerp.web.search.ExtendedSearchProposition.Selection', + + 'id': 'openerp.web.search.ExtendedSearchProposition.Id' }); }; diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 53d7eeb60fb..84041ef8b60 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -776,6 +776,25 @@ openerp.web.form.Widget = openerp.web.Widget.extend(/** @lends openerp.web.form. var template = this.template; return QWeb.render(template, { "widget": this }); }, + do_attach_tooltip: function(widget, trigger, options) { + widget = widget || this; + trigger = trigger || this.$element; + options = _.extend({ + delay: 1000, + maxWidth: openerp.connection.debug ? '300px' : '200px', + content: function() { + var template = widget.template + '.tooltip'; + if (!QWeb.has_template(template)) { + template = 'WidgetLabel.tooltip'; + } + return QWeb.render(template, { + debug: openerp.connection.debug, + widget: widget + }); + } + }, options || {}); + trigger.tipTip(options); + }, _build_view_fields_values: function() { var a_dataset = this.view.dataset; var fields_values = this.view.get_fields_values(); @@ -916,6 +935,10 @@ openerp.web.form.WidgetFrame = openerp.web.form.Widget.extend({ } }); +openerp.web.form.WidgetGroup = openerp.web.form.WidgetFrame.extend({ + template: 'WidgetGroup', +}), + openerp.web.form.WidgetNotebook = openerp.web.form.Widget.extend({ template: 'WidgetNotebook', init: function(view, node) { @@ -944,6 +967,11 @@ openerp.web.form.WidgetNotebook = openerp.web.form.Widget.extend({ }); this.$element.tabs(); this.view.on_button_new.add_first(this.do_select_first_visible_tab); + if (openerp.connection.debug) { + this.do_attach_tooltip(this, this.$element.find('ul:first'), { + defaultPosition: 'top' + }); + } }, do_select_first_visible_tab: function() { for (var i = 0; i < this.pages.length; i++) { @@ -1007,6 +1035,9 @@ openerp.web.form.WidgetButton = openerp.web.form.Widget.extend({ start: function() { this._super.apply(this, arguments); this.$element.find("button").click(this.on_click); + if (this.help || openerp.connection.debug) { + this.do_attach_tooltip(); + } }, on_click: function() { var self = this; @@ -1106,6 +1137,9 @@ openerp.web.form.WidgetLabel = openerp.web.form.Widget.extend({ start: function() { this._super(); var self = this; + if (this['for'] && (this['for'].help || openerp.connection.debug)) { + this.do_attach_tooltip(self['for']); + } this.$element.find("label").dblclick(function() { var widget = self['for'] || self; openerp.log(widget.element_class , widget); @@ -1151,6 +1185,11 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f this.view.translatable_fields.push(this); this.$element.find('.oe_field_translate').click(this.on_translate); } + if (this.nolabel && openerp.connection.debug) { + this.do_attach_tooltip(this, this.$element, { + defaultPosition: 'top' + }); + } }, set_value: function(value) { this.value = value; @@ -3083,7 +3122,7 @@ openerp.web.form.FieldMany2OneReadonly = openerp.web.form.FieldURIReadonly.exten */ openerp.web.form.widgets = new openerp.web.Registry({ 'frame' : 'openerp.web.form.WidgetFrame', - 'group' : 'openerp.web.form.WidgetFrame', + 'group' : 'openerp.web.form.WidgetGroup', 'notebook' : 'openerp.web.form.WidgetNotebook', 'notebookpage' : 'openerp.web.form.WidgetNotebookPage', 'separator' : 'openerp.web.form.WidgetSeparator', diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 207d12a64e1..77f04d4c864 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -365,6 +365,9 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# return {}; } var aggregation_func = column['group_operator'] || 'sum'; + if (!(aggregation_func in column)) { + return {}; + } return _.extend({}, column, { 'function': aggregation_func, @@ -873,15 +876,20 @@ openerp.web.ListView.List = openerp.web.Class.extend( /** @lends openerp.web.Lis } var cells = []; if (this.options.selectable) { - cells.push('<td title="selection"></td>'); + cells.push('<th class="oe-record-selector"></td>'); } _(this.columns).each(function(column) { - if (column.invisible !== '1') { + if (column.invisible === '1') { + return; + } + if (column.tag === 'button') { + cells.push('<td class="oe-button" title="' + column.string + '"> </td>'); + } else { cells.push('<td title="' + column.string + '"> </td>'); } }); if (this.options.deletable) { - cells.push('<td><button type="button" style="visibility: hidden"> </button></td>'); + cells.push('<td class="oe-record-delete"><button type="button" style="visibility: hidden"> </button></td>'); } cells.unshift('<tr>'); cells.push('</tr>'); diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index e1986fd26a8..efa5ac5b2a8 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -568,35 +568,26 @@ session.web.Sidebar = session.web.Widget.extend({ self.do_toggle(); }); }, - - call_default_on_sidebar: function(item) { - var func_name = 'on_sidebar_' + _.underscored(item.label); - var fn = this.widget_parent[func_name]; - if(typeof fn === 'function') { - fn(item); - } - }, - add_default_sections: function() { if (this.session.uid === 1) { this.add_section(_t('Customize'), 'customize'); this.add_items('customize', [ { label: _t("Manage Views"), - callback: this.call_default_on_sidebar, + callback: this.widget_parent.on_sidebar_manage_views, title: _t("Manage views of the current object") }, { label: _t("Edit Workflow"), - callback: this.call_default_on_sidebar, + callback: this.widget_parent.on_sidebar_edit_workflow, title: _t("Manage views of the current object"), classname: 'oe_hide oe_sidebar_edit_workflow' }, { label: _t("Customize Object"), - callback: this.call_default_on_sidebar, + callback: this.widget_parent.on_sidebar_customize_object, title: _t("Manage views of the current object") }, { label: _t("Translate"), - callback: this.call_default_on_sidebar, + callback: this.widget_parent.on_sidebar_translate, title: _t("Technical translation") } ]); @@ -606,13 +597,13 @@ session.web.Sidebar = session.web.Widget.extend({ this.add_items('other', [ { label: _t("Import"), - callback: this.call_default_on_sidebar + callback: this.widget_parent.on_sidebar_import }, { label: _t("Export"), - callback: this.call_default_on_sidebar + callback: this.widget_parent.on_sidebar_export }, { label: _t("View Log"), - callback: this.call_default_on_sidebar, + callback: this.widget_parent.on_sidebar_view_log, classname: 'oe_hide oe_sidebar_view_log' } ]); @@ -682,34 +673,17 @@ session.web.Sidebar = session.web.Widget.extend({ item.callback.apply(self, [item]); } if (item.action) { - var ids = self.widget_parent.get_selected_ids(); - if (ids.length == 0) { - //TODO: make prettier warning? - $("<div />").text(_t("You must choose at least one record.")).dialog({ - title: _t("Warning"), - modal: true + if (self.widget_parent instanceof session.web.FormView) { + self.widget_parent.do_save(function() { + self.on_item_action_clicked(item); }); - return false; + } else { + self.on_item_action_clicked(item); } - var additional_context = { - active_id: ids[0], - active_ids: ids, - active_model: self.widget_parent.dataset.model - }; - self.rpc("/web/action/load", { - action_id: item.action.id, - context: additional_context - }, function(result) { - result.result.context = _.extend(result.result.context || {}, - additional_context); - result.result.flags = result.result.flags || {}; - result.result.flags.new_window = true; - self.do_action(result.result); - }); } return false; }); - + var $ul = $section.find('ul'); if(!$ul.length) { $ul = $('<ul/>').appendTo($section); @@ -717,6 +691,33 @@ session.web.Sidebar = session.web.Widget.extend({ $items.appendTo($ul); } }, + on_item_action_clicked: function(item) { + var self = this; + var ids = self.widget_parent.get_selected_ids(); + if (ids.length == 0) { + //TODO: make prettier warning? + $("<div />").text(_t("You must choose at least one record.")).dialog({ + title: _t("Warning"), + modal: true + }); + return false; + } + var additional_context = { + active_id: ids[0], + active_ids: ids, + active_model: self.widget_parent.dataset.model + }; + self.rpc("/web/action/load", { + action_id: item.action.id, + context: additional_context + }, function(result) { + result.result.context = _.extend(result.result.context || {}, + additional_context); + result.result.flags = result.result.flags || {}; + result.result.flags.new_window = true; + self.do_action(result.result); + }); + }, do_fold: function() { this.$element.addClass('closed-sidebar').removeClass('open-sidebar'); }, diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 0c27eee70b4..9b1c5175571 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -629,7 +629,8 @@ <t t-foreach="columns" t-as="column"> <t t-set="align" t-value="column.type === 'integer' or column.type == 'float'"/> <td t-if="!column.meta and column.invisible !== '1'" t-att-title="column.help" - t-att-class="'oe-field-cell' + (align ? ' oe-number' : '')" + t-att-class="'oe-field-cell' + (align ? ' oe-number' : '') + + (column.tag === 'button' ? ' oe-button' : '')" t-att-data-field="column.id"> <t t-raw="render_cell(record, column)"/> </td> @@ -720,6 +721,17 @@ </tr> </table> </t> +<t t-name="WidgetGroup"> + <t t-if="widget.string"> + <fieldset class="oe_group_box"> + <legend><t t-esc="widget.string"/></legend> + <t t-call="WidgetFrame"/> + </fieldset> + </t> + <t t-if="!widget.string"> + <t t-call="WidgetFrame"/> + </t> +</t> <t t-name="WidgetNotebook"> <ul> <li t-foreach="widget.pages" t-as="page"> @@ -732,6 +744,19 @@ <t t-raw="page.render()"/> </t> </t> +<t t-name="WidgetNotebook.tooltip"> + <t t-foreach="widget.pages" t-as="page"> + <div class="oe_tooltip_string"> + Notebook Page "<t t-esc="page.string"/>" + </div> + <ul class="oe_tooltip_technical"> + <li data-item="modifiers"> + <span class="oe_tooltip_technical_title">Modifiers:</span> + <t t-esc="page.node.attrs.modifiers"/> + </li> + </ul> + </t> +</t> <t t-name="WidgetNotebookPage"> <div> <t t-call="WidgetFrame"/> @@ -744,13 +769,72 @@ </t> <t t-name="WidgetLabel"> <label t-att-for="widget.element_id" - t-attf-class="oe_label#{widget.help ? '_help' : ''} oe_align_#{widget.align}" - t-att-title="widget.help"> + t-attf-class="oe_label#{widget.help ? '_help' : ''} oe_align_#{widget.align}"> <t t-esc="widget.string"/> <span t-if="widget.help">?</span> <t t-if="widget.string and widget.node.tag != 'label'">:</t> </label> </t> +<t t-name="WidgetLabel.tooltip"> + <div class="oe_tooltip_string" t-if="widget.string"> + <t t-esc="widget.string"/> <t t-if="debug and widget.nolabel">(nolabel)</t> + </div> + <p t-if="widget.help" class="oe_tooltip_help"> + <t t-esc="widget.help"/> + </p> + <ul t-if="debug" class="oe_tooltip_technical"> + <li data-item="field" t-if="widget.name"> + <span class="oe_tooltip_technical_title">Field:</span> + <t t-esc="widget.name"/> + </li> + <li data-item="object" t-if="widget.view and widget.view.fields_view"> + <span class="oe_tooltip_technical_title">Object:</span> + <t t-esc="widget.view.fields_view.model"/> + </li> + <li data-item="type" t-if="widget.field"> + <span class="oe_tooltip_technical_title">Type:</span> + <t t-esc="widget.field.type"/> + </li> + <li t-if="widget.node.attrs.widget" data-item="widget"> + <span class="oe_tooltip_technical_title">Widget:</span> + <t t-esc="widget.node.attrs.widget"/> + </li> + <li t-if="widget.node.attrs.size || (widget.field and widget.field.size)" data-item="size"> + <span class="oe_tooltip_technical_title">Size:</span> + <t t-esc="widget.node.attrs.size || widget.field.size"/> + </li> + <li t-if="widget.node.attrs.context" data-item="context"> + <span class="oe_tooltip_technical_title">Context:</span> + <t t-esc="widget.node.attrs.context_string"/> + </li> + <li t-if="widget.node.attrs.domain" data-item="domain"> + <span class="oe_tooltip_technical_title">Domain:</span> + <t t-esc="widget.node.attrs.domain_string"/> + </li> + <li t-if="widget.node.attrs.modifiers and widget.node.attrs.modifiers != '{}'" data-item="modifiers"> + <span class="oe_tooltip_technical_title">Modifiers:</span> + <t t-esc="widget.node.attrs.modifiers"/> + </li> + <li t-if="widget.node.attrs.on_change" data-item="on_change"> + <span class="oe_tooltip_technical_title">On change:</span> + <t t-esc="widget.node.attrs.on_change"/> + </li> + <li t-if="widget.field and widget.field.relation" data-item="relation"> + <span class="oe_tooltip_technical_title">Relation:</span> + <t t-esc="widget.field.relation"/> + </li> + <li t-if="widget.field and widget.field.selection" data-item="selection"> + <span class="oe_tooltip_technical_title">Selection:</span> + <ul> + <li t-foreach="widget.field.selection" t-as="option"> + [<t t-esc="option[0]"/>] + <t t-if="option[1]"> - </t> + <t t-esc="option[1]"/> + </li> + </ul> + </li> + </ul> +</t> <t t-name="WidgetParagraph"> <p t-attf-class="oe_form_paragraph oe_align_#{widget.align}"><t t-esc="widget.string"/></p> </t> @@ -758,7 +842,7 @@ <input t-att-type="widget.password ? 'password' : 'text'" size="1" t-att-name="widget.name" t-att-id="widget.element_id" - t-attf-class="field_#{widget.type}" + t-attf-class="field_#{widget.type} #{_(['integer', 'float', 'float_time']).contains(widget.type) ? 'oe-number' : ''}" t-attf-style="width: #{widget.field.translate ? '99' : '100'}%" /> <img class="oe_field_translate" t-if="widget.field.translate" src="/web/static/src/img/icons/terp-translate.png" width="16" height="16" border="0"/> @@ -766,7 +850,7 @@ <t t-name="FieldChar.readonly"> <div t-att-id="widget.element_id" - t-attf-class="field_#{widget.type}" + t-attf-class="field_#{widget.type} #{_(['integer', 'float', 'float_time']).contains(widget.type) ? 'oe-number' : ''}" t-attf-style="width: #{widget.field.translate ? '99' : '100'}%"> </div> </t> @@ -986,13 +1070,42 @@ </table> </t> <t t-name="WidgetButton"> - <button type="button" - t-att-title="widget.help" - style="width: 100%" class="button"> + <button type="button" style="width: 100%" class="button"> <img t-if="widget.node.attrs.icon" t-att-src="'/web/static/src/img/icons/' + widget.node.attrs.icon + '.png'" width="16" height="16"/> <span t-if="widget.string"><t t-esc="widget.string"/></span> </button> </t> +<t t-name="WidgetButton.tooltip" t-extend="WidgetLabel.tooltip"> + <t t-jquery="div.oe_tooltip_string" t-operation="replace"> + <div class="oe_tooltip_string" t-if="debug || widget.string"> + <t t-if="debug"> + Button + <t t-if="widget.string">: </t> + <t t-if="!widget.string"> (no string)</t> + </t> + <t t-esc="widget.string"/> + </div> + </t> + <t t-jquery="ul.oe_tooltip_technical" t-operation="append"> + <li t-if="widget.node.attrs.special" data-item="special"> + <span class="oe_tooltip_technical_title">Special:</span> + <t t-esc="widget.node.attrs.special"/> + </li> + <t t-set="button_type" t-value="widget.node.attrs.type"/> + <li t-if="button_type" data-item="button_type"> + <span class="oe_tooltip_technical_title">Button Type:</span> + <t t-esc="button_type"/> + </li> + <li t-if="button_type === 'object'" data-item="button_method"> + <span class="oe_tooltip_technical_title">Method:</span> + <t t-esc="widget.node.attrs.name"/> + </li> + <li t-if="button_type === 'action'" data-item="button_action"> + <span class="oe_tooltip_technical_title">Action ID:</span> + <t t-esc="widget.node.attrs.name"/> + </li> + </t> +</t> <t t-name="SearchView"> <form class="oe_forms"> |
