diff options
author | Go MAEDA <maeda@farend.jp> | 2024-12-01 07:26:45 +0000 |
---|---|---|
committer | Go MAEDA <maeda@farend.jp> | 2024-12-01 07:26:45 +0000 |
commit | 096fcbf4aaa864792d835ea73cc75ae91de675f8 (patch) | |
tree | ba21eaeca022642058a153ba28c23bdb28a606f2 | |
parent | d99b67467d36d6419be9d521a768da210b432664 (diff) | |
download | redmine-096fcbf4aaa864792d835ea73cc75ae91de675f8.tar.gz redmine-096fcbf4aaa864792d835ea73cc75ae91de675f8.zip |
Scale pasted images to appropriate size on HiDPI displays using devicePixelRatio (#38504).
Patch by Go MAEDA (user:maeda).
git-svn-id: https://svn.redmine.org/redmine/trunk@23344 e93f8b46-1217-0410-a6f0-8f06a7374b81
-rw-r--r-- | app/assets/javascripts/attachments.js | 75 |
1 files changed, 58 insertions, 17 deletions
diff --git a/app/assets/javascripts/attachments.js b/app/assets/javascripts/attachments.js index e8e9ac6e8..df9c7090e 100644 --- a/app/assets/javascripts/attachments.js +++ b/app/assets/javascripts/attachments.js @@ -229,15 +229,60 @@ function setupFileDrop() { } } +function getImageWidth(file) { + return new Promise((resolve, reject) => { + if (file.type.startsWith("image/")) { + const reader = new FileReader(); + reader.onload = function(event) { + const img = new Image(); + img.onload = function() { + resolve(img.width); + }; + img.onerror = reject; + img.src = event.target.result; + }; + reader.onerror = reject; + reader.readAsDataURL(file); + } else { + resolve(0); + } + }); +} + +async function getInlineAttachmentMarkup(file) { + const sanitizedFilename = file.name.replace(/[\/\?\%\*\:\|\"\'<>\n\r]+/g, '_'); + const inlineFilename = encodeURIComponent(sanitizedFilename) + .replace(/[!()]/g, function(match) { return "%" + match.charCodeAt(0).toString(16) }); + + const isFromClipboard = /^clipboard-\d{12}-[a-z0-9]{5}\.\w+$/.test(file.name); + let imageDisplayWidth; + if (isFromClipboard) { + const imageWidth = await getImageWidth(file).catch(() => 0); + imageDisplayWidth = Math.round(imageWidth / window.devicePixelRatio); + } + const hasValidWidth = isFromClipboard && imageDisplayWidth > 0; + + switch (document.body.getAttribute('data-text-formatting')) { + case 'textile': + return hasValidWidth + ? `!{width: ${imageDisplayWidth}px}.${inlineFilename}!` + : `!${inlineFilename}!`; + case 'common_mark': + return hasValidWidth + ? `<img style="width: ${imageDisplayWidth}px;" src="${inlineFilename}"><br>` + : `![](${inlineFilename})`; + default: + // Text formatting is "none" or unknown + return ''; + } +} + function addInlineAttachmentMarkup(file) { // insert uploaded image inline if dropped area is currently focused textarea if($(handleFileDropEvent.target).hasClass('wiki-edit') && $.inArray(file.type, window.wikiImageMimeTypes) > -1) { var $textarea = $(handleFileDropEvent.target); var cursorPosition = $textarea.prop('selectionStart'); var description = $textarea.val(); - var sanitizedFilename = file.name.replace(/[\/\?\%\*\:\|\"\'<>\n\r]+/, '_'); - var inlineFilename = encodeURIComponent(sanitizedFilename) - .replace(/[!()]/g, function(match) { return "%" + match.charCodeAt(0).toString(16) }); var newLineBefore = true; var newLineAfter = true; if(cursorPosition === 0 || description.substr(cursorPosition-1,1).match(/\r|\n/)) { @@ -247,20 +292,16 @@ function addInlineAttachmentMarkup(file) { newLineAfter = false; } - $textarea.val( - description.substring(0, cursorPosition) - + (newLineBefore ? '\n' : '') - + inlineFilename - + (newLineAfter ? '\n' : '') - + description.substring(cursorPosition, description.length) - ); - - $textarea.prop({ - 'selectionStart': cursorPosition + newLineBefore, - 'selectionEnd': cursorPosition + inlineFilename.length + newLineBefore - }); - $textarea.parents('.jstBlock') - .find('.jstb_img').click(); + getInlineAttachmentMarkup(file) + .then(imageMarkup => { + $textarea.val( + description.substring(0, cursorPosition) + + (newLineBefore ? '\n' : '') + + imageMarkup + + (newLineAfter ? '\n' : '') + + description.substring(cursorPosition, description.length) + ); + }) // move cursor into next line cursorPosition = $textarea.prop('selectionStart'); |