Skip to content

Commit

Permalink
Enforce max sizing for layout=responsive
Browse files Browse the repository at this point in the history
We want elements to not grow beyond their width and shrink to
fill the screen on viewports smaller than their width.

We do this by adding a `sizes` attribute (when not already set) to
enforce this behavior.

See #101
  • Loading branch information
mjangda committed Jan 15, 2016
1 parent 0feae4c commit 2b0ca8f
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 38 deletions.
22 changes: 8 additions & 14 deletions class-amp-content.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
class AMP_Content {
private $original_content;
private $scripts;
private $args;

public function __construct( $content ) {
public function __construct( $content, $args = array() ) {
$this->original_content = $content;
$this->scripts = array();
$this->args = $args;
}

public function transform() {
Expand All @@ -39,23 +41,15 @@ public function transform() {

$dom = AMP_DOM_Utils::get_dom_from_content( $content );

$this->sanitize( new AMP_Blacklist_Sanitizer( $dom ) );
$this->sanitize( new AMP_Blacklist_Sanitizer( $dom, $this->args ) );

$this->sanitize( new AMP_Img_Sanitizer( $dom ), array(
'layout' => 'responsive',
) );
$this->sanitize( new AMP_Img_Sanitizer( $dom, $this->args ) );

$this->sanitize( new AMP_Video_Sanitizer( $dom ), array(
'layout' => 'responsive',
) );
$this->sanitize( new AMP_Video_Sanitizer( $dom, $this->args ) );

$this->sanitize( new AMP_Iframe_Sanitizer( $dom ), array(
'layout' => 'responsive',
) );
$this->sanitize( new AMP_Iframe_Sanitizer( $dom, $this->args ) );

$this->sanitize( new AMP_Audio_Sanitizer( $dom ), array(
'layout' => 'responsive',
) );
$this->sanitize( new AMP_Audio_Sanitizer( $dom, $this->args ) );

$content = AMP_DOM_Utils::get_content_from_dom( $dom );

Expand Down
10 changes: 9 additions & 1 deletion class-amp-post.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ class AMP_Post {
private $content;
private $metadata;
private $scripts;
private $content_max_width;

function __construct( $post_id ) {
$this->ID = $post_id;
$this->post = get_post( $post_id );

$this->author = apply_filters( 'amp_post_author', get_userdata( $this->post->post_author ) );

$amp_content = new AMP_Content( $this->post->post_content );
$this->content_max_width = apply_filters( 'amp_content_max_width', isset( $GLOBALS['content_width'] ) ? absint( $GLOBALS['content_width'] ) : 600 );
$amp_content = new AMP_Content( $this->post->post_content, array(
'content_max_width' => $this->content_max_width,
) );
$this->content = apply_filters( 'amp_post_content', $amp_content->transform(), $this->post );
$this->scripts = apply_filters( 'amp_post_scripts', $amp_content->get_scripts(), $this->post );
$this->metadata = apply_filters( 'amp_post_metadata', $this->build_metadata(), $this->post );
Expand Down Expand Up @@ -46,6 +50,10 @@ function get_content() {
return $this->content;
}

function get_content_max_width() {
return $this->content_max_width();
}

private function build_metadata() {
$metadata = array(
'@context' => 'http://schema.org',
Expand Down
38 changes: 37 additions & 1 deletion includes/sanitizers/class-amp-base-sanitizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,51 @@

abstract class AMP_Base_Sanitizer {
protected $dom;
protected $args;
protected $did_convert_elements = false;

public function __construct( $dom ) {
public function __construct( $dom, $args = array() ) {
$this->dom = $dom;
$this->args = $args;
}

abstract public function sanitize( $amp_attributes = array() );

public function get_scripts() {
return array();
}

/**
* This is our workaround to enforce max sizing with layout=responsive.
*
* We want elements to not grow beyond their width and shrink to fill the screen on viewports smaller than their width.
*
* See https://github.com/ampproject/amphtml/issues/1280#issuecomment-171533526
* See https://github.com/Automattic/amp-wp/issues/101
*/
public function enforce_sizes_attribute( $attributes ) {
if ( isset( $attributes['sizes'] ) ) {
return $attributes;
}

if ( ! isset( $attributes['width'], $attributes['height'] ) ) {
return $attributes;
}

$max_width = $attributes['width'];
if ( isset( $this->args['content_max_width'] ) && $max_width >= $this->args['content_max_width'] ) {
$max_width = $this->args['content_max_width'];
}

$attributes['sizes'] = sprintf( '(min-width: %1$dpx) %1$dpx, 100vw', absint( $max_width ) );

$class = 'wp-amp-enforced-sizes';
if ( isset( $attributes['class'] ) ) {
$attributes['class'] += ' ' . $class;
} else {
$attributes['class'] = $class;
}

return $attributes;
}
}
1 change: 1 addition & 0 deletions includes/sanitizers/class-amp-iframe-sanitizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public function sanitize( $amp_attributes = array() ) {
$this->did_convert_elements = true;

$new_attributes = $this->filter_attributes( $old_attributes );
$new_attributes = $this->enforce_sizes_attribute( $new_attributes );
$new_attributes = array_merge( $new_attributes, $amp_attributes );

$new_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-iframe', $new_attributes );
Expand Down
30 changes: 9 additions & 21 deletions includes/sanitizers/class-amp-img-sanitizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,17 @@ public function sanitize( $amp_attributes = array() ) {
}

$new_attributes = $this->filter_attributes( $old_attributes );
$new_attributes = array_merge( $new_attributes, $amp_attributes );

// Workaround for https://github.com/Automattic/amp-wp/issues/20
// responsive + float don't mix
if ( isset( $new_attributes['class'] )
&& $this->is_aligned_image( $new_attributes['class'] ) ) {
unset( $new_attributes['layout'] );
if ( ! isset( $new_attributes['width'] ) || ! isset( $new_attributes['height'] ) ) {
$dimensions = AMP_Image_Dimension_Extractor::extract( $new_attributes['src'] );
if ( $dimensions ) {
$new_attributes['width'] = $dimensions[0];
$new_attributes['height'] = $dimensions[1];
}
}

$new_attributes = $this->enforce_sizes_attribute( $new_attributes );
$new_attributes = array_merge( $new_attributes, $amp_attributes );

if ( $this->is_gif_url( $new_attributes['src'] ) ) {
$this->did_convert_elements = true;
$new_tag = 'amp-anim';
Expand Down Expand Up @@ -79,23 +81,9 @@ private function filter_attributes( $attributes ) {
}
}

if ( ! isset( $out['width'] ) || ! isset( $out['height'] ) ) {
$dimensions = AMP_Image_Dimension_Extractor::extract( $out['src'] );
if ( $dimensions ) {
$out['width'] = $dimensions[0];
$out['height'] = $dimensions[1];
}
}

return $out;
}

private function is_aligned_image( $class ) {
return false !== strpos( $class, 'alignleft' )
|| false !== strpos( $class, 'alignright' )
|| false !== strpos( $class, 'aligncenter' );
}

private function is_gif_url( $url ) {
$ext = self::$anim_extension;
$path = parse_url( $url, PHP_URL_PATH );
Expand Down
1 change: 1 addition & 0 deletions includes/sanitizers/class-amp-video-sanitizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public function sanitize( $amp_attributes = array() ) {
$old_attributes = AMP_DOM_Utils::get_node_attributes_as_assoc_array( $node );

$new_attributes = $this->filter_attributes( $old_attributes );
$new_attributes = $this->enforce_sizes_attribute( $new_attributes );
$new_attributes = array_merge( $new_attributes, $amp_attributes );

$new_node = AMP_DOM_Utils::create_node( $this->dom, 'amp-video', $new_attributes );
Expand Down
9 changes: 8 additions & 1 deletion templates/amp-index.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
$post_id = $amp_post->get_ID();
$post = $amp_post->get_post();
$post_author = $amp_post->get_author();
$content_max_width = $amp_post->get_content_max_width();
?>
<!doctype html>
<html amp>
Expand All @@ -23,9 +24,15 @@
.wp-caption.alignleft { margin-right: 1em; }
.wp-caption.alignright { margin-left: 1em; }

.wp-amp-enforced-sizes {
/** Our sizes fallback is 100vw, and we have a padding on the container; the max-width here prevents the element from overflowing. **/
max-width: 100%;
}

/* Generic WP.com reader style */
.content, .title-bar div {
max-width: 600px;
/** TODO: need to pass max_width in **/
max-width: <?php echo sprintf( '%dpx', isset( $content_max_width ) ? absint( $content_max_width ) : 600 ) ?>;
margin: 0 auto;
}

Expand Down

0 comments on commit 2b0ca8f

Please sign in to comment.