@progress/kendo-editor-common 1.6.1-dev.202112152003 → 1.7.0-dev.202201030643

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/es/source.js CHANGED
@@ -1,9 +1,58 @@
1
1
  import { DOMSerializer, DOMParser as ProseMirrorDOMParser } from 'prosemirror-model';
2
2
  import { AllSelection } from 'prosemirror-state';
3
+ import { rowTypeAttr, colgroupAttr } from './config/constants';
3
4
  var blockWrappers = [
4
5
  'div', 'ol', 'ul', 'li', 'table', 'tbody', 'thead', 'tfoot', 'td', 'th', 'p',
5
6
  'tr', 'col', 'colgroup', 'article', 'main', 'nav', 'header', 'footer', 'aside', 'section'
6
7
  ];
8
+ var removeRowType = function (table, nodeName) {
9
+ var wrapper = (table.ownerDocument || document).createElement(nodeName);
10
+ Array.from(table.rows).filter(function (r) { return r.getAttribute(rowTypeAttr) === nodeName; }).forEach(function (row) {
11
+ row.removeAttribute(rowTypeAttr);
12
+ wrapper.appendChild(row);
13
+ });
14
+ if (wrapper.children.length) {
15
+ table.appendChild(wrapper);
16
+ }
17
+ };
18
+ var restoreTables = function (fragment) {
19
+ Array.from(fragment.querySelectorAll('table')).forEach(function (table) {
20
+ removeRowType(table, 'thead');
21
+ removeRowType(table, 'tbody');
22
+ removeRowType(table, 'tfoot');
23
+ var emptyElement = Array.from(table.children).find(function (el) { return el.children.length === 0; });
24
+ if (emptyElement) {
25
+ emptyElement.remove();
26
+ }
27
+ });
28
+ };
29
+ var setRowType = function (children, nodeName) {
30
+ var tag = nodeName.toUpperCase();
31
+ children.filter(function (c) { return c.nodeName === tag; }).forEach(function (rowsWrapper) {
32
+ Array.from(rowsWrapper.children).forEach(function (row) {
33
+ row.setAttribute(rowTypeAttr, nodeName);
34
+ if (rowsWrapper.parentNode) {
35
+ rowsWrapper.parentNode.insertBefore(row, rowsWrapper);
36
+ }
37
+ });
38
+ rowsWrapper.remove();
39
+ });
40
+ };
41
+ var validateTablesToPmSchema = function (fragment) {
42
+ Array.from(fragment.querySelectorAll('table')).forEach(function (table) {
43
+ var children = Array.from(table.children);
44
+ if (children.some(function (e) { return e.nodeName === 'THEAD' || e.nodeName === 'TFOOT'; })) {
45
+ setRowType(children, 'thead');
46
+ setRowType(children, 'tbody');
47
+ setRowType(children, 'tfoot');
48
+ }
49
+ var colgroup = children.find(function (c) { return c.nodeName === 'COLGROUP'; });
50
+ if (colgroup) {
51
+ table.setAttribute(colgroupAttr, colgroup.outerHTML);
52
+ colgroup.remove();
53
+ }
54
+ });
55
+ };
7
56
  /**
8
57
  * Trims the whitespace around the provided block nodes.
9
58
  *
@@ -52,7 +101,9 @@ export var htmlToFragment = function (html) {
52
101
  * @returns DocumentFragment
53
102
  */
54
103
  export var pmDocToFragment = function (doc) {
55
- return DOMSerializer.fromSchema(doc.type.schema).serializeFragment(doc.content);
104
+ var fragment = DOMSerializer.fromSchema(doc.type.schema).serializeFragment(doc.content);
105
+ restoreTables(fragment);
106
+ return fragment;
56
107
  };
57
108
  /**
58
109
  * Creates a ProseMirrorNode from the given DOM element.
@@ -75,6 +126,7 @@ export var domToPmDoc = function (dom, schema, parseOptions) {
75
126
  */
76
127
  export var parseContent = function (content, schema, parseOptions) {
77
128
  var dom = htmlToFragment(content);
129
+ validateTablesToPmSchema(dom);
78
130
  return domToPmDoc(dom, schema, parseOptions);
79
131
  };
