From 57043e6602f1b01ad9ab77d34be3019bf98cd5a5 Mon Sep 17 00:00:00 2001 From: JuliaSvinareva Date: Tue, 20 Apr 2021 19:49:49 +0300 Subject: [PATCH 1/8] [DE mobile] Changes related to main controller --- apps/documenteditor/mobile/locale/en.json | 3 +- .../mobile/src/controller/Error.jsx | 7 ++--- .../mobile/src/controller/LongActions.jsx | 4 +-- .../mobile/src/controller/Main.jsx | 29 +++++++++++++++++-- .../src/controller/settings/Download.jsx | 10 +++++-- 5 files changed, 41 insertions(+), 12 deletions(-) diff --git a/apps/documenteditor/mobile/locale/en.json b/apps/documenteditor/mobile/locale/en.json index 9ca0208b9..7e4fee34d 100644 --- a/apps/documenteditor/mobile/locale/en.json +++ b/apps/documenteditor/mobile/locale/en.json @@ -94,7 +94,8 @@ "errorUpdateVersionOnDisconnect": "Internet connection has been restored, and the file version has been changed.
Before you can continue working, you need to download the file or copy its content to make sure nothing is lost, and then reload this page.", "errorDefaultMessage": "Error code: %1", "criticalErrorExtText": "Press 'OK' to back to document list.", - "notcriticalErrorTitle": "Warning" + "notcriticalErrorTitle": "Warning", + "scriptLoadError": "The connection is too slow, some of the components could not be loaded. Please reload the page." }, "LongActions": { "openTitleText": "Opening Document", diff --git a/apps/documenteditor/mobile/src/controller/Error.jsx b/apps/documenteditor/mobile/src/controller/Error.jsx index 6ae81ef0d..ff499f251 100644 --- a/apps/documenteditor/mobile/src/controller/Error.jsx +++ b/apps/documenteditor/mobile/src/controller/Error.jsx @@ -1,8 +1,7 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect } from 'react'; import { inject } from 'mobx-react'; import { f7 } from 'framework7-react'; import { useTranslation } from 'react-i18next'; -import LongActionsController from "./LongActions"; const ErrorController = inject('storeAppOptions')(({storeAppOptions, LoadingDocument}) => { const {t} = useTranslation(); @@ -22,7 +21,7 @@ const ErrorController = inject('storeAppOptions')(({storeAppOptions, LoadingDocu if (id === Asc.c_oAscError.ID.LoadingScriptError) { f7.notification.create({ title: _t.criticalErrorTitle, - text: _t.criticalErrorTitle, + text: _t.scriptLoadError, closeButton: true }).open(); return; @@ -183,7 +182,7 @@ const ErrorController = inject('storeAppOptions')(({storeAppOptions, LoadingDocu // report only critical errors Common.Gateway.reportError(id, config.msg); - config.title = this.criticalErrorTitle; + config.title = _t.criticalErrorTitle; if (storeAppOptions.canBackToFolder && !storeAppOptions.isDesktopApp) { config.msg += '

' + _t.criticalErrorExtText; diff --git a/apps/documenteditor/mobile/src/controller/LongActions.jsx b/apps/documenteditor/mobile/src/controller/LongActions.jsx index 2c2e0f9fb..5365f7264 100644 --- a/apps/documenteditor/mobile/src/controller/LongActions.jsx +++ b/apps/documenteditor/mobile/src/controller/LongActions.jsx @@ -20,7 +20,7 @@ class LongActions extends Component { } closePreloader() { - if (this.loadMask.el) { + if (this.loadMask && this.loadMask.el) { f7.dialog.close(this.loadMask.el); } } @@ -70,7 +70,7 @@ class LongActions extends Component { if (action) { this.setLongActionView(action) } else { - this.loadMask.el && this.loadMask.el.classList.contains('modal-in') && f7.dialog.close(this.loadMask.el); + this.loadMask && this.loadMask.el && this.loadMask.el.classList.contains('modal-in') && f7.dialog.close(this.loadMask.el); } } diff --git a/apps/documenteditor/mobile/src/controller/Main.jsx b/apps/documenteditor/mobile/src/controller/Main.jsx index 061f1eae9..45e56bb10 100644 --- a/apps/documenteditor/mobile/src/controller/Main.jsx +++ b/apps/documenteditor/mobile/src/controller/Main.jsx @@ -189,6 +189,9 @@ class MainController extends Component { }; const onDocumentContentReady = () => { + if (this._isDocReady) + return; + const appOptions = this.props.storeAppOptions; const appSettings = this.props.storeApplicationSettings; @@ -327,8 +330,8 @@ class MainController extends Component { Common.Utils.Metric.setCurrentMetric(value); this.api.asc_SetDocumentUnits((value === Common.Utils.Metric.c_MetricUnits.inch) ? Asc.c_oAscDocumentUnits.Inch : ((value===Common.Utils.Metric.c_MetricUnits.pt) ? Asc.c_oAscDocumentUnits.Point : Asc.c_oAscDocumentUnits.Millimeter)); - //me.api.asc_registerCallback('asc_onDocumentModifiedChanged', _.bind(me.onDocumentModifiedChanged, me)); - //me.api.asc_registerCallback('asc_onDocumentCanSaveChanged', _.bind(me.onDocumentCanSaveChanged, me)); + this.api.asc_registerCallback('asc_onDocumentModifiedChanged', this.onDocumentModifiedChanged.bind(this)); + this.api.asc_registerCallback('asc_onDocumentCanSaveChanged', this.onDocumentCanSaveChanged.bind(this)); //if (me.stackLongActions.exist({id: ApplyEditRights, type: Asc.c_oAscAsyncActionType['BlockInteraction']})) { // me.onLongActionEnd(Asc.c_oAscAsyncActionType['BlockInteraction'], ApplyEditRights); @@ -342,6 +345,19 @@ class MainController extends Component { window.onunload = this.onUnload.bind(this); } + onDocumentModifiedChanged () { + const isModified = this.api.asc_isDocumentCanSave(); + if (this._state.isDocModified !== isModified) { + this._isDocReady && Common.Gateway.setDocumentModified(this.api.isDocumentModified()); + } + + this.updateWindowTitle(); + } + + onDocumentCanSaveChanged (isCanSave) { + // + } + onBeforeUnload () { LocalStorage.save(); @@ -485,6 +501,7 @@ class MainController extends Component { this.api.asc_registerCallback('asc_onServerVersion', this.onServerVersion.bind(this)); this.api.asc_registerCallback('asc_onDocumentName', this.onDocumentName.bind(this)); this.api.asc_registerCallback('asc_onPrintUrl', this.onPrintUrl.bind(this)); + this.api.asc_registerCallback('asc_onPrint', this.onPrint.bind(this)); EditorUIController.initThemeColors && EditorUIController.initThemeColors(); @@ -677,6 +694,14 @@ class MainController extends Component { } } + onPrint () { + if (!this.props.storeAppOptions.canPrint) return; + + if (this.api) + this.api.asc_Print(); + Common.component.Analytics.trackEvent('Print'); + } + onPrintUrl (url) { if (this.iframePrint) { this.iframePrint.parentNode.removeChild(this.iframePrint); diff --git a/apps/documenteditor/mobile/src/controller/settings/Download.jsx b/apps/documenteditor/mobile/src/controller/settings/Download.jsx index 5bf78d0ba..187b65c7b 100644 --- a/apps/documenteditor/mobile/src/controller/settings/Download.jsx +++ b/apps/documenteditor/mobile/src/controller/settings/Download.jsx @@ -55,6 +55,8 @@ class DownloadController extends Component { const DownloadWithTranslation = withTranslation()(DownloadController); const onAdvancedOptions = (type, advOptions, mode, formatOptions, _t, canRequestClose) => { + if ($$('.dlg-adv-options.modal-in').length > 0) return; + const api = Common.EditorApi.get(); if (type == Asc.c_oAscAdvancedOptionsID.TXT) { let picker; @@ -97,7 +99,8 @@ const onAdvancedOptions = (type, advOptions, mode, formatOptions, _t, canRequest '' + '
' + '', - buttons: buttons + buttons: buttons, + cssClass: 'dlg-adv-options' }).open(); dialog.on('opened', () => { picker = f7.picker.create({ @@ -122,7 +125,7 @@ const onAdvancedOptions = (type, advOptions, mode, formatOptions, _t, canRequest const password = document.getElementById('modal-password').value; api.asc_setAdvancedOptions(type, new Asc.asc_CDRMAdvancedOptions(password)); //if (!me._isDocReady) { - //me.onLongActionBegin(Asc.c_oAscAsyncActionType['BlockInteraction'], LoadingDocument); + //Common.Notifications.trigger('preloader:beginAction', Asc.c_oAscAsyncActionType['BlockInteraction'], this.LoadingDocument); //} } }]; @@ -138,7 +141,8 @@ const onAdvancedOptions = (type, advOptions, mode, formatOptions, _t, canRequest text: _t.txtProtected, content: '
', - buttons: buttons + buttons: buttons, + cssClass: 'dlg-adv-options' }).open(); } }; From eb63c42891f64ccc5452050da85214d34a280627 Mon Sep 17 00:00:00 2001 From: JuliaSvinareva Date: Tue, 20 Apr 2021 19:52:36 +0300 Subject: [PATCH 2/8] [PE mobile] Make main controller, add error controller, add controller for long actions --- apps/presentationeditor/mobile/locale/en.json | 103 +++- .../mobile/src/controller/Error.jsx | 222 +++++++ .../mobile/src/controller/LongActions.jsx | 192 ++++++ .../mobile/src/controller/Main.jsx | 559 ++++++++++++++++-- .../settings/ApplicationSettings.jsx | 17 +- .../mobile/src/page/app.jsx | 2 + 6 files changed, 1043 insertions(+), 52 deletions(-) create mode 100644 apps/presentationeditor/mobile/src/controller/Error.jsx create mode 100644 apps/presentationeditor/mobile/src/controller/LongActions.jsx diff --git a/apps/presentationeditor/mobile/locale/en.json b/apps/presentationeditor/mobile/locale/en.json index bcf17b851..a4aaae940 100644 --- a/apps/presentationeditor/mobile/locale/en.json +++ b/apps/presentationeditor/mobile/locale/en.json @@ -21,9 +21,110 @@ "Slide subtitle": "Slide subtitle", "Table": "Table", "Slide title": "Slide title" - } + }, + "closeButtonText": "Close File", + "advDRMOptions": "Protected File", + "advDRMPassword": "Password", + + "leavePageText": "You have unsaved changes in this document. Click 'Stay on this Page' to await the autosave of the document. Click 'Leave this Page' to discard all the unsaved changes.", + "titleLicenseExp": "License expired", + "warnLicenseExp": "Your license has expired. Please update your license and refresh the page.", + "errorServerVersion": "The editor version has been updated. The page will be reloaded to apply the changes.", + "titleServerVersion": "Editor updated", + "notcriticalErrorTitle": "Warning", + "errorOpensource": "Using the free Community version you can open documents for viewing only. To access mobile web editors, a commercial license is required.", + "warnLicenseLimitedNoAccess": "License expired. You have no access to document editing functionality. Please contact your administrator.", + "warnLicenseLimitedRenewed": "License needs to be renewed. You have a limited access to document editing functionality.
Please contact your administrator to get full access", + "warnLicenseExceeded": "You've reached the limit for simultaneous connections to %1 editors. This document will be opened for viewing only. Contact your administrator to learn more.", + "warnLicenseUsersExceeded": "You've reached the user limit for %1 editors. Contact your administrator to learn more.", + "warnNoLicense": "You've reached the limit for simultaneous connections to %1 editors. This document will be opened for viewing only. Contact %1 sales team for personal upgrade terms.", + "warnNoLicenseUsers": "You've reached the user limit for %1 editors. Contact %1 sales team for personal upgrade terms.", + "textBuyNow": "Visit website", + "textContactUs": "Contact sales", + "textNoLicenseTitle": "License limit reached", + "textPaidFeature": "Paid feature", + "textCustomLoader": "Please note that according to the terms of the license you are not entitled to change the loader. Please contact our Sales Department to get a quote.", + "textClose": "Close", + + "errorProcessSaveResult": "Saving is failed.", + "criticalErrorTitle": "Error", + "warnProcessRightsChange": "You have been denied the right to edit the file.", + "errorAccessDeny": "You are trying to perform an action you do not have rights for.
Please contact your Document Server administrator.", + + "errorUpdateVersion": "The file version has been changed. The page will be reloaded.", + "titleUpdateVersion": "Version changed", + "textHasMacros": "The file contains automatic macros.
Do you want to run macros?", + "textRemember": "Remember my choice", + "textYes": "Yes", + "textNo": "No" } }, + "Error": { + "criticalErrorTitle": "Error", + "unknownErrorText": "Unknown error.", + "convertationTimeoutText": "Convertation timeout exceeded.", + "openErrorText": "An error has occurred while opening the file", + "saveErrorText": "An error has occurred while saving the file", + "downloadErrorText": "Download failed.", + "uploadImageSizeMessage": "Maximium image size limit exceeded.", + "uploadImageExtMessage": "Unknown image format.", + "uploadImageFileCountMessage": "No images uploaded.", + "splitMaxRowsErrorText": "The number of rows must be less than %1", + "splitMaxColsErrorText": "The number of columns must be less than %1", + "splitDividerErrorText": "The number of rows must be a divisor of %1", + "errorKeyEncrypt": "Unknown key descriptor", + "errorKeyExpire": "Key descriptor expired", + "errorUsersExceed": "Count of users was exceed", + "errorViewerDisconnect": "Connection is lost. You can still view the document,
but will not be able to download until the connection is restored and page is reloaded.", + "errorFilePassProtect": "The file is password protected and could not be opened.", + "errorStockChart": "Incorrect row order. To build a stock chart place the data on the sheet in the following order:
opening price, max price, min price, closing price.", + "errorDataRange": "Incorrect data range.", + "errorDatabaseConnection": "External error.
Database connection error. Please, contact support.", + "errorUserDrop": "The file cannot be accessed right now.", + "errorConnectToServer": " The document could not be saved. Please check connection settings or contact your administrator.
When you click the 'OK' button, you will be prompted to download the document.", + "errorBadImageUrl": "Image url is incorrect", + "errorSessionAbsolute": "The document editing session has expired. Please reload the page.", + "errorSessionIdle": "The document has not been edited for quite a long time. Please reload the page.", + "errorSessionToken": "The connection to the server has been interrupted. Please reload the page.", + "errorDataEncrypted": "Encrypted changes have been received, they cannot be deciphered.", + "errorAccessDeny": "You are trying to perform an action you do not have rights for.
Please contact your Document Server administrator.", + "errorEditingDownloadas": "An error occurred during the work with the document.
Use the 'Download' option to save the file backup copy to your computer hard drive.", + "errorFileSizeExceed": "The file size exceeds the limitation set for your server.
Please contact your Document Server administrator for details.", + "errorUpdateVersionOnDisconnect": "Internet connection has been restored, and the file version has been changed.
Before you can continue working, you need to download the file or copy its content to make sure nothing is lost, and then reload this page.", + "errorDefaultMessage": "Error code: %1", + "criticalErrorExtText": "Press 'OK' to back to document list.", + "notcriticalErrorTitle": "Warning", + "scriptLoadError": "The connection is too slow, some of the components could not be loaded. Please reload the page." + }, + "LongActions": { + "openTitleText": "Opening Document", + "openTextText": "Opening document...", + "saveTitleText": "Saving Document", + "saveTextText": "Saving document...", + "loadFontsTitleText": "Loading Data", + "loadFontsTextText": "Loading data...", + "loadImagesTitleText": "Loading Images", + "loadImagesTextText": "Loading images...", + "loadFontTitleText": "Loading Data", + "loadFontTextText": "Loading data...", + "loadImageTitleText": "Loading Image", + "loadImageTextText": "Loading image...", + "downloadTitleText": "Downloading Document", + "downloadTextText": "Downloading document...", + "printTitleText": "Printing Document", + "printTextText": "Printing document...", + "uploadImageTitleText": "Uploading Image", + "uploadImageTextText": "Uploading image...", + "applyChangesTitleText": "Loading Data", + "applyChangesTextText": "Loading data...", + "savePreparingText": "Preparing to save", + "savePreparingTitle": "Preparing to save. Please wait...", + "waitText": "Please, wait...", + "txtEditingMode": "Set editing mode...", + "loadingDocumentTitleText": "Loading document", + "loadingDocumentTextText": "Loading document...", + "textLoadingDocument": "Loading document" + }, "ContextMenu": { "menuViewComment": "View Comment", "menuAddComment": "Add Comment", diff --git a/apps/presentationeditor/mobile/src/controller/Error.jsx b/apps/presentationeditor/mobile/src/controller/Error.jsx new file mode 100644 index 000000000..a8cd9213e --- /dev/null +++ b/apps/presentationeditor/mobile/src/controller/Error.jsx @@ -0,0 +1,222 @@ +import React, { useEffect } from 'react'; +import { inject } from 'mobx-react'; +import { f7 } from 'framework7-react'; +import { useTranslation } from 'react-i18next'; + +const ErrorController = inject('storeAppOptions')(({storeAppOptions, LoadingDocument}) => { + const {t} = useTranslation(); + const _t = t("Error", { returnObjects: true }); + + useEffect(() => { + Common.Notifications.on('engineCreated', (api) => { + api.asc_registerCallback('asc_onError', onError); + }); + return () => { + const api = Common.EditorApi.get(); + api.asc_unregisterCallback('asc_onError', onError); + } + }); + + const onError = (id, level, errData) => { + if (id === -82) return; // format error + + if (id === Asc.c_oAscError.ID.LoadingScriptError) { + f7.notification.create({ + title: _t.criticalErrorTitle, + text: _t.scriptLoadError, + closeButton: true + }).open(); + return; + } + + Common.Notifications.trigger('preloader:close'); + Common.Notifications.trigger('preloader:endAction', Asc.c_oAscAsyncActionType['BlockInteraction'], LoadingDocument); + + const api = Common.EditorApi.get(); + + const config = { + closable: false + }; + + switch (id) + { + case Asc.c_oAscError.ID.Unknown: + config.msg = _t.unknownErrorText; + break; + + case Asc.c_oAscError.ID.ConvertationTimeout: + config.msg = _t.convertationTimeoutText; + break; + + case Asc.c_oAscError.ID.ConvertationOpenError: + config.msg = _t.openErrorText; + break; + + case Asc.c_oAscError.ID.ConvertationSaveError: + config.msg = _t.saveErrorText; + break; + + case Asc.c_oAscError.ID.DownloadError: + config.msg = _t.downloadErrorText; + break; + + case Asc.c_oAscError.ID.UplImageSize: + config.msg = _t.uploadImageSizeMessage; + break; + + case Asc.c_oAscError.ID.UplImageExt: + config.msg = _t.uploadImageExtMessage; + break; + + case Asc.c_oAscError.ID.UplImageFileCount: + config.msg = _t.uploadImageFileCountMessage; + break; + + case Asc.c_oAscError.ID.SplitCellMaxRows: + config.msg = _t.splitMaxRowsErrorText.replace('%1', errData.get_Value()); + break; + + case Asc.c_oAscError.ID.SplitCellMaxCols: + config.msg = _t.splitMaxColsErrorText.replace('%1', errData.get_Value()); + break; + + case Asc.c_oAscError.ID.SplitCellRowsDivider: + config.msg = _t.splitDividerErrorText.replace('%1', errData.get_Value()); + break; + + case Asc.c_oAscError.ID.VKeyEncrypt: + config.msg = _t.errorKeyEncrypt; + break; + + case Asc.c_oAscError.ID.KeyExpire: + config.msg = _t.errorKeyExpire; + break; + + case Asc.c_oAscError.ID.UserCountExceed: + config.msg = _t.errorUsersExceed; + break; + + case Asc.c_oAscError.ID.CoAuthoringDisconnect: + config.msg = _t.errorViewerDisconnect; + break; + + case Asc.c_oAscError.ID.ConvertationPassword: + config.msg = _t.errorFilePassProtect; + break; + + case Asc.c_oAscError.ID.StockChartError: + config.msg = _t.errorStockChart; + break; + + case Asc.c_oAscError.ID.DataRangeError: + config.msg = _t.errorDataRange; + break; + + case Asc.c_oAscError.ID.Database: + config.msg = _t.errorDatabaseConnection; + break; + + case Asc.c_oAscError.ID.UserDrop: + const lostEditingRights = storeAppOptions.lostEditingRights; + if (lostEditingRights) { + storeAppOptions.changeEditingRights(false); + return; + } + storeAppOptions.changeEditingRights(true); + config.msg = _t.errorUserDrop; + break; + + case Asc.c_oAscError.ID.Warning: + config.msg = _t.errorConnectToServer; + break; + + case Asc.c_oAscError.ID.UplImageUrl: + config.msg = _t.errorBadImageUrl; + break; + + case Asc.c_oAscError.ID.SessionAbsolute: + config.msg = _t.errorSessionAbsolute; + break; + + case Asc.c_oAscError.ID.SessionIdle: + config.msg = _t.errorSessionIdle; + break; + + case Asc.c_oAscError.ID.SessionToken: + config.msg = _t.errorSessionToken; + break; + + case Asc.c_oAscError.ID.DataEncrypted: + config.msg = _t.errorDataEncrypted; + break; + + case Asc.c_oAscError.ID.AccessDeny: + config.msg = _t.errorAccessDeny; + break; + + case Asc.c_oAscError.ID.EditingError: + config.msg = _t.errorEditingDownloadas; + break; + + case Asc.c_oAscError.ID.ConvertationOpenLimitError: + config.msg = _t.errorFileSizeExceed; + break; + + case Asc.c_oAscError.ID.UpdateVersion: + config.msg = _t.errorUpdateVersionOnDisconnect; + break; + + default: + config.msg = _t.errorDefaultMessage.replace('%1', id); + break; + } + + if (level === Asc.c_oAscError.Level.Critical) { + + // report only critical errors + Common.Gateway.reportError(id, config.msg); + + config.title = _t.criticalErrorTitle; + + if (storeAppOptions.canBackToFolder && !storeAppOptions.isDesktopApp) { + config.msg += '

