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

Layout: Add preview layoutFocus for DesignPreview #4690

Merged
merged 9 commits into from
May 12, 2016

Conversation

sirbrillig
Copy link
Member

@sirbrillig sirbrillig commented Apr 12, 2016

Summary

Adds a new layoutFocus called preview which, when activated (layoutFocus.set( 'preview' )), shows a preview of the current site pretty much anywhere in Calypso.

preview-layout-demo

How it works

The DesignPreview component can render raw markup to a preview and then apply customizations to that preview. This PR adds a data layer for the preview markup and the customizations.

The raw markup is fetched from the REST API and saved as previewMarkup in the Redux state tree (one for each site). When it is rendered, the method updatePreviewWithChanges() in lib/design-preview will be called with the arguments:

  1. The document object of the iframe.
  2. The current value of the customizations object from the Redux state tree for this site.

The customizations object and the previewMarkup used by the preview are stored in the Redux state tree under the preview key for a given site. The state also keeps track of the "saved" status of the customizations and a history of all customization changes (enabling an "undo" feature).

This PR is essentially a newer version of several parts of #4140 and #4153 except without DesignMenu, the updaters, or the save-functions, which can be added separately.

Testing

To activate it right now you can press the "customize" button in the sidebar, but that is only temporary and should be removed before merging. It would be nice if we could replace that with a command-line method of activating the layout. Not sure how to go about that...

@sirbrillig
Copy link
Member Author

Ping @mtias, @ehg, and @mcsf for comments

@sirbrillig sirbrillig force-pushed the add/preview-layout-focus branch 2 times, most recently from 2e203b7 to f00754c Compare April 21, 2016 16:05
} )
.catch( reject );
} );
};
Copy link
Member

Choose a reason for hiding this comment

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

Two notes:

  • I think we should add one step of indentation when starting a line with .then, .catch, or any other property/method access, and that is AFAIK the convention in Calypso.
  • I'd refactor things here, as the handling of promises is repeated verbatim in the function:
const request = postData && Object.keys( postData ).length > 0
  ? this.wpcom.req.post( endpoint, query, { customized: postData } )
  : this.wpcom.req.get( endpoint, query );

request
  .then( response => {  } )
  .catch( reject );

As a side effect, it makes the function more self-explanatory.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good points! I don't like long ternaries as I think they decrease readability, but I also think combining the requests is a good idea, so I compromised and made a shorter ternary with some extra consts.

const endpoint = `/sites/${siteId}/previews/mine`;
const query = { path: slug };
const isPreviewCustomized = ( postData && Object.keys( postData ).length > 0 );
const { post, get } = this.wpcom.req;
Copy link
Member

Choose a reason for hiding this comment

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

Interesting. I didn't expect post and get to be automatically bound to req.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh yeah, interesting indeed. I didn't expect that get or post would use this, but there it is. It looks like maybe binding to the right-hand-side object is part of object destructuring assignment.

Copy link
Member

Choose a reason for hiding this comment

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

It still makes me uncomfortable, though. :) And, actually, I'm not convinced that there's any magic binding happening: see Babel output.

I'd keep the method calls attached to the whole context tree (this.wpcom.req.post( bla )). Then again, I am not bothered by three-line ternaries. ;)

Copy link
Member Author

@sirbrillig sirbrillig May 2, 2016

Choose a reason for hiding this comment

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

Fair enough. Changed to the longer version.

@lsinger
Copy link
Contributor

lsinger commented Apr 29, 2016

This looks great! Two things I noticed after playing around a bit:

  • When I change my site (in this case, I changed my header image) the preview doesn't refresh, even if I reload Calypso.dev. Should it notice changes by itself? Should I have a way to refresh?
  • When I open the preview, it opens in tablet size by default. I prefer desktop size, so I set it to that. I close the preview. I open the preview again. It's now in desktop size, great--but apparently the CSS stops working. Can anyone reproduce or is it just me?

@sirbrillig
Copy link
Member Author

