mirror of
https://github.com/discourse/discourse.git
synced 2025-05-23 21:41:26 +08:00
FEATURE: Allow pausing animated images in posts (#12795)
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
This commit is contained in:
@ -0,0 +1,66 @@
|
|||||||
|
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||||
|
|
||||||
|
let _gifClickHandlers = {};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "animated-images-pause-on-click",
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
withPluginApi("0.8.7", (api) => {
|
||||||
|
function _cleanUp() {
|
||||||
|
Object.values(_gifClickHandlers || {}).forEach((handler) =>
|
||||||
|
handler.removeEventListener("click", _handleClick)
|
||||||
|
);
|
||||||
|
|
||||||
|
_gifClickHandlers = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function _handleClick(event) {
|
||||||
|
const img = event.target;
|
||||||
|
if (img && !img.previousSibling) {
|
||||||
|
let canvas = document.createElement("canvas");
|
||||||
|
canvas.width = img.width;
|
||||||
|
canvas.height = img.height;
|
||||||
|
canvas.getContext("2d").drawImage(img, 0, 0, img.width, img.height);
|
||||||
|
canvas.setAttribute("aria-hidden", "true");
|
||||||
|
canvas.setAttribute("role", "presentation");
|
||||||
|
|
||||||
|
img.parentNode.classList.add("paused-animated-image");
|
||||||
|
img.parentNode.insertBefore(canvas, img);
|
||||||
|
} else {
|
||||||
|
img.previousSibling.remove();
|
||||||
|
img.parentNode.classList.remove("paused-animated-image");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _attachCommands(post, helper) {
|
||||||
|
if (!helper) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let images = post.querySelectorAll("img.animated");
|
||||||
|
|
||||||
|
images.forEach((img) => {
|
||||||
|
if (_gifClickHandlers[img.src]) {
|
||||||
|
_gifClickHandlers[img.src].removeEventListener(
|
||||||
|
"click",
|
||||||
|
_handleClick
|
||||||
|
);
|
||||||
|
|
||||||
|
delete _gifClickHandlers[img.src];
|
||||||
|
}
|
||||||
|
|
||||||
|
_gifClickHandlers[img.src] = img;
|
||||||
|
img.addEventListener("click", _handleClick, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
api.decorateCookedElement(_attachCommands, {
|
||||||
|
onlyStream: true,
|
||||||
|
id: "animated-images-pause-on-click",
|
||||||
|
});
|
||||||
|
|
||||||
|
api.cleanupStream(_cleanUp);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
@ -1233,3 +1233,19 @@ a.mention-group {
|
|||||||
@include ellipsis;
|
@include ellipsis;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.paused-animated-image {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
> canvas {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.animated {
|
||||||
|
// need to keep the image hidden but clickable
|
||||||
|
// so the user can resume animation
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -318,6 +318,12 @@ class CookedPostProcessor
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
upload = Upload.get_from_url(src)
|
||||||
|
|
||||||
|
if upload.present? && upload.animated?
|
||||||
|
img.add_class("animated")
|
||||||
|
end
|
||||||
|
|
||||||
return if original_width <= SiteSetting.max_image_width && original_height <= SiteSetting.max_image_height
|
return if original_width <= SiteSetting.max_image_width && original_height <= SiteSetting.max_image_height
|
||||||
|
|
||||||
user_width, user_height = [original_width, original_height] if user_width.to_i <= 0 && user_height.to_i <= 0
|
user_width, user_height = [original_width, original_height] if user_width.to_i <= 0 && user_height.to_i <= 0
|
||||||
@ -332,7 +338,6 @@ class CookedPostProcessor
|
|||||||
width, height = ImageSizer.resize(width, height)
|
width, height = ImageSizer.resize(width, height)
|
||||||
end
|
end
|
||||||
|
|
||||||
upload = Upload.get_from_url(src)
|
|
||||||
if upload.present?
|
if upload.present?
|
||||||
upload.create_thumbnail!(width, height, crop: crop)
|
upload.create_thumbnail!(width, height, crop: crop)
|
||||||
|
|
||||||
|
@ -973,7 +973,7 @@ describe CookedPostProcessor do
|
|||||||
expect(doc.css('img').first['srcset']).to_not eq(nil)
|
expect(doc.css('img').first['srcset']).to_not eq(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not optimize animated images" do
|
it "does not optimize animated images but adds a class so animated images can be identified" do
|
||||||
upload.update!(animated: true)
|
upload.update!(animated: true)
|
||||||
post = Fabricate(:post, raw: "")
|
post = Fabricate(:post, raw: "")
|
||||||
|
|
||||||
@ -984,6 +984,7 @@ describe CookedPostProcessor do
|
|||||||
expect(doc.css('.lightbox-wrapper').size).to eq(1)
|
expect(doc.css('.lightbox-wrapper').size).to eq(1)
|
||||||
expect(doc.css('img').first['src']).to include(upload.url)
|
expect(doc.css('img').first['src']).to include(upload.url)
|
||||||
expect(doc.css('img').first['srcset']).to eq(nil)
|
expect(doc.css('img').first['srcset']).to eq(nil)
|
||||||
|
expect(doc.css('img.animated').size).to eq(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "optimizes images in quotes" do
|
it "optimizes images in quotes" do
|
||||||
|
Reference in New Issue
Block a user