Merge branch 'feature/mobile-apps-on-reactjs' into feature/mobile-apps-on-reactjs-se-edit-settings

This commit is contained in:
SergeyEzhin 2021-02-08 16:53:15 +03:00
commit ef0449b49b
37 changed files with 1552 additions and 42 deletions

View file

@ -1,3 +1,5 @@
@import "./ios/_contextmenu";
@import "icons-ios";
.device-ios {
@blockTitleColor: #6d6d72;
@ -198,8 +200,11 @@
}
li.no-indicator {
.item-link {
.item-inner:before {
content: none;
.item-inner {
padding-right: 15px;
&:before {
content: none;
}
}
}
}
@ -237,6 +242,9 @@
}
}
}
.list-input-right input {
text-align: right;
}
}
.tab-buttons {

View file

@ -152,8 +152,11 @@
.list {
li.no-indicator {
.item-link {
.item-inner:before {
content: none;
.item-inner{
padding-right: 15px;
&:before {
content: none;
}
}
}
}

View file

@ -0,0 +1,9 @@
.device-ios {
i.icon {
&.icon-paste {
width: 24px;
height: 24px;
.encoded-svg-background('<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M5 2H0V20H9V24H24V7H19V2H14V3H18V7H9V19H1V3H5V2ZM10 8H23V23H10V8Z" fill="white"/><path d="M5 0H14V5H5V0Z" fill="white"/><path fill-rule="evenodd" clip-rule="evenodd" d="M21 12H12V11H21V12Z" fill="white"/><path fill-rule="evenodd" clip-rule="evenodd" d="M21 16H12V15H21V16Z" fill="white"/><path fill-rule="evenodd" clip-rule="evenodd" d="M21 20H12V19H21V20Z" fill="white"/></svg>');
}
}
}

View file

@ -5,8 +5,15 @@ export default class Notifications {
}
on(event, callback) {
!this._events[event] && (this._events[event] = []);
this._events[event].push(callback);
const addevent = (e, c) => {
!this._events[e] && (this._events[e] = []);
this._events[e].push(c);
};
if ( typeof(event) == 'object' )
for (const i in event)
addevent(i, event[i])
else addevent(event, callback);
}
off(event, callback) {

View file

@ -0,0 +1,74 @@
import React, { Component } from 'react';
import { f7 } from 'framework7-react';
import ContextMenuView from '../view/ContextMenu';
class ContextMenuController extends Component {
constructor(props) {
super(props);
this.state = {
pos: [-10000,-10000],
show: false
};
this.onMenuClosed = this.onMenuClosed.bind(this);
Common.Notifications.on({
'engineCreated': api => {
api.asc_registerCallback('asc_onShowPopMenu', this.onApiShowPopMenu.bind(this));
api.asc_registerCallback('asc_onHidePopMenu', this.onApiHidePopMenu.bind(this));
},
'document:ready': () => {
this.$targetEl = $$('<div id="idx-context-menu-target" style="position:absolute;width:15px;height:15px;background-color:green;z-index:1;"></div>');
this.$targetEl.css({left: '-10000px', top: '-10000px'});
$$('#editor_sdk').append(this.$targetEl);
}
});
console.log('context menu controller created');
}
onApiShowPopMenu(x, y) {
console.log('show context menu ' + [x,y]);
this.$targetEl.css({left: `${x}px`, top: `${y}px`});
this.setState({
pos: [x,y],
show: true });
}
onApiHidePopMenu() {
// console.log('hide context menu');
if ( this.state.show ) {
f7.popover.close('#idx-context-menu-popover');
}
}
onMenuClosed() {
(async () => {
await 1 && this.setState(state => {
this.$targetEl.css({left: '-10000px', top: '-10000px'});
return ({pos: [-10000, -10000], show: false});
});
})();
}
componentWillUnmount() {
console.log('context menu controller will be unmounted');
}
componentDidMount() {
console.log('context menu controller did mount');
}
render() {
return (
!this.state.show ? null :
<ContextMenuView onMenuClosed={this.onMenuClosed} />)
}
}
export { ContextMenuController as ContextMenu };

View file

@ -134,6 +134,8 @@ class MainController extends Component {
const onDocumentContentReady = () => {
Common.Gateway.documentReady();
f7.emit('resize');
Common.Notifications.trigger('document:ready');
};
const _process_array = (array, fn) => {

View file

@ -7,6 +7,7 @@ import Settings from '../view/settings/Settings';
import CollaborationView from '../../../../common/mobile/lib/view/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) {
@ -89,6 +90,7 @@ export default class MainPage extends Component {
!this.state.collaborationVisible ? null :
<CollaborationView onclosed={this.handleOptionsViewClosed.bind(this, 'coauth')} />
}
{/*<ContextMenu />*/}
</Page>
)
}

View file

@ -0,0 +1,50 @@
import React, { Component } from 'react';
import { Popover, List, ListItem, ListButton, Link, Icon } from 'framework7-react';
import { f7 } from 'framework7-react';
const buttons = [
{
text: 'Edit',
action: 'edit'
}, {
text: 'View',
action: 'view'
}, {
icon: 'icon-paste',
action: 'review'
}
];
class ContextMenuView extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
f7.popover.open('#idx-context-menu-popover', '#idx-context-menu-target');
}
render() {
return (
<Popover id="idx-context-menu-popover"
className="document-menu"
backdrop={false}
closeByBackdropClick={false}
closeByOutsideClick={false}
onPopoverClosed={e => this.props.onMenuClosed()}
>
<List className="list-block">
{buttons.map((b, index) =>
!!b.text ?
<ListButton className="asd" title={b.text} key={index} /> :
<ListButton className="asd" title={b.text} key={index}>
<Icon slot="media" icon={b.icon} />
</ListButton>
)}
</List>
</Popover>
)
}
}
export default ContextMenuView;

View file

@ -229,7 +229,22 @@
"textRemoveTable": "Remove Table",
"textCellMargins": "Cell Margins",
"textRemoveChart": "Remove Chart",
"textNoStyles": "No styles for this type of charts."
"textNoStyles": "No styles for this type of charts.",
"textLinkType": "Link Type",
"textExternalLink": "External Link",
"textSlideInThisPresentation": "Slide in this Presentation",
"textLink": "Link",
"textLinkTo": "Link to",
"textNextSlide": "Next Slide",
"textPreviousSlide": "Previous Slide",
"textFirstSlide": "First Slide",
"textLastSlide": "Last Slide",
"textSlideNumber": "Slide Number",
"textEditLink": "Edit Link",
"textRemoveLink": "Remove Link",
"textDisplay": "Display",
"textScreenTip": "Screen Tip",
"textDefault": "Selected text"
}
},
"Common": {

View file

@ -322,6 +322,14 @@ class MainController extends Component {
storeChartSettings.updateChartStyles(this.api.asc_getChartPreviews(storeFocusObjects.chartObject.getType()));
}
});
// Link settings
const storeLinkSettings = this.props.storeLinkSettings;
this.api.asc_registerCallback('asc_onCanAddHyperlink', (value) => {
storeLinkSettings.canAddHyperlink(value);
});
}
_onDocumentContentReady() {

View file

@ -0,0 +1,114 @@
import React, { Component } from 'react';
import { f7 } from 'framework7-react';
import { Device } from '../../../../../common/mobile/utils/device';
import {observer, inject} from "mobx-react";
import { withTranslation } from 'react-i18next';
import { EditLink } from '../../view/edit/EditLink';
class EditLinkController extends Component {
constructor (props) {
super(props);
this.onEditLink = this.onEditLink.bind(this);
this.onRemoveLink = this.onRemoveLink.bind(this);
}
closeModal () {
if ( Device.phone ) {
f7.sheet.close('#edit-sheet', true);
} else {
f7.popover.close('#edit-popover');
}
}
onEditLink(type, linkInfo) {
const api = Common.EditorApi.get();
const { t } = this.props;
const _t = t("View.Edit", { 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.textNotUrl, _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.change_Hyperlink(props);
this.closeModal();
}
onRemoveLink() {
const api = Common.EditorApi.get();
api.remove_Hyperlink();
this.closeModal();
}
render () {
return (
<EditLink
onEditLink={this.onEditLink}
onRemoveLink={this.onRemoveLink}
/>
)
}
}
const EditLinkWithTranslation = withTranslation()(EditLinkController);
export {EditLinkWithTranslation as EditLinkController};

View file

@ -163,4 +163,19 @@ export class storeFocusObjects {
return undefined;
}
}
@computed get linkObject() {
const links = [];
for (let object of this._focusObjects) {
if (object.get_ObjectType() == Asc.c_oAscTypeSelectElement.Hyperlink) {
links.push(object);
}
}
if (links.length > 0) {
const object = links[links.length - 1]; // get top
return object.get_ObjectValue();
} else {
return undefined;
}
}
}

View file

@ -5,4 +5,68 @@ export class storeLinkSettings {
@action canAddHyperlink (value) {
this.canAddLink = value;
}
}
@observable typeLink;
@action changeLinkType(value) {
this.typeLink = value;
}
@observable slideLink;
@action changeSlideLink(value) {
this.slideLink = value;
}
@observable slideNum;
@action changeSlideNum(value) {
this.slideNum = value;
}
@observable slideName;
@action changeSlideName(value) {
this.slideName = value;
}
initCategory(linkObject) {
const url = linkObject.get_Value();
const api = Common.EditorApi.get();
let indAction;
let slidesCount;
let slideNum;
if(url === null || url === undefined || url === '') {
this.changeLinkType(1);
}
else {
indAction = url.indexOf("ppaction://hlink");
if(0 == indAction) {
if (url == "ppaction://hlinkshowjump?jump=firstslide") {
this.changeSlideLink(2);
} else if (url == "ppaction://hlinkshowjump?jump=lastslide") {
this.changeSlideLink(3);
}
else if (url == "ppaction://hlinkshowjump?jump=nextslide") {
this.changeSlideLink(0);
}
else if (url == "ppaction://hlinkshowjump?jump=previousslide") {
this.changeSlideLink(1);
}
else {
this.changeSlideLink(4);
slidesCount = api.getCountPages();
let mask = "ppaction://hlinksldjumpslide",
indSlide = url.indexOf(mask);
if (0 == indSlide) {
slideNum = parseInt(url.substring(mask.length));
if (slideNum < 0) this.changeSlideNum(0);
if (slideNum >= slidesCount) this.changeSlideNum(slidesCount - 1);
} else this.changeSlideNum(0);
}
this.changeLinkType(0);
} else {
this.changeLinkType(1);
}
}
}
}

