@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
|
@@ -71,7 +71,11 @@ class CollabConnector extends _SimpleConnector.default {
|
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
_defineProperty(this, "updateSchema", (schema, data) => {
|
|
74
|
-
this._connection.updateSchema(schema, data);
|
|
74
|
+
this._connection.updateSchema(schema, data, this._dataDefined);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
_defineProperty(this, "updateContent", data => {
|
|
78
|
+
this._connection.start(data, this._dataDefined);
|
|
75
79
|
});
|
|
76
80
|
|
|
77
81
|
const {
|
|
@@ -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
|
|
|
@@ -158,8 +158,9 @@ class EditorConnection {
|
|
|
158
158
|
} // Load the document from the server and start up
|
|
159
159
|
|
|
160
160
|
|
|
161
|
-
start() {
|
|
162
|
-
|
|
161
|
+
start(input, dataDefined) {
|
|
162
|
+
const query = '?dataDefined=' + dataDefined;
|
|
163
|
+
this.run(input ? (0, _http.PUT)(this.url + query, JSON.stringify(input), 'application/json') : (0, _http.GET)(this.url, 'application/json')).then(data => {
|
|
163
164
|
data = JSON.parse(data);
|
|
164
165
|
this.report.success();
|
|
165
166
|
this.backOff = 0;
|
|
@@ -266,14 +267,14 @@ class EditorConnection {
|
|
|
266
267
|
// Send the modified schema to server
|
|
267
268
|
|
|
268
269
|
|
|
269
|
-
updateSchema(schema, input) {
|
|
270
|
+
updateSchema(schema, input, dataDefined) {
|
|
270
271
|
// to avoid cyclic reference error, use flatted string.
|
|
271
272
|
const schemaFlatted = (0, _flatted.stringify)(schema);
|
|
272
273
|
this.run((0, _http.POST)(this.url + '/schema/', schemaFlatted, 'text/plain')).then(data => {
|
|
273
274
|
console.log("collab server's schema updated"); // [FS] IRAD-1040 2020-09-08
|
|
274
275
|
|
|
275
276
|
this.schema = schema;
|
|
276
|
-
this.start(input);
|
|
277
|
+
this.start(input, dataDefined);
|
|
277
278
|
}, err => {
|
|
278
279
|
this.report.failure(err);
|
|
279
280
|
});
|
|
@@ -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/dist/client/Licit.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.default = void 0;
|
|
6
|
+
exports.default = exports.DataType = void 0;
|
|
7
7
|
|
|
8
8
|
var _prosemirrorState = require("prosemirror-state");
|
|
9
9
|
|
|
@@ -45,6 +45,8 @@ var _EditorMarks = _interopRequireDefault(require("../EditorMarks"));
|
|
|
45
45
|
|
|
46
46
|
var _EditorNodes = _interopRequireDefault(require("../EditorNodes"));
|
|
47
47
|
|
|
48
|
+
var _convertFromHTML = _interopRequireDefault(require("../convertFromHTML"));
|
|
49
|
+
|
|
48
50
|
var _Types = require("../Types");
|
|
49
51
|
|
|
50
52
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -55,8 +57,10 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
|
|
|
55
57
|
|
|
56
58
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
57
59
|
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
+
const DataType = Object.freeze({
|
|
61
|
+
JSON: Symbol('json'),
|
|
62
|
+
HTML: Symbol('html')
|
|
63
|
+
});
|
|
60
64
|
/**
|
|
61
65
|
* LICIT properties:
|
|
62
66
|
* docID {string} [] Collaborative Doument ID
|
|
@@ -69,12 +73,15 @@ const ATTR_OBJMETADATA = 'objectMetaData';
|
|
|
69
73
|
* @param data {JSON} Modified document data.
|
|
70
74
|
* onReady {@callback} [null] Fires when the editor is fully ready.
|
|
71
75
|
* @param ref {LICIT} Rerefence of the editor.
|
|
72
|
-
* data {JSON} [null] Document data to be loaded into the editor.
|
|
76
|
+
* data {JSON|HTML} [null] Document data to be loaded into the editor.
|
|
77
|
+
* dataType {JSON|HTML} [JSON] Document data to be loaded into the editor.
|
|
73
78
|
* disabled {boolean} [false] Disable the editor.
|
|
74
79
|
* embedded {boolean} [false] Disable/Enable inline behaviour.
|
|
75
80
|
* plugins [plugins] External Plugins into the editor.
|
|
76
81
|
*/
|
|
77
82
|
|
|
83
|
+
exports.DataType = DataType;
|
|
84
|
+
|
|
78
85
|
class Licit extends React.Component {
|
|
79
86
|
// This will be handy in updating document's content.
|
|
80
87
|
// Flag to decide whether to skip shouldComponentUpdate
|
|
@@ -114,17 +121,21 @@ class Licit extends React.Component {
|
|
|
114
121
|
|
|
115
122
|
_defineProperty(this, "setContent", function () {
|
|
116
123
|
let content = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
117
|
-
|
|
124
|
+
let dataType = arguments.length > 1 ? arguments[1] : undefined;
|
|
125
|
+
_this.skipDataTypeCheck = false; // [FS] IRAD-1571 2021-09-27
|
|
118
126
|
// dispatch a transaction that MUST start from the views current state;
|
|
127
|
+
|
|
119
128
|
const editorState = _this._editorView.state;
|
|
120
129
|
const {
|
|
121
|
-
doc
|
|
122
|
-
schema
|
|
130
|
+
doc
|
|
123
131
|
} = editorState;
|
|
124
132
|
let {
|
|
125
133
|
tr
|
|
126
134
|
} = editorState;
|
|
127
|
-
|
|
135
|
+
|
|
136
|
+
const document = _this.getDocument(content, editorState, dataType);
|
|
137
|
+
|
|
138
|
+
_this.skipDataTypeCheck = true; // [FS] IRAD-1593 2021-10-12
|
|
128
139
|
// Reset lastKeyCode since the content is set dynamically and so lastKeyCode is invalid now.
|
|
129
140
|
|
|
130
141
|
_this._editorView.lastKeyCode = null;
|
|
@@ -133,9 +144,11 @@ class Licit extends React.Component {
|
|
|
133
144
|
|
|
134
145
|
tr = tr.setSelection(selection).replaceSelectionWith(document, false); // [FS] IRAD-1092 2020-12-03
|
|
135
146
|
// set the value for object metadata and objectId
|
|
147
|
+
// Should update all document attributes.
|
|
136
148
|
|
|
137
|
-
|
|
138
|
-
|
|
149
|
+
Object.keys(document.attrs).forEach(attr => {
|
|
150
|
+
tr = tr.step(new _licitDocAttrsStep.SetDocAttrStep(attr, document.attrs[attr]));
|
|
151
|
+
});
|
|
139
152
|
_this._skipSCU = true;
|
|
140
153
|
|
|
141
154
|
_this._editorView.dispatch(tr);
|
|
@@ -243,9 +256,10 @@ class Licit extends React.Component {
|
|
|
243
256
|
propsCopy.readOnly = false;
|
|
244
257
|
delete propsCopy.data;
|
|
245
258
|
this.setState(propsCopy);
|
|
246
|
-
}
|
|
247
|
-
// so that content is modified gracefully using transaction so that undo/redo works too.
|
|
259
|
+
}
|
|
248
260
|
|
|
261
|
+
this.skipDataTypeCheck = false; // Need to go through shouldComponentUpdate lifecycle here, when updated from outside,
|
|
262
|
+
// so that content is modified gracefully using transaction so that undo/redo works too.
|
|
249
263
|
|
|
250
264
|
this._skipSCU = false;
|
|
251
265
|
this.setState(props);
|
|
@@ -278,33 +292,32 @@ class Licit extends React.Component {
|
|
|
278
292
|
const onChangeCB = typeof props.onChange === 'function' ? props.onChange : noop;
|
|
279
293
|
const onReadyCB = typeof props.onReady === 'function' ? props.onReady : noop;
|
|
280
294
|
const readOnly = props.readOnly || false;
|
|
281
|
-
|
|
295
|
+
let data = props.data || null;
|
|
296
|
+
const dataType = props.dataType || DataType.JSON;
|
|
282
297
|
const disabled = props.disabled || false;
|
|
283
298
|
const embedded = props.embedded || false; // [FS] IRAD-996 2020-06-30
|
|
284
299
|
// [FS] 2020-07-03
|
|
285
300
|
// Handle Image Upload from Angular App
|
|
286
301
|
|
|
287
302
|
const runtime = props.runtime || null;
|
|
288
|
-
const plugins = props.plugins || null;
|
|
303
|
+
const plugins = props.plugins || null; // This flag decides whether DataType.HTML check is needed when
|
|
304
|
+
// changing document. If it forcefully done, it is not needed, otherwise needed.
|
|
305
|
+
|
|
306
|
+
this.skipDataTypeCheck = false;
|
|
289
307
|
this._defaultEditorSchema = new _prosemirrorModel.Schema({
|
|
290
308
|
nodes: _EditorNodes.default,
|
|
291
309
|
marks: _EditorMarks.default
|
|
292
310
|
});
|
|
293
311
|
this._defaultEditorPlugins = new _buildEditorPlugins.default(this._defaultEditorSchema).get();
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
if (null === editorState) {
|
|
298
|
-
editorState = (0, _convertFromJSON.default)(_createEmptyEditorState.EMPTY_DOC_JSON, null, this._defaultEditorSchema, plugins, this._defaultEditorPlugins);
|
|
299
|
-
this.showAlert();
|
|
300
|
-
}
|
|
301
|
-
|
|
312
|
+
const editorState = this.initEditorState(plugins, dataType, data);
|
|
313
|
+
data = editorState.doc;
|
|
302
314
|
const setState = this.setState.bind(this);
|
|
303
315
|
this._connector = collaborative ? new _CollabConnector.default(editorState, setState, {
|
|
304
316
|
docID,
|
|
305
317
|
collabServiceURL
|
|
306
318
|
}, this._defaultEditorSchema, this._defaultEditorPlugins, // [FS] IRAD-1578 2021-09-27
|
|
307
|
-
this.onReady.bind(this)) : new _SimpleConnector.default(editorState, setState);
|
|
319
|
+
this.onReady.bind(this)) : new _SimpleConnector.default(editorState, setState);
|
|
320
|
+
this._connector._dataDefined = !!props.data; // FS IRAD-989 2020-18-06
|
|
308
321
|
// updating properties should automatically render the changes
|
|
309
322
|
|
|
310
323
|
this.state = {
|
|
@@ -320,7 +333,8 @@ class Licit extends React.Component {
|
|
|
320
333
|
debug,
|
|
321
334
|
disabled,
|
|
322
335
|
embedded,
|
|
323
|
-
runtime
|
|
336
|
+
runtime,
|
|
337
|
+
dataType
|
|
324
338
|
}; // FS IRAD-1040 2020-26-08
|
|
325
339
|
// Get the modified schema from editorstate and send it to collab server
|
|
326
340
|
|
|
@@ -328,6 +342,50 @@ class Licit extends React.Component {
|
|
|
328
342
|
// Use known editorState to update schema.
|
|
329
343
|
this._connector.updateSchema(editorState.schema, data);
|
|
330
344
|
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
initEditorState(plugins, dataType, data) {
|
|
348
|
+
let editorState = null;
|
|
349
|
+
const effectivePlugins = this.getEffectivePlugins(this._defaultEditorSchema, this._defaultEditorPlugins, plugins);
|
|
350
|
+
|
|
351
|
+
if (DataType.JSON === dataType) {
|
|
352
|
+
editorState = (0, _convertFromJSON.default)(data, null, effectivePlugins.schema, effectivePlugins.plugins); // [FS] IRAD-1067 2020-09-19
|
|
353
|
+
// The editorState will return null if the doc Json is mal-formed
|
|
354
|
+
|
|
355
|
+
if (null === editorState) {
|
|
356
|
+
editorState = (0, _convertFromJSON.default)(_createEmptyEditorState.EMPTY_DOC_JSON, null, effectivePlugins.schema, effectivePlugins.plugins);
|
|
357
|
+
this.showAlert();
|
|
358
|
+
}
|
|
359
|
+
} else {
|
|
360
|
+
editorState = (0, _convertFromHTML.default)(data, effectivePlugins.schema, effectivePlugins.plugins);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return editorState;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
getEffectivePlugins(schema, defaultPlugins, plugins) {
|
|
367
|
+
const effectivePlugins = defaultPlugins;
|
|
368
|
+
|
|
369
|
+
if (plugins) {
|
|
370
|
+
for (const p of plugins) {
|
|
371
|
+
if (!effectivePlugins.includes(p)) {
|
|
372
|
+
effectivePlugins.push(p);
|
|
373
|
+
|
|
374
|
+
if (p.getEffectiveSchema) {
|
|
375
|
+
schema = p.getEffectiveSchema(schema);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (p.initKeyCommands) {
|
|
379
|
+
effectivePlugins.push(p.initKeyCommands());
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return {
|
|
386
|
+
plugins: effectivePlugins,
|
|
387
|
+
schema
|
|
388
|
+
};
|
|
331
389
|
} // [FS] IRAD-1578 2021-09-27
|
|
332
390
|
|
|
333
391
|
|
|
@@ -426,7 +484,23 @@ class Licit extends React.Component {
|
|
|
426
484
|
return node.attrs && node.attrs[attrName];
|
|
427
485
|
}
|
|
428
486
|
|
|
429
|
-
|
|
487
|
+
getDocument(content, editorState, dataType) {
|
|
488
|
+
let document = null;
|
|
489
|
+
const {
|
|
490
|
+
schema
|
|
491
|
+
} = editorState;
|
|
492
|
+
|
|
493
|
+
if (DataType.JSON === dataType || this.skipDataTypeCheck) {
|
|
494
|
+
document = schema.nodeFromJSON(content ? content : _createEmptyEditorState.EMPTY_DOC_JSON);
|
|
495
|
+
} else {
|
|
496
|
+
const tempEState = (0, _convertFromHTML.default)(content ? content : '', schema, editorState.plugins);
|
|
497
|
+
document = tempEState.doc;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return document;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
hasDataChanged(nextData, nextDataType) {
|
|
430
504
|
let dataChanged = false; // [FS] IRAD-1571 2021-09-27
|
|
431
505
|
// dispatch a transaction that MUST start from the views current state;
|
|
432
506
|
// [FS] IRAD-1589 2021-10-04
|
|
@@ -434,19 +508,19 @@ class Licit extends React.Component {
|
|
|
434
508
|
|
|
435
509
|
if ((0, _flatted.stringify)(this.state.data) !== (0, _flatted.stringify)(nextData)) {
|
|
436
510
|
const editorState = this._editorView.state;
|
|
437
|
-
const nextDoc =
|
|
511
|
+
const nextDoc = this.getDocument(nextData, editorState, nextDataType);
|
|
438
512
|
dataChanged = !nextDoc.eq(editorState.doc);
|
|
439
513
|
}
|
|
440
514
|
|
|
441
515
|
return dataChanged;
|
|
442
516
|
}
|
|
443
517
|
|
|
444
|
-
changeContent(data) {
|
|
445
|
-
if (this.hasDataChanged(data)) {
|
|
518
|
+
changeContent(data, dataType) {
|
|
519
|
+
if (this.hasDataChanged(data, dataType)) {
|
|
446
520
|
// FS IRAD-1592 2021-11-10
|
|
447
521
|
// Release here quickly, so that update doesn't care about at this point.
|
|
448
522
|
// data changed, so update document content
|
|
449
|
-
setTimeout(this.setContent.bind(this, data), 1);
|
|
523
|
+
setTimeout(this.setContent.bind(this, data, dataType), 1);
|
|
450
524
|
}
|
|
451
525
|
}
|
|
452
526
|
|
|
@@ -454,13 +528,14 @@ class Licit extends React.Component {
|
|
|
454
528
|
// Only interested if properties are set from outside.
|
|
455
529
|
if (!this._skipSCU) {
|
|
456
530
|
this._skipSCU = false;
|
|
457
|
-
this.changeContent(nextState.data);
|
|
531
|
+
this.changeContent(nextState.data, nextState.dataType);
|
|
458
532
|
|
|
459
533
|
if (this.state.docID !== nextState.docID) {
|
|
460
534
|
setTimeout(this.setDocID.bind(this, nextState), 1);
|
|
461
535
|
}
|
|
462
536
|
}
|
|
463
537
|
|
|
538
|
+
this.skipDataTypeCheck = true;
|
|
464
539
|
return true;
|
|
465
540
|
}
|
|
466
541
|
|
|
@@ -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;
|