mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-31 19:02:59 +01:00
Moved to ts for other dependencies.
This commit is contained in:
parent
7b99edc471
commit
237f7242ec
8 changed files with 884 additions and 1379 deletions
|
@ -1,10 +1,6 @@
|
||||||
|
import "eslint-config-etherpad/patch/modern-module-resolution";
|
||||||
'use strict';
|
'use strict';
|
||||||
|
export const ignorePatterns = [
|
||||||
// This is a workaround for https://github.com/eslint/eslint/issues/3458
|
|
||||||
require('eslint-config-etherpad/patch/modern-module-resolution');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
ignorePatterns: [
|
|
||||||
'/static/js/admin/jquery.autosize.js',
|
'/static/js/admin/jquery.autosize.js',
|
||||||
'/static/js/admin/minify.json.js',
|
'/static/js/admin/minify.json.js',
|
||||||
'/static/js/vendors/browser.js',
|
'/static/js/vendors/browser.js',
|
||||||
|
@ -14,128 +10,132 @@ module.exports = {
|
||||||
'/static/js/vendors/jquery.js',
|
'/static/js/vendors/jquery.js',
|
||||||
'/static/js/vendors/nice-select.js',
|
'/static/js/vendors/nice-select.js',
|
||||||
'/tests/frontend/lib/',
|
'/tests/frontend/lib/',
|
||||||
],
|
];
|
||||||
overrides: [
|
export const overrides = [
|
||||||
{
|
{
|
||||||
files: [
|
files: [
|
||||||
'**/.eslintrc.*',
|
'**/.eslintrc.*',
|
||||||
],
|
],
|
||||||
extends: 'etherpad/node',
|
extends: 'etherpad/node',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: [
|
files: [
|
||||||
'**/*',
|
'**/*',
|
||||||
],
|
],
|
||||||
excludedFiles: [
|
excludedFiles: [
|
||||||
'**/.eslintrc.*',
|
'**/.eslintrc.*',
|
||||||
'tests/frontend/**/*',
|
|
||||||
],
|
|
||||||
extends: 'etherpad/node',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: [
|
|
||||||
'static/**/*',
|
|
||||||
'tests/frontend/helper.js',
|
|
||||||
'tests/frontend/helper/**/*',
|
|
||||||
],
|
|
||||||
excludedFiles: [
|
|
||||||
'**/.eslintrc.*',
|
|
||||||
],
|
|
||||||
extends: 'etherpad/browser',
|
|
||||||
env: {
|
|
||||||
'shared-node-browser': true,
|
|
||||||
},
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: [
|
|
||||||
'tests/frontend/helper/**/*',
|
|
||||||
],
|
|
||||||
globals: {
|
|
||||||
helper: 'readonly',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: [
|
|
||||||
'tests/**/*',
|
|
||||||
],
|
|
||||||
excludedFiles: [
|
|
||||||
'**/.eslintrc.*',
|
|
||||||
'tests/frontend/cypress/**/*',
|
|
||||||
'tests/frontend/helper.js',
|
|
||||||
'tests/frontend/helper/**/*',
|
|
||||||
'tests/frontend/travis/**/*',
|
|
||||||
'tests/ratelimit/**/*',
|
|
||||||
],
|
|
||||||
extends: 'etherpad/tests',
|
|
||||||
rules: {
|
|
||||||
'mocha/no-exports': 'off',
|
|
||||||
'mocha/no-top-level-hooks': 'off',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: [
|
|
||||||
'tests/backend/**/*',
|
|
||||||
],
|
|
||||||
excludedFiles: [
|
|
||||||
'**/.eslintrc.*',
|
|
||||||
],
|
|
||||||
extends: 'etherpad/tests/backend',
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: [
|
|
||||||
'tests/backend/**/*',
|
|
||||||
],
|
|
||||||
excludedFiles: [
|
|
||||||
'tests/backend/specs/**/*',
|
|
||||||
],
|
|
||||||
rules: {
|
|
||||||
'mocha/no-exports': 'off',
|
|
||||||
'mocha/no-top-level-hooks': 'off',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: [
|
|
||||||
'tests/frontend/**/*',
|
|
||||||
],
|
|
||||||
excludedFiles: [
|
|
||||||
'**/.eslintrc.*',
|
|
||||||
'tests/frontend/cypress/**/*',
|
|
||||||
'tests/frontend/helper.js',
|
|
||||||
'tests/frontend/helper/**/*',
|
|
||||||
'tests/frontend/travis/**/*',
|
|
||||||
],
|
|
||||||
extends: 'etherpad/tests/frontend',
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: [
|
|
||||||
'tests/frontend/**/*',
|
'tests/frontend/**/*',
|
||||||
],
|
],
|
||||||
excludedFiles: [
|
extends: 'etherpad/node',
|
||||||
'tests/frontend/specs/**/*',
|
},
|
||||||
],
|
{
|
||||||
rules: {
|
files: [
|
||||||
|
'static/**/*',
|
||||||
|
'tests/frontend/helper.js',
|
||||||
|
'tests/frontend/helper/**/*',
|
||||||
|
],
|
||||||
|
excludedFiles: [
|
||||||
|
'**/.eslintrc.*',
|
||||||
|
],
|
||||||
|
extends: 'etherpad/browser',
|
||||||
|
env: {
|
||||||
|
'shared-node-browser': true,
|
||||||
|
},
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'tests/frontend/helper/**/*',
|
||||||
|
],
|
||||||
|
globals: {
|
||||||
|
helper: 'readonly',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'tests/**/*',
|
||||||
|
],
|
||||||
|
excludedFiles: [
|
||||||
|
'**/.eslintrc.*',
|
||||||
|
'tests/frontend/cypress/**/*',
|
||||||
|
'tests/frontend/helper.js',
|
||||||
|
'tests/frontend/helper/**/*',
|
||||||
|
'tests/frontend/travis/**/*',
|
||||||
|
'tests/ratelimit/**/*',
|
||||||
|
],
|
||||||
|
extends: 'etherpad/tests',
|
||||||
|
rules: {
|
||||||
'mocha/no-exports': 'off',
|
'mocha/no-exports': 'off',
|
||||||
'mocha/no-top-level-hooks': 'off',
|
'mocha/no-top-level-hooks': 'off',
|
||||||
},
|
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: [
|
files: [
|
||||||
'tests/frontend/cypress/**/*',
|
'tests/backend/**/*',
|
||||||
],
|
],
|
||||||
extends: 'etherpad/tests/cypress',
|
excludedFiles: [
|
||||||
|
'**/.eslintrc.*',
|
||||||
|
],
|
||||||
|
extends: 'etherpad/tests/backend',
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'tests/backend/**/*',
|
||||||
|
],
|
||||||
|
excludedFiles: [
|
||||||
|
'tests/backend/specs/**/*',
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
'mocha/no-exports': 'off',
|
||||||
|
'mocha/no-top-level-hooks': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: [
|
files: [
|
||||||
'tests/frontend/travis/**/*',
|
'tests/frontend/**/*',
|
||||||
],
|
],
|
||||||
extends: 'etherpad/node',
|
excludedFiles: [
|
||||||
|
'**/.eslintrc.*',
|
||||||
|
'tests/frontend/cypress/**/*',
|
||||||
|
'tests/frontend/helper.js',
|
||||||
|
'tests/frontend/helper/**/*',
|
||||||
|
'tests/frontend/travis/**/*',
|
||||||
|
],
|
||||||
|
extends: 'etherpad/tests/frontend',
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'tests/frontend/**/*',
|
||||||
|
],
|
||||||
|
excludedFiles: [
|
||||||
|
'tests/frontend/specs/**/*',
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
'mocha/no-exports': 'off',
|
||||||
|
'mocha/no-top-level-hooks': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
{
|
||||||
root: true,
|
files: [
|
||||||
|
'tests/frontend/cypress/**/*',
|
||||||
|
],
|
||||||
|
extends: 'etherpad/tests/cypress',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'tests/frontend/travis/**/*',
|
||||||
|
],
|
||||||
|
extends: 'etherpad/node',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export const root = true;
|
||||||
|
export default {
|
||||||
|
ignorePatterns,
|
||||||
|
overrides,
|
||||||
|
root
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import AttributeMap from '../../static/js/AttributeMap';
|
import AttributeMap from '../../static/js/AttributeMap';
|
||||||
import {applyToAText, makeAText} from '../../static/js/Changeset';
|
import {applyToAText, copyAText, makeAText} from '../../static/js/Changeset';
|
||||||
import ChatMessage from '../../static/js/ChatMessage';
|
import ChatMessage from '../../static/js/ChatMessage';
|
||||||
import {AttributePool} from '../../static/js/AttributePool';
|
import {AttributePool} from '../../static/js/AttributePool';
|
||||||
import {Stream} from '../utils/Stream';
|
import {Stream} from '../utils/Stream';
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
import AttributeMap from '../../static/js/AttributeMap';
|
import AttributeMap from '../../static/js/AttributeMap';
|
||||||
import {getPad} from '../db/PadManager';
|
import {getPad} from '../db/PadManager';
|
||||||
import Changeset from '../../static/js/Changeset';
|
import {} from '../../static/js/Changeset';
|
||||||
import ChatMessage from '../../static/js/ChatMessage';
|
import ChatMessage from '../../static/js/ChatMessage';
|
||||||
import {AttributePool} from '../../static/js/AttributePool';
|
import {AttributePool} from '../../static/js/AttributePool';
|
||||||
import AttributeManager from '../../static/js/AttributeManager';
|
import AttributeManager from '../../static/js/AttributeManager';
|
||||||
|
@ -797,6 +797,7 @@ const _correctMarkersInPad = (atext, apool) => {
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export let clientVars:any
|
||||||
/**
|
/**
|
||||||
* Handles a CLIENT_READY. A CLIENT_READY is the first message from the client
|
* Handles a CLIENT_READY. A CLIENT_READY is the first message from the client
|
||||||
* to the server. The Client sends his token
|
* to the server. The Client sends his token
|
||||||
|
@ -954,7 +955,7 @@ const handleClientReady = async (socket, message) => {
|
||||||
|
|
||||||
// Warning: never ever send sessionInfo.padId to the client. If the client is read only you
|
// Warning: never ever send sessionInfo.padId to the client. If the client is read only you
|
||||||
// would open a security hole 1 swedish mile wide...
|
// would open a security hole 1 swedish mile wide...
|
||||||
const clientVars = {
|
clientVars = {
|
||||||
skinName: skinName,
|
skinName: skinName,
|
||||||
skinVariants: skinVariants,
|
skinVariants: skinVariants,
|
||||||
randomVersionString: randomString(4),
|
randomVersionString: randomString(4),
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,49 +1,27 @@
|
||||||
|
import * as hooks from "./pluginfw/hooks.js";
|
||||||
|
import { makeCSSManager as makeCSSManager$0 } from "./cssmanager.js";
|
||||||
|
import * as pluginUtils from "./pluginfw/shared.js";
|
||||||
|
import {Ace2EditorInfo, AceDocType} from "../module/Ace2EditorInfo";
|
||||||
|
import {clientVars} from "../../node/handler/PadMessageHandler";
|
||||||
|
import {CustomWindow} from "../module/CustomWindow";
|
||||||
'use strict';
|
'use strict';
|
||||||
/**
|
const makeCSSManager = { makeCSSManager: makeCSSManager$0 }.makeCSSManager;
|
||||||
* This code is mostly from the old Etherpad. Please help us to comment this code.
|
|
||||||
* This helps other people to understand this code better and helps them to improve it.
|
|
||||||
* TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copyright 2009 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS-IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// requires: top
|
|
||||||
// requires: undefined
|
|
||||||
|
|
||||||
const hooks = require('./pluginfw/hooks');
|
|
||||||
const makeCSSManager = require('./cssmanager').makeCSSManager;
|
|
||||||
const pluginUtils = require('./pluginfw/shared');
|
|
||||||
|
|
||||||
const debugLog = (...args) => {};
|
|
||||||
|
|
||||||
|
const debugLog = (...args) => { };
|
||||||
// The inner and outer iframe's locations are about:blank, so relative URLs are relative to that.
|
// The inner and outer iframe's locations are about:blank, so relative URLs are relative to that.
|
||||||
// Firefox and Chrome seem to do what the developer intends if given a relative URL, but Safari
|
// Firefox and Chrome seem to do what the developer intends if given a relative URL, but Safari
|
||||||
// errors out unless given an absolute URL for a JavaScript-created element.
|
// errors out unless given an absolute URL for a JavaScript-created element.
|
||||||
const absUrl = (url) => new URL(url, window.location.href).href;
|
const absUrl = (url) => new URL(url, window.location.href).href;
|
||||||
|
|
||||||
const eventFired = async (obj, event, cleanups = [], predicate = () => true) => {
|
const eventFired = async (obj, event, cleanups = [], predicate = () => true) => {
|
||||||
if (typeof cleanups === 'function') {
|
if (typeof cleanups === 'function') {
|
||||||
predicate = cleanups;
|
predicate = cleanups;
|
||||||
cleanups = [];
|
cleanups = [];
|
||||||
}
|
}
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
let cleanup;
|
let cleanup;
|
||||||
const successCb = () => {
|
const successCb = () => {
|
||||||
if (!predicate()) return;
|
if (!predicate())
|
||||||
|
return;
|
||||||
debugLog(`Ace2Editor.init() ${event} event on`, obj);
|
debugLog(`Ace2Editor.init() ${event} event on`, obj);
|
||||||
cleanup();
|
cleanup();
|
||||||
resolve();
|
resolve();
|
||||||
|
@ -55,7 +33,7 @@ const eventFired = async (obj, event, cleanups = [], predicate = () => true) =>
|
||||||
reject(err);
|
reject(err);
|
||||||
};
|
};
|
||||||
cleanup = () => {
|
cleanup = () => {
|
||||||
cleanup = () => {};
|
cleanup = () => { };
|
||||||
obj.removeEventListener(event, successCb);
|
obj.removeEventListener(event, successCb);
|
||||||
obj.removeEventListener('error', errorCb);
|
obj.removeEventListener('error', errorCb);
|
||||||
};
|
};
|
||||||
|
@ -64,14 +42,13 @@ const eventFired = async (obj, event, cleanups = [], predicate = () => true) =>
|
||||||
obj.addEventListener('error', errorCb);
|
obj.addEventListener('error', errorCb);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Resolves when the frame's document is ready to be mutated. Browsers seem to be quirky about
|
// Resolves when the frame's document is ready to be mutated. Browsers seem to be quirky about
|
||||||
// iframe ready events so this function throws the kitchen sink at the problem. Maybe one day we'll
|
// iframe ready events so this function throws the kitchen sink at the problem. Maybe one day we'll
|
||||||
// find a concise general solution.
|
// find a concise general solution.
|
||||||
const frameReady = async (frame) => {
|
const frameReady = async (frame) => {
|
||||||
// Can't do `const doc = frame.contentDocument;` because Firefox seems to asynchronously replace
|
// Can't do `const doc = frame.contentDocument;` because Firefox seems to asynchronously replace
|
||||||
// the document object after the frame is first created for some reason. ¯\_(ツ)_/¯
|
// the document object after the frame is first created for some reason. ¯\_(ツ)_/¯
|
||||||
const doc = () => frame.contentDocument;
|
const doc:AceDocType = () => frame.contentDocument;
|
||||||
const cleanups = [];
|
const cleanups = [];
|
||||||
try {
|
try {
|
||||||
await Promise.race([
|
await Promise.race([
|
||||||
|
@ -81,28 +58,27 @@ const frameReady = async (frame) => {
|
||||||
eventFired(doc(), 'DOMContentLoaded', cleanups),
|
eventFired(doc(), 'DOMContentLoaded', cleanups),
|
||||||
eventFired(doc(), 'readystatechange', cleanups, () => doc.readyState === 'complete'),
|
eventFired(doc(), 'readystatechange', cleanups, () => doc.readyState === 'complete'),
|
||||||
]);
|
]);
|
||||||
} finally {
|
}
|
||||||
for (const cleanup of cleanups) cleanup();
|
finally {
|
||||||
|
for (const cleanup of cleanups)
|
||||||
|
cleanup();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const Ace2Editor = function () {
|
const Ace2Editor = function () {
|
||||||
let info = {editor: this};
|
let info:Ace2EditorInfo = { editor: this };
|
||||||
let loaded = false;
|
let loaded = false;
|
||||||
|
|
||||||
let actionsPendingInit = [];
|
let actionsPendingInit = [];
|
||||||
|
|
||||||
const pendingInit = (func) => function (...args) {
|
const pendingInit = (func) => function (...args) {
|
||||||
const action = () => func.apply(this, args);
|
const action = () => func.apply(this, args);
|
||||||
if (loaded) return action();
|
if (loaded)
|
||||||
|
return action();
|
||||||
actionsPendingInit.push(action);
|
actionsPendingInit.push(action);
|
||||||
};
|
};
|
||||||
|
|
||||||
const doActionsPendingInit = () => {
|
const doActionsPendingInit = () => {
|
||||||
for (const fn of actionsPendingInit) fn();
|
for (const fn of actionsPendingInit)
|
||||||
|
fn();
|
||||||
actionsPendingInit = [];
|
actionsPendingInit = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
// The following functions (prefixed by 'ace_') are exposed by editor, but
|
// The following functions (prefixed by 'ace_') are exposed by editor, but
|
||||||
// execution is delayed until init is complete
|
// execution is delayed until init is complete
|
||||||
const aceFunctionsPendingInit = [
|
const aceFunctionsPendingInit = [
|
||||||
|
@ -124,7 +100,6 @@ const Ace2Editor = function () {
|
||||||
'execCommand',
|
'execCommand',
|
||||||
'replaceRange',
|
'replaceRange',
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const fnName of aceFunctionsPendingInit) {
|
for (const fnName of aceFunctionsPendingInit) {
|
||||||
// Note: info[`ace_${fnName}`] does not exist yet, so it can't be passed directly to
|
// Note: info[`ace_${fnName}`] does not exist yet, so it can't be passed directly to
|
||||||
// pendingInit(). A simple wrapper is used to defer the info[`ace_${fnName}`] lookup until
|
// pendingInit(). A simple wrapper is used to defer the info[`ace_${fnName}`] lookup until
|
||||||
|
@ -133,12 +108,9 @@ const Ace2Editor = function () {
|
||||||
info[`ace_${fnName}`].apply(this, args);
|
info[`ace_${fnName}`].apply(this, args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.exportText = () => loaded ? info.ace_exportText() : '(awaiting init)\n';
|
this.exportText = () => loaded ? info.ace_exportText() : '(awaiting init)\n';
|
||||||
|
|
||||||
this.getInInternationalComposition =
|
this.getInInternationalComposition =
|
||||||
() => loaded ? info.ace_getInInternationalComposition() : null;
|
() => loaded ? info.ace_getInInternationalComposition() : null;
|
||||||
|
|
||||||
// prepareUserChangeset:
|
// prepareUserChangeset:
|
||||||
// Returns null if no new changes or ACE not ready. Otherwise, bundles up all user changes
|
// Returns null if no new changes or ACE not ready. Otherwise, bundles up all user changes
|
||||||
// to the latest base text into a Changeset, which is returned (as a string if encodeAsString).
|
// to the latest base text into a Changeset, which is returned (as a string if encodeAsString).
|
||||||
|
@ -148,7 +120,6 @@ const Ace2Editor = function () {
|
||||||
// prepareUserChangeset will return an updated changeset that takes into account the latest user
|
// prepareUserChangeset will return an updated changeset that takes into account the latest user
|
||||||
// changes, and modify the changeset to be applied by applyPreparedChangesetToBase accordingly.
|
// changes, and modify the changeset to be applied by applyPreparedChangesetToBase accordingly.
|
||||||
this.prepareUserChangeset = () => loaded ? info.ace_prepareUserChangeset() : null;
|
this.prepareUserChangeset = () => loaded ? info.ace_prepareUserChangeset() : null;
|
||||||
|
|
||||||
const addStyleTagsFor = (doc, files) => {
|
const addStyleTagsFor = (doc, files) => {
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const link = doc.createElement('link');
|
const link = doc.createElement('link');
|
||||||
|
@ -158,17 +129,14 @@ const Ace2Editor = function () {
|
||||||
doc.head.appendChild(link);
|
doc.head.appendChild(link);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.destroy = pendingInit(() => {
|
this.destroy = pendingInit(() => {
|
||||||
info.ace_dispose();
|
info.ace_dispose();
|
||||||
info.frame.parentNode.removeChild(info.frame);
|
info.frame.parentNode.removeChild(info.frame);
|
||||||
info = null; // prevent IE 6 closure memory leaks
|
info = null; // prevent IE 6 closure memory leaks
|
||||||
});
|
});
|
||||||
|
|
||||||
this.init = async function (containerId, initialCode) {
|
this.init = async function (containerId, initialCode) {
|
||||||
debugLog('Ace2Editor.init()');
|
debugLog('Ace2Editor.init()');
|
||||||
this.importText(initialCode);
|
this.importText(initialCode);
|
||||||
|
|
||||||
const includedCSS = [
|
const includedCSS = [
|
||||||
`../static/css/iframe_editor.css?v=${clientVars.randomVersionString}`,
|
`../static/css/iframe_editor.css?v=${clientVars.randomVersionString}`,
|
||||||
`../static/css/pad.css?v=${clientVars.randomVersionString}`,
|
`../static/css/pad.css?v=${clientVars.randomVersionString}`,
|
||||||
|
@ -177,12 +145,9 @@ const Ace2Editor = function () {
|
||||||
(p) => /\/\//.test(p) ? p : `../static/plugins/${p}`),
|
(p) => /\/\//.test(p) ? p : `../static/plugins/${p}`),
|
||||||
`../static/skins/${clientVars.skinName}/pad.css?v=${clientVars.randomVersionString}`,
|
`../static/skins/${clientVars.skinName}/pad.css?v=${clientVars.randomVersionString}`,
|
||||||
];
|
];
|
||||||
|
|
||||||
const skinVariants = clientVars.skinVariants.split(' ').filter((x) => x !== '');
|
const skinVariants = clientVars.skinVariants.split(' ').filter((x) => x !== '');
|
||||||
|
|
||||||
const outerFrame = document.createElement('iframe');
|
const outerFrame = document.createElement('iframe');
|
||||||
outerFrame.name = 'ace_outer';
|
outerFrame.name = 'ace_outer';
|
||||||
outerFrame.frameBorder = 0; // for IE
|
|
||||||
outerFrame.title = 'Ether';
|
outerFrame.title = 'Ether';
|
||||||
// Some browsers do strange things unless the iframe has a src or srcdoc property:
|
// Some browsers do strange things unless the iframe has a src or srcdoc property:
|
||||||
// - Firefox replaces the frame's contentWindow.document object with a different object after
|
// - Firefox replaces the frame's contentWindow.document object with a different object after
|
||||||
|
@ -197,25 +162,20 @@ const Ace2Editor = function () {
|
||||||
info.frame = outerFrame;
|
info.frame = outerFrame;
|
||||||
document.getElementById(containerId).appendChild(outerFrame);
|
document.getElementById(containerId).appendChild(outerFrame);
|
||||||
const outerWindow = outerFrame.contentWindow;
|
const outerWindow = outerFrame.contentWindow;
|
||||||
|
|
||||||
debugLog('Ace2Editor.init() waiting for outer frame');
|
debugLog('Ace2Editor.init() waiting for outer frame');
|
||||||
await frameReady(outerFrame);
|
await frameReady(outerFrame);
|
||||||
debugLog('Ace2Editor.init() outer frame ready');
|
debugLog('Ace2Editor.init() outer frame ready');
|
||||||
|
|
||||||
// Firefox might replace the outerWindow.document object after iframe creation so this variable
|
// Firefox might replace the outerWindow.document object after iframe creation so this variable
|
||||||
// is assigned after the Window's load event.
|
// is assigned after the Window's load event.
|
||||||
const outerDocument = outerWindow.document;
|
const outerDocument = outerWindow.document;
|
||||||
|
|
||||||
// <html> tag
|
// <html> tag
|
||||||
outerDocument.documentElement.classList.add('outer-editor', 'outerdoc', ...skinVariants);
|
outerDocument.documentElement.classList.add('outer-editor', 'outerdoc', ...skinVariants);
|
||||||
|
|
||||||
// <head> tag
|
// <head> tag
|
||||||
addStyleTagsFor(outerDocument, includedCSS);
|
addStyleTagsFor(outerDocument, includedCSS);
|
||||||
const outerStyle = outerDocument.createElement('style');
|
const outerStyle = outerDocument.createElement('style');
|
||||||
outerStyle.type = 'text/css';
|
outerStyle.type = 'text/css';
|
||||||
outerStyle.title = 'dynamicsyntax';
|
outerStyle.title = 'dynamicsyntax';
|
||||||
outerDocument.head.appendChild(outerStyle);
|
outerDocument.head.appendChild(outerStyle);
|
||||||
|
|
||||||
// <body> tag
|
// <body> tag
|
||||||
outerDocument.body.id = 'outerdocbody';
|
outerDocument.body.id = 'outerdocbody';
|
||||||
outerDocument.body.classList.add('outerdocbody', ...pluginUtils.clientPluginNames());
|
outerDocument.body.classList.add('outerdocbody', ...pluginUtils.clientPluginNames());
|
||||||
|
@ -231,30 +191,24 @@ const Ace2Editor = function () {
|
||||||
lineMetricsDiv.id = 'linemetricsdiv';
|
lineMetricsDiv.id = 'linemetricsdiv';
|
||||||
lineMetricsDiv.appendChild(outerDocument.createTextNode('x'));
|
lineMetricsDiv.appendChild(outerDocument.createTextNode('x'));
|
||||||
outerDocument.body.appendChild(lineMetricsDiv);
|
outerDocument.body.appendChild(lineMetricsDiv);
|
||||||
|
|
||||||
const innerFrame = outerDocument.createElement('iframe');
|
const innerFrame = outerDocument.createElement('iframe');
|
||||||
innerFrame.name = 'ace_inner';
|
innerFrame.name = 'ace_inner';
|
||||||
innerFrame.title = 'pad';
|
innerFrame.title = 'pad';
|
||||||
innerFrame.scrolling = 'no';
|
innerFrame.scrolling = 'no';
|
||||||
innerFrame.frameBorder = 0;
|
innerFrame.frameBorder = String(0);
|
||||||
innerFrame.allowTransparency = true; // for IE
|
|
||||||
// The iframe MUST have a src or srcdoc property to avoid browser quirks. See the comment above
|
// The iframe MUST have a src or srcdoc property to avoid browser quirks. See the comment above
|
||||||
// outerFrame.srcdoc.
|
// outerFrame.srcdoc.
|
||||||
innerFrame.src = 'empty.html';
|
innerFrame.src = 'empty.html';
|
||||||
outerDocument.body.insertBefore(innerFrame, outerDocument.body.firstChild);
|
outerDocument.body.insertBefore(innerFrame, outerDocument.body.firstChild);
|
||||||
const innerWindow = innerFrame.contentWindow;
|
const innerWindow = innerFrame.contentWindow as unknown as CustomWindow;
|
||||||
|
|
||||||
debugLog('Ace2Editor.init() waiting for inner frame');
|
debugLog('Ace2Editor.init() waiting for inner frame');
|
||||||
await frameReady(innerFrame);
|
await frameReady(innerFrame);
|
||||||
debugLog('Ace2Editor.init() inner frame ready');
|
debugLog('Ace2Editor.init() inner frame ready');
|
||||||
|
|
||||||
// Firefox might replace the innerWindow.document object after iframe creation so this variable
|
// Firefox might replace the innerWindow.document object after iframe creation so this variable
|
||||||
// is assigned after the Window's load event.
|
// is assigned after the Window's load event.
|
||||||
const innerDocument = innerWindow.document;
|
const innerDocument = innerWindow.document;
|
||||||
|
|
||||||
// <html> tag
|
// <html> tag
|
||||||
innerDocument.documentElement.classList.add('inner-editor', ...skinVariants);
|
innerDocument.documentElement.classList.add('inner-editor', ...skinVariants);
|
||||||
|
|
||||||
// <head> tag
|
// <head> tag
|
||||||
addStyleTagsFor(innerDocument, includedCSS);
|
addStyleTagsFor(innerDocument, includedCSS);
|
||||||
const requireKernel = innerDocument.createElement('script');
|
const requireKernel = innerDocument.createElement('script');
|
||||||
|
@ -267,7 +221,7 @@ const Ace2Editor = function () {
|
||||||
const script = innerDocument.createElement('script');
|
const script = innerDocument.createElement('script');
|
||||||
script.type = 'text/javascript';
|
script.type = 'text/javascript';
|
||||||
script.src = absUrl(`../javascripts/lib/ep_etherpad-lite/static/js/${module}.js` +
|
script.src = absUrl(`../javascripts/lib/ep_etherpad-lite/static/js/${module}.js` +
|
||||||
`?callback=require.define&v=${clientVars.randomVersionString}`);
|
`?callback=require.define&v=${clientVars.randomVersionString}`);
|
||||||
innerDocument.head.appendChild(script);
|
innerDocument.head.appendChild(script);
|
||||||
}
|
}
|
||||||
const innerStyle = innerDocument.createElement('style');
|
const innerStyle = innerDocument.createElement('style');
|
||||||
|
@ -275,16 +229,13 @@ const Ace2Editor = function () {
|
||||||
innerStyle.title = 'dynamicsyntax';
|
innerStyle.title = 'dynamicsyntax';
|
||||||
innerDocument.head.appendChild(innerStyle);
|
innerDocument.head.appendChild(innerStyle);
|
||||||
const headLines = [];
|
const headLines = [];
|
||||||
hooks.callAll('aceInitInnerdocbodyHead', {iframeHTML: headLines});
|
hooks.callAll('aceInitInnerdocbodyHead', { iframeHTML: headLines });
|
||||||
innerDocument.head.appendChild(
|
innerDocument.head.appendChild(innerDocument.createRange().createContextualFragment(headLines.join('\n')));
|
||||||
innerDocument.createRange().createContextualFragment(headLines.join('\n')));
|
|
||||||
|
|
||||||
// <body> tag
|
// <body> tag
|
||||||
innerDocument.body.id = 'innerdocbody';
|
innerDocument.body.id = 'innerdocbody';
|
||||||
innerDocument.body.classList.add('innerdocbody');
|
innerDocument.body.classList.add('innerdocbody');
|
||||||
innerDocument.body.setAttribute('spellcheck', 'false');
|
innerDocument.body.setAttribute('spellcheck', 'false');
|
||||||
innerDocument.body.appendChild(innerDocument.createTextNode('\u00A0')); //
|
innerDocument.body.appendChild(innerDocument.createTextNode('\u00A0')); //
|
||||||
|
|
||||||
debugLog('Ace2Editor.init() waiting for require kernel load');
|
debugLog('Ace2Editor.init() waiting for require kernel load');
|
||||||
await eventFired(requireKernel, 'load');
|
await eventFired(requireKernel, 'load');
|
||||||
debugLog('Ace2Editor.init() require kernel loaded');
|
debugLog('Ace2Editor.init() require kernel loaded');
|
||||||
|
@ -292,17 +243,13 @@ const Ace2Editor = function () {
|
||||||
require.setRootURI(absUrl('../javascripts/src'));
|
require.setRootURI(absUrl('../javascripts/src'));
|
||||||
require.setLibraryURI(absUrl('../javascripts/lib'));
|
require.setLibraryURI(absUrl('../javascripts/lib'));
|
||||||
require.setGlobalKeyPath('require');
|
require.setGlobalKeyPath('require');
|
||||||
|
|
||||||
// intentially moved before requiring client_plugins to save a 307
|
// intentially moved before requiring client_plugins to save a 307
|
||||||
innerWindow.Ace2Inner = require('ep_etherpad-lite/static/js/ace2_inner');
|
innerWindow.Ace2Inner = require('ep_etherpad-lite/static/js/ace2_inner');
|
||||||
innerWindow.plugins = require('ep_etherpad-lite/static/js/pluginfw/client_plugins');
|
innerWindow.plugins = require('ep_etherpad-lite/static/js/pluginfw/client_plugins');
|
||||||
innerWindow.plugins.adoptPluginsFromAncestorsOf(innerWindow);
|
innerWindow.plugins.adoptPluginsFromAncestorsOf(innerWindow);
|
||||||
|
|
||||||
innerWindow.$ = innerWindow.jQuery = require('ep_etherpad-lite/static/js/rjquery').jQuery;
|
innerWindow.$ = innerWindow.jQuery = require('ep_etherpad-lite/static/js/rjquery').jQuery;
|
||||||
|
|
||||||
debugLog('Ace2Editor.init() waiting for plugins');
|
debugLog('Ace2Editor.init() waiting for plugins');
|
||||||
await new Promise((resolve, reject) => innerWindow.plugins.ensure(
|
await new Promise((resolve, reject) => innerWindow.plugins.ensure((err) => err != null ? reject(err) : resolve()));
|
||||||
(err) => err != null ? reject(err) : resolve()));
|
|
||||||
debugLog('Ace2Editor.init() waiting for Ace2Inner.init()');
|
debugLog('Ace2Editor.init() waiting for Ace2Inner.init()');
|
||||||
await innerWindow.Ace2Inner.init(info, {
|
await innerWindow.Ace2Inner.init(info, {
|
||||||
inner: makeCSSManager(innerStyle.sheet),
|
inner: makeCSSManager(innerStyle.sheet),
|
||||||
|
@ -315,5 +262,4 @@ const Ace2Editor = function () {
|
||||||
debugLog('Ace2Editor.init() done');
|
debugLog('Ace2Editor.init() done');
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
export { Ace2Editor };
|
||||||
exports.Ace2Editor = Ace2Editor;
|
|
5
src/static/module/Ace2EditorInfo.ts
Normal file
5
src/static/module/Ace2EditorInfo.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export type Ace2EditorInfo = {
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AceDocType = any
|
14
src/static/module/CustomWindow.ts
Normal file
14
src/static/module/CustomWindow.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
export type CustomWindow = {
|
||||||
|
require: RequireFunction,
|
||||||
|
Ace2Inner:any,
|
||||||
|
plugins: any,
|
||||||
|
jQuery: any,
|
||||||
|
document: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type RequireFunction= {
|
||||||
|
setRootURI: (url: string)=>void,
|
||||||
|
setLibraryURI: (url: string)=>void,
|
||||||
|
setGlobalKeyPath: (path: string)=>void,
|
||||||
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"outDir": "../dist"
|
"outDir": "dist"
|
||||||
},
|
},
|
||||||
"lib": ["es2015"]
|
"lib": ["es2015"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue