diff --git a/apps/common/mobile/lib/controller/ContextMenu.jsx b/apps/common/mobile/lib/controller/ContextMenu.jsx index ef0f50118..f25deba51 100644 --- a/apps/common/mobile/lib/controller/ContextMenu.jsx +++ b/apps/common/mobile/lib/controller/ContextMenu.jsx @@ -12,8 +12,10 @@ class ContextMenuController extends Component { this.state = { opened: false + , items: [] }; + this.onMenuItemClick = this.onMenuItemClick.bind(this); this.onMenuClosed = this.onMenuClosed.bind(this); this.onDocumentReady = this.onDocumentReady.bind(this); this.onApiOpenContextMenu = this.onApiOpenContextMenu.bind(this); @@ -94,6 +96,8 @@ class ContextMenuController extends Component { onApiOpenContextMenu(x, y) { if ( !this.state.opened ) { + this.setState({items: this.initMenuItems()}); + this.$targetEl.css({left: `${x}px`, top: `${y}px`}); const popover = f7.popover.open(idContextMenuElement, idCntextMenuTargetElement); @@ -108,7 +112,8 @@ class ContextMenuController extends Component { onApiHideContextMenu() { if ( this.state.opened ) { - f7.popover.close(idContextMenuElement); + $$(idContextMenuElement).hide(); + f7.popover.close(idContextMenuElement, false); this.$targetEl.css({left: '-10000px', top: '-10000px'}); this.setState({opened: false}); @@ -116,6 +121,9 @@ class ContextMenuController extends Component { } onMenuClosed() { + this.$targetEl.css({left: '-10000px', top: '-10000px'}); + this.setState({opened: false}); + // (async () => { // await 1 && this.setState(state => { // this.$targetEl.css({left: '-10000px', top: '-10000px'}); @@ -125,6 +133,7 @@ class ContextMenuController extends Component { } onMenuItemClick(action) { + this.onApiHideContextMenu(); } componentWillUnmount() { @@ -151,7 +160,7 @@ class ContextMenuController extends Component { render() { return ( - + ) } } diff --git a/apps/common/mobile/lib/controller/collaboration/Comments.jsx b/apps/common/mobile/lib/controller/collaboration/Comments.jsx index a55dff87d..8b44d1322 100644 --- a/apps/common/mobile/lib/controller/collaboration/Comments.jsx +++ b/apps/common/mobile/lib/controller/collaboration/Comments.jsx @@ -5,7 +5,7 @@ import {Device} from '../../../../../common/mobile/utils/device'; import { withTranslation} from 'react-i18next'; import { LocalStorage } from '../../../utils/LocalStorage'; -import {AddComment, EditComment, ViewComments} from '../../view/collaboration/Comments'; +import {AddComment, EditComment, AddReply, EditReply, ViewComments, ViewCurrentComments} from '../../view/collaboration/Comments'; // utils const timeZoneOffsetInMs = (new Date()).getTimezoneOffset() * 60000; @@ -113,9 +113,9 @@ class CommentsController extends Component { let user = this.usersStore.searchUserById(data.asc_getUserId()); comment.comment = data.asc_getText(); - comment.userid = data.asc_getUserId(); + comment.userId = data.asc_getUserId(); comment.userName = data.asc_getUserName(); - comment.usercolor = (user) ? user.asc_getColor() : null; + comment.userColor = (user) ? user.asc_getColor() : null; comment.resolved = data.asc_getSolved(); comment.quote = data.asc_getQuoteText(); comment.time = date.getTime(); @@ -218,8 +218,20 @@ class CommentsController extends Component { class AddCommentController extends Component { constructor(props) { super(props); + this.closeAddComment = this.closeAddComment.bind(this); this.getUserInfo = this.getUserInfo.bind(this); this.onAddNewComment = this.onAddNewComment.bind(this); + + this.state = { + isOpen: false + }; + + Common.Notifications.on('addcomment', () => { + this.setState({isOpen: true}); + }); + } + closeAddComment () { + this.setState({isOpen: false}); } getUserInfo () { this.currentUser = this.props.users.currentUser; @@ -255,34 +267,30 @@ class AddCommentController extends Component { return false; } render() { - const isOpen = this.props.storeComments.isOpenAddComment; - let userInfo; - if (isOpen) { - userInfo = this.getUserInfo(); - } return( - isOpen ? : null + this.state.isOpen ? : null ) } } -class ViewCommentsController extends Component { +class EditCommentController extends Component { constructor (props) { super(props); - this.onCommentMenuClick = this.onCommentMenuClick.bind(this); - this.onResolveComment = this.onResolveComment.bind(this); this.onEditComment = this.onEditComment.bind(this); - this.closeEditComment = this.closeEditComment.bind(this); - + this.onAddReply = this.onAddReply.bind(this); + this.onEditReply = this.onEditReply.bind(this); + } + getUserInfo () { this.currentUser = this.props.users.currentUser; - - this.state = { - showEditComment: false, - showEditReply: false + const name = this.currentUser.asc_getUserName(); + return { + name: name, + initials: this.props.users.getInitials(name), + color: this.currentUser.asc_getColor() }; } onChangeComment (comment) { - const ascComment = !!Asc.asc_CCommentDataWord ? new Asc.asc_CCommentDataWord(null) : new Asc.asc_CCommentData(null); + const ascComment = typeof Asc.asc_CCommentDataWord !== 'undefined' ? new Asc.asc_CCommentDataWord(null) : new Asc.asc_CCommentData(null); if (ascComment && comment) { ascComment.asc_putText(comment.comment); ascComment.asc_putQuoteText(comment.quote); @@ -316,6 +324,104 @@ class ViewCommentsController extends Component { api.asc_changeComment(comment.uid, ascComment); } } + onEditComment (comment, text) { + comment.comment = text.trim(); + const user = this.props.users.currentUser; + comment.userid = user.asc_getIdOriginal(); + comment.username = user.asc_getUserName(); + this.onChangeComment(comment); + } + onAddReply (comment, replyVal) { + let reply = null; + let addReply = null; + const ascComment = (typeof Asc.asc_CCommentDataWord !== 'undefined' ? new Asc.asc_CCommentDataWord(null) : new Asc.asc_CCommentData(null)); + + if (ascComment) { + ascComment.asc_putText(comment.comment); + ascComment.asc_putQuoteText(comment.quote); + ascComment.asc_putTime(utcDateToString(new Date(comment.time))); + ascComment.asc_putOnlyOfficeTime(ooDateToString(new Date(comment.time))); + ascComment.asc_putUserId(comment.userId); + ascComment.asc_putUserName(comment.userName); + ascComment.asc_putSolved(comment.resolved); + ascComment.asc_putGuid(comment.guid); + + if (!!ascComment.asc_putDocumentFlag) { + ascComment.asc_putDocumentFlag(comment.unattached); + } + + reply = comment.replies; + if (reply && reply.length) { + reply.forEach(function (reply) { + + addReply = (typeof Asc.asc_CCommentDataWord !== 'undefined' ? new Asc.asc_CCommentDataWord(null) : new Asc.asc_CCommentData(null)); + if (addReply) { + addReply.asc_putText(reply.reply); + addReply.asc_putTime(utcDateToString(new Date(reply.time))); + addReply.asc_putOnlyOfficeTime(ooDateToString(new Date(reply.time))); + addReply.asc_putUserId(reply.userId); + addReply.asc_putUserName(reply.userName); + + ascComment.asc_addReply(addReply); + } + }); + } + + addReply = (typeof Asc.asc_CCommentDataWord !== 'undefined' ? new Asc.asc_CCommentDataWord(null) : new Asc.asc_CCommentData(null)); + if (addReply) { + addReply.asc_putText(replyVal); + addReply.asc_putTime(utcDateToString(new Date())); + addReply.asc_putOnlyOfficeTime(ooDateToString(new Date())); + const currentUser = this.props.users.currentUser; + addReply.asc_putUserId(currentUser.asc_getIdOriginal()); + addReply.asc_putUserName(currentUser.asc_getUserName()); + + ascComment.asc_addReply(addReply); + + const api = Common.EditorApi.get(); + api.asc_changeComment(comment.uid, ascComment); + } + } + } + onEditReply (comment, reply, textReply) { + const currentUser = this.props.users.currentUser; + const indReply = reply.ind; + comment.replies[indReply].reply = textReply; + comment.replies[indReply].userid = currentUser.asc_getIdOriginal(); + comment.replies[indReply].username = currentUser.asc_getUserName(); + this.onChangeComment(comment); + } + render() { + const storeComments = this.props.storeComments; + const comment = storeComments.currentComment; + return ( + + {storeComments.isOpenEditComment && } + {storeComments.isOpenAddReply && } + {storeComments.isOpenEditReply && } + + ) + } +} + +class ViewCommentsController extends Component { + constructor (props) { + super(props); + this.onCommentMenuClick = this.onCommentMenuClick.bind(this); + this.onResolveComment = this.onResolveComment.bind(this); + this.closeViewCurComments = this.closeViewCurComments.bind(this); + + this.state = { + isOpenViewCurComments: false + }; + + Common.Notifications.on('viewcomment', () => { + this.setState({isOpenViewCurComments: true}); + }); + } + closeViewCurComments () { + this.setState({isOpenViewCurComments: false}); + } onResolveComment (comment) { let reply = null, addReply = null, @@ -358,17 +464,13 @@ class ViewCommentsController extends Component { const api = Common.EditorApi.get(); comment && api.asc_removeComment(comment.uid); } - onEditComment (comment, text) { - comment.comment = text.trim(); - comment.userid = this.currentUser.asc_getIdOriginal(); - comment.username = this.currentUser.asc_getUserName(); - this.onChangeComment(comment); - } - deleteReply (comment, indReply) { + deleteReply (comment, reply) { let replies = null, addReply = null, ascComment = (!!Asc.asc_CCommentDataWord ? new Asc.asc_CCommentDataWord(null) : new Asc.asc_CCommentData(null)); + const indReply = reply.ind; + if (ascComment && comment) { ascComment.asc_putText(comment.comment); ascComment.asc_putQuoteText(comment.quote); @@ -404,19 +506,12 @@ class ViewCommentsController extends Component { api.asc_changeComment(comment.uid, ascComment); } } - onCommentMenuClick (action, comment) { + onCommentMenuClick (action, comment, reply) { const { t } = this.props; const _t = t("Common.Collaboration", { returnObjects: true }); switch (action) { case 'editComment': - this.setState({ - showEditComment: true, - editProps: { - comment: comment, - onEditComment: this.onEditComment - } - }); - console.log('editComment'); + this.props.storeComments.openEditComment(true, comment); break; case 'resolve': this.onResolveComment(comment); @@ -431,35 +526,27 @@ class ViewCommentsController extends Component { ); break; case 'editReply': - this.setState({showEditReply: true}); - console.log('editReply'); + this.props.storeComments.openEditReply(true, comment, reply); break; case 'deleteReply': f7.dialog.confirm( _t.textMessageDeleteReply, _t.textDeleteReply, () => { - this.deleteReply(comment, indReply); + this.deleteReply(comment, reply); } ); break; case 'addReply': - console.log('addReply'); + this.props.storeComments.openAddReply(true, comment); break; } } - - closeEditComment () { - this.setState({showEditComment: false}); - } render() { return( - - {this.state.showEditComment && } + {this.props.allComments && } + {this.state.isOpenViewCurComments && } ) } @@ -467,10 +554,12 @@ class ViewCommentsController extends Component { const _CommentsController = inject('storeAppOptions', 'storeComments', 'users')(observer(CommentsController)); const _AddCommentController = inject('storeAppOptions', 'storeComments', 'users')(observer(AddCommentController)); +const _EditCommentController = inject('storeComments', 'users')(observer(EditCommentController)); const _ViewCommentsController = inject('storeComments', 'users')(observer(withTranslation()(ViewCommentsController))); export { _CommentsController as CommentsController, _AddCommentController as AddCommentController, + _EditCommentController as EditCommentController, _ViewCommentsController as ViewCommentsController }; \ No newline at end of file diff --git a/apps/common/mobile/lib/store/comments.js b/apps/common/mobile/lib/store/comments.js index 345636f10..ffc55c4c2 100644 --- a/apps/common/mobile/lib/store/comments.js +++ b/apps/common/mobile/lib/store/comments.js @@ -1,11 +1,35 @@ -import {observable, action, computed} from 'mobx'; +import {makeObservable, observable, action, computed} from 'mobx'; export class storeComments { - @observable collectionComments = []; - @observable groupCollectionComments = []; + constructor() { + makeObservable(this, { + collectionComments: observable, + groupCollectionComments: observable, + filter: observable, + groupCollectionFilter: observable, - @action addComment (comment) { + addComment: action, + removeComment: action, + changeFilter: action, + + sortComments: computed, + + isOpenEditComment: observable, + openEditComment: action, + isOpenAddReply: observable, + openAddReply: action, + isOpenEditReply: observable, + openEditReply: action + }) + } + collectionComments = []; + groupCollectionComments = []; + + filter = undefined; + groupCollectionFilter = []; // for sse + + addComment (comment) { comment.groupName ? this.addCommentToGroupCollection(comment) : this.addCommentToCollection(comment); } @@ -24,7 +48,7 @@ export class storeComments { } } - @action removeComment (id) { + removeComment (id) { if (this.collectionComments.length > 0) { this.removeCommentFromCollection(id); } else { @@ -57,10 +81,7 @@ export class storeComments { } } - @observable filter; // for sse - @observable groupCollectionFilter = []; // for sse - - @action changeFilter (filter) { + changeFilter (filter) { let comments = []; this.filter = filter; filter.forEach((item) => { @@ -94,7 +115,7 @@ export class storeComments { return model; } - @computed get sortComments () { + get sortComments () { const comments = (this.groupCollectionFilter.length !== 0) ? this.groupCollectionFilter : (this.collectionComments.length !== 0 ? this.collectionComments : false); if (comments.length > 0) { return [...comments].sort((a, b) => a.time > b.time ? 1 : -1); @@ -102,12 +123,31 @@ export class storeComments { return false; } - // Add comment modal window - @observable isOpenAddComment = false; + // Edit comment + currentComment = null; + isOpenEditComment = false; + openEditComment (open, comment) { + if (open !== this.isOpenEditComment) { + this.currentComment = open ? comment : null; + this.isOpenEditComment = open; + } + } - @action openAddComment (open) { - if (open !== this.isOpenAddComment) { - this.isOpenAddComment = open; + currentReply = null; + isOpenAddReply = false; + openAddReply (open, comment) { + if (open !== this.isOpenAddReply) { + this.currentComment = open ? comment : null; + this.isOpenAddReply = open; + } + } + + isOpenEditReply = false; + openEditReply (open, comment, reply) { + if (open !== this.isOpenEditReply) { + this.currentComment = open ? comment : null; + this.currentReply = open ? reply : null; + this.isOpenEditReply = open; } } } \ No newline at end of file diff --git a/apps/common/mobile/lib/store/users.js b/apps/common/mobile/lib/store/users.js index 3597f63a2..4b4dc4eb3 100644 --- a/apps/common/mobile/lib/store/users.js +++ b/apps/common/mobile/lib/store/users.js @@ -1,16 +1,25 @@ -import {observable, action, computed} from 'mobx'; +import {makeObservable, observable, action} from 'mobx'; export class storeUsers { - @observable users = []; + constructor() { + makeObservable(this, { + users: observable, + reset: action, + currentUser: observable, + setCurrentUser: action, + connection: action + }) + } - @action reset(users) { + users = []; + currentUser; + + reset (users) { this.users = Object.values(users) } - @observable currentUser; - - @action setCurrentUser(id) { + setCurrentUser (id) { this.users.forEach((item) => { if (item.asc_getIdOriginal() === id) { this.currentUser = item; @@ -18,7 +27,7 @@ export class storeUsers { }); } - @action connection (change) { + connection (change) { let changed = false; for (let uid in this.users) { if (undefined !== uid) { @@ -45,10 +54,12 @@ export class storeUsers { } searchUserById (id) { + let user = null; this.users.forEach((item) => { if (item.asc_getIdOriginal() === id) { - return item; + user = item; } }); + return user; } } diff --git a/apps/common/mobile/lib/view/ContextMenu.jsx b/apps/common/mobile/lib/view/ContextMenu.jsx index 954b15e5b..4bf1c2c61 100644 --- a/apps/common/mobile/lib/view/ContextMenu.jsx +++ b/apps/common/mobile/lib/view/ContextMenu.jsx @@ -26,9 +26,9 @@ class ContextMenuView extends Component { > {buttons.map((b, index) => - !!b.text ? - this.props.onMenuItemClick(b.action)} /> : - + !b.icon ? + this.props.onMenuItemClick(b.event)} /> : + )} diff --git a/apps/common/mobile/lib/view/collaboration/Collaboration.jsx b/apps/common/mobile/lib/view/collaboration/Collaboration.jsx index 76f48102c..03e2a3051 100644 --- a/apps/common/mobile/lib/view/collaboration/Collaboration.jsx +++ b/apps/common/mobile/lib/view/collaboration/Collaboration.jsx @@ -49,7 +49,12 @@ const routes = [ }, { path: '/comments/', - component: ViewCommentsController + component: ViewCommentsController, + options: { + props: { + allComments: true + } + } } ]; diff --git a/apps/common/mobile/lib/view/collaboration/Comments.jsx b/apps/common/mobile/lib/view/collaboration/Comments.jsx index 10bb4a25f..96d87328f 100644 --- a/apps/common/mobile/lib/view/collaboration/Comments.jsx +++ b/apps/common/mobile/lib/view/collaboration/Comments.jsx @@ -1,6 +1,6 @@ import React, {useState, useEffect, Fragment} from 'react'; import {observer, inject} from "mobx-react"; -import { f7, Popup, Page, Navbar, NavLeft, NavRight, NavTitle, Link, Input, Icon, List, ListItem, Actions, ActionsGroup, ActionsButton } from 'framework7-react'; +import { f7, Popup, Sheet, Popover, Page, Toolbar, Navbar, NavLeft, NavRight, NavTitle, Link, Input, Icon, List, ListItem, Actions, ActionsGroup, ActionsButton } from 'framework7-react'; import { useTranslation } from 'react-i18next'; import {Device} from '../../../utils/device'; @@ -19,7 +19,7 @@ const AddCommentPopup = inject("storeComments")(observer(props => { { - props.storeComments.openAddComment(false); + props.closeAddComment(); f7.popup.close('.add-comment-popup'); }}>{_t.textCancel} @@ -28,7 +28,7 @@ const AddCommentPopup = inject("storeComments")(observer(props => { { if (props.onAddNewComment(stateText, false)) { - props.storeComments.openAddComment(false); + props.closeAddComment(); f7.popup.close('.add-comment-popup'); } }}> @@ -37,7 +37,7 @@ const AddCommentPopup = inject("storeComments")(observer(props => {
-
+
{Device.android &&
{userInfo.initials}
} @@ -74,7 +74,7 @@ const AddCommentDialog = inject("storeComments")(observer(props => {
-
+
${Device.android ? templateInitials : ''}
${userInfo.name}
@@ -87,14 +87,14 @@ const AddCommentDialog = inject("storeComments")(observer(props => { const cancel = document.getElementById('comment-cancel'); cancel.addEventListener('click', () => { f7.dialog.close(); - props.storeComments.openAddComment(false); + props.closeAddComment(); }); const done = document.getElementById('comment-done'); done.addEventListener('click', () => { const value = document.getElementById('comment-text').value; if (value.length > 0 && props.onAddNewComment(value, false)) { f7.dialog.close(); - props.storeComments.openAddComment(false); + props.closeAddComment(); } }); const area = document.getElementById('comment-text'); @@ -118,8 +118,8 @@ const AddCommentDialog = inject("storeComments")(observer(props => { const AddComment = props => { return ( Device.phone ? - : - + : + ) }; @@ -148,19 +148,40 @@ const CommentActions = ({comment, onCommentMenuClick, opened, openActionComment} ) }; -// Edit comment -const EditCommentPopup = ({comment, onEditComment, opened, close}) => { +const ReplyActions = ({comment, reply, onCommentMenuClick, opened, openActionReply}) => { const { t } = useTranslation(); const _t = t('Common.Collaboration', {returnObjects: true}); - const [stateText, setText] = useState(comment.comment); - console.log(comment); return ( - + openActionReply(false)}> + + {reply && + {reply.editable && {onCommentMenuClick('editReply', comment, reply);}}>{_t.textEdit}} + {reply.removable && {onCommentMenuClick('deleteReply', comment, reply);}}>{_t.textDeleteReply}} + + } + + + {_t.textCancel} + + + ) +}; + +// Edit comment +const EditCommentPopup = inject("storeComments")(observer(({storeComments, comment, onEditComment}) => { + const { t } = useTranslation(); + const _t = t('Common.Collaboration', {returnObjects: true}); + useEffect(() => { + f7.popup.open('.edit-comment-popup'); + }); + const [stateText, setText] = useState(comment.comment); + return ( + { - close(); - //f7.popup.close('.edit-comment-popup'); + f7.popup.close('.edit-comment-popup'); + storeComments.openEditComment(false); }}>{_t.textCancel} {_t.textEditComment} @@ -168,8 +189,8 @@ const EditCommentPopup = ({comment, onEditComment, opened, close}) => { { onEditComment(comment, stateText); - close(); - //f7.popup.close('.edit-comment-popup'); + f7.popup.close('.edit-comment-popup'); + storeComments.openEditComment(false); }} > {Device.android ? : _t.textDone} @@ -192,13 +213,315 @@ const EditCommentPopup = ({comment, onEditComment, opened, close}) => {
) -}; +})); -const EditComment = ({editProps, opened, close}) => { +const EditCommentDialog = inject("storeComments")(observer(({storeComments, comment, onEditComment}) => { + const { t } = useTranslation(); + const _t = t('Common.Collaboration', {returnObjects: true}); + const templateInitials = `
${comment.userInitials}
`; + useEffect(() => { + f7.dialog.create({ + destroyOnClose: true, + containerEl: document.getElementById('edit-comment-dialog'), + content: + ` +
+
+ ${Device.android ? templateInitials : ''} +
+
${comment.userName}
+
${comment.date}
+
+
+
+ +
+
`, + on: { + opened: () => { + const cancel = document.getElementById('comment-cancel'); + cancel.addEventListener('click', () => { + f7.dialog.close(); + storeComments.openEditComment(false); + }); + const done = document.getElementById('comment-done'); + done.addEventListener('click', () => { + const value = document.getElementById('comment-text').value; + if (value.length > 0) { + onEditComment(comment, value); + f7.dialog.close(); + storeComments.openEditComment(false); + } + }); + const area = document.getElementById('comment-text'); + area.addEventListener('input', (event) => { + if (event.target.value.length === 0 && !done.classList.contains('disabled')) { + done.classList.add('disabled'); + } else if (event.target.value.length > 0 && done.classList.contains('disabled')) { + done.classList.remove('disabled'); + } + }); + } + } + }).open(); + }); + return ( +
+ ); +})); + +const EditComment = ({comment, onEditComment}) => { return ( Device.phone ? - : - + : + + ) +}; + +const AddReplyPopup = inject("storeComments")(observer(({storeComments, userInfo, comment, onAddReply}) => { + const { t } = useTranslation(); + const _t = t('Common.Collaboration', {returnObjects: true}); + useEffect(() => { + f7.popup.open('.add-reply-popup'); + }); + const [stateText, setText] = useState(''); + return ( + + + + { + storeComments.openAddReply(false); + f7.popup.close('.add-reply-popup'); + }}>{_t.textCancel} + + {_t.textAddReply} + + { + onAddReply(comment, stateText); + storeComments.openAddReply(false); + f7.popup.close('.add-reply-popup'); + }}> + {Device.android ? : _t.textDone} + + + +
+
+ {Device.android && +
{userInfo.initials}
+ } +
{userInfo.name}
+
+
+ {setText(event.target.value);}}> +
+
+
+ ) +})); + +const AddReplyDialog = inject("storeComments")(observer(({storeComments, userInfo, comment, onAddReply}) => { + const { t } = useTranslation(); + const _t = t('Common.Collaboration', {returnObjects: true}); + const templateInitials = `
${userInfo.initials}
`; + useEffect(() => { + f7.dialog.create({ + destroyOnClose: true, + containerEl: document.getElementById('add-reply-dialog'), + content: + ` +
+
+ ${Device.android ? templateInitials : ''} +
${userInfo.name}
+
+
+ +
+
`, + on: { + opened: () => { + const cancel = document.getElementById('reply-cancel'); + cancel.addEventListener('click', () => { + f7.dialog.close(); + storeComments.openAddReply(false); + }); + const done = document.getElementById('reply-done'); + done.addEventListener('click', () => { + const value = document.getElementById('reply-text').value; + if (value.length > 0) { + onAddReply(comment, value); + f7.dialog.close(); + storeComments.openAddReply(false); + } + }); + const area = document.getElementById('reply-text'); + area.addEventListener('input', (event) => { + if (event.target.value.length === 0 && !done.classList.contains('disabled')) { + done.classList.add('disabled'); + } else if (event.target.value.length > 0 && done.classList.contains('disabled')) { + done.classList.remove('disabled'); + } + }); + done.classList.add('disabled'); + } + } + }).open(); + }); + return ( +
+ ); +})); + +const AddReply = ({userInfo, comment, onAddReply}) => { + return ( + Device.phone ? + : + + ) +}; + +const EditReplyPopup = inject("storeComments")(observer(({storeComments, comment, reply, onEditReply}) => { + const { t } = useTranslation(); + const _t = t('Common.Collaboration', {returnObjects: true}); + useEffect(() => { + f7.popup.open('.edit-reply-popup'); + }); + const [stateText, setText] = useState(reply.reply); + return ( + + + + { + f7.popup.close('.edit-reply-popup'); + storeComments.openEditReply(false); + }}>{_t.textCancel} + + {_t.textEditReply} + + { + onEditReply(comment, reply, stateText); + f7.popup.close('.edit-reply-popup'); + storeComments.openEditReply(false); + }} + > + {Device.android ? : _t.textDone} + + + +
+
+ {Device.android && +
{reply.userInitials}
+ } +
+
{reply.userName}
+
{reply.date}
+
+
+
+ {setText(event.target.value);}}> +
+
+
+ ) +})); + +const EditReplyDialog = inject("storeComments")(observer(({storeComments, comment, reply, onEditReply}) => { + const { t } = useTranslation(); + const _t = t('Common.Collaboration', {returnObjects: true}); + const templateInitials = `
${reply.userInitials}
`; + useEffect(() => { + f7.dialog.create({ + destroyOnClose: true, + containerEl: document.getElementById('edit-reply-dialog'), + content: + ` +
+
+ ${Device.android ? templateInitials : ''} +
+
${reply.userName}
+
${reply.date}
+
+
+
+ +
+
`, + on: { + opened: () => { + const cancel = document.getElementById('reply-cancel'); + cancel.addEventListener('click', () => { + f7.dialog.close(); + storeComments.openEditReply(false); + }); + const done = document.getElementById('reply-done'); + done.addEventListener('click', () => { + const value = document.getElementById('reply-text').value; + if (value.length > 0) { + onEditReply(comment, reply, value); + f7.dialog.close(); + storeComments.openEditReply(false); + } + }); + const area = document.getElementById('reply-text'); + area.addEventListener('input', (event) => { + if (event.target.value.length === 0 && !done.classList.contains('disabled')) { + done.classList.add('disabled'); + } else if (event.target.value.length > 0 && done.classList.contains('disabled')) { + done.classList.remove('disabled'); + } + }); + } + } + }).open(); + }); + return ( +
+ ); +})); + +const EditReply = ({comment, reply, onEditReply}) => { + return ( + Device.phone ? + : + ) }; @@ -221,9 +544,12 @@ const ViewComments = ({storeComments, storeAppOptions, onCommentMenuClick, onRes } }; - const [clickComment, setClickComment] = useState(); + const [clickComment, setComment] = useState(); const [commentActionsOpened, openActionComment] = useState(false); + const [reply, setReply] = useState(); + const [replyActionsOpened, openActionReply] = useState(false); + return ( @@ -245,7 +571,7 @@ const ViewComments = ({storeComments, storeAppOptions, onCommentMenuClick, onRes
{onResolveComment(comment);}}>
{setClickComment(comment); openActionComment(true);}} + onClick={() => {setComment(comment); openActionComment(true);}} >
} @@ -254,7 +580,7 @@ const ViewComments = ({storeComments, storeAppOptions, onCommentMenuClick, onRes {comment.quote &&
{sliceQuote(comment.quote)}
}
{comment.comment}
{comment.replies.length > 0 && -
    +
      {comment.replies.map((reply, indexReply) => { return (
    • {!viewMode &&
      -
      +
      {setComment(comment); setReply(reply); openActionReply(true);}} + > + +
      }
@@ -296,14 +626,108 @@ const ViewComments = ({storeComments, storeAppOptions, onCommentMenuClick, onRes } + ) }; const _ViewComments = inject('storeComments', 'storeAppOptions')(observer(ViewComments)); +const CommentList = () => { + return ( + + + + ) +}; + +const ViewCommentSheet = ({closeCurComments}) => { + const { t } = useTranslation(); + const _t = t('Common.Collaboration', {returnObjects: true}); + + useEffect(() => { + f7.sheet.open('#view-comment-sheet'); + }); + + const [stateHeight, setHeight] = useState('45%'); + const [stateOpacity, setOpacity] = useState(1); + + const [stateStartY, setStartY] = useState(); + const [isNeedClose, setNeedClose] = useState(false); + + const handleTouchStart = (event) => { + const touchObj = event.changedTouches[0]; + setStartY(parseInt(touchObj.clientY)); + }; + const handleTouchMove = (event) => { + const touchObj = event.changedTouches[0]; + const dist = parseInt(touchObj.clientY) - stateStartY; + if (dist < 0) { // to top + setHeight('90%'); + setOpacity(1); + setNeedClose(false); + } else if (dist < 80) { + setHeight('45%'); + setOpacity(1); + setNeedClose(false); + } else { + setNeedClose(true); + setOpacity(0.6); + } + }; + const handleTouchEnd = (event) => { + console.log('end'); + const touchObj = event.changedTouches[0]; + const swipeEnd = parseInt(touchObj.clientY); + const dist = swipeEnd - stateStartY; + if (isNeedClose) { + f7.sheet.close('#view-comment-sheet'); + closeCurComments(); + } else if (stateHeight === '90%' && dist > 20) { + setHeight('45%'); + } + }; + return ( + + + {_t.textAddReply} +
+ + +
+
+
+ +
+ +
+ ) +}; + +const ViewCommentPopover = () => { + useEffect(() => { + f7.popover.open('#view-comment-popover', '#btn-coauth'); + }); + return ( + + + + ) +}; + +const ViewCurrentComments = props => { + return ( + Device.phone ? + : + + ) +}; + export { AddComment, EditComment, - _ViewComments as ViewComments -} + AddReply, + EditReply, + _ViewComments as ViewComments, + ViewCurrentComments +}; diff --git a/apps/common/mobile/resources/less/comments.less b/apps/common/mobile/resources/less/comments.less index abc2140ad..9bd88e835 100644 --- a/apps/common/mobile/resources/less/comments.less +++ b/apps/common/mobile/resources/less/comments.less @@ -1,3 +1,6 @@ +@comment-date: #6d6d72; +@swipe-icon: rgba(0, 0, 0, 0.12); + @import './ios/comments'; @import './material/comments'; @@ -17,14 +20,14 @@ } } } -#add-comment-dialog { +#add-comment-dialog, #edit-comment-dialog, #add-reply-dialog, #edit-reply-dialog { .dialog { --f7-dialog-width: 400px; .dialog-inner { padding: 0; height: 400px; .wrap-comment { - .name { + .name, .comment-date, .reply-date { text-align: left; } .wrap-textarea { @@ -74,7 +77,6 @@ line-height: 18px; color: @comment-date; margin: 0; - margin-top: 0; } .comment-quote { color: @themeColor; @@ -96,11 +98,60 @@ overflow-wrap: break-word; } } - .list-reply { + .reply-list { padding-left: 26px; } } -.edit-comment-popup { +.edit-comment-popup, .add-reply-popup, .edit-reply-popup { z-index: 20000; +} + +#view-comment-sheet { + background-color: @white; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + height: 45%; + box-shadow: 0 1px 10px rgba(0, 0, 0, 0.2), 0 4px 5px rgba(0, 0, 0, 0.12); + webkit-transition: height 200ms; + transition: height 200ms; + .top { + height: 90%; + } + .swipe-container { + display: flex; + justify-content: center; + height: 40px; + .icon-swipe { + margin-top: 8px; + width: 40px; + height: 4px; + background: @swipe-icon; + border-radius: 2px; + } + } + .toolbar { + position: fixed; + background-color: @white; + box-shadow: 0px 1px 10px rgba(0, 0, 0, 0.2), 0px 4px 5px rgba(0, 0, 0, 0.12), 0px 2px 4px rgba(0, 0, 0, 0.14); + .link { + --f7-toolbar-link-color: @themeColor; + } + .toolbar-inner { + padding: 0 16px; + } + .btn-add-reply { + padding: 0; + min-width: 80px; + font-size: 16px; + } + .comment-navigation { + min-width: 62px; + display: flex; + justify-content: space-between; + .link { + padding: 0 12px; + } + } + } } \ No newline at end of file diff --git a/apps/common/mobile/resources/less/common.less b/apps/common/mobile/resources/less/common.less index 690e48226..ea20b6639 100644 --- a/apps/common/mobile/resources/less/common.less +++ b/apps/common/mobile/resources/less/common.less @@ -8,8 +8,6 @@ @background-normal: @white; @autoColor: @black; -@comment-date: #6d6d72; - .popup, .popover, .sheet-modal { .list { &:first-child { diff --git a/apps/common/mobile/resources/less/material/comments.less b/apps/common/mobile/resources/less/material/comments.less index 89ad41807..35725b330 100644 --- a/apps/common/mobile/resources/less/material/comments.less +++ b/apps/common/mobile/resources/less/material/comments.less @@ -1,11 +1,8 @@ .device-android { - .wrap-comment { - .header-comment { + .wrap-comment, .comment-list, .reply-list { + .comment-header, .reply-header { display: flex; - align-items: center; .initials { - height: 30px; - width: 30px; border-radius: 50px; color: @white; display: flex; @@ -15,13 +12,24 @@ font-size: 14px; } } + } + + .wrap-comment { + .comment-header { + align-items: center; + .initials { + height: 30px; + width: 30px; + } + } .wrap-textarea { .input:not(.input-outline):after { content: none; } } } - #add-comment-dialog { + + #add-comment-dialog, #edit-comment-dialog, #add-reply-dialog, #edit-reply-dialog { .dialog { --f7-dialog-text-color: @black; .done { @@ -29,4 +37,46 @@ } } } + + .comment-list { + .item-inner:after { + content: none; + } + .comment-header { + .left { + display: flex; + align-items: center; + .initials { + width: 40px; + height: 40px; + font-size: 18px; + } + } + } + } + .reply-list { + .reply-header { + .left { + display: flex; + .initials { + margin-top: 5px; + width: 24px; + height: 24px; + font-size: 11px; + } + } + } + } + + .edit-comment-popup, .edit-reply-popup, #edit-comment-dialog, #edit-reply-dialog { + .wrap-comment { + .comment-header, .reply-header { + .initials { + height: 40px; + width: 40px; + } + } + } + } + } \ No newline at end of file diff --git a/apps/documenteditor/mobile/locale/en.json b/apps/documenteditor/mobile/locale/en.json index b7ebd65e8..9ef6d3d38 100644 --- a/apps/documenteditor/mobile/locale/en.json +++ b/apps/documenteditor/mobile/locale/en.json @@ -125,7 +125,8 @@ "textMessageDeleteComment": "Do you really want to delete this comment?", "textMessageDeleteReply": "Do you really want to delete this reply?", "textDeleteReply": "Delete Reply", - "textEditComment": "Edit Comment" + "textEditComment": "Edit Comment", + "textEditReply": "Edit Reply" } }, "Settings": { diff --git a/apps/documenteditor/mobile/src/controller/ContextMenu.jsx b/apps/documenteditor/mobile/src/controller/ContextMenu.jsx index 23d5d362d..c82ae0f3a 100644 --- a/apps/documenteditor/mobile/src/controller/ContextMenu.jsx +++ b/apps/documenteditor/mobile/src/controller/ContextMenu.jsx @@ -1,13 +1,43 @@ -import React from 'react'; +import React, { useContext } from 'react'; import { f7 } from 'framework7-react'; +import { inject, observer } from "mobx-react"; import ContextMenuController from '../../../../common/mobile/lib/controller/ContextMenu'; import { idContextMenuElement } from '../../../../common/mobile/lib/view/ContextMenu'; +import { Device } from '../../../../common/mobile/utils/device'; +@inject ( stores => ({ + isEdit: stores.storeAppOptions.isEdit, + canViewComments: stores.storeAppOptions.canViewComments, + canReview: stores.storeAppOptions.canReview +})) 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); + } + + static closeContextMenu() { + f7.popover.close(idContextMenuElement, false); + } + + componentWillUnmount() { + super.componentWillUnmount(); + + const api = Common.EditorApi.get(); + api.asc_unregisterCallback('asc_onShowComment', this.onApiShowComment); + api.asc_unregisterCallback('asc_onHideComment', this.onApiHideComment); + } + + + onApiShowComment(comments) { + this.isComments = comments && comments.length > 0; + } + + onApiHideComment() { + this.isComments = false; } // onMenuClosed() { @@ -17,23 +47,244 @@ class ContextMenu extends ContextMenuController { onMenuItemClick(action) { super.onMenuItemClick(action); - console.log("on click item"); + switch (action) { + case 'addcomment': + Common.Notifications.trigger('addcomment'); + break; + case 'viewcomment': + Common.Notifications.trigger('viewcomment'); + break; + } + + console.log("click context menu item: " + action); + } + + onDocumentReady() { + super.onDocumentReady(); + + const api = Common.EditorApi.get(); + api.asc_registerCallback('asc_onShowComment', this.onApiShowComment); + api.asc_registerCallback('asc_onHideComment', this.onApiHideComment); } initMenuItems() { - return [ - { - text: 'Edit', - action: 'edit' - }, { - text: 'View', - action: 'view' - }, { - icon: 'icon-paste', - action: 'review' + if ( !Common.EditorApi ) return []; + + const { isEdit, canViewComments, canReview } = this.props; + + const api = Common.EditorApi.get(); + const stack = api.getSelectedElements(); + const canCopy = api.can_CopyCut(); + + let itemsIcon = [], + itemsText = []; + + if ( canCopy ) { + itemsIcon.push({ + caption: /*me.menuCopy*/ 'Copy', + event: 'copy', + icon: 'icon-copy' + }); + } + + if ( canViewComments && this.isComments && !isEdit ) { + itemsText.push({ + caption: /*me.menuViewComment*/'View Comment', + event: 'viewcomment' + }); + } + + let isText = false, + isTable = false, + isImage = false, + isChart = false, + isShape = false, + isLink = false, + lockedText = false, + lockedTable = false, + lockedImage = false, + lockedHeader = false; + + stack.forEach(item => { + const objectType = item.get_ObjectType(), + objectValue = item.get_ObjectValue(); + + if ( objectType == Asc.c_oAscTypeSelectElement.Header ) { + lockedHeader = objectValue.get_Locked(); + } else + if ( objectType == Asc.c_oAscTypeSelectElement.Paragraph ) { + lockedText = objectValue.get_Locked(); + isText = true; + } else + if ( objectType == Asc.c_oAscTypeSelectElement.Image ) { + lockedImage = objectValue.get_Locked(); + if ( objectValue && objectValue.get_ChartProperties() ) { + isChart = true; + } else + if ( objectValue && objectValue.get_ShapeProperties() ) { + isShape = true; + } else { + isImage = true; + } + } else + if ( objectType == Asc.c_oAscTypeSelectElement.Table ) { + lockedTable = objectValue.get_Locked(); + isTable = true; + } else + if ( objectType == Asc.c_oAscTypeSelectElement.Hyperlink ) { + isLink = true; } - ]; + }); + + if ( stack.length > 0 ) { + const swapItems = function(items, indexBefore, indexAfter) { + items[indexAfter] = items.splice(indexBefore, 1, items[indexAfter])[0]; + }; + + if ( isEdit && !this.isDisconnected ) { + if ( !lockedText && !lockedTable && !lockedImage && !lockedHeader && canCopy ) { + itemsIcon.push({ + // caption: me.menuCut, + event: 'cut', + icon: 'icon-cut' + }); + + // Swap 'Copy' and 'Cut' + swapItems(itemsIcon, 0, 1); + } + + if ( !lockedText && !lockedTable && !lockedImage && !lockedHeader ) { + itemsIcon.push({ + // caption: me.menuPaste, + event: 'paste', + icon: 'icon-paste' + }); + } + + // For test + if ( this.isComments && canViewComments ) { + itemsText.push({ + caption: /*me.menuViewComment*/'View Comment', + event: 'viewcomment' + }); + } + + const isObject = isShape || isChart || isImage || isTable; + const hideAddComment = !canViewComments || api.can_AddQuotedComment() === false || lockedText || lockedTable || lockedImage || lockedHeader || (!isText && isObject); + if ( !hideAddComment ) { + itemsText.push({ + caption: /*me.menuAddComment*/'Add Comment', + event: 'addcomment' + }); + } + // end test + + if ( isTable && api.CheckBeforeMergeCells() && !lockedTable && !lockedHeader) { + itemsText.push({ + caption: /*me.menuMerge*/'Merge', + event: 'merge' + }); + } + + if ( isTable && api.CheckBeforeSplitCells() && !lockedTable && !lockedHeader ) { + itemsText.push({ + caption: /*me.menuSplit*/'Split', + event: 'split' + }); + } + + if ( !lockedText && !lockedTable && !lockedImage && !lockedHeader ) { + itemsText.push({ + caption: /*me.menuDelete*/'Delete', + event: 'delete' + }); + } + + if ( isTable && !lockedTable && !lockedText && !lockedHeader ) { + itemsText.push({ + caption: /*me.menuDeleteTable*/'Delete Table', + event: 'deletetable' + }); + } + + if ( !lockedText && !lockedTable && !lockedImage && !lockedHeader ){ + itemsText.push({ + caption: /*me.menuEdit*/'Edit', + event: 'edit' + }); + } + + // if ( !_.isEmpty(api.can_AddHyperlink()) && !lockedHeader) { + // arrItems.push({ + // caption: me.menuAddLink, + // event: 'addlink' + // }); + // } + + if ( canReview ) { + if (false /*_inRevisionChange*/) { + itemsText.push({ + caption: /*me.menuReviewChange*/'Review Change', + event: 'reviewchange' + }); + } else { + itemsText.push({ + caption: /*me.menuReview*/'Review', + event: 'review' + }); + } + } + + if ( this.isComments && canViewComments ) { + itemsText.push({ + caption: /*me.menuViewComment*/'View Comment', + event: 'viewcomment' + }); + } + + /*const isObject = isShape || isChart || isImage || isTable; + const hideAddComment = !canViewComments || api.can_AddQuotedComment() === false || lockedText || lockedTable || lockedImage || lockedHeader || (!isText && isObject); + if ( !hideAddComment ) { + itemsText.push({ + caption: 'Add Comment', + event: 'addcomment' + }); + }*/ + } + } + + if ( isLink ) { + itemsText.push({ + caption: /*me.menuOpenLink*/'Open Link', + event: 'openlink' + }); + } + + if ( Device.phone && itemsText.length > 2 ) { + // _actionSheets = arrItems.slice(2); + // arrItems = arrItems.slice(0, 2); + // arrItems.push({ + // caption: me.menuMore, + // event: 'showActionSheet' + // }); + this.extraItems = itemsText.splice(2,itemsText.length, { + caption: /*me.menuMore*/'More', + event: 'showActionSheet' + }); + } + + return itemsIcon.concat(itemsText); + // return [{ + // caption: 'Edit', + // event: 'edit' + // }, { + // caption: 'View', + // event: 'view' + // }, { + // icon: 'icon-paste', + // event: 'review' + // }]; } } -export { ContextMenu, idContextMenuElement }; \ No newline at end of file +export { ContextMenu as default }; \ No newline at end of file diff --git a/apps/documenteditor/mobile/src/controller/Main.jsx b/apps/documenteditor/mobile/src/controller/Main.jsx index 3bd8fa965..564edf439 100644 --- a/apps/documenteditor/mobile/src/controller/Main.jsx +++ b/apps/documenteditor/mobile/src/controller/Main.jsx @@ -6,7 +6,12 @@ import { withTranslation } from 'react-i18next'; import CollaborationController from '../../../../common/mobile/lib/controller/collaboration/Collaboration.jsx'; import {InitReviewController as ReviewController} from '../../../../common/mobile/lib/controller/collaboration/Review.jsx'; import { onAdvancedOptions } from './settings/Download.jsx'; -import {CommentsController, AddCommentController} from "../../../../common/mobile/lib/controller/collaboration/Comments"; +import { + CommentsController, + AddCommentController, + EditCommentController, + ViewCommentsController +} from "../../../../common/mobile/lib/controller/collaboration/Comments"; @inject( "storeAppOptions", @@ -335,6 +340,8 @@ class MainController extends Component { + + ) } diff --git a/apps/documenteditor/mobile/src/controller/settings/ApplicationSettings.jsx b/apps/documenteditor/mobile/src/controller/settings/ApplicationSettings.jsx index 39b4fd77e..4f8275494 100644 --- a/apps/documenteditor/mobile/src/controller/settings/ApplicationSettings.jsx +++ b/apps/documenteditor/mobile/src/controller/settings/ApplicationSettings.jsx @@ -25,16 +25,14 @@ class ApplicationSettingsController extends Component { } switchNoCharacters(value) { - Common.localStorage.setItem("de-mobile-no-characters", value); + LocalStorage.setItem("de-mobile-no-characters", value); - const api = Common.EditorApi.get(); - api.put_ShowParaMarks(value); + Common.EditorApi.get().put_ShowParaMarks(value); } switchShowTableEmptyLine(value) { - Common.localStorage.setItem("de-mobile-hidden-borders", value); - const api = Common.EditorApi.get(); - api.put_ShowTableEmptyLine(value); + LocalStorage.setItem("de-mobile-hidden-borders", value); + Common.EditorApi.get().put_ShowTableEmptyLine(value); } switchDisplayComments(value) { @@ -51,10 +49,9 @@ class ApplicationSettingsController extends Component { } switchDisplayResolved(value) { - const api = Common.EditorApi.get(); const displayComments = LocalStorage.getBool("de-mobile-settings-livecomment"); if (displayComments) { - api.asc_showComments(value); + Common.EditorApi.get().asc_showComments(value); LocalStorage.setBool("de-settings-resolvedcomment", value); } } diff --git a/apps/documenteditor/mobile/src/less/icons-material.less b/apps/documenteditor/mobile/src/less/icons-material.less index 75630079b..a388db33f 100644 --- a/apps/documenteditor/mobile/src/less/icons-material.less +++ b/apps/documenteditor/mobile/src/less/icons-material.less @@ -440,16 +440,6 @@ height: 24px; .encoded-svg-background(''); } - &.icon-prev-comment { - width: 24px; - height: 24px; - .encoded-svg-background(''); - } - &.icon-next-comment { - width: 24px; - height: 24px; - .encoded-svg-background(''); - } &.icon-done-comment { width: 24px; height: 24px; diff --git a/apps/documenteditor/mobile/src/page/main.jsx b/apps/documenteditor/mobile/src/page/main.jsx index 2072e41db..38d3e529f 100644 --- a/apps/documenteditor/mobile/src/page/main.jsx +++ b/apps/documenteditor/mobile/src/page/main.jsx @@ -8,10 +8,9 @@ import EditOptions from '../view/edit/Edit'; import AddOptions from '../view/add/Add'; import Settings from '../view/settings/Settings'; import Collaboration from '../../../../common/mobile/lib/view/collaboration/Collaboration.jsx' -import { AddCommentController } from '../../../../common/mobile/lib/controller/collaboration/Comments.jsx'; import { Device } from '../../../../common/mobile/utils/device' import { Search, SearchSettings } from '../controller/Search'; -import { ContextMenu, idContextMenuElement } from '../controller/ContextMenu'; +import ContextMenu from '../controller/ContextMenu'; export default class MainPage extends Component { constructor(props) { @@ -25,7 +24,7 @@ export default class MainPage extends Component { } handleClickToOpenOptions = opts => { - f7.popover.close(idContextMenuElement, false); + ContextMenu.closeContextMenu(); this.setState(state => { if ( opts == 'edit' ) diff --git a/apps/documenteditor/mobile/src/store/appOptions.js b/apps/documenteditor/mobile/src/store/appOptions.js index 5020a25a8..a26bc4255 100644 --- a/apps/documenteditor/mobile/src/store/appOptions.js +++ b/apps/documenteditor/mobile/src/store/appOptions.js @@ -1,8 +1,23 @@ -import {action, observable} from 'mobx'; +import {makeObservable, action, observable} from 'mobx'; export class storeAppOptions { + constructor() { + makeObservable(this, { + isEdit: observable, + canViewComments: observable, + canReview: observable, + setConfigOptions: action, + setPermissionOptions: action, + setCanViewReview: action + }); + } + + isEdit = false; + canViewComments = false; + canReview = false; + config = {}; - @action setConfigOptions (config) { + setConfigOptions (config) { this.config = config; this.user = Common.Utils.fillUserInfo(config.user, config.lang, "Local.User"/*me.textAnonymous*/); this.isDesktopApp = config.targetApp == 'desktop'; @@ -24,7 +39,7 @@ export class storeAppOptions { this.canBack = this.canBackToFolder === true; this.canPlugins = false; } - @action setPermissionOptions (document, licType, params, permissions) { + setPermissionOptions (document, licType, params, permissions) { this.review = (permissions.review === undefined) ? (permissions.edit !== false) : permissions.review; this.canAnalytics = params.asc_getIsAnalyticsEnable(); this.canLicense = (licType === Asc.c_oLicenseResult.Success || licType === Asc.c_oLicenseResult.SuccessLimit); @@ -71,7 +86,7 @@ export class storeAppOptions { this.canUseReviewPermissions = this.canLicense && this.customization && this.customization.reviewPermissions && (typeof (this.customization.reviewPermissions) == 'object'); } - @action setCanViewReview (value) { + setCanViewReview (value) { this.canViewReview = value; } } \ No newline at end of file diff --git a/apps/documenteditor/mobile/src/store/applicationSettings.js b/apps/documenteditor/mobile/src/store/applicationSettings.js index 968c84b78..a1e17a40c 100644 --- a/apps/documenteditor/mobile/src/store/applicationSettings.js +++ b/apps/documenteditor/mobile/src/store/applicationSettings.js @@ -1,45 +1,59 @@ -import {action, observable} from 'mobx'; +import {makeObservable, action, observable} from 'mobx'; export class storeApplicationSettings { - - @observable unitMeasurement = 1; + constructor() { + makeObservable(this, { + unitMeasurement: observable + , isSpellChecking: observable + , isNonprintingCharacters: observable + , isHiddenTableBorders: observable + , isComments: observable + , isResolvedComments: observable + , macrosMode: observable + , changeSpellCheck: action + , changeUnitMeasurement: action + , changeNoCharacters: action + , changeShowTableEmptyLine: action + , changeDisplayComments: action + , changeDisplayResolved: action + , changeMacrosSettings: action + }) + } - @observable isSpellChecking = true; + unitMeasurement = 1; + isSpellChecking = true; + isNonprintingCharacters = false; + isHiddenTableBorders = false; + isComments = true; + isResolvedComments = true; + macrosMode = 0; - @observable isNonprintingCharacters = false; - @observable isHiddenTableBorders = false; - - @observable isComments = true; - @observable isResolvedComments = true; - - @observable macrosMode = 0; - - @action changeUnitMeasurement(value) { + changeUnitMeasurement(value) { this.unitMeasurement = +value; } - @action changeSpellCheck(value) { + changeSpellCheck(value) { this.isSpellChecking = value; } - @action changeNoCharacters(value) { + changeNoCharacters(value) { this.isNonprintingCharacters = value; } - @action changeShowTableEmptyLine(value) { + changeShowTableEmptyLine(value) { this.isHiddenTableBorders = value; } - @action changeDisplayComments(value) { + changeDisplayComments(value) { this.isComments = value; if (!value) this.changeDisplayResolved(value); } - @action changeDisplayResolved(value) { + changeDisplayResolved(value) { this.isResolvedComments = value; } - @action changeMacrosSettings(value) { + changeMacrosSettings(value) { this.macrosMode = +value; } } \ No newline at end of file diff --git a/apps/documenteditor/mobile/src/store/tableSettings.js b/apps/documenteditor/mobile/src/store/tableSettings.js index 440c1f658..b40d71bc0 100644 --- a/apps/documenteditor/mobile/src/store/tableSettings.js +++ b/apps/documenteditor/mobile/src/store/tableSettings.js @@ -1,7 +1,11 @@ -import {action, observable, computed} from 'mobx'; +import {makeObservable, action, observable, computed} from 'mobx'; import {f7} from 'framework7-react'; export class storeTableSettings { + constructor() { + makeObservable(this) + } + @observable _templates = []; @action initTableTemplates (templates) { this._templates = templates; @@ -67,7 +71,6 @@ export class storeTableSettings { // Border style @observable cellBorders; @observable cellBorderWidth = 0.5; - @observable cellBorderWidth = 0.5; @observable cellBorderColor = '000000'; borderSizeTransform () { diff --git a/apps/documenteditor/mobile/src/view/add/AddOther.jsx b/apps/documenteditor/mobile/src/view/add/AddOther.jsx index 15dc2e139..25040fc49 100644 --- a/apps/documenteditor/mobile/src/view/add/AddOther.jsx +++ b/apps/documenteditor/mobile/src/view/add/AddOther.jsx @@ -202,7 +202,7 @@ const AddOther = props => { { props.closeModal(); - props.storeComments.openAddComment(true); + Common.Notifications.trigger('addcomment'); }}> diff --git a/apps/presentationeditor/mobile/src/less/icons-ios.less b/apps/presentationeditor/mobile/src/less/icons-ios.less index 6b77662cd..d43e2a6b4 100644 --- a/apps/presentationeditor/mobile/src/less/icons-ios.less +++ b/apps/presentationeditor/mobile/src/less/icons-ios.less @@ -187,18 +187,6 @@ .encoded-svg-mask(''); } - &.icon-prev, &.icon-prev-comment { - width: 22px; - height: 22px; - .encoded-svg-background(''); - } - - &.icon-next, &.icon-next-comment { - width: 22px; - height: 22px; - .encoded-svg-background(''); - } - &.icon-table-add-column-left { width: 22px; height: 22px; diff --git a/apps/presentationeditor/mobile/src/less/icons-material.less b/apps/presentationeditor/mobile/src/less/icons-material.less index b1de085b6..3c7098570 100644 --- a/apps/presentationeditor/mobile/src/less/icons-material.less +++ b/apps/presentationeditor/mobile/src/less/icons-material.less @@ -471,18 +471,6 @@ .encoded-svg-background(''); } - &.icon-prev-comment { - width: 24px; - height: 24px; - .encoded-svg-background(''); - } - - &.icon-next-comment { - width: 24px; - height: 24px; - .encoded-svg-background(''); - } - &.icon-done-comment { width: 24px; height: 24px; diff --git a/apps/presentationeditor/mobile/src/store/appOptions.js b/apps/presentationeditor/mobile/src/store/appOptions.js index 7bec65bc4..c07f81eaa 100644 --- a/apps/presentationeditor/mobile/src/store/appOptions.js +++ b/apps/presentationeditor/mobile/src/store/appOptions.js @@ -1,8 +1,17 @@ -import {action, observable} from 'mobx'; +import {makeObservable, action, observable} from 'mobx'; export class storeAppOptions { + constructor() { + makeObservable(this, { + isEdit: observable, + setConfigOptions: action, + setPermissionOptions: action + }); + } + + isEdit = false; config = {}; - @action setConfigOptions (config) { + setConfigOptions (config) { this.config = config; this.user = Common.Utils.fillUserInfo(config.user, config.lang, "Local.User"/*me.textAnonymous*/); this.isDesktopApp = config.targetApp == 'desktop'; @@ -24,7 +33,7 @@ export class storeAppOptions { this.canBack = this.canBackToFolder === true; this.canPlugins = false; } - @action setPermissionOptions (document, licType, params, permissions) { + setPermissionOptions (document, licType, params, permissions) { this.review = (permissions.review === undefined) ? (permissions.edit !== false) : permissions.review; this.canAnalytics = params.asc_getIsAnalyticsEnable(); this.canLicense = (licType === Asc.c_oLicenseResult.Success || licType === Asc.c_oLicenseResult.SuccessLimit); diff --git a/apps/spreadsheeteditor/mobile/src/less/icons-ios.less b/apps/spreadsheeteditor/mobile/src/less/icons-ios.less index ec61398a8..ded1d72c2 100644 --- a/apps/spreadsheeteditor/mobile/src/less/icons-ios.less +++ b/apps/spreadsheeteditor/mobile/src/less/icons-ios.less @@ -123,16 +123,6 @@ height: 22px; .encoded-svg-mask(''); } - &.icon-prev, &.icon-prev-comment { - width: 22px; - height: 22px; - .encoded-svg-background(''); - } - &.icon-next, &.icon-next-comment { - width: 22px; - height: 22px; - .encoded-svg-background(''); - } &.icon-expand-down { width: 22px; height: 22px; diff --git a/apps/spreadsheeteditor/mobile/src/less/icons-material.less b/apps/spreadsheeteditor/mobile/src/less/icons-material.less index 008cd29ab..1aad05d4f 100644 --- a/apps/spreadsheeteditor/mobile/src/less/icons-material.less +++ b/apps/spreadsheeteditor/mobile/src/less/icons-material.less @@ -365,16 +365,6 @@ height: 24px; .encoded-svg-background(''); } - &.icon-prev-comment { - width: 24px; - height: 24px; - .encoded-svg-background(''); - } - &.icon-next-comment { - width: 24px; - height: 24px; - .encoded-svg-background(''); - } &.icon-done-comment { width: 24px; height: 24px; diff --git a/vendor/framework7-react/babel.config.js b/vendor/framework7-react/babel.config.js index a899c701d..b6def8dbb 100644 --- a/vendor/framework7-react/babel.config.js +++ b/vendor/framework7-react/babel.config.js @@ -9,6 +9,6 @@ module.exports = { '@babel/plugin-transform-runtime', '@babel/plugin-syntax-dynamic-import', ['@babel/plugin-proposal-decorators', {'legacy': true }], - ['@babel/plugin-proposal-class-properties',{'loose':true}], + ['@babel/plugin-proposal-class-properties',{'loose':false}], ], }; diff --git a/vendor/framework7-react/package.json b/vendor/framework7-react/package.json index 2cfa15418..a7e241a4d 100644 --- a/vendor/framework7-react/package.json +++ b/vendor/framework7-react/package.json @@ -58,8 +58,8 @@ "less": "^3.13.1", "less-loader": "^6.2.0", "mini-css-extract-plugin": "^0.9.0", - "mobx": "^5.15.7", - "mobx-react": "^6.3.1", + "mobx": "^6.1.8", + "mobx-react": "^7.1.0", "optimize-css-assets-webpack-plugin": "^5.0.4", "ora": "^4.1.1", "postcss-loader": "^3.0.0",