import h from '../Util/DomUtil.js'; class Layer { constructor(id, name) { this.id = id; this.name = name; this.subLayers = []; this.visible = true; } } class LayerData { constructor() { this.layers = []; this.idPool = 0; } _getNewId() { const id = this.idPool; this.idPool += 1; return `layer${id}`; } _getContainerAndId(idChain) { if (idChain.length === 0) return [ this.layers, null ]; let container = this.layers; while (idChain.length > 1) { const id = idChain.pop(); console.log(container, id); container = container.find(layer => layer.id === id).subLayers; console.log(idChain); } return [ container, idChain[0] ]; } _idToIndex(container, id) { return container.findIndex(layer => layer.id === id); } insertLayer(idChain) { const layerId = this._getNewId(); const newLayer = new Layer(layerId, `Layer ${layerId}`); const [ container, id ] = this._getContainerAndId(idChain); if (id === null) { container.push(newLayer); return; } const index = this._idToIndex(container, id); container.splice(index+1, 0, newLayer); } removeLayer(idChain) { const [ container, id ] = this._getContainerAndId(idChain); if (id === null) return; const index = this._idToIndex(container, id); container.splice(index, 1); } pushLayer(idChain) { const [ container, id ] = this._getContainerAndId(idChain); if (id === null) return; // nothing to do const index = this._idToIndex(container, id); const after = container[index+1]; if (!after) return; // no successor to push to, do nothing after.subLayers.push(container[index]); container.splice(index, 1); } popLayer(idChain) { const parentChain = idChain.slice(1); const [ container, id ] = this._getContainerAndId(idChain); const index = this._idToIndex(container, id); const layer = container[index]; container.splice(index, 1); const [ parentContainer, parentId ] = this._getContainerAndId(parentChain); const parentIndex = this._idToIndex(parentContainer, parentId); parentContainer.splice(parentIndex, 0, layer); } moveUp(idChain) { const [ container, id ] = this._getContainerAndId(idChain); const index = this._idToIndex(container, id); if (index === container.length-1) return; const layer = container[index]; container.splice(index, 1); container.splice(index+1, 0, layer); } moveDown(idChain) { const [ container, id ] = this._getContainerAndId(idChain); const index = this._idToIndex(container, id); if (index === 0) return; const layer = container[index]; container.splice(index, 1); container.splice(index-1, 0, layer); } toggleVisible(idChain) { const [ container, id ] = this._getContainerAndId(idChain); const index = this._idToIndex(container, id); const layer = container[index]; const visible = !layer.visible; const recursiveToggle = layer => { layer.visible = visible; for (let subLayer of layer.subLayers) recursiveToggle(subLayer); } recursiveToggle(layer); } rename(idChain, name) { const [ container, id ] = this._getContainerAndId(idChain); const index = this._idToIndex(container, id); const layer = container[index]; layer.name = name; } } class LayerView { constructor(parentId) { const parentElement = document.getElementById(parentId); const button = (label, f) => { const b = h('button', label, { 'style': 'margin: 0 5px' }); b.onclick = f; return b; } this.layersList = h('ul'); const root = h('fieldset', { 'class': 'layer-view' }, [ h('legend', 'Layers'), this.layersList, button('Move Up', () => this.onMoveUp(this._getIdChain())), button('Move Down', () => this.onMoveDown(this._getIdChain())), button('Toggle Visible', () => this.onShowHideLayer(this._getIdChain())), button('Rename', () => this.onRenameLayer(this._getIdChain())), h('br'), h('br'), button('Add Layer', () => this.onAddLayer(this._getIdChain())), button('Remove Layer', () => this.onRemoveLayer(this._getIdChain())), button('Push', () => this.onPushLayer(this._getIdChain())), button('Pop', () => this.onPopLayer(this._getIdChain())), ]); parentElement.appendChild(root); this.selectedId = null; this.onAddLayer = () => {}; this.onRemoveLayer = () => {}; this.onPushLayer = () => {}; this.onPopLayer = () => {}; this.onMoveUp = () => {}; this.onMoveDown = () => {}; this.onShowHideLayer = () => {}; this.onRenameLayer = () => {}; } _getIdChain() { const chain = []; let el = this.selected; if (el === null || el === undefined) return []; while (el !== this.layersList && el !== null) { if (el.nodeName.toLowerCase() === 'li') chain.push(el.id); el = el.parentNode; } return chain; } renderLayers(layers, root=this.layersList) { let selectedId = ''; if (this.selected) selectedId = this.selected.id; if (root === this.layersList) this.layersList.replaceChildren(); for (let layer of layers) { let classList = ''; if (layer.visible) classList += 'visible '; const el = h( 'li', layer.name, { id: layer.id, 'class': classList, } ); if (selectedId === layer.id) { el.classList.add('selected'); this.selected = el; } el.onclick = e => { e.stopPropagation(); if (this.selected) this.selected.classList.remove('selected'); this.selected = el; el.classList.add('selected'); }; if (layer.subLayers.length !== 0) { const ul = h('ul'); this.renderLayers(layer.subLayers, ul); el.appendChild(ul); } root.prepend(el); } } } class LayerController { constructor(data, view) { this.data = data; this.view = view; const respond = f => ( idChain => { f(idChain); this.updateView(); } ); this.view.onAddLayer = idChain => { this.data.insertLayer(idChain); this.updateView(); }; this.view.onRemoveLayer = idChain => { this.data.removeLayer(idChain); this.updateView(); } this.view.onPushLayer = idChain => { this.data.pushLayer(idChain); this.updateView(); }; this.view.onPopLayer = idChain => { this.data.popLayer(idChain); this.updateView(); }; this.view.onMoveUp = idChain => { this.data.moveUp(idChain); this.updateView(); }; this.view.onMoveDown = idChain => { this.data.moveDown(idChain); this.updateView(); }; this.view.onShowHideLayer = idChain => { this.data.toggleVisible(idChain); this.updateView(); }; this.view.onRenameLayer = idChain => { const newName = prompt("New layer name"); this.data.rename(idChain, newName); this.updateView(); } } updateView() { this.view.renderLayers(this.data.layers); } } export { LayerData, LayerView, LayerController };