/* * (c) Copyright Ascensio System SIA 2010-2024 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish * street, Riga, Latvia, EU, LV-1050. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ /** * PdfSignDialog.js * * Created on 26/08/24 * */ define([], function () { 'use strict'; Common.Views.PdfSignDialog = Common.UI.Window.extend(_.extend({ options: { width: 535, style: 'min-width: 350px;', cls: 'modal-dlg', buttons: ['ok', 'cancel'], id: 'window-pdf-sign' }, initialize : function(options) { _.extend(this.options, { title: this.txtTitle }, options || {}); this.api = this.options.api; this.props = this.options.props; this.fontStore = this.options.fontStore; this.mode = 0; // 0 - upload, 1 - draw, 2 - type this.storage = !!this.options.storage; this.isImageLoaded = false; this.iconType = this.options.iconType; this.font = { size: 11, name: 'Arial', bold: false, italic: false }; this.template = [ '
', '', '
', '', '', '', '
', '', '
', '
', '
', '', '', '', '
', '
', '
', '', '
', '', '', '
', '
', '
', '', '', '', '','', '', '', '
', '', '
', '
', ].join(''); this.options.tpl = _.template(this.template)(this.options); Common.UI.Window.prototype.initialize.call(this, this.options); }, render: function() { Common.UI.Window.prototype.render.call(this); var me = this, $window = this.getChild(), is_svg_icon = this.iconType === 'svg'; this.btnUpload = new Common.UI.Button({ el: $window.find('#id-dlg-pdf-btn-upload'), enableToggle: true, toggleGroup: 'pdf-img-type', allowDepress: false, pressed: true }); this.btnUpload.on('click', _.bind(this.onImgModeClick, this, 0)); this.btnDraw = new Common.UI.Button({ el: $window.find('#id-dlg-pdf-btn-draw'), enableToggle: true, toggleGroup: 'pdf-img-type', allowDepress: false }); this.btnDraw.on('click', _.bind(this.onImgModeClick, this, 1)); this.btnType = new Common.UI.Button({ el: $window.find('#id-dlg-pdf-btn-type'), enableToggle: true, toggleGroup: 'pdf-img-type', allowDepress: false }); this.btnType.on('click', _.bind(this.onImgModeClick, this, 2)); Common.UI.GroupedButtons([me.btnUpload, me.btnDraw, me.btnType]); this.btnSelectImage = new Common.UI.Button({ parentEl: $window.find('#id-dlg-pdf-select-image'), cls: 'btn-text-menu-default', caption: this.textSelect, style: 'min-width: 142px;', menu: new Common.UI.Menu({ style: 'min-width: 142px;', maxHeight: 200, additionalAlign: this.menuAddAlign, items: [ {caption: this.textFromFile, value: 0}, {caption: this.textFromUrl, value: 1}, {caption: this.textFromStorage, value: 2} ] }), takeFocusOnClose: true }); this.btnSelectImage.menu.on('item:click', _.bind(this.onImageSelect, this)); this.btnSelectImage.menu.items[2].setVisible(this.storage); this.btnSelectImage.menu.items[1].setDisabled(this.options.disableNetworkFunctionality); this.btnSelectImage.menu.items[2].setDisabled(this.options.disableNetworkFunctionality); this.chRemBack = new Common.UI.CheckBox({ el: $window.find('#pdf-sign-ch-back'), labelText: this.txtRemBack }); this.chRemBack.on('change', function(field, newValue, oldValue, eOpts){ me.props && me.props.put_RemoveBackground(field.getValue()==='checked'); }); this.cmbFonts = new Common.UI.ComboBoxFonts({ el : $window.find('#pdf-sign-fonts'), cls : 'input-group-nr', style : 'width: 100px;', menuCls : 'scrollable-menu', menuStyle : 'min-width: 100%;max-height: 270px;', store : new Common.Collections.Fonts(), recent : 0, takeFocusOnClose: true }).on('selected', function(combo, record) { me.font.name = record.name; me.props && me.props.put_TypeFont(record.name); }); this.cmbFontSize = new Common.UI.ComboBox({ el: $window.find('#pdf-sign-font-size'), cls: 'input-group-nr', style: 'width: 50px;', menuCls : 'scrollable-menu', menuStyle: 'min-width: 50px;max-height: 270px;', data: [ { value: 8, displayValue: "8" }, { value: 9, displayValue: "9" }, { value: 10, displayValue: "10" }, { value: 11, displayValue: "11" }, { value: 12, displayValue: "12" }, { value: 14, displayValue: "14" }, { value: 16, displayValue: "16" }, { value: 18, displayValue: "18" }, { value: 20, displayValue: "20" }, { value: 22, displayValue: "22" }, { value: 24, displayValue: "24" }, { value: 26, displayValue: "26" }, { value: 28, displayValue: "28" }, { value: 36, displayValue: "36" }, { value: 48, displayValue: "48" }, { value: 72, displayValue: "72" }, { value: 96, displayValue: "96" } ], takeFocusOnClose: true }).on('selected', function(combo, record) { me.font.size= record.value; me.props && me.props.put_TypeFontSize(record.value); }); this.cmbFontSize.setValue(this.font.size); this.cmbFontSize.on({ 'changed:before': this.onFontSizeChanged.bind(this, true), 'changed:after': this.onFontSizeChanged.bind(this, false), }); this.btnBold = new Common.UI.Button({ parentEl: $window.find('#pdf-sign-bold'), cls: 'btn-toolbar', iconCls: 'toolbar__icon btn-bold', enableToggle: true, hint: this.textBold }); this.btnBold.on('click', function(btn, e) { me.font.bold = btn.pressed; me.props && me.props.put_TypeBold(btn.pressed); }); this.btnItalic = new Common.UI.Button({ parentEl: $window.find('#pdf-sign-italic'), cls: 'btn-toolbar', iconCls: 'toolbar__icon btn-italic', enableToggle: true, hint: this.textItalic }); this.btnItalic.on('click', function(btn, e) { me.font.italic = btn.pressed; me.props && me.props.put_TypeItalic(btn.pressed); }); this.inputName = new Common.UI.InputField({ el: $window.find('#pdf-sign-name'), style: 'width: 150px;', validateOnChange: true }).on ('changing', _.bind(this.onChangeName, this)); this.btnLineColor = new Common.UI.ColorButton({ parentEl: $window.find('#pdf-sign-line-color'), additionalAlign: this.menuAddAlign, color: 'auto', auto: true, menu: true, takeFocusOnClose: true }); this.btnLineColor.setMenu(new Common.UI.Menu({ style: 'min-width: 100px;', items: [ { template: _.template('
'), stopPropagation: true }, { id: 'sign-draw-line-color-new', template: _.template('' + this.btnLineColor.textNewColor + '') }, ] }), true); // color const currentColor = '000000'; this.btnLineColor.currentColor = currentColor; this.btnLineColor.setColor(currentColor); const picker = new Common.UI.ThemeColorPalette({ el: $('#id-sign-window-draw-line-color'), colors: [ '1755A0', 'D43230', 'F5C346', 'EA3368', '12A489', '552F8B', '9D1F87', 'BB2765', '479ED2', '67C9FA', '3D8A44', '80CA3D', '1C19B4', '7F4B0F', 'FF7E07', 'FFFFFF', 'D3D3D4', '879397', '575757', '000000' ], value: currentColor, dynamiccolors: 5, themecolors: 0, effects: 0, columns: 5, outerMenu: {menu: this.btnLineColor.menu, index: 0, focusOnShow: true}, storageSuffix: '-sign' }); this.btnLineColor.setPicker(picker); picker.on('select', this.onColorsLineSelect.bind(this)); this.btnLineColor.menu.setInnerMenu([{menu: picker, index: 0}]); this.btnLineColor.menu.cmpEl.find('#sign-draw-line-color-new').on('click', function() { picker.addNewColor(me.btnLineColor.currentColor); }); var data = []; for (var i=1; i<6; i++) { data.push({ value: i, displayValue: i + ' px' }); } this.cmbLineSize = new Common.UI.ComboBox({ el: $window.find('#pdf-sign-line-size'), cls: 'input-group-nr', style: 'width: 50px;', menuCls : 'scrollable-menu', menuStyle: 'min-width: 50px;max-height: 270px;', data: data, takeFocusOnClose: true }); this.cmbLineSize.setValue(2); this.cmbLineSize.on({ 'selected': function(combo, record) { me.props && me.props.put_LineSize(record.value); }, 'changed:before': this.onLineSizeChanged.bind(this), }); this.btnUndo = new Common.UI.Button({ parentEl : $window.find('#btn-sign-undo'), cls : 'btn-toolbar', iconCls : is_svg_icon ? 'svg-icon undo icon-rtl scaling-off' : 'toolbar__icon btn-undo icon-rtl', hint : this.tipUndo }).on('click', _.bind(this.onUndo, this)); this.btnRedo = new Common.UI.Button({ parentEl : $window.find('#btn-sign-redo'), cls : 'btn-toolbar', iconCls : is_svg_icon ? 'svg-icon redo icon-rtl scaling-off' : 'toolbar__icon btn-redo icon-rtl', hint : this.tipRedo }).on('click', _.bind(this.onRedo, this)); this.btnClear = new Common.UI.Button({ el: $window.find('#pdf-sign-btn-clear') }); this.btnClear.on('click', _.bind(this.onClear, this)); this.imgUploadPnl = $window.find('.img-upload'); this.imgDrawPnl = $window.find('.img-draw'); this.imgTypePnl = $window.find('.img-type'); this.uploadEmptyPnl = $window.find('#pdf-sign-img-upload'); this.uploadPreviewPnl = $window.find('#pdf-sign-img-upload-preview'); this.btnOk = _.find(this.getFooterButtons(), function (item) { return (item.$el && item.$el.find('.primary').addBack().filter('.primary').length>0); }) || new Common.UI.Button({ el: this.$window.find('.primary') }); this.btnOk.setDisabled(true); this.afterRender(); }, getFocusedComponents: function() { return [this.btnUpload, this.btnDraw, this.btnType, this.btnSelectImage, this.chRemBack, this.cmbLineSize, this.btnLineColor, this.inputName, this.cmbFonts, this.cmbFontSize, this.btnBold, this.btnItalic, this.btnUndo, this.btnRedo, this.btnClear].concat(this.getFooterButtons()); }, getDefaultFocusableComponent: function () { }, afterRender: function() { this.cmbFonts.fillFonts(this.fontStore); this.cmbFonts.selectRecord(this.fontStore.findWhere({name: this.font.name})); this.updateThemeColors(); this._setDefaults(this.props); var me = this; var onApiImgLoaded = function() { me.isImageLoaded = true; me.uploadEmptyPnl.toggleClass('hidden', true); me.uploadPreviewPnl.toggleClass('hidden', false); me.props.updateView(0); me.btnOk.setDisabled(false); }; this.api.asc_registerCallback('asc_onSignatureImageLoaded', onApiImgLoaded); var onCanUndoChanged = function(canUndo) { me.btnUndo.setDisabled(!canUndo); }; var onCanRedoChanged = function(canRedo) { me.btnRedo.setDisabled(!canRedo); }; this.api.asc_registerCallback('asc_CanUndoSignature', onCanUndoChanged); this.api.asc_registerCallback('asc_CanRedoSignature', onCanRedoChanged); this.restoreSignature(); var insertImageFromStorage = function(data) { if (data && data._urls && data.c==='signature') { me.props.put_ImageUrl(data._urls[0], data.token); } }; Common.NotificationCenter.on('storage:image-insert', insertImageFromStorage); me.keydownHandler = function(e) { if (!(me.$window && me.$window.is(':visible'))) return; if (me.mode !== 1) return; var ctrlKey = e.ctrlKey || e.metaKey; if (!ctrlKey) return; if (e.keyCode === 90 && !e.shiftKey) { if (!me.btnUndo.isDisabled()) { me.onUndo(); e.preventDefault(); } } else if (e.keyCode === 89 || (e.keyCode === 90 && e.shiftKey)) { if (!me.btnRedo.isDisabled()) { me.onRedo(); e.preventDefault(); } } }; document.addEventListener('keydown', me.keydownHandler, true); this.on('close', function(obj){ me.api.asc_unregisterCallback('asc_onSignatureImageLoaded', onApiImgLoaded); me.api.asc_unregisterCallback('asc_CanUndoSignature', onCanUndoChanged); me.api.asc_unregisterCallback('asc_CanRedoSignature', onCanRedoChanged); Common.NotificationCenter.off('storage:image-insert', insertImageFromStorage); document.removeEventListener('keydown', me.keydownHandler, true); }); const $window = this.getChild(); $window.find('.dlg-btn').on('click', e => { const result = e.currentTarget.getAttribute('result'); if (result === 'ok' && me.props) { const serialized = me.props.serialize(); serialized.mode = me.mode; Common.localStorage.setItem(me.getKey(), JSON.stringify(serialized)); } if ( me.options.handler ) me.options.handler.call(me, result); me.close(); }); }, updateThemeColors: function() { // this.colorsLine.updateColors(Common.Utils.ThemeColor.getEffectColors(), Common.Utils.ThemeColor.getStandartColors()); }, getSignatureId: function() { return this.props ? this.props.getResult().internalId : ''; }, getKey: function() { return 'dialog-signature-' + this.getSignatureId(); }, getStoredData: function() { var storedJson = Common.localStorage.getItem(this.getKey()); if (!storedJson) return null; return JSON.parse(storedJson); }, restoreSignature: function() { if (!this.props) return; var data = this.getStoredData(); if (!data) return; this.props.deserialize(data); var mode = data.mode !== undefined ? data.mode : 0; this.mode = mode; this.btnUpload.toggle(mode === 0, true); this.btnDraw.toggle(mode === 1, true); this.btnType.toggle(mode === 2, true); this.ShowHideElem(mode); if (mode === 1) { var lineColor = data.lineColor; if (lineColor) this.btnLineColor.setColor(lineColor.replace('#', '')); if (data.lineSize) this.cmbLineSize.setValue(data.lineSize); } else if (mode === 2) { if (data.text) this.inputName.setValue(data.text); if (data.font) { this.font.name = data.font; var rec = this.fontStore && this.fontStore.findWhere({name: data.font}); if (rec) this.cmbFonts.selectRecord(rec); this.props.put_TypeFont(data.font); } if (data.fontSize) { this.font.size = data.fontSize; this.cmbFontSize.setValue(data.fontSize); } if (data.bold !== undefined) { this.font.bold = data.bold; this.btnBold.toggle(data.bold); } if (data.italic !== undefined) { this.font.italic = data.italic; this.btnItalic.toggle(data.italic); } } }, onImgModeClick: function(mode, btn) { this.mode = mode; this.ShowHideElem(mode); }, ShowHideElem: function(mode) { this.imgUploadPnl.toggleClass('hidden', !!mode); this.imgDrawPnl.toggleClass('hidden', mode!==1); this.imgTypePnl.toggleClass('hidden', mode!==2); this.btnOk.setDisabled(!mode && !this.isImageLoaded); var me = this; _.delay(function(){ me.props.updateView(mode); mode===1 ? me.cmbLineSize.focus() : mode===2 ? me.inputName.focus() : me.btnSelectImage.focus(); },50); }, onImageSelect: function(menu, item) { if (item.value==1) { var me = this; (new Common.Views.ImageFromUrlDialog({ handler: function(result, value) { if (result == 'ok') { var checkUrl = value.replace(/ /g, ''); if (!_.isEmpty(checkUrl)) { me.props.put_ImageUrl(checkUrl); } } } })).on('close', function() { }).show(); } else if (item.value==2) { Common.NotificationCenter.trigger('storage:image-load', 'signature'); } else { this.props.showFileDialog(); } }, onColorsLineSelect: function(btn, color) { Common.UI.Menu.Manager.hideAll(); this.btnLineColor.setColor(color); this.props && this.props.put_LineColor(Common.Utils.ThemeColor.getRgbColor(color)); }, _setDefaults: function (props) { if (props) { props.put_PreviewImgId('pdf-sign-img-upload-preview'); props.put_PreviewDrawId('pdf-sign-img-draw-preview'); props.put_PreviewTypeId('pdf-sign-img-type-preview'); this.btnUndo.setDisabled(!props.asc_canUndo()); this.btnRedo.setDisabled(!props.asc_canRedo()); } }, getSettings: function () { }, onBtnClick: function(event) { this._handleInput(event.currentTarget.attributes['result'].value); }, onPrimary: function(event) { this._handleInput('ok'); return false; }, _handleInput: function(state) { if (this.options.handler) { if (state == 'ok' && this.btnOk.isDisabled()) { return; } this.options.handler.call(this, state, this.getSettings()); } this.close(); }, onClear: function () { switch (this.mode) { case 0: this.props.clearImg(); this.isImageLoaded = false; this.uploadEmptyPnl.toggleClass('hidden', false); this.uploadPreviewPnl.toggleClass('hidden', true); this.btnOk.setDisabled(true); break; case 1: this.props.clearDraw(); break; case 2: this.props.clearType(); break; } }, onUndo: function () { this.props.undo(); }, onRedo: function () { this.props.redo(); }, onFontSizeChanged: function(before, combo, record, e) { var value; if (before) { var item = combo.store.findWhere({ displayValue: record.value }); if (!item) { value = /^\+?(\d*(\.|,)?\d+)$|^\+?(\d+(\.|,)?\d*)$/.exec(record.value); if (!value) { value = combo.getValue(); combo.setRawValue(value); e.preventDefault(); return false; } } } else { var maxvalue = 300; value = Common.Utils.String.parseFloat(record.value); value = value > maxvalue ? maxvalue : value < 1 ? 1 : Math.floor((value+0.4)*2)/2; combo.setRawValue(value); this.font.size = value; this.props && this.props.put_TypeFontSize(value); } }, onLineSizeChanged: function(combo, record, e) { const item = combo.store.findWhere({ displayValue: record.value }); if (!item) { const value = /^\+?(\d*(\.|,)?\d+)$|^\+?(\d+(\.|,)?\d*)$/.exec(record.value); if (!value) { let value = combo.getValue(); combo.setRawValue(value + ' px'); e.preventDefault(); return false; } } }, onChangeName: function (input, value) { this.props && this.props.setText(value); }, txtTitle: 'Signature', txtUpload: 'Upload', txtDraw: 'Draw', txtType: 'Type', textLooksAs: 'Signature looks as', textClear: 'Clear', textSelect: 'Select Image', txtUploadDesc: 'You can upload images in JPEG, JPG, GIF and PNG formats with a max size of 30 Mb', textBefore: 'Before signing this document, verify that the content you are signing is correct', txtRemBack: 'Remove white background', textFromUrl: 'From URL', textFromFile: 'From File', textFromStorage: 'From Storage', tipUndo: 'Undo', tipRedo: 'Redo', textBold: 'Bold', textItalic: 'Italic' }, Common.Views.PdfSignDialog || {})) });