rich-html-editor 0.2.1 → 1.0.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.
- package/README.md +17 -5
- package/dist/{chunk-ZDGUOGND.mjs → chunk-W3ULZ2LR.mjs} +23 -1
- package/dist/chunk-W3ULZ2LR.mjs.map +1 -0
- package/dist/index.js +413 -218
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +394 -219
- package/dist/index.mjs.map +1 -1
- package/dist/{state-CZIMHTJ3.mjs → state-DA3PGFTN.mjs} +2 -2
- package/package.json +2 -2
- package/dist/chunk-ZDGUOGND.mjs.map +0 -1
- /package/dist/{state-CZIMHTJ3.mjs.map → state-DA3PGFTN.mjs.map} +0 -0
package/dist/index.mjs
CHANGED
|
@@ -16,10 +16,12 @@ import {
|
|
|
16
16
|
LABEL_BOLD,
|
|
17
17
|
LABEL_ITALIC,
|
|
18
18
|
LABEL_LINK,
|
|
19
|
+
LABEL_ORDERED_LIST,
|
|
19
20
|
LABEL_REDO,
|
|
20
21
|
LABEL_STRIKETHROUGH,
|
|
21
22
|
LABEL_UNDERLINE,
|
|
22
23
|
LABEL_UNDO,
|
|
24
|
+
LABEL_UNORDERED_LIST,
|
|
23
25
|
SIZE_OPTIONS,
|
|
24
26
|
STYLE_ID,
|
|
25
27
|
TOOLBAR_BG,
|
|
@@ -37,7 +39,7 @@ import {
|
|
|
37
39
|
getEditorEventEmitter,
|
|
38
40
|
pushStandaloneSnapshot,
|
|
39
41
|
sanitizeHtml
|
|
40
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-W3ULZ2LR.mjs";
|
|
41
43
|
|
|
42
44
|
// src/dom/styles.ts
|
|
43
45
|
function injectStyles(doc) {
|
|
@@ -317,218 +319,73 @@ function injectStyles(doc) {
|
|
|
317
319
|
styleEl.textContent = css;
|
|
318
320
|
}
|
|
319
321
|
|
|
320
|
-
// src/toolbar/
|
|
321
|
-
function
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
322
|
+
// src/toolbar/color.ts
|
|
323
|
+
function makeColorInput(doc, options, title, command, initialColor) {
|
|
324
|
+
const input = doc.createElement("input");
|
|
325
|
+
input.type = "color";
|
|
326
|
+
input.className = "toolbar-color-input";
|
|
327
|
+
const wrapper = doc.createElement("label");
|
|
328
|
+
wrapper.className = "color-label";
|
|
329
|
+
wrapper.appendChild(doc.createTextNode(title + " "));
|
|
330
|
+
wrapper.appendChild(input);
|
|
331
|
+
let savedRange = null;
|
|
332
|
+
input.addEventListener("pointerdown", () => {
|
|
333
|
+
const s = doc.getSelection();
|
|
334
|
+
if (s && s.rangeCount) savedRange = s.getRangeAt(0).cloneRange();
|
|
335
|
+
});
|
|
336
|
+
input.onchange = (e) => {
|
|
337
|
+
try {
|
|
338
|
+
const s = doc.getSelection();
|
|
339
|
+
if (savedRange && s) {
|
|
340
|
+
s.removeAllRanges();
|
|
341
|
+
s.addRange(savedRange);
|
|
342
|
+
}
|
|
343
|
+
} catch (err) {
|
|
335
344
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
ev.preventDefault();
|
|
346
|
-
btn.click();
|
|
345
|
+
options.onCommand(command, e.target.value);
|
|
346
|
+
savedRange = null;
|
|
347
|
+
};
|
|
348
|
+
function rgbToHex(input2) {
|
|
349
|
+
if (!input2) return null;
|
|
350
|
+
const v = input2.trim();
|
|
351
|
+
if (v.startsWith("#")) {
|
|
352
|
+
if (v.length === 4) {
|
|
353
|
+
return ("#" + v[1] + v[1] + v[2] + v[2] + v[3] + v[3]).toLowerCase();
|
|
347
354
|
}
|
|
348
|
-
|
|
349
|
-
return btn;
|
|
350
|
-
}
|
|
351
|
-
function makeSelect(title, command, optionsList, initialValue) {
|
|
352
|
-
const select = doc.createElement("select");
|
|
353
|
-
select.title = title;
|
|
354
|
-
select.setAttribute("aria-label", title);
|
|
355
|
-
select.appendChild(new Option(title, "", true, true));
|
|
356
|
-
for (const opt of optionsList) {
|
|
357
|
-
select.appendChild(new Option(opt.label, opt.value));
|
|
355
|
+
return v.toLowerCase();
|
|
358
356
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
357
|
+
const rgbMatch = v.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/i);
|
|
358
|
+
if (rgbMatch) {
|
|
359
|
+
const r = Number(rgbMatch[1]);
|
|
360
|
+
const g = Number(rgbMatch[2]);
|
|
361
|
+
const b = Number(rgbMatch[3]);
|
|
362
|
+
const hex = "#" + [r, g, b].map((n) => n.toString(16).padStart(2, "0")).join("").toLowerCase();
|
|
363
|
+
return hex;
|
|
362
364
|
}
|
|
363
|
-
|
|
364
|
-
const val = e.target.value;
|
|
365
|
-
options.onCommand(command, val);
|
|
366
|
-
select.selectedIndex = 0;
|
|
367
|
-
};
|
|
368
|
-
return select;
|
|
365
|
+
return null;
|
|
369
366
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
wrapper.appendChild(doc.createTextNode(title + " "));
|
|
377
|
-
wrapper.appendChild(input);
|
|
378
|
-
let savedRange = null;
|
|
379
|
-
input.addEventListener("pointerdown", () => {
|
|
380
|
-
const s = doc.getSelection();
|
|
381
|
-
if (s && s.rangeCount) savedRange = s.getRangeAt(0).cloneRange();
|
|
382
|
-
});
|
|
383
|
-
input.onchange = (e) => {
|
|
384
|
-
try {
|
|
385
|
-
const s = doc.getSelection();
|
|
386
|
-
if (savedRange && s) {
|
|
387
|
-
s.removeAllRanges();
|
|
388
|
-
s.addRange(savedRange);
|
|
389
|
-
}
|
|
390
|
-
} catch (err) {
|
|
391
|
-
}
|
|
392
|
-
options.onCommand(command, e.target.value);
|
|
393
|
-
savedRange = null;
|
|
394
|
-
};
|
|
395
|
-
function rgbToHex(input2) {
|
|
396
|
-
if (!input2) return null;
|
|
397
|
-
const v = input2.trim();
|
|
398
|
-
if (v.startsWith("#")) {
|
|
399
|
-
if (v.length === 4) {
|
|
400
|
-
return ("#" + v[1] + v[1] + v[2] + v[2] + v[3] + v[3]).toLowerCase();
|
|
401
|
-
}
|
|
402
|
-
return v.toLowerCase();
|
|
403
|
-
}
|
|
404
|
-
const rgbMatch = v.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/i);
|
|
405
|
-
if (rgbMatch) {
|
|
406
|
-
const r = Number(rgbMatch[1]);
|
|
407
|
-
const g = Number(rgbMatch[2]);
|
|
408
|
-
const b = Number(rgbMatch[3]);
|
|
409
|
-
const hex = "#" + [r, g, b].map((n) => n.toString(16).padStart(2, "0")).join("").toLowerCase();
|
|
410
|
-
return hex;
|
|
367
|
+
const setColor = (val) => {
|
|
368
|
+
if (!val) return;
|
|
369
|
+
const hex = rgbToHex(val) || val;
|
|
370
|
+
try {
|
|
371
|
+
if (hex && hex.startsWith("#") && input.value !== hex) {
|
|
372
|
+
input.value = hex;
|
|
411
373
|
}
|
|
412
|
-
|
|
374
|
+
} catch (e) {
|
|
413
375
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
setColor(val);
|
|
428
|
-
});
|
|
429
|
-
input.title = title;
|
|
430
|
-
input.setAttribute("aria-label", title);
|
|
431
|
-
return wrapper;
|
|
432
|
-
}
|
|
433
|
-
const format = options.getFormatState();
|
|
434
|
-
function makeGroup() {
|
|
435
|
-
const g = doc.createElement("div");
|
|
436
|
-
g.className = "toolbar-group";
|
|
437
|
-
return g;
|
|
438
|
-
}
|
|
439
|
-
function makeSep() {
|
|
440
|
-
const s = doc.createElement("div");
|
|
441
|
-
s.className = "toolbar-sep";
|
|
442
|
-
return s;
|
|
443
|
-
}
|
|
444
|
-
const undoBtn = makeButton(
|
|
445
|
-
LABEL_UNDO,
|
|
446
|
-
"Undo",
|
|
447
|
-
"undo",
|
|
448
|
-
void 0,
|
|
449
|
-
false,
|
|
450
|
-
!options.canUndo()
|
|
451
|
-
);
|
|
452
|
-
undoBtn.onclick = () => options.onUndo();
|
|
453
|
-
const redoBtn = makeButton(
|
|
454
|
-
LABEL_REDO,
|
|
455
|
-
"Redo",
|
|
456
|
-
"redo",
|
|
457
|
-
void 0,
|
|
458
|
-
false,
|
|
459
|
-
!options.canRedo()
|
|
460
|
-
);
|
|
461
|
-
redoBtn.onclick = () => options.onRedo();
|
|
462
|
-
const grp1 = makeGroup();
|
|
463
|
-
grp1.appendChild(undoBtn);
|
|
464
|
-
grp1.appendChild(redoBtn);
|
|
465
|
-
toolbar.appendChild(grp1);
|
|
466
|
-
toolbar.appendChild(makeSep());
|
|
467
|
-
const grp2 = makeGroup();
|
|
468
|
-
grp2.className = "toolbar-group collapse-on-small";
|
|
469
|
-
grp2.appendChild(
|
|
470
|
-
makeSelect(
|
|
471
|
-
"Format",
|
|
472
|
-
"formatBlock",
|
|
473
|
-
FORMAT_OPTIONS,
|
|
474
|
-
format.formatBlock
|
|
475
|
-
)
|
|
476
|
-
);
|
|
477
|
-
grp2.appendChild(
|
|
478
|
-
makeSelect("Font", "fontName", FONT_OPTIONS, format.fontName)
|
|
479
|
-
);
|
|
480
|
-
grp2.appendChild(
|
|
481
|
-
makeSelect("Size", "fontSize", SIZE_OPTIONS, format.fontSize)
|
|
482
|
-
);
|
|
483
|
-
toolbar.appendChild(grp2);
|
|
484
|
-
toolbar.appendChild(makeSep());
|
|
485
|
-
const grp3 = makeGroup();
|
|
486
|
-
grp3.appendChild(
|
|
487
|
-
makeButton(LABEL_BOLD, "Bold", "bold", void 0, format.bold)
|
|
488
|
-
);
|
|
489
|
-
grp3.appendChild(
|
|
490
|
-
makeButton(LABEL_ITALIC, "Italic", "italic", void 0, format.italic)
|
|
491
|
-
);
|
|
492
|
-
grp3.appendChild(
|
|
493
|
-
makeButton(
|
|
494
|
-
LABEL_UNDERLINE,
|
|
495
|
-
"Underline",
|
|
496
|
-
"underline",
|
|
497
|
-
void 0,
|
|
498
|
-
format.underline
|
|
499
|
-
)
|
|
500
|
-
);
|
|
501
|
-
grp3.appendChild(makeButton(LABEL_STRIKETHROUGH, "Strikethrough", "strike"));
|
|
502
|
-
toolbar.appendChild(grp3);
|
|
503
|
-
toolbar.appendChild(makeSep());
|
|
504
|
-
const grp4 = makeGroup();
|
|
505
|
-
grp4.appendChild(makeButton(LABEL_ALIGN_LEFT, "Align left", "align", "left"));
|
|
506
|
-
grp4.appendChild(
|
|
507
|
-
makeButton(LABEL_ALIGN_CENTER, "Align center", "align", "center")
|
|
508
|
-
);
|
|
509
|
-
grp4.appendChild(
|
|
510
|
-
makeButton(LABEL_ALIGN_RIGHT, "Align right", "align", "right")
|
|
511
|
-
);
|
|
512
|
-
toolbar.appendChild(grp4);
|
|
513
|
-
toolbar.appendChild(makeSep());
|
|
514
|
-
const grp5 = makeGroup();
|
|
515
|
-
grp5.className = "toolbar-group collapse-on-small";
|
|
516
|
-
grp5.appendChild(
|
|
517
|
-
makeColorInput("Text color", "foreColor", format.foreColor)
|
|
518
|
-
);
|
|
519
|
-
grp5.appendChild(
|
|
520
|
-
makeColorInput(
|
|
521
|
-
"Highlight color",
|
|
522
|
-
"hiliteColor",
|
|
523
|
-
format.hiliteColor
|
|
524
|
-
)
|
|
525
|
-
);
|
|
526
|
-
toolbar.appendChild(grp5);
|
|
527
|
-
toolbar.appendChild(makeSep());
|
|
528
|
-
const grp6 = makeGroup();
|
|
529
|
-
grp6.className = "toolbar-group collapse-on-small";
|
|
530
|
-
grp6.appendChild(makeButton(LABEL_LINK, "Insert link", "link"));
|
|
531
|
-
toolbar.appendChild(grp6);
|
|
376
|
+
};
|
|
377
|
+
if (initialColor) setColor(initialColor);
|
|
378
|
+
input.addEventListener("input", (e) => {
|
|
379
|
+
const val = e.target.value;
|
|
380
|
+
setColor(val);
|
|
381
|
+
});
|
|
382
|
+
input.title = title;
|
|
383
|
+
input.setAttribute("aria-label", title);
|
|
384
|
+
return wrapper;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// src/toolbar/overflow.ts
|
|
388
|
+
function setupOverflow(doc, toolbar, options, format, helpers) {
|
|
532
389
|
const overflowBtn = doc.createElement("button");
|
|
533
390
|
overflowBtn.type = "button";
|
|
534
391
|
overflowBtn.className = "toolbar-overflow-btn";
|
|
@@ -555,7 +412,7 @@ function injectToolbar(doc, options) {
|
|
|
555
412
|
overflowBtn.setAttribute("aria-expanded", "false");
|
|
556
413
|
overflowBtn.focus();
|
|
557
414
|
}
|
|
558
|
-
overflowBtn.addEventListener("click", (
|
|
415
|
+
overflowBtn.addEventListener("click", () => {
|
|
559
416
|
if (overflowMenu.hidden) openOverflow();
|
|
560
417
|
else closeOverflow();
|
|
561
418
|
});
|
|
@@ -582,35 +439,105 @@ function injectToolbar(doc, options) {
|
|
|
582
439
|
}
|
|
583
440
|
});
|
|
584
441
|
overflowMenu.appendChild(
|
|
585
|
-
makeSelect(
|
|
442
|
+
helpers.makeSelect(
|
|
586
443
|
"Format",
|
|
587
444
|
"formatBlock",
|
|
588
|
-
|
|
445
|
+
window.RHE_FORMAT_OPTIONS || [],
|
|
589
446
|
format.formatBlock
|
|
590
447
|
)
|
|
591
448
|
);
|
|
592
449
|
overflowMenu.appendChild(
|
|
593
|
-
makeSelect(
|
|
450
|
+
helpers.makeSelect(
|
|
451
|
+
"Font",
|
|
452
|
+
"fontName",
|
|
453
|
+
window.RHE_FONT_OPTIONS || [],
|
|
454
|
+
format.fontName
|
|
455
|
+
)
|
|
594
456
|
);
|
|
595
457
|
overflowMenu.appendChild(
|
|
596
|
-
makeSelect(
|
|
458
|
+
helpers.makeSelect(
|
|
459
|
+
"Size",
|
|
460
|
+
"fontSize",
|
|
461
|
+
window.RHE_SIZE_OPTIONS || [],
|
|
462
|
+
format.fontSize
|
|
463
|
+
)
|
|
597
464
|
);
|
|
598
465
|
overflowMenu.appendChild(
|
|
599
|
-
makeColorInput("Text color", "foreColor", format.foreColor)
|
|
466
|
+
helpers.makeColorInput("Text color", "foreColor", format.foreColor)
|
|
600
467
|
);
|
|
601
468
|
overflowMenu.appendChild(
|
|
602
|
-
makeColorInput(
|
|
469
|
+
helpers.makeColorInput(
|
|
603
470
|
"Highlight color",
|
|
604
471
|
"hiliteColor",
|
|
605
472
|
format.hiliteColor
|
|
606
473
|
)
|
|
607
474
|
);
|
|
608
|
-
overflowMenu.appendChild(makeButton(
|
|
609
|
-
const overflowWrap = makeGroup();
|
|
475
|
+
overflowMenu.appendChild(helpers.makeButton("Link", "Insert link", "link"));
|
|
476
|
+
const overflowWrap = helpers.makeGroup();
|
|
610
477
|
overflowWrap.className = "toolbar-group toolbar-overflow-wrap";
|
|
611
478
|
overflowWrap.appendChild(overflowBtn);
|
|
612
479
|
overflowWrap.appendChild(overflowMenu);
|
|
613
480
|
toolbar.appendChild(overflowWrap);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/toolbar/buttons.ts
|
|
484
|
+
function makeButton(doc, options, label, title, command, value, isActive, disabled) {
|
|
485
|
+
const btn = doc.createElement("button");
|
|
486
|
+
btn.type = "button";
|
|
487
|
+
if (label && label.trim().startsWith("<")) {
|
|
488
|
+
btn.innerHTML = label;
|
|
489
|
+
} else {
|
|
490
|
+
btn.textContent = label;
|
|
491
|
+
}
|
|
492
|
+
btn.title = title;
|
|
493
|
+
btn.setAttribute("aria-label", title);
|
|
494
|
+
if (typeof isActive !== "undefined")
|
|
495
|
+
btn.setAttribute("aria-pressed", String(!!isActive));
|
|
496
|
+
btn.tabIndex = 0;
|
|
497
|
+
if (disabled) btn.disabled = true;
|
|
498
|
+
btn.onclick = () => options.onCommand(command, value);
|
|
499
|
+
btn.addEventListener("keydown", (ev) => {
|
|
500
|
+
if (ev.key === "Enter" || ev.key === " ") {
|
|
501
|
+
ev.preventDefault();
|
|
502
|
+
btn.click();
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
return btn;
|
|
506
|
+
}
|
|
507
|
+
function makeGroup(doc) {
|
|
508
|
+
const g = doc.createElement("div");
|
|
509
|
+
g.className = "toolbar-group";
|
|
510
|
+
return g;
|
|
511
|
+
}
|
|
512
|
+
function makeSep(doc) {
|
|
513
|
+
const s = doc.createElement("div");
|
|
514
|
+
s.className = "toolbar-sep";
|
|
515
|
+
return s;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// src/toolbar/selects.ts
|
|
519
|
+
function makeSelect(doc, options, title, command, optionsList, initialValue) {
|
|
520
|
+
const select = doc.createElement("select");
|
|
521
|
+
select.title = title;
|
|
522
|
+
select.setAttribute("aria-label", title);
|
|
523
|
+
select.appendChild(new Option(title, "", true, true));
|
|
524
|
+
for (const opt of optionsList) {
|
|
525
|
+
select.appendChild(new Option(opt.label, opt.value));
|
|
526
|
+
}
|
|
527
|
+
try {
|
|
528
|
+
if (initialValue) select.value = initialValue;
|
|
529
|
+
} catch (e) {
|
|
530
|
+
}
|
|
531
|
+
select.onchange = (e) => {
|
|
532
|
+
const val = e.target.value;
|
|
533
|
+
options.onCommand(command, val);
|
|
534
|
+
select.selectedIndex = 0;
|
|
535
|
+
};
|
|
536
|
+
return select;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// src/toolbar/navigation.ts
|
|
540
|
+
function setupNavigation(toolbar) {
|
|
614
541
|
toolbar.addEventListener("keydown", (e) => {
|
|
615
542
|
const focusable = Array.from(
|
|
616
543
|
toolbar.querySelectorAll("button, select, input, [tabindex]")
|
|
@@ -633,6 +560,158 @@ function injectToolbar(doc, options) {
|
|
|
633
560
|
focusable[focusable.length - 1].focus();
|
|
634
561
|
}
|
|
635
562
|
});
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// src/toolbar/render.ts
|
|
566
|
+
function injectToolbar(doc, options) {
|
|
567
|
+
const existing = doc.getElementById(TOOLBAR_ID);
|
|
568
|
+
if (existing) existing.remove();
|
|
569
|
+
const toolbar = doc.createElement("div");
|
|
570
|
+
toolbar.id = TOOLBAR_ID;
|
|
571
|
+
toolbar.setAttribute("role", "toolbar");
|
|
572
|
+
toolbar.setAttribute("aria-label", "Rich text editor toolbar");
|
|
573
|
+
const makeButton2 = (label, title, command, value, isActive, disabled) => makeButton(
|
|
574
|
+
doc,
|
|
575
|
+
{ onCommand: options.onCommand },
|
|
576
|
+
label,
|
|
577
|
+
title,
|
|
578
|
+
command,
|
|
579
|
+
value,
|
|
580
|
+
isActive,
|
|
581
|
+
disabled
|
|
582
|
+
);
|
|
583
|
+
const makeSelect2 = (title, command, optionsList, initialValue) => makeSelect(
|
|
584
|
+
doc,
|
|
585
|
+
{ onCommand: options.onCommand },
|
|
586
|
+
title,
|
|
587
|
+
command,
|
|
588
|
+
optionsList,
|
|
589
|
+
initialValue
|
|
590
|
+
);
|
|
591
|
+
const format = options.getFormatState();
|
|
592
|
+
const makeGroup2 = () => makeGroup(doc);
|
|
593
|
+
const makeSep2 = () => makeSep(doc);
|
|
594
|
+
const undoBtn = makeButton2(
|
|
595
|
+
LABEL_UNDO,
|
|
596
|
+
"Undo",
|
|
597
|
+
"undo",
|
|
598
|
+
void 0,
|
|
599
|
+
false,
|
|
600
|
+
!options.canUndo()
|
|
601
|
+
);
|
|
602
|
+
undoBtn.onclick = () => options.onUndo();
|
|
603
|
+
const redoBtn = makeButton2(
|
|
604
|
+
LABEL_REDO,
|
|
605
|
+
"Redo",
|
|
606
|
+
"redo",
|
|
607
|
+
void 0,
|
|
608
|
+
false,
|
|
609
|
+
!options.canRedo()
|
|
610
|
+
);
|
|
611
|
+
redoBtn.onclick = () => options.onRedo();
|
|
612
|
+
const grp1 = makeGroup2();
|
|
613
|
+
grp1.appendChild(undoBtn);
|
|
614
|
+
grp1.appendChild(redoBtn);
|
|
615
|
+
toolbar.appendChild(grp1);
|
|
616
|
+
toolbar.appendChild(makeSep2());
|
|
617
|
+
const grp2 = makeGroup2();
|
|
618
|
+
grp2.className = "toolbar-group collapse-on-small";
|
|
619
|
+
grp2.appendChild(
|
|
620
|
+
makeSelect2(
|
|
621
|
+
"Format",
|
|
622
|
+
"formatBlock",
|
|
623
|
+
FORMAT_OPTIONS,
|
|
624
|
+
format.formatBlock
|
|
625
|
+
)
|
|
626
|
+
);
|
|
627
|
+
grp2.appendChild(
|
|
628
|
+
makeSelect2("Font", "fontName", FONT_OPTIONS, format.fontName)
|
|
629
|
+
);
|
|
630
|
+
grp2.appendChild(
|
|
631
|
+
makeSelect2("Size", "fontSize", SIZE_OPTIONS, format.fontSize)
|
|
632
|
+
);
|
|
633
|
+
toolbar.appendChild(grp2);
|
|
634
|
+
toolbar.appendChild(makeSep2());
|
|
635
|
+
const grp3 = makeGroup2();
|
|
636
|
+
grp3.appendChild(
|
|
637
|
+
makeButton2(LABEL_BOLD, "Bold", "bold", void 0, format.bold)
|
|
638
|
+
);
|
|
639
|
+
grp3.appendChild(
|
|
640
|
+
makeButton2(LABEL_ITALIC, "Italic", "italic", void 0, format.italic)
|
|
641
|
+
);
|
|
642
|
+
grp3.appendChild(
|
|
643
|
+
makeButton2(
|
|
644
|
+
LABEL_UNDERLINE,
|
|
645
|
+
"Underline",
|
|
646
|
+
"underline",
|
|
647
|
+
void 0,
|
|
648
|
+
format.underline
|
|
649
|
+
)
|
|
650
|
+
);
|
|
651
|
+
grp3.appendChild(makeButton2(LABEL_STRIKETHROUGH, "Strikethrough", "strike"));
|
|
652
|
+
grp3.appendChild(
|
|
653
|
+
makeButton2(
|
|
654
|
+
LABEL_UNORDERED_LIST,
|
|
655
|
+
"Unordered list",
|
|
656
|
+
"unorderedList",
|
|
657
|
+
void 0,
|
|
658
|
+
format.listType === "ul"
|
|
659
|
+
)
|
|
660
|
+
);
|
|
661
|
+
grp3.appendChild(
|
|
662
|
+
makeButton2(
|
|
663
|
+
LABEL_ORDERED_LIST,
|
|
664
|
+
"Ordered list",
|
|
665
|
+
"orderedList",
|
|
666
|
+
void 0,
|
|
667
|
+
format.listType === "ol"
|
|
668
|
+
)
|
|
669
|
+
);
|
|
670
|
+
toolbar.appendChild(grp3);
|
|
671
|
+
toolbar.appendChild(makeSep2());
|
|
672
|
+
const grp4 = makeGroup2();
|
|
673
|
+
grp4.appendChild(makeButton2(LABEL_ALIGN_LEFT, "Align left", "align", "left"));
|
|
674
|
+
grp4.appendChild(
|
|
675
|
+
makeButton2(LABEL_ALIGN_CENTER, "Align center", "align", "center")
|
|
676
|
+
);
|
|
677
|
+
grp4.appendChild(
|
|
678
|
+
makeButton2(LABEL_ALIGN_RIGHT, "Align right", "align", "right")
|
|
679
|
+
);
|
|
680
|
+
toolbar.appendChild(grp4);
|
|
681
|
+
toolbar.appendChild(makeSep2());
|
|
682
|
+
const grp5 = makeGroup2();
|
|
683
|
+
grp5.className = "toolbar-group collapse-on-small";
|
|
684
|
+
grp5.appendChild(
|
|
685
|
+
makeColorInput(
|
|
686
|
+
doc,
|
|
687
|
+
options,
|
|
688
|
+
"Text color",
|
|
689
|
+
"foreColor",
|
|
690
|
+
format.foreColor
|
|
691
|
+
)
|
|
692
|
+
);
|
|
693
|
+
grp5.appendChild(
|
|
694
|
+
makeColorInput(
|
|
695
|
+
doc,
|
|
696
|
+
options,
|
|
697
|
+
"Highlight color",
|
|
698
|
+
"hiliteColor",
|
|
699
|
+
format.hiliteColor
|
|
700
|
+
)
|
|
701
|
+
);
|
|
702
|
+
toolbar.appendChild(grp5);
|
|
703
|
+
toolbar.appendChild(makeSep2());
|
|
704
|
+
const grp6 = makeGroup2();
|
|
705
|
+
grp6.className = "toolbar-group collapse-on-small";
|
|
706
|
+
grp6.appendChild(makeButton2(LABEL_LINK, "Insert link", "link"));
|
|
707
|
+
toolbar.appendChild(grp6);
|
|
708
|
+
setupOverflow(doc, toolbar, options, format, {
|
|
709
|
+
makeSelect: makeSelect2,
|
|
710
|
+
makeColorInput: (title, command, initial) => makeColorInput(doc, options, title, command, initial),
|
|
711
|
+
makeButton: makeButton2,
|
|
712
|
+
makeGroup: makeGroup2
|
|
713
|
+
});
|
|
714
|
+
setupNavigation(toolbar);
|
|
636
715
|
doc.body.insertBefore(toolbar, doc.body.firstChild);
|
|
637
716
|
}
|
|
638
717
|
|
|
@@ -672,7 +751,8 @@ function computeFormatState(doc) {
|
|
|
672
751
|
hiliteColor: null,
|
|
673
752
|
fontName: null,
|
|
674
753
|
fontSize: null,
|
|
675
|
-
formatBlock: null
|
|
754
|
+
formatBlock: null,
|
|
755
|
+
listType: null
|
|
676
756
|
};
|
|
677
757
|
const computed = (_a = doc.defaultView) == null ? void 0 : _a.getComputedStyle(el);
|
|
678
758
|
const bold = !!(el.closest("strong, b") || computed && (computed.fontWeight === "700" || Number(computed.fontWeight) >= 700));
|
|
@@ -708,6 +788,18 @@ function computeFormatState(doc) {
|
|
|
708
788
|
blockEl = blockEl.parentElement;
|
|
709
789
|
}
|
|
710
790
|
const formatBlock = blockEl ? blockEl.tagName.toLowerCase() : null;
|
|
791
|
+
let listType = null;
|
|
792
|
+
try {
|
|
793
|
+
if (blockEl && blockEl.tagName === "LI") {
|
|
794
|
+
const list = blockEl.closest("ul,ol");
|
|
795
|
+
if (list) listType = list.tagName.toLowerCase();
|
|
796
|
+
} else {
|
|
797
|
+
const possible = el.closest("ul,ol");
|
|
798
|
+
if (possible) listType = possible.tagName.toLowerCase();
|
|
799
|
+
}
|
|
800
|
+
} catch (e) {
|
|
801
|
+
listType = null;
|
|
802
|
+
}
|
|
711
803
|
return {
|
|
712
804
|
bold,
|
|
713
805
|
italic,
|
|
@@ -716,7 +808,8 @@ function computeFormatState(doc) {
|
|
|
716
808
|
hiliteColor,
|
|
717
809
|
fontName,
|
|
718
810
|
fontSize,
|
|
719
|
-
formatBlock
|
|
811
|
+
formatBlock,
|
|
812
|
+
listType
|
|
720
813
|
};
|
|
721
814
|
} catch (err) {
|
|
722
815
|
return {
|
|
@@ -727,7 +820,8 @@ function computeFormatState(doc) {
|
|
|
727
820
|
hiliteColor: null,
|
|
728
821
|
fontName: null,
|
|
729
822
|
fontSize: null,
|
|
730
|
-
formatBlock: null
|
|
823
|
+
formatBlock: null,
|
|
824
|
+
listType: null
|
|
731
825
|
};
|
|
732
826
|
}
|
|
733
827
|
}
|
|
@@ -1120,6 +1214,9 @@ function applyStandaloneCommand(command, value) {
|
|
|
1120
1214
|
} else {
|
|
1121
1215
|
wrapSelectionWithElement(doc, tag);
|
|
1122
1216
|
}
|
|
1217
|
+
} else if (command === "unorderedList" || command === "orderedList") {
|
|
1218
|
+
const tag = command === "unorderedList" ? "ul" : "ol";
|
|
1219
|
+
toggleList(doc, tag);
|
|
1123
1220
|
}
|
|
1124
1221
|
pushStandaloneSnapshot();
|
|
1125
1222
|
} catch (error) {
|
|
@@ -1155,6 +1252,57 @@ function wrapSelectionWithElement(doc, tagName, style) {
|
|
|
1155
1252
|
newRange.selectNodeContents(wrapper);
|
|
1156
1253
|
sel.addRange(newRange);
|
|
1157
1254
|
}
|
|
1255
|
+
function toggleList(doc, listTag) {
|
|
1256
|
+
var _a, _b;
|
|
1257
|
+
const sel = doc.getSelection();
|
|
1258
|
+
if (!sel || !sel.rangeCount) return;
|
|
1259
|
+
const node = sel.anchorNode || null;
|
|
1260
|
+
const block = findBlockAncestor(node);
|
|
1261
|
+
if (block && block.tagName === "LI" && block.parentElement) {
|
|
1262
|
+
const parentList = block.parentElement;
|
|
1263
|
+
const parentTag = parentList.tagName.toLowerCase();
|
|
1264
|
+
if (parentTag === listTag) {
|
|
1265
|
+
const frag = doc.createDocumentFragment();
|
|
1266
|
+
Array.from(parentList.children).forEach((li2) => {
|
|
1267
|
+
const p = doc.createElement("p");
|
|
1268
|
+
while (li2.firstChild) p.appendChild(li2.firstChild);
|
|
1269
|
+
frag.appendChild(p);
|
|
1270
|
+
});
|
|
1271
|
+
(_a = parentList.parentElement) == null ? void 0 : _a.replaceChild(frag, parentList);
|
|
1272
|
+
return;
|
|
1273
|
+
} else {
|
|
1274
|
+
const newList = doc.createElement(listTag);
|
|
1275
|
+
while (parentList.firstChild) newList.appendChild(parentList.firstChild);
|
|
1276
|
+
(_b = parentList.parentElement) == null ? void 0 : _b.replaceChild(newList, parentList);
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
const range = sel.getRangeAt(0);
|
|
1281
|
+
if (range.collapsed) {
|
|
1282
|
+
const list2 = doc.createElement(listTag);
|
|
1283
|
+
const li2 = doc.createElement("li");
|
|
1284
|
+
const zw = doc.createTextNode("\u200B");
|
|
1285
|
+
li2.appendChild(zw);
|
|
1286
|
+
list2.appendChild(li2);
|
|
1287
|
+
range.insertNode(list2);
|
|
1288
|
+
const newRange2 = doc.createRange();
|
|
1289
|
+
newRange2.setStart(zw, 1);
|
|
1290
|
+
newRange2.collapse(true);
|
|
1291
|
+
sel.removeAllRanges();
|
|
1292
|
+
sel.addRange(newRange2);
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1295
|
+
const content = range.extractContents();
|
|
1296
|
+
const list = doc.createElement(listTag);
|
|
1297
|
+
const li = doc.createElement("li");
|
|
1298
|
+
li.appendChild(content);
|
|
1299
|
+
list.appendChild(li);
|
|
1300
|
+
range.insertNode(list);
|
|
1301
|
+
sel.removeAllRanges();
|
|
1302
|
+
const newRange = doc.createRange();
|
|
1303
|
+
newRange.selectNodeContents(li);
|
|
1304
|
+
sel.addRange(newRange);
|
|
1305
|
+
}
|
|
1158
1306
|
function findBlockAncestor(node) {
|
|
1159
1307
|
let n = node;
|
|
1160
1308
|
const BLOCKS = [
|
|
@@ -1296,6 +1444,33 @@ function attachStandaloneHandlers(doc) {
|
|
|
1296
1444
|
},
|
|
1297
1445
|
true
|
|
1298
1446
|
);
|
|
1447
|
+
doc.addEventListener(
|
|
1448
|
+
"keydown",
|
|
1449
|
+
(e) => {
|
|
1450
|
+
if (e.key !== "Enter") return;
|
|
1451
|
+
if (e.shiftKey) return;
|
|
1452
|
+
const sel = doc.getSelection();
|
|
1453
|
+
if (!sel || !sel.rangeCount) return;
|
|
1454
|
+
const node = sel.anchorNode;
|
|
1455
|
+
const el = node && node.nodeType === Node.ELEMENT_NODE ? node : node && node.parentElement || null;
|
|
1456
|
+
if (!el) return;
|
|
1457
|
+
const li = el.closest("li");
|
|
1458
|
+
if (!li || !li.parentElement) return;
|
|
1459
|
+
e.preventDefault();
|
|
1460
|
+
const list = li.parentElement;
|
|
1461
|
+
const newLi = doc.createElement("li");
|
|
1462
|
+
const zw = doc.createTextNode("\u200B");
|
|
1463
|
+
newLi.appendChild(zw);
|
|
1464
|
+
if (li.nextSibling) list.insertBefore(newLi, li.nextSibling);
|
|
1465
|
+
else list.appendChild(newLi);
|
|
1466
|
+
const range = doc.createRange();
|
|
1467
|
+
range.setStart(zw, 1);
|
|
1468
|
+
range.collapse(true);
|
|
1469
|
+
sel.removeAllRanges();
|
|
1470
|
+
sel.addRange(range);
|
|
1471
|
+
},
|
|
1472
|
+
true
|
|
1473
|
+
);
|
|
1299
1474
|
}
|
|
1300
1475
|
|
|
1301
1476
|
// src/core/editor.ts
|
|
@@ -1316,7 +1491,7 @@ function initRichEditor(iframe, config) {
|
|
|
1316
1491
|
_setRedoStack([]);
|
|
1317
1492
|
_setCurrentEditable(null);
|
|
1318
1493
|
if (config == null ? void 0 : config.maxStackSize) {
|
|
1319
|
-
import("./state-
|
|
1494
|
+
import("./state-DA3PGFTN.mjs").then((m) => m.setMaxStackSize(config.maxStackSize)).catch(() => {
|
|
1320
1495
|
});
|
|
1321
1496
|
}
|
|
1322
1497
|
attachStandaloneHandlers(doc);
|