UNPKG

word-marker

Version:

The library used to tag web page text, which can store tag information.

507 lines (506 loc) 15.9 kB
/** wordMarker v1.1.16 * (c) 2025-7-23 * @license MIT */ const ot = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ __proto__: null }, Symbol.toStringTag, { value: "Module" })), E = "data-mark-id", B = (e) => { let r = ""; for (let t = 0; t < e; t++) { const s = Math.random() * 62 | 0; s < 10 ? r += s : s < 36 ? r += String.fromCharCode(65 + s - 10) : r += String.fromCharCode(97 + s - 36); } return r; }, y = (e) => Object.prototype.toString.call(e) === "[object Text]", K = (e, r = 50) => { let t = null; return () => { t && clearTimeout(t), t = setTimeout(() => { e(), t = null; }, r); }; }, Y = (e) => { const r = /translateY\((\d+(\.\d+)?)px\)/.exec(e.style.transform); return r ? Number(r[1]) : 0; }, z = (e, r) => { let t = e.parentElement; return t != null && t.parentElement && t.parentElement !== r && (t = t.parentElement), Array.from(t.children).map((s) => s.localName).join(","); }, _ = (e, r) => { var s; let t = e.parentElement; return (t == null ? void 0 : t.parentElement) === r ? "" : ((s = t.parentElement) == null ? void 0 : s.textContent) || ""; }, Q = (e, r, t = 1) => { const s = document.createElement("div"); s.setAttribute("style", `position: absolute; top: 0; left: 0; z-index: ${t}; pointer-events: none;`); const n = document.createElement("canvas"); return n.width = e.scrollWidth, n.height = r ? window.innerHeight * 3 : e.scrollHeight, s.appendChild(n), e.appendChild(s), n; }, V = (e) => { const r = []; let t = e.parentElement; for (; t; ) r.push(t), t = (t == null ? void 0 : t.parentElement) || null; return r; }, Z = (e, r) => { let t = e.parentElement; for (; t; ) { if (r.includes(t)) return t; t = (t == null ? void 0 : t.parentElement) || null; } return null; }, q = (e, r) => { let t = e == null ? void 0 : e.parentElement; for (; t; ) { if (t === r) return t; t = (t == null ? void 0 : t.parentElement) || null; } return null; }; let R = !1, M = !1; const X = (e, r, t, s) => { const n = []; return !e || R || Array.from(e.childNodes).forEach((o) => { R || (o.nodeType === 1 ? n.push(...X(o, r, t, s)) : o.nodeType === 3 && !(s != null && s(o)) && (!M && o === r && (M = !0), M && n.push(o)), o === t && (R = !0)); }), n; }, tt = (e, r, t) => { if (!e || !r) return []; if (e === r) return [e]; const s = V(e), n = Z(r, s), i = q(e, n), o = q(r, n); if (!i || !o) return []; const l = []; let c = i; for (; c !== o.nextSibling; ) R = !1, M = !1, l.push(...X(c, e, r, t)), c = c == null ? void 0 : c.nextSibling; return l; }, H = (e, r, t) => { const s = e.canvas; e.fillStyle = t.color, e.globalAlpha = t.globalAlpha, e.clearRect(0, 0, s.width, s.height); const n = Y(s); r.forEach((i) => { i.range.forEach((o) => { const { x: l, y: c, width: h, height: d } = o; if (c >= n && c <= n + window.innerHeight * 3) { const w = c - n; t.mark ? t.mark(e, { x: l, y: w, width: h, height: d }) : e.fillRect(l, w, h, d); } }); }); }, F = (e, r, t, s, n) => { const i = r.findIndex((l) => l.id === s); if (i > -1) { const l = r.splice(i, 1)[0]; if (l.startEle) { const c = k(l.startEle.parentElement, n.attribute || E); r.find((h) => h.startEleId === c) || $(l.startEle.parentElement, E); } if (l.endEle) { const c = k(l.endEle.parentElement, n.attribute || E); r.find((h) => h.endEleId === c) || $(l.endEle.parentElement, E); } } const o = t.findIndex((l) => l.id === s); o > -1 && (t.splice(o, 1), H(e, t, n)); }, G = (e, r, t, s) => { const n = r.getBoundingClientRect(), i = t.getClientRects(), o = []; for (let l = 0; l < i.length; l++) { const c = i[l], h = c.left - n.left, d = c.top - n.top, w = c.right - c.left, b = c.bottom - c.top; if (w === 0 || b === 0) continue; const A = Y(e.canvas), a = d - A; s == null || s({ x: h, y: a, width: w, height: b }), o.push({ x: h, y: d, width: w, height: b }); } return o; }, L = (e, r, t, s, n) => { const i = tt(r.startEle, r.endEle, n.ignoreNode), o = []; i.forEach((l, c) => { const h = document.createRange(); h.setStart(l, c === 0 ? r.startOffset : 0); let d = c === i.length - 1 ? r.endOffset : l.data.length; d > l.length && (d = l.length), h.setEnd(l, d); const w = G(e, s, h, (b) => { const { x: A, y: a, width: f, height: g } = b; n.mark ? n.mark(e, { x: A, y: a, width: f, height: g }) : e.fillRect(A, a, f, g); }); o.push(...w); }), t.push({ id: r.id, range: o, message: r.message }); }, k = (e, r) => { var t; return !e || !r ? "" : ((t = e.getAttribute) == null ? void 0 : t.call(e, r)) || ""; }, $ = (e, r) => { if (!(!e || !r)) return e.removeAttribute(r); }, J = (e = E, r) => !!document.querySelector(`[${e}="${r}"]`), O = (e, r, t) => { e && r && (e == null || e.setAttribute(r, t || "")); }; function et(e, r) { const t = nt(e, r); if (!t) return; const { firstNode: s, endNode: n } = t; let i = document.createRange(); i.setStart(s.node, s.index), i.setEnd(n.node, n.index); let o = window.getSelection(); o && (o.removeAllRanges(), o.addRange(i)); } function D(e, r) { var t; if ((t = e.textContent) != null && t.includes(r)) { for (const s of Array.from(e.children)) { let n = D(s, r); if (n) return D(n, r); } return e; } } function j(e, r, t, s = 0) { var n, i, o; for (const l of Array.from(e.childNodes)) { if (y(l)) s += ((n = l.textContent) == null ? void 0 : n.length) || 0; else { const c = j(l, r, t, s); if (typeof c == "number") s = c; else return c; } if (y(l)) { if (t === "start" && s > r) return { index: r - (s - (((i = l.textContent) == null ? void 0 : i.length) || 0)), node: l }; if (t === "end" && s >= r) return { index: r - (s - (((o = l.textContent) == null ? void 0 : o.length) || 0)), node: l }; } } return s; } function nt(e, r) { var o, l; if (!r || !((o = e.textContent) != null && o.includes(r))) return; const t = D(e, r); if (!t) return; const s = ((l = t.textContent) == null ? void 0 : l.indexOf(r)) || 0, n = j(t, s, "start"), i = j(t, s + r.length, "end"); if (!(typeof n == "number" || typeof i == "number")) return { firstNode: n, endNode: i }; } const U = (e, r) => { const { startEle: t, endEle: s } = e; if (!t || !s || !y(t) || !y(s)) return; let n = "", i = ""; r ? (n = k(t.parentElement, r), i = k(s.parentElement, r)) : (n = k(t.parentElement, E), n || (n = B(10), O(t.parentElement, E, n)), i = k(s.parentElement, E), i || (i = B(10), O(s.parentElement, E, i))), e.startEleId = n, e.endEleId = i; }, rt = (e, r) => { const t = r.getRangeAt(0), s = t.startContainer, n = t.endContainer; return !y(s) || !y(n) ? void 0 : { id: B(10), startEle: s, startOffset: t.startOffset, startText: s.data, startBrother: z(s, e), startParentText: _(s, e), endEle: n, endOffset: t.endOffset, endText: n.data, endBrother: z(n, e), endParentText: _(n, e), text: r.toString(), message: "", single: s === n }; }, I = (e) => { const r = []; return Array.from(e.childNodes).forEach((s) => { s.nodeType === 1 ? r.push(...I(s)) : s.nodeType === 3 && r.push(s); }), r; }, S = (e, r) => { const { startEle: t, startEleId: s, endEle: n, endEleId: i } = e; if (t && n && y(t) && y(n) && r === E) { const o = k(t.parentElement, E); s && !o && O(t.parentElement, E, s); const l = k(n.parentElement, E); i && !l && O(n.parentElement, E, i); } }, W = (e, r, t) => { if (e.nodeType !== 1) return; const s = e.textContent; for (const n of r) { if (!y(n.startEle)) { if (n.startEleId && J(t, n.startEleId)) { if (n.startEleId === k(e, t)) { const i = I(e); for (const o of i) if (o.data === n.startText) { n.startEle = o, n.single && (n.endEle = n.startEle, S(n, t)); break; } } } else if (!n.startParentText || n.startParentText === s) { if (Array.from(e == null ? void 0 : e.children).map((l) => l.localName).join(",") !== n.startBrother) continue; const o = I(e); for (const l of o) if (l.data === n.startText) { n.startEle = l, n.single && (n.endEle = n.startEle, S(n, t)); break; } } } if (!n.single && !y(n.endEle)) { if (n.endEleId && J(t, n.endEleId)) { if (n.endEleId === k(e, t)) { const i = I(e); for (const o of i) if (o.data === n.endText) { n.endEle = o, S(n, t); break; } } } else if (!n.endParentText || n.endParentText === s) { if (Array.from(e == null ? void 0 : e.children).map((l) => l.localName).join(",") !== n.endBrother) continue; const o = I(e); for (const l of o) if (l.data === n.endText) { n.endEle = l, S(n, t); break; } } } } }, P = (e, r, t) => { var o; const s = t.attribute || E; let n = !1; if (r.forEach((l) => { const c = e.querySelector(`[${s}="${l.startEleId}"]`), h = e.querySelector(`[${s}="${l.endEleId}"]`); c && c.childNodes.forEach((d) => { y(d) && d.textContent === l.startText && (l.startEle = d, l.single && (l.endEle = d)); }), h && !l.endEle && h.childNodes.forEach((d) => { y(d) && d.textContent === l.endText && (l.endEle = d); }), (!l.startEle || !l.endEle) && (n = !0); }), !n && !t.tag && !t.attribute) return; const i = Array.from(e.childNodes); for (r.length && W(e, r, t.attribute || E); i.length; ) { const l = i.shift(); l && ((o = t.tag) == null || o.call(t, l)), r.length && W(l, r, t.attribute || E); for (let c = 0; c < (l == null ? void 0 : l.childNodes.length); c++) i.push(l == null ? void 0 : l.childNodes[c]); } }, lt = (e, r, t, s, n) => { const i = e.getContext("2d"); i.clearRect(0, 0, e.width, e.height), r.forEach((o) => { L(i, o, t, s, n); }); }, st = { scrollBy: document, color: "rgba(224, 108, 117)", globalAlpha: 0.3, data: [] }; function it(e, r) { const t = { ...st, ...r }; let s = t.lazy === void 0 ? e.scrollHeight / 4 > window.innerHeight : t.lazy; s && e.scrollHeight <= window.innerHeight * 3 && (s = !1); const n = [], i = Q(e, s, t.zIndex), o = i.getContext("2d"); o.fillStyle = t.color, o.globalAlpha = t.globalAlpha; let l = JSON.parse(JSON.stringify(t.data)); (t.tag || l.length) && (P(e, l, t), l = l.filter((a) => a.startEle && a.endEle)), l.length && lt(i, l, n, e, t); let c = "", h = !1; const d = () => { var f, g, x; const a = window.getSelection(); if (a != null && a.toString()) { h = !0; const p = rt(e, a); if (!p) (f = t.callback) == null || f.call(t); else { const m = e.getBoundingClientRect(), v = a.getRangeAt(0), u = v.getBoundingClientRect(), T = G(o, e, v); (g = t.callback) == null || g.call(t, p, { x: u.x - m.x, y: u.y - m.y, width: u.width, height: u.height, range: T }); } } else (x = t.callback) == null || x.call(t); }, w = (a, f) => { var g; if (c !== a || f) { if (H(o, n, t), a) { const x = n.find((m) => m.id === a), p = Y(i); if (x) for (const m of x.range) { const { x: v, y: u, width: T, height: C } = m; let N = u; u >= p && u <= p + window.innerHeight * 3 && (N = u - p), (g = t.highlight) == null || g.call(t, o, { x: v, y: N, width: T, height: C }); } } c = a; } }, b = K(() => { const a = e.getBoundingClientRect(); let f = 0; a.y >= -window.innerHeight ? f = 0 : a.y <= window.innerHeight * 3 - e.scrollHeight ? f = e.scrollHeight - window.innerHeight * 3 : f = -window.innerHeight - a.y, i.style.transform = `translateY(${f}px)`, H(o, n, t), c && w(c, !0); }); t.callback && e.addEventListener("mouseup", d), s && (t.scrollBy.addEventListener("scroll", b), b()); let A = ""; return { // 自动选中文本 selectText: et, // 触发标记动作 triggerMarker: d, // 获取完整的标记数据 getActualMarkData() { return l.map((a) => ({ ...a })); }, /** * 获取所有的标记数据 * @returns 获取标记数据 */ getMarkData() { return JSON.parse(JSON.stringify(l, (a, f) => { if ((f == null ? void 0 : f.nodeType) !== 3) return f; })); }, /** * 添加标记 * @param data */ addMark(a) { if (Array.isArray(a)) { l.push(...a); for (const f of a) (!y(f.startEle) || !y(f.endEle)) && P(e, l, t), U(f, t.attribute), L(o, f, n, e, t); } else l.push(a), (!y(a.startEle) || !y(a.endEle)) && P(e, l, t), U(a, t.attribute), L(o, a, n, e, t); }, /** * 修改标记备注 * @param id * @param msg */ modifyMark(a, f) { const g = l.find((p) => p.id === a); g && (g.message = f); const x = n.find((p) => p.id === a); x && (x.message = f); }, /** * 根据 ID 获取标记位置 * @param id * @returns */ getPosition(a) { const f = n.find((g) => g.id === a); if (f) { let g = 1 / 0, x = 1 / 0; for (const p of f.range) g = Math.min(g, p.x), x = Math.min(x, p.y); return { x: g, y: x, range: f.range }; } }, /** * 根据 ID 删除标记 * @param id */ deleteMark(a) { if (Array.isArray(a)) for (const f of a) F(o, l, n, f, t); else F(o, l, n, a, t); }, /** * 根据 x y 获取该位置是否有标记 * @param x * @param y * @returns */ checkMark(a, f) { if (h) { h = !1; return; } const g = e.getBoundingClientRect(), x = a - window.scrollX - g.left, p = f - window.scrollY - g.top, m = []; let v = !1; for (const u of n) for (const T of u.range) if (x >= T.x && x <= T.x + T.width && p >= T.y && p <= T.y + T.height) { const C = l.find((N) => N.id === u.id); C && (m.push(C), v || (v = A === C.id)); } if (!m.length) { A = ""; return; } if (!v) return A = m[0].id, { ...m[0] }; for (let u = 0; u < m.length; u++) if (m[u].id === A) return u === m.length - 1 ? (A = m[0].id, { ...m[0] }) : (A = m[u + 1].id, { ...m[u + 1] }); }, /** * 高亮标记 * @param id */ highlightMark: w, /** * 重新刷新标记 */ refresh() { H(o, n, t); }, /** * 清除所有标记 */ clear() { l = [], n.length = 0, o.clearRect(0, 0, i.width, i.height); const a = document.querySelectorAll(`[${E}]`); a.length && Array.from(a).forEach((f) => { $(f, E); }); }, /** * 销毁所有事件 */ destroy() { var a; t.callback && e.removeEventListener("mouseup", d), s && t.scrollBy.removeEventListener("scroll", b), this.clear(), (a = i.parentElement) == null || a.remove(); }, /** * @deprecated 请使用 destroy 方法 */ destory() { var a; t.callback && e.removeEventListener("mouseup", d), s && t.scrollBy.removeEventListener("scroll", b), this.clear(), (a = i.parentElement) == null || a.remove(); } }; } export { ot as WordMarker, it as default };