[PE mobile] Corrected conflict

This commit is contained in:
SergeyEzhin 2021-01-29 11:57:14 +03:00
commit 2c6c3c3a71
41 changed files with 1610 additions and 294 deletions

View file

@ -0,0 +1,13 @@
import React from 'react';
import SearchView, {SearchSettingsView} from '../view/Search'
const SearchController = props => {
const onSearchQuery = params => {
console.log('on search: ' + params);
};
return <SearchView onSearchQuery={onSearchQuery} />
};
export {SearchController, SearchView, SearchSettingsView};

View file

@ -0,0 +1,226 @@
import React, { Component } from 'react';
import { Searchbar, Popover, Popup, View, Page, List, ListItem, Navbar, NavRight, Link } from 'framework7-react';
import { Toggle } from 'framework7-react';
import { f7 } from 'framework7-react';
import { Dom7 } from 'framework7';
import { Device } from '../../../../common/mobile/utils/device';
import { observable } from "mobx";
import { observer } from "mobx-react";
const searchOptions = observable({
usereplace: false
});
const popoverStyle = {
height: '300px'
};
const SEARCH_BACKWARD = 'back';
const SEARCH_FORWARD = 'next';
class SearchSettingsView extends Component {
constructor(props) {
super(props);
this.state = {
useReplace: false,
caseSensitive: false,
markResults: false
};
}
onFindReplaceClick(action) {
searchOptions.usereplace = action == 'replace';
this.setState({
useReplace: searchOptions.usereplace
});
if (this.onReplaceChecked) {}
}
extraSearchOptions() {
}
render() {
const show_popover = true;
const navbar =
<Navbar title="Find and replace">
{!show_popover &&
<NavRight>
<Link popupClose=".search-settings-popup">Done</Link>
</NavRight>}
</Navbar>;
const extra = this.extraSearchOptions();
const content =
<View style={popoverStyle}>
<Page>
{navbar}
<List>
<ListItem radio title="Find" name="find-replace-checkbox" checked={!this.state.useReplace} onClick={e => this.onFindReplaceClick('find')} />
<ListItem radio title="Find and replace" name="find-replace-checkbox" checked={this.state.useReplace} onClick={e => this.onFindReplaceClick('replace')} />
</List>
{ extra }
</Page>
</View>;
return (
show_popover ?
<Popover id="idx-search-settings" className="popover__titled">{content}</Popover> :
<Popup id="idx-search-settings">{content}</Popup>
)
}
}
@observer
class SearchView extends Component {
constructor(props) {
super(props);
$$(document).on('page:init', (e, page) => {
if ( page.name == 'home' ) {
this.searchbar = f7.searchbar.create({
el: '.searchbar',
customSearch: true,
expandable: true,
backdrop: false,
on: {
search: (bar, curval, prevval) => {
},
enable: this.onSearchbarShow.bind(this, true),
disable: this.onSearchbarShow.bind(this, false)
}
});
// function iOSVersion() {
// var ua = navigator.userAgent;
// var m;
// return (m = /(iPad|iPhone|iphone).*?(OS |os |OS\_)(\d+((_|\.)\d)?((_|\.)\d)?)/.exec(ua)) ? parseFloat(m[3]) : 0;
// }
const $$ = Dom7;
const $editor = $$('#editor_sdk');
if (false /*iOSVersion() < 13*/) {
// $editor.single('mousedown touchstart', _.bind(me.onEditorTouchStart, me));
// $editor.single('mouseup touchend', _.bind(me.onEditorTouchEnd, me));
} else {
// $editor.single('pointerdown', this.onEditorTouchStart, me));
// $editor.single('pointerup', _.bind(me.onEditorTouchEnd, me));
}
$editor.on('pointerdown', this.onEditorTouchStart.bind(this));
$editor.on('pointerup', this.onEditorTouchEnd.bind(this));
}
});
this.onSettingsClick = this.onSettingsClick.bind(this);
this.onSearchClick = this.onSearchClick.bind(this);
}
componentDidMount(){
const $$ = Dom7;
this.$repalce = $$('#idx-replace-val');
}
onSettingsClick(e) {
if ( Device.phone ) {
// f7.popup.open('.settings-popup');
} else f7.popover.open('#idx-search-settings', '#idx-btn-search-settings');
}
searchParams() {
let params = {
find: this.searchbar.query
};
if ( searchOptions.usereplace )
params.replace = this.$replace.val();
return params;
}
onSearchClick(action) {
if ( this.searchbar && this.searchbar.query) {
if ( this.props.onSearchQuery ) {
let params = this.searchParams();
params.forward = action != SEARCH_BACKWARD;
this.props.onSearchQuery(params);
}
}
}
onSearchbarShow(isshowed, bar) {
if ( !isshowed ) {
this.$repalce.val('');
}
}
onEditorTouchStart(e) {
this.startPoint = this.pointerPosition(e);
}
onEditorTouchEnd(e) {
const endPoint = this.pointerPosition(e);
if ( this.searchbar.enabled ) {
const distance = (this.startPoint.x === undefined || this.startPoint.y === undefined) ? 0 :
Math.sqrt((endPoint.x -= this.startPoint.x) * endPoint.x + (endPoint.y -= this.startPoint.y) * endPoint.y);
if ( distance < 1 ) {
this.searchbar.disable();
}
}
}
pointerPosition(e) {
let out = {x:0, y:0};
if ( e.type == 'touchstart' || e.type == 'touchend' ) {
const touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
out.x = touch.pageX;
out.y = touch.pageY;
} else
if ( e.type == 'mousedown' || e.type == 'mouseup' ) {
out.x = e.pageX;
out.y = e.pageY;
}
return out;
}
render() {
const usereplace = searchOptions.usereplace;
const hidden = {display: "none"};
return (
<form className="searchbar">
<div className="searchbar-bg"></div>
<div className="searchbar-inner">
<div className="buttons-row">
<a id="idx-btn-search-settings" className="link icon-only" onClick={this.onSettingsClick}>
<i className="icon icon-settings" />
</a>
</div>
<div className="searchbar-input-wrap">
<input placeholder="Search" type="search" />
<i className="searchbar-icon" />
<span className="input-clear-button" />
</div>
<div className="searchbar-input-wrap" style={!usereplace ? hidden: null}>
<input placeholder="Replace" type="search" id="idx-replace-val" />
<i className="searchbar-icon" />
<span className="input-clear-button" />
</div>
<div className="buttons-row">
<a className="link icon-only prev" onClick={e => this.onSearchClick(SEARCH_BACKWARD)}>
<i className="icon icon-prev" />
</a>
<a className="link icon-only next" onClick={e => this.onSearchClick(SEARCH_FORWARD)}>
<i className="icon icon-next" />
</a>
</div>
</div>
</form>
)
}
}
export {SearchView as default, SearchView, SearchSettingsView};

View file

@ -153,14 +153,24 @@
} }
} }
.popover li:last-child { .popover {
.segmented a { li:last-child {
&:first-child { .segmented a {
border-radius: var(--f7-button-border-radius) 0 0 var(--f7-button-border-radius); &:first-child {
} border-radius: var(--f7-button-border-radius) 0 0 var(--f7-button-border-radius);
}
&:last-child { &:last-child {
border-radius: 0 var(--f7-button-border-radius) var(--f7-button-border-radius) 0; border-radius: 0 var(--f7-button-border-radius) var(--f7-button-border-radius) 0;
}
}
}
.page-content {
> .list {
&:last-child {
margin-bottom: 30px;
}
} }
} }
} }
@ -366,8 +376,8 @@
} }
} }
.dataview, #add-table, #add-shape { .dataview, #add-table, #add-shape, #add-slide {
&.page-content { &.page-content, .page-content {
background-color: @white; background-color: @white;
} }
} }

View file

@ -165,10 +165,10 @@
} }
} }
&.inputs-list { &.inputs-list {
.item-input { .item-input, .item-link {
.item-inner { .item-inner {
display: block; display: block;
.item-label { .item-title, .item-label {
width: 100%; width: 100%;
font-size: 12px; font-size: 12px;
} }

View file

@ -13,4 +13,8 @@
.hairline(bottom, @statusBarBorderColor); .hairline(bottom, @statusBarBorderColor);
} }
} }
.searchbar-input-wrap {
margin-right: 10px;
}
} }

