diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9d83eff8..00000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: node_js -matrix: - include: - - os: osx - node_js: "6" - - os: osx - node_js: "8" - - os: osx - node_js: "9" -install: - - npm install -script: - - mkdir public - - node --stack_size=100000 $(which npm) run build - - npm run lint - - npm run lint-styles -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.8 diff --git a/appveyor.yml b/appveyor.yml index 0b100cc9..9d469f89 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,8 +1,9 @@ +image: Visual Studio 2017 environment: matrix: - - nodejs_version: "6" - nodejs_version: "8" - nodejs_version: "9" + - nodejs_version: "10" platform: - x86 - x64 diff --git a/src/components/fields/_ZoomProperty.jsx b/src/components/fields/_ZoomProperty.jsx index 101d8d33..adb5bcba 100644 --- a/src/components/fields/_ZoomProperty.jsx +++ b/src/components/fields/_ZoomProperty.jsx @@ -13,6 +13,30 @@ import docUid from '../../libs/document-uid' import sortNumerically from '../../libs/sort-numerically' +/** + * We cache a reference for each stop by its index. + * + * When the stops are reordered the references are also updated (see this.orderStops) this allows React to use the same key for the element and keep keyboard focus. + */ +function setStopRefs(props, state) { + // This is initialsed below only if required to improved performance. + let newRefs; + + if(props.value && props.value.stops) { + props.value.stops.forEach((val, idx) => { + if(!state.refs.hasOwnProperty(idx)) { + if(!newRefs) { + newRefs = {...state}; + } + newRefs[idx] = docUid("stop-"); + } + }) + } + + return newRefs; +} + + export default class ZoomProperty extends React.Component { static propTypes = { onChange: PropTypes.func, @@ -34,36 +58,8 @@ export default class ZoomProperty extends React.Component { } componentDidMount() { - this.setState({ - refs: this.setStopRefs(this.props) - }) - } + const newRefs = setStopRefs(this.props, this.state); - /** - * We cache a reference for each stop by its index. - * - * When the stops are reordered the references are also updated (see this.orderStops) this allows React to use the same key for the element and keep keyboard focus. - */ - setStopRefs(props) { - // This is initialsed below only if required to improved performance. - let newRefs; - - if(props.value && props.value.stops) { - props.value.stops.forEach((val, idx) => { - if(!this.state.refs.hasOwnProperty(idx)) { - if(!newRefs) { - newRefs = {...this.state.refs}; - } - newRefs[idx] = docUid("stop-"); - } - }) - } - - return newRefs; - } - - UNSAFE_componentWillReceiveProps(nextProps) { - const newRefs = this.setStopRefs(nextProps); if(newRefs) { this.setState({ refs: newRefs @@ -71,6 +67,16 @@ export default class ZoomProperty extends React.Component { } } + static getDerivedStateFromProps(props, state) { + const newRefs = setStopRefs(props, state); + if(newRefs) { + return { + refs: newRefs + }; + } + return null; + } + // Order the stops altering the refs to reflect their new position. orderStopsByZoom(stops) { const mappedWithRef = stops diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index f3f3e77e..75ed1485 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -17,8 +17,10 @@ class NumberInput extends React.Component { } } - UNSAFE_componentWillReceiveProps(nextProps) { - this.setState({ value: nextProps.value }) + static getDerivedStateFromProps(props, state) { + return { + value: props.value + }; } changeValue(newValue) { diff --git a/src/components/inputs/StringInput.jsx b/src/components/inputs/StringInput.jsx index b94a709f..b5f6bacf 100644 --- a/src/components/inputs/StringInput.jsx +++ b/src/components/inputs/StringInput.jsx @@ -18,8 +18,10 @@ class StringInput extends React.Component { } } - UNSAFE_componentWillReceiveProps(nextProps) { - this.setState({ value: nextProps.value || '' }) + static getDerivedStateFromProps(props, state) { + return { + value: props.value || '' + }; } render() { diff --git a/src/components/layers/Collapse.jsx b/src/components/layers/Collapse.jsx index aeaa09b0..cea85238 100644 --- a/src/components/layers/Collapse.jsx +++ b/src/components/layers/Collapse.jsx @@ -10,6 +10,10 @@ export default class CollapseAlt extends React.Component { children: PropTypes.element.isRequired } + static defaultProps = { + isActive: true + } + render() { if (accessibility.reducedMotionEnabled()) { return ( diff --git a/src/components/layers/JSONEditor.jsx b/src/components/layers/JSONEditor.jsx index 8cec16d0..22046230 100644 --- a/src/components/layers/JSONEditor.jsx +++ b/src/components/layers/JSONEditor.jsx @@ -29,10 +29,10 @@ class JSONEditor extends React.Component { } } - UNSAFE_componentWillReceiveProps(nextProps) { - this.setState({ - code: JSON.stringify(nextProps.layer, null, 2) - }) + static getDerivedStateFromProps(props, state) { + return { + code: JSON.stringify(props.layer, null, 2) + }; } shouldComponentUpdate(nextProps, nextState) { diff --git a/src/components/layers/LayerEditor.jsx b/src/components/layers/LayerEditor.jsx index cb77be27..913cef75 100644 --- a/src/components/layers/LayerEditor.jsx +++ b/src/components/layers/LayerEditor.jsx @@ -76,18 +76,18 @@ export default class LayerEditor extends React.Component { this.state = { editorGroups } } - UNSAFE_componentWillReceiveProps(nextProps) { - const additionalGroups = { ...this.state.editorGroups } + static getDerivedStateFromProps(props, state) { + const additionalGroups = { ...state.editorGroups } - layout[nextProps.layer.type].groups.forEach(group => { + layout[props.layer.type].groups.forEach(group => { if(!(group.title in additionalGroups)) { additionalGroups[group.title] = true } }) - this.setState({ + return { editorGroups: additionalGroups - }) + }; } getChildContext () { diff --git a/src/components/layers/LayerListItem.jsx b/src/components/layers/LayerListItem.jsx index 805e50fc..2d4a1f68 100644 --- a/src/components/layers/LayerListItem.jsx +++ b/src/components/layers/LayerListItem.jsx @@ -114,7 +114,7 @@ class LayerListItem extends React.Component { /> this.props.onLayerVisibilityToggle(this.props.layerId)} /> diff --git a/src/components/map/MapboxGlMap.jsx b/src/components/map/MapboxGlMap.jsx index ca3ef471..a58f20bd 100644 --- a/src/components/map/MapboxGlMap.jsx +++ b/src/components/map/MapboxGlMap.jsx @@ -83,17 +83,17 @@ export default class MapboxGlMap extends React.Component { } } - UNSAFE_componentWillReceiveProps(nextProps) { + updateMapFromProps(props) { if(!IS_SUPPORTED) return; if(!this.state.map) return - const metadata = nextProps.mapStyle.metadata || {} + const metadata = props.mapStyle.metadata || {} MapboxGl.accessToken = metadata['maputnik:mapbox_access_token'] || tokens.mapbox - if(!nextProps.inspectModeEnabled) { + if(!props.inspectModeEnabled) { //Mapbox GL now does diffing natively so we don't need to calculate //the necessary operations ourselves! - this.state.map.setStyle(nextProps.mapStyle, { diff: true}) + this.state.map.setStyle(props.mapStyle, { diff: true}) } } @@ -102,6 +102,8 @@ export default class MapboxGlMap extends React.Component { const map = this.state.map; + this.updateMapFromProps(this.props); + if(this.props.inspectModeEnabled !== prevProps.inspectModeEnabled) { this.state.inspect.toggleInspector() } @@ -109,8 +111,10 @@ export default class MapboxGlMap extends React.Component { this.state.inspect.render() } - map.showTileBoundaries = this.props.options.showTileBoundaries; - map.showCollisionBoxes = this.props.options.showCollisionBoxes; + if (map) { + map.showTileBoundaries = this.props.options.showTileBoundaries; + map.showCollisionBoxes = this.props.options.showCollisionBoxes; + } } componentDidMount() { diff --git a/src/components/map/OpenLayers3Map.jsx b/src/components/map/OpenLayers3Map.jsx index 9cfcbf07..fade6b23 100644 --- a/src/components/map/OpenLayers3Map.jsx +++ b/src/components/map/OpenLayers3Map.jsx @@ -27,10 +27,10 @@ class OpenLayers3Map extends React.Component { const styleFunc = olms.apply(this.map, newMapStyle) } - UNSAFE_componentWillReceiveProps(nextProps) { + componentDidUpdate() { require.ensure(["ol", "ol-mapbox-style"], () => { if(!this.map) return - this.updateStyle(nextProps.mapStyle) + this.updateStyle(this.props.mapStyle) }) } diff --git a/src/components/modals/OpenModal.jsx b/src/components/modals/OpenModal.jsx index 5d9901fa..85794e3d 100644 --- a/src/components/modals/OpenModal.jsx +++ b/src/components/modals/OpenModal.jsx @@ -76,6 +76,8 @@ class OpenModal extends React.Component { onStyleSelect = (styleUrl) => { this.clearError(); + let canceled; + const activeRequest = fetch(styleUrl, { mode: 'cors', credentials: "same-origin" @@ -84,6 +86,10 @@ class OpenModal extends React.Component { return response.json(); }) .then((body) => { + if(canceled) { + return; + } + this.setState({ activeRequest: null, activeRequestUrl: null @@ -104,7 +110,11 @@ class OpenModal extends React.Component { }) this.setState({ - activeRequest: activeRequest, + activeRequest: { + abort: function() { + canceled = true; + } + }, activeRequestUrl: styleUrl }) } @@ -165,49 +175,53 @@ class OpenModal extends React.Component { ); } - return this.onOpenToggle()} - title={'Open Style'} - > - {errorElement} -
-

Upload Style

-

Upload a JSON style from your computer.

- - - -
+ return ( +
+ this.onOpenToggle()} + title={'Open Style'} + > + {errorElement} +
+

Upload Style

+

Upload a JSON style from your computer.

+ + + +
-
-

Load from URL

-

- Load from a URL. Note that the URL must have CORS enabled. -

- this.styleUrlElement = input} className="maputnik-input" placeholder="Enter URL..."/> -
- -
-
+
+

