diff --git a/apps/presentationeditor/mobile/index.html b/apps/presentationeditor/mobile/index.html deleted file mode 100644 index f10e8f8c0..000000000 --- a/apps/presentationeditor/mobile/index.html +++ /dev/null @@ -1,274 +0,0 @@ - - - - - - - - - - ONLYOFFICE Presentations - - - - - - - - - -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - - - - - - - - - - - diff --git a/apps/presentationeditor/mobile/src/app.js b/apps/presentationeditor/mobile/src/app.js new file mode 100644 index 000000000..048ac06ae --- /dev/null +++ b/apps/presentationeditor/mobile/src/app.js @@ -0,0 +1,42 @@ +// Import React and ReactDOM +import React, { Suspense } from 'react'; +import ReactDOM from 'react-dom'; + +// Import Framework7 +import Framework7 from 'framework7/framework7-lite.esm.bundle.js'; + +// Import Framework7-React Plugin +import Framework7React from 'framework7-react'; + +import jQuery from 'jquery'; +window.jQuery = jQuery; +window.$ = jQuery; + +// Import Framework7 Styles +import 'framework7/css/framework7.bundle.css'; + +// Import App Custom Styles +import './less/app.less'; + +// Import App Component +import App from './page/app'; +import { I18nextProvider } from 'react-i18next'; +import i18n from './lib/i18n.js'; + +import { Provider } from 'mobx-react' +import { stores } from './store/mainStore' + +// Init F7 React Plugin +Framework7.use(Framework7React) + +// Mount React App +ReactDOM.render( + + + + + + + , + document.getElementById('app'), +); \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/controller/Main.jsx b/apps/presentationeditor/mobile/src/controller/Main.jsx new file mode 100644 index 000000000..06c2b87c1 --- /dev/null +++ b/apps/presentationeditor/mobile/src/controller/Main.jsx @@ -0,0 +1,205 @@ + +import React, { Component } from 'react' +import { inject } from "mobx-react"; +import { withTranslation } from 'react-i18next'; +import CollaborationController from '../../../../common/mobile/lib/controller/Collaboration.jsx' + +class MainController extends Component { + constructor(props) { + super(props) + } + + initSdk() { + const script = document.createElement("script"); + script.src = "../../../../sdkjs/develop/sdkjs/slide/scripts.js"; + script.async = true; + script.onload = () => { + let dep_scripts = [ + '../../../vendor/xregexp/xregexp-all-min.js', + '../../../vendor/sockjs/sockjs.min.js']; + dep_scripts.push(...sdk_scripts); + + const promise_get_script = (scriptpath) => { + return new Promise((resolve, reject) => { + const script = document.createElement("script"); + script.src = scriptpath; + script.onload = () => { + resolve('ok'); + }; + script.onerror = () => { + reject('error'); + }; + + document.body.appendChild(script); + }); + }; + + const loadConfig = data => { + let me = this; + console.log('load config'); + + me.editorConfig = Object.assign({}, this.editorConfig, data.config); + me.appOptions.user = Common.Utils.fillUserInfo(me.editorConfig.user, me.editorConfig.lang, "Local.User"/*me.textAnonymous*/); + }; + + const loadDocument = data => { + this.permissions = {}; + this.document = data.doc; + + let docInfo = {}; + + if (data.doc) { + this.permissions = Object.assign(this.permissions, data.doc.permissions); + + let _permissions = Object.assign({}, data.doc.permissions), + _user = new Asc.asc_CUserInfo(); + _user.put_Id(this.appOptions.user.id); + _user.put_FullName(this.appOptions.user.fullname); + + docInfo = new Asc.asc_CDocInfo(); + docInfo.put_Id(data.doc.key); + docInfo.put_Url(data.doc.url); + docInfo.put_Title(data.doc.title); + docInfo.put_Format(data.doc.fileType); + docInfo.put_VKey(data.doc.vkey); + docInfo.put_Options(data.doc.options); + docInfo.put_UserInfo(_user); + docInfo.put_CallbackUrl(this.editorConfig.callbackUrl); + docInfo.put_Token(data.doc.token); + docInfo.put_Permissions(_permissions); + docInfo.put_EncryptedInfo(this.editorConfig.encryptionKeys); + + // var enable = !this.editorConfig.customization || (this.editorConfig.customization.macros!==false); + // docInfo.asc_putIsEnabledMacroses(!!enable); + // enable = !this.editorConfig.customization || (this.editorConfig.customization.plugins!==false); + // docInfo.asc_putIsEnabledPlugins(!!enable); + } + + this.api.asc_registerCallback('asc_onGetEditorPermissions', onEditorPermissions); + // this.api.asc_registerCallback('asc_onLicenseChanged', _.bind(this.onLicenseChanged, this)); + // this.api.asc_registerCallback('asc_onRunAutostartMacroses', _.bind(this.onRunAutostartMacroses, this)); + this.api.asc_setDocInfo(docInfo); + this.api.asc_getEditorPermissions(this.editorConfig.licenseUrl, this.editorConfig.customerId); + + // Common.SharedSettings.set('document', data.doc); + + // if (data.doc) { + // DE.getController('Toolbar').setDocumentTitle(data.doc.title); + // if (data.doc.info) { + // data.doc.info.author && console.log("Obsolete: The 'author' parameter of the document 'info' section is deprecated. Please use 'owner' instead."); + // data.doc.info.created && console.log("Obsolete: The 'created' parameter of the document 'info' section is deprecated. Please use 'uploaded' instead."); + // } + // } + }; + + const onEditorPermissions = params => { + let me = this; + const licType = params.asc_getLicenseType(); + + me.appOptions.canLicense = (licType === Asc.c_oLicenseResult.Success || licType === Asc.c_oLicenseResult.SuccessLimit); + // me.appOptions.canEdit = (me.permissions.edit !== false || me.permissions.review === true) && // can edit or review + // (me.editorConfig.canRequestEditRights || me.editorConfig.mode !== 'view') && // if mode=="view" -> canRequestEditRights must be defined + // (!me.appOptions.isReviewOnly || me.appOptions.canLicense) && // if isReviewOnly==true -> canLicense must be true + // me.isSupportEditFeature(); + // me.appOptions.isEdit = me.appOptions.canLicense && me.appOptions.canEdit && me.editorConfig.mode !== 'view'; + + // me.api.asc_setViewMode(!me.appOptions.isEdit); + me.api.asc_setViewMode(false); + me.api.asc_LoadDocument(); + }; + + const _process_array = (array, fn) => { + let results = []; + return array.reduce(function(p, item) { + return p.then(function() { + return fn(item).then(function(data) { + results.push(data); + return results; + }); + }); + }, Promise.resolve()); + }; + + _process_array(dep_scripts, promise_get_script) + .then ( result => { + const {t} = this.props; + this.api = new Asc.asc_docs_api({ + 'id-view': 'editor_sdk', + 'mobile': true, + 'translate': t('Controller.Main.SDK', {returnObjects:true}) + }); + + this.appOptions = {}; + this.bindEvents(); + + let value = null /*Common.localStorage.getItem("pe-settings-fontrender")*/; + if (value===null) value = window.devicePixelRatio > 1 ? '1' : '3'; + this.api.SetFontRenderingMode(parseInt(value)); + this.api.SetDrawingFreeze(true); + this.api.SetThemesPath("../../../../sdkjs/slide/themes/"); + // Common.Utils.Metric.setCurrentMetric(1); //pt + + Common.Gateway.on('init', loadConfig); + // Common.Gateway.on('showmessage', _.bind(me.onExternalMessage, me)); + Common.Gateway.on('opendocument', loadDocument); + Common.Gateway.appReady(); + + Common.Notifications.trigger('engineCreated', this.api); + Common.EditorApi = {get: () => this.api}; + }, error => { + console.log('promise failed ' + error); + }); + }; + + script.onerror = () => { + console.log('error'); + }; + + document.body.appendChild(script); + } + + bindEvents() { + const me = this; + // me.api.asc_registerCallback('asc_onError', _.bind(me.onError, me)); + me.api.asc_registerCallback('asc_onDocumentContentReady', me._onDocumentContentReady.bind(me)); + me.api.asc_registerCallback('asc_onOpenDocumentProgress', me._onOpenDocumentProgress.bind(me)); + // me.api.asc_registerCallback('asc_onDocumentUpdateVersion', _.bind(me.onUpdateVersion, me)); + // me.api.asc_registerCallback('asc_onServerVersion', _.bind(me.onServerVersion, me)); + // me.api.asc_registerCallback('asc_onAdvancedOptions', _.bind(me.onAdvancedOptions, me)); + // me.api.asc_registerCallback('asc_onDocumentName', _.bind(me.onDocumentName, me)); + // me.api.asc_registerCallback('asc_onPrintUrl', _.bind(me.onPrintUrl, me)); + // me.api.asc_registerCallback('asc_onThumbnailsShow', _.bind(me.onThumbnailsShow, me)); + // me.api.asc_registerCallback('asc_onMeta', _.bind(me.onMeta, me)); + } + + _onDocumentContentReady() { + const me = this; + me.api.SetDrawingFreeze(false); + + me.api.Resize(); + me.api.zoomFitToPage(); + // me.api.asc_GetDefaultTableStyles && _.defer(function () {me.api.asc_GetDefaultTableStyles()}); + + Common.Gateway.documentReady(); + } + + _onOpenDocumentProgress(progress) { + // if (this.loadMask) { + // var $title = $$(this.loadMask).find('.modal-title'), + // const proc = (progress.asc_getCurrentFont() + progress.asc_getCurrentImage())/(progress.asc_getFontsCount() + progress.asc_getImagesCount()); + + // $title.text(this.textLoadingDocument + ': ' + Math.min(Math.round(proc * 100), 100) + '%'); + // } + } + + render() { + return + } + + componentDidMount() { + this.initSdk(); + } +} + +const translated = withTranslation()(MainController); +export {translated as MainController}; diff --git a/apps/presentationeditor/mobile/src/index_dev.html b/apps/presentationeditor/mobile/src/index_dev.html new file mode 100644 index 000000000..4342a52b6 --- /dev/null +++ b/apps/presentationeditor/mobile/src/index_dev.html @@ -0,0 +1,95 @@ + + + + + + + + + + + + Presentation Editor + + + + + + + + + + + + + + +
+ + + + + \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/less/app-ios.less b/apps/presentationeditor/mobile/src/less/app-ios.less new file mode 100644 index 000000000..a1575794a --- /dev/null +++ b/apps/presentationeditor/mobile/src/less/app-ios.less @@ -0,0 +1,5 @@ + +.device-ios { + + +} diff --git a/apps/presentationeditor/mobile/src/less/app-material.less b/apps/presentationeditor/mobile/src/less/app-material.less new file mode 100644 index 000000000..879f3a67c --- /dev/null +++ b/apps/presentationeditor/mobile/src/less/app-material.less @@ -0,0 +1,24 @@ + +// Colors +@themeColorLight: #a2bdde; +@navBarIconColor: #fff; + + +.device-android { + --f7-navbar-bg-color: @themeColor; + --f7-navbar-link-color: @navBarIconColor; + --f7-navbar-text-color: @navBarIconColor; + + // Main Toolbar + #editor-navbar.navbar .right { + padding-right: 4px; + } + #editor-navbar.navbar .right a.link, + #editor-navbar.navbar .left a.link { + padding: 0 13px; + justify-content: space-between; + box-sizing: border-box; + align-items: center; + width: auto; + } +} \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/less/app.less b/apps/presentationeditor/mobile/src/less/app.less new file mode 100644 index 000000000..24c5dc0fb --- /dev/null +++ b/apps/presentationeditor/mobile/src/less/app.less @@ -0,0 +1,47 @@ +@themeColor: #446995; + +@import '../../../../common/mobile/resources/less/_mixins.less'; +@import '../../../../common/mobile/resources/less/collaboration.less'; +@import '../../../../common/mobile/resources/less/common.less'; +@import '../../../../common/mobile/resources/less/common-ios.less'; +@import '../../../../common/mobile/resources/less/common-material.less'; +@import './app-material.less'; +@import './app-ios.less'; +@import './icons-ios.less'; +@import './icons-material.less'; + +/* Left Panel right border when it is visible by breakpoint */ +.panel-left.panel-in-breakpoint:before { + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 1px; + background: rgba(0,0,0,0.1); + content: ''; + z-index: 6000; +} + +/* Hide navbar link which opens left panel when it is visible by breakpoint */ +.panel-left.panel-in-breakpoint ~ .view .navbar .panel-open[data-panel="left"] { + display: none; +} + +/* + Extra borders for main view and left panel for iOS theme when it behaves as panel (before breakpoint size) +*/ +.ios .panel-left:not(.panel-in-breakpoint).panel-in ~ .view-main:before, +.ios .panel-left:not(.panel-in-breakpoint).panel-closing ~ .view-main:before { + position: absolute; + left: 0; + top: 0; + height: 100%; + width: 1px; + background: rgba(0,0,0,0.1); + content: ''; + z-index: 6000; +} + +:root { + --f7-popover-width: 360px; +} diff --git a/apps/presentationeditor/mobile/src/lib/i18n.js b/apps/presentationeditor/mobile/src/lib/i18n.js new file mode 100644 index 000000000..b3d3566ee --- /dev/null +++ b/apps/presentationeditor/mobile/src/lib/i18n.js @@ -0,0 +1,17 @@ +import i18n from 'i18next' +import {initReactI18next} from 'react-i18next' +import Fetch from 'i18next-fetch-backend' + +i18n.use(initReactI18next) + .use(Fetch) + .init({ + lng: Common.Locale.currentLang, + fallbackLng: "en", + escapeValue: false, + backend: { + loadPath: './locale/{{lng}}.json' + }, + interpolation: { escapeValue: false }, + }); + +export default i18n; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/page/app.jsx b/apps/presentationeditor/mobile/src/page/app.jsx new file mode 100644 index 000000000..d8451deb7 --- /dev/null +++ b/apps/presentationeditor/mobile/src/page/app.jsx @@ -0,0 +1,44 @@ +import React from 'react'; + +import {App,Panel,Views,View,Popup,Page,Navbar,Toolbar,NavRight,Link,Block,BlockTitle,List,ListItem,ListInput,ListButton,BlockFooter} 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'; + +export default class extends React.Component { + constructor() { + super(); + + this.state = { + // Framework7 Parameters + f7params: { + name: 'Presentation Editor', // App name + theme: 'auto', // Automatic theme detection + + // App routes + routes: routes, + }, + } + + Common.Notifications = new Notifications(); + } + render() { + return ( + + {/* Your main view, should have "view-main" class */} + + + + ) + } + + componentDidMount() { + this.$f7ready((f7) => { + // Call F7 APIs here + }); + } +} diff --git a/apps/presentationeditor/mobile/src/page/main.jsx b/apps/presentationeditor/mobile/src/page/main.jsx new file mode 100644 index 000000000..b2bb7fdde --- /dev/null +++ b/apps/presentationeditor/mobile/src/page/main.jsx @@ -0,0 +1,80 @@ +import React, { Component } from 'react'; +import { Page, View, Navbar, NavLeft, NavRight, Link, Icon } from 'framework7-react'; + +// import EditOptions from '../view/edit/Edit'; +// import Settings from '../view/settings/Settings'; +import CollaborationView from '../../../../common/mobile/lib/view/Collaboration.jsx' + +export default class MainPage extends Component { + constructor(props) { + super(props); + this.state = { + editOptionsVisible: false, + settingsVisible: false, + collaborationVisible: false, + }; + } + + handleClickToOpenOptions = opts => { + this.setState(state => { + if ( opts == 'edit' ) + return {editOptionsVisible: true}; + else + if ( opts == 'settings' ) + return {settingsVisible: true}; + else + if ( opts == 'coauth' ) + return {collaborationVisible: true} + }); + }; + + handleOptionsViewClosed = opts => { + (async () => { + await 1 && this.setState(state => { + if ( opts == 'edit' ) + return {editOptionsVisible: false}; + else + if ( opts == 'settings' ) + return {settingsVisible: false}; + else + if ( opts == 'coauth' ) + return {collaborationVisible: false} + }) + })(); + }; + + render() { + console.log(this.$f7router) + return ( + + {/* Top Navbar */} + +
+ + + + + + this.handleClickToOpenOptions('edit')}> + this.handleClickToOpenOptions('coauth')}> + this.handleClickToOpenOptions('settings')}> + +
+ {/* Page content */} + + {/*{*/} + {/*!this.state.editOptionsVisible ? null :*/} + {/**/} + {/*}*/} + {/*{*/} + {/*!this.state.settingsVisible ? null :*/} + {/**/} + {/*}*/} + { + !this.state.collaborationVisible ? null : + + } +
+ ) + } +}; \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/router/routes.js b/apps/presentationeditor/mobile/src/router/routes.js new file mode 100644 index 000000000..027d62ae6 --- /dev/null +++ b/apps/presentationeditor/mobile/src/router/routes.js @@ -0,0 +1,17 @@ + +import MainPage from '../page/main'; + +import { PageCollaboration, PageUsers } from '../../../../common/mobile/lib/view/Collaboration.jsx'; + +var routes = [ + { + path: '/', + component: MainPage, + }, + { + path: '/users/', + component: PageUsers + }, +]; + +export default routes; diff --git a/apps/presentationeditor/mobile/src/store/mainStore.js b/apps/presentationeditor/mobile/src/store/mainStore.js new file mode 100644 index 000000000..05abdf386 --- /dev/null +++ b/apps/presentationeditor/mobile/src/store/mainStore.js @@ -0,0 +1,23 @@ + +// import {storeDocumentSettings} from './documentSettings'; +// import {storeFocusObjects} from "./focusObjects"; +import {storeUsers} from '../../../../common/mobile/lib/store/users'; +// import {storeTextSettings} from "./textSettings"; +// import {storeParagraphSettings} from "./paragraphSettings"; +// import {storeShapeSettings} from "./shapeSettings"; +// import {storeImageSettings} from "./imageSettings"; +// import {storeTableSettings} from "./tableSettings"; +// import {storeChartSettings} from "./chartSettings"; + +export const stores = { + // storeFocusObjects: new storeFocusObjects(), + // storeDocumentSettings: new storeDocumentSettings(), + users: new storeUsers(), + // storeTextSettings: new storeTextSettings(), + // storeParagraphSettings: new storeParagraphSettings(), + // storeShapeSettings: new storeShapeSettings(), + // storeChartSettings: new storeChartSettings(), + // storeImageSettings: new storeImageSettings(), + // storeTableSettings: new storeTableSettings() +}; +