UNPKG

jodit

Version:

Jodit is an awesome and useful wysiwyg editor with filebrowser

123 lines (122 loc) 4.89 kB
/*! * Jodit Editor (https://xdsoft.net/jodit/) * Released under MIT see LICENSE.txt in the project root for license information. * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net */ /** * @module helpers/html */ import { globalDocument, IS_PROD } from "../../constants.js"; import { Dom } from "../../dom/dom.js"; import { trim } from "../string/trim.js"; import { $$ } from "../utils/selector.js"; function normalizeCSS(s) { return s .replace(/mso-[a-z-]+:[\s]*[^;]+;/gi, '') .replace(/mso-[a-z-]+:[\s]*[^";']+$/gi, '') .replace(/border[a-z-]*:[\s]*[^;]+;/gi, '') .replace(/([0-9.]+)(pt|cm)/gi, (match, units, metrics) => { switch (metrics.toLowerCase()) { case 'pt': return (parseFloat(units) * 1.328).toFixed(0) + 'px'; case 'cm': return (parseFloat(units) * 0.02645833).toFixed(0) + 'px'; } return match; }); } /** * If the HTML has CSS rules with selectors, * it applies them to the selectors in the HTML itself * and then removes the selector styles, leaving only the inline ones. */ export function applyStyles(html) { // Match the opening <html> tag whether or not it carries attributes. MS // Word emits `<html xmlns:o=…>` (note the trailing space), but Excel/Calc // wrap the copied table in a bare `<html>`. The old `'<html '` check missed // the bare tag, so for Excel clipboards the `<style>` rules (class-based // cell backgrounds/borders, e.g. `.xl31 { background:#FCE4D6 }`) were never // inlined and all styling was lost once the `<style>` block got stripped. // See https://github.com/xdan/jodit/issues/1362 const openMatch = /<html(?:\s[^>]*)?>/i.exec(html); if (!openMatch) { return html; } html = html.substring(openMatch.index); const closeIndex = html.toLowerCase().lastIndexOf('</html>'); if (closeIndex !== -1) { html = html.substring(0, closeIndex + '</html>'.length); } const iframe = globalDocument.createElement('iframe'); iframe.style.display = 'none'; globalDocument.body.appendChild(iframe); let convertedString = '', collection = []; try { const iframeDoc = iframe.contentDocument || (iframe.contentWindow ? iframe.contentWindow.document : null); if (iframeDoc) { iframeDoc.open(); iframeDoc.write(html); iframeDoc.close(); // Word marks its auto-generated list markers (the literal // bullet/number, e.g. `1.` or `·`) with `mso-list:Ignore`. // They are display-only and must not be imported, otherwise // the marker text leaks into the content. Drop them before any // style normalization strips the `mso-list` hint. See #948 Dom.each(iframeDoc.body, (node) => { if (Dom.isElement(node) && /mso-list:\s*ignore/i.test(node.getAttribute('style') || '')) { Dom.safeRemove(node); } }); try { for (let i = 0; i < iframeDoc.styleSheets.length; i += 1) { const rules = iframeDoc.styleSheets[i].cssRules; for (let idx = 0; idx < rules.length; idx += 1) { if (rules[idx].selectorText === '') { continue; } collection = $$(rules[idx].selectorText, iframeDoc.body); collection.forEach((elm) => { elm.style.cssText = normalizeCSS(rules[idx].style.cssText + ';' + elm.style.cssText); }); } } } catch (e) { if (!IS_PROD) { throw e; } } Dom.each(iframeDoc.body, node => { if (Dom.isElement(node)) { const elm = node; const css = elm.getAttribute('style'); if (css) { elm.style.cssText = normalizeCSS(css); } if (elm.hasAttribute('style') && !elm.getAttribute('style')) { elm.removeAttribute('style'); } } }); convertedString = iframeDoc.firstChild ? trim(iframeDoc.body.innerHTML) : ''; } } catch (_a) { } finally { Dom.safeRemove(iframe); } if (convertedString) { html = convertedString; } return trim(html .replace(/<(\/)?(html|colgroup|col|o:p)[^>]*>/g, '') .replace(/<!--[^>]*>/g, '')); }