diff --git a/apps/common/main/lib/component/ComboBoxFonts.js b/apps/common/main/lib/component/ComboBoxFonts.js index c1bf141bd..7ea19885f 100644 --- a/apps/common/main/lib/component/ComboBoxFonts.js +++ b/apps/common/main/lib/component/ComboBoxFonts.js @@ -113,6 +113,8 @@ define([ this._input.on('keyup', _.bind(this.onInputKeyUp, this)); this._input.on('keydown', _.bind(this.onInputKeyDown, this)); + this._modalParents = this.cmpEl.closest('.asc-window'); + return this; }, @@ -319,6 +321,8 @@ define([ var name = (_.isFunction(font.get_Name) ? font.get_Name() : font.asc_getName()); if (this.getRawValue() !== name) { + if (this._modalParents.length > 0) return; + var record = this.store.findWhere({ name: name }); diff --git a/apps/common/main/lib/util/utils.js b/apps/common/main/lib/util/utils.js index da546a159..45d89d50e 100644 --- a/apps/common/main/lib/util/utils.js +++ b/apps/common/main/lib/util/utils.js @@ -101,7 +101,8 @@ Common.Utils = _.extend(new(function() { Shape : 5, Slide : 6, Chart : 7, - MailMerge : 8 + MailMerge : 8, + Signature : 9 }, isMobile = /android|avantgo|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent || navigator.vendor || window.opera), me = this, diff --git a/apps/common/main/lib/view/SignDialog.js b/apps/common/main/lib/view/SignDialog.js new file mode 100644 index 000000000..c44c3bd1e --- /dev/null +++ b/apps/common/main/lib/view/SignDialog.js @@ -0,0 +1,347 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2017 + * + * 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 Lubanas st. 125a-25, Riga, Latvia, + * EU, LV-1021. + * + * 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 + * +*/ +/** + * SignDialog.js + * + * Created by Julia Radzhabova on 5/19/17 + * Copyright (c) 2017 Ascensio System SIA. All rights reserved. + * + */ + + +if (Common === undefined) + var Common = {}; + +define([ + 'common/main/lib/util/utils', + 'common/main/lib/component/InputField', + 'common/main/lib/component/Window', + 'common/main/lib/component/ComboBoxFonts' +], function () { 'use strict'; + + Common.Views.SignDialog = Common.UI.Window.extend(_.extend({ + options: { + width: 350, + style: 'min-width: 350px;', + cls: 'modal-dlg' + }, + + initialize : function(options) { + _.extend(this.options, { + title: this.textTitle + }, options || {}); + + this.api = this.options.api; + this.signType = this.options.signType || 'invisible'; + this.signSize = this.options.signSize || {width: 0, height: 0}; + this.certificateId = null; + this.signObject = null; + this.fontStore = this.options.fontStore; + this.font = { + size: 11, + name: 'Arial', + bold: false, + italic: false + }; + + this.template = [ + '
', + '
', + '
', + '', + '
', + '
', + '
', + '
', + '
', + '', + '
', + '
', + '
', + '
', + '
','
', + '
', + '', + '
', + '', + '
', + '', + '
', + '
', + '
', + '', + '', + '' + + '', + '', + '', + '
', + '
', + '' + ].join(''); + + this.templateCertificate = _.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(); + + me.inputPurpose = new Common.UI.InputField({ + el : $('#id-dlg-sign-purpose'), + style : 'width: 100%;' + }); + + me.inputName = new Common.UI.InputField({ + el : $('#id-dlg-sign-name'), + style : 'width: 100%;', + validateOnChange: true + }).on ('changing', _.bind(me.onChangeName, me)); + + me.cmbFonts = new Common.UI.ComboBoxFonts({ + el : $('#id-dlg-sign-fonts'), + cls : 'input-group-nr', + style : 'width: 214px;', + menuCls : 'scrollable-menu', + menuStyle : 'min-width: 55px;max-height: 270px;', + store : new Common.Collections.Fonts(), + recent : 0, + hint : me.tipFontName + }).on('selected', function(combo, record) { + if (me.signObject) { + me.signObject.setText(me.inputName.getValue(), record.name, me.font.size, me.font.italic, me.font.bold); + } + me.font.name = record.name; + }); + + this.cmbFontSize = new Common.UI.ComboBox({ + el: $('#id-dlg-sign-font-size'), + cls: 'input-group-nr', + style: 'width: 55px;', + menuCls : 'scrollable-menu', + menuStyle: 'min-width: 55px;max-height: 270px;', + hint: this.tipFontSize, + 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" } + ] + }).on('selected', function(combo, record) { + if (me.signObject) { + me.signObject.setText(me.inputName.getValue(), me.font.name, record.value, me.font.italic, me.font.bold); + } + me.font.size = record.value; + }); + this.cmbFontSize.setValue(this.font.size); + + me.btnBold = new Common.UI.Button({ + cls: 'btn-toolbar', + iconCls: 'btn-bold', + enableToggle: true, + hint: me.textBold + }); + me.btnBold.render($('#id-dlg-sign-bold')) ; + me.btnBold.on('click', function(btn, e) { + if (me.signObject) { + me.signObject.setText(me.inputName.getValue(), me.font.name, me.font.size, me.font.italic, btn.pressed); + } + me.font.bold = btn.pressed; + }); + + me.btnItalic = new Common.UI.Button({ + cls: 'btn-toolbar', + iconCls: 'btn-italic', + enableToggle: true, + hint: me.textItalic + }); + me.btnItalic.render($('#id-dlg-sign-italic')) ; + me.btnItalic.on('click', function(btn, e) { + if (me.signObject) { + me.signObject.setText(me.inputName.getValue(), me.font.name, me.font.size, btn.pressed, me.font.bold); + } + me.font.italic = btn.pressed; + }); + + me.btnSelectImage = new Common.UI.Button({ + el: '#id-dlg-sign-image' + }); + me.btnSelectImage.on('click', _.bind(me.onSelectImage, me)); + + me.btnChangeCertificate = new Common.UI.Button({ + el: '#id-dlg-sign-change' + }); + me.btnChangeCertificate.on('click', _.bind(me.onChangeCertificate, me)); + + me.cntCertificate = $('#id-dlg-sign-certificate'); + me.cntVisibleSign = $('#id-dlg-sign-visible'); + me.cntInvisibleSign = $('#id-dlg-sign-invisible'); + + (me.signType == 'visible') ? me.cntInvisibleSign.addClass('hidden') : me.cntVisibleSign.addClass('hidden'); + + $window.find('.dlg-btn').on('click', _.bind(me.onBtnClick, me)); + $window.find('input').on('keypress', _.bind(me.onKeyPress, me)); + + me.afterRender(); + }, + + show: function() { + Common.UI.Window.prototype.show.apply(this, arguments); + + var me = this; + _.delay(function(){ + ((me.signType == 'visible') ? me.inputName : me.inputPurpose).cmpEl.find('input').focus(); + },500); + }, + + hide: function() { + Common.UI.Window.prototype.hide.apply(this, arguments); + + if (this.signObject) + this.signObject.destroy(); + }, + + afterRender: function () { + if (this.api) { + this.api.asc_unregisterCallback('on_signature_defaultcertificate_ret', _.bind(this.onCertificateChanged, this)); + this.api.asc_registerCallback('on_signature_defaultcertificate_ret', _.bind(this.onCertificateChanged, this)); + this.api.asc_unregisterCallback('on_signature_selectsertificate_ret', _.bind(this.onCertificateChanged, this)); + this.api.asc_registerCallback('on_signature_selectsertificate_ret', _.bind(this.onCertificateChanged, this)); + this.api.asc_GetDefaultCertificate(); + } + + if (this.signType == 'visible') { + this.cmbFonts.fillFonts(this.fontStore); + this.cmbFonts.selectRecord(this.fontStore.findWhere({name: this.font.name}) || this.fontStore.at(0)); + + this.signObject = new AscCommon.CSignatureDrawer('signature-preview-img', this.api, this.signSize.width, this.signSize.height); + } + }, + + getSettings: function () { + var props = {}; + props.certificateId = this.certificateId; + if (this.signType == 'invisible') { + props.purpose = this.inputPurpose.getValue(); + } else { + props.images = this.signObject ? this.signObject.getImages() : [null, null]; + } + + return props; + }, + + onBtnClick: function(event) { + this._handleInput(event.currentTarget.attributes['result'].value); + }, + + onKeyPress: function(event) { + if (event.keyCode == Common.UI.Keys.RETURN) { + this._handleInput('ok'); + return false; + } + }, + + _handleInput: function(state) { + if (this.options.handler) { + if (state == 'ok' && this.signObject && !this.signObject.isValid()) + return; + + this.options.handler.call(this, this, state); + } + this.close(); + }, + + onChangeCertificate: function() { + this.api.asc_SelectCertificate(); + }, + + onCertificateChanged: function(certificate) { + this.certificateId = certificate.id; + var date = certificate.date, + arr_date = (typeof date == 'string') ? date.split(' - ') : ['', '']; + this.cntCertificate.html(this.templateCertificate({name: certificate.name, valid: this.textValid.replace('%1', arr_date[0]).replace('%2', arr_date[1])})); + }, + + onSelectImage: function() { + if (!this.signObject) return; + this.signObject.selectImage(); + this.inputName.setValue(''); + }, + + onChangeName: function (input, value) { + if (!this.signObject) return; + this.signObject.setText(value, this.font.name, this.font.size, this.font.italic, this.font.bold); + }, + + textTitle: 'Sign Document', + textPurpose: 'Purpose for signing this document', + textCertificate: 'Certificate', + textValid: 'Valid from %1 to %2', + textChange: 'Change', + cancelButtonText: 'Cancel', + okButtonText: 'Ok', + textInputName: 'Input signer name', + textUseImage: 'or click \'Select Image\' to use a picture as signature', + textSelectImage: 'Select Image', + textSignature: 'Signature looks as', + tipFontName: 'Font Name', + tipFontSize: 'Font Size', + textBold: 'Bold', + textItalic: 'Italic' + + }, Common.Views.SignDialog || {})) +}); \ No newline at end of file diff --git a/apps/common/main/lib/view/SignSettingsDialog.js b/apps/common/main/lib/view/SignSettingsDialog.js new file mode 100644 index 000000000..20f718568 --- /dev/null +++ b/apps/common/main/lib/view/SignSettingsDialog.js @@ -0,0 +1,203 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2017 + * + * 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 Lubanas st. 125a-25, Riga, Latvia, + * EU, LV-1021. + * + * 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 + * +*/ +/** + * SignSettingsDialog.js + * + * Created by Julia Radzhabova on 5/19/17 + * Copyright (c) 2017 Ascensio System SIA. All rights reserved. + * + */ + + +if (Common === undefined) + var Common = {}; + +define([ + 'common/main/lib/util/utils', + 'common/main/lib/component/InputField', + 'common/main/lib/component/CheckBox', + 'common/main/lib/component/Window' +], function () { 'use strict'; + + Common.Views.SignSettingsDialog = Common.UI.Window.extend(_.extend({ + options: { + width: 350, + style: 'min-width: 350px;', + cls: 'modal-dlg' + }, + + initialize : function(options) { + _.extend(this.options, { + title: this.textTitle + }, options || {}); + + this.template = [ + '
', + '
', + '', + '
', + '
', + '', + '
', + '
', + '
', + '', + '
', + '
', + '
', + '', + '
', + '
', + '
', + '', + '
', + '', + '
', + '
', + '' + ].join(''); + + this.options.tpl = _.template(this.template)(this.options); + this.api = this.options.api; + + Common.UI.Window.prototype.initialize.call(this, this.options); + }, + + render: function() { + Common.UI.Window.prototype.render.call(this); + + var me = this, + $window = this.getChild(); + + me.inputName = new Common.UI.InputField({ + el : $('#id-dlg-sign-settings-name'), + style : 'width: 100%;' + }); + + me.inputTitle = new Common.UI.InputField({ + el : $('#id-dlg-sign-settings-title'), + style : 'width: 100%;' + }); + + me.inputEmail = new Common.UI.InputField({ + el : $('#id-dlg-sign-settings-email'), + style : 'width: 100%;' + }); + + me.textareaInstructions = this.$window.find('textarea'); + me.textareaInstructions.keydown(function (event) { + if (event.keyCode == Common.UI.Keys.RETURN) { + event.stopPropagation(); + } + }); + + this.chDate = new Common.UI.CheckBox({ + el: $('#id-dlg-sign-settings-date'), + labelText: this.textShowDate + }); + + $window.find('.dlg-btn').on('click', _.bind(this.onBtnClick, this)); + $window.find('input').on('keypress', _.bind(this.onKeyPress, this)); + }, + + show: function() { + Common.UI.Window.prototype.show.apply(this, arguments); + + var me = this; + _.delay(function(){ + me.inputName.cmpEl.find('input').focus(); + },500); + }, + + setSettings: function (props) { + if (props) { + var me = this; + + // var value = props.asc_getSigner1(); + // me.inputName.setValue(value ? value : ''); + // value = props.asc_getSigner2(); + // me.inputTitle.setValue(value ? value : ''); + // value = props.asc_getEmail(); + // me.inputEmail.setValue(value ? value : ''); + // value = props.asc_getInstructions(); + // me.textareaInstructions.val(value ? value : ''); + // me.chDate.setValue(props.asc_getShowDate()); + } + }, + + getSettings: function () { + var me = this, + props = new AscCommon.asc_CSignatureLine(); + + props.asc_setSigner1(me.inputName.getValue()); + props.asc_setSigner2(me.inputTitle.getValue()); + props.asc_setEmail(me.inputEmail.getValue()); + props.asc_setInstructions(me.textareaInstructions.val()); + props.asc_setShowDate(me.chDate.getValue()=='checked'); + + return props; + }, + + onBtnClick: function(event) { + this._handleInput(event.currentTarget.attributes['result'].value); + }, + + onKeyPress: function(event) { + if (event.keyCode == Common.UI.Keys.RETURN) { + this._handleInput('ok'); + return false; + } + }, + + _handleInput: function(state) { + if (this.options.handler) + this.options.handler.call(this, this, state); + this.close(); + }, + + textInfo: 'Signer Info', + textInfoName: 'Name', + textInfoTitle: 'Signer Title', + textInfoEmail: 'E-mail', + textInstructions: 'Instructions for Signer', + cancelButtonText: 'Cancel', + okButtonText: 'Ok', + txtEmpty: 'This field is required', + textAllowComment: 'Allow signer to add comment in the signature dialog', + textShowDate: 'Show sign date in signature line', + textTitle: 'Signature Settings' + }, Common.Views.SignSettingsDialog || {})) +}); \ No newline at end of file diff --git a/apps/documenteditor/main/app/controller/LeftMenu.js b/apps/documenteditor/main/app/controller/LeftMenu.js index a05ae62e0..884c3baad 100644 --- a/apps/documenteditor/main/app/controller/LeftMenu.js +++ b/apps/documenteditor/main/app/controller/LeftMenu.js @@ -43,6 +43,8 @@ define([ 'core', 'common/main/lib/util/Shortcuts', + 'common/main/lib/view/SignSettingsDialog', + 'common/main/lib/view/SignDialog', 'documenteditor/main/app/view/LeftMenu', 'documenteditor/main/app/view/FileMenu' ], function () { @@ -85,7 +87,9 @@ define([ 'saveas:format': _.bind(this.clickSaveAsFormat, this), 'settings:apply': _.bind(this.applySettings, this), 'create:new': _.bind(this.onCreateNew, this), - 'recent:open': _.bind(this.onOpenRecent, this) + 'recent:open': _.bind(this.onOpenRecent, this), + 'signature:visible': _.bind(this.addVisibleSign, this), + 'signature:invisible': _.bind(this.addInvisibleSign, this) }, 'Toolbar': { 'file:settings': _.bind(this.clickToolbarSettings,this), @@ -676,6 +680,41 @@ define([ Common.Gateway.requestHistory(); }, + addVisibleSign: function(menu) { + var me = this, + win = new Common.Views.SignSettingsDialog({ + handler: function(dlg, result) { + if (result == 'ok') { + me.api.asc_AddSignatureLine2(dlg.getSettings()); + } + Common.NotificationCenter.trigger('edit:complete', me); + } + }); + + win.show(); + + menu.hide(); + }, + + addInvisibleSign: function(menu) { + var me = this, + win = new Common.Views.SignDialog({ + api: me.api, + signType: 'invisible', + handler: function(dlg, result) { + if (result == 'ok') { + var props = dlg.getSettings(); + me.api.asc_Sign(props.certificateId); + } + Common.NotificationCenter.trigger('edit:complete', me); + } + }); + + win.show(); + + menu.hide(); + }, + textNoTextFound : 'Text not found', newDocumentTitle : 'Unnamed document', requestEditRightsText : 'Requesting editing rights...', diff --git a/apps/documenteditor/main/app/controller/Main.js b/apps/documenteditor/main/app/controller/Main.js index d0fe09077..17d3bf213 100644 --- a/apps/documenteditor/main/app/controller/Main.js +++ b/apps/documenteditor/main/app/controller/Main.js @@ -1015,6 +1015,7 @@ define([ this.appOptions.forcesave = this.appOptions.canForcesave; this.appOptions.canEditComments= this.appOptions.isOffline || !(typeof (this.editorConfig.customization) == 'object' && this.editorConfig.customization.commentAuthorOnly); this.appOptions.trialMode = params.asc_getLicenseMode(); + this.appOptions.canProtect = this.appOptions.isDesktopApp && this.api.asc_isSignaturesSupport(); if ( this.appOptions.isLightVersion ) { this.appOptions.canUseHistory = diff --git a/apps/documenteditor/main/app/controller/RightMenu.js b/apps/documenteditor/main/app/controller/RightMenu.js index 67e8afae1..c56a64f5a 100644 --- a/apps/documenteditor/main/app/controller/RightMenu.js +++ b/apps/documenteditor/main/app/controller/RightMenu.js @@ -78,7 +78,8 @@ define([ this._settings[Common.Utils.documentSettingsType.Shape] = {panelId: "id-shape-settings", panel: rightMenu.shapeSettings, btn: rightMenu.btnShape, hidden: 1, locked: false}; this._settings[Common.Utils.documentSettingsType.TextArt] = {panelId: "id-textart-settings", panel: rightMenu.textartSettings, btn: rightMenu.btnTextArt, hidden: 1, locked: false}; this._settings[Common.Utils.documentSettingsType.Chart] = {panelId: "id-chart-settings", panel: rightMenu.chartSettings, btn: rightMenu.btnChart, hidden: 1, locked: false}; - this._settings[Common.Utils.documentSettingsType.MailMerge] = {panelId: "id-mail-merge-settings", panel: rightMenu.mergeSettings, btn: rightMenu.btnMailMerge, hidden: 1, props: {}, locked: false}; + this._settings[Common.Utils.documentSettingsType.MailMerge] = {panelId: "id-mail-merge-settings", panel: rightMenu.mergeSettings, btn: rightMenu.btnMailMerge, hidden: 1, props: {}, locked: false}; + this._settings[Common.Utils.documentSettingsType.Signature] = {panelId: "id-signature-settings", panel: rightMenu.signatureSettings, btn: rightMenu.btnSignature, hidden: (rightMenu.signatureSettings) ? 0 : 1, props: {}, locked: false}; }, setApi: function(api) { @@ -96,7 +97,7 @@ define([ var panel = this._settings[type].panel; var props = this._settings[type].props; if (props && panel) - panel.ChangeSettings.call(panel, (type==Common.Utils.documentSettingsType.MailMerge) ? undefined : props); + panel.ChangeSettings.call(panel, (type==Common.Utils.documentSettingsType.MailMerge || type==Common.Utils.documentSettingsType.Signature) ? undefined : props); } else if (minimized && type==Common.Utils.documentSettingsType.MailMerge) { this.rightmenu.mergeSettings.disablePreviewMode(); } @@ -112,13 +113,14 @@ define([ in_equation = false, needhide = true; for (var i=0; i
  • +
  • @@ -30,4 +31,5 @@
    +
    \ No newline at end of file diff --git a/apps/documenteditor/main/app/template/RightMenu.template b/apps/documenteditor/main/app/template/RightMenu.template index a0226ef70..6605f9949 100644 --- a/apps/documenteditor/main/app/template/RightMenu.template +++ b/apps/documenteditor/main/app/template/RightMenu.template @@ -16,6 +16,8 @@
    +
    +
    @@ -27,5 +29,6 @@ +
    \ No newline at end of file diff --git a/apps/documenteditor/main/app/template/SignatureSettings.template b/apps/documenteditor/main/app/template/SignatureSettings.template new file mode 100644 index 000000000..5a4fa0157 --- /dev/null +++ b/apps/documenteditor/main/app/template/SignatureSettings.template @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + +
    \ No newline at end of file diff --git a/apps/documenteditor/main/app/view/DocumentHolder.js b/apps/documenteditor/main/app/view/DocumentHolder.js index 51c8c2c72..b09e538cf 100644 --- a/apps/documenteditor/main/app/view/DocumentHolder.js +++ b/apps/documenteditor/main/app/view/DocumentHolder.js @@ -49,6 +49,7 @@ define([ 'common/main/lib/component/Menu', 'common/main/lib/view/InsertTableDialog', 'common/main/lib/view/CopyWarningDialog', + 'common/main/lib/view/SignDialog', 'documenteditor/main/app/view/DropcapSettingsAdvanced', 'documenteditor/main/app/view/HyperlinkSettingsDialog', 'documenteditor/main/app/view/ParagraphSettingsAdvanced', @@ -80,6 +81,7 @@ define([ me._currentMathObj = undefined; me._currentParaObjDisabled = false; me._isDisabled = false; + me._currentSignGuid = null; var showPopupMenu = function(menu, value, event, docElement, eOpts){ if (!_.isUndefined(menu) && menu !== null){ @@ -724,6 +726,36 @@ define([ me.mode.isEdit = false; }; + var onSignatureClick = function(guid, width, height) { + if (_.isUndefined(me.fontStore)) { + me.fontStore = new Common.Collections.Fonts(); + var fonts = DE.getController('Toolbar').getView('Toolbar').cmbFontName.store.toJSON(); + var arr = []; + _.each(fonts, function(font, index){ + if (!font.cloneid) { + arr.push(_.clone(font)); + } + }); + me.fontStore.add(arr); + } + + var win = new Common.Views.SignDialog({ + api: me.api, + signType: 'visible', + fontStore: me.fontStore, + signSize: {width: width, height: height}, + handler: function(dlg, result) { + if (result == 'ok') { + var props = dlg.getSettings(); + me.api.asc_Sign(props.certificateId, guid, props.images[0], props.images[1]); + } + Common.NotificationCenter.trigger('edit:complete'); + } + }); + + win.show(); + }; + var onTextLanguage = function(langid) { me._currLang.id = langid; }; @@ -1528,6 +1560,7 @@ define([ this.api.asc_registerCallback('asc_onShowSpecialPasteOptions', _.bind(onShowSpecialPasteOptions, this)); this.api.asc_registerCallback('asc_onHideSpecialPasteOptions', _.bind(onHideSpecialPasteOptions, this)); + this.api.asc_registerCallback('asc_onSignatureClick', _.bind(onSignatureClick, this)); } return this; diff --git a/apps/documenteditor/main/app/view/FileMenu.js b/apps/documenteditor/main/app/view/FileMenu.js index 542e822a5..9be53947c 100644 --- a/apps/documenteditor/main/app/view/FileMenu.js +++ b/apps/documenteditor/main/app/view/FileMenu.js @@ -168,6 +168,12 @@ define([ this.miSaveAs, this.miPrint, this.miRename, + new Common.UI.MenuItem({ + el : $('#fm-btn-protect',this.el), + action : 'protect', + caption : this.btnProtectCaption, + canFocused: false + }), this.miRecent, this.miNew, new Common.UI.MenuItem({ @@ -234,7 +240,8 @@ define([ applyMode: function() { this.miPrint[this.mode.canPrint?'show':'hide'](); this.miRename[(this.mode.canRename && !this.mode.isDesktopApp) ?'show':'hide'](); - this.miRename.$el.find('+.devider')[!this.mode.isDisconnected?'show':'hide'](); + this.items[7][(this.mode.canProtect) ?'show':'hide'](); + this.items[7].$el.find('+.devider')[!this.mode.isDisconnected?'show':'hide'](); this.miRecent[this.mode.canOpenRecent?'show':'hide'](); this.miNew[this.mode.canCreateNew?'show':'hide'](); this.miNew.$el.find('+.devider')[this.mode.canCreateNew?'show':'hide'](); @@ -270,8 +277,10 @@ define([ } } - if (this.mode.isDesktopApp) { + if (this.mode.canProtect) { // this.$el.find('#fm-btn-back').hide(); + this.panels['protect'] = (new DE.Views.FileMenuPanels.ProtectDoc({menu:this})).render(); + this.panels['protect'].setMode(this.mode); } if (this.mode.canDownload) { @@ -302,6 +311,7 @@ define([ setApi: function(api) { this.api = api; this.panels['info'].setApi(api); + if (this.panels['protect']) this.panels['protect'].setApi(api); }, loadDocument: function(data) { @@ -360,6 +370,7 @@ define([ btnSaveAsCaption : 'Save as', textDownload : 'Download', btnRenameCaption : 'Rename...', - btnCloseMenuCaption : 'Close Menu' + btnCloseMenuCaption : 'Close Menu', + btnProtectCaption: 'Protect\\Sign' }, DE.Views.FileMenu || {})); }); diff --git a/apps/documenteditor/main/app/view/FileMenuPanels.js b/apps/documenteditor/main/app/view/FileMenuPanels.js index 8ef6e6458..c10a95fc8 100644 --- a/apps/documenteditor/main/app/view/FileMenuPanels.js +++ b/apps/documenteditor/main/app/view/FileMenuPanels.js @@ -1097,4 +1097,136 @@ define([ } } }); + + DE.Views.FileMenuPanels.ProtectDoc = Common.UI.BaseView.extend(_.extend({ + el: '#panel-protect', + menu: undefined, + + template: _.template([ + '', + '', + '', + '
    ', + '
    ', + '
    ' + ].join('')), + + initialize: function(options) { + Common.UI.BaseView.prototype.initialize.call(this,arguments); + + this.menu = options.menu; + + this.templateRequested = _.template([ + '', + '', + '<% _.each(signatures, function(item) { %>', + '', + '', + '', + '<% }); %>', + '
    <%= Common.Utils.String.htmlEncode(item) %>
    ' + ].join('')); + + this.templateValid = _.template([ + '', + '', + '<% _.each(signatures, function(item) { %>', + '', + '', + '', + '', + '<% }); %>', + '
    <%= Common.Utils.String.htmlEncode(item.name) %><%= Common.Utils.String.htmlEncode(item.date) %>
    ' + ].join('')); + }, + + render: function() { + $(this.el).html(this.template({scope: this})); + + this.btnAddInvisibleSign = new Common.UI.Button({ + el: '#fms-btn-invisible-sign' + }); + this.btnAddInvisibleSign.on('click', _.bind(this.addInvisibleSign, this)); + + this.btnAddVisibleSign = new Common.UI.Button({ + el: '#fms-btn-visible-sign' + }); + this.btnAddVisibleSign.on('click', _.bind(this.addVisibleSign, this)); + + this.lblSignHeader = $('#id-fms-lbl-sign-header', this.$el); + + this.cntRequestedSign = $('#id-fms-requested-sign'); + this.cntValidSign = $('#id-fms-valid-sign'); + this.cntInvalidSign = $('#id-fms-invalid-sign'); + + if (_.isUndefined(this.scroller)) { + this.scroller = new Common.UI.Scroller({ + el: $(this.el), + suppressScrollX: true + }); + } + + return this; + }, + + show: function() { + Common.UI.BaseView.prototype.show.call(this,arguments); + this.updateSignatures(); + }, + + setMode: function(mode) { + this.mode = mode; + if (!this.mode.isEdit) { + this.btnAddInvisibleSign.setVisible(false); + this.btnAddVisibleSign.setVisible(false); + this.lblSignHeader.html(this.strSignature); + } + }, + + setApi: function(o) { + this.api = o; + return this; + }, + + addInvisibleSign: function() { + if (this.menu) + this.menu.fireEvent('signature:invisible', [this.menu]); + }, + + addVisibleSign: function() { + if (this.menu) + this.menu.fireEvent('signature:visible', [this.menu]); + }, + + updateSignatures: function(){ + var requested = this.api.asc_getRequestSignatures(), + requested_arr = [], + valid = this.api.asc_getSignatures(), + valid_arr = [], invalid_arr = []; + + _.each(requested, function(item, index){ + requested_arr.push(item.asc_getSigner1()); + }); + _.each(valid, function(item, index){ + var sign = {name: item.asc_getSigner1(), date: '18/05/2017'}; + (item.asc_getValid()==0) ? valid_arr.push(sign) : invalid_arr.push(sign); + }); + this.cntRequestedSign.html(this.templateRequested({signatures: requested_arr, header: this.strRequested})); + this.cntValidSign.html(this.templateValid({signatures: valid_arr, header: this.strValid})); + this.cntInvalidSign.html(this.templateValid({signatures: invalid_arr, header: this.strInvalid})); + // this.cntRequestedSign.html(this.templateRequested({signatures: ['Hammish Mitchell', 'Someone Somewhere', 'Mary White', 'John Black'], header: this.strRequested})); + // this.cntValidSign.html(this.templateValid({signatures: [{name: 'Hammish Mitchell', date: '18/05/2017'}, {name: 'Someone Somewhere', date: '18/05/2017'}], header: this.strValid})); + // this.cntInvalidSign.html(this.templateValid({signatures: [{name: 'Mary White', date: '18/05/2017'}, {name: 'John Black', date: '18/05/2017'}], header: this.strInvalid})); + }, + + strProtect: 'Protect Document', + strInvisibleSign: 'Add invisible digital signature', + strVisibleSign: 'Add visible signature', + strRequested: 'Requested signatures', + strValid: 'Valid signatures', + strInvalid: 'Invalid signatures', + strSignature: 'Signature' + + }, DE.Views.FileMenuPanels.ProtectDoc || {})); + }); diff --git a/apps/documenteditor/main/app/view/RightMenu.js b/apps/documenteditor/main/app/view/RightMenu.js index 0d52aace0..453cd508e 100644 --- a/apps/documenteditor/main/app/view/RightMenu.js +++ b/apps/documenteditor/main/app/view/RightMenu.js @@ -57,6 +57,7 @@ define([ 'documenteditor/main/app/view/ShapeSettings', 'documenteditor/main/app/view/MailMergeSettings', 'documenteditor/main/app/view/TextArtSettings', + 'documenteditor/main/app/view/SignatureSettings', 'common/main/lib/component/Scroller' ], function (menuTemplate, $, _, Backbone) { 'use strict'; @@ -194,6 +195,21 @@ define([ this.mergeSettings = new DE.Views.MailMergeSettings(); } + if (mode && mode.canProtect) { + this.btnSignature = new Common.UI.Button({ + hint: this.txtSignatureSettings, + asctype: Common.Utils.documentSettingsType.Signature, + enableToggle: true, + disabled: true, + toggleGroup: 'tabpanelbtnsGroup' + }); + this._settings[Common.Utils.documentSettingsType.Signature] = {panel: "id-signature-settings", btn: this.btnSignature}; + + this.btnSignature.el = $('#id-right-menu-signature'); this.btnSignature.render().setVisible(true); + this.btnSignature.on('click', _.bind(this.onBtnMenuClick, this)); + this.signatureSettings = new DE.Views.SignatureSettings(); + } + if (_.isUndefined(this.scroller)) { this.scroller = new Common.UI.Scroller({ el: $(this.el).find('.right-panel'), @@ -223,6 +239,7 @@ define([ this.shapeSettings.setApi(api).on('editcomplete', _.bind( fire, this)); this.textartSettings.setApi(api).on('editcomplete', _.bind( fire, this)); if (this.mergeSettings) this.mergeSettings.setApi(api).on('editcomplete', _.bind( fire, this)); + if (this.signatureSettings) this.signatureSettings.setApi(api).on('editcomplete', _.bind( fire, this)); }, setMode: function(mode) { @@ -303,6 +320,7 @@ define([ txtShapeSettings: 'Shape Settings', txtTextArtSettings: 'Text Art Settings', txtChartSettings: 'Chart Settings', - txtMailMergeSettings: 'Mail Merge Settings' + txtMailMergeSettings: 'Mail Merge Settings', + txtSignatureSettings: 'Signature Settings' }, DE.Views.RightMenu || {})); }); \ No newline at end of file diff --git a/apps/documenteditor/main/app/view/SignatureSettings.js b/apps/documenteditor/main/app/view/SignatureSettings.js new file mode 100644 index 000000000..d05122ec3 --- /dev/null +++ b/apps/documenteditor/main/app/view/SignatureSettings.js @@ -0,0 +1,288 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2017 + * + * 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 Lubanas st. 125a-25, Riga, Latvia, + * EU, LV-1021. + * + * 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 + * +*/ +/** + * SignatureSettings.js + * + * Created by Julia Radzhabova on 5/24/17 + * Copyright (c) 2017 Ascensio System SIA. All rights reserved. + * + */ + +define([ + 'text!documenteditor/main/app/template/SignatureSettings.template', + 'jquery', + 'underscore', + 'backbone', + 'common/main/lib/component/Button', + 'common/main/lib/view/SignDialog', + 'common/main/lib/view/SignSettingsDialog' +], function (menuTemplate, $, _, Backbone) { + 'use strict'; + + DE.Views.SignatureSettings = Backbone.View.extend(_.extend({ + el: '#id-signature-settings', + + // Compile our stats template + template: _.template(menuTemplate), + + // Delegated events for creating new items, and clearing completed ones. + events: { + }, + + options: { + alias: 'SignatureSettings' + }, + + initialize: function () { + var me = this; + + this._initSettings = true; + + this._state = { + DisabledControls: false, + requestedSignatures: undefined, + validSignatures: undefined, + invalidSignatures: undefined + }; + this._locked = false; + this.lockedControls = []; + + this._noApply = false; + this._originalProps = null; + + this.templateRequested = _.template([ + '', + '', + '', + '<% _.each(signatures, function(item) { %>', + '', + '', + '', + '', + '<% }); %>', + '
    ', + '' + ].join('')); + + this.templateValid = _.template([ + '', + '', + '', + '<% _.each(signatures, function(item) { %>', + '', + '', + '', + '', + '', + '<% }); %>', + '
    <%= Common.Utils.String.htmlEncode(item.name) %>
    <%= Common.Utils.String.htmlEncode(item.date) %>
    ', + '' + ].join('')); + + this.render(); + }, + + render: function () { + this.$el.html(this.template({ + scope: this + })); + + this.btnAddInvisibleSign = new Common.UI.Button({ + el: this.$el.find('#signature-invisible-sign') + }); + this.btnAddInvisibleSign.on('click', _.bind(this.addInvisibleSign, this)); + this.lockedControls.push(this.btnAddInvisibleSign); + + this.btnAddVisibleSign = new Common.UI.Button({ + el: this.$el.find('#signature-visible-sign') + }); + this.btnAddVisibleSign.on('click', _.bind(this.addVisibleSign, this)); + this.lockedControls.push(this.btnAddVisibleSign); + + this.cntRequestedSign = $('#signature-requested-sign'); + this.cntValidSign = $('#signature-valid-sign'); + this.cntInvalidSign = $('#signature-invalid-sign'); + }, + + setApi: function(api) { + this.api = api; + if (this.api) { + this.api.asc_registerCallback('asc_onUpdateSignatures', _.bind(this.onUpdateSignatures, this)); + } + return this; + }, + + createDelayedControls: function() { + this._initSettings = false; + }, + + ChangeSettings: function(props) { + if (this._initSettings) + this.createDelayedControls(); + + if (!this._state.requestedSignatures || !this._state.validSignatures || !this._state.invalidSignatures) { + this.onUpdateSignatures(this.api.asc_getSignatures(), this.api.asc_getRequestSignatures()); + } + + this.disableControls(this._locked); + }, + + setLocked: function (locked) { + this._locked = locked; + }, + + disableControls: function(disable) { + if (this._initSettings) return; + + if (this._state.DisabledControls!==disable) { + this._state.DisabledControls = disable; + _.each(this.lockedControls, function(item) { + item.setDisabled(disable); + }); + this.$linksSign.toggleClass('disabled', disable); + this.$linksView.toggleClass('disabled', disable); + } + }, + + setMode: function(mode) { + this.mode = mode; + }, + + onUpdateSignatures: function(valid, requested){ + var me = this; + me._state.requestedSignatures = []; + me._state.validSignatures = []; + me._state.invalidSignatures = []; + + _.each(requested, function(item, index){ + me._state.requestedSignatures.push({name: item.asc_getSigner1(), guid: item.asc_getGuid()}); + }); + _.each(valid, function(item, index){ + var sign = {name: item.asc_getSigner1(), guid: item.asc_getId(), date: '18/05/2017'}; + (item.asc_getValid()==0) ? me._state.validSignatures.push(sign) : me._state.invalidSignatures.push(sign); + }); + this.cntRequestedSign.html(this.templateRequested({signatures: me._state.requestedSignatures, header: this.strRequested})); + this.cntValidSign.html(this.templateValid({signatures: me._state.validSignatures, header: this.strValid})); + this.cntInvalidSign.html(this.templateValid({signatures: me._state.invalidSignatures, header: this.strInvalid})); + // this.cntRequestedSign.html(this.templateRequested({signatures: [{name: 'Hammish Mitchell', guid: '123'}, {name: 'Someone Somewhere', guid: '123'}, {name: 'Mary White', guid: '123'}, {name: 'John Black', guid: '123'}], header: this.strRequested})); + // this.cntValidSign.html(this.templateValid({signatures: [{name: 'Hammish Mitchell', guid: '123', date: '18/05/2017'}, {name: 'Someone Somewhere', guid: '345', date: '18/05/2017'}], header: this.strValid})); + // this.cntInvalidSign.html(this.templateValid({signatures: [{name: 'Mary White', guid: '111', date: '18/05/2017'}, {name: 'John Black', guid: '456', date: '18/05/2017'}], header: this.strInvalid})); + + this.$linksSign = $('.signature-sign-link', this.$el); + this.$linksView = $('.signature-view-link', this.$el); + this.$el.on('click', '.signature-sign-link', _.bind(this.onSign, this)); + this.$el.on('click', '.signature-view-link', _.bind(this.onViewSignature, this)); + }, + + addVisibleSign: function(btn) { + var me = this, + win = new Common.Views.SignSettingsDialog({ + handler: function(dlg, result) { + if (result == 'ok') { + me.api.asc_AddSignatureLine2(dlg.getSettings()); + } + me.fireEvent('editcomplete', me); + } + }); + + win.show(); + }, + + addInvisibleSign: function(btn) { + var me = this, + win = new Common.Views.SignDialog({ + api: me.api, + signType: 'invisible', + handler: function(dlg, result) { + if (result == 'ok') { + var props = dlg.getSettings(); + me.api.asc_Sign(props.certificateId); + } + me.fireEvent('editcomplete', me); + } + }); + + win.show(); + }, + + onSign: function(event) { + var me = this, + target = $(event.currentTarget); + + if (target.hasClass('disabled')) return; + + if (_.isUndefined(me.fontStore)) { + me.fontStore = new Common.Collections.Fonts(); + var fonts = DE.getController('Toolbar').getView('Toolbar').cmbFontName.store.toJSON(); + var arr = []; + _.each(fonts, function(font, index){ + if (!font.cloneid) { + arr.push(_.clone(font)); + } + }); + me.fontStore.add(arr); + } + + var win = new Common.Views.SignDialog({ + api: me.api, + signType: 'visible', + fontStore: me.fontStore, + handler: function(dlg, result) { + if (result == 'ok') { + var props = dlg.getSettings(); + me.api.asc_Sign(props.certificateId, target.attr('data-value'), props.images[0], props.images[1]); + } + me.fireEvent('editcomplete', me); + } + }); + win.show(); + }, + + onViewSignature: function(event) { + var target = $(event.currentTarget); + if (target.hasClass('disabled')) return; + + this.api.asc_ViewCertificate(target.attr('data-value')); + }, + + strSignature: 'Signature', + strInvisibleSign: 'Add invisible digital signature', + strVisibleSign: 'Add visible signature', + strRequested: 'Requested signatures', + strValid: 'Valid signatures', + strInvalid: 'Invalid signatures', + strSign: 'Sign', + strView: 'View' + + }, DE.Views.SignatureSettings || {})); +}); \ No newline at end of file diff --git a/apps/documenteditor/main/locale/en.json b/apps/documenteditor/main/locale/en.json index 630f89fa0..4b4e0df75 100644 --- a/apps/documenteditor/main/locale/en.json +++ b/apps/documenteditor/main/locale/en.json @@ -228,6 +228,32 @@ "Common.Views.ReviewChangesDialog.txtReject": "Reject", "Common.Views.ReviewChangesDialog.txtRejectAll": "Reject All Changes", "Common.Views.ReviewChangesDialog.txtRejectCurrent": "Reject Current Change", + "Common.Views.SignDialog.textTitle": "Sign Document", + "Common.Views.SignDialog.textPurpose": "Purpose for signing this document", + "Common.Views.SignDialog.textCertificate": "Certificate", + "Common.Views.SignDialog.textValid": "Valid from %1 to %2", + "Common.Views.SignDialog.textChange": "Change", + "Common.Views.SignDialog.cancelButtonText": "Cancel", + "Common.Views.SignDialog.okButtonText": "Ok", + "Common.Views.SignDialog.textInputName": "Input signer name", + "Common.Views.SignDialog.textUseImage": "or click 'Select Image' to use a picture as signature", + "Common.Views.SignDialog.textSelectImage": "Select Image", + "Common.Views.SignDialog.textSignature": "Signature looks as", + "Common.Views.SignDialog.tipFontName": "Font Name", + "Common.Views.SignDialog.tipFontSize": "Font Size", + "Common.Views.SignDialog.textBold": "Bold", + "Common.Views.SignDialog.textItalic": "Italic", + "Common.Views.SignSettingsDialog.textInfo": "Signer Info", + "Common.Views.SignSettingsDialog.textInfoName": "Name", + "Common.Views.SignSettingsDialog.textInfoTitle": "Signer Title", + "Common.Views.SignSettingsDialog.textInfoEmail": "E-mail", + "Common.Views.SignSettingsDialog.textInstructions": "Instructions for Signer", + "Common.Views.SignSettingsDialog.cancelButtonText": "Cancel", + "Common.Views.SignSettingsDialog.okButtonText": "Ok", + "Common.Views.SignSettingsDialog.txtEmpty": "This field is required", + "Common.Views.SignSettingsDialog.textAllowComment": "Allow signer to add comment in the signature dialog", + "Common.Views.SignSettingsDialog.textShowDate": "Show sign date in signature line", + "Common.Views.SignSettingsDialog.textTitle": "Signature Settings", "DE.Controllers.LeftMenu.leavePageText": "All unsaved changes in this document will be lost.
    Click \"Cancel\" then \"Save\" to save them. Click \"OK\" to discard all the unsaved changes.", "DE.Controllers.LeftMenu.newDocumentTitle": "Unnamed document", "DE.Controllers.LeftMenu.notcriticalErrorTitle": "Warning", @@ -963,6 +989,7 @@ "DE.Views.FileMenu.btnSettingsCaption": "Advanced Settings...", "DE.Views.FileMenu.btnToEditCaption": "Edit Document", "DE.Views.FileMenu.textDownload": "Download", + "DE.Views.FileMenu.btnProtectCaption": "Protect\\Sign", "DE.Views.FileMenuPanels.CreateNew.fromBlankText": "From Blank", "DE.Views.FileMenuPanels.CreateNew.fromTemplateText": "From Template", "DE.Views.FileMenuPanels.CreateNew.newDescriptionText": "Create a new blank text document which you will be able to style and format after it is created during the editing. Or choose one of the templates to start a document of a certain type or purpose where some styles have already been pre-applied.", @@ -1029,6 +1056,13 @@ "DE.Views.HeaderFooterSettings.textBottomCenter": "Bottom center", "DE.Views.HeaderFooterSettings.textBottomLeft": "Bottom left", "DE.Views.HeaderFooterSettings.textBottomRight": "Bottom right", + "DE.Views.FileMenuPanels.ProtectDoc.strProtect": "Protect Document", + "DE.Views.FileMenuPanels.ProtectDoc.strInvisibleSign": "Add invisible digital signature", + "DE.Views.FileMenuPanels.ProtectDoc.strVisibleSign": "Add visible signature", + "DE.Views.FileMenuPanels.ProtectDoc.strRequested": "Requested signatures", + "DE.Views.FileMenuPanels.ProtectDoc.strValid": "Valid signatures", + "DE.Views.FileMenuPanels.ProtectDoc.strInvalid": "Invalid signatures", + "DE.Views.FileMenuPanels.ProtectDoc.strSignature": "Signature", "DE.Views.HeaderFooterSettings.textDiffFirst": "Different first page", "DE.Views.HeaderFooterSettings.textDiffOdd": "Different odd and even pages", "DE.Views.HeaderFooterSettings.textHeaderFromBottom": "Footer from Bottom", @@ -1307,6 +1341,7 @@ "DE.Views.RightMenu.txtShapeSettings": "Shape settings", "DE.Views.RightMenu.txtTableSettings": "Table settings", "DE.Views.RightMenu.txtTextArtSettings": "Text Art settings", + "DE.Views.RightMenu.txtSignatureSettings": "Signature Settings", "DE.Views.ShapeSettings.strBackground": "Background color", "DE.Views.ShapeSettings.strChange": "Change Autoshape", "DE.Views.ShapeSettings.strColor": "Color", @@ -1357,6 +1392,14 @@ "DE.Views.ShapeSettings.txtTight": "Tight", "DE.Views.ShapeSettings.txtTopAndBottom": "Top and bottom", "DE.Views.ShapeSettings.txtWood": "Wood", + "DE.Views.SignatureSettings.strSignature": "Signature", + "DE.Views.SignatureSettings.strInvisibleSign": "Add invisible digital signature", + "DE.Views.SignatureSettings.strVisibleSign": "Add visible signature", + "DE.Views.SignatureSettings.strRequested": "Requested signatures", + "DE.Views.SignatureSettings.strValid": "Valid signatures", + "DE.Views.SignatureSettings.strInvalid": "Invalid signatures", + "DE.Views.SignatureSettings.strSign": "Sign", + "DE.Views.SignatureSettings.strView": "View", "DE.Views.Statusbar.goToPageText": "Go to Page", "DE.Views.Statusbar.pageIndexText": "Page {0} of {1}", "DE.Views.Statusbar.tipFitPage": "Fit to page", diff --git a/apps/documenteditor/main/resources/img/toolbar-menu.png b/apps/documenteditor/main/resources/img/toolbar-menu.png index 8eda1c7d8..c7d05082f 100644 Binary files a/apps/documenteditor/main/resources/img/toolbar-menu.png and b/apps/documenteditor/main/resources/img/toolbar-menu.png differ diff --git a/apps/documenteditor/main/resources/img/toolbar-menu@2x.png b/apps/documenteditor/main/resources/img/toolbar-menu@2x.png index b9f258d3f..c544741f9 100644 Binary files a/apps/documenteditor/main/resources/img/toolbar-menu@2x.png and b/apps/documenteditor/main/resources/img/toolbar-menu@2x.png differ diff --git a/apps/documenteditor/main/resources/less/leftmenu.less b/apps/documenteditor/main/resources/less/leftmenu.less index ee490c488..faf5a8bc4 100644 --- a/apps/documenteditor/main/resources/less/leftmenu.less +++ b/apps/documenteditor/main/resources/less/leftmenu.less @@ -77,4 +77,32 @@ button.notify .btn-menu-comments {background-position: -0*@toolbar-icon-size -60 -webkit-transform: rotate(180deg); -o-transform: rotate(180deg); transform: rotate(180deg); +} + +#panel-protect { + #file-menu-panel & { + padding: 30px 30px; + } + + + button { + display: block; + width: auto; + margin-top: 20px; + } + + label { + font: 12px tahoma, arial, verdana, sans-serif; + } + + .header { + font-weight: bold; + margin: 30px 0 10px; + } + + table { + td { + padding: 5px 5px; + } + } } \ No newline at end of file diff --git a/apps/documenteditor/main/resources/less/rightmenu.less b/apps/documenteditor/main/resources/less/rightmenu.less index 2983c04f0..f4ea5aab2 100644 --- a/apps/documenteditor/main/resources/less/rightmenu.less +++ b/apps/documenteditor/main/resources/less/rightmenu.less @@ -105,6 +105,7 @@ /*menuTextArt*/ .button-normal-icon(btn-menu-textart, 54, @toolbar-icon-size); +.button-normal-icon(btn-menu-signature, 78, @toolbar-icon-size); .button-otherstates-icon2(btn-category, @toolbar-icon-size); diff --git a/apps/documenteditor/main/resources/less/toolbar.less b/apps/documenteditor/main/resources/less/toolbar.less index 171114fe6..af45fb7fb 100644 --- a/apps/documenteditor/main/resources/less/toolbar.less +++ b/apps/documenteditor/main/resources/less/toolbar.less @@ -312,12 +312,6 @@ .button-normal-icon(mmerge-first, 74, @toolbar-icon-size); //.button-normal-icon(btn-columns, 75, @toolbar-icon-size); //.button-normal-icon(btn-pagemargins, 76, @toolbar-icon-size); -//.button-normal-icon(btn-img-frwd, 83, @toolbar-icon-size); -//.button-normal-icon(btn-img-bkwd, 84, @toolbar-icon-size); -//.button-normal-icon(btn-img-wrap, 85, @toolbar-icon-size); -//.button-normal-icon(btn-img-group, 86, @toolbar-icon-size); -//.button-normal-icon(btn-img-align, 87, @toolbar-icon-size); -.button-normal-icon(btn-goback, 88, @toolbar-icon-size); //.button-normal-icon(btn-insertimage, 17, @toolbar-icon-size); //.button-normal-icon(btn-inserttable, 18, @toolbar-icon-size); @@ -328,11 +322,6 @@ //.button-normal-icon(btn-insertequation, 53, @toolbar-icon-size); //.button-normal-icon(btn-dropcap, 50, @toolbar-icon-size); //.button-normal-icon(btn-ic-doclang, 67, @toolbar-icon-size); -//.button-normal-icon(btn-notes, 78, @toolbar-icon-size); -//.button-normal-icon(review-prev, 79, @toolbar-icon-size); -//.button-normal-icon(review-next, 80, @toolbar-icon-size); -//.button-normal-icon(review-save, 81, @toolbar-icon-size); -//.button-normal-icon(review-deny, 82, @toolbar-icon-size); @menu-icon-size: 22px; .menu-icon-normal(mnu-wrap-inline, 0, @menu-icon-size); diff --git a/apps/presentationeditor/main/app/controller/LeftMenu.js b/apps/presentationeditor/main/app/controller/LeftMenu.js index 45e4e9550..2edbc567b 100644 --- a/apps/presentationeditor/main/app/controller/LeftMenu.js +++ b/apps/presentationeditor/main/app/controller/LeftMenu.js @@ -43,6 +43,7 @@ define([ 'core', 'common/main/lib/util/Shortcuts', + 'common/main/lib/view/SignDialog', 'presentationeditor/main/app/view/LeftMenu', 'presentationeditor/main/app/view/FileMenu' ], function () { @@ -83,7 +84,8 @@ define([ 'saveas:format': _.bind(this.clickSaveAsFormat, this), 'settings:apply': _.bind(this.applySettings, this), 'create:new': _.bind(this.onCreateNew, this), - 'recent:open': _.bind(this.onOpenRecent, this) + 'recent:open': _.bind(this.onOpenRecent, this), + 'signature:invisible': _.bind(this.addInvisibleSign, this) }, 'Toolbar': { 'file:settings': _.bind(this.clickToolbarSettings,this), @@ -533,18 +535,37 @@ define([ }, onPluginOpen: function(panel, type, action) { - if ( type == 'onboard' ) { - if ( action == 'open' ) { + if (type == 'onboard') { + if (action == 'open') { this.leftMenu.close(); this.leftMenu.btnThumbs.toggle(false, false); this.leftMenu.panelPlugins.show(); - this.leftMenu.onBtnMenuClick({pressed:true, options: {action: 'plugins'}}); + this.leftMenu.onBtnMenuClick({pressed: true, options: {action: 'plugins'}}); } else { this.leftMenu.close(); } } }, + addInvisibleSign: function(menu) { + var me = this, + win = new Common.Views.SignDialog({ + api: me.api, + signType: 'invisible', + handler: function(dlg, result) { + if (result == 'ok') { + var props = dlg.getSettings(); + me.api.asc_Sign(props.certificateId); + } + Common.NotificationCenter.trigger('edit:complete', me); + } + }); + + win.show(); + + menu.hide(); + }, + textNoTextFound : 'Text not found', newDocumentTitle : 'Unnamed document', requestEditRightsText : 'Requesting editing rights...' diff --git a/apps/presentationeditor/main/app/controller/Main.js b/apps/presentationeditor/main/app/controller/Main.js index 9412332c1..4b1c88f24 100644 --- a/apps/presentationeditor/main/app/controller/Main.js +++ b/apps/presentationeditor/main/app/controller/Main.js @@ -787,6 +787,7 @@ define([ this.appOptions.forcesave = this.appOptions.canForcesave; this.appOptions.canEditComments= this.appOptions.isOffline || !(typeof (this.editorConfig.customization) == 'object' && this.editorConfig.customization.commentAuthorOnly); this.appOptions.trialMode = params.asc_getLicenseMode(); + this.appOptions.canProtect = this.appOptions.isDesktopApp && this.api.asc_isSignaturesSupport(); this._state.licenseWarning = (licType===Asc.c_oLicenseResult.Connections) && this.appOptions.canEdit && this.editorConfig.mode !== 'view'; diff --git a/apps/presentationeditor/main/app/controller/RightMenu.js b/apps/presentationeditor/main/app/controller/RightMenu.js index a625e3887..b9aa0bf20 100644 --- a/apps/presentationeditor/main/app/controller/RightMenu.js +++ b/apps/presentationeditor/main/app/controller/RightMenu.js @@ -79,6 +79,7 @@ define([ this._settings[Common.Utils.documentSettingsType.Shape] = {panelId: "id-shape-settings", panel: rightMenu.shapeSettings, btn: rightMenu.btnShape, hidden: 1, locked: false}; this._settings[Common.Utils.documentSettingsType.TextArt] = {panelId: "id-textart-settings", panel: rightMenu.textartSettings, btn: rightMenu.btnTextArt, hidden: 1, locked: false}; this._settings[Common.Utils.documentSettingsType.Chart] = {panelId: "id-chart-settings", panel: rightMenu.chartSettings, btn: rightMenu.btnChart, hidden: 1, locked: false}; + this._settings[Common.Utils.documentSettingsType.Signature] = {panelId: "id-signature-settings", panel: rightMenu.signatureSettings, btn: rightMenu.btnSignature, hidden: (rightMenu.signatureSettings) ? 0 : 1, props: {}, locked: false}; }, setApi: function(api) { @@ -97,7 +98,7 @@ define([ var panel = this._settings[type].panel; var props = this._settings[type].props; if (props && panel) - panel.ChangeSettings.call(panel, props); + panel.ChangeSettings.call(panel, (type==Common.Utils.documentSettingsType.Signature) ? undefined : props); } Common.NotificationCenter.trigger('layout:changed', 'rightmenu'); this.rightmenu.fireEvent('editcomplete', this.rightmenu); @@ -109,12 +110,14 @@ define([ var needhide = true; for (var i=0; i0) ? 0 : 1; + this._settings[Common.Utils.documentSettingsType.Signature].locked = false; for (i=0; i
  • +
  • @@ -29,4 +30,5 @@
    +
    \ No newline at end of file diff --git a/apps/presentationeditor/main/app/template/RightMenu.template b/apps/presentationeditor/main/app/template/RightMenu.template index baba70c3e..f4cfb2d7b 100644 --- a/apps/presentationeditor/main/app/template/RightMenu.template +++ b/apps/presentationeditor/main/app/template/RightMenu.template @@ -14,6 +14,8 @@
    +
    +
    @@ -24,5 +26,6 @@ +
    \ No newline at end of file diff --git a/apps/presentationeditor/main/app/template/SignatureSettings.template b/apps/presentationeditor/main/app/template/SignatureSettings.template new file mode 100644 index 000000000..b5b986dc7 --- /dev/null +++ b/apps/presentationeditor/main/app/template/SignatureSettings.template @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + +
    + +
    + +
    \ No newline at end of file diff --git a/apps/presentationeditor/main/app/view/DocumentHolder.js b/apps/presentationeditor/main/app/view/DocumentHolder.js index af797dd8c..7e5cd5083 100644 --- a/apps/presentationeditor/main/app/view/DocumentHolder.js +++ b/apps/presentationeditor/main/app/view/DocumentHolder.js @@ -38,6 +38,7 @@ define([ 'common/main/lib/util/utils', 'common/main/lib/component/Menu', 'common/main/lib/view/CopyWarningDialog', + 'common/main/lib/view/SignDialog', 'presentationeditor/main/app/view/HyperlinkSettingsDialog', // 'common/main/lib/view/InsertTableDialog', 'presentationeditor/main/app/view/ParagraphSettingsAdvanced', @@ -678,6 +679,36 @@ define([ } }; + var onSignatureClick = function(guid, width, height) { + if (_.isUndefined(me.fontStore)) { + me.fontStore = new Common.Collections.Fonts(); + var fonts = PE.getController('Toolbar').getView('Toolbar').cmbFontName.store.toJSON(); + var arr = []; + _.each(fonts, function(font, index){ + if (!font.cloneid) { + arr.push(_.clone(font)); + } + }); + me.fontStore.add(arr); + } + + var win = new Common.Views.SignDialog({ + api: me.api, + signType: 'visible', + fontStore: me.fontStore, + signSize: {width: width, height: height}, + handler: function(dlg, result) { + if (result == 'ok') { + var props = dlg.getSettings(); + me.api.asc_Sign(props.certificateId, guid, props.images[0], props.images[1]); + } + me.fireEvent('editcomplete', me); + } + }); + + win.show(); + }; + var onTextLanguage = function(langid) { me._currLang.id = langid; }; @@ -1518,6 +1549,7 @@ define([ me.api.asc_registerCallback('asc_onUpdateThemeIndex', _.bind(onApiUpdateThemeIndex, me)); me.api.asc_registerCallback('asc_onLockDocumentTheme', _.bind(onApiLockDocumentTheme, me)); me.api.asc_registerCallback('asc_onUnLockDocumentTheme', _.bind(onApiUnLockDocumentTheme, me)); + me.api.asc_registerCallback('asc_onSignatureClick', _.bind(onSignatureClick, me)); } return me; diff --git a/apps/presentationeditor/main/app/view/FileMenu.js b/apps/presentationeditor/main/app/view/FileMenu.js index e6d79d23d..d8c9fd30c 100644 --- a/apps/presentationeditor/main/app/view/FileMenu.js +++ b/apps/presentationeditor/main/app/view/FileMenu.js @@ -164,6 +164,12 @@ define([ this.miSaveAs, this.miPrint, this.miRename, + new Common.UI.MenuItem({ + el : $('#fm-btn-protect',this.el), + action : 'protect', + caption : this.btnProtectCaption, + canFocused: false + }), this.miRecent, this.miNew, new Common.UI.MenuItem({ @@ -228,7 +234,8 @@ define([ applyMode: function() { this.miPrint[this.mode.canPrint?'show':'hide'](); this.miRename[(this.mode.canRename && !this.mode.isDesktopApp) ?'show':'hide'](); - this.miRename.$el.find('+.devider')[!this.mode.isDisconnected?'show':'hide'](); + this.items[7][(this.mode.canProtect) ?'show':'hide'](); + this.items[7].$el.find('+.devider')[!this.mode.isDisconnected?'show':'hide'](); this.miRecent[this.mode.canOpenRecent?'show':'hide'](); this.miNew[this.mode.canCreateNew?'show':'hide'](); this.miNew.$el.find('+.devider')[this.mode.canCreateNew?'show':'hide'](); @@ -264,8 +271,10 @@ define([ } } - if (this.mode.targetApp == 'desktop') { + if (this.mode.canProtect) { this.$el.find('#fm-btn-create, #fm-btn-back, #fm-btn-create+.devider').hide(); + this.panels['protect'] = (new PE.Views.FileMenuPanels.ProtectDoc({menu:this})).render(); + this.panels['protect'].setMode(this.mode); } this.panels['help'].setLangConfig(this.mode.lang); @@ -288,6 +297,7 @@ define([ setApi: function(api) { this.api = api; + if (this.panels['protect']) this.panels['protect'].setApi(api); this.api.asc_registerCallback('asc_onDocumentName', _.bind(this.onDocumentName, this)); }, @@ -354,6 +364,7 @@ define([ btnSettingsCaption : 'Advanced Settings...', btnSaveAsCaption : 'Save as', btnRenameCaption : 'Rename...', - btnCloseMenuCaption : 'Close Menu' + btnCloseMenuCaption : 'Close Menu', + btnProtectCaption: 'Protect\\Sign' }, PE.Views.FileMenu || {})); }); diff --git a/apps/presentationeditor/main/app/view/FileMenuPanels.js b/apps/presentationeditor/main/app/view/FileMenuPanels.js index 4aae8916d..22b38dbbf 100644 --- a/apps/presentationeditor/main/app/view/FileMenuPanels.js +++ b/apps/presentationeditor/main/app/view/FileMenuPanels.js @@ -866,4 +866,102 @@ define([ } } }); + + PE.Views.FileMenuPanels.ProtectDoc = Common.UI.BaseView.extend(_.extend({ + el: '#panel-protect', + menu: undefined, + + template: _.template([ + '', + '', + '
    ', + '
    ' + ].join('')), + + initialize: function(options) { + Common.UI.BaseView.prototype.initialize.call(this,arguments); + + this.menu = options.menu; + + this.templateValid = _.template([ + '', + '', + '<% _.each(signatures, function(item) { %>', + '', + '', + '', + '', + '<% }); %>', + '
    <%= Common.Utils.String.htmlEncode(item.name) %><%= Common.Utils.String.htmlEncode(item.date) %>
    ' + ].join('')); + }, + + render: function() { + $(this.el).html(this.template({scope: this})); + + this.btnAddInvisibleSign = new Common.UI.Button({ + el: '#fms-btn-invisible-sign' + }); + this.btnAddInvisibleSign.on('click', _.bind(this.addInvisibleSign, this)); + + this.lblSignHeader = $('#id-fms-lbl-sign-header', this.$el); + + this.cntValidSign = $('#id-fms-valid-sign'); + this.cntInvalidSign = $('#id-fms-invalid-sign'); + + if (_.isUndefined(this.scroller)) { + this.scroller = new Common.UI.Scroller({ + el: $(this.el), + suppressScrollX: true + }); + } + + return this; + }, + + show: function() { + Common.UI.BaseView.prototype.show.call(this,arguments); + this.updateSignatures(); + }, + + setMode: function(mode) { + this.mode = mode; + if (!this.mode.isEdit) { + this.btnAddInvisibleSign.setVisible(false); + this.lblSignHeader.html(this.strSignature); + } + }, + + setApi: function(o) { + this.api = o; + return this; + }, + + addInvisibleSign: function() { + if (this.menu) + this.menu.fireEvent('signature:invisible', [this.menu]); + }, + + updateSignatures: function(){ + var valid = this.api.asc_getSignatures(), + valid_arr = [], invalid_arr = []; + + _.each(valid, function(item, index){ + var sign = {name: item.asc_getSigner1(), date: '18/05/2017'}; + (item.asc_getValid()==0) ? valid_arr.push(sign) : invalid_arr.push(sign); + }); + this.cntValidSign.html(this.templateValid({signatures: valid_arr, header: this.strValid})); + this.cntInvalidSign.html(this.templateValid({signatures: invalid_arr, header: this.strInvalid})); + // this.cntValidSign.html(this.templateValid({signatures: [{name: 'Hammish Mitchell', date: '18/05/2017'}, {name: 'Someone Somewhere', date: '18/05/2017'}], header: this.strValid})); + // this.cntInvalidSign.html(this.templateValid({signatures: [{name: 'Mary White', date: '18/05/2017'}, {name: 'John Black', date: '18/05/2017'}], header: this.strInvalid})); + }, + + strProtect: 'Protect Document', + strInvisibleSign: 'Add invisible digital signature', + strValid: 'Valid signatures', + strInvalid: 'Invalid signatures', + strSignature: 'Signature' + + }, PE.Views.FileMenuPanels.ProtectDoc || {})); + }); diff --git a/apps/presentationeditor/main/app/view/RightMenu.js b/apps/presentationeditor/main/app/view/RightMenu.js index fe1d4583a..9f12f3b79 100644 --- a/apps/presentationeditor/main/app/view/RightMenu.js +++ b/apps/presentationeditor/main/app/view/RightMenu.js @@ -56,6 +56,7 @@ define([ 'presentationeditor/main/app/view/ShapeSettings', 'presentationeditor/main/app/view/SlideSettings', 'presentationeditor/main/app/view/TextArtSettings', + 'presentationeditor/main/app/view/SignatureSettings', 'common/main/lib/component/Scroller' ], function (menuTemplate, $, _, Backbone) { 'use strict'; @@ -143,7 +144,7 @@ define([ return this; }, - render: function () { + render: function (mode) { var el = $(this.el); this.trigger('render:before', this); @@ -178,6 +179,21 @@ define([ this.shapeSettings = new PE.Views.ShapeSettings(); this.textartSettings = new PE.Views.TextArtSettings(); + if (mode && mode.canProtect) { + this.btnSignature = new Common.UI.Button({ + hint: this.txtSignatureSettings, + asctype: Common.Utils.documentSettingsType.Signature, + enableToggle: true, + disabled: true, + toggleGroup: 'tabpanelbtnsGroup' + }); + this._settings[Common.Utils.documentSettingsType.Signature] = {panel: "id-signature-settings", btn: this.btnSignature}; + + this.btnSignature.el = $('#id-right-menu-signature'); this.btnSignature.render().setVisible(true); + this.btnSignature.on('click', _.bind(this.onBtnMenuClick, this)); + this.signatureSettings = new PE.Views.SignatureSettings(); + } + if (_.isUndefined(this.scroller)) { this.scroller = new Common.UI.Scroller({ el: $(this.el).find('.right-panel'), @@ -206,6 +222,7 @@ define([ this.tableSettings.setApi(api).on('editcomplete', _.bind( fire, this)); this.shapeSettings.setApi(api).on('editcomplete', _.bind( fire, this)); this.textartSettings.setApi(api).on('editcomplete', _.bind( fire, this)); + if (this.signatureSettings) this.signatureSettings.setApi(api).on('editcomplete', _.bind( fire, this)); }, setMode: function(mode) { @@ -299,6 +316,7 @@ define([ txtShapeSettings: 'Shape Settings', txtTextArtSettings: 'Text Art Settings', txtSlideSettings: 'Slide Settings', - txtChartSettings: 'Chart Settings' + txtChartSettings: 'Chart Settings', + txtSignatureSettings: 'Signature Settings' }, PE.Views.RightMenu || {})); }); \ No newline at end of file diff --git a/apps/presentationeditor/main/app/view/SignatureSettings.js b/apps/presentationeditor/main/app/view/SignatureSettings.js new file mode 100644 index 000000000..7a9a52228 --- /dev/null +++ b/apps/presentationeditor/main/app/view/SignatureSettings.js @@ -0,0 +1,207 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2017 + * + * 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 Lubanas st. 125a-25, Riga, Latvia, + * EU, LV-1021. + * + * 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 + * +*/ +/** + * SignatureSettings.js + * + * Created by Julia Radzhabova on 5/24/17 + * Copyright (c) 2017 Ascensio System SIA. All rights reserved. + * + */ + +define([ + 'text!presentationeditor/main/app/template/SignatureSettings.template', + 'jquery', + 'underscore', + 'backbone', + 'common/main/lib/component/Button', + 'common/main/lib/view/SignDialog' +], function (menuTemplate, $, _, Backbone) { + 'use strict'; + + PE.Views.SignatureSettings = Backbone.View.extend(_.extend({ + el: '#id-signature-settings', + + // Compile our stats template + template: _.template(menuTemplate), + + // Delegated events for creating new items, and clearing completed ones. + events: { + }, + + options: { + alias: 'SignatureSettings' + }, + + initialize: function () { + var me = this; + + this._initSettings = true; + + this._state = { + DisabledControls: false, + validSignatures: undefined, + invalidSignatures: undefined + }; + this._locked = false; + this.lockedControls = []; + + this._noApply = false; + this._originalProps = null; + + this.templateValid = _.template([ + '', + '', + '', + '<% _.each(signatures, function(item) { %>', + '', + '', + '', + '', + '', + '<% }); %>', + '
    <%= Common.Utils.String.htmlEncode(item.name) %>
    <%= Common.Utils.String.htmlEncode(item.date) %>
    ', + '' + ].join('')); + + this.render(); + }, + + render: function () { + this.$el.html(this.template({ + scope: this + })); + + this.btnAddInvisibleSign = new Common.UI.Button({ + el: this.$el.find('#signature-invisible-sign') + }); + this.btnAddInvisibleSign.on('click', _.bind(this.addInvisibleSign, this)); + this.lockedControls.push(this.btnAddInvisibleSign); + + this.cntValidSign = $('#signature-valid-sign'); + this.cntInvalidSign = $('#signature-invalid-sign'); + }, + + setApi: function(api) { + this.api = api; + if (this.api) { + this.api.asc_registerCallback('asc_onUpdateSignatures', _.bind(this.onUpdateSignatures, this)); + } + return this; + }, + + createDelayedControls: function() { + this._initSettings = false; + }, + + ChangeSettings: function(props) { + if (this._initSettings) + this.createDelayedControls(); + + if (!this._state.validSignatures || !this._state.invalidSignatures) { + this.onUpdateSignatures(this.api.asc_getSignatures()); + } + + this.disableControls(this._locked); + }, + + setLocked: function (locked) { + this._locked = locked; + }, + + disableControls: function(disable) { + if (this._initSettings) return; + + if (this._state.DisabledControls!==disable) { + this._state.DisabledControls = disable; + _.each(this.lockedControls, function(item) { + item.setDisabled(disable); + }); + this.$linksSign.toggleClass('disabled', disable); + this.$linksView.toggleClass('disabled', disable); + } + }, + + setMode: function(mode) { + this.mode = mode; + }, + + onUpdateSignatures: function(valid){ + var me = this; + me._state.validSignatures = []; + me._state.invalidSignatures = []; + + _.each(valid, function(item, index){ + var sign = {name: item.asc_getSigner1(), guid: item.asc_getId(), date: '18/05/2017'}; + (item.asc_getValid()==0) ? me._state.validSignatures.push(sign) : me._state.invalidSignatures.push(sign); + }); + this.cntValidSign.html(this.templateValid({signatures: me._state.validSignatures, header: this.strValid})); + this.cntInvalidSign.html(this.templateValid({signatures: me._state.invalidSignatures, header: this.strInvalid})); + // this.cntValidSign.html(this.templateValid({signatures: [{name: 'Hammish Mitchell', guid: '123', date: '18/05/2017'}, {name: 'Someone Somewhere', guid: '345', date: '18/05/2017'}], header: this.strValid})); + // this.cntInvalidSign.html(this.templateValid({signatures: [{name: 'Mary White', guid: '111', date: '18/05/2017'}, {name: 'John Black', guid: '456', date: '18/05/2017'}], header: this.strInvalid})); + + this.$linksView = $('.signature-view-link', this.$el); + this.$el.on('click', '.signature-view-link', _.bind(this.onViewSignature, this)); + }, + + addInvisibleSign: function(btn) { + var me = this, + win = new Common.Views.SignDialog({ + api: me.api, + signType: 'invisible', + handler: function(dlg, result) { + if (result == 'ok') { + var props = dlg.getSettings(); + me.api.asc_Sign(props.certificateId); + } + me.fireEvent('editcomplete', me); + } + }); + + win.show(); + }, + + onViewSignature: function(event) { + var target = $(event.currentTarget); + if (target.hasClass('disabled')) return; + + this.api.asc_ViewCertificate(target.attr('data-value')); + }, + + strSignature: 'Signature', + strInvisibleSign: 'Add invisible digital signature', + strValid: 'Valid signatures', + strInvalid: 'Invalid signatures', + strView: 'View' + + }, PE.Views.SignatureSettings || {})); +}); \ No newline at end of file diff --git a/apps/presentationeditor/main/app/view/Viewport.js b/apps/presentationeditor/main/app/view/Viewport.js index e7da2ea5f..e1be9b2d2 100644 --- a/apps/presentationeditor/main/app/view/Viewport.js +++ b/apps/presentationeditor/main/app/view/Viewport.js @@ -123,7 +123,7 @@ define([ }, applyEditorMode: function() { - PE.getController('RightMenu').getView('RightMenu').render(); + PE.getController('RightMenu').getView('RightMenu').render(this.mode); if ( Common.localStorage.getBool('pe-hidden-status') ) PE.getController('Statusbar').getView('Statusbar').setVisible(false); diff --git a/apps/presentationeditor/main/locale/en.json b/apps/presentationeditor/main/locale/en.json index 30ef68240..72032e2bf 100644 --- a/apps/presentationeditor/main/locale/en.json +++ b/apps/presentationeditor/main/locale/en.json @@ -126,6 +126,32 @@ "Common.Views.RenameDialog.okButtonText": "Ok", "Common.Views.RenameDialog.textName": "File name", "Common.Views.RenameDialog.txtInvalidName": "The file name cannot contain any of the following characters: ", + "Common.Views.SignDialog.textTitle": "Sign Document", + "Common.Views.SignDialog.textPurpose": "Purpose for signing this document", + "Common.Views.SignDialog.textCertificate": "Certificate", + "Common.Views.SignDialog.textValid": "Valid from %1 to %2", + "Common.Views.SignDialog.textChange": "Change", + "Common.Views.SignDialog.cancelButtonText": "Cancel", + "Common.Views.SignDialog.okButtonText": "Ok", + "Common.Views.SignDialog.textInputName": "Input signer name", + "Common.Views.SignDialog.textUseImage": "or click 'Select Image' to use a picture as signature", + "Common.Views.SignDialog.textSelectImage": "Select Image", + "Common.Views.SignDialog.textSignature": "Signature looks as", + "Common.Views.SignDialog.tipFontName": "Font Name", + "Common.Views.SignDialog.tipFontSize": "Font Size", + "Common.Views.SignDialog.textBold": "Bold", + "Common.Views.SignDialog.textItalic": "Italic", + "Common.Views.SignSettingsDialog.textInfo": "Signer Info", + "Common.Views.SignSettingsDialog.textInfoName": "Name", + "Common.Views.SignSettingsDialog.textInfoTitle": "Signer Title", + "Common.Views.SignSettingsDialog.textInfoEmail": "E-mail", + "Common.Views.SignSettingsDialog.textInstructions": "Instructions for Signer", + "Common.Views.SignSettingsDialog.cancelButtonText": "Cancel", + "Common.Views.SignSettingsDialog.okButtonText": "Ok", + "Common.Views.SignSettingsDialog.txtEmpty": "This field is required", + "Common.Views.SignSettingsDialog.textAllowComment": "Allow signer to add comment in the signature dialog", + "Common.Views.SignSettingsDialog.textShowDate": "Show sign date in signature line", + "Common.Views.SignSettingsDialog.textTitle": "Signature Settings", "PE.Controllers.LeftMenu.newDocumentTitle": "Unnamed presentation", "PE.Controllers.LeftMenu.requestEditRightsText": "Requesting editing rights...", "PE.Controllers.LeftMenu.textNoTextFound": "The data you have been searching for could not be found. Please adjust your search options.", @@ -817,6 +843,7 @@ "PE.Views.FileMenu.btnSaveCaption": "Save", "PE.Views.FileMenu.btnSettingsCaption": "Advanced Settings...", "PE.Views.FileMenu.btnToEditCaption": "Edit Presentation", + "PE.Views.FileMenu.btnProtectCaption": "Protect\\Sign", "PE.Views.FileMenuPanels.CreateNew.fromBlankText": "From Blank", "PE.Views.FileMenuPanels.CreateNew.fromTemplateText": "From Template", "PE.Views.FileMenuPanels.CreateNew.newDescriptionText": "Create a new blank presentation which you will be able to style and format after it is created during the editing. Or choose one of the templates to start a presentation of a certain type or purpose where some styles have already been pre-applied.", @@ -865,6 +892,11 @@ "PE.Views.FileMenuPanels.Settings.txtLast": "View Last", "PE.Views.FileMenuPanels.Settings.txtPt": "Point", "PE.Views.FileMenuPanels.Settings.txtSpellCheck": "Spell Checking", + "PE.Views.FileMenuPanels.ProtectDoc.strProtect": "Protect Document", + "PE.Views.FileMenuPanels.ProtectDoc.strInvisibleSign": "Add invisible digital signature", + "PE.Views.FileMenuPanels.ProtectDoc.strValid": "Valid signatures", + "PE.Views.FileMenuPanels.ProtectDoc.strInvalid": "Invalid signatures", + "PE.Views.FileMenuPanels.ProtectDoc.strSignature": "Signature", "PE.Views.HyperlinkSettingsDialog.cancelButtonText": "Cancel", "PE.Views.HyperlinkSettingsDialog.okButtonText": "OK", "PE.Views.HyperlinkSettingsDialog.strDisplay": "Display", @@ -964,6 +996,7 @@ "PE.Views.RightMenu.txtSlideSettings": "Slide settings", "PE.Views.RightMenu.txtTableSettings": "Table settings", "PE.Views.RightMenu.txtTextArtSettings": "Text Art settings", + "PE.Views.RightMenu.txtSignatureSettings": "Signature Settings", "PE.Views.ShapeSettings.strBackground": "Background color", "PE.Views.ShapeSettings.strChange": "Change Autoshape", "PE.Views.ShapeSettings.strColor": "Color", @@ -1006,6 +1039,11 @@ "PE.Views.ShapeSettings.txtNoBorders": "No Line", "PE.Views.ShapeSettings.txtPapyrus": "Papyrus", "PE.Views.ShapeSettings.txtWood": "Wood", + "PE.Views.SignatureSettings.strSignature": "Signature", + "PE.Views.SignatureSettings.strInvisibleSign": "Add invisible digital signature", + "PE.Views.SignatureSettings.strValid": "Valid signatures", + "PE.Views.SignatureSettings.strInvalid": "Invalid signatures", + "PE.Views.SignatureSettings.strView": "View", "PE.Views.ShapeSettingsAdvanced.cancelButtonText": "Cancel", "PE.Views.ShapeSettingsAdvanced.okButtonText": "OK", "PE.Views.ShapeSettingsAdvanced.strColumns": "Columns", diff --git a/apps/presentationeditor/main/resources/img/toolbar-menu.png b/apps/presentationeditor/main/resources/img/toolbar-menu.png index 2c5504c88..9e974f07a 100644 Binary files a/apps/presentationeditor/main/resources/img/toolbar-menu.png and b/apps/presentationeditor/main/resources/img/toolbar-menu.png differ diff --git a/apps/presentationeditor/main/resources/img/toolbar-menu@2x.png b/apps/presentationeditor/main/resources/img/toolbar-menu@2x.png index b379daadb..019642884 100644 Binary files a/apps/presentationeditor/main/resources/img/toolbar-menu@2x.png and b/apps/presentationeditor/main/resources/img/toolbar-menu@2x.png differ diff --git a/apps/presentationeditor/main/resources/less/leftmenu.less b/apps/presentationeditor/main/resources/less/leftmenu.less index d12639436..92711e3a2 100644 --- a/apps/presentationeditor/main/resources/less/leftmenu.less +++ b/apps/presentationeditor/main/resources/less/leftmenu.less @@ -468,4 +468,32 @@ -webkit-transform: rotate(180deg); -o-transform: rotate(180deg); transform: rotate(180deg); +} + +#panel-protect { + #file-menu-panel & { + padding: 30px 30px; + } + + + button { + display: block; + width: auto; + margin-top: 20px; + } + + label { + font: 12px tahoma, arial, verdana, sans-serif; + } + + .header { + font-weight: bold; + margin: 30px 0 10px; + } + + table { + td { + padding: 5px 5px; + } + } } \ No newline at end of file diff --git a/apps/presentationeditor/main/resources/less/rightmenu.less b/apps/presentationeditor/main/resources/less/rightmenu.less index c2955f812..ede64e887 100644 --- a/apps/presentationeditor/main/resources/less/rightmenu.less +++ b/apps/presentationeditor/main/resources/less/rightmenu.less @@ -26,6 +26,9 @@ /*menuTextArt*/ .toolbar-btn-icon(btn-menu-textart, 57, @toolbar-icon-size); + + /**menuSignature*/ + .toolbar-btn-icon(btn-menu-signature, 77, @toolbar-icon-size); } } diff --git a/apps/spreadsheeteditor/main/app/controller/DocumentHolder.js b/apps/spreadsheeteditor/main/app/controller/DocumentHolder.js index 1ca136c2b..559e87d97 100644 --- a/apps/spreadsheeteditor/main/app/controller/DocumentHolder.js +++ b/apps/spreadsheeteditor/main/app/controller/DocumentHolder.js @@ -44,6 +44,7 @@ define([ 'core', 'common/main/lib/util/utils', 'common/main/lib/view/CopyWarningDialog', + 'common/main/lib/view/SignDialog', 'spreadsheeteditor/main/app/view/DocumentHolder', 'spreadsheeteditor/main/app/view/HyperlinkSettingsDialog', 'spreadsheeteditor/main/app/view/ParagraphSettingsAdvanced', @@ -267,6 +268,7 @@ define([ this.api.asc_registerCallback('asc_onShowSpecialPasteOptions', _.bind(this.onShowSpecialPasteOptions, this)); this.api.asc_registerCallback('asc_onHideSpecialPasteOptions', _.bind(this.onHideSpecialPasteOptions, this)); } + this.api.asc_registerCallback('asc_onSignatureClick', _.bind(this.onSignatureClick, this)); return this; }, @@ -2434,6 +2436,37 @@ define([ _conf && view.paraBulletsPicker.selectRecord(_conf.rec, true); }, + onSignatureClick: function(guid, width, height) { + var me = this; + if (_.isUndefined(me.fontStore)) { + me.fontStore = new Common.Collections.Fonts(); + var fonts = SSE.getController('Toolbar').getView('Toolbar').cmbFontName.store.toJSON(); + var arr = []; + _.each(fonts, function(font, index){ + if (!font.cloneid) { + arr.push(_.clone(font)); + } + }); + me.fontStore.add(arr); + } + + var win = new Common.Views.SignDialog({ + api: me.api, + signType: 'visible', + fontStore: me.fontStore, + signSize: {width: width, height: height}, + handler: function(dlg, result) { + if (result == 'ok') { + var props = dlg.getSettings(); + me.api.asc_Sign(props.certificateId, guid, props.images[0], props.images[1]); + } + Common.NotificationCenter.trigger('edit:complete', me.documentHolder); + } + }); + + win.show(); + }, + guestText : 'Guest', textCtrlClick : 'Press CTRL and click link', txtHeight : 'Height', diff --git a/apps/spreadsheeteditor/main/app/controller/LeftMenu.js b/apps/spreadsheeteditor/main/app/controller/LeftMenu.js index 4ee7ee9a8..2401b5cfa 100644 --- a/apps/spreadsheeteditor/main/app/controller/LeftMenu.js +++ b/apps/spreadsheeteditor/main/app/controller/LeftMenu.js @@ -33,6 +33,8 @@ define([ 'core', 'common/main/lib/util/Shortcuts', + 'common/main/lib/view/SignSettingsDialog', + 'common/main/lib/view/SignDialog', 'spreadsheeteditor/main/app/view/LeftMenu', 'spreadsheeteditor/main/app/view/FileMenu' ], function () { @@ -73,7 +75,9 @@ define([ 'saveas:format': _.bind(this.clickSaveAsFormat, this), 'settings:apply': _.bind(this.applySettings, this), 'create:new': _.bind(this.onCreateNew, this), - 'recent:open': _.bind(this.onOpenRecent, this) + 'recent:open': _.bind(this.onOpenRecent, this), + 'signature:visible': _.bind(this.addVisibleSign, this), + 'signature:invisible': _.bind(this.addInvisibleSign, this) }, 'Toolbar': { 'file:settings': _.bind(this.clickToolbarSettings,this), @@ -751,11 +755,11 @@ define([ }, onPluginOpen: function(panel, type, action) { - if ( type == 'onboard' ) { - if ( action == 'open' ) { + if (type == 'onboard') { + if (action == 'open') { this.leftMenu.close(); this.leftMenu.panelPlugins.show(); - this.leftMenu.onBtnMenuClick({pressed:true, options: {action: 'plugins'}}); + this.leftMenu.onBtnMenuClick({pressed: true, options: {action: 'plugins'}}); this.leftMenu._state.pluginIsRunning = true; } else { this.leftMenu._state.pluginIsRunning = false; @@ -764,6 +768,41 @@ define([ } }, + addVisibleSign: function(menu) { + var me = this, + win = new Common.Views.SignSettingsDialog({ + handler: function(dlg, result) { + if (result == 'ok') { + me.api.asc_AddSignatureLine2(dlg.getSettings()); + } + Common.NotificationCenter.trigger('edit:complete', me); + } + }); + + win.show(); + + menu.hide(); + }, + + addInvisibleSign: function(menu) { + var me = this, + win = new Common.Views.SignDialog({ + api: me.api, + signType: 'invisible', + handler: function(dlg, result) { + if (result == 'ok') { + var props = dlg.getSettings(); + me.api.asc_Sign(props.certificateId); + } + Common.NotificationCenter.trigger('edit:complete', me); + } + }); + + win.show(); + + menu.hide(); + }, + textNoTextFound : 'Text not found', newDocumentTitle : 'Unnamed document', textItemEntireCell : 'Entire cell contents', diff --git a/apps/spreadsheeteditor/main/app/controller/Main.js b/apps/spreadsheeteditor/main/app/controller/Main.js index 9bf081dbd..ddd2693f9 100644 --- a/apps/spreadsheeteditor/main/app/controller/Main.js +++ b/apps/spreadsheeteditor/main/app/controller/Main.js @@ -808,6 +808,7 @@ define([ this.appOptions.canChat = this.appOptions.canLicense && !this.appOptions.isOffline && !((typeof (this.editorConfig.customization) == 'object') && this.editorConfig.customization.chat===false); this.appOptions.canRename = !!this.permissions.rename; this.appOptions.trialMode = params.asc_getLicenseMode(); + this.appOptions.canProtect = this.appOptions.isDesktopApp && this.api.asc_isSignaturesSupport(); this.appOptions.canBranding = (licType === Asc.c_oLicenseResult.Success) && (typeof this.editorConfig.customization == 'object'); if (this.appOptions.canBranding) diff --git a/apps/spreadsheeteditor/main/app/controller/RightMenu.js b/apps/spreadsheeteditor/main/app/controller/RightMenu.js index 85af0e8a4..9a5c5acf2 100644 --- a/apps/spreadsheeteditor/main/app/controller/RightMenu.js +++ b/apps/spreadsheeteditor/main/app/controller/RightMenu.js @@ -85,6 +85,7 @@ define([ this._settings[Common.Utils.documentSettingsType.TextArt] = {panelId: "id-textart-settings", panel: rightMenu.textartSettings, btn: rightMenu.btnTextArt, hidden: 1, locked: false}; this._settings[Common.Utils.documentSettingsType.Chart] = {panelId: "id-chart-settings", panel: rightMenu.chartSettings, btn: rightMenu.btnChart, hidden: 1, locked: false}; this._settings[Common.Utils.documentSettingsType.Table] = {panelId: "id-table-settings", panel: rightMenu.tableSettings, btn: rightMenu.btnTable, hidden: 1, locked: false}; + this._settings[Common.Utils.documentSettingsType.Signature] = {panelId: "id-signature-settings", panel: rightMenu.signatureSettings, btn: rightMenu.btnSignature, hidden: (rightMenu.signatureSettings) ? 0 : 1, props: {}, locked: false}; }, setApi: function(api) { @@ -103,7 +104,7 @@ define([ var panel = this._settings[type].panel; var props = this._settings[type].props; if (props && panel) - panel.ChangeSettings.call(panel, props); + panel.ChangeSettings.call(panel, (type==Common.Utils.documentSettingsType.Signature) ? undefined : props); } Common.NotificationCenter.trigger('layout:changed', 'rightmenu'); }, @@ -138,11 +139,13 @@ define([ return; for (var i=0; i
  • +
  • @@ -29,4 +30,5 @@
    +
    \ No newline at end of file diff --git a/apps/spreadsheeteditor/main/app/template/RightMenu.template b/apps/spreadsheeteditor/main/app/template/RightMenu.template index 1f7d9abf6..24c8de9ca 100644 --- a/apps/spreadsheeteditor/main/app/template/RightMenu.template +++ b/apps/spreadsheeteditor/main/app/template/RightMenu.template @@ -12,6 +12,8 @@
    +
    +
    @@ -21,5 +23,6 @@ +
    \ No newline at end of file diff --git a/apps/spreadsheeteditor/main/app/template/SignatureSettings.template b/apps/spreadsheeteditor/main/app/template/SignatureSettings.template new file mode 100644 index 000000000..5a4fa0157 --- /dev/null +++ b/apps/spreadsheeteditor/main/app/template/SignatureSettings.template @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + +
    \ No newline at end of file diff --git a/apps/spreadsheeteditor/main/app/view/FileMenu.js b/apps/spreadsheeteditor/main/app/view/FileMenu.js index f1067ae56..674408d44 100644 --- a/apps/spreadsheeteditor/main/app/view/FileMenu.js +++ b/apps/spreadsheeteditor/main/app/view/FileMenu.js @@ -158,6 +158,12 @@ define([ this.miSaveAs, this.miPrint, this.miRename, + new Common.UI.MenuItem({ + el : $('#fm-btn-protect',this.el), + action : 'protect', + caption : this.btnProtectCaption, + canFocused: false + }), this.miRecent, this.miNew, new Common.UI.MenuItem({ @@ -217,7 +223,8 @@ define([ applyMode: function() { this.miPrint[this.mode.canPrint?'show':'hide'](); this.miRename[(this.mode.canRename && !this.mode.isDesktopApp) ?'show':'hide'](); - this.miRename.$el.find('+.devider')[!this.mode.isDisconnected?'show':'hide'](); + this.items[7][(this.mode.canProtect) ?'show':'hide'](); + this.items[7].$el.find('+.devider')[!this.mode.isDisconnected?'show':'hide'](); this.miRecent[this.mode.canOpenRecent?'show':'hide'](); this.miNew[this.mode.canCreateNew?'show':'hide'](); this.miNew.$el.find('+.devider')[this.mode.canCreateNew?'show':'hide'](); @@ -255,6 +262,11 @@ define([ } } + if (this.mode.canProtect) { + this.panels['protect'] = (new SSE.Views.FileMenuPanels.ProtectDoc({menu:this})).render(); + this.panels['protect'].setMode(this.mode); + } + this.panels['help'].setLangConfig(this.mode.lang); }, @@ -276,6 +288,7 @@ define([ setApi: function(api) { this.api = api; if (this.panels['opts']) this.panels['opts'].setApi(api); + if (this.panels['protect']) this.panels['protect'].setApi(api); this.api.asc_registerCallback('asc_onDocumentName', _.bind(this.onDocumentName, this)); }, @@ -333,6 +346,7 @@ define([ btnSettingsCaption : 'Advanced Settings...', btnSaveAsCaption : 'Save as', btnRenameCaption : 'Rename...', - btnCloseMenuCaption : 'Close Menu' + btnCloseMenuCaption : 'Close Menu', + btnProtectCaption: 'Protect\\Sign' }, SSE.Views.FileMenu || {})); }); diff --git a/apps/spreadsheeteditor/main/app/view/FileMenuPanels.js b/apps/spreadsheeteditor/main/app/view/FileMenuPanels.js index 8f765ea10..73d97b9ee 100644 --- a/apps/spreadsheeteditor/main/app/view/FileMenuPanels.js +++ b/apps/spreadsheeteditor/main/app/view/FileMenuPanels.js @@ -1333,4 +1333,136 @@ define([ } } }); + + SSE.Views.FileMenuPanels.ProtectDoc = Common.UI.BaseView.extend(_.extend({ + el: '#panel-protect', + menu: undefined, + + template: _.template([ + '', + '', + '', + '
    ', + '
    ', + '
    ' + ].join('')), + + initialize: function(options) { + Common.UI.BaseView.prototype.initialize.call(this,arguments); + + this.menu = options.menu; + + this.templateRequested = _.template([ + '', + '', + '<% _.each(signatures, function(item) { %>', + '', + '', + '', + '<% }); %>', + '
    <%= Common.Utils.String.htmlEncode(item) %>
    ' + ].join('')); + + this.templateValid = _.template([ + '', + '', + '<% _.each(signatures, function(item) { %>', + '', + '', + '', + '', + '<% }); %>', + '
    <%= Common.Utils.String.htmlEncode(item.name) %><%= Common.Utils.String.htmlEncode(item.date) %>
    ' + ].join('')); + }, + + render: function() { + $(this.el).html(this.template({scope: this})); + + this.btnAddInvisibleSign = new Common.UI.Button({ + el: '#fms-btn-invisible-sign' + }); + this.btnAddInvisibleSign.on('click', _.bind(this.addInvisibleSign, this)); + + this.btnAddVisibleSign = new Common.UI.Button({ + el: '#fms-btn-visible-sign' + }); + this.btnAddVisibleSign.on('click', _.bind(this.addVisibleSign, this)); + + this.lblSignHeader = $('#id-fms-lbl-sign-header', this.$el); + + this.cntRequestedSign = $('#id-fms-requested-sign'); + this.cntValidSign = $('#id-fms-valid-sign'); + this.cntInvalidSign = $('#id-fms-invalid-sign'); + + if (_.isUndefined(this.scroller)) { + this.scroller = new Common.UI.Scroller({ + el: $(this.el), + suppressScrollX: true + }); + } + + return this; + }, + + show: function() { + Common.UI.BaseView.prototype.show.call(this,arguments); + this.updateSignatures(); + }, + + setMode: function(mode) { + this.mode = mode; + if (!this.mode.isEdit) { + this.btnAddInvisibleSign.setVisible(false); + this.btnAddVisibleSign.setVisible(false); + this.lblSignHeader.html(this.strSignature); + } + }, + + setApi: function(o) { + this.api = o; + return this; + }, + + addInvisibleSign: function() { + if (this.menu) + this.menu.fireEvent('signature:invisible', [this.menu]); + }, + + addVisibleSign: function() { + if (this.menu) + this.menu.fireEvent('signature:visible', [this.menu]); + }, + + updateSignatures: function(){ + var requested = this.api.asc_getRequestSignatures(), + requested_arr = [], + valid = this.api.asc_getSignatures(), + valid_arr = [], invalid_arr = []; + + _.each(requested, function(item, index){ + requested_arr.push(item.asc_getSigner1()); + }); + _.each(valid, function(item, index){ + var sign = {name: item.asc_getSigner1(), date: '18/05/2017'}; + (item.asc_getValid()==0) ? valid_arr.push(sign) : invalid_arr.push(sign); + }); + this.cntRequestedSign.html(this.templateRequested({signatures: requested_arr, header: this.strRequested})); + this.cntValidSign.html(this.templateValid({signatures: valid_arr, header: this.strValid})); + this.cntInvalidSign.html(this.templateValid({signatures: invalid_arr, header: this.strInvalid})); + // this.cntRequestedSign.html(this.templateRequested({signatures: ['Hammish Mitchell', 'Someone Somewhere', 'Mary White', 'John Black'], header: this.strRequested})); + // this.cntValidSign.html(this.templateValid({signatures: [{name: 'Hammish Mitchell', date: '18/05/2017'}, {name: 'Someone Somewhere', date: '18/05/2017'}], header: this.strValid})); + // this.cntInvalidSign.html(this.templateValid({signatures: [{name: 'Mary White', date: '18/05/2017'}, {name: 'John Black', date: '18/05/2017'}], header: this.strInvalid})); + }, + + strProtect: 'Protect Document', + strInvisibleSign: 'Add invisible digital signature', + strVisibleSign: 'Add visible signature', + strRequested: 'Requested signatures', + strValid: 'Valid signatures', + strInvalid: 'Invalid signatures', + strSignature: 'Signature' + + }, SSE.Views.FileMenuPanels.ProtectDoc || {})); + }); diff --git a/apps/spreadsheeteditor/main/app/view/RightMenu.js b/apps/spreadsheeteditor/main/app/view/RightMenu.js index c685e418a..fe331911a 100644 --- a/apps/spreadsheeteditor/main/app/view/RightMenu.js +++ b/apps/spreadsheeteditor/main/app/view/RightMenu.js @@ -55,6 +55,7 @@ define([ 'spreadsheeteditor/main/app/view/ShapeSettings', 'spreadsheeteditor/main/app/view/TextArtSettings', 'spreadsheeteditor/main/app/view/TableSettings', + 'spreadsheeteditor/main/app/view/SignatureSettings', 'common/main/lib/component/Scroller' ], function (menuTemplate, $, _, Backbone) { 'use strict'; @@ -134,7 +135,7 @@ define([ return this; }, - render: function () { + render: function (mode) { var el = $(this.el); this.trigger('render:before', this); @@ -166,6 +167,21 @@ define([ this.textartSettings = new SSE.Views.TextArtSettings(); this.tableSettings = new SSE.Views.TableSettings(); + if (mode && mode.canProtect) { + this.btnSignature = new Common.UI.Button({ + hint: this.txtSignatureSettings, + asctype: Common.Utils.documentSettingsType.Signature, + enableToggle: true, + disabled: true, + toggleGroup: 'tabpanelbtnsGroup' + }); + this._settings[Common.Utils.documentSettingsType.Signature] = {panel: "id-signature-settings", btn: this.btnSignature}; + + this.btnSignature.el = $('#id-right-menu-signature'); this.btnSignature.render().setVisible(true); + this.btnSignature.on('click', _.bind(this.onBtnMenuClick, this)); + this.signatureSettings = new SSE.Views.SignatureSettings(); + } + if (_.isUndefined(this.scroller)) { this.scroller = new Common.UI.Scroller({ el: $(this.el).find('.right-panel'), @@ -187,7 +203,7 @@ define([ this.shapeSettings.setApi(api); this.textartSettings.setApi(api); this.tableSettings.setApi(api); - + if (this.signatureSettings) this.signatureSettings.setApi(api); return this; }, @@ -264,6 +280,7 @@ define([ txtTextArtSettings: 'Text Art Settings', txtChartSettings: 'Chart Settings', txtSparklineSettings: 'Sparkline Settings', - txtTableSettings: 'Table Settings' + txtTableSettings: 'Table Settings', + txtSignatureSettings: 'Signature Settings' }, SSE.Views.RightMenu || {})); }); \ No newline at end of file diff --git a/apps/spreadsheeteditor/main/app/view/SignatureSettings.js b/apps/spreadsheeteditor/main/app/view/SignatureSettings.js new file mode 100644 index 000000000..32241a8c5 --- /dev/null +++ b/apps/spreadsheeteditor/main/app/view/SignatureSettings.js @@ -0,0 +1,288 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2017 + * + * 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 Lubanas st. 125a-25, Riga, Latvia, + * EU, LV-1021. + * + * 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 + * +*/ +/** + * SignatureSettings.js + * + * Created by Julia Radzhabova on 5/24/17 + * Copyright (c) 2017 Ascensio System SIA. All rights reserved. + * + */ + +define([ + 'text!spreadsheeteditor/main/app/template/SignatureSettings.template', + 'jquery', + 'underscore', + 'backbone', + 'common/main/lib/component/Button', + 'common/main/lib/view/SignDialog', + 'common/main/lib/view/SignSettingsDialog' +], function (menuTemplate, $, _, Backbone) { + 'use strict'; + + SSE.Views.SignatureSettings = Backbone.View.extend(_.extend({ + el: '#id-signature-settings', + + // Compile our stats template + template: _.template(menuTemplate), + + // Delegated events for creating new items, and clearing completed ones. + events: { + }, + + options: { + alias: 'SignatureSettings' + }, + + initialize: function () { + var me = this; + + this._initSettings = true; + + this._state = { + DisabledControls: false, + requestedSignatures: undefined, + validSignatures: undefined, + invalidSignatures: undefined + }; + this._locked = false; + this.lockedControls = []; + + this._noApply = false; + this._originalProps = null; + + this.templateRequested = _.template([ + '', + '', + '', + '<% _.each(signatures, function(item) { %>', + '', + '', + '', + '', + '<% }); %>', + '
    ', + '' + ].join('')); + + this.templateValid = _.template([ + '', + '', + '', + '<% _.each(signatures, function(item) { %>', + '', + '', + '', + '', + '', + '<% }); %>', + '
    <%= Common.Utils.String.htmlEncode(item.name) %>
    <%= Common.Utils.String.htmlEncode(item.date) %>
    ', + '' + ].join('')); + + this.render(); + }, + + render: function () { + this.$el.html(this.template({ + scope: this + })); + + this.btnAddInvisibleSign = new Common.UI.Button({ + el: this.$el.find('#signature-invisible-sign') + }); + this.btnAddInvisibleSign.on('click', _.bind(this.addInvisibleSign, this)); + this.lockedControls.push(this.btnAddInvisibleSign); + + this.btnAddVisibleSign = new Common.UI.Button({ + el: this.$el.find('#signature-visible-sign') + }); + this.btnAddVisibleSign.on('click', _.bind(this.addVisibleSign, this)); + this.lockedControls.push(this.btnAddVisibleSign); + + this.cntRequestedSign = $('#signature-requested-sign'); + this.cntValidSign = $('#signature-valid-sign'); + this.cntInvalidSign = $('#signature-invalid-sign'); + }, + + setApi: function(api) { + this.api = api; + if (this.api) { + this.api.asc_registerCallback('asc_onUpdateSignatures', _.bind(this.onUpdateSignatures, this)); + } + return this; + }, + + createDelayedControls: function() { + this._initSettings = false; + }, + + ChangeSettings: function(props) { + if (this._initSettings) + this.createDelayedControls(); + + if (!this._state.requestedSignatures || !this._state.validSignatures || !this._state.invalidSignatures) { + this.onUpdateSignatures(this.api.asc_getSignatures(), this.api.asc_getRequestSignatures()); + } + + this.disableControls(this._locked); + }, + + setLocked: function (locked) { + this._locked = locked; + }, + + disableControls: function(disable) { + if (this._initSettings) return; + + if (this._state.DisabledControls!==disable) { + this._state.DisabledControls = disable; + _.each(this.lockedControls, function(item) { + item.setDisabled(disable); + }); + this.$linksSign.toggleClass('disabled', disable); + this.$linksView.toggleClass('disabled', disable); + } + }, + + setMode: function(mode) { + this.mode = mode; + }, + + onUpdateSignatures: function(valid, requested){ + var me = this; + me._state.requestedSignatures = []; + me._state.validSignatures = []; + me._state.invalidSignatures = []; + + _.each(requested, function(item, index){ + me._state.requestedSignatures.push({name: item.asc_getSigner1(), guid: item.asc_getGuid()}); + }); + _.each(valid, function(item, index){ + var sign = {name: item.asc_getSigner1(), guid: item.asc_getId(), date: '18/05/2017'}; + (item.asc_getValid()==0) ? me._state.validSignatures.push(sign) : me._state.invalidSignatures.push(sign); + }); + this.cntRequestedSign.html(this.templateRequested({signatures: me._state.requestedSignatures, header: this.strRequested})); + this.cntValidSign.html(this.templateValid({signatures: me._state.validSignatures, header: this.strValid})); + this.cntInvalidSign.html(this.templateValid({signatures: me._state.invalidSignatures, header: this.strInvalid})); + // this.cntRequestedSign.html(this.templateRequested({signatures: [{name: 'Hammish Mitchell', guid: '123'}, {name: 'Someone Somewhere', guid: '123'}, {name: 'Mary White', guid: '123'}, {name: 'John Black', guid: '123'}], header: this.strRequested})); + // this.cntValidSign.html(this.templateValid({signatures: [{name: 'Hammish Mitchell', guid: '123', date: '18/05/2017'}, {name: 'Someone Somewhere', guid: '345', date: '18/05/2017'}], header: this.strValid})); + // this.cntInvalidSign.html(this.templateValid({signatures: [{name: 'Mary White', guid: '111', date: '18/05/2017'}, {name: 'John Black', guid: '456', date: '18/05/2017'}], header: this.strInvalid})); + + this.$linksSign = $('.signature-sign-link', this.$el); + this.$linksView = $('.signature-view-link', this.$el); + this.$el.on('click', '.signature-sign-link', _.bind(this.onSign, this)); + this.$el.on('click', '.signature-view-link', _.bind(this.onViewSignature, this)); + }, + + addVisibleSign: function(btn) { + var me = this, + win = new Common.Views.SignSettingsDialog({ + handler: function(dlg, result) { + if (result == 'ok') { + me.api.asc_AddSignatureLine2(dlg.getSettings()); + } + me.fireEvent('editcomplete', me); + } + }); + + win.show(); + }, + + addInvisibleSign: function(btn) { + var me = this, + win = new Common.Views.SignDialog({ + api: me.api, + signType: 'invisible', + handler: function(dlg, result) { + if (result == 'ok') { + var props = dlg.getSettings(); + me.api.asc_Sign(props.certificateId); + } + me.fireEvent('editcomplete', me); + } + }); + + win.show(); + }, + + onSign: function(event) { + var me = this, + target = $(event.currentTarget); + + if (target.hasClass('disabled')) return; + + if (_.isUndefined(me.fontStore)) { + me.fontStore = new Common.Collections.Fonts(); + var fonts = SSE.getController('Toolbar').getView('Toolbar').cmbFontName.store.toJSON(); + var arr = []; + _.each(fonts, function(font, index){ + if (!font.cloneid) { + arr.push(_.clone(font)); + } + }); + me.fontStore.add(arr); + } + + var win = new Common.Views.SignDialog({ + api: me.api, + signType: 'visible', + fontStore: me.fontStore, + handler: function(dlg, result) { + if (result == 'ok') { + var props = dlg.getSettings(); + me.api.asc_Sign(props.certificateId, target.attr('data-value'), props.images[0], props.images[1]); + } + me.fireEvent('editcomplete', me); + } + }); + win.show(); + }, + + onViewSignature: function(event) { + var target = $(event.currentTarget); + if (target.hasClass('disabled')) return; + + this.api.asc_ViewCertificate(target.attr('data-value')); + }, + + strSignature: 'Signature', + strInvisibleSign: 'Add invisible digital signature', + strVisibleSign: 'Add visible signature', + strRequested: 'Requested signatures', + strValid: 'Valid signatures', + strInvalid: 'Invalid signatures', + strSign: 'Sign', + strView: 'View' + + }, SSE.Views.SignatureSettings || {})); +}); \ No newline at end of file diff --git a/apps/spreadsheeteditor/main/app/view/Viewport.js b/apps/spreadsheeteditor/main/app/view/Viewport.js index 341b4a1e1..86c059741 100644 --- a/apps/spreadsheeteditor/main/app/view/Viewport.js +++ b/apps/spreadsheeteditor/main/app/view/Viewport.js @@ -147,7 +147,7 @@ define([ var me = this, rightMenuView = SSE.getController('RightMenu').getView('RightMenu'); - me._rightMenu = rightMenuView.render(); + me._rightMenu = rightMenuView.render(this.mode); }, setMode: function(mode, delay) { diff --git a/apps/spreadsheeteditor/main/locale/en.json b/apps/spreadsheeteditor/main/locale/en.json index 63c2602d6..e21627e7d 100644 --- a/apps/spreadsheeteditor/main/locale/en.json +++ b/apps/spreadsheeteditor/main/locale/en.json @@ -112,6 +112,32 @@ "Common.Views.RenameDialog.okButtonText": "Ok", "Common.Views.RenameDialog.textName": "File name", "Common.Views.RenameDialog.txtInvalidName": "The file name cannot contain any of the following characters: ", + "Common.Views.SignDialog.textTitle": "Sign Document", + "Common.Views.SignDialog.textPurpose": "Purpose for signing this document", + "Common.Views.SignDialog.textCertificate": "Certificate", + "Common.Views.SignDialog.textValid": "Valid from %1 to %2", + "Common.Views.SignDialog.textChange": "Change", + "Common.Views.SignDialog.cancelButtonText": "Cancel", + "Common.Views.SignDialog.okButtonText": "Ok", + "Common.Views.SignDialog.textInputName": "Input signer name", + "Common.Views.SignDialog.textUseImage": "or click 'Select Image' to use a picture as signature", + "Common.Views.SignDialog.textSelectImage": "Select Image", + "Common.Views.SignDialog.textSignature": "Signature looks as", + "Common.Views.SignDialog.tipFontName": "Font Name", + "Common.Views.SignDialog.tipFontSize": "Font Size", + "Common.Views.SignDialog.textBold": "Bold", + "Common.Views.SignDialog.textItalic": "Italic", + "Common.Views.SignSettingsDialog.textInfo": "Signer Info", + "Common.Views.SignSettingsDialog.textInfoName": "Name", + "Common.Views.SignSettingsDialog.textInfoTitle": "Signer Title", + "Common.Views.SignSettingsDialog.textInfoEmail": "E-mail", + "Common.Views.SignSettingsDialog.textInstructions": "Instructions for Signer", + "Common.Views.SignSettingsDialog.cancelButtonText": "Cancel", + "Common.Views.SignSettingsDialog.okButtonText": "Ok", + "Common.Views.SignSettingsDialog.txtEmpty": "This field is required", + "Common.Views.SignSettingsDialog.textAllowComment": "Allow signer to add comment in the signature dialog", + "Common.Views.SignSettingsDialog.textShowDate": "Show sign date in signature line", + "Common.Views.SignSettingsDialog.textTitle": "Signature Settings", "SSE.Controllers.DocumentHolder.alignmentText": "Alignment", "SSE.Controllers.DocumentHolder.centerText": "Center", "SSE.Controllers.DocumentHolder.deleteColumnText": "Delete Column", @@ -1077,6 +1103,7 @@ "SSE.Views.FileMenu.btnSaveCaption": "Save", "SSE.Views.FileMenu.btnSettingsCaption": "Advanced Settings...", "SSE.Views.FileMenu.btnToEditCaption": "Edit Spreadsheet", + "SSE.Views.FileMenu.btnProtectCaption": "Protect\\Sign", "SSE.Views.FileMenuPanels.CreateNew.fromBlankText": "From Blank", "SSE.Views.FileMenuPanels.CreateNew.fromTemplateText": "From Template", "SSE.Views.FileMenuPanels.CreateNew.newDescriptionText": "Create a new blank spreadsheet which you will be able to style and format after it is created during the editing. Or choose one of the templates to start a spreadsheet of a certain type or purpose where some styles have already been pre-applied.", @@ -1131,6 +1158,13 @@ "SSE.Views.FileMenuPanels.MainSettingsGeneral.txtWin": "as Windows", "SSE.Views.FileMenuPanels.Settings.txtGeneral": "General", "SSE.Views.FileMenuPanels.Settings.txtPageSettings": "Page Settings", + "SSE.Views.FileMenuPanels.ProtectDoc.strProtect": "Protect Document", + "SSE.Views.FileMenuPanels.ProtectDoc.strInvisibleSign": "Add invisible digital signature", + "SSE.Views.FileMenuPanels.ProtectDoc.strVisibleSign": "Add visible signature", + "SSE.Views.FileMenuPanels.ProtectDoc.strRequested": "Requested signatures", + "SSE.Views.FileMenuPanels.ProtectDoc.strValid": "Valid signatures", + "SSE.Views.FileMenuPanels.ProtectDoc.strInvalid": "Invalid signatures", + "SSE.Views.FileMenuPanels.ProtectDoc.strSignature": "Signature", "SSE.Views.FormatSettingsDialog.textCancel": "Cancel", "SSE.Views.FormatSettingsDialog.textCategory": "Category", "SSE.Views.FormatSettingsDialog.textDecimal": "Decimal", @@ -1380,6 +1414,7 @@ "SSE.Views.RightMenu.txtSparklineSettings": "Sparkline Settings", "SSE.Views.RightMenu.txtTableSettings": "Table settings", "SSE.Views.RightMenu.txtTextArtSettings": "Text Art settings", + "SSE.Views.RightMenu.txtSignatureSettings": "Signature Settings", "SSE.Views.SetValueDialog.cancelButtonText": "Cancel", "SSE.Views.SetValueDialog.okButtonText": "OK", "SSE.Views.SetValueDialog.txtMaxText": "The maximum value for this field is {0}", @@ -1427,6 +1462,14 @@ "SSE.Views.ShapeSettings.txtNoBorders": "No Line", "SSE.Views.ShapeSettings.txtPapyrus": "Papyrus", "SSE.Views.ShapeSettings.txtWood": "Wood", + "SSE.Views.SignatureSettings.strSignature": "Signature", + "SSE.Views.SignatureSettings.strInvisibleSign": "Add invisible digital signature", + "SSE.Views.SignatureSettings.strVisibleSign": "Add visible signature", + "SSE.Views.SignatureSettings.strRequested": "Requested signatures", + "SSE.Views.SignatureSettings.strValid": "Valid signatures", + "SSE.Views.SignatureSettings.strInvalid": "Invalid signatures", + "SSE.Views.SignatureSettings.strSign": "Sign", + "SSE.Views.SignatureSettings.strView": "View", "SSE.Views.ShapeSettingsAdvanced.cancelButtonText": "Cancel", "SSE.Views.ShapeSettingsAdvanced.okButtonText": "OK", "SSE.Views.ShapeSettingsAdvanced.strColumns": "Columns", diff --git a/apps/spreadsheeteditor/main/resources/img/toolbar-menu.png b/apps/spreadsheeteditor/main/resources/img/toolbar-menu.png index 91577a92e..2f165110c 100644 Binary files a/apps/spreadsheeteditor/main/resources/img/toolbar-menu.png and b/apps/spreadsheeteditor/main/resources/img/toolbar-menu.png differ diff --git a/apps/spreadsheeteditor/main/resources/img/toolbar-menu@2x.png b/apps/spreadsheeteditor/main/resources/img/toolbar-menu@2x.png index 0b67bd39b..12c20e083 100644 Binary files a/apps/spreadsheeteditor/main/resources/img/toolbar-menu@2x.png and b/apps/spreadsheeteditor/main/resources/img/toolbar-menu@2x.png differ diff --git a/apps/spreadsheeteditor/main/resources/less/leftmenu.less b/apps/spreadsheeteditor/main/resources/less/leftmenu.less index 100eaaa2d..36a0aed6c 100644 --- a/apps/spreadsheeteditor/main/resources/less/leftmenu.less +++ b/apps/spreadsheeteditor/main/resources/less/leftmenu.less @@ -537,4 +537,32 @@ -webkit-transform: rotate(180deg); -o-transform: rotate(180deg); transform: rotate(180deg); +} + +#panel-protect { + #file-menu-panel & { + padding: 30px 30px; + } + + + button { + display: block; + width: auto; + margin-top: 20px; + } + + label { + font: 12px tahoma, arial, verdana, sans-serif; + } + + .header { + font-weight: bold; + margin: 30px 0 10px; + } + + table { + td { + padding: 5px 5px; + } + } } \ No newline at end of file diff --git a/apps/spreadsheeteditor/main/resources/less/rightmenu.less b/apps/spreadsheeteditor/main/resources/less/rightmenu.less index d50c9bf07..ea2ef2037 100644 --- a/apps/spreadsheeteditor/main/resources/less/rightmenu.less +++ b/apps/spreadsheeteditor/main/resources/less/rightmenu.less @@ -23,6 +23,9 @@ /*menuTable*/ .toolbar-btn-icon(btn-menu-table, 80, @toolbar-icon-size); + + /**menuSignature*/ + .toolbar-btn-icon(btn-menu-signature, 83, @toolbar-icon-size); } }