When I change my site (in this case, I changed my header image) the preview doesn't refresh, even if I reload Calypso.dev. Should it notice changes by itself? Should I have a way to refresh?

I think that was a bug having to do with the site ID not being available when the component loads. I've just fixed it in 9153d4e. Let me know if that solves the issue for you.

When I open the preview, it opens in tablet size by default. I prefer desktop size, so I set it to that. I close the preview. I open the preview again. It's now in desktop size, great--but apparently the CSS stops working. Can anyone reproduce or is it just me?

@lsinger Interesting! I wasn't able to reproduce but it may be something about your particular site. Can you share the site with me? (we can do this via Slack.)

@sirbrillig
Copy link
Member Author

Rebased to remove conflicts. Sorry to anyone who had this checked out.

@lsinger
Copy link
Contributor

lsinger commented May 3, 2016

I think that was a bug having to do with the site ID not being available when the component loads. I've just fixed it in 9153d4e. Let me know if that solves the issue for you.

Yup, reloading Calypso does the trick now. 👍

Would it make sense to (while the preview is open) regularly poll the API whether anything about the site has changed?

Interesting! I wasn't able to reproduce but it may be something about your particular site. Can you share the site with me? (we can do this via Slack.)

Sent it to you in Slack. See also the following font differences.

Actual site:

live

Preview:

preview

@sirbrillig
Copy link
Member Author

Would it make sense to (while the preview is open) regularly poll the API whether anything about the site has changed?

Hm... Probably? OTOH polling is expensive, especially here because the preview is large. I'm open to discussion but I think it might be best to put that off as a feature for later (perhaps with a more efficient mechanism to query for a changed site).

@lsinger
Copy link
Contributor

lsinger commented May 4, 2016

it might be best to put that off as a feature for later

That's what I thought, just wanted to make sure I'd mentioned it. :)

/**
* External dependencies
*/
import assign from 'lodash/assign';
Copy link
Member

Choose a reason for hiding this comment

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

Any reason not to use Object.assign instead of lodash?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because, as I found out relatively recently, Object.assign is ES6 and (at least last time I checked) we don't support polyfills for prototype methods in Calypso. So if I use Object.assign() then it will only work in browsers that support that feature.

Copy link
Member

Choose a reason for hiding this comment

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

It isn't a prototype method :) Ref: #2360 (comment)

Copy link
Member Author

@sirbrillig sirbrillig May 5, 2016

Choose a reason for hiding this comment

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

Half true. We're not actually using babel/polyfill, we're using the babel/runtime with webpack, which only polyfills non-prototype things. So we get Map and Set and Object.assign, but not things on String.prototype like startsWith.

Ohhhhh... TIL. Thanks!

@ehg
Copy link
Member

ehg commented May 5, 2016

I think this is looking like a pretty solid start. Nice job. No doubt we'll find bugs/missing features when we use it in anger, but for me it makes sense to remove the 'Customize' hijack and merge this now.

@lsinger @mcsf what do you think?

