Skip to content

Commit e70da1b

Browse files
ReFFaTmakhnatkin
andauthored
fix(imageSize): fixed the insertion of the svg image (#857)
Co-authored-by: Sergey Makhnatkin <[email protected]>
1 parent 5cbdf0a commit e70da1b

File tree

4 files changed

+104
-1
lines changed

4 files changed

+104
-1
lines changed

src/extensions/yfm/ImgSize/ImagePaste/index.ts

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,15 @@ import type {FileUploadHandler} from '../../../../utils';
1212
import {clipboardUtils} from '../../../behavior/Clipboard';
1313
import {DataTransferType} from '../../../behavior/Clipboard/utils';
1414
import {ImageAttr, ImgSizeAttr, imageType} from '../../../specs';
15-
import {type CreateImageNodeOptions, isImageNode} from '../utils';
15+
import {
16+
type CreateImageNodeOptions,
17+
checkSvg,
18+
findImageNode,
19+
getImageSize,
20+
getImageSizeNew,
21+
isImageNode,
22+
loadImageFromUrl,
23+
} from '../utils';
1624

1725
import {ImagesUploadProcess} from './upload';
1826

@@ -82,15 +90,77 @@ export const ImagePaste: ExtensionAuto<ImagePasteOptions> = (builder, opts) => {
8290

8391
e.preventDefault();
8492

93+
const isSvg = checkSvg(imageUrl);
94+
95+
const trackingId = `img-${Math.random().toString(36).slice(2)}`;
96+
8597
const imageNode = imageType(view.state.schema).create({
8698
src: imageUrl,
8799
alt: title,
100+
id: trackingId,
88101
});
89102

90103
const tr = view.state.tr.replaceSelectionWith(imageNode);
91104
view.dispatch(tr.scrollIntoView());
92105
logger.event({event: 'paste-url-as-image'});
93106

107+
loadImageFromUrl(imageUrl)
108+
.then((img) =>
109+
opts?.enableNewImageSizeCalculation || isSvg
110+
? getImageSizeNew(img)
111+
: getImageSize(img),
112+
)
113+
.then(
114+
(sizes: {
115+
[ImgSizeAttr.Height]?: string;
116+
[ImgSizeAttr.Width]?: string;
117+
}) => {
118+
const currentState = view.state;
119+
120+
const imageResult = findImageNode(
121+
currentState.doc,
122+
trackingId,
123+
);
124+
125+
if (imageResult === null) {
126+
logger.error({
127+
event: 'img-node-not-found',
128+
trackingId,
129+
});
130+
return;
131+
}
132+
133+
const {pos: targetPos} = imageResult;
134+
135+
const updateTr = currentState.tr
136+
.setNodeAttribute(
137+
targetPos,
138+
ImgSizeAttr.Height,
139+
sizes.height,
140+
)
141+
.setNodeAttribute(
142+
targetPos,
143+
ImgSizeAttr.Width,
144+
sizes.width,
145+
)
146+
.setNodeAttribute(targetPos, 'id', null);
147+
148+
view.dispatch(updateTr);
149+
150+
logger.event({
151+
event: 'img-dimensions-updated',
152+
position: targetPos,
153+
sizes,
154+
});
155+
},
156+
)
157+
.catch((error) => {
158+
logger.error({
159+
event: 'img-dimensions-load-failed',
160+
error: error.message,
161+
});
162+
});
163+
94164
return true;
95165
}
96166

src/extensions/yfm/ImgSize/ImgSizeSpecs/const.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ export const ImgSizeAttr = {
77
Width: ImsizeAttr.Width,
88
Height: ImsizeAttr.Height,
99
Loading: 'loading',
10+
Id: 'id',
1011
} as const;

src/extensions/yfm/ImgSize/ImgSizeSpecs/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type ImsizeTypedAttributes = {
1515
[ImgSizeAttr.Width]: string | null;
1616
[ImgSizeAttr.Height]: string | null;
1717
[ImgSizeAttr.Loading]: string | null;
18+
[ImgSizeAttr.Id]: string | null;
1819
};
1920

2021
export {ImgSizeAttr};
@@ -40,6 +41,7 @@ export const ImgSizeSpecs: ExtensionAuto<ImgSizeSpecsOptions> = (builder, opts)
4041
[ImgSizeAttr.Height]: {default: null},
4142
[ImgSizeAttr.Width]: {default: null},
4243
[ImgSizeAttr.Loading]: {default: null},
44+
[ImgSizeAttr.Id]: {default: null},
4345
},
4446
placeholder: placeholderContent ? {content: placeholderContent} : opts.placeholder,
4547
group: 'inline',
@@ -60,6 +62,7 @@ export const ImgSizeSpecs: ExtensionAuto<ImgSizeSpecsOptions> = (builder, opts)
6062
),
6163
[ImgSizeAttr.Height]: isNumber(height) ? height : null,
6264
[ImgSizeAttr.Width]: isNumber(width) ? height : null,
65+
[ImgSizeAttr.Id]: (dom as Element).getAttribute(ImgSizeAttr.Id),
6366
};
6467
},
6568
},
@@ -79,6 +82,7 @@ export const ImgSizeSpecs: ExtensionAuto<ImgSizeSpecsOptions> = (builder, opts)
7982
[ImgSizeAttr.Width]: tok.attrGet(ImgSizeAttr.Width),
8083
[ImgSizeAttr.Loading]: tok.attrGet(ImgSizeAttr.Loading),
8184
[ImgSizeAttr.Alt]: tok.children?.[0]?.content || null,
85+
[ImgSizeAttr.Id]: tok.attrGet(ImgSizeAttr.Id),
8286
}),
8387
},
8488
},

src/extensions/yfm/ImgSize/utils.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export const createImageNode =
2323
[ImgSizeAttr.Src]: result.url,
2424
[ImgSizeAttr.Alt]: result.name ?? file.name,
2525
};
26+
2627
if (opts.needDimensions) {
2728
try {
2829
const sizes = await loadImage(file).then(
@@ -49,6 +50,15 @@ export async function loadImage(imgFile: File) {
4950
});
5051
}
5152

53+
export async function loadImageFromUrl(url: string): Promise<HTMLImageElement> {
54+
return new Promise<HTMLImageElement>((resolve, reject) => {
55+
const img = new Image();
56+
img.onload = () => resolve(img);
57+
img.onerror = (_e, _s, _l, _c, error) => reject(error);
58+
img.src = url;
59+
});
60+
}
61+
5262
export function getImageSize(img: HTMLImageElement): {[ImgSizeAttr.Height]?: string} {
5363
return {height: String(Math.min(IMG_MAX_HEIGHT, img.height))};
5464
}
@@ -64,3 +74,21 @@ export function getImageSizeNew({width, height}: HTMLImageElement): {
6474
});
6575
return {width: String(size.width), height: String(size.height)};
6676
}
77+
78+
export function checkSvg(imageUrl?: string) {
79+
return imageUrl && (/\.svg($|\?|#)/i.test(imageUrl) || imageUrl.startsWith('data:image/svg'));
80+
}
81+
82+
export function findImageNode(doc: Node, id: string): {node: Node; pos: number} | null {
83+
let result: {node: Node; pos: number} | null = null;
84+
85+
doc.descendants((node, pos) => {
86+
if (isImageNode(node) && node.attrs.id === id) {
87+
result = {node, pos};
88+
return false;
89+
}
90+
return true;
91+
});
92+
93+
return result;
94+
}

0 commit comments

Comments
 (0)