80
132
  /**
package/dist/es/table.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { addRowAfter as pmAddRowAfter, addRowBefore as pmAddRowBefore } from 'prosemirror-tables';
2
+ import { rowTypeAttr } from './config/constants';
1
3
  /**
2
4
  * Creates a table.
3
5
  * @returns Node
@@ -15,3 +17,50 @@ export var createTable = function (nodes, rows, columns) {
15
17
  }
16
18
  return table.createAndFill(undefined, tableRows);
17
19
  };
20
+ var closest = function (selection, name) {
21
+ var pos = selection.$head;
22
+ for (var i = pos.depth; i > 0; i--) {
23
+ var node = pos.node(i);
24
+ if (node.type.name === name) {
25
+ return {
26
+ pos: pos.before(i),
27
+ node: node
28
+ };
29
+ }
30
+ }
31
+ return null;
32
+ };
33
+ export var addRowBefore = function (state, dispatch) {
34
+ var cmdDispatch = dispatch && (function (tr) {
35
+ var _a;
36
+ var row = closest(tr.selection, 'table_row');
37
+ var table = closest(tr.selection, 'table');
38
+ if (row && table && row.node.attrs[rowTypeAttr]) {
39
+ var index = 0;
40
+ for (var i = 0; i < table.node.nodeSize; i++) {
41
+ if (table.node.child(i).eq(row.node)) {
42
+ index = i;
43
+ break;
44
+ }
45
+ }
46
+ var next = table.node.child(index - 1);
47
+ var from = row.pos - next.nodeSize;
48
+ tr.setNodeMarkup(from, undefined, (_a = {}, _a[rowTypeAttr] = row.node.attrs[rowTypeAttr], _a));
49
+ }
50
+ return dispatch(tr);
51
+ });
52
+ return pmAddRowBefore(state, cmdDispatch);
53
+ };
54
+ export var addRowAfter = function (state, dispatch) {
55
+ var cmdDispatch = dispatch && (function (tr) {
56
+ var _a;
57
+ var row = closest(tr.selection, 'table_row');
58
+ if (row && row.node.attrs[rowTypeAttr]) {
59
+ var from = row.pos + row.node.nodeSize;
60
+ tr.setNodeMarkup(from, undefined, (_a = {}, _a[rowTypeAttr] = row.node.attrs[rowTypeAttr], _a));
61
+ }
62
+ return dispatch(tr);
63
+ });
64
+ return pmAddRowAfter(state, cmdDispatch);
65
+ };
66
+ export { pmAddRowBefore, pmAddRowAfter };
@@ -0,0 +1,2 @@
1
+ export const rowTypeAttr = 'k-parent-node';
2
+ export const colgroupAttr = 'k-colgroup-data';
@@ -1,8 +1,11 @@
1
+ import { Schema } from 'prosemirror-model';
1
2
  import { tableNodes } from 'prosemirror-tables';
3
+ import { domToPmDoc, htmlToFragment, pmDocToFragment } from '../source';
4
+ import { rowTypeAttr, colgroupAttr } from './constants';
2
5
  const hole = 0;
3
6
  const blockquoteDOM = ['blockquote', hole], hrDOM = ['hr'], preDOM = ['pre', ['code', hole]];
4
7
  const olDOM = ['ol', 0], ulDOM = ['ul', 0], liDOM = ['li', 0];
5
- const getAttributes = (dom) => {
8
+ const domAttributes = (dom) => {
6
9
  const result = {};
7
10
  let attributes = dom.attributes, attr;
8
11
  for (let i = 0; i < attributes.length; i++) {
@@ -11,13 +14,14 @@ const getAttributes = (dom) => {
11
14
  }
12
15
  return result;
13
16
  };
14
- const commonAttributes = () => {
15
- return {
16
- style: { default: null },
17
- class: { default: null },
18
- id: { default: null }
19
- };
17
+ const defaultAttrs = (attrs) => {
18
+ const nodeAttrs = {};
19
+ attrs.forEach(attr => {
20
+ nodeAttrs[attr] = { default: null };
21
+ });
22
+ return nodeAttrs;
20
23
  };
24
+ const commonAttributes = () => defaultAttrs(['style', 'class', 'id']);
21
25
  const hasAttrs = (attrs, exclude) => {
22
26
  for (let attr in attrs) {
23
27
  if (attr && attrs[attr] !== null && attr !== exclude) {
@@ -26,7 +30,7 @@ const hasAttrs = (attrs, exclude) => {
26
30
  }
27
31
  return false;
28
32
  };
29
- const getAttrs = (attrs, exclude) => {
33
+ const pmAttributes = (attrs, exclude) => {
30
34
  const result = {};
31
35
  for (let attr in attrs) {
32
36
  if (attr && attrs[attr] !== null && attr !== exclude) {
@@ -52,17 +56,91 @@ const marks = Object.assign({
52
56
  link: {
53
57
  attrs: Object.assign({}, commonAttributes(), { href: { default: null }, target: { default: null }, title: { default: null } }),
54
58
  inclusive: false,
55
- parseDOM: [{ tag: 'a', getAttrs: getAttributes }],
56
- toDOM: (node) => ['a', getAttrs(node.attrs), hole]
59
+ parseDOM: [{ tag: 'a', getAttrs: domAttributes }],
60
+ toDOM: (node) => ['a', pmAttributes(node.attrs), hole]
57
61
  } }, tagMark('strong'), tagMark('b'), tagMark('em'), tagMark('i'), tagMark('u'), tagMark('del'), tagMark('sub'), tagMark('sup'), tagMark('code'), { style: {
58
62
  attrs: Object.assign({}, commonAttributes()),
59
63
  parseDOM: [{
60
64
  tag: 'span',
61
- getAttrs: getAttributes
65
+ getAttrs: domAttributes
62
66
  }],
63
67
  toDOM: node => hasAttrs(node.attrs) ?
64
- ['span', getAttrs(node.attrs), hole] : ['span', hole]
68
+ ['span', pmAttributes(node.attrs), hole] : ['span', hole]
65
69
  } });
70
+ const cellAttribute = (name) => {
71
+ return {
72
+ [name]: {
73
+ default: null,
74
+ getFromDOM: (cell) => cell.getAttribute(name),
75
+ setDOMAttr: (value, attrs) => { attrs[name] = value; }
76
+ }
77
+ };
78
+ };
79
+ const cellAttributes = Object.assign({}, cellAttribute('style'), cellAttribute('class'), cellAttribute('id'), cellAttribute('headers'));
80
+ const colgroupNodes = {
81
+ doc: { content: 'colgroup*' },
82
+ col: {
83
+ attrs: defaultAttrs(['id', 'class', 'style', 'span']),
84
+ parseDOM: [{ getAttrs: domAttributes, tag: 'col' }],
85
+ toDOM: node => ['col', node.attrs]
86
+ },
87
+ colgroup: {
88
+ attrs: defaultAttrs(['id', 'class', 'style', 'span']),
89
+ content: 'col*',
90
+ parseDOM: [{ getAttrs: domAttributes, tag: 'colgroup' }],
91
+ toDOM: node => ['colgroup', node.attrs, 0]
92
+ },
93
+ text: { inline: true, group: 'inline' }
94
+ };
95
+ const colgroupSchema = new Schema({ nodes: colgroupNodes, marks: {} });
96
+ // will be removed when we implement our own columnResizing
97
+ const shouldSkipColgroup = (node) => {
98
+ let shouldSkip = false;
99
+ const row = node.child(0);
100
+ for (let r = 0; r < row.childCount; r++) {
101
+ const cell = row.child(r);
102
+ if (cell.attrs.colwidth) {
103
+ shouldSkip = true;
104
+ break;
105
+ }
106
+ }
107
+ return shouldSkip;
108
+ };
109
+ const tNodes = tableNodes({ tableGroup: 'block', cellContent: 'block+', cellAttributes });
110
+ tNodes.table_row.attrs = Object.assign({}, tNodes.table_row.attrs, defaultAttrs([rowTypeAttr, 'style', 'class', 'id']));
111
+ tNodes.table_row.toDOM = node => ['tr', pmAttributes(node.attrs), 0];
112
+ tNodes.table_row.parseDOM = [{ tag: 'tr', getAttrs: domAttributes }];
113
+ tNodes.table.attrs = Object.assign({}, tNodes.table.attrs, defaultAttrs(['style', 'class', 'id', colgroupAttr]));
114
+ tNodes.table.toDOM = (node) => {
115
+ const tableAttrs = hasAttrs(node.attrs) ? pmAttributes(node.attrs, colgroupAttr) : {};
116
+ let colgroup = null;
117
+ if (node.attrs[colgroupAttr] && !shouldSkipColgroup(node)) {
118
+ const doc = domToPmDoc(htmlToFragment(node.attrs[colgroupAttr]), colgroupSchema, { preserveWhitespace: false });
119
+ const fragment = pmDocToFragment(doc);
120
+ const colgroupEl = fragment.firstChild;
121
+ if (colgroupEl) {
122
+ const cols = Array.from(colgroupEl.children).map((c) => ['col', domAttributes(c)]);
123
+ colgroup = [
124
+ 'colgroup',
125
+ domAttributes(colgroupEl),
126
+ ...cols
127
+ ];
128
+ }
129
+ }
130
+ return colgroup ? ['table', tableAttrs, colgroup, ['tbody', 0]] :
131
+ ['table', tableAttrs, ['tbody', 0]];
132
+ };
133
+ tNodes.table.parseDOM = [{
134
+ tag: 'table',
135
+ getAttrs: (node) => {
136
+ const attrs = domAttributes(node);
137
+ const colgroup = Array.from(node.childNodes).find(c => c.nodeName === 'COLGROUP');
138
+ if (colgroup) {
139
+ attrs[colgroupAttr] = colgroup.outerHTML;
140
+ }
141
+ return attrs;
142
+ }
143
+ }];
66
144
  const nodes = Object.assign({
67
145
  // :: NodeSpec The top level document node.
68
146
  doc: {
@@ -76,9 +154,9 @@ const nodes = Object.assign({
76
154
  attrs: Object.assign({}, commonAttributes()),
77
155
  parseDOM: [{
78
156
  tag: 'p',
79
- getAttrs: getAttributes
157
+ getAttrs: domAttributes
80
158
  }],
81
- toDOM: node => hasAttrs(node.attrs) ? ['p', getAttrs(node.attrs), hole] : ['p', hole]
159
+ toDOM: node => hasAttrs(node.attrs) ? ['p', pmAttributes(node.attrs), hole] : ['p', hole]
82
160
  }, div: {
83
161
  // Uncaught SyntaxError: Mixing inline and block content (in content expression '(block | inline)*')
84
162
  // content: '(block | inline)*',
@@ -87,9 +165,9 @@ const nodes = Object.assign({
87
165
  attrs: Object.assign({}, commonAttributes()),
88
166
  parseDOM: [{
89
167
  tag: 'div',
90
- getAttrs: getAttributes
168
+ getAttrs: domAttributes
91
169
  }],
92
- toDOM: node => hasAttrs(node.attrs) ? ['div', getAttrs(node.attrs), hole] : ['div', hole]
170
+ toDOM: node => hasAttrs(node.attrs) ? ['div', pmAttributes(node.attrs), hole] : ['div', hole]
93
171
  },
94
172
  // :: NodeSpec A blockquote (`<blockquote>`) wrapping one or more blocks.
95
173
  blockquote: {
@@ -99,9 +177,9 @@ const nodes = Object.assign({
99
177
  defining: true,
100
178
  parseDOM: [{
101
179
  tag: 'blockquote',
102
- getAttrs: getAttributes
180
+ getAttrs: domAttributes
103
181
  }],
104
- toDOM: node => hasAttrs(node.attrs) ? ['blockquote', getAttrs(node.attrs), hole] : blockquoteDOM
182
+ toDOM: node => hasAttrs(node.attrs) ? ['blockquote', pmAttributes(node.attrs), hole] : blockquoteDOM
105
183
  },
106
184
  // :: NodeSpec A horizontal rule (`<hr>`).
107
185
  horizontal_rule: {
@@ -118,15 +196,15 @@ const nodes = Object.assign({
118
196
  group: 'block',
119
197
  defining: true,
120
198
  parseDOM: [
121
- { tag: 'h1', getAttrs: node => (Object.assign({}, getAttributes(node), { level: 1 })) },
122
- { tag: 'h2', getAttrs: node => (Object.assign({}, getAttributes(node), { level: 2 })) },
123
- { tag: 'h3', getAttrs: node => (Object.assign({}, getAttributes(node), { level: 3 })) },
124
- { tag: 'h4', getAttrs: node => (Object.assign({}, getAttributes(node), { level: 4 })) },
125
- { tag: 'h5', getAttrs: node => (Object.assign({}, getAttributes(node), { level: 5 })) },
126
- { tag: 'h6', getAttrs: node => (Object.assign({}, getAttributes(node), { level: 6 })) }
199
+ { tag: 'h1', getAttrs: node => (Object.assign({}, domAttributes(node), { level: 1 })) },
200
+ { tag: 'h2', getAttrs: node => (Object.assign({}, domAttributes(node), { level: 2 })) },
201
+ { tag: 'h3', getAttrs: node => (Object.assign({}, domAttributes(node), { level: 3 })) },
202
+ { tag: 'h4', getAttrs: node => (Object.assign({}, domAttributes(node), { level: 4 })) },
203
+ { tag: 'h5', getAttrs: node => (Object.assign({}, domAttributes(node), { level: 5 })) },
204
+ { tag: 'h6', getAttrs: node => (Object.assign({}, domAttributes(node), { level: 6 })) }
127
205
  ],
128
206
  toDOM: node => hasAttrs(node.attrs, 'level') ?
129
- ['h' + node.attrs.level, getAttrs(node.attrs, 'level'), hole] :
207
+ ['h' + node.attrs.level, pmAttributes(node.attrs, 'level'), hole] :
130
208
  ['h' + node.attrs.level, hole]
131
209
  },
132
210
  // :: NodeSpec A code listing. Disallows marks or non-text inline
@@ -154,8 +232,8 @@ const nodes = Object.assign({
154
232
  attrs: Object.assign({ src: { default: null }, alt: { default: null }, title: { default: null }, width: { default: null }, height: { default: null } }, commonAttributes()),
155
233
  group: 'inline',
156
234
  draggable: true,
157
- parseDOM: [{ tag: 'img', getAttrs: getAttributes }],
158
- toDOM: node => hasAttrs(node.attrs) ? ['img', getAttrs(node.attrs)] : ['img']
235
+ parseDOM: [{ tag: 'img', getAttrs: domAttributes }],
236
+ toDOM: node => hasAttrs(node.attrs) ? ['img', pmAttributes(node.attrs)] : ['img']
159
237
  },
160
238
  // :: NodeSpec A hard line break represented in the DOM as a `<br>` element.
161
239
  hard_break: {
@@ -165,9 +243,9 @@ const nodes = Object.assign({
165
243
  selectable: false,
166
244
  parseDOM: [{
167
245
  tag: 'br',
168
- getAttrs: getAttributes
246
+ getAttrs: domAttributes
169
247
  }],
170
- toDOM: node => hasAttrs(node.attrs) ? ['br', getAttrs(node.attrs)] : ['br']
248
+ toDOM: node => hasAttrs(node.attrs) ? ['br', pmAttributes(node.attrs)] : ['br']
171
249
  },
172
250
  // :: NodeSpec
173
251
  // An ordered list [node spec](#model.NodeSpec). Has a single
@@ -179,12 +257,12 @@ const nodes = Object.assign({
179
257
  group: 'block',
180
258
  attrs: Object.assign({}, commonAttributes(), { type: { default: null }, order: { default: 1 } }),
181
259
  parseDOM: [{ tag: 'ol', getAttrs: (dom) => {
182
- return Object.assign({}, getAttributes(dom), { order: dom.hasAttribute('start') ? parseInt(dom.getAttribute('start') || '1', 10) : 1 });
260
+ return Object.assign({}, domAttributes(dom), { order: dom.hasAttribute('start') ? parseInt(dom.getAttribute('start') || '1', 10) : 1 });
183
261
  } }],
184
262
  toDOM: node => {
185
263
  return node.attrs.order === 1 ?
186
- (hasAttrs(node.attrs, 'order') ? ['ol', getAttrs(node.attrs, 'order'), hole] : olDOM) :
187
- ['ol', Object.assign({}, getAttrs(node.attrs, 'order'), { start: node.attrs.order }), hole];
264
+ (hasAttrs(node.attrs, 'order') ? ['ol', pmAttributes(node.attrs, 'order'), hole] : olDOM) :
265
+ ['ol', Object.assign({}, pmAttributes(node.attrs, 'order'), { start: node.attrs.order }), hole];
188
266
  }
189
267
  },
190
268
  // :: NodeSpec
@@ -193,16 +271,16 @@ const nodes = Object.assign({
193
271
  content: 'list_item+',
194
272
  group: 'block',
195
273
  attrs: Object.assign({}, commonAttributes()),
196
- parseDOM: [{ tag: 'ul', getAttrs: getAttributes }],
197
- toDOM: node => hasAttrs(node.attrs) ? ['ul', getAttrs(node.attrs), hole] : ulDOM
274
+ parseDOM: [{ tag: 'ul', getAttrs: domAttributes }],
275
+ toDOM: node => hasAttrs(node.attrs) ? ['ul', pmAttributes(node.attrs), hole] : ulDOM
198
276
  },
199
277
  // :: NodeSpec
200
278
  // A list item (`<li>`) specification.
201
279
  list_item: {
202
280
  content: '(paragraph | heading) block*',
203
281
  attrs: Object.assign({}, commonAttributes()),
204
- parseDOM: [{ tag: 'li', getAttrs: getAttributes }],
205
- toDOM: node => hasAttrs(node.attrs) ? ['li', getAttrs(node.attrs), hole] : liDOM,
282
+ parseDOM: [{ tag: 'li', getAttrs: domAttributes }],
283
+ toDOM: node => hasAttrs(node.attrs) ? ['li', pmAttributes(node.attrs), hole] : liDOM,
206
284
  defining: true
207
- } }, tableNodes({ tableGroup: 'block', cellContent: 'block+', cellAttributes: {} }));
285
+ } }, tNodes);
208
286
  export { nodes, marks };
@@ -18,7 +18,6 @@ export { buildKeymap, buildListKeymap } from './config/keymap';
18
18
  export { bold, italic, underline, strikethrough, subscript, superscript, link } from './config/commands';
19
19
  export { sanitize, removeComments, removeTag, pasteCleanup, sanitizeClassAttr, sanitizeStyleAttr, removeAttribute, replaceImageSourcesFromRtf } from './paste';
20
20
  export { convertMsLists } from './listConvert';
21
- export { createTable } from './table';
22
21
  export { find, findAt, findAll, replace, replaceAll } from './find-replace';
23
22
  export { placeholder } from './plugins/placeholder';
24
23
  export { spacesFix } from './plugins/spaces-fix';
@@ -37,3 +36,4 @@ export * from 'prosemirror-state';
37
36
  export * from 'prosemirror-tables';
38
37
  export * from 'prosemirror-transform';
39
38
  export * from 'prosemirror-view';
39
+ export { createTable, addRowAfter, addRowBefore, pmAddRowAfter, pmAddRowBefore } from './table';
@@ -1,9 +1,58 @@
1
1
  import { DOMSerializer, DOMParser as ProseMirrorDOMParser } from 'prosemirror-model';
2
2
  import { AllSelection } from 'prosemirror-state';
3
+ import { rowTypeAttr, colgroupAttr } from './config/constants';
3
4
  const blockWrappers = [
4
5
  'div', 'ol', 'ul', 'li', 'table', 'tbody', 'thead', 'tfoot', 'td', 'th', 'p',
5
6
  'tr', 'col', 'colgroup', 'article', 'main', 'nav', 'header', 'footer', 'aside', 'section'
6
7
  ];
8
+ const removeRowType = (table, nodeName) => {
9
+ const wrapper = (table.ownerDocument || document).createElement(nodeName);
10
+ Array.from(table.rows).filter(r => r.getAttribute(rowTypeAttr) === nodeName).forEach(row => {
11
+ row.removeAttribute(rowTypeAttr);
12
+ wrapper.appendChild(row);
13
+ });
14
+ if (wrapper.children.length) {
15
+ table.appendChild(wrapper);
16
+ }
17
+ };
18
+ const restoreTables = (fragment) => {
19
+ Array.from(fragment.querySelectorAll('table')).forEach((table) => {
20
+ removeRowType(table, 'thead');
21
+ removeRowType(table, 'tbody');
22
+ removeRowType(table, 'tfoot');
23
+ const emptyElement = Array.from(table.children).find(el => el.children.length === 0);
24
+ if (emptyElement) {
25
+ emptyElement.remove();
26
+ }
27
+ });
28
+ };
29
+ const setRowType = (children, nodeName) => {
30
+ const tag = nodeName.toUpperCase();
31
+ children.filter(c => c.nodeName === tag).forEach(rowsWrapper => {
32
+ Array.from(rowsWrapper.children).forEach(row => {
33
+ row.setAttribute(rowTypeAttr, nodeName);
34
+ if (rowsWrapper.parentNode) {
35
+ rowsWrapper.parentNode.insertBefore(row, rowsWrapper);
36
+ }
37
+ });
38
+ rowsWrapper.remove();
39
+ });
40
+ };
41
+ const validateTablesToPmSchema = (fragment) => {
42
+ Array.from(fragment.querySelectorAll('table')).forEach((table) => {
43
+ const children = Array.from(table.children);
44
+ if (children.some(e => e.nodeName === 'THEAD' || e.nodeName === 'TFOOT')) {
45
+ setRowType(children, 'thead');
46
+ setRowType(children, 'tbody');
47
+ setRowType(children, 'tfoot');
48
+ }
49
+ const colgroup = children.find(c => c.nodeName === 'COLGROUP');
50
+ if (colgroup) {
51
+ table.setAttribute(colgroupAttr, colgroup.outerHTML);
52
+ colgroup.remove();
53
+ }
54
+ });
55
+ };
7
56
  /**
8
57
  * Trims the whitespace around the provided block nodes.
9
58
  *
@@ -51,7 +100,9 @@ export const htmlToFragment = (html) => {
51
100
  * @returns DocumentFragment
52
101
  */