View file

@ -11,6 +11,7 @@ import EditShapeController from "../../controller/edit/EditShape";
import EditImageController from "../../controller/edit/EditImage";
import EditTableController from "../../controller/edit/EditTable";
import EditChartController from "../../controller/edit/EditChart";
import { EditLinkController } from "../../controller/edit/EditLink";
import { Theme, Layout, Transition, Type, Effect, StyleFillColor, CustomFillColor } from './EditSlide';
import { PageTextFonts, PageTextFontColor, PageTextCustomFontColor, PageTextAddFormatting, PageTextBullets, PageTextNumbers, PageTextLineSpacing } from './EditText';
@ -18,7 +19,7 @@ import { PageShapeStyle, PageShapeStyleNoFill, PageReplaceContainer, PageReorder
import { PageImageReplace, PageImageReorder, PageImageAlign, PageLinkSettings } from './EditImage';
import { PageTableStyle, PageTableStyleOptions, PageTableCustomFillColor, PageTableBorderColor, PageTableCustomBorderColor, PageTableReorder, PageTableAlign } from './EditTable';
import { PageChartStyle, PageChartCustomFillColor, PageChartBorderColor, PageChartCustomBorderColor, PageChartReorder, PageChartAlign } from './EditChart'
//import EditLinkController from "../../controller/edit/EditLink";
import { PageLinkTo, PageTypeLink } from './EditLink'
const routes = [
@ -194,6 +195,17 @@ const routes = [
{
path: '/edit-chart-custom-fill-color/',
component: PageChartCustomFillColor
},
// Link
{
path: '/edit-link-type/',
component: PageTypeLink
},
{
path: '/edit-link-to/',
component: PageLinkTo
}
];
@ -303,14 +315,13 @@ const EditTabs = props => {
component: <EditChartController />
})
}
/*
if (settings.indexOf('hyperlink') > -1) {
editors.push({
caption: _t.textHyperlink,
id: 'edit-link',
component: <EditLinkController />
})
}*/
}
}
return (

View file

@ -0,0 +1,187 @@
import React, {useState, useEffect} 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.Edit', {returnObjects: true});
const storeLinkSettings = props.storeLinkSettings;
const typeLink = storeLinkSettings.typeLink;
return (
<Page>
<Navbar title={_t.textLinkType} backLink={_t.textBack}/>
<List>
<ListItem title={_t.textExternalLink} radio checked={typeLink === 1} onClick={() => {storeLinkSettings.changeLinkType(1);}}></ListItem>
<ListItem title={_t.textSlideInThisPresentation} radio checked={typeLink === 0} onClick={() => {storeLinkSettings.changeLinkType(0);}}></ListItem>
</List>
</Page>
)
};
const PageLinkTo = props => {
const isAndroid = Device.android;
const { t } = useTranslation();
const _t = t('View.Edit', {returnObjects: true});
const api = Common.EditorApi.get();
const slidesCount = api.getCountPages();
const storeLinkSettings = props.storeLinkSettings;
const slideLink = storeLinkSettings.slideLink;
// console.log(slideLink);
// const slideNum = storeLinkSettings.slideNum;
// const [stateTypeTo, setTypeTo] = useState(props.curTo);
const changeTypeTo = (type) => {
storeLinkSettings.changeSlideLink(type);
props.changeTo(type);
};
const [stateNumberTo, setNumberTo] = useState(0);
const changeNumber = (curNumber, isDecrement) => {
storeLinkSettings.changeSlideLink(4);
let value;
if (isDecrement) {
value = Math.max(0, --curNumber);
} else {
value = Math.min(slidesCount - 1, ++curNumber);
}
setNumberTo(value);
storeLinkSettings.changeSlideNum(value);
props.changeTo(4, value);
};
return (
<Page>
<Navbar title={_t.textLinkTo} backLink={_t.textBack}/>
<List>
<ListItem title={_t.textNextSlide} radio checked={slideLink === 0} onClick={() => {changeTypeTo(0)}}></ListItem>
<ListItem title={_t.textPreviousSlide} radio checked={slideLink === 1} onClick={() => {changeTypeTo(1)}}></ListItem>
<ListItem title={_t.textFirstSlide} radio checked={slideLink === 2} onClick={() => {changeTypeTo(2)}}></ListItem>
<ListItem title={_t.textLastSlide} radio checked={slideLink === 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.Edit', {returnObjects: true});
const storeFocusObjects = props.storeFocusObjects;
const storeLinkSettings = props.storeLinkSettings;
const linkObject = storeFocusObjects.linkObject;
useEffect(() => {
storeLinkSettings.initCategory(linkObject);
}, [linkObject]);
const url = linkObject.get_Value();
const tooltip = linkObject.get_ToolTip();
const display = linkObject.get_Text();
const slideNum = storeLinkSettings.slideNum;
const slideLink = storeLinkSettings.slideLink;
const typeLink = storeLinkSettings.typeLink;
if(typeLink === 1) {
storeLinkSettings.changeSlideName(_t.textNextSlide);
storeLinkSettings.changeSlideLink(0);
}
const textType = typeLink === 1 ? _t.textExternalLink : _t.textSlideInThisPresentation;
const [link, setLink] = useState(typeLink !== 0 ? url : '');
const changeTo = (slideLink, number) => {
switch (slideLink) {
case 0 : storeLinkSettings.changeSlideName(_t.textNextSlide); break;
case 1 : storeLinkSettings.changeSlideName(_t.textPreviousSlide); break;
case 2 : storeLinkSettings.changeSlideName(_t.textFirstSlide); break;
case 3 : storeLinkSettings.changeSlideName(_t.textLastSlide); break;
case 4 : storeLinkSettings.changeSlideName(`${_t.textSlide} ${number + 1}`); storeLinkSettings.changeSlideNum(number);
}
}
changeTo(slideLink, slideNum);
const slideName = storeLinkSettings.slideName;
const [screenTip, setScreenTip] = useState(tooltip);
const displayDisabled = display !== false && display === null;
const [stateDisplay, setDisplay] = useState(display !== false ? ((display !== null) ? display : _t.textDefault) : "");
return (
<Page>
<Navbar title={_t.textLink} backLink={_t.textBack}/>
<List inlineLabels className='inputs-list'>
<ListItem link={'/edit-link-type/'} title={_t.textLinkType} after={textType} routeProps={{
curType: typeLink
}} />
{typeLink !== 0 ?
<ListInput label={_t.textLink}
type="text"
placeholder={_t.textLink}
value={link}
onChange={(event) => {setLink(event.target.value)}}
/> :
<ListItem link={'/edit-link-to/'} title={_t.textLinkTo} after={slideName} routeProps={{
changeTo: changeTo,
curTo: slideLink
}}/>
}
<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.textEditLink}
className={`button-fill button-raised${typeLink === 1 && link.length < 1 && ' disabled'}`}
onClick={() => {
props.onEditLink(typeLink, (typeLink === 1 ?
{url: link, display: stateDisplay, tip: screenTip, displayDisabled: displayDisabled } :
{linkTo: slideLink, numberTo: slideNum, display: stateDisplay, tip: screenTip, displayDisabled: displayDisabled}));
}}
/>
<ListButton title={_t.textRemoveLink}
className={`button-fill button-red`}
onClick={() => {
props.onRemoveLink()
}}
/>
</List>
</Page>
)
};
const EditLink = inject("storeFocusObjects", "storeLinkSettings")(observer(PageLink));
const LinkTo = inject("storeFocusObjects", "storeLinkSettings")(observer(PageLinkTo));
const TypeLink = inject("storeFocusObjects", "storeLinkSettings")(observer(PageTypeLink));
export {EditLink,
LinkTo as PageLinkTo,
TypeLink as PageTypeLink}

View file

@ -11,7 +11,42 @@
"textChart": "Chart",
"textFunction": "Function",
"textShape": "Shape",
"textOther": "Other"
"textOther": "Other",
"textGroups": "CATEGORIES",
"textBack": "Back",
"sCatLogical": "Logical",
"sCatDateAndTime": "Date and time",
"sCatEngineering": "Engineering",
"sCatFinancial": "Financial",
"sCatInformation": "Information",
"sCatLookupAndReference": "Lookup and Reference",
"sCatMathematic": "Math and trigonometry",
"sCatStatistical": "Statistical",
"sCatTextAndData": "Text and data",
"textImage": "Image",
"textInsertImage": "Insert Image",
"textLinkSettings": "Link Settings",
"textAddress": "Address",
"textImageURL": "Image URL",
"textPictureFromLibrary": "Picture from library",
"textPictureFromURL": "Picture from URL",
"txtNotUrl": "This field should be a URL in the format \"http://www.example.com\"",
"textEmptyImgUrl": "You need to specify image URL.",
"notcriticalErrorTitle": "Warning",
"textLink": "Link",
"textAddLink": "Add Link",
"textLinkType": "Link Type",
"textExternalLink": "External Link",
"textInternalDataRange": "Internal Data Range",
"textSheet": "Sheet",
"textRange": "Range",
"textRequired": "Required",
"textDisplay": "Display",
"textScreenTip": "Screen Tip",
"textInsert": "Insert",
"textInvalidRange": "ERROR! Invalid cells range",
"textSortAndFilter": "Sort and Filter",
"textFilter": "Filter"
},
"Edit" : {
"textSelectObjectToEdit": "Select object to edit",

View file

@ -159,7 +159,7 @@ class MainController extends Component {
const {t} = this.props;
this.api = new Asc.spreadsheet_api({
'id-view': 'editor_sdk',
'id-input' : 'ce-cell-content',
'id-input': 'idx-cell-content',
'mobile': true
// 'translate': translate
});

View file

@ -0,0 +1,67 @@
import React, {Component} from 'react';
import AddSortAndFilter from '../../view/add/AddFilter';
class AddFilterController extends Component {
constructor (props) {
super(props);
this.onInsertFilter = this.onInsertFilter.bind(this);
this.uncheckedFilter = this.uncheckedFilter.bind(this);
const api = Common.EditorApi.get();
const filterInfo = api.asc_getCellInfo().asc_getAutoFilterInfo();
const isFilter = (filterInfo ? filterInfo.asc_getIsAutoFilter() : false);
this.state = {
isFilter: isFilter
};
}
componentDidMount () {
const api = Common.EditorApi.get();
api.asc_registerCallback('asc_onError', this.uncheckedFilter);
}
componentWillUnmount () {
const api = Common.EditorApi.get();
api.asc_unregisterCallback('asc_onError', this.uncheckedFilter);
}
uncheckedFilter (id, level, errData) {
setTimeout(() => {
if (id === Asc.c_oAscError.ID.AutoFilterDataRangeError) {
this.setState({isFilter: false});
}
}, 0);
}
onInsertSort (type) {
const api = Common.EditorApi.get();
api.asc_sortColFilter(type == 'down' ? Asc.c_oAscSortOptions.Ascending : Asc.c_oAscSortOptions.Descending, '', undefined, undefined, true);
}
onInsertFilter (checked) {
this.setState({isFilter: checked});
const api = Common.EditorApi.get();
const formatTableInfo = api.asc_getCellInfo().asc_getFormatTableInfo();
const tablename = (formatTableInfo) ? formatTableInfo.asc_getTableName() : undefined;
if (checked) {
api.asc_addAutoFilter();
} else {
api.asc_changeAutoFilter(tablename, Asc.c_oAscChangeFilterOptions.filter, checked);
}
}
render () {
return (
<AddSortAndFilter getIsAutoFilter={this.getIsAutoFilter}
onInsertSort={this.onInsertSort}
onInsertFilter={this.onInsertFilter}
isFilter={this.state.isFilter}
/>
)
}
}
export default AddFilterController;

View file

@ -1,12 +1,65 @@
import React, {Component} from 'react';
import {observer, inject} from "mobx-react";
import { f7 } from 'framework7-react';
import {Device} from '../../../../../common/mobile/utils/device';
import AddFunction from '../../view/add/AddFunction';
import {LocalStorage} from '../../../../../common/mobile/utils/LocalStorage';
import {AddFunction} from '../../view/add/AddFunction';
class _FunctionGroups extends Component {
constructor (props) {
super(props);
}
componentDidMount() {
Common.Notifications.on('engineCreated', api => {
this.api = api;
this.init();
});
}
init () {
const editorLang = LocalStorage.getItem('sse-settings-func-lang');
this._editorLang = (editorLang ? editorLang : 'en').split(/[\-\_]/)[0].toLowerCase();
const localizationFunctions = (data) => {
this.api.asc_setLocalization(data);
this.fill(data);
};
fetch(`locale/l10n/functions/${this._editorLang}.json`)
.then(response => response.json())
.then((data) => {
localizationFunctions(data);
});
}
fill () {
this._functions = {};
const localizationFunctionsDesc = (data) => {
let jsonDesc = {};
try {
jsonDesc = JSON.parse(data);
} catch (e) {
jsonDesc = data;
}
const grouparr = this.api.asc_getFormulasInfo();
this.props.storeFunctions.initFunctions(grouparr, jsonDesc);
};
fetch(`locale/l10n/functions/${this._editorLang}_desc.json`)
.then(response => response.json())
.then((data) => {
localizationFunctionsDesc(data);
});
}
render() {
return null;
}
}
const FunctionGroups = inject("storeFunctions")(observer(_FunctionGroups));
class AddFunctionController extends Component {
constructor (props) {
super(props);
this.onInsertFunction = this.onInsertFunction.bind(this);
}
closeModal () {
@ -17,12 +70,19 @@ class AddFunctionController extends Component {
}
}
onInsertFunction (type) {
const api = Common.EditorApi.get();
api.asc_insertInCell(api.asc_getFormulaLocaleName(type), Asc.c_oAscPopUpSelectorType.Func, true);
this.closeModal();
}
render () {
return (
<AddFunction
<AddFunction onInsertFunction={this.onInsertFunction}
onOptionClick={this.props.onOptionClick}
/>
)
}
}
export default AddFunctionController;
export {FunctionGroups, AddFunctionController};

View file

@ -0,0 +1,60 @@
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.asc_addImageDrawingObject(_value);
} else {
f7.dialog.alert(_t.txtNotUrl, _t.notcriticalErrorTitle);
}
} else {
f7.dialog.alert(_t.textEmptyImgUrl, _t.notcriticalErrorTitle);
}
}
render () {
return (
<AddImage inTabs={this.props.inTabs}
onInsertByFile={this.onInsertByFile}
onInsertByUrl={this.onInsertByUrl}
/>
)
}
}
const AddImageWithTranslation = withTranslation()(AddImageController);
export {AddImageWithTranslation as AddImageController};

