Skip to content
Snippets Groups Projects
Select Git revision
  • 8206decae6bf0ea99525067b5944dec1e96fbd8c
  • mui5-annotation-on-video-stable default
  • get_setter_canvasSizeInformations
  • fix-error-div-into-p
  • annotation-on-video-v2
  • detached
  • annotation-on-video-r17
  • mui5
  • mui5-react-18
  • jacob-test
  • annotation-on-video protected
  • master
  • test-antoinev1
  • 20-fetch-thumbnail-on-annotation
  • add-research-field
  • Save
  • add-plugin
  • 14-wip-no-seek-to
  • 14-bug-on-video-time-control
  • 9_wip_videotests
  • _upgrade_material_ui
  • latest-tetras-16
  • v3.3.0
  • v3.2.0
  • v3.1.1
  • v3.1.0
  • v3.0.0
  • v3.0.0-rc.7
  • v3.0.0-rc.6
  • v3.0.0-rc.5
  • v3.0.0-rc.4
  • v3.0.0-rc.3
  • v3.0.0-rc.2
  • v3.0.0-rc.1
  • v3.0.0-beta.10
  • v3.0.0-beta.9
  • v3.0.0-beta.8
  • v3.0.0-beta.7
  • v3.0.0-beta.6
  • v3.0.0-beta.5
  • v3.0.0-beta.3
41 results

SearchPanelControls.js

  • SearchPanelControls.js 4.97 KiB
    import React, { Component } from 'react';
    import PropTypes from 'prop-types';
    import deburr from 'lodash/deburr';
    import debounce from 'lodash/debounce';
    import Autocomplete from '@material-ui/lab/Autocomplete';
    import CircularProgress from '@material-ui/core/CircularProgress';
    import TextField from '@material-ui/core/TextField';
    import SearchIcon from '@material-ui/icons/SearchSharp';
    import MiradorMenuButton from '../containers/MiradorMenuButton';
    import SearchPanelNavigation from '../containers/SearchPanelNavigation';
    
    /** */
    export class SearchPanelControls extends Component {
      /** */
      constructor(props) {
        super(props);
    
        this.state = { search: props.query, suggestions: [] };
        this.handleChange = this.handleChange.bind(this);
        this.submitSearch = this.submitSearch.bind(this);
        this.getSuggestions = this.getSuggestions.bind(this);
        this.selectItem = this.selectItem.bind(this);
        this.fetchAutocomplete = debounce(this.fetchAutocomplete.bind(this), 500);
        this.receiveAutocomplete = this.receiveAutocomplete.bind(this);
      }
    
      /**
       * Set the component's local search state
       * to blank when the query has been cleared
       */
      componentDidUpdate(prevProps) {
        const { query } = this.props;
        if (query !== prevProps.query) {
          // We are setting local state directly here ONLY when the query prop (from redux)
          // changed
          this.setState({ // eslint-disable-line react/no-did-update-set-state
            search: query,
          });
        }
      }
    
      /** */
      handleChange(event, value, reason) {
        this.setState({
          search: value,
          suggestions: [],
        });
    
        if (value) {
          this.fetchAutocomplete(value);
        }
      }
    
      /** */
      getSuggestions(value, { showEmpty = false } = {}) {
        const { suggestions } = this.state;
    
        const inputValue = deburr(value.trim()).toLowerCase();
        const inputLength = inputValue.length;
    
        return inputLength === 0 && !showEmpty
          ? []
          : suggestions;
      }
    
      /** */
      fetchAutocomplete(value) {
        const { autocompleteService } = this.props;
    
        if (!autocompleteService) return;
        if (!value) return;
    
        fetch(`${autocompleteService.id}?q=${value}`)
          .then(response => response.json())
          .then(this.receiveAutocomplete);
      }
    
      /** */
      receiveAutocomplete(json) {
        this.setState({ suggestions: json.terms });
      }
    
      /** */
      submitSearch(event) {
        const {
          companionWindowId, fetchSearch, searchService, windowId,
        } = this.props;
        const { search } = this.state;
        event && event.preventDefault();
        if (!search) return;
        fetchSearch(windowId, companionWindowId, `${searchService.id}?q=${search}`, search);
      }
    
      /** */
      selectItem(_event, selectedItem, _reason) {
        if (selectedItem && selectedItem.match) {
          this.setState({ search: selectedItem.match }, this.submitSearch);
        }
      }
    
      /** */
      render() {
        const {
          classes, companionWindowId, searchIsFetching, t, windowId,
        } = this.props;
    
        const { search, suggestions } = this.state;
        const id = `search-${companionWindowId}`;
        return (
          <>
            <form onSubmit={this.submitSearch} className={classes.form}>
              <Autocomplete
                id={id}
                inputValue={search}
                options={suggestions}
                getOptionLabel={option => option.match}
                getOptionSelected={(option, value) => (
                  deburr(option.match.trim()).toLowerCase()
                    === deburr(value.match.trim()).toLowerCase()
                )}
                noOptionsText=""
                onChange={this.selectItem}
                onInputChange={this.handleChange}
                renderInput={params => (
                  <TextField
                    {...params}
                    label={t('searchInputLabel')}
                    InputProps={{
                      ...params.InputProps,
                      endAdornment: (
                        <div className={classes.endAdornment}>
                          <MiradorMenuButton aria-label={t('searchSubmitAria')} type="submit">
                            <SearchIcon />
                          </MiradorMenuButton>
                          {Boolean(searchIsFetching) && (
                            <CircularProgress className={classes.searchProgress} size={50} />
                          )}
                        </div>
                      ),
                    }}
                  />
                )}
              />
            </form>
            <SearchPanelNavigation windowId={windowId} companionWindowId={companionWindowId} />
          </>
        );
      }
    }
    
    SearchPanelControls.propTypes = {
      autocompleteService: PropTypes.shape({
        id: PropTypes.string,
      }),
      classes: PropTypes.objectOf(PropTypes.string),
      companionWindowId: PropTypes.string.isRequired,
      fetchSearch: PropTypes.func.isRequired,
      query: PropTypes.string,
      searchIsFetching: PropTypes.bool.isRequired,
      searchService: PropTypes.shape({
        id: PropTypes.string,
      }).isRequired,
      t: PropTypes.func,
      windowId: PropTypes.string.isRequired,
    };
    
    SearchPanelControls.defaultProps = {
      autocompleteService: undefined,
      classes: {},
      query: '',
      t: key => key,
    };