' + _t.criticalErrorExtText; + config.callback = function() { + Common.Notifications.trigger('goback', true); + } + } + if (id === Asc.c_oAscError.ID.DataEncrypted) { + api.asc_coAuthoringDisconnect(); + Common.Notifications.trigger('api:disconnect'); + } + } + else { + Common.Gateway.reportWarning(id, config.msg); + + config.title = _t.notcriticalErrorTitle; + config.callback = (btn) => { + if (id === Asc.c_oAscError.ID.Warning && btn === 'ok' && (storeAppOptions.canDownload || storeAppOptions.canDownloadOrigin)) { + api.asc_DownloadOrigin(); + } + storeAppOptions.changeEditingRights(false); + }; + } + + f7.dialog.create({ + cssClass: 'error-dialog', + title : config.title, + text : config.msg, + buttons: [ + { + text: 'OK', + onClick: config.callback + } + ] + }).open(); + + Common.component.Analytics.trackEvent('Internal Error', id.toString()); + }; + + return null +}); + +export default ErrorController; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/controller/LongActions.jsx b/apps/presentationeditor/mobile/src/controller/LongActions.jsx new file mode 100644 index 000000000..0828925ab --- /dev/null +++ b/apps/presentationeditor/mobile/src/controller/LongActions.jsx @@ -0,0 +1,192 @@ +import React, { Component } from 'react'; +import { inject } from 'mobx-react'; +import { f7 } from 'framework7-react'; +import { withTranslation } from 'react-i18next'; +import IrregularStack from "../../../../common/mobile/utils/IrregularStack"; + +class LongActions extends Component { + constructor(props) { + super(props); + + this.stackLongActions = new IrregularStack({ + strongCompare : function(obj1, obj2){return obj1.id === obj2.id && obj1.type === obj2.type;}, + weakCompare : function(obj1, obj2){return obj1.type === obj2.type;} + }); + + this.onLongActionBegin = this.onLongActionBegin.bind(this); + this.onLongActionEnd = this.onLongActionEnd.bind(this); + this.onOpenDocument = this.onOpenDocument.bind(this); + this.closePreloader = this.closePreloader.bind(this); + } + + closePreloader() { + if (this.loadMask && this.loadMask.el) { + f7.dialog.close(this.loadMask.el); + } + } + + componentDidMount() { + Common.Notifications.on('engineCreated', (api) => { + api.asc_registerCallback('asc_onStartAction', this.onLongActionBegin); + api.asc_registerCallback('asc_onEndAction', this.onLongActionEnd); + api.asc_registerCallback('asc_onOpenDocumentProgress', this.onOpenDocument); + }); + Common.Notifications.on('preloader:endAction', this.onLongActionEnd); + Common.Notifications.on('preloader:beginAction', this.onLongActionBegin); + Common.Notifications.on('preloader:close', this.closePreloader); + } + + componentWillUnmount() { + const api = Common.EditorApi.get(); + api.asc_unregisterCallback('asc_onStartAction', this.onLongActionBegin); + api.asc_unregisterCallback('asc_onEndAction', this.onLongActionEnd); + api.asc_unregisterCallback('asc_onOpenDocumentProgress', this.onOpenDocument); + + Common.Notifications.off('preloader:endAction', this.onLongActionEnd); + Common.Notifications.off('preloader:beginAction', this.onLongActionBegin); + Common.Notifications.off('preloader:close', this.closePreloader); + } + + onLongActionBegin (type, id) { + const action = {id: id, type: type}; + this.stackLongActions.push(action); + this.setLongActionView(action); + } + + onLongActionEnd (type, id) { + let action = {id: id, type: type}; + this.stackLongActions.pop(action); + + //this.updateWindowTitle(true); + + action = this.stackLongActions.get({type: Asc.c_oAscAsyncActionType.Information}); + + if (action) { + this.setLongActionView(action) + } + + action = this.stackLongActions.get({type: Asc.c_oAscAsyncActionType.BlockInteraction}); + + if (action) { + this.setLongActionView(action) + } else { + this.loadMask && this.loadMask.el && this.loadMask.el.classList.contains('modal-in') && f7.dialog.close(this.loadMask.el); + } + } + + setLongActionView (action) { + const { t } = this.props; + const _t = t("LongActions", { returnObjects: true }); + let title = ''; + let text = ''; + switch (action.id) { + case Asc.c_oAscAsyncAction['Open']: + title = _t.openTitleText; + text = _t.openTextText; + break; + + case Asc.c_oAscAsyncAction['Save']: + title = _t.saveTitleText; + text = _t.saveTextText; + break; + + case Asc.c_oAscAsyncAction['LoadDocumentFonts']: + title = _t.loadFontsTitleText; + text = _t.loadFontsTextText; + break; + + case Asc.c_oAscAsyncAction['LoadDocumentImages']: + title = _t.loadImagesTitleText; + text = _t.loadImagesTextText; + break; + + case Asc.c_oAscAsyncAction['LoadFont']: + title = _t.loadFontTitleText; + text = _t.loadFontTextText; + break; + + case Asc.c_oAscAsyncAction['LoadImage']: + title = _t.loadImageTitleText; + text = _t.loadImageTextText; + break; + + case Asc.c_oAscAsyncAction['DownloadAs']: + title = _t.downloadTitleText; + text = _t.downloadTextText; + break; + + case Asc.c_oAscAsyncAction['Print']: + title = _t.printTitleText; + text = _t.printTextText; + break; + + case Asc.c_oAscAsyncAction['UploadImage']: + title = _t.uploadImageTitleText; + text = _t.uploadImageTextText; + break; + + case Asc.c_oAscAsyncAction['ApplyChanges']: + title = _t.applyChangesTitleText; + text = _t.applyChangesTextText; + break; + + case Asc.c_oAscAsyncAction['PrepareToSave']: + title = _t.savePreparingText; + text = _t.savePreparingTitle; + break; + + case Asc.c_oAscAsyncAction['Waiting']: + title = _t.waitText; + text = _t.waitText; + break; + + case ApplyEditRights: + title = _t.txtEditingMode; + text = _t.txtEditingMode; + break; + + case LoadingDocument: + title = _t.loadingDocumentTitleText; + text = _t.loadingDocumentTextText; + break; + default: + if (typeof action.id == 'string'){ + title = action.id; + text = action.id; + } + break; + } + + if (action.type === Asc.c_oAscAsyncActionType['BlockInteraction']) { + if (action.id === Asc.c_oAscAsyncAction['ApplyChanges']) { + return; + } + + if (this.loadMask && this.loadMask.el && this.loadMask.el.classList.contains('modal-in')) { + this.loadMask.el.getElementsByClassName('dialog-title')[0].innerHTML = title; + } else { + this.loadMask = f7.dialog.preloader(title); + } + } + + } + + onOpenDocument (progress) { + if (this.loadMask && this.loadMask.el) { + const $title = this.loadMask.el.getElementsByClassName('dialog-title')[0]; + const proc = (progress.asc_getCurrentFont() + progress.asc_getCurrentImage())/(progress.asc_getFontsCount() + progress.asc_getImagesCount()); + + const { t } = this.props; + const _t = t("LongActions", { returnObjects: true }); + $title.innerHTML = `${_t.textLoadingDocument}: ${Math.min(Math.round(proc * 100), 100)}%`; + } + } + + render() { + return null; + } +} + +const LongActionsController = withTranslation()(LongActions); + +export default LongActionsController; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/controller/Main.jsx b/apps/presentationeditor/mobile/src/controller/Main.jsx index 8c5e89e0b..aa626e48e 100644 --- a/apps/presentationeditor/mobile/src/controller/Main.jsx +++ b/apps/presentationeditor/mobile/src/controller/Main.jsx @@ -7,19 +7,44 @@ import CollaborationController from '../../../../common/mobile/lib/controller/co import EditorUIController from '../lib/patch'; import { CommentsController, - AddCommentController, - EditCommentController, ViewCommentsController } from "../../../../common/mobile/lib/controller/collaboration/Comments"; +import ErrorController from "./Error"; +import LongActionsController from "./LongActions"; +import {LocalStorage} from "../../../../common/mobile/utils/LocalStorage"; +import About from '../../../../common/mobile/lib/view/About'; -@inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings", "storeSlideSettings", "storeTextSettings", "storeTableSettings", "storeChartSettings", "storeLinkSettings") +@inject( + "storeFocusObjects", + "storeAppOptions", + "storePresentationInfo", + "storePresentationSettings", + "storeSlideSettings", + "storeTextSettings", + "storeTableSettings", + "storeChartSettings", + "storeLinkSettings", + "storeApplicationSettings" + ) class MainController extends Component { - constructor(props) { + constructor (props) { super(props) window.editorType = 'pe'; + + this.LoadingDocument = -256; + + this._state = { + licenseType: false, + isDocModified: false + }; + + this.defaultTitleText = __APP_TITLE_TEXT__; + + const { t } = this.props; + this._t = t('Controller.Main', {returnObjects:true}); } - initSdk() { + initSdk () { const script = document.createElement("script"); script.src = "../../../../sdkjs/develop/sdkjs/slide/scripts.js"; script.async = true; @@ -54,7 +79,15 @@ class MainController extends Component { this.props.storeAppOptions.setConfigOptions(this.editorConfig); this.editorConfig.lang && this.api.asc_setLocale(this.editorConfig.lang); - // console.log(this.editorConfig); + + let value = LocalStorage.getItem("pe-mobile-macros-mode"); + if (value === null) { + value = this.editorConfig.customization ? this.editorConfig.customization.macrosMode : 'warn'; + value = (value === 'enable') ? 1 : (value === 'disable' ? 2 : 0); + } else { + value = parseInt(value); + } + this.props.storeApplicationSettings.changeMacrosSettings(value); }; const loadDocument = data => { @@ -85,15 +118,15 @@ class MainController extends Component { docInfo.put_Permissions(_permissions); docInfo.put_EncryptedInfo(this.editorConfig.encryptionKeys); - // var enable = !this.editorConfig.customization || (this.editorConfig.customization.macros!==false); - // docInfo.asc_putIsEnabledMacroses(!!enable); - // enable = !this.editorConfig.customization || (this.editorConfig.customization.plugins!==false); - // docInfo.asc_putIsEnabledPlugins(!!enable); + let enable = !this.editorConfig.customization || (this.editorConfig.customization.macros !== false); + docInfo.asc_putIsEnabledMacroses(!!enable); + enable = !this.editorConfig.customization || (this.editorConfig.customization.plugins !== false); + docInfo.asc_putIsEnabledPlugins(!!enable); } this.api.asc_registerCallback('asc_onGetEditorPermissions', onEditorPermissions); - // this.api.asc_registerCallback('asc_onLicenseChanged', _.bind(this.onLicenseChanged, this)); - // this.api.asc_registerCallback('asc_onRunAutostartMacroses', _.bind(this.onRunAutostartMacroses, this)); + this.api.asc_registerCallback('asc_onLicenseChanged', this.onLicenseChanged.bind(this)); + this.api.asc_registerCallback('asc_onRunAutostartMacroses', this.onRunAutostartMacroses.bind(this)); this.api.asc_setDocInfo(docInfo); this.api.asc_getEditorPermissions(this.editorConfig.licenseUrl, this.editorConfig.customerId); @@ -111,16 +144,16 @@ class MainController extends Component { }; const onEditorPermissions = params => { - let me = this; const licType = params.asc_getLicenseType(); - me.appOptions.canLicense = (licType === Asc.c_oLicenseResult.Success || licType === Asc.c_oLicenseResult.SuccessLimit); + this.appOptions.canLicense = (licType === Asc.c_oLicenseResult.Success || licType === Asc.c_oLicenseResult.SuccessLimit); - this.props.storeAppOptions.setPermissionOptions(this.document, licType, params, this.permissions); + const storeAppOptions = this.props.storeAppOptions; + storeAppOptions.setPermissionOptions(this.document, licType, params, this.permissions); + this.applyMode(storeAppOptions); - // me.api.asc_setViewMode(!me.appOptions.isEdit); - me.api.asc_setViewMode(false); - me.api.asc_LoadDocument(); + this.api.asc_LoadDocument(); + this.api.Resize(); }; const _process_array = (array, fn) => { @@ -144,24 +177,36 @@ class MainController extends Component { 'translate': t('Controller.Main.SDK', {returnObjects:true}) }); + Common.Notifications.trigger('engineCreated', this.api); Common.EditorApi = {get: () => this.api}; this.appOptions = {}; this.bindEvents(); - let value = null /*Common.localStorage.getItem("pe-settings-fontrender")*/; + let value = LocalStorage.getItem("pe-settings-fontrender"); if (value===null) value = window.devicePixelRatio > 1 ? '1' : '3'; this.api.SetFontRenderingMode(parseInt(value)); this.api.SetDrawingFreeze(true); this.api.SetThemesPath("../../../../sdkjs/slide/themes/"); - // Common.Utils.Metric.setCurrentMetric(1); //pt + Common.Utils.Metric.setCurrentMetric(1); //pt Common.Gateway.on('init', loadConfig); - // Common.Gateway.on('showmessage', _.bind(me.onExternalMessage, me)); + Common.Gateway.on('showmessage', this.onExternalMessage.bind(this)); Common.Gateway.on('opendocument', loadDocument); Common.Gateway.appReady(); - Common.Notifications.trigger('engineCreated', this.api); + Common.Gateway.on('internalcommand', function(data) { + if (data.command === 'hardBack') { + if ($$('.modal-in').length > 0) { + if ( !($$('.error-dialog.modal-in').length > 0) ) { + f7.dialog.close(); + } + Common.Gateway.internalMessage('hardBack', false); + } else + Common.Gateway.internalMessage('hardBack', true); + } + }); + Common.Gateway.internalMessage('listenHardBack'); }, error => { console.log('promise failed ' + error); }); @@ -174,11 +219,76 @@ class MainController extends Component { document.body.appendChild(script); } - bindEvents() { - - // me.api.asc_registerCallback('asc_onError', _.bind(me.onError, me)); - this.api.asc_registerCallback('asc_onDocumentContentReady', this._onDocumentContentReady.bind(this)); - this.api.asc_registerCallback('asc_onOpenDocumentProgress', this._onOpenDocumentProgress.bind(this)); + applyMode(appOptions) { + this.api.asc_enableKeyEvents(appOptions.isEdit); + this.api.asc_setViewMode(!appOptions.isEdit && !appOptions.isRestrictedEdit); + (appOptions.isRestrictedEdit && appOptions.canComments) && this.api.asc_setRestriction(Asc.c_oAscRestrictionType.OnlyComments); + + let value = LocalStorage.getItem('pe-mobile-settings-unit'); + value = (value !== null) ? + parseInt(value) : + (appOptions.customization && appOptions.customization.unit ? Common.Utils.Metric.c_MetricUnits[appOptions.customization.unit.toLocaleLowerCase()] : Common.Utils.Metric.getDefaultMetric()); + (value === undefined) && (value = Common.Utils.Metric.getDefaultMetric()); + Common.Utils.Metric.setCurrentMetric(value); + this.api.asc_SetDocumentUnits((value === Common.Utils.Metric.c_MetricUnits.inch) ? + Asc.c_oAscDocumentUnits.Inch : + ((value === Common.Utils.Metric.c_MetricUnits.pt) ? Asc.c_oAscDocumentUnits.Point : Asc.c_oAscDocumentUnits.Millimeter)); + + this.api.asc_registerCallback('asc_onDocumentModifiedChanged', this.onDocumentModifiedChanged.bind(this)); + this.api.asc_registerCallback('asc_onDocumentCanSaveChanged', this.onDocumentCanSaveChanged.bind(this)); + + //if (me.stackLongActions.exist({id: ApplyEditRights, type: Asc.c_oAscAsyncActionType['BlockInteraction']})) { + // me.onLongActionEnd(Asc.c_oAscAsyncActionType['BlockInteraction'], ApplyEditRights); + //} else if (!this._isDocReady) { + // me.hidePreloader(); + // me.onLongActionBegin(Asc.c_oAscAsyncActionType['BlockInteraction'], LoadingDocument); + //} + + // Message on window close + window.onbeforeunload = this.onBeforeUnload.bind(this); + window.onunload = this.onUnload.bind(this); + } + + onDocumentModifiedChanged () { + const isModified = this.api.asc_isDocumentCanSave(); + if (this._state.isDocModified !== isModified) { + this._isDocReady && Common.Gateway.setDocumentModified(this.api.isDocumentModified()); + } + + this.updateWindowTitle(); + } + + onDocumentCanSaveChanged (isCanSave) { + // + } + + onBeforeUnload () { + LocalStorage.save(); + + if (this.api.isDocumentModified()) { + this.api.asc_stopSaving(); + this.continueSavingTimer = window.setTimeout(() => { + this.api.asc_continueSaving(); + }, 500); + + return this._t.leavePageText; + } + } + + onUnload () { + if (this.continueSavingTimer) + clearTimeout(this.continueSavingTimer); + } + + bindEvents () { + this.api.asc_registerCallback('asc_onDocumentContentReady', this.onDocumentContentReady.bind(this)); + this.api.asc_registerCallback('asc_onDocumentUpdateVersion', this.onUpdateVersion.bind(this)); + this.api.asc_registerCallback('asc_onServerVersion', this.onServerVersion.bind(this)); + this.api.asc_registerCallback('asc_onAdvancedOptions', this.onAdvancedOptions.bind(this)); + this.api.asc_registerCallback('asc_onDocumentName', this.onDocumentName.bind(this)); + this.api.asc_registerCallback('asc_onPrintUrl', this.onPrintUrl.bind(this)); + this.api.asc_registerCallback('asc_onPrint', this.onPrint.bind(this)); + this.api.asc_registerCallback('asc_onMeta', this.onMeta.bind(this)); EditorUIController.initThemeColors && EditorUIController.initThemeColors(); @@ -266,12 +376,48 @@ class MainController extends Component { EditorUIController.updateChartStyles && EditorUIController.updateChartStyles(this.props.storeChartSettings, this.props.storeFocusObjects); } - _onDocumentContentReady() { + onDocumentContentReady () { + if (this._isDocReady) + return; + + this._isDocReady = true; + + const appOptions = this.props.storeAppOptions; + const appSettings = this.props.storeApplicationSettings; + this.api.SetDrawingFreeze(false); + Common.Notifications.trigger('preloader:close'); + Common.Notifications.trigger('preloader:endAction', Asc.c_oAscAsyncActionType['BlockInteraction'], this.LoadingDocument); + + let value = LocalStorage.getItem("pe-settings-zoom"); + const zf = (value!==null) ? parseInt(value) : (appOptions.customization && appOptions.customization.zoom ? parseInt(appOptions.customization.zoom) : -1); + (zf === -1) ? this.api.zoomFitToPage() : ((zf === -2) ? this.api.zoomFitToWidth() : this.api.zoom(zf>0 ? zf : 100)); + + value = LocalStorage.getBool("pe-mobile-spellcheck", !(appOptions.customization && appOptions.customization.spellcheck===false)); + appSettings.changeSpellCheck(value); + this.api.asc_setSpellCheck(value); + + this.updateWindowTitle(true); + + this.api.SetTextBoxInputMode(LocalStorage.getBool("pe-settings-inputmode")); + + if (appOptions.isEdit && this.needToUpdateVersion) { + Common.Notifications.trigger('api:disconnect'); + } + + Common.Gateway.on('processsaveresult', this.onProcessSaveResult.bind(this)); + Common.Gateway.on('processrightschange', this.onProcessRightsChange.bind(this)); + Common.Gateway.on('downloadas', this.onDownloadAs.bind(this)); + Common.Gateway.on('requestclose', this.onRequestClose.bind(this)); + + Common.Gateway.sendInfo({ + mode: appOptions.isEdit ? 'edit' : 'view' + }); + this.api.Resize(); this.api.zoomFitToPage(); - // me.api.asc_GetDefaultTableStyles && _.defer(function () {me.api.asc_GetDefaultTableStyles()}); + this.api.asc_GetDefaultTableStyles && setTimeout(() => {this.api.asc_GetDefaultTableStyles()}, 1); this.applyLicense(); @@ -281,23 +427,354 @@ class MainController extends Component { Common.Notifications.trigger('document:ready'); } - _onOpenDocumentProgress(progress) { - // if (this.loadMask) { - // var $title = $$(this.loadMask).find('.modal-title'), - // const proc = (progress.asc_getCurrentFont() + progress.asc_getCurrentImage())/(progress.asc_getFontsCount() + progress.asc_getImagesCount()); - - // $title.text(this.textLoadingDocument + ': ' + Math.min(Math.round(proc * 100), 100) + '%'); - // } + onLicenseChanged (params) { + const appOptions = this.props.storeAppOptions; + const licType = params.asc_getLicenseType(); + if (licType !== undefined && appOptions.canEdit && appOptions.config.mode !== 'view' && + (licType === Asc.c_oLicenseResult.Connections || licType === Asc.c_oLicenseResult.UsersCount || licType === Asc.c_oLicenseResult.ConnectionsOS || licType === Asc.c_oLicenseResult.UsersCountOS + || licType === Asc.c_oLicenseResult.SuccessLimit && (appOptions.trialMode & Asc.c_oLicenseMode.Limited) !== 0)) + this._state.licenseType = licType; + if (this._isDocReady && this._state.licenseType) + this.applyLicense(); } - applyLicense() { - /* TO DO */ - Common.Notifications.trigger('toolbar:activatecontrols'); + applyLicense () { + const _t = this._t; + const warnNoLicense = _t.warnNoLicense.replace(/%1/g, __COMPANY_NAME__); + const warnNoLicenseUsers = _t.warnNoLicenseUsers.replace(/%1/g, __COMPANY_NAME__); + const textNoLicenseTitle = _t.textNoLicenseTitle.replace(/%1/g, __COMPANY_NAME__); + const warnLicenseExceeded = _t.warnLicenseExceeded.replace(/%1/g, __COMPANY_NAME__); + const warnLicenseUsersExceeded = _t.warnLicenseUsersExceeded.replace(/%1/g, __COMPANY_NAME__); + + const appOptions = this.props.storeAppOptions; + if (appOptions.config.mode !== 'view' && !EditorUIController.isSupportEditFeature()) { + let value = LocalStorage.getItem("pe-opensource-warning"); + value = (value !== null) ? parseInt(value) : 0; + const now = (new Date).getTime(); + if (now - value > 86400000) { + LocalStorage.setItem("pe-opensource-warning", now); + f7.dialog.create({ + title: _t.notcriticalErrorTitle, + text : _t.errorOpensource, + buttons: [{text: 'OK'}] + }).open(); + } + Common.Notifications.trigger('toolbar:activatecontrols'); + return; + } + + if (this._state.licenseType) { + let license = this._state.licenseType; + let buttons = [{text: 'OK'}]; + if ((appOptions.trialMode & Asc.c_oLicenseMode.Limited) !== 0 && + (license === Asc.c_oLicenseResult.SuccessLimit || + license === Asc.c_oLicenseResult.ExpiredLimited || + appOptions.permissionsLicense === Asc.c_oLicenseResult.SuccessLimit) + ) { + license = (license === Asc.c_oLicenseResult.ExpiredLimited) ? _t.warnLicenseLimitedNoAccess : _t.warnLicenseLimitedRenewed; + } else if (license === Asc.c_oLicenseResult.Connections || license === Asc.c_oLicenseResult.UsersCount) { + license = (license===Asc.c_oLicenseResult.Connections) ? warnLicenseExceeded : warnLicenseUsersExceeded; + } else { + license = (license === Asc.c_oLicenseResult.ConnectionsOS) ? warnNoLicense : warnNoLicenseUsers; + buttons = [{ + text: _t.textBuyNow, + bold: true, + onClick: function() { + window.open(`${__PUBLISHER_URL__}`, "_blank"); + } + }, + { + text: _t.textContactUs, + onClick: function() { + window.open(`mailto:${__SALES_EMAIL__}`, "_blank"); + } + }]; + } + if (this._state.licenseType === Asc.c_oLicenseResult.SuccessLimit) { + Common.Notifications.trigger('toolbar:activatecontrols'); + } else { + Common.Notifications.trigger('toolbar:activatecontrols'); + Common.Notifications.trigger('toolbar:deactivateeditcontrols'); + Common.Notifications.trigger('api:disconnect'); + } + + let value = LocalStorage.getItem("pe-license-warning"); + value = (value !== null) ? parseInt(value) : 0; + const now = (new Date).getTime(); + + if (now - value > 86400000) { + LocalStorage.setItem("pe-license-warning", now); + f7.dialog.create({ + title: textNoLicenseTitle, + text : license, + buttons: buttons + }).open(); + } + } else { + if (!appOptions.isDesktopApp && !appOptions.canBrandingExt && + appOptions.config && appOptions.config.customization && (appOptions.config.customization.loaderName || appOptions.config.customization.loaderLogo)) { + f7.dialog.create({ + title: _t.textPaidFeature, + text : _t.textCustomLoader, + buttons: [{ + text: _t.textContactUs, + bold: true, + onClick: () => { + window.open(`mailto:${__SALES_EMAIL__}`, "_blank"); + } + }, + { text: _t.textClose }] + }).open(); + } + Common.Notifications.trigger('toolbar:activatecontrols'); + } } - render() { + onUpdateVersion (callback) { + const _t = this._t; + + this.needToUpdateVersion = true; + Common.Notifications.trigger('preloader:endAction', Asc.c_oAscAsyncActionType['BlockInteraction'], this.LoadingDocument); + + f7.dialog.alert( + _t.errorUpdateVersion, + _t.titleUpdateVersion, + () => { + Common.Gateway.updateVersion(); + if (callback) { + callback.call(this); + } + Common.Notifications.trigger('preloader:beginAction', Asc.c_oAscAsyncActionType['BlockInteraction'], this.LoadingDocument); + }); + } + + onServerVersion (buildVersion) { + if (this.changeServerVersion) return true; + const _t = this._t; + + if (About.appVersion() !== buildVersion && !window.compareVersions) { + this.changeServerVersion = true; + f7.dialog.alert( + _t.errorServerVersion, + _t.titleServerVersion, + () => { + setTimeout(() => {Common.Gateway.updateVersion()}, 0); + }); + return true; + } + return false; + } + + onAdvancedOptions (type, advOptions) { + if ($$('.dlg-adv-options.modal-in').length > 0) return; + + const _t = this._t; + + if (type == Asc.c_oAscAdvancedOptionsID.DRM) { + Common.Notifications.trigger('preloader:close'); + Common.Notifications.trigger('preloader:endAction', Asc.c_oAscAsyncActionType['BlockInteraction'], this.LoadingDocument); + + const buttons = [{ + text: 'OK', + bold: true, + close: false, + onClick: () => { + const password = document.getElementById('modal-password').value; + this.api.asc_setAdvancedOptions(type, new Asc.asc_CDRMAdvancedOptions(password)); + + if (!this._isDocReady) { + Common.Notifications.trigger('preloader:beginAction', Asc.c_oAscAsyncActionType['BlockInteraction'], this.LoadingDocument); + } + } + }]; + if (this.props.storeAppOptions.canRequestClose) + buttons.push({ + text: _t.closeButtonText, + onClick: () => { + Common.Gateway.requestClose(); + } + }); + + f7.dialog.create({ + title: _t.advDRMOptions, + text: (typeof advOptions === 'string' ? advOptions : _t.txtProtected), + content: + `
+ +
`, + buttons: buttons, + cssClass: 'dlg-adv-options' + }).open(); + } + } + + onDocumentName () { + this.updateWindowTitle(true); + } + + updateWindowTitle (force) { + const isModified = this.api.isDocumentModified(); + if (this._state.isDocModified !== isModified || force) { + const title = this.defaultTitleText; + + if (window.document.title !== title) { + window.document.title = title; + } + + this._isDocReady && (this._state.isDocModified !== isModified) && Common.Gateway.setDocumentModified(isModified); + this._state.isDocModified = isModified; + } + } + + onPrint () { + if (!this.props.storeAppOptions.canPrint) return; + + if (this.api) + this.api.asc_Print(); + Common.component.Analytics.trackEvent('Print'); + } + + onPrintUrl (url) { + if (this.iframePrint) { + this.iframePrint.parentNode.removeChild(this.iframePrint); + this.iframePrint = null; + } + + if (!this.iframePrint) { + this.iframePrint = document.createElement("iframe"); + this.iframePrint.id = "id-print-frame"; + this.iframePrint.style.display = 'none'; + this.iframePrint.style.visibility = "hidden"; + this.iframePrint.style.position = "fixed"; + this.iframePrint.style.right = "0"; + this.iframePrint.style.bottom = "0"; + document.body.appendChild(this.iframePrint); + this.iframePrint.onload = function() { + this.iframePrint.contentWindow.focus(); + this.iframePrint.contentWindow.print(); + this.iframePrint.contentWindow.blur(); + window.focus(); + }; + } + + if (url) { + this.iframePrint.src = url; + } + } + + onMeta (meta) { + this.updateWindowTitle(true); + Common.Gateway.metaChange(meta); + } + + onExternalMessage (msg) { + if (msg && msg.msg) { + msg.msg = (msg.msg).toString(); + f7.notification.create({ + //title: uiApp.params.modalTitle, + text: [msg.msg.charAt(0).toUpperCase() + msg.msg.substring(1)], + closeButton: true + }).open(); + + Common.component.Analytics.trackEvent('External Error'); + } + } + + onRunAutostartMacroses () { + const config = this.props.storeAppOptions.config; + const enable = !config.customization || (config.customization.macros !== false); + if (enable) { + const value = this.props.storeApplicationSettings.macrosMode; + if (value === 1) { + this.api.asc_runAutostartMacroses(); + } else if (value === 0) { + const _t = this._t; + f7.dialog.create({ + title: _t.notcriticalErrorTitle, + text: _t.textHasMacros, + content: `
+ + ${_t.textRemember} +
`, + buttons: [{ + text: _t.textYes, + onClick: () => { + const dontshow = $$('input[name="checkbox-show-macros"]').prop('checked'); + if (dontshow) { + this.props.storeApplicationSettings.changeMacrosSettings(1); + LocalStorage.setItem("pe-mobile-macros-mode", 1); + } + setTimeout(() => { + this.api.asc_runAutostartMacroses(); + }, 1); + }}, + { + text: _t.textNo, + onClick: () => { + const dontshow = $$('input[name="checkbox-show-macros"]').prop('checked'); + if (dontshow) { + this.props.storeApplicationSettings.changeMacrosSettings(2); + LocalStorage.setItem("pe-mobile-macros-mode", 2); + } + } + }] + }).open(); + } + } + } + + onProcessSaveResult (data) { + this.api.asc_OnSaveEnd(data.result); + + if (data && data.result === false) { + const _t = this._t; + f7.dialog.alert( + (!data.message) ? _t.errorProcessSaveResult : data.message, + _t.criticalErrorTitle + ); + } + } + + onProcessRightsChange (data) { + if (data && data.enabled === false) { + const appOptions = this.props.storeAppOptions; + const old_rights = appOptions.lostEditingRights; + appOptions.changeEditingRights(!old_rights); + this.api.asc_coAuthoringDisconnect(); + Common.Notifications.trigger('api:disconnect'); + + if (!old_rights) { + const _t = this._t; + f7.dialog.alert( + (!data.message) ? _t.warnProcessRightsChange : data.message, + _t.notcriticalErrorTitle, + () => { appOptions.changeEditingRights(false); } + ); + } + } + } + + onDownloadAs () { + if ( !this.props.storeAppOptions.canDownload) { + Common.Gateway.reportError(Asc.c_oAscError.ID.AccessDeny, this.errorAccessDeny); + return; + } + this._state.isFromGatewayDownloadAs = true; + this.api.asc_DownloadAs(new Asc.asc_CDownloadOptions(Asc.c_oAscFileType.PPTX, true)); + } + + onRequestClose () { + Common.Gateway.requestClose(); + } + + render () { return ( + + {EditorUIController.getEditCommentControllers && EditorUIController.getEditCommentControllers()} @@ -306,7 +783,7 @@ class MainController extends Component { ) } - componentDidMount() { + componentDidMount () { this.initSdk(); } } diff --git a/apps/presentationeditor/mobile/src/controller/settings/ApplicationSettings.jsx b/apps/presentationeditor/mobile/src/controller/settings/ApplicationSettings.jsx index c976d1f66..bc72b63bb 100644 --- a/apps/presentationeditor/mobile/src/controller/settings/ApplicationSettings.jsx +++ b/apps/presentationeditor/mobile/src/controller/settings/ApplicationSettings.jsx @@ -1,5 +1,6 @@ import React, { Component } from "react"; import { ApplicationSettings } from "../../view/settings/ApplicationSettings"; +import { LocalStorage } from '../../../../../common/mobile/utils/LocalStorage'; class ApplicationSettingsController extends Component { constructor(props) { @@ -8,23 +9,19 @@ class ApplicationSettingsController extends Component { setUnitMeasurement(value) { const api = Common.EditorApi.get(); - value = (value!==null) ? parseInt(value) : Common.Utils.Metric.getDefaultMetric(); + value = (value !== null) ? parseInt(value) : Common.Utils.Metric.getDefaultMetric(); Common.Utils.Metric.setCurrentMetric(value); - // Common.localStorage.setItem("pe-mobile-settings-unit", value); - api.asc_SetDocumentUnits((value==Common.Utils.Metric.c_MetricUnits.inch) ? Asc.c_oAscDocumentUnits.Inch : ((value==Common.Utils.Metric.c_MetricUnits.pt) ? Asc.c_oAscDocumentUnits.Point : Asc.c_oAscDocumentUnits.Millimeter)); + LocalStorage.setItem("pe-mobile-settings-unit", value); + api.asc_SetDocumentUnits((value === Common.Utils.Metric.c_MetricUnits.inch) ? Asc.c_oAscDocumentUnits.Inch : ((value === Common.Utils.Metric.c_MetricUnits.pt) ? Asc.c_oAscDocumentUnits.Point : Asc.c_oAscDocumentUnits.Millimeter)); } switchSpellCheck(value) { - const api = Common.EditorApi.get(); - // let state = value === '1' ? true : false; - // Common.localStorage.setItem("pe-mobile-spellcheck", state ? 1 : 0); - // Common.Utils.InternalSettings.set("pe-mobile-spellcheck", state); - api.asc_setSpellCheck(value); + LocalStorage.setBool("pe-mobile-spellcheck", value); + Common.EditorApi.get().asc_setSpellCheck(value); } setMacrosSettings(value) { - Common.Utils.InternalSettings.set("pe-mobile-macros-mode", value); - // Common.localStorage.setItem("pe-mobile-macros-mode", value); + LocalStorage.setItem("pe-mobile-macros-mode", value); } diff --git a/apps/presentationeditor/mobile/src/page/app.jsx b/apps/presentationeditor/mobile/src/page/app.jsx index 8e4ceafe1..55d94d9b2 100644 --- a/apps/presentationeditor/mobile/src/page/app.jsx +++ b/apps/presentationeditor/mobile/src/page/app.jsx @@ -3,6 +3,8 @@ import React from 'react'; import {App,Panel,Views,View,Popup,Page,Navbar,Toolbar,NavRight,Link,Block,BlockTitle,List,ListItem,ListInput,ListButton,BlockFooter} from 'framework7-react'; import { f7ready } from 'framework7-react'; +import '../../../../common/Analytics.js'; + import '../../../../common/Gateway.js'; import '../../../../common/main/lib/util/utils.js'; From 7c72e8cb1b3e06ac72b0e7156d33b8a8d3206dc4 Mon Sep 17 00:00:00 2001 From: JuliaSvinareva Date: Wed, 21 Apr 2021 16:32:30 +0300 Subject: [PATCH 3/8] [SSE mobile] Changes for code decomposition --- .../mobile/src/controller/Main.jsx | 52 ++----- .../mobile/src/store/focusObjects.js | 129 +----------------- 2 files changed, 12 insertions(+), 169 deletions(-) diff --git a/apps/spreadsheeteditor/mobile/src/controller/Main.jsx b/apps/spreadsheeteditor/mobile/src/controller/Main.jsx index 1e166bd36..afd6c2524 100644 --- a/apps/spreadsheeteditor/mobile/src/controller/Main.jsx +++ b/apps/spreadsheeteditor/mobile/src/controller/Main.jsx @@ -187,6 +187,8 @@ class MainController extends Component { // 'translate': translate }); + Common.EditorApi = {get: () => this.api}; + this.appOptions = {}; this.bindEvents(); @@ -202,7 +204,6 @@ class MainController extends Component { Common.Gateway.appReady(); Common.Notifications.trigger('engineCreated', this.api); - Common.EditorApi = {get: () => this.api}; }, error => { console.log('promise failed ' + error); }); @@ -227,58 +228,21 @@ class MainController extends Component { // me.api.asc_registerCallback('asc_onDocumentName', _.bind(me.onDocumentName, me)); me.api.asc_registerCallback('asc_onEndAction', me._onLongActionEnd.bind(me)); - const storeSpreadsheetSettings = this.props.storeSpreadsheetSettings; - const storeFocusObjects = this.props.storeFocusObjects; - const storeCellSettings = this.props.storeCellSettings; - const storeTextSettings = this.props.storeTextSettings; - const storeChartSettings = this.props.storeChartSettings; - const styleSize = storeCellSettings.styleSize; - - this.api.asc_registerCallback('asc_onSelectionChanged', cellInfo => { - console.log(cellInfo); - - storeFocusObjects.resetCellInfo(cellInfo); - storeCellSettings.initCellSettings(cellInfo); - storeTextSettings.initTextSettings(cellInfo); + EditorUIController.initThemeColors && EditorUIController.initThemeColors(); - let selectedObjects = Common.EditorApi.get().asc_getGraphicObjectProps(); + EditorUIController.initCellInfo && EditorUIController.initCellInfo(this.props); - if(selectedObjects.length) { - storeFocusObjects.resetFocusObjects(selectedObjects); + EditorUIController.initEditorStyles && EditorUIController.initEditorStyles(this.props.storeCellSettings); - // Chart Settings - - if (storeFocusObjects.chartObject) { - storeChartSettings.updateChartStyles(this.api.asc_getChartPreviews(storeFocusObjects.chartObject.get_ChartProperties().getType())); - } - } - }); + EditorUIController.initFonts && EditorUIController.initFonts(this.props); + const styleSize = this.props.storeCellSettings.styleSize; this.api.asc_setThumbnailStylesSizes(styleSize.width, styleSize.height); - this.api.asc_registerCallback('asc_onInitEditorFonts', (fonts, select) => { - storeCellSettings.initEditorFonts(fonts, select); - storeTextSettings.initEditorFonts(fonts, select); - }); - - this.api.asc_registerCallback('asc_onEditorSelectionChanged', fontObj => { - console.log(fontObj) - storeCellSettings.initFontInfo(fontObj); - storeTextSettings.initFontInfo(fontObj); - }); - - this.api.asc_registerCallback('asc_onInitEditorStyles', styles => { - storeCellSettings.initCellStyles(styles); - }); - - this.api.asc_registerCallback('asc_onSendThemeColors', (colors, standart_colors) => { - Common.Utils.ThemeColor.setColors(colors, standart_colors); - }); - // Spreadsheet Settings this.api.asc_registerCallback('asc_onSendThemeColorSchemes', schemes => { - storeSpreadsheetSettings.addSchemes(schemes); + this.props.storeSpreadsheetSettings.addSchemes(schemes); }); // Downloaded Advanced Options diff --git a/apps/spreadsheeteditor/mobile/src/store/focusObjects.js b/apps/spreadsheeteditor/mobile/src/store/focusObjects.js index a5d710292..936293cb0 100644 --- a/apps/spreadsheeteditor/mobile/src/store/focusObjects.js +++ b/apps/spreadsheeteditor/mobile/src/store/focusObjects.js @@ -61,140 +61,19 @@ export class storeFocusObjects { } get selections () { - const _selections = []; - - let isCell, isRow, isCol, isAll, isChart, isImage, isTextShape, isShape, isTextChart, - selType = this._cellInfo.asc_getSelectionType(), - isObjLocked = false; - - switch (selType) { - case Asc.c_oAscSelectionType.RangeCells: isCell = true; break; - case Asc.c_oAscSelectionType.RangeRow: isRow = true; break; - case Asc.c_oAscSelectionType.RangeCol: isCol = true; break; - case Asc.c_oAscSelectionType.RangeMax: isAll = true; break; - case Asc.c_oAscSelectionType.RangeImage: isImage = true; break; - case Asc.c_oAscSelectionType.RangeShape: isShape = true; break; - case Asc.c_oAscSelectionType.RangeChart: isChart = true; break; - case Asc.c_oAscSelectionType.RangeChartText:isTextChart = true; break; - case Asc.c_oAscSelectionType.RangeShapeText: isTextShape = true; break; - } - - if (isImage || isShape || isChart) { - isImage = isShape = isChart = false; - let has_chartprops = false; - let selectedObjects = Common.EditorApi.get().asc_getGraphicObjectProps(); - - for (let i = 0; i < selectedObjects.length; i++) { - if (selectedObjects[i].asc_getObjectType() == Asc.c_oAscTypeSelectElement.Image) { - const elValue = selectedObjects[i].asc_getObjectValue(); - isObjLocked = isObjLocked || elValue.asc_getLocked(); - const shapeProps = elValue.asc_getShapeProperties(); - - if (shapeProps) { - if (shapeProps.asc_getFromChart()) { - isChart = true; - } else { - isShape = true; - - } - } else if (elValue.asc_getChartProperties()) { - isChart = true; - has_chartprops = true; - } else { - isImage = true; - } - } - } - } else if (isTextShape || isTextChart) { - const selectedObjects = Common.EditorApi.get().asc_getGraphicObjectProps(); - let isEquation = false; - - for (var i = 0; i < selectedObjects.length; i++) { - const elType = selectedObjects[i].asc_getObjectType(); - if (elType == Asc.c_oAscTypeSelectElement.Image) { - const value = selectedObjects[i].asc_getObjectValue(); - isObjLocked = isObjLocked || value.asc_getLocked(); - } else if (elType == Asc.c_oAscTypeSelectElement.Paragraph) { - } else if (elType == Asc.c_oAscTypeSelectElement.Math) { - isEquation = true; - } - } - } - if (isChart || isTextChart) { - _selections.push('chart'); - - if (isTextChart) { - _selections.push('text'); - } - } else if ((isShape || isTextShape) && !isImage) { - _selections.push('shape'); - - if (isTextShape) { - _selections.push('text'); - } - } else if (isImage) { - _selections.push('image'); - - if (isShape) { - _selections.push('shape'); - } - } else { - _selections.push('cell'); - - if (this._cellInfo.asc_getHyperlink()) { - _selections.push('hyperlink'); - } - } - return _selections; + return !!this.intf ? this.intf.getSelections() : null; } get shapeObject() { - const shapes = []; - for (let object of this._focusObjects) { - if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Image) { - if (object.get_ObjectValue() && object.get_ObjectValue().get_ShapeProperties()) { - shapes.push(object); - } - } - } - if (shapes.length > 0) { - const object = shapes[shapes.length - 1]; // get top - return object.get_ObjectValue(); - } else { - return undefined; - } + return !!this.intf ? this.intf.getShapeObject() : null; } get imageObject() { - const images = []; - for (let object of this._focusObjects) { - if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Image) { - images.push(object); - } - } - if (images.length > 0) { - const object = images[images.length - 1]; // get top - return object.get_ObjectValue(); - } else { - return undefined; - } + return !!this.intf ? this.intf.getImageObject() : null; } get chartObject() { - const charts = []; - for (let object of this._focusObjects) { - if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Image) { - if (object.get_ObjectValue() && object.get_ObjectValue().get_ChartProperties()) { - charts.push(object); - } - } - } - if (charts.length > 0) { - const object = charts[charts.length - 1]; // get top - return object.get_ObjectValue(); - } else { - return undefined; - } + return !!this.intf ? this.intf.getChartObject() : null; } } \ No newline at end of file From 26523317e7a5a66e4b76b504f1f1edb9e64c4b05 Mon Sep 17 00:00:00 2001 From: JuliaSvinareva Date: Wed, 21 Apr 2021 21:03:14 +0300 Subject: [PATCH 4/8] [PE mobile] Add translations --- apps/presentationeditor/mobile/locale/en.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/presentationeditor/mobile/locale/en.json b/apps/presentationeditor/mobile/locale/en.json index a4aaae940..44a1aa35b 100644 --- a/apps/presentationeditor/mobile/locale/en.json +++ b/apps/presentationeditor/mobile/locale/en.json @@ -138,6 +138,12 @@ "errorCopyCutPaste": "Copy, cut and paste actions using the context menu will be performed within the current file only.", "textDoNotShowAgain": "Don't show again" }, + "Toolbar": { + "dlgLeaveTitleText": "You leave the application", + "dlgLeaveMsgText": "You have unsaved changes in this document. Click \\'Stay on this Page\\' to await the autosave of the document. Click \\'Leave this Page\\' to discard all the unsaved changes.", + "leaveButtonText": "Leave this Page", + "stayButtonText": "Stay on this Page" + }, "View": { "Settings": { "textDone": "Done", From cfbb8ce795ef5af699597d6410909c3ae6f5e3f0 Mon Sep 17 00:00:00 2001 From: JuliaSvinareva Date: Wed, 21 Apr 2021 21:04:52 +0300 Subject: [PATCH 5/8] [SSE mobile] Add toolbar, add logo --- apps/spreadsheeteditor/mobile/locale/en.json | 6 + .../mobile/src/controller/Main.jsx | 6 + .../mobile/src/controller/Toolbar.jsx | 207 ++++++++++++++++++ .../mobile/src/page/main.jsx | 37 ++-- .../mobile/src/store/appOptions.js | 2 - .../mobile/src/view/Toolbar.jsx | 33 +++ 6 files changed, 269 insertions(+), 22 deletions(-) create mode 100644 apps/spreadsheeteditor/mobile/src/controller/Toolbar.jsx create mode 100644 apps/spreadsheeteditor/mobile/src/view/Toolbar.jsx diff --git a/apps/spreadsheeteditor/mobile/locale/en.json b/apps/spreadsheeteditor/mobile/locale/en.json index e1b4b968c..773ef247b 100644 --- a/apps/spreadsheeteditor/mobile/locale/en.json +++ b/apps/spreadsheeteditor/mobile/locale/en.json @@ -29,6 +29,12 @@ "menuEdit": "Edit", "menuDelete": "Delete" }, + "Toolbar": { + "dlgLeaveTitleText": "You leave the application", + "dlgLeaveMsgText": "You have unsaved changes in this document. Click \\'Stay on this Page\\' to await the autosave of the document. Click \\'Leave this Page\\' to discard all the unsaved changes.", + "leaveButtonText": "Leave this Page", + "stayButtonText": "Stay on this Page" + }, "View" : { "Add" : { "textChart": "Chart", diff --git a/apps/spreadsheeteditor/mobile/src/controller/Main.jsx b/apps/spreadsheeteditor/mobile/src/controller/Main.jsx index afd6c2524..2b34515cb 100644 --- a/apps/spreadsheeteditor/mobile/src/controller/Main.jsx +++ b/apps/spreadsheeteditor/mobile/src/controller/Main.jsx @@ -278,6 +278,8 @@ class MainController extends Component { me.api.asc_getWorksheetsCount(); me.api.asc_showWorksheet(me.api.asc_getActiveWorksheetIndex()); + this.applyLicense(); + Common.Gateway.documentReady(); f7.emit('resize'); } @@ -291,6 +293,10 @@ class MainController extends Component { // } } + applyLicense () { + Common.Notifications.trigger('toolbar:activatecontrols'); + } + render() { return ( diff --git a/apps/spreadsheeteditor/mobile/src/controller/Toolbar.jsx b/apps/spreadsheeteditor/mobile/src/controller/Toolbar.jsx new file mode 100644 index 000000000..16dd1b657 --- /dev/null +++ b/apps/spreadsheeteditor/mobile/src/controller/Toolbar.jsx @@ -0,0 +1,207 @@ +import React, { useEffect, useState } from 'react'; +import { inject } from 'mobx-react'; +import { f7 } from 'framework7-react'; +import { useTranslation } from 'react-i18next'; +import ToolbarView from "../view/Toolbar"; + +const ToolbarController = inject('storeAppOptions', 'users', 'storeSpreadsheetInfo')(props => { + const {t} = useTranslation(); + const _t = t("Toolbar", { returnObjects: true }); + + const appOptions = props.storeAppOptions; + const isDisconnected = props.users.isDisconnected; + const displayCollaboration = props.users.hasEditUsers || appOptions.canViewComments; + const docTitle = props.storeSpreadsheetInfo.dataDoc ? props.storeSpreadsheetInfo.dataDoc.title : ''; + + useEffect(() => { + const onDocumentReady = () => { + const api = Common.EditorApi.get(); + api.asc_registerCallback('asc_onCanUndoChanged', onApiCanUndo); + api.asc_registerCallback('asc_onCanRedoChanged', onApiCanRedo); + api.asc_registerCallback('asc_onSelectionChanged', onApiSelectionChanged); + api.asc_registerCallback('asc_onWorkbookLocked', onApiSelectionChanged); + api.asc_registerCallback('asc_onWorksheetLocked', onApiSelectionChanged); + api.asc_registerCallback('asc_onActiveSheetChanged', onApiActiveSheetChanged); + api.asc_registerCallback('asc_onCoAuthoringDisconnect', onCoAuthoringDisconnect); + + Common.Notifications.on('api:disconnect', onCoAuthoringDisconnect); + Common.Notifications.on('toolbar:activatecontrols', activateControls); + Common.Notifications.on('toolbar:deactivateeditcontrols', deactivateEditControls); + Common.Notifications.on('goback', goBack); + Common.Notifications.on('sheet:active', onApiActiveSheetChanged); + }; + if ( !Common.EditorApi ) { + Common.Notifications.on('document:ready', onDocumentReady); + Common.Gateway.on('init', loadConfig); + } else { + onDocumentReady(); + } + + return () => { + Common.Notifications.off('document:ready', onDocumentReady); + Common.Notifications.off('api:disconnect', onCoAuthoringDisconnect); + Common.Notifications.off('toolbar:activatecontrols', activateControls); + Common.Notifications.off('toolbar:deactivateeditcontrols', deactivateEditControls); + Common.Notifications.off('goback', goBack); + Common.Notifications.off('sheet:active', onApiActiveSheetChanged); + + const api = Common.EditorApi.get(); + api.asc_unregisterCallback('asc_onCanUndoChanged', onApiCanUndo); + api.asc_unregisterCallback('asc_onCanRedoChanged', onApiCanRedo); + //api.asc_unregisterCallback('asc_onSelectionChanged', onApiSelectionChanged); TO DO + api.asc_unregisterCallback('asc_onWorkbookLocked', onApiSelectionChanged); + api.asc_unregisterCallback('asc_onWorksheetLocked', onApiSelectionChanged); + api.asc_unregisterCallback('asc_onActiveSheetChanged', onApiActiveSheetChanged); + api.asc_unregisterCallback('asc_onCoAuthoringDisconnect', onCoAuthoringDisconnect); + } + }); + + // Back button + const [isShowBack, setShowBack] = useState(false); + const loadConfig = (data) => { + if (data && data.config && data.config.canBackToFolder !== false && + data.config.customization && data.config.customization.goback && + (data.config.customization.goback.url || data.config.customization.goback.requestClose && data.config.canRequestClose)) { + setShowBack(true); + } + }; + const onBack = () => { + const api = Common.EditorApi.get(); + if (api.asc_isDocumentModified()) { + f7.dialog.create({ + title : _t.dlgLeaveTitleText, + text : _t.dlgLeaveMsgText, + verticalButtons: true, + buttons : [ + { + text: _t.leaveButtonText, + onClick: function() { + goBack(); + } + }, + { + text: _t.stayButtonText, + bold: true + } + ] + }).open(); + } else { + goBack(); + } + }; + const goBack = (current) => { + //if ( !Common.Controllers.Desktop.process('goback') ) { + if (appOptions.customization.goback.requestClose && appOptions.canRequestClose) { + Common.Gateway.requestClose(); + } else { + const href = appOptions.customization.goback.url; + if (!current && appOptions.customization.goback.blank !== false) { + window.open(href, "_blank"); + } else { + parent.location.href = href; + } + } + //} + } + + // Undo and Redo + const [isCanUndo, setCanUndo] = useState(false); + const [isCanRedo, setCanRedo] = useState(false); + const onApiCanUndo = (can) => { + if (isDisconnected) return; + setCanUndo(can); + }; + const onApiCanRedo = (can) => { + if (isDisconnected) return; + setCanRedo(can); + }; + const onUndo = () => { + const api = Common.EditorApi.get(); + if (api) { + api.asc_Undo(); + } + }; + const onRedo = () => { + const api = Common.EditorApi.get(); + if (api) { + api.asc_Redo(); + } + } + + const [disabledEditControls, setDisabledEditControls] = useState(false); + const onApiSelectionChanged = (cellInfo) => { + if (isDisconnected) return; + + const api = Common.EditorApi.get(); + const info = !!cellInfo ? cellInfo : api.asc_getCellInfo(); + let islocked = false; + + switch (info.asc_getSelectionType()) { + case Asc.c_oAscSelectionType.RangeChart: + case Asc.c_oAscSelectionType.RangeImage: + case Asc.c_oAscSelectionType.RangeShape: + case Asc.c_oAscSelectionType.RangeChartText: + case Asc.c_oAscSelectionType.RangeShapeText: + const objects = api.asc_getGraphicObjectProps(); + for ( let i in objects ) { + if ( objects[i].asc_getObjectType() == Asc.c_oAscTypeSelectElement.Image ) { + if ((islocked = objects[i].asc_getObjectValue().asc_getLocked())) + break; + } + } + break; + default: + islocked = info.asc_getLocked(); + } + + setDisabledEditControls(islocked); + }; + + const onApiActiveSheetChanged = (index) => { + Common.Notifications.trigger('comments:filterchange', ['doc', 'sheet' + Common.EditorApi.get().asc_getWorksheetId(index)], false ); + }; + + const [disabledSettings, setDisabledSettings] = useState(false); + const deactivateEditControls = (enableDownload) => { + setDisabledEditControls(true); + if (enableDownload) { + //DE.getController('Settings').setMode({isDisconnected: true, enableDownload: enableDownload}); + } else { + setDisabledSettings(true); + } + }; + + + const [disabledControls, setDisabledControls] = useState(true); + const activateControls = () => { + setDisabledControls(false); + }; + + const onCoAuthoringDisconnect = (enableDownload) => { + deactivateEditControls(enableDownload); + setCanUndo(false); + setCanRedo(false); + f7.popover.close(); + f7.sheet.close(); + f7.popup.close(); + }; + + return ( + + ) +}); + +export {ToolbarController as Toolbar}; \ No newline at end of file diff --git a/apps/spreadsheeteditor/mobile/src/page/main.jsx b/apps/spreadsheeteditor/mobile/src/page/main.jsx index 2f7b3713d..e02028e24 100644 --- a/apps/spreadsheeteditor/mobile/src/page/main.jsx +++ b/apps/spreadsheeteditor/mobile/src/page/main.jsx @@ -1,21 +1,21 @@ import React, { Component } from 'react'; -import { Page, View, Navbar, NavLeft, NavRight, Link, Icon } from 'framework7-react'; +import { Page, View, Navbar, Subnavbar, Icon } from 'framework7-react'; +import { observer, inject } from "mobx-react"; -// import EditOptions from '../view/edit/Edit'; import Settings from '../view/settings/Settings'; import CollaborationView from '../../../../common/mobile/lib/view/collaboration/Collaboration.jsx' import CellEditor from '../controller/CellEditor'; import Statusbar from '../controller/StatusBar' import AddOptions from "../view/add/Add"; import EditOptions from "../view/edit/Edit"; -import { Device } from '../../../../common/mobile/utils/device'; import { Search, SearchSettings } from '../controller/Search'; import { f7 } from 'framework7-react'; import {FunctionGroups} from "../controller/add/AddFunction"; import ContextMenu from '../controller/ContextMenu'; +import { Toolbar } from "../controller/Toolbar"; -export default class MainPage extends Component { +class MainPage extends Component { constructor(props) { super(props); this.state = { @@ -61,23 +61,18 @@ export default class MainPage extends Component { }; render() { + const appOptions = this.props.storeAppOptions; + const config = appOptions.config; + const showLogo = !(appOptions.canBrandingExt && (config.customization && (config.customization.loaderName || config.customization.loaderLogo))); return ( - + {/* Top Navbar */} - - {/*
*/} - - - - - - this.handleClickToOpenOptions('edit')}> - this.handleClickToOpenOptions('add')}> - { Device.phone ? null : } - this.handleClickToOpenOptions('coauth')}> - this.handleClickToOpenOptions('settings')}> - - + + {showLogo &&
} + + + +
this.handleClickToOpenOptions('add', {panels: panels, button: button})}/> {/* Page content */} @@ -106,4 +101,6 @@ export default class MainPage extends Component {
) } -}; \ No newline at end of file +} + +export default inject("storeAppOptions")(observer(MainPage)); \ No newline at end of file diff --git a/apps/spreadsheeteditor/mobile/src/store/appOptions.js b/apps/spreadsheeteditor/mobile/src/store/appOptions.js index bb3f69a2d..75900a131 100644 --- a/apps/spreadsheeteditor/mobile/src/store/appOptions.js +++ b/apps/spreadsheeteditor/mobile/src/store/appOptions.js @@ -12,8 +12,6 @@ export class storeAppOptions { isEdit = false; config = {}; - - isEdit = false; canViewComments = false; setConfigOptions (config) { diff --git a/apps/spreadsheeteditor/mobile/src/view/Toolbar.jsx b/apps/spreadsheeteditor/mobile/src/view/Toolbar.jsx new file mode 100644 index 000000000..26887d95b --- /dev/null +++ b/apps/spreadsheeteditor/mobile/src/view/Toolbar.jsx @@ -0,0 +1,33 @@ +import React, {Fragment} from 'react'; +import {NavLeft, NavRight, NavTitle, Link, Icon} from 'framework7-react'; +import { Device } from '../../../../common/mobile/utils/device'; +import EditorUIController from '../lib/patch' + +const ToolbarView = props => { + return ( + + + {props.isShowBack && } + {props.isEdit && EditorUIController.toolbarOptions && EditorUIController.toolbarOptions.getUndoRedo({ + disabledUndo: !props.isCanUndo, + disabledRedo: !props.isCanRedo, + onUndoClick: props.onUndo, + onRedoClick: props.onRedo + })} + + {!Device.phone && {props.docTitle}} + + {props.isEdit && EditorUIController.toolbarOptions && EditorUIController.toolbarOptions.getEditOptions({ + disabled: props.disabledEditControls || props.disabledControls, + onEditClick: () => props.openOptions('edit'), + onAddClick: () => props.openOptions('add') + })} + { Device.phone ? null : } + {props.displayCollaboration && props.openOptions('coauth')}>} + props.openOptions('settings')}> + + + ) +}; + +export default ToolbarView; \ No newline at end of file From 588a7f03863ebf9ec3251a36decc8b4e280dda59 Mon Sep 17 00:00:00 2001 From: JuliaSvinareva Date: Thu, 22 Apr 2021 13:54:26 +0300 Subject: [PATCH 6/8] [SSE mobile] Moved edit functions of context menu to private branch --- .../mobile/src/controller/ContextMenu.jsx | 243 ++++-------------- 1 file changed, 45 insertions(+), 198 deletions(-) diff --git a/apps/spreadsheeteditor/mobile/src/controller/ContextMenu.jsx b/apps/spreadsheeteditor/mobile/src/controller/ContextMenu.jsx index 39dad5fe2..7965086fb 100644 --- a/apps/spreadsheeteditor/mobile/src/controller/ContextMenu.jsx +++ b/apps/spreadsheeteditor/mobile/src/controller/ContextMenu.jsx @@ -7,6 +7,7 @@ import { LocalStorage } from '../../../../common/mobile/utils/LocalStorage'; import ContextMenuController from '../../../../common/mobile/lib/controller/ContextMenu'; import { idContextMenuElement } from '../../../../common/mobile/lib/view/ContextMenu'; import { Device } from '../../../../common/mobile/utils/device'; +import EditorUIController from '../lib/patch'; @inject ( stores => ({ isEdit: stores.storeAppOptions.isEdit, @@ -61,11 +62,14 @@ class ContextMenu extends ContextMenuController { super.onMenuItemClick(action); + if ( EditorUIController.ContextMenu && EditorUIController.ContextMenu.handleMenuItemClick(this, action) ) + return; + const api = Common.EditorApi.get(); const info = api.asc_getCellInfo(); switch (action) { case 'cut': - if (!api.asc_Cut() && !LocalStorage.getBool("sse-hide-copy-cut-paste-warning")) { + if (!LocalStorage.getBool("sse-hide-copy-cut-paste-warning")) { this.showCopyCutPasteModal(); } break; @@ -75,55 +79,13 @@ class ContextMenu extends ContextMenuController { } break; case 'paste': - if (!api.asc_Paste() && !LocalStorage.getBool("sse-hide-copy-cut-paste-warning")) { + if (!LocalStorage.getBool("sse-hide-copy-cut-paste-warning")) { this.showCopyCutPasteModal(); } break; - case 'addcomment': - Common.Notifications.trigger('addcomment'); - break; case 'viewcomment': Common.Notifications.trigger('viewcomment'); break; - case 'del': - api.asc_emptyCells(Asc.c_oAscCleanOptions.All); - break; - case 'wrap': - api.asc_setCellTextWrap(true); - break; - case 'unwrap': - api.asc_setCellTextWrap(false); - break; - case 'edit': - setTimeout(() => { - this.props.openOptions('edit'); - }, 0); - break; - case 'merge': - if (api.asc_mergeCellsDataLost(Asc.c_oAscMergeOptions.Merge)) { - setTimeout(() => { - f7.dialog.confirm(_t.warnMergeLostData, _t.notcriticalErrorTitle, () => { - api.asc_mergeCells(Asc.c_oAscMergeOptions.Merge); - }); - }, 0); - } else { - api.asc_mergeCells(Asc.c_oAscMergeOptions.Merge); - } - break; - case 'unmerge': - api.asc_mergeCells(Asc.c_oAscMergeOptions.None); - break; - case 'hide': - api[info.asc_getSelectionType() == Asc.c_oAscSelectionType.RangeRow ? 'asc_hideRows' : 'asc_hideColumns'](); - break; - case 'show': - api[info.asc_getSelectionType() == Asc.c_oAscSelectionType.RangeRow ? 'asc_showRows' : 'asc_showColumns'](); - break; - case 'addlink': - setTimeout(() => { - this.props.openOptions('add', 'link'); - }, 400) - break; case 'openlink': const linkinfo = info.asc_getHyperlink(); if ( linkinfo.asc_getType() == Asc.c_oAscHyperlinkType.RangeLink ) { @@ -145,12 +107,22 @@ class ContextMenu extends ContextMenuController { api.asc_getUrlType(url) > 0 && this.openLink(url); } break; - case 'freezePanes': - api.asc_freezePane(); - break; } + } - console.log("click context menu item: " + action); + onMergeCells() { + const { t } = this.props; + const _t = t("ContextMenu", { returnObjects: true }); + const api = Common.EditorApi.get(); + if (api.asc_mergeCellsDataLost(Asc.c_oAscMergeOptions.Merge)) { + setTimeout(() => { + f7.dialog.confirm(_t.warnMergeLostData, _t.notcriticalErrorTitle, () => { + api.asc_mergeCells(Asc.c_oAscMergeOptions.Merge); + }); + }, 0); + } else { + api.asc_mergeCells(Asc.c_oAscMergeOptions.Merge); + } } showCopyCutPasteModal() { @@ -198,33 +170,35 @@ class ContextMenu extends ContextMenuController { const { t } = this.props; const _t = t("ContextMenu", { returnObjects: true }); - const { isEdit, canViewComments, isDisconnected } = this.props; + const { isEdit } = this.props; - const api = Common.EditorApi.get(); - const cellinfo = api.asc_getCellInfo(); + if (isEdit && EditorUIController.ContextMenu) { + return EditorUIController.ContextMenu.mapMenuItems(this); + } else { + const {canViewComments } = this.props; - const itemsIcon = []; - const itemsText = []; + const api = Common.EditorApi.get(); + const cellinfo = api.asc_getCellInfo(); - let iscellmenu, isrowmenu, iscolmenu, isallmenu, ischartmenu, isimagemenu, istextshapemenu, isshapemenu, istextchartmenu; - let iscelllocked = cellinfo.asc_getLocked(); - const seltype = cellinfo.asc_getSelectionType(); - const xfs = cellinfo.asc_getXfs(); - const isComments = cellinfo.asc_getComments().length > 0; //prohibit adding multiple comments in one cell; + const itemsIcon = []; + const itemsText = []; - switch (seltype) { - case Asc.c_oAscSelectionType.RangeCells: iscellmenu = true; break; - case Asc.c_oAscSelectionType.RangeRow: isrowmenu = true; break; - case Asc.c_oAscSelectionType.RangeCol: iscolmenu = true; break; - case Asc.c_oAscSelectionType.RangeMax: isallmenu = true; break; - case Asc.c_oAscSelectionType.RangeImage: isimagemenu = true; break; - case Asc.c_oAscSelectionType.RangeShape: isshapemenu = true; break; - case Asc.c_oAscSelectionType.RangeChart: ischartmenu = true; break; - case Asc.c_oAscSelectionType.RangeChartText: istextchartmenu = true; break; - case Asc.c_oAscSelectionType.RangeShapeText: istextshapemenu = true; break; - } + let iscellmenu, isrowmenu, iscolmenu, isallmenu, ischartmenu, isimagemenu, istextshapemenu, isshapemenu, istextchartmenu; + const seltype = cellinfo.asc_getSelectionType(); + const isComments = cellinfo.asc_getComments().length > 0; //prohibit adding multiple comments in one cell; + + switch (seltype) { + case Asc.c_oAscSelectionType.RangeCells: iscellmenu = true; break; + case Asc.c_oAscSelectionType.RangeRow: isrowmenu = true; break; + case Asc.c_oAscSelectionType.RangeCol: iscolmenu = true; break; + case Asc.c_oAscSelectionType.RangeMax: isallmenu = true; break; + case Asc.c_oAscSelectionType.RangeImage: isimagemenu = true; break; + case Asc.c_oAscSelectionType.RangeShape: isshapemenu = true; break; + case Asc.c_oAscSelectionType.RangeChart: ischartmenu = true; break; + case Asc.c_oAscSelectionType.RangeChartText: istextchartmenu = true; break; + case Asc.c_oAscSelectionType.RangeShapeText: istextshapemenu = true; break; + } - if (!isEdit) { if (iscellmenu || istextchartmenu || istextshapemenu) { itemsIcon.push({ event: 'copy', @@ -243,136 +217,9 @@ class ContextMenu extends ContextMenuController { event: 'viewcomment' }); } - } else { - if (!iscelllocked && (isimagemenu || isshapemenu || ischartmenu || istextshapemenu || istextchartmenu)) { - api.asc_getGraphicObjectProps().every((object) => { - if (object.asc_getObjectType() == Asc.c_oAscTypeSelectElement.Image) { - iscelllocked = object.asc_getObjectValue().asc_getLocked(); - } - return !iscelllocked; - }); - } - - if (iscelllocked || api.isCellEdited) { - itemsIcon.push({ - event: 'copy', - icon: 'icon-copy' - }); - - } else { - itemsIcon.push({ - event: 'cut', - icon: 'icon-cut' - }); - itemsIcon.push({ - event: 'copy', - icon: 'icon-copy' - }); - itemsIcon.push({ - event: 'paste', - icon: 'icon-paste' - }); - itemsText.push({ - caption: _t.menuDelete, - event: 'del' - }); - - if (isimagemenu || isshapemenu || ischartmenu || - istextshapemenu || istextchartmenu) { - itemsText.push({ - caption: _t.menuEdit, - event: 'edit' - }); - } else { - if (iscolmenu || isrowmenu) { - itemsText.push({ - caption: _t.menuHide, - event: 'hide' - }); - itemsText.push({ - caption: _t.menuShow, - event: 'show' - }); - } else if (iscellmenu) { - if (!iscelllocked) { - itemsText.push({ - caption: _t.menuCell, - event: 'edit' - }); - } - - if (cellinfo.asc_getMerge() == Asc.c_oAscMergeOptions.None) { - itemsText.push({ - caption: _t.menuMerge, - event: 'merge' - }); - } - - if (cellinfo.asc_getMerge() == Asc.c_oAscMergeOptions.Merge) { - itemsText.push({ - caption: _t.menuUnmerge, - event: 'unmerge' - }); - } - - itemsText.push( - xfs.asc_getWrapText() ? - { - caption: _t.menuUnwrap, - event: 'unwrap' - } : - { - caption: _t.menuWrap, - event: 'wrap' - }); - - if (cellinfo.asc_getHyperlink() && !cellinfo.asc_getMultiselect()) { - itemsText.push({ - caption: _t.menuOpenLink, - event: 'openlink' - }); - } else if (!cellinfo.asc_getHyperlink() && !cellinfo.asc_getMultiselect() && - !cellinfo.asc_getLockText() && !!cellinfo.asc_getText()) { - itemsText.push({ - caption: _t.menuAddLink, - event: 'addlink' - }); - } - } - - itemsText.push({ - caption: api.asc_getSheetViewSettings().asc_getIsFreezePane() ? _t.menuUnfreezePanes : _t.menuFreezePanes, - event: 'freezePanes' - }); - - } - - if (canViewComments) { - if (isComments) { - itemsText.push({ - caption: _t.menuViewComment, - event: 'viewcomment' - }); - } else if (iscellmenu) { - itemsText.push({ - caption: _t.menuAddComment, - event: 'addcomment' - }); - } - } - } + return itemsIcon.concat(itemsText); } - - - if ( Device.phone && itemsText.length > 2 ) { - this.extraItems = itemsText.splice(2,itemsText.length, { - caption: _t.menuMore, - event: 'showActionSheet' - }); - } - - return itemsIcon.concat(itemsText); } initExtraItems () { From d66852e54071a6fef3cfa09137fb96fb4400c336 Mon Sep 17 00:00:00 2001 From: JuliaSvinareva Date: Thu, 22 Apr 2021 21:55:57 +0300 Subject: [PATCH 7/8] [DE PE mobile] Refactoring long actions controller --- .../mobile/src/controller/LongActions.jsx | 117 ++++++++--------- .../mobile/src/controller/LongActions.jsx | 121 ++++++++---------- 2 files changed, 106 insertions(+), 132 deletions(-) diff --git a/apps/documenteditor/mobile/src/controller/LongActions.jsx b/apps/documenteditor/mobile/src/controller/LongActions.jsx index 5365f7264..740351164 100644 --- a/apps/documenteditor/mobile/src/controller/LongActions.jsx +++ b/apps/documenteditor/mobile/src/controller/LongActions.jsx @@ -1,82 +1,75 @@ -import React, { Component } from 'react'; -import { inject } from 'mobx-react'; +import React, { useEffect } from 'react'; import { f7 } from 'framework7-react'; -import { withTranslation } from 'react-i18next'; +import { useTranslation } from 'react-i18next'; import IrregularStack from "../../../../common/mobile/utils/IrregularStack"; -class LongActions extends Component { - constructor(props) { - super(props); +const LongActionsController = () => { + const {t} = useTranslation(); + const _t = t("LongActions", { returnObjects: true }); - this.stackLongActions = new IrregularStack({ - strongCompare : function(obj1, obj2){return obj1.id === obj2.id && obj1.type === obj2.type;}, - weakCompare : function(obj1, obj2){return obj1.type === obj2.type;} - }); + const stackLongActions = new IrregularStack({ + strongCompare : function(obj1, obj2){return obj1.id === obj2.id && obj1.type === obj2.type;}, + weakCompare : function(obj1, obj2){return obj1.type === obj2.type;} + }); - this.onLongActionBegin = this.onLongActionBegin.bind(this); - this.onLongActionEnd = this.onLongActionEnd.bind(this); - this.onOpenDocument = this.onOpenDocument.bind(this); - this.closePreloader = this.closePreloader.bind(this); - } + let loadMask = null; - closePreloader() { - if (this.loadMask && this.loadMask.el) { - f7.dialog.close(this.loadMask.el); + const closePreloader = () => { + if (loadMask && loadMask.el) { + f7.dialog.close(loadMask.el); } } - componentDidMount() { + useEffect( () => { Common.Notifications.on('engineCreated', (api) => { - api.asc_registerCallback('asc_onStartAction', this.onLongActionBegin); - api.asc_registerCallback('asc_onEndAction', this.onLongActionEnd); - api.asc_registerCallback('asc_onOpenDocumentProgress', this.onOpenDocument); + api.asc_registerCallback('asc_onStartAction', onLongActionBegin); + api.asc_registerCallback('asc_onEndAction', onLongActionEnd); + api.asc_registerCallback('asc_onOpenDocumentProgress', onOpenDocument); }); - Common.Notifications.on('preloader:endAction', this.onLongActionEnd); - Common.Notifications.on('preloader:beginAction', this.onLongActionBegin); - Common.Notifications.on('preloader:close', this.closePreloader); - } + Common.Notifications.on('preloader:endAction', onLongActionEnd); + Common.Notifications.on('preloader:beginAction', onLongActionBegin); + Common.Notifications.on('preloader:close', closePreloader); - componentWillUnmount() { - const api = Common.EditorApi.get(); - api.asc_unregisterCallback('asc_onStartAction', this.onLongActionBegin); - api.asc_unregisterCallback('asc_onEndAction', this.onLongActionEnd); - api.asc_unregisterCallback('asc_onOpenDocumentProgress', this.onOpenDocument); + return ( () => { + const api = Common.EditorApi.get(); + api.asc_unregisterCallback('asc_onStartAction', onLongActionBegin); + api.asc_unregisterCallback('asc_onEndAction', onLongActionEnd); + api.asc_unregisterCallback('asc_onOpenDocumentProgress', onOpenDocument); - Common.Notifications.off('preloader:endAction', this.onLongActionEnd); - Common.Notifications.off('preloader:beginAction', this.onLongActionBegin); - Common.Notifications.off('preloader:close', this.closePreloader); - } + Common.Notifications.off('preloader:endAction', onLongActionEnd); + Common.Notifications.off('preloader:beginAction', onLongActionBegin); + Common.Notifications.off('preloader:close', closePreloader); + }) + }); - onLongActionBegin (type, id) { + const onLongActionBegin = (type, id) => { const action = {id: id, type: type}; - this.stackLongActions.push(action); - this.setLongActionView(action); - } + stackLongActions.push(action); + setLongActionView(action); + }; - onLongActionEnd (type, id) { + const onLongActionEnd = (type, id) => { let action = {id: id, type: type}; - this.stackLongActions.pop(action); + stackLongActions.pop(action); //this.updateWindowTitle(true); - action = this.stackLongActions.get({type: Asc.c_oAscAsyncActionType.Information}); + action = stackLongActions.get({type: Asc.c_oAscAsyncActionType.Information}); if (action) { - this.setLongActionView(action) + setLongActionView(action) } - action = this.stackLongActions.get({type: Asc.c_oAscAsyncActionType.BlockInteraction}); + action = stackLongActions.get({type: Asc.c_oAscAsyncActionType.BlockInteraction}); if (action) { - this.setLongActionView(action) + setLongActionView(action) } else { - this.loadMask && this.loadMask.el && this.loadMask.el.classList.contains('modal-in') && f7.dialog.close(this.loadMask.el); + loadMask && loadMask.el && loadMask.el.classList.contains('modal-in') && f7.dialog.close(loadMask.el); } - } + }; - setLongActionView (action) { - const { t } = this.props; - const _t = t("LongActions", { returnObjects: true }); + const setLongActionView = (action) => { let title = ''; let text = ''; switch (action.id) { @@ -177,31 +170,25 @@ class LongActions extends Component { return; } - if (this.loadMask && this.loadMask.el && this.loadMask.el.classList.contains('modal-in')) { - this.loadMask.el.getElementsByClassName('dialog-title')[0].innerHTML = title; + if (loadMask && loadMask.el && loadMask.el.classList.contains('modal-in')) { + loadMask.el.getElementsByClassName('dialog-title')[0].innerHTML = title; } else { - this.loadMask = f7.dialog.preloader(title); + loadMask = f7.dialog.preloader(title); } } - } + }; - onOpenDocument (progress) { - if (this.loadMask && this.loadMask.el) { - const $title = this.loadMask.el.getElementsByClassName('dialog-title')[0]; + const onOpenDocument = (progress) => { + if (loadMask && loadMask.el) { + const $title = loadMask.el.getElementsByClassName('dialog-title')[0]; const proc = (progress.asc_getCurrentFont() + progress.asc_getCurrentImage())/(progress.asc_getFontsCount() + progress.asc_getImagesCount()); - const { t } = this.props; - const _t = t("LongActions", { returnObjects: true }); $title.innerHTML = `${_t.textLoadingDocument}: ${Math.min(Math.round(proc * 100), 100)}%`; } } - render() { - return null; - } -} - -const LongActionsController = withTranslation()(LongActions); + return null; +}; export default LongActionsController; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/controller/LongActions.jsx b/apps/presentationeditor/mobile/src/controller/LongActions.jsx index 0828925ab..4dbb515cf 100644 --- a/apps/presentationeditor/mobile/src/controller/LongActions.jsx +++ b/apps/presentationeditor/mobile/src/controller/LongActions.jsx @@ -1,82 +1,75 @@ -import React, { Component } from 'react'; -import { inject } from 'mobx-react'; +import React, { useEffect } from 'react'; import { f7 } from 'framework7-react'; -import { withTranslation } from 'react-i18next'; +import { useTranslation } from 'react-i18next'; import IrregularStack from "../../../../common/mobile/utils/IrregularStack"; -class LongActions extends Component { - constructor(props) { - super(props); +const LongActionsController = () => { + const {t} = useTranslation(); + const _t = t("LongActions", {returnObjects: true}); - this.stackLongActions = new IrregularStack({ - strongCompare : function(obj1, obj2){return obj1.id === obj2.id && obj1.type === obj2.type;}, - weakCompare : function(obj1, obj2){return obj1.type === obj2.type;} - }); + const stackLongActions = new IrregularStack({ + strongCompare : function(obj1, obj2){return obj1.id === obj2.id && obj1.type === obj2.type;}, + weakCompare : function(obj1, obj2){return obj1.type === obj2.type;} + }); - this.onLongActionBegin = this.onLongActionBegin.bind(this); - this.onLongActionEnd = this.onLongActionEnd.bind(this); - this.onOpenDocument = this.onOpenDocument.bind(this); - this.closePreloader = this.closePreloader.bind(this); - } + let loadMask = null; - closePreloader() { - if (this.loadMask && this.loadMask.el) { - f7.dialog.close(this.loadMask.el); + const closePreloader = () => { + if (loadMask && loadMask.el) { + f7.dialog.close(loadMask.el); } - } + }; - componentDidMount() { + useEffect( () => { Common.Notifications.on('engineCreated', (api) => { - api.asc_registerCallback('asc_onStartAction', this.onLongActionBegin); - api.asc_registerCallback('asc_onEndAction', this.onLongActionEnd); - api.asc_registerCallback('asc_onOpenDocumentProgress', this.onOpenDocument); + api.asc_registerCallback('asc_onStartAction', onLongActionBegin); + api.asc_registerCallback('asc_onEndAction', onLongActionEnd); + api.asc_registerCallback('asc_onOpenDocumentProgress', onOpenDocument); }); - Common.Notifications.on('preloader:endAction', this.onLongActionEnd); - Common.Notifications.on('preloader:beginAction', this.onLongActionBegin); - Common.Notifications.on('preloader:close', this.closePreloader); - } + Common.Notifications.on('preloader:endAction', onLongActionEnd); + Common.Notifications.on('preloader:beginAction', onLongActionBegin); + Common.Notifications.on('preloader:close', closePreloader); - componentWillUnmount() { - const api = Common.EditorApi.get(); - api.asc_unregisterCallback('asc_onStartAction', this.onLongActionBegin); - api.asc_unregisterCallback('asc_onEndAction', this.onLongActionEnd); - api.asc_unregisterCallback('asc_onOpenDocumentProgress', this.onOpenDocument); + return (() => { + const api = Common.EditorApi.get(); + api.asc_unregisterCallback('asc_onStartAction', onLongActionBegin); + api.asc_unregisterCallback('asc_onEndAction', onLongActionEnd); + api.asc_unregisterCallback('asc_onOpenDocumentProgress', onOpenDocument); - Common.Notifications.off('preloader:endAction', this.onLongActionEnd); - Common.Notifications.off('preloader:beginAction', this.onLongActionBegin); - Common.Notifications.off('preloader:close', this.closePreloader); - } + Common.Notifications.off('preloader:endAction', onLongActionEnd); + Common.Notifications.off('preloader:beginAction', onLongActionBegin); + Common.Notifications.off('preloader:close', closePreloader); + }) + }); - onLongActionBegin (type, id) { + const onLongActionBegin = (type, id) => { const action = {id: id, type: type}; - this.stackLongActions.push(action); - this.setLongActionView(action); - } + stackLongActions.push(action); + setLongActionView(action); + }; - onLongActionEnd (type, id) { + const onLongActionEnd = (type, id) => { let action = {id: id, type: type}; - this.stackLongActions.pop(action); + stackLongActions.pop(action); //this.updateWindowTitle(true); - action = this.stackLongActions.get({type: Asc.c_oAscAsyncActionType.Information}); + action = stackLongActions.get({type: Asc.c_oAscAsyncActionType.Information}); if (action) { - this.setLongActionView(action) + setLongActionView(action) } - action = this.stackLongActions.get({type: Asc.c_oAscAsyncActionType.BlockInteraction}); + action = stackLongActions.get({type: Asc.c_oAscAsyncActionType.BlockInteraction}); if (action) { - this.setLongActionView(action) + setLongActionView(action) } else { - this.loadMask && this.loadMask.el && this.loadMask.el.classList.contains('modal-in') && f7.dialog.close(this.loadMask.el); + loadMask && loadMask.el && loadMask.el.classList.contains('modal-in') && f7.dialog.close(loadMask.el); } - } + }; - setLongActionView (action) { - const { t } = this.props; - const _t = t("LongActions", { returnObjects: true }); + const setLongActionView = (action) => { let title = ''; let text = ''; switch (action.id) { @@ -162,31 +155,25 @@ class LongActions extends Component { return; } - if (this.loadMask && this.loadMask.el && this.loadMask.el.classList.contains('modal-in')) { - this.loadMask.el.getElementsByClassName('dialog-title')[0].innerHTML = title; + if (loadMask && loadMask.el && loadMask.el.classList.contains('modal-in')) { + loadMask.el.getElementsByClassName('dialog-title')[0].innerHTML = title; } else { - this.loadMask = f7.dialog.preloader(title); + loadMask = f7.dialog.preloader(title); } } - } + }; - onOpenDocument (progress) { - if (this.loadMask && this.loadMask.el) { - const $title = this.loadMask.el.getElementsByClassName('dialog-title')[0]; + const onOpenDocument = (progress) => { + if (loadMask && loadMask.el) { + const $title = loadMask.el.getElementsByClassName('dialog-title')[0]; const proc = (progress.asc_getCurrentFont() + progress.asc_getCurrentImage())/(progress.asc_getFontsCount() + progress.asc_getImagesCount()); - const { t } = this.props; - const _t = t("LongActions", { returnObjects: true }); $title.innerHTML = `${_t.textLoadingDocument}: ${Math.min(Math.round(proc * 100), 100)}%`; } - } + }; - render() { - return null; - } -} - -const LongActionsController = withTranslation()(LongActions); + return null; +}; export default LongActionsController; \ No newline at end of file From 0d82918ed5b8ae62ec3065bac21bddb1016c1804 Mon Sep 17 00:00:00 2001 From: JuliaSvinareva Date: Thu, 22 Apr 2021 21:57:08 +0300 Subject: [PATCH 8/8] [SSE mobile] Add error controller, add long actions controller --- apps/spreadsheeteditor/mobile/locale/en.json | 97 +++++ .../mobile/src/controller/Error.jsx | 355 ++++++++++++++++++ .../mobile/src/controller/LongActions.jsx | 190 ++++++++++ .../mobile/src/controller/Main.jsx | 6 + .../spreadsheeteditor/mobile/src/page/app.jsx | 5 +- 5 files changed, 652 insertions(+), 1 deletion(-) create mode 100644 apps/spreadsheeteditor/mobile/src/controller/Error.jsx create mode 100644 apps/spreadsheeteditor/mobile/src/controller/LongActions.jsx diff --git a/apps/spreadsheeteditor/mobile/locale/en.json b/apps/spreadsheeteditor/mobile/locale/en.json index 773ef247b..9b308263c 100644 --- a/apps/spreadsheeteditor/mobile/locale/en.json +++ b/apps/spreadsheeteditor/mobile/locale/en.json @@ -6,6 +6,103 @@ "textAnonymous": "Anonymous" } }, + "LongActions": { + "openTitleText": "Opening Document", + "openTextText": "Opening document...", + "saveTitleText": "Saving Document", + "saveTextText": "Saving document...", + "loadFontsTitleText": "Loading Data", + "loadFontsTextText": "Loading data...", + "loadImagesTitleText": "Loading Images", + "loadImagesTextText": "Loading images...", + "loadFontTitleText": "Loading Data", + "loadFontTextText": "Loading data...", + "loadImageTitleText": "Loading Image", + "loadImageTextText": "Loading image...", + "downloadTitleText": "Downloading Document", + "downloadTextText": "Downloading document...", + "printTitleText": "Printing Document", + "printTextText": "Printing document...", + "uploadImageTitleText": "Uploading Image", + "uploadImageTextText": "Uploading image...", + "applyChangesTitleText": "Loading Data", + "applyChangesTextText": "Loading data...", + "savePreparingText": "Preparing to save", + "savePreparingTitle": "Preparing to save. Please wait...", + "waitText": "Please, wait...", + "txtEditingMode": "Set editing mode...", + "loadingDocumentTitleText": "Loading document", + "loadingDocumentTextText": "Loading document...", + "textLoadingDocument": "Loading document" + }, + "Error": { + "criticalErrorTitle": "Error", + "unknownErrorText": "Unknown error.", + "convertationTimeoutText": "Convertation timeout exceeded.", + "openErrorText": "An error has occurred while opening the file", + "saveErrorText": "An error has occurred while saving the file", + "downloadErrorText": "Download failed.", + "uploadImageSizeMessage": "Maximium image size limit exceeded.", + "uploadImageExtMessage": "Unknown image format.", + "uploadImageFileCountMessage": "No images uploaded.", + "errorKeyEncrypt": "Unknown key descriptor", + "errorKeyExpire": "Key descriptor expired", + "errorUsersExceed": "Count of users was exceed", + "errorViewerDisconnect": "Connection is lost. You can still view the document,
but will not be able to download until the connection is restored and page is reloaded.", + "errorFilePassProtect": "The file is password protected and could not be opened.", + "errorStockChart": "Incorrect row order. To build a stock chart place the data on the sheet in the following order:
opening price, max price, min price, closing price.", + "errorDataRange": "Incorrect data range.", + "errorDatabaseConnection": "External error.
Database connection error. Please, contact support.", + "errorUserDrop": "The file cannot be accessed right now.", + "errorConnectToServer": " The document could not be saved. Please check connection settings or contact your administrator.
When you click the 'OK' button, you will be prompted to download the document.", + "errorBadImageUrl": "Image url is incorrect", + "errorSessionAbsolute": "The document editing session has expired. Please reload the page.", + "errorSessionIdle": "The document has not been edited for quite a long time. Please reload the page.", + "errorSessionToken": "The connection to the server has been interrupted. Please reload the page.", + "errorDataEncrypted": "Encrypted changes have been received, they cannot be deciphered.", + "errorAccessDeny": "You are trying to perform an action you do not have rights for.
Please contact your Document Server administrator.", + "errorEditingDownloadas": "An error occurred during the work with the document.
Use the 'Download' option to save the file backup copy to your computer hard drive.", + "errorFileSizeExceed": "The file size exceeds the limitation set for your server.
Please contact your Document Server administrator for details.", + "errorUpdateVersionOnDisconnect": "Internet connection has been restored, and the file version has been changed.
Before you can continue working, you need to download the file or copy its content to make sure nothing is lost, and then reload this page.", + "errorDefaultMessage": "Error code: %1", + "criticalErrorExtText": "Press 'OK' to back to document list.", + "notcriticalErrorTitle": "Warning", + "scriptLoadError": "The connection is too slow, some of the components could not be loaded. Please reload the page.", + "pastInMergeAreaError": "Cannot change part of a merged cell", + "errorWrongBracketsCount": "Found an error in the formula entered.
Wrong cout of brackets.", + "errorWrongOperator": "An error in the entered formula. Wrong operator is used.
Please correct the error or use the Esc button to cancel the formula editing.", + "errorCountArgExceed": "Found an error in the formula entered.
Count of arguments exceeded.", + "errorCountArg": "Found an error in the formula entered.
Invalid number of arguments.", + "errorFormulaName": "Found an error in the formula entered.
Incorrect formula name.", + "errorFormulaParsing": "Internal error while the formula parsing.", + "errorArgsRange": "Found an error in the formula entered.
Incorrect arguments range.", + "errorUnexpectedGuid": "External error.
Unexpected Guid. Please, contact support.", + "errorFileRequest": "External error.
File Request. Please, contact support.", + "errorFileVKey": "External error.
Incorrect securety key. Please, contact support.", + "errorMaxPoints": "The maximum number of points in series per chart is 4096.", + "errorOperandExpected": "The entered function syntax is not correct. Please check if you are missing one of the parentheses - '(' or ')'.", + "errorMoveRange": "Cann't change a part of merged cell", + "errorAutoFilterDataRange": "The operation could not be done for the selected range of cells.
Select a uniform data range inside or outside the table and try again.", + "errorAutoFilterChangeFormatTable": "The operation could not be done for the selected cells as you cannot move a part of the table.
Select another data range so that the whole table was shifted and try again.", + "errorAutoFilterChange": "The operation is not allowed, as it is attempting to shift cells in a table on your worksheet.", + "errorAutoFilterHiddenRange": "The operation cannot be performed because the area contains filtered cells.
Please unhide the filtered elements and try again.", + "errorFillRange": "Could not fill the selected range of cells.
All the merged cells need to be the same size.", + "errorInvalidRef": "Enter a correct name for the selection or a valid reference to go to.", + "errorCreateDefName": "The existing named ranges cannot be edited and the new ones cannot be created
at the moment as some of them are being edited.", + "errorPasteMaxRange": "The copy and paste area does not match. Please select an area with the same size or click the first cell in a row to paste the copied cells.", + "errorLockedAll": "The operation could not be done as the sheet has been locked by another user.", + "errorLockedWorksheetRename": "The sheet cannot be renamed at the moment as it is being renamed by another user", + "errorOpenWarning": "The length of one of the formulas in the file exceeded
the allowed number of characters and it was removed.", + "errorFrmlWrongReferences": "The function refers to a sheet that does not exist.
Please check the data and try again.", + "errorCopyMultiselectArea": "This command cannot be used with multiple selections.
Select a single range and try again.", + "errorPrintMaxPagesCount": "Unfortunately, it’s not possible to print more than 1500 pages at once in the current version of the program.
This restriction will be eliminated in upcoming releases.", + "errorChangeArray": "You cannot change part of an array.", + "errorMultiCellFormula": "Multi-cell array formulas are not allowed in tables.", + "errorFrmlMaxTextLength": "Text values in formulas are limited to 255 characters.
Use the CONCATENATE function or concatenation operator (&)", + "errorFrmlMaxLength": "You cannot add this formula as its length exceeded the allowed number of characters.
Please edit it and try again.", + "errorFrmlMaxReference": "You cannot enter this formula because it has too many values,
cell references, and/or names.", + "errorDataValidate":"The value you entered is not valid.
A user has restricted values that can be entered into this cell." + }, "ContextMenu": { "menuViewComment": "View Comment", "menuAddComment": "Add Comment", diff --git a/apps/spreadsheeteditor/mobile/src/controller/Error.jsx b/apps/spreadsheeteditor/mobile/src/controller/Error.jsx new file mode 100644 index 000000000..340da6739 --- /dev/null +++ b/apps/spreadsheeteditor/mobile/src/controller/Error.jsx @@ -0,0 +1,355 @@ +import React, { useEffect } from 'react'; +import { inject } from 'mobx-react'; +import { f7 } from 'framework7-react'; +import { useTranslation } from 'react-i18next'; + +const ErrorController = inject('storeAppOptions')(({storeAppOptions, LoadingDocument}) => { + const {t} = useTranslation(); + const _t = t("Error", { returnObjects: true }); + + useEffect(() => { + Common.Notifications.on('engineCreated', (api) => { + api.asc_registerCallback('asc_onError', onError); + }); + return () => { + const api = Common.EditorApi.get(); + api.asc_unregisterCallback('asc_onError', onError); + } + }); + + const onError = (id, level, errData) => { + + if (id === Asc.c_oAscError.ID.LoadingScriptError) { + f7.notification.create({ + title: _t.criticalErrorTitle, + text: _t.scriptLoadError, + closeButton: true + }).open(); + return; + } + + Common.Notifications.trigger('preloader:close'); + Common.Notifications.trigger('preloader:endAction', Asc.c_oAscAsyncActionType['BlockInteraction'], LoadingDocument); + + const api = Common.EditorApi.get(); + + const config = { + closable: false + }; + + switch (id) + { + case Asc.c_oAscError.ID.Unknown: + config.msg = _t.unknownErrorText; + break; + + case Asc.c_oAscError.ID.ConvertationTimeout: + config.msg = _t.convertationTimeoutText; + break; + + case Asc.c_oAscError.ID.ConvertationOpenError: + config.msg = _t.openErrorText; + break; + + case Asc.c_oAscError.ID.ConvertationSaveError: + config.msg = _t.saveErrorText; + break; + + case Asc.c_oAscError.ID.DownloadError: + config.msg = _t.downloadErrorText; + break; + + case Asc.c_oAscError.ID.UplImageSize: + config.msg = _t.uploadImageSizeMessage; + break; + + case Asc.c_oAscError.ID.UplImageExt: + config.msg = _t.uploadImageExtMessage; + break; + + case Asc.c_oAscError.ID.UplImageFileCount: + config.msg = _t.uploadImageFileCountMessage; + break; + + case Asc.c_oAscError.ID.PastInMergeAreaError: + config.msg = _t.pastInMergeAreaError; + break; + + case Asc.c_oAscError.ID.FrmlWrongCountParentheses: + config.msg = _t.errorWrongBracketsCount; + config.closable = true; + break; + + case Asc.c_oAscError.ID.FrmlWrongOperator: + config.msg = _t.errorWrongOperator; + config.closable = true; + break; + + case Asc.c_oAscError.ID.FrmlWrongMaxArgument: + config.msg = _t.errorCountArgExceed; + config.closable = true; + break; + + case Asc.c_oAscError.ID.FrmlWrongCountArgument: + config.msg = _t.errorCountArg; + config.closable = true; + break; + + case Asc.c_oAscError.ID.FrmlWrongFunctionName: + config.msg = _t.errorFormulaName; + config.closable = true; + break; + + case Asc.c_oAscError.ID.FrmlAnotherParsingError: + config.msg = _t.errorFormulaParsing; + config.closable = true; + break; + + case Asc.c_oAscError.ID.FrmlWrongArgumentRange: + config.msg = _t.errorArgsRange; + config.closable = true; + break; + + case Asc.c_oAscError.ID.UnexpectedGuid: + config.msg = _t.errorUnexpectedGuid; + break; + + case Asc.c_oAscError.ID.FileRequest: + config.msg = _t.errorFileRequest; + break; + + case Asc.c_oAscError.ID.FileVKey: + config.msg = _t.errorFileVKey; + break; + + case Asc.c_oAscError.ID.MaxDataPointsError: + config.msg = _t.errorMaxPoints; + break; + + case Asc.c_oAscError.ID.FrmlOperandExpected: + config.msg = _t.errorOperandExpected; + config.closable = true; + break; + + case Asc.c_oAscError.ID.CannotMoveRange: + config.msg = _t.errorMoveRange; + break; + + case Asc.c_oAscError.ID.AutoFilterDataRangeError: + config.msg = _t.errorAutoFilterDataRange; + break; + + case Asc.c_oAscError.ID.AutoFilterChangeFormatTableError: + config.msg = _t.errorAutoFilterChangeFormatTable; + break; + + case Asc.c_oAscError.ID.AutoFilterChangeError: + config.msg = _t.errorAutoFilterChange; + break; + + case Asc.c_oAscError.ID.AutoFilterMoveToHiddenRangeError: + config.msg = _t.errorAutoFilterHiddenRange; + break; + + case Asc.c_oAscError.ID.CannotFillRange: + config.msg = _t.errorFillRange; + break; + + case Asc.c_oAscError.ID.InvalidReferenceOrName: + config.msg = _t.errorInvalidRef; + break; + + case Asc.c_oAscError.ID.LockCreateDefName: + config.msg = _t.errorCreateDefName; + break; + + case Asc.c_oAscError.ID.PasteMaxRangeError: + config.msg = _t.errorPasteMaxRange; + break; + + case Asc.c_oAscError.ID.LockedAllError: + config.msg = _t.errorLockedAll; + break; + + case Asc.c_oAscError.ID.LockedWorksheetRename: + config.msg = _t.errorLockedWorksheetRename; + break; + + case Asc.c_oAscError.ID.OpenWarning: + config.msg = _t.errorOpenWarning; + break; + + case Asc.c_oAscError.ID.FrmlWrongReferences: + config.msg = _t.errorFrmlWrongReferences; + config.closable = true; + break; + + case Asc.c_oAscError.ID.CopyMultiselectAreaError: + config.msg = _t.errorCopyMultiselectArea; + break; + + case Asc.c_oAscError.ID.PrintMaxPagesCount: + config.msg = _t.errorPrintMaxPagesCount; + break; + + case Asc.c_oAscError.ID.CannotChangeFormulaArray: + config.msg = _t.errorChangeArray; + break; + + case Asc.c_oAscError.ID.MultiCellsInTablesFormulaArray: + config.msg = _t.errorMultiCellFormula; + break; + + case Asc.c_oAscError.ID.FrmlMaxTextLength: + config.msg = _t.errorFrmlMaxTextLength; + break; + + case Asc.c_oAscError.ID.FrmlMaxLength: + config.msg = _t.errorFrmlMaxLength; + break; + + case Asc.c_oAscError.ID.FrmlMaxReference: + config.msg = _t.errorFrmlMaxReference; + break; + + case Asc.c_oAscError.ID.DataValidate: + errData && errData.asc_getErrorTitle() && (config.title = Common.Utils.String.htmlEncode(errData.asc_getErrorTitle())); + config.msg = errData && errData.asc_getError() ? Common.Utils.String.htmlEncode(errData.asc_getError()) : _t.errorDataValidate; + break; + + case Asc.c_oAscError.ID.VKeyEncrypt: + config.msg = _t.errorKeyEncrypt; + break; + + case Asc.c_oAscError.ID.KeyExpire: + config.msg = _t.errorKeyExpire; + break; + + case Asc.c_oAscError.ID.UserCountExceed: + config.msg = _t.errorUsersExceed; + break; + + case Asc.c_oAscError.ID.CoAuthoringDisconnect: + config.msg = _t.errorViewerDisconnect; + break; + + case Asc.c_oAscError.ID.ConvertationPassword: + config.msg = _t.errorFilePassProtect; + break; + + case Asc.c_oAscError.ID.StockChartError: + config.msg = _t.errorStockChart; + break; + + case Asc.c_oAscError.ID.DataRangeError: + config.msg = _t.errorDataRange; + break; + + case Asc.c_oAscError.ID.Database: + config.msg = _t.errorDatabaseConnection; + break; + + case Asc.c_oAscError.ID.UserDrop: + const lostEditingRights = storeAppOptions.lostEditingRights; + if (lostEditingRights) { + storeAppOptions.changeEditingRights(false); + return; + } + storeAppOptions.changeEditingRights(true); + config.msg = _t.errorUserDrop; + break; + + case Asc.c_oAscError.ID.Warning: + config.msg = _t.errorConnectToServer; + break; + + case Asc.c_oAscError.ID.UplImageUrl: + config.msg = _t.errorBadImageUrl; + break; + + case Asc.c_oAscError.ID.SessionAbsolute: + config.msg = _t.errorSessionAbsolute; + break; + + case Asc.c_oAscError.ID.SessionIdle: + config.msg = _t.errorSessionIdle; + break; + + case Asc.c_oAscError.ID.SessionToken: + config.msg = _t.errorSessionToken; + break; + + case Asc.c_oAscError.ID.DataEncrypted: + config.msg = _t.errorDataEncrypted; + break; + + case Asc.c_oAscError.ID.AccessDeny: + config.msg = _t.errorAccessDeny; + break; + + case Asc.c_oAscError.ID.EditingError: + config.msg = _t.errorEditingDownloadas; + break; + + case Asc.c_oAscError.ID.ConvertationOpenLimitError: + config.msg = _t.errorFileSizeExceed; + break; + + case Asc.c_oAscError.ID.UpdateVersion: + config.msg = _t.errorUpdateVersionOnDisconnect; + break; + + default: + config.msg = _t.errorDefaultMessage.replace('%1', id); + break; + } + + if (level === Asc.c_oAscError.Level.Critical) { + + // report only critical errors + Common.Gateway.reportError(id, config.msg); + + config.title = _t.criticalErrorTitle; + + if (storeAppOptions.canBackToFolder && !storeAppOptions.isDesktopApp) { + config.msg += '

' + _t.criticalErrorExtText; + config.callback = function() { + Common.Notifications.trigger('goback', true); + } + } + if (id === Asc.c_oAscError.ID.DataEncrypted) { + api.asc_coAuthoringDisconnect(); + Common.Notifications.trigger('api:disconnect'); + } + } + else { + Common.Gateway.reportWarning(id, config.msg); + + config.title = config.title || _t.notcriticalErrorTitle; + config.callback = (btn) => { + if (id == Asc.c_oAscError.ID.DataValidate) { + api.asc_closeCellEditor(true); + } + storeAppOptions.changeEditingRights(false); + }; + } + + f7.dialog.create({ + cssClass: 'error-dialog', + title : config.title, + text : config.msg, + buttons: [ + { + text: 'OK', + onClick: config.callback + } + ] + }).open(); + + Common.component.Analytics.trackEvent('Internal Error', id.toString()); + }; + + return null +}); + +export default ErrorController; \ No newline at end of file diff --git a/apps/spreadsheeteditor/mobile/src/controller/LongActions.jsx b/apps/spreadsheeteditor/mobile/src/controller/LongActions.jsx new file mode 100644 index 000000000..0f2fb50f7 --- /dev/null +++ b/apps/spreadsheeteditor/mobile/src/controller/LongActions.jsx @@ -0,0 +1,190 @@ +import React, { useEffect } from 'react'; +import { f7 } from 'framework7-react'; +import { useTranslation } from 'react-i18next'; +import IrregularStack from "../../../../common/mobile/utils/IrregularStack"; + +const LongActionsController = () => { + const {t} = useTranslation(); + const _t = t("LongActions", { returnObjects: true }); + + const stackLongActions = new IrregularStack({ + strongCompare : function(obj1, obj2){return obj1.id === obj2.id && obj1.type === obj2.type;}, + weakCompare : function(obj1, obj2){return obj1.type === obj2.type;} + }); + + let loadMask = null; + + const closePreloader = () => { + if (loadMask && loadMask.el) { + f7.dialog.close(loadMask.el); + } + } + + useEffect( () => { + Common.Notifications.on('engineCreated', (api) => { + api.asc_registerCallback('asc_onStartAction', onLongActionBegin); + api.asc_registerCallback('asc_onEndAction', onLongActionEnd); + api.asc_registerCallback('asc_onOpenDocumentProgress', onOpenDocument); + }); + Common.Notifications.on('preloader:endAction', onLongActionEnd); + Common.Notifications.on('preloader:beginAction', onLongActionBegin); + Common.Notifications.on('preloader:close', closePreloader); + + return ( () => { + const api = Common.EditorApi.get(); + api.asc_unregisterCallback('asc_onStartAction', onLongActionBegin); + api.asc_unregisterCallback('asc_onEndAction', onLongActionEnd); + api.asc_unregisterCallback('asc_onOpenDocumentProgress', onOpenDocument); + + Common.Notifications.off('preloader:endAction', onLongActionEnd); + Common.Notifications.off('preloader:beginAction', onLongActionBegin); + Common.Notifications.off('preloader:close', closePreloader); + }) + }); + + const onLongActionBegin = (type, id) => { + const action = {id: id, type: type}; + stackLongActions.push(action); + setLongActionView(action); + }; + + const onLongActionEnd = (type, id) => { + let action = {id: id, type: type}; + stackLongActions.pop(action); + + //this.updateWindowTitle(true); + + action = stackLongActions.get({type: Asc.c_oAscAsyncActionType.Information}); + + if (action) { + this.setLongActionView(action) + } + + action = stackLongActions.get({type: Asc.c_oAscAsyncActionType.BlockInteraction}); + + if (action) { + setLongActionView(action) + } else { + loadMask && loadMask.el && loadMask.el.classList.contains('modal-in') && f7.dialog.close(loadMask.el); + } + }; + + const setLongActionView = (action) => { + let title = ''; + let text = ''; + switch (action.id) { + case Asc.c_oAscAsyncAction['Open']: + title = _t.openTitleText; + text = _t.openTextText; + break; + + case Asc.c_oAscAsyncAction['Save']: + title = _t.saveTitleText; + text = _t.saveTextText; + break; + + case Asc.c_oAscAsyncAction['LoadDocumentFonts']: + title = _t.loadFontsTitleText; + text = _t.loadFontsTextText; + break; + + case Asc.c_oAscAsyncAction['LoadDocumentImages']: + title = _t.loadImagesTitleText; + text = _t.loadImagesTextText; + break; + + case Asc.c_oAscAsyncAction['LoadFont']: + title = _t.loadFontTitleText; + text = _t.loadFontTextText; + break; + + case Asc.c_oAscAsyncAction['LoadImage']: + title = _t.loadImageTitleText; + text = _t.loadImageTextText; + break; + + case Asc.c_oAscAsyncAction['DownloadAs']: + title = _t.downloadTitleText; + text = _t.downloadTextText; + break; + + case Asc.c_oAscAsyncAction['Print']: + title = _t.printTitleText; + text = _t.printTextText; + break; + + case Asc.c_oAscAsyncAction['UploadImage']: + title = _t.uploadImageTitleText; + text = _t.uploadImageTextText; + break; + + case Asc.c_oAscAsyncAction['ApplyChanges']: + title = _t.applyChangesTitleText; + text = _t.applyChangesTextText; + break; + + case Asc.c_oAscAsyncAction['PrepareToSave']: + title = _t.savePreparingText; + text = _t.savePreparingTitle; + break; + + case Asc.c_oAscAsyncAction['MailMergeLoadFile']: + title = _t.mailMergeLoadFileText; + text = _t.mailMergeLoadFileTitle; + break; + + case Asc.c_oAscAsyncAction['DownloadMerge']: + title = _t.downloadMergeTitle; + text = _t.downloadMergeText; + break; + + case Asc.c_oAscAsyncAction['SendMailMerge']: + title = _t.sendMergeTitle; + text = _t.sendMergeText; + break; + + case Asc.c_oAscAsyncAction['Waiting']: + title = _t.waitText; + text = _t.waitText; + break; + + case ApplyEditRights: + title = _t.txtEditingMode; + text = _t.txtEditingMode; + break; + + case LoadingDocument: + title = _t.loadingDocumentTitleText; + text = _t.loadingDocumentTextText; + break; + default: + if (typeof action.id == 'string'){ + title = action.id; + text = action.id; + } + break; + } + + if (action.type == Asc.c_oAscAsyncActionType.BlockInteraction) { + if (loadMask && loadMask.el && loadMask.el.classList.contains('modal-in')) { + loadMask.el.getElementsByClassName('dialog-title')[0].innerHTML = title; + } else { + loadMask = f7.dialog.preloader(title); + } + } + + }; + + const onOpenDocument = (progress) => { + if (loadMask && loadMask.el) { + const $title = loadMask.el.getElementsByClassName('dialog-title')[0]; + const proc = (progress.asc_getCurrentFont() + progress.asc_getCurrentImage())/(progress.asc_getFontsCount() + progress.asc_getImagesCount()); + + $title.innerHTML = `${_t.textLoadingDocument}: ${Math.min(Math.round(proc * 100), 100)}%`; + } + } + + return null; +}; + +export default LongActionsController; \ No newline at end of file diff --git a/apps/spreadsheeteditor/mobile/src/controller/Main.jsx b/apps/spreadsheeteditor/mobile/src/controller/Main.jsx index 2b34515cb..c64810f94 100644 --- a/apps/spreadsheeteditor/mobile/src/controller/Main.jsx +++ b/apps/spreadsheeteditor/mobile/src/controller/Main.jsx @@ -12,12 +12,16 @@ import { EditCommentController, ViewCommentsController } from "../../../../common/mobile/lib/controller/collaboration/Comments"; +import LongActionsController from "./LongActions"; +import ErrorController from "./Error"; @inject("storeAppOptions", "storeFocusObjects", "storeCellSettings", "storeTextSettings", "storeChartSettings", "storeSpreadsheetSettings", "storeSpreadsheetInfo") class MainController extends Component { constructor(props) { super(props); window.editorType = 'sse'; + + this.LoadingDocument = -256; } initSdk() { @@ -300,6 +304,8 @@ class MainController extends Component { render() { return ( + + diff --git a/apps/spreadsheeteditor/mobile/src/page/app.jsx b/apps/spreadsheeteditor/mobile/src/page/app.jsx index b38f5c34a..2bf443815 100644 --- a/apps/spreadsheeteditor/mobile/src/page/app.jsx +++ b/apps/spreadsheeteditor/mobile/src/page/app.jsx @@ -1,10 +1,13 @@ -import '../../../../common/Gateway.js'; import React from 'react'; import {App,Views,View,Navbar,NavLeft,NavRight,Link} from 'framework7-react'; import { f7ready } from 'framework7-react'; +import '../../../../common/Analytics.js'; + +import '../../../../common/Gateway.js'; + import routes from '../router/routes.js'; import '../../../../common/main/lib/util/utils.js';