[DE mobile] Add navigation and correct a table of contents

This commit is contained in:
SergeyEzhin 2022-01-29 17:57:41 +04:00
parent 98ffebb52d
commit c90c0ac259
9 changed files with 232 additions and 32 deletions

View file

@ -640,7 +640,10 @@
"txtScheme6": "Concourse",
"txtScheme7": "Equity",
"txtScheme8": "Flow",
"txtScheme9": "Foundry"
"txtScheme9": "Foundry",
"textNavigation": "Navigation",
"textEmptyScreens": "There are no headings in the document. Apply a headings style to the text so that it appeas in the table of cotents.",
"textBeginningDocument": "Beginning of document"
},
"Toolbar": {
"dlgLeaveMsgText": "You have unsaved changes. Click 'Stay on this Page' to wait for autosave. Click 'Leave this Page' to discard all the unsaved changes.",

View file

@ -27,7 +27,6 @@ class EditTableContentsController extends Component {
const propsTableContents = api.asc_GetTableOfContentsPr();
propsTableContents.put_ShowPageNumbers(value);
propsTableContents.put_RightAlignTab(value);
api.asc_SetTableOfContentsPr(propsTableContents);
}
@ -80,6 +79,8 @@ class EditTableContentsController extends Component {
}
});
console.log(styles);
if(props) {
let start = props.get_OutlineStart(),
end = props.get_OutlineEnd(),
@ -190,43 +191,22 @@ class EditTableContentsController extends Component {
disableOutlines,
checkStyles
}
// this.stylesLevels.reset(styles);
// if (checkStyles) {
// this._forceUpdateOutlineLevels = true;
// this.radioStyles.setValue(true);
// this.stylesList.scroller.update({alwaysVisibleY: true});
// var rec = this.stylesLevels.findWhere({checked: true});
// if (rec)
// this.stylesList.scrollToRecord(rec);
// }
}
addStyles(styleName, value) {
const api = Common.EditorApi.get();
const propsTableContents = api.asc_GetTableOfContentsPr();
// propsTableContents.clear_Styles();
propsTableContents.add_Style(styleName, value);
if (propsTableContents.get_StylesCount() > 0) {
propsTableContents.put_OutlineRange(-1, -1);
} else {
propsTableContents.put_OutlineRange(1, 9);
}
// if (propsTableContents.get_StylesCount() > 0)
// propsTableContents.put_OutlineRange(-1, -1);
// else
// propsTableContents.put_OutlineRange(1, 9);
// api.asc_SetTableOfContentsPr(propsTableContents);
}
changeCaption(value) {
const api = Common.EditorApi.get();
const propsTableContents = api.asc_GetTableOfContentsPr();
if(record) {
propsTableContents.put_Caption(value);
properties.clear_Styles();
api.asc_SetTableOfContentsPr(propsTableContents);
}
}
onTableContentsUpdate(type, currentTOC) {
const api = Common.EditorApi.get();
@ -259,7 +239,6 @@ class EditTableContentsController extends Component {
onLeader={this.onLeader}
onLevelsChange={this.onLevelsChange}
fillTOCProps={this.fillTOCProps}
changeCaption={this.changeCaption}
addStyles={this.addStyles}
/>
)

View file

@ -0,0 +1,35 @@
import React, { Component } from "react";
import Navigation from "../../view/settings/Navigation";
import { Device } from '../../../../../common/mobile/utils/device';
import { f7, Sheet } from 'framework7-react';
class NavigationController extends Component {
constructor(props) {
super(props);
}
closeModal() {
if (Device.phone) {
f7.sheet.close('.settings-popup', false);
} else {
f7.popover.close('#settings-popover');
}
}
onSelectItem(index) {
const api = Common.EditorApi.get();
const navigationObject = api.asc_ShowDocumentOutline();
if (navigationObject) {
navigationObject.goto(index);
}
};
render() {
return (
<Navigation onSelectItem={this.onSelectItem} />
);
}
}
export default NavigationController

View file

@ -163,4 +163,21 @@
padding: 0 16px;
}
// Navigation
.empty-screens {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 100%;
&__icon {
margin-bottom: 48px;
}
&__text {
margin: 0 32px;
text-align: center;
}
}

View file

