[DE][mobile] framework7-react project

This commit is contained in:
Maxim Kadushkin 2020-07-31 20:33:13 +03:00
parent 929495644f
commit d1add672c5
46 changed files with 1250 additions and 211 deletions

40
apps/documenteditor/mobile/.gitignore vendored Normal file
View file

@ -0,0 +1,40 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Dependency directories
node_modules/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# Misc
.DS_Store
Thumbs.db
# Production build
www/

View file

@ -0,0 +1,74 @@
# Desktop Editor
## Framework7 CLI Options
Framework7 app created with following options:
```
{
"cwd": "E:\\Work\\Projects\\WebOffice\\web-apps\\apps\\documenteditor\\mobile",
"type": [
"web"
],
"name": "Desktop Editor",
"framework": "react",
"template": "split-view",
"cssPreProcessor": "less",
"bundler": "webpack",
"webpack": {
"developmentSourceMap": true,
"productionSourceMap": true,
"hashAssets": false,
"preserveAssetsPaths": false,
"inlineAssets": true
},
"theming": {
"customColor": false,
"color": "#007aff",
"darkTheme": false,
"iconFonts": true,
"fillBars": false
},
"customBuild": false
}
```
## NPM Scripts
* 🔥 `start` - run development server
* 🔧 `dev` - run development server
* 🔧 `build-dev` - build web app using development mode (faster build without minification and optimization)
* 🔧 `build-prod` - build web app for production
## WebPack
There is a webpack bundler setup. It compiles and bundles all "front-end" resources. You should work only with files located in `/src` folder. Webpack config located in `build/webpack.config.js`.
Webpack has specific way of handling static assets (CSS files, images, audios). You can learn more about correct way of doing things on [official webpack documentation](https://webpack.js.org/guides/asset-management/).
## Assets
Assets (icons, splash screens) source images located in `assets-src` folder. To generate your own icons and splash screen images, you will need to replace all assets in this directory with your own images (pay attention to image size and format), and run the following command in the project directory:
```
framework7 assets
```
Or launch UI where you will be able to change icons and splash screens:
```
framework7 assets --ui
```
## Documentation & Resources
* [Framework7 Core Documentation](https://framework7.io/docs/)
* [Framework7 React Documentation](https://framework7.io/react/)
* [Framework7 Icons Reference](https://framework7.io/icons/)
* [Community Forum](https://forum.framework7.io)
## Support Framework7
Love Framework7? Support project by donating or pledging on patreon:
https://patreon.com/vladimirkharlampidi

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,12 @@
module.exports = {
presets: [
'@babel/preset-react',
['@babel/preset-env', {
modules: false,
}],
],
plugins: [
'@babel/plugin-transform-runtime',
'@babel/plugin-syntax-dynamic-import',
],
};

View file

@ -0,0 +1,36 @@
const webpack = require('webpack');
const ora = require('ora');
const rm = require('rimraf');
const chalk = require('chalk');
const config = require('./webpack.config.js');
const env = process.env.NODE_ENV || 'development';
const target = process.env.TARGET || 'web';
const isCordova = target === 'cordova'
const spinner = ora(env === 'production' ? 'building for production...' : 'building development version...');
spinner.start();
rm(isCordova ? './cordova/www' : './www/', (removeErr) => {
if (removeErr) throw removeErr;
webpack(config, (err, stats) => {
if (err) throw err;
spinner.stop();
process.stdout.write(`${stats.toString({
colors: true,
modules: false,
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
chunks: false,
chunkModules: false,
})}\n\n`);
if (stats.hasErrors()) {
console.log(chalk.red('Build failed with errors.\n'));
process.exit(1);
}
console.log(chalk.cyan('Build complete.\n'));
});
});

View file

@ -0,0 +1,232 @@
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const path = require('path');
function resolvePath(dir) {
return path.join(__dirname, '..', dir);
}
const env = process.env.NODE_ENV || 'development';
const target = process.env.TARGET || 'web';
module.exports = {
mode: env,
entry: {
app: './src/js/app.js',
},
output: {
path: resolvePath('./'),
filename: 'js/[name].js',
chunkFilename: 'js/[name].js',
publicPath: '',
hotUpdateChunkFilename: 'hot/hot-update.js',
hotUpdateMainFilename: 'hot/hot-update.json',
},
resolve: {
extensions: ['.js', '.jsx', '.json'],
alias: {
'@': resolvePath('src'),
},
},
watch: true,
watchOptions: {
aggregateTimeout: 600,
poll: 1000,
},
externals: {
jquery: 'jQuery'
},
devtool: env === 'production' ? 'source-map' : 'source-map',
devServer: {
hot: true,
open: false,
compress: true,
contentBase: '/www/',
disableHostCheck: true,
historyApiFallback: true,
watchOptions: {
poll: 1000,
},
},
optimization: {
minimizer: [new TerserPlugin({
sourceMap: true,
})],
},
module: {
rules: [
{
test: /\.(mjs|js|jsx)$/,
use: 'babel-loader',
include: [
resolvePath('src'),
resolvePath('node_modules/framework7'),
resolvePath('node_modules/framework7-react'),
resolvePath('node_modules/template7'),
resolvePath('node_modules/dom7'),
resolvePath('node_modules/ssr-window'),
],
},
{
test: /\.css$/,
use: [
(env === 'development' ? 'style-loader' : {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../www'
}
}),
'css-loader',
'postcss-loader',
],
},
{
test: /\.styl(us)?$/,
use: [
(env === 'development' ? 'style-loader' : {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../www'
}
}),
'css-loader',
'postcss-loader',
'stylus-loader',
],
},
{
test: /\.less$/,
use: [
(env === 'development' ? 'style-loader' : {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../www'
}
}),
'css-loader',
'postcss-loader',
'less-loader',
],
},
{
test: /\.(sa|sc)ss$/,
use: [
(env === 'development' ? 'style-loader' : {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../www'
}
}),
'css-loader',
'postcss-loader',
'sass-loader',
],
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'images/[name].[ext]',
},
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac|m4a)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'media/[name].[ext]',
},
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'fonts/[name].[ext]',
},
},
{
test: /jquery.+\.js$/,
use: [{
loader: 'expose-loader',
options: 'jQuery'
},{
loader: 'expose-loader',
options: '$'
}]
},
],
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(env),
'process.env.TARGET': JSON.stringify(target),
}),
...(env === 'production' ? [
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true,
map: { inline: false },
},
}),
new webpack.optimize.ModuleConcatenationPlugin(),
] : [
// Development only plugins
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
]),
new HtmlWebpackPlugin({
filename: './index.html',
template: './index_dev.html',
inject: true,
minify: env === 'production' ? {
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true
} : false,
}),
new MiniCssExtractPlugin({
filename: 'css/[name].css',
}),
new CopyWebpackPlugin({
patterns: [
{
noErrorOnMissing: true,
from: resolvePath('src/static'),
to: resolvePath('www/static'),
},
],
}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
}),
],
};

