Created library app

This commit is contained in:
Tris
2021-03-11 09:32:44 +11:00
parent 98fe7b77ce
commit 526ae4f59b
19 changed files with 1086 additions and 0 deletions
@@ -0,0 +1,193 @@
{% extends "interface/project_base.html" %}
{% block admin %}
<a href="#" onclick="saveTags()"><i class="fas fa-save"></i> Save</a>&nbsp;
{% endblock %}
{% block page %}
<h2><a href="{% url 'work_list' %}">Works</a> / <a href="{% url 'work_detail' document.work.pk %}">{{ document.work.name }}</a></h2>
<div id="annotation-area">
<div style="display: flex">
<canvas id="inline-viewer" style="width: 600px;"></canvas>
<div style="margin: 0px 20px">
<div>
<div style="text-align: center;">
<p>Page: <span id="page_num"></span> / <span id="page_count"></span></p>
</div>
<button id="prev"><i class="fas fa-backward"></i></button>
<button id="next"><i class="fas fa-forward"></i></button>
</div>
<div id="tag-list" style="cursor: pointer; margin-top: 20px;">
<div id="tag-None" data-tag="None">No tag</div>
<div id="tag-Score" data-tag="Score">Score</div>
{% for instrument in document.work.instruments %}
<div id="tag-{{ instrument.0 }}" data-tag="{{ instrument.0 }}">{{ instrument.1 }}</div>
{% endfor %}
</div>
</div>
</div>
</div>
<p>{{ document.upload.name }}</p>
{% endblock %}
{% block scripts %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.7.570/pdf.min.js" integrity="sha512-g4FwCPWM/fZB1Eie86ZwKjOP+yBIxSBM/b2gQAiSVqCgkyvZ0XxYPDEcN2qqaKKEvK6a05+IPL1raO96RrhYDQ==" crossorigin="anonymous"></script>
{{ json_data|json_script:"data" }}
<script type="text/javascript">
let url = "{{ document.upload.url|safe }}";
// Loaded via <script> tag, create shortcut to access PDF.js exports.
let pdfjsLib = window['pdfjs-dist/build/pdf'];
// The workerSrc property shall be specified.
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.7.570/pdf.worker.min.js';
// get current page tags
let data = JSON.parse(document.getElementById('data').textContent);
let currentTags = document.getElementById('current-tags');
var selectedTag = document.getElementById('tag-None');
var dirty = false;
document.getElementById('tag-list').onclick = (e) => setTag(e.target.dataset.tag);
var pdfDoc = null,
pageNum = 1,
pageRendering = false,
pageNumPending = null,
scale = 1,
canvas = document.getElementById('inline-viewer'),
ctx = canvas.getContext('2d');
/**
* Get page info from document, resize canvas accordingly, and render page.
* @param num Page number.
*/
function renderPage(num) {
pageRendering = true;
// Using promise to fetch the page
pdfDoc.getPage(num).then(function(page) {
var viewport = page.getViewport({scale: scale});
canvas.height = viewport.height;
canvas.width = viewport.width;
// Render PDF page into canvas context
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
var renderTask = page.render(renderContext);
// Wait for rendering to finish
renderTask.promise.then(function() {
pageRendering = false;
if (pageNumPending !== null) {
// New page rendering is pending
renderPage(pageNumPending);
pageNumPending = null;
}
});
});
// Update page counters
document.getElementById('page_num').textContent = num;
// get the page tags
let tag = data.pageTags[num];
if(tag) {
selectTag(tag);
} else {
if (selectedTag) {
setTag(selectedTag.dataset.tag);
}
}
}
/**
* If another page rendering in progress, waits until the rendering is
* finised. Otherwise, executes rendering immediately.
*/
function queueRenderPage(num) {
if (pageRendering) {
pageNumPending = num;
} else {
renderPage(num);
}
}
/**
* Displays previous page.
*/
function onPrevPage() {
if (pageNum <= 1) {
return;
}
pageNum--;
queueRenderPage(pageNum);
}
document.getElementById('prev').addEventListener('click', onPrevPage);
/**
* Displays next page.
*/
function onNextPage() {
if (pageNum >= pdfDoc.numPages) {
return;
}
pageNum++;
queueRenderPage(pageNum);
}
document.getElementById('next').addEventListener('click', onNextPage);
/**
* Asynchronously downloads PDF.
*/
pdfjsLib.getDocument(url).promise.then(function(pdfDoc_) {
pdfDoc = pdfDoc_;
document.getElementById('page_count').textContent = pdfDoc.numPages;
// Initial/first page rendering
renderPage(pageNum);
});
function setTag(tag) {
data.pageTags[pageNum] = tag;
dirty = true;
selectTag(tag);
}
function selectTag(tag) {
if( selectedTag ) {
selectedTag.classList.remove('selected');
}
selectedTag = document.getElementById('tag-' + tag);
if( selectedTag) {
selectedTag.classList.add('selected');
}
}
function saveTags() {
console.log(data.pageTags);
fetch("", {
method: "POST",
headers: {"Content-Type": "application/json", "X-CSRFToken": "{{ csrf_token }}"},
body: JSON.stringify(data.pageTags)}
).then((response) => {
if(response.ok) {
window.location = "{% url 'work_detail' document.work.pk %}"
} else {
alert("Failed: " + response.statusText)
}
});
dirty = false;
}
function checkSaved(e) {
if (dirty) {
e.preventDefault();
}
}
window.addEventListener('beforeunload', checkSaved);
</script>
{% endblock %}
@@ -0,0 +1,11 @@
{% extends 'interface/project_base.html' %}
{% block page %}
<h2>{{ folder.name }}</h2>
<h3>Works</h3>
<ul>
{% for work in folder.works.all %}
<li>{{ work.name }}</li>
{% endfor %}
</ul>
{% endblock %}
@@ -0,0 +1,94 @@
{% extends "interface/project_base.html" %}
{% block admin %}
<a href="#" onclick="save()"><i class="fas fa-save"></i><span class="smhide action">Save</span></a>
<a href="{% url 'playlist_append' project.pk %}"><i class="fas fa-plus-circle"></i><span class="smhide action">Add</a></a>
{% endblock %}
{% block page %}
<table style="max-width: 600px; margin: 10pt auto;" class="item-table">
<thead>
<tr>
<th>Piece</th>
<th>Part</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="text-align: center;">
<i class="fas fa-arrow-up clickable" title="Move up" onclick="moveItem({{ item.pk }}, -1)"></i>
<i class="fas fa-arrow-down clickable" title="Move down" onclick="moveItem({{ item.pk }}, 1)"></i>
<i class="fas fa-trash clickable" title="Remove"></i>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% block scripts %}
<script type="text/javascript">
let workList = document.getElementById('work-list');
var dirty = false;
function moveItem(pk, dir) {
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;
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]);
}
dirty = true;
}
function save() {
let items = Array.prototype.slice.call(workList.children, 0);
let data = {};
for(var i=0; i<items.length; i++) {
let item = items[i].dataset;
data[item.pk] = item.order;
}
console.log(data);
fetch("", {
method: "POST",
headers: {"Content-Type": "application/json", "X-CSRFToken": "{{ csrf_token }}"},
body: JSON.stringify(data)
}).then((response) => {
if (response.ok) {
dirty=false;
window.location = "{% url 'project_playlist' project=project.pk %}";
} else {
alert("Failed: " + response.statusText)
}
})
}
function checkSaved(e) {
if(dirty) {
e.preventDefault();
}
}
window.addEventListener('beforeunload', checkSaved);
</script>
{% endblock %}
@@ -0,0 +1,84 @@
{% extends "interface/project_base.html" %}
{% block admin %}
<a href="{% url 'playlist_manage' project.pk %}"><i class="fas fa-list"></i><span class="smhide admin">Change works</span></a>
{% endblock %}
{% block page %}
<p>
This page lets you download a complete set of music for your part by selecting your instrument
and optionally a part (e.g. Flute 1 or 2).<br/>
You can also tweak which parts you get in the list or click on a piece for more download options.
</p>
<form action="" method="post" target="_blank" style="display: flex;">
{% csrf_token %}
<table style="max-width: 600px; margin: 10pt auto;" class="item-table">
<thead>
</thead>
<tbody>
{% for item in object_list %}
<tr>
<td>
<a href="{% url 'work_detail' item.work.pk %}">{{ item.work.name }}</a>
</td>
<td class="select-cell">
<input type="hidden" name="works" value="{{ item.work.pk }}"/>
<select name="instruments">
<option value='-'>None</option>
{% for part in item.work.parts %}
<option value='{{ part.tag }}'>{{ part.instrument }}</option>
{% endfor %}
</select>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div style="margin: 0px 20px; text-align: right;">
<label for="instrument-select">Pick your instrument</label>
<select id="instrument-select" name="instrument" onchange="updateParts()">
{% for tag, instrument in instruments %}
<option value="{{ tag }}">{{ instrument }}</option>
{% endfor %}
</select><br/><br/>
<label for="part-preference">Part preference</label>
<input id="part-preference" name="part" type="number" value="0" min="0" max="4" onchange="updateParts()" size="1"/><br/><br/>
<button type="submit" style="height: 32px;"><i class="fas fa-copy"></i> Get My Parts!</button>
</div>
</form>
{% endblock %}
{% block scripts %}
<script type="text/javascript">
function updateParts() {
let inst = document.getElementById("instrument-select").value;
let part = document.getElementById("part-preference").value;
let prefix = inst + part;
let instruments = document.getElementsByName("instruments");
for(let i=0; i<instruments.length; i++) {
var result = "-"
let options = instruments[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;
}
}
instruments[i].value = result;
}
}
document.getElementById("instrument-select").value="{{instrument}}";
document.getElementById("part-preference").value="{{part}}";
updateParts();
</script>
{% endblock %}
@@ -0,0 +1 @@
<a href="{% url 'project_playlist' project=project.pk %}">My Music</a>
@@ -0,0 +1,28 @@
{% extends 'interface/project_base.html' %}
{% block admin %}
<a href="{% url 'document_add' work.pk %}"><i class="fas fa-plus-circle"></i> Upload file</a>
{% endblock %}
{% block page %}
<h2><a href="{% url 'work_list' %}">Works</a> / {{ work.name }}</h2>
<p>{{ work.notes }}</p>
<h3>Parts</h3>
<ul>
{% for part in work.parts %}
<li><a href="{% url 'part_download' pk=part.pk filename=part.filename %}" target="part_{{ part.pk }}" rel="">{{ part.instrument }}</a></li>
{% endfor %}
</ul>
<h3>Original Documents</h3>
<ul>
{% for doc in work.docs.all %}
<li>
<a href="{% url 'document_download' pk=doc.pk %}" target="_blank">{{ doc.upload.name }}</a> [{{ doc.parts.count }} parts]
{% if request.is_admin %}
<a href="{% url 'document_annotate' pk=doc.pk %}"><i class="fas fa-edit"></i></a>
{% endif %}
</li>
{% endfor %}
</ul>
{% endblock %}
+25
View File
@@ -0,0 +1,25 @@
{% extends "interface/project_base.html" %}
{% block admin %}
<a href="{% url 'work_add' %}"><i class="fas fa-plus-circle"></i> Add new</a>
{% endblock %}
{% block page %}
<h2>Works</h2>
<table style="max-width: 800px; margin: 10pt auto;">
<thead>
</thead>
<tbody>
{% for work in object_list %}
{% with work.docs.count as doc_count %}
{% with work.parts.count as part_count %}
<tr>
<td><a href="{% url 'work_detail' pk=work.pk %}">{{ work.name }}</a></td>
<td>{{ doc_count }} file{{ doc_count|pluralize }} with {{ part_count }} part{{ part_count|pluralize }}</td>
</tr>
{% endwith %}
{% endwith %}
{% endfor %}
</tbody>
</table>
{% endblock %}