1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | 5x 1x 5x 5x 5x 5x 5x 2x 1x 5x 5x 5x 4x 2x 1x 1x 3x 3x 5x 1x 4x 9x 5x 5x 1x | import React, {Component, PropTypes} from 'react'; function getDisplayName(WrappedComponent) { return `Geolocated(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`; } const geolocated = ({ positionOptions = { enableHighAccuracy: true, maximumAge: 0, timeout: Infinity, }, userDecisionTimeout = null, geolocationProvider = (typeof (navigator) !== 'undefined' && navigator.geolocation), } = {}) => (WrappedComponent) => { let result = class Geolocated extends Component { constructor(props) { super(props); this.state = { coords: null, isGeolocationAvailable: Boolean(geolocationProvider), isGeolocationEnabled: true, // be optimistic positionError: null, }; if (userDecisionTimeout) { this.userDecisionTimeoutId = setTimeout(() => { this.onPositionError(); }, userDecisionTimeout); } this.onPositionError = this.onPositionError.bind(this); this.onPositionSuccess = this.onPositionSuccess.bind(this); this.cancelUserDecisionTimeout = this.cancelUserDecisionTimeout.bind(this); } cancelUserDecisionTimeout() { if (this.userDecisionTimeoutId) { clearTimeout(this.userDecisionTimeoutId); } } onPositionError(positionError) { this.cancelUserDecisionTimeout(); this.setState({ coords: null, isGeolocationAvailable: this.state.isGeolocationAvailable, isGeolocationEnabled: false, positionError, }); } onPositionSuccess(position) { this.cancelUserDecisionTimeout(); this.setState({ coords: position.coords, isGeolocationAvailable: this.state.isGeolocationAvailable, isGeolocationEnabled: true, positionError: null, }); } componentDidMount() { if (!geolocationProvider || !geolocationProvider.getCurrentPosition) { throw new Error('The provided geolocation provider is invalid'); } geolocationProvider.getCurrentPosition(this.onPositionSuccess, this.onPositionError, positionOptions); } componentWillUnmount() { this.cancelUserDecisionTimeout(); } render() { return <WrappedComponent {...this.state} {...this.props} />; } }; result.displayName = getDisplayName(WrappedComponent); return result; }; export default geolocated; export const geoPropTypes = { coords: PropTypes.shape({ latitude: PropTypes.number, longitude: PropTypes.number, altitude: PropTypes.number, accuracy: PropTypes.number, altitudeAccuracy: PropTypes.number, heading: PropTypes.number, speed: PropTypes.number, }), isGeolocationAvailable: PropTypes.bool, isGeolocationEnabled: PropTypes.bool, positionError: PropTypes.shape({ code: PropTypes.oneOf([1, 2, 3]), message: PropTypes.string, }), }; |