@pie-lib/editable-html 11.1.1 → 11.2.1-beta.0

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 (166) hide show
  1. package/CHANGELOG.md +43 -167
  2. package/NEXT.CHANGELOG.json +1 -0
  3. package/package.json +10 -6
  4. package/src/__tests__/editor.test.jsx +363 -0
  5. package/src/__tests__/serialization.test.js +291 -0
  6. package/src/__tests__/utils.js +36 -0
  7. package/src/block-tags.js +17 -0
  8. package/src/constants.js +7 -0
  9. package/src/editor.jsx +303 -49
  10. package/src/index.jsx +19 -10
  11. package/src/plugins/characters/index.jsx +11 -3
  12. package/src/plugins/characters/utils.js +12 -12
  13. package/src/plugins/css/icons/index.jsx +17 -0
  14. package/src/plugins/css/index.jsx +346 -0
  15. package/src/plugins/customPlugin/index.jsx +85 -0
  16. package/src/plugins/html/index.jsx +9 -6
  17. package/src/plugins/image/__tests__/__snapshots__/component.test.jsx.snap +51 -0
  18. package/src/plugins/image/__tests__/__snapshots__/image-toolbar-logic.test.jsx.snap +27 -0
  19. package/src/plugins/image/__tests__/__snapshots__/image-toolbar.test.jsx.snap +44 -0
  20. package/src/plugins/image/__tests__/component.test.jsx +41 -0
  21. package/src/plugins/image/__tests__/image-toolbar-logic.test.jsx +42 -0
  22. package/src/plugins/image/__tests__/image-toolbar.test.jsx +11 -0
  23. package/src/plugins/image/__tests__/index.test.js +95 -0
  24. package/src/plugins/image/__tests__/insert-image-handler.test.js +113 -0
  25. package/src/plugins/image/__tests__/mock-change.js +15 -0
  26. package/src/plugins/image/index.jsx +2 -1
  27. package/src/plugins/image/insert-image-handler.js +13 -6
  28. package/src/plugins/index.jsx +248 -5
  29. package/src/plugins/list/__tests__/index.test.js +54 -0
  30. package/src/plugins/list/index.jsx +130 -0
  31. package/src/plugins/math/__tests__/__snapshots__/index.test.jsx.snap +48 -0
  32. package/src/plugins/math/__tests__/index.test.jsx +245 -0
  33. package/src/plugins/math/index.jsx +87 -56
  34. package/src/plugins/media/__tests__/index.test.js +75 -0
  35. package/src/plugins/media/index.jsx +3 -2
  36. package/src/plugins/media/media-dialog.js +106 -57
  37. package/src/plugins/rendering/index.js +31 -0
  38. package/src/plugins/respArea/drag-in-the-blank/choice.jsx +4 -1
  39. package/src/plugins/respArea/explicit-constructed-response/index.jsx +10 -8
  40. package/src/plugins/respArea/index.jsx +53 -7
  41. package/src/plugins/respArea/inline-dropdown/index.jsx +13 -6
  42. package/src/plugins/respArea/math-templated/index.jsx +104 -0
  43. package/src/plugins/respArea/utils.jsx +11 -0
  44. package/src/plugins/table/CustomTablePlugin.js +113 -0
  45. package/src/plugins/table/__tests__/__snapshots__/table-toolbar.test.jsx.snap +44 -0
  46. package/src/plugins/table/__tests__/index.test.jsx +401 -0
  47. package/src/plugins/table/__tests__/table-toolbar.test.jsx +42 -0
  48. package/src/plugins/table/index.jsx +46 -59
  49. package/src/plugins/table/table-toolbar.jsx +39 -2
  50. package/src/plugins/textAlign/icons/index.jsx +139 -0
  51. package/src/plugins/textAlign/index.jsx +23 -0
  52. package/src/plugins/toolbar/__tests__/__snapshots__/default-toolbar.test.jsx.snap +923 -0
  53. package/src/plugins/toolbar/__tests__/__snapshots__/editor-and-toolbar.test.jsx.snap +20 -0
  54. package/src/plugins/toolbar/__tests__/__snapshots__/toolbar-buttons.test.jsx.snap +36 -0
  55. package/src/plugins/toolbar/__tests__/__snapshots__/toolbar.test.jsx.snap +46 -0
  56. package/src/plugins/toolbar/__tests__/default-toolbar.test.jsx +94 -0
  57. package/src/plugins/toolbar/__tests__/editor-and-toolbar.test.jsx +37 -0
  58. package/src/plugins/toolbar/__tests__/toolbar-buttons.test.jsx +51 -0
  59. package/src/plugins/toolbar/__tests__/toolbar.test.jsx +106 -0
  60. package/src/plugins/toolbar/default-toolbar.jsx +82 -20
  61. package/src/plugins/toolbar/done-button.jsx +3 -1
  62. package/src/plugins/toolbar/editor-and-toolbar.jsx +18 -13
  63. package/src/plugins/toolbar/toolbar-buttons.jsx +52 -11
  64. package/src/plugins/toolbar/toolbar.jsx +31 -8
  65. package/src/serialization.jsx +213 -38
  66. package/README.md +0 -45
  67. package/deploy.sh +0 -16
  68. package/lib/editor.js +0 -1094
  69. package/lib/editor.js.map +0 -1
  70. package/lib/index.js +0 -253
  71. package/lib/index.js.map +0 -1
  72. package/lib/parse-html.js +0 -16
  73. package/lib/parse-html.js.map +0 -1
  74. package/lib/plugins/characters/custom-popper.js +0 -73
  75. package/lib/plugins/characters/custom-popper.js.map +0 -1
  76. package/lib/plugins/characters/index.js +0 -300
  77. package/lib/plugins/characters/index.js.map +0 -1
  78. package/lib/plugins/characters/utils.js +0 -381
  79. package/lib/plugins/characters/utils.js.map +0 -1
  80. package/lib/plugins/html/icons/index.js +0 -38
  81. package/lib/plugins/html/icons/index.js.map +0 -1
  82. package/lib/plugins/html/index.js +0 -76
  83. package/lib/plugins/html/index.js.map +0 -1
  84. package/lib/plugins/image/alt-dialog.js +0 -129
  85. package/lib/plugins/image/alt-dialog.js.map +0 -1
  86. package/lib/plugins/image/component.js +0 -419
  87. package/lib/plugins/image/component.js.map +0 -1
  88. package/lib/plugins/image/image-toolbar.js +0 -177
  89. package/lib/plugins/image/image-toolbar.js.map +0 -1
  90. package/lib/plugins/image/index.js +0 -262
  91. package/lib/plugins/image/index.js.map +0 -1
  92. package/lib/plugins/image/insert-image-handler.js +0 -152
  93. package/lib/plugins/image/insert-image-handler.js.map +0 -1
  94. package/lib/plugins/index.js +0 -143
  95. package/lib/plugins/index.js.map +0 -1
  96. package/lib/plugins/list/index.js +0 -204
  97. package/lib/plugins/list/index.js.map +0 -1
  98. package/lib/plugins/math/index.js +0 -419
  99. package/lib/plugins/math/index.js.map +0 -1
  100. package/lib/plugins/media/index.js +0 -384
  101. package/lib/plugins/media/index.js.map +0 -1
  102. package/lib/plugins/media/media-dialog.js +0 -668
  103. package/lib/plugins/media/media-dialog.js.map +0 -1
  104. package/lib/plugins/media/media-toolbar.js +0 -101
  105. package/lib/plugins/media/media-toolbar.js.map +0 -1
  106. package/lib/plugins/media/media-wrapper.js +0 -93
  107. package/lib/plugins/media/media-wrapper.js.map +0 -1
  108. package/lib/plugins/respArea/drag-in-the-blank/choice.js +0 -251
  109. package/lib/plugins/respArea/drag-in-the-blank/choice.js.map +0 -1
  110. package/lib/plugins/respArea/drag-in-the-blank/index.js +0 -97
  111. package/lib/plugins/respArea/drag-in-the-blank/index.js.map +0 -1
  112. package/lib/plugins/respArea/explicit-constructed-response/index.js +0 -55
  113. package/lib/plugins/respArea/explicit-constructed-response/index.js.map +0 -1
  114. package/lib/plugins/respArea/icons/index.js +0 -95
  115. package/lib/plugins/respArea/icons/index.js.map +0 -1
  116. package/lib/plugins/respArea/index.js +0 -293
  117. package/lib/plugins/respArea/index.js.map +0 -1
  118. package/lib/plugins/respArea/inline-dropdown/index.js +0 -70
  119. package/lib/plugins/respArea/inline-dropdown/index.js.map +0 -1
  120. package/lib/plugins/respArea/utils.js +0 -110
  121. package/lib/plugins/respArea/utils.js.map +0 -1
  122. package/lib/plugins/table/icons/index.js +0 -69
  123. package/lib/plugins/table/icons/index.js.map +0 -1
  124. package/lib/plugins/table/index.js +0 -499
  125. package/lib/plugins/table/index.js.map +0 -1
  126. package/lib/plugins/table/table-toolbar.js +0 -158
  127. package/lib/plugins/table/table-toolbar.js.map +0 -1
  128. package/lib/plugins/toolbar/default-toolbar.js +0 -174
  129. package/lib/plugins/toolbar/default-toolbar.js.map +0 -1
  130. package/lib/plugins/toolbar/done-button.js +0 -50
  131. package/lib/plugins/toolbar/done-button.js.map +0 -1
  132. package/lib/plugins/toolbar/editor-and-toolbar.js +0 -287
  133. package/lib/plugins/toolbar/editor-and-toolbar.js.map +0 -1
  134. package/lib/plugins/toolbar/index.js +0 -34
  135. package/lib/plugins/toolbar/index.js.map +0 -1
  136. package/lib/plugins/toolbar/toolbar-buttons.js +0 -161
  137. package/lib/plugins/toolbar/toolbar-buttons.js.map +0 -1
  138. package/lib/plugins/toolbar/toolbar.js +0 -352
  139. package/lib/plugins/toolbar/toolbar.js.map +0 -1
  140. package/lib/plugins/utils.js +0 -62
  141. package/lib/plugins/utils.js.map +0 -1
  142. package/lib/serialization.js +0 -488
  143. package/lib/serialization.js.map +0 -1
  144. package/lib/theme.js +0 -9
  145. package/lib/theme.js.map +0 -1
  146. package/playground/image/data.js +0 -59
  147. package/playground/image/index.html +0 -22
  148. package/playground/image/index.jsx +0 -81
  149. package/playground/index.html +0 -25
  150. package/playground/mathquill/index.html +0 -22
  151. package/playground/mathquill/index.jsx +0 -155
  152. package/playground/package.json +0 -15
  153. package/playground/prod-test/index.html +0 -22
  154. package/playground/prod-test/index.jsx +0 -28
  155. package/playground/schema-override/data.js +0 -29
  156. package/playground/schema-override/image-plugin.jsx +0 -41
  157. package/playground/schema-override/index.html +0 -21
  158. package/playground/schema-override/index.jsx +0 -97
  159. package/playground/serialization/data.js +0 -29
  160. package/playground/serialization/image-plugin.jsx +0 -41
  161. package/playground/serialization/index.html +0 -22
  162. package/playground/serialization/index.jsx +0 -12
  163. package/playground/static.json +0 -3
  164. package/playground/table-examples.html +0 -70
  165. package/playground/webpack.config.js +0 -42
  166. package/static.json +0 -1
