diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-01-12 19:13:10 +0100 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-01-12 19:13:10 +0100 |
| commit | 03a36a9bbadbf874837ff85692a1d8f1c13cc36d (patch) | |
| tree | b50823afe76b8300faf02962bcd265fb3a8b3e60 /addons/web/static/src/js | |
| parent | 2304edd46cc12aaef4fddaa22887ff51f51581bc (diff) | |
| parent | 56974322f8c67ec5680654ed4bcb08ca57117c46 (diff) | |
[MERGE] forward port branch saas-11.1 up to 56974322f8c
Diffstat (limited to 'addons/web/static/src/js')
| -rw-r--r-- | addons/web/static/src/js/core/utils.js | 18 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/abstract_field.js | 5 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/basic_fields.js | 21 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/field_registry.js | 1 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/field_utils.js | 10 | ||||
| -rw-r--r-- | addons/web/static/src/js/services/data_manager.js | 4 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/basic/basic_model.js | 45 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/form/form_renderer.js | 11 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/kanban/kanban_controller.js | 19 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/kanban/kanban_renderer.js | 12 |
10 files changed, 100 insertions, 46 deletions
diff --git a/addons/web/static/src/js/core/utils.js b/addons/web/static/src/js/core/utils.js index 99534708a94..1bdd9e70a69 100644 --- a/addons/web/static/src/js/core/utils.js +++ b/addons/web/static/src/js/core/utils.js @@ -24,6 +24,22 @@ var utils = { } }, /** + * Check if the value is a bin_size or not. + * If not, compute an approximate size out of the base64 encoded string. + * + * @param {string} value original format + * @return {string} bin_size (human-readable) + */ + binaryToBinsize: function (value) { + if (!this.is_bin_size(value)) { + // Computing approximate size out of base64 encoded string + // http://en.wikipedia.org/wiki/Base64#MIME + return this.human_size(value.length / 1.37); + } + // already bin_size + return value; + }, + /** * Confines a value inside an interval * * @param {number} [val] the value to confine @@ -132,7 +148,7 @@ var utils = { size /= 1024; ++i; } - return size.toFixed(2) + ' ' + units[i]; + return size.toFixed(2) + ' ' + units[i].trim(); }, /** * Insert "thousands" separators in the provided number (which is actually diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js index 2534f8ae90a..8bb9afca065 100644 --- a/addons/web/static/src/js/fields/abstract_field.js +++ b/addons/web/static/src/js/fields/abstract_field.js @@ -45,6 +45,11 @@ var AbstractField = Widget.extend({ }, /** + * fields can extend the context, e.g. binary fields add {bin_size: true} + */ + context: null, + + /** * An object representing fields to be fetched by the model eventhough not present in the view * This object contains "field name" as key and an object as value. * That value object must contain the key "type" diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index d0662fe7cef..f3e66cee421 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -1094,6 +1094,7 @@ var AbstractFieldBinary = AbstractField.extend({ }, 'click .o_clear_file_button': 'on_clear', }), + context: { bin_size: true }, init: function (parent, name, record) { this._super.apply(this, arguments); this.fields = record.fields; @@ -1312,25 +1313,6 @@ var FieldBinaryFile = AbstractFieldBinary.extend({ }, }); -var FieldBinaryDownloadLink = AbstractFieldBinary.extend({ - template: 'FieldBinaryDownloadLink', - events: _.extend({}, AbstractFieldBinary.prototype.events, { - 'click': function (ev) { - ev.stopPropagation(); - }, - }), - supportedFieldTypes: ['binary'], - init: function () { - this._super.apply(this, arguments); - this.filename = _t("Binary File"); - if (this.nodeOptions.filename && this.recordData[this.nodeOptions.filename]) { - this.filename = this.recordData[this.nodeOptions.filename]; - } - this.url = "data:application/octet-stream;base64," + this.value; - this.text = _t("Download"); - }, -}); - var PriorityWidget = AbstractField.extend({ // the current implementation of this widget makes it // only usable for fields of type selection @@ -2561,7 +2543,6 @@ return { TranslatableFieldMixin: TranslatableFieldMixin, DebouncedField: DebouncedField, FieldEmail: FieldEmail, - FieldBinaryDownloadLink: FieldBinaryDownloadLink, FieldBinaryFile: FieldBinaryFile, FieldBinaryImage: FieldBinaryImage, FieldBoolean: FieldBoolean, diff --git a/addons/web/static/src/js/fields/field_registry.js b/addons/web/static/src/js/fields/field_registry.js index 85b4fc1187f..6692663d5f9 100644 --- a/addons/web/static/src/js/fields/field_registry.js +++ b/addons/web/static/src/js/fields/field_registry.js @@ -33,7 +33,6 @@ registry .add('email', basic_fields.FieldEmail) .add('phone', basic_fields.FieldPhone) .add('url', basic_fields.UrlWidget) - .add('download_link', basic_fields.FieldBinaryDownloadLink) .add('image', basic_fields.FieldBinaryImage) .add('binary', basic_fields.FieldBinaryFile) .add('monetary', basic_fields.FieldMonetary) diff --git a/addons/web/static/src/js/fields/field_utils.js b/addons/web/static/src/js/fields/field_utils.js index 812a7f380f7..5ac180b1de1 100644 --- a/addons/web/static/src/js/fields/field_utils.js +++ b/addons/web/static/src/js/fields/field_utils.js @@ -28,17 +28,17 @@ var _t = core._t; //------------------------------------------------------------------------------ /** + * Convert binary to bin_size * - * @param {string} value base64 representation of the binary + * @param {string} value base64 representation of the binary (might be already a bin_size!) * @param {Object} [field] * a description of the field (note: this parameter is ignored) * @param {Object} [options] additional options (note: this parameter is ignored) + * + * @returns {string} bin_size (which is human-readable) */ function formatBinary(value, field, options) { - if (!value) { - return ''; - } - return utils.human_size(value.length / 1.37); // base64 estimated size: http://en.wikipedia.org/wiki/Base64#MIME + return utils.binaryToBinsize(value); } /** diff --git a/addons/web/static/src/js/services/data_manager.js b/addons/web/static/src/js/services/data_manager.js index 72ec816efdd..948d3a1c73a 100644 --- a/addons/web/static/src/js/services/data_manager.js +++ b/addons/web/static/src/js/services/data_manager.js @@ -387,6 +387,10 @@ return core.Class.extend({ attrs.fieldDependencies = attrs.Widget.prototype.fieldDependencies; } + if (attrs.Widget.prototype.context) { + attrs.context = attrs.Widget.prototype.context; + } + return attrs; }, /** diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index 3621b7c1227..a6979776c99 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -33,7 +33,7 @@ odoo.define('web.BasicModel', function (require) { * isOpen: {boolean}, * loadMoreOffset: {integer}, * limit: {integer}, - * model: {string, + * model: {string}, * offset: {integer}, * openGroupByDefault: {boolean}, * orderedBy: {Object[]}, @@ -1854,7 +1854,7 @@ var BasicModel = AbstractModel.extend({ model: record.model, method: 'read', args: [[record.res_id], fieldNames], - context: _.extend({}, record.getContext(), {bin_size: true}), + context: record.getContext(), }) .then(function (result) { if (result.length === 0) { @@ -2374,7 +2374,7 @@ var BasicModel = AbstractModel.extend({ }); record.data[fieldName] = list.id; if (!fieldInfo.__no_fetch) { - var def = self._readUngroupedList(list).then(function () { + var def = self._readUngroupedList(list).then(function (list) { return $.when( self._fetchX2ManysBatched(list), self._fetchReferencesBatched(list) @@ -3040,10 +3040,33 @@ var BasicModel = AbstractModel.extend({ * the resource in the localData object. * * @param {Object} params + * @param {Object} [params.aggregateValues={}] + * @param {Object} [params.context={}] context of the action + * @param {integer} [params.count=0] number of record being manipulated + * @param {Object|Object[]} [params.data={}|[]] data of the record + * @param {*[]} [params.domain=[]] + * @param {Object} params.fields contains the description of each field * @param {Object} [params.fieldsInfo={}] contains the fieldInfo of each field - * @param {Array} [params.fieldNames] the name of fields to load, the list + * @param {Object[]} [params.fieldNames] the name of fields to load, the list * of all fields by default - * @param {Object} params.fields contains the description of each field + * @param {string[]} [params.groupedBy=[]] + * @param {boolean} [params.isOpen] + * @param {integer} params.limit max number of records shown on screen (pager size) + * @param {string} params.modelName + * @param {integer} [params.offset] + * @param {boolean} [params.openGroupByDefault] + * @param {Object[]} [params.orderedBy=[]] + * @param {integer[]} [params.orderedResIDs] + * @param {string} [params.parentID] model name ID of the parent model + * @param {Object} [params.rawContext] + * @param {[type]} [params.ref] + * @param {string} [params.relationField] + * @param {integer|null} [params.res_id] actual id of record in the server + * @param {integer[]} [params.res_ids] context in which the data point is used, from a list of res_id + * @param {boolean} [params.static=false] + * @param {string} [params.type='record'|'list'] + * @param {[type]} [params.value] + * @param {string} [params.viewType] the type of the view, e.g. 'list' or 'form' * @returns {Object} the resource created */ _makeDataPoint: function (params) { @@ -3069,13 +3092,23 @@ var BasicModel = AbstractModel.extend({ id: {type: 'integer'}, }, params.fields); + // datapoint context is extended by fields widgets + var context = _.extend({}, params.context); + if (params.fieldsInfo && params.viewType) { + _.each(params.fieldsInfo[params.viewType], function (field) { + if (field.context) { + _.extend(context, field.context); + } + }); + } + var dataPoint = { _cache: type === 'list' ? {} : undefined, _changes: null, _domains: {}, _rawChanges: {}, aggregateValues: params.aggregateValues || {}, - context: params.context || {}, + context: context, count: params.count || res_ids.length, data: data, domain: params.domain || [], diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js index 9409a51b7e0..779121de3e9 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -693,6 +693,7 @@ var FormRenderer = BasicRenderer.extend({ var self = this; var $headers = $('<ul class="nav nav-tabs">'); var $pages = $('<div class="tab-content nav nav-tabs">'); + var autofocusTab = -1; // renderedTabs is used to aggregate the generated $headers and $pages // alongside their node, so that their modifiers can be registered once // all tabs have been rendered, to ensure that the first visible tab @@ -701,9 +702,8 @@ var FormRenderer = BasicRenderer.extend({ var pageID = _.uniqueId('notebook_page_'); var $header = self._renderTabHeader(child, pageID); var $page = self._renderTabPage(child, pageID); - if (index === 0) { - $header.addClass('active'); - $page.addClass('active'); + if (autofocusTab === -1 && child.attrs.autofocus === 'autofocus') { + autofocusTab = index; } self._handleAttributes($header, child); $headers.append($header); @@ -714,6 +714,11 @@ var FormRenderer = BasicRenderer.extend({ node: child, }; }); + if (renderedTabs.length) { + var tabToFocus = renderedTabs[Math.max(0, autofocusTab)]; + tabToFocus.$header.addClass('active'); + tabToFocus.$page.addClass('active'); + } // register the modifiers for each tab _.each(renderedTabs, function (tab) { self._registerModifiers(tab.node, self.state, tab.$header, { diff --git a/addons/web/static/src/js/views/kanban/kanban_controller.js b/addons/web/static/src/js/views/kanban/kanban_controller.js index 2f6f566649e..9e97ec40686 100644 --- a/addons/web/static/src/js/views/kanban/kanban_controller.js +++ b/addons/web/static/src/js/views/kanban/kanban_controller.js @@ -239,15 +239,16 @@ var KanbanController = BasicController.extend({ * @private */ _onButtonNew: function () { - var data = this.model.get(this.handle, {raw: true}); - if (data.groupedBy.length > 0 && data.count > 0 && this.on_create === 'quick_create') { + var state = this.model.get(this.handle, {raw: true}); + var hasColumns = state.groupedBy.length > 0 && state.data.length > 0; + if (hasColumns && this.on_create === 'quick_create') { // Activate the quick create in the first column this.renderer.addQuickCreate(); } else if (this.on_create && this.on_create !== 'quick_create') { // Execute the given action this.do_action(this.on_create, { on_close: this.reload.bind(this), - additional_context: data.context, + additional_context: state.context, }); } else { // Open the form view @@ -355,11 +356,13 @@ var KanbanController = BasicController.extend({ self._updateEnv(); var columnState = self.model.getColumn(db_id); - return self.renderer.updateColumn(columnState.id, columnState).then(function () { - if (event.data.openRecord) { - self.trigger_up('open_record', {id: db_id, mode: 'edit'}); - } - }); + return self.renderer + .updateColumn(columnState.id, columnState, {openQuickCreate: true}) + .then(function () { + if (event.data.openRecord) { + self.trigger_up('open_record', {id: db_id, mode: 'edit'}); + } + }); }); } }, diff --git a/addons/web/static/src/js/views/kanban/kanban_renderer.js b/addons/web/static/src/js/views/kanban/kanban_renderer.js index 0f91fb2ae14..e4e37095afa 100644 --- a/addons/web/static/src/js/views/kanban/kanban_renderer.js +++ b/addons/web/static/src/js/views/kanban/kanban_renderer.js @@ -141,15 +141,23 @@ var KanbanRenderer = BasicRenderer.extend({ * * @param {string} localID the column id * @param {Object} columnState + * @param {Object} [options] + * @param {boolean} [options.openQuickCreate] if true, directly opens the + * QuickCreate widget in the updated column * * @returns {Deferred} */ - updateColumn: function (localID, columnState) { + updateColumn: function (localID, columnState, options) { var newColumn = new KanbanColumn(this, columnState, this.columnOptions, this.recordOptions); var index = _.findIndex(this.widgets, {db_id: localID}); var column = this.widgets[index]; this.widgets[index] = newColumn; - return newColumn.insertAfter(column.$el).then(column.destroy.bind(column)); + return newColumn.insertAfter(column.$el).then(function () { + if (options && options.openQuickCreate) { + newColumn.addQuickCreate(); + } + column.destroy(); + }); }, /** * Updates a given record with its new state. |
