mirror of https://github.com/zulip/zulip.git
thumbnail: Add a data-original-dimensions attribute.
This allows clients to potentially lay out the thumbnails more intelligently, or to provide a better "progressive-load" experience when enlarging the thumbnail.
This commit is contained in:
parent
65828b20e9
commit
2ea0cc0005
|
@ -20,6 +20,12 @@ format used by the Zulip server that they are interacting with.
|
||||||
|
|
||||||
## Changes in Zulip 9.0
|
## Changes in Zulip 9.0
|
||||||
|
|
||||||
|
**Feature level 276**
|
||||||
|
|
||||||
|
* [Markdown message formatting](/api/message-formatting#image-previews):
|
||||||
|
Image preview elements not contain a `data-original-dimensions`
|
||||||
|
attribute containing the dimensions of the original image.
|
||||||
|
|
||||||
**Feature level 275**
|
**Feature level 275**
|
||||||
|
|
||||||
* [`POST /register`](/api/register-queue), [`PATCH
|
* [`POST /register`](/api/register-queue), [`PATCH
|
||||||
|
|
|
@ -34,7 +34,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
|
||||||
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
||||||
# entries in the endpoint's documentation in `zulip.yaml`.
|
# entries in the endpoint's documentation in `zulip.yaml`.
|
||||||
|
|
||||||
API_FEATURE_LEVEL = 275 # Last bumped for `web_animate_image_previews` setting.
|
API_FEATURE_LEVEL = 276 # Last bumped for data-original-dimensions
|
||||||
|
|
||||||
|
|
||||||
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
||||||
|
|
|
@ -329,6 +329,8 @@ def split_thumbnail_path(file_path: str) -> tuple[str, BaseThumbnailFormat]:
|
||||||
class MarkdownImageMetadata:
|
class MarkdownImageMetadata:
|
||||||
url: str
|
url: str
|
||||||
is_animated: bool
|
is_animated: bool
|
||||||
|
original_width_px: int
|
||||||
|
original_height_px: int
|
||||||
|
|
||||||
|
|
||||||
def get_user_upload_previews(
|
def get_user_upload_previews(
|
||||||
|
@ -347,6 +349,8 @@ def get_user_upload_previews(
|
||||||
upload_preview_data[image_attachment.path_id] = MarkdownImageMetadata(
|
upload_preview_data[image_attachment.path_id] = MarkdownImageMetadata(
|
||||||
url=url,
|
url=url,
|
||||||
is_animated=is_animated,
|
is_animated=is_animated,
|
||||||
|
original_width_px=image_attachment.original_width_px,
|
||||||
|
original_height_px=image_attachment.original_height_px,
|
||||||
)
|
)
|
||||||
return upload_preview_data
|
return upload_preview_data
|
||||||
|
|
||||||
|
@ -421,6 +425,9 @@ def rewrite_thumbnailed_images(
|
||||||
changed = True
|
changed = True
|
||||||
del image_tag["class"]
|
del image_tag["class"]
|
||||||
image_tag["src"] = image_data.url
|
image_tag["src"] = image_data.url
|
||||||
|
image_tag["data-original-dimensions"] = (
|
||||||
|
f"{image_data.original_width_px}x{image_data.original_height_px}"
|
||||||
|
)
|
||||||
if image_data.is_animated:
|
if image_data.is_animated:
|
||||||
image_tag["data-animated"] = "true"
|
image_tag["data-animated"] = "true"
|
||||||
|
|
||||||
|
|
|
@ -73,15 +73,15 @@ class MarkdownThumbnailTest(ZulipTestCase):
|
||||||
"<p>Test 1<br>\n"
|
"<p>Test 1<br>\n"
|
||||||
f'<a href="/user_uploads/{path_ids[0]}">{image_names[0]}</a> </p>\n'
|
f'<a href="/user_uploads/{path_ids[0]}">{image_names[0]}</a> </p>\n'
|
||||||
f'<div class="message_inline_image"><a href="/user_uploads/{path_ids[0]}" title="{image_names[0]}">'
|
f'<div class="message_inline_image"><a href="/user_uploads/{path_ids[0]}" title="{image_names[0]}">'
|
||||||
f'<img src="/user_uploads/thumbnail/{path_ids[0]}/840x560.webp"></a></div>'
|
f'<img data-original-dimensions="128x128" src="/user_uploads/thumbnail/{path_ids[0]}/840x560.webp"></a></div>'
|
||||||
"<p>Next image<br>\n"
|
"<p>Next image<br>\n"
|
||||||
f'<a href="/user_uploads/{path_ids[1]}">{image_names[1]}</a> </p>\n'
|
f'<a href="/user_uploads/{path_ids[1]}">{image_names[1]}</a> </p>\n'
|
||||||
f'<div class="message_inline_image"><a href="/user_uploads/{path_ids[1]}" title="{image_names[1]}">'
|
f'<div class="message_inline_image"><a href="/user_uploads/{path_ids[1]}" title="{image_names[1]}">'
|
||||||
f'<img src="/user_uploads/thumbnail/{path_ids[1]}/840x560.webp"></a></div>'
|
f'<img data-original-dimensions="128x128" src="/user_uploads/thumbnail/{path_ids[1]}/840x560.webp"></a></div>'
|
||||||
"<p>Another screenshot<br>\n"
|
"<p>Another screenshot<br>\n"
|
||||||
f'<a href="/user_uploads/{path_ids[2]}">{image_names[2]}</a></p>\n'
|
f'<a href="/user_uploads/{path_ids[2]}">{image_names[2]}</a></p>\n'
|
||||||
f'<div class="message_inline_image"><a href="/user_uploads/{path_ids[2]}" title="{image_names[2]}">'
|
f'<div class="message_inline_image"><a href="/user_uploads/{path_ids[2]}" title="{image_names[2]}">'
|
||||||
f'<img src="/user_uploads/thumbnail/{path_ids[2]}/840x560.webp"></a></div>'
|
f'<img data-original-dimensions="128x128" src="/user_uploads/thumbnail/{path_ids[2]}/840x560.webp"></a></div>'
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ class MarkdownThumbnailTest(ZulipTestCase):
|
||||||
expected = (
|
expected = (
|
||||||
f'<p><a href="/user_uploads/{path_id}">image</a></p>\n'
|
f'<p><a href="/user_uploads/{path_id}">image</a></p>\n'
|
||||||
f'<div class="message_inline_image"><a href="/user_uploads/{path_id}" title="image">'
|
f'<div class="message_inline_image"><a href="/user_uploads/{path_id}" title="image">'
|
||||||
f'<img src="/user_uploads/thumbnail/{path_id}/840x560.webp"></a></div>'
|
f'<img data-original-dimensions="128x128" src="/user_uploads/thumbnail/{path_id}/840x560.webp"></a></div>'
|
||||||
)
|
)
|
||||||
self.assert_message_content_is(message_id, expected)
|
self.assert_message_content_is(message_id, expected)
|
||||||
|
|
||||||
|
@ -142,7 +142,8 @@ class MarkdownThumbnailTest(ZulipTestCase):
|
||||||
message_id = self.send_message_content(f"[I am 95% ± 5% certain!](/user_uploads/{path_id})")
|
message_id = self.send_message_content(f"[I am 95% ± 5% certain!](/user_uploads/{path_id})")
|
||||||
expected = (
|
expected = (
|
||||||
f'<p><a href="/user_uploads/{path_id}">I am 95% ± 5% certain!</a></p>\n'
|
f'<p><a href="/user_uploads/{path_id}">I am 95% ± 5% certain!</a></p>\n'
|
||||||
f'<div class="message_inline_image"><a href="/user_uploads/{path_id}" title="I am 95% ± 5% certain!"><img src="/user_uploads/thumbnail/{path_id}/840x560.webp"></a></div>'
|
f'<div class="message_inline_image"><a href="/user_uploads/{path_id}" title="I am 95% ± 5% certain!">'
|
||||||
|
f'<img data-original-dimensions="128x128" src="/user_uploads/thumbnail/{path_id}/840x560.webp"></a></div>'
|
||||||
)
|
)
|
||||||
self.assert_message_content_is(message_id, expected)
|
self.assert_message_content_is(message_id, expected)
|
||||||
|
|
||||||
|
@ -157,12 +158,13 @@ class MarkdownThumbnailTest(ZulipTestCase):
|
||||||
ThumbnailFormat("webp", 100, 75, animated=True),
|
ThumbnailFormat("webp", 100, 75, animated=True),
|
||||||
ThumbnailFormat("webp", 100, 75, animated=False),
|
ThumbnailFormat("webp", 100, 75, animated=False),
|
||||||
):
|
):
|
||||||
path_id = self.upload_and_thumbnail_image("animated_img.gif")
|
path_id = self.upload_and_thumbnail_image("animated_unequal_img.gif")
|
||||||
content = f"[animated_img.gif](/user_uploads/{path_id})"
|
content = f"[animated_unequal_img.gif](/user_uploads/{path_id})"
|
||||||
expected = (
|
expected = (
|
||||||
f'<p><a href="/user_uploads/{path_id}">animated_img.gif</a></p>\n'
|
f'<p><a href="/user_uploads/{path_id}">animated_unequal_img.gif</a></p>\n'
|
||||||
f'<div class="message_inline_image"><a href="/user_uploads/{path_id}" title="animated_img.gif">'
|
f'<div class="message_inline_image"><a href="/user_uploads/{path_id}" title="animated_unequal_img.gif">'
|
||||||
f'<img data-animated="true" src="/user_uploads/thumbnail/{path_id}/100x75-anim.webp"></a></div>'
|
'<img data-animated="true" data-original-dimensions="128x56"'
|
||||||
|
f' src="/user_uploads/thumbnail/{path_id}/100x75-anim.webp"></a></div>'
|
||||||
)
|
)
|
||||||
message_id = self.send_message_content(content, do_thumbnail=True)
|
message_id = self.send_message_content(content, do_thumbnail=True)
|
||||||
self.assert_message_content_is(message_id, expected)
|
self.assert_message_content_is(message_id, expected)
|
||||||
|
@ -208,7 +210,7 @@ class MarkdownThumbnailTest(ZulipTestCase):
|
||||||
f'<div class="message_inline_image"><a href="/user_uploads/{first_path_id}" title="first image">'
|
f'<div class="message_inline_image"><a href="/user_uploads/{first_path_id}" title="first image">'
|
||||||
'<img class="image-loading-placeholder" src="/static/images/loading/loader-black.svg"></a></div>'
|
'<img class="image-loading-placeholder" src="/static/images/loading/loader-black.svg"></a></div>'
|
||||||
f'<div class="message_inline_image"><a href="/user_uploads/{second_path_id}" title="second image">'
|
f'<div class="message_inline_image"><a href="/user_uploads/{second_path_id}" title="second image">'
|
||||||
f'<img src="/user_uploads/thumbnail/{second_path_id}/840x560.webp"></a></div>'
|
f'<img data-original-dimensions="128x128" src="/user_uploads/thumbnail/{second_path_id}/840x560.webp"></a></div>'
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -220,9 +222,9 @@ class MarkdownThumbnailTest(ZulipTestCase):
|
||||||
f'<p><a href="/user_uploads/{first_path_id}">first image</a><br>\n'
|
f'<p><a href="/user_uploads/{first_path_id}">first image</a><br>\n'
|
||||||
f'<a href="/user_uploads/{second_path_id}">second image</a></p>\n'
|
f'<a href="/user_uploads/{second_path_id}">second image</a></p>\n'
|
||||||
f'<div class="message_inline_image"><a href="/user_uploads/{first_path_id}" title="first image">'
|
f'<div class="message_inline_image"><a href="/user_uploads/{first_path_id}" title="first image">'
|
||||||
f'<img src="/user_uploads/thumbnail/{first_path_id}/840x560.webp"></a></div>'
|
f'<img data-original-dimensions="128x128" src="/user_uploads/thumbnail/{first_path_id}/840x560.webp"></a></div>'
|
||||||
f'<div class="message_inline_image"><a href="/user_uploads/{second_path_id}" title="second image">'
|
f'<div class="message_inline_image"><a href="/user_uploads/{second_path_id}" title="second image">'
|
||||||
f'<img src="/user_uploads/thumbnail/{second_path_id}/840x560.webp"></a></div>'
|
f'<img data-original-dimensions="128x128" src="/user_uploads/thumbnail/{second_path_id}/840x560.webp"></a></div>'
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -247,7 +249,7 @@ class MarkdownThumbnailTest(ZulipTestCase):
|
||||||
expected = (
|
expected = (
|
||||||
f'<p><a href="/user_uploads/{path_id}">image</a></p>\n'
|
f'<p><a href="/user_uploads/{path_id}">image</a></p>\n'
|
||||||
f'<div class="message_inline_image"><a href="/user_uploads/{path_id}" title="image">'
|
f'<div class="message_inline_image"><a href="/user_uploads/{path_id}" title="image">'
|
||||||
f'<img src="/user_uploads/thumbnail/{path_id}/840x560.webp"></a></div>'
|
f'<img data-original-dimensions="128x128" src="/user_uploads/thumbnail/{path_id}/840x560.webp"></a></div>'
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
ArchivedMessage.objects.get(id=message_id).rendered_content,
|
ArchivedMessage.objects.get(id=message_id).rendered_content,
|
||||||
|
@ -320,7 +322,7 @@ class MarkdownThumbnailTest(ZulipTestCase):
|
||||||
|
|
||||||
rendered_thumb = (
|
rendered_thumb = (
|
||||||
f'<div class="message_inline_image"><a href="/user_uploads/{path_id}" title="image">'
|
f'<div class="message_inline_image"><a href="/user_uploads/{path_id}" title="image">'
|
||||||
f'<img src="/user_uploads/thumbnail/{path_id}/100x75.webp"></a></div>'
|
f'<img data-original-dimensions="128x128" src="/user_uploads/thumbnail/{path_id}/100x75.webp"></a></div>'
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assert_message_content_is(
|
self.assert_message_content_is(
|
||||||
|
|
|
@ -147,6 +147,8 @@ def ensure_thumbnails(image_attachment: ImageAttachment) -> int:
|
||||||
MarkdownImageMetadata(
|
MarkdownImageMetadata(
|
||||||
url=url,
|
url=url,
|
||||||
is_animated=is_animated,
|
is_animated=is_animated,
|
||||||
|
original_width_px=image_attachment.original_width_px,
|
||||||
|
original_height_px=image_attachment.original_height_px,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return written_images
|
return written_images
|
||||||
|
|
Loading…
Reference in New Issue