Skip to content

Commit

Permalink
Set aspect ratio preserving CSS on previews with fixed size iframes (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
notnownikki authored Sep 7, 2018
1 parent 0b0342c commit 8d46362
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 54 deletions.
125 changes: 105 additions & 20 deletions packages/block-library/src/embed/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/
import { parse } from 'url';
import { includes, kebabCase, toLower } from 'lodash';
import classnames from 'classnames';
import classnames from 'classnames/dedupe';

/**
* WordPress dependencies
Expand Down Expand Up @@ -43,6 +43,7 @@ export function getEmbedEdit( title, icon ) {
this.setUrl = this.setUrl.bind( this );
this.maybeSwitchBlock = this.maybeSwitchBlock.bind( this );
this.setAttributesFromPreview = this.setAttributesFromPreview.bind( this );
this.maybeSetAspectRatioClassName = this.maybeSetAspectRatioClassName.bind( this );

this.state = {
editingURL: false,
Expand Down Expand Up @@ -136,6 +137,58 @@ export function getEmbedEdit( title, icon ) {
return false;
}

/**
* Sets the appropriate CSS class to enforce an aspect ratio when the embed is resized
* if the HTML has an iframe with width and height set.
*
* @param {string} html The preview HTML that possibly contains an iframe with width and height set.
*/
maybeSetAspectRatioClassName( html ) {
const previewDom = document.createElement( 'div' );
previewDom.innerHTML = html;
const iframe = previewDom.querySelector( 'iframe' );

if ( ! iframe ) {
return;
}

if ( iframe.height && iframe.width ) {
const aspectRatio = ( iframe.width / iframe.height ).toFixed( 2 );
let aspectRatioClassName;

switch ( aspectRatio ) {
// Common video resolutions.
case '2.33':
aspectRatioClassName = 'wp-embed-aspect-21-9';
break;
case '2.00':
aspectRatioClassName = 'wp-embed-aspect-18-9';
break;
case '1.78':
aspectRatioClassName = 'wp-embed-aspect-16-9';
break;
case '1.33':
aspectRatioClassName = 'wp-embed-aspect-4-3';
break;
// Vertical video and instagram square video support.
case '1.00':
aspectRatioClassName = 'wp-embed-aspect-1-1';
break;
case '0.56':
aspectRatioClassName = 'wp-embed-aspect-9-16';
break;
case '0.50':
aspectRatioClassName = 'wp-embed-aspect-1-2';
break;
}

if ( aspectRatioClassName ) {
const className = classnames( this.props.attributes.className, 'wp-has-aspect-ratio', aspectRatioClassName );
this.props.setAttributes( { className } );
}
}
}

/***
* Sets block attributes based on the preview data.
*/
Expand All @@ -156,6 +209,8 @@ export function getEmbedEdit( title, icon ) {
if ( html || 'photo' === type ) {
setAttributes( { type, providerNameSlug } );
}

this.maybeSetAspectRatioClassName( html );
}

switchBackToURLInput() {
Expand Down Expand Up @@ -218,6 +273,7 @@ export function getEmbedEdit( title, icon ) {
const cannotPreview = includes( HOSTS_NO_PREVIEWS, parsedUrl.host.replace( /^www\./, '' ) );
// translators: %s: host providing embed content e.g: www.youtube.com
const iframeTitle = sprintf( __( 'Embedded content from %s' ), parsedUrl.host );
const sandboxClassnames = classnames( type, className );
const embedWrapper = 'wp-embed' === type ? (
<div
className="wp-block-embed__wrapper"
Expand All @@ -228,7 +284,7 @@ export function getEmbedEdit( title, icon ) {
<SandBox
html={ html }
title={ iframeTitle }
type={ type }
type={ sandboxClassnames }
/>
</div>
);
Expand Down Expand Up @@ -257,6 +313,24 @@ export function getEmbedEdit( title, icon ) {
};
}

const embedAttributes = {
url: {
type: 'string',
},
caption: {
type: 'array',
source: 'children',
selector: 'figcaption',
default: [],
},
type: {
type: 'string',
},
providerNameSlug: {
type: 'string',
},
};

function getEmbedBlockSettings( { title, description, icon, category = 'embed', transforms, keywords = [] } ) {
// translators: %s: Name of service (e.g. VideoPress, YouTube)
const blockDescription = description || sprintf( __( 'Add a block that displays content pulled from other sites, like Twitter, Instagram or YouTube.' ), title );
Expand All @@ -266,23 +340,7 @@ function getEmbedBlockSettings( { title, description, icon, category = 'embed',
icon,
category,
keywords,
attributes: {
url: {
type: 'string',
},
caption: {
type: 'array',
source: 'children',
selector: 'figcaption',
default: [],
},
type: {
type: 'string',
},
providerNameSlug: {
type: 'string',
},
},
attributes: embedAttributes,

supports: {
align: true,
Expand Down Expand Up @@ -320,11 +378,38 @@ function getEmbedBlockSettings( { title, description, icon, category = 'embed',

return (
<figure className={ embedClassName }>
{ `\n${ url }\n` /* URL needs to be on its own line. */ }
<div className="wp-block-embed__wrapper">
{ `\n${ url }\n` /* URL needs to be on its own line. */ }
</div>
{ ! RichText.isEmpty( caption ) && <RichText.Content tagName="figcaption" value={ caption } /> }
</figure>
);
},

deprecated: [
{
attributes: embedAttributes,
save( { attributes } ) {
const { url, caption, type, providerNameSlug } = attributes;

if ( ! url ) {
return null;
}

const embedClassName = classnames( 'wp-block-embed', {
[ `is-type-${ type }` ]: type,
[ `is-provider-${ providerNameSlug }` ]: providerNameSlug,
} );

return (
<figure className={ embedClassName }>
{ `\n${ url }\n` /* URL needs to be on its own line. */ }
{ ! RichText.isEmpty( caption ) && <RichText.Content tagName="figcaption" value={ caption } /> }
</figure>
);
},
},
],
};
}

Expand Down
55 changes: 55 additions & 0 deletions packages/block-library/src/embed/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,59 @@
figcaption {
@include caption-style();
}

// Add responsiveness to common aspect ratios.
&.wp-embed-aspect-21-9 .wp-block-embed__wrapper,
&.wp-embed-aspect-18-9 .wp-block-embed__wrapper,
&.wp-embed-aspect-16-9 .wp-block-embed__wrapper,
&.wp-embed-aspect-4-3 .wp-block-embed__wrapper,
&.wp-embed-aspect-1-1 .wp-block-embed__wrapper,
&.wp-embed-aspect-9-16 .wp-block-embed__wrapper,
&.wp-embed-aspect-1-2 .wp-block-embed__wrapper {
position: relative;

&::before {
content: "";
display: block;
padding-top: 50%; // Default to 2:1 aspect ratio.
}

iframe {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
}
}

&.wp-embed-aspect-21-9 .wp-block-embed__wrapper::before {
padding-top: 42.85%; // 9 / 21 * 100
}

&.wp-embed-aspect-18-9 .wp-block-embed__wrapper::before {
padding-top: 50%; // 9 / 18 * 100
}

&.wp-embed-aspect-16-9 .wp-block-embed__wrapper::before {
padding-top: 56.25%; // 9 / 16 * 100
}

&.wp-embed-aspect-4-3 .wp-block-embed__wrapper::before {
padding-top: 75%; // 3 / 4 * 100
}

&.wp-embed-aspect-1-1 .wp-block-embed__wrapper::before {
padding-top: 100%; // 1 / 1 * 100
}

&.wp-embed-aspect-9-6 .wp-block-embed__wrapper::before {
padding-top: 66.66%; // 6 / 9 * 100
}

&.wp-embed-aspect-1-2 .wp-block-embed__wrapper::before {
padding-top: 200%; // 2 / 1 * 100
}
}
40 changes: 11 additions & 29 deletions packages/components/src/sandbox/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,31 +79,18 @@ class Sandbox extends Component {
const observeAndResizeJS = `
( function() {
var observer;
var aspectRatio = false;
var iframe = false;
if ( ! window.MutationObserver || ! document.body || ! window.parent ) {
return;
}
function sendResize() {
var clientBoundingRect = document.body.getBoundingClientRect();
var height = aspectRatio ? Math.ceil( clientBoundingRect.width / aspectRatio ) : clientBoundingRect.height;
if ( iframe && aspectRatio ) {
// This is embedded content delivered in an iframe with a fixed aspect ratio,
// so set the height correctly and stop processing. The DOM mutation will trigger
// another event and the resize message will get posted.
if ( iframe.height != height ) {
iframe.height = height;
return;
}
}
window.parent.postMessage( {
action: 'resize',
width: clientBoundingRect.width,
height: height,
height: clientBoundingRect.height,
}, '*' );
}
Expand Down Expand Up @@ -139,20 +126,6 @@ class Sandbox extends Component {
document.body.style.width = '100%';
document.body.setAttribute( 'data-resizable-iframe-connected', '' );
// Make embedded content in an iframe with a fixed size responsive,
// keeping the correct aspect ratio.
var potentialIframe = document.body.children[0];
if ( 'DIV' === potentialIframe.tagName || 'SPAN' === potentialIframe.tagName ) {
potentialIframe = potentialIframe.children[0];
}
if ( potentialIframe && 'IFRAME' === potentialIframe.tagName ) {
if ( potentialIframe.width ) {
iframe = potentialIframe;
aspectRatio = potentialIframe.width / potentialIframe.height;
potentialIframe.width = '100%';
}
}
sendResize();
// Resize events can change the width of elements with 100% width, but we don't
Expand All @@ -164,9 +137,18 @@ class Sandbox extends Component {
body {
margin: 0;
}
html,
body,
body > div,
body > div > iframe {
width: 100%;
}
html.wp-has-aspect-ratio,
body.wp-has-aspect-ratio,
body.wp-has-aspect-ratio > div,
body.wp-has-aspect-ratio > div > iframe {
height: 100%;
}
body > div > * {
margin-top: 0 !important; /* has to have !important to override inline styles */
margin-bottom: 0 !important;
Expand All @@ -176,7 +158,7 @@ class Sandbox extends Component {
// put the html snippet into a html document, and then write it to the iframe's document
// we can use this in the future to inject custom styles or scripts
const htmlDoc = (
<html lang={ document.documentElement.lang }>
<html lang={ document.documentElement.lang } className={ this.props.type }>
<head>
<title>{ this.props.title }</title>
<style dangerouslySetInnerHTML={ { __html: style } } />
Expand Down
4 changes: 3 additions & 1 deletion test/integration/full-content/fixtures/core__embed.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<!-- wp:core/embed {"url":"https://example.com/"} -->
<figure class="wp-block-embed">
https://example.com/
<div class="wp-block-embed__wrapper">
https://example.com/
</div>
<figcaption>Embedded content from an example URL</figcaption>
</figure>
<!-- /wp:core/embed -->
2 changes: 1 addition & 1 deletion test/integration/full-content/fixtures/core__embed.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
]
},
"innerBlocks": [],
"originalContent": "<figure class=\"wp-block-embed\">\n https://example.com/\n <figcaption>Embedded content from an example URL</figcaption>\n</figure>"
"originalContent": "<figure class=\"wp-block-embed\">\n <div class=\"wp-block-embed__wrapper\">\n https://example.com/\n </div>\n <figcaption>Embedded content from an example URL</figcaption>\n</figure>"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"url": "https://example.com/"
},
"innerBlocks": [],
"innerHTML": "\n<figure class=\"wp-block-embed\">\n https://example.com/\n <figcaption>Embedded content from an example URL</figcaption>\n</figure>\n"
"innerHTML": "\n<figure class=\"wp-block-embed\">\n <div class=\"wp-block-embed__wrapper\">\n https://example.com/\n </div>\n <figcaption>Embedded content from an example URL</figcaption>\n</figure>\n"
},
{
"attrs": {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!-- wp:embed {"url":"https://example.com/"} -->
<figure class="wp-block-embed">
<figure class="wp-block-embed"><div class="wp-block-embed__wrapper">
https://example.com/
<figcaption>Embedded content from an example URL</figcaption></figure>
</div><figcaption>Embedded content from an example URL</figcaption></figure>
<!-- /wp:embed -->

0 comments on commit 8d46362

Please sign in to comment.