View file

@ -0,0 +1,121 @@
import React, {Component} from 'react';
import { f7 } from 'framework7-react';
import {Device} from '../../../../../common/mobile/utils/device';
import {withTranslation} from 'react-i18next';
import {AddLink} from '../../view/add/AddLink';
class AddLinkController extends Component {
constructor (props) {
super(props);
this.onInsertLink = this.onInsertLink.bind(this);
const api = Common.EditorApi.get();
const cell = api.asc_getCellInfo();
const celltype = cell.asc_getSelectionType();
this.allowInternal = (celltype !== Asc.c_oAscSelectionType.RangeImage && celltype !== Asc.c_oAscSelectionType.RangeShape &&
celltype !== Asc.c_oAscSelectionType.RangeShapeText && celltype !== Asc.c_oAscSelectionType.RangeChart &&
celltype !== Asc.c_oAscSelectionType.RangeChartText);
this.displayText = cell.asc_getLockText() ? 'locked' : cell.asc_getText();
// sheets
let items = [];
let wsc = api.asc_getWorksheetsCount();
const aws = api.asc_getActiveWorksheetIndex();
if (wsc > 0) {
items = [];
while ( !(--wsc < 0) ) {
if ( !api.asc_isWorksheetHidden(wsc) ) {
items.unshift({
value: wsc,
caption: api.asc_getWorksheetName(wsc)
});
if (wsc === aws) {
this.activeSheet = {
value: wsc,
caption: api.asc_getWorksheetName(wsc)
}
}
}
}
this.sheets = items;
}
}
onInsertLink (args) {
const api = Common.EditorApi.get();
const { t } = this.props;
const _t = t("View.Add", { returnObjects: true });
const link = new Asc.asc_CHyperlink();
let display = '';
if (args.type == 'ext') {
let url = args.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'), " ");
link.asc_setType(Asc.c_oAscHyperlinkType.WebLink);
link.asc_setHyperlinkUrl(url);
display = url;
} else {
const isValid = api.asc_checkDataRange(Asc.c_oAscSelectionDialogType.FormatTable, args.url, false);
if (isValid !== Asc.c_oAscError.ID.No) {
f7.dialog.alert(_t.textInvalidRange, _t.notcriticalErrorTitle);
return;
}
link.asc_setType(Asc.c_oAscHyperlinkType.RangeLink);
link.asc_setSheet(args.sheet);
link.asc_setRange(args.url);
display = args.sheet + '!' + args.url;
}
link.asc_setText(args.text == null ? null : !!args.text ? args.text : display);
link.asc_setTooltip(args.tooltip);
api.asc_insertHyperlink(link);
this.closeModal();
}
closeModal () {
if ( Device.phone ) {
f7.sheet.close('.add-popup', true);
} else {
f7.popover.close('#add-popover');
}
}
render () {
return (
<AddLink inTabs={this.props.inTabs}
allowInternal={this.allowInternal}
displayText={this.displayText}
sheets={this.sheets}
activeSheet={this.activeSheet}
onInsertLink={this.onInsertLink}
/>
)
}
}
const AddLinkWithTranslation = withTranslation()(AddLinkController);
export {AddLinkWithTranslation as AddLinkController};

