Spaces:
Paused
Paused
| import { TAG_ID as $, NS, ATTRS, getTagID } from './html.js'; | |
| //MIME types | |
| const MIME_TYPES = { | |
| TEXT_HTML: 'text/html', | |
| APPLICATION_XML: 'application/xhtml+xml', | |
| }; | |
| //Attributes | |
| const DEFINITION_URL_ATTR = 'definitionurl'; | |
| const ADJUSTED_DEFINITION_URL_ATTR = 'definitionURL'; | |
| const SVG_ATTRS_ADJUSTMENT_MAP = new Map([ | |
| 'attributeName', | |
| 'attributeType', | |
| 'baseFrequency', | |
| 'baseProfile', | |
| 'calcMode', | |
| 'clipPathUnits', | |
| 'diffuseConstant', | |
| 'edgeMode', | |
| 'filterUnits', | |
| 'glyphRef', | |
| 'gradientTransform', | |
| 'gradientUnits', | |
| 'kernelMatrix', | |
| 'kernelUnitLength', | |
| 'keyPoints', | |
| 'keySplines', | |
| 'keyTimes', | |
| 'lengthAdjust', | |
| 'limitingConeAngle', | |
| 'markerHeight', | |
| 'markerUnits', | |
| 'markerWidth', | |
| 'maskContentUnits', | |
| 'maskUnits', | |
| 'numOctaves', | |
| 'pathLength', | |
| 'patternContentUnits', | |
| 'patternTransform', | |
| 'patternUnits', | |
| 'pointsAtX', | |
| 'pointsAtY', | |
| 'pointsAtZ', | |
| 'preserveAlpha', | |
| 'preserveAspectRatio', | |
| 'primitiveUnits', | |
| 'refX', | |
| 'refY', | |
| 'repeatCount', | |
| 'repeatDur', | |
| 'requiredExtensions', | |
| 'requiredFeatures', | |
| 'specularConstant', | |
| 'specularExponent', | |
| 'spreadMethod', | |
| 'startOffset', | |
| 'stdDeviation', | |
| 'stitchTiles', | |
| 'surfaceScale', | |
| 'systemLanguage', | |
| 'tableValues', | |
| 'targetX', | |
| 'targetY', | |
| 'textLength', | |
| 'viewBox', | |
| 'viewTarget', | |
| 'xChannelSelector', | |
| 'yChannelSelector', | |
| 'zoomAndPan', | |
| ].map((attr) => [attr.toLowerCase(), attr])); | |
| const XML_ATTRS_ADJUSTMENT_MAP = new Map([ | |
| ['xlink:actuate', { prefix: 'xlink', name: 'actuate', namespace: NS.XLINK }], | |
| ['xlink:arcrole', { prefix: 'xlink', name: 'arcrole', namespace: NS.XLINK }], | |
| ['xlink:href', { prefix: 'xlink', name: 'href', namespace: NS.XLINK }], | |
| ['xlink:role', { prefix: 'xlink', name: 'role', namespace: NS.XLINK }], | |
| ['xlink:show', { prefix: 'xlink', name: 'show', namespace: NS.XLINK }], | |
| ['xlink:title', { prefix: 'xlink', name: 'title', namespace: NS.XLINK }], | |
| ['xlink:type', { prefix: 'xlink', name: 'type', namespace: NS.XLINK }], | |
| ['xml:lang', { prefix: 'xml', name: 'lang', namespace: NS.XML }], | |
| ['xml:space', { prefix: 'xml', name: 'space', namespace: NS.XML }], | |
| ['xmlns', { prefix: '', name: 'xmlns', namespace: NS.XMLNS }], | |
| ['xmlns:xlink', { prefix: 'xmlns', name: 'xlink', namespace: NS.XMLNS }], | |
| ]); | |
| //SVG tag names adjustment map | |
| export const SVG_TAG_NAMES_ADJUSTMENT_MAP = new Map([ | |
| 'altGlyph', | |
| 'altGlyphDef', | |
| 'altGlyphItem', | |
| 'animateColor', | |
| 'animateMotion', | |
| 'animateTransform', | |
| 'clipPath', | |
| 'feBlend', | |
| 'feColorMatrix', | |
| 'feComponentTransfer', | |
| 'feComposite', | |
| 'feConvolveMatrix', | |
| 'feDiffuseLighting', | |
| 'feDisplacementMap', | |
| 'feDistantLight', | |
| 'feFlood', | |
| 'feFuncA', | |
| 'feFuncB', | |
| 'feFuncG', | |
| 'feFuncR', | |
| 'feGaussianBlur', | |
| 'feImage', | |
| 'feMerge', | |
| 'feMergeNode', | |
| 'feMorphology', | |
| 'feOffset', | |
| 'fePointLight', | |
| 'feSpecularLighting', | |
| 'feSpotLight', | |
| 'feTile', | |
| 'feTurbulence', | |
| 'foreignObject', | |
| 'glyphRef', | |
| 'linearGradient', | |
| 'radialGradient', | |
| 'textPath', | |
| ].map((tn) => [tn.toLowerCase(), tn])); | |
| //Tags that causes exit from foreign content | |
| const EXITS_FOREIGN_CONTENT = new Set([ | |
| $.B, | |
| $.BIG, | |
| $.BLOCKQUOTE, | |
| $.BODY, | |
| $.BR, | |
| $.CENTER, | |
| $.CODE, | |
| $.DD, | |
| $.DIV, | |
| $.DL, | |
| $.DT, | |
| $.EM, | |
| $.EMBED, | |
| $.H1, | |
| $.H2, | |
| $.H3, | |
| $.H4, | |
| $.H5, | |
| $.H6, | |
| $.HEAD, | |
| $.HR, | |
| $.I, | |
| $.IMG, | |
| $.LI, | |
| $.LISTING, | |
| $.MENU, | |
| $.META, | |
| $.NOBR, | |
| $.OL, | |
| $.P, | |
| $.PRE, | |
| $.RUBY, | |
| $.S, | |
| $.SMALL, | |
| $.SPAN, | |
| $.STRONG, | |
| $.STRIKE, | |
| $.SUB, | |
| $.SUP, | |
| $.TABLE, | |
| $.TT, | |
| $.U, | |
| $.UL, | |
| $.VAR, | |
| ]); | |
| //Check exit from foreign content | |
| export function causesExit(startTagToken) { | |
| const tn = startTagToken.tagID; | |
| const isFontWithAttrs = tn === $.FONT && | |
| startTagToken.attrs.some(({ name }) => name === ATTRS.COLOR || name === ATTRS.SIZE || name === ATTRS.FACE); | |
| return isFontWithAttrs || EXITS_FOREIGN_CONTENT.has(tn); | |
| } | |
| //Token adjustments | |
| export function adjustTokenMathMLAttrs(token) { | |
| for (let i = 0; i < token.attrs.length; i++) { | |
| if (token.attrs[i].name === DEFINITION_URL_ATTR) { | |
| token.attrs[i].name = ADJUSTED_DEFINITION_URL_ATTR; | |
| break; | |
| } | |
| } | |
| } | |
| export function adjustTokenSVGAttrs(token) { | |
| for (let i = 0; i < token.attrs.length; i++) { | |
| const adjustedAttrName = SVG_ATTRS_ADJUSTMENT_MAP.get(token.attrs[i].name); | |
| if (adjustedAttrName != null) { | |
| token.attrs[i].name = adjustedAttrName; | |
| } | |
| } | |
| } | |
| export function adjustTokenXMLAttrs(token) { | |
| for (let i = 0; i < token.attrs.length; i++) { | |
| const adjustedAttrEntry = XML_ATTRS_ADJUSTMENT_MAP.get(token.attrs[i].name); | |
| if (adjustedAttrEntry) { | |
| token.attrs[i].prefix = adjustedAttrEntry.prefix; | |
| token.attrs[i].name = adjustedAttrEntry.name; | |
| token.attrs[i].namespace = adjustedAttrEntry.namespace; | |
| } | |
| } | |
| } | |
| export function adjustTokenSVGTagName(token) { | |
| const adjustedTagName = SVG_TAG_NAMES_ADJUSTMENT_MAP.get(token.tagName); | |
| if (adjustedTagName != null) { | |
| token.tagName = adjustedTagName; | |
| token.tagID = getTagID(token.tagName); | |
| } | |
| } | |
| //Integration points | |
| function isMathMLTextIntegrationPoint(tn, ns) { | |
| return ns === NS.MATHML && (tn === $.MI || tn === $.MO || tn === $.MN || tn === $.MS || tn === $.MTEXT); | |
| } | |
| function isHtmlIntegrationPoint(tn, ns, attrs) { | |
| if (ns === NS.MATHML && tn === $.ANNOTATION_XML) { | |
| for (let i = 0; i < attrs.length; i++) { | |
| if (attrs[i].name === ATTRS.ENCODING) { | |
| const value = attrs[i].value.toLowerCase(); | |
| return value === MIME_TYPES.TEXT_HTML || value === MIME_TYPES.APPLICATION_XML; | |
| } | |
| } | |
| } | |
| return ns === NS.SVG && (tn === $.FOREIGN_OBJECT || tn === $.DESC || tn === $.TITLE); | |
| } | |
| export function isIntegrationPoint(tn, ns, attrs, foreignNS) { | |
| return (((!foreignNS || foreignNS === NS.HTML) && isHtmlIntegrationPoint(tn, ns, attrs)) || | |
| ((!foreignNS || foreignNS === NS.MATHML) && isMathMLTextIntegrationPoint(tn, ns))); | |
| } | |