summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/extensions/blocks/gif/edit.js')
-rw-r--r--plugins/jetpack/extensions/blocks/gif/edit.js217
1 files changed, 217 insertions, 0 deletions
diff --git a/plugins/jetpack/extensions/blocks/gif/edit.js b/plugins/jetpack/extensions/blocks/gif/edit.js
new file mode 100644
index 00000000..d16fa4db
--- /dev/null
+++ b/plugins/jetpack/extensions/blocks/gif/edit.js
@@ -0,0 +1,217 @@
+/**
+ * External dependencies
+ */
+import classNames from 'classnames';
+import { __ } from '@wordpress/i18n';
+import { Component, createRef } from '@wordpress/element';
+import { Button, PanelBody, Path, Placeholder, SVG, TextControl } from '@wordpress/components';
+import { InspectorControls, RichText } from '@wordpress/editor';
+
+/**
+ * Internal dependencies
+ */
+import { icon, title } from './';
+
+const GIPHY_API_KEY = 't1PkR1Vq0mzHueIFBvZSZErgFs9NBmYW';
+const INPUT_PROMPT = __( 'Search for a term or paste a Giphy URL', 'jetpack' );
+
+class GifEdit extends Component {
+ textControlRef = createRef();
+
+ state = {
+ captionFocus: false,
+ results: null,
+ };
+
+ onFormSubmit = event => {
+ event.preventDefault();
+ this.onSubmit();
+ };
+
+ onSubmit = () => {
+ const { attributes } = this.props;
+ const { searchText } = attributes;
+ this.parseSearch( searchText );
+ };
+
+ parseSearch = searchText => {
+ let giphyID = null;
+ // If search is hardcoded Giphy URL following this pattern: https://giphy.com/embed/4ZFekt94LMhNK
+ if ( searchText.indexOf( '//giphy.com/gifs' ) !== -1 ) {
+ giphyID = this.splitAndLast( this.splitAndLast( searchText, '/' ), '-' );
+ }
+ // If search is hardcoded Giphy URL following this patterh: http://i.giphy.com/4ZFekt94LMhNK.gif
+ if ( searchText.indexOf( '//i.giphy.com' ) !== -1 ) {
+ giphyID = this.splitAndLast( searchText, '/' ).replace( '.gif', '' );
+ }
+ // https://media.giphy.com/media/gt0hYzKlMpfOg/giphy.gif
+ const match = searchText.match(
+ /http[s]?:\/\/media.giphy.com\/media\/([A-Za-z0-9\-.]+)\/giphy.gif/
+ );
+ if ( match ) {
+ giphyID = match[ 1 ];
+ }
+ if ( giphyID ) {
+ return this.fetch( this.urlForId( giphyID ) );
+ }
+
+ return this.fetch( this.urlForSearch( searchText ) );
+ };
+
+ urlForSearch = searchText => {
+ return `https://api.giphy.com/v1/gifs/search?q=${ encodeURIComponent(
+ searchText
+ ) }&api_key=${ encodeURIComponent( GIPHY_API_KEY ) }&limit=10`;
+ };
+
+ urlForId = giphyId => {
+ return `https://api.giphy.com/v1/gifs/${ encodeURIComponent(
+ giphyId
+ ) }?api_key=${ encodeURIComponent( GIPHY_API_KEY ) }`;
+ };
+
+ splitAndLast = ( array, delimiter ) => {
+ const split = array.split( delimiter );
+ return split[ split.length - 1 ];
+ };
+
+ fetch = url => {
+ const xhr = new XMLHttpRequest();
+ xhr.open( 'GET', url );
+ xhr.onload = () => {
+ if ( xhr.status === 200 ) {
+ const res = JSON.parse( xhr.responseText );
+ // If there is only one result, Giphy's API does not return an array.
+ // The following statement normalizes the data into an array with one member in this case.
+ const results = typeof res.data.images !== 'undefined' ? [ res.data ] : res.data;
+ const giphyData = results[ 0 ];
+ // No results
+ if ( ! giphyData.images ) {
+ return;
+ }
+ this.setState( { results }, () => {
+ this.selectGiphy( giphyData );
+ } );
+ } else {
+ // Error handling TK
+ }
+ };
+ xhr.send();
+ };
+
+ selectGiphy = giphy => {
+ const { setAttributes } = this.props;
+ const calculatedPaddingTop = Math.floor(
+ ( giphy.images.original.height / giphy.images.original.width ) * 100
+ );
+ const paddingTop = `${ calculatedPaddingTop }%`;
+ const giphyUrl = giphy.embed_url;
+ setAttributes( { giphyUrl, paddingTop } );
+ };
+
+ setFocus = () => {
+ this.textControlRef.current.querySelector( 'input' ).focus();
+ this.setState( { captionFocus: false } );
+ };
+
+ hasSearchText = () => {
+ const { attributes } = this.props;
+ const { searchText } = attributes;
+ return searchText && searchText.length > 0;
+ };
+
+ thumbnailClicked = thumbnail => {
+ this.selectGiphy( thumbnail );
+ };
+
+ render() {
+ const { attributes, className, isSelected, setAttributes } = this.props;
+ const { align, caption, giphyUrl, searchText, paddingTop } = attributes;
+ const { captionFocus, results } = this.state;
+ const style = { paddingTop };
+ const classes = classNames( className, `align${ align }` );
+ const inputFields = (
+ <form
+ className="wp-block-jetpack-gif_input-container"
+ onSubmit={ this.onFormSubmit }
+ ref={ this.textControlRef }
+ >
+ <TextControl
+ className="wp-block-jetpack-gif_input"
+ label={ INPUT_PROMPT }
+ placeholder={ INPUT_PROMPT }
+ onChange={ value => setAttributes( { searchText: value } ) }
+ value={ searchText }
+ />
+ <Button isLarge onClick={ this.onSubmit }>
+ { __( 'Search', 'jetpack' ) }
+ </Button>
+ </form>
+ );
+ return (
+ <div className={ classes }>
+ <InspectorControls>
+ <PanelBody className="components-panel__body-gif-branding">
+ <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 202 22">
+ <Path d="M4.6 5.9H0v10h1.6v-3.1h3c4.8 0 4.8-6.9 0-6.9zm0 5.4h-3v-4h3c2.6.1 2.6 4 0 4zM51.2 12.3c2-.3 2.7-1.7 2.7-3.1 0-1.7-1.2-3.3-3.5-3.3h-4.6v10h1.6v-3.4h2.1l3 3.4h1.9l-.2-.3-3-3.3zM47.4 11V7.4h3c1.3 0 1.9.9 1.9 1.8s-.6 1.8-1.9 1.8h-3zM30.6 13.6L28 5.9h-1.1l-2.5 7.7-2.6-7.7H20l3.7 10H25l1.4-3.5L27.5 9l1.1 3.4 1.3 3.5h1.4l3.5-10h-1.7z" />
+ <Path d="M14.4 5.7c-3 0-5.1 2.2-5.1 5.2 0 2.6 1.6 5.1 5.1 5.1 3.5 0 5.1-2.5 5.1-5.2-.1-2.6-1.7-5.1-5.1-5.1zm-.1 8.9c-2.5 0-3.5-1.9-3.5-3.7 0-2.2 1.2-3.8 3.5-3.8 2.4 0 3.5 2 3.5 3.8.1 2-1 3.7-3.5 3.7zM57.7 11.6h5.5v-1.5h-5.5V7.4h5.7V5.9h-7.3v10h7.3v-1.6h-5.7zM38 14.3v-2.7h5.5v-1.5H38V7.4h5.7V5.9h-7.3v10h7.3v-1.6zM93 10.3l-2.7-4.4h-1.9V6l3.8 5.8v4.1h1.6v-4.1l4-5.8v-.1h-2zM69.3 5.9h-3.8v10h3.8c3.5 0 5.1-2.5 5-5.1-.1-2.5-1.6-4.9-5-4.9zm0 8.4h-2.2V7.4h2.2c2.3 0 3.4 1.7 3.4 3.4s-1 3.5-3.4 3.5zM86.3 10.7c.9-.4 1.4-1.1 1.4-2 0-2-1.5-2.8-3.4-2.8h-4.6v10h4.6c2 0 3.7-.7 3.7-2.8 0-.8-.5-2-1.7-2.4zm-5-3.4h3c1.2 0 1.8.7 1.8 1.4 0 .8-.6 1.3-1.8 1.3h-3V7.3zm3 7.1h-3v-2.9h3c.9 0 2.1.5 2.1 1.6 0 1-1.2 1.3-2.1 1.3zM113.9 13.3h5.3V16c-1.2.9-2.9 1.1-4 1.1-4.2 0-5.6-3.3-5.6-6 0-4.1 2.2-6.1 5.6-6.1 1.4 0 3.2.4 4.8 1.8l3.4-3.4C120.7.6 118.1 0 115.2 0c-7.8 0-11.4 5.6-11.4 11s3.1 10.9 11.4 10.9c4 0 7.6-1.4 8.9-4.1V8.6h-10.2v4.7zM171.9 8.5h-7.4V.6h-5.9v20.8h5.9v-7.8h7.4v7.8h5.9V.6h-5.9zM195.1.6l-4.5 7.1-4.3-7.1h-6.6v.2l7.9 12.3v8.3h5.9v-8.3L201.8.9V.6zM127.4.6h5.9v20.8h-5.9zM147.6.6h-10.1v20.8h5.9v-5.6h4.2c5.6-.1 8.3-3.4 8.3-7.6.1-4.1-2.7-7.6-8.3-7.6zm0 10.2h-4.2V5.6h4.2c1.6 0 2.5 1.2 2.5 2.6 0 1.4-.9 2.6-2.5 2.6z" />
+ </SVG>
+ </PanelBody>
+ </InspectorControls>
+ { ! giphyUrl ? (
+ <Placeholder className="wp-block-jetpack-gif_placeholder" icon={ icon } label={ title }>
+ { inputFields }
+ </Placeholder>
+ ) : (
+ <figure>
+ { isSelected && inputFields }
+ { isSelected && results && results.length > 1 && (
+ <div className="wp-block-jetpack-gif_thumbnails-container">
+ { results.map( thumbnail => {
+ const thumbnailStyle = {
+ backgroundImage: `url(${ thumbnail.images.downsized_still.url })`,
+ };
+ return (
+ <button
+ className="wp-block-jetpack-gif_thumbnail-container"
+ key={ thumbnail.id }
+ onClick={ () => {
+ this.thumbnailClicked( thumbnail );
+ } }
+ style={ thumbnailStyle }
+ />
+ );
+ } ) }
+ </div>
+ ) }
+ <div className="wp-block-jetpack-gif-wrapper" style={ style }>
+ <div
+ className="wp-block-jetpack-gif_cover"
+ onClick={ this.setFocus }
+ onKeyDown={ this.setFocus }
+ role="button"
+ tabIndex="0"
+ />
+ <iframe src={ giphyUrl } title={ searchText } />
+ </div>
+ { ( ! RichText.isEmpty( caption ) || isSelected ) && !! giphyUrl && (
+ <RichText
+ className="wp-block-jetpack-gif-caption gallery-caption"
+ inlineToolbar
+ isSelected={ captionFocus }
+ unstableOnFocus={ () => {
+ this.setState( { captionFocus: true } );
+ } }
+ onChange={ value => setAttributes( { caption: value } ) }
+ placeholder={ __( 'Write caption…', 'jetpack' ) }
+ tagName="figcaption"
+ value={ caption }
+ />
+ ) }
+ </figure>
+ ) }
+ </div>
+ );
+ }
+}
+export default GifEdit;