@atlaskit/media-common 13.0.1 → 13.0.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.
- package/CHANGELOG.md +8 -0
- package/dist/cjs/copyIntent/clientIdCache.js +55 -10
- package/dist/es2019/copyIntent/clientIdCache.js +55 -10
- package/dist/esm/copyIntent/clientIdCache.js +55 -10
- package/dist/types/copyIntent/clientIdCache.d.ts +0 -3
- package/dist/types-ts4.5/copyIntent/clientIdCache.d.ts +0 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @atlaskit/media-common
|
|
2
2
|
|
|
3
|
+
## 13.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`83401665664f5`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/83401665664f5) -
|
|
8
|
+
Fix failure to extract clientId when performing cross client copy/paste of rich text containing
|
|
9
|
+
media
|
|
10
|
+
|
|
3
11
|
## 13.0.1
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
|
@@ -47,20 +47,65 @@ var clearClientIdCache = exports.clearClientIdCache = function clearClientIdCach
|
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* Used to store fileId to clientId mappings on paste of Editor PM Node
|
|
50
|
+
*
|
|
51
|
+
* Handles two sources of pasted HTML:
|
|
52
|
+
*
|
|
53
|
+
* 1. Editor-to-editor copy: the clientId is stored as a `data-client-id` attribute
|
|
54
|
+
* directly on the `<div data-node-type="media">` element, written by the editor's
|
|
55
|
+
* clipboard serialiser.
|
|
56
|
+
*
|
|
57
|
+
* 2. Renderer-to-editor copy (e.g. pasting from a published Confluence page): the
|
|
58
|
+
* renderer does not write `data-client-id` on the media div. Instead, the clientId
|
|
59
|
+
* is embedded inside the blob URL on the `<img>` child element, in the hash params:
|
|
60
|
+
* `src="blob:https://...#media-blob-url=true&id=FILE_ID&...&clientId=CLIENT_ID"`
|
|
61
|
+
*
|
|
62
|
+
* All media nodes in a single pasted HTML fragment always share the same clientId,
|
|
63
|
+
* so we extract it once and apply it to all file IDs found in the HTML.
|
|
50
64
|
*/
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Extract the clientId from a blob URL hash fragment (renderer-to-editor path).
|
|
68
|
+
* Returns undefined if not found.
|
|
69
|
+
*/
|
|
70
|
+
var extractClientIdFromBlobUrl = function extractClientIdFromBlobUrl(html) {
|
|
71
|
+
// Matches both:
|
|
72
|
+
// - blob: URLs (client-rendered renderer)
|
|
73
|
+
// - HTTPS URLs with #media-blob-url=true in the hash (SSR-rendered renderer)
|
|
74
|
+
var imgSrcRegex = /src="([^"]*#media-blob-url=true[^"]*)"/g;
|
|
75
|
+
var match;
|
|
76
|
+
while ((match = imgSrcRegex.exec(html)) !== null) {
|
|
77
|
+
var src = match[1];
|
|
78
|
+
// clientId is encoded in the hash fragment as a URL param
|
|
79
|
+
// e.g. blob:https://hello.atlassian.net/uuid#media-blob-url=true&id=FILE_ID&clientId=CLIENT_ID
|
|
80
|
+
var hash = src.includes('#') ? src.slice(src.indexOf('#') + 1) : '';
|
|
81
|
+
// Unescape HTML-encoded ampersands that appear in raw clipboard HTML attribute values
|
|
82
|
+
var decodedHash = hash.replace(/&/g, '&');
|
|
83
|
+
var clientId = new URLSearchParams(decodedHash).get('clientId');
|
|
84
|
+
if (clientId) {
|
|
85
|
+
return clientId;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return undefined;
|
|
89
|
+
};
|
|
51
90
|
var extractClientIdsFromHtml = exports.extractClientIdsFromHtml = function extractClientIdsFromHtml(html) {
|
|
52
|
-
|
|
91
|
+
var _exec$, _exec;
|
|
92
|
+
if (!html) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// All media nodes in a single paste share the same clientId.
|
|
97
|
+
// Extract it once from either source:
|
|
98
|
+
// - Editor-to-editor: present as data-client-id="..." attribute
|
|
99
|
+
// - Renderer-to-editor: embedded in the blob URL hash as clientId=...
|
|
100
|
+
var clientId = (_exec$ = (_exec = /data-client-id="([^"]*)"/.exec(html)) === null || _exec === void 0 ? void 0 : _exec[1]) !== null && _exec$ !== void 0 ? _exec$ : extractClientIdFromBlobUrl(html);
|
|
101
|
+
if (!clientId) {
|
|
53
102
|
return;
|
|
54
103
|
}
|
|
55
|
-
|
|
104
|
+
|
|
105
|
+
// Map every file ID in the HTML to the single clientId
|
|
106
|
+
var fileIdRegex = /data-id="([^"]*)"/g;
|
|
56
107
|
var match;
|
|
57
|
-
while ((match =
|
|
58
|
-
|
|
59
|
-
var tag = match[0];
|
|
60
|
-
var fileId = (_exec = /data-id="([^"]*)"/.exec(tag)) === null || _exec === void 0 ? void 0 : _exec[1];
|
|
61
|
-
var clientId = (_exec2 = /data-client-id="([^"]*)"/.exec(tag)) === null || _exec2 === void 0 ? void 0 : _exec2[1];
|
|
62
|
-
if (fileId && clientId) {
|
|
63
|
-
setClientIdForFile(fileId, clientId);
|
|
64
|
-
}
|
|
108
|
+
while ((match = fileIdRegex.exec(html)) !== null) {
|
|
109
|
+
setClientIdForFile(match[1], clientId);
|
|
65
110
|
}
|
|
66
111
|
};
|
|
@@ -41,20 +41,65 @@ export const clearClientIdCache = () => {
|
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* Used to store fileId to clientId mappings on paste of Editor PM Node
|
|
44
|
+
*
|
|
45
|
+
* Handles two sources of pasted HTML:
|
|
46
|
+
*
|
|
47
|
+
* 1. Editor-to-editor copy: the clientId is stored as a `data-client-id` attribute
|
|
48
|
+
* directly on the `<div data-node-type="media">` element, written by the editor's
|
|
49
|
+
* clipboard serialiser.
|
|
50
|
+
*
|
|
51
|
+
* 2. Renderer-to-editor copy (e.g. pasting from a published Confluence page): the
|
|
52
|
+
* renderer does not write `data-client-id` on the media div. Instead, the clientId
|
|
53
|
+
* is embedded inside the blob URL on the `<img>` child element, in the hash params:
|
|
54
|
+
* `src="blob:https://...#media-blob-url=true&id=FILE_ID&...&clientId=CLIENT_ID"`
|
|
55
|
+
*
|
|
56
|
+
* All media nodes in a single pasted HTML fragment always share the same clientId,
|
|
57
|
+
* so we extract it once and apply it to all file IDs found in the HTML.
|
|
44
58
|
*/
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Extract the clientId from a blob URL hash fragment (renderer-to-editor path).
|
|
62
|
+
* Returns undefined if not found.
|
|
63
|
+
*/
|
|
64
|
+
const extractClientIdFromBlobUrl = html => {
|
|
65
|
+
// Matches both:
|
|
66
|
+
// - blob: URLs (client-rendered renderer)
|
|
67
|
+
// - HTTPS URLs with #media-blob-url=true in the hash (SSR-rendered renderer)
|
|
68
|
+
const imgSrcRegex = /src="([^"]*#media-blob-url=true[^"]*)"/g;
|
|
69
|
+
let match;
|
|
70
|
+
while ((match = imgSrcRegex.exec(html)) !== null) {
|
|
71
|
+
const src = match[1];
|
|
72
|
+
// clientId is encoded in the hash fragment as a URL param
|
|
73
|
+
// e.g. blob:https://hello.atlassian.net/uuid#media-blob-url=true&id=FILE_ID&clientId=CLIENT_ID
|
|
74
|
+
const hash = src.includes('#') ? src.slice(src.indexOf('#') + 1) : '';
|
|
75
|
+
// Unescape HTML-encoded ampersands that appear in raw clipboard HTML attribute values
|
|
76
|
+
const decodedHash = hash.replace(/&/g, '&');
|
|
77
|
+
const clientId = new URLSearchParams(decodedHash).get('clientId');
|
|
78
|
+
if (clientId) {
|
|
79
|
+
return clientId;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
};
|
|
45
84
|
export const extractClientIdsFromHtml = html => {
|
|
46
|
-
|
|
85
|
+
var _exec$, _exec;
|
|
86
|
+
if (!html) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// All media nodes in a single paste share the same clientId.
|
|
91
|
+
// Extract it once from either source:
|
|
92
|
+
// - Editor-to-editor: present as data-client-id="..." attribute
|
|
93
|
+
// - Renderer-to-editor: embedded in the blob URL hash as clientId=...
|
|
94
|
+
const clientId = (_exec$ = (_exec = /data-client-id="([^"]*)"/.exec(html)) === null || _exec === void 0 ? void 0 : _exec[1]) !== null && _exec$ !== void 0 ? _exec$ : extractClientIdFromBlobUrl(html);
|
|
95
|
+
if (!clientId) {
|
|
47
96
|
return;
|
|
48
97
|
}
|
|
49
|
-
|
|
98
|
+
|
|
99
|
+
// Map every file ID in the HTML to the single clientId
|
|
100
|
+
const fileIdRegex = /data-id="([^"]*)"/g;
|
|
50
101
|
let match;
|
|
51
|
-
while ((match =
|
|
52
|
-
|
|
53
|
-
const tag = match[0];
|
|
54
|
-
const fileId = (_exec = /data-id="([^"]*)"/.exec(tag)) === null || _exec === void 0 ? void 0 : _exec[1];
|
|
55
|
-
const clientId = (_exec2 = /data-client-id="([^"]*)"/.exec(tag)) === null || _exec2 === void 0 ? void 0 : _exec2[1];
|
|
56
|
-
if (fileId && clientId) {
|
|
57
|
-
setClientIdForFile(fileId, clientId);
|
|
58
|
-
}
|
|
102
|
+
while ((match = fileIdRegex.exec(html)) !== null) {
|
|
103
|
+
setClientIdForFile(match[1], clientId);
|
|
59
104
|
}
|
|
60
105
|
};
|
|
@@ -41,20 +41,65 @@ export var clearClientIdCache = function clearClientIdCache() {
|
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* Used to store fileId to clientId mappings on paste of Editor PM Node
|
|
44
|
+
*
|
|
45
|
+
* Handles two sources of pasted HTML:
|
|
46
|
+
*
|
|
47
|
+
* 1. Editor-to-editor copy: the clientId is stored as a `data-client-id` attribute
|
|
48
|
+
* directly on the `<div data-node-type="media">` element, written by the editor's
|
|
49
|
+
* clipboard serialiser.
|
|
50
|
+
*
|
|
51
|
+
* 2. Renderer-to-editor copy (e.g. pasting from a published Confluence page): the
|
|
52
|
+
* renderer does not write `data-client-id` on the media div. Instead, the clientId
|
|
53
|
+
* is embedded inside the blob URL on the `<img>` child element, in the hash params:
|
|
54
|
+
* `src="blob:https://...#media-blob-url=true&id=FILE_ID&...&clientId=CLIENT_ID"`
|
|
55
|
+
*
|
|
56
|
+
* All media nodes in a single pasted HTML fragment always share the same clientId,
|
|
57
|
+
* so we extract it once and apply it to all file IDs found in the HTML.
|
|
44
58
|
*/
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Extract the clientId from a blob URL hash fragment (renderer-to-editor path).
|
|
62
|
+
* Returns undefined if not found.
|
|
63
|
+
*/
|
|
64
|
+
var extractClientIdFromBlobUrl = function extractClientIdFromBlobUrl(html) {
|
|
65
|
+
// Matches both:
|
|
66
|
+
// - blob: URLs (client-rendered renderer)
|
|
67
|
+
// - HTTPS URLs with #media-blob-url=true in the hash (SSR-rendered renderer)
|
|
68
|
+
var imgSrcRegex = /src="([^"]*#media-blob-url=true[^"]*)"/g;
|
|
69
|
+
var match;
|
|
70
|
+
while ((match = imgSrcRegex.exec(html)) !== null) {
|
|
71
|
+
var src = match[1];
|
|
72
|
+
// clientId is encoded in the hash fragment as a URL param
|
|
73
|
+
// e.g. blob:https://hello.atlassian.net/uuid#media-blob-url=true&id=FILE_ID&clientId=CLIENT_ID
|
|
74
|
+
var hash = src.includes('#') ? src.slice(src.indexOf('#') + 1) : '';
|
|
75
|
+
// Unescape HTML-encoded ampersands that appear in raw clipboard HTML attribute values
|
|
76
|
+
var decodedHash = hash.replace(/&/g, '&');
|
|
77
|
+
var clientId = new URLSearchParams(decodedHash).get('clientId');
|
|
78
|
+
if (clientId) {
|
|
79
|
+
return clientId;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
};
|
|
45
84
|
export var extractClientIdsFromHtml = function extractClientIdsFromHtml(html) {
|
|
46
|
-
|
|
85
|
+
var _exec$, _exec;
|
|
86
|
+
if (!html) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// All media nodes in a single paste share the same clientId.
|
|
91
|
+
// Extract it once from either source:
|
|
92
|
+
// - Editor-to-editor: present as data-client-id="..." attribute
|
|
93
|
+
// - Renderer-to-editor: embedded in the blob URL hash as clientId=...
|
|
94
|
+
var clientId = (_exec$ = (_exec = /data-client-id="([^"]*)"/.exec(html)) === null || _exec === void 0 ? void 0 : _exec[1]) !== null && _exec$ !== void 0 ? _exec$ : extractClientIdFromBlobUrl(html);
|
|
95
|
+
if (!clientId) {
|
|
47
96
|
return;
|
|
48
97
|
}
|
|
49
|
-
|
|
98
|
+
|
|
99
|
+
// Map every file ID in the HTML to the single clientId
|
|
100
|
+
var fileIdRegex = /data-id="([^"]*)"/g;
|
|
50
101
|
var match;
|
|
51
|
-
while ((match =
|
|
52
|
-
|
|
53
|
-
var tag = match[0];
|
|
54
|
-
var fileId = (_exec = /data-id="([^"]*)"/.exec(tag)) === null || _exec === void 0 ? void 0 : _exec[1];
|
|
55
|
-
var clientId = (_exec2 = /data-client-id="([^"]*)"/.exec(tag)) === null || _exec2 === void 0 ? void 0 : _exec2[1];
|
|
56
|
-
if (fileId && clientId) {
|
|
57
|
-
setClientIdForFile(fileId, clientId);
|
|
58
|
-
}
|
|
102
|
+
while ((match = fileIdRegex.exec(html)) !== null) {
|
|
103
|
+
setClientIdForFile(match[1], clientId);
|
|
59
104
|
}
|
|
60
105
|
};
|
|
@@ -19,7 +19,4 @@ export declare const getClientIdForFile: (fileId: string) => string | undefined;
|
|
|
19
19
|
* Clear all cached clientIds (for testing purposes)
|
|
20
20
|
*/
|
|
21
21
|
export declare const clearClientIdCache: () => void;
|
|
22
|
-
/**
|
|
23
|
-
* Used to store fileId to clientId mappings on paste of Editor PM Node
|
|
24
|
-
*/
|
|
25
22
|
export declare const extractClientIdsFromHtml: (html: string) => void;
|
|
@@ -19,7 +19,4 @@ export declare const getClientIdForFile: (fileId: string) => string | undefined;
|
|
|
19
19
|
* Clear all cached clientIds (for testing purposes)
|
|
20
20
|
*/
|
|
21
21
|
export declare const clearClientIdCache: () => void;
|
|
22
|
-
/**
|
|
23
|
-
* Used to store fileId to clientId mappings on paste of Editor PM Node
|
|
24
|
-
*/
|
|
25
22
|
export declare const extractClientIdsFromHtml: (html: string) => void;
|