@attivio/suit
Version:
Attivio SUIT, the Search UI Toolkit, is a library for creating search clients for searching the Attivio platform.
392 lines (353 loc) • 12.5 kB
JavaScript
var _class, _temp;
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
import React from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import Dropdown from 'react-bootstrap/lib/Dropdown';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import MenuItem from 'react-bootstrap/lib/MenuItem';
import Configurable from './Configurable';
import AutoCompleteInput from './AutoCompleteInput';
import SignalData from '../api/SignalData';
import AuthUtils from '../util/AuthUtils';
import Signals from '../api/Signals'; // Prevent complaints about this not existing
/**
* Component to include in the Masthead for entering the query
* to use when searching. Must be inside a Searcher component.
*/
var SearchBar = (_temp = _class = function (_React$Component) {
_inherits(SearchBar, _React$Component);
function SearchBar(props) {
_classCallCheck(this, SearchBar);
var _this = _possibleConstructorReturn(this, _React$Component.call(this, props));
_this.state = {
query: '',
recognizing: false,
suggestions: []
};
_this.doKeyPress = _this.doKeyPress.bind(_this);
_this.doSearch = _this.doSearch.bind(_this);
_this.startSpeechRecognition = _this.startSpeechRecognition.bind(_this);
_this.queryChanged = _this.queryChanged.bind(_this);
_this.updateQuery = _this.updateQuery.bind(_this);
_this.languageChanged = _this.languageChanged.bind(_this);
_this.addSignal = _this.addSignal.bind(_this);
if (_this.props.allowVoice && !('webkitSpeechRecognition' in window)) {
console.log('Requested speech recognition but the browser doesn’t support it'); // eslint-disable-line no-console
}
return _this;
}
SearchBar.prototype.getSuggestionList = function getSuggestionList() {
if (!this.state.suggestions || this.state.suggestions.length === 0) {
return null;
}
var contents = this.state.suggestions.map(function (suggestion) {
return React.createElement(
MenuItem,
{ key: suggestion },
suggestion
);
});
return React.createElement(
'ul',
{ className: 'list-unstyled', role: 'menu' },
contents
);
};
SearchBar.prototype.startSpeechRecognition = function startSpeechRecognition() {
var _this2 = this;
var recognition = new webkitSpeechRecognition(); // eslint-disable-line new-cap,no-undef
recognition.continuous = true;
recognition.interrimResults = true;
// recognition.lang = 'en';
recognition.onresult = function (e) {
recognition.stop();
var newQuery = e.results[0][0].transcript;
if (e.results[0].isFinal) {
var searcher = _this2.context.searcher;
if (searcher) {
searcher.setQueryAndSearch(newQuery);
}
}
_this2.setState({
recognizing: false
});
};
recognition.onerror = function () {
recognition.stop();
_this2.setState({
recognizing: false
});
};
recognition.start();
this.setState({
recognizing: true
});
};
SearchBar.prototype.languageChanged = function languageChanged(newLanguage) {
var searcher = this.context.searcher;
if (searcher && newLanguage) {
searcher.updateQueryLanguage(newLanguage);
}
};
SearchBar.prototype.addSignal = function addSignal(query, signalData) {
var signalType = this.props.createAutoCompleteSignal;
var savedUser = AuthUtils.getSavedUser();
if (!signalType || !savedUser) {
return;
}
var signal = signalData.clone();
signal.docId = query;
signal.featureVector = '';
signal.locale = 'en';
signal.principal = AuthUtils.config.ALL.defaultRealm + ':' + savedUser.fullName + ':' + savedUser.userId;
signal.relevancyModelName = 'default';
signal.relevancyModelNames = ['default'];
signal.relevancyModelVersion = 1;
signal.signalTimestamp = Date.now();
signal.type = 'autocomplete';
signal.weight = 1;
new Signals(this.props.baseUri).addRawSignal(signal);
};
SearchBar.prototype.updateQuery = function updateQuery(newQuery) {
var doSearch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var signalData = arguments[2];
// Update the searcher
var searcher = this.context.searcher;
if (signalData) {
this.addSignal(newQuery, signalData);
}
if (searcher) {
if (doSearch) {
if (!searcher.state.haveSearched) {
// on click of Enter, if a new query is being searched
// reset filters & display results
searcher.setQueryAndSearch(newQuery);
this.route();
} else {
// do not reset only search
searcher.doSearch();
}
} else {
searcher.updateQuery(newQuery);
}
}
this.forceUpdate();
};
SearchBar.prototype.queryChanged = function queryChanged(e) {
if (e.target instanceof HTMLInputElement) {
var newQuery = e.target.value;
this.updateQuery(newQuery);
}
};
SearchBar.prototype.route = function route() {
var searcher = this.context.searcher;
if (this.props.route && searcher) {
// We need to do this to ensure the Searcher's state survives the navigation
var searchString = searcher.generateLocationQueryStringFromState(searcher.state);
this.props.history.push({
pathname: this.props.route,
search: searchString
});
}
};
SearchBar.prototype.doSearch = function doSearch() {
var searcher = this.context.searcher;
if (this.props.route && searcher) {
this.route();
} else if (searcher.state.query && !searcher.state.haveSearched) {
// on click of Go, if a new query is being searched
// reset filters & display results
searcher.setQueryAndSearch(searcher.state.query);
} else if (searcher.state.query && searcher.state.haveSearched) {
// do not reset only search
searcher.doSearch();
}
if (this.submitButton) {
this.submitButton.blur();
}
};
SearchBar.prototype.doKeyPress = function doKeyPress(e) {
// If the user presses enter, do the search
if (e.target instanceof HTMLInputElement) {
if (e.keyCode === 13) {
this.doSearch();
}
}
};
SearchBar.prototype.render = function render() {
var _this3 = this;
var showMicrophone = this.props.allowVoice && 'webkitSpeechRecognition' in window;
var micStyle = {};
if (this.state.recognizing) {
micStyle.backgroundSize = '125%';
}
var containerClass = this.props.inMasthead ? 'attivio-globalmast-search-container' : '';
var inputClass = this.props.inMasthead ? 'form-control attivio-globalmast-search-input' : 'form-control';
var query = '';
var language = 'simple';
var searcher = this.context.searcher;
if (searcher) {
query = searcher.state.query;
language = searcher.state.queryLanguage;
}
var simpleMenuItem = React.createElement(
MenuItem,
{
onSelect: function onSelect() {
_this3.languageChanged('simple');
if (_this3.simpleMenuItem) {
_this3.simpleMenuItem.blur();
}
}
},
React.createElement(
'span',
{ ref: function ref(c) {
_this3.simpleMenuItem = c;
} },
React.createElement(
'span',
{ style: { visibility: language === 'simple' ? 'visible' : 'hidden' } },
'\u2713'
),
' ',
'Simple'
)
);
var advancedMenuItem = React.createElement(
MenuItem,
{
onSelect: function onSelect() {
_this3.languageChanged('advanced');
if (_this3.advancedMenuItem) {
_this3.advancedMenuItem.blur();
}
}
},
React.createElement(
'span',
{ ref: function ref(c) {
_this3.advancedMenuItem = c;
} },
React.createElement(
'span',
{ style: { visibility: language === 'advanced' ? 'visible' : 'hidden' } },
'\u2713'
),
' ',
'Advanced'
)
);
var languageControl = this.props.allowLanguageSelect ? React.createElement(
Dropdown,
{
id: 'myDropdown',
className: '',
onSelect: this.languageChanged,
componentClass: 'div',
style: { display: 'inline-block' }
},
React.createElement(
Dropdown.Toggle,
{
noCaret: true,
useAnchor: true,
className: 'attivio-smalltoolbar-btn',
bsClass: 'attivio-smalltoolbar-btn',
title: 'Query Language',
style: {
position: 'relative',
top: '1px',
left: '-2px',
color: '#fff',
border: 'none',
background: 'transparent'
}
},
React.createElement(Glyphicon, { glyph: 'search', style: { color: 'white' } }),
' ',
React.createElement('span', { className: 'attivio-globalmast-icon attivio-icon-arrow-down-blue' })
),
React.createElement(
Dropdown.Menu,
{
style: {
paddingTop: 0,
paddingBottom: 0
}
},
simpleMenuItem,
advancedMenuItem
)
) : '';
var placeholder = this.props.placeholder;
if (this.props.allowLanguageSelect && language === 'advanced') {
placeholder = this.props.placeholderAdvanced;
}
var suggestionList = this.getSuggestionList();
var inputComponent = this.props.autoCompleteUri ? React.createElement(AutoCompleteInput, {
uri: '' + this.props.baseUri + this.props.autoCompleteUri,
updateValue: this.updateQuery,
placeholder: placeholder || '',
value: query,
className: inputClass
}) : React.createElement('input', {
type: 'search',
className: inputClass,
placeholder: placeholder,
onChange: this.queryChanged,
onKeyDown: this.doKeyPress,
value: query
});
return React.createElement(
'div',
{ className: containerClass },
React.createElement(
'div',
{ className: 'attivio-globalmast-search', role: 'search' },
React.createElement(
'div',
{ className: 'form-group' },
inputComponent,
showMicrophone ? React.createElement(
'a',
{ onClick: this.startSpeechRecognition, role: 'button', tabIndex: 0 },
React.createElement('span', { className: 'attivio-globalmast-search-mic-icon attivio-icon-microphone', style: micStyle })
) : '',
React.createElement(
'button',
{
type: 'submit',
className: 'btn attivio-globalmast-search-submit',
onClick: this.doSearch,
ref: function ref(c) {
_this3.submitButton = c;
}
},
this.props.buttonLabel
)
),
suggestionList
),
languageControl
);
};
return SearchBar;
}(React.Component), _class.defaultProps = {
inMasthead: false,
placeholder: 'Search\u2026',
placeholderAdvanced: 'Enter an advanced query\u2026',
buttonLabel: 'Go',
allowLanguageSelect: true,
allowVoice: false,
autoCompleteUri: null,
route: null,
baseUri: '',
createAutoCompleteSignal: false
}, _class.contextTypes = {
searcher: PropTypes.any
}, _class.displayName = 'SearchBar', _class.AUTOCOMPLETE_THRESHOLD = 2, _temp);
export default withRouter(Configurable(SearchBar));