diff options
| author | jpr-odoo <jpr@openerp.com> | 2017-11-01 15:15:04 +0530 |
|---|---|---|
| committer | Yannick Tivisse <yti@odoo.com> | 2018-02-09 06:59:56 +0100 |
| commit | b7aa439826df6b3e442b3f60bb593ff28efc8679 (patch) | |
| tree | 953d340f839717c5de254ca90cb3d3cde9b44d0d /addons | |
| parent | dfdc06fe4332b3de97a3b1f8f554ce6adc3b948d (diff) | |
[ADD] web: Add a new widget to attach documents on a record
Purpose
=======
Add the possibility to easily attach a document on a record. That could be used for to attach receipts on expense for example.
Specification
=============
Add a new widget (AttachDocument) to allow attach document from mobile/web directly on record form
After attaching document it will call action given on widget, that action will be a method name on given model
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/web/static/src/js/views/basic/basic_renderer.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/form/form_renderer.js | 3 | ||||
| -rw-r--r-- | addons/web/static/src/js/widgets/attach_document.js | 135 | ||||
| -rw-r--r-- | addons/web/static/src/xml/base.xml | 16 | ||||
| -rw-r--r-- | addons/web/static/tests/views/form_tests.js | 22 | ||||
| -rw-r--r-- | addons/web/views/webclient_templates.xml | 1 |
6 files changed, 178 insertions, 1 deletions
diff --git a/addons/web/static/src/js/views/basic/basic_renderer.js b/addons/web/static/src/js/views/basic/basic_renderer.js index d9c0f1a570b..f0d41f31f49 100644 --- a/addons/web/static/src/js/views/basic/basic_renderer.js +++ b/addons/web/static/src/js/views/basic/basic_renderer.js @@ -594,7 +594,7 @@ var BasicRenderer = AbstractRenderer.extend({ */ _renderWidget: function (record, node) { var Widget = widgetRegistry.get(node.attrs.name); - var widget = new Widget(this, record); + var widget = new Widget(this, record, node); // Prepare widget rendering and save the related deferred var def = widget._widgetRenderAndInsert(function () {}); 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 b289663fb19..b28d25c5b90 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -370,6 +370,9 @@ var FormRenderer = BasicRenderer.extend({ if (child.tag === 'button') { $buttons.append(self._renderHeaderButton(child)); } + if (child.tag === 'widget') { + $buttons.append(self._renderTagWidget(child)); + } }); return $buttons; }, diff --git a/addons/web/static/src/js/widgets/attach_document.js b/addons/web/static/src/js/widgets/attach_document.js new file mode 100644 index 00000000000..041b021d60b --- /dev/null +++ b/addons/web/static/src/js/widgets/attach_document.js @@ -0,0 +1,135 @@ +odoo.define('web.AttachDocument', function (require) { +"use static"; + +var core = require('web.core'); +var framework = require('web.framework'); +var widgetRegistry = require('web.widget_registry'); +var Widget = require('web.Widget'); + +var _t = core._t; + +var AttachDocument = Widget.extend({ + template: 'AttachDocument', + events: { + 'click span.o_attach_document': '_onClickAttachDocument', + 'change input.o_input_file': '_onFileChanged', + }, + /** + * @constructor + * @param {Widget} parent + * @param {Object} record + * @param {Object} nodeInfo + */ + init: function (parent, record, nodeInfo) { + this._super.apply(this, arguments); + this.res_id = record.res_id; + this.res_model = record.model; + this.state = record; + this.node = nodeInfo; + this.fileuploadID = _.uniqueId('o_fileupload'); + }, + /** + * @override + */ + start: function () { + $(window).on(this.fileuploadID, this._onFileLoaded.bind(this)); + return this._super.apply(this, arguments); + }, + /** + * @override + */ + destroy: function () { + $(window).off(this.fileuploadID); + this._super.apply(this, arguments); + }, + + //-------------------------------------------------------------------------- + // private + //-------------------------------------------------------------------------- + + /** + * Helper function to display a warning that some fields have an invalid + * value. This is used when a save operation cannot be completed. + * + * @private + * @param {string[]} invalidFields - list of field names + */ + _notifyInvalidFields: function (invalidFields) { + var fields = this.state.fields; + var warnings = invalidFields.map(function (fieldName) { + var fieldStr = fields[fieldName].string; + return _.str.sprintf('<li>%s</li>', _.escape(fieldStr)); + }); + warnings.unshift('<ul>'); + warnings.push('</ul>'); + this.do_warn(_t("The following fields are invalid:"), warnings.join('')); + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * Opens File Explorer dialog if all fields are valid and record is saved + * + * @private + * @param {Event} ev + */ + _onClickAttachDocument: function (ev) { + var fieldNames = this.getParent().canBeSaved(this.state.id); + if (fieldNames.length) { + return this._notifyInvalidFields(fieldNames); + } + // We want to save record on widget click and then open File Selection Explorer + // but due to this security restriction give warning to save record first. + // https://stackoverflow.com/questions/29728705/trigger-click-on-input-file-on-asynchronous-ajax-done/29873845#29873845 + if (!this.res_id) { + return this.do_warn(_t('Warning : You have to save first before attaching a file.')); + } + this.$('input.o_input_file').trigger('click'); + }, + /** + * Submits file + * + * @private + * @param {Event} ev + */ + _onFileChanged: function (ev) { + ev.stopPropagation(); + this.$('form.o_form_binary_form').trigger('submit'); + framework.blockUI(); + }, + /** + * Call action given as node attribute after file submission + * + * @private + */ + _onFileLoaded: function () { + var self = this, + def = $.Deferred(); + + if (self.node.attrs.action) { + // the first argument isn't a file but the jQuery.Event + var files = Array.prototype.slice.call(arguments, 1); + self._rpc({ + model: self.res_model, + method: self.node.attrs.action, + args: [self.res_id], + kwargs: { + 'attachment_ids': _.map(files, function (file) {return file.id;}), + } + }).then( function () { + def.resolve(); + }); + } else { + def.resolve(); + } + return $.when(def).then(function () { + self.trigger_up('reload'); + framework.unblockUI(); + }); + }, + +}); +widgetRegistry.add('attach_document', AttachDocument); +}); diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 196346d4d9c..ce432fea823 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -1351,4 +1351,20 @@ </div> </t> +<t t-name="AttachDocument"> + <button class="btn btn-sm btn-default o_attachment_button"> + <span class="o_attach_document"><t t-esc="widget.node.attrs.string"/></span> + <span class="hide"> + <t t-call="HiddenInputFile"> + <t t-set="fileupload_id" t-value="widget.fileuploadID"/> + <t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t> + <t t-set="multi_upload" t-value="true"/> + <input type="hidden" name="model" t-att-value="widget.res_model"/> + <input type="hidden" name="id" t-att-value="widget.res_id"/> + <input type="hidden" name="session_id" t-att-value="widget.getSession().session_id"/> + </t> + </span> + </button> +</t> + </templates> diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index 6d8909ff2c3..37420e0f076 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -6227,6 +6227,28 @@ QUnit.module('Views', { delete widgetRegistry.map.test; }); + QUnit.test('support header button as widgets on form statusbar', function (assert) { + assert.expect(2); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<header>' + + '<widget name="attach_document" string="Attach document"/>' + + '</header>' + + '</form>', + }); + + assert.strictEqual(form.$('button.o_attachment_button').length, 1, + "should have 1 attach_document widget in the statusbar"); + assert.strictEqual(form.$('span.o_attach_document').text().trim(), 'Attach document', + "widget should have been instantiated"); + + form.destroy(); + }); + QUnit.test('bounce edit button in readonly mode', function (assert) { assert.expect(3); diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml index 2742871c790..35ded8170cf 100644 --- a/addons/web/views/webclient_templates.xml +++ b/addons/web/views/webclient_templates.xml @@ -240,6 +240,7 @@ <script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_quick_create.js"></script> <script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_renderer.js"></script> <script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_view.js"></script> + <script type="text/javascript" src="/web/static/src/js/widgets/attach_document.js"></script> <script type="text/javascript" src="/web/static/src/js/report/utils.js"/> <script type="text/javascript" src="/web/static/src/js/report/client_action.js"/> |
