diff --git a/apps/api/documents/api.js b/apps/api/documents/api.js index bdcc11f603..1958e6f8d4 100644 --- a/apps/api/documents/api.js +++ b/apps/api/documents/api.js @@ -403,7 +403,8 @@ _config.editorConfig.canRequestSelectSpreadsheet = _config.events && !!_config.events.onRequestSelectSpreadsheet; _config.editorConfig.canRequestReferenceSource = _config.events && !!_config.events.onRequestReferenceSource; _config.editorConfig.canSaveDocumentToBinary = _config.events && !!_config.events.onSaveDocument; - _config.editorConfig.canStartFilling = _config.events && !!_config.events.onRequestStartFilling; + _config.editorConfig.canRequestStartFilling = _config.events && !!_config.events.onRequestStartFilling; + _config.editorConfig.canStartFilling = _config.events && !!_config.events.onStartFilling; _config.editorConfig.canRequestRefreshFile = _config.events && !!_config.events.onRequestRefreshFile; _config.editorConfig.canUpdateVersion = _config.events && !!_config.events.onOutdatedVersion; _config.editorConfig.canRequestFillingStatus = _config.events && !!_config.events.onRequestFillingStatus; diff --git a/apps/common/Gateway.js b/apps/common/Gateway.js index 9a39cb5c6a..701e7fb53d 100644 --- a/apps/common/Gateway.js +++ b/apps/common/Gateway.js @@ -413,8 +413,11 @@ if (window.Common === undefined) { _postMessage({event:'onSwitchEditorType', data: {type: value, restart: restart}}); }, - startFilling: function () { - _postMessage({event:'onStartFilling'}); + startFilling: function (roles) { + _postMessage({ + event:'onStartFilling', + data: roles + }); }, requestFillingStatus: function (role) { diff --git a/apps/common/main/lib/util/utils.js b/apps/common/main/lib/util/utils.js index 26f7dd1aff..bdbda1dfda 100644 --- a/apps/common/main/lib/util/utils.js +++ b/apps/common/main/lib/util/utils.js @@ -118,7 +118,8 @@ define([], function () { Pivot: 10, Cell: 11, Slicer: 12, - Form: 13 + Form: 13, + SendForSigning: 15 }, importTextType = { DRM: 0, diff --git a/apps/common/main/lib/view/Header.js b/apps/common/main/lib/view/Header.js index 56e4499f0e..420d1d289a 100644 --- a/apps/common/main/lib/view/Header.js +++ b/apps/common/main/lib/view/Header.js @@ -402,7 +402,11 @@ define([ } me.btnStartFill && me.btnStartFill.on('click', function (e) { - Common.NotificationCenter.trigger('forms:request-fill'); + if(appConfig.canRequestStartFilling) { + Common.NotificationCenter.trigger('forms:request-fill'); + } else { + Common.NotificationCenter.trigger('forms:show-send-for-signing'); + } }); if (me.btnFillStatus) { @@ -1011,7 +1015,7 @@ define([ } else $html.find('#slot-btn-edit-mode').hide(); - if (config.canStartFilling) { + if (config.showStartFillingButton) { me.btnStartFill = new Common.UI.Button({ cls: 'btn-text-default auto yellow', caption: config.customization && config.customization.startFillingForm && config.customization.startFillingForm.text ? config.customization.startFillingForm.text : me.textStartFill, diff --git a/apps/common/main/resources/img/toolbar/1.25x/btn-menu-send-to-sign.png b/apps/common/main/resources/img/toolbar/1.25x/btn-menu-send-to-sign.png new file mode 100644 index 0000000000..93654cc547 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/1.25x/btn-menu-send-to-sign.png differ diff --git a/apps/common/main/resources/img/toolbar/1.25x/btn-user.png b/apps/common/main/resources/img/toolbar/1.25x/btn-user.png new file mode 100644 index 0000000000..3def96e68a Binary files /dev/null and b/apps/common/main/resources/img/toolbar/1.25x/btn-user.png differ diff --git a/apps/common/main/resources/img/toolbar/1.5x/btn-menu-send-to-sign.png b/apps/common/main/resources/img/toolbar/1.5x/btn-menu-send-to-sign.png new file mode 100644 index 0000000000..7c23da5dc8 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/1.5x/btn-menu-send-to-sign.png differ diff --git a/apps/common/main/resources/img/toolbar/1.5x/btn-user.png b/apps/common/main/resources/img/toolbar/1.5x/btn-user.png new file mode 100644 index 0000000000..5d5ae5af45 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/1.5x/btn-user.png differ diff --git a/apps/common/main/resources/img/toolbar/1.75x/btn-menu-send-to-sign.png b/apps/common/main/resources/img/toolbar/1.75x/btn-menu-send-to-sign.png new file mode 100644 index 0000000000..d3a21de809 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/1.75x/btn-menu-send-to-sign.png differ diff --git a/apps/common/main/resources/img/toolbar/1.75x/btn-user.png b/apps/common/main/resources/img/toolbar/1.75x/btn-user.png new file mode 100644 index 0000000000..c6cd7569bb Binary files /dev/null and b/apps/common/main/resources/img/toolbar/1.75x/btn-user.png differ diff --git a/apps/common/main/resources/img/toolbar/1x/btn-menu-send-to-sign.png b/apps/common/main/resources/img/toolbar/1x/btn-menu-send-to-sign.png new file mode 100644 index 0000000000..fca5e1af7c Binary files /dev/null and b/apps/common/main/resources/img/toolbar/1x/btn-menu-send-to-sign.png differ diff --git a/apps/common/main/resources/img/toolbar/1x/btn-user.png b/apps/common/main/resources/img/toolbar/1x/btn-user.png new file mode 100644 index 0000000000..30f7904036 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/1x/btn-user.png differ diff --git a/apps/common/main/resources/img/toolbar/2.5x/btn-menu-send-to-sign.svg b/apps/common/main/resources/img/toolbar/2.5x/btn-menu-send-to-sign.svg new file mode 100644 index 0000000000..7e21ef90fc --- /dev/null +++ b/apps/common/main/resources/img/toolbar/2.5x/btn-menu-send-to-sign.svg @@ -0,0 +1,4 @@ + + + + diff --git a/apps/common/main/resources/img/toolbar/2.5x/btn-user.svg b/apps/common/main/resources/img/toolbar/2.5x/btn-user.svg new file mode 100644 index 0000000000..1ffd4c1ca7 --- /dev/null +++ b/apps/common/main/resources/img/toolbar/2.5x/btn-user.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/common/main/resources/img/toolbar/2x/btn-menu-send-to-sign.png b/apps/common/main/resources/img/toolbar/2x/btn-menu-send-to-sign.png new file mode 100644 index 0000000000..c55f25bd19 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/2x/btn-menu-send-to-sign.png differ diff --git a/apps/common/main/resources/img/toolbar/2x/btn-user.png b/apps/common/main/resources/img/toolbar/2x/btn-user.png new file mode 100644 index 0000000000..e60aa1511a Binary files /dev/null and b/apps/common/main/resources/img/toolbar/2x/btn-user.png differ diff --git a/apps/common/main/resources/img/toolbar/v2/1.25x/btn-menu-send-to-sign.png b/apps/common/main/resources/img/toolbar/v2/1.25x/btn-menu-send-to-sign.png new file mode 100644 index 0000000000..bd5090fac6 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/v2/1.25x/btn-menu-send-to-sign.png differ diff --git a/apps/common/main/resources/img/toolbar/v2/1.25x/btn-user.png b/apps/common/main/resources/img/toolbar/v2/1.25x/btn-user.png new file mode 100644 index 0000000000..7330200bf5 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/v2/1.25x/btn-user.png differ diff --git a/apps/common/main/resources/img/toolbar/v2/1.5x/btn-menu-send-to-sign.png b/apps/common/main/resources/img/toolbar/v2/1.5x/btn-menu-send-to-sign.png new file mode 100644 index 0000000000..1878e080be Binary files /dev/null and b/apps/common/main/resources/img/toolbar/v2/1.5x/btn-menu-send-to-sign.png differ diff --git a/apps/common/main/resources/img/toolbar/v2/1.5x/btn-user.png b/apps/common/main/resources/img/toolbar/v2/1.5x/btn-user.png new file mode 100644 index 0000000000..c6865f33f1 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/v2/1.5x/btn-user.png differ diff --git a/apps/common/main/resources/img/toolbar/v2/1.75x/btn-menu-send-to-sign.png b/apps/common/main/resources/img/toolbar/v2/1.75x/btn-menu-send-to-sign.png new file mode 100644 index 0000000000..a20eb4de80 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/v2/1.75x/btn-menu-send-to-sign.png differ diff --git a/apps/common/main/resources/img/toolbar/v2/1.75x/btn-user.png b/apps/common/main/resources/img/toolbar/v2/1.75x/btn-user.png new file mode 100644 index 0000000000..4b01b687b0 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/v2/1.75x/btn-user.png differ diff --git a/apps/common/main/resources/img/toolbar/v2/1x/btn-menu-send-to-sign.png b/apps/common/main/resources/img/toolbar/v2/1x/btn-menu-send-to-sign.png new file mode 100644 index 0000000000..dbafd730a3 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/v2/1x/btn-menu-send-to-sign.png differ diff --git a/apps/common/main/resources/img/toolbar/v2/1x/btn-user.png b/apps/common/main/resources/img/toolbar/v2/1x/btn-user.png new file mode 100644 index 0000000000..3feadfdf28 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/v2/1x/btn-user.png differ diff --git a/apps/common/main/resources/img/toolbar/v2/2.5x/btn-menu-send-to-sign.svg b/apps/common/main/resources/img/toolbar/v2/2.5x/btn-menu-send-to-sign.svg new file mode 100644 index 0000000000..33b2898bde --- /dev/null +++ b/apps/common/main/resources/img/toolbar/v2/2.5x/btn-menu-send-to-sign.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/common/main/resources/img/toolbar/v2/2.5x/btn-user.svg b/apps/common/main/resources/img/toolbar/v2/2.5x/btn-user.svg new file mode 100644 index 0000000000..7a30953be7 --- /dev/null +++ b/apps/common/main/resources/img/toolbar/v2/2.5x/btn-user.svg @@ -0,0 +1,4 @@ + + + + diff --git a/apps/common/main/resources/img/toolbar/v2/2x/btn-menu-send-to-sign.png b/apps/common/main/resources/img/toolbar/v2/2x/btn-menu-send-to-sign.png new file mode 100644 index 0000000000..397fd69d26 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/v2/2x/btn-menu-send-to-sign.png differ diff --git a/apps/common/main/resources/img/toolbar/v2/2x/btn-user.png b/apps/common/main/resources/img/toolbar/v2/2x/btn-user.png new file mode 100644 index 0000000000..1ef864dd56 Binary files /dev/null and b/apps/common/main/resources/img/toolbar/v2/2x/btn-user.png differ diff --git a/apps/documenteditor/main/app/controller/FormsTab.js b/apps/documenteditor/main/app/controller/FormsTab.js index 3d127da58b..53da9e9013 100644 --- a/apps/documenteditor/main/app/controller/FormsTab.js +++ b/apps/documenteditor/main/app/controller/FormsTab.js @@ -90,6 +90,7 @@ define([ Common.NotificationCenter.on('forms:close-help', _.bind(this.closeHelpTip, this)); Common.NotificationCenter.on('forms:show-help', _.bind(this.showHelpTip, this)); Common.NotificationCenter.on('forms:request-fill', _.bind(this.requestStartFilling, this)); + Common.NotificationCenter.on('forms:show-send-for-signing', _.bind(this.showSendForSigning, this)); Common.NotificationCenter.on('document:ready', _.bind(this.onDocumentReady, this)); return this; }, @@ -724,6 +725,11 @@ define([ Common.Gateway.requestStartFilling(arr); }, + showSendForSigning: function() { + const rightmenuController = this.getApplication().getController('RightMenu'); + rightmenuController.openSendForSigning(); + }, + onActiveTab: function(tab) { (tab !== 'forms') && this.onTabCollapse(); }, diff --git a/apps/documenteditor/main/app/controller/Main.js b/apps/documenteditor/main/app/controller/Main.js index 115d9c6e60..a9ddc906a9 100644 --- a/apps/documenteditor/main/app/controller/Main.js +++ b/apps/documenteditor/main/app/controller/Main.js @@ -1776,7 +1776,9 @@ define([ this.appOptions.canSwitchMode = this.appOptions.isEdit; this.appOptions.canSubmitForms = this.appOptions.isRestrictedEdit && this.appOptions.canFillForms && this.appOptions.canLicense && !this.appOptions.isOffline && (typeof (this.editorConfig.customization) == 'object') && !!this.editorConfig.customization.submitForm && (typeof this.editorConfig.customization.submitForm !== 'object' || this.editorConfig.customization.submitForm.visible!==false); - this.appOptions.canStartFilling = this.editorConfig.canStartFilling && this.appOptions.isEdit && this.appOptions.isPDFForm; // show Start Filling button in the header + this.appOptions.canStartFilling = this.editorConfig.canStartFilling && this.appOptions.isEdit && this.appOptions.isPDFForm; + this.appOptions.canRequestStartFilling = this.editorConfig.canRequestStartFilling && this.appOptions.isEdit && this.appOptions.isPDFForm; + this.appOptions.showStartFillingButton = this.appOptions.canStartFilling || this.appOptions.canRequestStartFilling; // show Start Filling button in the header this.appOptions.compactHeader = this.appOptions.customization && (typeof (this.appOptions.customization) == 'object') && !!this.appOptions.customization.compactHeader; this.appOptions.twoLevelHeader = this.appOptions.isEdit || this.appOptions.isPDFForm && this.appOptions.canFillForms && this.appOptions.isRestrictedEdit; // when compactHeader=true some buttons move to toolbar @@ -1983,8 +1985,9 @@ define([ (!inViewMode || force) && Common.NotificationCenter.trigger('doc:mode-changed', mode); }, - onStartFilling: function(disconnect) { + onStartFilling: function(disconnect, roles) { this._isFillInitiator = true; + this._rolesForFilling = roles; this.api.asc_CompletePreparingOForm(!!disconnect); !disconnect && this.onDisconnectEveryone(); // disable editing only for current user }, @@ -1999,7 +2002,7 @@ define([ }, onCompletePreparingOForm: function() { - Common.Gateway.startFilling(); + Common.Gateway.startFilling(this._rolesForFilling); }, applyModeCommonElements: function() { diff --git a/apps/documenteditor/main/app/controller/RightMenu.js b/apps/documenteditor/main/app/controller/RightMenu.js index 7412a499ab..775f38d641 100644 --- a/apps/documenteditor/main/app/controller/RightMenu.js +++ b/apps/documenteditor/main/app/controller/RightMenu.js @@ -100,6 +100,8 @@ define([ 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: 1, props: {}, locked: false}; this._settings[Common.Utils.documentSettingsType.Form] = {panelId: "id-form-settings", panel: rightMenu.formSettings, btn: rightMenu.btnForm, hidden: 1, props: {}, locked: false}; + // this._settings[Common.Utils.documentSettingsType.FillingStatus] = {panelId: "id-filling-status-settings", panel: rightMenu.fillingStatusSettings, btn: rightMenu.btnFillingStatus, hidden: 1, props: {}, locked: false}; + this._settings[Common.Utils.documentSettingsType.SendForSigning] = {panelId: "id-send-for-signing-settings", panel: rightMenu.sendForSigningSettings, btn: rightMenu.btnSendForSigning, hidden: 1, props: {}, locked: false}; }, setApi: function(api) { @@ -359,6 +361,8 @@ define([ this._settings[Common.Utils.documentSettingsType.Image].needShow = false; this._settings[Common.Utils.documentSettingsType.Chart].needShow = false; + + this.rightmenu.btnSendForSigning && this.rightmenu.btnSendForSigning.setDisabled(false); }, onCoAuthoringDisconnect: function() { @@ -504,6 +508,8 @@ define([ disabled && this.rightmenu.btnMailMerge.setDisabled(disabled); } this.rightmenu.chartSettings.disableControls(disabled); + this.rightmenu.fillingStatusSettings && this.rightmenu.fillingStatusSettings.disableControls(disabled); + this.rightmenu.sendForSigningSettings && this.rightmenu.sendForSigningSettings.disableControls(disabled); if (this.rightmenu.signatureSettings) { !allowSignature && this.rightmenu.btnSignature.setDisabled(disabled); @@ -519,6 +525,8 @@ define([ this.rightmenu.btnTextArt.setDisabled(disabled); this.rightmenu.btnChart.setDisabled(disabled); this.rightmenu.btnForm && this.rightmenu.btnForm.setDisabled(disabled); + this.rightmenu.btnFillingStatus && this.rightmenu.btnFillingStatus.setDisabled(disabled); + this.rightmenu.btnSendForSigning && this.rightmenu.btnSendForSigning.setDisabled(disabled); this.rightmenu.setDisabledAllMoreMenuItems(disabled); } else { var selectedElements = this.api.getSelectedElements(); @@ -610,6 +618,20 @@ define([ this.rightmenu.fireEvent('editcomplete', this.rightmenu); }, + openSendForSigning: function() { + const btnSendForSigning = this.rightmenu.btnSendForSigning; + if(!btnSendForSigning.isActive()) { + btnSendForSigning.click(); + } + }, + + closeSendForSigning: function() { + const btnSendForSigning = this.rightmenu.btnSendForSigning; + if(btnSendForSigning.isActive()) { + btnSendForSigning.click(); + } + }, + onHidePlugins: function() { Common.NotificationCenter.trigger('layout:changed', 'rightmenu'); }, diff --git a/apps/documenteditor/main/app/template/FillingStatusSettings.template b/apps/documenteditor/main/app/template/FillingStatusSettings.template new file mode 100644 index 0000000000..2f4817af45 --- /dev/null +++ b/apps/documenteditor/main/app/template/FillingStatusSettings.template @@ -0,0 +1,48 @@ + + + + + + + +
+ +
+ <% _.each(items, function(item, index) { %> +
+
+
<%= index + 1 %>
+
+
+
+
+
<%= item.name %>
+ <% if (item.status == 'done') { %> +
+ <% } %> +
+
<%= item.email %>
+ <% if (item.status == 'done') { %> + + <% } %> +
+
+ <% }) %> +
+
+
+
+
+
+
+
+
Complete
+
+
+
+
\ 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 90cb7c62bb..0f09cade57 100644 --- a/apps/documenteditor/main/app/template/RightMenu.template +++ b/apps/documenteditor/main/app/template/RightMenu.template @@ -10,6 +10,8 @@
+
+
\ No newline at end of file diff --git a/apps/documenteditor/main/app/template/SendForSigningSettings.template b/apps/documenteditor/main/app/template/SendForSigningSettings.template new file mode 100644 index 0000000000..429a71faf1 --- /dev/null +++ b/apps/documenteditor/main/app/template/SendForSigningSettings.template @@ -0,0 +1,22 @@ + + + + +
+
+
+ + +
+
+
+
+
+
+
+ +
+
\ No newline at end of file diff --git a/apps/documenteditor/main/app/view/FillingStatusSettings.js b/apps/documenteditor/main/app/view/FillingStatusSettings.js new file mode 100644 index 0000000000..39712be187 --- /dev/null +++ b/apps/documenteditor/main/app/view/FillingStatusSettings.js @@ -0,0 +1,107 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2024 + * + * This program is a free software product. You can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License (AGPL) + * version 3 as published by the Free Software Foundation. In accordance with + * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect + * that Ascensio System SIA expressly excludes the warranty of non-infringement + * of any third-party rights. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For + * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html + * + * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish + * street, Riga, Latvia, EU, LV-1050. + * + * The interactive user interfaces in modified source and object code versions + * of the Program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU AGPL version 3. + * + * Pursuant to Section 7(b) of the License you must retain the original Product + * logo when distributing the program. Pursuant to Section 7(e) we decline to + * grant you any rights under trademark law for use of our trademarks. + * + * All the Product's GUI elements, including illustrations and icon sets, as + * well as technical writing content are licensed under the terms of the + * Creative Commons Attribution-ShareAlike 4.0 International. See the License + * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + * + */ +/** + * FillingStatusSettings.js + * + * Created on 10.03.2026 + * + */ + +define([ + 'text!documenteditor/main/app/template/FillingStatusSettings.template', + 'jquery', + 'underscore', + 'backbone', + 'common/main/lib/component/Button' +], function (menuTemplate, $, _, Backbone) { + 'use strict'; + + DE.Views.FillingStatusSettings = Backbone.View.extend(_.extend({ + el: '#id-filling-status-settings', + + // Compile our stats template + template: _.template(menuTemplate), + + // Delegated events for creating new items, and clearing completed ones. + events: { + }, + + options: { + alias: 'FillingStatusSettings' + }, + + initialize: function () { + this._state = {}; + this._locked = false; + + this.render(); + }, + + render: function () { + const items = [ + { email: 'user333@gmail.com', name: 'Anyone', date: '1/20/2026 9:00 PM', status: 'done' }, + { email: 'test@yandex.ru', name: 'User1', date: null, status: 'done' }, + { email: 'test@yandex.ru', name: 'User2', date: null, status: 'done' } + ]; + const el = this.$el || $(this.el); + el.html(this.template({ + scope: this, + items: items, + isAllDone: items.every(function(item) { return item.status == 'done'}) + })); + }, + + setApi: function(api) { + this.api = api; + return this; + }, + + ChangeSettings: function(props) { + + }, + + setLocked: function (locked) { + this._locked = locked; + }, + + setMode: function(mode) { + this.mode = mode; + }, + + disableControls: function(disable) { + + }, + + txtTitle: 'Filling status', + + }, DE.Views.FillingStatusSettings || {})); +}); \ No newline at end of file diff --git a/apps/documenteditor/main/app/view/RightMenu.js b/apps/documenteditor/main/app/view/RightMenu.js index 182a489d41..538cb81a99 100644 --- a/apps/documenteditor/main/app/view/RightMenu.js +++ b/apps/documenteditor/main/app/view/RightMenu.js @@ -39,6 +39,7 @@ var SCALE_MIN = 40; var MENU_SCALE_PART = 260; var MENU_BASE_WIDTH = 220; +// var MENU_BASE_WIDTH = 360; define([ 'text!documenteditor/main/app/template/RightMenu.template', @@ -59,6 +60,8 @@ define([ 'documenteditor/main/app/view/TextArtSettings', 'documenteditor/main/app/view/SignatureSettings', 'documenteditor/main/app/view/FormSettings', + 'documenteditor/main/app/view/FillingStatusSettings', + 'documenteditor/main/app/view/SendForSigningSettings', 'common/main/lib/component/Scroller', 'common/main/lib/component/ListView', ], function (menuTemplate, $, _, Backbone) { @@ -253,6 +256,39 @@ define([ this.formSettings = new DE.Views.FormSettings(); } + if (false) { + this.btnFillingStatus = new Common.UI.Button({ + hint: this.txtFormSettings, + asctype: Common.Utils.documentSettingsType.FillingStatus, + enableToggle: true, + disabled: true, + iconCls: 'btn-field', + toggleGroup: 'tabpanelbtnsGroup', + allowMouseEventsOnDisabled: true + }); + this._settings[Common.Utils.documentSettingsType.FillingStatus] = {panel: "id-filling-status-settings", btn: this.btnFillingStatus}; + this.btnFillingStatus.setElement($markup.findById('#id-right-menu-filling-status'), false); + this.btnFillingStatus.render().setVisible(true); + this.btnFillingStatus.on('click', this.onBtnMenuClick.bind(this)); + this.fillingStatusSettings = new DE.Views.FillingStatusSettings(); + } + + if (!mode.canRequestStartFilling) { + this.btnSendForSigning = new Common.UI.Button({ + hint: this.txtSendForSigning, + asctype: Common.Utils.documentSettingsType.SendForSigning, + enableToggle: true, + disabled: false, + iconCls: 'btn-field', + toggleGroup: 'tabpanelbtnsGroup', + allowMouseEventsOnDisabled: true + }); + this._settings[Common.Utils.documentSettingsType.SendForSigning] = {panel: "id-send-for-signing-settings", btn: this.btnSendForSigning}; + this.btnSendForSigning.setElement($markup.findById('#id-right-menu-send-for-signing'), false); + this.btnSendForSigning.render().setVisible(true); + this.btnSendForSigning.on('click', this.onBtnMenuClick.bind(this)); + this.sendForSigningSettings = new DE.Views.SendForSigningSettings(); + } if (_.isUndefined(this.scroller)) { this.scroller = new Common.UI.Scroller({ @@ -289,6 +325,8 @@ define([ if (this.mergeSettings) this.mergeSettings.setApi(api).on('editcomplete', _fire_editcomplete); if (this.signatureSettings) this.signatureSettings.setApi(api).on('editcomplete', _fire_editcomplete); if (this.formSettings) this.formSettings.setApi(api).on('editcomplete', _fire_editcomplete).on('updatescroller', _updateScroller); + if (this.fillingStatusSettings) this.fillingStatusSettings.setApi(api).on('editcomplete', _fire_editcomplete).on('updatescroller', _updateScroller); + if (this.sendForSigningSettings) this.sendForSigningSettings.setApi(api).on('editcomplete', _fire_editcomplete).on('updatescroller', _updateScroller); }, setMode: function(mode) { @@ -300,6 +338,8 @@ define([ this.chartSettings && this.chartSettings.setMode(mode); // this.headerSettings && this.headerSettings.setMode(mode); this.signatureSettings && this.signatureSettings.setMode(mode); + this.fillingStatusSettings && this.fillingStatusSettings.setMode(mode); + this.sendForSigningSettings && this.sendForSigningSettings.setMode(mode); }, onBtnMenuClick: function(btn, e) { @@ -402,7 +442,7 @@ define([ setButtons: function () { var allButtons = [this.btnText, this.btnTable, this.btnImage, this.btnShape, this.btnChart, this.btnTextArt, - this.btnMailMerge, this.btnSignature, this.btnForm]; + this.btnMailMerge, this.btnSignature, this.btnForm, this.btnFillingStatus, this.btnSendForSigning]; Common.UI.SideMenu.prototype.setButtons.apply(this, [allButtons]); }, @@ -434,6 +474,7 @@ define([ txtMailMergeSettings: 'Mail Merge Settings', txtSignatureSettings: 'Signature Settings', txtFormSettings: 'Form Settings', + txtSendForSigning: 'Send for signing', ariaRightMenu: 'Right menu' }, DE.Views.RightMenu || {})); }); \ No newline at end of file diff --git a/apps/documenteditor/main/app/view/SendForSigningSettings.js b/apps/documenteditor/main/app/view/SendForSigningSettings.js new file mode 100644 index 0000000000..83509afbfd --- /dev/null +++ b/apps/documenteditor/main/app/view/SendForSigningSettings.js @@ -0,0 +1,302 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2024 + * + * This program is a free software product. You can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License (AGPL) + * version 3 as published by the Free Software Foundation. In accordance with + * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect + * that Ascensio System SIA expressly excludes the warranty of non-infringement + * of any third-party rights. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For + * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html + * + * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish + * street, Riga, Latvia, EU, LV-1050. + * + * The interactive user interfaces in modified source and object code versions + * of the Program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU AGPL version 3. + * + * Pursuant to Section 7(b) of the License you must retain the original Product + * logo when distributing the program. Pursuant to Section 7(e) we decline to + * grant you any rights under trademark law for use of our trademarks. + * + * All the Product's GUI elements, including illustrations and icon sets, as + * well as technical writing content are licensed under the terms of the + * Creative Commons Attribution-ShareAlike 4.0 International. See the License + * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + * + */ +/** + * SendForSigningSettings.js + * + * Created on 10.03.2026 + * + */ + +define([ + 'text!documenteditor/main/app/template/SendForSigningSettings.template', + 'jquery', + 'underscore', + 'backbone', + 'common/main/lib/component/Button' +], function (menuTemplate, $, _, Backbone) { + 'use strict'; + + DE.Views.SendForSigningSettings = Backbone.View.extend(_.extend({ + el: '#id-send-for-signing-settings', + + // Compile our stats template + template: _.template(menuTemplate), + + // Delegated events for creating new items, and clearing completed ones. + events: { + }, + + options: { + alias: 'SendForSigningSettings' + }, + + initialize: function (options) { + this._initSettings = true; + this._state = { + isUsersListLoading: false + }; + this._locked = false; + + this.users = []; + this.render(); + + + // TODO: if (config.canRequestUsers)??? + this._state.isUsersListLoading = true; + Common.UI.ExternalUsers.get('filler'); + Common.NotificationCenter.on('mentions:setusers', _.bind(this.onUsersListLoad, this)); + }, + + render: function () { + const el = this.$el || $(this.el); + el.html(this.template({ + scope: this + })); + }, + + createDelayedElements: function() { + this._initSettings = false; + const me = this; + const $markup = this.$el || $(this.el); + + this._updateRolesListHeight(); + this.scrollerOptions = { + el: $markup.find('#id-send-for-signing-settings-roles-list'), + wheelSpeed: 8, + alwaysVisibleY: true + }; + this.scroller = new Common.UI.Scroller(this.scrollerOptions); + + this.sendBtn = new Common.UI.Button({ + el: $markup.find('#id-send-for-signing-settings-send-btn'), + disabled: true + }); + this.sendBtn.on('click', _.bind(this.onSend, this)); + + this.cancelBtn = $markup.find('#id-send-for-signing-settings-cancel-btn'); + this.cancelBtn.on('click', _.bind(this.onCancel, this)); + + const oForm = this.api.asc_GetOForm(); + this.rolesCollection = new Backbone.Collection(); + this.rolesCollection.on('reset', function(newCollection, details) { + me._renderRolesList(); + }, this); + this.setRoles(oForm ? oForm.asc_getAllRoles() : []); + + $(window).on('resize', _.bind(this.onWindowResize, this)); + }, + + setApi: function(api) { + this.api = api; + if (this.api) { + this.api.asc_registerCallback('asc_onUpdateOFormRoles', _.bind(this.onRefreshRolesList, this)); + } + return this; + }, + + ChangeSettings: function(props) { + if (this._initSettings) { + this.createDelayedElements(); + } + }, + + setLocked: function (locked) { + this._locked = locked; + }, + + setMode: function(mode) { + this.mode = mode; + }, + + disableControls: function(disable) { + + }, + + updateDisableSendButton: function() { + const hasEmptyUser = this.rolesCollection.some(function(role) { + return !role.get('user'); + }); + this.sendBtn.setDisabled(hasEmptyUser); + }, + + setRoles: function(roles) { + const oldArray = this.rolesCollection.toJSON(); + const oldMap = {}; + const newArray = (roles).map(function(role) { + role = role.asc_getSettings(); + let color = role.asc_getColor(); + color && (color = Common.Utils.ThemeColor.getHexColor(color.get_r(), color.get_g(), color.get_b())); + return { + name: role.asc_getName(), + color: color, + user: null + } + }); + + oldArray.forEach(function(item) { + oldMap[item.name] = item; + }); + + // Arrays are merged by 'name', only the `user` field is carried over from the old array + const resultArray = newArray.map(function(item) { + if (oldMap.hasOwnProperty(item.name)) { + item.user = oldMap[item.name].user; + } + return item; + }); + + this.rolesCollection.reset(resultArray); + }, + + onUsersListLoad: function(type, users, isPaginated) { + if (this._state.isUsersListLoading && type!=='filler') return; + + this._state.isUsersListLoading = false; + this.users = (users || []).map(function(user) { + return { + id: user.id, + name: user.name, + email: user.email, + image: user.image, + initials: Common.Utils.getUserInitials(user.name) + } + }); + }, + + onSend: function() { + const roles = this.rolesCollection.map(function(role) { + return { + name: role.get('name'), + color: role.get('color'), + user: role.get('user') + } + }); + DE.getController('Main').onStartFilling(true, roles); + }, + + onCancel: function() { + // TODO: Move this out of the component by emitting an event + const rightmenuController = DE.getController('RightMenu'); + rightmenuController.closeSendForSigning(); + }, + + onRefreshRolesList: function(roles) { + if (this._initSettings) return; + this.setRoles(roles); + }, + + onWindowResize: function() { + this._updateRolesListHeight(); + this.scroller.update(this.scrollerOptions); + }, + + _renderRolesList: function() { + const me = this; + const userCmbOptions = this.users.map(function(user) { + return Object.assign({value: user.id, displayValue: user.name || user.email}, user); + }); + + this.$el.find('#id-send-for-signing-settings-roles-list').empty(); + this.rolesCollection.each(function(role, index) { + const $item = $( + '
' + + '
' + + '
' + + (index + 1) + + '
' + + '
' + + '
' + + '
' + + '
' + role.get('name') + '
' + + '
' + + '
' + + '
' + ); + const user = role.get('user'); + const cmb = new Common.UI.ComboBox({ + el: $item.find('.role-item-user-cmb'), + cls: 'input-group-nr', + menuCls: 'role-item-user-cmb-menu', + restoreMenuHeightAndTop: true, + editable: false, + data: userCmbOptions, + placeHolder: me.txtSelectUser, + itemTemplate: _.template( + '
  • ' + + '' + + '<% if(image) { %>' + + '
    ' + + '<% } else { %>' + + '
    ' + + ' ' + + '
    ' + + '<% } %>' + + '
    ' + + '
    <%= name %>
    ' + + '' + + '
    ' + + '
    ' + + '
  • ' + ) + }); + (user && user.id) && cmb.setValue(user.id); + cmb.on('selected', function(combo, record) { + role.set('user', { + id: record.id, + name: record.name, + email: record.email, + image: record.image + }); + me.updateDisableSendButton(); + }); + me.$el.find('#id-send-for-signing-settings-roles-list').append($item); + }); + this.updateDisableSendButton(); + this.scroller.update(this.scrollerOptions); + }, + + _updateRolesListHeight: function() { + const $markup = this.$el || $(this.el); + const $listWrapper = $markup.find('.roles-list-wrapper'); + const height = $listWrapper.height(); + + $markup.find('#id-send-for-signing-settings-roles-list').height(height); + }, + + txtTitle: 'Send for signing', + txtDescription: 'Please check the order of filling before sending.', + txtSelectUser: 'Select user', + txtSend: 'Send', + txtCancel: 'Cancel', + + }, DE.Views.SendForSigningSettings || {})); +}); \ 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 385bbbe0aa..22ec97396f 100644 --- a/apps/documenteditor/main/resources/less/rightmenu.less +++ b/apps/documenteditor/main/resources/less/rightmenu.less @@ -228,6 +228,337 @@ .margin-right-2(); } } + + &#id-filling-status-settings { + .progress-item { + display: flex; + margin-bottom: 4px; + + .progress-item-left { + display: flex; + flex-direction: column; + align-items: center; + .margin-right(12px); + + .progress-item-number { + opacity: 0.4; + min-width: 24px; + min-height: 24px; + margin-bottom: 4px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 100%; + border: @scaled-one-px-value-ie solid @text-normal-ie; + border: @scaled-one-px-value solid @text-normal; + color: @text-normal-ie; + color: @text-normal; + } + + .progress-item-dashes { + opacity: 0.4; + width: @scaled-one-px-value-ie; + width: @scaled-one-px-value; + height: 100%; + background: repeating-linear-gradient( + to bottom, + @text-normal-ie 0px, + @text-normal-ie 3px, + transparent 3px, + transparent 6px + ); + background: repeating-linear-gradient( + to bottom, + @text-normal 0px, + @text-normal 3px, + transparent 3px, + transparent 6px + ); + } + } + + .progress-item-content { + flex: 1; + color: @text-normal-ie; + color: @text-normal; + min-height: 43px; + + .progress-item-header { + display: flex; + align-items: center; + + .progress-item-label { + line-height: 24px; + font-weight: 600; + .margin-right(4px); + } + } + } + + .progress-item-footer { + display: flex; + align-items: center; + justify-content: space-between; + + .progress-item-date { + color: @text-secondary-ie; + color: @text-secondary; + } + } + + .progress-item-check { + display: block; + + position: relative; + width: 24px; + height: 24px; + + &::before, + &::after { + content: ""; + position: absolute; + background: #009900; + // border-radius: 2px; + } + + &::before { + width: 4px; + height: 2px; + left: 7px; + top: 12px; + transform: rotate(45deg); + } + + &::after { + width: 10px; + height: 2px; + left: 9px; + top: 11px; + transform: rotate(-45deg); + } + } + + &.active { + .progress-item-number { + opacity: 1 !important; + border-color: @background-accent-button-ie !important; + border-color: @background-accent-button !important; + } + .progress-item-label { + color: @border-fill-input-focused-ie !important; + color: @border-fill-input-focused !important; + } + } + + &.complete { + &:not(.all-done) { + opacity: 0.4; + } + + .progress-item-number { + opacity: 1 !important; + border-color: #009900 !important; + } + .progress-item-content { + min-height: auto !important; + } + } + } + } + + &#id-send-for-signing-settings { + padding: 0; + &, table { + height: 100%; + } + + .content-padding { + padding: @layout-padding-right-panel-content-ie; + padding: @layout-padding-right-panel-content; + + .rtl & { + padding: @layout-padding-right-panel-content-rtl-ie; + padding: @layout-padding-right-panel-content-rtl; + } + } + + .inner { + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + flex: 1; + + .content { + display: flex; + flex-direction: column; + flex: 1; + } + + .footer { + padding: 12px 0; + display: flex; + justify-content: center; + + #id-send-for-signing-settings-send-btn { + .margin-right(10px); + } + } + + .description { + color: @text-secondary-ie; + color: @text-secondary; + } + + .roles-list-wrapper { + flex: 1; + position: relative; + } + + #id-send-for-signing-settings-roles-list { + width: 100%; + position: absolute; + overflow: hidden; + padding-top: 0; + + .role-item { + display: flex; + margin-bottom: 4px; + + .role-item-left { + display: flex; + flex-direction: column; + align-items: center; + .margin-right(12px); + + .role-item-number { + min-width: 24px; + min-height: 24px; + margin-bottom: 4px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 100%; + border: @scaled-one-px-value-ie solid rgba(0, 0, 0, 0.15); + border: @scaled-one-px-value solid rgba(0, 0, 0, 0.15); + color: #000000CC; + } + + .role-item-dashes { + opacity: 0.4; + width: @scaled-one-px-value-ie; + width: @scaled-one-px-value; + height: 100%; + background: repeating-linear-gradient( + to bottom, + @text-normal-ie 0px, + @text-normal-ie 3px, + transparent 3px, + transparent 6px + ); + background: repeating-linear-gradient( + to bottom, + @text-normal 0px, + @text-normal 3px, + transparent 3px, + transparent 6px + ); + } + } + + .role-item-content { + .role-item-user-cmb { + margin-bottom: 8px; + } + .role-item-user-cmb-menu { + width: 196px; + left: -36px; + .rtl & { + left: unset; + right: -36px; + } + + .item { + a { + display: flex; + padding: 5px 7px; + + .avatar { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 24px; + height: 24px; + border-radius: 24px; + background-color: @border-divider-ie; + background-color: @border-divider; + // color: @toolbar-header-text-on-background-ie; + // color: @toolbar-header-text-on-background; + vertical-align: middle; + background-size: cover; + background-position: center; + font-size: 10px; + line-height: 24px; + overflow: hidden; + text-align: center; + .margin-right(4px); + + .icon { + display: block; + width: @x-small-btn-icon-size-ie; + width: @x-small-btn-icon-size; + height: @x-small-btn-icon-size-ie; + height: @x-small-btn-icon-size; + } + } + + .content { + min-width: 0; + & > * { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .email { + color: @text-secondary-ie; + color: @text-secondary; + } + } + } + } + } + } + + &.last { + .role-item-dashes { + display: none; + } + } + + .role-item-content { + flex: 1; + color: @text-normal-ie; + color: @text-normal; + min-width: 0; + + .role-item-label { + line-height: 24px; + font-weight: 600; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .role-item-user-cmb { + height: 24px; + } + } + } + } + } + } } .ie {