diff options
17 files changed, 41 insertions, 24 deletions
diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/button-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/button-test.js.snap index 86fbba917..bfc091d45 100644 --- a/app/javascript/mastodon/components/__tests__/__snapshots__/button-test.js.snap +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/button-test.js.snap @@ -4,6 +4,7 @@ exports[`<Button /> adds class "button-secondary" if props.secondary given 1`] = <button className="button button-secondary" onClick={[Function]} + type="button" /> `; @@ -11,6 +12,7 @@ exports[`<Button /> renders a button element 1`] = ` <button className="button" onClick={[Function]} + type="button" /> `; @@ -19,6 +21,7 @@ exports[`<Button /> renders a disabled attribute if props.disabled given 1`] = ` className="button" disabled={true} onClick={[Function]} + type="button" /> `; @@ -26,6 +29,7 @@ exports[`<Button /> renders class="button--block" if props.block given 1`] = ` <button className="button button--block" onClick={[Function]} + type="button" /> `; @@ -33,6 +37,7 @@ exports[`<Button /> renders the children 1`] = ` <button className="button" onClick={[Function]} + type="button" > <p> children @@ -44,6 +49,7 @@ exports[`<Button /> renders the given text 1`] = ` <button className="button" onClick={[Function]} + type="button" > foo </button> @@ -53,6 +59,7 @@ exports[`<Button /> renders the props.text instead of children 1`] = ` <button className="button" onClick={[Function]} + type="button" > foo </button> diff --git a/app/javascript/mastodon/components/button.js b/app/javascript/mastodon/components/button.js index bcb855c7c..42ce01f38 100644 --- a/app/javascript/mastodon/components/button.js +++ b/app/javascript/mastodon/components/button.js @@ -16,8 +16,12 @@ export default class Button extends React.PureComponent { children: PropTypes.node, }; + static defaultProps = { + type: 'button', + }; + handleClick = (e) => { - if (!this.props.disabled) { + if (!this.props.disabled && this.props.onClick) { this.props.onClick(e); } } diff --git a/app/javascript/mastodon/components/icon_button.js b/app/javascript/mastodon/components/icon_button.js index 47945c475..8fd9e10c0 100644 --- a/app/javascript/mastodon/components/icon_button.js +++ b/app/javascript/mastodon/components/icon_button.js @@ -141,6 +141,7 @@ export default class IconButton extends React.PureComponent { return ( <button + type='button' aria-label={title} aria-pressed={pressed} aria-expanded={expanded} diff --git a/app/javascript/mastodon/components/load_more.js b/app/javascript/mastodon/components/load_more.js index 389c3e1e1..00e023ca2 100644 --- a/app/javascript/mastodon/components/load_more.js +++ b/app/javascript/mastodon/components/load_more.js @@ -18,7 +18,7 @@ export default class LoadMore extends React.PureComponent { const { disabled, visible } = this.props; return ( - <button className='load-more' disabled={disabled || !visible} style={{ visibility: visible ? 'visible' : 'hidden' }} onClick={this.props.onClick}> + <button type='button' className='load-more' disabled={disabled || !visible} style={{ visibility: visible ? 'visible' : 'hidden' }} onClick={this.props.onClick}> <FormattedMessage id='status.load_more' defaultMessage='Load more' /> </button> ); diff --git a/app/javascript/mastodon/features/compose/components/compose_form.js b/app/javascript/mastodon/features/compose/components/compose_form.js index 9f5c3b314..6a65f44da 100644 --- a/app/javascript/mastodon/features/compose/components/compose_form.js +++ b/app/javascript/mastodon/features/compose/components/compose_form.js @@ -93,7 +93,7 @@ class ComposeForm extends ImmutablePureComponent { return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 500 || (isOnlyWhitespace && !anyMedia)); } - handleSubmit = () => { + handleSubmit = (e) => { if (this.props.text !== this.autosuggestTextarea.textarea.value) { // Something changed the text inside the textarea (e.g. browser extensions like Grammarly) // Update the state to match the current text @@ -105,6 +105,10 @@ class ComposeForm extends ImmutablePureComponent { } this.props.onSubmit(this.context.router ? this.context.router.history : null); + + if (e) { + e.preventDefault(); + } } onSuggestionsClearRequested = () => { @@ -217,7 +221,7 @@ class ComposeForm extends ImmutablePureComponent { } return ( - <form className='compose-form'> + <form className='compose-form' onSubmit={this.handleSubmit}> <WarningContainer /> <ReplyIndicatorContainer /> @@ -280,9 +284,8 @@ class ComposeForm extends ImmutablePureComponent { <div className='compose-form__publish'> <div className='compose-form__publish-button-wrapper'> <Button - type="submit" + type='submit' text={publishText} - onClick={this.handleSubmit} disabled={!this.canSubmit()} block /> diff --git a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js index f433e4de9..8cca8af2a 100644 --- a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js +++ b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.js @@ -96,12 +96,12 @@ class ModifierPickerMenu extends React.PureComponent { return ( <div className='emoji-picker-dropdown__modifiers__menu' style={{ display: active ? 'block' : 'none' }} ref={this.setRef}> - <button onClick={this.handleClick} data-index={1}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={1} backgroundImageFn={backgroundImageFn} /></button> - <button onClick={this.handleClick} data-index={2}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={2} backgroundImageFn={backgroundImageFn} /></button> - <button onClick={this.handleClick} data-index={3}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={3} backgroundImageFn={backgroundImageFn} /></button> - <button onClick={this.handleClick} data-index={4}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={4} backgroundImageFn={backgroundImageFn} /></button> - <button onClick={this.handleClick} data-index={5}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={5} backgroundImageFn={backgroundImageFn} /></button> - <button onClick={this.handleClick} data-index={6}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={6} backgroundImageFn={backgroundImageFn} /></button> + <button type='button' onClick={this.handleClick} data-index={1}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={1} backgroundImageFn={backgroundImageFn} /></button> + <button type='button' onClick={this.handleClick} data-index={2}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={2} backgroundImageFn={backgroundImageFn} /></button> + <button type='button' onClick={this.handleClick} data-index={3}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={3} backgroundImageFn={backgroundImageFn} /></button> + <button type='button' onClick={this.handleClick} data-index={4}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={4} backgroundImageFn={backgroundImageFn} /></button> + <button type='button' onClick={this.handleClick} data-index={5}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={5} backgroundImageFn={backgroundImageFn} /></button> + <button type='button' onClick={this.handleClick} data-index={6}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={6} backgroundImageFn={backgroundImageFn} /></button> </div> ); } diff --git a/app/javascript/mastodon/features/compose/components/language_dropdown.js b/app/javascript/mastodon/features/compose/components/language_dropdown.js index 0af3db7a4..e48fa60ff 100644 --- a/app/javascript/mastodon/features/compose/components/language_dropdown.js +++ b/app/javascript/mastodon/features/compose/components/language_dropdown.js @@ -227,7 +227,7 @@ class LanguageDropdownMenu extends React.PureComponent { <div className={`language-dropdown__dropdown ${placement}`} style={{ ...style, opacity: opacity, transform: mounted ? `scale(${scaleX}, ${scaleY})` : null }} ref={this.setRef}> <div className='emoji-mart-search'> <input type='search' value={searchValue} onChange={this.handleSearchChange} onKeyDown={this.handleSearchKeyDown} placeholder={intl.formatMessage(messages.search)} autoFocus /> - <button className='emoji-mart-search-icon' disabled={!isSearching} aria-label={intl.formatMessage(messages.clear)} onClick={this.handleClear}>{!isSearching ? loupeIcon : deleteIcon}</button> + <button type='button' className='emoji-mart-search-icon' disabled={!isSearching} aria-label={intl.formatMessage(messages.clear)} onClick={this.handleClear}>{!isSearching ? loupeIcon : deleteIcon}</button> </div> <div className='language-dropdown__dropdown__results emoji-mart-scroll' role='listbox' ref={this.setListRef}> diff --git a/app/javascript/mastodon/features/compose/components/poll_form.js b/app/javascript/mastodon/features/compose/components/poll_form.js index db49f90eb..ede29b8a0 100644 --- a/app/javascript/mastodon/features/compose/components/poll_form.js +++ b/app/javascript/mastodon/features/compose/components/poll_form.js @@ -157,7 +157,7 @@ class PollForm extends ImmutablePureComponent { </ul> <div className='poll__footer'> - <button disabled={options.size >= 4} className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button> + <button type='button' disabled={options.size >= 4} className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button> {/* eslint-disable-next-line jsx-a11y/no-onchange */} <select value={expiresIn} onChange={this.handleSelectDuration}> diff --git a/app/javascript/mastodon/features/compose/components/text_icon_button.js b/app/javascript/mastodon/features/compose/components/text_icon_button.js index cd644b680..73da32ad5 100644 --- a/app/javascript/mastodon/features/compose/components/text_icon_button.js +++ b/app/javascript/mastodon/features/compose/components/text_icon_button.js @@ -22,6 +22,7 @@ export default class TextIconButton extends React.PureComponent { return ( <button + type='button' title={title} aria-label={title} className={`text-icon-button ${active ? 'active' : ''}`} diff --git a/app/javascript/mastodon/features/compose/components/upload.js b/app/javascript/mastodon/features/compose/components/upload.js index 706824dc7..44bf9a24a 100644 --- a/app/javascript/mastodon/features/compose/components/upload.js +++ b/app/javascript/mastodon/features/compose/components/upload.js @@ -43,13 +43,13 @@ export default class Upload extends ImmutablePureComponent { {({ scale }) => ( <div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}> <div className='compose-form__upload__actions'> - <button className='icon-button' onClick={this.handleUndoClick}><Icon id='times' /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button> - {!isEditingStatus && (<button className='icon-button' onClick={this.handleFocalPointClick}><Icon id='pencil' /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button>)} + <button type='button' className='icon-button' onClick={this.handleUndoClick}><Icon id='times' /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button> + {!isEditingStatus && (<button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon id='pencil' /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button>)} </div> {(media.get('description') || '').length === 0 && ( <div className='compose-form__upload__warning'> - <button className='icon-button' onClick={this.handleFocalPointClick}><Icon id='info-circle' /> <FormattedMessage id='upload_form.description_missing' defaultMessage='No description added' /></button> + <button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon id='info-circle' /> <FormattedMessage id='upload_form.description_missing' defaultMessage='No description added' /></button> </div> )} </div> diff --git a/app/javascript/mastodon/features/favourites/index.js b/app/javascript/mastodon/features/favourites/index.js index ad10744da..66ec6a31b 100644 --- a/app/javascript/mastodon/features/favourites/index.js +++ b/app/javascript/mastodon/features/favourites/index.js @@ -68,7 +68,7 @@ class Favourites extends ImmutablePureComponent { showBackButton multiColumn={multiColumn} extraButton={( - <button className='column-header__button' title={intl.formatMessage(messages.refresh)} aria-label={intl.formatMessage(messages.refresh)} onClick={this.handleRefresh}><Icon id='refresh' /></button> + <button type='button' className='column-header__button' title={intl.formatMessage(messages.refresh)} aria-label={intl.formatMessage(messages.refresh)} onClick={this.handleRefresh}><Icon id='refresh' /></button> )} /> diff --git a/app/javascript/mastodon/features/filters/select_filter.js b/app/javascript/mastodon/features/filters/select_filter.js index b5b354529..b68a5de6c 100644 --- a/app/javascript/mastodon/features/filters/select_filter.js +++ b/app/javascript/mastodon/features/filters/select_filter.js @@ -177,7 +177,7 @@ class SelectFilter extends React.PureComponent { <div className='emoji-mart-search'> <input type='search' value={searchValue} onChange={this.handleSearchChange} onKeyDown={this.handleSearchKeyDown} placeholder={intl.formatMessage(messages.search)} autoFocus /> - <button className='emoji-mart-search-icon' disabled={!isSearching} aria-label={intl.formatMessage(messages.clear)} onClick={this.handleClear}>{!isSearching ? loupeIcon : deleteIcon}</button> + <button type='button' className='emoji-mart-search-icon' disabled={!isSearching} aria-label={intl.formatMessage(messages.clear)} onClick={this.handleClear}>{!isSearching ? loupeIcon : deleteIcon}</button> </div> <div className='language-dropdown__dropdown__results emoji-mart-scroll' role='listbox' ref={this.setListRef}> diff --git a/app/javascript/mastodon/features/home_timeline/index.js b/app/javascript/mastodon/features/home_timeline/index.js index 838ed7dd8..749a47e76 100644 --- a/app/javascript/mastodon/features/home_timeline/index.js +++ b/app/javascript/mastodon/features/home_timeline/index.js @@ -126,6 +126,7 @@ class HomeTimeline extends React.PureComponent { if (hasAnnouncements) { announcementsButton = ( <button + type='button' className={classNames('column-header__button', { 'active': showAnnouncements })} title={intl.formatMessage(showAnnouncements ? messages.hide_announcements : messages.show_announcements)} aria-label={intl.formatMessage(showAnnouncements ? messages.hide_announcements : messages.show_announcements)} diff --git a/app/javascript/mastodon/features/list_timeline/index.js b/app/javascript/mastodon/features/list_timeline/index.js index fd9d33df7..f1829d34d 100644 --- a/app/javascript/mastodon/features/list_timeline/index.js +++ b/app/javascript/mastodon/features/list_timeline/index.js @@ -178,11 +178,11 @@ class ListTimeline extends React.PureComponent { multiColumn={multiColumn} > <div className='column-settings__row column-header__links'> - <button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleEditClick}> + <button type='button' className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleEditClick}> <Icon id='pencil' /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' /> </button> - <button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleDeleteClick}> + <button type='button' className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleDeleteClick}> <Icon id='trash' /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' /> </button> </div> diff --git a/app/javascript/mastodon/features/reblogs/index.js b/app/javascript/mastodon/features/reblogs/index.js index 70d338ef1..36ca11d1a 100644 --- a/app/javascript/mastodon/features/reblogs/index.js +++ b/app/javascript/mastodon/features/reblogs/index.js @@ -68,7 +68,7 @@ class Reblogs extends ImmutablePureComponent { showBackButton multiColumn={multiColumn} extraButton={( - <button className='column-header__button' title={intl.formatMessage(messages.refresh)} aria-label={intl.formatMessage(messages.refresh)} onClick={this.handleRefresh}><Icon id='refresh' /></button> + <button type='button' className='column-header__button' title={intl.formatMessage(messages.refresh)} aria-label={intl.formatMessage(messages.refresh)} onClick={this.handleRefresh}><Icon id='refresh' /></button> )} /> diff --git a/app/javascript/mastodon/features/status/components/card.js b/app/javascript/mastodon/features/status/components/card.js index 3d81bcb29..82537dd5d 100644 --- a/app/javascript/mastodon/features/status/components/card.js +++ b/app/javascript/mastodon/features/status/components/card.js @@ -247,7 +247,7 @@ export default class Card extends React.PureComponent { {revealed && ( <div className='status-card__actions'> <div> - <button onClick={this.handleEmbedClick}><Icon id={iconVariant} /></button> + <button type='button' onClick={this.handleEmbedClick}><Icon id={iconVariant} /></button> {horizontal && <a href={card.get('url')} target='_blank' rel='noopener noreferrer'><Icon id='external-link' /></a>} </div> </div> diff --git a/app/javascript/mastodon/features/status/index.js b/app/javascript/mastodon/features/status/index.js index 02f390c6a..c0ba1f2d6 100644 --- a/app/javascript/mastodon/features/status/index.js +++ b/app/javascript/mastodon/features/status/index.js @@ -619,7 +619,7 @@ class Status extends ImmutablePureComponent { showBackButton multiColumn={multiColumn} extraButton={( - <button className='column-header__button' title={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll} aria-pressed={status.get('hidden') ? 'false' : 'true'}><Icon id={status.get('hidden') ? 'eye-slash' : 'eye'} /></button> + <button type='button' className='column-header__button' title={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} aria-label={intl.formatMessage(status.get('hidden') ? messages.revealAll : messages.hideAll)} onClick={this.handleToggleAll} aria-pressed={status.get('hidden') ? 'false' : 'true'}><Icon id={status.get('hidden') ? 'eye-slash' : 'eye'} /></button> )} /> |