Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image Block: Adding image resizing handles #2213

Merged
merged 11 commits into from
Aug 9, 2017

Conversation

youknowriad
Copy link
Contributor

closes #600

Implementation notes

  • We need to know the original image width and height before allowing to resize the image, this is done by loading the image before showing it and limiting its width/height to the canvas size (see ImageSize component)

Testing instructions

  • Try inserting and resizing an image

Questions

Should we resize the container (image + caption) or just the image?

@youknowriad youknowriad added [Feature] Blocks Overall functionality of blocks [Feature] Media Anything that impacts the experience of managing media labels Aug 4, 2017
@youknowriad youknowriad self-assigned this Aug 4, 2017
@youknowriad youknowriad force-pushed the add/image-resize-handles branch 2 times, most recently from 257b482 to 8a20ead Compare August 4, 2017 09:13
@jasmussen
Copy link
Contributor

Holy guacamole you're so fast it's hard to keep up!

This works really really well.

I can't decide whether we should change the block behavior when the image has no alignment. But it does bring some challenges with it, when it comes to floats and centering:

screen shot 2017-08-04 at 11 35 11

screen shot 2017-08-04 at 11 35 19

It seems right now we hard-code a width when we float. Can we undo that?

I have a bad feeling we might need to revisit the full-wide hack we've been using, or at least rethink how images float in such a world. Which is on me, but let's see what we can do with the floated block width for now...

Thanks Riad!

@jasmussen
Copy link
Contributor

There appear to be some issues with the demo content in this branch:

screen shot 2017-08-04 at 11 42 09

@youknowriad
Copy link
Contributor Author

@jasmussen Fixed the demo content bug but for the left/right width it's way harder. The width is fixed using the $float-margin mixin but It's hard to override when the width is dynamic. I think you're right, we need to revisit the full-wide hack we've been using to make this work.

