2016-09-10 14:10:25 +02:00
|
|
|
import React from 'react'
|
2017-01-11 18:18:47 +01:00
|
|
|
import classnames from 'classnames'
|
2016-12-20 20:21:35 +01:00
|
|
|
import cloneDeep from 'lodash.clonedeep'
|
2016-09-15 09:13:23 +02:00
|
|
|
|
2017-01-11 15:48:15 +01:00
|
|
|
import Button from '../Button'
|
2017-01-11 17:52:21 +01:00
|
|
|
import LayerListGroup from './LayerListGroup'
|
2016-12-20 11:44:22 +01:00
|
|
|
import LayerListItem from './LayerListItem'
|
2017-01-11 15:48:15 +01:00
|
|
|
import AddIcon from 'react-icons/lib/md/add-circle-outline'
|
2017-01-11 15:59:51 +01:00
|
|
|
import AddModal from '../modals/AddModal'
|
2016-12-20 11:44:22 +01:00
|
|
|
|
2016-12-20 20:21:35 +01:00
|
|
|
import style from '../../libs/style.js'
|
2016-12-17 19:58:30 +01:00
|
|
|
import {SortableContainer, SortableHandle, arrayMove} from 'react-sortable-hoc';
|
2016-12-17 16:09:37 +01:00
|
|
|
|
2016-12-17 19:58:30 +01:00
|
|
|
const layerListPropTypes = {
|
2016-12-20 16:08:49 +01:00
|
|
|
layers: React.PropTypes.array.isRequired,
|
2016-12-20 19:20:56 +01:00
|
|
|
selectedLayerIndex: React.PropTypes.number.isRequired,
|
2016-12-20 20:21:35 +01:00
|
|
|
onLayersChange: React.PropTypes.func.isRequired,
|
|
|
|
onLayerSelect: React.PropTypes.func,
|
2017-01-11 15:59:51 +01:00
|
|
|
sources: React.PropTypes.object.isRequired,
|
2016-12-17 19:58:30 +01:00
|
|
|
}
|
|
|
|
|
2017-01-11 19:39:09 +01:00
|
|
|
function layerPrefix(name) {
|
|
|
|
return name.replace(' ', '-').replace('_', '-').split('-')[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
function findClosestCommonPrefix(layers, idx) {
|
|
|
|
console.log('find prefix', idx, layers)
|
|
|
|
const currentLayerPrefix = layerPrefix(layers[idx].id)
|
|
|
|
let closestIdx = idx
|
|
|
|
for (let i = idx; i > 0; i--) {
|
|
|
|
const previousLayerPrefix = layerPrefix(layers[i-1].id)
|
|
|
|
if(previousLayerPrefix === currentLayerPrefix) {
|
|
|
|
closestIdx = i - 1
|
|
|
|
} else {
|
|
|
|
return closestIdx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return closestIdx
|
|
|
|
}
|
|
|
|
|
2016-12-17 19:58:30 +01:00
|
|
|
// List of collapsible layer editors
|
|
|
|
@SortableContainer
|
|
|
|
class LayerListContainer extends React.Component {
|
|
|
|
static propTypes = {...layerListPropTypes}
|
2016-12-17 16:09:37 +01:00
|
|
|
static defaultProps = {
|
2016-12-20 20:21:35 +01:00
|
|
|
onLayerSelect: () => {},
|
2016-12-04 17:03:36 +01:00
|
|
|
}
|
|
|
|
|
2017-01-11 15:59:51 +01:00
|
|
|
constructor(props) {
|
|
|
|
super(props)
|
|
|
|
this.state = {
|
2017-01-11 18:18:47 +01:00
|
|
|
collapsedGroups: {},
|
2017-01-11 15:59:51 +01:00
|
|
|
isOpen: {
|
|
|
|
add: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-20 20:21:35 +01:00
|
|
|
onLayerDestroy(layerId) {
|
|
|
|
const remainingLayers = this.props.layers.slice(0)
|
|
|
|
const idx = style.indexOfLayer(remainingLayers, layerId)
|
|
|
|
remainingLayers.splice(idx, 1);
|
|
|
|
this.props.onLayersChange(remainingLayers)
|
|
|
|
}
|
|
|
|
|
|
|
|
onLayerCopy(layerId) {
|
|
|
|
const changedLayers = this.props.layers.slice(0)
|
|
|
|
const idx = style.indexOfLayer(changedLayers, layerId)
|
|
|
|
|
|
|
|
const clonedLayer = cloneDeep(changedLayers[idx])
|
|
|
|
clonedLayer.id = clonedLayer.id + "-copy"
|
|
|
|
changedLayers.splice(idx, 0, clonedLayer)
|
|
|
|
this.props.onLayersChange(changedLayers)
|
|
|
|
}
|
|
|
|
|
|
|
|
onLayerVisibilityToggle(layerId) {
|
|
|
|
const changedLayers = this.props.layers.slice(0)
|
|
|
|
const idx = style.indexOfLayer(changedLayers, layerId)
|
|
|
|
|
|
|
|
const layer = { ...changedLayers[idx] }
|
|
|
|
const changedLayout = 'layout' in layer ? {...layer.layout} : {}
|
|
|
|
changedLayout.visibility = changedLayout.visibility === 'none' ? 'visible' : 'none'
|
|
|
|
|
|
|
|
layer.layout = changedLayout
|
|
|
|
changedLayers[idx] = layer
|
|
|
|
this.props.onLayersChange(changedLayers)
|
2016-12-04 17:03:36 +01:00
|
|
|
}
|
|
|
|
|
2017-01-11 15:59:51 +01:00
|
|
|
toggleModal(modalName) {
|
|
|
|
this.setState({
|
|
|
|
isOpen: {
|
|
|
|
...this.state.isOpen,
|
|
|
|
[modalName]: !this.state.isOpen[modalName]
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-01-11 17:52:21 +01:00
|
|
|
groupedLayers() {
|
|
|
|
const groups = []
|
|
|
|
for (let i = 0; i < this.props.layers.length; i++) {
|
|
|
|
const previousLayer = this.props.layers[i-1]
|
|
|
|
const layer = this.props.layers[i]
|
|
|
|
if(previousLayer && layerPrefix(previousLayer.id) == layerPrefix(layer.id)) {
|
|
|
|
const lastGroup = groups[groups.length - 1]
|
|
|
|
lastGroup.push(layer)
|
|
|
|
} else {
|
|
|
|
groups.push([layer])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return groups
|
|
|
|
}
|
|
|
|
|
2017-01-11 19:39:09 +01:00
|
|
|
toggleLayerGroup(groupPrefix, idx) {
|
|
|
|
const lookupKey = [groupPrefix, idx].join('-')
|
2017-01-11 18:18:47 +01:00
|
|
|
const newGroups = { ...this.state.collapsedGroups }
|
2017-01-11 19:39:09 +01:00
|
|
|
if(lookupKey in this.state.collapsedGroups) {
|
|
|
|
newGroups[lookupKey] = !this.state.collapsedGroups[lookupKey]
|
2017-01-11 18:18:47 +01:00
|
|
|
} else {
|
2017-01-11 19:39:09 +01:00
|
|
|
newGroups[lookupKey] = true
|
2017-01-11 18:18:47 +01:00
|
|
|
}
|
2017-01-11 19:39:09 +01:00
|
|
|
console.log(newGroups)
|
2017-01-11 18:18:47 +01:00
|
|
|
this.setState({
|
|
|
|
collapsedGroups: newGroups
|
2017-01-11 17:52:21 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-01-11 19:39:09 +01:00
|
|
|
isCollapsed(groupPrefix, idx) {
|
|
|
|
console.log('is collapsed', groupPrefix, idx)
|
|
|
|
const collapsed = this.state.collapsedGroups[[groupPrefix, idx].join('-')]
|
|
|
|
return collapsed === undefined ? false : collapsed
|
|
|
|
}
|
|
|
|
|
2016-12-04 17:03:36 +01:00
|
|
|
render() {
|
2017-01-11 18:18:47 +01:00
|
|
|
|
2017-01-11 17:52:21 +01:00
|
|
|
const listItems = []
|
|
|
|
let idx = 0
|
|
|
|
this.groupedLayers().forEach(layers => {
|
2017-01-11 18:18:47 +01:00
|
|
|
const groupPrefix = layerPrefix(layers[0].id)
|
2017-01-11 17:52:21 +01:00
|
|
|
if(layers.length > 1) {
|
|
|
|
const grp = <LayerListGroup
|
2017-01-11 19:39:09 +01:00
|
|
|
key={[groupPrefix, idx].join('-')}
|
2017-01-11 17:52:21 +01:00
|
|
|
title={groupPrefix}
|
2017-01-11 19:39:09 +01:00
|
|
|
isActive={!this.isCollapsed(groupPrefix, idx)}
|
|
|
|
onActiveToggle={this.toggleLayerGroup.bind(this, groupPrefix, idx)}
|
2017-01-11 17:52:21 +01:00
|
|
|
/>
|
|
|
|
listItems.push(grp)
|
|
|
|
}
|
|
|
|
|
2017-01-11 19:39:09 +01:00
|
|
|
layers.forEach((layer, idxInGroup) => {
|
|
|
|
const groupIdx = findClosestCommonPrefix(this.props.layers, idx)
|
2017-01-11 17:52:21 +01:00
|
|
|
const listItem = <LayerListItem
|
2017-01-11 18:18:47 +01:00
|
|
|
className={classnames({
|
2017-01-11 19:39:09 +01:00
|
|
|
'maputnik-layer-list-item-collapsed': this.isCollapsed(groupPrefix, groupIdx),
|
|
|
|
'maputnik-layer-list-item-collapsed-last': idxInGroup == layers.length - 1 && layers.length > 1
|
2017-01-11 18:18:47 +01:00
|
|
|
})}
|
2017-01-11 17:52:21 +01:00
|
|
|
index={idx}
|
|
|
|
key={layer.id}
|
|
|
|
layerId={layer.id}
|
|
|
|
layerType={layer.type}
|
|
|
|
visibility={(layer.layout || {}).visibility}
|
|
|
|
isSelected={idx === this.props.selectedLayerIndex}
|
|
|
|
onLayerSelect={this.props.onLayerSelect}
|
|
|
|
onLayerDestroy={this.onLayerDestroy.bind(this)}
|
|
|
|
onLayerCopy={this.onLayerCopy.bind(this)}
|
|
|
|
onLayerVisibilityToggle={this.onLayerVisibilityToggle.bind(this)}
|
|
|
|
/>
|
|
|
|
listItems.push(listItem)
|
|
|
|
idx += 1
|
|
|
|
})
|
2016-12-17 19:58:30 +01:00
|
|
|
})
|
2017-01-11 17:52:21 +01:00
|
|
|
|
2017-01-11 15:48:15 +01:00
|
|
|
return <div className="maputnik-layer-list">
|
2017-01-11 15:59:51 +01:00
|
|
|
<AddModal
|
|
|
|
layers={this.props.layers}
|
|
|
|
sources={this.props.sources}
|
|
|
|
isOpen={this.state.isOpen.add}
|
|
|
|
onOpenToggle={this.toggleModal.bind(this, 'add')}
|
|
|
|
onLayersChange={this.props.onLayersChange}
|
|
|
|
/>
|
2017-01-11 15:48:15 +01:00
|
|
|
<header className="maputnik-layer-list-header">
|
|
|
|
<span>Layers</span>
|
|
|
|
<span className="maputnik-space" />
|
2017-01-11 15:59:51 +01:00
|
|
|
<Button
|
|
|
|
onClick={this.toggleModal.bind(this, 'add')}
|
|
|
|
className="maputnik-add-layer">
|
|
|
|
Add Layer
|
|
|
|
</Button>
|
2017-01-11 15:48:15 +01:00
|
|
|
</header>
|
|
|
|
<ul className="maputnik-layer-list-container">
|
2017-01-11 17:52:21 +01:00
|
|
|
{listItems}
|
2017-01-11 15:48:15 +01:00
|
|
|
</ul>
|
|
|
|
</div>
|
2016-12-17 19:58:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-20 11:44:22 +01:00
|
|
|
export default class LayerList extends React.Component {
|
2016-12-17 19:58:30 +01:00
|
|
|
static propTypes = {...layerListPropTypes}
|
|
|
|
|
|
|
|
onSortEnd(move) {
|
|
|
|
const { oldIndex, newIndex } = move
|
|
|
|
if(oldIndex === newIndex) return
|
2016-12-20 16:08:49 +01:00
|
|
|
let layers = this.props.layers.slice(0)
|
2016-12-17 19:58:30 +01:00
|
|
|
layers = arrayMove(layers, oldIndex, newIndex)
|
2016-12-20 20:21:35 +01:00
|
|
|
this.props.onLayersChange(layers)
|
2016-12-17 19:58:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
return <LayerListContainer
|
|
|
|
{...this.props}
|
|
|
|
onSortEnd={this.onSortEnd.bind(this)}
|
|
|
|
useDragHandle={true}
|
|
|
|
/>
|
2016-12-04 17:03:36 +01:00
|
|
|
}
|
2016-09-10 14:10:25 +02:00
|
|
|
}
|