diff options
Diffstat (limited to 'addons/web/static/src/js/views')
9 files changed, 136 insertions, 73 deletions
diff --git a/addons/web/static/src/js/views/basic/basic_controller.js b/addons/web/static/src/js/views/basic/basic_controller.js index 7998a6ca8f1..05031ca2463 100644 --- a/addons/web/static/src/js/views/basic/basic_controller.js +++ b/addons/web/static/src/js/views/basic/basic_controller.js @@ -272,6 +272,13 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { * @returns {Deferred} */ _confirmChange: function (id, fields, e) { + if (e.name === 'discard_changes' && e.target.reset) { + // the target of the discard event is a field widget. In that + // case, we simply want to reset the specific field widget, + // not the full view + return e.target.reset(this.model.get(e.target.dataPointID), e, true); + } + var state = this.model.get(this.handle); return this.renderer.confirmChange(state, id, fields, e); }, 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 2ef65cbd1b6..3013cb32f85 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -198,6 +198,90 @@ var BasicModel = AbstractModel.extend({ }); }, /** + * Add and process default values for a given record. Those values are + * parsed and stored in the '_changes' key of the record. For relational + * fields, sub-dataPoints are created, and missing relational data is + * fetched. Also generate default values for fields with no given value. + * Typically, this function is called with the result of a 'default_get' + * RPC, to populate a newly created dataPoint. It may also be called when a + * one2many subrecord is open in a form view (dialog), to generate the + * default values for the fields displayed in the o2m form view, but not in + * the list or kanban (mainly to correctly create sub-dataPoints for + * relational fields). + * + * @param {string} recordID local id for a record + * @param {Object} values dict of default values for the given record + * @param {Object} [options] + * @param {string} [options.viewType] current viewType. If not set, we will + * assume main viewType from the record + * @param {Array} [options.fieldNames] list of field names for which a + * default value must be generated (used to complete the values dict) + * @returns {Deferred} + */ + applyDefaultValues: function (recordID, values, options) { + options = options || {}; + var record = this.localData[recordID]; + var viewType = options.viewType || record.viewType; + var fieldNames = options.fieldNames || Object.keys(record.fieldsInfo[viewType]); + var field; + var fieldName; + record._changes = record._changes || {}; + + // ignore values for non requested fields (for instance, fields that are + // not in the view) + values = _.pick(values, fieldNames); + + // fill default values for missing fields + for (var i = 0; i < fieldNames.length; i++) { + fieldName = fieldNames[i]; + if (!(fieldName in values) && !(fieldName in record._changes)) { + field = record.fields[fieldName]; + if (field.type === 'float' || + field.type === 'integer' || + field.type === 'monetary') { + values[fieldName] = 0; + } else if (field.type === 'one2many' || field.type === 'many2many') { + values[fieldName] = []; + } else { + values[fieldName] = null; + } + } + } + + // parse each value and create dataPoints for relational fields + var defs = []; + for (fieldName in values) { + field = record.fields[fieldName]; + record.data[fieldName] = null; + var dp; + if (field.type === 'many2one' && values[fieldName]) { + dp = this._makeDataPoint({ + context: record.context, + data: {id: values[fieldName]}, + modelName: field.relation, + parentID: record.id, + }); + record._changes[fieldName] = dp.id; + } else if (field.type === 'reference' && values[fieldName]) { + var ref = values[fieldName].split(','); + dp = this._makeDataPoint({ + context: record.context, + data: {id: parseInt(ref[1])}, + modelName: ref[0], + parentID: record.id, + }); + defs.push(this._fetchNameGet(dp)); + record._changes[fieldName] = dp.id; + } else if (field.type === 'one2many' || field.type === 'many2many') { + defs.push(this._processX2ManyCommands(record, fieldName, values[fieldName], options)); + } else { + record._changes[fieldName] = this._parseServerValue(field, values[fieldName]); + } + } + + return $.when.apply($, defs); + }, + /** * Onchange RPCs may return values for fields that are not in the current * view. Those fields might even be unknown when the onchange returns (e.g. * in x2manys, we only know the fields that are used in the inner view, but @@ -1414,6 +1498,7 @@ var BasicModel = AbstractModel.extend({ list = self._makeDataPoint({ fields: view ? view.fields : fieldInfo.relatedFields, fieldsInfo: view ? view.fieldsInfo : fieldInfo.fieldsInfo, + limit: fieldInfo.limit, modelName: field.relation, parentID: record.id, static: true, @@ -2980,7 +3065,7 @@ var BasicModel = AbstractModel.extend({ if (field.type === 'one2many' || field.type === 'many2many') { var ids; if (!context[fieldName] || _.isArray(context[fieldName])) { // no dataPoint created yet - ids = context[fieldName] || []; + ids = context[fieldName] ? context[fieldName].slice(0) : []; } else { relDataPoint = this._applyX2ManyOperations(this.localData[context[fieldName]]); ids = relDataPoint.res_ids.slice(0); @@ -3260,27 +3345,8 @@ var BasicModel = AbstractModel.extend({ context: params.context, }) .then(function (result) { - // fill default values for missing fields - for (var i = 0; i < fieldNames.length; i++) { - var fieldName = fieldNames[i]; - if (!(fieldName in result)) { - var field = params.fields[fieldName]; - if (field.type === 'float' || - field.type === 'integer' || - field.type === 'monetary') { - result[fieldName] = 0; - } else if (field.type === 'one2many' || field.type === 'many2many') { - result[fieldName] = []; - } else { - result[fieldName] = null; - } - } - } - - var data = {}; var record = self._makeDataPoint({ modelName: modelName, - data: data, fields: params.fields, fieldsInfo: params.fieldsInfo, context: params.context, @@ -3289,37 +3355,7 @@ var BasicModel = AbstractModel.extend({ viewType: params.viewType, }); - var defs = []; - _.each(fieldNames, function (name) { - var field = params.fields[name]; - data[name] = null; - record._changes = record._changes || {}; - var dp; - if (field.type === 'many2one' && result[name]) { - dp = self._makeDataPoint({ - context: record.context, - data: {id: result[name]}, - modelName: field.relation, - parentID: record.id, - }); - record._changes[name] = dp.id; - } else if (field.type === 'reference' && result[name]) { - var ref = result[name].split(','); - dp = self._makeDataPoint({ - context: record.context, - data: {id: parseInt(ref[1])}, - modelName: ref[0], - parentID: record.id, - }); - defs.push(self._fetchNameGet(dp)); - record._changes[name] = dp.id; - } else if (field.type === 'one2many' || field.type === 'many2many') { - defs.push(self._processX2ManyCommands(record, name, result[name])); - } else { - record._changes[name] = self._parseServerValue(field, result[name]); - } - }); - return $.when.apply($, defs) + return self.applyDefaultValues(record.id, result) .then(function () { var def = $.Deferred(); self._performOnChange(record, fields_key).always(function () { @@ -3502,13 +3538,17 @@ var BasicModel = AbstractModel.extend({ * @param {Object} record * @param {string} fieldName * @param {Array[Array]} commands + * @param {Object} [options] + * @param {string} [options.viewType] current viewType. If not set, we will + * assume main viewType from the record * @returns {Deferred} */ - _processX2ManyCommands: function (record, fieldName, commands) { + _processX2ManyCommands: function (record, fieldName, commands, options) { var self = this; + options = options || {}; var defs = []; var field = record.fields[fieldName]; - var fieldInfo = record.fieldsInfo[record.viewType][fieldName]; + var fieldInfo = record.fieldsInfo[options.viewType || record.viewType][fieldName]; var view = fieldInfo.views && fieldInfo.views[fieldInfo.mode]; var fieldsInfo = view ? view.fieldsInfo : fieldInfo.fieldsInfo; var fields = view ? view.fields : fieldInfo.relatedFields; @@ -3802,14 +3842,14 @@ var BasicModel = AbstractModel.extend({ // for multi-pages list datapoints, we might need to read the // order field first to apply the order on all pages - if (list.res_ids.length > list.limit) { - if (!list.orderedResIDs && list.orderedBy.length) { + if (list.res_ids.length > list.limit && list.orderedBy.length) { + if (!list.orderedResIDs) { var fieldNames = _.pluck(list.orderedBy, 'name'); def = this._readMissingFields(list, _.filter(list.res_ids, _.isNumber), fieldNames); - def.then(function () { - self._sortList(list); - }); } + def.then(function () { + self._sortList(list); + }); } return def.then(function () { var resIDs = []; diff --git a/addons/web/static/src/js/views/basic/basic_view.js b/addons/web/static/src/js/views/basic/basic_view.js index df9f9807bfd..b4df9c8e09e 100644 --- a/addons/web/static/src/js/views/basic/basic_view.js +++ b/addons/web/static/src/js/views/basic/basic_view.js @@ -45,7 +45,7 @@ var BasicView = AbstractView.extend({ this.rendererParams.viewType = this.viewType; this.controllerParams.confirmOnDelete = true; - this.controllerParams.archiveEnabled = 'active' in viewInfo.fields; + this.controllerParams.archiveEnabled = 'active' in this.fields; this.controllerParams.hasButtons = 'action_buttons' in params ? params.action_buttons : true; @@ -161,7 +161,12 @@ var BasicView = AbstractView.extend({ // (because those fields were unknow at that time). So we ask // the model to process them. def = this.model.applyRawChanges(record.id, viewType).then(function () { - if (!self.model.isNew(record.id)) { + if (self.model.isNew(record.id)) { + return self.model.applyDefaultValues(record.id, {}, { + fieldNames: fieldNames, + viewType: viewType, + }); + } else { return self.model.reload(record.id, { fieldNames: fieldNames, keepChanges: true, diff --git a/addons/web/static/src/js/views/calendar/calendar_controller.js b/addons/web/static/src/js/views/calendar/calendar_controller.js index 2755c4c39fd..d49c7c33f5c 100644 --- a/addons/web/static/src/js/views/calendar/calendar_controller.js +++ b/addons/web/static/src/js/views/calendar/calendar_controller.js @@ -183,7 +183,7 @@ var CalendarController = AbstractController.extend({ // When clicking on a random day of a random other week, switch to week view this.model.setScale('week'); } - this.model.setDate(event.data.date, true); + this.model.setDate(event.data.date); this.reload(); }, /** diff --git a/addons/web/static/src/js/views/calendar/calendar_model.js b/addons/web/static/src/js/views/calendar/calendar_model.js index ca28e90713f..5542ab06476 100644 --- a/addons/web/static/src/js/views/calendar/calendar_model.js +++ b/addons/web/static/src/js/views/calendar/calendar_model.js @@ -218,9 +218,9 @@ return AbstractModel.extend({ filters: params.filters, }; + this.setDate(params.initialDate); // Use mode attribute in xml file to specify zoom timeline (day,week,month) // by default month. - this.setDate(params.initialDate, true); this.setScale(params.mode); _.each(this.data.filters, function (filter) { @@ -260,9 +260,8 @@ return AbstractModel.extend({ }, /** * @param {Moment} start - * @param {boolean} highlight */ - setDate: function (start, highlight) { + setDate: function (start) { this.data.start_date = this.data.end_date = this.data.target_date = this.data.highlight_date = start; this.data.start_date.utc().add(this.getSession().getTZOffset(this.data.start_date), 'minutes'); @@ -279,9 +278,6 @@ return AbstractModel.extend({ this.data.start_date = this.data.start_date.clone().startOf('day'); this.data.end_date = this.data.end_date.clone().endOf('day'); } - if (highlight) { - this.data.highlight_date = this.data.target_date; - } }, /** * @param {string} scale the scale to set diff --git a/addons/web/static/src/js/views/calendar/calendar_renderer.js b/addons/web/static/src/js/views/calendar/calendar_renderer.js index 469130c723a..a8d5d07ed0d 100644 --- a/addons/web/static/src/js/views/calendar/calendar_renderer.js +++ b/addons/web/static/src/js/views/calendar/calendar_renderer.js @@ -467,11 +467,6 @@ return AbstractRenderer.extend({ this.target_date = this.state.target_date.toString(); } - var highlightDate = moment(this.state.highlight_date).format('YYYY-MM-DD'); - $calendar.find('.o_target_date').removeClass('o_target_date'); - $calendar.find('.fc-bg .fc-day[data-date="'+highlightDate+'"]') - .addClass('o_target_date'); - this.$small_calendar.datepicker("setDate", this.state.highlight_date.toDate()) .find('.o_selected_range') .removeClass('o_color o_selected_range'); diff --git a/addons/web/static/src/js/views/pivot/pivot_controller.js b/addons/web/static/src/js/views/pivot/pivot_controller.js index 731183e7efe..5f31c7103c7 100644 --- a/addons/web/static/src/js/views/pivot/pivot_controller.js +++ b/addons/web/static/src/js/views/pivot/pivot_controller.js @@ -126,6 +126,7 @@ var PivotController = AbstractController.extend({ var table = this.model.exportData(); if(table.measure_row.length + 1 > 256) { crash_manager.show_message(_t("For Excel compatibility, data cannot be exported if there are more than 256 columns.\n\nTip: try to flip axis, filter further or reduce the number of measures.")); + framework.unblockUI(); return; } framework.blockUI(); diff --git a/addons/web/static/src/js/views/pivot/pivot_model.js b/addons/web/static/src/js/views/pivot/pivot_model.js index 99a5e4ee334..1c76c41ab71 100644 --- a/addons/web/static/src/js/views/pivot/pivot_model.js +++ b/addons/web/static/src/js/views/pivot/pivot_model.js @@ -135,7 +135,7 @@ var PivotModel = AbstractModel.extend({ exportData: function () { var measureNbr = this.data.measures.length; var headers = this._computeHeaders(); - var measureRow = measureNbr > 1 ? _.last(headers) : []; + var measureRow = measureNbr >= 1 ? _.last(headers) : []; var rows = this._computeRows(); var i, j, value; headers[0].splice(0,1); diff --git a/addons/web/static/src/js/views/view_dialogs.js b/addons/web/static/src/js/views/view_dialogs.js index 4be84c23b71..1b74068d44d 100644 --- a/addons/web/static/src/js/views/view_dialogs.js +++ b/addons/web/static/src/js/views/view_dialogs.js @@ -260,6 +260,7 @@ var SelectCreateDialog = ViewDialog.extend({ var searchData = this._process_search_data(d.domains, d.contexts, d.groupbys); this.list_controller.reload(searchData); }, + get_controller_context: '_onGetControllerContext', }), /** @@ -416,6 +417,24 @@ var SelectCreateDialog = ViewDialog.extend({ dialog.on('closed', this, this.close); return dialog; }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * Handles a context request: provides to the caller the context of the + * list controller. + * + * @private + * @param {OdooEvent} ev + * @param {function} ev.data.callback used to send the requested context + */ + _onGetControllerContext: function (ev) { + ev.stopPropagation(); + var context = this.list_controller && this.list_controller.getContext(); + ev.data.callback(context || {}); + } }); return { |