View file

@ -0,0 +1,31 @@
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);
}
closeModal () {
if ( Device.phone ) {
f7.sheet.close('.add-popup', true);
} else {
f7.popover.close('#add-popover');
}
}
render () {
return (
<AddOther
/>
)
}
}
const AddOtherWithTranslation = withTranslation()(AddOtherController);
export {AddOtherWithTranslation as AddOtherController};

View file

@ -0,0 +1,35 @@
import React, {Component} from 'react';
import { f7 } from 'framework7-react';
import {Device} from '../../../../../common/mobile/utils/device';
import AddShape from '../../view/add/AddShape';
class AddShapeController extends Component {
constructor (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.asc_addShapeOnSheet(type);
this.closeModal();
}
render () {
return (
<AddShape onShapeClick={this.onShapeClick}
/>
)
}
}
export default AddShapeController;

View file

@ -30,3 +30,12 @@
--f7-popover-width: 360px;
//--f7-page-content-extra-padding-top: 37px;
}
.function-info {
padding: 0 15px;
}
.page-function-info {
&.page-content, .page-content {
background-color: @white;
}
}

View file

@ -1,3 +1,5 @@
import '../../../../common/Gateway.js';
import React from 'react';
import {App,Views,View,Navbar,NavLeft,NavRight,Link} from 'framework7-react';
@ -5,7 +7,6 @@ import { f7ready } from 'framework7-react';
import routes from '../router/routes.js';
import '../../../../common/Gateway.js';
import '../../../../common/main/lib/util/utils.js';
import Notifications from '../../../../common/mobile/utils/notifications.js'
import {MainController} from '../controller/Main';

