UNPKG

@diplodoc/transform

Version:

A simple transformer of text in YFM (Yandex Flavored Markdown) to HTML

612 lines (601 loc) 21.5 kB
"use strict"; (() => { var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); // node_modules/get-root-node-polyfill/index.js var require_get_root_node_polyfill = __commonJS({ "node_modules/get-root-node-polyfill/index.js"(exports, module) { "use strict"; function getRootNode2(opt) { var composed = typeof opt === "object" && Boolean(opt.composed); return composed ? getShadowIncludingRoot(this) : getRoot(this); } function getShadowIncludingRoot(node) { var root = getRoot(node); if (isShadowRoot(root)) { return getShadowIncludingRoot(root.host); } return root; } function getRoot(node) { if (node.parentNode != null) { return getRoot(node.parentNode); } return node; } function isShadowRoot(node) { return node.nodeName === "#document-fragment" && node.constructor.name === "ShadowRoot"; } if (typeof module === "object" && module.exports) { module.exports = getRootNode2; } } }); // src/js/polyfill.js var import_get_root_node_polyfill = __toESM(require_get_root_node_polyfill()); if (typeof document !== "undefined") { (function(e) { const matches = e.matches || e.matchesSelector || e.webkitMatchesSelector || e.mozMatchesSelector || e.msMatchesSelector || e.oMatchesSelector; if (matches) { e.matches = e.matchesSelector = matches; } else { e.matches = e.matchesSelector = function matches2(selector) { const rootNode = e.getRootNode ? e.getRootNode() : import_get_root_node_polyfill.default.call(e); const matches3 = rootNode.querySelectorAll(selector); const th = this; return Array.prototype.some.call(matches3, (e2) => { return e2 === th; }); }; } })(Element.prototype); } // src/js/utils.ts var getEventTarget = (event) => { const path = event.composedPath(); return Array.isArray(path) && path.length > 0 ? path[0] : event.target; }; var isCustom = (event) => { const target = getEventTarget(event); return !target || !target.matches; }; var copyToClipboard = async (text) => { if (!text) { return; } if (navigator.clipboard && typeof navigator.clipboard.writeText) { return navigator.clipboard.writeText(text); } const textarea = document.createElement("textarea"); textarea.setAttribute("style", "position: absolute; left: 1000%"); textarea.textContent = text; document.body.append(textarea); textarea.select(); document.execCommand("copy"); document.body.removeChild(textarea); }; // src/js/code.ts var COPY_BUTTON_SELECTOR = ".yfm-clipboard-button"; var WRAP_BUTTON_SELECTOR = ".yfm-wrapping-button"; function notifySuccess(svgButton) { if (!svgButton) { return; } const id = svgButton.getAttribute("data-animation"); const icon = svgButton.getRootNode().getElementById(`visibileAnimation-${id}`); if (!icon) { return; } icon.beginElement(); } function buttonCopyFn(target) { var _a; const container = (_a = target.parentNode) == null ? void 0 : _a.parentNode; const code = container == null ? void 0 : container.querySelector("pre code"); if (!container || !code) { return; } const textContent = Array.from(code.childNodes).filter((node) => { if (node instanceof HTMLElement && node.classList.contains("yfm-line-number")) { return false; } return true; }).map((node) => node.textContent).join(""); copyToClipboard(textContent.trim()).then(() => { notifySuccess(container.querySelector(".yfm-clipboard-icon")); setTimeout(() => target.blur(), 1500); }); } function buttonWrapFn(target) { var _a; const container = (_a = target.parentNode) == null ? void 0 : _a.parentNode; const code = container == null ? void 0 : container.querySelector("pre code"); if (!container || !code) { return; } code.classList.toggle("wrap"); setTimeout(() => target.blur(), 500); } if (typeof document !== "undefined") { document.addEventListener("click", (event) => { if (isCustom(event)) { return; } const target = getEventTarget(event); if (target.matches(COPY_BUTTON_SELECTOR)) { buttonCopyFn(target); } else if (target.matches(WRAP_BUTTON_SELECTOR)) { buttonWrapFn(target); } }); } // src/js/tooltip/constant.ts var PAGE_CONTAINER_SELECTOR = ".dc-doc-page__content"; var TOOLTIP_BASE_CLASS = "yfm yfm-tooltip"; var TOOLTIP_OPEN_CLASS = "open"; var TOOLTIP_DATA_ATTR = "data-tooltip-id"; var DEFAULT_OFFSET_VALUES = { mainAxis: 5 }; var OPPOSITE_SIDES = { top: "bottom", bottom: "top", left: "right", right: "left" }; var DEFAULT_SIDE_OBJECT = { top: 0, bottom: 0, left: 0, right: 0 }; // src/js/tooltip/utils.ts function isVerticalSide(side) { return side === "top" || side === "bottom"; } function createSideObject(value = 0) { if (typeof value === "number") { return { top: value, bottom: value, left: value, right: value }; } return { ...DEFAULT_SIDE_OBJECT, ...value }; } function parsePlacement(placement) { const [side, alignment] = placement.split("-"); return { side, alignment }; } function getOppositeSide(side) { return OPPOSITE_SIDES[side]; } function flipPlacement(placement) { const { side, alignment } = parsePlacement(placement); const opposite = getOppositeSide(side); return alignment ? `${opposite}-${alignment}` : opposite; } function getOverflow(tooltip3, coords, viewport) { const rect = updateRect(tooltip3, { top: coords.y, left: coords.x }); return detectOverflow(viewport, rect, 5); } function shouldFlip(overflow, flippedOverflow, side) { const opposite = getOppositeSide(side); return overflow[side] > 0 && flippedOverflow[opposite] < overflow[side]; } function computePosition(reference, tooltip3, viewport, placement, offset, isRtl, flip = true) { const coords = computeCoordsFromPlacement(reference, tooltip3, offset, placement, isRtl); if (!flip) { return { coords, placement }; } const overflow = getOverflow(tooltip3, coords, viewport); const { side } = parsePlacement(placement); if (overflow[side] <= 0) { return { coords, placement }; } const flipped = flipPlacement(placement); const flippedCoords = computeCoordsFromPlacement(reference, tooltip3, offset, flipped, isRtl); const flippedOverflow = getOverflow(tooltip3, flippedCoords, viewport); if (shouldFlip(overflow, flippedOverflow, side)) { return { coords: flippedCoords, placement: flipped }; } return { coords, placement }; } function generateId() { const random = Math.random().toString(36).substring(2, 6); const now = Date.now().toString(36); return `${random}${now}`; } function createRect(params) { return { ...params, right: params.left + params.width, bottom: params.top + params.height }; } function updateRect(rect, params) { var _a, _b, _c, _d; return createRect({ top: (_a = params.top) != null ? _a : rect.top, left: (_b = params.left) != null ? _b : rect.left, width: (_c = params.width) != null ? _c : rect.width, height: (_d = params.height) != null ? _d : rect.height }); } function getViewportRect() { const { documentElement, body } = document; const scrollTop = window.scrollY || documentElement.scrollTop || body.scrollTop; const scrollLeft = window.scrollX || documentElement.scrollLeft || body.scrollLeft; const clientTop = documentElement.clientTop || body.clientTop || 0; const clientLeft = documentElement.clientLeft || body.clientLeft || 0; return createRect({ top: Math.round(scrollTop - clientTop), left: Math.round(scrollLeft - clientLeft), width: document.body.clientWidth, height: document.body.clientHeight }); } function getElementRect(element) { const viewport = getViewportRect(); const box = element.getBoundingClientRect(); return createRect({ top: Math.round(box.top + viewport.top), left: Math.round(box.left + viewport.left), width: box.width, height: box.height }); } function computeAxisOffset(offset, side, isRtl) { const { mainAxis = 0, crossAxis = 0 } = offset; const isVertical = isVerticalSide(side); const mainDirection = side === "top" || side === "left" ? -1 : 1; const crossDirection = isRtl && isVertical ? -1 : 1; const mainOffset = mainAxis * mainDirection; const crossOffset = crossAxis * crossDirection; if (isVertical) { return { x: crossOffset, y: mainOffset }; } return { x: mainOffset, y: crossOffset }; } function computeCoordsFromPlacement(reference, tooltip3, offset, placement, isRtl) { const { side, alignment } = parsePlacement(placement); const isVertical = isVerticalSide(side); const alignmentAxis = isVertical ? "x" : "y"; const alignLength = alignmentAxis === "y" ? "height" : "width"; const centerX = reference.left + reference.width / 2 - tooltip3.width / 2; const centerY = reference.top + reference.height / 2 - tooltip3.height / 2; const alignmentOffset = reference[alignLength] / 2 - tooltip3[alignLength] / 2; const coords = { x: reference.left, y: reference.top }; switch (side) { case "top": { coords.x = centerX; coords.y = reference.top - tooltip3.height; break; } case "bottom": { coords.x = centerX; coords.y = reference.top + reference.height; break; } case "right": { coords.x = reference.left + reference.width; coords.y = centerY; break; } case "left": { coords.x = reference.left - tooltip3.width; coords.y = centerY; break; } } switch (alignment) { case "start": { coords[alignmentAxis] -= alignmentOffset * (isRtl && isVertical ? -1 : 1); break; } case "end": { coords[alignmentAxis] += alignmentOffset * (isRtl && isVertical ? -1 : 1); break; } } const axisOffset = computeAxisOffset(offset, side, isRtl); coords.x += axisOffset.x; coords.y += axisOffset.y; return coords; } function convertToRelativeToOffsetParentRect(rect, offsetParent) { const offsetRect = getElementRect(offsetParent); return createRect({ top: rect.top - offsetRect.top + offsetParent.offsetTop, left: rect.left - offsetRect.left + offsetParent.offsetLeft, width: rect.width, height: rect.height }); } function detectOverflow(boundary, element, padding = 0) { const { top, bottom, left, right } = createSideObject(padding); return { top: boundary.top - element.top + top, bottom: element.bottom - boundary.bottom + bottom, left: boundary.left - element.left + left, right: element.right - boundary.right + right }; } // src/js/tooltip/tooltip.ts function createTooltipFactory(options = {}) { const { closeDelay = 1e3, additionalClassName } = options; let initialized = false; const state = { currentId: null, timer: null, unsubscribe: null }; const getActiveTooltip = () => { if (!state.currentId) { return null; } return document.getElementById(state.currentId); }; const getActiveReference = () => { if (!state.currentId) { return null; } return getReferenceByTooltipId(state.currentId); }; const hide = () => { const tooltip3 = getActiveTooltip(); if (state.timer) { clearTimeout(state.timer); state.timer = null; } if (state.unsubscribe) { state.unsubscribe(); state.unsubscribe = null; } if (tooltip3) { tooltip3.classList.remove(TOOLTIP_OPEN_CLASS); detachTooltip(tooltip3); state.currentId = null; } }; const show = (reference, text) => { hide(); const tooltip3 = createTooltipElement({ text, className: additionalClassName }); const update = updateTooltipPosition.bind(null, options, reference, tooltip3); state.currentId = tooltip3.id; attachTooltip(tooltip3, reference); state.unsubscribe = subscribeToScroll(reference, update); tooltip3.classList.add(TOOLTIP_OPEN_CLASS); update(); if (closeDelay > 0) { state.timer = setTimeout(hide, closeDelay); } }; const handleUpdate = () => { const activeTooltip = getActiveTooltip(); const activeReference = getActiveReference(); if (activeTooltip && !activeReference) { hide(); return; } if (activeTooltip && activeReference) { updateTooltipPosition(options, activeReference, activeTooltip); } }; const init = () => { if (!initialized) { initialized = true; window.addEventListener("scroll", handleUpdate); window.addEventListener("resize", handleUpdate); } }; const cleanup = () => { if (initialized) { initialized = false; window.removeEventListener("scroll", handleUpdate); window.removeEventListener("resize", handleUpdate); } }; return { get visible() { return Boolean(state.currentId); }, getActiveReference, show, hide, init, cleanup }; } function createTooltipElement(options) { const { text, className } = options; const id = generateId(); const tooltip3 = document.createElement("div"); tooltip3.id = id; tooltip3.className = className ? `${TOOLTIP_BASE_CLASS} ${className}` : TOOLTIP_BASE_CLASS; tooltip3.setAttribute("role", "tooltip"); tooltip3.setAttribute("aria-live", "polite"); tooltip3.textContent = text; return tooltip3; } function attachTooltip(tooltip3, reference) { const container = document.querySelector(PAGE_CONTAINER_SELECTOR) || document.body; const ariaLive = reference.getAttribute("aria-live"); reference.setAttribute(TOOLTIP_DATA_ATTR, tooltip3.id); if (ariaLive) { tooltip3.setAttribute("aria-live", ariaLive); } container.appendChild(tooltip3); } function detachTooltip(tooltip3) { if (tooltip3.id) { const reference = getReferenceByTooltipId(tooltip3.id); reference == null ? void 0 : reference.removeAttribute(TOOLTIP_DATA_ATTR); } tooltip3.remove(); } function getReferenceByTooltipId(id) { return document.querySelector(`[${TOOLTIP_DATA_ATTR}="${id}"]`); } function subscribeToScroll(reference, update) { const scrollableElement = getParentScrollableElement(reference); scrollableElement.addEventListener("scroll", update); return () => { scrollableElement.removeEventListener("scroll", update); }; } function getParentScrollableElement(target) { const closestScrollableParent = target.closest("table") || target.closest("code"); return closestScrollableParent || target.parentElement || document.body; } function createTooltipContext(referenceElement, tooltipElement) { const tooltipParent = tooltipElement.parentElement; if (!tooltipParent) { return null; } const elements = { reference: referenceElement, tooltip: tooltipElement, offsetParent: tooltipParent }; const viewport = getViewportRect(); const reference = getElementRect(referenceElement); const { width, height } = tooltipElement.getBoundingClientRect(); return { isRtl: document.dir === "rtl", viewport, reference, tooltip: createRect({ top: 0, left: 0, width, height }), elements }; } function updateTooltipPosition(options, referenceElement, tooltipElement) { const context = createTooltipContext(referenceElement, tooltipElement); if (!context) { return; } const coords = getTooltipCoords(context, options); tooltipElement.style.top = `${coords.y}px`; tooltipElement.style.left = `${coords.x}px`; } function getTooltipCoords(context, options) { const { placement = "bottom-start", offset = DEFAULT_OFFSET_VALUES, flip = true } = options; const { reference, tooltip: tooltip3, viewport, isRtl } = context; const { coords } = computePosition(reference, tooltip3, viewport, placement, offset, isRtl, flip); const rect = updateRect(tooltip3, { top: coords.y, left: coords.x }); const relativeRect = convertToRelativeToOffsetParentRect(rect, context.elements.offsetParent); return { x: relativeRect.left, y: relativeRect.top }; } // src/js/constant.ts var COPIED_LANG_TOKEN = { ru: "\u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u043D\u043E", en: "Copied", ar: "\u062A\u0645 \u0627\u0644\u0646\u0633\u062E", cs: "Zkop\xEDrov\xE1no", fr: "Copi\xE9", es: "Copiado", he: "\u05D4\u05D5\u05E2\u05EA\u05E7", bg: "\u041A\u043E\u043F\u0438\u0440\u0430\u043D\u043E", et: "Kopeeritud", el: "\u0391\u03BD\u03C4\u03B9\u03B3\u03C1\u03AC\u03C6\u03B7\u03BA\u03B5", pt: "Copiado", zh: "\u5DF2\u590D\u5236", "zh-tw": "\u5DF2\u8907\u88FD", kk: "\u041A\u04E9\u0448\u0456\u0440\u0456\u043B\u0434\u0456", tr: "Kopyaland\u0131", uz: "Nusxalandi" }; // src/js/anchor.ts var ALLOWED_PROTOCOL_RE = /^(?:https?|file):$/; var ANCHOR_BUTTON_SELECTOR = ".yfm-clipboard-anchor"; var tooltip = createTooltipFactory(); function getLink(target) { const href = target.nodeName === "A" ? target.href : target.dataset.href; const link = new URL(href || "", window.location.href); if (ALLOWED_PROTOCOL_RE.test(link.protocol)) { return link.href; } return window.location.href; } if (typeof document !== "undefined") { tooltip.init(); document.addEventListener("click", (event) => { const target = getEventTarget(event); if (isCustom(event) || !target.matches(ANCHOR_BUTTON_SELECTOR)) { return; } const link = getLink(target); copyToClipboard(link).then(() => { var _a; const lang = document.documentElement.lang || "en"; const tooltipText = (_a = COPIED_LANG_TOKEN[lang]) != null ? _a : COPIED_LANG_TOKEN.en; tooltip.show(target, tooltipText); }); }); } // src/js/inline-code/index.ts var CLASS_INLINE_CODE = "yfm-clipboard-inline-code"; var INLINE_CODE = `.${CLASS_INLINE_CODE}`; var tooltip2 = createTooltipFactory({ // NOTE: Add additional className for backward capability additionalClassName: "inline_code_tooltip" }); function inlineCopyFn(target) { const innerText = target.innerText; if (!innerText) { return; } copyToClipboard(innerText).then(() => { var _a; const lang = document.documentElement.lang || "en"; const tooltipText = (_a = COPIED_LANG_TOKEN[lang]) != null ? _a : COPIED_LANG_TOKEN.en; tooltip2.show(target, tooltipText); }); } if (typeof document !== "undefined") { tooltip2.init(); document.addEventListener("click", (event) => { const target = getEventTarget(event); const inline = target.matches(INLINE_CODE); if (isCustom(event) || !inline) { return; } inlineCopyFn(target); }); document.addEventListener("keydown", (event) => { if (event.key === "Enter" && document.activeElement) { const activeElement = document.activeElement; if (!activeElement.classList.contains(CLASS_INLINE_CODE)) { return; } inlineCopyFn(activeElement); } if (event.key === "Escape" && tooltip2.visible) { const reference = tooltip2.getActiveReference(); tooltip2.hide(); reference == null ? void 0 : reference.focus(); } }); } })(); //# sourceMappingURL=base.js.map