Skip to content

Instantly share code, notes, and snippets.

@lewdev
Last active August 29, 2023 01:51
Show Gist options
  • Select an option

  • Save lewdev/af8b9c781eb1e36dab88f894cb7aa042 to your computer and use it in GitHub Desktop.

Select an option

Save lewdev/af8b9c781eb1e36dab88f894cb7aa042 to your computer and use it in GitHub Desktop.
🀚 Configurable Drag and Drop Assignments

🀚 Configurable Drag and Drop Assignments

Drag and drop names on the left to put into the chart on the right.

This is useful when you have a fix list of things you want to put in a chart.

This is configurable with text boxes to add, edit, or remove column headers, row headers, or items.

I've always wanted to make something like this, but didn't really look into it.

I stumbled upon the draggable attribute and then looked into how to use it.

This is a proof of concept that I may add to further. I think this works great with assigning shift schedules.

Hopefully, this can lead to being able to create a quick app to do simple drag and drop processes.

TODO

  • Highlight box when dragging an item over it
  • Retain data after configuration updates or page refresh using localStorage

Diagram

App used to create this diagram: https://asciiflow.com

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”
β”‚         β”‚     β”‚Col1β”‚Col2β”‚Col3β”‚Colβ”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€
β”‚ Item 1  β”‚Row 1β”‚    β”‚    β”‚    β”‚   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€
β”‚ Item 2  β”‚Row 2β”‚    β”‚    β”‚    β”‚   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€
β”‚ Item 3  β”‚Row 3β”‚    β”‚    β”‚    β”‚   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€
β”‚         β”‚Row 4β”‚    β”‚    β”‚    β”‚   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€
β”‚         β”‚Row 5β”‚    β”‚    β”‚    β”‚   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€
β”‚         β”‚Row 6β”‚    β”‚    β”‚    β”‚   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”˜
<!DOCTYPE HTML>
<html>
<head>
<title>draggable attribute</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1>Assignment</h1>
<details>
<summary>Configurations</summary>
<div id="configInputs" class="p-2 justify-content-between d-flex"></div>
</details>
<div class="justify-content-between d-flex">
<div id="nameList"></div>
<table id="chart" class="table table-striped" style="width:50rem">
<thead></thead>
<tbody></tbody>
</table>
</div>
</div>
<script>
const positions = "Male 1,Male 2,Male 3,Female 1,Female 2,Female 3,Hyoshigi,Chanpon,Surigane,Taiko,Kotsuzumi,Koto,Shamisen,Kokyu".split`,`;
const parts = "Seated Service,First Half,Second Half".split`,`;
const names = "Emma,Charlotte,Amelia,Sophia,Isabella,Ava,Mia,Evelyn,Luna".split`,`;
const droppoint = e => {
const data = e.dataTransfer.getData("Text");
e.target.appendChild(document.getElementById(data));
e.preventDefault();
initNameList();
};
const allowDropOption = e => e.preventDefault();
const dragpoint = e => e.dataTransfer.setData("Text", e.target.id);
const initNameList = () => {
nameList.ondrop = droppoint;
nameList.ondragover = allowDropOption;
nameList.innerHTML = names.map(n => `<div id="${n + (new Date).getTime()}">${n}</div>`).join``;
for (const nameDiv of nameList.getElementsByTagName`div`) {
nameDiv.draggable = true;
nameDiv.ondragstart = dragpoint;
}
};
const cap = s => s.charAt(0).toUpperCase() + s.substring(1);
const populateInput = (id, arr) => {
const textarea = document.getElementById(id);
textarea.innerHTML = arr.join`\n`;
textarea.onchange = () => renderTable();
};
const initConfigInputs = () => {
configInputs.innerHTML = ["items", "columnHeaders", "rowHeaders"].map((a, i) => `<div class="w-100 mr-2">
<div${i ? ' style="margin-left:1rem"' : ''}>
<div><strong>${cap(a)}:</strong></div>
<textarea id="${a}" class="form-control" rows="10"></textarea>
</div>
</div>`).join``;
//add test data
populateInput("columnHeaders", parts);
populateInput("rowHeaders", positions);
populateInput("items", names);
};
const renderTable = () => {
const thead = chart.getElementsByTagName`thead`[0];
const tbody = chart.getElementsByTagName`tbody`[0];
const headers = columnHeaders.value.split`\n`;
const rows = rowHeaders.value.split`\n`;
thead.innerHTML = `<tr><th></th>${headers.map(p => `<th>${p}</th>`).join``}</tr>`;
tbody.innerHTML = rows.map(r => `<tr><th>${r}</th>${"<td></td>".repeat(headers.length)}</tr>`).join``;
for (const td of chart.getElementsByTagName`td`) {
td.ondrop = droppoint;
td.ondragover = allowDropOption;
}
};
onload = () => {
initConfigInputs();
initNameList();
renderTable();
};
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment