Skip to content

Commit

Permalink
switched to react-movable for drag/drop functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
reed-tom committed Apr 17, 2024
1 parent 2dd7288 commit 200643f
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 159 deletions.
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"react-highlight-words": "^0.20.0",
"react-icons": "^4.8.0",
"react-masonry-css": "^1.0.16",
"react-movable": "^3.2.0",
"react-responsive-modal": "^6.4.2",
"react-router-dom": "^6.15.0",
"react-scripts": "5.0.1",
Expand Down
4 changes: 4 additions & 0 deletions src/helpers/SC.css
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,10 @@ input[type="number"]::-webkit-outer-spin-button {
.sc-attachment-icon {
color: #626262;
}

.sc-drag-icon {
color: #626262;
}
@media print {
.no-print,
.no-print * {
Expand Down
3 changes: 3 additions & 0 deletions src/sidebar/components/toc/toc-list-new/LayerItem.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
.sc-toc-item-container {
display: table;
-webkit-user-select: none; /* Chrome all / Safari all */
-moz-user-select: none; /* Firefox all */
-ms-user-select: none; /* IE 10+ */
user-select: none;
margin-right: 2px;
margin-left: 2px;
Expand Down
11 changes: 7 additions & 4 deletions src/sidebar/components/toc/toc-list-new/LayerItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Highlighter from "react-highlight-words";
import LayerLegend from "../common/LayerLegend";
import { acceptDisclaimer } from "../common/TOCHelpers.jsx";
import { FaPaperclip } from "react-icons/fa";
import { IoReorderThreeSharp } from "react-icons/io5";

import "./LayerItem.css";
class LayerItem extends Component {
Expand Down Expand Up @@ -67,7 +68,9 @@ class LayerItem extends Component {
return (
<div id={layerInfo.name + "_" + layerInfo.group + "_listview"}>
<div className={containerClassName}>
<div className="sc-toc-item-plus-minus-container" onClick={() => this.props.onLegendToggle(layerInfo, this.props.group)}>
<IoReorderThreeSharp className="sc-drag-icon" size="15px" title="Drag to reorder" />

<div className="sc-toc-item-plus-minus-container" role="button" onClick={() => this.props.onLegendToggle(layerInfo, this.props.group)}>
<img
src={
this.props.layerInfo.styleUrl === "" && (this.props.layerInfo.legendObj === undefined || this.props.layerInfo.legendObj === null)
Expand All @@ -88,9 +91,9 @@ class LayerItem extends Component {
<div className="sc-toc-item-plus-minus-sign" />
<div className="sc-toc-item-lines-expanded" />
</div>
<label>
<label htmlFor={`sc-toc-item-checkbox-${layerInfo.name}_${layerInfo.group}`}>
<input
id="sc-toc-item-checkbox"
id={`sc-toc-item-checkbox-${layerInfo.name}_${layerInfo.group}`}
className="sc-toc-item-checkbox"
key={helpers.getUID()}
type="checkbox"
Expand Down Expand Up @@ -122,7 +125,7 @@ class LayerItem extends Component {
<img src={images["user-icon.png"]} alt="user added layer" />
</div>
</div>
<div className="sc-toc-list-item-toolbox" title="Layer Options" onClick={(evt) => this.props.onLayerOptionsClick(evt, layerInfo)}>
<div className="sc-toc-list-item-toolbox" title="Layer Options" role="button" onClick={(evt) => this.props.onLayerOptionsClick(evt, layerInfo)}>
<img src={images["more-options.png"]} alt="more options" />
</div>
<div className={layerInfo.showLegend ? "sc-toc-layer-info-container" : "sc-hidden"}>
Expand Down
16 changes: 13 additions & 3 deletions src/sidebar/components/toc/toc-list-new/Layers.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,17 @@
margin-left: 5px !important;
}

.sc-dragover {
background-color: blueviolet;
padding-left: 10px;
#sc-toc-list-layers-sortablevirtuallist-virtual-layers {
list-style: none;
padding: 0;
margin: 0;
}

.sc-toc-list-layers-sortablevirtuallist-virtual-layers-listitem {
min-height: 30px;
list-style: none;
}

.sc-toc-list-layers-sortablevirtuallist-virtual-layers-listitem.sc-dragged {
z-index: 4 !important; /*override default z-index to show dragged item above sidebar*/
}
199 changes: 47 additions & 152 deletions src/sidebar/components/toc/toc-list-new/Layers.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,23 @@
//https://medium.com/nerd-for-tech/simple-drag-and-drop-in-react-without-an-external-library-ebf1c1b809e
import React, { useState, useEffect, useRef } from "react";
import * as helpers from "../../../../helpers/helpers";
import { debounce } from "../../../../helpers/react";

import { List, arrayMove } from "react-movable";
import LayerItem from "./LayerItem.jsx";
import "./Layers.css";
// CUSTOM
import "./Layers.css";
import { preventDefault } from "ol/events/Event.js";
const Layers = (props) => {
const Layers = (layersProps) => {
const storageKey = "Layers";
const lastPositionRef = useRef(null);
const virtualId = "sc-toc-list-layers-sortablevirtuallist-virtual-layers";
const [recalcId, setRecalcId] = useState("");
const [layers, setLayers] = useState([]);
const [allLayers, setAllLayers] = useState([]);
const startYRef = useRef();
const draggedElementRef = useRef();
const dragItemRef = useRef();
const dragOverItemRef = useRef();
const [dragItem, setDragItem] = useState();
const [dragOverItem, setDragOverItem] = useState();

useEffect(() => {
// LISTEN FOR SEARCH RESULT
const activeTocLayerListener = (layerItem) => {
if (props.visible) onActivateLayer(layerItem);
if (layersProps.visible) onActivateLayer(layerItem);
};
window.emitter.addListener("activeTocLayer", activeTocLayerListener);
window.addEventListener("resize", updateRecalcId);
Expand All @@ -37,20 +29,20 @@ const Layers = (props) => {
}, []);

useEffect(() => {
if (props.group.layers && props.group.layers.length > 0) {
setAllLayers(props.group.layers);
if (layersProps.group.layers && layersProps.group.layers.length > 0) {
setAllLayers(layersProps.group.layers);
setLayers(
props.group.layers.filter((layer) => {
if (props.searchText === "") return true;
else if (layer.tocDisplayName.toUpperCase().indexOf(props.searchText.toUpperCase()) !== -1) return true;
layersProps.group.layers.filter((layer) => {
if (layersProps.searchText === "") return true;
else if (layer.tocDisplayName.toUpperCase().indexOf(layersProps.searchText.toUpperCase()) !== -1) return true;
else return false;
})
);
}
}, [props.searchText, props.group]);
}, [layersProps.searchText, layersProps.group]);

const updateRecalcId = () => {
if (!props.visible) return;
if (!layersProps.visible) return;
try {
lastPositionRef.current = document.getElementById(virtualId).scrollTop;
} catch (e) {
Expand All @@ -63,7 +55,7 @@ const Layers = (props) => {
};

const onActivateLayer = (layerItem) => {
if (!props.visible) return;
if (!layersProps.visible) return;
const elementId = layerItem.fullName + "_" + layerItem.layerGroup + "-container";

allLayers.forEach((layer) => {
Expand Down Expand Up @@ -94,144 +86,47 @@ const Layers = (props) => {
});
};

const handleDragStart = (e) => {
startYRef.current = e.clientY;
draggedElementRef.current = e.target;
e.dataTransfer.effectAllowed = "move";
// e.dataTransfer.setDragImage(e.target.firstChild.firstChild, 10, 10);
var di = new Image();
// di.src = toDataURL(&quot;image/png&quot;);
e.dataTransfer.setDragImage(di, 10, 10);
dragItemRef.current = e.target.id;
setDragItem(e.target.id);
};
const handleDragLeave = (callback) => {
callback(dragOverItemRef.current);
};
const handleDragEnter = (e) => {
e.preventDefault();
if (e.currentTarget.id === dragItemRef.current || dragOverItemRef.current === e.currentTarget.id) return;
dragOverItemRef.current = e.currentTarget.id;
setDragOverItem(e.currentTarget.id);
};
const handleDragEnd = () => {
const oldIndex = allLayers.indexOf(allLayers.find((layer) => props.id + "-" + helpers.getHash(layer.name) + "-container" === dragItemRef.current));
const newIndex = allLayers.indexOf(allLayers.find((layer) => props.id + "-" + helpers.getHash(layer.name) + "-container" === dragOverItemRef.current));
const oldIndexFiltered = layers.indexOf(layers.find((layer) => props.id + "-" + helpers.getHash(layer.name) + "-container" === dragItemRef.current));
const newIndexFiltered = layers.indexOf(layers.find((layer) => props.id + "-" + helpers.getHash(layer.name) + "-container" === dragOverItemRef.current));
const newLayers = [...layers];
const movedLayer = newLayers.splice(oldIndexFiltered, 1);
newLayers.splice(newIndexFiltered, 0, movedLayer[0]);
// setLayers(newLayers);

props.onSortEnd({ oldIndex: oldIndex, newIndex: newIndex });
draggedElementRef.current.style.transform = "";
dragItemRef.current = null;
dragOverItemRef.current = null;
setDragOverItem(null);
setDragItem(null);
};
const handleDragCancel = () => {
draggedElementRef.current.style.transform = "";
dragItemRef.current = null;
dragOverItemRef.current = null;
setDragOverItem(null);
setDragItem(null);
};
const handleDragOver = (e) => {
e.preventDefault();
const deltaY = e.clientY - startYRef.current;
draggedElementRef.current.style.transform = `translateY(${deltaY}px)`;
};

if (props.group.layers === undefined) return <div />;
if (layersProps.group.layers === undefined) return <div />;
else
return (
<div className="sc-toc-layer-container">
<ul id={virtualId}>
{layers.map((layer) => (
<LayerListItem
key={props.id + "-" + helpers.getHash(layer.name) + "-container"}
id={props.id + "-" + helpers.getHash(layer.name) + "-container"}
parent={props.id}
layer={layer}
onDragStart={handleDragStart}
onDragEnter={handleDragEnter}
onDragEnd={handleDragEnd}
onDragExit={handleDragCancel}
onDragLeave={handleDragLeave}
onDragOver={handleDragOver}
currentSelection={dragOverItem}
draggedItem={dragItem}
onLegendToggle={props.onLegendToggle}
group={props.group}
onLayerChange={props.onLayerChange}
onCheckboxChange={props.onCheckboxChange}
searchText={props.searchText}
onLayerOptionsClick={props.onLayerOptionsClick}
/>
))}
</ul>
<List
values={layers}
onChange={({ oldIndex, newIndex }) => {
if (layersProps.sortAlpha) return;
const oldIndexAllLayers = allLayers.indexOf(layers[oldIndex]);
const newIndexAllLayers = allLayers.indexOf(layers[newIndex]);

setLayers(arrayMove(layers, oldIndex, newIndex));
layersProps.onSortEnd({ oldIndex: oldIndexAllLayers, newIndex: newIndexAllLayers });
}}
lockVertically={true}
beforeDrag={() => {
if (layersProps.sortAlpha) return;
}}
renderList={({ children, props }) => (
<ul id={virtualId} {...props}>
{children}
</ul>
)}
renderItem={({ value, props, isDragged, isSelected }) => (
<li id={virtualId + "-listitem"} className={`${virtualId}-listitem${isDragged || isSelected ? " sc-dragged" : ""}`} {...props}>
<LayerItem
key={layersProps.id + "-" + helpers.getHash(value.name)}
id={layersProps.id + "-" + helpers.getHash(value.name)}
layerInfo={value}
onLegendToggle={layersProps.onLegendToggle}
group={layersProps.group}
onLayerChange={layersProps.onLayerChange}
onCheckboxChange={layersProps.onCheckboxChange}
searchText={layersProps.searchText}
onLayerOptionsClick={layersProps.onLayerOptionsClick}
/>
</li>
)}
/>
</div>
);
};

export default Layers;

const LayerListItem = (props) => {
const [open, setOpen] = useState(false);
const { layer, parent } = props;

useEffect(() => {
if (props.id !== props.currentSelection) setOpen(false);
}, [props.currentSelection]);
const handleDragEnter = (e) => {
e.preventDefault();
if (props.id !== props.draggedItem) setOpen(true);
props.onDragEnter(e);
};
const handleDragLeave = (e) => {
e.preventDefault();
};
const handleDragEnd = () => {
setOpen(false);
props.onDragEnd();
};
const handleDragExit = () => {
setOpen(false);
props.onDragExit();
};

return (
<li
className={`sc-toc-layer-list-item sc-draggable`}
key={props.id}
onDragStart={(e) => props.onDragStart(e)}
onDragEnter={(e) => handleDragEnter(e)}
onDragEnd={() => handleDragEnd()}
onDragExit={() => handleDragExit()}
onDragOver={(e) => props.onDragOver(e)}
onDragLeave={(e) => handleDragLeave(e)}
id={props.id}
draggable
style={{
minHeight: "30px",
transition: "padding 50ms linear 50ms",
padding: open ? "0px 0px 30px 0px" : "",
border: "1px dashed #000",
}}
>
<LayerItem
key={parent + "-" + helpers.getHash(layer.name)}
id={parent + "-" + helpers.getHash(layer.name)}
layerInfo={layer}
onLegendToggle={props.onLegendToggle}
group={props.group}
onLayerChange={props.onLayerChange}
onCheckboxChange={props.onCheckboxChange}
searchText={props.searchText}
onLayerOptionsClick={props.onLayerOptionsClick}
/>
</li>
);
};

0 comments on commit 200643f

Please sign in to comment.