Web: Doceditor: refactoring server
This commit is contained in:
parent
4d9422ef0d
commit
3ac7597ef7
@ -83,7 +83,6 @@ export const initDocEditor = async (req) => {
|
||||
const actionLink = config?.editorConfig?.actionLink || null;
|
||||
|
||||
return {
|
||||
props: {
|
||||
fileInfo,
|
||||
docApiUrl,
|
||||
config,
|
||||
@ -97,7 +96,6 @@ export const initDocEditor = async (req) => {
|
||||
doc,
|
||||
fileId,
|
||||
view,
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
error = { errorMessage: typeof err === "string" ? err : err.message };
|
||||
|
@ -1,140 +0,0 @@
|
||||
const express = require("express");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const React = require("react");
|
||||
const ReactDOMServer = require("react-dom/server");
|
||||
const compression = require("compression");
|
||||
const i18nextMiddleware = require("i18next-express-middleware");
|
||||
const i18next = require("i18next");
|
||||
const Backend = require("i18next-fs-backend");
|
||||
const process = require("process");
|
||||
const { ServerStyleSheet } = require("styled-components");
|
||||
const pkg = require("../../package.json");
|
||||
const title = pkg.title;
|
||||
const { App } = require("../client/App");
|
||||
const initDocEditor = require("./lib/initDocEditor");
|
||||
|
||||
const loadPath = (lng, ns) => {
|
||||
let resourcePath = path.resolve(
|
||||
process.cwd(),
|
||||
`dist/locales/${lng}/${ns}.json`
|
||||
);
|
||||
if (ns === "Common")
|
||||
resourcePath = path.join(
|
||||
__dirname,
|
||||
`../../../../public/locales/${lng}/${ns}.json`
|
||||
);
|
||||
|
||||
return resourcePath;
|
||||
};
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT || 5013;
|
||||
|
||||
i18next.use(Backend).init({
|
||||
backend: {
|
||||
loadPath: loadPath,
|
||||
allowMultiLoading: true,
|
||||
crossDomain: false,
|
||||
},
|
||||
fallbackLng: "en",
|
||||
load: "currentOnly",
|
||||
|
||||
saveMissing: true,
|
||||
ns: ["Editor", "Common"],
|
||||
defaultNS: "Editor",
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
format: function (value, format) {
|
||||
if (format === "lowercase") return value.toLowerCase();
|
||||
return value;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
app.set("view engine", "ejs");
|
||||
app.set("views", path.join(__dirname, "views"));
|
||||
|
||||
// app.get(
|
||||
// /\.(js|css|map|ico)$/,
|
||||
// express.static(path.resolve(process.cwd(), "dist"))
|
||||
// );
|
||||
|
||||
app.use(i18nextMiddleware.handle(i18next));
|
||||
app.use(compression());
|
||||
|
||||
app.use(
|
||||
"/products/files/doceditor/",
|
||||
express.static(path.resolve(process.cwd(), "dist"))
|
||||
);
|
||||
//app.use(express.static(path.resolve(process.cwd(), "dist")));
|
||||
|
||||
app.get("/products/files/doceditor", async (req, res) => {
|
||||
const manifest = fs.readFileSync(
|
||||
path.join(process.cwd(), "dist/manifest.json"),
|
||||
"utf-8"
|
||||
);
|
||||
const initialState = await initDocEditor(req);
|
||||
|
||||
const assets = JSON.parse(manifest);
|
||||
const sheet = new ServerStyleSheet();
|
||||
const component = ReactDOMServer.renderToString(
|
||||
sheet.collectStyles(React.createElement(App))
|
||||
);
|
||||
const styleTags = sheet.getStyleTags();
|
||||
const userLng = initialState?.props?.user?.cultureName || "en";
|
||||
const initialI18nStore = {};
|
||||
|
||||
i18next.changeLanguage(userLng).then(() => {
|
||||
const initialLanguage = userLng;
|
||||
const usedNamespaces = req.i18n.reportNamespaces
|
||||
? req.i18n.reportNamespaces.getUsedNamespaces()
|
||||
: ["Common", "Editor"];
|
||||
|
||||
initialI18nStore[initialLanguage] = {};
|
||||
usedNamespaces.forEach((namespace) => {
|
||||
initialI18nStore[initialLanguage][namespace] =
|
||||
req.i18n.services.resourceStore.data[initialLanguage][namespace];
|
||||
});
|
||||
|
||||
const parsedI18nStore = JSON.stringify(initialI18nStore);
|
||||
const parsedInitialState = JSON.stringify(initialState);
|
||||
const docApiUrl = initialState?.props?.docApiUrl || "";
|
||||
|
||||
res.render("editor", {
|
||||
assets,
|
||||
component,
|
||||
title,
|
||||
parsedI18nStore,
|
||||
initialLanguage,
|
||||
parsedInitialState,
|
||||
docApiUrl,
|
||||
styleTags,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const server = app.listen(port, () => {
|
||||
console.log(`Server is listening on port <http://localhost:${port}>`);
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
const ws = require("./websocket");
|
||||
|
||||
const wss = ws(server);
|
||||
const manifestFile = path.resolve(process.cwd(), "dist/manifest.json");
|
||||
|
||||
let fsWait = false;
|
||||
fs.watch(manifestFile, (event, filename) => {
|
||||
if (filename && event === "change") {
|
||||
if (fsWait) return;
|
||||
fsWait = true;
|
||||
fsWait = setTimeout(() => {
|
||||
fsWait = false;
|
||||
}, 100);
|
||||
|
||||
wss.broadcast("reload");
|
||||
}
|
||||
});
|
||||
}
|
@ -1,107 +1,104 @@
|
||||
// import express from "express";
|
||||
// import template from "./template";
|
||||
// import render from "./render";
|
||||
// import i18nextMiddleware from "i18next-express-middleware";
|
||||
// import i18next from "i18next";
|
||||
// import Backend from "i18next-fs-backend";
|
||||
// import path from "path";
|
||||
// import compression from "compression";
|
||||
// // import webpack from "webpack";
|
||||
// // import WebpackDevMiddleware from "webpack-dev-middleware";
|
||||
// // import WebpackHotMiddleware from "webpack-hot-middleware";
|
||||
import express from "express";
|
||||
import template from "./render";
|
||||
import initMiddleware from "./initMiddleware";
|
||||
import i18nextMiddleware from "i18next-express-middleware";
|
||||
import i18next from "i18next";
|
||||
import Backend from "i18next-fs-backend";
|
||||
import path from "path";
|
||||
import compression from "compression";
|
||||
import ws from "./websocket";
|
||||
import fs from "fs";
|
||||
|
||||
// const loadPath = (lng, ns) => {
|
||||
// let resourcePath =
|
||||
// path.resolve(process.cwd(), "dist/client") + `/locales/${lng}/${ns}.json`;
|
||||
// if (ns === "Common")
|
||||
// resourcePath = path.join(
|
||||
// __dirname,
|
||||
// `../../../../public/locales/${lng}/${ns}.json`
|
||||
// );
|
||||
const loadPath = (lng, ns) => {
|
||||
let resourcePath =
|
||||
path.resolve(process.cwd(), "dist/client") + `/locales/${lng}/${ns}.json`;
|
||||
if (ns === "Common")
|
||||
resourcePath = path.resolve(
|
||||
process.cwd(),
|
||||
`../../public/locales/${lng}/${ns}.json`
|
||||
);
|
||||
|
||||
// return resourcePath;
|
||||
// };
|
||||
return resourcePath;
|
||||
};
|
||||
|
||||
// const app = express();
|
||||
// const port = process.env.PORT || 5013;
|
||||
const port = PORT || 5013;
|
||||
const app = express();
|
||||
|
||||
// i18next.use(Backend).init({
|
||||
// backend: {
|
||||
// loadPath: loadPath,
|
||||
// allowMultiLoading: true,
|
||||
// crossDomain: false,
|
||||
// },
|
||||
// fallbackLng: "en",
|
||||
// load: "currentOnly",
|
||||
i18next.use(Backend).init({
|
||||
backend: {
|
||||
loadPath: loadPath,
|
||||
allowMultiLoading: true,
|
||||
crossDomain: false,
|
||||
},
|
||||
fallbackLng: "en",
|
||||
load: "currentOnly",
|
||||
|
||||
// saveMissing: true,
|
||||
// ns: ["Editor", "Common"],
|
||||
// defaultNS: "Editor",
|
||||
saveMissing: true,
|
||||
ns: ["Editor", "Common"],
|
||||
defaultNS: "Editor",
|
||||
|
||||
// interpolation: {
|
||||
// escapeValue: false, // not needed for react as it escapes by default
|
||||
// format: function (value, format) {
|
||||
// if (format === "lowercase") return value.toLowerCase();
|
||||
// return value;
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
|
||||
// // if (process.env.NODE_ENV === "development") {
|
||||
// // const webpackConfig = require("../../webpack/dev/webpack.dev.client.js");
|
||||
// // const compiler = webpack(webpackConfig);
|
||||
// // app.use(
|
||||
// // WebpackDevMiddleware(compiler, {
|
||||
// // publicPath: webpackConfig.output.publicPath,
|
||||
// // serverSideRender: true,
|
||||
// // })
|
||||
// // );
|
||||
|
||||
// //
|
||||
// // }
|
||||
|
||||
// app.use(i18nextMiddleware.handle(i18next));
|
||||
// app.use(compression());
|
||||
// app.use(
|
||||
// "/products/files/doceditor/static/",
|
||||
// express.static(path.resolve(__dirname, "../../dist/client/static"))
|
||||
// );
|
||||
// app.use(express.static(path.resolve(__dirname, "../../dist/client")));
|
||||
|
||||
// app.get("/products/files/doceditor", async (req, res) => {
|
||||
// const { props, content, styleTags, extractor } = await render(req);
|
||||
// const userLng = props?.user?.cultureName || "en";
|
||||
// const initialI18nStore = {};
|
||||
|
||||
// i18next.changeLanguage(userLng).then(() => {
|
||||
// const initialLanguage = userLng;
|
||||
|
||||
// const usedNamespaces = req.i18n.reportNamespaces.getUsedNamespaces();
|
||||
|
||||
// initialI18nStore[initialLanguage] = {};
|
||||
// usedNamespaces.forEach((namespace) => {
|
||||
// initialI18nStore[initialLanguage][namespace] =
|
||||
// req.i18n.services.resourceStore.data[initialLanguage][namespace];
|
||||
// });
|
||||
// const response = template(
|
||||
// props,
|
||||
// content,
|
||||
// styleTags,
|
||||
// initialI18nStore,
|
||||
// initialLanguage,
|
||||
// extractor
|
||||
// );
|
||||
|
||||
// res.send(response);
|
||||
// });
|
||||
// });
|
||||
|
||||
// app.listen(port, () => {
|
||||
// console.log(`Server is listening on port ${port}`);
|
||||
// });
|
||||
const path = require("path");
|
||||
|
||||
require("@babel/register")({
|
||||
configFile: path.resolve(__dirname, "../../babel.config.js"),
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
format: function (value, format) {
|
||||
if (format === "lowercase") return value.toLowerCase();
|
||||
return value;
|
||||
},
|
||||
},
|
||||
});
|
||||
require("./app.js");
|
||||
|
||||
app.use(i18nextMiddleware.handle(i18next));
|
||||
app.use(compression());
|
||||
app.use(
|
||||
"/products/files/doceditor/static/",
|
||||
express.static(path.resolve(process.cwd(), "dist/client/static"))
|
||||
);
|
||||
app.use(express.static(path.resolve(process.cwd(), "dist/client")));
|
||||
app.use(initMiddleware);
|
||||
app.get("/products/files/doceditor", async (req, res) => {
|
||||
const { i18n, initialState, appComponent, styleTags, assets } = req;
|
||||
const userLng = initialState?.user?.cultureName || "en";
|
||||
const initialI18nStore = {};
|
||||
|
||||
await i18next.changeLanguage(userLng);
|
||||
const usedNamespaces = i18n.reportNamespaces.getUsedNamespaces();
|
||||
|
||||
initialI18nStore[userLng] = {};
|
||||
usedNamespaces.forEach((namespace) => {
|
||||
initialI18nStore[namespace] =
|
||||
i18n.services.resourceStore.data[userLng][namespace];
|
||||
});
|
||||
|
||||
const htmlString = template(
|
||||
initialState,
|
||||
appComponent,
|
||||
styleTags,
|
||||
initialI18nStore,
|
||||
userLng,
|
||||
assets
|
||||
);
|
||||
|
||||
res.send(htmlString);
|
||||
});
|
||||
|
||||
const server = app.listen(port, () => {
|
||||
console.log(`Server is listening on port ${port}`);
|
||||
});
|
||||
|
||||
if (IS_DEVELOPMENT) {
|
||||
const wss = ws(server);
|
||||
|
||||
const manifestFile = path.resolve(process.cwd(), "dist/client/manifest.json");
|
||||
|
||||
let fsWait = false;
|
||||
fs.watch(manifestFile, (event, filename) => {
|
||||
if (filename && event === "change") {
|
||||
if (fsWait) return;
|
||||
fsWait = true;
|
||||
fsWait = setTimeout(() => {
|
||||
fsWait = false;
|
||||
}, 100);
|
||||
|
||||
wss.broadcast("reload");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
56
web/ASC.Web.Editor/src/server/initMiddleware.js
Normal file
56
web/ASC.Web.Editor/src/server/initMiddleware.js
Normal file
@ -0,0 +1,56 @@
|
||||
import React from "react";
|
||||
import { renderToString } from "react-dom/server";
|
||||
import App from "../client/Editor.js";
|
||||
import { initDocEditor } from "../helpers/utils";
|
||||
import { ServerStyleSheet, createGlobalStyle } from "styled-components";
|
||||
import path from "path";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import fs from "fs";
|
||||
|
||||
const GlobalStyle = createGlobalStyle`
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#root {
|
||||
min-height: 100%;
|
||||
|
||||
.pageLoader {
|
||||
position: fixed;
|
||||
left: calc(50% - 20px);
|
||||
top: 35%;
|
||||
}
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body.loading * {
|
||||
cursor: wait !important;
|
||||
}
|
||||
`;
|
||||
|
||||
const sheet = new ServerStyleSheet();
|
||||
|
||||
export default async (req, res, next) => {
|
||||
const manifest = fs.readFileSync(
|
||||
path.join(process.cwd(), "dist/client/manifest.json"),
|
||||
"utf-8"
|
||||
);
|
||||
|
||||
req.initialState = await initDocEditor(req);
|
||||
req.assets = JSON.parse(manifest);
|
||||
|
||||
req.appComponent = renderToString(
|
||||
sheet.collectStyles(
|
||||
<I18nextProvider i18n={req.i18n}>
|
||||
<GlobalStyle />
|
||||
<App {...req.initialState} />
|
||||
</I18nextProvider>
|
||||
)
|
||||
);
|
||||
req.styleTags = sheet.getStyleTags();
|
||||
|
||||
next();
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,63 +0,0 @@
|
||||
const request = require("./requestManager");
|
||||
const Encoder = require("./encoder");
|
||||
exports.getDocServiceUrl = (headers) => {
|
||||
return request({ method: "get", url: `/files/docservice`, headers });
|
||||
};
|
||||
|
||||
exports.getFileInfo = (fileId, headers) => {
|
||||
const options = {
|
||||
method: "get",
|
||||
url: `/files/file/${fileId}`,
|
||||
headers,
|
||||
};
|
||||
|
||||
return request(options);
|
||||
};
|
||||
|
||||
exports.openEdit = (fileId, version, doc, view, headers) => {
|
||||
const params = []; // doc ? `?doc=${doc}` : "";
|
||||
|
||||
if (view) {
|
||||
params.push(`view=${view}`);
|
||||
}
|
||||
|
||||
if (version) {
|
||||
params.push(`version=${version}`);
|
||||
}
|
||||
|
||||
if (doc) {
|
||||
params.push(`doc=${doc}`);
|
||||
}
|
||||
|
||||
const paramsString = params.length > 0 ? `?${params.join("&")}` : "";
|
||||
|
||||
const options = {
|
||||
method: "get",
|
||||
url: `/files/file/${fileId}/openedit${paramsString}`,
|
||||
headers,
|
||||
};
|
||||
|
||||
return request(options);
|
||||
};
|
||||
|
||||
exports.getSettings = (headers) => {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/settings.json",
|
||||
headers,
|
||||
});
|
||||
};
|
||||
|
||||
exports.getUser = (userName = null, headers) => {
|
||||
return request({
|
||||
method: "get",
|
||||
url: `/people/${userName || "@self"}.json`,
|
||||
skipUnauthorized: true,
|
||||
headers,
|
||||
}).then((user) => {
|
||||
if (user && user.displayName) {
|
||||
user.displayName = Encoder.htmlDecode(user.displayName);
|
||||
}
|
||||
return user;
|
||||
});
|
||||
};
|
@ -1,48 +0,0 @@
|
||||
const axios = require("axios");
|
||||
const apiPrefixURL = "/api/2.0";
|
||||
const apiTimeout = 30000;
|
||||
|
||||
module.exports = (options) => {
|
||||
const basePath = options.basePath;
|
||||
const xRewriterUrl = options.headers["x-rewriter-url"];
|
||||
const url = `${xRewriterUrl}${apiPrefixURL}${options.url}`;
|
||||
|
||||
const axiosOptions = {
|
||||
baseURL: url,
|
||||
responseType: "json",
|
||||
timeout: apiTimeout,
|
||||
headers: options.headers,
|
||||
};
|
||||
|
||||
const getResponseError = (res) => {
|
||||
if (!res) return;
|
||||
|
||||
if (res.data && res.data.error) {
|
||||
return res.data.error.message;
|
||||
}
|
||||
|
||||
if (res.isAxiosError && res.message) {
|
||||
return res.message;
|
||||
}
|
||||
};
|
||||
|
||||
const onSuccess = (response) => {
|
||||
const error = getResponseError(response);
|
||||
if (error) throw new Error(error);
|
||||
|
||||
if (!response || !response.data || response.isAxiosError) return null;
|
||||
if (response.request.responseType === "text") return response.data;
|
||||
|
||||
return response.data.response;
|
||||
};
|
||||
|
||||
const onError = (error) => {
|
||||
const errorText = error.response
|
||||
? getResponseError(error.response)
|
||||
: error.message;
|
||||
return Promise.reject(errorText || error);
|
||||
};
|
||||
|
||||
const request = axios.create(axiosOptions);
|
||||
return request().then(onSuccess).catch(onError);
|
||||
};
|
@ -1,110 +0,0 @@
|
||||
const {
|
||||
getDocServiceUrl,
|
||||
getFileInfo,
|
||||
openEdit,
|
||||
getUser,
|
||||
getSettings,
|
||||
} = require("./api/init");
|
||||
|
||||
const combineUrl = (host = "", ...params) => {
|
||||
let url = host.replace(/\/+$/, "");
|
||||
|
||||
params.forEach((part) => {
|
||||
const newPart = part.trim().replace(/^\/+/, "");
|
||||
url += newPart
|
||||
? url.length > 0 && url[url.length - 1] === "/"
|
||||
? newPart
|
||||
: `/${newPart}`
|
||||
: "";
|
||||
});
|
||||
|
||||
return url;
|
||||
};
|
||||
|
||||
module.exports = async (req) => {
|
||||
if (!req) return false;
|
||||
|
||||
const { headers, url, query } = req;
|
||||
const { version, desktop: isDesktop } = query;
|
||||
let error = null;
|
||||
|
||||
try {
|
||||
const decodedId = query.fileId || query.fileid || null;
|
||||
const fileId =
|
||||
typeof decodedId === "string" ? encodeURIComponent(decodedId) : decodedId;
|
||||
|
||||
if (!fileId) {
|
||||
return {
|
||||
props: {
|
||||
needLoader: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const doc = query?.doc || null;
|
||||
const view = url.indexOf("action=view") !== -1;
|
||||
const fileVersion = version || null;
|
||||
|
||||
const [user, settings] = await Promise.all([
|
||||
getUser(null, headers),
|
||||
getSettings(headers),
|
||||
]);
|
||||
|
||||
const successAuth = !!user;
|
||||
const personal = settings?.personal;
|
||||
|
||||
if (!successAuth && !doc) {
|
||||
error = {
|
||||
unAuthorized: true,
|
||||
redirectPath: combineUrl(
|
||||
"", //AppServerConfig.proxyURL,
|
||||
personal ? "/sign-in" : "/login"
|
||||
),
|
||||
};
|
||||
return {
|
||||
props: {
|
||||
error,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
let [config, docApiUrl, fileInfo] = await Promise.all([
|
||||
openEdit(fileId, fileVersion, doc, view, headers),
|
||||
getDocServiceUrl(headers),
|
||||
getFileInfo(fileId, headers),
|
||||
]);
|
||||
|
||||
const isSharingAccess = fileInfo && fileInfo.canShare;
|
||||
|
||||
if (view) {
|
||||
config.editorConfig.mode = "view";
|
||||
}
|
||||
|
||||
const actionLink = config?.editorConfig?.actionLink || null;
|
||||
|
||||
return {
|
||||
props: {
|
||||
fileInfo,
|
||||
docApiUrl,
|
||||
config,
|
||||
personal,
|
||||
successAuth,
|
||||
user,
|
||||
error,
|
||||
actionLink,
|
||||
isSharingAccess,
|
||||
url,
|
||||
doc,
|
||||
fileId,
|
||||
view,
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
error = { errorMessage: typeof err === "string" ? err : err.message };
|
||||
return {
|
||||
props: {
|
||||
error,
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
@ -1,57 +1,372 @@
|
||||
import React from "react";
|
||||
import { renderToString } from "react-dom/server";
|
||||
import App from "../client/Editor.js";
|
||||
import { initDocEditor } from "../helpers/utils";
|
||||
import { ServerStyleSheet, createGlobalStyle } from "styled-components";
|
||||
import { ChunkExtractor, ChunkExtractorManager } from "@loadable/server";
|
||||
import path from "path";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import { getFavicon } from "../helpers/utils";
|
||||
import pkg from "../../package.json";
|
||||
|
||||
const GlobalStyle = createGlobalStyle`
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
export default function template(
|
||||
initialState = {},
|
||||
appComponent = "",
|
||||
styleTags,
|
||||
initialI18nStore,
|
||||
initialLanguage,
|
||||
assets
|
||||
) {
|
||||
const { title } = pkg;
|
||||
const { docApiUrl } = initialState;
|
||||
const faviconHref = getFavicon(initialState?.config?.documentType);
|
||||
|
||||
#root {
|
||||
min-height: 100%;
|
||||
const scripts = `
|
||||
<script id="__ASC_INITIAL_STATE__">
|
||||
window.__ASC_INITIAL_STATE__ = ${JSON.stringify(initialState)}
|
||||
</script>
|
||||
<script id="__ASC_I18N_INIT__">
|
||||
window.initialI18nStore = ${JSON.stringify(initialI18nStore)}
|
||||
window.initialLanguage = '${initialLanguage}'
|
||||
</script>
|
||||
<script>
|
||||
const tempElm = document.getElementById("loader");
|
||||
tempElm.style.backgroundColor =
|
||||
localStorage.theme === "Dark" ? "#333333" : "#f4f4f4";
|
||||
|
||||
.pageLoader {
|
||||
position: fixed;
|
||||
left: calc(50% - 20px);
|
||||
top: 35%;
|
||||
}
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
console.log("It's Editor INIT");
|
||||
</script>
|
||||
<script type='text/javascript' id='scripDocServiceAddress' src="${docApiUrl}" async></script>
|
||||
<script defer="defer" src='${assets["client.js"]}'></script>
|
||||
|
||||
body.loading * {
|
||||
cursor: wait !important;
|
||||
}
|
||||
`;
|
||||
// <script defer="defer" src='${assets["runtime.js"]}'></script>
|
||||
// <script defer="defer" src='${assets["vendor.js"]}'></script>
|
||||
const page = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title> ${title} </title>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no, viewport-fit=cover"
|
||||
/>
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<link id="favicon" rel="shortcut icon" href=${faviconHref} />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<link rel="apple-touch-icon" href="/appIcon.png" />
|
||||
${styleTags}
|
||||
<style type="text/css">
|
||||
.loadmask {
|
||||
left: 0;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
background-color: #f4f4f4;
|
||||
z-index: 1001;
|
||||
}
|
||||
.loader-page {
|
||||
width: 100%;
|
||||
height: 170px;
|
||||
bottom: 42%;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
line-height: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.loader-page-romb {
|
||||
width: 40px;
|
||||
display: inline-block;
|
||||
}
|
||||
.romb {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
position: absolute;
|
||||
background: red;
|
||||
border-radius: 6px;
|
||||
-webkit-transform: rotate(135deg) skew(20deg, 20deg);
|
||||
-moz-transform: rotate(135deg) skew(20deg, 20deg);
|
||||
-ms-transform: rotate(135deg) skew(20deg, 20deg);
|
||||
-o-transform: rotate(135deg) skew(20deg, 20deg);
|
||||
-webkit-animation: movedown 3s infinite ease;
|
||||
-moz-animation: movedown 3s infinite ease;
|
||||
-ms-animation: movedown 3s infinite ease;
|
||||
-o-animation: movedown 3s infinite ease;
|
||||
animation: movedown 3s infinite ease;
|
||||
}
|
||||
#blue {
|
||||
z-index: 3;
|
||||
background: #55bce6;
|
||||
-webkit-animation-name: blue;
|
||||
-moz-animation-name: blue;
|
||||
-ms-animation-name: blue;
|
||||
-o-animation-name: blue;
|
||||
animation-name: blue;
|
||||
}
|
||||
#red {
|
||||
z-index: 1;
|
||||
background: #de7a59;
|
||||
-webkit-animation-name: red;
|
||||
-moz-animation-name: red;
|
||||
-ms-animation-name: red;
|
||||
-o-animation-name: red;
|
||||
animation-name: red;
|
||||
}
|
||||
#green {
|
||||
z-index: 2;
|
||||
background: #a1cb5c;
|
||||
-webkit-animation-name: green;
|
||||
-moz-animation-name: green;
|
||||
-ms-animation-name: green;
|
||||
-o-animation-name: green;
|
||||
animation-name: green;
|
||||
}
|
||||
@-webkit-keyframes red {
|
||||
0% {
|
||||
top: 120px;
|
||||
background: #de7a59;
|
||||
}
|
||||
10% {
|
||||
top: 120px;
|
||||
background: #f2cbbf;
|
||||
}
|
||||
14% {
|
||||
background: #f4f4f4;
|
||||
top: 120px;
|
||||
}
|
||||
15% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
}
|
||||
20% {
|
||||
background: #e6e4e4;
|
||||
}
|
||||
30% {
|
||||
background: #d2d2d2;
|
||||
}
|
||||
40% {
|
||||
top: 120px;
|
||||
}
|
||||
100% {
|
||||
top: 120px;
|
||||
background: #de7a59;
|
||||
}
|
||||
}
|
||||
@keyframesred {
|
||||
0% {
|
||||
top: 120px;
|
||||
background: #de7a59;
|
||||
}
|
||||
10% {
|
||||
top: 120px;
|
||||
background: #f2cbbf;
|
||||
}
|
||||
14% {
|
||||
background: #f4f4f4;
|
||||
top: 120px;
|
||||
}
|
||||
15% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
}
|
||||
20% {
|
||||
background: #e6e4e4;
|
||||
}
|
||||
30% {
|
||||
background: #d2d2d2;
|
||||
}
|
||||
40% {
|
||||
top: 120px;
|
||||
}
|
||||
100% {
|
||||
top: 120px;
|
||||
background: #de7a59;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes green {
|
||||
0% {
|
||||
top: 110px;
|
||||
background: #a1cb5c;
|
||||
opacity: 1;
|
||||
}
|
||||
10% {
|
||||
top: 110px;
|
||||
background: #cbe0ac;
|
||||
opacity: 1;
|
||||
}
|
||||
14% {
|
||||
background: #f4f4f4;
|
||||
top: 110px;
|
||||
opacity: 1;
|
||||
}
|
||||
15% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
20% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
25% {
|
||||
background: #efefef;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
30% {
|
||||
background: #e6e4e4;
|
||||
}
|
||||
70% {
|
||||
top: 110px;
|
||||
}
|
||||
100% {
|
||||
top: 110px;
|
||||
background: #a1cb5c;
|
||||
}
|
||||
}
|
||||
@keyframes green {
|
||||
0% {
|
||||
top: 110px;
|
||||
background: #a1cb5c;
|
||||
opacity: 1;
|
||||
}
|
||||
10% {
|
||||
top: 110px;
|
||||
background: #cbe0ac;
|
||||
opacity: 1;
|
||||
}
|
||||
14% {
|
||||
background: #f4f4f4;
|
||||
top: 110px;
|
||||
opacity: 1;
|
||||
}
|
||||
15% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
20% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
25% {
|
||||
background: #efefef;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
30% {
|
||||
background: #e6e4e4;
|
||||
}
|
||||
70% {
|
||||
top: 110px;
|
||||
}
|
||||
100% {
|
||||
top: 110px;
|
||||
background: #a1cb5c;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes blue {
|
||||
0% {
|
||||
top: 100px;
|
||||
background: #55bce6;
|
||||
opacity: 1;
|
||||
}
|
||||
10% {
|
||||
top: 100px;
|
||||
background: #bfe8f8;
|
||||
opacity: 1;
|
||||
}
|
||||
14% {
|
||||
background: #f4f4f4;
|
||||
top: 100px;
|
||||
opacity: 1;
|
||||
}
|
||||
15% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
20% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
25% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
45% {
|
||||
background: #efefef;
|
||||
top: 0;
|
||||
opacity: 0.2;
|
||||
}
|
||||
100% {
|
||||
top: 100px;
|
||||
background: #55bce6;
|
||||
}
|
||||
}
|
||||
@keyframes blue {
|
||||
0% {
|
||||
top: 100px;
|
||||
background: #55bce6;
|
||||
opacity: 1;
|
||||
}
|
||||
10% {
|
||||
top: 100px;
|
||||
background: #bfe8f8;
|
||||
opacity: 1;
|
||||
}
|
||||
14% {
|
||||
background: #f4f4f4;
|
||||
top: 100px;
|
||||
opacity: 1;
|
||||
}
|
||||
15% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
20% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
25% {
|
||||
background: #fff;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
45% {
|
||||
background: #efefef;
|
||||
top: 0;
|
||||
opacity: 0.2;
|
||||
}
|
||||
100% {
|
||||
top: 100px;
|
||||
background: #55bce6;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">${appComponent}</div>
|
||||
<noscript> You need to enable JavaScript to run this app. </noscript>
|
||||
<div id="loader" class="loadmask">
|
||||
<div class="loader-page">
|
||||
<div class="loader-page-romb">
|
||||
<div class="romb" id="blue"></div>
|
||||
<div class="romb" id="green"></div>
|
||||
<div class="romb" id="red"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
${scripts}
|
||||
|
||||
const sheet = new ServerStyleSheet();
|
||||
const loadableJson = path.resolve(__dirname, "./client/loadable-stats.json");
|
||||
export default async (req) => {
|
||||
const props = await initDocEditor(req);
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
const extractor = new ChunkExtractor({
|
||||
statsFile: loadableJson,
|
||||
entrypoints: ["client"],
|
||||
});
|
||||
|
||||
const content = renderToString(
|
||||
sheet.collectStyles(
|
||||
<ChunkExtractorManager extractor={extractor}>
|
||||
<GlobalStyle />
|
||||
<I18nextProvider i18n={req.i18n}>
|
||||
<App />
|
||||
</I18nextProvider>
|
||||
</ChunkExtractorManager>
|
||||
)
|
||||
);
|
||||
const styleTags = sheet.getStyleTags();
|
||||
|
||||
return { ...props, content, styleTags, extractor };
|
||||
};
|
||||
return page;
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
import { getFavicon } from "../helpers/utils";
|
||||
import pkg from "../../package.json";
|
||||
|
||||
export default function template(
|
||||
initialState = {},
|
||||
content = "",
|
||||
styleTags,
|
||||
//scriptTags,
|
||||
initialI18nStore,
|
||||
initialLanguage,
|
||||
extractor
|
||||
) {
|
||||
const { title } = pkg;
|
||||
const { docApiUrl } = initialState;
|
||||
const faviconHref = getFavicon(initialState?.config?.documentType);
|
||||
|
||||
const scripts = `
|
||||
<script id="__ASC_INITIAL_STATE__">
|
||||
window.__ASC_INITIAL_STATE__ = ${JSON.stringify(initialState)}
|
||||
</script>
|
||||
<script id="__ASC_I18N_INIT__">
|
||||
window.initialI18nStore = ${JSON.stringify(initialI18nStore)}
|
||||
window.initialLanguage = '${initialLanguage}'
|
||||
</script>
|
||||
<script type='text/javascript' id='scripDocServiceAddress' src="${docApiUrl}" async></script>
|
||||
${extractor.getScriptTags()}
|
||||
`;
|
||||
|
||||
const page = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title> ${title} </title>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no, viewport-fit=cover"
|
||||
/>
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<link id="favicon" rel="shortcut icon" href=${faviconHref} />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<link rel="apple-touch-icon" href="/appIcon.png" />
|
||||
${styleTags}
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">${content}</div>
|
||||
${scripts}
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
return page;
|
||||
}
|
@ -1,351 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<%- styleTags %>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no, viewport-fit=cover"
|
||||
/>
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
|
||||
-->
|
||||
<link id="favicon" rel="shortcut icon" sizes="any" href="/favicon.ico" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<!-- Tell the browser it's a PWA -->
|
||||
<!-- <meta name="mobile-web-app-capable" content="yes" /> -->
|
||||
<!-- Tell iOS it's a PWA -->
|
||||
<!-- <meta name="apple-mobile-web-app-capable" content="yes" /> -->
|
||||
<link rel="apple-touch-icon" href="/appIcon-180.png" />
|
||||
|
||||
<style type="text/css">
|
||||
.loadmask {
|
||||
left: 0;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
background-color: #f4f4f4;
|
||||
z-index: 1001;
|
||||
}
|
||||
.loader-page {
|
||||
width: 100%;
|
||||
height: 170px;
|
||||
bottom: 42%;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
line-height: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.loader-page-romb {
|
||||
width: 40px;
|
||||
display: inline-block;
|
||||
}
|
||||
.romb {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
position: absolute;
|
||||
background: red;
|
||||
border-radius: 6px;
|
||||
-webkit-transform: rotate(135deg) skew(20deg, 20deg);
|
||||
-moz-transform: rotate(135deg) skew(20deg, 20deg);
|
||||
-ms-transform: rotate(135deg) skew(20deg, 20deg);
|
||||
-o-transform: rotate(135deg) skew(20deg, 20deg);
|
||||
-webkit-animation: movedown 3s infinite ease;
|
||||
-moz-animation: movedown 3s infinite ease;
|
||||
-ms-animation: movedown 3s infinite ease;
|
||||
-o-animation: movedown 3s infinite ease;
|
||||
animation: movedown 3s infinite ease;
|
||||
}
|
||||
#blue {
|
||||
z-index: 3;
|
||||
background: #55bce6;
|
||||
-webkit-animation-name: blue;
|
||||
-moz-animation-name: blue;
|
||||
-ms-animation-name: blue;
|
||||
-o-animation-name: blue;
|
||||
animation-name: blue;
|
||||
}
|
||||
#red {
|
||||
z-index: 1;
|
||||
background: #de7a59;
|
||||
-webkit-animation-name: red;
|
||||
-moz-animation-name: red;
|
||||
-ms-animation-name: red;
|
||||
-o-animation-name: red;
|
||||
animation-name: red;
|
||||
}
|
||||
#green {
|
||||
z-index: 2;
|
||||
background: #a1cb5c;
|
||||
-webkit-animation-name: green;
|
||||
-moz-animation-name: green;
|
||||
-ms-animation-name: green;
|
||||
-o-animation-name: green;
|
||||
animation-name: green;
|
||||
}
|
||||
@-webkit-keyframes red {
|
||||
0% {
|
||||
top: 120px;
|
||||
background: #de7a59;
|
||||
}
|
||||
10% {
|
||||
top: 120px;
|
||||
background: #f2cbbf;
|
||||
}
|
||||
14% {
|
||||
background: #f4f4f4;
|
||||
top: 120px;
|
||||
}
|
||||
15% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
}
|
||||
20% {
|
||||
background: #e6e4e4;
|
||||
}
|
||||
30% {
|
||||
background: #d2d2d2;
|
||||
}
|
||||
40% {
|
||||
top: 120px;
|
||||
}
|
||||
100% {
|
||||
top: 120px;
|
||||
background: #de7a59;
|
||||
}
|
||||
}
|
||||
@keyframesred {
|
||||
0% {
|
||||
top: 120px;
|
||||
background: #de7a59;
|
||||
}
|
||||
10% {
|
||||
top: 120px;
|
||||
background: #f2cbbf;
|
||||
}
|
||||
14% {
|
||||
background: #f4f4f4;
|
||||
top: 120px;
|
||||
}
|
||||
15% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
}
|
||||
20% {
|
||||
background: #e6e4e4;
|
||||
}
|
||||
30% {
|
||||
background: #d2d2d2;
|
||||
}
|
||||
40% {
|
||||
top: 120px;
|
||||
}
|
||||
100% {
|
||||
top: 120px;
|
||||
background: #de7a59;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes green {
|
||||
0% {
|
||||
top: 110px;
|
||||
background: #a1cb5c;
|
||||
opacity: 1;
|
||||
}
|
||||
10% {
|
||||
top: 110px;
|
||||
background: #cbe0ac;
|
||||
opacity: 1;
|
||||
}
|
||||
14% {
|
||||
background: #f4f4f4;
|
||||
top: 110px;
|
||||
opacity: 1;
|
||||
}
|
||||
15% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
20% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
25% {
|
||||
background: #efefef;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
30% {
|
||||
background: #e6e4e4;
|
||||
}
|
||||
70% {
|
||||
top: 110px;
|
||||
}
|
||||
100% {
|
||||
top: 110px;
|
||||
background: #a1cb5c;
|
||||
}
|
||||
}
|
||||
@keyframes green {
|
||||
0% {
|
||||
top: 110px;
|
||||
background: #a1cb5c;
|
||||
opacity: 1;
|
||||
}
|
||||
10% {
|
||||
top: 110px;
|
||||
background: #cbe0ac;
|
||||
opacity: 1;
|
||||
}
|
||||
14% {
|
||||
background: #f4f4f4;
|
||||
top: 110px;
|
||||
opacity: 1;
|
||||
}
|
||||
15% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
20% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
25% {
|
||||
background: #efefef;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
30% {
|
||||
background: #e6e4e4;
|
||||
}
|
||||
70% {
|
||||
top: 110px;
|
||||
}
|
||||
100% {
|
||||
top: 110px;
|
||||
background: #a1cb5c;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes blue {
|
||||
0% {
|
||||
top: 100px;
|
||||
background: #55bce6;
|
||||
opacity: 1;
|
||||
}
|
||||
10% {
|
||||
top: 100px;
|
||||
background: #bfe8f8;
|
||||
opacity: 1;
|
||||
}
|
||||
14% {
|
||||
background: #f4f4f4;
|
||||
top: 100px;
|
||||
opacity: 1;
|
||||
}
|
||||
15% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
20% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
25% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
45% {
|
||||
background: #efefef;
|
||||
top: 0;
|
||||
opacity: 0.2;
|
||||
}
|
||||
100% {
|
||||
top: 100px;
|
||||
background: #55bce6;
|
||||
}
|
||||
}
|
||||
@keyframes blue {
|
||||
0% {
|
||||
top: 100px;
|
||||
background: #55bce6;
|
||||
opacity: 1;
|
||||
}
|
||||
10% {
|
||||
top: 100px;
|
||||
background: #bfe8f8;
|
||||
opacity: 1;
|
||||
}
|
||||
14% {
|
||||
background: #f4f4f4;
|
||||
top: 100px;
|
||||
opacity: 1;
|
||||
}
|
||||
15% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
20% {
|
||||
background: #f4f4f4;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
25% {
|
||||
background: #fff;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
45% {
|
||||
background: #efefef;
|
||||
top: 0;
|
||||
opacity: 0.2;
|
||||
}
|
||||
100% {
|
||||
top: 100px;
|
||||
background: #55bce6;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<title><%- title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript> You need to enable JavaScript to run this app. </noscript>
|
||||
<div id="loader" class="loadmask">
|
||||
<div class="loader-page">
|
||||
<div class="loader-page-romb">
|
||||
<div class="romb" id="blue"></div>
|
||||
<div class="romb" id="green"></div>
|
||||
<div class="romb" id="red"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="root"><%- component %></div>
|
||||
<script defer="defer" src="<%= assets["client.js"] %>"></script>
|
||||
<script defer="defer" src="<%= assets["runtime.js"] %>"></script>
|
||||
<script defer="defer" src="<%= assets["vendor.js"] %>"></script>
|
||||
<script>
|
||||
window.__ASC_INITIAL_STATE__ = JSON.parse(`<%- parsedInitialState%>`);
|
||||
const initialI18nStore = `<%- parsedI18nStore%>`
|
||||
window.initialI18nStore = JSON.parse(initialI18nStore);
|
||||
window.initialLanguage = '<%- initialLanguage%>';
|
||||
|
||||
const tempElm = document.getElementById("loader");
|
||||
tempElm.style.backgroundColor =
|
||||
localStorage.theme === "Dark" ? "#333333" : "#f4f4f4";
|
||||
|
||||
console.log("It's Editor INIT");
|
||||
</script>
|
||||
<script defer type='text/javascript' id='scripDocServiceAddress' src="<%= docApiUrl%>" async></script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user