View file

@ -0,0 +1,3 @@
@border-regular-control: #cbcbcb;
@text-normal: #000;

View file

@ -1,8 +1,75 @@
import React from 'react'; import React from 'react';
import SearchView, {SearchSettingsView} from '../view/Search' import { List, ListItem, Toggle } from 'framework7-react';
import { SearchController, SearchView, SearchSettingsView } from '../../../../common/mobile/lib/controller/Search';
import { f7 } from 'framework7-react';
const SearchController = props => {
return <SearchView /> class SearchSettings extends SearchSettingsView {
constructor(props) {
super(props);
this.onToggleMarkResults = this.onToggleMarkResults.bind(this);
}
onToggleMarkResults(checked) {
const api = Common.EditorApi.get();
api.asc_selectSearchingResults(checked);
}
extraSearchOptions() {
const anc_markup = super.extraSearchOptions();
const markup = <List>
<ListItem title="Case sensitive">
<Toggle slot="after" className="toggle-case-sensitive" />
</ListItem>
<ListItem title="Highlight results">
<Toggle slot="after" className="toggle-mark-results" defaultChecked onToggleChange={this.onToggleMarkResults} />
</ListItem>
</List>;
return {...anc_markup, ...markup};
}
}
class DESearchView extends SearchView {
searchParams() {
let params = super.searchParams();
const checkboxCaseSensitive = f7.toggle.get('.toggle-case-sensitive'),
checkboxMarkResults = f7.toggle.get('.toggle-mark-results');
const searchOptions = {
caseSensitive: checkboxCaseSensitive.checked,
highlight: checkboxMarkResults.checked
};
return {...params, ...searchOptions};
}
onSearchbarShow(isshowed, bar) {
super.onSearchbarShow(isshowed, bar);
const api = Common.EditorApi.get();
if ( isshowed ) {
const checkboxMarkResults = f7.toggle.get('.toggle-mark-results');
api.asc_selectSearchingResults(checkboxMarkResults.checked);
} else api.asc_selectSearchingResults(false);
}
}
const Search = props => {
const onSearchQuery = params => {
const api = Common.EditorApi.get();
if ( !params.replace ) {
if ( !api.asc_findText(params.find, params.forward, params.caseSensitive, params.highlight) ) {
f7.dialog.alert('there are no more results', e => {
});
}
}
};
return <DESearchView onSearchQuery={onSearchQuery} />
}; };
export {SearchController as Search, SearchSettingsView as SearchSettings}; export {Search, SearchSettings}

View file

@ -1,116 +0,0 @@
import React, { Component } from 'react';
import { Searchbar, Popover, Popup, View, Page, List, ListItem, Navbar, NavRight, Link } from 'framework7-react';
import { f7ready, f7 } from 'framework7-react';
import { Device } from '../../../../common/mobile/utils/device';
const popoverStyle = {
height: '300px'
};
class SearchSettingsView extends Component {
constructor(props) {
super(props);
this.state = {
useReplace: false,
caseSensitive: false,
markResults: false
};
}
onFindReplaceClick(action) {
this.setState({
useReplace: action == 'replace'
});
}
render() {
const show_popover = true;
const navbar =
<Navbar title="Find and replace">
{!show_popover &&
<NavRight>
<Link popupClose=".search-settings-popup">Done</Link>
</NavRight>}
</Navbar>;
const content =
<View style={popoverStyle}>
<Page>
{navbar}
<List>
<ListItem radio title="Find" name="find-replace-checkbox" checked={!this.state.useReplace} onClick={e => this.onFindReplaceClick('find')}></ListItem>
<ListItem radio title="Find and replace" name="find-replace-checkbox" checked={this.state.useReplace} onClick={e => this.onFindReplaceClick('replace')}></ListItem>
</List>
</Page>
</View>;
return (
show_popover ?
<Popover id="idx-search-settings" className="popover__titled">{content}</Popover> :
<Popup id="idx-search-settings">{content}</Popup>
)
}
}
class SearchView extends Component {
constructor(props) {
super(props);
$$(document).on('page:init', (e, page) => {
if ( page.name == 'home' ) {
f7.searchbar.create({
el: '.searchbar',
customSearch: true,
expandable: true,
backdrop: false,
on: {
search: (bar, curval, prevval) => {
console.log('on search results ' + curval);
}
}
});
}
});
this.onSettingsClick = this.onSettingsClick.bind(this);
}
componentDidMount(){
}
onSettingsClick(e) {
if ( Device.phone ) {
// f7.popup.open('.settings-popup');
} else f7.popover.open('#idx-search-settings', '#idx-btn-search-settings');
}
render() {
return (
<form className="searchbar">
<div className="searchbar-bg"></div>
<div className="searchbar-inner">
<div className="buttons-row">
<a id="idx-btn-search-settings" className="link icon-only" onClick={this.onSettingsClick}>
<i className="icon icon-settings" />
</a>
</div>
<div className="searchbar-input-wrap">
<input placeholder="Search" type="search" />
<i className="searchbar-icon" />
<span className="input-clear-button" />
</div>
<div className="buttons-row">
<a className="link icon-only prev disabled">
<i className="icon icon-prev" />
</a>
<a className="link icon-only next disabled">
<i className="icon icon-next" />
</a>
</div>
<span className="searchbar-disable-button">Cancel</span>
</div>
</form>
)
}
}
export {SearchView as default, SearchSettingsView};

View file

@ -1,116 +0,0 @@
import React, { Component } from 'react';
import { Searchbar, Popover, Popup, View, Page, List, ListItem, Navbar, NavRight, Link } from 'framework7-react';
import { f7ready, f7 } from 'framework7-react';
import { Device } from '../../../../common/mobile/utils/device';
const popoverStyle = {
height: '300px'
};
class SearchSettingsView extends Component {
constructor(props) {
super(props);
this.state = {
useReplace: false,
caseSensitive: false,
markResults: false
};
}
onFindReplaceClick(action) {
this.setState({
useReplace: action == 'replace'
});
}
render() {
const show_popover = true;
const navbar =
<Navbar title="Find and replace">
{!show_popover &&
<NavRight>
<Link popupClose=".search-settings-popup">Done</Link>
</NavRight>}
</Navbar>;
const content =
<View style={popoverStyle}>
<Page>
{navbar}
<List>
<ListItem radio title="Find" name="find-replace-checkbox" checked={!this.state.useReplace} onClick={e => this.onFindReplaceClick('find')}></ListItem>
<ListItem radio title="Find and replace" name="find-replace-checkbox" checked={this.state.useReplace} onClick={e => this.onFindReplaceClick('replace')}></ListItem>
</List>
</Page>
</View>;
return (
show_popover ?
<Popover id="idx-search-settings" className="popover__titled">{content}</Popover> :
<Popup id="idx-search-settings">{content}</Popup>
)
}
}
class SearchView extends Component {
constructor(props) {
super(props);
$$(document).on('page:init', (e, page) => {
if ( page.name == 'home' ) {
f7.searchbar.create({
el: '.searchbar',
customSearch: true,
expandable: true,
backdrop: false,
on: {
search: (bar, curval, prevval) => {
console.log('on search results ' + curval);
}
}
});
}
});
this.onSettingsClick = this.onSettingsClick.bind(this);
}
componentDidMount(){
}
onSettingsClick(e) {
if ( Device.phone ) {
// f7.popup.open('.settings-popup');
} else f7.popover.open('#idx-search-settings', '#idx-btn-search-settings');
}
render() {
return (
<form className="searchbar">
<div className="searchbar-bg"></div>
<div className="searchbar-inner">
<div className="buttons-row">
<a id="idx-btn-search-settings" className="link icon-only" onClick={this.onSettingsClick}>
<i className="icon icon-settings" />
</a>
</div>
<div className="searchbar-input-wrap">
<input placeholder="Search" type="search" />
<i className="searchbar-icon" />
<span className="input-clear-button" />
</div>
<div className="buttons-row">
<a className="link icon-only prev disabled">
<i className="icon icon-prev" />
</a>
<a className="link icon-only next disabled">
<i className="icon icon-next" />
</a>
</div>
<span className="searchbar-disable-button">Cancel</span>
</div>
</form>
)
}
}
export {SearchView as default, SearchSettingsView};

