UNPKG

terriajs

Version:

Geospatial data visualization platform.

238 lines (220 loc) 8.04 kB
import React from "react"; import { removeMarker } from "../../Models/LocationMarkerUtils"; import { reaction, runInAction } from "mobx"; import { Trans } from "react-i18next"; import PropTypes from "prop-types"; import { observer } from "mobx-react"; import styled from "styled-components"; // import { ThemeContext } from "styled-components"; import SearchBox from "../Search/SearchBox"; // import SidebarSearch from "../Search/SidebarSearch"; import LocationSearchResults from "../Search/LocationSearchResults"; import Icon, { StyledIcon } from "../../Styled/Icon"; import Box from "../../Styled/Box"; import Text from "../../Styled/Text"; import Spacing from "../../Styled/Spacing"; import { RawButton } from "../../Styled/Button"; import { addMarker } from "../../Models/LocationMarkerUtils"; export function SearchInDataCatalog({ viewState, handleClick }) { const locationSearchText = viewState.searchState.locationSearchText; return ( <RawButton fullWidth onClick={() => { const { searchState } = viewState; // Set text here as a separate action so that it doesn't get batched up and the catalog // search text has a chance to set isWaitingToStartCatalogSearch searchState.setCatalogSearchText(searchState.locationSearchText); viewState.searchInCatalog(searchState.locationSearchText); handleClick && handleClick(); }} > <Box paddedRatio={2} rounded charcoalGreyBg> <StyledIcon styledWidth={"14px"} glyph={Icon.GLYPHS["dataCatalog"]} /> <Spacing right={2} /> <Text textAlignLeft textLight large fullWidth> <Trans i18nKey="search.searchInDataCatalog" values={{ locationSearchText }} > Search <strong>{locationSearchText}</strong> in the Data Catalogue </Trans> </Text> <StyledIcon glyph={Icon.GLYPHS.right2} styledWidth={"14px"} light /> </Box> </RawButton> ); } SearchInDataCatalog.propTypes = { handleClick: PropTypes.func.isRequired, viewState: PropTypes.object.isRequired }; const PresentationBox = styled(Box).attrs({ fullWidth: true })` ${(props) => props.highlightBottom && ` // styled-components doesn't seem to prefix linear-gradient.. soo background-image: linear-gradient(bottom, ${props.theme.greyLightest} 50%, transparent 50%); background-image: -o-linear-gradient(bottom, ${props.theme.greyLightest} 50%, transparent 50%); background-image: -moz-linear-gradient(bottom, ${props.theme.greyLightest} 50%, transparent 50%); background-image: -webkit-linear-gradient(bottom, ${props.theme.greyLightest} 50%, transparent 50%); background-image: -ms-linear-gradient(bottom, ${props.theme.greyLightest} 50%, transparent 50%); `} `; export const LOCATION_SEARCH_INPUT_NAME = "LocationSearchInput"; export class SearchBoxAndResultsRaw extends React.Component { constructor(props) { super(props); this.locationSearchRef = React.createRef(); } componentDidMount() { this.props.viewState.updateAppRef( LOCATION_SEARCH_INPUT_NAME, this.locationSearchRef ); this.subscribeToProps(); } componentDidUpdate() { this.subscribeToProps(); } componentWillUnmount() { this.unsubscribeFromProps(); } subscribeToProps() { this.unsubscribeFromProps(); // TODO(wing): why is this a reaction here and not in viewState itself? // Close the search results when the Now Viewing changes (so that it's visible). this._nowViewingChangeSubscription = reaction( () => this.props.terria.workbench.items, () => { this.props.viewState.searchState.showLocationSearchResults = false; } ); } unsubscribeFromProps() { if (this._nowViewingChangeSubscription) { this._nowViewingChangeSubscription(); this._nowViewingChangeSubscription = undefined; } } changeSearchText(newText) { runInAction(() => { this.props.viewState.searchState.locationSearchText = newText; }); if (newText.length === 0) { removeMarker(this.props.terria); runInAction(() => { this.toggleShowLocationSearchResults(false); }); } if ( newText.length > 0 && !this.props.viewState.searchState.showLocationSearchResults ) { runInAction(() => { this.toggleShowLocationSearchResults(true); }); } } search() { this.props.viewState.searchState.searchLocations(); } toggleShowLocationSearchResults(bool) { runInAction(() => { this.props.viewState.searchState.showLocationSearchResults = bool; }); } startLocationSearch() { this.toggleShowLocationSearchResults(true); } render() { const { viewState, placeholder } = this.props; const searchState = viewState.searchState; const locationSearchText = searchState.locationSearchText; const shouldShowResults = searchState.locationSearchText.length > 0 && searchState.showLocationSearchResults; return ( <Text textDarker> <Box fullWidth> <PresentationBox highlightBottom={shouldShowResults}> <SearchBox ref={this.locationSearchRef} onSearchTextChanged={this.changeSearchText.bind(this)} onDoSearch={this.search.bind(this)} onFocus={this.startLocationSearch.bind(this)} searchText={searchState.locationSearchText} placeholder={placeholder} /> </PresentationBox> {/* Results */} <If condition={shouldShowResults}> <Box position="absolute" fullWidth column css={` top: 100%; background-color: ${(props) => props.theme.greyLightest}; max-height: calc(100vh - 120px); border-radius: 0 0 ${(props) => props.theme.radius40Button}px ${(props) => props.theme.radius40Button}px; `} > {/* search {searchterm} in data catalog */} {/* ~TODO: Put this back once we add a MobX DataCatalogSearch Provider~ */} {/* TODO2: Implement a more generic MobX DataCatalogSearch */} {searchState.catalogSearchProvider && ( <Box column paddedRatio={2}> <SearchInDataCatalog viewState={viewState} handleClick={() => { this.toggleShowLocationSearchResults(false); }} /> </Box> )} <Box column css={` overflow-y: auto; `} > <For each="search" of={this.props.viewState.searchState.locationSearchResults} > <LocationSearchResults key={search.searchProvider.name} terria={this.props.terria} viewState={this.props.viewState} search={search} locationSearchText={locationSearchText} onLocationClick={(result) => { addMarker(this.props.terria, result); result.clickAction(); runInAction(() => { searchState.showLocationSearchResults = false; }); }} isWaitingForSearchToStart={ searchState.isWaitingToStartLocationSearch } /> </For> </Box> </Box> </If> </Box> </Text> ); } } SearchBoxAndResultsRaw.propTypes = { terria: PropTypes.object.isRequired, viewState: PropTypes.object.isRequired, placeholder: PropTypes.string.isRequired }; export default observer(SearchBoxAndResultsRaw);