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

[Gutenberg] Add amp-fit-text support to text blocks #1151

Merged
merged 14 commits into from
May 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions amp.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ function amp_init() {
add_action( 'admin_init', 'AMP_Options_Manager::register_settings' );
add_action( 'wp_loaded', 'amp_editor_core_blocks' );
add_action( 'wp_loaded', 'amp_post_meta_box' );
add_action( 'wp_loaded', 'amp_editor_core_blocks' );
add_action( 'wp_loaded', 'amp_add_options_menu' );
add_action( 'parse_query', 'amp_correct_query_when_is_front_page' );

Expand Down
10 changes: 10 additions & 0 deletions assets/css/amp-default.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,13 @@
/** Force the image into a box of fixed dimensions and use object-fit to scale. **/
object-fit: contain;
}

.entry__content amp-fit-text blockquote,
amp-fit-text h1,
amp-fit-text h2,
amp-fit-text h3,
amp-fit-text h4,
amp-fit-text h5,
amp-fit-text h6 {
font-size: inherit;
}
4 changes: 4 additions & 0 deletions assets/css/amp-editor-blocks.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.is-amp-fit-text + .blocks-font-size > .components-font-size-picker__buttons,
.is-amp-fit-text + .blocks-font-size > .components-font-size-picker__custom-input {
display: none;
}
197 changes: 194 additions & 3 deletions assets/js/amp-editor-blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,19 @@ var ampEditorBlocks = ( function() { // eslint-disable-line no-unused-vars
'core/image',
'core/video',
'core/audio'
]
],
textBlocks: [
'core/paragraph',
'core/heading',
'core/code',
'core/quote',
'core/subhead'
],
ampSettingsLabel: __( 'AMP Settings' ),
fontSizes: {
small: 14,
larger: 48
}
}
};

Expand Down Expand Up @@ -178,6 +190,38 @@ var ampEditorBlocks = ( function() { // eslint-disable-line no-unused-vars
};
}

// Fit-text for text blocks.
if ( -1 !== component.data.textBlocks.indexOf( name ) ) {
if ( ! settings.attributes ) {
settings.attributes = {};
}
settings.attributes.ampFitText = {
type: 'boolean',
default: false
};
settings.attributes.minFont = {
type: 'number',
default: component.data.fontSizes.small,
source: 'attribute',
selector: 'amp-fit-text',
attribute: 'min-font-size'
};
settings.attributes.maxFont = {
type: 'number',
default: component.data.fontSizes.larger,
source: 'attribute',
selector: 'amp-fit-text',
attribute: 'max-font-size'
};
settings.attributes.height = {
type: 'number',
default: 50,
source: 'attribute',
selector: 'amp-fit-text',
attribute: 'height'
};
}

// Layout settings for embeds and media blocks.
if ( 0 === name.indexOf( 'core-embed' ) || -1 !== component.data.mediaBlocks.indexOf( name ) ) {
if ( ! settings.attributes ) {
Expand Down Expand Up @@ -222,6 +266,8 @@ var ampEditorBlocks = ( function() { // eslint-disable-line no-unused-vars
}
} else if ( -1 !== component.data.mediaBlocks.indexOf( name ) || 0 === name.indexOf( 'core-embed/' ) ) {
inspectorControls = component.setUpInspectorControls( props );
} else if ( -1 !== component.data.textBlocks.indexOf( name ) ) {
inspectorControls = component.setUpTextBlocksInspectorControls( props );
}

// Return just inspector controls in case of 'nodisplay'.
Expand Down Expand Up @@ -314,6 +360,135 @@ var ampEditorBlocks = ( function() { // eslint-disable-line no-unused-vars
);
};

/**
* Setup inspector controls for text blocks.
*
* @todo Consider wrapping the render function to delete the original font size in text settings when ampFitText.
*
* @param {Object} props Props.
* @return {Object|Element|*|{$$typeof, type, key, ref, props, _owner}} Inspector Controls.
*/
component.setUpTextBlocksInspectorControls = function setUpInspectorControls( props ) {
var inspectorPanelBodyArgs,
ampFitText = props.attributes.ampFitText,
minFont = props.attributes.minFont,
maxFont = props.attributes.maxFont,
height = props.attributes.height,
isSelected = props.isSelected,
el = wp.element.createElement,
InspectorControls = wp.editor.InspectorControls,
TextControl = wp.components.TextControl,
FontSizePicker = wp.components.FontSizePicker,
ToggleControl = wp.components.ToggleControl,
PanelBody = wp.components.PanelBody,
label = __( 'Use AMP Fit Text' ),
FONT_SIZES = [
{
name: 'small',
shortName: __( 'S' ),
size: 14
},
{
name: 'regular',
shortName: __( 'M' ),
size: 16
},
{
name: 'large',
shortName: __( 'L' ),
size: 36
},
{
name: 'larger',
shortName: __( 'XL' ),
size: 48
}
];

if ( ! isSelected ) {
return null;
}

inspectorPanelBodyArgs = [
PanelBody,
{ title: component.data.ampSettingsLabel, className: ampFitText ? 'is-amp-fit-text' : '' },
el( ToggleControl, {
label: label,
checked: ampFitText,
onChange: function() {
props.setAttributes( { ampFitText: ! ampFitText } );
}
} )
];

if ( ampFitText ) {
inspectorPanelBodyArgs.push.apply( inspectorPanelBodyArgs, [
el( TextControl, {
label: __( 'Height' ),
value: height,
type: 'number',
min: 1,
onChange: function( nextHeight ) {
props.setAttributes( { height: nextHeight } );
}
} ),
maxFont > height && el(
wp.components.Notice,
{
status: 'error',
isDismissible: false
},
__( 'The height must be greater than the max font size.' )
),
el( PanelBody, { title: __( 'Minimum font size' ) },
el( FontSizePicker, {
fallbackFontSize: 14,
value: minFont,
fontSizes: FONT_SIZES,
onChange: function( nextMinFont ) {
if ( ! nextMinFont ) {
nextMinFont = component.data.fontSizes.small; // @todo Supplying fallbackFontSize should be done automatically by the component?
}
if ( nextMinFont <= maxFont ) {
props.setAttributes( { minFont: nextMinFont } );
}
}
} )
),
minFont > maxFont && el(
wp.components.Notice,
{
status: 'error',
isDismissible: false
},
__( 'The min font size must less than the max font size.' )
),
el( PanelBody, { title: __( 'Maximum font size' ) },
el( FontSizePicker, {
value: maxFont,
fallbackFontSize: 48,
fontSizes: FONT_SIZES,
onChange: function( nextMaxFont ) {
if ( ! nextMaxFont ) {
nextMaxFont = component.data.fontSizes.larger; // @todo Supplying fallbackFontSize should be done automatically by the component?
}
props.setAttributes( {
maxFont: nextMaxFont,
height: Math.max( nextMaxFont, height )
} );
}
} )
)
] );
}

return (
el( InspectorControls, { key: 'inspector' },
el.apply( null, inspectorPanelBodyArgs )
)
);
};

/**
* Set up inspector controls for shortcode block.
* Adds ampCarousel attribute in case of gallery shortcode.
Expand All @@ -325,7 +500,7 @@ var ampEditorBlocks = ( function() { // eslint-disable-line no-unused-vars
var ampCarousel = props.attributes.ampCarousel,
isSelected = props.isSelected,
el = wp.element.createElement,
InspectorControls = wp.blocks.InspectorControls,
InspectorControls = wp.editor.InspectorControls,
ToggleControl = wp.components.ToggleControl,
PanelBody = wp.components.PanelBody,
toggleControl;
Expand Down Expand Up @@ -359,7 +534,12 @@ var ampEditorBlocks = ( function() { // eslint-disable-line no-unused-vars
* @return {*} Output element.
*/
component.filterBlocksSave = function filterBlocksSave( element, blockType, attributes ) {
var text;
var text,
fitTextProps = {
layout: 'fixed-height',
children: element
};

if ( 'core/shortcode' === blockType.name && component.isGalleryShortcode( attributes ) ) {
if ( attributes.ampCarousel ) {
// If the text contains amp-carousel, lets remove it.
Expand Down Expand Up @@ -390,6 +570,17 @@ var ampEditorBlocks = ( function() { // eslint-disable-line no-unused-vars
{},
text
);
} else if ( -1 !== component.data.textBlocks.indexOf( blockType.name ) && attributes.ampFitText ) {
if ( attributes.minFont ) {
fitTextProps[ 'min-font-size' ] = attributes.minFont;
}
if ( attributes.maxFont ) {
fitTextProps[ 'max-font-size' ] = attributes.maxFont;
}
if ( attributes.height ) {
fitTextProps.height = attributes.height;
}
return wp.element.createElement( 'amp-fit-text', fitTextProps );
}
return element;
};
Expand Down
76 changes: 64 additions & 12 deletions includes/admin/class-amp-editor-blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,39 @@
*/
class AMP_Editor_Blocks {

/**
* List of AMP scripts that need to be printed when AMP components are used in non-AMP document context ("dirty AMP").
*
* @var array
*/
public $content_required_amp_scripts = array();

/**
* AMP components that have blocks.
*
* @var array
*/
public $amp_blocks = array(
'amp-mathml',
'amp-o2-player',
'amp-ooyala-player',
'amp-reach-player',
'amp-springboard-player',
'amp-jwplayer',
'amp-brid-player',
'amp-ima-video',
'amp-fit-text',
);

/**
* Init.
*/
public function init() {
if ( function_exists( 'gutenberg_init' ) ) {
add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ) );
add_filter( 'wp_kses_allowed_html', array( $this, 'whitelist_block_atts_in_wp_kses_allowed_html' ), 10, 2 );
add_filter( 'the_content', array( $this, 'tally_content_requiring_amp_scripts' ) );
add_action( 'wp_print_footer_scripts', array( $this, 'print_dirty_amp_scripts' ) );
}
}

Expand All @@ -40,18 +66,7 @@ public function whitelist_block_atts_in_wp_kses_allowed_html( $tags, $context )
$tag['data-amp-noloading'] = true;
}

$amp_blocks = array(
'amp-mathml',
'amp-o2-player',
'amp-ooyala-player',
'amp-reach-player',
'amp-springboard-player',
'amp-jwplayer',
'amp-brid-player',
'amp-ima-video',
);

foreach ( $amp_blocks as $amp_block ) {
foreach ( $this->amp_blocks as $amp_block ) {
if ( ! isset( $tags[ $amp_block ] ) ) {
$tags[ $amp_block ] = array();
}
Expand All @@ -62,6 +77,7 @@ public function whitelist_block_atts_in_wp_kses_allowed_html( $tags, $context )
'layout',
'width',
'height',
'class',
),
true
),
Expand Down Expand Up @@ -89,6 +105,14 @@ public function whitelist_block_atts_in_wp_kses_allowed_html( $tags, $context )
*/
public function enqueue_block_editor_assets() {

// Styles.
wp_enqueue_style(
'amp-editor-blocks-style',
amp_get_asset_url( 'css/amp-editor-blocks.css' ),
array(),
AMP__VERSION
);

// Scripts.
wp_enqueue_script(
'amp-editor-blocks-build',
Expand All @@ -107,4 +131,32 @@ public function enqueue_block_editor_assets() {

wp_add_inline_script( 'amp-editor-blocks', sprintf( 'ampEditorBlocks.boot();' ) );
}

/**
* Tally the AMP component scripts that are needed in a dirty AMP document.
*
* @param string $content Content.
* @return string Content (unmodified).
*/
public function tally_content_requiring_amp_scripts( $content ) {
if ( ! is_amp_endpoint() ) {
$pattern = sprintf( '/<(%s)\b.*?>/s', join( '|', $this->amp_blocks ) );
if ( preg_match_all( $pattern, $content, $matches ) ) {
$this->content_required_amp_scripts = array_merge(
$this->content_required_amp_scripts,
$matches[1]
);
}
}
return $content;
}

/**
* Print AMP scripts required for AMP components used in a non-AMP document (dirty AMP).
*/
public function print_dirty_amp_scripts() {
if ( ! is_amp_endpoint() && ! empty( $this->content_required_amp_scripts ) ) {
wp_scripts()->do_items( $this->content_required_amp_scripts );
}
}
}