@@ -0,0 +1,363 @@
1
+ import React from 'react';
2
+ import { htmlToValue, valueToHtml } from '../index';
3
+ import { Editor } from '../editor';
4
+ import { shallow, configure } from 'enzyme';
5
+ import debug from 'debug';
6
+
7
+ import { mockComponents } from './utils';
8
+
9
+ const log = debug('@pie-lib:editable-html:test');
10
+
11
+ const value = htmlToValue('hi');
12
+
13
+ const resizeWindow = (width, height) => {
14
+ window.innerWidth = width;
15
+ window.innerHeight = height;
16
+ window.dispatchEvent(new Event('resize'));
17
+ };
18
+ jest.mock('@pie-lib/math-toolbar', () => ({}));
19
+ jest.mock('@pie-lib/math-input', () => {
20
+ HorizontalKeypad: () => <div>HorizontalKeypad</div>;
21
+ });
22
+
23
+ expect.extend({
24
+ toEqualHtml(value, html) {
25
+ const v = valueToHtml(value);
26
+ const pass = v === html;
27
+
28
+ return {
29
+ pass,
30
+ message: () => `expected ${html} to match ${v}`,
31
+ };
32
+ },
33
+ });
34
+
35
+ describe('logic', () => {
36
+ test('onFocus/onBlur saves the value', async () => {
37
+ const wrapper = shallow(
38
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
39
+ );
40
+
41
+ await wrapper.instance().onFocus();
42
+
43
+ const v = htmlToValue('hi');
44
+
45
+ expect(wrapper.state('stashedValue')).toEqualHtml('<div>hi</div>');
46
+
47
+ wrapper.instance().onChange({ value: htmlToValue('new value') });
48
+
49
+ expect(wrapper.state('value')).toEqualHtml('<div>new value</div>');
50
+
51
+ return wrapper
52
+ .instance()
53
+ .onBlur({})
54
+ .then(() => {
55
+ expect(wrapper.state('value')).toEqualHtml('<div>new value</div>');
56
+ });
57
+ });
58
+ });
59
+
60
+ test('onFocus does not change focus if related target is a button from language keypad', async () => {
61
+ const wrapper = shallow(
62
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
63
+ );
64
+
65
+ const event = {
66
+ relatedTarget: {
67
+ tagName: 'button',
68
+ },
69
+ };
70
+
71
+ const change = {
72
+ focus: jest.fn(),
73
+ };
74
+
75
+ wrapper.instance().keypadInteractionDetected = true;
76
+
77
+ await wrapper.instance().onFocus(event, change);
78
+
79
+ expect(change.focus).not.toHaveBeenCalled();
80
+ });
81
+
82
+ test('onFocus changes focus if related target is not a button from language keypad', async () => {
83
+ const wrapper = shallow(
84
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
85
+ );
86
+
87
+ const event = {
88
+ relatedTarget: {
89
+ tagName: 'div',
90
+ },
91
+ };
92
+
93
+ const change = {
94
+ focus: jest.fn(),
95
+ };
96
+
97
+ await wrapper.instance().onFocus(event, change);
98
+
99
+ expect(change.focus).toHaveBeenCalled();
100
+ });
101
+
102
+ test('onFocus stashes the value', async () => {
103
+ const wrapper = shallow(
104
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
105
+ );
106
+
107
+ await wrapper.instance().onFocus();
108
+
109
+ expect(wrapper.state('stashedValue')).toEqualHtml('<div>hi</div>');
110
+ });
111
+
112
+ test('onBlur does not set focusToolbar if related target is RawDoneButton', async () => {
113
+ const wrapper = shallow(
114
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
115
+ );
116
+
117
+ const toolbarElement = document.createElement('div');
118
+ const relatedTarget = document.createElement('button');
119
+ relatedTarget.className = 'RawDoneButton';
120
+ toolbarElement.className = 'toolbar';
121
+ toolbarElement.appendChild(relatedTarget);
122
+
123
+ wrapper.instance().toolbarRef = toolbarElement;
124
+ wrapper.instance().doneButtonRef.current = relatedTarget;
125
+
126
+ const event = { relatedTarget };
127
+
128
+ await wrapper.instance().onBlur(event);
129
+
130
+ expect(wrapper.state('focusToolbar')).toBe(false);
131
+ });
132
+
133
+ test('handleToolbarFocus sets focusToolbar to true', () => {
134
+ const wrapper = shallow(
135
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
136
+ );
137
+
138
+ wrapper.instance().handleToolbarFocus();
139
+ expect(wrapper.state('focusToolbar')).toBe(true);
140
+ });
141
+
142
+ test('handleToolbarBlur sets focusToolbar to false if toolbar does not contain focus', (done) => {
143
+ const wrapper = shallow(
144
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
145
+ );
146
+
147
+ wrapper.instance().toolbarContainsFocus = jest.fn().mockReturnValue(false);
148
+
149
+ wrapper.instance().handleToolbarBlur();
150
+
151
+ setTimeout(() => {
152
+ expect(wrapper.state('focusToolbar')).toBe(false);
153
+ done();
154
+ }, 20);
155
+ });
156
+
157
+ test('handleToolbarBlur does not set focusToolbar to false if toolbar contains focus', (done) => {
158
+ const wrapper = shallow(
159
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
160
+ );
161
+
162
+ wrapper.instance().toolbarContainsFocus = jest.fn().mockReturnValue(true);
163
+
164
+ wrapper.setState({ focusToolbar: true });
165
+
166
+ wrapper.instance().handleToolbarBlur();
167
+
168
+ setTimeout(() => {
169
+ expect(wrapper.state('focusToolbar')).toBe(true);
170
+ done();
171
+ }, 20);
172
+ });
173
+
174
+ test('toolbarContainsFocus correctly detects focus within toolbar', () => {
175
+ const wrapper = shallow(
176
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
177
+ );
178
+
179
+ const toolbarElement = document.createElement('div');
180
+ const activeElement = document.createElement('button');
181
+ toolbarElement.appendChild(activeElement);
182
+
183
+ Object.defineProperty(document, 'activeElement', {
184
+ value: activeElement,
185
+ configurable: true,
186
+ });
187
+
188
+ wrapper.instance().toolbarRef = toolbarElement;
189
+
190
+ expect(wrapper.instance().toolbarContainsFocus()).toBe(true);
191
+
192
+ Object.defineProperty(document, 'activeElement', {
193
+ value: document.createElement('div'),
194
+ configurable: true,
195
+ });
196
+
197
+ expect(wrapper.instance().toolbarContainsFocus()).toBe(false);
198
+ });
199
+
200
+ test('onBlur sets focusToolbar to true if related target is within toolbar', async () => {
201
+ const wrapper = shallow(
202
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
203
+ );
204
+
205
+ const toolbarElement = document.createElement('div');
206
+ const relatedTarget = document.createElement('button');
207
+ toolbarElement.className = 'toolbar';
208
+ toolbarElement.appendChild(relatedTarget);
209
+
210
+ wrapper.instance().toolbarRef = toolbarElement;
211
+
212
+ const event = { relatedTarget };
213
+
214
+ await wrapper.instance().onBlur(event);
215
+
216
+ expect(wrapper.state('focusToolbar')).toBe(true);
217
+ });
218
+
219
+ describe('buildSizeStyle', () => {
220
+ const wrapper = (extras) => {
221
+ const props = Object.assign({}, extras);
222
+ return shallow(
223
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} {...props} />,
224
+ );
225
+ };
226
+
227
+ it('builds width with px', () => {
228
+ const w = wrapper({ width: 100 });
229
+ expect(w.instance().buildSizeStyle()).toEqual({
230
+ width: '100px',
231
+ height: undefined,
232
+ minHeight: undefined,
233
+ maxHeight: undefined,
234
+ });
235
+ });
236
+
237
+ it('returns undefined for % ', () => {
238
+ const w = wrapper({ height: '100%', width: '100%' });
239
+ expect(w.instance().buildSizeStyle()).toEqual({
240
+ width: undefined,
241
+ height: undefined,
242
+ minHeight: undefined,
243
+ maxHeight: undefined,
244
+ });
245
+ });
246
+
247
+ it('builds height', () => {
248
+ const w = wrapper({ height: 100 });
249
+ expect(w.instance().buildSizeStyle()).toEqual({
250
+ width: undefined,
251
+ height: '100px',
252
+ minHeight: undefined,
253
+ maxHeight: undefined,
254
+ });
255
+ });
256
+
257
+ it('builds minHeight', () => {
258
+ const w = wrapper({ minHeight: 100 });
259
+ expect(w.instance().buildSizeStyle()).toEqual({
260
+ width: undefined,
261
+ height: undefined,
262
+ minHeight: '100px',
263
+ maxHeight: undefined,
264
+ });
265
+ });
266
+
267
+ it('builds maxHeight', () => {
268
+ const w = wrapper({ maxHeight: 100 });
269
+ expect(w.instance().buildSizeStyle()).toEqual({
270
+ width: undefined,
271
+ height: undefined,
272
+ minHeight: undefined,
273
+ maxHeight: '100px',
274
+ });
275
+ });
276
+
277
+ it('builds width with calc()', () => {
278
+ const w = wrapper({ width: 'calc(10em + 42px)' });
279
+ expect(w.instance().buildSizeStyle()).toEqual({
280
+ width: 'calc(10em + 42px)',
281
+ height: undefined,
282
+ minHeight: undefined,
283
+ maxHeight: undefined,
284
+ });
285
+ });
286
+
287
+ it('builds width with ch', () => {
288
+ const w = wrapper({ width: '9ch' });
289
+ expect(w.instance().buildSizeStyle()).toEqual({
290
+ width: '9ch',
291
+ height: undefined,
292
+ minHeight: undefined,
293
+ maxHeight: undefined,
294
+ });
295
+ });
296
+
297
+ it('builds', () => {
298
+ const w = wrapper({});
299
+ expect(w.instance().buildSizeStyle()).toEqual({
300
+ width: undefined,
301
+ height: undefined,
302
+ minHeight: undefined,
303
+ maxHeight: undefined,
304
+ });
305
+ });
306
+ });
307
+
308
+ describe('onResize', () => {
309
+ it('should display html of current state on Resize', () => {
310
+ const wrapper = shallow(
311
+ <Editor editorRef={jest.fn()} value={value} classes={{}} onChange={jest.fn()} onRef={jest.fn()} />,
312
+ );
313
+
314
+ resizeWindow(500, 300);
315
+ expect(wrapper.state('value')).toEqualHtml('<div>hi</div>');
316
+
317
+ wrapper.instance().onChange({ value: htmlToValue('new value') });
318
+ resizeWindow(1024, 768);
319
+ expect(wrapper.state('value')).toEqualHtml('<div>new value</div>');
320
+
321
+ resizeWindow(500, 300);
322
+ expect(wrapper.state('value')).toEqualHtml('<div>new value</div>');
323
+ });
324
+ });
325
+
326
+ describe('MathMl', () => {
327
+ beforeEach(() => {});
328
+
329
+ it('should not call runSerializationOnMarkup if mathMl props are not there', () => {
330
+ const runSerializationOnMarkup = jest.fn();
331
+
332
+ const wrapper = shallow(
333
+ <Editor
334
+ editorRef={jest.fn()}
335
+ value={value}
336
+ classes={{}}
337
+ onChange={jest.fn()}
338
+ onRef={jest.fn()}
339
+ runSerializationOnMarkup={runSerializationOnMarkup}
340
+ />,
341
+ );
342
+
343
+ expect(runSerializationOnMarkup).not.toHaveBeenCalled();
344
+ });
345
+
346
+ it('should call runSerializationOnMarkup if mmlEditing or mmlOutput are true', () => {
347
+ const runSerializationOnMarkup = jest.fn();
348
+
349
+ const wrapper = shallow(
350
+ <Editor
351
+ editorRef={jest.fn()}
352
+ value={value}
353
+ classes={{}}
354
+ onChange={jest.fn()}
355
+ onRef={jest.fn()}
356
+ runSerializationOnMarkup={runSerializationOnMarkup}
357
+ mathMlOptions={{ mmlOutput: true }}
358
+ />,
359
+ );
360
+
361
+ expect(runSerializationOnMarkup).toHaveBeenCalled();
362
+ });
363
+ });
@@ -0,0 +1,291 @@
1
+ import { htmlToValue, TEXT_RULE } from '../serialization';
2
+
3
+ jest.mock('../plugins/math', () => ({
4
+ serialization: {
5
+ serialize: jest.fn((o, c) => {
6
+ return undefined;
7
+ }),
8
+ deserialize: jest.fn((el, next) => {
9
+ return undefined;
10
+ }),
11
+ },
12
+ }));
13
+
14
+ describe('TEXT_RULE', () => {
15
+ const mkBr = (previousSibling) => {
16
+ return {
17
+ remove: jest.fn(),
18
+ previousSibling,
19
+ replaceWith: (foo) => {
20
+ previousSibling.textContent = previousSibling.textContent.replace(/(<br>)|(<\/br>)/g, foo);
21
+ },
22
+ normalize: jest.fn().mockReturnThis(),
23
+ tagName: 'br',
24
+ };
25
+ };
26
+
27
+ const mkTextNode = (textContent = '') => ({
28
+ nodeName: '#text',
29
+ textContent,
30
+ normalize: jest.fn().mockReturnThis(),
31
+ });
32
+
33
+ const mkEl = (querySelectorAllResult) => ({
34
+ querySelectorAll: jest.fn().mockReturnValue(querySelectorAllResult),
35
+ normalize: jest.fn().mockReturnThis(),
36
+ });
37
+
38
+ describe('deserialize', () => {
39
+ it('if no previous text node, no error is thrown', () => {
40
+ const br = mkBr();
41
+ const el = mkEl([br]);
42
+ expect(() => TEXT_RULE.deserialize(el)).not.toThrow();
43
+ });
44
+ });
45
+ });
46
+
47
+ describe('htmlToValue', () => {
48
+ it('converts', () => {
49
+ const expected = {
50
+ object: 'value',
51
+ document: {
52
+ object: 'document',
53
+ data: {},
54
+ nodes: [
55
+ {
56
+ object: 'block',
57
+ type: 'div',
58
+ isVoid: false,
59
+ data: {
60
+ attributes: {},
61
+ },
62
+ nodes: [
63
+ {
64
+ object: 'block',
65
+ type: 'paragraph',
66
+ isVoid: false,
67
+ data: {
68
+ attributes: {},
69
+ },
70
+ nodes: [
71
+ {
72
+ object: 'text',
73
+ leaves: [
74
+ {
75
+ object: 'leaf',
76
+ text: 'foo',
77
+ marks: [],
78
+ },
79
+ ],
80
+ },
81
+ {
82
+ object: 'inline',
83
+ type: 'image',
84
+ isVoid: true,
85
+ data: {
86
+ src: 'blah.jpg',
87
+ width: null,
88
+ height: null,
89
+ margin: '',
90
+ justifyContent: '',
91
+ alignment: null,
92
+ alt: null,
93
+ },
94
+ nodes: [
95
+ {
96
+ object: 'text',
97
+ leaves: [
98
+ {
99
+ object: 'leaf',
100
+ text: '',
101
+ marks: [],
102
+ },
103
+ ],
104
+ },
105
+ ],
106
+ },
107
+ {
108
+ object: 'text',
109
+ leaves: [
110
+ {
111
+ object: 'leaf',
112
+ text: 'bar',
113
+ marks: [],
114
+ },
115
+ ],
116
+ },
117
+ ],
118
+ },
119
+ ],
120
+ },
121
+ ],
122
+ },
123
+ };
124
+ const html = `<div><p>foo<img src="blah.jpg"/>bar</p></div>`;
125
+ const v = htmlToValue(html);
126
+
127
+ console.log(JSON.stringify(v.toJSON()));
128
+ expect(v.toJSON()).toEqual(expected);
129
+ });
130
+
131
+ it('does not break', () => {
132
+ /*
133
+ More than 12 iterations of the same kind would previously break the input. Here we have 16 text nodes, and now it works.
134
+ */
135
+ const expected = {
136
+ object: 'value',
137
+ document: {
138
+ object: 'document',
139
+ data: {},
140
+ nodes: [
141
+ {
142
+ object: 'block',
143
+ type: 'div',
144
+ isVoid: false,
145
+ data: { attributes: {} },
146
+ nodes: [
147
+ {
148
+ object: 'text',
149
+ leaves: [
150
+ {
151
+ object: 'leaf',
152
+ text: 'Foo ',
153
+ marks: [],
154
+ },
155
+ {
156
+ object: 'leaf',
157
+ text: 'x',
158
+ marks: [
159
+ {
160
+ object: 'mark',
161
+ type: 'italic',
162
+ data: {},
163
+ },
164
+ ],
165
+ },
166
+ {
167
+ object: 'leaf',
168
+ text: ' bar ',
169
+ marks: [],
170
+ },
171
+ {
172
+ object: 'leaf',
173
+ text: 'x',
174
+ marks: [
175
+ {
176
+ object: 'mark',
177
+ type: 'italic',
178
+ data: {},
179
+ },
180
+ ],
181
+ },
182
+ {
183
+ object: 'leaf',
184
+ text: ' Foo ',
185
+ marks: [],
186
+ },
187
+ {
188
+ object: 'leaf',
189
+ text: 'x',
190
+ marks: [
191
+ {
192
+ object: 'mark',
193
+ type: 'italic',
194
+ data: {},
195
+ },
196
+ ],
197
+ },
198
+ {
199
+ object: 'leaf',
200
+ text: ' bar ',
201
+ marks: [],
202
+ },
203
+ {
204
+ object: 'leaf',
205
+ text: 'x',
206
+ marks: [
207
+ {
208
+ object: 'mark',
209
+ type: 'italic',
210
+ data: {},
211
+ },
212
+ ],
213
+ },
214
+ {
215
+ object: 'leaf',
216
+ text: ' Foo ',
217
+ marks: [],
218
+ },
219
+ {
220
+ object: 'leaf',
221
+ text: 'x',
222
+ marks: [
223
+ {
224
+ object: 'mark',
225
+ type: 'italic',
226
+ data: {},
227
+ },
228
+ ],
229
+ },
230
+ {
231
+ object: 'leaf',
232
+ text: ' bar ',
233
+ marks: [],
234
+ },
235
+ {
236
+ object: 'leaf',
237
+ text: 'x',
238
+ marks: [
239
+ {
240
+ object: 'mark',
241
+ type: 'italic',
242
+ data: {},
243
+ },
244
+ ],
245
+ },
246
+ {
247
+ object: 'leaf',
248
+ text: ' Foo ',
249
+ marks: [],
250
+ },
251
+ {
252
+ object: 'leaf',
253
+ text: 'x',
254
+ marks: [
255
+ {
256
+ object: 'mark',
257
+ type: 'italic',
258
+ data: {},
259
+ },
260
+ ],
261
+ },
262
+ {
263
+ object: 'leaf',
264
+ text: ' bar ',
265
+ marks: [],
266
+ },
267
+ {
268
+ object: 'leaf',
269
+ text: 'x',
270
+ marks: [
271
+ {
272
+ object: 'mark',
273
+ type: 'italic',
274
+ data: {},
275
+ },
276
+ ],
277
+ },
278
+ ],
279
+ },
280
+ ],
281
+ },
282
+ ],
283
+ },
284
+ };
285
+ const html =
286
+ '<div>Foo <em>x</em> bar <em>x</em> Foo <em>x</em> bar <em>x</em> Foo <em>x</em> bar <em>x</em> Foo <em>x</em> bar <em>x</em></div>';
287
+ const v = htmlToValue(html);
288
+
289
+ expect(v.toJSON()).toEqual(expected);
290
+ });
291
+ });
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+
3
+ export function classObject() {
4
+ const out = {};
5
+ for (var a in arguments) {
6
+ const value = arguments[a];
7
+ out[value] = value;
8
+ }
9
+ return out;
10
+ }
11
+
12
+ export function mockComponents() {
13
+ const out = {};
14
+ for (var a in arguments) {
15
+ const value = arguments[a];
16
+ out[value] = class extends React.Component {
17
+ render() {
18
+ return <div data-mock-component="true">{value}</div>;
19
+ }
20
+ };
21
+ }
22
+ return out;
23
+ }
24
+
25
+ export function mockIconButton() {
26
+ jest.mock('@material-ui/core/IconButton', () => {
27
+ return (props) => <div className={props.className} style={props.style} ariaLabel={props['aria-label']} />;
28
+ });
29
+ }
30
+ export function mockMathInput() {
31
+ jest.mock('@pie-lib/math-input', () => ({
32
+ addBrackets: jest.fn((s) => s),
33
+ removeBrackets: jest.fn((s) => s),
34
+ ...mockComponents('Keypad', 'MathQuillInput', 'EditableMathInput', 'HorizontalKeypad'),
35
+ }));
36
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Tags to blocks.
3
+ *
4
+ * @type {Object}
5
+ */
6
+
7
+ export const BLOCK_TAGS = {
8
+ div: 'div',
9
+ // span: 'span',
10
+ p: 'paragraph',
11
+ pre: 'code',
12
+ h1: 'heading-one',
13
+ h2: 'heading-two',
14
+ h4: 'heading-four',
15
+ h5: 'heading-five',
16
+ h6: 'heading-six',
17
+ };
@@ -0,0 +1,7 @@
1
+ export const MAIN_CONTAINER_CLASS = 'main-container';
2
+ export const PIE_TOOLBAR__CLASS = 'pie-toolbar';
3
+
4
+ export default {
5
+ MAIN_CONTAINER_CLASS,
6
+ PIE_TOOLBAR__CLASS,
7
+ };