Public
Edited
Apr 5, 2023
Insert cell
Insert cell
viewof demo = selectOrder([
"Peas",
"Apples",
"Bananas",
"Pears",
"Broccoli",
"Cabbage"
], {value: ['Cabbage']})
Insert cell
demo
Insert cell
function selectOrder(items, options) {
let dragging = null;

const value = options ? options.value || [] : []

const list = html`<ul style="display: inline-block; min-width: 200px; margin: 5px 0; padding: 0; font-size: 0.85em;">${items.map(
i => html`
<li draggable="true" style="display: block; cursor: move; padding: 3px 5px 3px 0; border-top: ${topBorder}; border-bottom: ${bottomBorder}"><input type="checkbox" style="vertical-align: baseline; margin-right: 8px;" ${value.includes(i) ? "checked": ""} />${i}</li>
`
)}</ul>`;

function getValue() {
return Array.from(list.childNodes)
.filter(li => li.firstChild.checked)
.map(li => li.innerText);
}

function ondragstart(event) {
var target = getLi(event.target);
dragging = target;
event.dataTransfer.setData('text/plain', null);
}

function ondragover(event) {
event.preventDefault();
var target = getLi(event.target);
var bounding = target.getBoundingClientRect();
var offset = bounding.y + bounding.height / 2;
if (event.clientY - offset > 0) {
target.style['border-bottom'] = dragBorder;
target.style['border-top'] = topBorder;
target.inserting = "below";
} else {
target.style['border-top'] = dragBorder;
target.style['border-bottom'] = bottomBorder;
target.inserting = "above";
}
}

function ondragleave(event) {
reset(getLi(event.target));
}

function ondrop(event) {
event.preventDefault();
var target = getLi(event.target);
if (target.inserting === "below") {
reset(target);
target.parentNode.insertBefore(dragging, event.target.nextSibling);
} else {
reset(target);
target.parentNode.insertBefore(dragging, event.target);
}
list.value = getValue();
list.dispatchEvent(new CustomEvent("input"));
}

function oninput(event) {
list.value = getValue();
}

return Object.assign(list, {
ondragstart,
ondragover,
ondragleave,
ondrop,
oninput,
value: getValue()
});
}
Insert cell
function reset(li) {
li.style['border-top'] = topBorder;
li.style['border-bottom'] = bottomBorder;
}
Insert cell
function getLi(target) {
while (
target.nodeName.toLowerCase() != 'li' &&
target.nodeName.toLowerCase() != 'body'
) {
target = target.parentNode;
}
if (target.nodeName.toLowerCase() == 'body') {
return false;
} else {
return target;
}
}
Insert cell
topBorder = 'solid 1px transparent'
Insert cell
bottomBorder = 'solid 1px #ddd'
Insert cell
dragBorder = 'solid 1px blue'
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more