From 49bb394f97d5051a9eb13968aeabf591fd994079 Mon Sep 17 00:00:00 2001 From: Mario Zorz Date: Thu, 20 Dec 2018 09:02:38 -0300 Subject: [PATCH 01/11] temporarily disable link formatting --- .../editor/src/components/rich-text/index.native.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/editor/src/components/rich-text/index.native.js b/packages/editor/src/components/rich-text/index.native.js index f6796a97fdbaa..d8f9a1cfb0476 100644 --- a/packages/editor/src/components/rich-text/index.native.js +++ b/packages/editor/src/components/rich-text/index.native.js @@ -40,11 +40,12 @@ const FORMATTING_CONTROLS = [ title: __( 'Italic' ), format: 'italic', }, - { - icon: 'admin-links', - title: __( 'Link' ), - format: 'link', - }, + // TODO: get this back after alpha + // { + // icon: 'admin-links', + // title: __( 'Link' ), + // format: 'link', + // }, { icon: 'editor-strikethrough', title: __( 'Strikethrough' ), From 96a73c5864262e02fa3bf907723eb43e6515c9d7 Mon Sep 17 00:00:00 2001 From: Jorge Bernal Date: Thu, 20 Dec 2018 19:21:34 +0100 Subject: [PATCH 02/11] Make sure RichText resigns focus when unmounted (#13048) --- packages/editor/src/components/rich-text/index.native.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/editor/src/components/rich-text/index.native.js b/packages/editor/src/components/rich-text/index.native.js index d8f9a1cfb0476..fd9d074472f5a 100644 --- a/packages/editor/src/components/rich-text/index.native.js +++ b/packages/editor/src/components/rich-text/index.native.js @@ -291,6 +291,12 @@ export class RichText extends Component { } } + componentWillUnmount() { + if ( this._editor.isFocused() ) { + this._editor.blur(); + } + } + componentDidUpdate( prevProps ) { if ( this.props.isSelected && ! prevProps.isSelected ) { this._editor.focus(); From e2b08e1dab2ab073d0294c63dc47130daa387090 Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Fri, 4 Jan 2019 16:49:05 -0300 Subject: [PATCH 03/11] Implements a native version of post-title. --- .../editor/src/components/index.native.js | 1 + .../src/components/post-title/index.native.js | 123 ++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 packages/editor/src/components/post-title/index.native.js diff --git a/packages/editor/src/components/index.native.js b/packages/editor/src/components/index.native.js index 229efa5879cc3..d226b4fe46480 100644 --- a/packages/editor/src/components/index.native.js +++ b/packages/editor/src/components/index.native.js @@ -7,5 +7,6 @@ export { default as BlockFormatControls } from './block-format-controls'; export { default as BlockControls } from './block-controls'; export { default as BlockEdit } from './block-edit'; export { default as DefaultBlockAppender } from './default-block-appender'; +export { default as PostTitle } from './post-title'; export { default as EditorHistoryRedo } from './editor-history/redo'; export { default as EditorHistoryUndo } from './editor-history/undo'; diff --git a/packages/editor/src/components/post-title/index.native.js b/packages/editor/src/components/post-title/index.native.js new file mode 100644 index 0000000000000..7d2194ba91ad2 --- /dev/null +++ b/packages/editor/src/components/post-title/index.native.js @@ -0,0 +1,123 @@ +/** + * External dependencies + */ +import { TextInput } from 'react-native'; +import { get } from 'lodash'; + +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { Component } from '@wordpress/element'; +import { decodeEntities } from '@wordpress/html-entities'; +import { ENTER } from '@wordpress/keycodes'; +import { withSelect, withDispatch } from '@wordpress/data'; +import { KeyboardShortcuts } from '@wordpress/components'; +import { withInstanceId, compose } from '@wordpress/compose'; +/** + * Internal dependencies + */ +import PostTypeSupportCheck from '../post-type-support-check'; + +/** + * Constants + */ +const REGEXP_NEWLINES = /[\r\n]+/g; + +class PostTitle extends Component { + constructor() { + super( ...arguments ); + + this.onChange = this.onChange.bind( this ); + this.onSelect = this.onSelect.bind( this ); + this.onUnselect = this.onUnselect.bind( this ); + this.onKeyDown = this.onKeyDown.bind( this ); + this.redirectHistory = this.redirectHistory.bind( this ); + + console.log( "Arguments: " + JSON.stringify(arguments) ); + + this.state = { + isSelected: false, + }; + } + + handleFocusOutside() { + this.onUnselect(); + } + + onSelect() { + this.setState( { isSelected: true } ); + this.props.clearSelectedBlock(); + } + + onUnselect() { + this.setState( { isSelected: false } ); + } + + onChange( title ) { + this.props.onUpdate( title ); + } + + onKeyDown( event ) { + if ( event.keyCode === ENTER ) { + event.preventDefault(); + this.props.onEnterPress(); + } + } + + /** + * Emulates behavior of an undo or redo on its corresponding key press + * combination. This is a workaround to React's treatment of undo in a + * controlled textarea where characters are updated one at a time. + * Instead, leverage the store's undo handling of title changes. + * + * @see https://github.com/facebook/react/issues/8514 + * + * @param {KeyboardEvent} event Key event. + */ + redirectHistory( event ) { + if ( event.shiftKey ) { + this.props.onRedo(); + } else { + this.props.onUndo(); + } + + event.preventDefault(); + } + + render() { + const { + hasFixedToolbar, + isCleanNewPost, + isFocusMode, + isPostTypeViewable, + instanceId, + placeholder, + style, + title, + } = this.props; + + const { isSelected } = this.state; + const decodedPlaceholder = decodeEntities( placeholder ); + + console.log("Placeholder: " + placeholder); + console.log("Decoded: " + decodedPlaceholder); + + return ( + + + ); + } +} + +export default compose( + withInstanceId, +)( PostTitle ); From d5910a871dd4de55aaafb89feecb5ebcbcb8ebfd Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Fri, 4 Jan 2019 19:09:22 -0300 Subject: [PATCH 04/11] Removes some unnecessary log calls. --- packages/editor/src/components/post-title/index.native.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/editor/src/components/post-title/index.native.js b/packages/editor/src/components/post-title/index.native.js index 7d2194ba91ad2..6e4541a4a9525 100644 --- a/packages/editor/src/components/post-title/index.native.js +++ b/packages/editor/src/components/post-title/index.native.js @@ -34,8 +34,6 @@ class PostTitle extends Component { this.onKeyDown = this.onKeyDown.bind( this ); this.redirectHistory = this.redirectHistory.bind( this ); - console.log( "Arguments: " + JSON.stringify(arguments) ); - this.state = { isSelected: false, }; @@ -100,9 +98,6 @@ class PostTitle extends Component { const { isSelected } = this.state; const decodedPlaceholder = decodeEntities( placeholder ); - console.log("Placeholder: " + placeholder); - console.log("Decoded: " + decodedPlaceholder); - return ( Date: Thu, 10 Jan 2019 17:14:53 -0300 Subject: [PATCH 05/11] Submits a few lint fixes. --- .../src/components/post-title/index.native.js | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/packages/editor/src/components/post-title/index.native.js b/packages/editor/src/components/post-title/index.native.js index 6e4541a4a9525..948b517f523eb 100644 --- a/packages/editor/src/components/post-title/index.native.js +++ b/packages/editor/src/components/post-title/index.native.js @@ -2,27 +2,14 @@ * External dependencies */ import { TextInput } from 'react-native'; -import { get } from 'lodash'; /** * WordPress dependencies */ -import { __ } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; import { decodeEntities } from '@wordpress/html-entities'; import { ENTER } from '@wordpress/keycodes'; -import { withSelect, withDispatch } from '@wordpress/data'; -import { KeyboardShortcuts } from '@wordpress/components'; import { withInstanceId, compose } from '@wordpress/compose'; -/** - * Internal dependencies - */ -import PostTypeSupportCheck from '../post-type-support-check'; - -/** - * Constants - */ -const REGEXP_NEWLINES = /[\r\n]+/g; class PostTitle extends Component { constructor() { @@ -85,17 +72,11 @@ class PostTitle extends Component { render() { const { - hasFixedToolbar, - isCleanNewPost, - isFocusMode, - isPostTypeViewable, - instanceId, placeholder, style, title, } = this.props; - const { isSelected } = this.state; const decodedPlaceholder = decodeEntities( placeholder ); return ( From 4f55ba9233d6080f584267615a2adb69abb9ff75 Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Thu, 10 Jan 2019 17:29:44 -0300 Subject: [PATCH 06/11] Fixes a linting issue. --- packages/editor/src/components/post-title/index.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/components/post-title/index.native.js b/packages/editor/src/components/post-title/index.native.js index 948b517f523eb..3ac4a94f139ac 100644 --- a/packages/editor/src/components/post-title/index.native.js +++ b/packages/editor/src/components/post-title/index.native.js @@ -76,7 +76,7 @@ class PostTitle extends Component { style, title, } = this.props; - + const decodedPlaceholder = decodeEntities( placeholder ); return ( From 4c276387aac1b0da9a2dc862b00df5e60b356520 Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Wed, 16 Jan 2019 17:59:56 -0300 Subject: [PATCH 07/11] When focusing the title, any focused block loses its focus. --- .../src/components/post-title/index.native.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/editor/src/components/post-title/index.native.js b/packages/editor/src/components/post-title/index.native.js index 3ac4a94f139ac..f63ba7a6d89a3 100644 --- a/packages/editor/src/components/post-title/index.native.js +++ b/packages/editor/src/components/post-title/index.native.js @@ -9,6 +9,7 @@ import { TextInput } from 'react-native'; import { Component } from '@wordpress/element'; import { decodeEntities } from '@wordpress/html-entities'; import { ENTER } from '@wordpress/keycodes'; +import { withSelect, withDispatch } from '@wordpress/data'; import { withInstanceId, compose } from '@wordpress/compose'; class PostTitle extends Component { @@ -86,6 +87,7 @@ class PostTitle extends Component { multiline numberOfLines={ 0 } onChangeText={ this.onChange } + onFocus={ this.onSelect } placeholder={ decodedPlaceholder } style={ style } value={ title }> @@ -94,6 +96,17 @@ class PostTitle extends Component { } } +const applyWithDispatch = withDispatch( ( dispatch ) => { + const { + clearSelectedBlock, + } = dispatch( 'core/editor' ); + + return { + clearSelectedBlock, + }; +} ); + export default compose( + applyWithDispatch, withInstanceId, )( PostTitle ); From 0ab5a1b6aa70d4d8b914eaefa45ac2f19322cd08 Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Wed, 16 Jan 2019 18:22:32 -0300 Subject: [PATCH 08/11] FocusOut is now wired for post-title for mobile. --- packages/components/src/index.native.js | 1 + packages/editor/src/components/post-title/index.native.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/packages/components/src/index.native.js b/packages/components/src/index.native.js index 3e44bdec61e50..cbaae28e089bd 100644 --- a/packages/components/src/index.native.js +++ b/packages/components/src/index.native.js @@ -9,3 +9,4 @@ export { createSlotFill, Slot, Fill, Provider as SlotFillProvider } from './slot // Higher-Order Components export { default as withFilters } from './higher-order/with-filters'; +export { default as withFocusOutside } from './higher-order/with-focus-outside'; diff --git a/packages/editor/src/components/post-title/index.native.js b/packages/editor/src/components/post-title/index.native.js index f63ba7a6d89a3..1b2e8091ac4f5 100644 --- a/packages/editor/src/components/post-title/index.native.js +++ b/packages/editor/src/components/post-title/index.native.js @@ -10,6 +10,7 @@ import { Component } from '@wordpress/element'; import { decodeEntities } from '@wordpress/html-entities'; import { ENTER } from '@wordpress/keycodes'; import { withSelect, withDispatch } from '@wordpress/data'; +import { withFocusOutside } from '@wordpress/components'; import { withInstanceId, compose } from '@wordpress/compose'; class PostTitle extends Component { @@ -109,4 +110,5 @@ const applyWithDispatch = withDispatch( ( dispatch ) => { export default compose( applyWithDispatch, withInstanceId, + withFocusOutside )( PostTitle ); From 1f9c722ee4b9a17d2659b8a624927dbe54b2d299 Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Wed, 16 Jan 2019 18:26:43 -0300 Subject: [PATCH 09/11] Removes unused some code. --- .../src/components/post-title/index.native.js | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/packages/editor/src/components/post-title/index.native.js b/packages/editor/src/components/post-title/index.native.js index 1b2e8091ac4f5..cf4af33ca24ca 100644 --- a/packages/editor/src/components/post-title/index.native.js +++ b/packages/editor/src/components/post-title/index.native.js @@ -8,7 +8,6 @@ import { TextInput } from 'react-native'; */ import { Component } from '@wordpress/element'; import { decodeEntities } from '@wordpress/html-entities'; -import { ENTER } from '@wordpress/keycodes'; import { withSelect, withDispatch } from '@wordpress/data'; import { withFocusOutside } from '@wordpress/components'; import { withInstanceId, compose } from '@wordpress/compose'; @@ -20,8 +19,6 @@ class PostTitle extends Component { this.onChange = this.onChange.bind( this ); this.onSelect = this.onSelect.bind( this ); this.onUnselect = this.onUnselect.bind( this ); - this.onKeyDown = this.onKeyDown.bind( this ); - this.redirectHistory = this.redirectHistory.bind( this ); this.state = { isSelected: false, @@ -45,33 +42,6 @@ class PostTitle extends Component { this.props.onUpdate( title ); } - onKeyDown( event ) { - if ( event.keyCode === ENTER ) { - event.preventDefault(); - this.props.onEnterPress(); - } - } - - /** - * Emulates behavior of an undo or redo on its corresponding key press - * combination. This is a workaround to React's treatment of undo in a - * controlled textarea where characters are updated one at a time. - * Instead, leverage the store's undo handling of title changes. - * - * @see https://github.com/facebook/react/issues/8514 - * - * @param {KeyboardEvent} event Key event. - */ - redirectHistory( event ) { - if ( event.shiftKey ) { - this.props.onRedo(); - } else { - this.props.onUndo(); - } - - event.preventDefault(); - } - render() { const { placeholder, From e54d5b9a074276dbd8798531e65c6ceee387e869 Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Wed, 16 Jan 2019 18:27:23 -0300 Subject: [PATCH 10/11] Added a file I failed to commit. --- .../with-focus-outside/index.native.js | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 packages/components/src/higher-order/with-focus-outside/index.native.js diff --git a/packages/components/src/higher-order/with-focus-outside/index.native.js b/packages/components/src/higher-order/with-focus-outside/index.native.js new file mode 100644 index 0000000000000..7d3ae52eaeb78 --- /dev/null +++ b/packages/components/src/higher-order/with-focus-outside/index.native.js @@ -0,0 +1,139 @@ +/** + * External dependencies + */ +import { includes } from 'lodash'; +import { View } from 'react-native'; + +/** + * WordPress dependencies + */ +import { Component } from '@wordpress/element'; +import { createHigherOrderComponent } from '@wordpress/compose'; + +/** + * Input types which are classified as button types, for use in considering + * whether element is a (focus-normalized) button. + * + * @type {string[]} + */ +const INPUT_BUTTON_TYPES = [ + 'button', + 'submit', +]; + +/** + * Returns true if the given element is a button element subject to focus + * normalization, or false otherwise. + * + * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus + * + * @param {Element} element Element to test. + * + * @return {boolean} Whether element is a button. + */ +function isFocusNormalizedButton( element ) { + switch ( element.nodeName ) { + case 'A': + case 'BUTTON': + return true; + + case 'INPUT': + return includes( INPUT_BUTTON_TYPES, element.type ); + } + + return false; +} + +export default createHigherOrderComponent( + ( WrappedComponent ) => { + return class extends Component { + constructor() { + super( ...arguments ); + + this.bindNode = this.bindNode.bind( this ); + this.cancelBlurCheck = this.cancelBlurCheck.bind( this ); + this.queueBlurCheck = this.queueBlurCheck.bind( this ); + this.normalizeButtonFocus = this.normalizeButtonFocus.bind( this ); + } + + componentWillUnmount() { + this.cancelBlurCheck(); + } + + bindNode( node ) { + if ( node ) { + this.node = node; + } else { + delete this.node; + this.cancelBlurCheck(); + } + } + + queueBlurCheck( event ) { + // React does not allow using an event reference asynchronously + // due to recycling behavior, except when explicitly persisted. + event.persist(); + + // Skip blur check if clicking button. See `normalizeButtonFocus`. + if ( this.preventBlurCheck ) { + return; + } + + this.blurCheckTimeout = setTimeout( () => { + if ( 'function' === typeof this.node.handleFocusOutside ) { + this.node.handleFocusOutside( event ); + } + }, 0 ); + } + + cancelBlurCheck() { + clearTimeout( this.blurCheckTimeout ); + } + + /** + * Handles a mousedown or mouseup event to respectively assign and + * unassign a flag for preventing blur check on button elements. Some + * browsers, namely Firefox and Safari, do not emit a focus event on + * button elements when clicked, while others do. The logic here + * intends to normalize this as treating click on buttons as focus. + * + * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus + * + * @param {MouseEvent} event Event for mousedown or mouseup. + */ + normalizeButtonFocus( event ) { + const { type, target } = event; + + const isInteractionEnd = includes( [ 'mouseup', 'touchend' ], type ); + + if ( isInteractionEnd ) { + this.preventBlurCheck = false; + } else if ( isFocusNormalizedButton( target ) ) { + this.preventBlurCheck = true; + } + } + + render() { + // Disable reason: See `normalizeButtonFocus` for browser-specific + // focus event normalization. + + /* eslint-disable jsx-a11y/no-static-element-interactions */ + return ( + + + + ); + /* eslint-enable jsx-a11y/no-static-element-interactions */ + } + }; + }, 'withFocusOutside' +); From 7f05b9ce0be41622efcd774d79932fccdf40a72c Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Thu, 17 Jan 2019 10:06:49 -0300 Subject: [PATCH 11/11] Fixes a linting issue. --- packages/editor/src/components/post-title/index.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/components/post-title/index.native.js b/packages/editor/src/components/post-title/index.native.js index cf4af33ca24ca..61148e0f4e7a6 100644 --- a/packages/editor/src/components/post-title/index.native.js +++ b/packages/editor/src/components/post-title/index.native.js @@ -8,7 +8,7 @@ import { TextInput } from 'react-native'; */ import { Component } from '@wordpress/element'; import { decodeEntities } from '@wordpress/html-entities'; -import { withSelect, withDispatch } from '@wordpress/data'; +import { withDispatch } from '@wordpress/data'; import { withFocusOutside } from '@wordpress/components'; import { withInstanceId, compose } from '@wordpress/compose';