123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- import PropTypes from 'prop-types';
- import React, { Component } from 'react';
- import { connect } from 'react-redux';
-
- import { appendSuffix } from '../functions';
-
- import { translate } from '../../base/i18n';
- import { participantDisplayNameChanged } from '../../base/participants';
-
- /**
- * React {@code Component} for displaying and editing a participant's name.
- *
- * @extends Component
- */
- class DisplayName extends Component {
- /**
- * {@code DisplayName}'s property types.
- *
- * @static
- */
- static propTypes = {
- /**
- * Whether or not the display name should be editable on click.
- */
- allowEditing: PropTypes.bool,
-
- /**
- * Invoked to update the participant's display name.
- */
- dispatch: PropTypes.func,
-
- /**
- * The participant's current display name.
- */
- displayName: PropTypes.string,
-
- /**
- * A string to append to the displayName, if provided.
- */
- displayNameSuffix: PropTypes.string,
-
- /**
- * The ID attribute to add to the component. Useful for global querying
- * for the component by legacy components and torture tests.
- */
- elementID: PropTypes.string,
-
- /**
- * The ID of the participant whose name is being displayed.
- */
- participantID: PropTypes.string,
-
- /**
- * Invoked to obtain translated strings.
- */
- t: PropTypes.func
- };
-
- /**
- * Initializes a new {@code DisplayName} instance.
- *
- * @param {Object} props - The read-only properties with which the new
- * instance is to be initialized.
- */
- constructor(props) {
- super(props);
-
- this.state = {
- /**
- * The current value of the display name in the edit field.
- *
- * @type {string}
- */
- editDisplayNameValue: '',
-
- /**
- * Whether or not the component should be displaying an editable
- * input.
- *
- * @type {boolean}
- */
- isEditing: false
- };
-
- /**
- * The internal reference to the HTML element backing the React
- * {@code Component} input with id {@code editDisplayName}. It is
- * necessary for automatically selecting the display name input field
- * when starting to edit the display name.
- *
- * @private
- * @type {HTMLInputElement}
- */
- this._nameInput = null;
-
- // Bind event handlers so they are only bound once for every instance.
- this._onChange = this._onChange.bind(this);
- this._onKeyDown = this._onKeyDown.bind(this);
- this._onStartEditing = this._onStartEditing.bind(this);
- this._onSubmit = this._onSubmit.bind(this);
- this._setNameInputRef = this._setNameInputRef.bind(this);
- }
-
- /**
- * Automatically selects the input field's value after starting to edit the
- * display name.
- *
- * @inheritdoc
- * @returns {void}
- */
- componentDidUpdate(previousProps, previousState) {
- if (!previousState.isEditing && this.state.isEditing) {
- this._nameInput.select();
- }
- }
-
- /**
- * Implements React's {@link Component#render()}.
- *
- * @inheritdoc
- * @returns {ReactElement}
- */
- render() {
- const {
- allowEditing,
- displayName,
- displayNameSuffix,
- elementID,
- t
- } = this.props;
-
- if (allowEditing && this.state.isEditing) {
- return (
- <input
- autoFocus = { true }
- className = 'editdisplayname'
- id = 'editDisplayName'
- onBlur = { this._onSubmit }
- onChange = { this._onChange }
- onKeyDown = { this._onKeyDown }
- placeholder = { t('defaultNickname') }
- ref = { this._setNameInputRef }
- spellCheck = { 'false' }
- type = 'text'
- value = { this.state.editDisplayNameValue } />
- );
- }
-
- return (
- <span
- className = 'displayname'
- id = { elementID }
- onClick = { this._onStartEditing }>
- { `${appendSuffix(displayName, displayNameSuffix)}` }
- </span>
- );
- }
-
- /**
- * Updates the internal state of the display name entered into the edit
- * field.
- *
- * @param {Object} event - DOM Event for value change.
- * @private
- * @returns {void}
- */
- _onChange(event) {
- this.setState({
- editDisplayNameValue: event.target.value
- });
- }
-
- /**
- * Submits the editted display name update if the enter key is pressed.
- *
- * @param {Event} event - Key down event object.
- * @private
- * @returns {void}
- */
- _onKeyDown(event) {
- if (event.key === 'Enter') {
- this._onSubmit();
- }
- }
-
- /**
- * Updates the component to display an editable input field and sets the
- * initial value to the current display name.
- *
- * @private
- * @returns {void}
- */
- _onStartEditing() {
- if (this.props.allowEditing) {
- this.setState({
- isEditing: true,
- editDisplayNameValue: this.props.displayName || ''
- });
- }
- }
-
- /**
- * Dispatches an action to update the display name if any change has
- * occurred after editing. Clears any temporary state used to keep track
- * of pending display name changes and exits editing mode.
- *
- * @param {Event} event - Key down event object.
- * @private
- * @returns {void}
- */
- _onSubmit() {
- const { editDisplayNameValue } = this.state;
- const { dispatch, participantID } = this.props;
-
- dispatch(participantDisplayNameChanged(
- participantID, editDisplayNameValue));
-
- this.setState({
- isEditing: false,
- editDisplayNameValue: ''
- });
-
- this._nameInput = null;
- }
-
- /**
- * Sets the internal reference to the HTML element backing the React
- * {@code Component} input with id {@code editDisplayName}.
- *
- * @param {HTMLInputElement} element - The DOM/HTML element for this
- * {@code Component}'s input.
- * @private
- * @returns {void}
- */
- _setNameInputRef(element) {
- this._nameInput = element;
- }
- }
-
- export default translate(connect()(DisplayName));
|