View file

@ -0,0 +1,26 @@
{
"cwd": "E:\\Work\\Projects\\WebOffice\\web-apps\\apps\\documenteditor\\mobile",
"type": [
"web"
],
"name": "Desktop Editor",
"framework": "react",
"template": "split-view",
"cssPreProcessor": "less",
"bundler": "webpack",
"webpack": {
"developmentSourceMap": true,
"productionSourceMap": true,
"hashAssets": false,
"preserveAssetsPaths": false,
"inlineAssets": true
},
"theming": {
"customColor": false,
"color": "#007aff",
"darkTheme": false,
"iconFonts": true,
"fillBars": false
},
"customBuild": false
}

View file

@ -1,224 +1,89 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="mobile-web-app-capable" content="yes">
<head>
<meta charset="utf-8">
<!--
Customize this policy to fit your own app's needs. For more guidance, see:
https://github.com/apache/cordova-plugin-whitelist/blob/master/README.md#content-security-policy
Some notes:
* https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly
* Disables use of inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:
* Enable inline JS: add 'unsafe-inline' to default-src
-->
<meta http-equiv="Content-Security-Policy" content="default-src * 'self' 'unsafe-inline' 'unsafe-eval' data: gap: content:">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover">
<title>ONLYOFFICE Documents</title>
<meta name="theme-color" content="#007aff">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
<title>Desktop Editor</title>
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="apple-touch-icon" href="static/icons/apple-touch-icon.png">
<link rel="icon" href="static/icons/favicon.png">
<!-- built styles file will be auto injected -->
</head>
<body>
<script>
const getUrlParams = () => {
let e,
a = /\+/g, // Regex for replacing addition symbol with a space
r = /([^&=]+)=?([^&]*)/g,
d = s => decodeURIComponent(s.replace(a, " ")),
q = window.location.search.substring(1),
urlParams = {};
<link href="https://fonts.googleapis.com/css?family=Roboto:400,300,500,700" rel="stylesheet" type="text/css">
<!-- App styles -->
while (e = r.exec(q))
urlParams[d(e[1])] = d(e[2]);
<!-- splash -->
return urlParams;
};
<style type="text/css">
.loadmask {
left: 0;
top: 0;
position: absolute;
height: 100%;
width: 100%;
overflow: hidden;
border: none;
background-color: #f4f4f4;
z-index: 10000;
const encodeUrlParam = str => str.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
let params = getUrlParams(),
lang = (params["lang"] || 'en').split(/[\-\_]/)[0],
logo = /*params["headerlogo"] ? encodeUrlParam(params["headerlogo"]) : */null,
logoOO = null;
if (!logo) {
logoOO = /Android/.test(navigator.userAgent) ? "../../common/mobile/resources/img/header/header-logo-android.png" : "../../common/mobile/resources/img/header/header-logo-ios.png";
}
window.frameEditorId = params["frameEditorId"];
window.parentOrigin = params["parentOrigin"];
let brendpanel = document.getElementsByClassName('brendpanel')[0];
if (brendpanel) {
if (/Android/.test(navigator.userAgent)) {
brendpanel.classList.add('android');
}
brendpanel.classList.add('visible');
.loadmask > .brendpanel {
width: 100%;
position: absolute;
height: 68px;
background-color: #e2e2e2;
opacity: 0;
let elem = document.querySelector('.loading-logo');
if (elem) {
logo && (elem.innerHTML = '<img src=' + logo + '>');
logoOO && (elem.innerHTML = '<img src=' + logoOO + '>');
elem.style.opacity = 1;
}
.loadmask > .brendpanel.visible {
opacity: 1;
var placeholder = document.getElementsByClassName('placeholder')[0];
if (placeholder && /Android/.test(navigator.userAgent)) {
placeholder.classList.add('android');
}
}
</script>
.loadmask > .brendpanel.android {
height: 80px;
background: #446995;
}
<script type="text/javascript" src="../../../vendor/jquery/jquery.min.js"></script>
.loadmask > .brendpanel > div {
display: flex;
align-items: flex-start;
height: 100%;
}
<div id="app"></div>
<!-- built script files will be auto injected -->
.loadmask > .brendpanel .loading-logo {
max-width: 200px;
height: 20px;
margin: 0 auto;
margin-top: 12px;
line-height: 14px;
opacity: 0;
}
.loadmask > .brendpanel .loading-logo > img {
display: inline-block;
max-width: 100px;
max-height: 20px;
}
.loadmask > .brendpanel .circle {
width: 28px;
height: 28px;
border-radius: 14px;
margin: 0 16px;
margin-bottom: 10px;
align-self: flex-end;
background: rgba(255, 255, 255, 0.3);
}
.loadmask > .brendpanel.android .circle {
margin-bottom: 12px;
background: rgba(255, 255, 255, 0.2);
}
.loadmask > .placeholder {
background: #fbfbfb;
width: 100%;
height: 100%;
padding-top: 65px;
}
.loadmask > .placeholder.android {
padding-top: 75px;
}
.loadmask > .placeholder > .line {
height: 15px;
margin: 30px;
background: #e2e2e2;
overflow: hidden;
position: relative;
-webkit-animation: flickerAnimation 2s infinite ease-in-out;
-moz-animation: flickerAnimation 2s infinite ease-in-out;
-o-animation: flickerAnimation 2s infinite ease-in-out;
animation: flickerAnimation 2s infinite ease-in-out;
}
@keyframes flickerAnimation {
0% { opacity:0.1; }
50% { opacity:1; }
100% { opacity:0.1; }
}
@-o-keyframes flickerAnimation{
0% { opacity:0.1; }
50% { opacity:1; }
100% { opacity:0.1; }
}
@-moz-keyframes flickerAnimation{
0% { opacity:0.1; }
50% { opacity:1; }
100% { opacity:0.1; }
}
@-webkit-keyframes flickerAnimation{
0% { opacity:0.1; }
50% { opacity:1; }
100% { opacity:0.1; }
}
</style>
</head>
<body>
<div id="loading-mask" class="loadmask"><div class="brendpanel"><div><div class="circle"></div><div class="loading-logo"></div><div class="circle"></div></div></div><div class="placeholder"><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div><div class="line"></div></div></div>
<script type="text/javascript">
function getUrlParams() {
var e,
a = /\+/g, // Regex for replacing addition symbol with a space
r = /([^&=]+)=?([^&]*)/g,
d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
q = window.location.search.substring(1),
urlParams = {};
while (e = r.exec(q))
urlParams[d(e[1])] = d(e[2]);
return urlParams;
}
function encodeUrlParam(str) {
return str.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
}
var params = getUrlParams(),
lang = (params["lang"] || 'en').split(/[\-\_]/)[0],
logo = /*params["headerlogo"] ? encodeUrlParam(params["headerlogo"]) : */null,
logoOO = null;
if (!logo) {
logoOO = /Android/.test(navigator.userAgent) ? "../../common/mobile/resources/img/header/header-logo-android.png" : "../../common/mobile/resources/img/header/header-logo-ios.png";
}
window.frameEditorId = params["frameEditorId"];
window.parentOrigin = params["parentOrigin"];
var brendpanel = document.getElementsByClassName('brendpanel')[0];
if (brendpanel) {
if (/Android/.test(navigator.userAgent)) {
brendpanel.classList.add('android');
}
brendpanel.classList.add('visible');
var elem = document.querySelector('.loading-logo');
if (elem) {
logo && (elem.innerHTML = '<img src=' + logo + '>');
logoOO && (elem.innerHTML = '<img src=' + logoOO + '>');
elem.style.opacity = 1;
}
var placeholder = document.getElementsByClassName('placeholder')[0];
if (placeholder && /Android/.test(navigator.userAgent)) {
placeholder.classList.add('android');
}
}
</script>
<script type="text/javascript" src="../../../vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../../../vendor/xregexp/xregexp-all-min.js"></script>
<script type="text/javascript" src="../../../../sdkjs/develop/sdkjs/word/scripts.js"></script>
<script>
var ua = navigator.userAgent;
if (/Sailfish/.test(ua) || /Jolla/.test(ua)) {
document.write('<script type="text/javascript" src="../../../vendor/iscroll/iscroll.min.js"><\/script>');
if (!/Android/.test(ua)) {
var ua = navigator.userAgent + ';Android 5.0;';
Object.defineProperty(navigator, 'userAgent', {
get: function () { return ua; }
});
}
}
window.sdk_scripts.forEach(function(item){
document.write('<script type="text/javascript" src="' + item + '"><\/script>');
});
window.requireTimeourError = function(){
var reqerr;
if ( lang == 'de') reqerr = 'Die Verbindung ist zu langsam, einige Komponenten konnten nicht geladen werden. Aktualisieren Sie bitte die Seite.';
else if ( lang == 'es') reqerr = 'La conexión es muy lenta, algunos de los componentes no han podido cargar. Por favor recargue la página.';
else if ( lang == 'fr') reqerr = 'La connexion est trop lente, certains des composants n\'ons pas pu être chargé. Veuillez recharger la page.';
else if ( lang == 'ru') reqerr = 'Слишком медленное соединение, не удается загрузить некоторые компоненты. Пожалуйста, обновите страницу.';
else reqerr = 'The connection is too slow, some of the components could not be loaded. Please reload the page.';
return reqerr;
};
</script>
<!-- application -->
<script data-main="app-dev" src="../../../vendor/requirejs/require.js"></script>
</body>
</html>
<script src="js/app.js"></script></body>
</html>

View file

@ -0,0 +1,89 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!--
Customize this policy to fit your own app's needs. For more guidance, see:
https://github.com/apache/cordova-plugin-whitelist/blob/master/README.md#content-security-policy
Some notes:
* https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly
* Disables use of inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:
* Enable inline JS: add 'unsafe-inline' to default-src
-->
<meta http-equiv="Content-Security-Policy" content="default-src * 'self' 'unsafe-inline' 'unsafe-eval' data: gap: content:">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover">
<meta name="theme-color" content="#007aff">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
<title>Desktop Editor</title>
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="apple-touch-icon" href="static/icons/apple-touch-icon.png">
<link rel="icon" href="static/icons/favicon.png">
<!-- built styles file will be auto injected -->
</head>
<body>
<script>
const getUrlParams = () => {
let e,
a = /\+/g, // Regex for replacing addition symbol with a space
r = /([^&=]+)=?([^&]*)/g,
d = s => decodeURIComponent(s.replace(a, " ")),
q = window.location.search.substring(1),
urlParams = {};
while (e = r.exec(q))
urlParams[d(e[1])] = d(e[2]);
return urlParams;
};
const encodeUrlParam = str => str.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
let params = getUrlParams(),
lang = (params["lang"] || 'en').split(/[\-\_]/)[0],
logo = /*params["headerlogo"] ? encodeUrlParam(params["headerlogo"]) : */null,
logoOO = null;
if (!logo) {
logoOO = /Android/.test(navigator.userAgent) ? "../../common/mobile/resources/img/header/header-logo-android.png" : "../../common/mobile/resources/img/header/header-logo-ios.png";
}
window.frameEditorId = params["frameEditorId"];
window.parentOrigin = params["parentOrigin"];
let brendpanel = document.getElementsByClassName('brendpanel')[0];
if (brendpanel) {
if (/Android/.test(navigator.userAgent)) {
brendpanel.classList.add('android');
}
brendpanel.classList.add('visible');
let elem = document.querySelector('.loading-logo');
if (elem) {
logo && (elem.innerHTML = '<img src=' + logo + '>');
logoOO && (elem.innerHTML = '<img src=' + logoOO + '>');
elem.style.opacity = 1;
}
var placeholder = document.getElementsByClassName('placeholder')[0];
if (placeholder && /Android/.test(navigator.userAgent)) {
placeholder.classList.add('android');
}
}
</script>
<script type="text/javascript" src="../../../vendor/jquery/jquery.min.js"></script>
<div id="app"></div>
<!-- built script files will be auto injected -->
</body>
</html>

View file

@ -0,0 +1,63 @@
{
"name": "desktop-editor",
"private": true,
"version": "1.0.0",
"description": "Desktop Editor",
"repository": "",
"license": "UNLICENSED",
"scripts": {
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development webpack-dev-server --config ./build/webpack.config.js",
"build-dev": "cross-env NODE_ENV=development node ./build/build.js",
"build-prod": "cross-env NODE_ENV=production node ./build/build.js",
"postinstall": "cpy ./node_modules/framework7-icons/fonts/*.* ./src/fonts/"
},
"browserslist": [
"Android >= 7",
"IOS >= 11",
"Safari >= 11",
"Chrome >= 49",
"Firefox >= 31",
"Samsung >= 5"
],
"dependencies": {
"dom7": "^2.1.5",
"framework7": "^5.7.10",
"framework7-icons": "^3.0.1",
"framework7-react": "^5.7.10",
"prop-types": "^15.7.2",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"template7": "^1.4.2"
},
"devDependencies": {
"@babel/core": "^7.10.5",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.10.5",
"@babel/preset-env": "^7.10.4",
"@babel/preset-react": "^7.10.4",
"@babel/runtime": "^7.10.5",
"babel-loader": "^8.1.0",
"chalk": "^4.1.0",
"copy-webpack-plugin": "^6.0.3",
"cpy-cli": "^3.1.1",
"cross-env": "^7.0.2",
"css-loader": "^4.0.0",
"file-loader": "^6.0.0",
"html-webpack-plugin": "^4.3.0",
"less": "^3.12.2",
"less-loader": "^6.2.0",
"mini-css-extract-plugin": "^0.9.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"ora": "^4.0.5",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"rimraf": "^3.0.2",
"style-loader": "^1.2.1",
"terser-webpack-plugin": "^3.0.7",
"url-loader": "^4.1.0",
"webpack": "^4.44.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0"
}
}

View file

@ -0,0 +1,5 @@
module.exports = {
plugins: {
'postcss-preset-env': {},
},
};

View file

@ -0,0 +1,256 @@
import React from 'react';
import {
App,
Panel,
Views,
View,
Popup,
Page,
Navbar,
Toolbar,
NavRight,
Link,
Block,
BlockTitle,
LoginScreen,
LoginScreenTitle,
List,
ListItem,
ListInput,
ListButton,
BlockFooter
} from 'framework7-react';
import routes from '../js/routes';
import '../../../../common/Gateway.js';
import '../../../../common/main/lib/util/utils.js';
export default class extends React.Component {
constructor() {
super();
this.state = {
// Framework7 Parameters
f7params: {
name: 'Desktop Editor', // App name
theme: 'auto', // Automatic theme detection
// App routes
routes: routes,
},
// Login screen demo data
username: '',
password: '',
}
}
render() {
return (
<App params={ this.state.f7params } >
{/* Left panel with cover effect when hidden */}
<Panel left cover themeDark visibleBreakpoint={960}>
<View>
<Page>
<Navbar title="Left Panel"/>
<BlockTitle>Left View Navigation</BlockTitle>
<List>
<ListItem link="/left-page-1/" title="Left Page 1"/>
<ListItem link="/left-page-2/" title="Left Page 2"/>
</List>
</Page>
</View>
</Panel>
{/* Right panel with reveal effect*/}
<Panel right reveal themeDark>
<View>
<Page>
<Navbar title="Right Panel"/>
<Block>Right panel content goes here</Block>
</Page>
</View>
</Panel>
{/* Your main view, should have "view-main" class */}
<View main className="safe-areas" url="/" />
{/* Popup */}
<Popup id="my-popup">
<View>
<Page>
<Navbar title="Popup">
<NavRight>
<Link popupClose>Close</Link>
</NavRight>
</Navbar>
<Block>
<p>Popup content goes here.</p>
</Block>
</Page>
</View>
</Popup>
</App>
)
}
alertLoginData() {
this.$f7.dialog.alert('Username: ' + this.state.username + '<br>Password: ' + this.state.password, () => {
this.$f7.loginScreen.close();
});
}
componentDidMount() {
this.$f7ready((f7) => {
// Call F7 APIs here
});
const script = document.createElement("script");
script.src = "../../../../sdkjs/develop/sdkjs/word/scripts.js";
script.async = true;
script.onload = () => {
let dep_scripts = ['../../../vendor/xregexp/xregexp-all-min.js',
'../../../vendor/sockjs/sockjs.min.js',
'../../../vendor/jszip/jszip.min.js',
'../../../vendor/jszip-utils/jszip-utils.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 = () => {
console.log('loaded ' + scriptpath);
resolve('ok');
};
script.onerror = () => {
console.log('error ' + scriptpath);
reject('error');
};
document.body.appendChild(script);
});
};
const loadConfig = data => {
let me = this;
console.log('load config');
me.editorConfig = Object.assign({}, this.editorConfig, data);
// 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);
// let type = /^(?:(pdf|djvu|xps))$/.exec(data.doc.fileType);
// if (type && typeof type[1] === 'string') {
// this.permissions.edit = this.permissions.review = false;
// }
}
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();
me.api.Resize();
};
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 => {
this.api = new Asc.asc_docs_api({
'id-view' : 'editor_sdk',
'mobile' : true,
// 'translate': translate
});
this.appOptions = {};
Common.Gateway.on('init', loadConfig);
// Common.Gateway.on('showmessage', _.bind(me.onExternalMessage, me));
Common.Gateway.on('opendocument', loadDocument);
Common.Gateway.appReady();
}, error => {
console.log('promise failed ' + error);
});
};
script.onerror = () => {
console.log('error');
};
document.body.appendChild(script);
}
}

