@aeriz/wysiwyg 1.0.0 → 1.0.2
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 +96 -0
- package/dist/aeriz-wysiwyg.css +10 -1
- package/dist/aeriz-wysiwyg.esm.js +332 -43
- package/dist/aeriz-wysiwyg.esm.min.js +941 -710
- package/dist/aeriz-wysiwyg.js +332 -43
- package/dist/aeriz-wysiwyg.min.css +1 -1
- package/dist/aeriz-wysiwyg.min.js +17 -17
- package/dist-types/core/AerizEditor.d.ts.map +1 -1
- package/dist-types/core/blocks.d.ts +10 -0
- package/dist-types/core/blocks.d.ts.map +1 -1
- package/dist-types/core/import-html.d.ts +13 -2
- package/dist-types/core/import-html.d.ts.map +1 -1
- package/package.json +3 -2
package/dist/aeriz-wysiwyg.js
CHANGED
|
@@ -2388,10 +2388,124 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2388
2388
|
function setLocale(locale) {
|
|
2389
2389
|
}
|
|
2390
2390
|
const STRIP_TAGS = ["script", "noscript", "meta", "link", "style", "base"];
|
|
2391
|
+
const INHERITED_PROPERTIES = /* @__PURE__ */ new Set([
|
|
2392
|
+
// CSS 2.1
|
|
2393
|
+
"border-collapse",
|
|
2394
|
+
"border-spacing",
|
|
2395
|
+
"caption-side",
|
|
2396
|
+
"color",
|
|
2397
|
+
"cursor",
|
|
2398
|
+
"direction",
|
|
2399
|
+
"empty-cells",
|
|
2400
|
+
"font-family",
|
|
2401
|
+
"font-size",
|
|
2402
|
+
"font-style",
|
|
2403
|
+
"font-variant",
|
|
2404
|
+
"font-weight",
|
|
2405
|
+
"letter-spacing",
|
|
2406
|
+
"line-height",
|
|
2407
|
+
"list-style",
|
|
2408
|
+
"list-style-image",
|
|
2409
|
+
"list-style-position",
|
|
2410
|
+
"list-style-type",
|
|
2411
|
+
"orphans",
|
|
2412
|
+
"quotes",
|
|
2413
|
+
"text-align",
|
|
2414
|
+
"text-indent",
|
|
2415
|
+
"text-transform",
|
|
2416
|
+
"visibility",
|
|
2417
|
+
"white-space",
|
|
2418
|
+
"widows",
|
|
2419
|
+
"word-spacing",
|
|
2420
|
+
// CSS 3+
|
|
2421
|
+
"caret-color",
|
|
2422
|
+
"font",
|
|
2423
|
+
"font-feature-settings",
|
|
2424
|
+
"font-kerning",
|
|
2425
|
+
"font-language-override",
|
|
2426
|
+
"font-optical-sizing",
|
|
2427
|
+
"font-palette",
|
|
2428
|
+
"font-size-adjust",
|
|
2429
|
+
"font-stretch",
|
|
2430
|
+
"font-synthesis",
|
|
2431
|
+
"font-synthesis-weight",
|
|
2432
|
+
"font-synthesis-style",
|
|
2433
|
+
"font-synthesis-small-caps",
|
|
2434
|
+
"font-variant-alternates",
|
|
2435
|
+
"font-variant-caps",
|
|
2436
|
+
"font-variant-east-asian",
|
|
2437
|
+
"font-variant-emoji",
|
|
2438
|
+
"font-variant-ligatures",
|
|
2439
|
+
"font-variant-numeric",
|
|
2440
|
+
"font-variant-position",
|
|
2441
|
+
"font-variation-settings",
|
|
2442
|
+
"hanging-punctuation",
|
|
2443
|
+
"hyphens",
|
|
2444
|
+
"image-rendering",
|
|
2445
|
+
"line-break",
|
|
2446
|
+
"overflow-wrap",
|
|
2447
|
+
"pointer-events",
|
|
2448
|
+
"ruby-align",
|
|
2449
|
+
"ruby-position",
|
|
2450
|
+
"tab-size",
|
|
2451
|
+
"text-align-last",
|
|
2452
|
+
"text-combine-upright",
|
|
2453
|
+
"text-decoration-color",
|
|
2454
|
+
"text-emphasis",
|
|
2455
|
+
"text-emphasis-color",
|
|
2456
|
+
"text-emphasis-position",
|
|
2457
|
+
"text-emphasis-style",
|
|
2458
|
+
"text-justify",
|
|
2459
|
+
"text-orientation",
|
|
2460
|
+
"text-rendering",
|
|
2461
|
+
"text-shadow",
|
|
2462
|
+
"text-size-adjust",
|
|
2463
|
+
"text-underline-offset",
|
|
2464
|
+
"text-underline-position",
|
|
2465
|
+
"white-space-collapse",
|
|
2466
|
+
"word-break",
|
|
2467
|
+
"word-wrap",
|
|
2468
|
+
"writing-mode",
|
|
2469
|
+
"color-scheme",
|
|
2470
|
+
"print-color-adjust",
|
|
2471
|
+
// Vendor
|
|
2472
|
+
"-webkit-font-smoothing",
|
|
2473
|
+
"-moz-osx-font-smoothing",
|
|
2474
|
+
"-webkit-locale",
|
|
2475
|
+
"-webkit-text-fill-color",
|
|
2476
|
+
"-webkit-text-stroke",
|
|
2477
|
+
"-webkit-text-stroke-color",
|
|
2478
|
+
"-webkit-text-stroke-width",
|
|
2479
|
+
"-webkit-print-color-adjust",
|
|
2480
|
+
// SVG
|
|
2481
|
+
"clip-rule",
|
|
2482
|
+
"color-interpolation",
|
|
2483
|
+
"color-interpolation-filters",
|
|
2484
|
+
"color-rendering",
|
|
2485
|
+
"fill",
|
|
2486
|
+
"fill-opacity",
|
|
2487
|
+
"fill-rule",
|
|
2488
|
+
"marker",
|
|
2489
|
+
"marker-end",
|
|
2490
|
+
"marker-mid",
|
|
2491
|
+
"marker-start",
|
|
2492
|
+
"paint-order",
|
|
2493
|
+
"shape-rendering",
|
|
2494
|
+
"stroke",
|
|
2495
|
+
"stroke-dasharray",
|
|
2496
|
+
"stroke-dashoffset",
|
|
2497
|
+
"stroke-linecap",
|
|
2498
|
+
"stroke-linejoin",
|
|
2499
|
+
"stroke-miterlimit",
|
|
2500
|
+
"stroke-opacity",
|
|
2501
|
+
"stroke-width",
|
|
2502
|
+
"text-anchor"
|
|
2503
|
+
]);
|
|
2391
2504
|
async function importHtmlWithComputedStyles(html, options = {}) {
|
|
2392
2505
|
const settleMs = options.settleMs ?? 1e3;
|
|
2393
2506
|
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
2394
2507
|
const width = options.width ?? 1024;
|
|
2508
|
+
const mountTarget = options.mountTarget ?? null;
|
|
2395
2509
|
return new Promise((resolve, reject) => {
|
|
2396
2510
|
const iframe = document.createElement("iframe");
|
|
2397
2511
|
iframe.setAttribute("aria-hidden", "true");
|
|
@@ -2444,7 +2558,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2444
2558
|
fail(new Error("iframe document 접근 실패"));
|
|
2445
2559
|
return;
|
|
2446
2560
|
}
|
|
2447
|
-
const baked = bakeBodyToImportable(doc.body, w);
|
|
2561
|
+
const baked = bakeBodyToImportable(doc.body, w, mountTarget);
|
|
2448
2562
|
window.clearTimeout(timer);
|
|
2449
2563
|
finish(baked);
|
|
2450
2564
|
} catch (err) {
|
|
@@ -2461,23 +2575,30 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2461
2575
|
document.body.appendChild(iframe);
|
|
2462
2576
|
});
|
|
2463
2577
|
}
|
|
2464
|
-
function bakeBodyToImportable(body, win) {
|
|
2578
|
+
function bakeBodyToImportable(body, win, mountTarget) {
|
|
2465
2579
|
var _a;
|
|
2580
|
+
const doc = body.ownerDocument;
|
|
2581
|
+
if (!doc) throw new Error("body has no ownerDocument");
|
|
2466
2582
|
const wrapper = document.createElement("div");
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2583
|
+
const baseline = createBaselineProbe(doc, win, mountTarget);
|
|
2584
|
+
try {
|
|
2585
|
+
for (let i = 0; i < body.attributes.length; i++) {
|
|
2586
|
+
const attr = body.attributes.item(i);
|
|
2587
|
+
if (!attr) continue;
|
|
2588
|
+
if (attr.name === "style") continue;
|
|
2589
|
+
wrapper.setAttribute(attr.name, attr.value);
|
|
2590
|
+
}
|
|
2591
|
+
const wrapperStyle = computeMinimalInline(body, null, "div", baseline.get, win);
|
|
2592
|
+
if (wrapperStyle.length > 0) {
|
|
2593
|
+
wrapper.setAttribute("style", wrapperStyle);
|
|
2594
|
+
}
|
|
2595
|
+
for (const child of Array.from(body.children)) {
|
|
2596
|
+
const imported = document.importNode(child, true);
|
|
2597
|
+
applyComputedStylesParallel(child, imported, body, baseline.get, win);
|
|
2598
|
+
wrapper.appendChild(imported);
|
|
2599
|
+
}
|
|
2600
|
+
} finally {
|
|
2601
|
+
baseline.cleanup();
|
|
2481
2602
|
}
|
|
2482
2603
|
for (const tag of STRIP_TAGS) {
|
|
2483
2604
|
for (const el of Array.from(wrapper.querySelectorAll(tag))) {
|
|
@@ -2491,24 +2612,83 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2491
2612
|
wrapper.setAttribute("data-imported-html", "true");
|
|
2492
2613
|
return [wrapper];
|
|
2493
2614
|
}
|
|
2494
|
-
function
|
|
2615
|
+
function createBaselineProbe(iframeDoc, iframeWin, mountTarget) {
|
|
2616
|
+
var _a;
|
|
2617
|
+
let probeDoc;
|
|
2618
|
+
let probeWin;
|
|
2619
|
+
let probeHost;
|
|
2620
|
+
const targetWin = ((_a = mountTarget == null ? void 0 : mountTarget.ownerDocument) == null ? void 0 : _a.defaultView) ?? null;
|
|
2621
|
+
if (mountTarget && targetWin) {
|
|
2622
|
+
probeDoc = mountTarget.ownerDocument;
|
|
2623
|
+
probeWin = targetWin;
|
|
2624
|
+
const host = probeDoc.createElement("div");
|
|
2625
|
+
host.setAttribute("data-imported-html", "true");
|
|
2626
|
+
host.setAttribute("aria-hidden", "true");
|
|
2627
|
+
host.style.cssText = "position:absolute;left:-99999px;top:0;visibility:hidden;pointer-events:none;";
|
|
2628
|
+
mountTarget.appendChild(host);
|
|
2629
|
+
probeHost = host;
|
|
2630
|
+
} else {
|
|
2631
|
+
probeDoc = iframeDoc;
|
|
2632
|
+
probeWin = iframeWin;
|
|
2633
|
+
const host = probeDoc.createElement("div");
|
|
2634
|
+
host.setAttribute("aria-hidden", "true");
|
|
2635
|
+
host.style.cssText = "position:absolute;left:-99999px;top:0;width:0;height:0;overflow:hidden;visibility:hidden;";
|
|
2636
|
+
probeDoc.body.appendChild(host);
|
|
2637
|
+
probeHost = host;
|
|
2638
|
+
}
|
|
2639
|
+
const cache = /* @__PURE__ */ new Map();
|
|
2640
|
+
const get = (tagName) => {
|
|
2641
|
+
const cached = cache.get(tagName);
|
|
2642
|
+
if (cached) return cached;
|
|
2643
|
+
const probe = probeDoc.createElement(tagName);
|
|
2644
|
+
probeHost.appendChild(probe);
|
|
2645
|
+
const cs = probeWin.getComputedStyle(probe);
|
|
2646
|
+
const map = /* @__PURE__ */ new Map();
|
|
2647
|
+
for (let i = 0; i < cs.length; i++) {
|
|
2648
|
+
const prop = cs.item(i);
|
|
2649
|
+
if (prop) map.set(prop, cs.getPropertyValue(prop));
|
|
2650
|
+
}
|
|
2651
|
+
probeHost.removeChild(probe);
|
|
2652
|
+
cache.set(tagName, map);
|
|
2653
|
+
return map;
|
|
2654
|
+
};
|
|
2655
|
+
const cleanup = () => {
|
|
2656
|
+
if (probeHost.parentNode) probeHost.parentNode.removeChild(probeHost);
|
|
2657
|
+
};
|
|
2658
|
+
return { get, cleanup };
|
|
2659
|
+
}
|
|
2660
|
+
function computeMinimalInline(el, parent, baselineTagName, getBaseline, win) {
|
|
2495
2661
|
const cs = win.getComputedStyle(el);
|
|
2662
|
+
const parentCs = parent ? win.getComputedStyle(parent) : null;
|
|
2663
|
+
const baseline = getBaseline(baselineTagName);
|
|
2496
2664
|
let cssText = "";
|
|
2497
2665
|
for (let i = 0; i < cs.length; i++) {
|
|
2498
2666
|
const prop = cs.item(i);
|
|
2499
2667
|
if (!prop) continue;
|
|
2500
2668
|
const val = cs.getPropertyValue(prop);
|
|
2501
|
-
if (val
|
|
2502
|
-
|
|
2669
|
+
if (!val) continue;
|
|
2670
|
+
if (INHERITED_PROPERTIES.has(prop)) {
|
|
2671
|
+
if (parentCs && parentCs.getPropertyValue(prop) === val) continue;
|
|
2672
|
+
} else {
|
|
2673
|
+
if (baseline.get(prop) === val) continue;
|
|
2503
2674
|
}
|
|
2675
|
+
cssText += `${prop}:${val};`;
|
|
2504
2676
|
}
|
|
2505
2677
|
return cssText;
|
|
2506
2678
|
}
|
|
2507
|
-
function applyComputedStylesParallel(orig, copy, win) {
|
|
2679
|
+
function applyComputedStylesParallel(orig, copy, origParent, getBaseline, win) {
|
|
2508
2680
|
if (orig.nodeType === 1 && copy.nodeType === 1) {
|
|
2509
|
-
const cssText =
|
|
2681
|
+
const cssText = computeMinimalInline(
|
|
2682
|
+
orig,
|
|
2683
|
+
origParent,
|
|
2684
|
+
orig.tagName.toLowerCase(),
|
|
2685
|
+
getBaseline,
|
|
2686
|
+
win
|
|
2687
|
+
);
|
|
2510
2688
|
if (cssText.length > 0) {
|
|
2511
2689
|
copy.setAttribute("style", cssText);
|
|
2690
|
+
} else if (copy.hasAttribute("style")) {
|
|
2691
|
+
copy.removeAttribute("style");
|
|
2512
2692
|
}
|
|
2513
2693
|
}
|
|
2514
2694
|
const origChildren = orig.children;
|
|
@@ -2517,7 +2697,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2517
2697
|
for (let i = 0; i < n; i++) {
|
|
2518
2698
|
const oc = origChildren[i];
|
|
2519
2699
|
const cc = copyChildren[i];
|
|
2520
|
-
if (oc && cc) applyComputedStylesParallel(oc, cc, win);
|
|
2700
|
+
if (oc && cc) applyComputedStylesParallel(oc, cc, orig, getBaseline, win);
|
|
2521
2701
|
}
|
|
2522
2702
|
}
|
|
2523
2703
|
function markdownToBlocks(md) {
|
|
@@ -2734,6 +2914,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2734
2914
|
label: "단락",
|
|
2735
2915
|
allowsInlineFormat: true,
|
|
2736
2916
|
allowedMarks: ALL_INLINE_MARKS,
|
|
2917
|
+
allowsColor: true,
|
|
2918
|
+
allowsFontSize: true,
|
|
2737
2919
|
matches: (el) => el.tagName === "P" ? { kind: "paragraph", attrs: {} } : null,
|
|
2738
2920
|
create: () => fillEmpty(document.createElement("p")),
|
|
2739
2921
|
isEmpty: (el) => isElementBlank(el)
|
|
@@ -2745,6 +2927,10 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2745
2927
|
// 사용자 지정 — 제목은 italic 만 허용. (bold 는 heading 자체가 굵으므로
|
|
2746
2928
|
// 중복, underline / strike 는 가독성/시맨틱 면에서 부적합.)
|
|
2747
2929
|
allowedMarks: ["italic"],
|
|
2930
|
+
// 글자색/배경색은 시맨틱 헤딩 톤 보존을 위해 X.
|
|
2931
|
+
allowsColor: false,
|
|
2932
|
+
// 글자 크기는 heading level (h1~h6) 로 결정되므로 X.
|
|
2933
|
+
allowsFontSize: false,
|
|
2748
2934
|
matches: (el) => {
|
|
2749
2935
|
const m = /^H([1-6])$/.exec(el.tagName);
|
|
2750
2936
|
if (!m) return null;
|
|
@@ -2761,6 +2947,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2761
2947
|
label: "글머리 목록",
|
|
2762
2948
|
allowsInlineFormat: true,
|
|
2763
2949
|
allowedMarks: ALL_INLINE_MARKS,
|
|
2950
|
+
allowsColor: true,
|
|
2951
|
+
allowsFontSize: true,
|
|
2764
2952
|
matches: (el) => el.tagName === "UL" ? { kind: "bulletList", attrs: {} } : null,
|
|
2765
2953
|
create: () => createListElement("ul"),
|
|
2766
2954
|
isEmpty: (el) => isListEmpty(el)
|
|
@@ -2770,6 +2958,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2770
2958
|
label: "번호 매기기 목록",
|
|
2771
2959
|
allowsInlineFormat: true,
|
|
2772
2960
|
allowedMarks: ALL_INLINE_MARKS,
|
|
2961
|
+
allowsColor: true,
|
|
2962
|
+
allowsFontSize: true,
|
|
2773
2963
|
matches: (el) => el.tagName === "OL" ? { kind: "orderedList", attrs: {} } : null,
|
|
2774
2964
|
create: () => createListElement("ol"),
|
|
2775
2965
|
isEmpty: (el) => isListEmpty(el)
|
|
@@ -2781,6 +2971,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2781
2971
|
// 사용자 지정 — 인용구는 italic 제외(인용 자체가 이미 italic 으로 렌더되어
|
|
2782
2972
|
// 중복). bold / underline / strike 만 허용.
|
|
2783
2973
|
allowedMarks: ["bold", "underline", "strike"],
|
|
2974
|
+
// 인용구 자체의 톤(이탤릭/주변 색조) 을 보존.
|
|
2975
|
+
allowsColor: false,
|
|
2976
|
+
allowsFontSize: true,
|
|
2784
2977
|
matches: (el) => el.tagName === "BLOCKQUOTE" ? { kind: "blockquote", attrs: {} } : null,
|
|
2785
2978
|
create: () => {
|
|
2786
2979
|
const bq = document.createElement("blockquote");
|
|
@@ -2794,6 +2987,10 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2794
2987
|
label: "코드 블록",
|
|
2795
2988
|
allowsInlineFormat: false,
|
|
2796
2989
|
allowedMarks: [],
|
|
2990
|
+
// 코드 블록은 인라인 서식은 막혀 있지만 글자 크기 조정은 (가독성) 의미가
|
|
2991
|
+
// 있어 예외적으로 허용. 색은 syntax highlight 와 충돌하므로 X.
|
|
2992
|
+
allowsColor: false,
|
|
2993
|
+
allowsFontSize: true,
|
|
2797
2994
|
matches: (el) => {
|
|
2798
2995
|
if (el.tagName !== "PRE") return null;
|
|
2799
2996
|
const code = el.querySelector(":scope > code");
|
|
@@ -2814,6 +3011,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2814
3011
|
label: "이미지",
|
|
2815
3012
|
allowsInlineFormat: false,
|
|
2816
3013
|
allowedMarks: [],
|
|
3014
|
+
allowsColor: false,
|
|
3015
|
+
allowsFontSize: false,
|
|
2817
3016
|
matches: (el) => {
|
|
2818
3017
|
if (el.tagName === "FIGURE") {
|
|
2819
3018
|
const img = el.querySelector(":scope > img");
|
|
@@ -2877,6 +3076,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2877
3076
|
label: "표",
|
|
2878
3077
|
allowsInlineFormat: true,
|
|
2879
3078
|
allowedMarks: ALL_INLINE_MARKS,
|
|
3079
|
+
allowsColor: true,
|
|
3080
|
+
allowsFontSize: true,
|
|
2880
3081
|
matches: (el) => {
|
|
2881
3082
|
var _a;
|
|
2882
3083
|
if (el.tagName !== "TABLE") return null;
|
|
@@ -2909,6 +3110,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2909
3110
|
label: "구분선",
|
|
2910
3111
|
allowsInlineFormat: false,
|
|
2911
3112
|
allowedMarks: [],
|
|
3113
|
+
allowsColor: false,
|
|
3114
|
+
allowsFontSize: false,
|
|
2912
3115
|
matches: (el) => el.tagName === "HR" ? { kind: "hr", attrs: {} } : null,
|
|
2913
3116
|
create: () => {
|
|
2914
3117
|
const hr = document.createElement("hr");
|
|
@@ -2922,6 +3125,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2922
3125
|
label: "유튜브",
|
|
2923
3126
|
allowsInlineFormat: false,
|
|
2924
3127
|
allowedMarks: [],
|
|
3128
|
+
allowsColor: false,
|
|
3129
|
+
allowsFontSize: false,
|
|
2925
3130
|
matches: (el) => {
|
|
2926
3131
|
if (el.tagName !== "DIV") return null;
|
|
2927
3132
|
if (!el.classList.contains("aw-youtube-embed")) return null;
|
|
@@ -2962,6 +3167,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2962
3167
|
label: "링크",
|
|
2963
3168
|
allowsInlineFormat: false,
|
|
2964
3169
|
allowedMarks: [],
|
|
3170
|
+
allowsColor: false,
|
|
3171
|
+
allowsFontSize: false,
|
|
2965
3172
|
matches: (el) => {
|
|
2966
3173
|
var _a, _b, _c, _d, _e;
|
|
2967
3174
|
if (el.tagName !== "A") return null;
|
|
@@ -3049,6 +3256,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3049
3256
|
label: "파일",
|
|
3050
3257
|
allowsInlineFormat: false,
|
|
3051
3258
|
allowedMarks: [],
|
|
3259
|
+
allowsColor: false,
|
|
3260
|
+
allowsFontSize: false,
|
|
3052
3261
|
matches: (el) => {
|
|
3053
3262
|
if (el.tagName !== "A") return null;
|
|
3054
3263
|
if (!el.classList.contains("aw-file-attachment")) return null;
|
|
@@ -3132,6 +3341,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3132
3341
|
label: "HTML",
|
|
3133
3342
|
allowsInlineFormat: false,
|
|
3134
3343
|
allowedMarks: [],
|
|
3344
|
+
allowsColor: false,
|
|
3345
|
+
allowsFontSize: false,
|
|
3135
3346
|
matches: (el) => {
|
|
3136
3347
|
if (el.tagName !== "DIV") return null;
|
|
3137
3348
|
if (el.getAttribute("data-imported-html") !== "true") return null;
|
|
@@ -3156,6 +3367,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3156
3367
|
label: "알 수 없음",
|
|
3157
3368
|
allowsInlineFormat: false,
|
|
3158
3369
|
allowedMarks: [],
|
|
3370
|
+
allowsColor: false,
|
|
3371
|
+
allowsFontSize: false,
|
|
3159
3372
|
matches: () => null,
|
|
3160
3373
|
create: () => fillEmpty(document.createElement("p")),
|
|
3161
3374
|
isEmpty: (el) => isElementBlank(el)
|
|
@@ -3430,6 +3643,72 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3430
3643
|
if (!target) return;
|
|
3431
3644
|
while (target.firstChild) target.removeChild(target.firstChild);
|
|
3432
3645
|
for (const node of content) target.appendChild(node);
|
|
3646
|
+
const type = BLOCK_TYPE_BY_KIND[kind];
|
|
3647
|
+
if (type) sanitizeInlineFormat(target, type);
|
|
3648
|
+
}
|
|
3649
|
+
function sanitizeInlineFormat(container, type) {
|
|
3650
|
+
const allowed = new Set(type.allowedMarks);
|
|
3651
|
+
for (const el of Array.from(container.querySelectorAll("*"))) {
|
|
3652
|
+
if (!(el instanceof HTMLElement)) continue;
|
|
3653
|
+
if (!el.parentNode) continue;
|
|
3654
|
+
const tag = el.tagName.toLowerCase();
|
|
3655
|
+
if ((tag === "b" || tag === "strong") && !allowed.has("bold") || (tag === "i" || tag === "em") && !allowed.has("italic") || tag === "u" && !allowed.has("underline") || (tag === "s" || tag === "strike" || tag === "del") && !allowed.has("strike")) {
|
|
3656
|
+
unwrapElement(el);
|
|
3657
|
+
continue;
|
|
3658
|
+
}
|
|
3659
|
+
if (tag === "span" || tag === "font") {
|
|
3660
|
+
const s = el.style;
|
|
3661
|
+
if (!allowed.has("bold")) {
|
|
3662
|
+
const fw = s.fontWeight;
|
|
3663
|
+
if (fw === "bold" || fw === "bolder" || /^[7-9]\d{2}$|^1000$/.test(fw)) {
|
|
3664
|
+
s.removeProperty("font-weight");
|
|
3665
|
+
}
|
|
3666
|
+
}
|
|
3667
|
+
if (!allowed.has("italic") && s.fontStyle === "italic") {
|
|
3668
|
+
s.removeProperty("font-style");
|
|
3669
|
+
}
|
|
3670
|
+
const td = s.textDecorationLine || s.textDecoration || "";
|
|
3671
|
+
if (td) {
|
|
3672
|
+
const parts = td.split(/\s+/);
|
|
3673
|
+
const kept = parts.filter((p) => {
|
|
3674
|
+
if (p === "underline" && !allowed.has("underline")) return false;
|
|
3675
|
+
if (p === "line-through" && !allowed.has("strike")) return false;
|
|
3676
|
+
return true;
|
|
3677
|
+
});
|
|
3678
|
+
if (kept.length !== parts.length) {
|
|
3679
|
+
s.removeProperty("text-decoration");
|
|
3680
|
+
s.removeProperty("text-decoration-line");
|
|
3681
|
+
if (kept.length > 0) s.textDecoration = kept.join(" ");
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
if (!type.allowsColor) {
|
|
3685
|
+
s.removeProperty("color");
|
|
3686
|
+
s.removeProperty("background-color");
|
|
3687
|
+
if (tag === "font") el.removeAttribute("color");
|
|
3688
|
+
}
|
|
3689
|
+
if (!type.allowsFontSize) {
|
|
3690
|
+
s.removeProperty("font-size");
|
|
3691
|
+
if (tag === "font") el.removeAttribute("size");
|
|
3692
|
+
}
|
|
3693
|
+
if (!type.allowsInlineFormat) {
|
|
3694
|
+
s.removeProperty("font-family");
|
|
3695
|
+
if (tag === "font") el.removeAttribute("face");
|
|
3696
|
+
}
|
|
3697
|
+
const hasStyle = s.cssText.trim().length > 0;
|
|
3698
|
+
const hasOtherAttrs = Array.from(el.attributes).some(
|
|
3699
|
+
(a) => a.name !== "style"
|
|
3700
|
+
);
|
|
3701
|
+
if (!hasStyle && !hasOtherAttrs) {
|
|
3702
|
+
unwrapElement(el);
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
}
|
|
3706
|
+
}
|
|
3707
|
+
function unwrapElement(el) {
|
|
3708
|
+
const parent = el.parentNode;
|
|
3709
|
+
if (!parent) return;
|
|
3710
|
+
while (el.firstChild) parent.insertBefore(el.firstChild, el);
|
|
3711
|
+
parent.removeChild(el);
|
|
3433
3712
|
}
|
|
3434
3713
|
function resolveTheme(theme = {}) {
|
|
3435
3714
|
const fg = theme.fg || "currentColor";
|
|
@@ -3582,12 +3861,32 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3582
3861
|
function mergeInlineStyle(el, portable) {
|
|
3583
3862
|
const existing = (el.getAttribute("style") ?? "").trim();
|
|
3584
3863
|
if (!existing) {
|
|
3585
|
-
|
|
3864
|
+
const trimmed = portable.replace(/;\s*$/, "").trim();
|
|
3865
|
+
if (trimmed) el.setAttribute("style", trimmed);
|
|
3586
3866
|
return;
|
|
3587
3867
|
}
|
|
3588
|
-
const
|
|
3589
|
-
const
|
|
3590
|
-
|
|
3868
|
+
const userDecls = parseStyleDeclarations(existing);
|
|
3869
|
+
const userProps = new Set(userDecls.map((d) => d.prop));
|
|
3870
|
+
const portableDecls = parseStyleDeclarations(portable).filter(
|
|
3871
|
+
(d) => !userProps.has(d.prop)
|
|
3872
|
+
);
|
|
3873
|
+
const merged = [...portableDecls, ...userDecls].map((d) => `${d.prop}:${d.value}`).join(";");
|
|
3874
|
+
if (merged) el.setAttribute("style", merged);
|
|
3875
|
+
else el.removeAttribute("style");
|
|
3876
|
+
}
|
|
3877
|
+
function parseStyleDeclarations(s) {
|
|
3878
|
+
const out = [];
|
|
3879
|
+
for (const part of s.split(";")) {
|
|
3880
|
+
const trimmed = part.trim();
|
|
3881
|
+
if (!trimmed) continue;
|
|
3882
|
+
const idx = trimmed.indexOf(":");
|
|
3883
|
+
if (idx <= 0) continue;
|
|
3884
|
+
const prop = trimmed.slice(0, idx).trim().toLowerCase();
|
|
3885
|
+
const value = trimmed.slice(idx + 1).trim();
|
|
3886
|
+
if (!prop || !value) continue;
|
|
3887
|
+
out.push({ prop, value });
|
|
3888
|
+
}
|
|
3889
|
+
return out;
|
|
3591
3890
|
}
|
|
3592
3891
|
function stripEditorOnlyAttrs(root) {
|
|
3593
3892
|
for (const el of Array.from(root.querySelectorAll("[data-block-kind]"))) {
|
|
@@ -4752,7 +5051,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
4752
5051
|
}
|
|
4753
5052
|
let imported;
|
|
4754
5053
|
try {
|
|
4755
|
-
imported = await importHtmlWithComputedStyles(result.html
|
|
5054
|
+
imported = await importHtmlWithComputedStyles(result.html, {
|
|
5055
|
+
mountTarget: this.content
|
|
5056
|
+
});
|
|
4756
5057
|
} catch (err) {
|
|
4757
5058
|
console.error("HTML 가져오기 실패:", err);
|
|
4758
5059
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -5269,27 +5570,15 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5269
5570
|
const type = BLOCK_TYPE_BY_KIND[active.kind] ?? BLOCK_TYPE_BY_KIND.unknown;
|
|
5270
5571
|
return type.allowsInlineFormat;
|
|
5271
5572
|
}
|
|
5272
|
-
const FONT_SIZE_ALLOWED_KINDS = /* @__PURE__ */ new Set([
|
|
5273
|
-
"paragraph",
|
|
5274
|
-
"bulletList",
|
|
5275
|
-
"orderedList",
|
|
5276
|
-
"blockquote",
|
|
5277
|
-
"codeBlock",
|
|
5278
|
-
"table"
|
|
5279
|
-
]);
|
|
5280
5573
|
function isFontSizeAllowed(active) {
|
|
5281
5574
|
if (!active) return false;
|
|
5282
|
-
|
|
5575
|
+
const type = BLOCK_TYPE_BY_KIND[active.kind] ?? BLOCK_TYPE_BY_KIND.unknown;
|
|
5576
|
+
return type.allowsFontSize;
|
|
5283
5577
|
}
|
|
5284
|
-
const COLOR_ALLOWED_KINDS = /* @__PURE__ */ new Set([
|
|
5285
|
-
"paragraph",
|
|
5286
|
-
"bulletList",
|
|
5287
|
-
"orderedList",
|
|
5288
|
-
"table"
|
|
5289
|
-
]);
|
|
5290
5578
|
function isColorAllowed(active) {
|
|
5291
5579
|
if (!active) return false;
|
|
5292
|
-
|
|
5580
|
+
const type = BLOCK_TYPE_BY_KIND[active.kind] ?? BLOCK_TYPE_BY_KIND.unknown;
|
|
5581
|
+
return type.allowsColor;
|
|
5293
5582
|
}
|
|
5294
5583
|
const ALIGN_ALLOWED_KINDS = /* @__PURE__ */ new Set([
|
|
5295
5584
|
"paragraph",
|