Skip to content

Commit

Permalink
[Mobile]: Add Image Caption Styling (#14883)
Browse files Browse the repository at this point in the history
* Add ability to style image caption

Adds ability to style image caption with bold, italic, links, and strikethrough (wordpress-mobile/gutenberg-mobile#574).
Adds ability for image captions to wrap to multiple lines instead of getting
cut off (wordpress-mobile/gutenberg-mobile#590).

* Address style errors from linter

* Hide image toolbar controls if caption selected

* Update state in componentDidMount

The previous approach of setting the child component's `isSelected` prop
at the time the child was rendered based on
`this.props.isSelected && this.state.isCaptionSelected` did not work when:

  (a) the child was selected (so its `isSelected` prop was true);
  (b) the child component had no text; and
  (c) the parent's `isSelected` prop was changed to false
      (i.e., another block was selected).

Because the child component is not rendered when both the parent's `isSelected`
prop is false and the caption does not contain any text, the child
component's `onBlur` prop function (the `onCaptionBlur function) would not
be called and update the `isCaptionSelected` state to be false.

This bug shows when a user selects an empty caption, then selects a different
block (thereby hiding the caption since it is empty), and then re-selects the
image with the empty caption. In that scenario, upon re-selecting the image
with the empty caption, the empty caption would appear and immediately be
selected instead of just appearing. This bug would not appear if there
was any text in the caption, because then the caption would always
render and its `onBlur` prop function would be called.

* Add comment explaining isSelected guard

* Update image caption tagname from p to figcaption

This change brings mobile's handling of image captinos in line
with the web. It also addresses a crash that was occurring when
the enter key was tapped to enter a new line in an image caption.

* Remove `onBlurCaption` function

On iOS the display of the link UI modal was causing the `onBlurCaption`
function to be called, which would update the image caption's `isSelected`
prop to false. That would, in turn, immediately remove the
just-displayed modal. Restructuring the logic to not like this to not
use the image caption's `onBlur` function avoids that issue.

* Remove tagName from caption RichText component

Explicitly setting the tagName to figcaption caused an
invalid block to be saved if a caption ended with an empty line.
  • Loading branch information
mchowning authored and etoledom committed Apr 27, 2019
1 parent 87d7fe4 commit d9390f3
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 24 deletions.
23 changes: 15 additions & 8 deletions packages/block-editor/src/components/rich-text/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export class RichText extends Component {
this.onSelectionChange = this.onSelectionChange.bind( this );
this.valueToFormat = this.valueToFormat.bind( this );
this.willTrimSpaces = this.willTrimSpaces.bind( this );
this.getHtmlToRender = this.getHtmlToRender.bind( this );
this.state = {
start: 0,
end: 0,
Expand Down Expand Up @@ -643,6 +644,19 @@ export class RichText extends Component {
return false;
}

getHtmlToRender( record, tagName ) {
// Save back to HTML from React tree
const value = this.valueToFormat( record );

if ( value === undefined || value === '' ) {
this.lastEventCount = undefined; // force a refresh on the native side
return '';
} else if ( tagName ) {
return `<${ tagName }>${ value }</${ tagName }>`;
}
return value;
}

render() {
const {
tagName,
Expand All @@ -653,14 +667,7 @@ export class RichText extends Component {
} = this.props;

const record = this.getRecord();
// Save back to HTML from React tree
const value = this.valueToFormat( record );
let html = `<${ tagName }>${ value }</${ tagName }>`;
// We need to check if the value is undefined or empty, and then assign it properly otherwise the placeholder is not visible
if ( value === undefined || value === '' ) {
html = '';
this.lastEventCount = undefined; // force a refresh on the native side
}
const html = this.getHtmlToRender( record, tagName );

let minHeight = styles[ 'block-editor-rich-text' ].minHeight;
if ( style && style.minHeight ) {
Expand Down
56 changes: 44 additions & 12 deletions packages/block-library/src/image/edit.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* External dependencies
*/
import React from 'react';
import { View, ImageBackground, TextInput, Text, TouchableWithoutFeedback } from 'react-native';
import { View, ImageBackground, Text, TouchableWithoutFeedback } from 'react-native';
import {
subscribeMediaUpload,
requestMediaPickFromMediaLibrary,
Expand Down Expand Up @@ -63,6 +63,7 @@ class ImageEdit extends React.Component {
progress: 0,
isUploadInProgress: false,
isUploadFailed: false,
isCaptionSelected: false,
};

this.mediaUpload = this.mediaUpload.bind( this );
Expand All @@ -74,6 +75,7 @@ class ImageEdit extends React.Component {
this.onSetLinkDestination = this.onSetLinkDestination.bind( this );
this.onImagePressed = this.onImagePressed.bind( this );
this.onClearSettings = this.onClearSettings.bind( this );
this.onFocusCaption = this.onFocusCaption.bind( this );
}

componentDidMount() {
Expand Down Expand Up @@ -101,6 +103,14 @@ class ImageEdit extends React.Component {
this.removeMediaUploadListener();
}

componentWillReceiveProps( nextProps ) {
// Avoid a UI flicker in the toolbar by insuring that isCaptionSelected
// is updated immediately any time the isSelected prop becomes false
this.setState( ( state ) => ( {
isCaptionSelected: nextProps.isSelected && state.isCaptionSelected,
} ) );
}

onImagePressed() {
const { attributes } = this.props;

Expand All @@ -109,6 +119,11 @@ class ImageEdit extends React.Component {
} else if ( attributes.id && ! isURL( attributes.url ) ) {
requestImageFailedRetryDialog( attributes.id );
}

this._caption.blur();
this.setState( {
isCaptionSelected: false,
} );
}

mediaUpload( payload ) {
Expand Down Expand Up @@ -210,6 +225,17 @@ class ImageEdit extends React.Component {
];
}

onFocusCaption() {
if ( this.props.onFocus ) {
this.props.onFocus();
}
if ( ! this.state.isCaptionSelected ) {
this.setState( {
isCaptionSelected: true,
} );
}
}

render() {
const { attributes, isSelected, setAttributes } = this.props;
const { url, caption, height, width, alt, href } = attributes;
Expand Down Expand Up @@ -344,9 +370,11 @@ class ImageEdit extends React.Component {
>
<View style={ { flex: 1 } }>
{ showSpinner && <Spinner progress={ progress } /> }
<BlockControls>
{ toolbarEditButton }
</BlockControls>
{ ( ! this.state.isCaptionSelected ) &&
<BlockControls>
{ toolbarEditButton }
</BlockControls>
}
<InspectorControls>
<ToolbarButton
title={ __( 'Image Settings' ) }
Expand Down Expand Up @@ -398,8 +426,7 @@ class ImageEdit extends React.Component {
} }
</ImageSize>
{ ( ! RichText.isEmpty( caption ) > 0 || isSelected ) && (
<View
style={ { padding: 12, flex: 1 } }
<View style={ { padding: 12, flex: 1 } }
accessible={ true }
accessibilityLabel={
isEmpty( caption ) ?
Expand All @@ -413,13 +440,18 @@ class ImageEdit extends React.Component {
}
accessibilityRole={ 'button' }
>
<TextInput
style={ { textAlign: 'center' } }
fontFamily={ this.props.fontFamily || ( styles[ 'caption-text' ].fontFamily ) }
underlineColorAndroid="transparent"
value={ caption }
<RichText
setRef={ ( ref ) => {
this._caption = ref;
} }
placeholder={ __( 'Write caption…' ) }
onChangeText={ ( newCaption ) => setAttributes( { caption: newCaption } ) }
value={ caption }
onChange={ ( newCaption ) => setAttributes( { caption: newCaption } ) }
onFocus={ this.onFocusCaption }
onBlur={ this.props.onBlur } // always assign onBlur as props
isSelected={ this.state.isCaptionSelected }
fontSize={ 14 }
underlineColorAndroid="transparent"
/>
</View>
) }
Expand Down
4 changes: 0 additions & 4 deletions packages/block-library/src/image/styles.native.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@
align-items: center;
}

.caption-text {
font-family: $default-regular-font;
}

.clearSettingsButton {
color: $alert-red;
}

0 comments on commit d9390f3

Please sign in to comment.