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

feat: Focus title if title is empty #9608

Merged
merged 5 commits into from Sep 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 1 addition & 4 deletions docs/data/data-core-editor.md
Expand Up @@ -54,9 +54,6 @@ Whether unsaved values exist.
Returns true if there are no unsaved values for the current edit session and
if the currently edited post is new (has never been saved before).

Note: This selector is not currently used by the editor package, but is made
available as an assumed-useful selector for external integrations.

*Parameters*

* state: Global application state.
Expand Down Expand Up @@ -1414,4 +1411,4 @@ Returns an action object used in signalling that the editor settings have been u

*Parameters*

* settings: Updated settings
* settings: Updated settings
10 changes: 5 additions & 5 deletions packages/block-library/src/list/index.js
Expand Up @@ -244,12 +244,12 @@ export const settings = {
} );
} );

// this checks for languages that do not typically have square brackets on their keyboards
// Check for languages that do not have square brackets on their keyboards.
Copy link
Member Author

Choose a reason for hiding this comment

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

These changes are largely unrelated, but I forget why I found this file when working on this patch and just wanted to tidy things up. Sorry 😉

const lang = window.navigator.browserLanguage || window.navigator.language;
const keyboardHasSqBracket = ! /^(?:fr|nl|sv|ru|de|es|it)/.test( lang );
const keyboardHasSquareBracket = ! /^(?:fr|nl|sv|ru|de|es|it)/.test( lang );

if ( keyboardHasSqBracket ) {
// keycode 219 = '[' and keycode 221 = ']'
if ( keyboardHasSquareBracket ) {
// `[` is keycode 219; `]` is keycode 221.
editor.shortcuts.add( 'meta+219', 'Decrease indent', 'Outdent' );
editor.shortcuts.add( 'meta+221', 'Increase indent', 'Indent' );
} else {
Expand All @@ -265,7 +265,7 @@ export const settings = {
const { setAttributes } = this.props;
const { internalListType } = this.state;
if ( internalListType ) {
// only change list types, don't toggle off internal lists
// Only change list types, don't toggle off internal lists.
if ( internalListType !== type && this.editor ) {
this.editor.execCommand( command );
}
Expand Down
22 changes: 20 additions & 2 deletions packages/editor/src/components/post-title/index.js
Expand Up @@ -88,7 +88,15 @@ class PostTitle extends Component {
}

render() {
const { title, placeholder, instanceId, isPostTypeViewable, isFocusMode, hasFixedToolbar } = this.props;
const {
hasFixedToolbar,
isCleanNewPost,
isFocusMode,
isPostTypeViewable,
instanceId,
placeholder,
title,
} = this.props;
const { isSelected } = this.state;
const className = classnames( 'editor-post-title__block', {
'is-selected': isSelected,
Expand Down Expand Up @@ -119,6 +127,15 @@ class PostTitle extends Component {
onFocus={ this.onSelect }
onKeyDown={ this.onKeyDown }
onKeyPress={ this.onUnselect }
/*
Only autofocus the title when the post is entirely empty.
This should only happen for a new post, which means we
focus the title on new post so the author can start typing
right away, without needing to click anything.
*/
/* eslint-disable jsx-a11y/no-autofocus */
autoFocus={ isCleanNewPost }
/* eslint-enable jsx-a11y/no-autofocus */
/>
</KeyboardShortcuts>
{ isSelected && isPostTypeViewable && <PostPermalink /> }
Expand All @@ -130,12 +147,13 @@ class PostTitle extends Component {
}

const applyWithSelect = withSelect( ( select ) => {
const { getEditedPostAttribute, getEditorSettings } = select( 'core/editor' );
const { getEditedPostAttribute, getEditorSettings, isCleanNewPost } = select( 'core/editor' );
const { getPostType } = select( 'core' );
const postType = getPostType( getEditedPostAttribute( 'type' ) );
const { titlePlaceholder, focusMode, hasFixedToolbar } = getEditorSettings();

return {
isCleanNewPost: isCleanNewPost(),
title: getEditedPostAttribute( 'title' ),
isPostTypeViewable: get( postType, [ 'viewable' ], false ),
placeholder: titlePlaceholder,
Expand Down
3 changes: 0 additions & 3 deletions packages/editor/src/store/selectors.js
Expand Up @@ -102,9 +102,6 @@ export function isEditedPostDirty( state ) {
* Returns true if there are no unsaved values for the current edit session and
* if the currently edited post is new (has never been saved before).
*
* Note: This selector is not currently used by the editor package, but is made
* available as an assumed-useful selector for external integrations.
*
* @param {Object} state Global application state.
*
* @return {boolean} Whether new post and unsaved values exist.
Expand Down
31 changes: 0 additions & 31 deletions test/e2e/specs/hello.test.js

This file was deleted.

75 changes: 75 additions & 0 deletions test/e2e/specs/new-post.test.js
@@ -0,0 +1,75 @@
/**
* Internal dependencies
*/
import { newPost } from '../support/utils';

describe( 'new editor state', () => {
beforeAll( async () => {
await newPost();
} );

it( 'should show the New Post page in Gutenberg', async () => {
expect( page.url() ).toEqual( expect.stringContaining( 'post-new.php' ) );
// Should display the title.
const title = await page.$( '[placeholder="Add title"]' );
expect( title ).not.toBeNull();
// Should display the Preview button.
const postPreviewButton = await page.$( '.editor-post-preview.components-button' );
expect( postPreviewButton ).not.toBeNull();
// Should display the Post Formats UI.
const postFormatsUi = await page.$( '.editor-post-format' );
expect( postFormatsUi ).not.toBeNull();
} );

it( 'should have no history', async () => {
const undoButton = await page.$( '.editor-history__undo:not( :disabled )' );
const redoButton = await page.$( '.editor-history__redo:not( :disabled )' );

expect( undoButton ).toBeNull();
expect( redoButton ).toBeNull();
} );

it( 'should focus the title if the title is empty', async () => {
// We need to remove the tips to make sure they aren't clicked/removed
// during our check of the title `textarea`'s focus.
await page.evaluate( () => {
return wp.data.dispatch( 'core/nux' ).disableTips();
} );

// And then reload the page to ensure we get a new page that should
// autofocus the title, without any NUX tips.
await page.reload();

const activeElementClasses = await page.evaluate( () => {
return Object.values( document.activeElement.classList );
} );
const activeElementTagName = await page.evaluate( () => {
return document.activeElement.tagName.toLowerCase();
} );

expect( activeElementClasses ).toContain( 'editor-post-title__input' );
expect( activeElementTagName ).toEqual( 'textarea' );
} );

it( 'should not focus the title if the title exists', async () => {
// Enter a title for this post.
await page.type( '.editor-post-title__input', 'Here is the title' );
// Save the post as a draft.
await page.click( '.editor-post-save-draft' );
await page.waitForSelector( '.editor-post-saved-state.is-saved' );
// Reload the browser so a post is loaded with a title.
await page.reload();

const activeElementClasses = await page.evaluate( () => {
return Object.values( document.activeElement.classList );
} );
const activeElementTagName = await page.evaluate( () => {
return document.activeElement.tagName.toLowerCase();
} );

expect( activeElementClasses ).not.toContain( 'editor-post-title__input' );
// The document `body` should be the `activeElement`, because nothing is
// focused by default when a post already has a title.
expect( activeElementTagName ).toEqual( 'body' );
} );
} );