@zipify/wysiwyg 1.0.0-dev.4 → 1.0.0-dev.5
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/.release-it.json +0 -1
- package/README.md +3 -1
- package/config/jest/setupTests.js +3 -1
- package/example/ExampleApp.vue +39 -31
- package/example/example.js +26 -0
- package/example/presets.js +2 -0
- package/lib/Wysiwyg.vue +6 -0
- package/lib/composables/__tests__/useEditor.test.js +12 -3
- package/lib/composables/useEditor.js +12 -5
- package/lib/extensions/Alignment.js +6 -0
- package/lib/extensions/BackgroundColor.js +8 -1
- package/lib/extensions/FontColor.js +8 -1
- package/lib/extensions/FontFamily.js +7 -0
- package/lib/extensions/FontSize.js +12 -0
- package/lib/extensions/FontStyle.js +11 -0
- package/lib/extensions/FontWeight.js +25 -1
- package/lib/extensions/LineHeight.js +17 -0
- package/lib/extensions/StylePreset.js +30 -3
- package/lib/extensions/TextDecoration.js +11 -0
- package/lib/extensions/__tests__/Alignment.test.js +22 -1
- package/lib/extensions/__tests__/BackgroundColor.test.js +30 -1
- package/lib/extensions/__tests__/CaseStyle.test.js +4 -1
- package/lib/extensions/__tests__/FontColor.test.js +30 -1
- package/lib/extensions/__tests__/FontFamily.test.js +30 -1
- package/lib/extensions/__tests__/FontSize.test.js +30 -1
- package/lib/extensions/__tests__/FontStyle.test.js +38 -1
- package/lib/extensions/__tests__/FontWeight.test.js +58 -1
- package/lib/extensions/__tests__/LineHeight.test.js +41 -1
- package/lib/extensions/__tests__/StylePreset.test.js +76 -1
- package/lib/extensions/__tests__/TextDecoration.test.js +63 -1
- package/lib/extensions/__tests__/__snapshots__/Alignment.test.js.snap +44 -0
- package/lib/extensions/__tests__/__snapshots__/BackgroundColor.test.js.snap +91 -0
- package/lib/extensions/__tests__/__snapshots__/FontColor.test.js.snap +91 -0
- package/lib/extensions/__tests__/__snapshots__/FontFamily.test.js.snap +91 -0
- package/lib/extensions/__tests__/__snapshots__/FontSize.test.js.snap +99 -0
- package/lib/extensions/__tests__/__snapshots__/FontStyle.test.js.snap +120 -0
- package/lib/extensions/__tests__/__snapshots__/FontWeight.test.js.snap +149 -0
- package/lib/extensions/__tests__/__snapshots__/LineHeight.test.js.snap +92 -0
- package/lib/extensions/__tests__/__snapshots__/StylePreset.test.js.snap +167 -2
- package/lib/extensions/__tests__/__snapshots__/TextDecoration.test.js.snap +207 -0
- package/lib/extensions/core/__tests__/NodeProcessor.test.js +4 -1
- package/lib/extensions/core/__tests__/SelectionProcessor.test.js +9 -4
- package/lib/extensions/core/__tests__/TextProcessor.test.js +4 -1
- package/lib/extensions/index.js +1 -0
- package/lib/extensions/list/List.js +34 -0
- package/lib/extensions/list/__tests__/List.test.js +115 -3
- package/lib/extensions/list/__tests__/__snapshots__/List.test.js.snap +457 -6
- package/lib/services/ContentNormalizer.js +113 -0
- package/lib/services/Storage.js +1 -13
- package/lib/services/__tests__/ContentNormalizer.test.js +41 -0
- package/lib/services/__tests__/FavoriteColors.test.js +20 -0
- package/lib/services/__tests__/JsonSerializer.test.js +23 -0
- package/lib/services/__tests__/Storage.test.js +79 -0
- package/lib/services/index.js +1 -0
- package/lib/utils/__tests__/convertColor.test.js +19 -0
- package/lib/utils/__tests__/createKeyboardShortcut.test.js +25 -0
- package/lib/utils/__tests__/renderInlineSetting.test.js +26 -0
- package/lib/utils/convertColor.js +7 -0
- package/lib/utils/index.js +1 -0
- package/lib/utils/renderInlineSetting.js +1 -1
- package/package.json +1 -1
|
@@ -92,9 +92,7 @@ Object {
|
|
|
92
92
|
"content": Array [
|
|
93
93
|
Object {
|
|
94
94
|
"attrs": Object {
|
|
95
|
-
"preset":
|
|
96
|
-
"id": "regular-1",
|
|
97
|
-
},
|
|
95
|
+
"preset": null,
|
|
98
96
|
},
|
|
99
97
|
"content": Array [
|
|
100
98
|
Object {
|
|
@@ -106,9 +104,7 @@ Object {
|
|
|
106
104
|
},
|
|
107
105
|
Object {
|
|
108
106
|
"attrs": Object {
|
|
109
|
-
"preset":
|
|
110
|
-
"id": "regular-1",
|
|
111
|
-
},
|
|
107
|
+
"preset": null,
|
|
112
108
|
},
|
|
113
109
|
"content": Array [
|
|
114
110
|
Object {
|
|
@@ -210,3 +206,458 @@ Object {
|
|
|
210
206
|
"type": "doc",
|
|
211
207
|
}
|
|
212
208
|
`;
|
|
209
|
+
|
|
210
|
+
exports[`parsing html should parse circle type by class 1`] = `
|
|
211
|
+
Object {
|
|
212
|
+
"content": Array [
|
|
213
|
+
Object {
|
|
214
|
+
"attrs": Object {
|
|
215
|
+
"bullet": Object {
|
|
216
|
+
"type": "circle",
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
"content": Array [
|
|
220
|
+
Object {
|
|
221
|
+
"content": Array [
|
|
222
|
+
Object {
|
|
223
|
+
"attrs": Object {
|
|
224
|
+
"preset": null,
|
|
225
|
+
},
|
|
226
|
+
"content": Array [
|
|
227
|
+
Object {
|
|
228
|
+
"text": "lorem ipsum",
|
|
229
|
+
"type": "text",
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
"type": "paragraph",
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
"type": "listItem",
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
"type": "list",
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
"type": "doc",
|
|
242
|
+
}
|
|
243
|
+
`;
|
|
244
|
+
|
|
245
|
+
exports[`parsing html should parse decimal as default 1`] = `
|
|
246
|
+
Object {
|
|
247
|
+
"content": Array [
|
|
248
|
+
Object {
|
|
249
|
+
"attrs": Object {
|
|
250
|
+
"bullet": Object {
|
|
251
|
+
"type": "decimal",
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
"content": Array [
|
|
255
|
+
Object {
|
|
256
|
+
"content": Array [
|
|
257
|
+
Object {
|
|
258
|
+
"attrs": Object {
|
|
259
|
+
"preset": null,
|
|
260
|
+
},
|
|
261
|
+
"content": Array [
|
|
262
|
+
Object {
|
|
263
|
+
"text": "lorem ipsum",
|
|
264
|
+
"type": "text",
|
|
265
|
+
},
|
|
266
|
+
],
|
|
267
|
+
"type": "paragraph",
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
"type": "listItem",
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
"type": "list",
|
|
274
|
+
},
|
|
275
|
+
],
|
|
276
|
+
"type": "doc",
|
|
277
|
+
}
|
|
278
|
+
`;
|
|
279
|
+
|
|
280
|
+
exports[`parsing html should parse decimal type by attribute 1`] = `
|
|
281
|
+
Object {
|
|
282
|
+
"content": Array [
|
|
283
|
+
Object {
|
|
284
|
+
"attrs": Object {
|
|
285
|
+
"bullet": Object {
|
|
286
|
+
"type": "decimal",
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
"content": Array [
|
|
290
|
+
Object {
|
|
291
|
+
"content": Array [
|
|
292
|
+
Object {
|
|
293
|
+
"attrs": Object {
|
|
294
|
+
"preset": null,
|
|
295
|
+
},
|
|
296
|
+
"content": Array [
|
|
297
|
+
Object {
|
|
298
|
+
"text": "lorem ipsum",
|
|
299
|
+
"type": "text",
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
"type": "paragraph",
|
|
303
|
+
},
|
|
304
|
+
],
|
|
305
|
+
"type": "listItem",
|
|
306
|
+
},
|
|
307
|
+
],
|
|
308
|
+
"type": "list",
|
|
309
|
+
},
|
|
310
|
+
],
|
|
311
|
+
"type": "doc",
|
|
312
|
+
}
|
|
313
|
+
`;
|
|
314
|
+
|
|
315
|
+
exports[`parsing html should parse decimal type by class 1`] = `
|
|
316
|
+
Object {
|
|
317
|
+
"content": Array [
|
|
318
|
+
Object {
|
|
319
|
+
"attrs": Object {
|
|
320
|
+
"bullet": Object {
|
|
321
|
+
"type": "decimal",
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
"content": Array [
|
|
325
|
+
Object {
|
|
326
|
+
"content": Array [
|
|
327
|
+
Object {
|
|
328
|
+
"attrs": Object {
|
|
329
|
+
"preset": null,
|
|
330
|
+
},
|
|
331
|
+
"content": Array [
|
|
332
|
+
Object {
|
|
333
|
+
"text": "lorem ipsum",
|
|
334
|
+
"type": "text",
|
|
335
|
+
},
|
|
336
|
+
],
|
|
337
|
+
"type": "paragraph",
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
"type": "listItem",
|
|
341
|
+
},
|
|
342
|
+
],
|
|
343
|
+
"type": "list",
|
|
344
|
+
},
|
|
345
|
+
],
|
|
346
|
+
"type": "doc",
|
|
347
|
+
}
|
|
348
|
+
`;
|
|
349
|
+
|
|
350
|
+
exports[`parsing html should parse disc as default 1`] = `
|
|
351
|
+
Object {
|
|
352
|
+
"content": Array [
|
|
353
|
+
Object {
|
|
354
|
+
"attrs": Object {
|
|
355
|
+
"bullet": Object {
|
|
356
|
+
"type": "disc",
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
"content": Array [
|
|
360
|
+
Object {
|
|
361
|
+
"content": Array [
|
|
362
|
+
Object {
|
|
363
|
+
"attrs": Object {
|
|
364
|
+
"preset": null,
|
|
365
|
+
},
|
|
366
|
+
"content": Array [
|
|
367
|
+
Object {
|
|
368
|
+
"text": "lorem ipsum",
|
|
369
|
+
"type": "text",
|
|
370
|
+
},
|
|
371
|
+
],
|
|
372
|
+
"type": "paragraph",
|
|
373
|
+
},
|
|
374
|
+
],
|
|
375
|
+
"type": "listItem",
|
|
376
|
+
},
|
|
377
|
+
],
|
|
378
|
+
"type": "list",
|
|
379
|
+
},
|
|
380
|
+
],
|
|
381
|
+
"type": "doc",
|
|
382
|
+
}
|
|
383
|
+
`;
|
|
384
|
+
|
|
385
|
+
exports[`parsing html should parse disc type by class 1`] = `
|
|
386
|
+
Object {
|
|
387
|
+
"content": Array [
|
|
388
|
+
Object {
|
|
389
|
+
"attrs": Object {
|
|
390
|
+
"bullet": Object {
|
|
391
|
+
"type": "disc",
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
"content": Array [
|
|
395
|
+
Object {
|
|
396
|
+
"content": Array [
|
|
397
|
+
Object {
|
|
398
|
+
"attrs": Object {
|
|
399
|
+
"preset": null,
|
|
400
|
+
},
|
|
401
|
+
"content": Array [
|
|
402
|
+
Object {
|
|
403
|
+
"text": "lorem ipsum",
|
|
404
|
+
"type": "text",
|
|
405
|
+
},
|
|
406
|
+
],
|
|
407
|
+
"type": "paragraph",
|
|
408
|
+
},
|
|
409
|
+
],
|
|
410
|
+
"type": "listItem",
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
"type": "list",
|
|
414
|
+
},
|
|
415
|
+
],
|
|
416
|
+
"type": "doc",
|
|
417
|
+
}
|
|
418
|
+
`;
|
|
419
|
+
|
|
420
|
+
exports[`parsing html should parse latin type by class 1`] = `
|
|
421
|
+
Object {
|
|
422
|
+
"content": Array [
|
|
423
|
+
Object {
|
|
424
|
+
"attrs": Object {
|
|
425
|
+
"bullet": Object {
|
|
426
|
+
"type": "latin",
|
|
427
|
+
},
|
|
428
|
+
},
|
|
429
|
+
"content": Array [
|
|
430
|
+
Object {
|
|
431
|
+
"content": Array [
|
|
432
|
+
Object {
|
|
433
|
+
"attrs": Object {
|
|
434
|
+
"preset": null,
|
|
435
|
+
},
|
|
436
|
+
"content": Array [
|
|
437
|
+
Object {
|
|
438
|
+
"text": "lorem ipsum",
|
|
439
|
+
"type": "text",
|
|
440
|
+
},
|
|
441
|
+
],
|
|
442
|
+
"type": "paragraph",
|
|
443
|
+
},
|
|
444
|
+
],
|
|
445
|
+
"type": "listItem",
|
|
446
|
+
},
|
|
447
|
+
],
|
|
448
|
+
"type": "list",
|
|
449
|
+
},
|
|
450
|
+
],
|
|
451
|
+
"type": "doc",
|
|
452
|
+
}
|
|
453
|
+
`;
|
|
454
|
+
|
|
455
|
+
exports[`parsing html should parse latin type by lower attribute 1`] = `
|
|
456
|
+
Object {
|
|
457
|
+
"content": Array [
|
|
458
|
+
Object {
|
|
459
|
+
"attrs": Object {
|
|
460
|
+
"bullet": Object {
|
|
461
|
+
"type": "latin",
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
"content": Array [
|
|
465
|
+
Object {
|
|
466
|
+
"content": Array [
|
|
467
|
+
Object {
|
|
468
|
+
"attrs": Object {
|
|
469
|
+
"preset": null,
|
|
470
|
+
},
|
|
471
|
+
"content": Array [
|
|
472
|
+
Object {
|
|
473
|
+
"text": "lorem ipsum",
|
|
474
|
+
"type": "text",
|
|
475
|
+
},
|
|
476
|
+
],
|
|
477
|
+
"type": "paragraph",
|
|
478
|
+
},
|
|
479
|
+
],
|
|
480
|
+
"type": "listItem",
|
|
481
|
+
},
|
|
482
|
+
],
|
|
483
|
+
"type": "list",
|
|
484
|
+
},
|
|
485
|
+
],
|
|
486
|
+
"type": "doc",
|
|
487
|
+
}
|
|
488
|
+
`;
|
|
489
|
+
|
|
490
|
+
exports[`parsing html should parse latin type by upper attribute 1`] = `
|
|
491
|
+
Object {
|
|
492
|
+
"content": Array [
|
|
493
|
+
Object {
|
|
494
|
+
"attrs": Object {
|
|
495
|
+
"bullet": Object {
|
|
496
|
+
"type": "latin",
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
"content": Array [
|
|
500
|
+
Object {
|
|
501
|
+
"content": Array [
|
|
502
|
+
Object {
|
|
503
|
+
"attrs": Object {
|
|
504
|
+
"preset": null,
|
|
505
|
+
},
|
|
506
|
+
"content": Array [
|
|
507
|
+
Object {
|
|
508
|
+
"text": "lorem ipsum",
|
|
509
|
+
"type": "text",
|
|
510
|
+
},
|
|
511
|
+
],
|
|
512
|
+
"type": "paragraph",
|
|
513
|
+
},
|
|
514
|
+
],
|
|
515
|
+
"type": "listItem",
|
|
516
|
+
},
|
|
517
|
+
],
|
|
518
|
+
"type": "list",
|
|
519
|
+
},
|
|
520
|
+
],
|
|
521
|
+
"type": "doc",
|
|
522
|
+
}
|
|
523
|
+
`;
|
|
524
|
+
|
|
525
|
+
exports[`parsing html should parse roman type by class 1`] = `
|
|
526
|
+
Object {
|
|
527
|
+
"content": Array [
|
|
528
|
+
Object {
|
|
529
|
+
"attrs": Object {
|
|
530
|
+
"bullet": Object {
|
|
531
|
+
"type": "roman",
|
|
532
|
+
},
|
|
533
|
+
},
|
|
534
|
+
"content": Array [
|
|
535
|
+
Object {
|
|
536
|
+
"content": Array [
|
|
537
|
+
Object {
|
|
538
|
+
"attrs": Object {
|
|
539
|
+
"preset": null,
|
|
540
|
+
},
|
|
541
|
+
"content": Array [
|
|
542
|
+
Object {
|
|
543
|
+
"text": "lorem ipsum",
|
|
544
|
+
"type": "text",
|
|
545
|
+
},
|
|
546
|
+
],
|
|
547
|
+
"type": "paragraph",
|
|
548
|
+
},
|
|
549
|
+
],
|
|
550
|
+
"type": "listItem",
|
|
551
|
+
},
|
|
552
|
+
],
|
|
553
|
+
"type": "list",
|
|
554
|
+
},
|
|
555
|
+
],
|
|
556
|
+
"type": "doc",
|
|
557
|
+
}
|
|
558
|
+
`;
|
|
559
|
+
|
|
560
|
+
exports[`parsing html should parse roman type by lower attribute 1`] = `
|
|
561
|
+
Object {
|
|
562
|
+
"content": Array [
|
|
563
|
+
Object {
|
|
564
|
+
"attrs": Object {
|
|
565
|
+
"bullet": Object {
|
|
566
|
+
"type": "roman",
|
|
567
|
+
},
|
|
568
|
+
},
|
|
569
|
+
"content": Array [
|
|
570
|
+
Object {
|
|
571
|
+
"content": Array [
|
|
572
|
+
Object {
|
|
573
|
+
"attrs": Object {
|
|
574
|
+
"preset": null,
|
|
575
|
+
},
|
|
576
|
+
"content": Array [
|
|
577
|
+
Object {
|
|
578
|
+
"text": "lorem ipsum",
|
|
579
|
+
"type": "text",
|
|
580
|
+
},
|
|
581
|
+
],
|
|
582
|
+
"type": "paragraph",
|
|
583
|
+
},
|
|
584
|
+
],
|
|
585
|
+
"type": "listItem",
|
|
586
|
+
},
|
|
587
|
+
],
|
|
588
|
+
"type": "list",
|
|
589
|
+
},
|
|
590
|
+
],
|
|
591
|
+
"type": "doc",
|
|
592
|
+
}
|
|
593
|
+
`;
|
|
594
|
+
|
|
595
|
+
exports[`parsing html should parse roman type by upper attribute 1`] = `
|
|
596
|
+
Object {
|
|
597
|
+
"content": Array [
|
|
598
|
+
Object {
|
|
599
|
+
"attrs": Object {
|
|
600
|
+
"bullet": Object {
|
|
601
|
+
"type": "roman",
|
|
602
|
+
},
|
|
603
|
+
},
|
|
604
|
+
"content": Array [
|
|
605
|
+
Object {
|
|
606
|
+
"content": Array [
|
|
607
|
+
Object {
|
|
608
|
+
"attrs": Object {
|
|
609
|
+
"preset": null,
|
|
610
|
+
},
|
|
611
|
+
"content": Array [
|
|
612
|
+
Object {
|
|
613
|
+
"text": "lorem ipsum",
|
|
614
|
+
"type": "text",
|
|
615
|
+
},
|
|
616
|
+
],
|
|
617
|
+
"type": "paragraph",
|
|
618
|
+
},
|
|
619
|
+
],
|
|
620
|
+
"type": "listItem",
|
|
621
|
+
},
|
|
622
|
+
],
|
|
623
|
+
"type": "list",
|
|
624
|
+
},
|
|
625
|
+
],
|
|
626
|
+
"type": "doc",
|
|
627
|
+
}
|
|
628
|
+
`;
|
|
629
|
+
|
|
630
|
+
exports[`parsing html should parse square type by class 1`] = `
|
|
631
|
+
Object {
|
|
632
|
+
"content": Array [
|
|
633
|
+
Object {
|
|
634
|
+
"attrs": Object {
|
|
635
|
+
"bullet": Object {
|
|
636
|
+
"type": "square",
|
|
637
|
+
},
|
|
638
|
+
},
|
|
639
|
+
"content": Array [
|
|
640
|
+
Object {
|
|
641
|
+
"content": Array [
|
|
642
|
+
Object {
|
|
643
|
+
"attrs": Object {
|
|
644
|
+
"preset": null,
|
|
645
|
+
},
|
|
646
|
+
"content": Array [
|
|
647
|
+
Object {
|
|
648
|
+
"text": "lorem ipsum",
|
|
649
|
+
"type": "text",
|
|
650
|
+
},
|
|
651
|
+
],
|
|
652
|
+
"type": "paragraph",
|
|
653
|
+
},
|
|
654
|
+
],
|
|
655
|
+
"type": "listItem",
|
|
656
|
+
},
|
|
657
|
+
],
|
|
658
|
+
"type": "list",
|
|
659
|
+
},
|
|
660
|
+
],
|
|
661
|
+
"type": "doc",
|
|
662
|
+
}
|
|
663
|
+
`;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export class ContentNormalizer {
|
|
2
|
+
static NORMALIZING_STYLE_BLACKLIST = ['text-align', 'line-height'];
|
|
3
|
+
|
|
4
|
+
normalize(content) {
|
|
5
|
+
if (typeof content !== 'string') return content;
|
|
6
|
+
|
|
7
|
+
return this._normalizeTextContent(content);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
_normalizeTextContent(content) {
|
|
11
|
+
const parser = new DOMParser();
|
|
12
|
+
const dom = parser.parseFromString(content, 'text/html');
|
|
13
|
+
|
|
14
|
+
this._iterateNodes(dom, this._normalizeStructure.bind(this), (node) => node.tagName === 'SPAN');
|
|
15
|
+
this._iterateNodes(dom, this._normalizeStyles.bind(this), (node) => node.tagName !== 'SPAN');
|
|
16
|
+
|
|
17
|
+
return dom.body.innerHTML;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_iterateNodes(dom, handler, condition) {
|
|
21
|
+
const iterator = dom.createNodeIterator(dom.body, NodeFilter.SHOW_ELEMENT, {
|
|
22
|
+
acceptNode: (node) => condition(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT
|
|
23
|
+
});
|
|
24
|
+
let currentNode = iterator.nextNode();
|
|
25
|
+
|
|
26
|
+
while (currentNode) {
|
|
27
|
+
handler(currentNode);
|
|
28
|
+
currentNode = iterator.nextNode();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
_normalizeStructure(element) {
|
|
33
|
+
const isTextChildren = Array.from(element.childNodes)
|
|
34
|
+
.every((node) => node.nodeType === Node.TEXT_NODE);
|
|
35
|
+
|
|
36
|
+
if (isTextChildren) return;
|
|
37
|
+
|
|
38
|
+
const cloned = element.cloneNode(true);
|
|
39
|
+
const migratingStyles = this._getMigratingStyles(element);
|
|
40
|
+
const content = [];
|
|
41
|
+
|
|
42
|
+
for (const node of cloned.childNodes) {
|
|
43
|
+
let child = node;
|
|
44
|
+
|
|
45
|
+
if (migratingStyles.length) {
|
|
46
|
+
child = this._wrapTextNode(cloned, node);
|
|
47
|
+
this._assignElementProperties(child, cloned, migratingStyles);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
content.push(child);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
element.replaceWith(...content);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
_normalizeStyles(element) {
|
|
57
|
+
const properties = this._getMigratingStyles(element);
|
|
58
|
+
|
|
59
|
+
for (const node of element.childNodes) {
|
|
60
|
+
const child = this._wrapTextNode(element, node);
|
|
61
|
+
|
|
62
|
+
this._assignElementProperties(child, element, properties);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this._removeStyleProperties(element, properties);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
_getMigratingStyles(element) {
|
|
69
|
+
const blacklist = ContentNormalizer.NORMALIZING_STYLE_BLACKLIST;
|
|
70
|
+
const properties = [];
|
|
71
|
+
|
|
72
|
+
for (let index = 0; index < element.style.length; index++) {
|
|
73
|
+
const property = element.style.item(index);
|
|
74
|
+
|
|
75
|
+
if (!blacklist.includes(property)) {
|
|
76
|
+
properties.push(property);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return properties;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
_wrapTextNode(parent, node) {
|
|
84
|
+
if (node.nodeType !== Node.TEXT_NODE) return node;
|
|
85
|
+
|
|
86
|
+
const span = document.createElement('span');
|
|
87
|
+
|
|
88
|
+
span.append(node.cloneNode());
|
|
89
|
+
parent.replaceChild(span, node);
|
|
90
|
+
|
|
91
|
+
return span;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
_assignElementProperties(target, source, properties) {
|
|
95
|
+
for (const property of properties) {
|
|
96
|
+
if (target.style.getPropertyValue(property)) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
target.style.setProperty(property, source.style.getPropertyValue(property));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
_removeStyleProperties(element, properties) {
|
|
105
|
+
for (const property of properties) {
|
|
106
|
+
element.style.removeProperty(property);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (element.style.length === 0) {
|
|
110
|
+
element.removeAttribute('style');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
package/lib/services/Storage.js
CHANGED
|
@@ -17,19 +17,11 @@ export class Storage {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
getItem(key) {
|
|
20
|
-
const json = this.
|
|
20
|
+
const json = this.accessToStorage((storage) => storage.getItem(this.makeKey(key)));
|
|
21
21
|
|
|
22
22
|
return JsonSerializer.decode(json);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
removeItem(key) {
|
|
26
|
-
this.accessToStorage((storage) => storage.removeItem(this.makeKey(key)));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
hasItem(key) {
|
|
30
|
-
return !!this._getItemFromStorage(key);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
25
|
accessToStorage(action) {
|
|
34
26
|
try {
|
|
35
27
|
return action(this.nativeStorage);
|
|
@@ -38,10 +30,6 @@ export class Storage {
|
|
|
38
30
|
}
|
|
39
31
|
}
|
|
40
32
|
|
|
41
|
-
_getItemFromStorage(key) {
|
|
42
|
-
return this.accessToStorage((storage) => storage.getItem(this.makeKey(key)));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
33
|
onPrivateModeEnabled(error) {
|
|
46
34
|
// eslint-disable-next-line no-console
|
|
47
35
|
console.error(error);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ContentNormalizer } from '../ContentNormalizer';
|
|
2
|
+
import { NodeFactory } from '../../__tests__/utils';
|
|
3
|
+
|
|
4
|
+
const normalize = (content) => new ContentNormalizer().normalize(content);
|
|
5
|
+
|
|
6
|
+
describe('normalize text settings', () => {
|
|
7
|
+
test('should ignore json content', () => {
|
|
8
|
+
const content = NodeFactory.doc([NodeFactory.paragraph('Test')]);
|
|
9
|
+
|
|
10
|
+
expect(normalize(content)).toBe(content);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test('should flat structure', () => {
|
|
14
|
+
const input = '<p style="text-align: center; color: rgb(255, 255, 255);"><span style="background-color: rgb(255, 0, 0);">lore<span style="color: rgb(0, 0, 0);">m ip</span>sum</span></p>';
|
|
15
|
+
const output = '<p style="text-align: center;">' +
|
|
16
|
+
'<span style="background-color: rgb(255, 0, 0); color: rgb(255, 255, 255);">lore</span>' +
|
|
17
|
+
'<span style="color: rgb(0, 0, 0); background-color: rgb(255, 0, 0);">m ip</span>' +
|
|
18
|
+
'<span style="background-color: rgb(255, 0, 0); color: rgb(255, 255, 255);">sum</span>' +
|
|
19
|
+
'</p>';
|
|
20
|
+
|
|
21
|
+
expect(normalize(input)).toBe(output);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('should move styles from paragraph to text', () => {
|
|
25
|
+
const input = '<p style="background-color: red;">lorem ipsum</p>';
|
|
26
|
+
const output = '<p><span style="background-color: red;">lorem ipsum</span></p>';
|
|
27
|
+
|
|
28
|
+
expect(normalize(input)).toBe(output);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('should move styles from paragraph to unstyled text', () => {
|
|
32
|
+
const input = '<p style="background-color: red;"><span style="background-color: #000;">lorem</span> ipsum <span style="color: white;">one</span></p>';
|
|
33
|
+
const output = '<p>' +
|
|
34
|
+
'<span style="background-color: #000;">lorem</span>' +
|
|
35
|
+
'<span style="background-color: red;"> ipsum </span>' +
|
|
36
|
+
'<span style="color: white; background-color: red;">one</span' +
|
|
37
|
+
'></p>';
|
|
38
|
+
|
|
39
|
+
expect(normalize(input)).toBe(output);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ref } from '@vue/composition-api';
|
|
2
|
+
import { FavoriteColors } from '../FavoriteColors';
|
|
3
|
+
|
|
4
|
+
function createService({ colors, onUpdate }) {
|
|
5
|
+
return new FavoriteColors({
|
|
6
|
+
listRef: ref(colors ?? []),
|
|
7
|
+
triggerUpdate: onUpdate
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('trigger update', () => {
|
|
12
|
+
test('should trigger colors update', () => {
|
|
13
|
+
const onUpdate = jest.fn();
|
|
14
|
+
const service = createService({ onUpdate });
|
|
15
|
+
|
|
16
|
+
service.triggerUpdate(['red']);
|
|
17
|
+
|
|
18
|
+
expect(onUpdate).toHaveBeenCalledWith(['red']);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { JsonSerializer } from '../JsonSerializer';
|
|
2
|
+
|
|
3
|
+
describe('decode', () => {
|
|
4
|
+
test('should decode json', () => {
|
|
5
|
+
const json = JsonSerializer.decode('{ "test": 1 }');
|
|
6
|
+
|
|
7
|
+
expect(json).toEqual({ test: 1 });
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test('should return null on error', () => {
|
|
11
|
+
const json = JsonSerializer.decode('{ "tes');
|
|
12
|
+
|
|
13
|
+
expect(json).toBe(null);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('encode', () => {
|
|
18
|
+
test('should encode object to json', () => {
|
|
19
|
+
const json = JsonSerializer.encode({ test: 1 });
|
|
20
|
+
|
|
21
|
+
expect(json).toBe('{"test":1}');
|
|
22
|
+
});
|
|
23
|
+
});
|