@ -81,6 +81,16 @@
height: 22px;
.encoded-svg-mask('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-1 7 22 22" fill="@{brandColor}"><g><path d="M21,18.5c0-0.3-0.1-0.6-0.7-0.9l-2.6-1.2l2.6-1.2c0.6-0.3,0.7-0.6,0.7-0.9c0-0.3-0.1-0.6-0.7-0.9l-8.9-4.1c-0.7-0.4-1.9-0.4-2.8,0l-8.9,4.1C-0.9,13.8-1,14.1-1,14.3s0.1,0.6,0.7,0.9l2.6,1.2l-2.6,1.2C-0.9,18-1,18.4-1,18.5c0,0.2,0.1,0.6,0.7,0.9l2.5,1.2l-2.5,1.2C-0.9,22.1-1,22.5-1,22.7c0,0.3,0.1,0.6,0.7,0.9l8.9,4.1c0.5,0.2,0.8,0.3,1.4,0.3s1-0.1,1.4-0.3l8.9-4.1c0.6-0.4,0.7-0.6,0.7-0.9c0-0.3-0.1-0.6-0.7-0.9l-2.5-1.2l2.5-1.2C20.9,19.2,21,18.8,21,18.5z M-0.2,14.3L-0.2,14.3c0,0,0.1-0.1,0.3-0.2L9,10c0.6-0.3,1.5-0.3,2,0l8.9,4.1c0.2,0.1,0.3,0.2,0.3,0.2l0,0c0,0-0.1,0.1-0.3,0.2L11,18.6c-0.6,0.3-1.5,0.3-2,0l-8.9-4.1C-0.1,14.4-0.2,14.3-0.2,14.3z M20.2,22.7L20.2,22.7c0,0-0.1,0.1-0.3,0.2L11,27.1c-0.6,0.3-1.5,0.3-2,0l-8.9-4.1c-0.2-0.1-0.3-0.2-0.3-0.2l0,0c0,0,0.1-0.1,0.3-0.2l3-1.5l5.5,2.6c0.7,0.4,1.9,0.4,2.8,0l5.5-2.6l3,1.5C20.1,22.7,20.2,22.7,20.2,22.7z M19.9,18.7L11,22.8c-0.6,0.3-1.5,0.3-2,0l-8.9-4.1c-0.2-0.1-0.3-0.2-0.3-0.2l0,0c0,0,0.1-0.1,0.3-0.2l3-1.5l5.5,2.6c0.7,0.4,1.9,0.4,2.8,0l5.5-2.6l3,1.5c0.2,0.1,0.3,0.2,0.3,0.2l0,0C20.2,18.5,20.1,18.6,19.9,18.7z"/></g></svg>');
}
&.icon-navigation {
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 d="M16 4H2V5H16V4Z" fill="@{brandColor}"/><path d="M19 9H5V10H19V9Z" fill="@{brandColor}"/><path d="M23 14V15H9V14H23Z" fill="@{brandColor}" /><path d="M16 20V19H2V20H16Z" fill="@{brandColor}"/></svg>')
}
&.icon-empty-screens {
width: 200px;
height: 200px;
.encoded-svg-background('<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0_876_40308)"><path d="M176.406 41.5727V47.1081M179.247 44.3397H173.566M193.447 82.6943V86.6484M195.477 84.6716H191.418M149.804 13.5V21.4068M153.861 17.4542H145.746M43.3426 37.0267V43.3521M46.5888 40.1895H40.0967M33.7747 50.4702V55.2143M36.2084 52.843H31.3394M15.1078 89.0626V92.2253M16.7309 90.644H13.4849M4.55885 97.762V105.669M8.6156 101.716H0.500488" stroke="#3C3C43" stroke-opacity="0.3" stroke-width="2" stroke-miterlimit="10" stroke-linecap="round"/><rect x="4" y="188" width="4" height="2" rx="1" fill="#3C3C43" fill-opacity="0.3"/><rect x="10" y="188" width="12" height="2" rx="1" fill="#3C3C43" fill-opacity="0.3"/><rect x="183" y="188" width="10" height="2" rx="1" fill="#3C3C43" fill-opacity="0.3"/><rect x="196" y="188" width="10" height="2" rx="1" fill="#3C3C43" fill-opacity="0.3"/><rect x="26" y="188" width="152" height="2" rx="1" fill="#3C3C43" fill-opacity="0.3"/><rect x="68" y="71" width="64" height="4" fill="#3C3C43" fill-opacity="0.3"/><rect x="68" y="160" width="64" height="4" fill="#3C3C43" fill-opacity="0.3"/><circle cx="100" cy="174" r="6.5" stroke="#3C3C43" stroke-opacity="0.3" stroke-width="3"/><rect x="88" y="64" width="14" height="3" rx="1.5" fill="#3C3C43" fill-opacity="0.3"/><rect x="104" y="64" width="8" height="3" rx="1.5" fill="#3C3C43" fill-opacity="0.3"/><path d="M77 95.5C77 94.6716 77.6716 94 78.5 94H115.5C116.328 94 117 94.6716 117 95.5C117 96.3284 116.328 97 115.5 97H78.5C77.6716 97 77 96.3284 77 95.5Z" fill="#3C3C43" fill-opacity="0.3"/><path d="M77 105.5C77 104.672 77.6716 104 78.5 104H99.5C100.328 104 101 104.672 101 105.5C101 106.328 100.328 107 99.5 107H78.5C77.6716 107 77 106.328 77 105.5Z" fill="#3C3C43" fill-opacity="0.3"/><path d="M77 115.5C77 114.672 77.6716 114 78.5 114H115.5C116.328 114 117 114.672 117 115.5C117 116.328 116.328 117 115.5 117H78.5C77.6716 117 77 116.328 77 115.5Z" fill="#3C3C43" fill-opacity="0.3"/><path d="M77 125.5C77 124.672 77.6716 124 78.5 124H107.5C108.328 124 109 124.672 109 125.5C109 126.328 108.328 127 107.5 127H78.5C77.6716 127 77 126.328 77 125.5Z" fill="#3C3C43" fill-opacity="0.3"/><circle cx="121.5" cy="95.5" r="1.5" fill="#3C3C43" fill-opacity="0.3"/><circle cx="121.5" cy="105.5" r="1.5" fill="#3C3C43" fill-opacity="0.3"/><circle cx="121.5" cy="115.5" r="1.5" fill="#3C3C43" fill-opacity="0.3"/><circle cx="121.5" cy="125.5" r="1.5" fill="#3C3C43" fill-opacity="0.3"/><rect x="66" y="58" width="68" height="128" rx="8" stroke="#3C3C43" stroke-opacity="0.3" stroke-width="4"/></g><defs><clipPath id="clip0_876_40308"><rect width="200" height="200" fill="white"/></clipPath></defs></svg>')
}
// Download

