Add zoomable images feature#3127
Conversation
e172cff to
4d67425
Compare
|
Updated failing tests as well, ready for review. :) |
|
ping @ehuss |
|
Won't this break images that are links? |
|
I think it would yes. Didn't think about that. If I only allow to zoom on non-link images, does it sound good to you? |
|
The description mentions the escape key for zooming back out, how would that work on a mobile device? Or does tapping it again toggle off the invisible checkbox? |
Tapping again will zoom-out. |
|
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
@ehuss Disabled the feature on images inside links and extended test to check it as well. |
There was a problem hiding this comment.
Thanks!
I'm not going to block on it, but this doesn't seem to support the ability to trigger with the keyboard. Generally we try to ensure to follow accessibility guidelines as much as we can.
Just curious, was it intentional that you can still scroll when the image is zoomed in? (I'm not sure if I have a preference, just checking.)
I'm slightly uneasy not having a way to turn this off. I'm fine with starting without it, but if people have issues, we may need to add something. In particular, small images like icons probably don't need or want to be zoomed in this way.
|
|
||
| let mut label = Element::new("label"); | ||
| label.insert_attr("class", "checkbox-label".to_tendril()); | ||
| label.insert_attr("for", img_input_id.to_tendril()); |
There was a problem hiding this comment.
The IDs end up getting broken on the print page because it rebuilds the IDs to be unique. I think the "for" here ends up being the wrong value in that case.
I'm not sure how to fix that, other than the print page also handling this attribute.
There was a problem hiding this comment.
It's the print page, so I don't think it matters in this case, no?
| } else { | ||
| img.insert_attr("title", alt.into()); |
There was a problem hiding this comment.
Why was this fallback to add the alt as the title added?
There was a problem hiding this comment.
I mentioned it in my first comment:
I also realized that images had the alt attribute, but not the title one, so I added it while I was at it.
It's better for accessibility, and for other users, to have text when they hover an image without moving for a while.
| label.insert_attr("for", img_input_id.to_tendril()); | ||
| self.push(Node::Element(label)); | ||
|
|
||
| self.append(Node::Element(img.clone())); |
There was a problem hiding this comment.
I'm a little concerned about this approach of using a duplicated <img> tag. Screen readers may have difficulty handling this. I think at a minimum it should have aria-hidden="true". I'm a bit uncomfortable with this approach in general, though I'm willing to give it a try.
There was a problem hiding this comment.
I think screen readers all handle display: none, so I think we're fine (although if we could test it, would be even better). However, won't aria-hidden=true be an issue when the image is zoomed-in?
|
|
||
| self.append(Node::Element(img)); | ||
|
|
||
| // We exit the `label` and the `div`. |
There was a problem hiding this comment.
This comment seems off. There is no div AFAIK.
Perhaps it means:
| // We exit the `label` and the `div`. | |
| // We exit the `label` and the `span` (which used push_no_stack). |
| margin-right: 8px; | ||
| } | ||
|
|
||
| .content .checkbox-img, .checkbox-label > .img-wrapper { |
There was a problem hiding this comment.
Can you add comments explaining what these rules are for and what they do? It can be just a short comment on each selector to explain what it's for (image zoom) and what that selector is doing.
|
|
||
| (function chapterNavigation() { | ||
| function zoomOutImages() { | ||
| for (const elem of Array.from(document.querySelectorAll('input.checkbox-img'))) { |
There was a problem hiding this comment.
I believe this can be simplified:
| for (const elem of Array.from(document.querySelectorAll('input.checkbox-img'))) { | |
| for (const elem of document.querySelectorAll('input.checkbox-img')) { |
There was a problem hiding this comment.
It can, but since we make modifications to the DOM, there is a non-zero chance that the selector list will recompute itself between each items (that was a huge issue in older rustdoc when we used it to generate [-] buttons).
| call-function: ("check-image-zoomed-in", {}) | ||
|
|
||
| // We click on the wrapper to "zoom out". | ||
| click: ".checkbox-label > img" |
There was a problem hiding this comment.
Is it intentional that this clicks on the image underneath the wrapper? That is, should this be something like ".image-wrapper > img" or ".image-wrapper" to simulate what the user would actually click on?
There was a problem hiding this comment.
Well, they click on the image, but the image being part of the label, since there is no preventDefault() on the image, the event is propagated to the parent until the parent is the label which then handles the click event and stops its propagation. So it is how users will interact with it.
| } | ||
|
|
||
| /// Returns the current `img_label_id` and increase its value. | ||
| fn get_current_img_label_id(&mut self) -> usize { |
There was a problem hiding this comment.
Just a very minor nit, but this method name seemed a little confusing to me since it has a side effect. Perhaps something like get_next_img_label_id would be a little clearer?
|
Also, it's probably a good idea to include at least some note in the documentation that this exists. Perhaps on the Images section? |
I was sure I tested that, I'll double-check and add a regression test to ensure it works.
I didn't consider it an issue but I can do it if you want as even with JS (it's required for that as I need to change a parent's style, so cannot be done with only CSS).
I can add a CLI option for that if you want? As for small images, if I want to know their size, I would need another dependency for that. Not sure it's worth it but again, your call. |
|
I simplified the DOM generation: no need for an ID anymore. We can now make the zoom in feature work with the keyboard (still no JS, works with spacebar). Added a GUI test for it as well. And mentioned it in the mdbook guide. I didn't add a new CLI option to disable it yet. Waiting for you to confirm if you want it or not. |
|
Updated tests with HTML comparisons. :) |
Fixes #2075.
The "zoomed-in" image looks like this:
The JS is only used to "zoom out" images with the "escape key", otherwise the feature works entirely without JS.
It works as follows: there is a (hidden) checkbox right before the image. The image itself is inside the label associated to the checkbox, meaning that when you click on the image, you switch the value of the checkbox. And thanks to
:checkedCSS selector, it changes the display of the zoomed out image.To make it obvious that you can "zoom in"/"zoom out" on an image, I changed the cursor to look like a loop using the CSS
cursor: zoom-in|zoom-outproperty.I also realized that images had the
altattribute, but not thetitleone, so I added it while I was at it.