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

FIX - Improve Link Entry #2779

Closed
wants to merge 13 commits into from
140 changes: 24 additions & 116 deletions blocks/editable/format-toolbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
*/
import { __ } from '@wordpress/i18n';
import { Component } from '@wordpress/element';
import { IconButton, Toolbar, withSpokenMessages } from '@wordpress/components';
import { Toolbar, withSpokenMessages } from '@wordpress/components';
import { keycodes } from '@wordpress/utils';

/**
* Internal dependencies
*/
import './style.scss';
import UrlInput from '../../url-input';
import { filterURLForDisplay } from '../../../editor/utils/url';
import ToggleControl from '../../inspector-controls/toggle-control';
import UrlInputButton from '../../url-input/button';

const { ESCAPE } = keycodes;

Expand Down Expand Up @@ -40,22 +38,9 @@ const DEFAULT_CONTROLS = [ 'bold', 'italic', 'strikethrough', 'link' ];
class FormatToolbar extends Component {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we could refactor this component to be just a functional component?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we can as it needs the lifecycle methods?

constructor() {
super( ...arguments );
this.state = {
isAddingLink: false,
isEditingLink: false,
settingsVisible: false,
opensInNewWindow: false,
newLinkValue: '',
};

this.addLink = this.addLink.bind( this );
this.editLink = this.editLink.bind( this );
this.dropLink = this.dropLink.bind( this );
this.submitLink = this.submitLink.bind( this );
this.onKeyDown = this.onKeyDown.bind( this );
this.onChangeLinkValue = this.onChangeLinkValue.bind( this );
this.toggleLinkSettingsVisibility = this.toggleLinkSettingsVisibility.bind( this );
this.setLinkTarget = this.setLinkTarget.bind( this );
this.onUrlChange = this.onUrlChange.bind( this );
}

componentDidMount() {
Expand All @@ -75,22 +60,6 @@ class FormatToolbar extends Component {
}
}

componentWillReceiveProps( nextProps ) {
if ( this.props.selectedNodeId !== nextProps.selectedNodeId ) {
this.setState( {
isAddingLink: false,
isEditingLink: false,
settingsVisible: false,
opensInNewWindow: !! nextProps.formats.link && !! nextProps.formats.link.target,
newLinkValue: '',
} );
}
}

onChangeLinkValue( value ) {
this.setState( { newLinkValue: value } );
}

toggleFormat( format ) {
return () => {
this.props.onChange( {
Expand All @@ -99,45 +68,20 @@ class FormatToolbar extends Component {
};
}

toggleLinkSettingsVisibility() {
this.setState( ( state ) => ( { settingsVisible: ! state.settingsVisible } ) );
}

setLinkTarget( event ) {
const opensInNewWindow = event.target.checked;
this.setState( { opensInNewWindow } );
this.props.onChange( { link: { value: this.props.formats.link.value, target: opensInNewWindow ? '_blank' : '' } } );
}

addLink() {
this.setState( { isEditingLink: false, isAddingLink: true, newLinkValue: '' } );
}
onUrlChange( { url, opensInNewWindow } ) {
if ( !! url ) {
this.props.onChange( { link: { value: url, target: opensInNewWindow ? '_blank' : '' } } );

dropLink() {
this.props.onChange( { link: undefined } );
this.setState( { isEditingLink: false, isAddingLink: false, newLinkValue: '' } );
}

editLink( event ) {
event.preventDefault();
this.setState( { isEditingLink: false, isAddingLink: true, newLinkValue: this.props.formats.link.value } );
}

submitLink( event ) {
event.preventDefault();
this.props.onChange( { link: { value: this.state.newLinkValue, target: this.state.opensInNewWindow ? '_blank' : '' } } );
if ( this.state.isAddingLink ) {
this.props.speak( __( 'Link inserted.' ), 'assertive' );
if ( ! this.props.formats.link ) {
this.props.speak( __( 'Link inserted.' ), 'assertive' );
}
} else {
this.props.onChange( { link: undefined } );
}
}

render() {
const { formats, focusPosition, enabledControls = DEFAULT_CONTROLS } = this.props;
const { isAddingLink, isEditingLink, newLinkValue, settingsVisible, opensInNewWindow } = this.state;
const linkStyle = focusPosition
? { position: 'absolute', ...focusPosition }
: null;

const { formats, enabledControls = DEFAULT_CONTROLS, extraButtons, selectedNodeId } = this.props;
const toolbarControls = FORMATTING_CONTROLS
.filter( control => enabledControls.indexOf( control.format ) !== -1 )
.map( ( control ) => ( {
Expand All @@ -146,56 +90,20 @@ class FormatToolbar extends Component {
isActive: !! formats[ control.format ],
} ) );

const linkSettings = settingsVisible && (
<fieldset className="blocks-format-toolbar__link-settings">
<ToggleControl
label={ __( 'Open in new window' ) }
checked={ opensInNewWindow }
onChange={ this.setLinkTarget } />
</fieldset>
);

if ( enabledControls.indexOf( 'link' ) !== -1 ) {
toolbarControls.push( {
icon: 'admin-links',
title: __( 'Link' ),
onClick: this.addLink,
isActive: isAddingLink || !! formats.link,
} );
}
const showLinkControl = enabledControls.indexOf( 'link' ) !== -1;

return (
<div className="blocks-format-toolbar">
<Toolbar controls={ toolbarControls } />

{ ( isAddingLink || isEditingLink ) &&
<form
className="blocks-format-toolbar__link-modal"
style={ linkStyle }
onSubmit={ this.submitLink }>
<UrlInput value={ newLinkValue } onChange={ this.onChangeLinkValue } />
<IconButton icon="editor-break" label={ __( 'Apply' ) } type="submit" />
<IconButton icon="editor-unlink" label={ __( 'Remove link' ) } onClick={ this.dropLink } />
<IconButton icon="admin-generic" onClick={ this.toggleLinkSettingsVisibility } aria-expanded={ settingsVisible } />
{ linkSettings }
</form>
}

{ !! formats.link && ! isAddingLink && ! isEditingLink &&
<div className="blocks-format-toolbar__link-modal" style={ linkStyle }>
<a
className="blocks-format-toolbar__link-value"
href={ formats.link.value }
target="_blank"
>
{ formats.link.value && filterURLForDisplay( decodeURI( formats.link.value ) ) }
</a>
<IconButton icon="edit" label={ __( 'Edit' ) } onClick={ this.editLink } />
<IconButton icon="editor-unlink" label={ __( 'Remove link' ) } onClick={ this.dropLink } />
<IconButton icon="admin-generic" onClick={ this.toggleLinkSettingsVisibility } aria-expanded={ settingsVisible } />
{ linkSettings }
</div>
}
<div ref={ this.bindRootNode } className="blocks-format-toolbar">
<Toolbar controls={ toolbarControls }>
{showLinkControl &&
<UrlInputButton
selectedNodeId={ selectedNodeId }
onChange={ this.onUrlChange }
url={ formats.link ? formats.link.value : '' } />
}
{ extraButtons }
</Toolbar>

</div>
);
}
Expand Down
40 changes: 0 additions & 40 deletions blocks/editable/format-toolbar/style.scss
Original file line number Diff line number Diff line change
@@ -1,43 +1,3 @@
.blocks-format-toolbar {
display: inline-flex;
}

.blocks-format-toolbar__link-modal {
position: absolute;
box-shadow: 0px 3px 20px rgba( 18, 24, 30, .1 ), 0px 1px 3px rgba( 18, 24, 30, .1 );
border: 1px solid #e0e5e9;
background: #fff;
width: 305px;
display: inline-flex;
flex-wrap: wrap;
align-items: center;
font-family: $default-font;
font-size: $default-font-size;
line-height: $default-line-height;
z-index: z-index( '.blocks-format-toolbar__link-modal' );

.blocks-url-input {
width: auto;
}
}

.blocks-format-toolbar__link-value {
padding: 10px;
flex-grow: 1;
overflow: hidden;
position: relative;

&:after {
@include long-content-fade( $size: 40% );
}
}

.blocks-format-toolbar__link-settings {
border-top: 1px solid $light-gray-500;
width: 100%;
padding: 10px 8px;

.blocks-base-control {
margin: 0;
}
}
2 changes: 2 additions & 0 deletions blocks/editable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@ export default class Editable extends Component {
placeholder,
multiline: MultilineTag,
keepPlaceholderOnFocus = false,
extraToolbarButtons,
} = this.props;

// Generating a key that includes `tagName` ensures that if the tag
Expand All @@ -610,6 +611,7 @@ export default class Editable extends Component {
formats={ this.state.formats }
onChange={ this.changeFormats }
enabledControls={ formattingControls }
extraButtons={ extraToolbarButtons }
/>
);

Expand Down
6 changes: 6 additions & 0 deletions blocks/editable/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,10 @@
ul.components-toolbar {
box-shadow: $shadow-toolbar;
}

.blocks-format-toolbar__link-modal {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
}
16 changes: 3 additions & 13 deletions blocks/library/button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { IconButton } from '@wordpress/components';

/**
* Internal dependencies
Expand All @@ -11,7 +10,7 @@ import './editor.scss';
import './style.scss';
import { registerBlockType, source } from '../../api';
import Editable from '../../editable';
import UrlInput from '../../url-input';
import UrlInputButton from '../../url-input/button';
import BlockControls from '../../block-controls';
import BlockAlignmentToolbar from '../../block-alignment-toolbar';
import ColorPalette from '../../color-palette';
Expand Down Expand Up @@ -58,6 +57,7 @@ registerBlockType( 'core/button', {
edit( { attributes, setAttributes, focus, setFocus, className } ) {
const { text, url, title, align, color } = attributes;
const updateAlignment = ( nextAlign ) => setAttributes( { align: nextAlign } );
const updateUrl = ( urlSettings ) => setAttributes( { url: urlSettings.url } );

return [
focus && (
Expand All @@ -75,18 +75,8 @@ registerBlockType( 'core/button', {
onChange={ ( value ) => setAttributes( { text: value } ) }
formattingControls={ [ 'bold', 'italic', 'strikethrough' ] }
keepPlaceholderOnFocus
extraToolbarButtons={ <UrlInputButton showSettings={ false } url={ url } onChange={ updateUrl } /> }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this prop? Can't we just put this putting in the BlockControls component?

/>
{ focus &&
<form
className="blocks-format-toolbar__link-modal"
onSubmit={ ( event ) => event.preventDefault() }>
<UrlInput
value={ url }
onChange={ ( value ) => setAttributes( { url: value } ) }
/>
<IconButton icon="editor-break" label={ __( 'Apply' ) } type="submit" />
</form>
}
{ focus &&
<InspectorControls key="inspector">
<ColorPalette
Expand Down
1 change: 0 additions & 1 deletion blocks/library/cover-image/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ registerBlockType( 'core/cover-image', {
focus={ focus }
onFocus={ setFocus }
onChange={ ( value ) => setAttributes( { title: value } ) }
inlineToolbar
/>
) : null }
</section>,
Expand Down
40 changes: 20 additions & 20 deletions blocks/library/image/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ class ImageBlock extends Component {
this.fetchMedia( media.id );
}

onSetHref( value ) {
this.props.setAttributes( { href: value } );
onSetHref( { url } ) {
this.props.setAttributes( { href: url } );
}

updateAlt( newAlt ) {
Expand Down Expand Up @@ -110,23 +110,24 @@ class ImageBlock extends Component {
value={ align }
onChange={ this.updateAlignment }
/>

<Toolbar>
<li>
<MediaUploadButton
buttonProps={ {
className: 'components-icon-button components-toolbar__control',
'aria-label': __( 'Edit image' ),
} }
onSelect={ this.onSelectImage }
type="image"
value={ id }
>
<Dashicon icon="edit" />
</MediaUploadButton>
</li>
<UrlInputButton onChange={ this.onSetHref } url={ href } />
</Toolbar>
{focus.editable !== 'caption' &&
<Toolbar>
<li>
<MediaUploadButton
buttonProps={ {
className: 'components-icon-button components-toolbar__control',
'aria-label': __( 'Edit image' ),
} }
onSelect={ this.onSelectImage }
type="image"
value={ id }
>
<Dashicon icon="edit" />
</MediaUploadButton>
</li>
<UrlInputButton onChange={ this.onSetHref } url={ href } />
</Toolbar>
}
</BlockControls>
)
);
Expand Down Expand Up @@ -248,7 +249,6 @@ class ImageBlock extends Component {
focus={ focus && focus.editable === 'caption' ? focus : undefined }
onFocus={ focusCaption }
onChange={ ( value ) => setAttributes( { caption: value } ) }
inlineToolbar
/>
) : null }
</figure>,
Expand Down
Loading