diff --git a/src/components/fields/ZoomSpecField.jsx b/src/components/fields/ZoomSpecField.jsx index 9f8e755ee..7eaf88f20 100644 --- a/src/components/fields/ZoomSpecField.jsx +++ b/src/components/fields/ZoomSpecField.jsx @@ -13,6 +13,11 @@ import FunctionIcon from 'react-icons/lib/md/functions' import capitalize from 'lodash.capitalize' +let REF = 0; +function getUniqueRef() { + return "r"+REF++; +} + function isZoomField(value) { return typeof value === 'object' && value.stops } @@ -35,6 +40,58 @@ export default class ZoomSpecProperty extends React.Component { ]), } + constructor() { + super() + this.state = { + refs: {} + } + } + + /** + * We cache a reference to the zoom level to use as a key in the react dom. + * + * We update the reference when a stop changed its zoom level. This way input focus is maintained. + */ + _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) => { + const zoomKey = val[0]; + + if(!this.state.refs.hasOwnProperty(zoomKey)) { + if(!newRefs) { + newRefs = {...this.state.refs}; + } + newRefs[zoomKey] = getUniqueRef(); + } + }) + } + + if(newRefs) { + this.setState({ + refs: newRefs + }) + } + } + + _transferStopRef(oldZoomLevel, newZoomLevel) { + let refs = this.state.refs; + let oldRef = refs[oldZoomLevel]; + delete refs[oldZoomLevel]; + + refs[newZoomLevel] = oldRef; + this.setState({ + refs: refs + }) + } + + + componentWillReceiveProps(nextProps) { + this._setStopRefs(nextProps); + } + addStop() { const stops = this.props.value.stops.slice(0) const lastStop = stops[stops.length - 1] @@ -74,12 +131,31 @@ export default class ZoomSpecProperty extends React.Component { this.props.onChange(this.props.fieldName, zoomFunc) } - changeStop(changeIdx, zoomLevel, value) { + sortNumerically(a, b) { + a = parseFloat(a, 10); + b = parseFloat(b, 10); + + if(a < b) { + return -1 + } + else if(a > b) { + return 1 + } + else { + return 0; + } + } + + changeStop(changeIdx, newZoomLevel, value) { const stops = this.props.value.stops.slice(0) - stops[changeIdx] = [zoomLevel, value] + const oldZoomLevel = stops[changeIdx][0]; + + this._transferStopRef(oldZoomLevel, newZoomLevel); + + stops[changeIdx] = [newZoomLevel, value] const changedValue = { ...this.props.value, - stops: stops, + stops: stops.sort((a, b) => this.sortNumerically(a[0], b[0])) } this.props.onChange(this.props.fieldName, changedValue) } @@ -87,11 +163,12 @@ export default class ZoomSpecProperty extends React.Component { renderZoomProperty() { const zoomFields = this.props.value.stops.map((stop, idx) => { const zoomLevel = stop[0] + const key = this.state.refs[zoomLevel]; const value = stop[1] const deleteStopBtn= return