@svgedit/svgcanvas 7.2.7 → 7.4.2

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.
@@ -1,5 +1,6 @@
1
1
  import {
2
- getStrokedBBoxDefaultVisible
2
+ getStrokedBBoxDefaultVisible,
3
+ getUrlFromAttr
3
4
  } from './utilities.js'
4
5
  import * as hstry from './history.js'
5
6
 
@@ -27,11 +28,15 @@ export const init = (canvas) => {
27
28
  * @fires module:svgcanvas.SvgCanvas#event:ext_IDsUpdated
28
29
  * @returns {void}
29
30
  */
30
- export const pasteElementsMethod = function (type, x, y) {
31
- let clipb = JSON.parse(sessionStorage.getItem(svgCanvas.getClipboardID()))
32
- if (!clipb) return
33
- let len = clipb.length
34
- if (!len) return
31
+ export const pasteElementsMethod = (type, x, y) => {
32
+ const rawClipboard = sessionStorage.getItem(svgCanvas.getClipboardID())
33
+ let clipb
34
+ try {
35
+ clipb = JSON.parse(rawClipboard)
36
+ } catch {
37
+ return
38
+ }
39
+ if (!Array.isArray(clipb) || !clipb.length) return
35
40
 
36
41
  const pasted = []
37
42
  const batchCmd = new BatchCommand('Paste elements')
@@ -50,7 +55,7 @@ export const pasteElementsMethod = function (type, x, y) {
50
55
  * @param {module:svgcanvas.SVGAsJSON} elem
51
56
  * @returns {void}
52
57
  */
53
- function checkIDs (elem) {
58
+ const checkIDs = (elem) => {
54
59
  if (elem.attr?.id) {
55
60
  changedIDs[elem.attr.id] = svgCanvas.getNextId()
56
61
  elem.attr.id = changedIDs[elem.attr.id]
@@ -59,6 +64,35 @@ export const pasteElementsMethod = function (type, x, y) {
59
64
  }
60
65
  clipb.forEach((elem) => checkIDs(elem))
61
66
 
67
+ // Update any internal references in the clipboard to match the new IDs.
68
+ /**
69
+ * @param {module:svgcanvas.SVGAsJSON} elem
70
+ * @returns {void}
71
+ */
72
+ const remapReferences = (elem) => {
73
+ const attrs = elem?.attr
74
+ if (attrs) {
75
+ for (const [attrName, attrVal] of Object.entries(attrs)) {
76
+ if (typeof attrVal !== 'string' || !attrVal) continue
77
+ if ((attrName === 'href' || attrName === 'xlink:href') && attrVal.startsWith('#')) {
78
+ const refId = attrVal.slice(1)
79
+ if (refId in changedIDs) {
80
+ attrs[attrName] = `#${changedIDs[refId]}`
81
+ }
82
+ }
83
+ const url = getUrlFromAttr(attrVal)
84
+ if (url) {
85
+ const refId = url.slice(1)
86
+ if (refId in changedIDs) {
87
+ attrs[attrName] = attrVal.replace(url, `#${changedIDs[refId]}`)
88
+ }
89
+ }
90
+ }
91
+ }
92
+ if (elem.children) elem.children.forEach((child) => remapReferences(child))
93
+ }
94
+ clipb.forEach((elem) => remapReferences(elem))
95
+
62
96
  // Give extensions like the connector extension a chance to reflect new IDs and remove invalid elements
63
97
  /**
64
98
  * Triggered when `pasteElements` is called from a paste action (context menu or key).
@@ -77,12 +111,14 @@ export const pasteElementsMethod = function (type, x, y) {
77
111
 
78
112
  extChanges.remove.forEach(function (removeID) {
79
113
  clipb = clipb.filter(function (clipBoardItem) {
80
- return clipBoardItem.attr.id !== removeID
114
+ return clipBoardItem?.attr?.id !== removeID
81
115
  })
82
116
  })
83
117
  })
84
118
 
85
119
  // Move elements to lastClickPoint
120
+ let len = clipb.length
121
+ if (!len) return
86
122
  while (len--) {
87
123
  const elem = clipb[len]
88
124
  if (!elem) { continue }
@@ -94,6 +130,7 @@ export const pasteElementsMethod = function (type, x, y) {
94
130
  svgCanvas.restoreRefElements(copy)
95
131
  }
96
132
 
133
+ if (!pasted.length) return
97
134
  svgCanvas.selectOnly(pasted)
98
135
 
99
136
  if (type !== 'in_place') {
@@ -108,18 +145,20 @@ export const pasteElementsMethod = function (type, x, y) {
108
145
  }
109
146
 
110
147
  const bbox = getStrokedBBoxDefaultVisible(pasted)
111
- const cx = ctrX - (bbox.x + bbox.width / 2)
112
- const cy = ctrY - (bbox.y + bbox.height / 2)
113
- const dx = []
114
- const dy = []
115
-
116
- pasted.forEach(function (_item) {
117
- dx.push(cx)
118
- dy.push(cy)
119
- })
148
+ if (bbox && Number.isFinite(ctrX) && Number.isFinite(ctrY)) {
149
+ const cx = ctrX - (bbox.x + bbox.width / 2)
150
+ const cy = ctrY - (bbox.y + bbox.height / 2)
151
+ const dx = []
152
+ const dy = []
153
+
154
+ pasted.forEach(function (_item) {
155
+ dx.push(cx)
156
+ dy.push(cy)
157
+ })
120
158
 
121
- const cmd = svgCanvas.moveSelectedElements(dx, dy, false)
122
- if (cmd) batchCmd.addSubCommand(cmd)
159
+ const cmd = svgCanvas.moveSelectedElements(dx, dy, false)
160
+ if (cmd) batchCmd.addSubCommand(cmd)
161
+ }
123
162
  }
124
163
 
125
164
  svgCanvas.addCommandToHistory(batchCmd)