View file

@ -0,0 +1,31 @@
/* 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;
}

View file

@ -0,0 +1,61 @@
/* Material Icons Font (for MD theme) */
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(../fonts/MaterialIcons-Regular.eot);
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url(../fonts/MaterialIcons-Regular.woff2) format('woff2'),
url(../fonts/MaterialIcons-Regular.woff) format('woff'),
url(../fonts/MaterialIcons-Regular.ttf) format('truetype');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
font-feature-settings: 'liga';
}
/* Framework7 Icons Font (for iOS theme) */
@font-face {
font-family: 'Framework7 Icons';
font-style: normal;
font-weight: 400;
src: url("../fonts/Framework7Icons-Regular.eot");
src: url("../fonts/Framework7Icons-Regular.woff2") format("woff2"),
url("../fonts/Framework7Icons-Regular.woff") format("woff"),
url("../fonts/Framework7Icons-Regular.ttf") format("truetype");
}
.f7-icons {
font-family: 'Framework7 Icons';
font-weight: normal;
font-style: normal;
font-size: 28px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
-webkit-font-feature-settings: "liga";
-moz-font-feature-settings: "liga=1";
-moz-font-feature-settings: "liga";
font-feature-settings: "liga";
text-align: center;
}

View file

@ -0,0 +1,32 @@
// Import React and ReactDOM
import React 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 Icons and App Custom Styles
import '../css/icons.css';
import '../css/app.less';
// Import App Component
import App from '../components/app.jsx';
// Init F7 React Plugin
Framework7.use(Framework7React)
// Mount React App
ReactDOM.render(
React.createElement(App),
document.getElementById('app'),
);

