Skip to content
Closed
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
Editable: Adding the link control
  • Loading branch information
youknowriad committed Apr 25, 2017
commit 9c261de24d926baf54e69563fc95c6cbe06b2f28
14 changes: 12 additions & 2 deletions blocks/components/editable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export default class Editable extends wp.element.Component {
}

onNodeChange( { parents } ) {
this.formats = parents.reduce( ( result, node ) => {
const formats = parents.reduce( ( result, node ) => {
const tag = node.nodeName.toLowerCase();

if ( formatMap.hasOwnProperty( tag ) ) {
Expand All @@ -141,6 +141,14 @@ export default class Editable extends wp.element.Component {
return result;
}, {} );

// Link format
const link = parents.find( parent => parent.nodeName === 'A' );
Copy link
Member

Choose a reason for hiding this comment

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

We're not polyfilling Array#find, this will error in IE11.

if ( link ) {
formats.link = link.getAttribute( 'href' );
}

this.formats = formats;

this.props.onFormatChange( this.formats );
}

Expand Down Expand Up @@ -215,7 +223,9 @@ export default class Editable extends wp.element.Component {
if ( state !== currentState ) {
this.editor.focus();

if ( state ) {
if ( format === 'link' ) {
this.editor.execCommand( 'mceInsertLink', true, state );
} else if ( state ) {
this.editor.formatter.apply( format );
} else {
this.editor.formatter.remove( format );
Expand Down
Empty file.
37 changes: 22 additions & 15 deletions editor/components/toolbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,34 @@ import classNames from 'classnames';
import './style.scss';
import IconButton from 'components/icon-button';

function Toolbar( { controls } ) {
function Toolbar( { attributes, setAttributes, controls } ) {
Copy link
Member

Choose a reason for hiding this comment

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

My first reaction to these changes is that the line is becoming blurred between the concept of a general-purpose toolbar and a block-specific toolbar. We should decide if there's value in the former and whether we can or care to preserve this distinction.

Copy link
Contributor Author

@youknowriad youknowriad Apr 25, 2017

Choose a reason for hiding this comment

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

Well attributes and setAttributes here don't mean "block attributes" and "update block attributes" but I see it as "toolbarState" "updateToolbarState" which is generic enough. Could be renamed but this would impact the attributes setAttributes used in the isActive and onClick of the block controls.

Copy link
Member

Choose a reason for hiding this comment

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

Well attributes and setAttributes here don't mean "block attributes" and "update block attributes" but I see it as "toolbarState" "updateToolbarState" which is generic enough.

Given that I had trouble making this distinction, I expect others will as well.

if ( ! controls || ! controls.length ) {
return null;
}

return (
<ul className="editor-toolbar">
{ controls.map( ( control, index ) => (
<IconButton
key={ index }
icon={ control.icon }
label={ control.title }
data-subscript={ control.subscript }
onClick={ ( event ) => {
event.stopPropagation();
control.onClick();
} }
className={ classNames( 'editor-toolbar__control', {
'is-active': control.isActive && control.isActive()
} ) } />
) ) }
{ controls.map( ( control, index ) => {
if ( control.edit ) {
const element = wp.element.createElement( control.edit, { attributes, setAttributes } );
return wp.element.cloneElement( element, { key: index } );
}

return (
<IconButton
key={ index }
icon={ control.icon }
label={ control.title }
data-subscript={ control.subscript }
onClick={ ( event ) => {
event.stopPropagation();
control.onClick( attributes, setAttributes );
} }
className={ classNames( 'editor-toolbar__control', {
'is-active': control.isActive && control.isActive( attributes )
Copy link
Member

Choose a reason for hiding this comment

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

This will need to be rebased to account for changes in #500.

} ) } />
);
} ) }
</ul>
);
}
Expand Down
64 changes: 23 additions & 41 deletions editor/modes/visual-editor/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,7 @@ import classnames from 'classnames';
import Toolbar from 'components/toolbar';
import BlockMover from 'components/block-mover';
import BlockSwitcher from 'components/block-switcher';

const formattingControls = [
{
icon: 'editor-bold',
title: wp.i18n.__( 'Bold' ),
format: 'bold'
},
{
icon: 'editor-italic',
title: wp.i18n.__( 'Italic' ),
format: 'italic'
},
{
icon: 'editor-strikethrough',
title: wp.i18n.__( 'Strikethrough' ),
format: 'strikethrough'
}
];
import formattingControls from './format-controls';

class VisualEditorBlock extends wp.element.Component {
constructor() {
Expand All @@ -37,7 +20,7 @@ class VisualEditorBlock extends wp.element.Component {
this.maybeDeselect = this.maybeDeselect.bind( this );
this.maybeHover = this.maybeHover.bind( this );
this.onFormatChange = this.onFormatChange.bind( this );
this.toggleFormat = this.toggleFormat.bind( this );
this.setFormats = this.setFormats.bind( this );
this.previousOffset = null;
this.state = {
formats: {}
Expand All @@ -56,13 +39,13 @@ class VisualEditorBlock extends wp.element.Component {
this.setState( { formats } );
}

toggleFormat( format ) {
setFormats( newFormats ) {
const { formats } = this.state;

this.setState( {
formats: {
...formats,
[ format ]: ! formats[ format ]
...newFormats
}
} );
}
Expand Down Expand Up @@ -143,7 +126,6 @@ class VisualEditorBlock extends wp.element.Component {
tabIndex="0"
onFocus={ onSelect }
onBlur={ this.maybeDeselect }
onKeyDown={ onStartTyping }
onMouseEnter={ onHover }
onMouseMove={ this.maybeHover }
onMouseLeave={ onMouseLeave }
Expand All @@ -155,31 +137,31 @@ class VisualEditorBlock extends wp.element.Component {
<BlockSwitcher uid={ block.uid } />
{ !! settings.controls && (
<Toolbar
controls={ settings.controls.map( ( control ) => ( {
...control,
onClick: () => control.onClick( block.attributes, this.setAttributes ),
isActive: () => control.isActive( block.attributes )
} ) ) } />
controls={ settings.controls }
attributes={ block.attributes }
setAttributes={ this.setAttributes }
/>
) }
{ this.state.hasEditable && (
<Toolbar
controls={ formattingControls.map( ( control ) => ( {
...control,
onClick: () => this.toggleFormat( control.format ),
isActive: () => !! this.state.formats[ control.format ]
} ) ) } />
controls={ formattingControls }
attributes={ this.state.formats }
setAttributes={ this.setFormats }
/>
) }
</div>
}
<BlockEdit
focus={ focus }
attributes={ block.attributes }
setAttributes={ this.setAttributes }
insertBlockAfter={ onInsertAfter }
setFocus={ onFocus }
onFormatChange={ this.onFormatChange }
formats={ this.state.formats }
/>
<div onKeyDown={ onStartTyping }>
<BlockEdit
focus={ focus }
attributes={ block.attributes }
setAttributes={ this.setAttributes }
insertBlockAfter={ onInsertAfter }
setFocus={ onFocus }
onFormatChange={ this.onFormatChange }
formats={ this.state.formats }
/>
</div>
</div>
);
/* eslint-enable jsx-a11y/no-static-element-interactions */
Expand Down
105 changes: 105 additions & 0 deletions editor/modes/visual-editor/format-controls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
Copy link
Member

Choose a reason for hiding this comment

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

Should this file have been named link-control.js?

Copy link
Member

Choose a reason for hiding this comment

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

Oh, I see now the LinkControl component is inlined in the file, but the default export is the array of formatting controls. Hmm...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could be two files

* External dependencies
*/
import classNames from 'classnames';

/**
* Internal dependencies
*/
import './style.scss';
import IconButton from 'components/icon-button';

class LinkControl extends wp.element.Component {
constructor() {
super( ...arguments );
this.state = {
opened: false
};
this.toggleLinkModal = this.toggleLinkModal.bind( this );
this.submitLinkModal = this.submitLinkModal.bind( this );
this.updateLinkValue = this.updateLinkValue.bind( this );
}

componentWillMount() {
this.setState( { value: this.props.attributes.link } );
}

componentWillReceiveProps( nextProps ) {
this.setState( { value: nextProps.attributes.link } );
}

toggleLinkModal() {
this.setState( {
opened: ! this.state.opened
} );
}

submitLinkModal( event ) {
event.preventDefault();
this.props.setAttributes( { link: this.state.value } );
this.setState( {
opened: false
} );
}

updateLinkValue( event ) {
this.setState( {
value: event.target.value
} );
}

render() {
return (
<div className="editable-visual-editor__link-control">
<IconButton
icon="admin-links"
label={ wp.i18n.__( 'Link' ) }
onClick={ this.toggleLinkModal }
className={ classNames( 'editor-toolbar__control', {
'is-active': !! this.props.attributes.link
} ) }
/>
{ this.state.opened &&
<div className="editable-visual-editor__link-modal">
Copy link
Member

Choose a reason for hiding this comment

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

Can we apply this class to the form and drop the wrapper element?

<form onSubmit={ this.submitLinkModal }>
<input type="url" value={ this.state.value } onChange={ this.updateLinkValue } />
<button>{ wp.i18n.__( 'Add Link' ) }</button>
Copy link
Member

Choose a reason for hiding this comment

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

Trying to decide if there's value in the <Button /> component (editor/components/button) being the preferred default usage so we can apply styles broadly to all buttons in the editor.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, this needs to be updated to match @jasmussen's comment

</form>
</div>
}
</div>
);
}
}

const formattingControls = [
{
icon: 'editor-bold',
title: wp.i18n.__( 'Bold' ),
isActive: ( { bold } ) => !! bold,
onClick( attributes, setAttributes ) {
setAttributes( { bold: ! attributes.bold } );
},
},
{
icon: 'editor-italic',
title: wp.i18n.__( 'Italic' ),
isActive: ( { italic } ) => !! italic,
onClick( attributes, setAttributes ) {
setAttributes( { italic: ! attributes.italic } );
},
},
{
icon: 'editor-strikethrough',
title: wp.i18n.__( 'Strikethrough' ),
isActive: ( { strikethrough } ) => !! strikethrough,
onClick( attributes, setAttributes ) {
setAttributes( { strikethrough: ! attributes.strikethrough } );
},
},
{
edit: LinkControl
}
];

export default formattingControls;
19 changes: 19 additions & 0 deletions editor/modes/visual-editor/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,22 @@
.editor-visual-editor .editor-inserter {
margin: $item-spacing;
}


// joen make me pretty
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jasmussen you shouldn't have showed me this tip :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Haha love it :D — I'll take a look.

.editable-visual-editor__link-control {
position: relative;
}

.editable-visual-editor__link-modal {
position: absolute;
top: 42px;
box-shadow: 0px 3px 20px rgba( 18, 24, 30, .1 ), 0px 1px 3px rgba( 18, 24, 30, .1 );
border: 1px solid #e0e5e9;
background: #fff;
padding: 10px;

input {
font-size: 13px;
}
}
14 changes: 11 additions & 3 deletions languages/gutenberg.pot
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,23 @@ msgstr ""
msgid "Publish"
msgstr ""

#: editor/modes/visual-editor/block.js:17
#: editor/modes/visual-editor/format-controls.js:56
msgid "Link"
msgstr ""

#: editor/modes/visual-editor/format-controls.js:66
msgid "Add Link"
msgstr ""

#: editor/modes/visual-editor/format-controls.js:78
msgid "Bold"
msgstr ""

#: editor/modes/visual-editor/block.js:22
#: editor/modes/visual-editor/format-controls.js:86
msgid "Italic"
msgstr ""

#: editor/modes/visual-editor/block.js:27
#: editor/modes/visual-editor/format-controls.js:94
msgid "Strikethrough"
msgstr ""

Expand Down