@svgedit/svgcanvas 7.2.6 → 7.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.md +6 -0
- package/core/history.js +1 -1
- package/core/paint.js +15 -9
- package/core/recalculate.js +28 -9
- package/core/sanitize.js +31 -26
- package/core/svg-exec.js +4 -2
- package/core/utilities.js +36 -35
- package/dist/svgcanvas.js +295 -167
- package/dist/svgcanvas.js.map +1 -1
- package/package.json +1 -1
package/CHANGES.md
CHANGED
package/core/history.js
CHANGED
|
@@ -425,7 +425,7 @@ export class BatchCommand extends Command {
|
|
|
425
425
|
*/
|
|
426
426
|
unapply (handler) {
|
|
427
427
|
super.unapply(handler, () => {
|
|
428
|
-
this.stack.reverse().forEach((stackItem) => {
|
|
428
|
+
[...this.stack].reverse().forEach((stackItem) => {
|
|
429
429
|
console.assert(stackItem, 'stack item should not be null')
|
|
430
430
|
stackItem && stackItem.unapply(handler)
|
|
431
431
|
})
|
package/core/paint.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
export default class Paint {
|
|
5
5
|
/**
|
|
6
6
|
* @param {module:jGraduate.jGraduatePaintOptions} [opt]
|
|
7
|
-
|
|
7
|
+
*/
|
|
8
8
|
constructor (opt) {
|
|
9
9
|
const options = opt || {}
|
|
10
10
|
this.alpha = isNaN(options.alpha) ? 100 : options.alpha
|
|
@@ -51,33 +51,39 @@ export default class Paint {
|
|
|
51
51
|
this.radialGradient = options.copy.radialGradient.cloneNode(true)
|
|
52
52
|
break
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
// create linear gradient paint
|
|
55
55
|
} else if (options.linearGradient) {
|
|
56
56
|
this.type = 'linearGradient'
|
|
57
57
|
this.solidColor = null
|
|
58
58
|
this.radialGradient = null
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
const hrefAttr =
|
|
60
|
+
options.linearGradient.getAttribute('href') ||
|
|
61
|
+
options.linearGradient.getAttribute('xlink:href')
|
|
62
|
+
if (hrefAttr) {
|
|
63
|
+
const xhref = document.getElementById(hrefAttr.replace(/^#/, ''))
|
|
61
64
|
this.linearGradient = xhref.cloneNode(true)
|
|
62
65
|
} else {
|
|
63
66
|
this.linearGradient = options.linearGradient.cloneNode(true)
|
|
64
67
|
}
|
|
65
|
-
|
|
68
|
+
// create linear gradient paint
|
|
66
69
|
} else if (options.radialGradient) {
|
|
67
70
|
this.type = 'radialGradient'
|
|
68
71
|
this.solidColor = null
|
|
69
72
|
this.linearGradient = null
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
const hrefAttr =
|
|
74
|
+
options.radialGradient.getAttribute('href') ||
|
|
75
|
+
options.radialGradient.getAttribute('xlink:href')
|
|
76
|
+
if (hrefAttr) {
|
|
77
|
+
const xhref = document.getElementById(hrefAttr.replace(/^#/, ''))
|
|
72
78
|
this.radialGradient = xhref.cloneNode(true)
|
|
73
79
|
} else {
|
|
74
80
|
this.radialGradient = options.radialGradient.cloneNode(true)
|
|
75
81
|
}
|
|
76
|
-
|
|
82
|
+
// create solid color paint
|
|
77
83
|
} else if (options.solidColor) {
|
|
78
84
|
this.type = 'solidColor'
|
|
79
85
|
this.solidColor = options.solidColor
|
|
80
|
-
|
|
86
|
+
// create empty paint
|
|
81
87
|
} else {
|
|
82
88
|
this.type = 'none'
|
|
83
89
|
this.solidColor = null
|
package/core/recalculate.js
CHANGED
|
@@ -236,16 +236,35 @@ export const recalculateDimensions = selected => {
|
|
|
236
236
|
// Handle rotation transformations
|
|
237
237
|
const angle = getRotationAngle(selected)
|
|
238
238
|
if (angle) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
x
|
|
242
|
-
y
|
|
239
|
+
if (selected.localName === 'image') {
|
|
240
|
+
// Use the center of the image as the rotation center
|
|
241
|
+
const xAttr = convertToNum('x', selected.getAttribute('x') || '0')
|
|
242
|
+
const yAttr = convertToNum('y', selected.getAttribute('y') || '0')
|
|
243
|
+
const width = convertToNum('width', selected.getAttribute('width') || '0')
|
|
244
|
+
const height = convertToNum('height', selected.getAttribute('height') || '0')
|
|
245
|
+
const cx = xAttr + width / 2
|
|
246
|
+
const cy = yAttr + height / 2
|
|
247
|
+
oldcenter = { x: cx, y: cy }
|
|
248
|
+
const transform = transformListToTransform(tlist).matrix
|
|
249
|
+
newcenter = transformPoint(cx, cy, transform)
|
|
250
|
+
} else if (selected.localName === 'text') {
|
|
251
|
+
// Use the center of the bounding box as the rotation center for text
|
|
252
|
+
const cx = box.x + box.width / 2
|
|
253
|
+
const cy = box.y + box.height / 2
|
|
254
|
+
oldcenter = { x: cx, y: cy }
|
|
255
|
+
newcenter = transformPoint(cx, cy, transformListToTransform(tlist).matrix)
|
|
256
|
+
} else {
|
|
257
|
+
// Include x and y in the rotation center calculation for other elements
|
|
258
|
+
oldcenter = {
|
|
259
|
+
x: box.x + box.width / 2 + x,
|
|
260
|
+
y: box.y + box.height / 2 + y
|
|
261
|
+
}
|
|
262
|
+
newcenter = transformPoint(
|
|
263
|
+
box.x + box.width / 2 + x,
|
|
264
|
+
box.y + box.height / 2 + y,
|
|
265
|
+
transformListToTransform(tlist).matrix
|
|
266
|
+
)
|
|
243
267
|
}
|
|
244
|
-
newcenter = transformPoint(
|
|
245
|
-
box.x + box.width / 2 + x,
|
|
246
|
-
box.y + box.height / 2 + y,
|
|
247
|
-
transformListToTransform(tlist).matrix
|
|
248
|
-
)
|
|
249
268
|
|
|
250
269
|
// Remove the rotation transform from the list
|
|
251
270
|
for (let i = 0; i < tlist.numberOfItems; ++i) {
|
package/core/sanitize.js
CHANGED
|
@@ -21,7 +21,7 @@ const REVERSE_NS = getReverseNS()
|
|
|
21
21
|
const svgGenericWhiteList = ['class', 'id', 'display', 'transform', 'style']
|
|
22
22
|
const svgWhiteList_ = {
|
|
23
23
|
// SVG Elements
|
|
24
|
-
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'],
|
|
24
|
+
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'],
|
|
25
25
|
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'],
|
|
26
26
|
clipPath: ['clipPathUnits'],
|
|
27
27
|
defs: [],
|
|
@@ -36,20 +36,20 @@ const svgWhiteList_ = {
|
|
|
36
36
|
feMergeNode: ['in'],
|
|
37
37
|
feMorphology: ['in', 'operator', 'radius'],
|
|
38
38
|
feOffset: ['dx', 'in', 'dy', 'result'],
|
|
39
|
-
filter: ['color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y'],
|
|
39
|
+
filter: ['color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'href', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y'],
|
|
40
40
|
foreignObject: ['font-size', 'height', 'opacity', 'requiredFeatures', 'width', 'x', 'y'],
|
|
41
41
|
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'],
|
|
42
|
-
image: ['clip-path', 'clip-rule', 'filter', 'height', 'mask', 'opacity', 'requiredFeatures', 'systemLanguage', 'width', 'x', 'xlink:href', 'xlink:title', 'y'],
|
|
42
|
+
image: ['clip-path', 'clip-rule', 'filter', 'height', 'mask', 'opacity', 'requiredFeatures', 'systemLanguage', 'width', 'x', 'href', 'xlink:href', 'xlink:title', 'y'],
|
|
43
43
|
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'],
|
|
44
|
-
linearGradient: ['gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2'],
|
|
44
|
+
linearGradient: ['gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'href', 'xlink:href', 'y1', 'y2'],
|
|
45
45
|
marker: ['markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'se_type', 'systemLanguage', 'viewBox'],
|
|
46
46
|
mask: ['height', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y'],
|
|
47
47
|
metadata: [],
|
|
48
48
|
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'],
|
|
49
|
-
pattern: ['height', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y'],
|
|
49
|
+
pattern: ['height', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'systemLanguage', 'viewBox', 'width', 'x', 'href', 'xlink:href', 'y'],
|
|
50
50
|
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'],
|
|
51
51
|
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'],
|
|
52
|
-
radialGradient: ['cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href'],
|
|
52
|
+
radialGradient: ['cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'href', 'xlink:href'],
|
|
53
53
|
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'],
|
|
54
54
|
stop: ['offset', 'requiredFeatures', 'stop-opacity', 'systemLanguage', 'stop-color', 'gradientUnits', 'gradientTransform'],
|
|
55
55
|
style: ['type'],
|
|
@@ -57,10 +57,10 @@ const svgWhiteList_ = {
|
|
|
57
57
|
switch: ['requiredFeatures', 'systemLanguage'],
|
|
58
58
|
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'],
|
|
59
59
|
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'],
|
|
60
|
-
textPath: ['dominant-baseline', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'systemLanguage', 'xlink:href'],
|
|
60
|
+
textPath: ['dominant-baseline', 'href', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'systemLanguage', 'xlink:href'],
|
|
61
61
|
title: [],
|
|
62
62
|
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'],
|
|
63
|
-
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'],
|
|
63
|
+
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'],
|
|
64
64
|
// Filter Primitives
|
|
65
65
|
feComponentTransfer: ['in', 'result'],
|
|
66
66
|
feFuncR: ['type', 'tableValues', 'slope', 'intercept', 'amplitude', 'exponent', 'offset'],
|
|
@@ -91,7 +91,7 @@ const svgWhiteList_ = {
|
|
|
91
91
|
mphantom: [],
|
|
92
92
|
mprescripts: [],
|
|
93
93
|
mroot: [],
|
|
94
|
-
mrow: ['xlink:href', 'xlink:type', 'xmlns:xlink'],
|
|
94
|
+
mrow: ['href', 'xlink:href', 'xlink:type', 'xmlns:xlink'],
|
|
95
95
|
mspace: ['depth', 'height', 'width'],
|
|
96
96
|
msqrt: [],
|
|
97
97
|
mstyle: ['displaystyle', 'mathbackground', 'mathcolor', 'mathvariant', 'scriptlevel'],
|
|
@@ -190,16 +190,20 @@ export const sanitizeSvg = (node) => {
|
|
|
190
190
|
// our whitelist or is a namespace declaration for one of our allowed namespaces
|
|
191
191
|
if (attrNsURI !== allowedAttrsNS[attrLocalName] && attrNsURI !== NS.XMLNS &&
|
|
192
192
|
!(attrNsURI === NS.XMLNS && REVERSE_NS[attr.value])) {
|
|
193
|
-
//
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
// We
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
193
|
+
// Special case: allow href attribute even without namespace if it's in the whitelist
|
|
194
|
+
const isHrefAttribute = (attrLocalName === 'href' && allowedAttrs.includes('href'))
|
|
195
|
+
if (!isHrefAttribute) {
|
|
196
|
+
// Bypassing the whitelist to allow se: and oi: prefixes
|
|
197
|
+
// We can add specific namepaces on demand for now.
|
|
198
|
+
// Is there a more appropriate way to do this?
|
|
199
|
+
if (attrName.startsWith('se:') || attrName.startsWith('oi:') || attrName.startsWith('data-')) {
|
|
200
|
+
// We should bypass the namespace aswell
|
|
201
|
+
const seAttrNS = (attrName.startsWith('se:')) ? NS.SE : ((attrName.startsWith('oi:')) ? NS.OI : null)
|
|
202
|
+
seAttrs.push([attrName, attr.value, seAttrNS])
|
|
203
|
+
} else {
|
|
204
|
+
console.warn(`sanitizeSvg: attribute ${attrName} in element ${node.nodeName} not in whitelist is removed: ${node.outerHTML}`)
|
|
205
|
+
node.removeAttributeNS(attrNsURI, attrLocalName)
|
|
206
|
+
}
|
|
203
207
|
}
|
|
204
208
|
}
|
|
205
209
|
|
|
@@ -224,34 +228,35 @@ export const sanitizeSvg = (node) => {
|
|
|
224
228
|
node.setAttributeNS(ns, att, val)
|
|
225
229
|
})
|
|
226
230
|
|
|
227
|
-
// for some elements that have a xlink:href, ensure the URI refers to a local element
|
|
228
|
-
// (but not for links)
|
|
231
|
+
// for some elements that have a xlink:href or href, ensure the URI refers to a local element
|
|
232
|
+
// (but not for links and other elements where external hrefs are allowed)
|
|
229
233
|
const href = getHref(node)
|
|
230
234
|
if (href &&
|
|
231
235
|
['filter', 'linearGradient', 'pattern',
|
|
232
236
|
'radialGradient', 'textPath', 'use'].includes(node.nodeName) && href[0] !== '#') {
|
|
233
237
|
// remove the attribute (but keep the element)
|
|
234
238
|
setHref(node, '')
|
|
235
|
-
console.warn(`sanitizeSvg: attribute href in element ${node.nodeName} pointing to a non-local reference (${href}) is removed`)
|
|
239
|
+
console.warn(`sanitizeSvg: attribute href in element ${node.nodeName} pointing to a non-local reference (${href}) is removed: ${node.outerHTML}`)
|
|
236
240
|
node.removeAttributeNS(NS.XLINK, 'href')
|
|
241
|
+
node.removeAttribute('href')
|
|
237
242
|
}
|
|
238
243
|
|
|
239
244
|
// Safari crashes on a <use> without a xlink:href, so we just remove the node here
|
|
240
245
|
if (node.nodeName === 'use' && !getHref(node)) {
|
|
241
|
-
console.warn(`sanitizeSvg: element ${node.nodeName} without a xlink:href is removed`)
|
|
246
|
+
console.warn(`sanitizeSvg: element ${node.nodeName} without a xlink:href or href is removed: ${node.outerHTML}`)
|
|
242
247
|
node.remove()
|
|
243
248
|
return
|
|
244
249
|
}
|
|
245
250
|
// if the element has attributes pointing to a non-local reference,
|
|
246
251
|
// need to remove the attribute
|
|
247
|
-
|
|
252
|
+
['clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke'].forEach((attr) => {
|
|
248
253
|
let val = node.getAttribute(attr)
|
|
249
254
|
if (val) {
|
|
250
255
|
val = getUrlFromAttr(val)
|
|
251
256
|
// simply check for first character being a '#'
|
|
252
257
|
if (val && val[0] !== '#') {
|
|
253
258
|
node.setAttribute(attr, '')
|
|
254
|
-
console.warn(`sanitizeSvg: attribute ${attr} in element ${node.nodeName} pointing to a non-local reference (${val}) is removed`)
|
|
259
|
+
console.warn(`sanitizeSvg: attribute ${attr} in element ${node.nodeName} pointing to a non-local reference (${val}) is removed: ${node.outerHTML}`)
|
|
255
260
|
node.removeAttribute(attr)
|
|
256
261
|
}
|
|
257
262
|
}
|
|
@@ -264,7 +269,7 @@ export const sanitizeSvg = (node) => {
|
|
|
264
269
|
} else {
|
|
265
270
|
// remove all children from this node and insert them before this node
|
|
266
271
|
// TODO: in the case of animation elements this will hardly ever be correct
|
|
267
|
-
console.warn(`sanitizeSvg: element ${node.nodeName} not supported is removed`)
|
|
272
|
+
console.warn(`sanitizeSvg: element ${node.nodeName} not supported is removed: ${node.outerHTML}`)
|
|
268
273
|
const children = []
|
|
269
274
|
while (node.hasChildNodes()) {
|
|
270
275
|
children.push(parent.insertBefore(node.firstChild, node))
|
package/core/svg-exec.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
text2xml,
|
|
13
13
|
cleanupElement,
|
|
14
14
|
findDefs,
|
|
15
|
+
setHref,
|
|
15
16
|
getHref,
|
|
16
17
|
preventClickDefault,
|
|
17
18
|
toXml,
|
|
@@ -443,7 +444,8 @@ const setSvgString = (xmlString, preventUndo) => {
|
|
|
443
444
|
// const url = decodeURIComponent(m.groups.url);
|
|
444
445
|
const iimg = new Image()
|
|
445
446
|
iimg.addEventListener('load', () => {
|
|
446
|
-
|
|
447
|
+
// Set the href attribute to the data URL
|
|
448
|
+
setHref(image, val)
|
|
447
449
|
})
|
|
448
450
|
iimg.src = url
|
|
449
451
|
}
|
|
@@ -858,7 +860,7 @@ const convertImagesToBase64 = async svgElement => {
|
|
|
858
860
|
const reader = new FileReader()
|
|
859
861
|
return new Promise(resolve => {
|
|
860
862
|
reader.onload = () => {
|
|
861
|
-
img
|
|
863
|
+
setHref(img, reader.result)
|
|
862
864
|
resolve()
|
|
863
865
|
}
|
|
864
866
|
reader.readAsDataURL(blob)
|
package/core/utilities.js
CHANGED
|
@@ -376,21 +376,22 @@ export const getUrlFromAttr = function (attrVal) {
|
|
|
376
376
|
/**
|
|
377
377
|
* @function module:utilities.getHref
|
|
378
378
|
* @param {Element} elem
|
|
379
|
-
* @returns {string} The given element's `
|
|
379
|
+
* @returns {string} The given element's `href` value
|
|
380
380
|
*/
|
|
381
381
|
export let getHref = function (elem) {
|
|
382
|
-
|
|
382
|
+
// Prefer 'href', fallback to 'xlink:href'
|
|
383
|
+
return elem.getAttribute('href') || elem.getAttributeNS(NS.XLINK, 'href')
|
|
383
384
|
}
|
|
384
385
|
|
|
385
386
|
/**
|
|
386
|
-
* Sets the given element's `
|
|
387
|
+
* Sets the given element's `href` value.
|
|
387
388
|
* @function module:utilities.setHref
|
|
388
389
|
* @param {Element} elem
|
|
389
390
|
* @param {string} val
|
|
390
391
|
* @returns {void}
|
|
391
392
|
*/
|
|
392
393
|
export let setHref = function (elem, val) {
|
|
393
|
-
elem.
|
|
394
|
+
elem.setAttribute('href', val)
|
|
394
395
|
}
|
|
395
396
|
|
|
396
397
|
/**
|
|
@@ -665,38 +666,38 @@ export const getPathDFromElement = function (elem) {
|
|
|
665
666
|
const h = b.height
|
|
666
667
|
num = 4 - num // Why? Because!
|
|
667
668
|
|
|
668
|
-
d =
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
[
|
|
685
|
-
'C',
|
|
669
|
+
d =
|
|
670
|
+
!rx && !ry // Regular rect
|
|
671
|
+
? getPathDFromSegments([
|
|
672
|
+
['M', [x, y]],
|
|
673
|
+
['L', [x + w, y]],
|
|
674
|
+
['L', [x + w, y + h]],
|
|
675
|
+
['L', [x, y + h]],
|
|
676
|
+
['L', [x, y]],
|
|
677
|
+
['Z', []]
|
|
678
|
+
])
|
|
679
|
+
: getPathDFromSegments([
|
|
680
|
+
['M', [x, y + ry]],
|
|
681
|
+
['C', [x, y + ry / num, x + rx / num, y, x + rx, y]],
|
|
682
|
+
['L', [x + w - rx, y]],
|
|
683
|
+
['C', [x + w - rx / num, y, x + w, y + ry / num, x + w, y + ry]],
|
|
684
|
+
['L', [x + w, y + h - ry]],
|
|
686
685
|
[
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
686
|
+
'C',
|
|
687
|
+
[
|
|
688
|
+
x + w,
|
|
689
|
+
y + h - ry / num,
|
|
690
|
+
x + w - rx / num,
|
|
691
|
+
y + h,
|
|
692
|
+
x + w - rx,
|
|
693
|
+
y + h
|
|
694
|
+
]
|
|
695
|
+
],
|
|
696
|
+
['L', [x + rx, y + h]],
|
|
697
|
+
['C', [x + rx / num, y + h, x, y + h - ry / num, x, y + h - ry]],
|
|
698
|
+
['L', [x, y + ry]],
|
|
699
|
+
['Z', []]
|
|
700
|
+
])
|
|
700
701
|
break
|
|
701
702
|
}
|
|
702
703
|
default:
|