From c5fbb9cc23edd4989dfdeddc343115c006e24a3d Mon Sep 17 00:00:00 2001 From: svs-odoo Date: Wed, 23 Oct 2019 10:04:09 +0000 Subject: [PATCH] [IMP] web: add widget signature Adding a new widget to display a sign button in the form view. task-1878607 --- addons/web/static/src/js/widgets/signature.js | 97 ++++++++++++++++++ addons/web/static/src/xml/base.xml | 6 ++ .../static/tests/fields/signature_tests.js | 99 +++++++++++++++++++ addons/web/views/webclient_templates.xml | 1 + 4 files changed, 203 insertions(+) create mode 100644 addons/web/static/src/js/widgets/signature.js diff --git a/addons/web/static/src/js/widgets/signature.js b/addons/web/static/src/js/widgets/signature.js new file mode 100644 index 00000000000..25cb16fdb45 --- /dev/null +++ b/addons/web/static/src/js/widgets/signature.js @@ -0,0 +1,97 @@ +odoo.define('web.signature_widget', function (require) { +"use strict"; + +const framework = require('web.framework'); +const SignatureDialog = require('web.signature_dialog'); +const widgetRegistry = require('web.widget_registry'); +const Widget = require('web.Widget'); + + +const WidgetSignature = Widget.extend({ + custom_events: Object.assign({}, Widget.prototype.custom_events, { + upload_signature: '_onUploadSignature', + }), + events: Object.assign({}, Widget.prototype.events, { + 'click .o_sign_label': '_onClickSignature', + }), + template: 'SignButton', + /** + * @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; + // signature_field is the field on which the signature image will be + // saved (`signature` by default). + this.signature_field = this.node.attrs.signature_field || 'signature'; + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * Open a dialog to sign. + * + * @private + */ + _onClickSignature: function () { + const nameAndSignatureOptions = { + displaySignatureRatio: 3, + mode: 'draw', + noInputName: true, + signatureType: 'signature', + }; + + if (this.node.attrs.full_name) { + let signName; + const fieldFullName = this.state.data[this.node.attrs.full_name]; + if (fieldFullName && fieldFullName.type === 'record') { + signName = fieldFullName.data.display_name; + } else { + signName = fieldFullName; + } + nameAndSignatureOptions.defaultName = signName || undefined; + } + + nameAndSignatureOptions.defaultFont = this.node.attrs.default_font || ''; + this.signDialog = new SignatureDialog(this, { + nameAndSignatureOptions: nameAndSignatureOptions, + }); + this.signDialog.open(); + }, + /** + * Upload the signature image (write it on the corresponding field) and + * close the dialog. + * + * @returns {Promise} + * @private + */ + _onUploadSignature: function (ev) { + const file = ev.data.signatureImage[1]; + const always = () => { + this.trigger_up('reload'); + framework.unblockUI(); + }; + framework.blockUI(); + const rpcProm = this._rpc({ + model: this.res_model, + method: 'write', + args: [[this.res_id], { + [this.signature_field]: file, + }], + }); + rpcProm.then(always).guardedCatch(always); + return rpcProm; + }, +}); + +widgetRegistry.add('signature', WidgetSignature); + +}); diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 7800bc1a218..6f8696926c6 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -1563,4 +1563,10 @@ + + + + diff --git a/addons/web/static/tests/fields/signature_tests.js b/addons/web/static/tests/fields/signature_tests.js index fcc3b67074f..088c6d705cb 100644 --- a/addons/web/static/tests/fields/signature_tests.js +++ b/addons/web/static/tests/fields/signature_tests.js @@ -113,6 +113,105 @@ QUnit.module('signature', { form.destroy(); }); + QUnit.module('Signature Widget'); + + QUnit.test('Signature widget renders a Sign button', async function (assert) { + assert.expect(3); + + const form = await createView({ + View: FormView, + model: 'partner', + res_id: 1, + data: this.data, + arch: '
' + + '
' + + '' + + '
' + + '
', + mockRPC: function (route, args) { + if (route === '/web/sign/get_fonts/') { + return Promise.resolve(); + } + return this._super(route, args); + }, + }); + + assert.containsOnce(form, 'button.o_sign_button.o_widget', + "Should have a signature widget button"); + assert.strictEqual($('.modal-dialog').length, 0, + "Should not have any modal"); + // Clicks on the sign button to open the sign modal. + await testUtils.dom.click(form.$('span.o_sign_label')); + assert.strictEqual($('.modal-dialog').length, 1, + "Should have one modal opened"); + + form.destroy(); + }); + + QUnit.test('Signature widget: full_name option', async function (assert) { + assert.expect(2); + + const form = await createView({ + View: FormView, + model: 'partner', + res_id: 1, + data: this.data, + arch: '
' + + '
' + + '' + + '
' + + '' + + '', + mockRPC: function (route, args) { + if (route === '/web/sign/get_fonts/') { + return Promise.resolve(); + } + return this._super(route, args); + }, + }); + + // Clicks on the sign button to open the sign modal. + await testUtils.dom.click(form.$('span.o_sign_label')); + assert.strictEqual($('.modal .modal-body a.o_web_sign_auto_button').length, 1, + "Should open a modal with \"Auto\" button"); + assert.strictEqual($('.modal .modal-body .o_web_sign_name_input').val(), "Pop's Chock'lit", + "Correct Value should be set in the input for auto drawing the signature"); + + form.destroy(); + }); + + QUnit.test('Signature widget: highlight option', async function (assert) { + assert.expect(3); + + const form = await createView({ + View: FormView, + model: 'partner', + res_id: 1, + data: this.data, + arch: '
' + + '
' + + '' + + '
' + + '
', + mockRPC: function (route, args) { + if (route === '/web/sign/get_fonts/') { + return Promise.resolve(); + } + return this._super(route, args); + }, + }); + + assert.hasClass(form.$('button.o_sign_button.o_widget'), 'btn-primary', + "The button must have the 'btn-primary' class as \"highlight=1\""); + // Clicks on the sign button to open the sign modal. + await testUtils.dom.click(form.$('span.o_sign_label')); + assert.isNotVisible($('.modal .modal-body a.o_web_sign_auto_button'), + "\"Auto\" button must be invisible"); + assert.strictEqual($('.modal .modal-body .o_web_sign_name_input').val(), '', + "No value should be set in the input for auto drawing the signature"); + + form.destroy(); + }); }); }); }); diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml index 297d6b63bde..294475e5aca 100644 --- a/addons/web/views/webclient_templates.xml +++ b/addons/web/views/webclient_templates.xml @@ -281,6 +281,7 @@ +