UNPKG

terriajs

Version:

Geospatial data visualization platform.

313 lines (273 loc) 11.4 kB
'use strict'; import { buildShareLink, buildShortShareLink, canShorten } from './BuildShareLink'; import classNames from 'classnames'; import Clipboard from '../../../Clipboard'; import createReactClass from 'create-react-class'; import defined from 'terriajs-cesium/Source/Core/defined'; import DropdownStyles from '../panel.scss'; import Icon from "../../../Icon.jsx"; import Loader from '../../../Loader'; import MenuPanel from '../../../StandardUserInterface/customizable/MenuPanel.jsx'; import ObserverModelMixin from '../../../ObserveModelMixin'; import PrintView from './PrintView'; import printWindow from '../../../../Core/printWindow'; import PropTypes from 'prop-types'; import React from 'react'; import Styles from './share-panel.scss'; const SharePanel = createReactClass({ displayName: 'SharePanel', mixins: [ObserverModelMixin], propTypes: { terria: PropTypes.object, userPropWhiteList: PropTypes.array, advancedIsOpen: PropTypes.bool, shortenUrls: PropTypes.bool, viewState: PropTypes.object.isRequired }, getDefaultProps() { return { advancedIsOpen: false, shortenUrls: false }; }, getInitialState() { return { isOpen: false, shortenUrls: this.props.shortenUrls && this.props.terria.getLocalProperty('shortenShareUrls'), shareUrl: '', creatingPrintView: false, creatingDownload: false }; }, componentDidMount() { if (this.props.terria.configParameters.interceptBrowserPrint) { window.addEventListener('beforeprint', this.beforeBrowserPrint, false); window.addEventListener('afterprint', this.afterBrowserPrint, false); const handlePrintMediaChange = evt => { if (evt.matches) { this.beforeBrowserPrint(); } else { this.afterBrowserPrint(); } }; if (window.matchMedia) { const matcher = window.matchMedia('print'); matcher.addListener(handlePrintMediaChange); this._unsubscribeFromPrintMediaChange = function () { matcher.removeListener(handlePrintMediaChange); }; } this._oldPrint = window.print; window.print = () => { this.print(); }; } }, componentWillUnmount() { window.removeEventListener('beforeprint', this.beforeBrowserPrint, false); window.removeEventListener('afterprint', this.afterBrowserPrint, false); if (this._unsubscribeFromPrintMediaChange) { this._unsubscribeFromPrintMediaChange(); } if (this._oldPrint) { window.print = this._oldPrint; } }, beforeBrowserPrint() { this.afterBrowserPrint(); this._message = document.createElement('div'); this._message.innerText = 'For better printed results, please use ' + this.props.terria.appName + '\'s Print button instead of your web browser\'s print feature.'; window.document.body.insertBefore(this._message, window.document.body.childNodes[0]); }, afterBrowserPrint() { if (this._message) { window.document.body.removeChild(this._message); this._message = undefined; } this.changeOpenState(true); }, advancedIsOpen() { return this.state.advancedIsOpen; }, toggleAdvancedOptions(e) { this.setState((prevState) => ({ advancedIsOpen: !prevState.advancedIsOpen })); }, updateForShortening() { this.setState({ shareUrl: '' }); if (this.shouldShorten()) { this.setState({ placeholder: 'Shortening...' }); buildShortShareLink(this.props.terria) .then(shareUrl => this.setState({ shareUrl })) .otherwise(() => { this.setUnshortenedUrl(); this.setState({ errorMessage: 'An error occurred while attempting to shorten the URL. Please check your internet connection and try again.' }); }); } else { this.setUnshortenedUrl(); } }, setUnshortenedUrl() { this.setState({ shareUrl: buildShareLink(this.props.terria) }); }, isUrlShortenable() { return canShorten(this.props.terria); }, shouldShorten() { const localStoragePref = this.props.terria.getLocalProperty('shortenShareUrls'); return this.isUrlShortenable() && (localStoragePref || !defined(localStoragePref)); }, onShortenClicked(e) { if (this.shouldShorten()) { this.props.terria.setLocalProperty('shortenShareUrls', false); } else if (this.isUrlShortenable()) { this.props.terria.setLocalProperty('shortenShareUrls', true); } else { return; } this.updateForShortening(); this.forceUpdate(); }, changeOpenState(open) { this.setState({ isOpen: open }); if (open) { this.updateForShortening(); } }, print() { this.createPrintView(true, true); }, showPrintView() { this.createPrintView(false, false); }, createPrintView(hidden, printAutomatically) { this.setState({ creatingPrintView: true }); let iframe; if (hidden) { iframe = document.createElement('iframe'); document.body.appendChild(iframe); } PrintView.create({ terria: this.props.terria, viewState: this.props.viewState, printWindow: iframe ? iframe.contentWindow : undefined, readyCallback: windowToPrint => { if (printAutomatically) { printWindow(windowToPrint).otherwise(e => { this.props.terria.error.raiseEvent(e); }).always(() => { if (iframe) { document.body.removeChild(iframe); } if (hidden) { this.setState({ creatingPrintView: false }); } }); } }, closeCallback: windowToPrint => { if (hidden) { this.setState({ creatingPrintView: false }); } } }); if (!hidden) { this.setState({ creatingPrintView: false }); } }, renderContent() { const iframeCode = this.state.shareUrl.length ? `<iframe style="width: 720px; height: 600px; border: none;" src="${this.state.shareUrl}" allowFullScreen mozAllowFullScreen webkitAllowFullScreen></iframe>` : ''; const shareUrlTextBox = <input className={Styles.shareUrlfield} type="text" value={this.state.shareUrl} placeholder={this.state.placeholder} readOnly onClick={e => e.target.select()} id='share-url' />; return ( <div> <div className={Styles.clipboard}><Clipboard source={shareUrlTextBox} id='share-url' /></div> <div className={DropdownStyles.section}> <div>Print Map</div> <div className={Styles.explanation}>Open a printable version of this map.</div> <div> <button className={Styles.printButton} onClick={this.print} disabled={this.state.creatingPrintView}>Print</button> <button className={Styles.printButton} onClick={this.showPrintView} disabled={this.state.creatingPrintView}>Show Print View</button> <div className={Styles.printViewLoader}> {this.state.creatingPrintView && <Loader message="Creating print view..." />} </div> </div> </div> <div className={classNames(DropdownStyles.section, Styles.shortenUrl)}> <div className={Styles.btnWrapper}> <button type='button' onClick={this.toggleAdvancedOptions} className={Styles.btnAdvanced}> <span>Advanced options</span> {this.advancedIsOpen() ? <Icon glyph={Icon.GLYPHS.opened} /> : <Icon glyph={Icon.GLYPHS.closed} />} </button> </div> <If condition={this.advancedIsOpen()}> <div className={DropdownStyles.section}> <p className={Styles.paragraph}>To embed, copy this code to embed this map into an HTML page:</p> <input className={Styles.field} type="text" readOnly placeholder={this.state.placeholder} value={iframeCode} onClick={e => e.target.select()} /> </div> <If condition={this.isUrlShortenable()}> <div className={classNames(DropdownStyles.section, Styles.shortenUrl)}> <button onClick={this.onShortenClicked}> {this.shouldShorten() ? <Icon glyph={Icon.GLYPHS.checkboxOn} /> : <Icon glyph={Icon.GLYPHS.checkboxOff} />} Shorten the share URL using a web service </button> </div> </If> </If> </div> </div>); }, renderDownloadFormatButton(format) { return ( <button key={format.name} className={Styles.formatButton} onClick={this.download} disabled={this.state.creatingDownload}>{format.name}</button> ); }, render() { const dropdownTheme = { btn: Styles.btnShare, outer: Styles.sharePanel, inner: Styles.dropdownInner, icon: 'share' }; return ( <div> <MenuPanel theme={dropdownTheme} btnText="Share" viewState={this.props.viewState} btnTitle="Share your map with others" isOpen={this.state.isOpen} onOpenChanged={this.changeOpenState} smallScreen={this.props.viewState.useSmallScreenInterface}> <If condition={this.state.isOpen}> {this.renderContent()} </If> </MenuPanel> </div> ); }, }); export default SharePanel;