diff options
Diffstat (limited to 'addons/web/static/src/js')
| -rw-r--r-- | addons/web/static/src/js/core/ajax.js | 11 | ||||
| -rw-r--r-- | addons/web/static/src/js/core/session.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/basic_fields.js | 32 | ||||
| -rw-r--r-- | addons/web/static/src/js/report/qwebactionmanager.js | 7 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/basic/basic_model.js | 36 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/form/form_renderer.js | 8 |
6 files changed, 77 insertions, 19 deletions
diff --git a/addons/web/static/src/js/core/ajax.js b/addons/web/static/src/js/core/ajax.js index d69574d2e10..0ee6d2ad1ed 100644 --- a/addons/web/static/src/js/core/ajax.js +++ b/addons/web/static/src/js/core/ajax.js @@ -212,6 +212,9 @@ var loadJS = (function () { * @param {Function} [options.success] callback in case of download success * @param {Function} [options.error] callback in case of request error, provided with the error body * @param {Function} [options.complete] called after both ``success`` and ``error`` callbacks have executed + * @returns {boolean} a false value means that a popup window was blocked. This + * mean that we probably need to inform the user that something needs to be + * changed to make it work. */ function get_file(options) { // need to detect when the file is done downloading (not used @@ -232,7 +235,12 @@ function get_file(options) { var url = options.session.url(options.url, params); if (options.complete) { options.complete(); } - return window.open(url); + var w = window.open(url); + if (!w || w.closed || typeof w.closed === 'undefined') { + // popup was blocked + return false; + } + return true; } var $form, $form_data = $('<div>'); @@ -309,6 +317,7 @@ function get_file(options) { } }; timer = setTimeout(waitLoop, CHECK_INTERVAL); + return true; }; function post (controller_url, data) { diff --git a/addons/web/static/src/js/core/session.js b/addons/web/static/src/js/core/session.js index 0ecea92fb71..c3181a7abe6 100644 --- a/addons/web/static/src/js/core/session.js +++ b/addons/web/static/src/js/core/session.js @@ -278,7 +278,7 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, { options.data.session_id = this.session_id; } options.session = this; - ajax.get_file(options); + return ajax.get_file(options); }, /** * (re)loads the content of a session: db name, username, user id, session diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index 7d7c6735531..8eae8f5b8f1 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -394,7 +394,7 @@ var LinkButton = AbstractField.extend({ var FieldDate = InputField.extend({ className: "o_field_date", tagName: "span", - supportedFieldTypes: ['date'], + supportedFieldTypes: ['date', 'datetime'], /** * @override @@ -453,12 +453,13 @@ var FieldDate = InputField.extend({ * @override * @private * @param {Moment|false} value + * @returns {boolean} */ _isSameValue: function (value) { if (value === false) { return this.value === false; } - return value.isSame(this.value); + return value.isSame(this.value, 'day'); }, /** * Instantiates a new DateWidget datepicker. @@ -497,7 +498,16 @@ var FieldDateTime = FieldDate.extend({ var value = this.datewidget.getValue(); return value && value.add(-this.getSession().getTZOffset(value), 'minutes'); }, - + /** + * @override + * @private + */ + _isSameValue: function (value) { + if (value === false) { + return this.value === false; + } + return value.isSame(this.value); + }, /** * Instantiates a new DateTimeWidget datepicker rather than DateWidget. * @@ -1171,7 +1181,6 @@ var FieldBinaryImage = AbstractFieldBinary.extend({ supportedFieldTypes: ['binary'], _render: function () { var self = this; - var attrs = this.attrs; var url = this.placeholder; if (this.value) { if (!utils.is_bin_size(this.value)) { @@ -1186,11 +1195,7 @@ var FieldBinaryImage = AbstractFieldBinary.extend({ }); } } - var $img = $('<img>').attr('src', url); - $img.css({ - width: this.nodeOptions.size ? this.nodeOptions.size[0] : attrs.img_width || attrs.width, - height: this.nodeOptions.size ? this.nodeOptions.size[1] : attrs.img_height || attrs.height, - }); + var $img = $(qweb.render("FieldBinaryImage-img", {widget: this, url: url})); this.$('> img').remove(); this.$el.prepend($img); $img.on('error', function () { @@ -2175,6 +2180,15 @@ var FieldDomain = AbstractField.extend({ //-------------------------------------------------------------------------- /** + * A domain field is always set since the false value is considered to be + * equal to "[]" (match all records). + * + * @override + */ + isSet: function () { + return true; + }, + /** * @override isValid from AbstractField.isValid * Parsing the char value is not enough for this field. It is considered * valid if the internal domain selector was built correctly and that the diff --git a/addons/web/static/src/js/report/qwebactionmanager.js b/addons/web/static/src/js/report/qwebactionmanager.js index 3c8fee859e3..cc875882ce2 100644 --- a/addons/web/static/src/js/report/qwebactionmanager.js +++ b/addons/web/static/src/js/report/qwebactionmanager.js @@ -21,7 +21,7 @@ var WKHTMLTOPDF_MESSAGES = { }; var trigger_download = function (session, response, c, action, options) { - session.get_file({ + return session.get_file({ url: '/report/download', data: {data: JSON.stringify(response)}, complete: framework.unblockUI, @@ -107,7 +107,10 @@ ActionManager.include({ report_urls['qweb-pdf'], action.report_type, //The 'root' report is considered the maine one, so we use its type for all the others. ]; - trigger_download(self.getSession(), response, c, current_action, options); + var success = trigger_download(self.getSession(), response, c, current_action, options); + if (!success) { + self.do_warn(_t('Warning'), _t('A popup window with your report was blocked. You may need to change your browser settings to allow popup windows for this page.'), true); + } treated_actions.push(current_action); current_action = current_action.next_report_to_generate; 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 6884442039e..1df118ecfd9 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -875,7 +875,10 @@ var BasicModel = AbstractModel.extend({ // id never changes, and should not be written delete record._changes.id; } - var changes = self._generateChanges(record, {viewType: options.viewType}); + var changes = self._generateChanges(record, {viewType: options.viewType, changesOnly: method !== 'create'}); + + // id field should never be written/changed + delete changes.id; if (method === 'create') { var fieldNames = record.getFieldNames(); @@ -1551,6 +1554,9 @@ var BasicModel = AbstractModel.extend({ removedDef = this._applyX2ManyChange(record, fieldName, { operation: 'DELETE', ids: _.map(removedIds, function (resID) { + if (resID in list._cache) { + return list._cache[resID]; + } return _.findWhere(listData, {res_id: resID}).id; }), }); @@ -2455,7 +2461,7 @@ var BasicModel = AbstractModel.extend({ changes = _.extend({}, record.data, record._changes); } else { changes = _.extend({}, record._changes); - }; + } var withReadonly = options.withReadonly || false; var commands = this._generateX2ManyCommands(record, { changesOnly: 'changesOnly' in options ? options.changesOnly : true, @@ -2492,6 +2498,7 @@ var BasicModel = AbstractModel.extend({ changes[fieldName] = false; } } + return changes; }, /** @@ -2608,6 +2615,7 @@ var BasicModel = AbstractModel.extend({ _.each(relRecordUpdated, function (relRecord) { var changes = self._generateChanges(relRecord, options); if (!_.isEmpty(changes)) { + delete changes.id; var command = x2ManyCommands.update(relRecord.res_id, changes); commands[fieldName].push(command); } @@ -2638,7 +2646,12 @@ var BasicModel = AbstractModel.extend({ // this is a new id relRecord = _.findWhere(relRecordAdded, {res_id: list.res_ids[i]}); changes = this._generateChanges(relRecord, options); - commands[fieldName].push(x2ManyCommands.create(relRecord.ref, changes)); + if ('id' in changes) { + delete changes.id; + commands[fieldName].push(x2ManyCommands.update(relRecord.res_id, changes)); + } else { + commands[fieldName].push(x2ManyCommands.create(relRecord.ref, changes)); + } } } if (options.changesOnly && !didChange && addedIds.length === 0 && removedIds.length === 0) { @@ -3294,11 +3307,17 @@ var BasicModel = AbstractModel.extend({ * This method is quite important: it is supposed to perform the /onchange * rpc and apply the result. * + * The changes that triggered the onchange are assumed to have already been + * applied to the record. + * * @param {Object} record * @param {string[]} fields changed fields * @param {string} [viewType] current viewType. If not set, we will assume * main viewType from the record - * @returns {Deferred} + * @returns {Deferred} Note: this deferred cannot fail. It is either in the + * 'success' or 'pending' state. If the onchange rpc fails, it will be + * resolved with an empty dictionary. Note that the initial change was + * already applied. */ _performOnChange: function (record, fields, viewType) { var self = this; @@ -3318,7 +3337,9 @@ var BasicModel = AbstractModel.extend({ var context = this._getContext(record, options); var currentData = this._generateOnChangeData(record, {changesOnly: false}); - return self._rpc({ + var def = $.Deferred(); + + self._rpc({ model: record.model, method: 'onchange', args: [idList, currentData, fields, onchangeSpec, context], @@ -3343,9 +3364,12 @@ var BasicModel = AbstractModel.extend({ record._domains = _.extend(record._domains, result.domain); } return self._applyOnChange(result.value, record).then(function () { - return result; + def.resolve(result); }); + }).fail(function () { + def.resolve({}); }); + return def; }, /** * Once a record is created and some data has been fetched, we need to do 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 ab5e4beb6b5..5224a6c149a 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -807,7 +807,15 @@ var FormRenderer = BasicRenderer.extend({ // Attach the tooltips on the fields' label _.each(this.allFieldWidgets[this.state.id], function (widget) { var idForLabel = self.idsForLabels[widget.name]; + // We usually don't support multiple widgets for the same field on the + // same view but it is the case with the new settings view on V11.0. + // Therefore, we need to retrieve the correct label since it could be + // displayed multiple times on the view, otherwise, for example the + // enterprise label will be displayed as many times as the field + // exists on settings. + var $widgets = self.$('.o_field_widget[name=' + widget.name + ']'); var $label = idForLabel ? self.$('label[for=' + idForLabel + ']') : $(); + $label = $label.eq($widgets.index(widget.$el)); if (config.debug || widget.attrs.help || widget.field.help) { self._addFieldTooltip(widget, $label); } |