All the help here would be appreciated (I don't have all the context about this hack) and maybe we could still ship this and resolve the left/right fixed width in another PR by changing the hack.

.eslintrc.json Outdated
@@ -24,7 +24,8 @@
"wp": true,
"wpApiSettings": true,
"window": true,
"document": true
"document": true,
"Image": true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See also: #1008

It was intentional to remove all globals and encourage to access through window, i.e. window.Image. Could be easy to think one had assigned a local Image variable but in fact it's referencing the global (as in the case of event bug of #1007). I guess same could be said of document (window.document), but... ¯\_(ツ)_/¯

this.image.onload = () => {
const maxWidth = this.container.clientWidth;
const ratio = this.image.height / this.image.width;
const width = this.image.width < maxWidth ? this.image.width : maxWidth;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Math.min could come in handy here:

const width = Math.min( maxWidth, this.image.width );

const maxWidth = this.container.clientWidth;
const ratio = this.image.height / this.image.width;
const width = this.image.width < maxWidth ? this.image.width : maxWidth;
const height = this.image.width < maxWidth ? this.image.height : maxWidth * ratio;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same note about Math.min, but also: Is maxWidth the correct value to test against? Or should maxHeight be a separate variable maxHeight = maxWidth * ratio ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maxWidth is the correct value, we adapt the height only if the image don't fit in the container's width.

const ratio = this.image.height / this.image.width;
const width = this.image.width < maxWidth ? this.image.width : maxWidth;
const height = this.image.width < maxWidth ? this.image.height : maxWidth * ratio;
this.setState( { width, height } );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the component has unmounted by this point?

Copy link
Contributor Author

@youknowriad youknowriad Aug 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a componentWillUnmount call.

Edit: I have a typo there

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, missed that. Is changing the src while the request is in flight enough to prevent onload from being called?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And setting the src to a function?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some testing. It seems to prevent onload callback if changed while in-flight. Though I think we'd ought to set to an empty string, not sure what the expected behavior of a function is.

image

lockAspectRatio
onResize={ ( event, { size } ) => setAttributes( size ) }
>
<img src={ url } alt={ alt } onClick={ setFocus } />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: We could create a single reference to this element to share between condition above and here:

diff --git a/blocks/library/image/index.js b/blocks/library/image/index.js
index f6985bc8..766fb8aa 100644
--- a/blocks/library/image/index.js
+++ b/blocks/library/image/index.js
@@ -178,8 +178,9 @@ registerBlockType( 'core/image', {
                        <figure key="image" className={ classes }>
                                <ImageSize src={ url }>
                                        { ( originalWidth = width, originalHeight = height ) => {
+                                               const img = <img src={ url } alt={ alt } onClick={ setFocus } />;
                                                if ( ! originalHeight || ! originalWidth ) {
-                                                       return <img src={ url } alt={ alt } onClick={ setFocus } />;
+                                                       return img;
                                                }
                                                return (
                                                        <ResizableBox
@@ -188,7 +189,7 @@ registerBlockType( 'core/image', {
                                                                lockAspectRatio
                                                                onResize={ ( event, { size } ) => setAttributes( size ) }
                                                        >
-                                                               <img src={ url } alt={ alt } onClick={ setFocus } />
+                                                               { img }
                                                        </ResizableBox>
                                                );
                                        } }

@mtias
Copy link
Member

mtias commented Aug 4, 2017

Pushed a change to account for resized images differently on floated instances (also centering on wider alignments).

image

The only slightly annoying thing is that, when the toolbar is wider than the image, it forces the width to be bigger:

image

When you unselect the image it goes back to the right size.

@mtias
Copy link
Member

mtias commented Aug 4, 2017

@jasmussen also maybe "wide" and "full-width" could clear the resized values.

@jasmussen
Copy link
Contributor

Vast improvements in a short amount of time, impressive. My hopes that we don't need to rewrite the full width math are restored.

Got some niggles still, though:

screen shot 2017-08-04 at 18 55 53

screen shot 2017-08-04 at 18 56 02

screen shot 2017-08-04 at 18 56 06

screen shot 2017-08-04 at 18 56 26

@youknowriad
Copy link
Contributor Author

Disabled the resizing for wide/full alignments but there're still some glitches for the left/right alignments.

@youknowriad
Copy link
Contributor Author

youknowriad commented Aug 4, 2017

Not sure I understand @mtias's fix but I found that always applying "data-resized" to the wrapper makes the component behave like I wanted.

@mtias
Copy link
Member

mtias commented Aug 4, 2017

@youknowriad if the image is not resized we'd want the 370px max-width to apply when floated.

@youknowriad
Copy link
Contributor Author

@mtias I'm not sure this is true, floating means "only floating" for me and frontend styling doesn't include this max-width.

@mtias
Copy link
Member

mtias commented Aug 4, 2017

Yes, it hasn't been applied to front-end, and we may want to revise that, but that was the intention of having the max-width, because if the image is larger than the text column, it doesn't look floated at all.

@youknowriad
Copy link
Contributor Author

youknowriad commented Aug 4, 2017

@mtias What about setting the 370px width to the image attributes when we switch to the left/right alignment (if no size set before) and always set data-resized. This will fix both issues at once.

@mtias
Copy link
Member

mtias commented Aug 4, 2017

Let's try it.

@youknowriad
Copy link
Contributor Author

Ok updated, It works well IMO but there's one caveat: I had to add a 'resized' attribute to the image to differentiate between explicitely resized image and a size set automatically when applying float alignments. This boolean is used when moving to "center" alignment: if we explicitly resized the image, we keep the size unless we reset it.

@youknowriad youknowriad force-pushed the add/image-resize-handles branch 2 times, most recently from cabd5d5 to d247219 Compare August 4, 2017 18:17
@youknowriad
Copy link
Contributor Author

There's some small remaining issue where we set a right value in the width/height attributes but the component is not rerendered accordingly unless we refresh.

@jasmussen
Copy link
Contributor

There are a couple of issues still. But if we believe these are issues we can address, then it's worth getting this in as a first pass, and then iterating. If, on the other hand, any of these sound like we can't address them easily, might be worth rethinking.

  1. The resize handle should only be visible when the block is selected
  2. If you resize an image reeeeally tiny, the handle doesn't follow all the way down. And when you later size up, the handle is out of sync.
  3. It feels like we should do the same as the current editor does with regards to image widths, when floated. Applying a max width seems arbitrary. Maybe you WANT a giant image that's left aligned.
  4. When you size an image bigger up, you can invoke multi select if you move the cursor downwards. This is easiest to test while resizing a thin image, like the landscape image in the demo content.
  5. There seems to have been a regression with images in the post content that are wide and full wide. Then handles there are gone, as they should be, but if you set one of those wide images to "float left" or "float right" instead, you have to first resize them down from their giant wide size first. And so, if you are sizing down an image in the demo content from fullwide, we should probably set the main column width first.

2 and 4 seem like they can be fixed both, by applying mininum and maximum dimensions.

@codecov
Copy link

codecov bot commented Aug 4, 2017

Codecov Report

Merging #2213 into master will decrease coverage by 0.06%.
The diff coverage is 6.52%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2213      +/-   ##
==========================================
- Coverage   25.35%   25.28%   -0.07%     
==========================================
  Files         151      152       +1     
  Lines        4701     4797      +96     
  Branches      792      816      +24     
==========================================
+ Hits         1192     1213      +21     
- Misses       2967     3026      +59     
- Partials      542      558      +16
Impacted Files Coverage Δ
blocks/with-editor-settings/index.js 60% <ø> (ø) ⬆️
editor/index.js 0% <0%> (ø) ⬆️
blocks/library/image/image-size.js 0% <0%> (ø)
blocks/library/image/index.js 12.24% <14.28%> (-2.47%) ⬇️
editor/effects.js 32.52% <0%> (+2.21%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update b4dc3e0...1c30f9a. Read the comment docs.

@youknowriad
Copy link
Contributor Author

@jasmussen Updated with another approach that seems simpler and more robust. Mind taking a look?

@youknowriad
Copy link
Contributor Author

Per slack discussion: I set the minimum width/height to 20px and the max-width to the image width.

@jasmussen
Copy link
Contributor

Thank you for working on this.

I'd love for the minimum dimensions to be 10px rather than 20px. But more importantly than those dimensions, I think, is that the handle detaches if you scale it smaller than what appears to be 20px height, and when you then scale up again, the handle sits in the air:

scaledown

Scaling up works 200% better now! It's almost perfect. But we may need scaling more scaling handles, or we're stuck when you make the image too big:

scaleup

It'd be nice (though not necessary for this PR) that the handles are hidden until you select the block.

For reference, here's what TinyMCE does:

tiny

Note how if you scale larger than the viewport, the sizing is discarded.

@youknowriad
Copy link
Contributor Author

youknowriad commented Aug 9, 2017

Note how if you scale larger than the viewport, the sizing is discarded.

TinyMCE limits scaling to the editor width and not the browser viewport. So, this seems more logic to me. For us, this might mean limit the scaling to the editor's content area size (which is 700px IIRC) but again, this means the user can't scale more than this even if it's theme allows it.

Also, the difference with TinyMCE is that Tinymce's size is flexible (it grows if you resize the window) which is not the case for our editor's content area.

I'm looking at the issues above

@youknowriad
Copy link
Contributor Author

the handle sits in the air:

This is fixed

It'd be nice (though not necessary for this PR) that the handles are hidden until you select the block.

This is fixed

But we may need more scaling handles

This can't be done with the current resizing library I'm using :(. Two options: find another library or write our own. The second one could be difficult to do. I'm looking at alternatives.

@jasmussen
Copy link
Contributor

TinyMCE limits scaling to the editor width and not the browser viewport. So, this seems more logic to me. For us, this might mean limit the scaling to the editor's content area size (which is 700px IIRC) but again, this means the user can't scale more than this even if it's theme allows it.

To be clear, it's fine to improvements in this area in separate non-milestoned PRs.

This can't be done with the current resizing library I'm using :(. Two options: find another library or write our own. The second one could be difficult to do. I'm looking at alternatives.

Bummer. Hmm. Can we choose which corner the handle sits on?

The big problem right now is that it's very easy to scale the image so large that the handle comes out of view, and then you can't scale it down. Perhaps we do need to limit the size to the editor width, so as to prevent this from happening.

Not saying it has to be perfect, looking for quick fixes here.

@youknowriad
Copy link
Contributor Author

@jasmussen Found a better library, let me know what do you think?

@jasmussen
Copy link
Contributor

🎉🎉🎉🎉

Oh my science this latest one is AMAZING! It feels completely solid! I think this can go in virtually as is!

A future improvement could be to improve this:

screen shot 2017-08-09 at 13 36 34

and this:

screen shot 2017-08-09 at 13 37 06

That is it'd be nice if the caption field was no larger than the image itself, and when the image is selected it seems like we might want to remove the 370px altogether on floats (which lets us remove the !important that Matías added).

The thing is, the max size on floated images is something we added because we didn't have a good resizing/insert thumbnail play. Now that we have good resizing, I don't think we need it.

@youknowriad
Copy link
Contributor Author

A future improvement could be to improve this:

Do you mean we should resize the whole "figure" node (image + caption) instead of resizing the image (current behaviour)? What do you suggest to fix those?

@jasmussen
Copy link
Contributor

Do you mean we should resize the whole "figure" node (image + caption) instead of resizing the image (current behaviour)? What do you suggest to fix those?

I'm not sure what the best way to improve this is. The idea would be that the caption field is no wider than the image. But let's explore this separately, and it doesn't have to be in the milestones.

@mtias
Copy link
Member

mtias commented Aug 9, 2017

For us, this might mean limit the scaling to the editor's content area size (which is 700px IIRC) but again, this means the user can't scale more than this even if it's theme allows it.

I think this is fine. If themes were to modify this, it would no longer be 700px in the editor.

@youknowriad
Copy link
Contributor Author

Not sure I understand, do you think this is ok to ship or is there anything else I should look at?

@mtias
Copy link
Member

mtias commented Aug 9, 2017

I meant not going beyond the width set on blocks that don't have wide/full alignment.

@youknowriad
Copy link
Contributor Author

👍 Understood and updated to constrain the resizing within the canvas. The value is hard-coded right now but we could easily make it overridable later.

@jasmussen
Copy link
Contributor

Love it, I think it's good to go!

We do definitely want ro revisit the max dimensions, but let's do that as part of a larger editor width discussion. I know there's a ticket for this separetely too. As it stands, this PR feels solid 👌

@youknowriad youknowriad merged commit 659b1bb into master Aug 9, 2017
@youknowriad youknowriad deleted the add/image-resize-handles branch August 9, 2017 17:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Blocks Overall functionality of blocks [Feature] Media Anything that impacts the experience of managing media [Priority] High Used to indicate top priority items that need quick attention
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Image Block: Need resize handles
4 participants