@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.
Files changed (62) hide show
  1. package/.eslintrc.js +59 -55
  2. package/README.md +15 -1
  3. package/dist/ListItemNodeSpec.js +1 -1
  4. package/dist/ListItemNodeSpec.js.flow +1 -1
  5. package/dist/bom.xml +5147 -8743
  6. package/dist/client/CollabConnector.js +5 -1
  7. package/dist/client/CollabConnector.js.flow +6 -2
  8. package/dist/client/EditorConnection.js +5 -4
  9. package/dist/client/EditorConnection.js.flow +10 -5
  10. package/dist/client/Licit.js +105 -30
  11. package/dist/client/Licit.js.flow +120 -47
  12. package/dist/client/Licit.test.js +29 -2
  13. package/dist/client/Licit.test.js.flow +33 -2
  14. package/dist/client/SimpleConnector.js +7 -0
  15. package/dist/client/SimpleConnector.js.flow +6 -0
  16. package/dist/client/http.js +12 -0
  17. package/dist/client/http.js.flow +4 -0
  18. package/dist/convertFromDOMElement.js.flow +2 -2
  19. package/dist/convertFromHTML.js +1 -4
  20. package/dist/convertFromHTML.js.flow +3 -5
  21. package/dist/convertFromJSON.js +12 -28
  22. package/dist/convertFromJSON.js.flow +9 -31
  23. package/dist/createEmptyEditorState.js +3 -6
  24. package/dist/createEmptyEditorState.js.flow +4 -8
  25. package/dist/index.js +11 -1
  26. package/dist/index.js.flow +1 -1
  27. package/dist/patchStyleElements.js +1 -3
  28. package/dist/patchStyleElements.js.flow +2 -2
  29. package/dist/ui/czi-link-tooltip.css +1 -1
  30. package/dist/ui/czi-vars.css +1 -1
  31. package/licit/client/index.js +2 -1
  32. package/licit/server/collab/instance.js +21 -6
  33. package/licit/server/collab/server.js +25 -5
  34. package/licit/server/collab/start.js +1 -1
  35. package/package.json +5 -10
  36. package/src/ListItemNodeSpec.js +1 -1
  37. package/src/client/CollabConnector.js +6 -2
  38. package/src/client/EditorConnection.js +10 -5
  39. package/src/client/Licit.js +120 -47
  40. package/src/client/Licit.test.js +33 -2
  41. package/src/client/SimpleConnector.js +6 -0
  42. package/src/client/http.js +4 -0
  43. package/src/convertFromDOMElement.js +2 -2
  44. package/src/convertFromHTML.js +3 -5
  45. package/src/convertFromJSON.js +9 -31
  46. package/src/createEmptyEditorState.js +4 -8
  47. package/src/index.js +1 -1
  48. package/src/patchStyleElements.js +2 -2
  49. package/src/ui/czi-link-tooltip.css +1 -1
  50. package/src/ui/czi-vars.css +1 -1
  51. package/utils/build_licit_collab_server.js +1 -1
  52. package/webpack.config.js +1 -1
  53. package/node_modules/prosemirror-utils/LICENSE +0 -13
  54. package/node_modules/prosemirror-utils/README.md +0 -0
  55. package/node_modules/prosemirror-utils/dist/helpers.js +0 -119
  56. package/node_modules/prosemirror-utils/dist/index.js +0 -17
  57. package/node_modules/prosemirror-utils/dist/index.js.map +0 -1
  58. package/node_modules/prosemirror-utils/dist/node.js +0 -106
  59. package/node_modules/prosemirror-utils/dist/selection.js +0 -168
  60. package/node_modules/prosemirror-utils/dist/transforms.js +0 -257
  61. package/node_modules/prosemirror-utils/package.json +0 -81
  62. 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: any;
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
- this.run((0, _http.GET)(this.url)).then(data => {
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
- this.run(GET(this.url)).then(
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);
@@ -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 ATTR_OBJID = 'objectId';
59
- const ATTR_OBJMETADATA = 'objectMetaData';
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
- // [FS] IRAD-1571 2021-09-27
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 view’s 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
- const document = schema.nodeFromJSON(content ? content : _createEmptyEditorState.EMPTY_DOC_JSON); // [FS] IRAD-1593 2021-10-12
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
- tr = _this.isNodeHasAttribute(document, ATTR_OBJMETADATA) ? tr.step(new _licitDocAttrsStep.SetDocAttrStep(ATTR_OBJMETADATA, document.attrs.objectMetaData)) : tr;
138
- tr = _this.isNodeHasAttribute(document, ATTR_OBJID) ? tr.step(new _licitDocAttrsStep.SetDocAttrStep(ATTR_OBJID, document.attrs.objectId)) : tr;
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
- } // Need to go through shouldComponentUpdate lifecycle here, when updated from outside,
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
- const data = props.data || null;
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
- let editorState = (0, _convertFromJSON.default)(data, null, this._defaultEditorSchema, plugins, this._defaultEditorPlugins); // [FS] IRAD-1067 2020-09-19
295
- // The editorState will return null if the doc Json is mal-formed
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); // FS IRAD-989 2020-18-06
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
- hasDataChanged(nextData) {
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 view’s 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 = editorState.schema.nodeFromJSON(nextData ? nextData : _createEmptyEditorState.EMPTY_DOC_JSON);
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 { createPopUp } from '@modusoperandi/licit-ui-commands';
18
- import { atViewportCenter } from '@modusoperandi/licit-ui-commands';
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: any;
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
- const data = props.data || null;
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
- let editorState = convertFromJSON(
113
- data,
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
- setContent = (content: any = {}): void => {
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 view’s current state;
269
344
  const editorState = this._editorView.state;
270
- const { doc, schema } = editorState;
345
+ const { doc } = editorState;
271
346
  let { tr } = editorState;
272
- const document = schema.nodeFromJSON(content ? content : EMPTY_DOC_JSON);
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
- tr = this.isNodeHasAttribute(document, ATTR_OBJMETADATA)
284
- ? tr.step(
285
- new SetDocAttrStep(ATTR_OBJMETADATA, document.attrs.objectMetaData)
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 = editorState.schema.nodeFromJSON(
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;