diff --git a/app/src/interfaces/input-rich-text-html/input-rich-text-html.vue b/app/src/interfaces/input-rich-text-html/input-rich-text-html.vue
index 7eba6dd4b9..d0fd5ebf44 100644
--- a/app/src/interfaces/input-rich-text-html/input-rich-text-html.vue
+++ b/app/src/interfaces/input-rich-text-html/input-rich-text-html.vue
@@ -278,7 +278,7 @@ export default defineComponent({
);
return value.replace(regex, (_, pre, matchedUrl, post) => {
- const matched = new URL(matchedUrl);
+ const matched = new URL(matchedUrl.replace(/&/g, '&'));
const params = new URLSearchParams(matched.search);
if (!token) {
@@ -341,6 +341,7 @@ export default defineComponent({
statusbar: false,
menubar: false,
convert_urls: false,
+ image_dimensions: false,
extended_valid_elements: 'audio[loop],source',
toolbar: toolbarString,
style_formats: styleFormats,
diff --git a/app/src/interfaces/input-rich-text-html/useImage.ts b/app/src/interfaces/input-rich-text-html/useImage.ts
index 7a5e2e0be4..f6bd4dd199 100644
--- a/app/src/interfaces/input-rich-text-html/useImage.ts
+++ b/app/src/interfaces/input-rich-text-html/useImage.ts
@@ -1,5 +1,6 @@
import { addTokenToURL } from '@/api';
import { i18n } from '@/lang';
+import { addQueryToPath } from '@/utils/add-query-to-path';
import { getPublicURL } from '@/utils/get-root-path';
import { Ref, ref } from 'vue';
@@ -44,7 +45,10 @@ export default function useImage(
if (buttonApi.isActive()) {
const node = editor.value.selection.getNode() as HTMLImageElement;
const imageUrl = node.getAttribute('src');
+ const imageUrlParams = imageUrl ? new URL(imageUrl).searchParams : undefined;
const alt = node.getAttribute('alt');
+ const width = Number(imageUrlParams?.get('width') || undefined) || undefined;
+ const height = Number(imageUrlParams?.get('height') || undefined) || undefined;
if (imageUrl === null || alt === null) {
return;
@@ -53,8 +57,8 @@ export default function useImage(
imageSelection.value = {
imageUrl,
alt,
- width: Number(node.getAttribute('width')) || undefined,
- height: Number(node.getAttribute('height')) || undefined,
+ width,
+ height,
previewUrl: imageUrl,
};
} else {
@@ -96,7 +100,11 @@ export default function useImage(
function saveImage() {
const img = imageSelection.value;
if (img === null) return;
- const imageHtml = `
`;
+ const resizedImageUrl = addQueryToPath(img.imageUrl, {
+ ...(img.width ? { width: img.width.toString() } : {}),
+ ...(img.height ? { height: img.height.toString() } : {}),
+ });
+ const imageHtml = `
`;
isEditorDirty.value = true;
editor.value.selection.setContent(imageHtml);
closeImageDrawer();
diff --git a/app/src/utils/add-query-to-path.ts b/app/src/utils/add-query-to-path.ts
index a793299aa6..2f87e01631 100644
--- a/app/src/utils/add-query-to-path.ts
+++ b/app/src/utils/add-query-to-path.ts
@@ -1,9 +1,9 @@
export function addQueryToPath(path: string, query: Record): string {
- const queryParams = [];
+ const queryParams = new URLSearchParams(path.split('?')[1] || '');
for (const [key, value] of Object.entries(query)) {
- queryParams.push(`${key}=${value}`);
+ queryParams.set(key, value);
}
- return path.includes('?') ? `${path}&${queryParams.join('&')}` : `${path}?${queryParams.join('&')}`;
+ return path.split('?')[0] + '?' + queryParams;
}