diff options
| author | jbm-odoo <jbm@odoo.com> | 2019-01-14 14:22:03 +0000 |
|---|---|---|
| committer | jbm-odoo <jbm@odoo.com> | 2019-02-14 12:59:10 +0000 |
| commit | 4960453db91b465c9429453ef3a0692a604c8ef9 (patch) | |
| tree | 3b02bb92556b523e91a949817e31da970b6f2a98 /addons/web/static/src/js/fields | |
| parent | 7410de111fe33731ba79f68f53e13dd3d511fb43 (diff) | |
[IMP] web Add widget signature on binary field
Add a new widget for binary fields. It open a dialog box and the user can sign manually,
or an signature can be draw automatically or he can upload a picture of his signature.
Move fonts, controller, scss,templates about signature from portal to web to avoid redundance
closes odoo/odoo#30222
Diffstat (limited to 'addons/web/static/src/js/fields')
| -rw-r--r-- | addons/web/static/src/js/fields/basic_fields.js | 1 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/field_registry.js | 1 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/signature.js | 272 |
3 files changed, 274 insertions, 0 deletions
diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index ae080f45a11..dcfdc982b7d 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -3005,6 +3005,7 @@ return { FieldEmail: FieldEmail, FieldBinaryFile: FieldBinaryFile, FieldPdfViewer: FieldPdfViewer, + AbstractFieldBinary: AbstractFieldBinary, FieldBinaryImage: FieldBinaryImage, FieldBoolean: FieldBoolean, FieldBooleanButton: FieldBooleanButton, diff --git a/addons/web/static/src/js/fields/field_registry.js b/addons/web/static/src/js/fields/field_registry.js index 35d10c5a5e4..a8bd80719e1 100644 --- a/addons/web/static/src/js/fields/field_registry.js +++ b/addons/web/static/src/js/fields/field_registry.js @@ -37,6 +37,7 @@ registry .add('CopyClipboardText', basic_fields.TextCopyClipboard) .add('CopyClipboardChar', basic_fields.CharCopyClipboard) .add('image', basic_fields.FieldBinaryImage) + .add('signature', basic_fields.FieldBinarySignature) .add('binary', basic_fields.FieldBinaryFile) .add('pdf_viewer', basic_fields.FieldPdfViewer) .add('monetary', basic_fields.FieldMonetary) diff --git a/addons/web/static/src/js/fields/signature.js b/addons/web/static/src/js/fields/signature.js new file mode 100644 index 00000000000..186c8fd764c --- /dev/null +++ b/addons/web/static/src/js/fields/signature.js @@ -0,0 +1,272 @@ +odoo.define('web.Signature', function (require) { + "use strict"; + + var AbstractFieldBinary = require('web.basic_fields').AbstractFieldBinary; + var core = require('web.core'); + var Dialog = require('web.Dialog'); + var field_utils = require('web.field_utils'); + var NameAndSignature = require('web.name_and_signature').NameAndSignature; + var registry = require('web.field_registry'); + var session = require('web.session'); + var utils = require('web.utils'); + + + var qweb = core.qweb; + var _t = core._t; + +// The goal of this dialog is to ask the user a signature request. +// It uses @see SignNameAndSignature for the name and signature fields. +var SignatureDialog = Dialog.extend({ + template: 'web.signature_dialog', + xmlDependencies: Dialog.prototype.xmlDependencies.concat( + ['/web/static/src/xml/name_and_signature.xml'] + ), + custom_events: { + 'signature_changed': '_onChangeSignature', + }, + + /** + * @constructor + * @param {Widget} parent + * @param {Object} options + * @param {string} [options.title='Adopt Your Signature'] - modal title + * @param {string} [options.size='medium'] - modal size + * @param {Object} [options.nameAndSignatureOptions={}] - options for + * @see NameAndSignature.init() + */ + init: function (parent, options) { + var self = this; + options = options || {}; + + options.title = options.title || _t("Adopt Your Signature"); + options.size = options.size || 'medium'; + options.technical = false; + + if (!options.buttons) { + options.buttons = []; + options.buttons.push({text: _t("Adopt and Sign"), classes: "btn-primary", disabled: true, click: function (e) { + self._onConfirm(); + }}); + options.buttons.push({text: _t("Cancel"), close: true}); + } + + this._super(parent, options); + + this.nameAndSignature = new NameAndSignature(this, options.nameAndSignatureOptions); + }, + /** + * Inserts the name and signature. + * + * @override + */ + start: function () { + var self = this; + this.$primaryButton = this.$footer.find('.btn-primary'); + + this.opened().then(function () { + self.nameAndSignature.replace(self.$('.o_web_sign_name_and_signature')); + }); + + return this._super.apply(this, arguments); + }, + + //---------------------------------------------------------------------- + // Public + //---------------------------------------------------------------------- + + /** + * Returns whether the drawing area is currently empty. + * + * @see NameAndSignature.isSignatureEmpty() + * @returns {boolean} Whether the drawing area is currently empty. + */ + isSignatureEmpty: function () { + return this.nameAndSignature.isSignatureEmpty(); + }, + + //---------------------------------------------------------------------- + // Handlers + //---------------------------------------------------------------------- + + /** + * Toggles the submit button depending on the signature state. + * + * @private + */ + _onChangeSignature: function () { + var isEmpty = this.nameAndSignature.isSignatureEmpty(); + this.$primaryButton.prop('disabled', isEmpty); + }, + /** + * Upload the signature image when confirm. + * + * @private + */ + _onConfirm: function (fct) { + this.trigger_up('upload_signature', { + name: this.nameAndSignature.getName(), + signatureImage: this.nameAndSignature.getSignatureImage(), + }); + }, +}); + +var FieldBinarySignature = AbstractFieldBinary.extend({ + fieldDependencies: _.extend({}, AbstractFieldBinary.prototype.fieldDependencies, { + __last_update: {type: 'datetime'}, + }), + custom_events: _.extend({}, AbstractFieldBinary.prototype.custom_events, { + upload_signature: '_onUploadSignature', + }), + events: _.extend({}, AbstractFieldBinary.prototype.events, { + 'click .o_signature': '_onClickSignature', + }), + template: null, + supportedFieldTypes: ['binary'], + file_type_magic_word: { + '/': 'jpg', + 'R': 'gif', + 'i': 'png', + 'P': 'svg+xml', + }, + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * This widget must always have render even if there are no signature. + * In edit mode, the real value is return to manage required fields. + * + * @override + */ + isSet: function () { + if (this.mode === 'edit') { + return this.value; + } + return true; + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * Renders an empty signature or the saved signature. Both must have the same size. + * + * @override + * @private + */ + + _render: function () { + var self = this; + var displaySignatureRatio = 3; + var url; + var $img; + var width = this.nodeOptions.size ? this.nodeOptions.size[0] : this.attrs.width; + var height = this.nodeOptions.size ? this.nodeOptions.size[1] : this.attrs.height; + if (this.value) { + if (!utils.is_bin_size(this.value)) { + // Use magic-word technique for detecting image type + url = 'data:image/' + (this.file_type_magic_word[this.value[0]] || 'png') + ';base64,' + this.value; + } else { + url = session.url('/web/image', { + model: this.model, + id: JSON.stringify(this.res_id), + field: this.nodeOptions.preview_image || this.name, + // unique forces a reload of the image when the record has been updated + unique: field_utils.format.datetime(this.recordData.__last_update).replace(/[^0-9]/g, ''), + }); + } + $img = $(qweb.render("FieldBinarySignature-img", {widget: this, url: url})); + } else { + $img = $('<div class="o_signature o_signature_empty"><svg></svg><p>' + _t('SIGNATURE') + '</p></div>'); + if (width && height) { + width = Math.min(width, displaySignatureRatio * height); + height = width / displaySignatureRatio; + } else if (width) { + height = width / displaySignatureRatio; + } else if (height) { + width = height * displaySignatureRatio; + } + } + if (width) { + $img.attr('width', width); + $img.css('max-width', width + 'px'); + } + if (height) { + $img.attr('height', height); + $img.css('max-height', height + 'px'); + } + this.$('> div').remove(); + this.$('> img').remove(); + + this.$el.prepend($img); + + $img.on('error', function () { + self._clearFile(); + $img.attr('src', self.placeholder); + self.do_warn(_t("Image"), _t("Could not display the selected image.")); + }); + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * If the view is in edit mode, open dialog to sign. + * + * @private + */ + _onClickSignature: function () { + var self = this; + if (this.mode === 'edit') { + + var nameAndSignatureOptions = { + mode: 'draw', + displaySignatureRatio: 3, + signatureType: 'signature', + noInputName: true, + }; + + if (this.nodeOptions.full_name) { + var $search = $("[name='" + this.nodeOptions.full_name + "']"); + // If full_name correspond to field in read-only mode + var signName = $($search).text(); + + // If full_name correspond to field to fill + if (!signName && $($search)[0]) { + signName = $($search)[0].value; + } + if (!signName) { + // If full_name is in the recordData. Last option because this value might not be the last value. + signName = this.recordData[this.nodeOptions.full_name] || ''; + } + nameAndSignatureOptions.defaultName = (signName === '') ? undefined : signName; + } + + nameAndSignatureOptions.defaultFont = this.nodeOptions.default_font || ''; + this.signDialog = new SignatureDialog(self, {nameAndSignatureOptions: nameAndSignatureOptions}); + + this.signDialog.open(); + } + }, + + /** + * Upload the signature image if valid and close the dialog. + * + * @private + */ + _onUploadSignature: function (ev) { + var signatureImage = ev.data.signatureImage; + if (signatureImage !== this.signDialog.emptySignature) { + var data = signatureImage[1]; + var type = signatureImage[0].split('/')[1]; + this.on_file_uploaded(data.length, ev.data.name, type, data); + } + this.signDialog.close(); + } +}); + +registry.add('signature', FieldBinarySignature); + +}); |
