argous 1.2.206 → 1.2.208
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/index.d.ts +4 -2
- package/dist/api/index.js +5 -2
- package/dist/components/Editor/Events.d.ts +9 -7
- package/dist/components/Editor/Events.js +0 -7
- package/dist/components/Editor/TinyMCE.d.ts +1 -8
- package/dist/components/Editor/TinyMCE.js +2 -10
- package/dist/components/Editor/Utils.d.ts +2 -7
- package/dist/components/Editor/Utils.js +29 -9
- package/dist/components/Editor/components/Editor.d.ts +17 -16
- package/dist/components/Editor/components/Editor.js +92 -49
- package/dist/components/Editor/components/EditorPropTypes.d.ts +1 -8
- package/dist/components/Editor/components/EditorPropTypes.js +19 -9
- package/dist/components/Editor/index.d.ts +2 -9
- package/dist/components/Editor/index.js +0 -7
- package/dist/utils/api.d.ts +1 -1
- package/dist/utils/api.js +3 -2
- package/lib/api/index.js +2 -2
- package/lib/components/Editor/Events.ts +9 -8
- package/lib/components/Editor/ScriptLoader2.ts +161 -0
- package/lib/components/Editor/TinyMCE.ts +2 -12
- package/lib/components/Editor/Utils.ts +25 -8
- package/lib/components/Editor/components/Editor.tsx +100 -78
- package/lib/components/Editor/components/EditorPropTypes.ts +21 -12
- package/lib/components/Editor/index.tsx +2 -10
- package/lib/utils/api.ts +3 -2
- package/package.json +1 -1
- package/lib/components/Editor/ScriptLoader.ts +0 -96
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2017-present, Ephox, Inc.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the Apache 2 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
1
|
import { Editor as TinyMCEEditor, EditorEvent, Events } from './tinymce/tinymce';
|
|
10
2
|
|
|
11
3
|
export type EventHandler<A> = (a: EditorEvent<A>, editor: TinyMCEEditor) => unknown;
|
|
@@ -53,6 +45,7 @@ export interface ITinyEvents {
|
|
|
53
45
|
onBeforeSetContent: EEventHandler<'BeforeSetContent'>;
|
|
54
46
|
onChange: EventHandler<unknown>;
|
|
55
47
|
onClearUndos: EEventHandler<'ClearUndos'>;
|
|
48
|
+
onCommentChange: EventHandler<unknown>;
|
|
56
49
|
onDeactivate: EEventHandler<'deactivate'>;
|
|
57
50
|
onDirty: EventHandler<unknown>;
|
|
58
51
|
onExecCommand: EEventHandler<'ExecCommand'>;
|
|
@@ -78,6 +71,14 @@ export interface ITinyEvents {
|
|
|
78
71
|
onSubmit: EventHandler<unknown>;
|
|
79
72
|
onUndo: EEventHandler<'Undo'>;
|
|
80
73
|
onVisualAid: EventHandler<unknown>;
|
|
74
|
+
onSkinLoadError: EEventHandler<'SkinLoadError'>;
|
|
75
|
+
onThemeLoadError: EEventHandler<'ThemeLoadError'>;
|
|
76
|
+
onModelLoadError: EEventHandler<'ModelLoadError'>;
|
|
77
|
+
onPluginLoadError: EEventHandler<'PluginLoadError'>;
|
|
78
|
+
onIconsLoadError: EEventHandler<'IconsLoadError'>;
|
|
79
|
+
onLanguageLoadError: EEventHandler<'LanguageLoadError'>;
|
|
80
|
+
onScriptsLoad: () => void;
|
|
81
|
+
onScriptsLoadError: (err: unknown) => void;
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
export interface IEvents extends INativeEvents, ITinyEvents {}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { uuid } from './Utils';
|
|
2
|
+
|
|
3
|
+
export type CallbackFn = () => void;
|
|
4
|
+
|
|
5
|
+
export interface ScriptItem {
|
|
6
|
+
src: string;
|
|
7
|
+
async?: boolean;
|
|
8
|
+
defer?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface Id {
|
|
12
|
+
id: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const injectScriptTag = (doc: Document, item: ScriptItem & Id, handler: (id: string, err?: unknown) => void) => {
|
|
16
|
+
const scriptTag = doc.createElement('script');
|
|
17
|
+
scriptTag.referrerPolicy = 'origin';
|
|
18
|
+
scriptTag.type = 'application/javascript';
|
|
19
|
+
scriptTag.id = item.id;
|
|
20
|
+
scriptTag.src = item.src;
|
|
21
|
+
scriptTag.async = item.async ?? false;
|
|
22
|
+
scriptTag.defer = item.defer ?? false;
|
|
23
|
+
|
|
24
|
+
const loadHandler = () => {
|
|
25
|
+
scriptTag.removeEventListener('load', loadHandler);
|
|
26
|
+
scriptTag.removeEventListener('error', errorHandler);
|
|
27
|
+
handler(item.src);
|
|
28
|
+
};
|
|
29
|
+
const errorHandler = (err: unknown) => {
|
|
30
|
+
scriptTag.removeEventListener('load', loadHandler);
|
|
31
|
+
scriptTag.removeEventListener('error', errorHandler);
|
|
32
|
+
handler(item.src, err);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
scriptTag.addEventListener('load', loadHandler);
|
|
36
|
+
scriptTag.addEventListener('error', errorHandler);
|
|
37
|
+
|
|
38
|
+
if (doc.head) {
|
|
39
|
+
doc.head.appendChild(scriptTag);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
interface ScriptState {
|
|
44
|
+
id: string;
|
|
45
|
+
src: string;
|
|
46
|
+
done: boolean;
|
|
47
|
+
error?: unknown;
|
|
48
|
+
handlers: ((src: string, err?: unknown) => void)[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const createDocumentScriptLoader = (doc: Document) => {
|
|
52
|
+
let lookup: Record<string, ScriptState> = {};
|
|
53
|
+
|
|
54
|
+
const scriptLoadOrErrorHandler = (src: string, err?: unknown) => {
|
|
55
|
+
const item = lookup[src];
|
|
56
|
+
item.done = true;
|
|
57
|
+
item.error = err;
|
|
58
|
+
for (const h of item.handlers) {
|
|
59
|
+
h(src, err);
|
|
60
|
+
}
|
|
61
|
+
item.handlers = [];
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const loadScripts = (items: ScriptItem[], success: () => void, failure?: (err: unknown) => void) => {
|
|
65
|
+
// eslint-disable-next-line no-console
|
|
66
|
+
const failureOrLog = (err: unknown) => failure !== undefined ? failure(err) : console.error(err);
|
|
67
|
+
if (items.length === 0) {
|
|
68
|
+
failureOrLog(new Error('At least one script must be provided'));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
let successCount = 0;
|
|
72
|
+
let failed = false;
|
|
73
|
+
const loaded = (_src: string, err?: unknown) => {
|
|
74
|
+
if (failed) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (err) {
|
|
78
|
+
failed = true;
|
|
79
|
+
failureOrLog(err);
|
|
80
|
+
} else if (++successCount === items.length) {
|
|
81
|
+
success();
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
for (const item of items) {
|
|
85
|
+
const existing = lookup[item.src];
|
|
86
|
+
if (existing) {
|
|
87
|
+
if (existing.done) {
|
|
88
|
+
loaded(item.src, existing.error);
|
|
89
|
+
} else {
|
|
90
|
+
existing.handlers.push(loaded);
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
// create a new entry
|
|
94
|
+
const id = uuid('tiny-');
|
|
95
|
+
lookup[item.src] = {
|
|
96
|
+
id,
|
|
97
|
+
src: item.src,
|
|
98
|
+
done: false,
|
|
99
|
+
error: null,
|
|
100
|
+
handlers: [loaded],
|
|
101
|
+
};
|
|
102
|
+
injectScriptTag(doc, { id, ...item }, scriptLoadOrErrorHandler);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const deleteScripts = () => {
|
|
108
|
+
for (const item of Object.values(lookup)) {
|
|
109
|
+
const scriptTag = doc.getElementById(item.id);
|
|
110
|
+
if (scriptTag != null && scriptTag.tagName === 'SCRIPT') {
|
|
111
|
+
scriptTag.parentNode?.removeChild(scriptTag);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
lookup = {};
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const getDocument = () => doc;
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
loadScripts,
|
|
121
|
+
deleteScripts,
|
|
122
|
+
getDocument
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
type DocumentScriptLoader = ReturnType<typeof createDocumentScriptLoader>;
|
|
127
|
+
|
|
128
|
+
const createScriptLoader = () => {
|
|
129
|
+
const cache: DocumentScriptLoader[] = [];
|
|
130
|
+
|
|
131
|
+
const getDocumentScriptLoader = (doc: Document) => {
|
|
132
|
+
let loader = cache.find((l) => l.getDocument() === doc);
|
|
133
|
+
if (loader === undefined) {
|
|
134
|
+
loader = createDocumentScriptLoader(doc);
|
|
135
|
+
cache.push(loader);
|
|
136
|
+
}
|
|
137
|
+
return loader;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const loadList = (doc: Document, items: ScriptItem[], delay: number, success: () => void, failure?: (err: unknown) => void) => {
|
|
141
|
+
const doLoad = () => getDocumentScriptLoader(doc).loadScripts(items, success, failure);
|
|
142
|
+
if (delay > 0) {
|
|
143
|
+
setTimeout(doLoad, delay);
|
|
144
|
+
} else {
|
|
145
|
+
doLoad();
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const reinitialize = () => {
|
|
150
|
+
for (let loader = cache.pop(); loader != null; loader = cache.pop()) {
|
|
151
|
+
loader.deleteScripts();
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
loadList,
|
|
157
|
+
reinitialize
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export const ScriptLoader = createScriptLoader();
|
|
@@ -1,17 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2017-present, Ephox, Inc.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the Apache 2 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
1
|
import { TinyMCE as TinyMCEGlobal } from './tinymce/tinymce';
|
|
10
2
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
const getTinymce = (): TinyMCEGlobal | null => {
|
|
14
|
-
const global = getGlobal();
|
|
3
|
+
const getTinymce = (view: Window): TinyMCEGlobal | null => {
|
|
4
|
+
const global = view as any;
|
|
15
5
|
|
|
16
6
|
return global && global.tinymce ? global.tinymce : null;
|
|
17
7
|
};
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2017-present, Ephox, Inc.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the Apache 2 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
1
|
import { IAllProps } from './components/Editor';
|
|
10
2
|
import { eventPropTypes, IEventPropTypes } from './components/EditorPropTypes';
|
|
11
3
|
import { Editor as TinyMCEEditor, EditorEvent } from './tinymce/tinymce';
|
|
@@ -60,6 +52,7 @@ export const configHandlers = (
|
|
|
60
52
|
lookup,
|
|
61
53
|
editor.on.bind(editor),
|
|
62
54
|
editor.off.bind(editor),
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
63
56
|
(handlerLookup, key) => (e) => handlerLookup(key)?.(e, editor),
|
|
64
57
|
prevProps,
|
|
65
58
|
props,
|
|
@@ -93,3 +86,27 @@ export const mergePlugins = (initPlugins: string | string[] | undefined, inputPl
|
|
|
93
86
|
|
|
94
87
|
export const isBeforeInputEventAvailable = () => window.InputEvent && typeof (InputEvent.prototype as any).getTargetRanges === 'function';
|
|
95
88
|
|
|
89
|
+
export const isInDoc = (elem: Node) => {
|
|
90
|
+
if (!('isConnected' in Node.prototype)) {
|
|
91
|
+
// Fallback for IE and old Edge
|
|
92
|
+
let current = elem;
|
|
93
|
+
let parent = elem.parentNode;
|
|
94
|
+
while (parent != null) {
|
|
95
|
+
current = parent;
|
|
96
|
+
parent = current.parentNode;
|
|
97
|
+
}
|
|
98
|
+
return current === elem.ownerDocument;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return elem.isConnected;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export const setMode = (editor: TinyMCEEditor | undefined, mode: 'readonly' | 'design') => {
|
|
105
|
+
if (editor !== undefined) {
|
|
106
|
+
if (editor.mode != null && typeof editor.mode === 'object' && typeof editor.mode.set === 'function') {
|
|
107
|
+
editor.mode.set(mode);
|
|
108
|
+
} else { // support TinyMCE 4
|
|
109
|
+
(editor as any).setMode(mode);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
@@ -1,20 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2017-present, Ephox, Inc.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the Apache 2 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
1
|
import { EditorPropTypes, IEditorPropTypes } from './EditorPropTypes';
|
|
10
2
|
import { IEvents } from '../Events';
|
|
11
|
-
import { ScriptLoader } from '../
|
|
3
|
+
import { ScriptItem, ScriptLoader } from '../ScriptLoader2';
|
|
12
4
|
import { getTinymce } from '../TinyMCE';
|
|
13
|
-
import { Bookmark, Editor as TinyMCEEditor, EditorEvent,
|
|
14
|
-
import { isFunction, isTextareaOrInput, mergePlugins, uuid, configHandlers, isBeforeInputEventAvailable } from '../Utils';
|
|
15
|
-
import { useTheme } from '@material-ui/core';
|
|
5
|
+
import { Bookmark, Editor as TinyMCEEditor, EditorEvent, TinyMCE } from '../tinymce/tinymce';
|
|
6
|
+
import { isFunction, isTextareaOrInput, mergePlugins, uuid, configHandlers, isBeforeInputEventAvailable, isInDoc, setMode } from '../Utils';
|
|
16
7
|
import * as React from 'react';
|
|
17
8
|
|
|
9
|
+
type EditorOptions = Parameters<TinyMCE['init']>[0];
|
|
10
|
+
|
|
18
11
|
export interface IProps {
|
|
19
12
|
apiKey: string;
|
|
20
13
|
id: string;
|
|
@@ -22,16 +15,15 @@ export interface IProps {
|
|
|
22
15
|
initialValue: string;
|
|
23
16
|
onEditorChange: (a: string, editor: TinyMCEEditor) => void;
|
|
24
17
|
value: string;
|
|
25
|
-
init:
|
|
26
|
-
/** @deprecated use `editor.getContent({format: 'text' })` in `onEditorChange` prop instead */
|
|
27
|
-
outputFormat: 'html' | 'text';
|
|
18
|
+
init: EditorOptions & { selector?: undefined; target?: undefined };
|
|
28
19
|
tagName: string;
|
|
29
20
|
cloudChannel: string;
|
|
30
|
-
plugins: NonNullable<
|
|
31
|
-
toolbar: NonNullable<
|
|
21
|
+
plugins: NonNullable<EditorOptions['plugins']>;
|
|
22
|
+
toolbar: NonNullable<EditorOptions['toolbar']>;
|
|
32
23
|
disabled: boolean;
|
|
33
24
|
textareaName: string;
|
|
34
|
-
tinymceScriptSrc: string;
|
|
25
|
+
tinymceScriptSrc: string | string[] | ScriptItem[];
|
|
26
|
+
rollback: number | false;
|
|
35
27
|
scriptLoading: {
|
|
36
28
|
async?: boolean;
|
|
37
29
|
defer?: boolean;
|
|
@@ -41,14 +33,11 @@ export interface IProps {
|
|
|
41
33
|
|
|
42
34
|
export interface IAllProps extends Partial<IProps>, Partial<IEvents> { }
|
|
43
35
|
|
|
44
|
-
const changeEvents = () => getTinymce()?.Env?.browser?.isIE() ? 'change keyup compositionend setcontent' : 'change input compositionend setcontent';
|
|
45
|
-
const beforeInputEvent = () => isBeforeInputEventAvailable() ? 'beforeinput SelectionChange' : 'SelectionChange';
|
|
46
|
-
|
|
47
36
|
export class Editor extends React.Component<IAllProps> {
|
|
48
37
|
public static propTypes: IEditorPropTypes = EditorPropTypes;
|
|
49
38
|
|
|
50
39
|
public static defaultProps: Partial<IAllProps> = {
|
|
51
|
-
cloudChannel: '
|
|
40
|
+
cloudChannel: '6'
|
|
52
41
|
};
|
|
53
42
|
|
|
54
43
|
public editor?: TinyMCEEditor;
|
|
@@ -69,6 +58,10 @@ export class Editor extends React.Component<IAllProps> {
|
|
|
69
58
|
this.boundHandlers = {};
|
|
70
59
|
}
|
|
71
60
|
|
|
61
|
+
private get view() {
|
|
62
|
+
return this.elementRef.current?.ownerDocument.defaultView ?? window;
|
|
63
|
+
}
|
|
64
|
+
|
|
72
65
|
public componentDidUpdate(prevProps: Partial<IAllProps>) {
|
|
73
66
|
if (this.rollbackTimer) {
|
|
74
67
|
clearTimeout(this.rollbackTimer);
|
|
@@ -114,23 +107,31 @@ export class Editor extends React.Component<IAllProps> {
|
|
|
114
107
|
}
|
|
115
108
|
if (this.props.disabled !== prevProps.disabled) {
|
|
116
109
|
const disabled = this.props.disabled ?? false;
|
|
117
|
-
this.editor
|
|
110
|
+
setMode(this.editor, disabled ? 'readonly' : 'design');
|
|
118
111
|
}
|
|
119
112
|
}
|
|
120
113
|
}
|
|
121
114
|
}
|
|
122
115
|
|
|
123
116
|
public componentDidMount() {
|
|
124
|
-
if (getTinymce() !== null) {
|
|
117
|
+
if (getTinymce(this.view) !== null) {
|
|
125
118
|
this.initialise();
|
|
126
|
-
} else if (this.
|
|
127
|
-
|
|
119
|
+
} else if (Array.isArray(this.props.tinymceScriptSrc) && this.props.tinymceScriptSrc.length === 0) {
|
|
120
|
+
this.props.onScriptsLoadError?.(new Error('No `tinymce` global is present but the `tinymceScriptSrc` prop was an empty array.'));
|
|
121
|
+
} else if (this.elementRef.current?.ownerDocument) {
|
|
122
|
+
const successHandler = () => {
|
|
123
|
+
this.props.onScriptsLoad?.();
|
|
124
|
+
this.initialise();
|
|
125
|
+
};
|
|
126
|
+
const errorHandler = (err: unknown) => {
|
|
127
|
+
this.props.onScriptsLoadError?.(err);
|
|
128
|
+
};
|
|
129
|
+
ScriptLoader.loadList(
|
|
128
130
|
this.elementRef.current.ownerDocument,
|
|
129
|
-
this.
|
|
130
|
-
this.props.scriptLoading?.async ?? false,
|
|
131
|
-
this.props.scriptLoading?.defer ?? false,
|
|
131
|
+
this.getScriptSources(),
|
|
132
132
|
this.props.scriptLoading?.delay ?? 0,
|
|
133
|
-
|
|
133
|
+
successHandler,
|
|
134
|
+
errorHandler
|
|
134
135
|
);
|
|
135
136
|
}
|
|
136
137
|
}
|
|
@@ -138,8 +139,8 @@ export class Editor extends React.Component<IAllProps> {
|
|
|
138
139
|
public componentWillUnmount() {
|
|
139
140
|
const editor = this.editor;
|
|
140
141
|
if (editor) {
|
|
141
|
-
editor.off(changeEvents(), this.handleEditorChange);
|
|
142
|
-
editor.off(beforeInputEvent(), this.handleBeforeInput);
|
|
142
|
+
editor.off(this.changeEvents(), this.handleEditorChange);
|
|
143
|
+
editor.off(this.beforeInputEvent(), this.handleBeforeInput);
|
|
143
144
|
editor.off('keypress', this.handleEditorChangeSpecial);
|
|
144
145
|
editor.off('keydown', this.handleBeforeInputSpecial);
|
|
145
146
|
editor.off('NewBlock', this.handleEditorChange);
|
|
@@ -153,11 +154,19 @@ export class Editor extends React.Component<IAllProps> {
|
|
|
153
154
|
}
|
|
154
155
|
|
|
155
156
|
public render() {
|
|
156
|
-
return
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
157
|
+
return this.inline ? this.renderInline() : this.renderIframe();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private changeEvents() {
|
|
161
|
+
const isIE = getTinymce(this.view)?.Env?.browser?.isIE();
|
|
162
|
+
return (isIE
|
|
163
|
+
? 'change keyup compositionend setcontent CommentChange'
|
|
164
|
+
: 'change input compositionend setcontent CommentChange'
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private beforeInputEvent() {
|
|
169
|
+
return isBeforeInputEventAvailable() ? 'beforeinput SelectionChange' : 'SelectionChange';
|
|
161
170
|
}
|
|
162
171
|
|
|
163
172
|
private renderInline() {
|
|
@@ -178,15 +187,29 @@ export class Editor extends React.Component<IAllProps> {
|
|
|
178
187
|
});
|
|
179
188
|
}
|
|
180
189
|
|
|
181
|
-
private
|
|
182
|
-
|
|
183
|
-
|
|
190
|
+
private getScriptSources(): ScriptItem[] {
|
|
191
|
+
const async = this.props.scriptLoading?.async;
|
|
192
|
+
const defer = this.props.scriptLoading?.defer;
|
|
193
|
+
if (this.props.tinymceScriptSrc !== undefined) {
|
|
194
|
+
if (typeof this.props.tinymceScriptSrc === 'string') {
|
|
195
|
+
return [{ src: this.props.tinymceScriptSrc, async, defer }];
|
|
196
|
+
}
|
|
197
|
+
// multiple scripts can be specified which allows for hybrid mode
|
|
198
|
+
return this.props.tinymceScriptSrc.map((item) => {
|
|
199
|
+
if (typeof item === 'string') {
|
|
200
|
+
// async does not make sense for multiple items unless
|
|
201
|
+
// they are not dependent (which will be unlikely)
|
|
202
|
+
return { src: item, async, defer };
|
|
203
|
+
}
|
|
204
|
+
return item;
|
|
205
|
+
|
|
206
|
+
});
|
|
184
207
|
}
|
|
185
|
-
|
|
208
|
+
// fallback to the cloud when the tinymceScriptSrc is not specified
|
|
186
209
|
const channel = this.props.cloudChannel;
|
|
187
210
|
const apiKey = this.props.apiKey ? this.props.apiKey : 'no-api-key';
|
|
188
|
-
|
|
189
|
-
return
|
|
211
|
+
const cloudTinyJs = `https://cdn.tiny.cloud/1/${apiKey}/tinymce/${channel}/tinymce.min.js`;
|
|
212
|
+
return [{ src: cloudTinyJs, async, defer }];
|
|
190
213
|
}
|
|
191
214
|
|
|
192
215
|
private getInitialValue() {
|
|
@@ -202,20 +225,20 @@ export class Editor extends React.Component<IAllProps> {
|
|
|
202
225
|
private bindHandlers(prevProps: Partial<IAllProps>) {
|
|
203
226
|
if (this.editor !== undefined) {
|
|
204
227
|
// typescript chokes trying to understand the type of the lookup function
|
|
205
|
-
configHandlers(this.editor
|
|
228
|
+
configHandlers(this.editor, prevProps, this.props, this.boundHandlers, (key) => this.props[key] as any);
|
|
206
229
|
// check if we should monitor editor changes
|
|
207
230
|
const isValueControlled = (p: Partial<IAllProps>) => p.onEditorChange !== undefined || p.value !== undefined;
|
|
208
231
|
const wasControlled = isValueControlled(prevProps);
|
|
209
232
|
const nowControlled = isValueControlled(this.props);
|
|
210
233
|
if (!wasControlled && nowControlled) {
|
|
211
|
-
this.editor.on(changeEvents(), this.handleEditorChange);
|
|
212
|
-
this.editor.on(beforeInputEvent(), this.handleBeforeInput);
|
|
234
|
+
this.editor.on(this.changeEvents(), this.handleEditorChange);
|
|
235
|
+
this.editor.on(this.beforeInputEvent(), this.handleBeforeInput);
|
|
213
236
|
this.editor.on('keydown', this.handleBeforeInputSpecial);
|
|
214
237
|
this.editor.on('keyup', this.handleEditorChangeSpecial);
|
|
215
238
|
this.editor.on('NewBlock', this.handleEditorChange);
|
|
216
239
|
} else if (wasControlled && !nowControlled) {
|
|
217
|
-
this.editor.off(changeEvents(), this.handleEditorChange);
|
|
218
|
-
this.editor.off(beforeInputEvent(), this.handleBeforeInput);
|
|
240
|
+
this.editor.off(this.changeEvents(), this.handleEditorChange);
|
|
241
|
+
this.editor.off(this.beforeInputEvent(), this.handleBeforeInput);
|
|
219
242
|
this.editor.off('keydown', this.handleBeforeInputSpecial);
|
|
220
243
|
this.editor.off('keyup', this.handleEditorChangeSpecial);
|
|
221
244
|
this.editor.off('NewBlock', this.handleEditorChange);
|
|
@@ -263,19 +286,20 @@ export class Editor extends React.Component<IAllProps> {
|
|
|
263
286
|
const editor = this.editor;
|
|
264
287
|
if (editor && editor.initialized) {
|
|
265
288
|
const newContent = editor.getContent();
|
|
266
|
-
if (this.props.value !== undefined && this.props.value !== newContent) {
|
|
289
|
+
if (this.props.value !== undefined && this.props.value !== newContent && this.props.rollback !== false) {
|
|
267
290
|
// start a timer and revert to the value if not applied in time
|
|
268
291
|
if (!this.rollbackTimer) {
|
|
269
|
-
this.rollbackTimer = window.setTimeout(
|
|
292
|
+
this.rollbackTimer = window.setTimeout(
|
|
293
|
+
this.rollbackChange,
|
|
294
|
+
typeof this.props.rollback === 'number' ? this.props.rollback : 200
|
|
295
|
+
);
|
|
270
296
|
}
|
|
271
297
|
}
|
|
272
298
|
|
|
273
299
|
if (newContent !== this.currentContent) {
|
|
274
300
|
this.currentContent = newContent;
|
|
275
301
|
if (isFunction(this.props.onEditorChange)) {
|
|
276
|
-
|
|
277
|
-
const out = format === 'html' ? newContent : editor.getContent({ format });
|
|
278
|
-
this.props.onEditorChange(out, editor);
|
|
302
|
+
this.props.onEditorChange(newContent, editor);
|
|
279
303
|
}
|
|
280
304
|
}
|
|
281
305
|
}
|
|
@@ -287,25 +311,41 @@ export class Editor extends React.Component<IAllProps> {
|
|
|
287
311
|
}
|
|
288
312
|
};
|
|
289
313
|
|
|
290
|
-
private initialise = () => {
|
|
314
|
+
private initialise = (attempts = 0) => {
|
|
291
315
|
const target = this.elementRef.current;
|
|
292
316
|
if (!target) {
|
|
293
317
|
return; // Editor has been unmounted
|
|
294
318
|
}
|
|
319
|
+
if (!isInDoc(target)) {
|
|
320
|
+
// this is probably someone trying to help by rendering us offscreen
|
|
321
|
+
// but we can't do that because the editor iframe must be in the document
|
|
322
|
+
// in order to have state
|
|
323
|
+
if (attempts === 0) {
|
|
324
|
+
// we probably just need to wait for the current events to be processed
|
|
325
|
+
setTimeout(() => this.initialise(1), 1);
|
|
326
|
+
} else if (attempts < 100) {
|
|
327
|
+
// wait for ten seconds, polling every tenth of a second
|
|
328
|
+
setTimeout(() => this.initialise(attempts + 1), 100);
|
|
329
|
+
} else {
|
|
330
|
+
// give up, at this point it seems that more polling is unlikely to help
|
|
331
|
+
throw new Error('tinymce can only be initialised when in a document');
|
|
332
|
+
}
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
295
335
|
|
|
296
|
-
const tinymce = getTinymce();
|
|
336
|
+
const tinymce = getTinymce(this.view);
|
|
297
337
|
if (!tinymce) {
|
|
298
338
|
throw new Error('tinymce should have been loaded into global scope');
|
|
299
339
|
}
|
|
300
340
|
|
|
301
|
-
const finalInit:
|
|
341
|
+
const finalInit: EditorOptions = {
|
|
302
342
|
...this.props.init,
|
|
303
343
|
selector: undefined,
|
|
304
344
|
target,
|
|
305
345
|
readonly: this.props.disabled,
|
|
306
346
|
inline: this.inline,
|
|
307
|
-
plugins: mergePlugins(this.props.init
|
|
308
|
-
toolbar: this.props.toolbar
|
|
347
|
+
plugins: mergePlugins(this.props.init?.plugins, this.props.plugins),
|
|
348
|
+
toolbar: this.props.toolbar ?? this.props.init?.toolbar,
|
|
309
349
|
setup: (editor) => {
|
|
310
350
|
this.editor = editor;
|
|
311
351
|
this.bindHandlers({});
|
|
@@ -339,7 +379,7 @@ export class Editor extends React.Component<IAllProps> {
|
|
|
339
379
|
editor.setDirty(false);
|
|
340
380
|
}
|
|
341
381
|
const disabled = this.props.disabled ?? false;
|
|
342
|
-
editor
|
|
382
|
+
setMode(this.editor, disabled ? 'readonly' : 'design');
|
|
343
383
|
// ensure existing init_instance_callback is called
|
|
344
384
|
if (this.props.init && isFunction(this.props.init.init_instance_callback)) {
|
|
345
385
|
this.props.init.init_instance_callback(editor);
|
|
@@ -353,24 +393,6 @@ export class Editor extends React.Component<IAllProps> {
|
|
|
353
393
|
target.value = this.getInitialValue();
|
|
354
394
|
}
|
|
355
395
|
|
|
356
|
-
tinymce.init(finalInit
|
|
396
|
+
tinymce.init(finalInit);
|
|
357
397
|
};
|
|
358
398
|
}
|
|
359
|
-
|
|
360
|
-
const Tema = ({ children }) => {
|
|
361
|
-
|
|
362
|
-
const theme = useTheme().palette.type;
|
|
363
|
-
|
|
364
|
-
return (
|
|
365
|
-
<div>
|
|
366
|
-
{theme === 'dark' ? <>
|
|
367
|
-
<link rel='stylesheet' href='./skins/ui/dark/skin.min.css' />
|
|
368
|
-
<link rel='stylesheet' href='./skins/ui/dark/content.min.css' />
|
|
369
|
-
</> : <>
|
|
370
|
-
<link rel='stylesheet' href='./skins/ui/default/content.min.css' />
|
|
371
|
-
<link rel='stylesheet' href='./skins/ui/default/skin.min.css' />
|
|
372
|
-
</>}
|
|
373
|
-
{children}
|
|
374
|
-
</div>
|
|
375
|
-
);
|
|
376
|
-
};
|
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2017-present, Ephox, Inc.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the Apache 2 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
1
|
import { IProps } from './Editor';
|
|
10
2
|
import { IEvents } from '../Events';
|
|
11
3
|
import * as PropTypes from 'prop-types';
|
|
12
4
|
|
|
13
|
-
export type CopyProps<T> = { [P in keyof T]: PropTypes.Requireable<
|
|
5
|
+
export type CopyProps<T> = { [P in keyof T]: PropTypes.Requireable<unknown> };
|
|
14
6
|
|
|
15
7
|
export type IEventPropTypes = CopyProps<IEvents>;
|
|
16
8
|
|
|
@@ -30,6 +22,7 @@ export const eventPropTypes: IEventPropTypes = {
|
|
|
30
22
|
onClearUndos: PropTypes.func,
|
|
31
23
|
onClick: PropTypes.func,
|
|
32
24
|
onContextMenu: PropTypes.func,
|
|
25
|
+
onCommentChange: PropTypes.func,
|
|
33
26
|
onCopy: PropTypes.func,
|
|
34
27
|
onCut: PropTypes.func,
|
|
35
28
|
onDblclick: PropTypes.func,
|
|
@@ -78,7 +71,15 @@ export const eventPropTypes: IEventPropTypes = {
|
|
|
78
71
|
onShow: PropTypes.func,
|
|
79
72
|
onSubmit: PropTypes.func,
|
|
80
73
|
onUndo: PropTypes.func,
|
|
81
|
-
onVisualAid: PropTypes.func
|
|
74
|
+
onVisualAid: PropTypes.func,
|
|
75
|
+
onSkinLoadError: PropTypes.func,
|
|
76
|
+
onThemeLoadError: PropTypes.func,
|
|
77
|
+
onModelLoadError: PropTypes.func,
|
|
78
|
+
onPluginLoadError: PropTypes.func,
|
|
79
|
+
onIconsLoadError: PropTypes.func,
|
|
80
|
+
onLanguageLoadError: PropTypes.func,
|
|
81
|
+
onScriptsLoad: PropTypes.func,
|
|
82
|
+
onScriptsLoadError: PropTypes.func,
|
|
82
83
|
};
|
|
83
84
|
|
|
84
85
|
export const EditorPropTypes: IEditorPropTypes = {
|
|
@@ -88,7 +89,6 @@ export const EditorPropTypes: IEditorPropTypes = {
|
|
|
88
89
|
init: PropTypes.object,
|
|
89
90
|
initialValue: PropTypes.string,
|
|
90
91
|
onEditorChange: PropTypes.func,
|
|
91
|
-
outputFormat: PropTypes.oneOf(['html', 'text']),
|
|
92
92
|
value: PropTypes.string,
|
|
93
93
|
tagName: PropTypes.string,
|
|
94
94
|
cloudChannel: PropTypes.string,
|
|
@@ -96,7 +96,16 @@ export const EditorPropTypes: IEditorPropTypes = {
|
|
|
96
96
|
toolbar: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
|
|
97
97
|
disabled: PropTypes.bool,
|
|
98
98
|
textareaName: PropTypes.string,
|
|
99
|
-
tinymceScriptSrc: PropTypes.
|
|
99
|
+
tinymceScriptSrc: PropTypes.oneOfType([
|
|
100
|
+
PropTypes.string,
|
|
101
|
+
PropTypes.arrayOf(PropTypes.string),
|
|
102
|
+
PropTypes.arrayOf(PropTypes.shape({
|
|
103
|
+
src: PropTypes.string,
|
|
104
|
+
async: PropTypes.bool,
|
|
105
|
+
defer: PropTypes.bool
|
|
106
|
+
}))
|
|
107
|
+
]),
|
|
108
|
+
rollback: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf([false])]),
|
|
100
109
|
scriptLoading: PropTypes.shape({
|
|
101
110
|
async: PropTypes.bool,
|
|
102
111
|
defer: PropTypes.bool,
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
* Copyright (c) 2017-present, Ephox, Inc.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the Apache 2 license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
1
|
+
import { Editor, IAllProps } from './components/Editor';
|
|
8
2
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export { Editor };
|
|
3
|
+
export { Editor, IAllProps };
|
package/lib/utils/api.ts
CHANGED
|
@@ -56,7 +56,7 @@ export const enableDebugger = () => {
|
|
|
56
56
|
debuging = true;
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
-
export const serverAction = async (metodo:string, dados = {}, pgCode?:string|boolean, tratarErro?:string|boolean) => {
|
|
59
|
+
export const serverAction = async (metodo:string, dados = {}, pgCode?:string|boolean, tratarErro?:string|boolean, token?:string) => {
|
|
60
60
|
|
|
61
61
|
const code = typeof pgCode === 'string' ? pgCode : typeof tratarErro === 'string' ? tratarErro : undefined;
|
|
62
62
|
const tErro = typeof tratarErro === 'boolean' ? tratarErro : typeof pgCode === 'boolean' ? pgCode : false;
|
|
@@ -66,7 +66,8 @@ export const serverAction = async (metodo:string, dados = {}, pgCode?:string|boo
|
|
|
66
66
|
const data = {
|
|
67
67
|
pgCode: currentProgram,
|
|
68
68
|
action: metodo,
|
|
69
|
-
dados
|
|
69
|
+
dados,
|
|
70
|
+
token
|
|
70
71
|
};
|
|
71
72
|
|
|
72
73
|
const res = await action(data);
|