Merge branch 'feature/mobile-apps-on-reactjs' into feature/mobile-apps-on-reactjs-se-edit-settings
This commit is contained in:
commit
ef0449b49b
|
@ -1,3 +1,5 @@
|
||||||
|
@import "./ios/_contextmenu";
|
||||||
|
@import "icons-ios";
|
||||||
|
|
||||||
.device-ios {
|
.device-ios {
|
||||||
@blockTitleColor: #6d6d72;
|
@blockTitleColor: #6d6d72;
|
||||||
|
@ -198,8 +200,11 @@
|
||||||
}
|
}
|
||||||
li.no-indicator {
|
li.no-indicator {
|
||||||
.item-link {
|
.item-link {
|
||||||
.item-inner:before {
|
.item-inner {
|
||||||
content: none;
|
padding-right: 15px;
|
||||||
|
&:before {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,6 +242,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.list-input-right input {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-buttons {
|
.tab-buttons {
|
||||||
|
|
|
@ -152,8 +152,11 @@
|
||||||
.list {
|
.list {
|
||||||
li.no-indicator {
|
li.no-indicator {
|
||||||
.item-link {
|
.item-link {
|
||||||
.item-inner:before {
|
.item-inner{
|
||||||
content: none;
|
padding-right: 15px;
|
||||||
|
&:before {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
9
apps/common/mobile/resources/less/icons-ios.less
Normal file
9
apps/common/mobile/resources/less/icons-ios.less
Normal 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>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,8 +5,15 @@ export default class Notifications {
|
||||||
}
|
}
|
||||||
|
|
||||||
on(event, callback) {
|
on(event, callback) {
|
||||||
!this._events[event] && (this._events[event] = []);
|
const addevent = (e, c) => {
|
||||||
this._events[event].push(callback);
|
!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) {
|
off(event, callback) {
|
||||||
|
|
74
apps/documenteditor/mobile/src/controller/ContextMenu.jsx
Normal file
74
apps/documenteditor/mobile/src/controller/ContextMenu.jsx
Normal 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 };
|
|
@ -134,6 +134,8 @@ class MainController extends Component {
|
||||||
const onDocumentContentReady = () => {
|
const onDocumentContentReady = () => {
|
||||||
Common.Gateway.documentReady();
|
Common.Gateway.documentReady();
|
||||||
f7.emit('resize');
|
f7.emit('resize');
|
||||||
|
|
||||||
|
Common.Notifications.trigger('document:ready');
|
||||||
};
|
};
|
||||||
|
|
||||||
const _process_array = (array, fn) => {
|
const _process_array = (array, fn) => {
|
||||||
|
|
|
@ -7,6 +7,7 @@ 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 { Device } from '../../../../common/mobile/utils/device'
|
import { Device } from '../../../../common/mobile/utils/device'
|
||||||
import { Search, SearchSettings } from '../controller/Search';
|
import { Search, SearchSettings } from '../controller/Search';
|
||||||
|
import { ContextMenu } from '../controller/ContextMenu';
|
||||||
|
|
||||||
export default class MainPage extends Component {
|
export default class MainPage extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -89,6 +90,7 @@ export default class MainPage extends Component {
|
||||||
!this.state.collaborationVisible ? null :
|
!this.state.collaborationVisible ? null :
|
||||||
<CollaborationView onclosed={this.handleOptionsViewClosed.bind(this, 'coauth')} />
|
<CollaborationView onclosed={this.handleOptionsViewClosed.bind(this, 'coauth')} />
|
||||||
}
|
}
|
||||||
|
{/*<ContextMenu />*/}
|
||||||
</Page>
|
</Page>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
50
apps/documenteditor/mobile/src/view/ContextMenu.jsx
Normal file
50
apps/documenteditor/mobile/src/view/ContextMenu.jsx
Normal 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;
|
|
@ -229,7 +229,22 @@
|
||||||
"textRemoveTable": "Remove Table",
|
"textRemoveTable": "Remove Table",
|
||||||
"textCellMargins": "Cell Margins",
|
"textCellMargins": "Cell Margins",
|
||||||
"textRemoveChart": "Remove Chart",
|
"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": {
|
"Common": {
|
||||||
|
|
|
@ -322,6 +322,14 @@ class MainController extends Component {
|
||||||
storeChartSettings.updateChartStyles(this.api.asc_getChartPreviews(storeFocusObjects.chartObject.getType()));
|
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() {
|
_onDocumentContentReady() {
|
||||||
|
|
114
apps/presentationeditor/mobile/src/controller/edit/EditLink.jsx
Normal file
114
apps/presentationeditor/mobile/src/controller/edit/EditLink.jsx
Normal 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};
|
|
@ -163,4 +163,19 @@ export class storeFocusObjects {
|
||||||
return undefined;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -5,4 +5,68 @@ export class storeLinkSettings {
|
||||||
@action canAddHyperlink (value) {
|
@action canAddHyperlink (value) {
|
||||||
this.canAddLink = 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import EditShapeController from "../../controller/edit/EditShape";
|
||||||
import EditImageController from "../../controller/edit/EditImage";
|
import EditImageController from "../../controller/edit/EditImage";
|
||||||
import EditTableController from "../../controller/edit/EditTable";
|
import EditTableController from "../../controller/edit/EditTable";
|
||||||
import EditChartController from "../../controller/edit/EditChart";
|
import EditChartController from "../../controller/edit/EditChart";
|
||||||
|
import { EditLinkController } from "../../controller/edit/EditLink";
|
||||||
|
|
||||||
import { Theme, Layout, Transition, Type, Effect, StyleFillColor, CustomFillColor } from './EditSlide';
|
import { Theme, Layout, Transition, Type, Effect, StyleFillColor, CustomFillColor } from './EditSlide';
|
||||||
import { PageTextFonts, PageTextFontColor, PageTextCustomFontColor, PageTextAddFormatting, PageTextBullets, PageTextNumbers, PageTextLineSpacing } from './EditText';
|
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 { PageImageReplace, PageImageReorder, PageImageAlign, PageLinkSettings } from './EditImage';
|
||||||
import { PageTableStyle, PageTableStyleOptions, PageTableCustomFillColor, PageTableBorderColor, PageTableCustomBorderColor, PageTableReorder, PageTableAlign } from './EditTable';
|
import { PageTableStyle, PageTableStyleOptions, PageTableCustomFillColor, PageTableBorderColor, PageTableCustomBorderColor, PageTableReorder, PageTableAlign } from './EditTable';
|
||||||
import { PageChartStyle, PageChartCustomFillColor, PageChartBorderColor, PageChartCustomBorderColor, PageChartReorder, PageChartAlign } from './EditChart'
|
import { PageChartStyle, PageChartCustomFillColor, PageChartBorderColor, PageChartCustomBorderColor, PageChartReorder, PageChartAlign } from './EditChart'
|
||||||
//import EditLinkController from "../../controller/edit/EditLink";
|
import { PageLinkTo, PageTypeLink } from './EditLink'
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
|
|
||||||
|
@ -194,6 +195,17 @@ const routes = [
|
||||||
{
|
{
|
||||||
path: '/edit-chart-custom-fill-color/',
|
path: '/edit-chart-custom-fill-color/',
|
||||||
component: PageChartCustomFillColor
|
component: PageChartCustomFillColor
|
||||||
|
},
|
||||||
|
|
||||||
|
// Link
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/edit-link-type/',
|
||||||
|
component: PageTypeLink
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/edit-link-to/',
|
||||||
|
component: PageLinkTo
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -303,14 +315,13 @@ const EditTabs = props => {
|
||||||
component: <EditChartController />
|
component: <EditChartController />
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if (settings.indexOf('hyperlink') > -1) {
|
if (settings.indexOf('hyperlink') > -1) {
|
||||||
editors.push({
|
editors.push({
|
||||||
caption: _t.textHyperlink,
|
caption: _t.textHyperlink,
|
||||||
id: 'edit-link',
|
id: 'edit-link',
|
||||||
component: <EditLinkController />
|
component: <EditLinkController />
|
||||||
})
|
})
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
187
apps/presentationeditor/mobile/src/view/edit/EditLink.jsx
Normal file
187
apps/presentationeditor/mobile/src/view/edit/EditLink.jsx
Normal 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}
|
|
@ -11,7 +11,42 @@
|
||||||
"textChart": "Chart",
|
"textChart": "Chart",
|
||||||
"textFunction": "Function",
|
"textFunction": "Function",
|
||||||
"textShape": "Shape",
|
"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" : {
|
"Edit" : {
|
||||||
"textSelectObjectToEdit": "Select object to edit",
|
"textSelectObjectToEdit": "Select object to edit",
|
||||||
|
|
|
@ -159,7 +159,7 @@ class MainController extends Component {
|
||||||
const {t} = this.props;
|
const {t} = this.props;
|
||||||
this.api = new Asc.spreadsheet_api({
|
this.api = new Asc.spreadsheet_api({
|
||||||
'id-view': 'editor_sdk',
|
'id-view': 'editor_sdk',
|
||||||
'id-input' : 'ce-cell-content',
|
'id-input': 'idx-cell-content',
|
||||||
'mobile': true
|
'mobile': true
|
||||||
// 'translate': translate
|
// 'translate': translate
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;
|
|
@ -1,12 +1,65 @@
|
||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
|
import {observer, inject} from "mobx-react";
|
||||||
import { f7 } from 'framework7-react';
|
import { f7 } from 'framework7-react';
|
||||||
import {Device} from '../../../../../common/mobile/utils/device';
|
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 {
|
class AddFunctionController extends Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
this.onInsertFunction = this.onInsertFunction.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
closeModal () {
|
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 () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<AddFunction
|
<AddFunction onInsertFunction={this.onInsertFunction}
|
||||||
|
onOptionClick={this.props.onOptionClick}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AddFunctionController;
|
export {FunctionGroups, AddFunctionController};
|
|
@ -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};
|
121
apps/spreadsheeteditor/mobile/src/controller/add/AddLink.jsx
Normal file
121
apps/spreadsheeteditor/mobile/src/controller/add/AddLink.jsx
Normal 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};
|
|
@ -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};
|
|
@ -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;
|
|
@ -30,3 +30,12 @@
|
||||||
--f7-popover-width: 360px;
|
--f7-popover-width: 360px;
|
||||||
//--f7-page-content-extra-padding-top: 37px;
|
//--f7-page-content-extra-padding-top: 37px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.function-info {
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
.page-function-info {
|
||||||
|
&.page-content, .page-content {
|
||||||
|
background-color: @white;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
import '../../../../common/Gateway.js';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import {App,Views,View,Navbar,NavLeft,NavRight,Link} from 'framework7-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 routes from '../router/routes.js';
|
||||||
|
|
||||||
import '../../../../common/Gateway.js';
|
|
||||||
import '../../../../common/main/lib/util/utils.js';
|
import '../../../../common/main/lib/util/utils.js';
|
||||||
import Notifications from '../../../../common/mobile/utils/notifications.js'
|
import Notifications from '../../../../common/mobile/utils/notifications.js'
|
||||||
import {MainController} from '../controller/Main';
|
import {MainController} from '../controller/Main';
|
||||||
|
|
|
@ -9,6 +9,8 @@ import Statusbar from '../controller/StatusBar'
|
||||||
import AddOptions from "../view/add/Add";
|
import AddOptions from "../view/add/Add";
|
||||||
import EditOptions from "../view/edit/Edit";
|
import EditOptions from "../view/edit/Edit";
|
||||||
|
|
||||||
|
import {FunctionGroups} from "../controller/add/AddFunction";
|
||||||
|
|
||||||
export default class MainPage extends Component {
|
export default class MainPage extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -89,6 +91,8 @@ export default class MainPage extends Component {
|
||||||
<CollaborationView onclosed={this.handleOptionsViewClosed.bind(this, 'coauth')} />
|
<CollaborationView onclosed={this.handleOptionsViewClosed.bind(this, 'coauth')} />
|
||||||
}
|
}
|
||||||
<Statusbar />
|
<Statusbar />
|
||||||
|
|
||||||
|
<FunctionGroups /> {/* hidden component*/}
|
||||||
</Page>
|
</Page>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,11 +136,9 @@ export class storeFocusObjects {
|
||||||
|
|
||||||
@computed get shapeObject() {
|
@computed get shapeObject() {
|
||||||
const shapes = [];
|
const shapes = [];
|
||||||
console.log(this._focusObjects);
|
|
||||||
for (let object of this._focusObjects) {
|
for (let object of this._focusObjects) {
|
||||||
if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Image) {
|
if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Image) {
|
||||||
if (object.get_ObjectValue() && object.get_ObjectValue().get_ShapeProperties()) {
|
if (object.get_ObjectValue() && object.get_ObjectValue().get_ShapeProperties()) {
|
||||||
console.log(object);
|
|
||||||
shapes.push(object);
|
shapes.push(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,10 +153,8 @@ export class storeFocusObjects {
|
||||||
|
|
||||||
@computed get imageObject() {
|
@computed get imageObject() {
|
||||||
const images = [];
|
const images = [];
|
||||||
console.log(this._focusObjects);
|
|
||||||
for (let object of this._focusObjects) {
|
for (let object of this._focusObjects) {
|
||||||
if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Image) {
|
if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Image) {
|
||||||
console.log(object);
|
|
||||||
images.push(object);
|
images.push(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
31
apps/spreadsheeteditor/mobile/src/store/functions.js
Normal file
31
apps/spreadsheeteditor/mobile/src/store/functions.js
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
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 {storeFunctions} from './functions';
|
||||||
import {storePalette} from "./palette";
|
import {storePalette} from "./palette";
|
||||||
// import {storeTextSettings} from "./textSettings";
|
// import {storeTextSettings} from "./textSettings";
|
||||||
// import {storeParagraphSettings} from "./paragraphSettings";
|
// import {storeParagraphSettings} from "./paragraphSettings";
|
||||||
|
@ -17,6 +18,7 @@ export const stores = {
|
||||||
// storeDocumentSettings: new storeDocumentSettings(),
|
// storeDocumentSettings: new storeDocumentSettings(),
|
||||||
users: new storeUsers(),
|
users: new storeUsers(),
|
||||||
sheets: new storeWorksheets(),
|
sheets: new storeWorksheets(),
|
||||||
|
storeFunctions: new storeFunctions(),
|
||||||
// storeTextSettings: new storeTextSettings(),
|
// storeTextSettings: new storeTextSettings(),
|
||||||
// storeParagraphSettings: new storeParagraphSettings(),
|
// storeParagraphSettings: new storeParagraphSettings(),
|
||||||
storeShapeSettings: new storeShapeSettings(),
|
storeShapeSettings: new storeShapeSettings(),
|
||||||
|
|
|
@ -6,11 +6,53 @@ import { observer, inject } from "mobx-react";
|
||||||
import {Device} from '../../../../../common/mobile/utils/device';
|
import {Device} from '../../../../../common/mobile/utils/device';
|
||||||
|
|
||||||
import AddChartController from "../../controller/add/AddChart";
|
import AddChartController from "../../controller/add/AddChart";
|
||||||
import AddFunctionController from "../../controller/add/AddFunction";
|
import {AddFunctionController} from "../../controller/add/AddFunction";
|
||||||
//import AddShapeController from "../../controller/add/AddShape";
|
import {PageFunctionGroup, PageFunctionInfo} from "./AddFunction";
|
||||||
//import {AddOtherController} from "../../controller/add/AddOther";
|
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 = [
|
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 }) => {
|
const AddLayoutNavbar = ({ tabs, inPopover }) => {
|
||||||
|
@ -62,21 +104,40 @@ const AddTabs = props => {
|
||||||
caption: _t.textFunction,
|
caption: _t.textFunction,
|
||||||
id: 'add-function',
|
id: 'add-function',
|
||||||
icon: 'icon-add-formula',
|
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 (
|
return (
|
||||||
<View style={props.style} stackPages={true} routes={routes}>
|
<View style={props.style} stackPages={true} routes={routes}>
|
||||||
<Page pageContent={false}>
|
<Page pageContent={false}>
|
||||||
|
@ -93,8 +154,8 @@ class AddView extends Component {
|
||||||
|
|
||||||
this.onoptionclick = this.onoptionclick.bind(this);
|
this.onoptionclick = this.onoptionclick.bind(this);
|
||||||
}
|
}
|
||||||
onoptionclick(page){
|
onoptionclick(page, props){
|
||||||
f7.views.current.router.navigate(page);
|
f7.views.current.router.navigate(page, props);
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
const show_popover = this.props.usePopover;
|
const show_popover = this.props.usePopover;
|
||||||
|
|
36
apps/spreadsheeteditor/mobile/src/view/add/AddFilter.jsx
Normal file
36
apps/spreadsheeteditor/mobile/src/view/add/AddFilter.jsx
Normal 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;
|
|
@ -1,12 +1,143 @@
|
||||||
import React, {Fragment, useState} from 'react';
|
import React, {Fragment, useState} from 'react';
|
||||||
import {observer, inject} from "mobx-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 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 (
|
return (
|
||||||
<Fragment>
|
<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>
|
</Fragment>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AddFunction;
|
const AddFunctionContainer = inject("storeFunctions")(observer(AddFunction));
|
||||||
|
|
||||||
|
export {
|
||||||
|
AddFunctionContainer as AddFunction,
|
||||||
|
PageGroup as PageFunctionGroup,
|
||||||
|
PageInfo as PageFunctionInfo
|
||||||
|
};
|
61
apps/spreadsheeteditor/mobile/src/view/add/AddImage.jsx
Normal file
61
apps/spreadsheeteditor/mobile/src/view/add/AddImage.jsx
Normal 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};
|
151
apps/spreadsheeteditor/mobile/src/view/add/AddLink.jsx
Normal file
151
apps/spreadsheeteditor/mobile/src/view/add/AddLink.jsx
Normal 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};
|
23
apps/spreadsheeteditor/mobile/src/view/add/AddOther.jsx
Normal file
23
apps/spreadsheeteditor/mobile/src/view/add/AddOther.jsx
Normal 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};
|
27
apps/spreadsheeteditor/mobile/src/view/add/AddShape.jsx
Normal file
27
apps/spreadsheeteditor/mobile/src/view/add/AddShape.jsx
Normal 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));
|
|
@ -12,7 +12,6 @@ const EditShape = props => {
|
||||||
// const selections = storeFocusObjects.selections;
|
// const selections = storeFocusObjects.selections;
|
||||||
// console.log(selections);
|
// console.log(selections);
|
||||||
const shapeObject = storeFocusObjects.shapeObject;
|
const shapeObject = storeFocusObjects.shapeObject;
|
||||||
console.log(shapeObject);
|
|
||||||
const canFill = shapeObject.get_ShapeProperties().asc_getCanFill();
|
const canFill = shapeObject.get_ShapeProperties().asc_getCanFill();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
Loading…
Reference in a new issue