Created library app
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
{% extends "interface/project_base.html" %}
|
||||
|
||||
{% block admin %}
|
||||
<a href="#" onclick="saveTags()"><i class="fas fa-save"></i> Save</a>
|
||||
{% 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 %}
|
||||
@@ -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 %}
|
||||
Reference in New Issue
Block a user