53
102
  export const pmDocToFragment = (doc) => {
54
- return DOMSerializer.fromSchema(doc.type.schema).serializeFragment(doc.content);
103
+ const fragment = DOMSerializer.fromSchema(doc.type.schema).serializeFragment(doc.content);
104
+ restoreTables(fragment);
105
+ return fragment;
55
106
  };
56
107
  /**
57
108
  * Creates a ProseMirrorNode from the given DOM element.
@@ -74,6 +125,7 @@ export const domToPmDoc = (dom, schema, parseOptions) => {
74
125
  */
75
126
  export const parseContent = (content, schema, parseOptions) => {
76
127
  const dom = htmlToFragment(content);
128
+ validateTablesToPmSchema(dom);
77
129
  return domToPmDoc(dom, schema, parseOptions);
78
130
  };
79
131
  /**
@@ -1,3 +1,5 @@
1
+ import { addRowAfter as pmAddRowAfter, addRowBefore as pmAddRowBefore } from 'prosemirror-tables';
2
+ import { rowTypeAttr } from './config/constants';
1
3
  /**
2
4
  * Creates a table.
3
5
  * @returns Node
@@ -15,3 +17,48 @@ export const createTable = (nodes, rows, columns) => {
15
17
  }
16
18
  return table.createAndFill(undefined, tableRows);
17
19
  };
20
+ const closest = (selection, name) => {
21
+ const pos = selection.$head;
22
+ for (let i = pos.depth; i > 0; i--) {
23
+ const node = pos.node(i);
24
+ if (node.type.name === name) {
25
+ return {
26
+ pos: pos.before(i),
27
+ node
28
+ };
29
+ }
30
+ }
31
+ return null;
32
+ };
33
+ export const addRowBefore = (state, dispatch) => {
34
+ const cmdDispatch = dispatch && (tr => {
35
+ const row = closest(tr.selection, 'table_row');
36
+ const table = closest(tr.selection, 'table');
37
+ if (row && table && row.node.attrs[rowTypeAttr]) {
38
+ let index = 0;
39
+ for (let i = 0; i < table.node.nodeSize; i++) {
40
+ if (table.node.child(i).eq(row.node)) {
41
+ index = i;
42
+ break;
43
+ }
44
+ }
45
+ const next = table.node.child(index - 1);
46
+ const from = row.pos - next.nodeSize;
47
+ tr.setNodeMarkup(from, undefined, { [rowTypeAttr]: row.node.attrs[rowTypeAttr] });
48
+ }
49
+ return dispatch(tr);
50
+ });
51
+ return pmAddRowBefore(state, cmdDispatch);
52
+ };
53
+ export const addRowAfter = (state, dispatch) => {
54
+ const cmdDispatch = dispatch && (tr => {
55
+ const row = closest(tr.selection, 'table_row');
56
+ if (row && row.node.attrs[rowTypeAttr]) {
57
+ const from = row.pos + row.node.nodeSize;
58
+ tr.setNodeMarkup(from, undefined, { [rowTypeAttr]: row.node.attrs[rowTypeAttr] });
59
+ }
60
+ return dispatch(tr);
61
+ });
62
+ return pmAddRowAfter(state, cmdDispatch);
63
+ };
64
+ export { pmAddRowBefore, pmAddRowAfter };
@@ -0,0 +1,2 @@
1
+ export declare const rowTypeAttr = "k-parent-node";
2
+ export declare const colgroupAttr = "k-colgroup-data";
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rowTypeAttr = 'k-parent-node';
4
+ exports.colgroupAttr = 'k-colgroup-data';