// Refresh the preview when it is being shown (since this component is
// always present but not always visible, this is similar to loading the
// preview when mounting).
if ( this.props.showPreview && ! prevProps.showPreview ) {
Copy link
Member

@ehg ehg May 5, 2016

Choose a reason for hiding this comment

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

Nifty interim solution!

@lsinger
Copy link
Contributor

lsinger commented May 6, 2016

I think this is looking like a pretty solid start. Nice job. No doubt we'll find bugs/missing features when we use it in anger, but for me it makes sense to remove the 'Customize' hijack and merge this now.

The incorrect fonts still worry me--also could point to a deeper problem.

@ehg
Copy link
Member

ehg commented May 6, 2016

The incorrect fonts still worry me--also could point to a deeper problem.

Hmm, interestingly the webfonts work for me in Firefox, but not in Chrome (consistently — I saw a brief flash). Taking a deeper look.

@ehg
Copy link
Member

ehg commented May 6, 2016

The incorrect fonts still worry me--also could point to a deeper problem.

Updating https://github.com/typekit/webfontloader on my WPCOM sandbox to the current version fixes this for Google Fonts in Chrome. TypeKit fonts will only work on wordpress.com domains.

@ehg
Copy link
Member

ehg commented May 6, 2016

I just got a 'your stats are booming!' notification. We shouldn't be bumping stats for previews…

@sirbrillig
Copy link
Member Author

I just got a 'your stats are booming!' notification. We shouldn't be bumping stats for previews

Ah, yes. 😩 I had forgotten about this. It's an issue with the Previews endpoint. @mattwiebe might have some insight.

@ehg
Copy link
Member

ehg commented May 9, 2016

Seeing as the webfonts and stat bumping are issues independent of this PR, I think we should merge this, and track them elsewhere.

@sirbrillig
Copy link
Member Author

I'll rebase to remove the sidebar hack and mark as Ready for Review

@sirbrillig sirbrillig force-pushed the add/preview-layout-focus branch 2 times, most recently from 672cc9a to 777f003 Compare May 9, 2016 17:00
@sirbrillig
Copy link
Member Author

Rebased. Sidebar "customize" hook is still available in 672cc9a4c10be24be8f90fee773dbee222596177 if needed for testing.

@sirbrillig sirbrillig added [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. and removed [Status] In Progress labels May 9, 2016
@ehg ehg force-pushed the add/preview-layout-focus branch from 777f003 to 588d24e Compare May 11, 2016 14:04
@ehg
Copy link
Member

ehg commented May 12, 2016

LGTM. :shipit: and onwards to #5117 :)

@ehg ehg added [Status] Ready to Merge and removed [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. labels May 12, 2016
@sirbrillig sirbrillig merged commit 44db302 into master May 12, 2016
@sirbrillig sirbrillig deleted the add/preview-layout-focus branch May 12, 2016 16:10
loadPreview() {
if ( this.props.selectedSiteId && this.props.actions.fetchPreviewMarkup ) {
debug( 'loading preview with customizations', this.props.customizations );
this.props.actions.fetchPreviewMarkup( this.props.selectedSiteId, '', this.props.customizations );
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we want to be triggering a network request for preview whenever navigating My Sites? At least, this is what I'm observing currently (assuming component is always mounted in the background?)

Copy link
Member Author

Choose a reason for hiding this comment

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

Hm. That doesn't sound right. I think my intent was that the preview request only load when either:

  1. The my-sites area for a specific site first loads.
  2. The preview is made visible (in case there are changes).
  3. When customizations had been applied but have since been removed.

Copy link
Contributor

Choose a reason for hiding this comment

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

@sirbrillig Unfortunately that doesn't appear to be the case. Here's an example refreshing the settings page, showing the network request on page load:

request

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, no good. We may want to speed up the merge of parts of #5117 which disable the preview endpoint.

Copy link
Member

@ehg ehg May 20, 2016

Choose a reason for hiding this comment

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

  1. The my-sites area for a specific site first loads.
  2. The preview is made visible (in case there are changes).
  3. When customizations had been applied but have since been removed.

an example refreshing the settings page, showing the network request on page load…

Doesn't this conform to the expected behaviour? I believe we want to load the preview on the initial page load, and for every site switched. We could switch it to fetch on demand, but we'd lose the 'instant' factor, which the editor preview has.

Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't this conform to the expected behaviour? I believe we want to load the preview on the initial page load, and for every site switched. We could switch it to fetch on demand, but we'd lose the 'instant' factor, which the editor preview has.

Eh, that feels a bit heavy. The likelihood that my session using My Sites will lead to previewing customizations is much much lower than the likelihood I'd preview a post I'm editing.

Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure what the behavior is here, but we're also not doing background loading for mobile devices in the editor.

I'm not a fan of the editor background loading FWIW 😄 I wonder if there's a middle ground where we interpret "intent" (e.g. hover action).

Copy link
Member Author

Choose a reason for hiding this comment

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

I'd like to get @mtias input also because the background loading (once for each site, when it first loads) was originally his idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants