FEATURE: Allow post/topic thumbnails to be prioritized via markdown (#12044)

Previously we would always take the first image in a post to use as the
thumbnail. On media-heavy sites, users may want to manually select a
specific image as the topic thumbnail. This commit allows this to be
done via a `|thumbnail` attribute in markdown.

For example, in this case, bbb would be chosen as the thumbnail:

```
![alttext|100x100](upload://aaa)
![alttext|100x100|thumbnail](upload://bbb)
```
This commit is contained in:
David Taylor 2021-02-11 15:44:41 +00:00 committed by GitHub
parent a6bb7e6d25
commit 830797a9c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 27 additions and 5 deletions

View File

@ -190,6 +190,7 @@ export const DEFAULT_LIST = [
"img[height]",
"img[title]",
"img[width]",
"img[data-thumbnail]",
"ins",
"kbd",
"li",

View File

@ -177,7 +177,7 @@ function renderImageOrPlayableMedia(tokens, idx, options, env, slf) {
const token = tokens[idx];
const alt = slf.renderInlineAsText(token.children, options, env);
const split = alt.split("|");
const altSplit = [];
const altSplit = [split[0]];
// markdown-it supports returning HTML instead of continuing to render the current token
// see https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer
@ -195,7 +195,7 @@ function renderImageOrPlayableMedia(tokens, idx, options, env, slf) {
}
// parsing ![myimage|500x300]() or ![myimage|75%]() or ![myimage|500x300, 75%]
for (let i = 0, match, data; i < split.length; ++i) {
for (let i = 1, match, data; i < split.length; ++i) {
if ((match = split[i].match(IMG_SIZE_REGEX)) && match[1] && match[2]) {
let width = match[1];
let height = match[2];
@ -238,6 +238,8 @@ function renderImageOrPlayableMedia(tokens, idx, options, env, slf) {
}
} else if ((data = extractDataAttribute(split[i]))) {
token.attrs.push(data);
} else if (split[i] === "thumbnail") {
token.attrs.push(["data-thumbnail", "true"]);
} else {
altSplit.push(split[i]);
}

View File

@ -483,14 +483,20 @@ class CookedPostProcessor
def update_post_image
upload = nil
eligible_image_fragments = extract_images_for_post
images = extract_images_for_post
# Loop through those fragments until we find one with an upload record
@post.each_upload_url(fragments: eligible_image_fragments) do |src, path, sha1|
@post.each_upload_url(fragments: images.css("[data-thumbnail]")) do |src, path, sha1|
upload = Upload.find_by(sha1: sha1)
break if upload
end
if upload.nil? # No specified thumbnail. Use any image:
@post.each_upload_url(fragments: images.css(":not([data-thumbnail])")) do |src, path, sha1|
upload = Upload.find_by(sha1: sha1)
break if upload
end
end
if upload.present?
@post.update_column(:image_upload_id, upload.id) # post
if @post.is_first_post? # topic

View File

@ -772,6 +772,19 @@ describe CookedPostProcessor do
end
end
it "prioritizes data-thumbnail images" do
upload1 = Fabricate(:image_upload, width: 1750, height: 2000)
upload2 = Fabricate(:image_upload, width: 1750, height: 2000)
post = Fabricate(:post, raw: <<~MD)
![alttext|1750x2000](#{upload1.url})
![alttext|1750x2000|thumbnail](#{upload2.url})
MD
CookedPostProcessor.new(post, disable_loading_image: true).post_process
expect(post.reload.image_upload_id).to eq(upload2.id)
end
context "post image" do
let(:reply) { Fabricate(:post_with_uploaded_image, post_number: 2) }
let(:cpp) { CookedPostProcessor.new(reply) }