View file

@ -9,6 +9,8 @@ import Statusbar from '../controller/StatusBar'
import AddOptions from "../view/add/Add";
import EditOptions from "../view/edit/Edit";
import {FunctionGroups} from "../controller/add/AddFunction";
export default class MainPage extends Component {
constructor(props) {
super(props);
@ -89,6 +91,8 @@ export default class MainPage extends Component {
<CollaborationView onclosed={this.handleOptionsViewClosed.bind(this, 'coauth')} />
}
<Statusbar />
<FunctionGroups /> {/* hidden component*/}
</Page>
)
}

View file

@ -136,11 +136,9 @@ export class storeFocusObjects {
@computed get shapeObject() {
const shapes = [];
console.log(this._focusObjects);
for (let object of this._focusObjects) {
if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Image) {
if (object.get_ObjectValue() && object.get_ObjectValue().get_ShapeProperties()) {
console.log(object);
shapes.push(object);
}
}
@ -155,10 +153,8 @@ export class storeFocusObjects {
@computed get imageObject() {
const images = [];
console.log(this._focusObjects);
for (let object of this._focusObjects) {
if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Image) {
console.log(object);
images.push(object);
}
}

View file

@ -0,0 +1,31 @@
import {action, computed} from 'mobx';
export class storeFunctions {
@action initFunctions (groups, data) {
this.groups = groups;
this.data = data;
}
@computed get functions () {
const groups = this.groups;
const data = this.data;
const functions = {};
for (let g in groups) {
const group = groups[g];
const groupname = group.asc_getGroupName();
const funcarr = group.asc_getFormulasArray();
for (let f in funcarr) {
const func = funcarr[f];
const _name = func.asc_getName();
functions[_name] = {
type: _name,
group: groupname,
caption: func.asc_getLocaleName(),
args: (data && data[_name]) ? data[_name].a : '',
descr: (data && data[_name]) ? data[_name].d : ''
};
}
}
return functions;
}
}

View file

@ -3,6 +3,7 @@
import {storeFocusObjects} from "./focusObjects";
import {storeUsers} from '../../../../common/mobile/lib/store/users';
import {storeWorksheets} from './sheets';
import {storeFunctions} from './functions';
import {storePalette} from "./palette";
// import {storeTextSettings} from "./textSettings";
// import {storeParagraphSettings} from "./paragraphSettings";
@ -17,6 +18,7 @@ export const stores = {
// storeDocumentSettings: new storeDocumentSettings(),
users: new storeUsers(),
sheets: new storeWorksheets(),
storeFunctions: new storeFunctions(),
// storeTextSettings: new storeTextSettings(),
// storeParagraphSettings: new storeParagraphSettings(),
storeShapeSettings: new storeShapeSettings(),

View file

@ -6,11 +6,53 @@ import { observer, inject } from "mobx-react";
import {Device} from '../../../../../common/mobile/utils/device';
import AddChartController from "../../controller/add/AddChart";
import AddFunctionController from "../../controller/add/AddFunction";
//import AddShapeController from "../../controller/add/AddShape";
//import {AddOtherController} from "../../controller/add/AddOther";
import {AddFunctionController} from "../../controller/add/AddFunction";
import {PageFunctionGroup, PageFunctionInfo} from "./AddFunction";
import AddShapeController from "../../controller/add/AddShape";
import {AddOtherController} from "../../controller/add/AddOther";
import {AddImageController} from "../../controller/add/AddImage";
import {PageImageLinkSettings} from "./AddImage";
import {AddLinkController} from "../../controller/add/AddLink";
import {PageTypeLink, PageSheet} from "./AddLink";
import AddFilterController from "../../controller/add/AddFilter";
const routes = [
// Functions
{
path: '/add-function-group/',
component: PageFunctionGroup
},
{
path: '/add-function-info/',
component: PageFunctionInfo
},
// Image
{
path: '/add-image/',
component: AddImageController
},
{
path: '/add-image-from-url/',
component: PageImageLinkSettings
},
// Link
{
path: '/add-link/',
component: AddLinkController
},
{
path: '/add-link-type/',
component: PageTypeLink
},
{
path: '/add-link-sheet/',
component: PageSheet
},
// Other
{
path: '/add-sort-and-filter/',
component: AddFilterController
}
];
const AddLayoutNavbar = ({ tabs, inPopover }) => {
@ -62,21 +104,40 @@ const AddTabs = props => {
caption: _t.textFunction,
id: 'add-function',
icon: 'icon-add-formula',
component: <AddFunctionController/>
component: <AddFunctionController onOptionClick={props.onOptionClick}/>
});
}
if (!showPanels || showPanels.indexOf('shape') > 0) {
tabs.push({
caption: _t.textShape,
id: 'add-shape',
icon: 'icon-add-shape',
component: <AddShapeController/>
});
}
if (showPanels && showPanels.indexOf('image') !== -1) {
tabs.push({
caption: _t.textImage,
id: 'add-image',
icon: 'icon-add-image',
component: <AddImageController inTabs={true}/>
});
}
if (!showPanels) {
tabs.push({
caption: _t.textOther,
id: 'add-other',
icon: 'icon-add-other',
component: <AddOtherController/>
});
}
if (showPanels && showPanels === 'hyperlink') {
tabs.push({
caption: _t.textAddLink,
id: 'add-link',
component: <AddLinkController/>
});
}
/*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}>
@ -93,8 +154,8 @@ class AddView extends Component {
this.onoptionclick = this.onoptionclick.bind(this);
}
onoptionclick(page){
f7.views.current.router.navigate(page);
onoptionclick(page, props){
f7.views.current.router.navigate(page, props);
}
render() {
const show_popover = this.props.usePopover;

View file

@ -0,0 +1,36 @@
import React, {useState} from 'react';
import {Page, Navbar, List, ListItem, Icon, Row, Toggle} from 'framework7-react';
import { useTranslation } from 'react-i18next';
const AddSortAndFilter = props => {
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
const isFilter = props.isFilter;
return (
<Page>
<Navbar title={_t.textSortAndFilter} backLink={_t.textBack}/>
<List>
<ListItem className='buttons'>
<Row>
<a className='button' onClick={() => {props.onInsertSort('down')}}>
<Icon slot="media" icon="sortdown"></Icon>
</a>
<a className='button' onClick={() => {props.onInsertSort('up')}}>
<Icon slot="media" icon="sortup"></Icon>
</a>
</Row>
</ListItem>
</List>
<List>
<ListItem title={_t.textFilter}>
<Toggle checked={isFilter}
onToggleChange={(prev) => {
props.onInsertFilter(!prev);
}}/>
</ListItem>
</List>
</Page>
)
};
export default AddSortAndFilter;

View file

@ -1,12 +1,143 @@
import React, {Fragment, useState} from 'react';
import {observer, inject} from "mobx-react";
import { useTranslation } from 'react-i18next';
import {List, ListItem, Page, Navbar, Icon, BlockTitle} from 'framework7-react';
const PageInfo = props => {
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
const f = props.functionInfo;
return(
<Page className='page-function-info'>
<Navbar title={f.caption} backLink={_t.textBack}/>
<div className='function-info'>
<h3>{`${f.caption} ${f.args}`}</h3>
<p>{f.descr}</p>
</div>
</Page>
)
};
const PageGroup = ({name, type, functions, onInsertFunction, f7router}) => {
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
const items = [];
for (let k in functions) {
if (functions[k].group == type)
items.push(functions[k]);
}
return (
<Page>
<Navbar title={name} backLink={_t.textBack}/>
<List>
{items.map((f, index) => {
return(
<ListItem key={`f-${index}`}
link={'#'}
title={f.caption}
className='no-indicator'
onClick={() => {onInsertFunction(f.type);}}
>
<div slot='after'
onClick={(event) => {
f7router.navigate('/add-function-info/', {
props: {
functionInfo: f
}
});
event.stopPropagation();
}}>
<Icon icon='icon-info'/>
</div>
</ListItem>
)
})}
</List>
</Page>
)
};
const AddFunction = props => {
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
const store = props.storeFunctions;
const functions = store.functions;
const quickFunctions = [
{caption: 'SUM', type: 'SUM'},
{caption: 'MIN', type: 'MIN'},
{caption: 'MAX', type: 'MAX'},
{caption: 'COUNT', type: 'COUNT'}
];
if (functions) {
quickFunctions.forEach((quickFunction) => {
const f = functions[quickFunction.type];
quickFunction.caption = f.caption;
quickFunction.args = f.args;
quickFunction.descr = f.descr;
});
}
let name = '';
const descriptions = ['DateAndTime', 'Engineering', 'Financial', 'Information', 'Logical', 'LookupAndReference', 'Mathematic', 'Statistical', 'TextAndData' ];
const groups = [];
for (let i = 0; i < descriptions.length; i++) {
name = descriptions[i];
name = _t['sCat' + name] || name;
groups.push({
type: descriptions[i],
name: name
})
}
return (
<Fragment>
<List>
{quickFunctions.map((f, index) => {
return (
<ListItem key={`f-${index}`}
title={f.caption}
className='no-indicator'
link='#'
onClick={() => {props.onInsertFunction(f.type);}}
>
<div slot='after'
onClick={(event) => {
props.onOptionClick('/add-function-info/', {
props: {
functionInfo: f
}
});
event.stopPropagation();
}}>
<Icon icon='icon-info'/>
</div>
</ListItem>
)
})}
</List>
<BlockTitle>{_t.textGroups}</BlockTitle>
<List>
{groups.map((group, index) => {
return(
<ListItem key={`gr-${index}`}
link={'/add-function-group/'}
title={group.name}
routeProps={{
name: group.name,
type: group.type,
functions: functions,
onInsertFunction: props.onInsertFunction
}}
/>
)
})}
</List>
</Fragment>
)
};
export default AddFunction;
const AddFunctionContainer = inject("storeFunctions")(observer(AddFunction));
export {
AddFunctionContainer as AddFunction,
PageGroup as PageFunctionGroup,
PageInfo as PageFunctionInfo
};

View file

@ -0,0 +1,61 @@
import React, {Fragment, useState} from 'react';
import {Page, Navbar, BlockTitle, List, ListItem, ListInput, ListButton, Icon} from 'framework7-react';
import { useTranslation } from 'react-i18next';
const AddImageList = 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>
)
};
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 (
props.inTabs ?
<AddImageList onInsertByFile={props.onInsertByFile} onInsertByUrl={ props.onInsertByUrl} /> :
<Page>
<Navbar title={_t.textImage} backLink={_t.textBack}/>
<AddImageList onInsertByFile={props.onInsertByFile} onInsertByUrl={ props.onInsertByUrl} />
</Page>
)
};
export {AddImage, PageLinkSettings as PageImageLinkSettings};

View file

@ -0,0 +1,151 @@
import React, {Fragment, useState} from 'react';
import {Page, Navbar, BlockTitle, List, ListItem, ListInput, ListButton, Icon} from 'framework7-react';
import { useTranslation } from 'react-i18next';
import {Device} from "../../../../../common/mobile/utils/device";
const PageTypeLink = ({curType, changeType}) => {
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
const [typeLink, setTypeLink] = useState(curType);
return (
<Page>
<Navbar title={_t.textLinkType} backLink={_t.textBack}/>
<List>
<ListItem title={_t.textExternalLink} radio checked={typeLink === 'ext'} onClick={() => {setTypeLink('ext'); changeType('ext');}}></ListItem>
<ListItem title={_t.textInternalDataRange} radio checked={typeLink === 'int'} onClick={() => {setTypeLink('int'); changeType('int');}}></ListItem>
</List>
</Page>
)
};
const PageSheet = ({curSheet, sheets, changeSheet}) => {
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
const [stateSheet, setSheet] = useState(curSheet.value);
return (
<Page>
<Navbar title={_t.textSheet} backLink={_t.textBack}/>
<List>
{sheets.map((sheet) => {
return(
<ListItem key={`sheet-${sheet.value}`}
title={sheet.caption}
radio
checked={stateSheet === sheet.value}
onClick={() => {
setSheet(sheet.value);
changeSheet(sheet);
}}
/>
)
})}
</List>
</Page>
)
};
const AddLinkView = props => {
const isIos = Device.ios;
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
const [typeLink, setTypeLink] = useState('ext');
const textType = typeLink === 'ext' ? _t.textExternalLink : _t.textInternalDataRange;
const changeType = (newType) => {
setTypeLink(newType);
};
const [link, setLink] = useState('');
let displayText = props.displayText;
const displayDisabled = displayText === 'locked';
displayText = displayDisabled ? _t.textSelectedRange : displayText;
const [stateDisplayText, setDisplayText] = useState(displayText);
const [screenTip, setScreenTip] = useState('');
const activeSheet = props.activeSheet;
const [curSheet, setSheet] = useState(activeSheet);
const changeSheet = (sheet) => {
setSheet(sheet);
};
const [range, setRange] = useState('');
return (
<Fragment>
<List inlineLabels className='inputs-list'>
{props.allowInternal &&
<ListItem link={'/add-link-type/'} title={_t.textLinkType} after={textType} routeProps={{
changeType: changeType,
curType: typeLink
}}/>
}
{typeLink === 'ext' &&
<ListInput label={_t.textLink}
type="text"
placeholder={_t.textLink}
value={link}
onChange={(event) => {setLink(event.target.value)}}
className={isIos ? 'list-input-right' : ''}
/>
}
{typeLink === 'int' &&
<ListItem link={'/add-link-sheet/'} title={_t.textSheet} after={curSheet.caption} routeProps={{
changeSheet: changeSheet,
sheets: props.sheets,
curSheet: curSheet
}}/>
}
{typeLink === 'int' &&
<ListInput label={_t.textRange}
type="text"
placeholder={_t.textRequired}
value={range}
onChange={(event) => {setRange(event.target.value)}}
className={isIos ? 'list-input-right' : ''}
/>
}
<ListInput label={_t.textDisplay}
type="text"
placeholder={_t.textDisplay}
value={stateDisplayText}
disabled={displayDisabled}
onChange={(event) => {setDisplayText(event.target.value)}}
className={isIos ? 'list-input-right' : ''}
/>
<ListInput label={_t.textScreenTip}
type="text"
placeholder={_t.textScreenTip}
value={screenTip}
onChange={(event) => {setScreenTip(event.target.value)}}
className={isIos ? 'list-input-right' : ''}
/>
</List>
<List>
<ListButton title={_t.textInsert}
className={`button-fill button-raised${(typeLink === 'ext' && link.length < 1 || typeLink === 'int' && range.length < 1) && ' disabled'}`}
onClick={() => {props.onInsertLink(typeLink === 'ext' ?
{type: 'ext', url: link, text: stateDisplayText, tooltip: screenTip} :
{type: 'int', url: range, sheet: curSheet.caption, text: stateDisplayText, tooltip: screenTip})}}
/>
</List>
</Fragment>
)
};
const AddLink = props => {
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
return (
props.inTabs ?
<AddLinkView allowInternal={props.allowInternal} displayText={props.displayText} sheets={props.sheets} activeSheet={props.activeSheet} onInsertLink={props.onInsertLink}/> :
<Page>
<Navbar title={_t.textAddLink} backLink={_t.textBack}/>
<AddLinkView allowInternal={props.allowInternal} displayText={props.displayText} sheets={props.sheets} activeSheet={props.activeSheet} onInsertLink={props.onInsertLink}/>
</Page>
)
};
export {AddLink, PageTypeLink, PageSheet};

View file

@ -0,0 +1,23 @@
import React from 'react';
import {List, ListItem, Icon} from 'framework7-react';
import { useTranslation } from 'react-i18next';
const AddOther = props => {
const { t } = useTranslation();
const _t = t('View.Add', {returnObjects: true});
return (
<List>
<ListItem title={_t.textImage} link={'/add-image/'}>
<Icon slot="media" icon="icon-insimage"></Icon>
</ListItem>
<ListItem title={_t.textLink} link={'/add-link/'}>
<Icon slot="media" icon="icon-link"></Icon>
</ListItem>
<ListItem title={_t.textSortAndFilter} link={'/add-sort-and-filter/'}>
<Icon slot="media" icon="icon-sort"></Icon>
</ListItem>
</List>
)
};
export {AddOther};

View file

@ -0,0 +1,27 @@
import React, {Fragment, useState} from 'react';
import {observer, inject} from "mobx-react";
const AddShape = props => {
const shapes = props.storeShapeSettings.getStyleGroups();
return (
<div className={'dataview shapes'}>
{shapes.map((row, indexRow) => {
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 default inject("storeShapeSettings")(observer(AddShape));

View file

@ -12,7 +12,6 @@ const EditShape = props => {
// const selections = storeFocusObjects.selections;
// console.log(selections);
const shapeObject = storeFocusObjects.shapeObject;
console.log(shapeObject);
const canFill = shapeObject.get_ShapeProperties().asc_getCanFill();
return (