View file

@ -0,0 +1,78 @@
import HomePage from '../pages/home.jsx';
import LeftPage1 from '../pages/left-page-1.jsx';
import LeftPage2 from '../pages/left-page-2.jsx';
import DynamicRoutePage from '../pages/dynamic-route.jsx';
import RequestAndLoad from '../pages/request-and-load.jsx';
var routes = [
{
path: '/',
component: HomePage,
},
{
path: '/left-page-1/',
component: LeftPage1,
},
{
path: '/left-page-2/',
component: LeftPage2,
},
{
path: '/dynamic-route/blog/:blogId/post/:postId/',
component: DynamicRoutePage,
},
{
path: '/request-and-load/user/:userId/',
async: function (routeTo, routeFrom, resolve, reject) {
// Router instance
var router = this;
// App instance
var app = router.app;
// Show Preloader
app.preloader.show();
// User ID from request
var userId = routeTo.params.userId;
// Simulate Ajax Request
setTimeout(function () {
// We got user data from request
var user = {
firstName: 'Vladimir',
lastName: 'Kharlampidi',
about: 'Hello, i am creator of Framework7! Hope you like it!',
links: [
{
title: 'Framework7 Website',
url: 'http://framework7.io',
},
{
title: 'Framework7 Forum',
url: 'http://forum.framework7.io',
},
]
};
// Hide Preloader
app.preloader.hide();
// Resolve route to load page
resolve(
{
component: RequestAndLoad,
},
{
context: {
user: user,
}
}
);
}, 1000);
},
},
];
export default routes;

