Item list management
This commit is contained in:
parent
471e465133
commit
ab123ba7b1
@ -2,8 +2,6 @@
|
||||
{% load polyphonic %}
|
||||
|
||||
{% block page %}
|
||||
<form action="" method="post" target="_blank">
|
||||
{% csrf_token %}
|
||||
<div>
|
||||
<div class="field is-grouped is-grouped-centered is-grouped-multiline">
|
||||
<div class="field has-addons control has-addons-centered is-expanded">
|
||||
@ -16,7 +14,7 @@
|
||||
<input type="text" class="input" list="instrument-list" id="instrument-name" onchange="updateParts()"/>
|
||||
<datalist id="instrument-list">
|
||||
{% for inst in instruments %}
|
||||
<option value="{{inst.1}}"/>
|
||||
<option value="{{inst}}"/>
|
||||
{% endfor %}
|
||||
</datalist>
|
||||
</span>
|
||||
@ -35,6 +33,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form action="" method="post" target="_blank">
|
||||
{% csrf_token %}
|
||||
|
||||
<table class="table is-striped mx-auto">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -58,7 +59,7 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="is-hidden-mobile">{{ item.work.composer }}</td>
|
||||
<td class="is-hidden-mobile">{% firstof item.work.running_time "------" %}</td>
|
||||
<td class="is-hidden-mobile">{% firstof item.work.running_time "-:--" %}</td>
|
||||
<td class="select-cell">
|
||||
<input type="hidden" name="works" value="{{ item.work.pk }}"/>
|
||||
<span class="select is-small" style="width: 100%">
|
||||
@ -84,7 +85,7 @@
|
||||
<td/>
|
||||
<td/>
|
||||
<td/>
|
||||
<td>{% firstof running_time "------" %}</td>
|
||||
<td>{% firstof running_time "-:--" %}</td>
|
||||
<td colspan="2">
|
||||
<button class="button is-link is-small" type="submit" name="action" value="pdf">
|
||||
{% icon "two_pager" %}
|
||||
@ -114,50 +115,49 @@
|
||||
const INSTRUMENTS = JSON.parse(document.getElementById('instruments').innerText);
|
||||
|
||||
function updateParts() {
|
||||
var inst = document.getElementById("instrument-name").value.toLowerCase();
|
||||
var inst = document.getElementById("instrument-name").value;
|
||||
window.localStorage.setItem('instrument-name', inst);
|
||||
console.log("Changing to", inst);
|
||||
|
||||
for (let i of INSTRUMENTS) {
|
||||
if (i[1].toLowerCase() === inst) {
|
||||
inst = i[0];
|
||||
|
||||
for (let i in INSTRUMENTS) {
|
||||
if (i.toLowerCase() === inst.toLowerCase()) {
|
||||
inst = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
console.log("Instrument code:", inst);
|
||||
|
||||
|
||||
let part = document.getElementById("part-preference").value;
|
||||
window.localStorage.setItem('part-preference', part);
|
||||
console.log("Part preference:", part);
|
||||
console.log("Part preference:", inst, part);
|
||||
|
||||
|
||||
selectParts(inst, part);
|
||||
selectParts(INSTRUMENTS[inst] || [inst.toLowerCase()], part);
|
||||
|
||||
}
|
||||
|
||||
function selectParts(inst, part) {
|
||||
function selectParts(codes, part) {
|
||||
|
||||
let n = parseInt(part);
|
||||
|
||||
let preferences = [];
|
||||
for (let i=n; i>0; i--) {
|
||||
for (let code of codes) preferences.push(code + "-" + i);
|
||||
}
|
||||
preferences.push(...codes);
|
||||
console.log("Preferences:", preferences);
|
||||
|
||||
let prefix = inst + "-" + part;
|
||||
|
||||
let selections = document.getElementsByName("instrument-selection");
|
||||
console.log("Updating selections:", prefix, selections);
|
||||
for(let i=0; i<selections.length; i++) {
|
||||
var result = "-"
|
||||
let options = selections[i].children;
|
||||
for(let j=0; j<options.length; j++) {
|
||||
let value = options[j].value;
|
||||
if (value.startsWith(prefix)) {
|
||||
result = value;
|
||||
break;
|
||||
}
|
||||
if (result==="-" && value.startsWith(inst)) {
|
||||
result = value;
|
||||
}
|
||||
const selection = selections[i];
|
||||
for(let pref of preferences) {
|
||||
selection.value = pref;
|
||||
if(selection.value == pref) break;
|
||||
}
|
||||
console.log("Selected:", result);
|
||||
selections[i].value = result;
|
||||
|
||||
if(!selection.value) selection.value = "-";
|
||||
|
||||
console.log("Selected:", selection.value);
|
||||
}
|
||||
|
||||
}
|
||||
@ -170,7 +170,7 @@ function downloadPart(collection, work) {
|
||||
}
|
||||
console.log(part);
|
||||
let url = "/collections/" + collection + "/works/" + work + "/download?tag=" + part;
|
||||
window.location = url;
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
|
||||
document.getElementById("instrument-name").value = localStorage.getItem('instrument-name', 'All');
|
||||
|
||||
@ -13,37 +13,57 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block page %}
|
||||
<table style="max-width: 600px; margin: 10pt auto;" class="zebra">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item</th>
|
||||
<th>Time</th>
|
||||
<th/>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="work-list">
|
||||
{% for item in object_list %}
|
||||
<tr data-pk="{{ item.pk }}" data-order="{{ forloop.counter }}">
|
||||
<td>{{ item.work.name }}</td>
|
||||
<td>{{ item.work.duration }}</td>
|
||||
<td style="text-align: center;">
|
||||
<span class="clickable" title="Move up" onclick="moveItem({{ item.pk }}, -1)">
|
||||
{% icon "arrow_upward" %}
|
||||
</span>
|
||||
<span class="clickable" title="Move down" onclick="moveItem({{ item.pk }}, 1)">
|
||||
{% icon "arrow_downward" %}
|
||||
</span>
|
||||
<span class="clickable" title="Remove" onClick="moveItem({{ item.pk }}, 0)">
|
||||
{% icon "delete" %}
|
||||
</span>
|
||||
</td>
|
||||
<div class="columns">
|
||||
|
||||
</tr>
|
||||
<div class="column">
|
||||
<h3 class="subtitle">Add from collection</h3>
|
||||
<div>
|
||||
{% for access in project.ensemble.allowed_collections.all %}
|
||||
<a href="" class="button is-link">{{ access.collection.name }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column card">
|
||||
<table style="max-width: 600px; margin: 10pt auto;" class="table is-striped is-narrow">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item</th>
|
||||
<th>Time</th>
|
||||
<th/>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="work-list">
|
||||
{% for item in object_list %}
|
||||
<tr data-pk="{{ item.pk }}" data-order="{{ forloop.counter }}">
|
||||
<td>{{ item.work.name }}</td>
|
||||
<td style="min-width: 100px;">{% firstof item.work.duration '-:--' %}</td>
|
||||
<td style="text-align: center;">
|
||||
<span class="clickable cursor-pointer" title="Remove" onClick="removeItem({{ item.pk }})">
|
||||
{% icon "delete" %}
|
||||
</span>
|
||||
<span class="clickable drag-handle cursor-drag" title="Reorder">
|
||||
{% icon "reorder" %}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="2">No items</td></tr>
|
||||
<tr><td colspan="2">No items</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block style %}
|
||||
{{ block.super }}
|
||||
<style>
|
||||
tr.dragging { opacity: 0.4; }
|
||||
.drag-handle { cursor: move; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
@ -51,36 +71,81 @@
|
||||
|
||||
let workList = document.getElementById('work-list');
|
||||
var dirty = false;
|
||||
var dragSrc = null;
|
||||
var dragSrcNext = null;
|
||||
|
||||
function moveItem(pk, dir) {
|
||||
function reorderItems() {
|
||||
let items = Array.prototype.slice.call(workList.children, 0);
|
||||
for (let j = 0; j < items.length; j++) {
|
||||
items[j].dataset.order = j;
|
||||
}
|
||||
}
|
||||
|
||||
function removeItem(pk) {
|
||||
let items = Array.prototype.slice.call(workList.children, 0);
|
||||
var i=0;
|
||||
pk = "" + pk;
|
||||
for(i=0; i<items.length; i++) {
|
||||
if(items[i].dataset.pk === pk) break;
|
||||
}
|
||||
if(i >= items.length) return;
|
||||
|
||||
// check the direction is sensible
|
||||
if (i + dir < 0 || i + dir >= items.length) return;
|
||||
|
||||
if (dir === 0) {
|
||||
items[i].dataset.order = -1;
|
||||
items[i].style = "display: none";
|
||||
} else {
|
||||
items[i].dataset.order = parseInt(items[i].dataset.order) + dir;
|
||||
items[i+dir].dataset.order = parseInt(items[i+dir].dataset.order) - dir;
|
||||
}
|
||||
|
||||
items.sort((a, b) => parseInt(a.dataset.order) - parseInt(b.dataset.order))
|
||||
|
||||
workList.innerHTML = ""
|
||||
for(let j=0; j<items.length; j++) {
|
||||
workList.appendChild(items[j]);
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].dataset.pk === pk) {
|
||||
items[i].dataset.order = -1;
|
||||
items[i].style = "display: none";
|
||||
break;
|
||||
}
|
||||
}
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
workList.addEventListener('mousedown', function(e) {
|
||||
let handle = e.target.closest('.drag-handle');
|
||||
if (handle) handle.closest('tr').draggable = true;
|
||||
});
|
||||
|
||||
workList.addEventListener('mouseup', function(e) {
|
||||
let handle = e.target.closest('.drag-handle');
|
||||
if (handle) handle.closest('tr').draggable = false;
|
||||
});
|
||||
|
||||
workList.addEventListener('dragstart', function(e) {
|
||||
dragSrc = e.target.closest('tr');
|
||||
if (!dragSrc) return;
|
||||
dragSrcNext = dragSrc.nextElementSibling;
|
||||
dragSrc.classList.add('dragging');
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
e.dataTransfer.setData('text/plain', dragSrc.dataset.pk);
|
||||
});
|
||||
|
||||
workList.addEventListener('dragover', function(e) {
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = 'move';
|
||||
let target = e.target.closest('tr');
|
||||
if (!target || target === dragSrc) return;
|
||||
|
||||
let rect = target.getBoundingClientRect();
|
||||
let midY = rect.top + rect.height / 2;
|
||||
|
||||
if (e.clientY < midY) {
|
||||
workList.insertBefore(dragSrc, target);
|
||||
} else {
|
||||
workList.insertBefore(dragSrc, target.nextElementSibling);
|
||||
}
|
||||
});
|
||||
|
||||
workList.addEventListener('drop', function(e) {
|
||||
e.preventDefault();
|
||||
dragSrcNext = null;
|
||||
reorderItems();
|
||||
dirty = true;
|
||||
});
|
||||
|
||||
workList.addEventListener('dragend', function(e) {
|
||||
if (!dragSrc) return;
|
||||
dragSrc.classList.remove('dragging');
|
||||
if (dragSrcNext) {
|
||||
workList.insertBefore(dragSrc, dragSrcNext);
|
||||
}
|
||||
dragSrc = null;
|
||||
dragSrcNext = null;
|
||||
});
|
||||
|
||||
function save() {
|
||||
|
||||
let items = Array.prototype.slice.call(workList.children, 0);
|
||||
@ -98,7 +163,7 @@ function save() {
|
||||
}).then((response) => {
|
||||
if (response.ok) {
|
||||
dirty=false;
|
||||
window.location = "{% url 'item_list' project=project.pk %}";
|
||||
window.location = "{% url 'project_detail' project=project.pk %}";
|
||||
} else {
|
||||
alert("Failed: " + response.statusText)
|
||||
}
|
||||
|
||||
@ -27,6 +27,11 @@ urlpatterns = [
|
||||
),
|
||||
path("library", views.LibraryWorkListView.as_view(), name="work_list"),
|
||||
path("collections", views.CollectionListView.as_view(), name="collection_list"),
|
||||
path(
|
||||
"projects/<int:project>/collections",
|
||||
views.ProjectWorkListView.as_view(),
|
||||
name="project_work_list",
|
||||
),
|
||||
path(
|
||||
"collections/<int:collection>",
|
||||
views.CollectionWorkListView.as_view(),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user