Merge pull request #2292 from ONLYOFFICE/feature/protection-document

Feature/protection document
This commit is contained in:
maxkadushkin
2023-03-24 11:17:37 +03:00
committed by GitHub
27 changed files with 645 additions and 68 deletions

View File

@ -701,6 +701,9 @@ const ViewComments = inject("storeComments", "storeAppOptions", "storeReview")(o
const comments = storeComments.groupCollectionFilter || storeComments.collectionComments;
const isEdit = storeAppOptions.isEdit || storeAppOptions.isRestrictedEdit;
const sortComments = comments.length > 0 ? [...comments].sort((a, b) => a.time > b.time ? -1 : 1) : null;
const isProtected = storeAppOptions.isProtected;
const typeProtection = storeAppOptions.typeProtection;
const isAvailableCommenting = !isProtected || typeProtection === Asc.c_oAscEDocProtect.TrackedChanges || typeProtection === Asc.c_oAscEDocProtect.Comments;
const [clickComment, setComment] = useState();
const [commentActionsOpened, openActionComment] = useState(false);
@ -737,8 +740,8 @@ const ViewComments = inject("storeComments", "storeAppOptions", "storeReview")(o
</div>
{isEdit && !viewMode &&
<div className='right'>
{(comment.editable && displayMode === 'markup' && !wsProps?.Objects && (!isViewer || canEditComments)) && <div className='comment-resolve' onClick={() => {onResolveComment(comment);}}><Icon icon={comment.resolved ? 'icon-resolve-comment check' : 'icon-resolve-comment'} /></div> }
{(displayMode === 'markup' && !wsProps?.Objects && (!isViewer || canEditComments)) &&
{(comment.editable && displayMode === 'markup' && !wsProps?.Objects && (!isViewer || canEditComments) && isAvailableCommenting) && <div className='comment-resolve' onClick={() => {onResolveComment(comment);}}><Icon icon={comment.resolved ? 'icon-resolve-comment check' : 'icon-resolve-comment'} /></div> }
{(displayMode === 'markup' && !wsProps?.Objects && (!isViewer || canEditComments) && isAvailableCommenting) &&
<div className='comment-menu'
onClick={() => {setComment(comment); openActionComment(true);}}>
<Icon icon='icon-menu-comment'/>
@ -768,7 +771,7 @@ const ViewComments = inject("storeComments", "storeAppOptions", "storeReview")(o
<div className='reply-date'>{reply.date}</div>
</div>
</div>
{isEdit && !viewMode && reply.editable && (!isViewer || canEditComments) &&
{isEdit && !viewMode && reply.editable && (!isViewer || canEditComments) && isAvailableCommenting &&
<div className='right'>
<div className='reply-menu'
onClick={() => {setComment(comment); setReply(reply); openActionReply(true);}}
@ -812,6 +815,9 @@ const CommentList = inject("storeComments", "storeAppOptions", "storeReview")(ob
const viewMode = !storeAppOptions.canComments;
const isEdit = storeAppOptions.isEdit || storeAppOptions.isRestrictedEdit;
const comments = storeComments.showComments;
const isProtected = storeAppOptions.isProtected;
const typeProtection = storeAppOptions.typeProtection;
const isAvailableCommenting = !isProtected || typeProtection === Asc.c_oAscEDocProtect.TrackedChanges || typeProtection === Asc.c_oAscEDocProtect.Comments;
const [currentIndex, setCurrentIndex] = useState(0);
const comment = comments[currentIndex];
@ -848,7 +854,7 @@ const CommentList = inject("storeComments", "storeAppOptions", "storeReview")(ob
<Fragment>
<Toolbar position='bottom'>
{isEdit && !viewMode &&
<Link className={`btn-add-reply${(wsProps?.Objects || isViewer) && !canEditComments ? ' disabled' : ''}`} href='#' onClick={() => {onCommentMenuClick('addReply', comment);}}>{_t.textAddReply}</Link>
<Link className={`btn-add-reply${((wsProps?.Objects || isViewer) && !canEditComments || !isAvailableCommenting) ? ' disabled' : ''}`} href='#' onClick={() => {onCommentMenuClick('addReply', comment);}}>{_t.textAddReply}</Link>
}
{comments.length > 1 &&
<div className='comment-navigation row'>
@ -870,15 +876,15 @@ const CommentList = inject("storeComments", "storeAppOptions", "storeReview")(ob
</div>
</div>
{isEdit && !viewMode &&
<div className='right'>
{(comment.editable && displayMode === 'markup' && !wsProps?.Objects && (!isViewer || canEditComments)) && <div className='comment-resolve' onClick={() => {onResolveComment(comment);}}><Icon icon={comment.resolved ? 'icon-resolve-comment check' : 'icon-resolve-comment'}/></div>}
{(displayMode === 'markup' && !wsProps?.Objects && (!isViewer || canEditComments)) &&
<div className='comment-menu'
onClick={() => {openActionComment(true);}}>
<Icon icon='icon-menu-comment'/>
</div>
}
</div>
<div className='right'>
{(comment.editable && displayMode === 'markup' && !wsProps?.Objects && (!isViewer || canEditComments) && isAvailableCommenting) && <div className='comment-resolve' onClick={() => {onResolveComment(comment);}}><Icon icon={comment.resolved ? 'icon-resolve-comment check' : 'icon-resolve-comment'}/></div>}
{(displayMode === 'markup' && !wsProps?.Objects && (!isViewer || canEditComments) && isAvailableCommenting) &&
<div className='comment-menu'
onClick={() => {openActionComment(true);}}>
<Icon icon='icon-menu-comment'/>
</div>
}
</div>
}
</div>
<div slot='footer'>
@ -902,7 +908,7 @@ const CommentList = inject("storeComments", "storeAppOptions", "storeReview")(ob
<div className='reply-date'>{reply.date}</div>
</div>
</div>
{isEdit && !viewMode && reply.editable && (!isViewer || canEditComments) &&
{isEdit && !viewMode && reply.editable && (!isViewer || canEditComments) && isAvailableCommenting &&
<div className='right'>
<div className='reply-menu'
onClick={() => {setReply(reply); openActionReply(true);}}

View File

@ -233,7 +233,7 @@
overflow: auto;
.item-content .item-input-wrap::after {
background-color: @text-normal;
background-color: @brandColor;
}
}

View File

@ -55,6 +55,8 @@
--f7-picker-item-text-color: rgba(var(--text-normal), 0.45);
--f7-picker-item-selected-text-color: @text-normal;
--f7-block-text-color: @text-secondary;
// Main Toolbar
#editor-navbar.navbar .right a + a,
#editor-navbar.navbar .left a + a {

View File

@ -50,6 +50,8 @@
--f7-input-bg-color: @background-primary;
--f7-input-placeholder-color: @text-secondary;
--f7-input-text-color: @text-normal;
--f7-block-text-color: @text-secondary;
.button {
--f7-touch-ripple-color: transparent;

View File

@ -1115,7 +1115,31 @@ input[type="number"]::-webkit-inner-spin-button {
}
}
// Block
.block {
margin-top: 8px;
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 16px;
}
// Inputs List
.block-title + .list, .block-title + .block, .block-title + .card, .block-title + .timeline, .block-title + .block-header {
margin: 0;
}
.inputs-list {
margin-bottom: 0;
ul {
list-style: none;
margin: 0;
padding: 0;
position: relative;
background: var(--f7-list-bg-color);
}
}

View File

@ -26,6 +26,16 @@
display: none;
}
}
&.icon-show-password {
width: 24px;
height: 24px;
.encoded-svg-mask('<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M9.89362 9.89062C10.4865 9.29688 11.1887 9 12 9C12.8113 9 13.5135 9.29688 14.1064 9.89062C14.6993 10.4844 14.9957 11.1875 14.9957 12C14.9957 12.8125 14.6993 13.5156 14.1064 14.1094C13.5135 14.7031 12.8113 15 12 15C11.1887 15 10.4865 14.7031 9.89362 14.1094C9.30071 13.5156 9.00426 12.8125 9.00426 12C9.00426 11.1875 9.30071 10.4844 9.89362 9.89062ZM8.44255 15.5625C9.44114 16.5312 10.627 17.0156 12 17.0156C13.373 17.0156 14.5433 16.5312 15.5106 15.5625C16.5092 14.5625 17.0085 13.375 17.0085 12C17.0085 10.625 16.5092 9.45312 15.5106 8.48438C14.5433 7.48438 13.373 6.98438 12 6.98438C10.627 6.98438 9.44114 7.48438 8.44255 8.48438C7.47518 9.45312 6.99149 10.625 6.99149 12C6.99149 13.375 7.47518 14.5625 8.44255 15.5625ZM5.30638 6.5625C7.30355 5.1875 9.53475 4.5 12 4.5C14.4652 4.5 16.6965 5.1875 18.6936 6.5625C20.6908 7.9375 22.1262 9.75 23 12C22.1262 14.25 20.6908 16.0625 18.6936 17.4375C16.6965 18.8125 14.4652 19.5 12 19.5C9.53475 19.5 7.30355 18.8125 5.30638 17.4375C3.30922 16.0625 1.87376 14.25 1 12C1.87376 9.75 3.30922 7.9375 5.30638 6.5625Z"/></svg>', @text-secondary);
}
&.icon-hide-password {
width: 24px;
height: 24px;
.encoded-svg-mask('<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M11.8827 9.00494H12.0235C12.8365 9.00494 13.5402 9.30206 14.1343 9.8963C14.7285 10.4905 15.0256 11.1942 15.0256 12.0074V12.1951L11.8827 9.00494ZM7.56716 9.80247C7.1919 10.5531 7.00426 11.2881 7.00426 12.0074C7.00426 13.3835 7.48898 14.572 8.45842 15.5728C9.45913 16.5424 10.6475 17.0272 12.0235 17.0272C12.7427 17.0272 13.4776 16.8395 14.2281 16.4642L12.6802 14.916C12.43 14.9786 12.2111 15.0099 12.0235 15.0099C11.2104 15.0099 10.5068 14.7128 9.91258 14.1185C9.31841 13.5243 9.02132 12.8206 9.02132 12.0074C9.02132 11.8198 9.05259 11.6008 9.11514 11.3506L7.56716 9.80247ZM2.03198 4.26667L3.29851 3L21.0299 20.7333L19.7633 22C19.607 21.8436 19.1066 21.3588 18.2623 20.5457C17.4492 19.7325 16.8237 19.107 16.3859 18.6691C15.0412 19.2321 13.5871 19.5136 12.0235 19.5136C9.55295 19.5136 7.31699 18.8255 5.31557 17.4494C3.31414 16.0733 1.87562 14.2593 1 12.0074C1.78181 10.0683 3.03269 8.4107 4.75267 7.03457C4.3774 6.65926 3.84577 6.12757 3.15778 5.43951C2.50107 4.75144 2.1258 4.36049 2.03198 4.26667ZM12.0235 6.98765C11.398 6.98765 10.7882 7.11276 10.194 7.36296L8.03625 5.20494C9.25586 4.7358 10.5849 4.50123 12.0235 4.50123C14.494 4.50123 16.7143 5.1893 18.6844 6.56543C20.6859 7.94156 22.1244 9.75556 23 12.0074C22.2495 13.8527 21.108 15.4321 19.5757 16.7457L16.6674 13.837C16.9176 13.2428 17.0426 12.6329 17.0426 12.0074C17.0426 10.6313 16.5423 9.45844 15.5416 8.48889C14.5721 7.48807 13.3994 6.98765 12.0235 6.98765Z"/></svg>', @text-secondary);
}
}
.navbar {
i.icon {

View File

@ -427,7 +427,8 @@
"unknownErrorText": "Unknown error.",
"uploadImageExtMessage": "Unknown image format.",
"uploadImageFileCountMessage": "No images uploaded.",
"uploadImageSizeMessage": "The image is too big. The maximum size is 25 MB."
"uploadImageSizeMessage": "The image is too big. The maximum size is 25 MB.",
"errorPasswordIsNotCorrect": "The password you supplied is not correct. Verify that the CAPS LOCK key is off and be sure to use the correct capitalization."
},
"LongActions": {
"applyChangesTextText": "Loading data...",
@ -476,6 +477,11 @@
"errorUpdateVersion": "The file version has been changed. The page will be reloaded.",
"leavePageText": "You have unsaved changes. Click 'Stay on this Page' to wait for autosave. Click 'Leave this Page' to discard all the unsaved changes.",
"notcriticalErrorTitle": "Warning",
"titleDialogProtectedDocument": "The document is protected",
"textDialogProtectedOnlyView": "You may only view this document",
"textDialogProtectedFillForms": "You may only fill in forms in this document",
"textDialogProtectedChangesTracked": "You may edit this document, but all changes will be tracked",
"textDialogProtectedEditComments": "You may only insert comments to this document",
"SDK": {
" -Section ": " -Section ",
"above": "above",
@ -661,6 +667,25 @@
"textRightToLeft": "Right To Left",
"textSearch": "Search",
"textSettings": "Settings",
"textProtection": "Protection",
"textProtectDocument": "Protect Document",
"titleDialogUnprotect": "Unprotect Document",
"textDialogUnprotect": "Enter a password to unprotect document",
"textUnprotect": "Unprotect",
"textProtectTurnOff": "Protect turn off",
"textSetPassword": "Set Password",
"textTypeEditing": "Type Of Editing",
"textNoChanges": "No changes (Read only)",
"textFillingForms": "Filling forms",
"textTrackedChanges": "Tracked changes",
"textPassword": "Password",
"textVerify": "Verify",
"textSave": "Save",
"textRequired": "Required",
"textPasswordNotMatched": "Passwords Dont Match",
"textEncryptFile": "Encrypt File",
"textRequirePassword": "Require Password",
"textChangePassword": "Change Password",
"textShowNotification": "Show Notification",
"textSpaces": "Spaces",
"textSpellcheck": "Spell Checking",

View File

@ -0,0 +1,28 @@
import React, { useState } from 'react';
import { ListInput, Icon } from "framework7-react";
import { Device } from '../../../../../common/mobile/utils/device';
const FieldPassword = ({ label, value, onInput, placeholder }) => {
const isIos = Device.ios;
const [isShowPassword, setShowPassword] = useState(false);
const toggleShowPassword = () => {
setShowPassword(!isShowPassword);
};
return (
<ListInput
// className="list-input-right"
label={label}
type={isShowPassword ? "text" : "password"}
placeholder={placeholder}
value={value}
onInput={onInput}
className={isIos ? 'list-input-right' : ''}
>
{/* <Icon icon="icon-show-password" slot="inner-end" onClick={toggleShowPassword} /> */}
</ListInput>
);
}
export default FieldPassword;

View File

@ -1,13 +1,27 @@
import React from 'react';
import { CSSTransition } from "react-transition-group";
const Snackbar = props => {
const Snackbar = ({ isShowSnackbar, message, closeCallback }) => {
return (
<div className="snackbar">
<div className="snackbar__content">
<p className="snackbar__text">{props.text}</p>
<CSSTransition
in={isShowSnackbar}
timeout={1500}
classNames="snackbar"
mountOnEnter
unmountOnExit
onEntered={(node, isAppearing) => {
if(!isAppearing) {
closeCallback();
}
}}
>
<div className="snackbar">
<div className="snackbar__content">
<p className="snackbar__text">{message}</p>
</div>
</div>
</div>
)
</CSSTransition>
);
}
export default Snackbar;

View File

@ -20,12 +20,13 @@ import EditorUIController from '../lib/patch';
displayMode: stores.storeReview.displayMode,
dataDoc: stores.storeDocumentInfo.dataDoc,
objects: stores.storeFocusObjects.settings,
isViewer: stores.storeAppOptions.isViewer
isViewer: stores.storeAppOptions.isViewer,
isProtected: stores.storeAppOptions.isProtected,
typeProtection: stores.storeAppOptions.typeProtection
}))
class ContextMenu extends ContextMenuController {
constructor(props) {
super(props);
// console.log('context menu controller created');
this.onApiShowComment = this.onApiShowComment.bind(this);
this.onApiHideComment = this.onApiHideComment.bind(this);
@ -282,13 +283,15 @@ class ContextMenu extends ContextMenuController {
} else {
const { t } = this.props;
const _t = t("ContextMenu", {returnObjects: true});
const { canViewComments, canCoAuthoring, canComments, dataDoc } = this.props;
const { canViewComments, canCoAuthoring, canComments, dataDoc, isProtected, typeProtection } = this.props;
const api = Common.EditorApi.get();
const inToc = api.asc_GetTableOfContentsPr(true);
const stack = api.getSelectedElements();
const canCopy = api.can_CopyCut();
const docExt = dataDoc ? dataDoc.fileType : '';
const isAllowedEditing = !isProtected || typeProtection === Asc.c_oAscEDocProtect.TrackedChanges;
const isAllowedCommenting = typeProtection === Asc.c_oAscEDocProtect.Comments;
let isText = false,
isObject = false,
@ -324,14 +327,14 @@ class ContextMenu extends ContextMenuController {
}
if (!isDisconnected) {
if (canFillForms && canCopy && !locked && (!isViewer || docExt === 'oform')) {
if (canFillForms && canCopy && !locked && (!isViewer || docExt === 'oform') && isAllowedEditing) {
itemsIcon.push({
event: 'cut',
icon: 'icon-cut'
});
}
if (canFillForms && canCopy && !locked && (!isViewer || docExt === 'oform')) {
if (canFillForms && canCopy && !locked && (!isViewer || docExt === 'oform') && isAllowedEditing) {
itemsIcon.push({
event: 'paste',
icon: 'icon-paste'
@ -345,7 +348,7 @@ class ContextMenu extends ContextMenuController {
});
}
if (api.can_AddQuotedComment() !== false && canCoAuthoring && canComments && !locked && !(!isText && isObject) && !isViewer && canEditComments) {
if (api.can_AddQuotedComment() !== false && canCoAuthoring && canComments && !locked && !(!isText && isObject) && !isViewer && canEditComments && (isAllowedEditing || isAllowedCommenting)) {
itemsText.push({
caption: _t.menuAddComment,
event: 'addcomment'
@ -358,13 +361,16 @@ class ContextMenu extends ContextMenuController {
caption: _t.menuOpenLink,
event: 'openlink'
});
itemsText.push({
caption: t('ContextMenu.menuEditLink'),
event: 'editlink'
});
if(isAllowedEditing) {
itemsText.push({
caption: t('ContextMenu.menuEditLink'),
event: 'editlink'
});
}
}
if(inToc && isEdit && !isViewer) {
if(inToc && isEdit && !isViewer && isAllowedEditing) {
itemsText.push({
caption: t('ContextMenu.textRefreshEntireTable'),
event: 'refreshEntireTable'

View File

@ -107,6 +107,10 @@ const ErrorController = inject('storeAppOptions','storeDocumentInfo')(({storeApp
config.msg = _t.errorFilePassProtect;
break;
case Asc.c_oAscError.ID.PasswordIsNotCorrect:
config.msg = t('Error.errorPasswordIsNotCorrect');
break;
case Asc.c_oAscError.ID.StockChartError:
config.msg = _t.errorStockChart;
break;

View File

@ -758,9 +758,12 @@ class MainController extends Component {
// Downloaded Advanced Options
this.api.asc_registerCallback('asc_onAdvancedOptions', (type, advOptions, mode, formatOptions) => {
const {t} = this.props;
const { t } = this.props;
const _t = t("Settings", { returnObjects: true });
const storeAppOptions = this.props.storeAppOptions;
if(type == Asc.c_oAscAdvancedOptionsID.DRM) {
storeAppOptions.setEncryptionFile(true);
onAdvancedOptions(type, _t, this._isDocReady, this.props.storeAppOptions.canRequestClose, this.isDRM);
this.isDRM = true;
}
@ -796,6 +799,22 @@ class MainController extends Component {
const storeAppOptions = this.props.storeAppOptions;
const props = this.getDocProps(true);
const isProtected = props && (props.isReadOnly || props.isCommentsOnly || props.isFormsOnly || props.isReviewOnly);
let textWarningDialog;
switch(props.type) {
case Asc.c_oAscEDocProtect.ReadOnly:
textWarningDialog = t('Main.textDialogProtectedOnlyView');
break;
case Asc.c_oAscEDocProtect.Comments:
textWarningDialog = t('Main.textDialogProtectedEditComments');
break;
case Asc.c_oAscEDocProtect.TrackedChanges:
textWarningDialog = t('Main.textDialogProtectedChangesTracked')
break;
case Asc.c_oAscEDocProtect.Forms:
textWarningDialog = t('Main.textDialogProtectedFillForms');
break;
}
storeAppOptions.setProtection(isProtected);
props && this.applyRestrictions(props.type);
@ -803,8 +822,8 @@ class MainController extends Component {
if(isProtected) {
f7.dialog.create({
title: t('Main.notcriticalErrorTitle'),
text: t('Main.textDocumentProtected'),
title: t('Main.titleDialogProtectedDocument'),
text: textWarningDialog,
buttons: [
{
text: t('Main.textOk')
@ -838,7 +857,7 @@ class MainController extends Component {
if (!storeAppOptions || !storeAppOptions.isEdit && !storeAppOptions.isRestrictedEdit) return;
if (isUpdate || !this.state.docProtection) {
if (isUpdate || !this._state.docProtection) {
const props = this.api.asc_getDocumentProtection();
const type = props ? props.asc_getEditType() : Asc.c_oAscEDocProtect.None;

View File

@ -0,0 +1,46 @@
import React from 'react';
import { Device } from '../../../../../common/mobile/utils/device';
import { observer, inject } from "mobx-react";
import ProtectionDocumentView from '../../view/settings/DocumentProtection';
import { f7 } from "framework7-react";
class ProtectionDocumentController extends React.Component {
constructor(props) {
super(props);
this.onProtectDocument = this.onProtectDocument.bind(this);
}
closeModal() {
if (Device.phone) {
f7.sheet.close('.settings-popup', false);
} else {
f7.popover.close('#settings-popover', false);
}
};
onProtectDocument(typeProtection, password) {
const api = Common.EditorApi.get();
const appOptions = this.props.storeAppOptions;
const isViewer = appOptions.isViewer;
const protection = api.asc_getDocumentProtection() || new AscCommonWord.CDocProtect();
appOptions.setProtection(true);
appOptions.setTypeProtection(typeProtection);
if(typeProtection !== Asc.c_oAscEDocProtect.TrackedChanges && !isViewer) {
appOptions.changeViewerMode();
}
protection.asc_setEditType(typeProtection);
protection.asc_setPassword(password);
api.asc_setDocumentProtection(protection);
this.closeModal();
};
render() {
return <ProtectionDocumentView onProtectDocument={this.onProtectDocument} />
}
}
export default inject('storeAppOptions')(observer(ProtectionDocumentController));

View File

@ -0,0 +1,50 @@
import React from 'react';
import { observer, inject } from "mobx-react";
import EncryptionView from '../../view/settings/FileEncryption';
import { withTranslation } from 'react-i18next';
import { f7 } from "framework7-react";
import { Device } from '../../../../../common/mobile/utils/device';
class FileEncryptionController extends React.Component {
constructor(props) {
super(props);
this.deletePassword = this.deletePassword.bind(this);
this.setPassword = this.setPassword.bind(this);
}
closeModal() {
if (Device.phone) {
f7.sheet.close('.settings-popup', false);
} else {
f7.popover.close('#settings-popover', false);
}
}
setPassword(passwordValue) {
const api = Common.EditorApi.get();
api.asc_setCurrentPassword(passwordValue);
this.closeModal();
}
deletePassword() {
const api = Common.EditorApi.get();
const appOptions = this.props.storeAppOptions;
appOptions.setEncryptionFile(false);
api.asc_resetPassword();
this.closeModal();
}
render() {
return (
<EncryptionView
deletePassword={this.deletePassword}
setPassword={this.setPassword}
/>
)
}
}
export default inject('storeAppOptions')(observer(withTranslation()(FileEncryptionController)));

View File

@ -0,0 +1,70 @@
import React, { useEffect, useState } from 'react';
import { observer, inject } from "mobx-react";
import ProtectionView from '../../view/settings/Protection';
import { useTranslation } from 'react-i18next';
import { f7 } from "framework7-react";
import { Device } from '../../../../../common/mobile/utils/device';
import Snackbar from '../../components/Snackbar/Snackbar';
const ProtectionController = props => {
const { t } = useTranslation();
const [isSnackbarVisible, setSnackbarVisible] = useState(false);
const onProtectClick = () => {
const api = Common.EditorApi.get();
const appOptions = props.storeAppOptions;
const isProtected = appOptions.isProtected;
let propsProtection = api.asc_getDocumentProtection();
const isPassword = propsProtection?.asc_getIsPassword();
if(isProtected) {
if(propsProtection && isPassword) {
f7.dialog.create({
title: t('Settings.titleDialogUnprotect'),
text: t('Settings.textDialogUnprotect'),
content: Device.ios ?
'<div class="input-field"><input type="password" class="modal-text-input" name="protection-password" placeholder="' + t('Settings.advDRMPassword') + '" id="protection-password"></div>' : '<div class="input-field"><div class="inputs-list list inline-labels"><ul><li><div class="item-content item-input"><div class="item-inner"><div class="item-input-wrap"><input type="password" name="protection-password" id="protection-password" placeholder=' + t('Settings.advDRMPassword') + '></div></div></div></li></ul></div></div>',
cssClass: 'dlg-adv-options',
buttons: [
{
text: t('Settings.textCancel')
},
{
text: t('Settings.textOk'),
onClick: () => {
const passwordValue = document.querySelector('#protection-password')?.value;
if(passwordValue) {
propsProtection.asc_setEditType(Asc.c_oAscEDocProtect.None);
propsProtection.asc_setPassword(passwordValue);
api.asc_setDocumentProtection(propsProtection);
}
}
}
]
}).open();
} else {
if (!propsProtection)
propsProtection = new AscCommonWord.CDocProtect();
appOptions.setTypeProtection(null);
propsProtection.asc_setEditType(Asc.c_oAscEDocProtect.None);
api.asc_setDocumentProtection(propsProtection);
setSnackbarVisible(true);
}
} else {
f7.views.current.router.navigate('/protect');
}
}
return (
<>
<ProtectionView onProtectClick={onProtectClick} />
<Snackbar isShowSnackbar={isSnackbarVisible} message={t('Settings.textProtectTurnOff')} closeCallback={() => setSnackbarVisible(false)} />
</>
);
}
export default inject('storeAppOptions')(observer(ProtectionController));

View File

@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next';
import {f7} from 'framework7-react';
import { observer, inject } from "mobx-react";
import {Device} from '../../../../../common/mobile/utils/device';
import SettingsView from "../../view/settings/Settings";
import {LocalStorage} from "../../../../../common/mobile/utils/LocalStorage.mjs";

View File

@ -60,7 +60,7 @@
// Snackbar
.snackbar {
max-width: 195px;
width: 195px;
position: absolute;
bottom: 24px;
left: calc(50% - 195px / 2);

View File

@ -110,7 +110,6 @@
.snackbar {
position: absolute;
width: 344px;
max-height: 48px;
left: calc(50% - 344px / 2);
bottom: 16px;
background: #333333;

View File

@ -55,6 +55,24 @@ i.icon {
.encoded-svg-background('<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"><path fill-rule="evenodd" clip-rule="evenodd" d="M18 12C14.6863 12 12 14.6863 12 18C12 21.3137 14.6863 24 18 24C21.3137 24 24 21.3137 24 18C24 14.6863 21.3137 12 18 12ZM18.7458 22V16.7307H21.2522V15.4956H18.7458H17.2265H14.7478V16.7307H17.2265V22H18.7458Z" fill="#A8A8A8"/><path fill-rule="evenodd" clip-rule="evenodd" d="M4 1C2.34315 1 1 2.34315 1 4V20C1 21.6569 2.34315 23 4 23H13.101C11.8045 21.7295 11 19.9587 11 18C11 17.4576 11.0617 16.9296 11.1785 16.4226C9.86316 15.0952 8.20867 14.5842 6.37705 14.5842C5.6032 14.5842 4.85524 14.7369 4.15044 15.018C4.14616 15.0202 4.14224 15.0216 4.13776 15.0231L4.13654 15.0235C4.12921 15.0255 4.12161 15.0269 4.11419 15.0269C4.0511 15.0269 4 14.959 4 14.8755C4 14.8263 4.01769 14.7835 4.04393 14.7567C4.0454 14.7554 4.04681 14.754 4.04819 14.7527C4.05119 14.7498 4.05401 14.7471 4.05679 14.7448C5.28644 13.6439 6.76778 13.0011 8.36321 13.0011C9.48515 13.0011 10.5512 13.3196 11.5132 13.891C12.1885 13.2535 12.9445 12.7563 13.7571 12.432C14.9342 11.5336 16.4048 11 18 11C19.9587 11 21.7295 11.8045 23 13.101V4C23 2.34315 21.6569 1 20 1H4ZM19.9523 7.74897V7.74817C19.9256 7.72981 19.8987 7.71247 19.8719 7.69519L19.8513 7.68188C19.3128 7.33699 18.7196 7.11012 18.0893 7.03103C16.9751 6.89113 15.9103 7.23056 15.0106 7.92168C14.3943 7.45795 13.6965 7.156 12.9453 7.06171C11.91 6.93181 10.9174 7.21642 10.0601 7.81245L10.0495 7.82011L10.0495 7.82011C10.0445 7.82374 10.0396 7.82735 10.0349 7.83046C10.0141 7.85206 10 7.88567 10 7.92342C10 7.98904 10.0394 8.04212 10.0894 8.04212C10.094 8.04212 10.0985 8.04118 10.1034 8.03985C10.1055 8.03958 10.1076 8.03838 10.1095 8.03785C10.5706 7.92475 11.0513 7.89274 11.5415 7.95423C12.9173 8.12667 14.1162 8.69056 14.9573 9.95625C15.0013 10.0169 15.04 10.0132 15.0846 9.95305C16.1426 8.32593 17.7652 7.68295 19.509 7.90154C19.6063 7.91408 19.7021 7.92995 19.7976 7.94889L19.8265 7.95483C19.8559 7.96094 19.8894 7.96791 19.9115 7.97116C19.969 7.97957 20 7.91822 20 7.85233C19.9995 7.80778 19.985 7.77044 19.9523 7.74897Z" fill="#3C6D88"/></svg>');
}
&.icon-protect-document {
width: 22px;
height: 22px;
.encoded-svg-mask('<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill-rule="evenodd" clip-rule="evenodd" d="M9 1L3 7V22H10V21H4V8H10V2H19V10H20V1H9ZM4.41422 7L9 2.41422V7H4.41422Z" fill="@{brandColor}"/><g clip-path="url(#clip0_205_12376)"><path fill-rule="evenodd" clip-rule="evenodd" d="M14.5002 15.5V15.5003C14.5001 15.6797 14.5002 15.8457 14.5008 16H14.5V17H13.5V16H13.5007C13.5001 15.8416 13.5001 15.675 13.5002 15.5C13.5002 13.567 15.0672 12 17.0002 12C18.9332 12 20.5002 13.567 20.5002 15.5C20.5002 15.675 20.5002 15.8416 20.4995 16H20.5V17H19.5V16H19.4994C19.5001 15.8457 19.5002 15.6795 19.5002 15.5C19.5002 14.1193 18.3809 13 17.0002 13C15.6195 13 14.5002 14.1193 14.5002 15.5ZM13.5 18H20.5C20.5 18 21 18 21 18.5V22.5C21 23 20.5 23 20.5 23H13.5C13.5 23 13 23 13 22.5V18.5C13 18 13.5 18 13.5 18ZM12 18C12 17 13 17 13 17H21C21 17 22 17 22 18V22.6667C22 23.3111 21.6443 24 21 24H13C13 24 12 24 12 23V18ZM17.5833 20.4023C17.7623 20.2421 17.875 20.0092 17.875 19.7501C17.875 19.2668 17.4832 18.8751 17 18.8751C16.5168 18.8751 16.125 19.2668 16.125 19.7501C16.125 20.0092 16.2377 20.2421 16.4167 20.4023V22.0834H17.5833V20.4023Z" fill="black"/></g><defs><clipPath id="clip0_205_12376"><rect width="12" height="12" fill="white" transform="translate(11 12)"/></clipPath></defs></svg>');
}
&.icon-protection {
width: 22px;
height: 22px;
.encoded-svg-mask('<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill-rule="evenodd" clip-rule="evenodd" d="M11.9995 2C15.3132 2 17.9995 4.68629 17.9995 8V10H18.9995C20.1041 10 20.9995 10.8954 20.9995 12V20C20.9995 21.1046 20.1041 22 18.9995 22H4.99951C3.89494 22 2.99951 21.1046 2.99951 20V12C2.99951 10.8954 3.89494 10 4.99951 10H5.99951V8C5.99951 4.68629 8.6858 2 11.9995 2ZM16.9995 10V8C16.9995 5.23858 14.7609 3 11.9995 3C9.23809 3 6.99951 5.23858 6.99951 8V10H16.9995ZM3.99951 12C3.99951 11.4477 4.44723 11 4.99951 11H18.9995C19.5518 11 19.9995 11.4477 19.9995 12V20C19.9995 20.5523 19.5518 21 18.9995 21H4.99951C4.44723 21 3.99951 20.5523 3.99951 20V12Z"/></svg>');
}
&.icon-encrypt-file {
width: 22px;
height: 22px;
.encoded-svg-mask('<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill-rule="evenodd" clip-rule="evenodd" d="M11.9995 2C15.3132 2 17.9995 4.68629 17.9995 8V10H18.9995C20.1041 10 20.9995 10.8954 20.9995 12V20C20.9995 21.1046 20.1041 22 18.9995 22H4.99951C3.89494 22 2.99951 21.1046 2.99951 20V12C2.99951 10.8954 3.89494 10 4.99951 10H5.99951V8C5.99951 4.68629 8.6858 2 11.9995 2ZM16.9995 10V8C16.9995 5.23858 14.7609 3 11.9995 3C9.23809 3 6.99951 5.23858 6.99951 8V10H16.9995ZM3.99951 12C3.99951 11.4477 4.44723 11 4.99951 11H18.9995C19.5518 11 19.9995 11.4477 19.9995 12V20C19.9995 20.5523 19.5518 21 18.9995 21H4.99951C4.44723 21 3.99951 20.5523 3.99951 20V12ZM12.9995 16.1185C13.3067 15.8438 13.5 15.4445 13.5 15C13.5 14.1716 12.8284 13.5 12 13.5C11.1716 13.5 10.5 14.1716 10.5 15C10.5 15.444 10.6929 15.843 10.9995 16.1176V19H12.9995V16.1185Z"/></svg>');
}
&.icon-format-fb2 {
width: 22px;
height: 22px;

View File

@ -79,7 +79,7 @@
height: 24px;
.encoded-svg-mask('<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill-rule="evenodd" clip-rule="evenodd" d="M7 1V3.5C7 3.77614 6.77614 4 6.5 4H4V3H6V1H7ZM17 3.5V1H18V3H20V4H17.5C17.2239 4 17 3.77614 17 3.5ZM17 20.5V23H18V21H20V20H17.5C17.2239 20 17 20.2239 17 20.5ZM7 20.5V23H6V21H4V20H6.5C6.77614 20 7 20.2239 7 20.5ZM16 6H8C7.44772 6 7 6.44772 7 7V17C7 17.5523 7.44772 18 8 18H16C16.5523 18 17 17.5523 17 17V7C17 6.44772 16.5523 6 16 6ZM8 5C6.89543 5 6 5.89543 6 7V17C6 18.1046 6.89543 19 8 19H16C17.1046 19 18 18.1046 18 17V7C18 5.89543 17.1046 5 16 5H8ZM9 8.5C9 8.22386 9.22386 8 9.5 8H14.5C14.7761 8 15 8.22386 15 8.5C15 8.77614 14.7761 9 14.5 9H9.5C9.22386 9 9 8.77614 9 8.5ZM9.5 11C9.22386 11 9 11.2239 9 11.5C9 11.7761 9.22386 12 9.5 12H14.5C14.7761 12 15 11.7761 15 11.5C15 11.2239 14.7761 11 14.5 11H9.5ZM9 14.5C9 14.2239 9.22386 14 9.5 14H14.5C14.7761 14 15 14.2239 15 14.5C15 14.7761 14.7761 15 14.5 15H9.5C9.22386 15 9 14.7761 9 14.5Z" fill="@{toolbar-icons}"/></svg>', @toolbar-icons);
}
&.icon-back-reader-mode {
&.icon-check {
width: 24px;
height: 24px;
.encoded-svg-mask('<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M9 16.1719L19.5938 5.57812L21 6.98438L9 18.9844L3.42188 13.4062L4.82812 12L9 16.1719Z" fill="@{toolbar-icons}" /></svg>', @toolbar-icons);
@ -92,6 +92,11 @@
height: 24px;
.encoded-svg-mask('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 22 22" fill="@{fill-white}"><g><path d="M21,12h-9v9h-2v-9H1v-2h9V1h2v9h9V12z"/></g></svg>', @fill-white);
}
&.icon-check {
width: 24px;
height: 24px;
.encoded-svg-mask('<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M9 16.1719L19.5938 5.57812L21 6.98438L9 18.9844L3.42188 13.4062L4.82812 12L9 16.1719Z" fill="@{brandColor}" /></svg>');
}
&.icon-expand-down {
width: 17px;
height: 17px;

View File

@ -15,7 +15,7 @@ import { Toolbar } from "../controller/Toolbar";
import NavigationController from '../controller/settings/Navigation';
import { AddLinkController } from '../controller/add/AddLink';
import EditHyperlink from '../controller/edit/EditHyperlink';
import Snackbar from "../components/Snackbar/Snackbar";
import Snackbar from '../components/Snackbar/Snackbar';
class MainPage extends Component {
constructor(props) {
@ -135,7 +135,8 @@ class MainPage extends Component {
const disabledControls = storeToolbarSettings.disabledControls;
const disabledSettings = storeToolbarSettings.disabledSettings;
const isProtected = appOptions.isProtected;
const isFabShow = isViewer && !disabledSettings && !disabledControls && !isDisconnected && isAvailableExt && isEdit && !isProtected;
const typeProtection = appOptions.typeProtection;
const isFabShow = isViewer && !disabledSettings && !disabledControls && !isDisconnected && isAvailableExt && isEdit && (!isProtected || typeProtection === Asc.c_oAscEDocProtect.TrackedChanges);
const config = appOptions.config;
const isShowPlaceholder = !appOptions.isDocReady && (!config.customization || !(config.customization.loaderName || config.customization.loaderLogo));
@ -205,23 +206,12 @@ class MainPage extends Component {
{/* {
Device.phone ? null : <SearchSettings />
} */}
<CSSTransition
in={this.state.snackbarVisible}
timeout={1500}
classNames="snackbar"
mountOnEnter
unmountOnExit
onEntered={(node, isAppearing) => {
if(!isAppearing) {
this.setState({
snackbarVisible: false
});
}
}}
>
<Snackbar
text={isMobileView ? t("Toolbar.textSwitchedMobileView") : t("Toolbar.textSwitchedStandardView")}/>
</CSSTransition>
<Snackbar
isShowSnackbar={this.state.snackbarVisible}
closeCallback={() => this.handleOptionsViewClosed('snackbar')}
message={isMobileView ? t("Toolbar.textSwitchedMobileView") : t("Toolbar.textSwitchedStandardView")}
/>
<SearchSettings useSuspense={false}/>
{
!this.state.editOptionsVisible ? null :

View File

@ -32,17 +32,33 @@ export class storeAppOptions {
changeMobileView: action,
isProtected: observable,
setProtection: action
setProtection: action,
typeProtection: observable,
setTypeProtection: action,
isFileEncrypted: observable,
setEncryptionFile: action
});
}
isEdit = false;
isFileEncrypted = false;
setEncryptionFile(value) {
this.isFileEncrypted = value;
}
isProtected = false;
setProtection(value) {
this.isProtected = value;
}
typeProtection = null;
setTypeProtection(type) {
this.typeProtection = type;
}
isMobileView = true;
changeMobileView() {
this.isMobileView = !this.isMobileView;

View File

@ -44,7 +44,7 @@ const ToolbarView = props => {
return (
<Fragment>
<NavLeft>
{!isViewer && <Link text={Device.ios ? t("Toolbar.textOk") : ''} icon={Device.android ? 'icon-back-reader-mode' : null} className='back-reader-mode' onClick={() => props.turnOnViewerMode()}></Link>}
{!isViewer && <Link text={Device.ios ? t("Toolbar.textOk") : ''} icon={Device.android ? 'icon-check' : null} className='back-reader-mode' onClick={() => props.turnOnViewerMode()}></Link>}
{(props.isShowBack && isViewer) && <Link className={`btn-doc-back${props.disabledControls && ' disabled'}`} icon='icon-back' onClick={props.onBack}></Link>}
{(Device.ios && props.isEdit && !isViewer) && EditorUIController.getUndoRedo && EditorUIController.getUndoRedo({
disabledUndo: !props.isCanUndo || isDisconnected,

View File

@ -0,0 +1,104 @@
import React, { useState } from 'react';
import { observer, inject } from "mobx-react";
import { Device } from '../../../../../common/mobile/utils/device';
import { Page, Navbar, List, ListItem, BlockTitle, Toggle, NavRight, f7, Link, ListInput, Icon, Block } from "framework7-react";
import { useTranslation } from "react-i18next";
import FieldPassword from '../../components/FieldPassword/FieldPassword';
const ProtectionDocumentView = inject("storeAppOptions")(observer(props => {
const { t } = useTranslation();
const _t = t("Settings", { returnObjects: true });
const isIos = Device.ios;
const appOptions = props.storeAppOptions;
const typeProtection = appOptions.typeProtection;
const [stateTypeProtection, setStateTypeProtection] = useState(typeProtection);
const [isRequirePassword, setRequirePassword] = useState(false);
const [password, changePassword] = useState('');
const [passwordRepeat, changeRepeationPassword] = useState('');
const isDisabledProtection = isRequirePassword ? ((!password.length || !passwordRepeat.length) || stateTypeProtection === null) : stateTypeProtection === null;
const showErrorDialog = () => {
f7.dialog.create({
title: t('Settings.textPasswordNotMatched'),
buttons: [
{
text: t('Settings.textOk')
}
]
}).open();
};
const changeHanlder = () => {
if(isRequirePassword && password !== passwordRepeat) {
showErrorDialog();
} else {
props.onProtectDocument(stateTypeProtection, password);
}
}
return (
<Page>
<Navbar title={t('Settings.textProtectDocument')} backLink={_t.textBack}>
<NavRight>
<Link text={isIos && t('Settings.textSave')} className={isDisabledProtection && 'disabled'} onClick={changeHanlder}>
{Device.android && <Icon icon='icon-check'/>}
</Link>
</NavRight>
</Navbar>
<List>
<ListItem title={t('Settings.textSetPassword')}>
<Toggle checked={isRequirePassword} onToggleChange={() => {
setRequirePassword(!isRequirePassword);
changePassword('');
changeRepeationPassword('');
}} />
</ListItem>
</List>
{isRequirePassword &&
<>
<List inlineLabels className="inputs-list">
<ListInput
label={t('Settings.textPassword')}
type="password"
placeholder={t('Settings.textRequired')}
value={password}
onInput={e => changePassword(e.target.value)}
className={isIos ? 'list-input-right' : ''}
/>
<ListInput
label={t('Settings.textVerify')}
type="password"
placeholder={t('Settings.textRequired')}
value={passwordRepeat}
onInput={e => changeRepeationPassword(e.target.value)}
className={isIos ? 'list-input-right' : ''}
/>
</List>
<Block>
<p>If the password is forgotten or lost, it cannot be recovered.</p>
</Block>
</>
}
<BlockTitle>{t('Settings.textTypeEditing')}</BlockTitle>
<List>
<ListItem radio checked={stateTypeProtection === Asc.c_oAscEDocProtect.ReadOnly} title={t('Settings.textNoChanges')} onClick={() => {
setStateTypeProtection(Asc.c_oAscEDocProtect.ReadOnly);
}}></ListItem>
<ListItem radio checked={stateTypeProtection === Asc.c_oAscEDocProtect.Forms} title={t('Settings.textFillingForms')} onClick={() => {
setStateTypeProtection(Asc.c_oAscEDocProtect.Forms);
}}></ListItem>
<ListItem radio checked={stateTypeProtection === Asc.c_oAscEDocProtect.TrackedChanges} title={t('Settings.textTrackedChanges')} onClick={() => {
setStateTypeProtection(Asc.c_oAscEDocProtect.TrackedChanges);
}}></ListItem>
<ListItem radio checked={stateTypeProtection === Asc.c_oAscEDocProtect.Comments} title={t('Settings.textComments')} onClick={() => {
setStateTypeProtection(Asc.c_oAscEDocProtect.Comments);
}}></ListItem>
</List>
<Block>
<p>Allow only this type of editing in the document.</p>
</Block>
</Page>
)
}));
export default ProtectionDocumentView;

View File

@ -0,0 +1,91 @@
import React, { useState } from 'react';
import { observer, inject } from "mobx-react";
import { Device } from '../../../../../common/mobile/utils/device';
import { Page, Navbar, List, ListItem, BlockTitle, Toggle, NavRight, f7, Link, ListInput, Icon, Block } from "framework7-react";
import { useTranslation } from "react-i18next";
const EncryptionView = inject("storeAppOptions")(observer(props => {
const { t } = useTranslation();
const _t = t("Settings", { returnObjects: true });
const isIos = Device.ios;
const appOptions = props.storeAppOptions;
const isFileEncrypted = appOptions.isFileEncrypted;
const [isRequiredPassword, setRequirePassword] = useState(isFileEncrypted);
const [password, changePassword] = useState('');
const [passwordRepeat, repeatPassword] = useState('');
const isDisabledEncryption = isFileEncrypted && !isRequiredPassword ? false : !password.length || !passwordRepeat.length;
const showErrorDialog = () => {
f7.dialog.create({
title: t('Settings.textPasswordNotMatched'),
buttons: [
{
text: t('Settings.textOk')
}
]
}).open();
};
const changeHanlder = () => {
if(isFileEncrypted && !isRequiredPassword) {
props.deletePassword();
} else if(password !== passwordRepeat) {
showErrorDialog();
} else {
props.setPassword(password);
}
}
return (
<Page>
<Navbar title={t('Settings.textEncryptFile')} backLink={_t.textBack}>
<NavRight>
<Link text={isIos && t('Settings.textSave')} className={isDisabledEncryption && 'disabled'} onClick={changeHanlder}>
{Device.android && <Icon icon='icon-check'/>}
</Link>
</NavRight>
</Navbar>
{isFileEncrypted &&
<>
<List>
<ListItem title={t('Settings.textRequirePassword')}>
<Toggle checked={isRequiredPassword} onToggleChange={() => {
setRequirePassword(!isRequiredPassword);
}} />
</ListItem>
</List>
</>
}
{isFileEncrypted && isRequiredPassword &&
<BlockTitle>{t('Settings.textChangePassword')}</BlockTitle>
}
{(isFileEncrypted && isRequiredPassword || !isFileEncrypted) &&
<>
<List inlineLabels className="inputs-list">
<ListInput
label={t('Settings.textPassword')}
type="password"
placeholder={t('Settings.textRequired')}
value={password}
onInput={e => changePassword(e.target.value)}
className={isIos ? 'list-input-right' : ''}
/>
<ListInput
label={t('Settings.textVerify')}
type="password"
placeholder={t('Settings.textRequired')}
value={passwordRepeat}
onInput={e => repeatPassword(e.target.value)}
className={isIos ? 'list-input-right' : ''}
/>
</List>
<Block>
<p>If the password is forgotten or lost, it cannot be recovered.</p>
</Block>
</>
}
</Page>
)
}));
export default EncryptionView;

View File

@ -0,0 +1,27 @@
import React, { useState } from 'react';
import { observer, inject } from "mobx-react";
import { Page, Navbar, List, ListItem, BlockTitle, Toggle, NavRight, f7, Link, ListInput, Icon, Block } from "framework7-react";
import { useTranslation } from "react-i18next";
const ProtectionView = inject("storeAppOptions")(observer(props => {
const { t } = useTranslation();
const _t = t("Settings", { returnObjects: true });
const appOptions = props.storeAppOptions;
const isProtected = appOptions.isProtected;
return (
<Page>
<Navbar title={t('Settings.textProtection')} backLink={_t.textBack} />
<List>
<ListItem title={isProtected ? t('Settings.textUnprotect') : t('Settings.textProtectDocument')} onClick={() => props.onProtectClick()} link="#">
<Icon slot="media" icon="icon-protect-document" />
</ListItem>
<ListItem title={t('Settings.textEncryptFile')} link="/encrypt">
<Icon slot="media" icon="icon-encrypt-file" />
</ListItem>
</List>
</Page>
)
}));
export default ProtectionView;

View File

@ -4,7 +4,6 @@ import { useTranslation } from 'react-i18next';
import {f7} from 'framework7-react';
import { observer, inject } from "mobx-react";
import {Device} from '../../../../../common/mobile/utils/device';
import DocumentSettingsController from "../../controller/settings/DocumentSettings";
import DocumentInfoController from "../../controller/settings/DocumentInfo";
import { DownloadController } from "../../controller/settings/Download";
@ -14,6 +13,9 @@ import { MacrosSettings, Direction } from "./ApplicationSettings";
import About from '../../../../../common/mobile/lib/view/About';
import NavigationController from '../../controller/settings/Navigation';
import SharingSettings from "../../../../../common/mobile/lib/view/SharingSettings";
import ProtectionDocumentController from '../../controller/settings/DocumentProtection';
import ProtectionController from '../../controller/settings/Protection';
import FileEncryptionController from '../../controller/settings/FileEncryption';
const routes = [
{
@ -65,17 +67,31 @@ const routes = [
},
// Direction
{
path: '/direction/',
component: Direction
},
// Sharing Settings
{
path: '/sharing-settings/',
component: SharingSettings
},
// Protection
{
path: '/protection',
component: ProtectionController
},
{
path: '/protect',
component: ProtectionDocumentController
},
// Encryption
{
path: '/encrypt',
component: FileEncryptionController
}
];
@ -155,6 +171,11 @@ const SettingsList = inject("storeAppOptions", "storeReview")(observer(props =>
<Icon slot="media" icon="icon-search"></Icon>
</ListItem>
}
{_isEdit &&
<ListItem title={t('Settings.textProtection')} link="#" onClick={onoptionclick.bind(this, '/protection')}>
<Icon slot="media" icon="icon-protection"></Icon>
</ListItem>
}
<ListItem title={t('Settings.textNavigation')} link='#' onClick={() => {
if(Device.phone) {
onOpenNavigation();
@ -245,13 +266,14 @@ class SettingsView extends Component {
render() {
const show_popover = this.props.usePopover;
return (
show_popover ?
<Popover id="settings-popover" closeByOutsideClick={false} className="popover__titled" onPopoverClosed={() => this.props.closeOptions('settings')}>
<SettingsList inPopover={true} onOptionClick={this.onoptionclick} closeOptions={this.props.closeOptions} openOptions={this.props.openOptions} style={{height: '410px'}} onChangeMobileView={this.props.onChangeMobileView} onPrint={this.props.onPrint} showHelp={this.props.showHelp} showFeedback={this.props.showFeedback} onOrthographyCheck={this.props.onOrthographyCheck} onDownloadOrigin={this.props.onDownloadOrigin}/>
<SettingsList inPopover={true} onOptionClick={this.onoptionclick} closeOptions={this.props.closeOptions} openOptions={this.props.openOptions} style={{height: '410px'}} onChangeMobileView={this.props.onChangeMobileView} onPrint={this.props.onPrint} showHelp={this.props.showHelp} showFeedback={this.props.showFeedback} onOrthographyCheck={this.props.onOrthographyCheck} onDownloadOrigin={this.props.onDownloadOrigin} />
</Popover> :
<Popup className="settings-popup" onPopupClosed={() => this.props.closeOptions('settings')}>
<SettingsList onOptionClick={this.onoptionclick} closeOptions={this.props.closeOptions} openOptions={this.props.openOptions} onChangeMobileView={this.props.onChangeMobileView} onPrint={this.props.onPrint} showHelp={this.props.showHelp} showFeedback={this.props.showFeedback} onOrthographyCheck={this.props.onOrthographyCheck} onDownloadOrigin={this.props.onDownloadOrigin}/>
<SettingsList onOptionClick={this.onoptionclick} closeOptions={this.props.closeOptions} openOptions={this.props.openOptions} onChangeMobileView={this.props.onChangeMobileView} onPrint={this.props.onPrint} showHelp={this.props.showHelp} showFeedback={this.props.showFeedback} onOrthographyCheck={this.props.onOrthographyCheck} onDownloadOrigin={this.props.onDownloadOrigin} />
</Popup>
)
}