From cdd5d27908ce1556d8868daa89005b527cfffbfa Mon Sep 17 00:00:00 2001 From: orangemug Date: Tue, 30 Oct 2018 20:35:22 +0000 Subject: [PATCH 01/88] Added range slider to --- src/components/inputs/NumberInput.jsx | 44 +++++++++++++++++++++----- src/components/layers/MaxZoomBlock.jsx | 1 + src/components/layers/MinZoomBlock.jsx | 1 + 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index 75ed148..e4fb221 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -68,14 +68,42 @@ class NumberInput extends React.Component { } render() { - return this.changeValue(e.target.value)} - onBlur={this.resetValue} - /> + let rangeEl; + + if( + this.props.hasOwnProperty("min") && this.props.hasOwnProperty("max") && + this.props.min !== undefined && this.props.max !== undefined && + this.props.allowRange + ) { + rangeEl = ( + this.changeValue(e.target.value)} + onBlur={this.resetValue} + /> + ); + } + + return
+ {rangeEl} + this.changeValue(e.target.value)} + onBlur={this.resetValue} + /> +
} } diff --git a/src/components/layers/MaxZoomBlock.jsx b/src/components/layers/MaxZoomBlock.jsx index b4ab33e..7447593 100644 --- a/src/components/layers/MaxZoomBlock.jsx +++ b/src/components/layers/MaxZoomBlock.jsx @@ -16,6 +16,7 @@ class MaxZoomBlock extends React.Component { data-wd-key="max-zoom" > Date: Thu, 1 Nov 2018 08:28:49 +0000 Subject: [PATCH 02/88] Make range step configurable --- src/components/inputs/NumberInput.jsx | 8 +++++++- src/components/layers/MaxZoomBlock.jsx | 1 + src/components/layers/MinZoomBlock.jsx | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index e4fb221..714ca56 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -8,6 +8,12 @@ class NumberInput extends React.Component { min: PropTypes.number, max: PropTypes.number, onChange: PropTypes.func, + allowRange: PropTypes.bool, + rangeStep: PropTypes.number, + } + + static defaultProps = { + rangeStep: 0.01 } constructor(props) { @@ -80,7 +86,7 @@ class NumberInput extends React.Component { style={{width: "calc(100% - 4em)", flexShrink: "0"}} key="range" type="range" - step="0.01" + step={this.props.rangeStep} max={this.props.max} min={this.props.min} spellCheck="false" diff --git a/src/components/layers/MaxZoomBlock.jsx b/src/components/layers/MaxZoomBlock.jsx index 7447593..f0683fd 100644 --- a/src/components/layers/MaxZoomBlock.jsx +++ b/src/components/layers/MaxZoomBlock.jsx @@ -17,6 +17,7 @@ class MaxZoomBlock extends React.Component { > Date: Thu, 1 Nov 2018 18:28:58 +0000 Subject: [PATCH 03/88] Changed min/max zoom range step from 0.1 -> 1 --- src/components/layers/MaxZoomBlock.jsx | 2 +- src/components/layers/MinZoomBlock.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/layers/MaxZoomBlock.jsx b/src/components/layers/MaxZoomBlock.jsx index f0683fd..6183d2e 100644 --- a/src/components/layers/MaxZoomBlock.jsx +++ b/src/components/layers/MaxZoomBlock.jsx @@ -17,7 +17,7 @@ class MaxZoomBlock extends React.Component { > Date: Fri, 2 Nov 2018 08:28:51 +0000 Subject: [PATCH 04/88] Fix to allow high precision on text input and integer on range. --- src/components/inputs/NumberInput.jsx | 39 ++++++++++++++++++--------- src/styles/_input.scss | 10 +++++++ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index 714ca56..3371e44 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -23,18 +23,13 @@ class NumberInput extends React.Component { } } - static getDerivedStateFromProps(props, state) { - return { - value: props.value - }; - } - changeValue(newValue) { const value = parseFloat(newValue) const hasChanged = this.state.value !== value if(this.isValid(value) && hasChanged) { this.props.onChange(value) + this.setState({ value: value }) } else { this.setState({ value: newValue }) } @@ -73,6 +68,27 @@ class NumberInput extends React.Component { } } + onChangeRange = (e) => { + const val = parseFloat(rawValue, 10); + const step = this.props.rangeStep; + let out = val; + + if(step) { + // Can't do this with the range step attribute else we won't be able to set a high precision value via the text input. + const snap = val % step; + + // Round up/down to step + if (snap < step/2) { + out = val - snap; + } + else { + out = val + (step - snap); + }; + } + + this.changeValue(out); + } + render() { let rangeEl; @@ -83,22 +99,21 @@ class NumberInput extends React.Component { ) { rangeEl = ( this.changeValue(e.target.value)} + value={this.state.value} + onChange={this.onChangeRange} onBlur={this.resetValue} /> ); } - return
+ return
{rangeEl} Date: Fri, 2 Nov 2018 08:54:20 +0000 Subject: [PATCH 05/88] Fixed typo --- src/components/inputs/NumberInput.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index 3371e44..929bbdf 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -69,7 +69,7 @@ class NumberInput extends React.Component { } onChangeRange = (e) => { - const val = parseFloat(rawValue, 10); + const val = parseFloat(e.target.value, 10); const step = this.props.rangeStep; let out = val; From 5053058c328001766703afe886d33952641aea08 Mon Sep 17 00:00:00 2001 From: orangemug Date: Mon, 20 May 2019 11:21:23 +0100 Subject: [PATCH 06/88] Fixed default values for range slider. --- src/components/inputs/NumberInput.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index 5c332ad..742a1cf 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -106,6 +106,8 @@ class NumberInput extends React.Component { this.props.min !== undefined && this.props.max !== undefined && this.props.allowRange ) { + const value = this.props.value === undefined ? this.props.default : this.props.value; + rangeEl = ( From 15cdfbc9805d0ba5287cb92b572b735060a3ca82 Mon Sep 17 00:00:00 2001 From: orangemug Date: Mon, 20 May 2019 11:28:27 +0100 Subject: [PATCH 07/88] Changed default of step 0.01 -> 1 --- src/components/inputs/NumberInput.jsx | 2 +- src/components/layers/MaxZoomBlock.jsx | 1 - src/components/layers/MinZoomBlock.jsx | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index 742a1cf..0d0e488 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -13,7 +13,7 @@ class NumberInput extends React.Component { } static defaultProps = { - rangeStep: 0.01 + rangeStep: 1 } constructor(props) { diff --git a/src/components/layers/MaxZoomBlock.jsx b/src/components/layers/MaxZoomBlock.jsx index 6183d2e..7447593 100644 --- a/src/components/layers/MaxZoomBlock.jsx +++ b/src/components/layers/MaxZoomBlock.jsx @@ -17,7 +17,6 @@ class MaxZoomBlock extends React.Component { > Date: Tue, 21 May 2019 18:42:19 +0100 Subject: [PATCH 08/88] Fixes for firefox, this makes the range input only update on pointerup --- src/components/inputs/NumberInput.jsx | 82 ++++++++++++++++++--------- src/styles/_input.scss | 5 ++ 2 files changed, 59 insertions(+), 28 deletions(-) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index 0d0e488..32e210b 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -21,26 +21,34 @@ class NumberInput extends React.Component { this.state = { editing: false, value: props.value, + dirtyValue: props.value, } } static getDerivedStateFromProps(props, state) { if (!state.editing) { return { - value: props.value + value: props.value, + dirtyValue: props.value, }; } + else { + return null; + } } changeValue(newValue) { this.setState({editing: true}); const value = parseFloat(newValue) - const hasChanged = this.state.value !== value + const hasChanged = this.state.value !== value; if(this.isValid(value) && hasChanged) { this.props.onChange(value) } - this.setState({ value: newValue }) + this.setState({ + value: newValue, + dirtyValue: newValue, + }) } isValid(v) { @@ -78,37 +86,36 @@ class NumberInput extends React.Component { } onChangeRange = (e) => { - const val = parseFloat(e.target.value, 10); + const value = parseFloat(e.target.value, 10); const step = this.props.rangeStep; - let out = val; + let dirtyValue = value; if(step) { // Can't do this with the range step attribute else we won't be able to set a high precision value via the text input. - const snap = val % step; + const snap = value % step; // Round up/down to step if (snap < step/2) { - out = val - snap; + dirtyValue = value - snap; } else { - out = val + (step - snap); + dirtyValue = value + (step - snap); }; } - this.changeValue(out); + this.setState({editing: true, value, dirtyValue}); } render() { - let rangeEl; - if( this.props.hasOwnProperty("min") && this.props.hasOwnProperty("max") && this.props.min !== undefined && this.props.max !== undefined && this.props.allowRange ) { - const value = this.props.value === undefined ? this.props.default : this.props.value; + const value = this.state.value === undefined ? this.props.default : this.state.value; + const rangeValue = Number.isNaN(parseFloat(value, 10)) ? this.props.default : value; - rangeEl = ( + return
{ + const {dirtyValue} = this.state; + const hasChanged = this.state.props !== dirtyValue + if(this.isValid(dirtyValue) && hasChanged) { + this.setState({editing: false}, () => { + this.props.onChange(dirtyValue); + }); + } + }} + /> + { + this.changeValue(e.target.value) + }} onBlur={this.resetValue} /> - ); +
+ } + else { + return
+ this.changeValue(e.target.value)} + onBlur={this.resetValue} + /> +
} - - return
- {rangeEl} - this.changeValue(e.target.value)} - onBlur={this.resetValue} - /> -
} } diff --git a/src/styles/_input.scss b/src/styles/_input.scss index 7d1f0cc..066a97b 100644 --- a/src/styles/_input.scss +++ b/src/styles/_input.scss @@ -183,3 +183,8 @@ margin-bottom: $margin-3; } } + +.maputnik-input-block-content { + position: relative; + overflow: hidden; +} From 911549aca33c95e3e9827d1f29ad4390e5a00ea3 Mon Sep 17 00:00:00 2001 From: orangemug Date: Tue, 21 May 2019 18:54:09 +0100 Subject: [PATCH 09/88] Moved data-wd-key onto element --- src/components/inputs/NumberInput.jsx | 10 ++++++++++ src/components/layers/MaxZoomBlock.jsx | 5 ++--- src/components/layers/MinZoomBlock.jsx | 5 ++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index 32e210b..a93db93 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -10,6 +10,7 @@ class NumberInput extends React.Component { onChange: PropTypes.func, allowRange: PropTypes.bool, rangeStep: PropTypes.number, + wdKey: PropTypes.string, } static defaultProps = { @@ -107,6 +108,13 @@ class NumberInput extends React.Component { } render() { + let wdProps = {}; + if (this.props.wdKey) { + wdProps = { + "data-wd-key": this.props.wdKey + }; + } + if( this.props.hasOwnProperty("min") && this.props.hasOwnProperty("max") && this.props.min !== undefined && this.props.max !== undefined && @@ -146,6 +154,7 @@ class NumberInput extends React.Component { this.changeValue(e.target.value) }} onBlur={this.resetValue} + {...wdProps} />
} @@ -159,6 +168,7 @@ class NumberInput extends React.Component { value={this.state.value} onChange={e => this.changeValue(e.target.value)} onBlur={this.resetValue} + {...wdProps} />
} diff --git a/src/components/layers/MaxZoomBlock.jsx b/src/components/layers/MaxZoomBlock.jsx index 7447593..99924aa 100644 --- a/src/components/layers/MaxZoomBlock.jsx +++ b/src/components/layers/MaxZoomBlock.jsx @@ -12,10 +12,9 @@ class MaxZoomBlock extends React.Component { } render() { - return + return + return Date: Tue, 21 May 2019 19:07:28 +0100 Subject: [PATCH 10/88] Moved back to data-wd-key approach and fixed tests --- src/components/inputs/NumberInput.jsx | 11 ++--------- src/components/layers/MaxZoomBlock.jsx | 5 +++-- src/components/layers/MinZoomBlock.jsx | 5 +++-- test/functional/layers/index.js | 4 ++-- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index a93db93..58b0866 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -108,13 +108,6 @@ class NumberInput extends React.Component { } render() { - let wdProps = {}; - if (this.props.wdKey) { - wdProps = { - "data-wd-key": this.props.wdKey - }; - } - if( this.props.hasOwnProperty("min") && this.props.hasOwnProperty("max") && this.props.min !== undefined && this.props.max !== undefined && @@ -146,6 +139,7 @@ class NumberInput extends React.Component { /> } @@ -162,13 +155,13 @@ class NumberInput extends React.Component { return
this.changeValue(e.target.value)} onBlur={this.resetValue} - {...wdProps} />
} diff --git a/src/components/layers/MaxZoomBlock.jsx b/src/components/layers/MaxZoomBlock.jsx index 99924aa..7447593 100644 --- a/src/components/layers/MaxZoomBlock.jsx +++ b/src/components/layers/MaxZoomBlock.jsx @@ -12,9 +12,10 @@ class MaxZoomBlock extends React.Component { } render() { - return + return + return Date: Wed, 16 Oct 2019 07:36:30 +0100 Subject: [PATCH 11/88] Added default support to --- src/components/inputs/ArrayInput.jsx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/components/inputs/ArrayInput.jsx b/src/components/inputs/ArrayInput.jsx index 69a01d5..5a8a4f5 100644 --- a/src/components/inputs/ArrayInput.jsx +++ b/src/components/inputs/ArrayInput.jsx @@ -12,29 +12,32 @@ class ArrayInput extends React.Component { onChange: PropTypes.func, } + static defaultProps = { + value: [], + default: [], + } + changeValue(idx, newValue) { console.log(idx, newValue) - const values = this.values.slice(0) + const values = this.props.value.slice(0) values[idx] = newValue this.props.onChange(values) } - get values() { - return this.props.value || this.props.default || [] - } - render() { - const inputs = this.values.map((v, i) => { + const inputs = Array(this.props.length).fill(null).map((_, i) => { if(this.props.type === 'number') { return } else { return } From 1f77e156e6dbeae2816ff08045cdb56434a38277 Mon Sep 17 00:00:00 2001 From: orangemug Date: Wed, 16 Oct 2019 07:38:50 +0100 Subject: [PATCH 12/88] Added support for root level properties - center - zoom - bearing - pitch --- src/components/modals/SettingsModal.jsx | 41 ++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx index 04ca51d..44dbf26 100644 --- a/src/components/modals/SettingsModal.jsx +++ b/src/components/modals/SettingsModal.jsx @@ -3,6 +3,8 @@ import PropTypes from 'prop-types' import {latest} from '@mapbox/mapbox-gl-style-spec' import InputBlock from '../inputs/InputBlock' +import ArrayInput from '../inputs/ArrayInput' +import NumberInput from '../inputs/NumberInput' import StringInput from '../inputs/StringInput' import SelectInput from '../inputs/SelectInput' import Modal from './Modal' @@ -26,7 +28,7 @@ class SettingsModal extends React.Component { render() { const metadata = this.props.mapStyle.metadata || {} - const {onChangeMetadataProperty} = this.props; + const {onChangeMetadataProperty, mapStyle} = this.props; const inputProps = { } return + + + + + + + + + + + + + + + + } From eb8686325c878ffcbaba3f08441b4107d8e16104 Mon Sep 17 00:00:00 2001 From: orangemug Date: Wed, 16 Oct 2019 08:13:37 +0100 Subject: [PATCH 13/88] Fixed typo in export. --- src/components/inputs/EnumInput.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/inputs/EnumInput.jsx b/src/components/inputs/EnumInput.jsx index 0c6039c..e704110 100644 --- a/src/components/inputs/EnumInput.jsx +++ b/src/components/inputs/EnumInput.jsx @@ -42,4 +42,4 @@ class EnumInput extends React.Component { } } -export default StringInput +export default EnumInput From e7622c20808401f1e4d4beced95855df8622a1ae Mon Sep 17 00:00:00 2001 From: orangemug Date: Wed, 16 Oct 2019 08:17:25 +0100 Subject: [PATCH 14/88] Added root level light property support. --- src/components/modals/SettingsModal.jsx | 55 +++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx index 44dbf26..e6aa890 100644 --- a/src/components/modals/SettingsModal.jsx +++ b/src/components/modals/SettingsModal.jsx @@ -7,6 +7,8 @@ import ArrayInput from '../inputs/ArrayInput' import NumberInput from '../inputs/NumberInput' import StringInput from '../inputs/StringInput' import SelectInput from '../inputs/SelectInput' +import EnumInput from '../inputs/EnumInput' +import ColorField from '../fields/ColorField' import Modal from './Modal' class SettingsModal extends React.Component { @@ -18,6 +20,17 @@ class SettingsModal extends React.Component { onOpenToggle: PropTypes.func.isRequired, } + changeLightProperty(property, value) { + const changedStyle = { + ...this.props.mapStyle, + light: { + ...this.props.mapStyle.light, + [property]: value + } + } + this.props.onStyleChanged(changedStyle) + } + changeStyleProperty(property, value) { const changedStyle = { ...this.props.mapStyle, @@ -30,6 +43,9 @@ class SettingsModal extends React.Component { const metadata = this.props.mapStyle.metadata || {} const {onChangeMetadataProperty, mapStyle} = this.props; const inputProps = { } + + const light = this.props.mapStyle.light || {}; + return + + + + + + + + + + + + + + + + + } From 392a845460d9c5b1e7f3d064bb736897f6abd1f8 Mon Sep 17 00:00:00 2001 From: orangemug Date: Wed, 16 Oct 2019 08:24:25 +0100 Subject: [PATCH 15/88] Moved "Style Renderer" options to bottom of list. --- src/components/modals/SettingsModal.jsx | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx index e6aa890..4f94b2a 100644 --- a/src/components/modals/SettingsModal.jsx +++ b/src/components/modals/SettingsModal.jsx @@ -107,18 +107,6 @@ class SettingsModal extends React.Component { /> - - - - + + + + + From c27deefdef8bf66dbbc5d2d0a67d0912d9ab7fd9 Mon Sep 17 00:00:00 2001 From: orangemug Date: Wed, 16 Oct 2019 09:56:26 +0100 Subject: [PATCH 16/88] Added profiling build to CI --- .circleci/config.yml | 1 + config/webpack.profiling.config.js | 20 ++++++++++++++++++++ package.json | 1 + 3 files changed, 22 insertions(+) create mode 100644 config/webpack.profiling.config.js diff --git a/.circleci/config.yml b/.circleci/config.yml index 27bf993..2328ded 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -18,6 +18,7 @@ templates: - run: mkdir -p /tmp/artifacts/logs - run: npm run build + - run: npm run profiling-build - run: npm run lint - run: npm run lint-styles - store_artifacts: diff --git a/config/webpack.profiling.config.js b/config/webpack.profiling.config.js new file mode 100644 index 0000000..84c4da2 --- /dev/null +++ b/config/webpack.profiling.config.js @@ -0,0 +1,20 @@ +const webpackProdConfig = require('./webpack.production.config'); +const artifacts = require("../test/artifacts"); + +const OUTPATH = artifacts.pathSync("/profiling"); + +module.exports = { + ...webpackProdConfig, + output: { + ...webpackProdConfig.output, + path: OUTPATH, + }, + resolve: { + ...webpackProdConfig.resolve, + alias: { + ...webpackProdConfig.resolve.alias, + 'react-dom$': 'react-dom/profiling', + 'scheduler/tracing': 'scheduler/tracing-profiling', + } + } +}; diff --git a/package.json b/package.json index b7d9a6b..1e6045f 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "stats": "webpack --config config/webpack.production.config.js --profile --json > stats.json", "build": "webpack --config config/webpack.production.config.js --progress --profile --colors", + "profiling-build": "webpack --config config/webpack.profiling.config.js --progress --profile --colors", "test": "cross-env NODE_ENV=test wdio config/wdio.conf.js", "test-watch": "cross-env NODE_ENV=test wdio config/wdio.conf.js --watch", "start": "webpack-dev-server --progress --profile --colors --config config/webpack.config.js", From 8c760bb8108dbc8991f2d918f5d920ca7c0726d0 Mon Sep 17 00:00:00 2001 From: orangemug Date: Wed, 16 Oct 2019 10:12:59 +0100 Subject: [PATCH 17/88] Added default support to --- src/components/inputs/EnumInput.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/inputs/EnumInput.jsx b/src/components/inputs/EnumInput.jsx index e704110..9472a2f 100644 --- a/src/components/inputs/EnumInput.jsx +++ b/src/components/inputs/EnumInput.jsx @@ -29,13 +29,13 @@ class EnumInput extends React.Component { if(options.length <= 3 && optionsLabelLength(options) <= 20) { return } else { return } From d0a47bd1226f4c7099f7d97fd374b6902b9381d4 Mon Sep 17 00:00:00 2001 From: orangemug Date: Wed, 16 Oct 2019 10:15:46 +0100 Subject: [PATCH 18/88] Added support for transition root property --- src/components/modals/SettingsModal.jsx | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx index 4f94b2a..2b9fdee 100644 --- a/src/components/modals/SettingsModal.jsx +++ b/src/components/modals/SettingsModal.jsx @@ -20,6 +20,17 @@ class SettingsModal extends React.Component { onOpenToggle: PropTypes.func.isRequired, } + changeTransitionProperty(property, value) { + const changedStyle = { + ...this.props.mapStyle, + transition: { + ...this.props.mapStyle.transition, + [property]: value + } + } + this.props.onStyleChanged(changedStyle) + } + changeLightProperty(property, value) { const changedStyle = { ...this.props.mapStyle, @@ -45,6 +56,7 @@ class SettingsModal extends React.Component { const inputProps = { } const light = this.props.mapStyle.light || {}; + const transition = this.props.mapStyle.transition || {}; return
+ + + + + + + + Date: Wed, 16 Oct 2019 15:34:24 +0200 Subject: [PATCH 19/88] Fix the layer type test in LayerEditor component `LayerSourceLayerBlock` was always included --- src/components/layers/LayerEditor.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/layers/LayerEditor.jsx b/src/components/layers/LayerEditor.jsx index 39c862d..ed16116 100644 --- a/src/components/layers/LayerEditor.jsx +++ b/src/components/layers/LayerEditor.jsx @@ -141,7 +141,7 @@ export default class LayerEditor extends React.Component { onChange={v => this.changeProperty(null, 'source', v)} /> } - {['background', 'raster', 'hillshade', 'heatmap'].indexOf(this.state.type) < 0 && + {['background', 'raster', 'hillshade', 'heatmap'].indexOf(this.props.layer.type) < 0 && Date: Wed, 16 Oct 2019 21:57:29 +0100 Subject: [PATCH 20/88] unsetting fix. --- src/components/inputs/NumberInput.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index 0de1fa4..f2fa3ce 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -65,7 +65,7 @@ class NumberInput extends React.Component { this.setState({editing: false}); // Reset explicitly to default value if value has been cleared if(this.state.value === "") { - return this.changeValue(this.props.default) + return; } // If set value is invalid fall back to the last valid value from props or at last resort the default value @@ -73,7 +73,7 @@ class NumberInput extends React.Component { if(this.isValid(this.props.value)) { this.changeValue(this.props.value) } else { - this.changeValue(this.props.default) + this.changeValue(undefined); } } } From 2910efde6e9462d7d1bb9c5d44427a48f3ace1d7 Mon Sep 17 00:00:00 2001 From: orangemug Date: Wed, 16 Oct 2019 21:58:24 +0100 Subject: [PATCH 21/88] Allow removal of light/transition properties. --- src/components/modals/SettingsModal.jsx | 42 ++++++++++++++++--------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx index 2b9fdee..aaa714d 100644 --- a/src/components/modals/SettingsModal.jsx +++ b/src/components/modals/SettingsModal.jsx @@ -21,25 +21,39 @@ class SettingsModal extends React.Component { } changeTransitionProperty(property, value) { - const changedStyle = { - ...this.props.mapStyle, - transition: { - ...this.props.mapStyle.transition, - [property]: value - } + const transition = { + ...this.props.mapStyle.transition, } - this.props.onStyleChanged(changedStyle) + + if (value === undefined) { + delete transition[property]; + } + else { + transition[property] = value; + } + + this.props.onStyleChanged({ + ...this.props.mapStyle, + transition, + }); } changeLightProperty(property, value) { - const changedStyle = { - ...this.props.mapStyle, - light: { - ...this.props.mapStyle.light, - [property]: value - } + const light = { + ...this.props.mapStyle.light, } - this.props.onStyleChanged(changedStyle) + + if (value === undefined) { + delete light[property]; + } + else { + light[property] = value; + } + + this.props.onStyleChanged({ + ...this.props.mapStyle, + light, + }); } changeStyleProperty(property, value) { From 0aa0dad7fb80c3de90192cfdd9fb4d015e8b819e Mon Sep 17 00:00:00 2001 From: orangemug Date: Wed, 16 Oct 2019 22:31:29 +0100 Subject: [PATCH 22/88] Remove undefined root properties. --- src/components/modals/SettingsModal.jsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx index aaa714d..43f881b 100644 --- a/src/components/modals/SettingsModal.jsx +++ b/src/components/modals/SettingsModal.jsx @@ -59,9 +59,15 @@ class SettingsModal extends React.Component { changeStyleProperty(property, value) { const changedStyle = { ...this.props.mapStyle, - [property]: value + }; + + if (value === undefined) { + delete changedStyle[property]; } - this.props.onStyleChanged(changedStyle) + else { + changedStyle[property] = value; + } + this.props.onStyleChanged(changedStyle); } render() { From 37e5ba0fff25e562e1e8cca1a3592c4d067b4ff2 Mon Sep 17 00:00:00 2001 From: orangemug Date: Wed, 16 Oct 2019 22:36:41 +0100 Subject: [PATCH 23/88] Remove 'center' and 'light position', as they weren't working properly. --- src/components/modals/SettingsModal.jsx | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx index 43f881b..5b918b7 100644 --- a/src/components/modals/SettingsModal.jsx +++ b/src/components/modals/SettingsModal.jsx @@ -139,16 +139,6 @@ class SettingsModal extends React.Component { /> - - - - - - - - Date: Sat, 19 Oct 2019 12:07:08 +0100 Subject: [PATCH 24/88] Added invalid style to inputs --- src/styles/_input.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/styles/_input.scss b/src/styles/_input.scss index 90e84ed..7caaa77 100644 --- a/src/styles/_input.scss +++ b/src/styles/_input.scss @@ -11,6 +11,11 @@ border: none; background-color: $color-gray; color: lighten($color-lowgray, 12); + + &:invalid { + border: solid 1px #B71C1C; + border-radius: 2px; + } } .maputnik-string { From 9743361e0d691708493153d4aae90afe6fb05ae0 Mon Sep 17 00:00:00 2001 From: orangemug Date: Sat, 19 Oct 2019 12:16:56 +0100 Subject: [PATCH 25/88] Added back in 'light position' and 'center' with fixes for This also improves the usage of *-translate which uses the --- src/components/fields/PropertyGroup.jsx | 2 +- src/components/inputs/ArrayInput.jsx | 73 ++++++++++++++++++++++--- src/components/inputs/NumberInput.jsx | 3 +- src/components/inputs/StringInput.jsx | 5 +- src/components/modals/SettingsModal.jsx | 21 +++++++ 5 files changed, 92 insertions(+), 12 deletions(-) diff --git a/src/components/fields/PropertyGroup.jsx b/src/components/fields/PropertyGroup.jsx index efb567b..3557724 100644 --- a/src/components/fields/PropertyGroup.jsx +++ b/src/components/fields/PropertyGroup.jsx @@ -59,7 +59,7 @@ export default class PropertyGroup extends React.Component { onChange={this.onPropertyChange} key={fieldName} fieldName={fieldName} - value={fieldValue === undefined ? fieldSpec.default : fieldValue} + value={fieldValue} fieldSpec={fieldSpec} /> }) diff --git a/src/components/inputs/ArrayInput.jsx b/src/components/inputs/ArrayInput.jsx index 5a8a4f5..bb406d8 100644 --- a/src/components/inputs/ArrayInput.jsx +++ b/src/components/inputs/ArrayInput.jsx @@ -17,27 +17,84 @@ class ArrayInput extends React.Component { default: [], } + constructor (props) { + super(props); + this.state = { + value: this.props.value.slice(0), + // This is so we can compare changes in getDerivedStateFromProps + initialPropsValue: this.props.value.slice(0), + }; + } + + static getDerivedStateFromProps(props, state) { + const value = []; + const initialPropsValue = state.initialPropsValue.slice(0); + + Array(props.length).fill(null).map((_, i) => { + if (props.value[i] === state.initialPropsValue[i]) { + value[i] = state.value[i]; + } + else { + value[i] = state.value[i]; + initialPropsValue[i] = state.value[i]; + } + }) + + return { + value, + initialPropsValue, + }; + } + + isComplete (value) { + return Array(this.props.length).fill(null).every((_, i) => { + const val = value[i] + return !(val === undefined || val === ""); + }); + } + changeValue(idx, newValue) { - console.log(idx, newValue) - const values = this.props.value.slice(0) - values[idx] = newValue - this.props.onChange(values) + const value = this.state.value.slice(0); + value[idx] = newValue; + + this.setState({ + value, + }, () => { + if (this.isComplete(value)) { + this.props.onChange(value); + } + else { + // Unset until complete + this.props.onChange(undefined); + } + }); } render() { + const {value} = this.state; + + const containsValues = ( + value.length > 0 && + !value.every(val => { + return (val === "" || val === undefined) + }) + ); + const inputs = Array(this.props.length).fill(null).map((_, i) => { if(this.props.type === 'number') { return } else { return } diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index f2fa3ce..1c8326d 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -83,9 +83,10 @@ class NumberInput extends React.Component { spellCheck="false" className="maputnik-number" placeholder={this.props.default} - value={this.state.value || ""} + value={this.state.value === undefined ? "" : this.state.value} onChange={e => this.changeValue(e.target.value)} onBlur={this.resetValue} + required={this.props.required} /> } } diff --git a/src/components/inputs/StringInput.jsx b/src/components/inputs/StringInput.jsx index 875a454..2819cc0 100644 --- a/src/components/inputs/StringInput.jsx +++ b/src/components/inputs/StringInput.jsx @@ -50,7 +50,7 @@ class StringInput extends React.Component { spellCheck: !(tag === "input"), className: classes.join(" "), style: this.props.style, - value: this.state.value, + value: this.state.value === undefined ? "" : this.state.value, placeholder: this.props.default, onChange: e => { this.setState({ @@ -63,7 +63,8 @@ class StringInput extends React.Component { this.setState({editing: false}); this.props.onChange(this.state.value); } - } + }, + required: this.props.required, }); } } diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx index 5b918b7..de4ced5 100644 --- a/src/components/modals/SettingsModal.jsx +++ b/src/components/modals/SettingsModal.jsx @@ -139,6 +139,16 @@ class SettingsModal extends React.Component { /> + + + + + + + + Date: Sat, 19 Oct 2019 12:21:38 +0100 Subject: [PATCH 26/88] Fixed lint errors. --- src/components/inputs/NumberInput.jsx | 1 + src/components/inputs/StringInput.jsx | 1 + 2 files changed, 2 insertions(+) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index 1c8326d..b2d7dec 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -8,6 +8,7 @@ class NumberInput extends React.Component { min: PropTypes.number, max: PropTypes.number, onChange: PropTypes.func, + required: PropTypes.bool, } constructor(props) { diff --git a/src/components/inputs/StringInput.jsx b/src/components/inputs/StringInput.jsx index 2819cc0..e160d69 100644 --- a/src/components/inputs/StringInput.jsx +++ b/src/components/inputs/StringInput.jsx @@ -9,6 +9,7 @@ class StringInput extends React.Component { default: PropTypes.string, onChange: PropTypes.func, multi: PropTypes.bool, + required: PropTypes.bool, } constructor(props) { From bf84fd24ee67d954f93bc4860fc971a5de600791 Mon Sep 17 00:00:00 2001 From: orangemug Date: Sat, 19 Oct 2019 12:33:54 +0100 Subject: [PATCH 27/88] Moved profiling to wdio-steps --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2328ded..0948946 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -18,7 +18,6 @@ templates: - run: mkdir -p /tmp/artifacts/logs - run: npm run build - - run: npm run profiling-build - run: npm run lint - run: npm run lint-styles - store_artifacts: @@ -42,6 +41,7 @@ templates: - run: mkdir -p /tmp/artifacts/logs - run: npm run build + - run: npm run profiling-build - run: npm run lint - run: npm run lint-styles - run: DOCKER_HOST=localhost npm test From 19e82e5890ba25368fbcf2fef2adb41ea41ed522 Mon Sep 17 00:00:00 2001 From: orangemug Date: Sat, 19 Oct 2019 13:11:29 +0100 Subject: [PATCH 28/88] Added support for raw GeoJSON --- src/components/modals/SourcesModal.jsx | 18 ++++++++++--- src/components/sources/SourceTypeEditor.jsx | 29 ++++++++++++++++++--- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/components/modals/SourcesModal.jsx b/src/components/modals/SourcesModal.jsx index eee6c85..06f0aeb 100644 --- a/src/components/modals/SourcesModal.jsx +++ b/src/components/modals/SourcesModal.jsx @@ -52,7 +52,14 @@ function editorMode(source) { if(source.tiles) return 'tilexyz_vector' return 'tilejson_vector' } - if(source.type === 'geojson') return 'geojson' + if(source.type === 'geojson') { + if (typeof(source.data) === "string") { + return 'geojson_url'; + } + else { + return 'geojson_json'; + } + } return null } @@ -106,10 +113,14 @@ class AddSource extends React.Component { defaultSource(mode) { const source = (this.state || {}).source || {} switch(mode) { - case 'geojson': return { + case 'geojson_url': return { type: 'geojson', data: source.data || 'http://localhost:3000/geojson.json' } + case 'geojson_json': return { + type: 'geojson', + data: source.data || {} + } case 'tilejson_vector': return { type: 'vector', url: source.url || 'http://localhost:3000/tilejson.json' @@ -155,7 +166,8 @@ class AddSource extends React.Component { + return this.props.onChange({ @@ -105,6 +106,27 @@ class GeoJSONSourceEditor extends React.Component { } } +class GeoJSONSourceJSONEditor extends React.Component { + static propTypes = { + source: PropTypes.object.isRequired, + onChange: PropTypes.func.isRequired, + } + + render() { + return + { + this.props.onChange({ + ...this.props.source, + data, + }) + }} + /> + + } +} + class SourceTypeEditor extends React.Component { static propTypes = { mode: PropTypes.string.isRequired, @@ -118,7 +140,8 @@ class SourceTypeEditor extends React.Component { onChange: this.props.onChange, } switch(this.props.mode) { - case 'geojson': return + case 'geojson_url': return + case 'geojson_json': return case 'tilejson_vector': return case 'tilexyz_vector': return case 'tilejson_raster': return From 9ac908948d92ae021c975684e970fd1376ef241c Mon Sep 17 00:00:00 2001 From: orangemug Date: Sat, 19 Oct 2019 13:12:09 +0100 Subject: [PATCH 29/88] Changed label/content styling for input blocks. --- src/styles/_modal.scss | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss index d4f11f1..2f6b1b7 100644 --- a/src/styles/_modal.scss +++ b/src/styles/_modal.scss @@ -180,10 +180,26 @@ border-width: 2px; border-style: solid; padding: $margin-2; + + .maputnik-input-block-label { + width: 30%; + } + + .maputnik-input-block-content { + width: 70%; + } } .maputnik-add-source { @extend .clearfix; + + .maputnik-input-block-label { + width: 30%; + } + + .maputnik-input-block-content { + width: 70%; + } } .maputnik-add-source-button { From ee525631fa6596b91e8afd5c9af4e1d4bdcf16b1 Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 20 Oct 2019 11:09:20 +0100 Subject: [PATCH 30/88] Fixes for codemirror in sources modal - Allows for max height - Override GeoJSON data when changing type --- src/components/layers/JSONEditor.jsx | 19 +++++++++++++------ src/components/modals/SourcesModal.jsx | 4 ++-- src/components/sources/SourceTypeEditor.jsx | 1 + src/styles/_codemirror.scss | 8 ++++++++ src/styles/index.scss | 1 + 5 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 src/styles/_codemirror.scss diff --git a/src/components/layers/JSONEditor.jsx b/src/components/layers/JSONEditor.jsx index 2f01b82..5621459 100644 --- a/src/components/layers/JSONEditor.jsx +++ b/src/components/layers/JSONEditor.jsx @@ -69,12 +69,19 @@ class JSONEditor extends React.Component { scrollbarStyle: "null", } - return this.onCodeUpdate(value)} - onFocusChange={focused => focused ? true : this.resetValue()} - options={codeMirrorOptions} - /> + const style = {}; + if (this.props.maxHeight) { + style.maxHeight = this.props.maxHeight; + } + + return
+ this.onCodeUpdate(value)} + onFocusChange={focused => focused ? true : this.resetValue()} + options={codeMirrorOptions} + /> +
} } diff --git a/src/components/modals/SourcesModal.jsx b/src/components/modals/SourcesModal.jsx index 06f0aeb..2d5c8ba 100644 --- a/src/components/modals/SourcesModal.jsx +++ b/src/components/modals/SourcesModal.jsx @@ -115,11 +115,11 @@ class AddSource extends React.Component { switch(mode) { case 'geojson_url': return { type: 'geojson', - data: source.data || 'http://localhost:3000/geojson.json' + data: 'http://localhost:3000/geojson.json' } case 'geojson_json': return { type: 'geojson', - data: source.data || {} + data: {} } case 'tilejson_vector': return { type: 'vector', diff --git a/src/components/sources/SourceTypeEditor.jsx b/src/components/sources/SourceTypeEditor.jsx index 5c4c2ec..83672e1 100644 --- a/src/components/sources/SourceTypeEditor.jsx +++ b/src/components/sources/SourceTypeEditor.jsx @@ -116,6 +116,7 @@ class GeoJSONSourceJSONEditor extends React.Component { return { this.props.onChange({ ...this.props.source, diff --git a/src/styles/_codemirror.scss b/src/styles/_codemirror.scss new file mode 100644 index 0000000..d2956c9 --- /dev/null +++ b/src/styles/_codemirror.scss @@ -0,0 +1,8 @@ +.CodeMirror-lint-tooltip { + z-index: 2000 !important; +} + +.CodeMirror-wrapper { + position: relative; + overflow: auto; +} diff --git a/src/styles/index.scss b/src/styles/index.scss index b27341d..abdca0d 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -37,6 +37,7 @@ $toolbar-offset: 0; @import 'zoomproperty'; @import 'popup'; @import 'map'; +@import 'codemirror'; @import 'react-collapse'; @import 'react-codemirror'; From 72b6dd1ae99bfd0d86a7569da165de35987096c7 Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 20 Oct 2019 11:12:54 +0100 Subject: [PATCH 31/88] Fix lint errors. --- src/components/layers/JSONEditor.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/layers/JSONEditor.jsx b/src/components/layers/JSONEditor.jsx index 5621459..34a2fb6 100644 --- a/src/components/layers/JSONEditor.jsx +++ b/src/components/layers/JSONEditor.jsx @@ -19,6 +19,7 @@ import '../../vendor/codemirror/addon/lint/json-lint' class JSONEditor extends React.Component { static propTypes = { layer: PropTypes.object.isRequired, + maxHeight: PropTypes.number, onChange: PropTypes.func, } From 0fa4d40e92df42f4d38b3ee5bcaedced9c387b3d Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 20 Oct 2019 11:21:38 +0100 Subject: [PATCH 32/88] Remove duplicate import rule. --- src/styles/index.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/src/styles/index.scss b/src/styles/index.scss index 287bc87..49af915 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -39,7 +39,6 @@ $toolbar-offset: 0; @import 'map'; @import 'codemirror'; @import 'react-collapse'; -@import 'codemirror'; /** * Hacks for webdriverio isVisibleWithinViewport From f3b8c5362ad40c4fe4c2517f47c7879d8d8a6093 Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 20 Oct 2019 12:25:43 +0100 Subject: [PATCH 33/88] Remove shouldComponentUpdate because mapbox-gl will do the diff for us, so updates will no longer diff twice. --- src/components/map/MapboxGlMap.jsx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/components/map/MapboxGlMap.jsx b/src/components/map/MapboxGlMap.jsx index ba33fc2..d5b221f 100644 --- a/src/components/map/MapboxGlMap.jsx +++ b/src/components/map/MapboxGlMap.jsx @@ -94,16 +94,6 @@ export default class MapboxGlMap extends React.Component { } } - shouldComponentUpdate(nextProps, nextState) { - let should = false; - try { - should = JSON.stringify(this.props) !== JSON.stringify(nextProps) || JSON.stringify(this.state) !== JSON.stringify(nextState); - } catch(e) { - // no biggie, carry on - } - return should; - } - componentDidUpdate(prevProps) { if(!IS_SUPPORTED) return; From b37b7276fb9c279298ee7bcddab23a80db0b6a6a Mon Sep 17 00:00:00 2001 From: pathmapper Date: Wed, 23 Oct 2019 11:10:05 +0200 Subject: [PATCH 34/88] Add node v13 to test runners --- .circleci/config.yml | 15 +++++++++++++++ appveyor.yml | 1 + 2 files changed, 16 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0948946..7e27134 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -66,6 +66,11 @@ jobs: - image: node:12 working_directory: ~/repo-linux-node-v12 steps: *build-steps + build-linux-node-v13: + docker: + - image: node:13 + working_directory: ~/repo-linux-node-v13 + steps: *build-steps build-osx-node-v8: macos: xcode: "9.0" @@ -90,6 +95,14 @@ jobs: - brew install node@12 working_directory: ~/repo-osx-node-v12 steps: *build-steps + build-osx-node-v13: + macos: + xcode: "9.0" + dependencies: + override: + - brew install node@13 + working_directory: ~/repo-osx-node-v13 + steps: *build-steps workflows: version: 2 @@ -98,6 +111,8 @@ workflows: - build-linux-node-v8 - build-linux-node-v10 - build-linux-node-v12 + - build-linux-node-v13 - build-osx-node-v8 - build-osx-node-v10 - build-osx-node-v12 + - build-osx-node-v13 diff --git a/appveyor.yml b/appveyor.yml index c5a86e5..4bfc59e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,6 +4,7 @@ environment: - nodejs_version: "8" - nodejs_version: "10" - nodejs_version: "12" + - nodejs_version: "13" platform: - x86 - x64 From be39fd2ec8368153647e2ed1d589abcfe514b6a6 Mon Sep 17 00:00:00 2001 From: Frederic Junod Date: Thu, 24 Oct 2019 16:51:37 +0200 Subject: [PATCH 35/88] Activate sponsor button in GitHub See: https://help.github.com/en/github/building-a-strong-community/displaying-a-sponsor-button-in-your-repository --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..c71688f --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: "https://maputnik.github.io/donate" From 58bdd39f9e192573b41171344b2326943f46814d Mon Sep 17 00:00:00 2001 From: Oliver Snowden Date: Fri, 25 Oct 2019 00:24:55 +0800 Subject: [PATCH 36/88] set OS Zoomstack endpoints to v2 --- src/config/styles.json | 8 ++++---- src/config/tilesets.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/config/styles.json b/src/config/styles.json index 155b927..c0a6595 100644 --- a/src/config/styles.json +++ b/src/config/styles.json @@ -38,25 +38,25 @@ { "id": "os-zoomstack-outdoor", "title": "Zoomstack Outdoor", - "url": "https://s3-eu-west-1.amazonaws.com/tiles.os.uk/styles/open-zoomstack-outdoor/style.json", + "url": "https://s3-eu-west-1.amazonaws.com/tiles.os.uk/v2/styles/open-zoomstack-outdoor/style.json", "thumbnail": "https://maputnik.github.io/thumbnails/os-zoomstack-outdoor.png" }, { "id": "os-zoomstack-road", "title": "Zoomstack Road", - "url": "https://s3-eu-west-1.amazonaws.com/tiles.os.uk/styles/open-zoomstack-road/style.json", + "url": "https://s3-eu-west-1.amazonaws.com/tiles.os.uk/v2/styles/open-zoomstack-road/style.json", "thumbnail": "https://maputnik.github.io/thumbnails/os-zoomstack-road.png" }, { "id": "os-zoomstack-light", "title": "Zoomstack Light", - "url": "https://s3-eu-west-1.amazonaws.com/tiles.os.uk/styles/open-zoomstack-light/style.json", + "url": "https://s3-eu-west-1.amazonaws.com/tiles.os.uk/v2/styles/open-zoomstack-light/style.json", "thumbnail": "https://maputnik.github.io/thumbnails/os-zoomstack-light.png" }, { "id": "os-zoomstack-night", "title": "Zoomstack Night", - "url": "https://s3-eu-west-1.amazonaws.com/tiles.os.uk/styles/open-zoomstack-night/style.json", + "url": "https://s3-eu-west-1.amazonaws.com/tiles.os.uk/v2/styles/open-zoomstack-night/style.json", "thumbnail": "https://maputnik.github.io/thumbnails/os-zoomstack-night.png" }, { diff --git a/src/config/tilesets.json b/src/config/tilesets.json index a586c10..1cd0286 100644 --- a/src/config/tilesets.json +++ b/src/config/tilesets.json @@ -16,7 +16,7 @@ }, "open_zoomstack": { "type": "vector", - "url": "https://s3-eu-west-1.amazonaws.com/tiles.os.uk/data/vector/open-zoomstack/config.json", + "url": "https://s3-eu-west-1.amazonaws.com/tiles.os.uk/v2/data/vector/open-zoomstack/config.json", "title": "OS Open Zoomstack" } } From fbf5cec6703c79e5d84020ad6d6876975a96233a Mon Sep 17 00:00:00 2001 From: Frederic Junod Date: Fri, 25 Oct 2019 13:16:00 +0200 Subject: [PATCH 37/88] Simplify and fix vertical alignment Use the same css as the `maputnik-make-data-function` and `maputnik-make-zoom-function` buttons. --- src/styles/_zoomproperty.scss | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/styles/_zoomproperty.scss b/src/styles/_zoomproperty.scss index 0c5adb0..2b9ce14 100644 --- a/src/styles/_zoomproperty.scss +++ b/src/styles/_zoomproperty.scss @@ -45,17 +45,12 @@ } .maputnik-delete-stop { + display: inline-block; + padding-bottom: 0; + padding-top: 0; + vertical-align: middle; + @extend .maputnik-icon-button; - - vertical-align: top; - - .maputnik-doc-wrapper { - width: auto; - } - - .maputnik-doc-target { - cursor: pointer; - } } .maputnik-add-stop { From ca202d7701c3873e07a2c8422ec1b6caf742fc24 Mon Sep 17 00:00:00 2001 From: orangemug Date: Fri, 25 Oct 2019 22:48:37 +0100 Subject: [PATCH 38/88] Use for enums again --- src/components/fields/SpecField.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/fields/SpecField.jsx b/src/components/fields/SpecField.jsx index 1f2aac6..194e123 100644 --- a/src/components/fields/SpecField.jsx +++ b/src/components/fields/SpecField.jsx @@ -11,7 +11,7 @@ import ArrayInput from '../inputs/ArrayInput' import DynamicArrayInput from '../inputs/DynamicArrayInput' import FontInput from '../inputs/FontInput' import IconInput from '../inputs/IconInput' -import EnumInput from '../inputs/SelectInput' +import EnumInput from '../inputs/EnumInput' import capitalize from 'lodash.capitalize' const iconProperties = ['background-pattern', 'fill-pattern', 'line-pattern', 'fill-extrusion-pattern', 'icon-image'] From 4cbcf14588e975234bb15b0f6f23917a2b6b3d91 Mon Sep 17 00:00:00 2001 From: orangemug Date: Fri, 25 Oct 2019 22:54:08 +0100 Subject: [PATCH 39/88] Make up defaults from function field if we can't find one from the spec. --- src/components/fields/FunctionSpecField.jsx | 27 ++++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/components/fields/FunctionSpecField.jsx b/src/components/fields/FunctionSpecField.jsx index 36d7930..75214df 100644 --- a/src/components/fields/FunctionSpecField.jsx +++ b/src/components/fields/FunctionSpecField.jsx @@ -14,6 +14,25 @@ function isDataField(value) { return typeof value === 'object' && value.stops && typeof value.property !== 'undefined' } +/** + * If we don't have a default value just make one up + */ +function findDefaultFromSpec (spec) { + if (spec.default) { + return spec.default; + } + + const defaults = { + 'color': '#000000', + 'string': '', + 'boolean': false, + 'number': 0, + 'array': [], + } + + return defaults[spec.type] || ''; +} + /** Supports displaying spec field for zoom function objects * https://www.mapbox.com/mapbox-gl-style-spec/#types-function-zoom-property */ @@ -82,8 +101,8 @@ export default class FunctionSpecProperty extends React.Component { makeZoomFunction = () => { const zoomFunc = { stops: [ - [6, this.props.value], - [10, this.props.value] + [6, this.props.value || findDefaultFromSpec(this.props.fieldSpec)], + [10, this.props.value || findDefaultFromSpec(this.props.fieldSpec)] ] } this.props.onChange(this.props.fieldName, zoomFunc) @@ -96,8 +115,8 @@ export default class FunctionSpecProperty extends React.Component { property: "", type: functionType, stops: [ - [{zoom: 6, value: stopValue}, this.props.value || stopValue], - [{zoom: 10, value: stopValue}, this.props.value || stopValue] + [{zoom: 6, value: stopValue}, this.props.value || findDefaultFromSpec(this.props.fieldSpec)], + [{zoom: 10, value: stopValue}, this.props.value || findDefaultFromSpec(this.props.fieldSpec)] ] } this.props.onChange(this.props.fieldName, dataFunc) From 7075a8b05e054ea4eec8f6b307e8adeb5d68f6e6 Mon Sep 17 00:00:00 2001 From: pathmapper Date: Sat, 26 Oct 2019 07:10:30 +0200 Subject: [PATCH 40/88] Update mbgl and style-spec --- package-lock.json | 14 +++++++------- package.json | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index ecc57ec..0fc459b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -964,9 +964,9 @@ "integrity": "sha512-RaCYfnxULUUUxNwcUimV9C/o2295ktTyLEUzD/+VWkqXqvaVfFcZ5slytGzb2Sd/Jj4MlbxD0DCZbfa6CzcmMw==" }, "@mapbox/mapbox-gl-style-spec": { - "version": "13.9.0", - "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.9.0.tgz", - "integrity": "sha512-w7wqxZ9pIyqyk30cj3ujmhaldnGhg9aNTmQX7nUE6aMuhhen0mMrVhTNgET11/LIMkr/yZE1BOdQ8Fbyb/2/FA==", + "version": "13.9.1", + "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.9.1.tgz", + "integrity": "sha512-7sOXtrliGz3LAErjJc0q1MtYGcmgwwE1G/PzoTrhvSQTcexSVz+v88QKZ4lAzvhF36ItxzI/UdFilsssAw6hYQ==", "requires": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", "@mapbox/unitbezier": "^0.0.0", @@ -7095,9 +7095,9 @@ } }, "mapbox-gl": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-1.4.1.tgz", - "integrity": "sha512-4Jkf1JjsBFKlZA3BHHghgIogbbOuodjVjsdOR/j4AtfLx0G4jXrPcGvwSEVcwyQ27kVECBCn6EyRb6eUNUQujw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-1.5.0.tgz", + "integrity": "sha512-seTQUttE7XaL93on+zfLv06HmROsIdTh3riEPrBdbylSirLmBRnofG+iV873ZbJQElf+d2USyHpWAJm37RehEQ==", "requires": { "@mapbox/geojson-rewind": "^0.4.0", "@mapbox/geojson-types": "^1.0.2", @@ -7115,7 +7115,7 @@ "grid-index": "^1.1.0", "minimist": "0.0.8", "murmurhash-js": "^1.0.0", - "pbf": "^3.0.5", + "pbf": "^3.2.1", "potpack": "^1.0.1", "quickselect": "^2.0.0", "rw": "^1.3.3", diff --git a/package.json b/package.json index 3cb0201..c08f087 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "dependencies": { "@babel/runtime": "^7.6.3", "@mapbox/mapbox-gl-rtl-text": "^0.2.3", - "@mapbox/mapbox-gl-style-spec": "^13.9.0", + "@mapbox/mapbox-gl-style-spec": "^13.9.1", "classnames": "^2.2.6", "codemirror": "^5.49.0", "color": "^3.1.2", @@ -37,7 +37,7 @@ "lodash.get": "^4.4.2", "lodash.isequal": "^4.5.0", "lodash.throttle": "^4.1.1", - "mapbox-gl": "^1.4.1", + "mapbox-gl": "^1.5.0", "mapbox-gl-inspect": "^1.3.1", "maputnik-design": "github:maputnik/design", "ol": "^6.0.1", From d06e053d34919df2a9b36f073c64547df15eeb5e Mon Sep 17 00:00:00 2001 From: orangemug Date: Sat, 26 Oct 2019 17:15:25 +0100 Subject: [PATCH 41/88] Fix zoom ordering for data property fields. --- src/components/fields/_DataProperty.jsx | 78 ++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/src/components/fields/_DataProperty.jsx b/src/components/fields/_DataProperty.jsx index 4116031..acfa2f6 100644 --- a/src/components/fields/_DataProperty.jsx +++ b/src/components/fields/_DataProperty.jsx @@ -8,11 +8,32 @@ import StringInput from '../inputs/StringInput' import SelectInput from '../inputs/SelectInput' import DocLabel from './DocLabel' import InputBlock from '../inputs/InputBlock' +import docUid from '../../libs/document-uid' +import sortNumerically from '../../libs/sort-numerically' import labelFromFieldName from './_labelFromFieldName' import DeleteStopButton from './_DeleteStopButton' + +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 DataProperty extends React.Component { static propTypes = { onChange: PropTypes.func, @@ -29,6 +50,30 @@ export default class DataProperty extends React.Component { ]), } + state = { + refs: {} + } + + componentDidMount() { + const newRefs = setStopRefs(this.props, this.state); + + if(newRefs) { + this.setState({ + refs: newRefs + }) + } + } + + static getDerivedStateFromProps(props, state) { + const newRefs = setStopRefs(props, state); + if(newRefs) { + return { + refs: newRefs + }; + } + return null; + } + getFieldFunctionType(fieldSpec) { if (fieldSpec.expression.interpolated) { return "exponential" @@ -48,14 +93,42 @@ export default class DataProperty extends React.Component { } } + // Order the stops altering the refs to reflect their new position. + orderStopsByZoom(stops) { + const mappedWithRef = stops + .map((stop, idx) => { + return { + ref: this.state.refs[idx], + data: stop + } + }) + // Sort by zoom + .sort((a, b) => sortNumerically(a.data[0].zoom, b.data[0].zoom)); + + // Fetch the new position of the stops + const newRefs = {}; + mappedWithRef + .forEach((stop, idx) =>{ + newRefs[idx] = stop.ref; + }) + + this.setState({ + refs: newRefs + }); + + return mappedWithRef.map((item) => item.data); + } changeStop(changeIdx, stopData, value) { const stops = this.props.value.stops.slice(0) const changedStop = stopData.zoom === undefined ? stopData.value : stopData stops[changeIdx] = [changedStop, value] + + const orderedStops = this.orderStopsByZoom(stops); + const changedValue = { ...this.props.value, - stops: stops, + stops: orderedStops, } this.props.onChange(this.props.fieldName, changedValue) } @@ -77,6 +150,7 @@ export default class DataProperty extends React.Component { const dataFields = this.props.value.stops.map((stop, idx) => { const zoomLevel = typeof stop[0] === 'object' ? stop[0].zoom : undefined; + const key = this.state.refs[idx]; const dataLevel = typeof stop[0] === 'object' ? stop[0].value : stop[0]; const value = stop[1] const deleteStopBtn = @@ -107,7 +181,7 @@ export default class DataProperty extends React.Component { } - return + return {zoomInput}
{dataInput} From dddd604f7be1170c91c31af87225f4b0a4a0ebcc Mon Sep 17 00:00:00 2001 From: orangemug Date: Sat, 26 Oct 2019 17:41:56 +0100 Subject: [PATCH 42/88] Removed left over conflict markers and set default. --- src/components/inputs/NumberInput.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index 383e875..890ea49 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -113,7 +113,6 @@ class NumberInput extends React.Component { } render() { -<<<<<<< HEAD if( this.props.hasOwnProperty("min") && this.props.hasOwnProperty("max") && this.props.min !== undefined && this.props.max !== undefined && @@ -149,7 +148,7 @@ class NumberInput extends React.Component { spellCheck="false" className="maputnik-number" placeholder={this.props.default} - value={this.state.dirtyValue} + value={this.state.dirtyValue === undefined ? "" : this.state.dirtyValue} onChange={e => { this.changeValue(e.target.value) }} From d61d0a5795b3c16ac654b65d718de7eb14510c26 Mon Sep 17 00:00:00 2001 From: orangemug Date: Sat, 26 Oct 2019 18:09:07 +0100 Subject: [PATCH 43/88] Fix test for range slider. --- test/functional/layers/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/layers/index.js b/test/functional/layers/index.js index 7665bc1..1186e41 100644 --- a/test/functional/layers/index.js +++ b/test/functional/layers/index.js @@ -200,7 +200,7 @@ describe("layers", function() { const elem = $(wd.$("layer-list-item:background:"+bgId)); elem.click(); - browser.setValueSafe(wd.$("min-zoom", "input"), 1) + browser.setValueSafe(wd.$("min-zoom", 'input[type="text"]'), 1) const elem2 = $(wd.$("layer-editor.layer-id", "input")); elem2.click(); @@ -232,7 +232,7 @@ describe("layers", function() { const elem = $(wd.$("layer-list-item:background:"+bgId)); elem.click(); - browser.setValueSafe(wd.$("max-zoom", "input"), 1) + browser.setValueSafe(wd.$("max-zoom", 'input[type="text"]'), 1) const elem2 = $(wd.$("layer-editor.layer-id", "input")); elem2.click(); From c588164190edd853dc314105f6bbe3d71a7feaf8 Mon Sep 17 00:00:00 2001 From: orangemug Date: Sat, 26 Oct 2019 18:27:11 +0100 Subject: [PATCH 44/88] console.log map errors. --- src/components/map/MapboxGlMap.jsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/map/MapboxGlMap.jsx b/src/components/map/MapboxGlMap.jsx index d5b221f..1530f4e 100644 --- a/src/components/map/MapboxGlMap.jsx +++ b/src/components/map/MapboxGlMap.jsx @@ -180,6 +180,10 @@ export default class MapboxGlMap extends React.Component { }) }) + map.on("error", e => { + console.log("ERROR", e); + }) + map.on("zoom", e => { this.setState({ zoom: map.getZoom() From 663f2956233799ef5a41257ee63ae4052e2c4ba9 Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 27 Oct 2019 10:00:22 +0000 Subject: [PATCH 45/88] Added default protocol and stub in error. --- src/components/modals/SourcesModal.jsx | 39 ++++++++++++++++++++------ 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/components/modals/SourcesModal.jsx b/src/components/modals/SourcesModal.jsx index 2d5c8ba..ad66243 100644 --- a/src/components/modals/SourcesModal.jsx +++ b/src/components/modals/SourcesModal.jsx @@ -112,10 +112,12 @@ class AddSource extends React.Component { defaultSource(mode) { const source = (this.state || {}).source || {} + const {protocol} = window.location; + switch(mode) { case 'geojson_url': return { type: 'geojson', - data: 'http://localhost:3000/geojson.json' + data: `${protocol}//localhost:3000/geojson.json` } case 'geojson_json': return { type: 'geojson', @@ -123,31 +125,31 @@ class AddSource extends React.Component { } case 'tilejson_vector': return { type: 'vector', - url: source.url || 'http://localhost:3000/tilejson.json' + url: source.url || `${protocol}//localhost:3000/tilejson.json` } case 'tilexyz_vector': return { type: 'vector', - tiles: source.tiles || ['http://localhost:3000/{x}/{y}/{z}.pbf'], + tiles: source.tiles || [`${protocol}//localhost:3000/{x}/{y}/{z}.pbf`], minZoom: source.minzoom || 0, maxZoom: source.maxzoom || 14 } case 'tilejson_raster': return { type: 'raster', - url: source.url || 'http://localhost:3000/tilejson.json' + url: source.url || `${protocol}//localhost:3000/tilejson.json` } case 'tilexyz_raster': return { type: 'raster', - tiles: source.tiles || ['http://localhost:3000/{x}/{y}/{z}.pbf'], + tiles: source.tiles || [`${protocol}//localhost:3000/{x}/{y}/{z}.pbf`], minzoom: source.minzoom || 0, maxzoom: source.maxzoom || 14 } case 'tilejson_raster-dem': return { type: 'raster-dem', - url: source.url || 'http://localhost:3000/tilejson.json' + url: source.url || `${protocol}//localhost:3000/tilejson.json` } case 'tilexyz_raster-dem': return { type: 'raster-dem', - tiles: source.tiles || ['http://localhost:3000/{x}/{y}/{z}.pbf'], + tiles: source.tiles || [`${protocol}//localhost:3000/{x}/{y}/{z}.pbf`], minzoom: source.minzoom || 0, maxzoom: source.maxzoom || 14 } @@ -155,6 +157,18 @@ class AddSource extends React.Component { } } + onAdd = () => { + this.props.onAdd(this.state.sourceId, this.state.source); + } + + onChangeSource = (source) => { + // let error = "CORs policy won't allow fetching resources served over http from https"; + this.setState({ + source, + error, + }); + } + render() { return
@@ -180,13 +194,20 @@ class AddSource extends React.Component { /> this.setState({ source: src })} + onChange={this.onChangeSource} mode={this.state.mode} source={this.state.source} /> + {this.state.error && +
+ Error: {this.state.error} +
+ }
From aead867e271e12584af5eedb3398550cad53735b Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 27 Oct 2019 10:05:05 +0000 Subject: [PATCH 46/88] Incorrectly checking for falsey when should be checking for presence. --- src/components/fields/FunctionSpecField.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/fields/FunctionSpecField.jsx b/src/components/fields/FunctionSpecField.jsx index 75214df..e2542c5 100644 --- a/src/components/fields/FunctionSpecField.jsx +++ b/src/components/fields/FunctionSpecField.jsx @@ -18,7 +18,7 @@ function isDataField(value) { * If we don't have a default value just make one up */ function findDefaultFromSpec (spec) { - if (spec.default) { + if (spec.hasOwnProperty('default')) { return spec.default; } From cd162309a82dc3ff92bd216154519ba80f8931cc Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 27 Oct 2019 10:15:11 +0000 Subject: [PATCH 47/88] Added hopeful fix + logging. --- src/components/inputs/NumberInput.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index 890ea49..ea1fba2 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -92,6 +92,7 @@ class NumberInput extends React.Component { } onChangeRange = (e) => { + console.log(">> onChangeRange"); const value = parseFloat(e.target.value, 10); const step = this.props.rangeStep; let dirtyValue = value; @@ -131,8 +132,9 @@ class NumberInput extends React.Component { step="any" spellCheck="false" value={rangeValue} - onChange={this.onChangeRange} + onInput={this.onChangeRange} onPointerUp={() => { + console.log(">> onPointerUp"); const {dirtyValue} = this.state; const hasChanged = this.state.props !== dirtyValue if(this.isValid(dirtyValue) && hasChanged) { From 5aa0b4e7d9cff57c9c22f82a937fadb5e74a5170 Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 27 Oct 2019 11:01:33 +0000 Subject: [PATCH 48/88] More logging additional attempt at fixes. --- src/components/inputs/NumberInput.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index ea1fba2..ab5ef25 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -93,6 +93,11 @@ class NumberInput extends React.Component { onChangeRange = (e) => { console.log(">> onChangeRange"); + if (this._cancelNextChangeEvent) { + console.log("onChangeRange:cancel"); + this._cancelNextChangeEvent = false; + return; + } const value = parseFloat(e.target.value, 10); const step = this.props.rangeStep; let dirtyValue = value; @@ -133,7 +138,12 @@ class NumberInput extends React.Component { spellCheck="false" value={rangeValue} onInput={this.onChangeRange} + onMouseUp={() => console.log("mouseup")} + onPointerDown={() => { + this._cancelNextChangeEvent = false; + }} onPointerUp={() => { + this._cancelNextChangeEvent = true; console.log(">> onPointerUp"); const {dirtyValue} = this.state; const hasChanged = this.state.props !== dirtyValue From 88841b56e784beea2394cda94f3422906fe8e08c Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 27 Oct 2019 15:56:22 +0000 Subject: [PATCH 49/88] Added another fix attempt and yet more logging. --- src/components/inputs/NumberInput.jsx | 28 +++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/components/inputs/NumberInput.jsx b/src/components/inputs/NumberInput.jsx index ab5ef25..e3262fb 100644 --- a/src/components/inputs/NumberInput.jsx +++ b/src/components/inputs/NumberInput.jsx @@ -1,6 +1,8 @@ import React from 'react' import PropTypes from 'prop-types' +let IDX = 0; + class NumberInput extends React.Component { static propTypes = { value: PropTypes.number, @@ -21,6 +23,7 @@ class NumberInput extends React.Component { constructor(props) { super(props) this.state = { + uuid: IDX++, editing: false, value: props.value, dirtyValue: props.value, @@ -29,6 +32,7 @@ class NumberInput extends React.Component { static getDerivedStateFromProps(props, state) { if (!state.editing) { + console.log("getDerivedStateFromProps[%s]", state.uuid, props.value); return { value: props.value, dirtyValue: props.value, @@ -38,13 +42,14 @@ class NumberInput extends React.Component { } changeValue(newValue) { - this.setState({editing: true}); const value = (newValue === "" || newValue === undefined) ? undefined : parseFloat(newValue); - const hasChanged = this.state.value !== value; + const hasChanged = this.props.value !== value; + console.log("changeValue[%s]->hasChanged", this.state.uuid, value, this.isValid(value), this.props.value, "!==", value) if(this.isValid(value) && hasChanged) { + console.log("changeValue[%s]->onChange", this.state.uuid, value); this.props.onChange(value) } this.setState({ @@ -92,9 +97,9 @@ class NumberInput extends React.Component { } onChangeRange = (e) => { - console.log(">> onChangeRange"); + console.log("onChangeRange[%s]", this.state.uuid); if (this._cancelNextChangeEvent) { - console.log("onChangeRange:cancel"); + console.log("onChangeRange[%s]:cancel", this.state.uuid); this._cancelNextChangeEvent = false; return; } @@ -126,6 +131,7 @@ class NumberInput extends React.Component { ) { const value = this.state.value === undefined ? this.props.default : this.state.value; const rangeValue = Number.isNaN(parseFloat(value, 10)) ? this.props.default : value; + console.log("render[%s]", this.state.uuid, value, rangeValue); return
{ this._cancelNextChangeEvent = false; }} + onBlur={() => { + console.log("onBlur[%s]", this.state.uuid); + this.changeValue(this.state.dirtyValue); + }} onPointerUp={() => { + console.log("onPointerUp[%s]", this.state.uuid); this._cancelNextChangeEvent = true; - console.log(">> onPointerUp"); - const {dirtyValue} = this.state; - const hasChanged = this.state.props !== dirtyValue - if(this.isValid(dirtyValue) && hasChanged) { - this.setState({editing: false}, () => { - this.props.onChange(dirtyValue); - }); - } + this.changeValue(this.state.dirtyValue); }} /> Date: Sun, 27 Oct 2019 17:08:23 +0000 Subject: [PATCH 50/88] Added UrlInput component to tidy things up a little. --- src/components/inputs/StringInput.jsx | 9 ++- src/components/inputs/UrlInput.jsx | 61 +++++++++++++++++++++ src/components/modals/SourcesModal.jsx | 15 +---- src/components/sources/SourceTypeEditor.jsx | 5 +- src/components/util/SmallError.jsx | 20 +++++++ src/components/util/SmallError.scss | 7 +++ src/styles/_vars.scss | 23 ++++++++ src/styles/index.scss | 24 +------- 8 files changed, 126 insertions(+), 38 deletions(-) create mode 100644 src/components/inputs/UrlInput.jsx create mode 100644 src/components/util/SmallError.jsx create mode 100644 src/components/util/SmallError.scss create mode 100644 src/styles/_vars.scss diff --git a/src/components/inputs/StringInput.jsx b/src/components/inputs/StringInput.jsx index e160d69..87bdd31 100644 --- a/src/components/inputs/StringInput.jsx +++ b/src/components/inputs/StringInput.jsx @@ -8,10 +8,15 @@ class StringInput extends React.Component { style: PropTypes.object, default: PropTypes.string, onChange: PropTypes.func, + onInput: PropTypes.func, multi: PropTypes.bool, required: PropTypes.bool, } + static defaultProps = { + onInput: () => {}, + } + constructor(props) { super(props) this.state = { @@ -57,7 +62,9 @@ class StringInput extends React.Component { this.setState({ editing: true, value: e.target.value - }) + }, () => { + this.props.onInput(this.state.value); + }); }, onBlur: () => { if(this.state.value!==this.props.value) { diff --git a/src/components/inputs/UrlInput.jsx b/src/components/inputs/UrlInput.jsx new file mode 100644 index 0000000..b729b07 --- /dev/null +++ b/src/components/inputs/UrlInput.jsx @@ -0,0 +1,61 @@ +import React from 'react' +import PropTypes from 'prop-types' +import StringInput from './StringInput' +import SmallError from '../util/SmallError' + +class UrlInput extends React.Component { + static propTypes = { + "data-wd-key": PropTypes.string, + value: PropTypes.string, + style: PropTypes.object, + default: PropTypes.string, + onChange: PropTypes.func, + multi: PropTypes.bool, + required: PropTypes.bool, + } + + state = { + error: null, + } + + onInput = (url) => { + let error; + const getProtocol = (url) => { + try { + const urlObj = new URL(url); + return urlObj.protocol; + } + catch (err) { + return undefined; + } + }; + const protocol = getProtocol(url); + if ( + protocol && + protocol === "https:" && + window.location.protocol !== "http:" + ) { + error = ( + + CORs policy won't allow fetching resources served over http from https, use a https:// domain + + ); + } + + this.setState({error}); + } + + render () { + return ( +
+ + {this.state.error} +
+ ); + } +} + +export default UrlInput diff --git a/src/components/modals/SourcesModal.jsx b/src/components/modals/SourcesModal.jsx index ad66243..e291607 100644 --- a/src/components/modals/SourcesModal.jsx +++ b/src/components/modals/SourcesModal.jsx @@ -158,15 +158,12 @@ class AddSource extends React.Component { } onAdd = () => { - this.props.onAdd(this.state.sourceId, this.state.source); + const {source, sourceId} = this.state; + this.props.onAdd(sourceId, source); } onChangeSource = (source) => { - // let error = "CORs policy won't allow fetching resources served over http from https"; - this.setState({ - source, - error, - }); + this.setState({source}); } render() { @@ -198,15 +195,9 @@ class AddSource extends React.Component { mode={this.state.mode} source={this.state.source} /> - {this.state.error && -
- Error: {this.state.error} -
- } diff --git a/src/components/sources/SourceTypeEditor.jsx b/src/components/sources/SourceTypeEditor.jsx index 83672e1..12094c0 100644 --- a/src/components/sources/SourceTypeEditor.jsx +++ b/src/components/sources/SourceTypeEditor.jsx @@ -3,6 +3,7 @@ import PropTypes from 'prop-types' import {latest} from '@mapbox/mapbox-gl-style-spec' import InputBlock from '../inputs/InputBlock' import StringInput from '../inputs/StringInput' +import UrlInput from '../inputs/UrlInput' import NumberInput from '../inputs/NumberInput' import SelectInput from '../inputs/SelectInput' import JSONEditor from '../layers/JSONEditor' @@ -18,7 +19,7 @@ class TileJSONSourceEditor extends React.Component { render() { return
- this.props.onChange({ ...this.props.source, @@ -52,7 +53,7 @@ class TileURLSourceEditor extends React.Component { const tiles = this.props.source.tiles || [] return tiles.map((tileUrl, tileIndex) => { return - diff --git a/src/components/util/SmallError.jsx b/src/components/util/SmallError.jsx new file mode 100644 index 0000000..03d9c78 --- /dev/null +++ b/src/components/util/SmallError.jsx @@ -0,0 +1,20 @@ +import React from 'react' +import PropTypes from 'prop-types' +import './SmallError.scss'; + + +class SmallError extends React.Component { + static propTypes = { + children: PropTypes.node, + } + + render () { + return ( +
+ Error: {this.props.children} +
+ ); + } +} + +export default SmallError diff --git a/src/components/util/SmallError.scss b/src/components/util/SmallError.scss new file mode 100644 index 0000000..5433091 --- /dev/null +++ b/src/components/util/SmallError.scss @@ -0,0 +1,7 @@ +@import '../../styles/vars'; + +.SmallError { + color: #E57373; + font-size: $font-size-5; + margin-top: $margin-2 +} diff --git a/src/styles/_vars.scss b/src/styles/_vars.scss new file mode 100644 index 0000000..7cb3d17 --- /dev/null +++ b/src/styles/_vars.scss @@ -0,0 +1,23 @@ +$color-black: #191b20; +$color-gray: #222429; +$color-midgray: #303237; +$color-lowgray: #a4a4a4; +$color-white: #f0f0f0; +$color-red: #cf4a4a; +$color-green: #53b972; +$margin-1: 3px; +$margin-2: 5px; +$margin-3: 10px; +$margin-4: 30px; +$margin-5: 40px; +$font-size-1: 24px; +$font-size-2: 20px; +$font-size-3: 18px; +$font-size-4: 16px; +$font-size-5: 14px; +$font-size-6: 12px; +$font-family: Roboto, sans-serif; + +$toolbar-height: 40px; +$toolbar-offset: 0; + diff --git a/src/styles/index.scss b/src/styles/index.scss index 49af915..759b73c 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -1,26 +1,4 @@ -$color-black: #191b20; -$color-gray: #222429; -$color-midgray: #303237; -$color-lowgray: #a4a4a4; -$color-white: #f0f0f0; -$color-red: #cf4a4a; -$color-green: #53b972; -$margin-1: 3px; -$margin-2: 5px; -$margin-3: 10px; -$margin-4: 30px; -$margin-5: 40px; -$font-size-1: 24px; -$font-size-2: 20px; -$font-size-3: 18px; -$font-size-4: 16px; -$font-size-5: 14px; -$font-size-6: 12px; -$font-family: Roboto, sans-serif; - -$toolbar-height: 40px; -$toolbar-offset: 0; - +@import 'vars'; @import 'mixins'; @import 'reset'; @import 'base'; From f39fb34f36449b54cf31302066b114aaa87c1430 Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 27 Oct 2019 17:15:17 +0000 Subject: [PATCH 51/88] Protocol logic and lint fixes. --- src/components/inputs/UrlInput.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/inputs/UrlInput.jsx b/src/components/inputs/UrlInput.jsx index b729b07..04bb531 100644 --- a/src/components/inputs/UrlInput.jsx +++ b/src/components/inputs/UrlInput.jsx @@ -32,12 +32,12 @@ class UrlInput extends React.Component { const protocol = getProtocol(url); if ( protocol && - protocol === "https:" && - window.location.protocol !== "http:" + protocol === "http:" && + window.location.protocol === "https:" ) { error = ( - CORs policy won't allow fetching resources served over http from https, use a https:// domain + CORs policy won't allow fetching resources served over http from https, use a https:// domain ); } From a51442921ae6af55e63af0a8702073a664d7482c Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 27 Oct 2019 17:19:03 +0000 Subject: [PATCH 52/88] Fix font-size inline with the rest of the UI. --- src/components/util/SmallError.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/util/SmallError.scss b/src/components/util/SmallError.scss index 5433091..1111282 100644 --- a/src/components/util/SmallError.scss +++ b/src/components/util/SmallError.scss @@ -2,6 +2,6 @@ .SmallError { color: #E57373; - font-size: $font-size-5; + font-size: $font-size-6; margin-top: $margin-2 } From f0371b41b1a908c9de7212ea90b7755478c241fb Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 27 Oct 2019 17:27:50 +0000 Subject: [PATCH 53/88] Also validate on constructor --- src/components/inputs/UrlInput.jsx | 62 +++++++++++++++++------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/src/components/inputs/UrlInput.jsx b/src/components/inputs/UrlInput.jsx index 04bb531..971d241 100644 --- a/src/components/inputs/UrlInput.jsx +++ b/src/components/inputs/UrlInput.jsx @@ -3,6 +3,34 @@ import PropTypes from 'prop-types' import StringInput from './StringInput' import SmallError from '../util/SmallError' + +function validate (url) { + let error; + const getProtocol = (url) => { + try { + const urlObj = new URL(url); + return urlObj.protocol; + } + catch (err) { + return undefined; + } + }; + const protocol = getProtocol(url); + if ( + protocol && + protocol === "http:" && + window.location.protocol === "https:" + ) { + error = ( + + CORs policy won't allow fetching resources served over http from https, use a https:// domain + + ); + } + + return error; +} + class UrlInput extends React.Component { static propTypes = { "data-wd-key": PropTypes.string, @@ -14,35 +42,17 @@ class UrlInput extends React.Component { required: PropTypes.bool, } - state = { - error: null, + constructor (props) { + super(props); + this.state = { + error: validate(props.value) + }; } onInput = (url) => { - let error; - const getProtocol = (url) => { - try { - const urlObj = new URL(url); - return urlObj.protocol; - } - catch (err) { - return undefined; - } - }; - const protocol = getProtocol(url); - if ( - protocol && - protocol === "http:" && - window.location.protocol === "https:" - ) { - error = ( - - CORs policy won't allow fetching resources served over http from https, use a https:// domain - - ); - } - - this.setState({error}); + this.setState({ + error: validate(url) + }); } render () { From e728e5f7e43f254acb7039e6c00bbedf2f8905b6 Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 27 Oct 2019 17:35:56 +0000 Subject: [PATCH 54/88] Exposed onInput in --- src/components/inputs/UrlInput.jsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/inputs/UrlInput.jsx b/src/components/inputs/UrlInput.jsx index 971d241..040c2b5 100644 --- a/src/components/inputs/UrlInput.jsx +++ b/src/components/inputs/UrlInput.jsx @@ -42,6 +42,10 @@ class UrlInput extends React.Component { required: PropTypes.bool, } + static defaultProps = { + onInput: () => {}, + } + constructor (props) { super(props); this.state = { @@ -53,6 +57,7 @@ class UrlInput extends React.Component { this.setState({ error: validate(url) }); + this.props.onInput(url); } render () { From 2e017d252aa6420f2fadadfcf533fc3363500f6d Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 27 Oct 2019 17:36:20 +0000 Subject: [PATCH 55/88] Added to open modal. --- src/components/modals/OpenModal.jsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/modals/OpenModal.jsx b/src/components/modals/OpenModal.jsx index d2c6477..dff6f80 100644 --- a/src/components/modals/OpenModal.jsx +++ b/src/components/modals/OpenModal.jsx @@ -4,6 +4,7 @@ import LoadingModal from './LoadingModal' import Modal from './Modal' import Button from '../Button' import FileReaderInput from 'react-file-reader-input' +import UrlInput from '../inputs/UrlInput' import {MdFileUpload} from 'react-icons/md' import {MdAddCircleOutline} from 'react-icons/md' @@ -160,9 +161,9 @@ class OpenModal extends React.Component { this.props.onOpenToggle(); } - onChangeUrl = () => { + onChangeUrl = (url) => { this.setState({ - styleUrl: this.styleUrlElement.value + styleUrl: url, }); } @@ -209,14 +210,13 @@ class OpenModal extends React.Component {

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

- this.styleUrlElement = input} className="maputnik-input" - placeholder="Enter URL..." + default="Enter URL..." value={this.state.styleUrl} - onChange={this.onChangeUrl} + onInput={this.onChangeUrl} />