View file

@ -141,6 +141,11 @@
height: 24px;
.encoded-svg-mask('<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 20 13" fill="@{brandColor}"><path fill-rule="evenodd" clip-rule="evenodd" d="M17 0H0V1H17V0ZM11.9 4H0V5H11.9V4ZM0 8H17V9H0V8ZM15 12H0V13H15V12Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M20 0H19V1H20V0ZM20 4H19V5H20V4ZM19 8H20V9H19V8ZM20 12H19V13H20V12Z"/></svg>');
}
&.icon-navigation {
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 d="M16 4H2V5H16V4Z" fill="@{brandColor}"/><path d="M19 9H5V10H19V9Z" fill="@{brandColor}"/><path d="M23 14V15H9V14H23Z" fill="@{brandColor}" /><path d="M16 20V19H2V20H16Z" fill="@{brandColor}"/></svg>')
}
// Download

View file

@ -9,7 +9,7 @@ const EditTableContents = props => {
const _t = t('Edit', {returnObjects: true});
const api = Common.EditorApi.get();
const propsTableContents = api.asc_GetTableOfContentsPr();
const count = propsTableContents.get_StylesCount();
const stylesCount = propsTableContents.get_StylesCount();
console.log(propsTableContents);
const [type, setType] = useState(0);
const [styleValue, setStyleValue] = useState(propsTableContents.get_StylesType());
@ -103,7 +103,7 @@ const EditTableContents = props => {
setLeaderValue
}}></ListItem>
}
<ListItem title={t('Edit.textStructure')} link="/edit-structure-table-contents/" after={count ? t('Edit.textStyles') : t('Edit.textLevels')} routeProps={{
<ListItem title={t('Edit.textStructure')} link="/edit-structure-table-contents/" after={stylesCount ? t('Edit.textStyles') : t('Edit.textLevels')} routeProps={{
onLevelsChange: props.onLevelsChange,
fillTOCProps: props.fillTOCProps,
addStyles: props.addStyles

View file

@ -0,0 +1,140 @@
import React, { useState, useEffect } from "react";
import { Device } from '../../../../../common/mobile/utils/device';
import {f7, View, List, ListItem, Icon, Row, Button, Page, Navbar, NavRight, Segmented, BlockTitle, Link, ListButton, Toggle, Actions, ActionsButton, ActionsGroup, Sheet} from 'framework7-react';
import { useTranslation } from 'react-i18next';
const Navigation = props => {
const { t } = useTranslation();
const _t = t('Settings', {returnObjects: true});
const android = Device.android;
const api = Common.EditorApi.get();
const navigationObject = api.asc_ShowDocumentOutline();
const count = navigationObject.get_ElementsCount();
const [currentPosition, setCurrentPosition] = useState(navigationObject.get_CurrentPosition());
const arrHeaders = [];
const updateNavigation = () => {
if (!navigationObject) return;
let prevLevel = -1,
headerLevel = -1,
firstHeader = !navigationObject.isFirstItemNotHeader();
for (let i = 0; i < count; i++) {
let level = navigationObject.get_Level(i),
hasParent = true;
if (level > prevLevel && i > 0)
arrHeaders[i - 1]['hasSubItems'] = true;
if (headerLevel < 0 || level <= headerLevel) {
if (i > 0 || firstHeader)
headerLevel = level;
hasParent = false;
}
arrHeaders.push({
name: navigationObject.get_Text(i),
level: level,
index: i,
hasParent: hasParent,
isEmptyItem: navigationObject.isEmptyItem(i)
});
prevLevel = level;
}
if (count > 0 && !firstHeader) {
arrHeaders[0]['hasSubItems'] = false;
arrHeaders[0]['isNotHeader'] = true;
arrHeaders[0]['name'] = t('Settings.textBeginningDocument');
}
}
updateNavigation();
// console.log(navigationObject);
return (
<Page>
<Navbar title={t('Settings.textNavigation')} backLink={_t.textBack} />
{!arrHeaders.length
?
<div className="empty-screens">
{!android &&
<div className="empty-screens__icon">
<Icon slot="media" icon="icon-empty-screens"></Icon>
</div>
}
<p className="empty-screens__text">{t('Settings.textEmptyScreens')}</p>
</div>
:
<List>
{arrHeaders.map((header, index) => {
return (
<ListItem radio key={index} title={header.name} checked={header.index === currentPosition} style={{paddingLeft: header.level * 16}} onClick={() => {
setCurrentPosition(header.index);
props.onSelectItem(header.index);
}}></ListItem>
)
})}
</List>
}
</Page>
)
}
const NavigationSheet = () => {
useEffect(() => {
f7.sheet.open('#view-navigation-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) => {
const touchObj = event.changedTouches[0];
const swipeEnd = parseInt(touchObj.clientY);
const dist = swipeEnd - stateStartY;
if (isNeedClose) {
closeCurComments();
} else if (stateHeight === '90%' && dist > 20) {
setHeight('45%');
}
};
return (
<Sheet id='view-navigation-sheet' style={{height: `${stateHeight}`, opacity: `${stateOpacity}`}}>
<div id='swipe-handler' className='swipe-container' onTouchStart={handleTouchStart} onTouchMove={handleTouchMove} onTouchEnd={handleTouchEnd}>
<Icon icon='icon-swipe' />
</div>
<Navigation />
</Sheet>
)
};
export default Navigation;

View file

@ -12,6 +12,7 @@ import ApplicationSettingsController from "../../controller/settings/Application
import { DocumentFormats, DocumentMargins, DocumentColorSchemes } from "./DocumentSettings";
import { MacrosSettings } from "./ApplicationSettings";
import About from '../../../../../common/mobile/lib/view/About';
import NavigationController from '../../controller/settings/Navigation';
const routes = [
{
@ -53,6 +54,13 @@ const routes = [
{
path: '/about/',
component: About
},
// Navigation
{
path: '/navigation/',
component: NavigationController
}
];
@ -121,6 +129,9 @@ const SettingsList = inject("storeAppOptions", "storeReview")(observer(props =>
<Icon slot="media" icon="icon-search"></Icon>
</ListItem>
}
<ListItem title={t('Settings.textNavigation')} link="#" onClick={onoptionclick.bind(this, "/navigation/")}>
<Icon slot="media" icon="icon-navigation"></Icon>
</ListItem>
{window.matchMedia("(max-width: 359px)").matches ?
<ListItem title={_t.textCollaboration} link="#" onClick={onOpenCollaboration} className='no-indicator'>
<Icon slot="media" icon="icon-collaboration"></Icon>