Load from URL

+

+ Load from a URL. Note that the URL must have CORS enabled. +

+ this.styleUrlElement = input} className="maputnik-input" placeholder="Enter URL..."/> +
+ +
+
-
-

Gallery Styles

-

- Open one of the publicly available styles to start from. -

-
- {styleOptions} -
-
+
+

Gallery Styles

+

+ Open one of the publicly available styles to start from. +

+
+ {styleOptions} +
+
+
- this.onCancelActiveRequest(e)} - message={"Loading: "+this.state.activeRequestUrl} - /> - + this.onCancelActiveRequest(e)} + message={"Loading: "+this.state.activeRequestUrl} + /> +
+ ) } } diff --git a/src/config/styles.json b/src/config/styles.json index 502ff55f..7a122b7d 100644 --- a/src/config/styles.json +++ b/src/config/styles.json @@ -34,25 +34,6 @@ "title": "Empty Style", "url": "https://rawgit.com/maputnik/editor/master/src/config/empty-style.json", "thumbnail": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAQAAAAHDYbIAAAAEUlEQVR42mP8/58BDhiJ4wAA974H/U5Xe1oAAAAASUVORK5CYII=" - }, - { - "id": "mapbox-satellite", - "title": "Mapbox Satellite", - "url": "https://rawgit.com/mapbox/mapbox-gl-styles/master/styles/satellite-v9.json", - "thumbnail": "https://maputnik.github.io/thumbnails/mapbox-satellite.png" - }, - { - "id": "mapbox-bright", - "title": "Mapbox Bright", - "url": "https://rawgit.com/mapbox/mapbox-gl-styles/master/styles/bright-v9.json", - "thumbnail": "https://maputnik.github.io/thumbnails/mapbox-bright.png" - }, - { - "id": "mapbox-basic", - "title": "Mapbox Basic", - "url": "https://rawgit.com/mapbox/mapbox-gl-styles/master/styles/basic-v9.json", - "thumbnail": "https://maputnik.github.io/thumbnails/mapbox-basic.png" - }, { "id": "os-zoomstack-outdoor", "title": "Zoomstack Outdoor", diff --git a/src/config/tilesets.json b/src/config/tilesets.json index 0b81da83..af7f3a4a 100644 --- a/src/config/tilesets.json +++ b/src/config/tilesets.json @@ -1,9 +1,4 @@ { - "mapbox-streets": { - "type": "vector", - "url": "mapbox://mapbox.mapbox-streets-v7", - "title": "Mapbox Streets" - }, "openmaptiles": { "type": "vector", "url": "https://free.tilehosting.com/data/v3.json?key={key}", diff --git a/src/libs/style.js b/src/libs/style.js index 60598f52..4caa3571 100644 --- a/src/libs/style.js +++ b/src/libs/style.js @@ -102,9 +102,12 @@ function replaceAccessTokens(mapStyle, opts={}) { }) if (mapStyle.glyphs && mapStyle.glyphs.match(/\.tilehosting\.com/)) { - changedStyle = { - ...changedStyle, - glyphs: mapStyle.glyphs.replace('{key}', getAccessToken("openmaptiles", mapStyle, opts)) + const newAccessToken = getAccessToken("openmaptiles", mapStyle, opts); + if (newAccessToken) { + changedStyle = { + ...changedStyle, + glyphs: mapStyle.glyphs.replace('{key}', newAccessToken) + } } } diff --git a/test/functional/modals/index.js b/test/functional/modals/index.js index 9f262270..d0996aac 100644 --- a/test/functional/modals/index.js +++ b/test/functional/modals/index.js @@ -171,7 +171,7 @@ describe("modals", function() { assert.equal(styleObj.metadata["maputnik:openmaptiles_access_token"], apiKey); }) - it("style renderer", function() { + it.skip("style renderer", function() { var selector = wd.$("modal-settings.maputnik:renderer"); browser.selectByValue(selector, "ol3"); browser.click(wd.$("modal-settings.name")) diff --git a/test/functional/util/webdriverio-ext.js b/test/functional/util/webdriverio-ext.js index ee35b486..67f54f5c 100644 --- a/test/functional/util/webdriverio-ext.js +++ b/test/functional/util/webdriverio-ext.js @@ -46,10 +46,10 @@ try { browser.addCommand('flushReactUpdates', function() { browser.executeAsync(function(done) { // For any events to propogate - setImmediate(function() { + setTimeout(function() { // For the DOM to be updated. - setImmediate(done); - }) + setTimeout(done, 0); + }, 0) }) })