Fix compose form submission reloading web interface (#19762)
* Fix compose form submission reloading web interface Fix regression introduced by #19742 * Fix various compose form buttons being handled like submit buttons * Fix coding style issue * Fix missing onClick prop check
This commit is contained in:
		
							parent
							
								
									1e7ea50f4c
								
							
						
					
					
						commit
						9616f5bb22
					
				
					 17 changed files with 41 additions and 24 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
            />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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}>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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}>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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' : ''}`}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
          )}
 | 
			
		||||
        />
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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}>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
          )}
 | 
			
		||||
        />
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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>
 | 
			
		||||
          )}
 | 
			
		||||
        />
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Reference in a new issue