UNPKG

labo-components

Version:
242 lines (211 loc) 7.96 kB
import React from 'react'; import PropTypes from 'prop-types'; import debounce from 'debounce'; import IDUtil from '../../util/IDUtil'; // for generating unique CSS classnames for this component import SessionStorageHandler from '../../util/SessionStorageHandler'; import { ResourceViewerContext } from './ResourceViewerContext'; import ASR from './contentAnnotationsColumn/ASR'; import Segments from './contentAnnotationsColumn/Segments'; import Info from '../shared/Info'; import _Strings from './_Strings'; // Types const TYPE_ASR = 'ASR'; const TYPE_SEGMENT = 'Segments'; const TYPE_SUBTITLES = 'Subtitles'; // Views export const VIEW_LIST = 'List'; export const VIEW_WORDCLOUD = 'Word cloud'; const VIEWS = [VIEW_LIST, VIEW_WORDCLOUD]; // Other const SESSION_SEARCH_TERM = 'bg__content-annotations-search-term'; export default class ContentAnnotationsColumn extends React.Component { static contextType = ResourceViewerContext; constructor(props) { super(props); // get last searchterm from sessionStorage const searchTerm = SessionStorageHandler.get(SESSION_SEARCH_TERM, ''); this.state = { type: '', view: VIEWS[0], searchTerm }; this.searchInputRef = React.createRef(); this.debounceOnSearch = debounce(this.changeSearch, 200); } componentDidMount() { this.checkCurrentType(); // Fill search term with query.term, if there is no user defined searchTerm set in if ( !this.state.searchTerm && this.context.query && this.context.query.term ) { this.setState({ searchTerm: this.context.query.term }); } } componentDidUpdate() { this.checkCurrentType(); } // check if the current type is available on the resource/mediaobject // if not: change it checkCurrentType() { const types = this.getAvailableTypes(); if (types.length > 0 && !types.includes(this.state.type)) { this.setState({ type: types.length > 0 ? types[0] : '' }); } } getActiveContent(type, view, searchTerm) { const activeTranscript = this.context.getActiveTranscript(type, true);//fetch them by title switch (type) { case TYPE_SEGMENT: return ( <Segments view={view} searchTerm={searchTerm} activeMediaObject={this.context.activeMediaObject} mediaEvents={this.context.mediaEvents} /> ); case TYPE_SUBTITLES: return ( <div> TODO: implement subtitles. Use ASR.jsx as example. </div> ); default: //otherwise return the selected transcript type return activeTranscript ? ( <ASR view={view} searchTerm={searchTerm} resource={this.context.resource} activeMediaObject={this.context.activeMediaObject} mediaEvents={this.context.mediaEvents} transcript={activeTranscript} //could be different types of transcripts (ASR, Voting, Agenda Points...) /> ) : null; } } changeType = e => { this.setState({ type: e.target.value }); }; changeView = e => { this.setState({ view: e.target.value }); }; changeSearch = () => { // use the ref so we use this as debounced function this.setSearchTerm(this.searchInputRef.current.value); }; clearSearch = () => { // manually empty the input value as it is only assigned with attr:defaultValue this.searchInputRef.current.value = ''; this.setSearchTerm(''); }; setSearchTerm = searchTerm => { // update state this.setState({ searchTerm }); // store searchTerm to session SessionStorageHandler.set(SESSION_SEARCH_TERM, searchTerm); }; // Return types available in current context //FIXME this should not be done here, but in the collectionConfig!! getAvailableTypes = () => { const types = []; // Segments if ( this.context.activeMediaObject && this.context.activeMediaObject.segments ) { types.push(TYPE_SEGMENT); } // Subtitles // TODO: which field? if (false) { types.push(TYPE_SUBTITLES); } //loop through the transcripts of the resource and add them as types const transcripts = this.context.getActiveTranscripts(); if(transcripts) { transcripts.forEach(transcript => { types.push(transcript.title); }); } return types; }; render() { const activeContent = this.getActiveContent(this.state.type, this.state.view, this.state.searchTerm); // Types const types = this.getAvailableTypes(); // No types available? Render a notification if (types.length === 0) { return ( <div className={IDUtil.cssClassName( 'content-annotations-column' )} > <div className="error-message"> No content annotations available <Info className="primary" id={'info_content_annotations'} text={ 'There are no content annotations available on the selected resource or the active media object' } /> </div> </div> ); } const typeSelector = ( <select value={this.state.type} onChange={this.changeType}> {types.map(type => ( <option value={type} key={type}> {type} </option> ))} </select> ); // Views const viewSelector = ( <select value={this.state.view} onChange={this.changeView}> {VIEWS.map(type => ( <option value={type} key={type}> {type} </option> ))} </select> ); return ( <div className={IDUtil.cssClassName('content-annotations-column')}> <div className="type-selector"> <strong>Type:</strong> {typeSelector} <Info className="primary" id={'info_content_annotations'} text={_Strings.CONTENT_ANNOTATIONS_TYPE_HELP} /> </div> <div className="filter"> <strong>View:</strong> {viewSelector} <input placeholder="Search..." defaultValue={this.state.searchTerm} onChange={this.debounceOnSearch} onKeyUp={this.debounceOnSearch} // required to register empty field? :S ref={this.searchInputRef} /> {this.state.searchTerm && ( <div className="clear" title="Clear search" onClick={this.clearSearch} /> )} </div> {activeContent} </div> ); } }