View file

@ -39,8 +39,7 @@ const PageApplicationSettings = props => {
onChange={() => changeMeasureSettings(2)}></ListItem> onChange={() => changeMeasureSettings(2)}></ListItem>
</List> </List>
<List> <List>
<ListItem> <ListItem title={_t.textSpellcheck}>
<span>{_t.textSpellcheck}</span>
<Toggle checked={isSpellChecking} <Toggle checked={isSpellChecking}
onChange={() => { onChange={() => {
store.changeSpellCheck(!isSpellChecking); store.changeSpellCheck(!isSpellChecking);
@ -50,8 +49,7 @@ const PageApplicationSettings = props => {
</ListItem> </ListItem>
</List> </List>
<List> <List>
<ListItem>{/*ToDo: if (DisplayMode == "final" || DisplayMode == "original") {disabled} */} <ListItem title={_t.textNoCharacters}>{/*ToDo: if (DisplayMode == "final" || DisplayMode == "original") {disabled} */}
<span>{_t.textNoCharacters}</span>
<Toggle checked={isNonprintingCharacters} <Toggle checked={isNonprintingCharacters}
onChange={() => { onChange={() => {
store.changeNoCharacters(!isNonprintingCharacters); store.changeNoCharacters(!isNonprintingCharacters);
@ -59,8 +57,7 @@ const PageApplicationSettings = props => {
}} }}
/> />
</ListItem> </ListItem>
<ListItem>{/*ToDo: if (DisplayMode == "final" || DisplayMode == "original") {disabled} */} <ListItem title={_t.textHiddenTableBorders}>{/*ToDo: if (DisplayMode == "final" || DisplayMode == "original") {disabled} */}
<span>{_t.textHiddenTableBorders}</span>
<Toggle checked={isHiddenTableBorders} <Toggle checked={isHiddenTableBorders}
onChange={() => { onChange={() => {
store.changeShowTableEmptyLine(!isHiddenTableBorders); store.changeShowTableEmptyLine(!isHiddenTableBorders);
@ -73,8 +70,7 @@ const PageApplicationSettings = props => {
} }
<BlockTitle>{_t.textCommentsDisplay}</BlockTitle> <BlockTitle>{_t.textCommentsDisplay}</BlockTitle>
<List> <List>
<ListItem> <ListItem title={_t.textComments}>
<span>{_t.textComments}</span>
<Toggle checked={isComments} <Toggle checked={isComments}
onChange={() => { onChange={() => {
store.changeDisplayComments(!isComments); store.changeDisplayComments(!isComments);
@ -82,8 +78,7 @@ const PageApplicationSettings = props => {
}} }}
/> />
</ListItem> </ListItem>
<ListItem> <ListItem title={_t.textResolvedComments}>
<span>{_t.textResolvedComments}</span>
<Toggle checked={isResolvedComments} disabled={!isComments} <Toggle checked={isResolvedComments} disabled={!isComments}
onChange={() => { onChange={() => {
store.changeDisplayResolved(!isResolvedComments); store.changeDisplayResolved(!isResolvedComments);

View file

@ -77,7 +77,37 @@
"textSlide": "Slide", "textSlide": "Slide",
"textShape": "Shape", "textShape": "Shape",
"textImage": "Image", "textImage": "Image",
"textOther": "Other" "textOther": "Other",
"textPictureFromLibrary": "Picture from Library",
"textPictureFromURL": "Picture from URL",
"textLinkSettings": "LinkSettings",
"textBack": "Back",
"textEmptyImgUrl": "You need to specify image URL.",
"txtNotUrl": "This field should be a URL in the format \"http://www.example.com\"",
"notcriticalErrorTitle": "Warning",
"textAddress": "Address",
"textImageURL": "Image URL",
"textInsertImage": "Insert Image",
"textTable": "Table",
"textComment": "Comment",
"textTableSize": "Table Size",
"textColumns": "Columns",
"textRows": "Rows",
"textCancel": "Cancel",
"textLink": "Link",
"textLinkType": "Link Type",
"textExternalLink": "External Link",
"textSlideInThisPresentation": "Slide in this Presentation",
"textLinkTo": "Link to",
"textNextSlide": "Next Slide",
"textPreviousSlide": "Previous Slide",
"textFirstSlide": "First Slide",
"textLastSlide": "Last Slide",
"textSlideNumber": "Slide Number",
"textDisplay": "Display",
"textDefault": "Selected text",
"textScreenTip": "Screen Tip",
"textInsert": "Insert"
}, },
"Edit": { "Edit": {
"textText": "Text", "textText": "Text",

View file

@ -5,7 +5,11 @@ import { f7 } from "framework7-react";
import { withTranslation } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import CollaborationController from '../../../../common/mobile/lib/controller/Collaboration.jsx' import CollaborationController from '../../../../common/mobile/lib/controller/Collaboration.jsx'
<<<<<<< HEAD
@inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings", "storeSlideSettings", "storeTextSettings", "storeTableSettings", "storeChartSettings") @inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings", "storeSlideSettings", "storeTextSettings", "storeTableSettings", "storeChartSettings")
=======
@inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings", "storeSlideSettings", "storeTextSettings", "storeTableSettings", "storeLinkSettings")
>>>>>>> feature/mobile-apps-on-reactjs
class MainController extends Component { class MainController extends Component {
constructor(props) { constructor(props) {
super(props) super(props)

View file

@ -0,0 +1,59 @@
import React, {Component} from 'react';
import { f7 } from 'framework7-react';
import {Device} from '../../../../../common/mobile/utils/device';
import { withTranslation} from 'react-i18next';
import {AddImage} from '../../view/add/AddImage';
class AddImageController extends Component {
constructor (props) {
super(props);
this.onInsertByFile = this.onInsertByFile.bind(this);
this.onInsertByUrl = this.onInsertByUrl.bind(this);
}
closeModal () {
if ( Device.phone ) {
f7.sheet.close('.add-popup', true);
} else {
f7.popover.close('#add-popover');
}
}
onInsertByFile () {
const api = Common.EditorApi.get();
api.asc_addImage();
this.closeModal();
}
onInsertByUrl (value) {
const { t } = this.props;
const _t = t("View.Add", { returnObjects: true });
const _value = value.replace(/ /g, '');
if (_value) {
if ((/((^https?)|(^ftp)):\/\/.+/i.test(_value))) {
this.closeModal();
const api = Common.EditorApi.get();
api.AddImageUrl(_value);
} else {
f7.dialog.alert(_t.txtNotUrl, _t.notcriticalErrorTitle);
}
} else {
f7.dialog.alert(_t.textEmptyImgUrl, _t.notcriticalErrorTitle);
}
}
render () {
return (
<AddImage onInsertByFile={this.onInsertByFile}
onInsertByUrl={this.onInsertByUrl}
/>
)
}
}
const AddImageWithTranslation = withTranslation()(AddImageController);
export {AddImageWithTranslation as AddImageController};

View file

@ -0,0 +1,112 @@
import React, {Component} from 'react';
import { f7 } from 'framework7-react';
import {Device} from '../../../../../common/mobile/utils/device';
import { withTranslation} from 'react-i18next';
import {PageLink} from '../../view/add/AddLink';
class AddLinkController extends Component {
constructor (props) {
super(props);
this.onInsertLink = this.onInsertLink.bind(this);
this.getTextDisplay = this.getTextDisplay.bind(this);
const api = Common.EditorApi.get();
this.textDisplay = api.can_AddHyperlink();
}
closeModal () {
if ( Device.phone ) {
f7.sheet.close('.add-popup', true);
} else {
f7.popover.close('#add-popover');
}
}
onInsertLink (type, linkInfo) {
const api = Common.EditorApi.get();
const { t } = this.props;
const _t = t("View.Add", { returnObjects: true });
const c_oHyperlinkType = {
InternalLink: 0,
WebLink: 1
};
const display = linkInfo.display;
const tip = linkInfo.tip;
const props = new Asc.CHyperlinkProperty();
let def_display = '';
if (type == c_oHyperlinkType.WebLink) {
let url = linkInfo.url;
const urltype = api.asc_getUrlType(url.trim());
const isEmail = (urltype == 2);
if (urltype < 1) {
f7.dialog.alert(_t.txtNotUrl, _t.notcriticalErrorTitle);
return;
}
url = url.replace(/^\s+|\s+$/g, '');
if (!/(((^https?)|(^ftp)):\/\/)|(^mailto:)/i.test(url))
url = (isEmail ? 'mailto:' : 'http://' ) + url;
url = url.replace(new RegExp("%20", 'g'), " ");
props.put_Value(url);
props.put_ToolTip(tip);
def_display = url;
} else {
let url = "ppaction://hlink";
let slidetip = '';
switch (linkInfo.linkTo) {
case 0:
url = url + "showjump?jump=nextslide";
slidetip = _t.textNextSlide;
break;
case 1:
url = url + "showjump?jump=previousslide";
slidetip = _t.textPrevSlide;
break;
case 2:
url = url + "showjump?jump=firstslide";
slidetip = _t.textFirstSlide;
break;
case 3:
url = url + "showjump?jump=lastslide";
slidetip = _t.textLastSlide;
break;
case 4:
url = url + "sldjumpslide" + linkInfo.numberTo;
slidetip = _t.textSlide + ' ' + (linkInfo.numberTo + 1);
break;
}
props.put_Value(url);
props.put_ToolTip(!tip ? slidetip : tip);
def_display = slidetip;
}
if (!linkInfo.displayDisabled) {
props.put_Text(!display ? def_display : display);
} else
props.put_Text(null);
api.add_Hyperlink(props);
this.closeModal();
}
getTextDisplay () {
return this.textDisplay;
}
render () {
return (
<PageLink onInsertLink={this.onInsertLink}
getTextDisplay={this.getTextDisplay}
/>
)
}
}
const AddLinkWithTranslation = withTranslation()(AddLinkController);
export {AddLinkWithTranslation as AddLinkController};

View file

@ -0,0 +1,102 @@
import React, {Component} from 'react';
import { f7 } from 'framework7-react';
import {Device} from '../../../../../common/mobile/utils/device';
import { withTranslation} from 'react-i18next';
import {AddOther} from '../../view/add/AddOther';
class AddOtherController extends Component {
constructor (props) {
super(props);
this.onStyleClick = this.onStyleClick.bind(this);
this.initStyleTable = this.initStyleTable.bind(this);
this.initTable = false;
}
closeModal () {
if ( Device.phone ) {
f7.sheet.close('.add-popup', true);
} else {
f7.popover.close('#add-popover');
}
}
initStyleTable () {
if (!this.initTable) {
const api = Common.EditorApi.get();
api.asc_GetDefaultTableStyles();
this.initTable = true;
}
}
onStyleClick (type) {
const api = Common.EditorApi.get();
this.closeModal();
const { t } = this.props;
const _t = t("View.Add", { returnObjects: true });
let picker;
const dialog = f7.dialog.create({
title: _t.textTableSize,
text: '',
content:
'<div class="content-block">' +
'<div class="row">' +
'<div class="col-50">' + _t.textColumns + '</div>' +
'<div class="col-50">' + _t.textRows + '</div>' +
'</div>' +
'<div id="picker-table-size"></div>' +
'</div>',
buttons: [
{
text: _t.textCancel
},
{
text: 'OK',
bold: true,
onClick: function () {
const size = picker.value;
api.put_Table(parseInt(size[0]), parseInt(size[1]), undefined, type.toString());
}
}
]
}).open();
dialog.on('opened', () => {
picker = f7.picker.create({
containerEl: document.getElementById('picker-table-size'),
cols: [
{
textAlign: 'center',
width: '100%',
values: [1,2,3,4,5,6,7,8,9,10]
},
{
textAlign: 'center',
width: '100%',
values: [1,2,3,4,5,6,7,8,9,10]
}
],
toolbar: false,
rotateEffect: true,
value: [3, 3]
});
});
}
render () {
return (
<AddOther onStyleClick={this.onStyleClick}
initStyleTable={this.initStyleTable}
/>
)
}
}
const AddOtherWithTranslation = withTranslation()(AddOtherController);
export {AddOtherWithTranslation as AddOtherController};

View file

@ -3,15 +3,31 @@ import { f7 } from 'framework7-react';
import {Device} from '../../../../../common/mobile/utils/device'; import {Device} from '../../../../../common/mobile/utils/device';
import {observer, inject} from "mobx-react"; import {observer, inject} from "mobx-react";
import { AddShape } from '../../view/add/AddShape'; import AddShape from '../../view/add/AddShape';
class AddShapeController extends Component { class AddShapeController extends Component {
constructor (props) { constructor (props) {
super(props); super(props);
this.onShapeClick = this.onShapeClick.bind(this);
} }
closeModal () {
if ( Device.phone ) {
f7.sheet.close('.add-popup', true);
} else {
f7.popover.close('#add-popover');
}
}
onShapeClick (type) {
const api = Common.EditorApi.get();
api.AddShapeOnCurrentPage(type);
this.closeModal();
}
render () { render () {
return ( return (
<AddShape <AddShape onShapeClick={this.onShapeClick}
/> />
) )
} }

View file

@ -3,15 +3,31 @@ import { f7 } from 'framework7-react';
import {Device} from '../../../../../common/mobile/utils/device'; import {Device} from '../../../../../common/mobile/utils/device';
import {observer, inject} from "mobx-react"; import {observer, inject} from "mobx-react";
import { AddSlide } from '../../view/add/AddSlide'; import AddSlide from '../../view/add/AddSlide';
class AddSlideController extends Component { class AddSlideController extends Component {
constructor (props) { constructor (props) {
super(props); super(props);
this.onSlideLayout = this.onSlideLayout.bind(this);
} }
closeModal () {
if ( Device.phone ) {
f7.sheet.close('.add-popup', true);
} else {
f7.popover.close('#add-popover');
}
}
onSlideLayout (type) {
const api = Common.EditorApi.get();
api.AddSlide(type);
this.closeModal();
}
render () { render () {
return ( return (
<AddSlide <AddSlide onSlideLayout={this.onSlideLayout}
/> />
) )
} }

View file

@ -83,6 +83,16 @@ export class storeFocusObjects {
} }
} }
@computed get paragraphLocked() {
let _paragraphLocked = false;
for (let object of this._focusObjects) {
if (Asc.c_oAscTypeSelectElement.Paragraph == object.get_ObjectType()) {
_paragraphLocked = object.get_ObjectValue().get_Locked();
}
}
return _paragraphLocked;
}
@computed get shapeObject() { @computed get shapeObject() {
const shapes = []; const shapes = [];
for (let object of this._focusObjects) { for (let object of this._focusObjects) {

View file

@ -0,0 +1,8 @@
import {action, observable, computed} from 'mobx';
export class storeLinkSettings {
@observable canAddLink;
@action canAddHyperlink (value) {
this.canAddLink = value;
}
}

View file

@ -41,6 +41,24 @@ export class storeSlideSettings {
@action addArrayLayouts(array) { @action addArrayLayouts(array) {
this.arrayLayouts = array; this.arrayLayouts = array;
} }
@computed get slideLayouts () {
const layouts = [];
const columns = 2;
let row = -1;
this.arrayLayouts.forEach((item, index)=>{
if (0 == index % columns) {
layouts.push([]);
row++
}
layouts[row].push({
type: item.getIndex(),
image: item.get_Image(),
width: item.get_Width(),
height: item.get_Height()
});
});
return layouts;
}
@action changeSlideLayoutIndex(index) { @action changeSlideLayoutIndex(index) {
this.slideLayoutIndex = index; this.slideLayoutIndex = index;

View file

@ -141,5 +141,4 @@ export class storeTableSettings {
border.put_Value(0); border.put_Value(0);
} }
} }
} }

View file

@ -7,11 +7,36 @@ import {Device} from '../../../../../common/mobile/utils/device';
import AddSlideController from "../../controller/add/AddSlide"; import AddSlideController from "../../controller/add/AddSlide";
import AddShapeController from "../../controller/add/AddShape"; import AddShapeController from "../../controller/add/AddShape";
//import AddImageController from "../../controller/add/AddImage"; import {AddImageController} from "../../controller/add/AddImage";
//import AddOtherController from "../../controller/add/AddOther"; import {PageImageLinkSettings} from "./AddImage";
import {AddOtherController} from "../../controller/add/AddOther";
import {PageAddTable} from "./AddOther";
import {AddLinkController} from "../../controller/add/AddLink";
import {PageTypeLink, PageLinkTo} from "./AddLink";
const routes = [ const routes = [
// Image
{
path: '/add-image-from-url/',
component: PageImageLinkSettings
},
// Other
{
path: '/add-table/',
component: PageAddTable
},
{
path: '/add-link/',
component: AddLinkController
},
{
path: '/add-link-type/',
component: PageTypeLink
},
{
path: '/add-link-to/',
component: PageLinkTo
}
]; ];
const AddLayoutNavbar = ({ tabs, inPopover }) => { const AddLayoutNavbar = ({ tabs, inPopover }) => {
@ -58,7 +83,7 @@ const AddTabs = props => {
icon: 'icon-add-shape', icon: 'icon-add-shape',
component: <AddShapeController /> component: <AddShapeController />
}); });
/*tabs.push({ tabs.push({
caption: _t.textImage, caption: _t.textImage,
id: 'add-image', id: 'add-image',
icon: 'icon-add-image', icon: 'icon-add-image',
@ -69,7 +94,7 @@ const AddTabs = props => {
id: 'add-other', id: 'add-other',
icon: 'icon-add-other', icon: 'icon-add-other',
component: <AddOtherController /> component: <AddOtherController />
});*/ });
return ( return (
<View style={props.style} stackPages={true} routes={routes}> <View style={props.style} stackPages={true} routes={routes}>
<Page pageContent={false}> <Page pageContent={false}>

View file

@ -0,0 +1,49 @@
import React, {useState} from 'react';
import {observer, inject} from "mobx-react";
import {List, ListItem, Page, Navbar, Icon, ListButton, ListInput, BlockTitle} from 'framework7-react';
import { useTranslation } from 'react-i18next';
const PageLinkSettings = props => {
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
const [stateValue, setValue] = useState('');
return (
<Page>
<Navbar title={_t.textLinkSettings} backLink={_t.textBack}></Navbar>
<BlockTitle>{_t.textAddress}</BlockTitle>
<List>
<ListInput
type='text'
placeholder={_t.textImageURL}
value={stateValue}
onChange={(event) => {setValue(event.target.value)}}
>
</ListInput>
</List>
<List>
<ListButton className={'button-fill button-raised' + (stateValue.length < 1 ? ' disabled' : '')}
title={_t.textInsertImage}
onClick={() => {props.onInsertByUrl(stateValue)}}></ListButton>
</List>
</Page>
)
};
const AddImage = props => {
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
return (
<List>
<ListItem title={_t.textPictureFromLibrary} onClick={() => {props.onInsertByFile()}}>
<Icon slot="media" icon="icon-image-library"></Icon>
</ListItem>
<ListItem title={_t.textPictureFromURL} link={'/add-image-from-url/'} routeProps={{
onInsertByUrl: props.onInsertByUrl
}}>
<Icon slot="media" icon="icon-link"></Icon>
</ListItem>
</List>
)
};
export {AddImage, PageLinkSettings as PageImageLinkSettings};

View file

@ -0,0 +1,154 @@
import React, {useState} from 'react';
import {observer, inject} from "mobx-react";
import {List, ListItem, Page, Navbar, Icon, ListButton, ListInput, Segmented, Button} from 'framework7-react';
import { useTranslation } from 'react-i18next';
import {Device} from "../../../../../common/mobile/utils/device";
const PageTypeLink = props => {
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
const [typeLink, setTypeLink] = useState(props.curType);
return (
<Page>
<Navbar title={_t.textLinkType} backLink={_t.textBack}/>
<List>
<ListItem title={_t.textExternalLink} radio checked={typeLink === 1} onClick={() => {setTypeLink(1); props.changeType(1);}}></ListItem>
<ListItem title={_t.textSlideInThisPresentation} radio checked={typeLink === 0} onClick={() => {setTypeLink(0); props.changeType(0);}}></ListItem>
</List>
</Page>
)
};
const PageLinkTo = props => {
const isAndroid = Device.android;
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
const [stateTypeTo, setTypeTo] = useState(props.curTo);
const changeTypeTo = (type) => {
setTypeTo(type);
props.changeTo(type);
};
const [stateNumberTo, setNumberTo] = useState(0);
const changeNumber = (curNumber, isDecrement) => {
setTypeTo(4);
let value;
if (isDecrement) {
value = curNumber - 1;
} else {
value = curNumber + 1;
}
setNumberTo(value);
props.changeTo(4, value);
};
return (
<Page>
<Navbar title={_t.textLinkTo} backLink={_t.textBack}/>
<List>
<ListItem title={_t.textNextSlide} radio checked={stateTypeTo === 0} onClick={() => {changeTypeTo(0)}}></ListItem>
<ListItem title={_t.textPreviousSlide} radio checked={stateTypeTo === 1} onClick={() => {changeTypeTo(1)}}></ListItem>
<ListItem title={_t.textFirstSlide} radio checked={stateTypeTo === 2} onClick={() => {changeTypeTo(2)}}></ListItem>
<ListItem title={_t.textLastSlide} radio checked={stateTypeTo === 3} onClick={() => {changeTypeTo(3)}}></ListItem>
<ListItem title={_t.textSlideNumber}>
{!isAndroid && <div slot='after-start'>{stateNumberTo + 1}</div>}
<div slot='after'>
<Segmented>
<Button outline className='decrement item-link' onClick={() => {changeNumber(stateNumberTo, true);}}>
{isAndroid ? <Icon icon="icon-expand-down"></Icon> : ' - '}
</Button>
{isAndroid && <label>{stateNumberTo + 1}</label>}
<Button outline className='increment item-link' onClick={() => {changeNumber(stateNumberTo, false);}}>
{isAndroid ? <Icon icon="icon-expand-up"></Icon> : ' + '}
</Button>
</Segmented>
</div>
</ListItem>
</List>
</Page>
)
};
const PageLink = props => {
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
const [typeLink, setTypeLink] = useState(1);
const textType = typeLink === 1 ? _t.textExternalLink : _t.textSlideInThisPresentation;
const changeType = (newType) => {
setTypeLink(newType);
};
const [link, setLink] = useState('');
const [linkTo, setLinkTo] = useState(0);
const [displayTo, setDisplayTo] = useState(_t.textNextSlide);
const [numberTo, setNumberTo] = useState(0);
const changeTo = (type, number) => {
setLinkTo(type);
switch (type) {
case 0 : setDisplayTo(_t.textNextSlide); break;
case 1 : setDisplayTo(_t.textPreviousSlide); break;
case 2 : setDisplayTo(_t.textFirstSlide); break;
case 3 : setDisplayTo(_t.textLastSlide); break;
case 4 : setDisplayTo(`${_t.textSlide} ${number + 1}`); setNumberTo(number); break;
}
};
const display = props.getTextDisplay();
const displayDisabled = display !== false && display === null;
const [stateDisplay, setDisplay] = useState(display !== false ? ((display !== null) ? display : _t.textDefault) : "");
const [screenTip, setScreenTip] = useState('');
return (
<Page>
<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,
curType: typeLink
}}/>
{typeLink === 1 ?
<ListInput label={_t.textLink}
type="text"
placeholder={_t.textLink}
value={link}
onChange={(event) => {setLink(event.target.value)}}
/> :
<ListItem link={'/add-link-to/'} title={_t.textLinkTo} after={displayTo} routeProps={{
changeTo: changeTo,
curTo: linkTo
}}/>
}
<ListInput label={_t.textDisplay}
type="text"
placeholder={_t.textDisplay}
value={stateDisplay}
disabled={displayDisabled}
onChange={(event) => {setDisplay(event.target.value)}}
/>
<ListInput label={_t.textScreenTip}
type="text"
placeholder={_t.textScreenTip}
value={screenTip}
onChange={(event) => {setScreenTip(event.target.value)}}
/>
</List>
<List>
<ListButton title={_t.textInsert}
className={`button-fill button-raised${typeLink === 1 && link.length < 1 && ' disabled'}`}
onClick={() => {
props.onInsertLink(typeLink, (typeLink === 1 ?
{url: link, display: stateDisplay, tip: screenTip, displayDisabled: displayDisabled } :
{linkTo: linkTo, numberTo: numberTo, display: stateDisplay, tip: screenTip, displayDisabled: displayDisabled}));
}}
/>
</List>
</Page>
)
};
export {PageLink,
PageLinkTo,
PageTypeLink}

View file

@ -0,0 +1,60 @@
import React, {useState} from 'react';
import {observer, inject} from "mobx-react";
import {List, ListItem, Page, Navbar, Icon, ListButton, ListInput, BlockTitle, Segmented, Button} from 'framework7-react';
import { useTranslation } from 'react-i18next';
import {Device} from "../../../../../common/mobile/utils/device";
const PageTable = props => {
props.initStyleTable();
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
const storeTableSettings = props.storeTableSettings;
const styles = storeTableSettings.styles;
return (
<Page id={'add-table'}>
<Navbar title={_t.textTable} backLink={_t.textBack}/>
<div className={'table-styles dataview'}>
<ul className="row">
{styles.map((style, index) => {
return (
<li key={index}
onClick={() => {props.onStyleClick(style.templateId)}}>
<img src={style.imageUrl}/>
</li>
)
})}
</ul>
</div>
</Page>
)
};
const AddOther = props => {
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
const showInsertLink = props.storeLinkSettings.canAddLink && !props.storeFocusObjects.paragraphLocked;
return (
<List>
<ListItem title={_t.textTable} link={'/add-table/'} routeProps={{
onStyleClick: props.onStyleClick,
initStyleTable: props.initStyleTable
}}>
<Icon slot="media" icon="icon-add-table"></Icon>
</ListItem>
<ListItem title={_t.textComment}>
<Icon slot="media" icon="icon-insert-comment"></Icon>
</ListItem>
{showInsertLink &&
<ListItem title={_t.textLink} link={'/add-link/'}>
<Icon slot="media" icon="icon-link"></Icon>
</ListItem>
}
</List>
)
};
const PageAddTable = inject("storeTableSettings")(observer(PageTable));
const AddOtherContainer = inject("storeFocusObjects", "storeLinkSettings")(observer(AddOther));
export {AddOtherContainer as AddOther,
PageAddTable};

View file

@ -5,11 +5,26 @@ import { useTranslation } from 'react-i18next';
import {Device} from '../../../../../common/mobile/utils/device'; import {Device} from '../../../../../common/mobile/utils/device';
const AddShape = props => { const AddShape = props => {
const shapes = props.storeShapeSettings.getStyleGroups();
return ( return (
<Fragment> <div className={'dataview shapes'}>
{shapes.map((row, indexRow) => {
</Fragment> return (
<ul className="row" key={'shape-row-' + indexRow}>
{row.map((shape, index) => {
return (
<li key={'shape-' + indexRow + '-' + index} onClick={() => {props.onShapeClick(shape.type)}}>
<div className="thumb"
style={{WebkitMaskImage: `url('resources/img/shapes/${shape.thumb}')`}}>
</div>
</li>
)
})}
</ul>
)
})}
</div>
) )
}; };
export {AddShape}; export default inject("storeShapeSettings")(observer(AddShape));

View file

@ -5,11 +5,24 @@ import { useTranslation } from 'react-i18next';
import {Device} from '../../../../../common/mobile/utils/device'; import {Device} from '../../../../../common/mobile/utils/device';
const AddSlide = props => { const AddSlide = props => {
const layouts = props.storeSlideSettings.slideLayouts;
return ( return (
<Fragment> <div className={'dataview slide-layout'}>
{layouts.map((row, rowIndex) => {
</Fragment> return (
<ul key={`row-${rowIndex}`} className={'row'}>
{row.map((layout, index) => {
return (
<li key={`item-${rowIndex}-${index}`} onClick={() => {props.onSlideLayout(layout.type)}}>
<img src={layout.image} width={layout.width} height={layout.height}/>
</li>
)
})}
</ul>
)
})}
</div>
) )
}; };
export {AddSlide}; export default inject("storeSlideSettings")(observer(AddSlide));

View file

@ -5,5 +5,18 @@
}, },
"textAnonymous": "Anonymous" "textAnonymous": "Anonymous"
} }
},
"View" : {
"Add" : {
"textChart": "Chart",
"textFormula": "Formula",
"textShape": "Shape",
"textOther": "Other"
},
"Edit" : {
"textSelectObjectToEdit": "Select object to edit",
"textSettings": "Settings",
"textCell": "Cell"
}
} }
} }

View file

@ -5,6 +5,7 @@ import { f7 } from 'framework7-react';
import { withTranslation } from 'react-i18next'; import { withTranslation } from 'react-i18next';
import CollaborationController from '../../../../common/mobile/lib/controller/Collaboration.jsx' import CollaborationController from '../../../../common/mobile/lib/controller/Collaboration.jsx'
@inject("storeFocusObjects")
class MainController extends Component { class MainController extends Component {
constructor(props) { constructor(props) {
super(props) super(props)
@ -202,6 +203,14 @@ class MainController extends Component {
// me.api.asc_registerCallback('asc_onPrintUrl', _.bind(me.onPrintUrl, me)); // me.api.asc_registerCallback('asc_onPrintUrl', _.bind(me.onPrintUrl, me));
// me.api.asc_registerCallback('asc_onDocumentName', _.bind(me.onDocumentName, me)); // me.api.asc_registerCallback('asc_onDocumentName', _.bind(me.onDocumentName, me));
me.api.asc_registerCallback('asc_onEndAction', me._onLongActionEnd.bind(me)); me.api.asc_registerCallback('asc_onEndAction', me._onLongActionEnd.bind(me));
const storeFocusObjects = this.props.storeFocusObjects;
this.api.asc_registerCallback('asc_onFocusObject', objects => {
storeFocusObjects.resetFocusObjects(objects);
});
this.api.asc_registerCallback('asc_onSelectionChanged', cellInfo => {
storeFocusObjects.resetCellInfo(cellInfo);
});
} }
_onLongActionEnd(type, id) { _onLongActionEnd(type, id) {

View file

@ -0,0 +1,28 @@
import React, {Component} from 'react';
import { f7 } from 'framework7-react';
import {Device} from '../../../../../common/mobile/utils/device';
import AddChart from '../../view/add/AddChart';
class AddChartController extends Component {
constructor (props) {
super(props);
}
closeModal () {
if ( Device.phone ) {
f7.sheet.close('.add-popup', true);
} else {
f7.popover.close('#add-popover');
}
}
render () {
return (
<AddChart
/>
)
}
}
export default AddChartController;

View file

@ -0,0 +1,28 @@
import React, {Component} from 'react';
import { f7 } from 'framework7-react';
import {Device} from '../../../../../common/mobile/utils/device';
import AddFormula from '../../view/add/AddFormula';
class AddFormulaController extends Component {
constructor (props) {
super(props);
}
closeModal () {
if ( Device.phone ) {
f7.sheet.close('.add-popup', true);
} else {
f7.popover.close('#add-popover');
}
}
render () {
return (
<AddFormula
/>
)
}
}
export default AddFormulaController;

View file

@ -0,0 +1,20 @@
import React, {Component} from 'react';
import { f7 } from 'framework7-react';
import {Device} from '../../../../../common/mobile/utils/device';
import EditCell from '../../view/edit/EditCell';
class EditCellController extends Component {
constructor (props) {
super(props);
}
render () {
return (
<EditCell
/>
)
}
}
export default EditCellController;

View file

@ -475,7 +475,7 @@
} }
} }
.active { .tab-link-active {
i.icon { i.icon {
&.icon-add-chart { &.icon-add-chart {
width: 24px; width: 24px;

View file

@ -6,12 +6,15 @@ import Settings from '../view/settings/Settings';
import CollaborationView from '../../../../common/mobile/lib/view/Collaboration.jsx' import CollaborationView from '../../../../common/mobile/lib/view/Collaboration.jsx'
import CellEditor from '../controller/CellEditor'; import CellEditor from '../controller/CellEditor';
import Statusbar from '../controller/StatusBar' import Statusbar from '../controller/StatusBar'
import AddOptions from "../view/add/Add";
import EditOptions from "../view/edit/Edit";
export default class MainPage extends Component { export default class MainPage extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
editOptionsVisible: false, editOptionsVisible: false,
addOptionsVisible: false,
settingsVisible: false, settingsVisible: false,
collaborationVisible: false, collaborationVisible: false,
}; };
@ -21,12 +24,12 @@ export default class MainPage extends Component {
this.setState(state => { this.setState(state => {
if ( opts == 'edit' ) if ( opts == 'edit' )
return {editOptionsVisible: true}; return {editOptionsVisible: true};
else else if ( opts == 'add' )
if ( opts == 'settings' ) return {addOptionsVisible: true};
else if ( opts == 'settings' )
return {settingsVisible: true}; return {settingsVisible: true};
else else if ( opts == 'coauth' )
if ( opts == 'coauth' ) return {collaborationVisible: true};
return {collaborationVisible: true}
}); });
}; };
@ -35,12 +38,12 @@ export default class MainPage extends Component {
await 1 && this.setState(state => { await 1 && this.setState(state => {
if ( opts == 'edit' ) if ( opts == 'edit' )
return {editOptionsVisible: false}; return {editOptionsVisible: false};
else else if ( opts == 'add' )
if ( opts == 'settings' ) return {addOptionsVisible: false};
else if ( opts == 'settings' )
return {settingsVisible: false}; return {settingsVisible: false};
else else if ( opts == 'coauth' )
if ( opts == 'coauth' ) return {collaborationVisible: false};
return {collaborationVisible: false}
}) })
})(); })();
}; };
@ -57,6 +60,7 @@ export default class MainPage extends Component {
</NavLeft> </NavLeft>
<NavRight> <NavRight>
<Link id='btn-edit' icon='icon-edit-settings' href={false} onClick={e => this.handleClickToOpenOptions('edit')}></Link> <Link id='btn-edit' icon='icon-edit-settings' href={false} onClick={e => this.handleClickToOpenOptions('edit')}></Link>
<Link id='btn-add' icon='icon-plus' href={false} onClick={e => this.handleClickToOpenOptions('add')}></Link>
<Link href={false} icon='icon-collaboration' onClick={e => this.handleClickToOpenOptions('coauth')}></Link> <Link href={false} icon='icon-collaboration' onClick={e => this.handleClickToOpenOptions('coauth')}></Link>
<Link id='btn-settings' icon='icon-settings' href={false} onClick={e => this.handleClickToOpenOptions('settings')}></Link> <Link id='btn-settings' icon='icon-settings' href={false} onClick={e => this.handleClickToOpenOptions('settings')}></Link>
</NavRight> </NavRight>
@ -64,10 +68,14 @@ export default class MainPage extends Component {
<CellEditor /> <CellEditor />
{/* Page content */} {/* Page content */}
<View id="editor_sdk" /> <View id="editor_sdk" />
{/*{*/} {
{/*!this.state.editOptionsVisible ? null :*/} !this.state.editOptionsVisible ? null :
{/*<EditOptions onclosed={this.handleOptionsViewClosed.bind(this, 'edit')} />*/} <EditOptions onclosed={this.handleOptionsViewClosed.bind(this, 'edit')} />
{/*}*/} }
{
!this.state.addOptionsVisible ? null :
<AddOptions onclosed={this.handleOptionsViewClosed.bind(this, 'add')} />
}
{ {
!this.state.settingsVisible ? null : !this.state.settingsVisible ? null :
<Settings onclosed={this.handleOptionsViewClosed.bind(this, 'settings')} /> <Settings onclosed={this.handleOptionsViewClosed.bind(this, 'settings')} />

View file

@ -0,0 +1,138 @@
import {action, observable, computed} from 'mobx';
export class storeFocusObjects {
@observable focusOn = undefined;
@observable _focusObjects = [];
@action resetFocusObjects(objects) {
this.focusOn = 'obj';
this._focusObjects = objects;
}
@computed get objects() {
const _objects = [];
for (let object of this._focusObjects) {
const type = object.get_ObjectType();
if (Asc.c_oAscTypeSelectElement.Paragraph == type) {
_objects.push('text', 'paragraph');
} else if (Asc.c_oAscTypeSelectElement.Table == type) {
_objects.push('table');
} else if (Asc.c_oAscTypeSelectElement.Image == type) {
if (object.get_ObjectValue().get_ChartProperties()) {
_objects.push('chart');
} else if (object.get_ObjectValue().get_ShapeProperties()) {
_objects.push('shape');
} else {
_objects.push('image');
}
} else if (Asc.c_oAscTypeSelectElement.Hyperlink == type) {
_objects.push('hyperlink');
}
}
const resultArr = _objects.filter((value, index, self) => self.indexOf(value) === index); //get uniq array
// Exclude shapes if chart exist
if (resultArr.indexOf('chart') > -1) {
resultArr.splice(resultArr.indexOf('shape'), 1);
}
return resultArr;
}
@observable _cellInfo;
@action resetCellInfo (cellInfo) {
this.focusOn = 'cell';
this._cellInfo = cellInfo;
}
@computed get selections () {
const _selections = [];
let isCell, isRow, isCol, isAll, isChart, isImage, isTextShape, isShape, isTextChart,
selType = this._cellInfo.asc_getSelectionType(),
isObjLocked = false;
switch (selType) {
case Asc.c_oAscSelectionType.RangeCells: isCell = true; break;
case Asc.c_oAscSelectionType.RangeRow: isRow = true; break;
case Asc.c_oAscSelectionType.RangeCol: isCol = true; break;
case Asc.c_oAscSelectionType.RangeMax: isAll = true; break;
case Asc.c_oAscSelectionType.RangeImage: isImage = true; break;
case Asc.c_oAscSelectionType.RangeShape: isShape = true; break;
case Asc.c_oAscSelectionType.RangeChart: isChart = true; break;
case Asc.c_oAscSelectionType.RangeChartText:isTextChart = true; break;
case Asc.c_oAscSelectionType.RangeShapeText: isTextShape = true; break;
}
if (isImage || isShape || isChart) {
isImage = isShape = isChart = false;
let has_chartprops = false;
let selectedObjects = Common.EditorApi.get().asc_getGraphicObjectProps();
for (let i = 0; i < selectedObjects.length; i++) {
if (selectedObjects[i].asc_getObjectType() == Asc.c_oAscTypeSelectElement.Image) {
const elValue = selectedObjects[i].asc_getObjectValue();
isObjLocked = isObjLocked || elValue.asc_getLocked();
const shapeProps = elValue.asc_getShapeProperties();
if (shapeProps) {
if (shapeProps.asc_getFromChart()) {
isChart = true;
} else {
isShape = true;
}
} else if (elValue.asc_getChartProperties()) {
isChart = true;
has_chartprops = true;
} else {
isImage = true;
}
}
}
} else if (isTextShape || isTextChart) {
const selectedObjects = this.api.asc_getGraphicObjectProps();
let isEquation = false;
for (var i = 0; i < selectedObjects.length; i++) {
const elType = selectedObjects[i].asc_getObjectType();
if (elType == Asc.c_oAscTypeSelectElement.Image) {
const value = selectedObjects[i].asc_getObjectValue();
isObjLocked = isObjLocked || value.asc_getLocked();
} else if (elType == Asc.c_oAscTypeSelectElement.Paragraph) {
} else if (elType == Asc.c_oAscTypeSelectElement.Math) {
isEquation = true;
}
}
}
if (isChart || isTextChart) {
_selections.push('chart');
if (isTextChart) {
_selections.push('text');
}
} else if ((isShape || isTextShape) && !isImage) {
_selections.push('shape');
if (isTextShape) {
_selections.push('text');
}
} else if (isImage) {
_selections.push('image');
if (isShape) {
_selections.push('shape');
}
} else {
_selections.push('cell');
if (this._cellInfo.asc_getHyperlink()) {
_selections.push('hyperlink');
}
}
return _selections;
}
}

View file

@ -1,6 +1,6 @@
// import {storeDocumentSettings} from './documentSettings'; // import {storeDocumentSettings} from './documentSettings';
// import {storeFocusObjects} from "./focusObjects"; import {storeFocusObjects} from "./focusObjects";
import {storeUsers} from '../../../../common/mobile/lib/store/users'; import {storeUsers} from '../../../../common/mobile/lib/store/users';
import {storeWorksheets} from './sheets'; import {storeWorksheets} from './sheets';
// import {storeTextSettings} from "./textSettings"; // import {storeTextSettings} from "./textSettings";
@ -11,7 +11,7 @@ import {storeWorksheets} from './sheets';
// import {storeChartSettings} from "./chartSettings"; // import {storeChartSettings} from "./chartSettings";
export const stores = { export const stores = {
// storeFocusObjects: new storeFocusObjects(), storeFocusObjects: new storeFocusObjects(),
// storeDocumentSettings: new storeDocumentSettings(), // storeDocumentSettings: new storeDocumentSettings(),
users: new storeUsers(), users: new storeUsers(),
sheets: new storeWorksheets() sheets: new storeWorksheets()

View file

@ -0,0 +1,122 @@
import React, {Component, useEffect} from 'react';
import {View,Page,Navbar,NavRight,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";
import {Device} from '../../../../../common/mobile/utils/device';
import AddChartController from "../../controller/add/AddChart";
import AddFormulaController from "../../controller/add/AddFormula";
//import AddShapeController from "../../controller/add/AddShape";
//import {AddOtherController} from "../../controller/add/AddOther";
const routes = [
];
const AddLayoutNavbar = ({ tabs, inPopover }) => {
const isAndroid = Device.android;
return (
<Navbar>
<div className='tab-buttons tabbar'>
{tabs.map((item, index) =>
<Link key={"sse-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>
{ !inPopover && <NavRight><Link icon='icon-expand-down' popupClose=".add-popup"></Link></NavRight> }
</Navbar>
)
};
const AddLayoutContent = ({ tabs }) => {
return (
<Tabs animated>
{tabs.map((item, index) =>
<Tab key={"sse-tab-" + item.id} id={item.id} className="page-content" tabActive={index === 0}>
{item.component}
</Tab>
)}
</Tabs>
)
};
const AddTabs = props => {
const { t } = useTranslation();
const _t = t('Add', {returnObjects: true});
const tabs = [];
tabs.push({
caption: _t.textChart,
id: 'add-chart',
icon: 'icon-add-chart',
component: <AddChartController />
});
tabs.push({
caption: _t.textFormula,
id: 'add-formula',
icon: 'icon-add-formula',
component: <AddFormulaController />
});
/*tabs.push({
caption: _t.textShape,
id: 'add-shape',
icon: 'icon-add-shape',
component: <AddShapeController />
});
tabs.push({
caption: _t.textOther,
id: 'add-other',
icon: 'icon-add-other',
component: <AddOtherController />
});*/
return (
<View style={props.style} stackPages={true} routes={routes}>
<Page pageContent={false}>
<AddLayoutNavbar tabs={tabs} inPopover={props.inPopover}/>
<AddLayoutContent tabs={tabs} />
</Page>
</View>
)
};
class AddView extends Component {
constructor(props) {
super(props);
this.onoptionclick = this.onoptionclick.bind(this);
}
onoptionclick(page){
f7.views.current.router.navigate(page);
}
render() {
const show_popover = this.props.usePopover;
return (
show_popover ?
<Popover id="add-popover" className="popover__titled" onPopoverClosed={() => this.props.onclosed()}>
<AddTabs inPopover={true} onOptionClick={this.onoptionclick} style={{height: '410px'}} />
</Popover> :
<Popup className="add-popup" onPopupClosed={() => this.props.onclosed()}>
<AddTabs onOptionClick={this.onoptionclick} />
</Popup>
)
}
}
const Add = props => {
useEffect(() => {
if ( Device.phone )
f7.popup.open('.add-popup');
else f7.popover.open('#add-popover', '#btn-add');
return () => {
// component will unmount
}
});
const onviewclosed = () => {
if ( props.onclosed )
props.onclosed();
};
return <AddView usePopover={!Device.phone} onclosed={onviewclosed} />
};
export default Add;

View file

@ -0,0 +1,12 @@
import React, {Fragment, useState} from 'react';
import {observer, inject} from "mobx-react";
const AddChart = props => {
return (
<Fragment>
</Fragment>
)
};
export default AddChart;

View file

@ -0,0 +1,12 @@
import React, {Fragment, useState} from 'react';
import {observer, inject} from "mobx-react";
const AddFormula = props => {
return (
<Fragment>
</Fragment>
)
};
export default AddFormula;

View file

@ -0,0 +1,138 @@
import React, {useState, useEffect} from 'react';
import {observer, inject} from "mobx-react";
import { Popover, Sheet, View, Page, Navbar, NavRight, NavLeft, NavTitle, Tabs, Tab, Link } from 'framework7-react';
import { f7 } from 'framework7-react';
import { useTranslation } from 'react-i18next';
import {Device} from '../../../../../common/mobile/utils/device';
import EditCellController from "../../controller/edit/EditCell";
const routes = [
];
const EmptyEditLayout = () => {
const { t } = useTranslation();
const _t = t('View.Edit', {returnObjects: true});
return (
<Page>
<div className="content-block inset">
<div className="content-block-inner">
<p>{_t.textSelectObjectToEdit}</p>
</div>
</div>
</Page>
)
};
const EditLayoutNavbar = ({ editors, inPopover }) => {
const isAndroid = Device.android;
const { t } = useTranslation();
const _t = t('View.Edit', {returnObjects: true});
return (
<Navbar>
{
editors.length > 1 ?
<div className='tab-buttons tabbar'>
{editors.map((item, index) => <Link key={"sse-link-" + item.id} tabLink={"#" + item.id} tabLinkActive={index === 0}>{item.caption}</Link>)}
{isAndroid && <span className='tab-link-highlight' style={{width: 100 / editors.lenght + '%'}}></span>}
</div> :
<NavTitle>{ editors[0].caption }</NavTitle>
}
{ !inPopover && <NavRight><Link icon='icon-expand-down' sheetClose></Link></NavRight> }
</Navbar>
)
};
const EditLayoutContent = ({ editors }) => {
if (editors.length > 1) {
return (
<Tabs animated>
{editors.map((item, index) =>
<Tab key={"sse-tab-" + item.id} id={item.id} className="page-content" tabActive={index === 0}>
{item.component}
</Tab>
)}
</Tabs>
)
} else {
return (
<Page>
{editors[0].component}
</Page>
)
}
};
const EditTabs = props => {
const { t } = useTranslation();
const _t = t('View.Edit', {returnObjects: true});
const store = props.storeFocusObjects;
const settings = !store.focusOn ? [] : (store.focusOn === 'obj' ? store.settings : store.selections);
let editors = [];
if (settings.length < 1) {
editors.push({
caption: _t.textSettings,
component: <EmptyEditLayout />
});
} else {
if (settings.indexOf('cell') > -1) {
editors.push({
caption: _t.textCell,
id: 'edit-text',
component: <EditCellController />
})
}
}
return (
<View style={props.style} stackPages={true} routes={routes}>
<Page pageContent={false}>
<EditLayoutNavbar editors={editors} inPopover={props.inPopover}/>
<EditLayoutContent editors={editors} />
</Page>
</View>
)
};
const EditTabsContainer = inject("storeFocusObjects")(observer(EditTabs));
const EditView = props => {
const onOptionClick = (page) => {
$f7.views.current.router.navigate(page);
};
const show_popover = props.usePopover;
return (
show_popover ?
<Popover id="edit-popover" className="popover__titled" onPopoverClosed={() => props.onClosed()}>
<EditTabsContainer inPopover={true} onOptionClick={onOptionClick} style={{height: '410px'}} />
</Popover> :
<Sheet id="edit-sheet" push onSheetClosed={() => props.onClosed()}>
<EditTabsContainer onOptionClick={onOptionClick} />
</Sheet>
)
};
const EditOptions = props => {
useEffect(() => {
if ( Device.phone )
f7.sheet.open('#edit-sheet');
else f7.popover.open('#edit-popover', '#btn-edit');
return () => {
// component will unmount
}
});
const onviewclosed = () => {
if ( props.onclosed )
props.onclosed();
};
return (
<EditView usePopover={!Device.phone} onClosed={onviewclosed} />
)
};
export default EditOptions;

View file

@ -0,0 +1,12 @@
import React, {Fragment, useState} from 'react';
import {observer, inject} from "mobx-react";
const EditCell = props => {
return (
<Fragment>
</Fragment>
)
};
export default EditCell;