View file

@ -0,0 +1,37 @@
import React, { Component } from 'react';
import { Page, Navbar, Block, Link } from 'framework7-react';
export default class DynamicRoutePage extends Component {
render() {
return (
<Page>
<Navbar title="Dynamic Route" backLink="Back" />
<Block strong>
<ul>
<li><b>Url:</b> {this.$f7route.url}</li>
<li><b>Path:</b> {this.$f7route.path}</li>
<li><b>Hash:</b> {this.$f7route.hash}</li>
<li><b>Params:</b>
<ul>
{Object.keys(this.$f7route.params).map(key => (
<li key={key}><b>{key}:</b> {this.$f7route.params[key]}</li>
))}
</ul>
</li>
<li><b>Query:</b>
<ul>
{Object.keys(this.$f7route.query).map(key => (
<li key={key}><b>{key}:</b> {this.$f7route.query[key]}</li>
))}
</ul>
</li>
<li><b>Route:</b> {this.$f7route.route.path}</li>
</ul>
</Block>
<Block strong>
<Link onClick={() => this.$f7router.back()}>Go back via Router API</Link>
</Block>
</Page>
);
}
}

View file

@ -0,0 +1,38 @@
import React from 'react';
import {
Page,
View,
Navbar,
NavLeft,
NavTitle,
NavTitleLarge,
NavRight,
Link,
Toolbar,
Block,
BlockTitle,
List,
ListItem,
Row,
Col,
Button
} from 'framework7-react';
export default () => (
<Page name="home">
{/* Top Navbar */}
<Navbar large sliding={false}>
<NavLeft>
<Link iconIos="f7:menu" iconAurora="f7:menu" iconMd="material:menu" panelOpen="left" />
</NavLeft>
<NavTitle sliding>Desktop Editor</NavTitle>
<NavRight>
<Link iconIos="f7:menu" iconAurora="f7:menu" iconMd="material:menu" panelOpen="right" />
</NavRight>
<NavTitleLarge>Desktop Editor</NavTitleLarge>
</Navbar>
{/* Page content */}
<View id="editor_sdk">
</View>
</Page>
);

