-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Editor: Add support for editing embeds inside a post #17152
Conversation
0fb745a
to
f680276
Compare
9c99a93
to
8084d6b
Compare
b38dc12
to
fab919e
Compare
The CI failure is just the linter complaining about an unrelated violated that exists in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good on my first pass - I've mentioned just a few little nits for now but happy give a proper run through & review over the weekend :)
import Button from 'components/button'; | ||
import Dialog from 'components/dialog'; | ||
import FormTextInput from 'components/forms/form-text-input'; | ||
import { localize } from 'i18n-calypso'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: We usually pile 'i18n-calypso' in to externals since it's source is outside of Calypso (even though really it's calypso specific)
} ); | ||
}; | ||
|
||
onUpdate = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be worth debouncing both of the input events for perf reasons.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you mean that onChangeEmbedUrl
(the <input onChange...
handler) should be debounced, or onUpdate
and onCancel
? The latter two only fire once when the Update
and Cancel
buttons are clicked, unless I'm missing something.
I'm planning on debouncing part of onChangeEmbedUrl
in #18171 , because that PR will add a preview embed of the new URL:
It doesn't debounce the setState()
call, though. I would think that would cause problems, since it's a controlled component. Wouldn't it interfere with the user typing a new URL in quickly, or am I misunderstanding how it works? It seems to work ok in my tests, and I don't see any warnings about it when searching, but I just wanna double check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, yes sorry, onChangeEmbedUrl
:P I'm glad you know which I meant!
I feel like debouncing all of onChangeEmbedUrl
might be sensible to avoid re-renders on every keypress (since the state is changing).
It would also avoid setting focus on every key up in #18171 - not sure if that helps or hinders that situation though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 thanks, I'll go with that approach :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, I added the debounce in 2134a11, but that broke the unit tests and introduced a bug where clicking Update
before the debounce callback has ran will cause the old URL to be returned to TinyMCE instead of the new one.
Those are fixable problems, but I'm just wondering if it's worth making the code more complex to avoid calling render()
here, especially since I don't think there'll be any diffs between the virtual DOM and the real one, since FormTextInput
is an uncontrolled component. Also because I think the most common use case will be copy/pasting a URL, rather than manually typing it.
I think previewing the new URL in #18171 should definitely be debounced, but I'm just not sure that setState
should be.
Is there a good way to tell what kind of performance impact setState
will have if left undebounced? Maybe profiling w/ Chrome dev tools or something? I can look into that tomorrow if you think it's worth it.
|
||
render() { | ||
const { translate } = this.props, | ||
dialogButtons = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure it's in the guidelines but the trend is to define each const
or let
separately - I believe for the same reasons mentioned in AirBnBs guidelines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, nice! I often prefer that as well. It doesn't look like there's anything about it in the docs, I think I was just doing it out of habit from the Core guidelines.
</h3> | ||
|
||
<FormTextInput | ||
autoFocus={ true } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
little tip: ={ true }
is redundant here as a bare prop (autoFocus
without assignment) would infer the value true
... totally fine to leave as is though!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, good to know, thanks! I tested both out, and having the explicit true
feels a bit nicer to me in this specific case, but it's definitely not a big deal. I can also see how leaving it off could come in handy in some cases, like <Foo autoFocus foo bar={ false }>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I definitely see the upside to it being explicit - it doesn't require knowing that a bare prop implies a true
value for a start :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think in this case the main thing that makes it feel "better" to me is just the visual consistency with the other parameters. No big deal either way, though :)
isVisible={ this.state.showDialog } | ||
onCancel={ this.onCancel } | ||
onUpdate={ this.onUpdate } | ||
translate={ identity } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be a little misleading to mention in the example. I'm not sure what others think but I'd leave it out since the reader of the example shouldn't need to consider it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you referring to translate
? I added it here since it's a required
prop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, I'm with you - I didn't spot that the base component was being imported directly :)
That said, should we be recommending it's use in the example or should we recommend using the enhanced component ( export default
)?
I could be wrong but I think the only reason one would need to import the base component would be for test purposes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I get what you're saying now, and you're totally right. The example should use the default
, localized component, since that's what would normally be used when adding new uses of the component elsewhere in Calypso. Great catch, thanks!
fab919e
to
6ba0690
Compare
I pushed some of those tweaks in 6ba0690. |
} ); | ||
}; | ||
|
||
onUpdate = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, yes sorry, onChangeEmbedUrl
:P I'm glad you know which I meant!
I feel like debouncing all of onChangeEmbedUrl
might be sensible to avoid re-renders on every keypress (since the state is changing).
It would also avoid setting focus on every key up in #18171 - not sure if that helps or hinders that situation though.
isVisible={ this.state.showDialog } | ||
onCancel={ this.onCancel } | ||
onUpdate={ this.onUpdate } | ||
translate={ identity } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, I'm with you - I didn't spot that the base component was being imported directly :)
That said, should we be recommending it's use in the example or should we recommend using the enhanced component ( export default
)?
I could be wrong but I think the only reason one would need to import the base component would be for test purposes.
/** | ||
* External dependencies | ||
*/ | ||
import Dialog from 'components/dialog'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though I get that they are external to this 'unit' I think we should keep import Dialog from 'components/dialog';
and import FormTextInput from 'components/forms/form-text-input';
in the internal deps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doh, I don't think I meant to put those in External
; thanks for catching that :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NP! :)
I didn’t dig very deep into the PR, but a general rule is you don’t want any delay with I understand you need to debounce the iframe updates. I would definitely do that. Simplest way would be to have a second state like |
@marekhrabe's completely right! Sorry Ian, I think I'd just got myself confused and passed that confusion on here! |
For clarity: I think you were on the right path in the first place - Updating the URL as the user types but debouncing the fetching. |
2134a11
to
d2ba91c
Compare
Thanks for the input :) I've removed the debounce and rebased. Any final thoughts before I merge? |
( CI failure is just an unrelated linter warning ) |
This is definitely outside the scope of this PR and something I don't think we can really get around, but editing the url of 1 (of 2) embedded youtube videos causes both of them to 'flash' (I'm guessing it's some effect of re-rendering. Other than that, this is looking great! Thanks Ian and sorry again for the curveball! 😃 |
This adds a dialog to edit the embed URL, but doesn't add a preview of the new URL, so it doesn't fully implement [the design in #1729](https://user-images.githubusercontent.com/191598/28643536-23f2e318-7224-11e7-8fd1-9a889d53b594.png). It's a step in that direction, though, and a future PR will add the preview. See #1729
d2ba91c
to
92bb1d2
Compare
Thanks! Merged :) |
This is still a work in progress.
Currently embeds can't be edited after they've been inserted into a post. They can only be deleted and then re-created with the new parameters.
This PR adds a method for editing them. It doesn't add a preview of the new embed, but that will be done in #18171.
See #1729
Test plan:
esc
and clicking outside the box will close the modalenter
in the text field will submit the new URL and update the embed