[SSE mobile] Resolved conflict

This commit is contained in:
SergeyEzhin 2021-03-23 17:18:39 +03:00
commit 4a0af99640
24 changed files with 663 additions and 83 deletions

View file

@ -1,6 +1,7 @@
import React, { Component, Fragment } from 'react';
import { f7 } from 'framework7-react';
import { Device } from '../../../../common/mobile/utils/device'
import {observer, inject} from "mobx-react";
import { Device } from '../../../../common/mobile/utils/device';
import ContextMenuView, { idContextMenuElement, ActionsWithExtraItems } from '../view/ContextMenu';
@ -23,6 +24,8 @@ class ContextMenuController extends Component {
this.onDocumentReady = this.onDocumentReady.bind(this);
this.onApiOpenContextMenu = this.onApiOpenContextMenu.bind(this);
this.onApiHideContextMenu = this.onApiHideContextMenu.bind(this);
this.onApiShowForeignCursorLabel = this.onApiShowForeignCursorLabel.bind(this);
this.onApiHideForeignCursorLabel = this.onApiHideForeignCursorLabel.bind(this);
}
onDocumentReady() {
@ -38,6 +41,8 @@ class ContextMenuController extends Component {
const api = Common.EditorApi.get();
api.asc_registerCallback('asc_onShowPopMenu', this.onApiOpenContextMenu);
api.asc_registerCallback('asc_onHidePopMenu', this.onApiHideContextMenu);
api.asc_registerCallback('asc_onShowForeignCursorLabel', this.onApiShowForeignCursorLabel);
api.asc_registerCallback('asc_onHideForeignCursorLabel', this.onApiHideForeignCursorLabel);
}
offsetPopoverTop(popover) {
@ -150,12 +155,61 @@ class ContextMenuController extends Component {
}
}
onApiShowForeignCursorLabel(UserId, X, Y, color) {
/** coauthoring begin **/
const tipHeight = 20;
if (!this.fastCoAuthTips) {
this.fastCoAuthTips = [];
}
let src;
for (let i=0; i<this.fastCoAuthTips.length; i++) {
if (this.fastCoAuthTips[i].attr('userid') === UserId) {
src = this.fastCoAuthTips[i];
break;
}
}
if (!src) {
src = $$(`<div class="username-tip"></div>`);
src.attr('userid', UserId);
src.css({'background-color': '#'+Common.Utils.ThemeColor.getHexColor(color.get_r(), color.get_g(), color.get_b())});
src.text(this.getUserName(UserId));
$$('#id_main_parent').append(src);
this.fastCoAuthTips.push(src);
//src.fadeIn(150);
src[0].classList.add('active');
$$('#id_main_view').append(src);
}
src.css({
top: (Y - tipHeight) + 'px',
left: X + 'px'});
/** coauthoring end **/
}
onApiHideForeignCursorLabel(userId) {
/** coauthoring begin **/
for (let i=0; i<this.fastCoAuthTips.length; i++) {
if (this.fastCoAuthTips[i].attr('userid') == userId) {
const src = this.fastCoAuthTips[i];
//this.fastCoAuthTips[i].fadeOut(150, () => {src.remove()});
src[0].classList.remove('active');
src.remove();
this.fastCoAuthTips.splice(i, 1);
break;
}
}
/** coauthoring end **/
}
componentWillUnmount() {
Common.Notifications.off('document:ready', this.onDocumentReady);
const api = Common.EditorApi.get();
api.asc_unregisterCallback('asc_onShowPopMenu', this.onApiOpenContextMenu);
api.asc_unregisterCallback('asc_onHidePopMenu', this.onApiHideContextMenu);
api.asc_unregisterCallback('asc_onShowForeignCursorLabel', this.onApiShowForeignCursorLabel);
api.asc_unregisterCallback('asc_onHideForeignCursorLabel', this.onApiHideForeignCursorLabel);
}
componentDidMount() {

View file

@ -1,17 +1,63 @@
import React, { Component } from 'react'
import {observer, inject} from "mobx-react"
import { LocalStorage } from '../../../utils/LocalStorage';
class CollaborationController extends Component {
constructor(props){
super(props);
Common.Notifications.on('configOptionsFill', () => {
const api = Common.EditorApi.get();
// this.api = api;
Common.Notifications.on('engineCreated', (api) => {
api.asc_registerCallback('asc_onAuthParticipantsChanged', this.onChangeEditUsers.bind(this));
api.asc_registerCallback('asc_onParticipantsChanged', this.onChangeEditUsers.bind(this));
api.asc_registerCallback('asc_onConnectionStateChanged', this.onUserConnection.bind(this));
api.asc_registerCallback('asc_onCoAuthoringDisconnect', this.onCoAuthoringDisconnect.bind(this));
});
Common.Notifications.on('document:ready', this.onDocumentReady.bind(this));
}
onDocumentReady() {
const api = Common.EditorApi.get();
const appOptions = this.props.storeAppOptions;
/** coauthoring begin **/
let isFastCoauth;
if (appOptions.isEdit && appOptions.canLicense && !appOptions.isOffline && appOptions.canCoAuthoring) {
// Force ON fast co-authoring mode
isFastCoauth = true;
api.asc_SetFastCollaborative(isFastCoauth);
if (window.editorType === 'de') {
const value = LocalStorage.getItem((isFastCoauth) ? "de-settings-showchanges-fast" : "de-settings-showchanges-strict");
if (value !== null) {
api.SetCollaborativeMarksShowType(
value === 'all' ? Asc.c_oAscCollaborativeMarksShowType.All :
value === 'none' ? Asc.c_oAscCollaborativeMarksShowType.None : Asc.c_oAscCollaborativeMarksShowType.LastChanges);
} else {
api.SetCollaborativeMarksShowType(isFastCoauth ? Asc.c_oAscCollaborativeMarksShowType.None : Asc.c_oAscCollaborativeMarksShowType.LastChanges);
}
}
} else if (!appOptions.isEdit && appOptions.isRestrictedEdit) {
isFastCoauth = true;
api.asc_SetFastCollaborative(isFastCoauth);
window.editorType === 'de' && api.SetCollaborativeMarksShowType(Asc.c_oAscCollaborativeMarksShowType.None);
api.asc_setAutoSaveGap(1);
} else {
isFastCoauth = false;
api.asc_SetFastCollaborative(isFastCoauth);
window.editorType === 'de' && api.SetCollaborativeMarksShowType(Asc.c_oAscCollaborativeMarksShowType.None);
}
if (appOptions.isEdit) {
let value;
if (window.editorType === 'sse') {
value = appOptions.canAutosave ? 1 : 0; // FORCE AUTOSAVE
} else {
value = isFastCoauth; // Common.localStorage.getItem("de-settings-autosave");
value = (!isFastCoauth && value !== null) ? parseInt(value) : (appOptions.canCoAuthoring ? 1 : 0);
}
api.asc_setAutoSaveGap(value);
}
/** coauthoring end **/
}
onChangeEditUsers(users) {
@ -24,6 +70,10 @@ class CollaborationController extends Component {
this.props.users.connection(change);
}
onCoAuthoringDisconnect() {
this.props.users.resetDisconnected(true);
}
render() {
return null
}

View file

@ -238,6 +238,9 @@ class AddCommentController extends Component {
}
getUserInfo () {
this.currentUser = this.props.users.currentUser;
if (!this.currentUser) {
this.currentUser = this.props.users.setCurrentUser(this.props.storeAppOptions.user.id);
}
const name = this.currentUser.asc_getUserName();
return {
name: name,

View file

@ -8,12 +8,15 @@ export class storeUsers {
reset: action,
currentUser: observable,
setCurrentUser: action,
connection: action
connection: action,
isDisconnected: observable,
resetDisconnected: action
})
}
users = [];
currentUser;
isDisconnected = false;
reset (users) {
this.users = Object.values(users)
@ -25,6 +28,7 @@ export class storeUsers {
this.currentUser = item;
}
});
return this.currentUser;
}
connection (change) {
@ -41,6 +45,10 @@ export class storeUsers {
!changed && change && (this.users[change.asc_getId()] = change);
}
resetDisconnected (isDisconnected) {
this.isDisconnected = isDisconnected;
}
getInitials (name) {
const fio = Common.Utils.UserInfoParser.getParsedName(name).split(' ');
let initials = fio[0].substring(0, 1).toUpperCase();
@ -62,4 +70,14 @@ export class storeUsers {
});
return user;
}
searchUserByCurrentId (id) {
let user = null;
this.users.forEach((item) => {
if (item.asc_getId() === id) {
user = item;
}
});
return user;
}
}

View file

@ -47,7 +47,7 @@ const ActionsWithExtraItems = ({items, onMenuItemClick, opened, onActionClosed})
<ActionsGroup>
{items.length > 0 && items.map((item, index)=>{
return(
<ActionsButton key={`act-${item.caption}`} onClick={() => {onMenuItemClick(item.event)}}>{item.caption}</ActionsButton>
<ActionsButton key={`act-${index}`} onClick={() => {onMenuItemClick(item.event)}}>{item.caption}</ActionsButton>
)
})}
</ActionsGroup>

View file

@ -669,6 +669,22 @@ input[type="number"]::-webkit-inner-spin-button {
}
}
.username-tip {
height: 20px;
color: @white;
padding: 0 10px;
position: absolute;
z-index: 900;
display: none;
pointer-events: none;
transition: opacity 0.1ms ease-out;
opacity: 0;
&.active {
display: block;
opacity: 1;
}
}

View file

@ -39,7 +39,7 @@
}
.comment-list {
.item-inner:after, li:last-child li .item-inner:after {
ul:after, .item-inner:after, li:last-child li .item-inner:after {
content: none;
}
.comment-header {

View file

@ -11,7 +11,9 @@ import { Device } from '../../../../common/mobile/utils/device';
@inject ( stores => ({
isEdit: stores.storeAppOptions.isEdit,
canViewComments: stores.storeAppOptions.canViewComments,
canReview: stores.storeAppOptions.canReview
canReview: stores.storeAppOptions.canReview,
users: stores.users,
isDisconnected: stores.users.isDisconnected
}))
class ContextMenu extends ContextMenuController {
constructor(props) {
@ -21,12 +23,18 @@ class ContextMenu extends ContextMenuController {
this.onApiShowComment = this.onApiShowComment.bind(this);
this.onApiHideComment = this.onApiHideComment.bind(this);
this.onApiShowChange = this.onApiShowChange.bind(this);
this.getUserName = this.getUserName.bind(this);
}
static closeContextMenu() {
f7.popover.close(idContextMenuElement, false);
}
getUserName(id) {
const user = this.props.users.searchUserByCurrentId(id);
return Common.Utils.UserInfoParser.getParsedName(user.asc_getUserName());
}
componentWillUnmount() {
super.componentWillUnmount();
@ -224,7 +232,7 @@ class ContextMenu extends ContextMenuController {
const { t } = this.props;
const _t = t("ContextMenu", { returnObjects: true });
const { isEdit, canViewComments, canReview } = this.props;
const { isEdit, canViewComments, canReview, isDisconnected } = this.props;
const api = Common.EditorApi.get();
const stack = api.getSelectedElements();
@ -294,7 +302,7 @@ class ContextMenu extends ContextMenuController {
items[indexAfter] = items.splice(indexBefore, 1, items[indexAfter])[0];
};
if ( isEdit && !this.isDisconnected ) {
if ( isEdit && !isDisconnected ) {
if ( !lockedText && !lockedTable && !lockedImage && !lockedHeader && canCopy ) {
itemsIcon.push({
event: 'cut',

View file

@ -24,6 +24,19 @@
}
}
},
"ContextMenu": {
"menuViewComment": "View Comment",
"menuAddComment": "Add Comment",
"menuDelete": "Delete",
"menuEdit": "Edit",
"menuAddLink": "Add Link",
"menuOpenLink": "Open Link",
"menuMore": "More",
"menuCancel": "Cancel",
"textCopyCutPasteActions": "Copy, Cut and Paste Actions",
"errorCopyCutPaste": "Copy, cut and paste actions using the context menu will be performed within the current file only.",
"textDoNotShowAgain": "Don't show again"
},
"View": {
"Settings": {
"textDone": "Done",
@ -101,6 +114,7 @@
"textColumns": "Columns",
"textRows": "Rows",
"textCancel": "Cancel",
"textAddLink": "Add Link",
"textLink": "Link",
"textLinkType": "Link Type",
"textExternalLink": "External Link",
@ -267,6 +281,27 @@
"textThemeColors": "Theme Colors",
"textStandartColors": "Standard Colors",
"textCustomColors": "Custom Colors"
},
"Collaboration": {
"textCollaboration": "Collaboration",
"textBack": "Back",
"textUsers": "Users",
"textEditUser": "Users who are editing the file:",
"textComments": "Comments",
"textAddComment": "Add Comment",
"textCancel": "Cancel",
"textDone": "Done",
"textNoComments": "This document doesn't contain comments",
"textEdit": "Edit",
"textResolve": "Resolve",
"textReopen": "Reopen",
"textAddReply": "Add Reply",
"textDeleteComment": "Delete Comment",
"textMessageDeleteComment": "Do you really want to delete this comment?",
"textMessageDeleteReply": "Do you really want to delete this reply?",
"textDeleteReply": "Delete Reply",
"textEditComment": "Edit Comment",
"textEditReply": "Edit Reply"
}
}
}

View file

@ -4,6 +4,8 @@ import ReactDOM from 'react-dom';
// Import Framework7
import Framework7 from 'framework7/lite-bundle';
import { Dom7 } from 'framework7';
window.$$ = Dom7;
// Import Framework7-React Plugin
import Framework7React from 'framework7-react';

View file

@ -0,0 +1,312 @@
import React, { useContext } from 'react';
import { f7 } from 'framework7-react';
import { inject, observer } from "mobx-react";
import { withTranslation} from 'react-i18next';
import { LocalStorage } from '../../../../common/mobile/utils/LocalStorage';
import ContextMenuController from '../../../../common/mobile/lib/controller/ContextMenu';
import { idContextMenuElement } from '../../../../common/mobile/lib/view/ContextMenu';
import { Device } from '../../../../common/mobile/utils/device';
@inject ( stores => ({
isEdit: stores.storeAppOptions.isEdit,
canViewComments: stores.storeAppOptions.canViewComments,
users: stores.users,
isDisconnected: stores.users.isDisconnected
}))
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);
this.getUserName = this.getUserName.bind(this);
}
static closeContextMenu() {
f7.popover.close(idContextMenuElement, false);
}
getUserName(id) {
const user = this.props.users.searchUserByCurrentId(id);
return Common.Utils.UserInfoParser.getParsedName(user.asc_getUserName());
}
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() {
// super.onMenuClosed();
// }
onMenuItemClick(action) {
super.onMenuItemClick(action);
const api = Common.EditorApi.get();
switch (action) {
case 'cut':
if (!api.Cut() && !LocalStorage.getBool("pe-hide-copy-cut-paste-warning")) {
this.showCopyCutPasteModal();
}
break;
case 'copy':
if (!api.Copy() && !LocalStorage.getBool("pe-hide-copy-cut-paste-warning")) {
this.showCopyCutPasteModal();
}
break;
case 'paste':
if (!api.Paste() && !LocalStorage.getBool("pe-hide-copy-cut-paste-warning")) {
this.showCopyCutPasteModal();
}
break;
case 'addcomment':
Common.Notifications.trigger('addcomment');
break;
case 'viewcomment':
Common.Notifications.trigger('viewcomment');
break;
case 'delete':
api.asc_Remove();
break;
case 'edit':
setTimeout(() => {
this.props.openOptions('edit');
}, 0);
break;
case 'addlink':
setTimeout(() => {
this.props.openOptions('add', 'link');
}, 400)
break;
case 'openlink':
const stack = Common.EditorApi.get().getSelectedElements();
let value;
stack.forEach((item) => {
if (item.get_ObjectType() == Asc.c_oAscTypeSelectElement.Hyperlink) {
value = item.get_ObjectValue().get_Value();
}
});
value && this.openLink(value);
break;
}
console.log("click context menu item: " + action);
}
showCopyCutPasteModal() {
const { t } = this.props;
const _t = t("ContextMenu", { returnObjects: true });
f7.dialog.create({
title: _t.textCopyCutPasteActions,
text: _t.errorCopyCutPaste,
content: `<div class="checkbox-in-modal">
<label class="checkbox">
<input type="checkbox" name="checkbox-show" />
<i class="icon-checkbox"></i>
</label>
<span class="right-text">${_t.textDoNotShowAgain}</span>
</div>`,
buttons: [{
text: 'OK',
onClick: () => {
const dontShow = $$('input[name="checkbox-show"]').prop('checked');
if (dontShow) LocalStorage.setItem("de-hide-copy-cut-paste-warning", 1);
}
}]
}).open();
}
openLink(url) {
const api = Common.EditorApi.get();
if (api.asc_getUrlType(url) > 0) {
const newDocumentPage = window.open(url, '_blank');
if (newDocumentPage) {
newDocumentPage.focus();
}
} else {
api.asc_GoToInternalHyperlink(url);
}
}
onDocumentReady() {
super.onDocumentReady();
const api = Common.EditorApi.get();
api.asc_registerCallback('asc_onShowComment', this.onApiShowComment);
api.asc_registerCallback('asc_onHideComment', this.onApiHideComment);
}
initMenuItems() {
if ( !Common.EditorApi ) return [];
const { t } = this.props;
const _t = t("ContextMenu", { returnObjects: true });
const { isEdit, canViewComments, canReview, isDisconnected } = this.props;
const api = Common.EditorApi.get();
const stack = api.getSelectedElements();
const canCopy = api.can_CopyCut();
let itemsIcon = [],
itemsText = [];
let isText = false,
isTable = false,
isImage = false,
isChart = false,
isShape = false,
isLink = false,
isSlide = false,
isObject = false;
stack.forEach(item => {
const objectType = item.get_ObjectType(),
objectValue = item.get_ObjectValue();
if (objectType == Asc.c_oAscTypeSelectElement.Paragraph) {
isText = true;
} else if (objectType == Asc.c_oAscTypeSelectElement.Image) {
isImage = true;
} else if (objectType == Asc.c_oAscTypeSelectElement.Chart) {
isChart = true;
} else if (objectType == Asc.c_oAscTypeSelectElement.Shape) {
isShape = true;
} else if (objectType == Asc.c_oAscTypeSelectElement.Table) {
isTable = true;
} else if (objectType == Asc.c_oAscTypeSelectElement.Hyperlink) {
isLink = true;
} else if (objectType == Asc.c_oAscTypeSelectElement.Slide) {
isSlide = true;
}
});
isObject = isText || isImage || isChart || isShape || isTable;
if (canCopy && isObject) {
itemsIcon.push({
event: 'copy',
icon: 'icon-copy'
});
}
if (canViewComments && this.isComments && !isEdit) {
itemsText.push({
caption: _t.menuViewComment,
event: 'viewcomment'
});
}
if ( stack.length > 0 ) {
let topObject = stack[stack.length - 1],
topObjectType = topObject.get_ObjectType(),
topObjectValue = topObject.get_ObjectValue(),
objectLocked = typeof topObjectValue.get_Locked === 'function' ? topObjectValue.get_Locked() : false;
!objectLocked && (objectLocked = typeof topObjectValue.get_LockDelete === 'function' ? topObjectValue.get_LockDelete() : false);
const swapItems = function(items, indexBefore, indexAfter) {
items[indexAfter] = items.splice(indexBefore, 1, items[indexAfter])[0];
};
if (!objectLocked && isEdit && !isDisconnected) {
if (canCopy && isObject) {
itemsIcon.push({
event: 'cut',
icon: 'icon-cut'
});
// Swap 'Copy' and 'Cut'
swapItems(itemsIcon, 0, 1);
}
itemsIcon.push({
event: 'paste',
icon: 'icon-paste'
});
if (isObject)
itemsText.push({
caption: _t.menuDelete,
event: 'delete'
});
itemsText.push({
caption: _t.menuEdit,
event: 'edit'
});
if (!isLink && api.can_AddHyperlink() !== false) {
itemsText.push({
caption: _t.menuAddLink,
event: 'addlink'
});
}
if (this.isComments && canViewComments) {
itemsText.push({
caption: _t.menuViewComment,
event: 'viewcomment'
});
}
var hideAddComment = (isText && isChart) || api.can_AddQuotedComment() === false || !canViewComments;
if (!hideAddComment) {
itemsText.push({
caption: _t.menuAddComment,
event: 'addcomment'
});
}
}
}
if (isLink) {
itemsText.push({
caption: _t.menuOpenLink,
event: 'openlink'
});
}
if ( Device.phone && itemsText.length > 2 ) {
this.extraItems = itemsText.splice(2,itemsText.length, {
caption: _t.menuMore,
event: 'showActionSheet'
});
}
return itemsIcon.concat(itemsText);
// return [{
// caption: 'Edit',
// event: 'edit'
// }, {
// caption: 'View',
// event: 'view'
// }, {
// icon: 'icon-paste',
// event: 'review'
// }];
}
initExtraItems () {
return (this.extraItems && this.extraItems.length > 0 ? this.extraItems : []);
}
}
const _ContextMenu = withTranslation()(ContextMenu);
_ContextMenu.closeContextMenu = ContextMenu.closeContextMenu;
export { _ContextMenu as default };

View file

@ -1,9 +1,15 @@
import React, { Component } from 'react'
import React, { Component, Fragment } from 'react'
import { inject } from "mobx-react";
import { f7 } from "framework7-react";
import { withTranslation } from 'react-i18next';
import CollaborationController from '../../../../common/mobile/lib/controller/collaboration/Collaboration.jsx'
import CollaborationController from '../../../../common/mobile/lib/controller/collaboration/Collaboration.jsx';
import {
CommentsController,
AddCommentController,
EditCommentController,
ViewCommentsController
} from "../../../../common/mobile/lib/controller/collaboration/Comments";
@inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings", "storeSlideSettings", "storeTextSettings", "storeTableSettings", "storeChartSettings", "storeLinkSettings")
class MainController extends Component {
@ -334,6 +340,8 @@ class MainController extends Component {
Common.Gateway.documentReady();
f7.emit('resize');
Common.Notifications.trigger('document:ready');
}
_onOpenDocumentProgress(progress) {
@ -346,7 +354,15 @@ class MainController extends Component {
}
render() {
return <CollaborationController />
return (
<Fragment>
<CollaborationController />
<CommentsController />
<AddCommentController />
<EditCommentController />
<ViewCommentsController />
</Fragment>
)
}
componentDidMount() {

View file

@ -102,6 +102,7 @@ class AddLinkController extends Component {
return (
<PageLink onInsertLink={this.onInsertLink}
getTextDisplay={this.getTextDisplay}
noNavbar={this.props.noNavbar}
/>
)
}

View file

@ -88,10 +88,38 @@ class AddOtherController extends Component {
});
}
hideAddComment () {
const api = Common.EditorApi.get();
const stack = api.getSelectedElements();
let isText = false,
isChart = false;
stack.forEach((item) => {
const objectType = item.get_ObjectType();
if (objectType === Asc.c_oAscTypeSelectElement.Paragraph) {
isText = true;
} else if (objectType === Asc.c_oAscTypeSelectElement.Chart) {
isChart = true;
}
});
if (stack.length > 0) {
const topObject = stack[stack.length - 1];
const topObjectValue = topObject.get_ObjectValue();
let objectLocked = typeof topObjectValue.get_Locked === 'function' ? topObjectValue.get_Locked() : false;
!objectLocked && (objectLocked = typeof topObjectValue.get_LockDelete === 'function' ? topObjectValue.get_LockDelete() : false);
if (!objectLocked) {
return ((isText && isChart) || api.can_AddQuotedComment() === false);
}
}
return true;
}
render () {
return (
<AddOther onStyleClick={this.onStyleClick}
<AddOther closeModal={this.closeModal}
onStyleClick={this.onStyleClick}
initStyleTable={this.initStyleTable}
hideAddComment={this.hideAddComment}
/>
)
}

View file

@ -11,6 +11,8 @@
@import '../../../../common/mobile/resources/less/dataview.less';
@import '../../../../common/mobile/resources/less/about.less';
@import '../../../../common/mobile/resources/less/search.less';
@import '../../../../common/mobile/resources/less/contextmenu.less';
@import '../../../../common/mobile/resources/less/comments.less';
@import './app-material.less';
@import './app-ios.less';
@import './icons-ios.less';

View file

@ -7,6 +7,7 @@ import Settings from '../view/settings/Settings';
import CollaborationView from '../../../../common/mobile/lib/view/collaboration/Collaboration.jsx';
import { Device } from '../../../../common/mobile/utils/device';
import { Search, SearchSettings } from '../controller/Search';
import ContextMenu from '../controller/ContextMenu';
export default class MainPage extends Component {
constructor(props) {
@ -19,12 +20,17 @@ export default class MainPage extends Component {
};
}
handleClickToOpenOptions = opts => {
handleClickToOpenOptions = (opts, showOpts) => {
ContextMenu.closeContextMenu();
this.setState(state => {
if ( opts == 'edit' )
return {editOptionsVisible: true};
else if ( opts == 'add' )
return {addOptionsVisible: true};
return {
addOptionsVisible: true,
addShowOptions: showOpts
};
else if ( opts == 'settings' )
return {settingsVisible: true};
else if ( opts == 'coauth' )
@ -77,7 +83,7 @@ export default class MainPage extends Component {
}
{
!this.state.addOptionsVisible ? null :
<AddOptions onclosed={this.handleOptionsViewClosed.bind(this, 'add')} />
<AddOptions onclosed={this.handleOptionsViewClosed.bind(this, 'add')} showOptions={this.state.addShowOptions} />
}
{
!this.state.settingsVisible ? null :
@ -87,6 +93,7 @@ export default class MainPage extends Component {
!this.state.collaborationVisible ? null :
<CollaborationView onclosed={this.handleOptionsViewClosed.bind(this, 'coauth')} />
}
<ContextMenu openOptions={this.handleClickToOpenOptions.bind(this)} />
</Page>
)
}

View file

@ -16,6 +16,7 @@ import { storeLinkSettings } from "./linkSettings";
// import {storeParagraphSettings} from "./paragraphSettings";
// import {storeShapeSettings} from "./shapeSettings";
// import {storeImageSettings} from "./imageSettings";
import {storeComments} from "../../../../common/mobile/lib/store/comments";
export const stores = {
storeAppOptions: new storeAppOptions(),
@ -31,10 +32,11 @@ export const stores = {
storeShapeSettings: new storeShapeSettings(),
storeTableSettings: new storeTableSettings(),
storeChartSettings: new storeChartSettings(),
storeLinkSettings: new storeLinkSettings()
storeLinkSettings: new storeLinkSettings(),
// storeTextSettings: new storeTextSettings(),
// storeParagraphSettings: new storeParagraphSettings(),
// storeShapeSettings: new storeShapeSettings(),
// storeChartSettings: new storeChartSettings(),
storeComments: new storeComments()
};

View file

@ -1,5 +1,5 @@
import React, {Component, useEffect} from 'react';
import {View,Page,Navbar,NavRight,Link,Popup,Popover,Icon,Tabs,Tab} from 'framework7-react';
import {View,Page,Navbar,NavRight, NavTitle, Link,Popup,Popover,Icon,Tabs,Tab} from 'framework7-react';
import { useTranslation } from 'react-i18next';
import {f7} from 'framework7-react';
import { observer, inject } from "mobx-react";
@ -43,13 +43,16 @@ const AddLayoutNavbar = ({ tabs, inPopover }) => {
const isAndroid = Device.android;
return (
<Navbar>
<div className='tab-buttons tabbar'>
{tabs.map((item, index) =>
<Link key={"pe-link-" + item.id} tabLink={"#" + item.id} tabLinkActive={index === 0}>
<Icon slot="media" icon={item.icon}></Icon>
</Link>)}
{isAndroid && <span className='tab-link-highlight' style={{width: 100 / tabs.lenght + '%'}}></span>}
</div>
{tabs.length > 1 ?
<div className='tab-buttons tabbar'>
{tabs.map((item, index) =>
<Link key={"pe-link-" + item.id} tabLink={"#" + item.id} tabLinkActive={index === 0}>
<Icon slot="media" icon={item.icon}></Icon>
</Link>)}
{isAndroid && <span className='tab-link-highlight' style={{width: 100 / tabs.lenght + '%'}}></span>}
</div> :
<NavTitle>{tabs[0].caption}</NavTitle>
}
{ !inPopover && <NavRight><Link icon='icon-expand-down' popupClose=".add-popup"></Link></NavRight> }
</Navbar>
)
@ -69,32 +72,42 @@ const AddLayoutContent = ({ tabs }) => {
const AddTabs = props => {
const { t } = useTranslation();
const _t = t('Add', {returnObjects: true});
const _t = t('View.Add', {returnObjects: true});
const showPanels = props.showPanels;
const tabs = [];
tabs.push({
caption: _t.textSlide,
id: 'add-slide',
icon: 'icon-add-slide',
component: <AddSlideController />
});
tabs.push({
caption: _t.textShape,
id: 'add-shape',
icon: 'icon-add-shape',
component: <AddShapeController />
});
tabs.push({
caption: _t.textImage,
id: 'add-image',
icon: 'icon-add-image',
component: <AddImageController />
});
tabs.push({
caption: _t.textOther,
id: 'add-other',
icon: 'icon-add-other',
component: <AddOtherController />
});
if (!showPanels) {
tabs.push({
caption: _t.textSlide,
id: 'add-slide',
icon: 'icon-add-slide',
component: <AddSlideController />
});
tabs.push({
caption: _t.textShape,
id: 'add-shape',
icon: 'icon-add-shape',
component: <AddShapeController/>
});
tabs.push({
caption: _t.textImage,
id: 'add-image',
icon: 'icon-add-image',
component: <AddImageController/>
});
tabs.push({
caption: _t.textOther,
id: 'add-other',
icon: 'icon-add-other',
component: <AddOtherController/>
});
}
if (showPanels && showPanels === 'link') {
tabs.push({
caption: _t.textAddLink,
id: 'add-link',
component: <AddLinkController noNavbar={true}/>
});
}
return (
<View style={props.style} stackPages={true} routes={routes}>
<Page pageContent={false}>
@ -119,10 +132,10 @@ class AddView extends Component {
return (
show_popover ?
<Popover id="add-popover" className="popover__titled" onPopoverClosed={() => this.props.onclosed()}>
<AddTabs inPopover={true} onOptionClick={this.onoptionclick} style={{height: '410px'}} />
<AddTabs inPopover={true} onOptionClick={this.onoptionclick} style={{height: '410px'}} showPanels={this.props.showPanels} />
</Popover> :
<Popup className="add-popup" onPopupClosed={() => this.props.onclosed()}>
<AddTabs onOptionClick={this.onoptionclick} />
<AddTabs onOptionClick={this.onoptionclick} showPanels={this.props.showPanels} />
</Popup>
)
}
@ -142,7 +155,7 @@ const Add = props => {
if ( props.onclosed )
props.onclosed();
};
return <AddView usePopover={!Device.phone} onclosed={onviewclosed} />
return <AddView usePopover={!Device.phone} onclosed={onviewclosed} showPanels={props.showOptions} />
};
export default Add;

View file

@ -103,7 +103,7 @@ const PageLink = props => {
return (
<Page>
<Navbar title={_t.textLink} backLink={_t.textBack}/>
{!props.noNavbar && <Navbar title={_t.textLink} backLink={_t.textBack}/>}
<List inlineLabels className='inputs-list'>
<ListItem link={'/add-link-type/'} title={_t.textLinkType} after={textType} routeProps={{
changeType: changeType,

View file

@ -33,6 +33,7 @@ const AddOther = props => {
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
const showInsertLink = props.storeLinkSettings.canAddLink && !props.storeFocusObjects.paragraphLocked;
const hideAddComment = props.hideAddComment();
return (
<List>
<ListItem title={_t.textTable} link={'/add-table/'} routeProps={{
@ -41,9 +42,12 @@ const AddOther = props => {
}}>
<Icon slot="media" icon="icon-add-table"></Icon>
</ListItem>
<ListItem title={_t.textComment}>
{!hideAddComment && <ListItem title={_t.textComment} onClick={() => {
props.closeModal();
Common.Notifications.trigger('addcomment');
}}>
<Icon slot="media" icon="icon-insert-comment"></Icon>
</ListItem>
</ListItem>}
{showInsertLink &&
<ListItem title={_t.textLink} link={'/add-link/'}>
<Icon slot="media" icon="icon-link"></Icon>

View file

@ -4,6 +4,8 @@ import ReactDOM from 'react-dom';
// Import Framework7
import Framework7 from 'framework7/lite-bundle';
import { Dom7 } from 'framework7';
window.$$ = Dom7;
// Import Framework7-React Plugin
import Framework7React from 'framework7-react';

View file

@ -18,17 +18,26 @@ const Statusbar = inject('sheets', 'storeAppOptions')(props => {
let isDisconnected = false;
useEffect(() => {
console.log("status bar did mount");
const on_api_created = api => {
api.asc_registerCallback('asc_onSheetsChanged', onApiSheetsChanged.bind(api));
};
const on_main_view_click = e => {
// f7.popover.close('.document-menu.modal-in');
};
Common.Notifications.on('api:disconnect', onApiDisconnect);
Common.Notifications.on('document:ready', onApiSheetsChanged);
Common.Notifications.on('engineCreated', api => {
api.asc_registerCallback('asc_onUpdateTabColor', onApiUpdateTabColor);
// api.asc_registerCallback('asc_onWorkbookLocked', onWorkbookLocked);
// api.asc_registerCallback('asc_onWorksheetLocked', onWorksheetLocked);
api.asc_registerCallback('asc_onSheetsChanged', onApiSheetsChanged);
api.asc_registerCallback('asc_onCoAuthoringDisconnect', onApiDisconnect);
});
Common.Notifications.on('engineCreated', on_api_created);
$$('.view-main').on('click', on_main_view_click);
return () => {
Common.Notifications.off('document:ready', onApiSheetsChanged);
Common.Notifications.off('engineCreated', on_api_created);
$$('.view-main').off('click', on_main_view_click);
};
}, []);
// const onWorkbookLocked = locked => {

View file

@ -4,7 +4,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const WorkboxPlugin = require('workbox-webpack-plugin');
@ -53,6 +53,7 @@ module.exports = {
minimizer: [new TerserPlugin({
sourceMap: true,
})],
moduleIds: 'named',
},
module: {
rules: [
@ -162,8 +163,8 @@ module.exports = {
}),
...(env === 'production' ? [
new OptimizeCSSPlugin({
cssProcessorOptions: {
new CssMinimizerPlugin({
processorOptions: {
safe: true,
map: { inline: false },
},
@ -172,7 +173,7 @@ module.exports = {
] : [
// Development only plugins
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
// new webpack.NamedModulesPlugin(),
]),
// new CleanWebpackPlugin(),
new HtmlWebpackPlugin({

View file

@ -25,14 +25,14 @@
],
"dependencies": {
"dom7": "^3.0.0",
"framework7": "^6.0.4",
"framework7": "^6.0.14",
"framework7-icons": "^3.0.1",
"framework7-react": "^6.0.4",
"framework7-react": "^6.0.14",
"i18next": "^19.8.4",
"i18next-fetch-backend": "^3.0.0",
"prop-types": "^15.7.2",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-i18next": "^11.8.5",
"swiper": "^6.4.8",
"template7": "^1.4.2"
@ -43,7 +43,7 @@
"@babel/plugin-proposal-decorators": "^7.12.12",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@babel/preset-env": "^7.13.12",
"@babel/preset-react": "^7.12.10",
"@babel/runtime": "^7.12.5",
"babel-loader": "^8.2.2",
@ -53,27 +53,24 @@
"cpy-cli": "^3.1.1",
"cross-env": "^7.0.3",
"css-loader": "^4.3.0",
"css-minimizer-webpack-plugin": "^1.3.0",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^4.5.1",
"html-webpack-plugin": "^5.3.1",
"less": "^3.13.1",
"less-loader": "^6.2.0",
"mini-css-extract-plugin": "^0.9.0",
"mini-css-extract-plugin": "^1.3.9",
"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",
"postcss-preset-env": "^6.7.0",
"react-redux": "^7.2.2",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"rimraf": "^3.0.2",
"style-loader": "^1.3.0",
"terser-webpack-plugin": "^3.1.0",
"url-loader": "^4.1.1",
"webpack": "^4.46.0",
"webpack-cli": "^3.3.12",
"webpack": "^5.26.3",
"webpack-cli": "^4.5.0",
"webpack-dev-server": "^3.11.2",
"workbox-webpack-plugin": "^5.1.4"
"workbox-webpack-plugin": "^6.1.2"
}
}