View file

@ -0,0 +1,15 @@
import React from 'react';
import { Page, Navbar, Block } from 'framework7-react';
export default () => (
<Page>
<Navbar title="Left Page 1" backLink="Back" />
<Block strong>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit deserunt vel accusamus voluptatem neque! Laborum, et facilis at. Est dolorem, reprehenderit, sed repellendus at cum incidunt labore vel perferendis excepturi?</p>
<p>Tempore accusantium quaerat officiis dolores ullam, perferendis labore assumenda. A sint quo necessitatibus temporibus ipsam adipisci et quos aliquid officiis, facilis nulla ut aperiam assumenda magnam blanditiis exercitationem facere non!</p>
<p>Omnis accusamus harum, vero dolores itaque, asperiores laudantium eligendi ipsa, labore dignissimos unde temporibus eius assumenda, obcaecati fuga et. Et provident at consectetur vel temporibus ea nam, veritatis excepturi obcaecati.</p>
<p>Aspernatur dolorum nostrum est sapiente deleniti in. Placeat itaque expedita dignissimos, suscipit tenetur necessitatibus sunt excepturi quisquam, doloremque repudiandae mollitia in. Nesciunt quo vel, dolorum magni nihil officia reprehenderit libero.</p>
<p>Fugit nesciunt nobis at doloribus labore, voluptatem quis, distinctio, saepe illo adipisci qui molestias fugiat ut! Quasi animi possimus temporibus repudiandae quam aspernatur, recusandae libero, reiciendis distinctio cupiditate nesciunt a.</p>
</Block>
</Page>
);

