8000 Prefer href to xlink href by jfhenon · Pull Request #1059 · SVG-Edit/svgedit · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Prefer href to xlink href #1059

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions coverage/coverage-summary.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion cypress/e2e/ui/scenario1.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,6 @@ describe('check tool shape and image of svg-edit', { testIsolation: false }, fun
// issue with snapshot not being consistent on CI/Interactive
// cy.svgSnapshot()
// so we use typical DOM tests to validate
cy.get('#svg_2').should('have.attr', 'xlink:href').and('equal', './images/logo.svg')
cy.get('#svg_2').should('have.attr', 'href').and('equal', './images/logo.svg')
})
})
4 changes: 2 additions & 2 deletions cypress/e2e/unit/test1.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ describe('Basic Module', function () {
svgCanvas.setSvgString(
"<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='400' x='300'>" +
"<rect id='the-rect' width='200' height='200'/>" +
"<use id='the-use' xlink:href='#the-rect'/>" +
"<use id='foreign-use' xlink:href='somefile.svg#the-rect'/>" +
"<use id='the-use' href='#the-rect'/>" +
"<use id='foreign-use' href='somefile.svg#the-rect'/>" +
"<use id='no-use'/>" +
'</svg>'
)
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/unit/utilities-performance.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('utilities performance', function () {
<!-- Must include this thumbnail view to see some of the performance issues -->
<svg id="overviewMiniView" width="132" height="112.5" x="0" y="0" viewBox="100 100 1000 1000" style="float: right;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<use x="0" y="0" xlink:href="#svgroot"></use>
<use x="0" y="0" href="#svgroot"></use>
</svg>


Expand Down
341 changes: 178 additions & 163 deletions package-lock.json

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,23 +85,23 @@
]
},
"dependencies": {
"@svgedit/svgcanvas": "7.2.4",
"@svgedit/svgcanvas": "7.2.6",
"browser-fs-access": "0.37.0",
"core-js": "3.42.0",
"core-js": "3.43.0",
"elix": "15.0.1",
"i18next": "25.1.2",
"i18next": "25.2.1",
"jspdf": "3.0.1",
"pathseg": "1.2.1",
"regenerator-runtime": "0.14.1",
"replace-in-file": "^8.3.0",
"svg2pdf.js": "2.5.0"
},
"devDependencies": {
"@babel/core": "7.27.1",
"@babel/core": "7.27.4",
"@babel/preset-env": "7.27.2",
"@babel/register": "7.27.1",
"@babel/runtime-corejs3": "7.27.1",
"@cypress/code-coverage": "3.14.1",
"@babel/runtime-corejs3": "7.27.6",
"@cypress/code-coverage": "3.14.4",
"@rollup/plugin-babel": "6.0.4",
"@rollup/plugin-commonjs": "28.0.3",
"@rollup/plugin-dynamic-import-vars": "2.1.5",
Expand All @@ -113,9 +113,9 @@
"@web/dev-server-rollup": "0.6.4",
"babel-plugin-istanbul": "7.0.0",
"babel-plugin-transform-object-rest-spread": "7.0.0-beta.3",
"core-js-bundle": "3.42.0",
"core-js-bundle": "3.43.0",
"cp-cli": "2.0.0",
"cypress": "14.3.3",
"cypress": "14.4.1",
"cypress-multi-reporters": "2.0.5",
"jamilih": "0.60.0",
"jsdoc": "4.0.4",
Expand All @@ -129,16 +129,16 @@
"remark-cli": "12.0.1",
"remark-lint-ordered-list-marker-value": "4.0.1",
"rimraf": "6.0.1",
"rollup": "4.40.2",
"rollup": "4.42.0",
"rollup-plugin-copy": "3.5.0",
"rollup-plugin-filesize": "10.0.0",
"rollup-plugin-html": "0.2.1",
"rollup-plugin-progress": "1.1.2",
"rollup-plugin-re": "1.0.7",
"standard": "17.1.2",
"start-server-and-test": "2.0.11"
"start-server-and-test": "2.0.12"
},
"optionalDependencies": {
"@rollup/rollup-linux-x64-gnu": "4.40.2"
"@rollup/rollup-linux-x64-gnu": "4.42.0"
}
}
24 changes: 15 additions & 9 deletions packages/svgcanvas/core/paint.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
export default class Paint {
/**
* @param {module:jGraduate.jGraduatePaintOptions} [opt]
*/
*/
constructor (opt) {
const options = opt || {}
this.alpha = isNaN(options.alpha) ? 100 : options.alpha
Expand Down Expand Up @@ -51,33 +51,39 @@ export default class Paint {
this.radialGradient = options.copy.radialGradient.cloneNode(true)
break
}
// create linear gradient paint
// create linear gradient paint
} else if (options.linearGradient) {
this.type = 'linearGradient'
this.solidColor = null
this.radialGradient = null
if (options.linearGradient.hasAttribute('xlink:href')) {
const xhref = document.getElementById(options.linearGradient.getAttribute('xlink:href').substr(1))
const hrefAttr =
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Duplicate attribute‐lookup logic

Consider extracting the repeated attribute-lookup logic into a helper function or reusing getHref to reduce duplication and maintain consistent fallback behavior.

Suggested implementation:

      const hrefAttr = getHref(options.linearGradient)
      if (hrefAttr) {
        const xhref = document.getElementById(hrefAttr.replace(/^#/, ''))
        this.linearGradient = xhref.cloneNode(true)
      } else {
        this.linearGradient = options.linearGradient.cloneNode(true)
      }
      // create linear gradient paint
    } else if (options.radialGradient) {
      this.type = 'radialGradient'
/**
 * Helper to get the 'href' or 'xlink:href' attribute from an element.
 * Returns null if neither is present.
 */
function getHref(element) {
  return element.getAttribute('href') || element.getAttribute('xlink:href')
}

options.linearGradient.getAttribute('href') ||
options.linearGradient.getAttribute('xlink:href')
if (hrefAttr) {
const xhref = document.getElementById(hrefAttr.replace(/^#/, ''))
this.linearGradient = xhref.cloneNode(true)
} else {
this.linearGradient = options.linearGradient.cloneNode(true)
}
// create linear gradient paint
// create linear gradient paint
} else if (options.radialGradient) {
this.type = 'radialGradient'
this.solidColor = null
this.linearGradient = null
if (options.radialGradient.hasAttribute('xlink:href')) {
const xhref = document.getElementById(options.radialGradient.getAttribute('xlink:href').substr(1))
const hrefAttr =
options.radialGradient.getAttribute('href') ||
options.radialGradient.getAttribute('xlink:href')
if (hrefAttr) {
const xhref = document.getElementById(hrefAttr.replace(/^#/, ''))
this.radialGradient = xhref.cloneNode(true)
} else {
this.radialGradient = options.radialGradient.cloneNode(true)
}
// create solid color paint
// create solid color paint
} else if (options.solidColor) {
this.type = 'solidColor'
this.solidColor = options.solidColor
// create empty paint
// create empty paint
} else {
this.type = 'none'
this.solidColor = null
Expand Down
57 changes: 31 additions & 26 deletions packages/svgcanvas/core/sanitize.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const REVERSE_NS = getReverseNS()
const svgGenericWhiteList = ['class', 'id', 'display', 'transform', 'style']
const svgWhiteList_ = {
// SVG Elements
a: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'xlink:href', 'xlink:title'],
a: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'href', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'xlink:href', 'xlink:title'],
circle: ['clip-path', 'clip-rule', 'cx', 'cy', 'enable-background', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage'],
clipPath: ['clipPathUnits'],
defs: [],
Expand All @@ -36,31 +36,31 @@ const svgWhiteList_ = {
feMergeNode: ['in'],
feMorphology: ['in', 'operator', 'radius'],
feOffset: ['dx', 'in', 'dy', 'result'],
filter: ['color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y'],
filter: ['color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'href', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y'],
foreignObject: ['font-size', 'height', 'opacity', 'requiredFeatures', 'width', 'x', 'y'],
g: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor'],
image: ['clip-path', 'clip-rule', 'filter', 'height', 'mask', 'opacity', 'requiredFeatures', 'systemLanguage', 'width', 'x', 'xlink:href', 'xlink:title', 'y'],
image: ['clip-path', 'clip-rule', 'filter', 'height', 'mask', 'opacity', 'requiredFeatures', 'systemLanguage', 'width', 'x', 'href', 'xlink:href', 'xlink:title', 'y'],
line: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'x1', 'x2', 'y1', 'y2'],
linearGradient: ['gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2'],
linearGradient: ['gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'href', 'xlink:href', 'y1', 'y2'],
marker: ['markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'se_type', 'systemLanguage', 'viewBox'],
mask: ['height', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y'],
metadata: [],
path: ['clip-path', 'clip-rule', 'd', 'enable-background', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage'],
pattern: ['height', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y'],
pattern: ['height', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'systemLanguage', 'viewBox', 'width', 'x', 'href', 'xlink:href', 'y'],
polygon: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'sides', 'shape', 'edge', 'point', 'starRadiusMultiplier', 'r', 'radialshift', 'r2', 'orient', 'cx', 'cy'],
polyline: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'se:connector'],
radialGradient: ['cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href'],
radialGradient: ['cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'href', 'xlink:href'],
rect: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'width', 'x', 'y'],
stop: ['offset', 'requiredFeatures', 'stop-opacity', 'systemLanguage', 'stop-color', 'gradientUnits', 'gradientTransform'],
style: ['type'],
svg: ['clip-path', 'clip-rule', 'enable-background', 'filter', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'systemLanguage', 'version', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'xmlns:oi', 'oi:animations', 'y', 'stroke-linejoin', 'fill-rule', 'aria-label', 'stroke-width', 'fill-rule', 'xml:space'],
switch: ['requiredFeatures', 'systemLanguage'],
symbol: ['fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'opacity', 'overflow', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'viewBox', 'width', 'height'],
text: ['clip-path', 'clip-rule', 'dominant-baseline', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'text-anchor', 'letter-spacing', 'word-spacing', 'text-decoration', 'textLength', 'lengthAdjust', 'x', 'xml:space', 'y'],
textPath: ['dominant-baseline', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'systemLanguage', 'xlink:href'],
textPath: ['dominant-baseline', 'href', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'systemLanguage', 'xlink:href'],
title: [],
tspan: ['clip-path', 'clip-rule', 'dx', 'dy', 'dominant-baseline', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'systemLanguage', 'text-anchor', 'textLength', 'x', 'xml:space', 'y'],
use: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'width', 'x', 'xlink:href', 'y', 'overflow'],
use: ['clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'href', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'width', 'x', 'xlink:href', 'y', 'overflow'],
// Filter Primitives
feComponentTransfer: ['in', 'result'],
feFuncR: ['type', 'tableValues', 'slope', 'intercept', 'amplitude', 'exponent', 'offset'],
Expand Down Expand Up @@ -91,7 +91,7 @@ const svgWhiteList_ = {
mphantom: [],
mprescripts: [],
mroot: [],
mrow: ['xlink:href', 'xlink:type', 'xmlns:xlink'],
mrow: ['href', 'xlink:href', 'xlink:type', 'xmlns:xlink'],
mspace: ['depth', 'height', 'width'],
msqrt: [],
mstyle: ['displaystyle', 'mathbackground', 'mathcolor', 'mathvariant', 'scriptlevel'],
Expand Down Expand Up @@ -190,16 +190,20 @@ export const sanitizeSvg = (node) => {
// our whitelist or is a namespace declaration for one of our allowed namespaces
if (attrNsURI !== allowedAttrsNS[attrLocalName] && attrNsURI !== NS.XMLNS &&
!(attrNsURI === NS.XMLNS && REVERSE_NS[attr.value])) {
// Bypassing the whitelist to allow se: and oi: prefixes
// We can add specific namepaces on demand for now.
// Is there a more appropriate way to do this?
if (attrName.startsWith('se:') || attrName.startsWith('oi:') || attrName.startsWith('data-')) {
// We should bypass the namespace aswell
const seAttrNS = (attrName.startsWith('se:')) ? NS.SE : ((attrName.startsWith('oi:')) ? NS.OI : null)
seAttrs.push([attrName, attr.value, seAttrNS])
} else {
console.warn(`sanitizeSvg: attribute ${attrName} in element ${node.nodeName} not in whitelist is removed`)
node.removeAttributeNS(attrNsURI, attrLocalName)
// Special case: allow href attribute even without namespace if it's in the whitelist
const isHrefAttribute = (attrLocalName === 'href' && allowedAttrs.includes('href'))
if (!isHrefAttribute) {
// Bypassing the whitelist to allow se: and oi: prefixes
// We can add specific namepaces on demand for now.
// Is there a more appropriate way to do this?
if (attrName.startsWith('se:') || attrName.startsWith('oi:') || attrName.startsWith('data-')) {
// We should bypass the namespace aswell
const seAttrNS = (attrName.startsWith('se:')) ? NS.SE : ((attrName.startsWith('oi:')) ? NS.OI : null)
seAttrs.push([attrName, attr.value, seAttrNS])
} else {
console.warn(`sanitizeSvg: attribute ${attrName} in element ${node.nodeName} not in whitelist is removed: ${node.outerHTML}`)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (performance): Logging outerHTML on every warning may be heavy

Logging the entire outerHTML may generate excessive output and affect performance. Suggest logging only the tag name or a shortened snippet instead.

Suggested change
console.warn(`sanitizeSvg: attribute ${attrName} in element ${node.nodeName} not in whitelist is removed: ${node.outerHTML}`)
const attrValSnippet = attr.value && attr.value.length > 30
? attr.value.slice(0, 30) + '...'
: attr.value;
console.warn(
`sanitizeSvg: attribute ${attrName} (value: "${attrValSnippet}") in <${node.nodeName}> not in whitelist and is removed`
)

node.removeAttributeNS(attrNsURI, attrLocalName)
}
}
}

Expand All @@ -224,34 +228,35 @@ export const sanitizeSvg = (node) => {
node.setAttributeNS(ns, att, val)
})

// for some elements that have a xlink:href, ensure the URI refers to a local element
// (but not for links)
// for some elements that have a xlink:href or href, ensure the URI refers to a local element
// (but not for links and other elements where external hrefs are allowed)
const href = getHref(node)
if (href &&
['filter', 'linearGradient', 'pattern',
'radialGradient', 'textPath', 'use'].includes(node.nodeName) && href[0] !== '#') {
// remove the attribute (but keep the element)
setHref(node, '')
console.warn(`sanitizeSvg: attribute href in element ${node.nodeName} pointing to a non-local reference (${href}) is removed`)
console.warn(`sanitizeSvg: attribute href in element ${node.nodeName} pointing to a non-local reference (${href}) is removed: ${node.outerHTML}`)
node.removeAttributeNS(NS.XLINK, 'href')
node.removeAttribute('href')
}

// Safari crashes on a <use> without a xlink:href, so we just remove the node here
if (node.nodeName === 'use' && !getHref(node)) {
console.warn(`sanitizeSvg: element ${node.nodeName} without a xlink:href is removed`)
console.warn(`sanitizeSvg: element ${node.nodeName} without a xlink:href or href is removed: ${node.outerHTML}`)
node.remove()
return
}
// if the element has attributes pointing to a non-local reference,
// need to remove the attribute
Object.values(['clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke'], (attr) => {
['clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke'].forEach((attr) => {
let val = node.getAttribute(attr)
if (val) {
val = getUrlFromAttr(val)
// simply check for first character being a '#'
if (val && val[0] !== '#') {
node.setAttribute(attr, '')
console.warn(`sanitizeSvg: attribute ${attr} in element ${node.nodeName} pointing to a non-local reference (${val}) is removed`)
console.warn(`sanitizeSvg: attribute ${attr} in element ${node.nodeName} pointing to a non-local reference (${val}) is removed: ${node.outerHTML}`)
node.removeAttribute(attr)
}
}
Expand All @@ -264,7 +269,7 @@ export const sanitizeSvg = (node) => {
} else {
// remove all children from this node and insert them before this node
// TODO: in the case of animation elements this will hardly ever be correct
console.warn(`sanitizeSvg: element ${node.nodeName} not supported is removed`)
console.warn(`sanitizeSvg: element ${node.nodeName} not supported is removed: ${node.outerHTML}`)
const children = []
while (node.hasChildNodes()) {
children.push(parent.insertBefore(node.firstChild, node))
Expand Down
6 changes: 4 additions & 2 deletions packages/svgcanvas/core/svg-exec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
text2xml,
cleanupElement,
findDefs,
setHref,
getHref,
preventClickDefault,
toXml,
Expand Down Expand Up @@ -443,7 +444,8 @@ const setSvgString = (xmlString, preventUndo) => {
// const url = decodeURIComponent(m.groups.url);
const iimg = new Image()
iimg.addEventListener('load', () => {
image.setAttributeNS(NS.XLINK, 'xlink:href', url)
// Set the href attribute to the data URL
setHref(image, val)
})
iimg.src = url
}
Expand Down Expand Up @@ -858,7 +860,7 @@ const convertImagesToBase64 = async svgElement => {
const reader = new FileReader()
return new Promise(resolve => {
reader. => {
img.setAttribute('xlink:href', reader.result)
setHref(img, reader.result)
resolve()
}
reader.readAsDataURL(blob)
Expand Down
Loading
0