@modusoperandi/licit 0.13.3 → 0.13.20
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/.eslintrc.js +59 -55
- package/README.md +15 -1
- package/dist/ListItemNodeSpec.js +1 -1
- package/dist/ListItemNodeSpec.js.flow +1 -1
- package/dist/bom.xml +5147 -8743
- package/dist/client/CollabConnector.js +5 -1
- package/dist/client/CollabConnector.js.flow +6 -2
- package/dist/client/EditorConnection.js +5 -4
- package/dist/client/EditorConnection.js.flow +10 -5
- package/dist/client/Licit.js +105 -30
- package/dist/client/Licit.js.flow +120 -47
- package/dist/client/Licit.test.js +29 -2
- package/dist/client/Licit.test.js.flow +33 -2
- package/dist/client/SimpleConnector.js +7 -0
- package/dist/client/SimpleConnector.js.flow +6 -0
- package/dist/client/http.js +12 -0
- package/dist/client/http.js.flow +4 -0
- package/dist/convertFromDOMElement.js.flow +2 -2
- package/dist/convertFromHTML.js +1 -4
- package/dist/convertFromHTML.js.flow +3 -5
- package/dist/convertFromJSON.js +12 -28
- package/dist/convertFromJSON.js.flow +9 -31
- package/dist/createEmptyEditorState.js +3 -6
- package/dist/createEmptyEditorState.js.flow +4 -8
- package/dist/index.js +11 -1
- package/dist/index.js.flow +1 -1
- package/dist/patchStyleElements.js +1 -3
- package/dist/patchStyleElements.js.flow +2 -2
- package/dist/ui/czi-link-tooltip.css +1 -1
- package/dist/ui/czi-vars.css +1 -1
- package/licit/client/index.js +2 -1
- package/licit/server/collab/instance.js +21 -6
- package/licit/server/collab/server.js +25 -5
- package/licit/server/collab/start.js +1 -1
- package/package.json +5 -10
- package/src/ListItemNodeSpec.js +1 -1
- package/src/client/CollabConnector.js +6 -2
- package/src/client/EditorConnection.js +10 -5
- package/src/client/Licit.js +120 -47
- package/src/client/Licit.test.js +33 -2
- package/src/client/SimpleConnector.js +6 -0
- package/src/client/http.js +4 -0
- package/src/convertFromDOMElement.js +2 -2
- package/src/convertFromHTML.js +3 -5
- package/src/convertFromJSON.js +9 -31
- package/src/createEmptyEditorState.js +4 -8
- package/src/index.js +1 -1
- package/src/patchStyleElements.js +2 -2
- package/src/ui/czi-link-tooltip.css +1 -1
- package/src/ui/czi-vars.css +1 -1
- package/utils/build_licit_collab_server.js +1 -1
- package/webpack.config.js +1 -1
- package/node_modules/prosemirror-utils/LICENSE +0 -13
- package/node_modules/prosemirror-utils/README.md +0 -0
- package/node_modules/prosemirror-utils/dist/helpers.js +0 -119
- package/node_modules/prosemirror-utils/dist/index.js +0 -17
- package/node_modules/prosemirror-utils/dist/index.js.map +0 -1
- package/node_modules/prosemirror-utils/dist/node.js +0 -106
- package/node_modules/prosemirror-utils/dist/selection.js +0 -168
- package/node_modules/prosemirror-utils/dist/transforms.js +0 -257
- package/node_modules/prosemirror-utils/package.json +0 -81
- package/node_modules/prosemirror-utils/typings.d.ts +0 -79
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modusoperandi/licit",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.20",
|
|
4
4
|
"subversion": "1",
|
|
5
5
|
"description": "Rich text editor built with React and ProseMirror",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,11 +9,8 @@
|
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/MO-Movia/licit.git"
|
|
11
11
|
},
|
|
12
|
-
"bundleDependencies": [
|
|
13
|
-
"prosemirror-utils"
|
|
14
|
-
],
|
|
15
12
|
"scripts": {
|
|
16
|
-
"test": "jest",
|
|
13
|
+
"test": "jest --coverage",
|
|
17
14
|
"build:bom": "cyclonedx-bom -o dist/bom.xml",
|
|
18
15
|
"build:clean": "rm -rf dist/ && rm -f modusoperandi-licit-*.*.*.tgz",
|
|
19
16
|
"build:css": "cp src/ui/*.css dist/ui && cp src/ui/mathquill-editor/*.css dist/ui/mathquill-editor && cp src/client/*.css dist/client && cp src/*.css dist",
|
|
@@ -92,9 +89,8 @@
|
|
|
92
89
|
"write-file-webpack-plugin": "4.5.1"
|
|
93
90
|
},
|
|
94
91
|
"dependencies": {
|
|
95
|
-
"@modusoperandi/licit-
|
|
96
|
-
"@modusoperandi/licit-
|
|
97
|
-
"@modusoperandi/licit-ui-commands": "^0.1.5",
|
|
92
|
+
"@modusoperandi/licit-doc-attrs-step": "^0.1.3",
|
|
93
|
+
"@modusoperandi/licit-ui-commands": "^0.1.6",
|
|
98
94
|
"@wojtekmaj/enzyme-adapter-react-17": "^0.6.7",
|
|
99
95
|
"body-parser": "^1.19.0",
|
|
100
96
|
"browserkeymap": "2.0.2",
|
|
@@ -123,14 +119,13 @@
|
|
|
123
119
|
"prosemirror-state": "^1.3.4",
|
|
124
120
|
"prosemirror-tables": "^1.1.1",
|
|
125
121
|
"prosemirror-transform": "^1.2.9",
|
|
126
|
-
"prosemirror-utils": "
|
|
122
|
+
"prosemirror-utils": "^1.0.0-0",
|
|
127
123
|
"prosemirror-view": "^1.17.3",
|
|
128
124
|
"query-string": "6.13.1",
|
|
129
125
|
"react": "^17.0.2",
|
|
130
126
|
"react-dom": "^17.0.2",
|
|
131
127
|
"resize-observer-polyfill": "1.5.1",
|
|
132
128
|
"smooth-scroll-into-view-if-needed": "1.1.28",
|
|
133
|
-
"stable": "0.1.8",
|
|
134
129
|
"style-loader": "^1.2.1",
|
|
135
130
|
"uuid": "8.2.0",
|
|
136
131
|
"webfontloader": "1.6.28"
|
package/src/ListItemNodeSpec.js
CHANGED
|
@@ -29,7 +29,7 @@ const ListItemNodeSpec: NodeSpec = {
|
|
|
29
29
|
// This spec does not support nested lists (e.g. `'paragraph block*'`)
|
|
30
30
|
// as content because of the complexity of dealing with indentation
|
|
31
31
|
// (context: https://github.com/ProseMirror/prosemirror/issues/92).
|
|
32
|
-
content: 'paragraph',
|
|
32
|
+
content: '(bullet_list|paragraph)+',
|
|
33
33
|
|
|
34
34
|
parseDOM: [{ tag: 'li', getAttrs }],
|
|
35
35
|
|
|
@@ -14,7 +14,7 @@ type IdStrict = string;
|
|
|
14
14
|
class CollabConnector extends SimpleConnector {
|
|
15
15
|
_clientID: string;
|
|
16
16
|
_connected: boolean;
|
|
17
|
-
_connection:
|
|
17
|
+
_connection: EditorConnection;
|
|
18
18
|
_docID: IdStrict;
|
|
19
19
|
_stepKeys: Object;
|
|
20
20
|
|
|
@@ -79,7 +79,11 @@ class CollabConnector extends SimpleConnector {
|
|
|
79
79
|
// FS IRAD-1040 2020-09-02
|
|
80
80
|
// Send the modified schema to server
|
|
81
81
|
updateSchema = (schema: Schema, data: any) => {
|
|
82
|
-
this._connection.updateSchema(schema, data);
|
|
82
|
+
this._connection.updateSchema(schema, data, this._dataDefined);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
updateContent = (data: any) => {
|
|
86
|
+
this._connection.start(data, this._dataDefined);
|
|
83
87
|
};
|
|
84
88
|
}
|
|
85
89
|
|
|
@@ -10,7 +10,7 @@ import { Plugin, EditorState } from 'prosemirror-state';
|
|
|
10
10
|
import { Step } from 'prosemirror-transform';
|
|
11
11
|
import { EditorView } from 'prosemirror-view';
|
|
12
12
|
import uuid from '../uuid';
|
|
13
|
-
import { GET, POST } from './http';
|
|
13
|
+
import { GET, POST, PUT } from './http';
|
|
14
14
|
// [FS] IRAD-1040 2020-09-02
|
|
15
15
|
import { Schema } from 'prosemirror-model';
|
|
16
16
|
import { stringify } from 'flatted';
|
|
@@ -144,8 +144,13 @@ class EditorConnection {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
// Load the document from the server and start up
|
|
147
|
-
start(): void {
|
|
148
|
-
|
|
147
|
+
start(input: any, dataDefined: boolean): void {
|
|
148
|
+
const query = '?dataDefined=' + dataDefined;
|
|
149
|
+
this.run(
|
|
150
|
+
input
|
|
151
|
+
? PUT(this.url + query, JSON.stringify(input), 'application/json')
|
|
152
|
+
: GET(this.url, 'application/json')
|
|
153
|
+
).then(
|
|
149
154
|
(data) => {
|
|
150
155
|
data = JSON.parse(data);
|
|
151
156
|
this.report.success();
|
|
@@ -253,7 +258,7 @@ class EditorConnection {
|
|
|
253
258
|
|
|
254
259
|
// [FS] IRAD-1040 2020-09-02
|
|
255
260
|
// Send the modified schema to server
|
|
256
|
-
updateSchema(schema: Schema, input: any) {
|
|
261
|
+
updateSchema(schema: Schema, input: any, dataDefined: boolean) {
|
|
257
262
|
// to avoid cyclic reference error, use flatted string.
|
|
258
263
|
const schemaFlatted = stringify(schema);
|
|
259
264
|
this.run(POST(this.url + '/schema/', schemaFlatted, 'text/plain')).then(
|
|
@@ -261,7 +266,7 @@ class EditorConnection {
|
|
|
261
266
|
console.log("collab server's schema updated");
|
|
262
267
|
// [FS] IRAD-1040 2020-09-08
|
|
263
268
|
this.schema = schema;
|
|
264
|
-
this.start(input);
|
|
269
|
+
this.start(input, dataDefined);
|
|
265
270
|
},
|
|
266
271
|
(err) => {
|
|
267
272
|
this.report.failure(err);
|
package/src/client/Licit.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
import { EditorState, TextSelection, Plugin } from 'prosemirror-state';
|
|
3
|
-
import { Node } from 'prosemirror-model';
|
|
3
|
+
import { Node, Schema } from 'prosemirror-model';
|
|
4
4
|
import { Transform } from 'prosemirror-transform';
|
|
5
5
|
import { EditorView } from 'prosemirror-view';
|
|
6
6
|
import * as React from 'react';
|
|
@@ -14,18 +14,23 @@ import SimpleConnector from './SimpleConnector';
|
|
|
14
14
|
import CollabConnector from './CollabConnector';
|
|
15
15
|
import { EMPTY_DOC_JSON } from '../createEmptyEditorState';
|
|
16
16
|
import type { EditorRuntime } from '../Types';
|
|
17
|
-
import {
|
|
18
|
-
|
|
17
|
+
import {
|
|
18
|
+
createPopUp,
|
|
19
|
+
atViewportCenter,
|
|
20
|
+
} from '@modusoperandi/licit-ui-commands';
|
|
19
21
|
import AlertInfo from '../ui/AlertInfo';
|
|
20
22
|
import { SetDocAttrStep } from '@modusoperandi/licit-doc-attrs-step';
|
|
21
23
|
import './licit.css';
|
|
22
24
|
import DefaultEditorPlugins from '../buildEditorPlugins';
|
|
23
|
-
import { Schema } from 'prosemirror-model';
|
|
24
25
|
import EditorMarks from '../EditorMarks';
|
|
25
26
|
import EditorNodes from '../EditorNodes';
|
|
27
|
+
import convertFromHTML from '../convertFromHTML';
|
|
28
|
+
|
|
29
|
+
export const DataType = Object.freeze({
|
|
30
|
+
JSON: Symbol('json'),
|
|
31
|
+
HTML: Symbol('html'),
|
|
32
|
+
});
|
|
26
33
|
|
|
27
|
-
const ATTR_OBJID = 'objectId';
|
|
28
|
-
const ATTR_OBJMETADATA = 'objectMetaData';
|
|
29
34
|
/**
|
|
30
35
|
* LICIT properties:
|
|
31
36
|
* docID {string} [] Collaborative Doument ID
|
|
@@ -38,14 +43,15 @@ const ATTR_OBJMETADATA = 'objectMetaData';
|
|
|
38
43
|
* @param data {JSON} Modified document data.
|
|
39
44
|
* onReady {@callback} [null] Fires when the editor is fully ready.
|
|
40
45
|
* @param ref {LICIT} Rerefence of the editor.
|
|
41
|
-
* data {JSON} [null] Document data to be loaded into the editor.
|
|
46
|
+
* data {JSON|HTML} [null] Document data to be loaded into the editor.
|
|
47
|
+
* dataType {JSON|HTML} [JSON] Document data to be loaded into the editor.
|
|
42
48
|
* disabled {boolean} [false] Disable the editor.
|
|
43
49
|
* embedded {boolean} [false] Disable/Enable inline behaviour.
|
|
44
50
|
* plugins [plugins] External Plugins into the editor.
|
|
45
51
|
*/
|
|
46
52
|
class Licit extends React.Component<any, any> {
|
|
47
53
|
_runtime: EditorRuntime;
|
|
48
|
-
_connector:
|
|
54
|
+
_connector: SimpleConnector;
|
|
49
55
|
_clientID: string;
|
|
50
56
|
_editorView: EditorView; // This will be handy in updating document's content.
|
|
51
57
|
_skipSCU: boolean; // Flag to decide whether to skip shouldComponentUpdate
|
|
@@ -93,13 +99,17 @@ class Licit extends React.Component<any, any> {
|
|
|
93
99
|
const onReadyCB =
|
|
94
100
|
typeof props.onReady === 'function' ? props.onReady : noop;
|
|
95
101
|
const readOnly = props.readOnly || false;
|
|
96
|
-
|
|
102
|
+
let data = props.data || null;
|
|
103
|
+
const dataType = props.dataType || DataType.JSON;
|
|
97
104
|
const disabled = props.disabled || false;
|
|
98
105
|
const embedded = props.embedded || false; // [FS] IRAD-996 2020-06-30
|
|
99
106
|
// [FS] 2020-07-03
|
|
100
107
|
// Handle Image Upload from Angular App
|
|
101
108
|
const runtime = props.runtime || null;
|
|
102
109
|
const plugins = props.plugins || null;
|
|
110
|
+
// This flag decides whether DataType.HTML check is needed when
|
|
111
|
+
// changing document. If it forcefully done, it is not needed, otherwise needed.
|
|
112
|
+
this.skipDataTypeCheck = false;
|
|
103
113
|
|
|
104
114
|
this._defaultEditorSchema = new Schema({
|
|
105
115
|
nodes: EditorNodes,
|
|
@@ -109,25 +119,8 @@ class Licit extends React.Component<any, any> {
|
|
|
109
119
|
this._defaultEditorSchema
|
|
110
120
|
).get();
|
|
111
121
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
null,
|
|
115
|
-
this._defaultEditorSchema,
|
|
116
|
-
plugins,
|
|
117
|
-
this._defaultEditorPlugins
|
|
118
|
-
);
|
|
119
|
-
// [FS] IRAD-1067 2020-09-19
|
|
120
|
-
// The editorState will return null if the doc Json is mal-formed
|
|
121
|
-
if (null === editorState) {
|
|
122
|
-
editorState = convertFromJSON(
|
|
123
|
-
EMPTY_DOC_JSON,
|
|
124
|
-
null,
|
|
125
|
-
this._defaultEditorSchema,
|
|
126
|
-
plugins,
|
|
127
|
-
this._defaultEditorPlugins
|
|
128
|
-
);
|
|
129
|
-
this.showAlert();
|
|
130
|
-
}
|
|
122
|
+
const editorState = this.initEditorState(plugins, dataType, data);
|
|
123
|
+
data = editorState.doc;
|
|
131
124
|
|
|
132
125
|
const setState = this.setState.bind(this);
|
|
133
126
|
this._connector = collaborative
|
|
@@ -145,6 +138,8 @@ class Licit extends React.Component<any, any> {
|
|
|
145
138
|
)
|
|
146
139
|
: new SimpleConnector(editorState, setState);
|
|
147
140
|
|
|
141
|
+
this._connector._dataDefined = !!props.data;
|
|
142
|
+
|
|
148
143
|
// FS IRAD-989 2020-18-06
|
|
149
144
|
// updating properties should automatically render the changes
|
|
150
145
|
|
|
@@ -162,6 +157,7 @@ class Licit extends React.Component<any, any> {
|
|
|
162
157
|
disabled,
|
|
163
158
|
embedded,
|
|
164
159
|
runtime,
|
|
160
|
+
dataType,
|
|
165
161
|
};
|
|
166
162
|
|
|
167
163
|
// FS IRAD-1040 2020-26-08
|
|
@@ -172,6 +168,66 @@ class Licit extends React.Component<any, any> {
|
|
|
172
168
|
}
|
|
173
169
|
}
|
|
174
170
|
|
|
171
|
+
initEditorState(plugins: Array<Plugin>, dataType: DataType, data: any) {
|
|
172
|
+
let editorState = null;
|
|
173
|
+
const effectivePlugins = this.getEffectivePlugins(
|
|
174
|
+
this._defaultEditorSchema,
|
|
175
|
+
this._defaultEditorPlugins,
|
|
176
|
+
plugins
|
|
177
|
+
);
|
|
178
|
+
if (DataType.JSON === dataType) {
|
|
179
|
+
editorState = convertFromJSON(
|
|
180
|
+
data,
|
|
181
|
+
null,
|
|
182
|
+
effectivePlugins.schema,
|
|
183
|
+
effectivePlugins.plugins
|
|
184
|
+
);
|
|
185
|
+
// [FS] IRAD-1067 2020-09-19
|
|
186
|
+
// The editorState will return null if the doc Json is mal-formed
|
|
187
|
+
if (null === editorState) {
|
|
188
|
+
editorState = convertFromJSON(
|
|
189
|
+
EMPTY_DOC_JSON,
|
|
190
|
+
null,
|
|
191
|
+
effectivePlugins.schema,
|
|
192
|
+
effectivePlugins.plugins
|
|
193
|
+
);
|
|
194
|
+
this.showAlert();
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
editorState = convertFromHTML(
|
|
198
|
+
data,
|
|
199
|
+
effectivePlugins.schema,
|
|
200
|
+
effectivePlugins.plugins
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return editorState;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
getEffectivePlugins(
|
|
208
|
+
schema: Schema,
|
|
209
|
+
defaultPlugins: Array<Plugin>,
|
|
210
|
+
plugins: Array<Plugin>
|
|
211
|
+
): { plugins: Array<Plugin>, schema: Schema } {
|
|
212
|
+
const effectivePlugins = defaultPlugins;
|
|
213
|
+
|
|
214
|
+
if (plugins) {
|
|
215
|
+
for (const p of plugins) {
|
|
216
|
+
if (!effectivePlugins.includes(p)) {
|
|
217
|
+
effectivePlugins.push(p);
|
|
218
|
+
if (p.getEffectiveSchema) {
|
|
219
|
+
schema = p.getEffectiveSchema(schema);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (p.initKeyCommands) {
|
|
223
|
+
effectivePlugins.push(p.initKeyCommands());
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return { plugins: effectivePlugins, schema };
|
|
229
|
+
}
|
|
230
|
+
|
|
175
231
|
// [FS] IRAD-1578 2021-09-27
|
|
176
232
|
onReady(state: EditorState) {
|
|
177
233
|
const collabEditing = this.state.docID !== '';
|
|
@@ -263,13 +319,33 @@ class Licit extends React.Component<any, any> {
|
|
|
263
319
|
return node.attrs && node.attrs[attrName];
|
|
264
320
|
}
|
|
265
321
|
|
|
266
|
-
|
|
322
|
+
getDocument(content: any, editorState: EditorState, dataType: DataType) {
|
|
323
|
+
let document = null;
|
|
324
|
+
const { schema } = editorState;
|
|
325
|
+
|
|
326
|
+
if (DataType.JSON === dataType || this.skipDataTypeCheck) {
|
|
327
|
+
document = schema.nodeFromJSON(content ? content : EMPTY_DOC_JSON);
|
|
328
|
+
} else {
|
|
329
|
+
const tempEState = convertFromHTML(
|
|
330
|
+
content ? content : '',
|
|
331
|
+
schema,
|
|
332
|
+
editorState.plugins
|
|
333
|
+
);
|
|
334
|
+
document = tempEState.doc;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return document;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
setContent = (content: any = {}, dataType: DataType): void => {
|
|
341
|
+
this.skipDataTypeCheck = false;
|
|
267
342
|
// [FS] IRAD-1571 2021-09-27
|
|
268
343
|
// dispatch a transaction that MUST start from the views current state;
|
|
269
344
|
const editorState = this._editorView.state;
|
|
270
|
-
const { doc
|
|
345
|
+
const { doc } = editorState;
|
|
271
346
|
let { tr } = editorState;
|
|
272
|
-
const document =
|
|
347
|
+
const document = this.getDocument(content, editorState, dataType);
|
|
348
|
+
this.skipDataTypeCheck = true;
|
|
273
349
|
|
|
274
350
|
// [FS] IRAD-1593 2021-10-12
|
|
275
351
|
// Reset lastKeyCode since the content is set dynamically and so lastKeyCode is invalid now.
|
|
@@ -280,20 +356,16 @@ class Licit extends React.Component<any, any> {
|
|
|
280
356
|
tr = tr.setSelection(selection).replaceSelectionWith(document, false);
|
|
281
357
|
// [FS] IRAD-1092 2020-12-03
|
|
282
358
|
// set the value for object metadata and objectId
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
: tr;
|
|
288
|
-
tr = this.isNodeHasAttribute(document, ATTR_OBJID)
|
|
289
|
-
? tr.step(new SetDocAttrStep(ATTR_OBJID, document.attrs.objectId))
|
|
290
|
-
: tr;
|
|
359
|
+
// Should update all document attributes.
|
|
360
|
+
Object.keys(document.attrs).forEach((attr) => {
|
|
361
|
+
tr = tr.step(new SetDocAttrStep(attr, document.attrs[attr]));
|
|
362
|
+
});
|
|
291
363
|
|
|
292
364
|
this._skipSCU = true;
|
|
293
365
|
this._editorView.dispatch(tr);
|
|
294
366
|
};
|
|
295
367
|
|
|
296
|
-
hasDataChanged(nextData: any) {
|
|
368
|
+
hasDataChanged(nextData: any, nextDataType: DataType) {
|
|
297
369
|
let dataChanged = false;
|
|
298
370
|
|
|
299
371
|
// [FS] IRAD-1571 2021-09-27
|
|
@@ -302,21 +374,19 @@ class Licit extends React.Component<any, any> {
|
|
|
302
374
|
// Do a proper circular JSON comparison.
|
|
303
375
|
if (stringify(this.state.data) !== stringify(nextData)) {
|
|
304
376
|
const editorState = this._editorView.state;
|
|
305
|
-
const nextDoc =
|
|
306
|
-
nextData ? nextData : EMPTY_DOC_JSON
|
|
307
|
-
);
|
|
377
|
+
const nextDoc = this.getDocument(nextData, editorState, nextDataType);
|
|
308
378
|
dataChanged = !nextDoc.eq(editorState.doc);
|
|
309
379
|
}
|
|
310
380
|
|
|
311
381
|
return dataChanged;
|
|
312
382
|
}
|
|
313
383
|
|
|
314
|
-
changeContent(data: any) {
|
|
315
|
-
if (this.hasDataChanged(data)) {
|
|
384
|
+
changeContent(data: any, dataType: DataType) {
|
|
385
|
+
if (this.hasDataChanged(data, dataType)) {
|
|
316
386
|
// FS IRAD-1592 2021-11-10
|
|
317
387
|
// Release here quickly, so that update doesn't care about at this point.
|
|
318
388
|
// data changed, so update document content
|
|
319
|
-
setTimeout(this.setContent.bind(this, data), 1);
|
|
389
|
+
setTimeout(this.setContent.bind(this, data, dataType), 1);
|
|
320
390
|
}
|
|
321
391
|
}
|
|
322
392
|
|
|
@@ -325,13 +395,15 @@ class Licit extends React.Component<any, any> {
|
|
|
325
395
|
if (!this._skipSCU) {
|
|
326
396
|
this._skipSCU = false;
|
|
327
397
|
|
|
328
|
-
this.changeContent(nextState.data);
|
|
398
|
+
this.changeContent(nextState.data, nextState.dataType);
|
|
329
399
|
|
|
330
400
|
if (this.state.docID !== nextState.docID) {
|
|
331
401
|
setTimeout(this.setDocID.bind(this, nextState), 1);
|
|
332
402
|
}
|
|
333
403
|
}
|
|
334
404
|
|
|
405
|
+
this.skipDataTypeCheck = true;
|
|
406
|
+
|
|
335
407
|
return true;
|
|
336
408
|
}
|
|
337
409
|
|
|
@@ -582,6 +654,7 @@ class Licit extends React.Component<any, any> {
|
|
|
582
654
|
delete propsCopy.data;
|
|
583
655
|
this.setState(propsCopy);
|
|
584
656
|
}
|
|
657
|
+
this.skipDataTypeCheck = false;
|
|
585
658
|
// Need to go through shouldComponentUpdate lifecycle here, when updated from outside,
|
|
586
659
|
// so that content is modified gracefully using transaction so that undo/redo works too.
|
|
587
660
|
this._skipSCU = false;
|
package/src/client/Licit.test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { configure, shallow } from 'enzyme';
|
|
3
3
|
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
|
|
4
|
-
import Licit from './Licit';
|
|
4
|
+
import Licit, { DataType } from './Licit';
|
|
5
5
|
import RichTextEditor from '../ui/RichTextEditor';
|
|
6
6
|
import { noop } from '@modusoperandi/licit-ui-commands';
|
|
7
7
|
|
|
@@ -34,7 +34,11 @@ describe('<Licit />', () => {
|
|
|
34
34
|
state: {
|
|
35
35
|
doc: {
|
|
36
36
|
content: { size: 10 },
|
|
37
|
-
resolve: () => ({
|
|
37
|
+
resolve: () => ({
|
|
38
|
+
min: () => 0,
|
|
39
|
+
max: () => 10,
|
|
40
|
+
parent: { inlineContent: true },
|
|
41
|
+
}),
|
|
38
42
|
toJSON: () => data,
|
|
39
43
|
},
|
|
40
44
|
tr: {
|
|
@@ -65,3 +69,30 @@ describe('<Licit />', () => {
|
|
|
65
69
|
});
|
|
66
70
|
});
|
|
67
71
|
});
|
|
72
|
+
|
|
73
|
+
describe('<Licit with HTML input/>', () => {
|
|
74
|
+
let wrapper;
|
|
75
|
+
let licit;
|
|
76
|
+
|
|
77
|
+
const HELLO = 'Hello ';
|
|
78
|
+
const WORLD = 'World';
|
|
79
|
+
const data =
|
|
80
|
+
'<p stylename="None">' +
|
|
81
|
+
HELLO +
|
|
82
|
+
'<strong overridden="false">' +
|
|
83
|
+
WORLD +
|
|
84
|
+
'</strong></p>';
|
|
85
|
+
|
|
86
|
+
beforeEach(() => {
|
|
87
|
+
wrapper = shallow(<Licit data={data} dataType={DataType.HTML} />);
|
|
88
|
+
licit = wrapper.instance();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should render a <RichTextEditor /> ', () => {
|
|
92
|
+
expect(wrapper.find(RichTextEditor)).toBeTruthy();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should match state text content with the passed in text ', () => {
|
|
96
|
+
expect(licit.state.editorState.doc.textContent).toBe(HELLO + WORLD);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -14,6 +14,10 @@ export type SetStateCall = (
|
|
|
14
14
|
class SimpleConnector {
|
|
15
15
|
_setState: SetStateCall;
|
|
16
16
|
_editorState: EditorState;
|
|
17
|
+
// This flag is used to deteremine if data passed in or not
|
|
18
|
+
// If not passed in, use the data from collab server when in collab mode.
|
|
19
|
+
// else use empty content.
|
|
20
|
+
_dataDefined: boolean;
|
|
17
21
|
|
|
18
22
|
constructor(editorState: EditorState, setState: SetStateCall) {
|
|
19
23
|
this._editorState = editorState;
|
|
@@ -49,6 +53,8 @@ class SimpleConnector {
|
|
|
49
53
|
// Send the modified schema to server
|
|
50
54
|
updateSchema = (schema: Schema, data: any) => {};
|
|
51
55
|
|
|
56
|
+
updateContent = (data: any) => {};
|
|
57
|
+
|
|
52
58
|
cleanUp = () => {};
|
|
53
59
|
}
|
|
54
60
|
|
package/src/client/http.js
CHANGED
|
@@ -53,6 +53,10 @@ export function POST(url, body, type) {
|
|
|
53
53
|
return req({ url, method: 'POST', body, headers: { 'Content-Type': type } });
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
export function PUT(url, body, type) {
|
|
57
|
+
return req({ url, method: 'PUT', body, headers: { 'Content-Type': type } });
|
|
58
|
+
}
|
|
59
|
+
|
|
56
60
|
// [FS] IRAD-1128 2021-02-03
|
|
57
61
|
// http DELETE request overrided
|
|
58
62
|
export function DELETE(url, type) {
|
|
@@ -11,8 +11,8 @@ import EditorSchema from './EditorSchema';
|
|
|
11
11
|
|
|
12
12
|
export default function convertFromDOMElement(
|
|
13
13
|
el: HTMLElement,
|
|
14
|
-
schema:
|
|
15
|
-
plugins:
|
|
14
|
+
schema: Schema,
|
|
15
|
+
plugins: Array<Plugin>
|
|
16
16
|
): EditorState {
|
|
17
17
|
const effectiveSchema = schema || EditorSchema;
|
|
18
18
|
const effectivePlugins = plugins || EditorPlugins;
|
package/src/convertFromHTML.js
CHANGED
|
@@ -5,15 +5,13 @@ import { EditorState } from 'prosemirror-state';
|
|
|
5
5
|
import { Plugin } from 'prosemirror-state';
|
|
6
6
|
|
|
7
7
|
import convertFromDOMElement from './convertFromDOMElement';
|
|
8
|
-
import normalizeHTML from './normalizeHTML';
|
|
9
8
|
|
|
10
9
|
export default function convertFromHTML(
|
|
11
10
|
html: string,
|
|
12
|
-
schema:
|
|
13
|
-
plugins:
|
|
11
|
+
schema: Schema,
|
|
12
|
+
plugins: Array<Plugin>
|
|
14
13
|
): EditorState {
|
|
15
14
|
const root = document.createElement('html');
|
|
16
|
-
|
|
17
|
-
root.innerHTML = newHTML;
|
|
15
|
+
root.innerHTML = html ? html : ' ';
|
|
18
16
|
return convertFromDOMElement(root, schema, plugins);
|
|
19
17
|
}
|
package/src/convertFromJSON.js
CHANGED
|
@@ -9,54 +9,32 @@ export default function convertFromJSON(
|
|
|
9
9
|
json: Object | string,
|
|
10
10
|
schema: ?Schema,
|
|
11
11
|
defaultSchema: Schema,
|
|
12
|
-
|
|
13
|
-
defaultPlugins: Array<Plugin>
|
|
12
|
+
effectivePlugins: Array<Plugin>
|
|
14
13
|
): EditorState {
|
|
15
|
-
|
|
14
|
+
const editorSchema = schema || defaultSchema;
|
|
15
|
+
let error = false;
|
|
16
16
|
|
|
17
|
-
// [FS][IRAD-???? 2020-08-17]
|
|
18
|
-
// Loads plugins and its corresponding schema in editor
|
|
19
|
-
const effectivePlugins = defaultPlugins;
|
|
20
|
-
|
|
21
|
-
if (plugins) {
|
|
22
|
-
for (const p of plugins) {
|
|
23
|
-
if (!effectivePlugins.includes(p)) {
|
|
24
|
-
effectivePlugins.push(p);
|
|
25
|
-
if (p.getEffectiveSchema) {
|
|
26
|
-
editorSchema = p.getEffectiveSchema(editorSchema);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (p.initKeyCommands) {
|
|
30
|
-
effectivePlugins.push(p.initKeyCommands());
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
17
|
if (typeof json === 'string') {
|
|
36
18
|
try {
|
|
37
19
|
json = JSON.parse(json);
|
|
38
20
|
} catch (ex) {
|
|
39
21
|
console.error('convertFromJSON:', ex);
|
|
40
|
-
|
|
41
|
-
// Use the effectivePlugins, editor hangs, b'coz of missing default core plugins
|
|
42
|
-
return createEmptyEditorState(
|
|
43
|
-
schema,
|
|
44
|
-
defaultSchema,
|
|
45
|
-
plugins,
|
|
46
|
-
defaultPlugins
|
|
47
|
-
);
|
|
22
|
+
error = true;
|
|
48
23
|
}
|
|
49
24
|
}
|
|
50
25
|
|
|
51
26
|
if (!json || typeof json !== 'object') {
|
|
52
27
|
console.error('convertFromJSON: invalid object', json);
|
|
28
|
+
error = true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if(error) {
|
|
53
32
|
// [FS] IRAD-1455 2021-06-16
|
|
54
33
|
// Use the effectivePlugins, editor hangs, b'coz of missing default core plugins
|
|
55
34
|
return createEmptyEditorState(
|
|
56
35
|
schema,
|
|
57
36
|
defaultSchema,
|
|
58
|
-
|
|
59
|
-
defaultPlugins
|
|
37
|
+
effectivePlugins
|
|
60
38
|
);
|
|
61
39
|
}
|
|
62
40
|
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import { Schema } from 'prosemirror-model';
|
|
4
4
|
import { EditorState } from 'prosemirror-state';
|
|
5
5
|
import { Plugin } from 'prosemirror-state';
|
|
6
|
-
import DefaultEditorPlugins from './buildEditorPlugins';
|
|
7
6
|
|
|
8
7
|
import convertFromJSON from './convertFromJSON';
|
|
9
8
|
import EditorSchema from './EditorSchema';
|
|
@@ -12,24 +11,21 @@ export const EMPTY_DOC_JSON = {
|
|
|
12
11
|
type: 'doc',
|
|
13
12
|
content: [
|
|
14
13
|
{
|
|
15
|
-
type: 'paragraph'
|
|
16
|
-
}
|
|
14
|
+
type: 'paragraph',
|
|
15
|
+
}, // [FS] IRAD-1710 2022-03-04 - No text content needed
|
|
17
16
|
],
|
|
18
17
|
};
|
|
19
18
|
|
|
20
19
|
export default function createEmptyEditorState(
|
|
21
20
|
schema: ?Schema,
|
|
22
21
|
defaultSchema: ?Schema,
|
|
23
|
-
plugins:
|
|
24
|
-
defaultPlugins: ?Array<Plugin>
|
|
22
|
+
plugins: Array<Plugin>
|
|
25
23
|
): EditorState {
|
|
26
|
-
const newSchema = schema || (defaultSchema ? defaultSchema : EditorSchema);
|
|
27
24
|
// TODO: Check if schema support doc and paragraph nodes.
|
|
28
25
|
return convertFromJSON(
|
|
29
26
|
EMPTY_DOC_JSON,
|
|
30
27
|
schema,
|
|
31
28
|
defaultSchema ? defaultSchema : EditorSchema,
|
|
32
|
-
plugins
|
|
33
|
-
defaultPlugins ? defaultPlugins : new DefaultEditorPlugins(newSchema).get()
|
|
29
|
+
plugins
|
|
34
30
|
);
|
|
35
31
|
}
|
package/src/index.js
CHANGED
|
@@ -5,6 +5,6 @@ export { default as isEditorStateEmpty } from './isEditorStateEmpty';
|
|
|
5
5
|
export { default as uuid } from './ui/uuid';
|
|
6
6
|
// [FS] IRAD-978 2020-06-05
|
|
7
7
|
// Export Licit as a component
|
|
8
|
-
export { default as Licit } from './client/Licit.js';
|
|
8
|
+
export { default as Licit, DataType } from './client/Licit.js';
|
|
9
9
|
export { ImageLike, EditorRuntime } from './Types';
|
|
10
10
|
export { GET, POST, DELETE, PATCH } from './client/http';
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
-
import stable from 'stable';
|
|
4
3
|
import toCSSColor from './ui/toCSSColor';
|
|
5
4
|
import { toCSSLineSpacing } from '@modusoperandi/licit-ui-commands';
|
|
6
5
|
|
|
@@ -94,7 +93,8 @@ export default function patchStyleElements(doc: Document): void {
|
|
|
94
93
|
});
|
|
95
94
|
|
|
96
95
|
// Sort selector by
|
|
97
|
-
|
|
96
|
+
selectorTextToCSSTexts
|
|
97
|
+
.sort(sortBySpecificity)
|
|
98
98
|
.reduce(buildElementToCSSTexts.bind(null, doc), new Map<any, any>())
|
|
99
99
|
.forEach(applyInlineStyleSheetCSSTexts);
|
|
100
100
|
}
|
package/src/ui/czi-vars.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
@import '
|
|
1
|
+
@import '~@modusoperandi/licit-ui-commands/dist/ui/czi-vars.css';
|
|
2
2
|
|