diff --git a/apps/common/main/lib/component/InputField.js b/apps/common/main/lib/component/InputField.js index fecc5c2922..c474c2dd2b 100644 --- a/apps/common/main/lib/component/InputField.js +++ b/apps/common/main/lib/component/InputField.js @@ -394,6 +394,7 @@ define([ title : errors.join('\n'), placement : 'cursor' }); + errorBadge.tooltip('show'); if (modalParents.length > 0) { errorBadge.data('bs.tooltip').tip().css('z-index', parseInt(modalParents.css('z-index')) + 10); diff --git a/apps/common/main/lib/component/Window.js b/apps/common/main/lib/component/Window.js index eaff31f1f7..0c403fd040 100644 --- a/apps/common/main/lib/component/Window.js +++ b/apps/common/main/lib/component/Window.js @@ -646,7 +646,7 @@ define([ var arrBtns = {ok: this.okButtonText, cancel: this.cancelButtonText, yes: this.yesButtonText, no: this.noButtonText, - close: this.closeButtonText}; + close: this.closeButtonText, apply: this.applyButtonText, doNotApply: this.doNotApplyButtonText}; if (options.buttons && _.isArray(options.buttons)) { if (options.primary==undefined) diff --git a/apps/common/main/lib/view/TextInputDialog.js b/apps/common/main/lib/view/TextInputDialog.js index 2698e41809..c818c0cd9d 100644 --- a/apps/common/main/lib/view/TextInputDialog.js +++ b/apps/common/main/lib/view/TextInputDialog.js @@ -138,6 +138,7 @@ define([], function () { 'use strict'; if (state == 'ok') { if (this.inputLabel.checkValidate() !== true) { this.inputLabel.cmpEl.find('input').focus(); + this.inputLabel.showError(this.inputLabel.checkValidate()) return; } } diff --git a/apps/pdfeditor/main/app/controller/RedactTab.js b/apps/pdfeditor/main/app/controller/RedactTab.js index 51fb4a692d..7778d2fd77 100644 --- a/apps/pdfeditor/main/app/controller/RedactTab.js +++ b/apps/pdfeditor/main/app/controller/RedactTab.js @@ -93,22 +93,119 @@ define([ 'redact:start' : this.onStartRedact.bind(this), 'redact:apply' : this.onApplyRedact.bind(this), 'redact:page' : this.onRedactCurrentPage.bind(this), - // 'smartart:mouseenter': this.mouseenterSmartArt, - // 'smartart:mouseleave': this.mouseleaveSmartArt, + 'redact:pages' : this.onRedactPages.bind(this), + }, + 'Toolbar': { + 'tab:active': this.onActiveTab } }); }, onApplyRedact: function() { - this.api.ApplyRedact(); + Common.UI.warning({ + width: 500, + msg: this.textApplyRedact, + buttons: ['yes', 'no'], + primary: 'yes', + callback: _.bind(function(btn) { + if (btn == 'yes') { + this.api.ApplyRedact(); + } + }, this) + }); }, onStartRedact: function(isMarkMode) { - this.api.SetRedactTool(isMarkMode) + this.api.SetRedactTool(isMarkMode); }, onRedactCurrentPage: function() { - this.api.RedactPages([0]); + this.api.RedactPages([this.api.getCurrentPage()]); + }, + + onRedactPages: function() { + const self = this; + const countPages = this.api.getCountPages(); + + (new Common.Views.TextInputDialog({ + title: this.textRedactPages, + label: this.textEnterPageRange, + value: `1-${countPages}`, + description: this.textEnterRangeDescription, + inputFixedConfig: {fixedWidth: 40}, + inputConfig: { + maxLength: 20, + allowBlank: false, + validation: function(value) { + const singlePage = /^\d+$/; + const range = /^(\d+)-(\d+)$/; + + if (singlePage.test(value)) { + const page = parseInt(value, 10); + if (page < 1 || page > countPages) return `Page must be between 1 and ${countPages}`; + return true; + } + + const match = value.match(range); + if (match) { + const start = parseInt(match[1], 10); + const end = parseInt(match[2], 10); + if (start < 1 || end < 1 || start > countPages || end > countPages) { + return `Pages must be between 1 and ${countPages}`; + } + if (start > end) return 'Start page must be less than or equal to end page'; + return true; + } + + return 'Invalid format. Use single number or range with dash, e.g., 2 or 2-6'; + } + }, + handler: function(result, value) { + if (result === 'ok') { + let pages = []; + + if (value.includes('-')) { + const [start, end] = value.split('-').map(p => parseInt(p, 10)); + for (let i = start; i <= end; i++) { + pages.push(i - 1); + } + } else { + pages.push(parseInt(value, 10)); + } + + self.api.RedactPages(pages); + } + } + })).show(); + }, + + onActiveTab: function(tab) { + Common.UI.TooltipManager.showTip('mark-for-redaction'); + const isMarked = this.api.HasRedact(); + if (isMarked) { + Common.UI.warning({ + width: 500, + msg: this.textUnappliedRedactions, + buttons: ['apply', 'doNotApply', 'cancel'], + primary: 'apply', + callback: _.bind(function(btn) { + if (btn == 'apply') { + this.api.ApplyRedact(); + this.api.SetRedactTool(false); + this.view.btnMarkForRedact.toggle(false); + } else if (btn == 'doNotApply') { + this.api.RemoveAllRedact(); + this.api.SetRedactTool(false); + this.view.btnMarkForRedact.toggle(false); + } else if (btn == 'cancel') { + // Common.NotificationCenter.trigger('tab:set-active', 'red'); + this.toolbar.toolbar.setTab('red') + }}, this) + }); + } else { + this.view.btnMarkForRedact.toggle(false); + this.api.SetRedactTool(false); + } }, SetDisabled: function(state) { @@ -138,6 +235,12 @@ define([ me.view.setEvents(); }); } + Common.UI.TooltipManager.addTips({ + 'mark-for-redaction' : {name: 'help-tip-mark-for-redaction', placement: 'bottom-right', offset: {x: 10, y: 0}, text: this.tipMarkForRedaction, header: this.tipMarkForRedactionHeader, target: '#slot-btn-markredact', + automove: true, next: 'apply-redaction', maxwidth: 270, closable: false, isNewFeature: true}, + 'apply-redaction' : {name: 'help-tip-apply-redaction', placement: 'bottom-left', offset: {x: 10, y: 0}, text: this.tipApplyRedaction, header: this.tipApplyRedactionHeader, target: '#slot-btn-apply-redactions', + automove: true, maxwidth: 270, closable: false, isNewFeature: true}, + }); }, onDocumentReady: function() { @@ -146,7 +249,6 @@ define([ // this.getApplication().getController('Common.Controllers.ExternalDiagramEditor').setApi(this.api).loadConfig({config:this.mode, customization: this.mode.customization}); // this.getApplication().getController('Common.Controllers.ExternalOleEditor').setApi(this.api).loadConfig({config:this.mode, customization: this.mode.customization}); - Common.Utils.lockControls(Common.enumLock.disableOnStart, false, {array: this.view.lockedControls}); } }, @@ -155,51 +257,6 @@ define([ }, onApiFocusObject: function(selectedObjects) { - var pr, i = -1, type, - paragraph_locked = false, - no_paragraph = true, - in_chart = false, - page_deleted = false; - - while (++i < selectedObjects.length) { - type = selectedObjects[i].get_ObjectType(); - pr = selectedObjects[i].get_ObjectValue(); - - if (type === Asc.c_oAscTypeSelectElement.Paragraph) { - paragraph_locked = pr.get_Locked(); - no_paragraph = false; - } else if (type == Asc.c_oAscTypeSelectElement.Image || type == Asc.c_oAscTypeSelectElement.Shape || type == Asc.c_oAscTypeSelectElement.Chart || type == Asc.c_oAscTypeSelectElement.Table) { - if (type == Asc.c_oAscTypeSelectElement.Table || - type == Asc.c_oAscTypeSelectElement.Shape && !pr.get_FromImage() && !pr.get_FromChart()) { - no_paragraph = false; - } - if (type == Asc.c_oAscTypeSelectElement.Chart) { - in_chart = true; - } - } else if (type == Asc.c_oAscTypeSelectElement.PdfPage) { - page_deleted = pr.asc_getDeleteLock(); - } - } - - // if (in_chart !== this._state.in_chart) { - // this.view.btnInsertChart.updateHint(in_chart ? this.view.tipChangeChart : this.view.tipInsertChart); - // this._state.in_chart = in_chart; - // } - - if (this._state.prcontrolsdisable !== paragraph_locked) { - if (this._state.activated) this._state.prcontrolsdisable = paragraph_locked; - Common.Utils.lockControls(Common.enumLock.paragraphLock, paragraph_locked===true, {array: this.view.lockedControls}); - } - - if (this._state.no_paragraph !== no_paragraph) { - if (this._state.activated) this._state.no_paragraph = no_paragraph; - Common.Utils.lockControls(Common.enumLock.noParagraphSelected, no_paragraph, {array: this.view.lockedControls}); - } - - if (page_deleted !== undefined && this._state.pagecontrolsdisable !== page_deleted) { - if (this._state.activated) this._state.pagecontrolsdisable = page_deleted; - Common.Utils.lockControls(Common.enumLock.pageDeleted, page_deleted, {array: this.view.lockedControls}); - } }, }, PDFE.Controllers.RedactTab || {})); diff --git a/apps/pdfeditor/main/app/controller/Toolbar.js b/apps/pdfeditor/main/app/controller/Toolbar.js index 381ade43a2..77d606fe40 100644 --- a/apps/pdfeditor/main/app/controller/Toolbar.js +++ b/apps/pdfeditor/main/app/controller/Toolbar.js @@ -1509,20 +1509,19 @@ define([ me.api.UpdateInterfaceState(); }, 50); - // var tab = {caption: toolbar.textTabInsert, action: 'ins', extcls: this.mode.isEdit ? 'canedit' : '', layoutname: 'toolbar-insert', dataHintTitle: 'I'}; - // var instab = this.getApplication().getController('InsTab'); - // instab.setApi(this.api).setConfig({toolbar: this, mode: this.mode}); - // toolbar.addTab(tab, instab.createToolbarPanel(), 1); - // instab.onAppReady(this.mode); - // setTimeout(function(){ - // instab.onDocumentReady(); - // }, 50); + var tab = {caption: toolbar.textTabInsert, action: 'ins', extcls: this.mode.isEdit ? 'canedit' : '', layoutname: 'toolbar-insert', dataHintTitle: 'I'}; + var instab = this.getApplication().getController('InsTab'); + instab.setApi(this.api).setConfig({toolbar: this, mode: this.mode}); + toolbar.addTab(tab, instab.createToolbarPanel(), 1); + instab.onAppReady(this.mode); + setTimeout(function(){ + instab.onDocumentReady(); + }, 50); var tab = {caption: 'Redact', action: 'red', extcls: this.mode.isEdit ? 'canedit' : '', layoutname: 'toolbar-redact', dataHintTitle: 'X'}; var redacttab = this.getApplication().getController('RedactTab'); - console.log(redacttab) redacttab.setApi(this.api).setConfig({toolbar: this, mode: this.mode}); - toolbar.addTab(tab, redacttab.createToolbarPanel(), 1); + toolbar.addTab(tab, redacttab.createToolbarPanel(), 2); redacttab.onAppReady(this.mode); setTimeout(function(){ redacttab.onDocumentReady(); @@ -1543,6 +1542,7 @@ define([ if (this.mode.isPDFEdit || toolbar.isTabActive('ins') || toolbar.isTabActive('forms')) toolbar.setTab('home'); toolbar.setVisible('ins', this.mode.isPDFEdit); + toolbar.setVisible('red', this.mode.isPDFEdit); toolbar.setVisible('forms', this.mode.isPDFEdit && this.mode.canFeatureForms); $host.find('.annotate').toggleClass('hidden', this.mode.isPDFEdit); $host.find('.pdfedit').toggleClass('hidden', !this.mode.isPDFEdit); diff --git a/apps/pdfeditor/main/app/view/RedactTab.js b/apps/pdfeditor/main/app/view/RedactTab.js index 6f7f0285b6..6e2051c054 100644 --- a/apps/pdfeditor/main/app/view/RedactTab.js +++ b/apps/pdfeditor/main/app/view/RedactTab.js @@ -152,7 +152,9 @@ define([ ] }).on('item:click', function (menu, item, e) { if (item.value === 'current') { - me.fireEvent('redact:page', [item.value]); + me.fireEvent('redact:page'); + } else { + me.fireEvent('redact:pages') } }) ); diff --git a/apps/pdfeditor/main/locale/en.json b/apps/pdfeditor/main/locale/en.json index 2cbe7cf48d..3297f1cc23 100644 --- a/apps/pdfeditor/main/locale/en.json +++ b/apps/pdfeditor/main/locale/en.json @@ -94,6 +94,8 @@ "Common.UI.Themes.txtThemeModernLight": "Modern Light", "Common.UI.Themes.txtThemeSystem": "Same as system", "Common.UI.Window.cancelButtonText": "Cancel", + "Common.UI.Window.applyButtonText": "Apply", + "Common.UI.Window.doNotApplyButtonText": "Dont't apply", "Common.UI.Window.closeButtonText": "Close", "Common.UI.Window.noButtonText": "No", "Common.UI.Window.okButtonText": "OK", @@ -865,6 +867,15 @@ "PDFE.Controllers.InsTab.txtSymbol_vdots": "Vertical ellipsis", "PDFE.Controllers.InsTab.txtSymbol_xsi": "Xi", "PDFE.Controllers.InsTab.txtSymbol_zeta": "Zeta", + "PDFE.Controllers.RedactTab.textApplyRedact": "Redacted information will be permanently removed from this document. Once you save it, information couldn't be retrieved anymore", + "PDFE.Controllers.RedactTab.textRedactPages": "Redact pages", + "PDFE.Controllers.RedactTab.textEnterPageRange": "Enter page range for redaction", + "PDFE.Controllers.RedactTab.textEnterRangeDescription": "e.g. 1, 2, 8-11", + "PDFE.Controllers.RedactTab.textUnappliedRedactions": "This document contains redaction marks that yet not have been applied.

Until you select “Apply Redactions” these marks can be removed and information can be retrieved", + "PDFE.Controllers.RedactTab.tipMarkForRedaction": "Use these tools to mark, search, and redact sensitive content in your PDF", + "PDFE.Controllers.RedactTab.tipApplyRedaction": "Apply and save all redactions. Unsaved redactions can still be undone.", + "PDFE.Controllers.RedactTab.tipApplyRedactionHeader": "Apply redactions", + "PDFE.Controllers.RedactTab.tipMarkForRedactionHeader": "Mark for redactions", "PDFE.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.", "PDFE.Controllers.LeftMenu.newDocumentTitle": "Unnamed document", "PDFE.Controllers.LeftMenu.notcriticalErrorTitle": "Warning",