View file

@ -0,0 +1,14 @@
import React from 'react';
import { Page, Navbar, Block } from 'framework7-react';
export default () => (
<Page>
<Navbar title="Left Page 2" backLink="Back" />
<Block strong>
<p>Maxime tempore, repellendus? Sequi saepe provident quas, neque assumenda dicta odit eaque nesciunt facere mollitia totam voluptate aspernatur vel corporis repudiandae commodi ad cumque repellendus. Saepe officia iure repellat repellendus.</p>
<p>Ea maiores accusantium non fuga dicta, vero minus veniam! Ipsum eveniet vero voluptate veritatis aspernatur hic dicta adipisci, debitis. Sint quam aperiam repellat quis perspiciatis accusantium ipsum nulla soluta temporibus.</p>
<p>Necessitatibus ipsum culpa doloremque, nostrum atque totam minima itaque! Blanditiis nobis nam repudiandae, ut nostrum voluptate accusantium atque, veniam libero quaerat corporis laborum earum rem nihil unde. Vitae cum, aliquam?</p>
<p>Debitis aliquid nemo maxime recusandae, mollitia sed error vero. Atque molestiae rem necessitatibus nam voluptas quaerat, reiciendis, excepturi quis facilis, quod cupiditate vitae voluptate repudiandae! Unde impedit aut id ut?</p>
</Block>
</Page>
);

View file

@ -0,0 +1,35 @@
import React from 'react';
import { Page, Navbar, Block, List, ListItem } from 'framework7-react';
export default class extends React.Component {
constructor(props) {
super(props);
this.state = {
user: props.f7route.context.user,
};
}
render() {
const user = this.state.user;
return (
<Page>
<Navbar title={`${user.firstName} ${user.lastName}`} backLink="Back" />
<Block strong>
{user.about}
</Block>
<List>
{user.links.map((link, index) => (
<ListItem
key={index}
link={link.url}
title={link.title}
external
target="_blank"
></ListItem>
))}
</List>
</Page>
);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB