JS codestyle enhancements

This commit is contained in:
Patrick Jentsch 2021-12-01 14:15:20 +01:00
parent 72ba61f369
commit 12ec6be60b
39 changed files with 490 additions and 288 deletions

View File

@ -6,36 +6,46 @@ class App {
this.socket.on('users.patch', patch => this.usersPatchHandler(patch)); this.socket.on('users.patch', patch => this.usersPatchHandler(patch));
} }
get users() {return this.data.users;} get users() {
return this.data.users;
}
addEventListener(type, listener) { addEventListener(type, listener) {
if (!(type in this.eventListeners)) {throw `Unknown event type: ${type}`;} if (!(type in this.eventListeners)) {
throw `Unknown event type: ${type}`;
}
this.eventListeners[type].push(listener); this.eventListeners[type].push(listener);
} }
flash(message, category) { flash(message, category) {
let toast, toastCloseActionElement; let iconPrefix;
let toast;
let toastCloseActionElement;
switch (category) { switch (category) {
case "corpus": case 'corpus':
message = `<i class="left material-icons">book</i>${message}`; iconPrefix = '<i class="left material-icons">book</i>';
break; break;
case "error": case 'error':
message = `<i class="left material-icons error-color-text">error</i>${message}`; iconPrefix = '<i class="error-color-text left material-icons">error</i>';
break; break;
case "job": case 'job':
message = `<i class="left nopaque-icons">J</i>${message}`; iconPrefix = '<i class="left nopaque-icons">J</i>';
break; break;
default: default:
message = `<i class="left material-icons">notifications</i>${message}`; iconPrefix = '<i class="left material-icons">notifications</i>';
break;
} }
toast = M.toast({ toast = M.toast(
{
html: ` html: `
<span>${message}</span> <span>${iconPrefix}${message}</span>
<button class="btn-flat toast-action white-text" data-action="close"> <button class="btn-flat toast-action white-text" data-action="close">
<i class="material-icons">close</i> <i class="material-icons">close</i>
</button> </button>
`.trim() `.trim()
}); }
);
toastCloseActionElement = toast.el.querySelector('.toast-action[data-action="close"]'); toastCloseActionElement = toast.el.querySelector('.toast-action[data-action="close"]');
toastCloseActionElement.addEventListener('click', () => {toast.dismiss();}); toastCloseActionElement.addEventListener('click', () => {toast.dismiss();});
} }
@ -55,8 +65,16 @@ class App {
} }
usersPatchHandler(patch) { usersPatchHandler(patch) {
let re, match, userId, ressourceId, jobId, relationship; let jobId;
for (let operation of patch.filter(operation => operation.op === 'add')) { let listener;
let match;
let operation;
let re;
let relationship;
let ressourceId;
let userId;
for (operation of patch.filter(operation => operation.op === 'add')) {
re = new RegExp(`^/users/([A-Za-z0-9]*)/corpora/([A-Za-z0-9]*)/(files)`); re = new RegExp(`^/users/([A-Za-z0-9]*)/corpora/([A-Za-z0-9]*)/(files)`);
if (re.test(operation.path)) { if (re.test(operation.path)) {
[match, userId, ressourceId, relationship] = operation.path.match(re); [match, userId, ressourceId, relationship] = operation.path.match(re);
@ -75,6 +93,6 @@ class App {
} }
} }
this.data = jsonpatch.apply_patch(this.data, patch); this.data = jsonpatch.apply_patch(this.data, patch);
for (let listener of this.eventListeners['users.patch']) {listener(patch);} for (listener of this.eventListeners['users.patch']) {listener(patch);}
} }
} }

View File

@ -4,7 +4,11 @@ class JobStatusNotifier {
} }
usersPatchHandler(patch) { usersPatchHandler(patch) {
let re, filteredPatch, match, jobId; let filteredPatch;
let jobId;
let match;
let re;
re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)/status$`) re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)/status$`)
filteredPatch = patch filteredPatch = patch
.filter(operation => operation.op === 'replace') .filter(operation => operation.op === 'replace')

View File

@ -2,34 +2,45 @@ class CorpusDisplay extends RessourceDisplay {
constructor(displayElement) { constructor(displayElement) {
super(displayElement); super(displayElement);
this.corpusId = displayElement.dataset.corpusId; this.corpusId = displayElement.dataset.corpusId;
for (let exportCorpusTriggerElement of this.displayElement.querySelectorAll('.export-corpus-trigger')) {
exportCorpusTriggerElement.addEventListener('click', () => this.requestCorpusExport());
}
app.socket.on(`export_corpus_${this.corpusId}`, () => this.downloadCorpus());
} }
init(user) { init(user) {
let corpus; let corpus;
corpus = user.corpora[this.corpusId]; corpus = user.corpora[this.corpusId];
this.setCreationDate(corpus.creation_date); this.setCreationDate(corpus.creation_date);
this.setDescription(corpus.description); this.setDescription(corpus.description);
this.setLastEditedDate(corpus.last_edited_date); this.setLastEditedDate(corpus.last_edited_date);
this.setStatus(corpus.status); this.setStatus(corpus.status);
this.setTitle(corpus.title); this.setTitle(corpus.title);
this.setTokenRatio(corpus.num_tokens, corpus.max_num_tokens); this.setNumTokens(corpus.num_tokens);
} }
patch(patch) { patch(patch) {
let re, filteredPatch; let filteredPatch;
let operation;
let re;
re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}`); re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}`);
filteredPatch = patch.filter(operation => re.test(operation.path)); filteredPatch = patch.filter(operation => re.test(operation.path));
for (let operation of filteredPatch) { for (operation of filteredPatch) {
switch(operation.op) { switch(operation.op) {
case 'replace': case 'replace':
re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/last_edited_date$`); re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/last_edited_date$`);
if (re.test(operation.path)) {this.setLastEditedDate(operation.value); break;} if (re.test(operation.path)) {
this.setLastEditedDate(operation.value);
break;
}
re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/num_tokens`);
if (re.test(operation.path)) {
this.numTokens(operation.value);
break;
}
re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/status$`); re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/status$`);
if (re.test(operation.path)) {this.status$(operation.value); break;} if (re.test(operation.path)) {
this.status(operation.value);
break;
}
break; break;
default: default:
break; break;
@ -37,55 +48,48 @@ class CorpusDisplay extends RessourceDisplay {
} }
} }
requestCorpusExport() {
app.socket.emit('export_corpus', app.users[this.userId].corpora[this.corpusId]);
app.flash('Preparing your corpus export...', 'corpus');
for (let exportCorpusTriggerElement of this.displayElement.querySelectorAll('.export-corpus-trigger')) {exportCorpusTriggerElement.classList.toggle('disabled', true);}
}
downloadCorpus() {
let downloadButton;
app.flash('Corpus download is ready!', 'corpus');
for (let exportCorpusTriggerElement of this.displayElement.querySelectorAll('.export-corpus-trigger')) {exportCorpusTriggerElement.classList.toggle('disabled', false);}
// Little trick to call the download view after ziping has finished
downloadButton = document.createElement('a');
downloadButton.href = `/corpora/${app.users[this.userId].corpora[this.corpusId]}/download`;
downloadButton.click();
}
setTitle(title) { setTitle(title) {
for (let element of this.displayElement.querySelectorAll('.corpus-title')) {this.setElement(element, title);} this.setElements(this.displayElement.querySelectorAll('.corpus-title'), title);
} }
setTokenRatio(numTokens, maxNumTokens) { setNumTokens(numTokens) {
for (let element of this.displayElement.querySelectorAll('.corpus-token-ratio')) {this.setElement(element, `${numTokens}/${maxNumTokens}`);} this.setElements(
this.displayElement.querySelectorAll('.corpus-token-ratio'),
`${numTokens}/${app.users[this.userId].corpora[this.corpusId].max_num_tokens}`
);
} }
setDescription(description) { setDescription(description) {
for (let element of this.displayElement.querySelectorAll('.corpus-description')) {this.setElement(element, description);} this.setElements(this.displayElement.querySelectorAll('.corpus-description'), description);
} }
setStatus(status) { setStatus(status) {
for (let element of this.displayElement.querySelectorAll('.analyse-corpus-trigger')) { let element;
let elements;
this.setElements(this.displayElement.querySelectorAll('.corpus-status'), status);
elements = this.displayElement.querySelectorAll('.analyse-corpus-trigger')
for (element of elements) {
if (['analysing', 'prepared', 'start analysis'].includes(status)) { if (['analysing', 'prepared', 'start analysis'].includes(status)) {
element.classList.remove('disabled'); element.classList.remove('disabled');
} else { } else {
element.classList.add('disabled'); element.classList.add('disabled');
} }
} }
for (let element of this.displayElement.querySelectorAll('.build-corpus-trigger')) { elements = this.displayElement.querySelectorAll('.build-corpus-trigger');
for (element of elements) {
if (status === 'unprepared' && Object.values(app.users[this.userId].corpora[this.corpusId].files).length > 0) { if (status === 'unprepared' && Object.values(app.users[this.userId].corpora[this.corpusId].files).length > 0) {
element.classList.remove('disabled'); element.classList.remove('disabled');
} else { } else {
element.classList.add('disabled'); element.classList.add('disabled');
} }
} }
for (let element of this.displayElement.querySelectorAll('.corpus-status')) {this.setElement(element, status);} elements = this.displayElement.querySelectorAll('.status');
for (let exportCorpusTriggerElement of this.displayElement.querySelectorAll('.export-corpus-trigger')) { for (element of elements) {
exportCorpusTriggerElement.classList.toggle('disabled', !['prepared', 'start analysis', 'stop analysis'].includes(status)); element.dataset.status = status;
} }
for (let element of this.displayElement.querySelectorAll('.status')) {element.dataset.status = status;} elements = this.displayElement.querySelectorAll('.status-spinner');
for (let element of this.displayElement.querySelectorAll('.status-spinner')) { for (element of elements) {
if (['submitted', 'queued', 'running', 'canceling', 'start analysis', 'stop analysis'].includes(status)) { if (['submitted', 'queued', 'running', 'canceling', 'start analysis', 'stop analysis'].includes(status)) {
element.classList.remove('hide'); element.classList.remove('hide');
} else { } else {
@ -95,14 +99,16 @@ class CorpusDisplay extends RessourceDisplay {
} }
setCreationDate(creationDate) { setCreationDate(creationDate) {
for (let element of this.displayElement.querySelectorAll('.corpus-creation-date')) { this.setElements(
this.setElement(element, creationDate.toLocaleString("en-US")); this.displayElement.querySelectorAll('.corpus-creation-date'),
} new Date(creationDate).toLocaleString("en-US")
);
} }
setLastEditedDate(lastEditedDate) { setLastEditedDate(lastEditedDate) {
for (let element of this.displayElement.querySelectorAll('.corpus-end-date')) { this.setElements(
this.setElement(element, lastEditedDate.toLocaleString("en-US")); this.displayElement.querySelectorAll('.corpus-end-date'),
} new Date(lastEditedDate).toLocaleString("en-US")
);
} }
} }

View File

@ -5,7 +5,9 @@ class JobDisplay extends RessourceDisplay {
} }
init(user) { init(user) {
let job = user.jobs[this.jobId]; let job;
job = user.jobs[this.jobId];
this.setCreationDate(job.creation_date); this.setCreationDate(job.creation_date);
this.setEndDate(job.creation_date); this.setEndDate(job.creation_date);
this.setDescription(job.description); this.setDescription(job.description);
@ -17,9 +19,13 @@ class JobDisplay extends RessourceDisplay {
} }
usersPatchHandler(patch) { usersPatchHandler(patch) {
let re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}`); let filteredPatch;
let filteredPatch = patch.filter(operation => re.test(operation.path)); let operation;
for (let operation of filteredPatch) { let re;
re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}`);
filteredPatch = patch.filter(operation => re.test(operation.path));
for (operation of filteredPatch) {
switch(operation.op) { switch(operation.op) {
case 'replace': case 'replace':
re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}/end_date$`); re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}/end_date$`);
@ -40,26 +46,33 @@ class JobDisplay extends RessourceDisplay {
} }
setTitle(title) { setTitle(title) {
for (let element of this.displayElement.querySelectorAll('.job-title')) {this.setElement(element, title);} this.setElements(this.displayElement.querySelectorAll('.job-title'), title);
} }
setDescription(description) { setDescription(description) {
for (let element of this.displayElement.querySelectorAll('.job-description')) {this.setElement(element, description);} this.setElements(this.displayElement.querySelectorAll('.job-description'), description);
} }
setStatus(status) { setStatus(status) {
for (let element of this.displayElement.querySelectorAll('.job-status')) { let element;
this.setElement(element, status); let elements;
this.setElements(this.displayElement.querySelectorAll('.job-status'), status);
elements = this.displayElement.querySelectorAll('.status');
for (element of elements) {
element.dataset.status = status;
} }
for (let element of this.displayElement.querySelectorAll('.status')) {element.dataset.status = status;} elements = this.displayElement.querySelectorAll('.status-spinner');
for (let element of this.displayElement.querySelectorAll('.status-spinner')) { for (element of elements) {
if (['complete', 'failed'].includes(status)) { if (['complete', 'failed'].includes(status)) {
element.classList.add('hide'); element.classList.add('hide');
} else { } else {
element.classList.remove('hide'); element.classList.remove('hide');
} }
} }
for (let element of this.displayElement.querySelectorAll('.restart-job-trigger')) { elements = this.displayElement.querySelectorAll('.restart-job-trigger');
for (element of elements) {
if (['complete', 'failed'].includes(status)) { if (['complete', 'failed'].includes(status)) {
element.classList.remove('hide'); element.classList.remove('hide');
} else { } else {
@ -69,26 +82,28 @@ class JobDisplay extends RessourceDisplay {
} }
setCreationDate(creationDate) { setCreationDate(creationDate) {
for (let element of this.displayElement.querySelectorAll('.job-creation-date')) { this.setElements(
this.setElement(element, creationDate.toLocaleString('en-US')); this.displayElement.querySelectorAll('.job-creation-date'),
} new Date(creationDate).toLocaleString('en-US')
);
} }
setEndDate(endDate) { setEndDate(endDate) {
for (let element of this.displayElement.querySelectorAll('.job-end-date')) { this.setElements(
this.setElement(element, endDate.toLocaleString('en-US')); this.displayElement.querySelectorAll('.job-end-date'),
} new Date(endDate).toLocaleString('en-US')
);
} }
setService(service) { setService(service) {
for (let element of this.displayElement.querySelectorAll('.job-service')) {this.setElement(element, service);} this.setElements(this.displayElement.querySelectorAll('.job-service'), service);
} }
setServiceArgs(serviceArgs) { setServiceArgs(serviceArgs) {
for (let element of this.displayElement.querySelectorAll('.job-service-args')) {this.setElement(element, serviceArgs);} this.setElements(this.displayElement.querySelectorAll('.job-service-args'), serviceArgs);
} }
setServiceVersion(serviceVersion) { setServiceVersion(serviceVersion) {
for (let element of this.displayElement.querySelectorAll('.job-service-version')) {this.setElement(element, serviceVersion);} this.setElements(this.displayElement.querySelectorAll('.job-service-version'), serviceVersion);
} }
} }

View File

@ -3,7 +3,7 @@ class RessourceDisplay {
this.displayElement = displayElement; this.displayElement = displayElement;
this.userId = this.displayElement.dataset.userId; this.userId = this.displayElement.dataset.userId;
app.addEventListener('users.patch', patch => this.usersPatchHandler(patch)); app.addEventListener('users.patch', patch => this.usersPatchHandler(patch));
app.getUserById(this.userId).then(user => this.init(user), error => {throw JSON.stringify(error);}); app.getUserById(this.userId).then(user => this.init(user));
} }
init(user) {throw 'Not implemented';} init(user) {throw 'Not implemented';}
@ -21,4 +21,12 @@ class RessourceDisplay {
break; break;
} }
} }
setElements(elements, value) {
let element;
for (element of elements) {
this.setElement(element, value);
}
}
} }

View File

@ -9,14 +9,23 @@ class CorpusFileList extends RessourceList {
} }
onclick(event) { onclick(event) {
let corpusFileElement = event.target.closest('tr[data-id]'); let action;
if (corpusFileElement === null) {throw 'Could not locate corpus file element';} let actionButtonElement;
let corpusFileId = corpusFileElement.dataset.id; let corpusFileElement;
let actionButtonElement = event.target.closest('.action-button[data-action]'); let corpusFileId;
let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action; let deleteModal;
let deleteModalElement;
let tmp;
corpusFileElement = event.target.closest('tr[data-id]');
if (corpusFileElement === null) {return;}
corpusFileId = corpusFileElement.dataset.id;
actionButtonElement = event.target.closest('.action-button[data-action]');
action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
switch (action) { switch (action) {
case 'delete': case 'delete':
let deleteModalHTML = ` tmp = document.createElement('div');
tmp.innerHTML = `
<div class="modal"> <div class="modal">
<div class="modal-content"> <div class="modal-content">
<h4>Confirm corpus deletion</h4> <h4>Confirm corpus deletion</h4>
@ -28,10 +37,16 @@ class CorpusFileList extends RessourceList {
</div> </div>
</div> </div>
`.trim(); `.trim();
let deleteModalParentElement = document.querySelector('#modals'); deleteModalElement = document.querySelector('#modals').appendChild(tmp.firstChild);
deleteModalParentElement.insertAdjacentHTML('beforeend', deleteModalHTML); deleteModal = M.Modal.init(
let deleteModalElement = deleteModalParentElement.lastChild; deleteModalElement,
let deleteModal = M.Modal.init(deleteModalElement, {onCloseEnd: () => {deleteModal.destroy(); deleteModalElement.remove();}}); {
onCloseEnd: () => {
deleteModal.destroy();
deleteModalElement.remove();
}
}
);
deleteModal.open(); deleteModal.open();
break; break;
case 'download': case 'download':
@ -46,13 +61,22 @@ class CorpusFileList extends RessourceList {
} }
usersPatchHandler(patch) { usersPatchHandler(patch) {
let re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/files/([A-Za-z0-9]*)`); let corpusFileId;
let filteredPatch = patch.filter(operation => re.test(operation.path)); let filteredPatch;
for (let operation of filteredPatch) { let match;
let operation;
let re;
let valueName;
re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/files/([A-Za-z0-9]*)`);
filteredPatch = patch.filter(operation => re.test(operation.path));
for (operation of filteredPatch) {
switch(operation.op) { switch(operation.op) {
case 'add': case 'add':
re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/files/([A-Za-z0-9]*)$`); re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/files/([A-Za-z0-9]*)$`);
if (re.test(operation.path)) {this.add(operation.value);} if (re.test(operation.path)) {
this.add(operation.value);
}
break; break;
case 'remove': case 'remove':
re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/files/([A-Za-z0-9]*)$`); re = new RegExp(`^/users/${this.userId}/corpora/${this.corpusId}/files/([A-Za-z0-9]*)$`);

View File

@ -8,14 +8,23 @@ class CorpusList extends RessourceList {
} }
onclick(event) { onclick(event) {
let corpusElement = event.target.closest('tr[data-id]'); let action;
if (corpusElement === null) {throw 'Could not locate corpus element';} let actionButtonElement;
let corpusId = corpusElement.dataset.id; let corpusElement;
let actionButtonElement = event.target.closest('.action-button[data-action]'); let corpusId;
let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action; let deleteModal;
let deleteModalElement;
let tmp;
corpusElement = event.target.closest('tr[data-id]');
if (corpusElement === null) {return;}
corpusId = corpusElement.dataset.id;
actionButtonElement = event.target.closest('.action-button[data-action]');
action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
switch (action) { switch (action) {
case 'delete': case 'delete':
let deleteModalHTML = ` tmp = document.createElement('div');
tmp.innerHTML = `
<div class="modal"> <div class="modal">
<div class="modal-content"> <div class="modal-content">
<h4>Confirm corpus deletion</h4> <h4>Confirm corpus deletion</h4>
@ -27,10 +36,16 @@ class CorpusList extends RessourceList {
</div> </div>
</div> </div>
`.trim(); `.trim();
let deleteModalParentElement = document.querySelector('#modals'); deleteModalElement = document.querySelector('#modals').appendChild(tmp.firstChild);
deleteModalParentElement.insertAdjacentHTML('beforeend', deleteModalHTML); deleteModal = M.Modal.init(
let deleteModalElement = deleteModalParentElement.lastChild; deleteModalElement,
let deleteModal = M.Modal.init(deleteModalElement, {onCloseEnd: () => {deleteModal.destroy(); deleteModalElement.remove();}}); {
onCloseEnd: () => {
deleteModal.destroy();
deleteModalElement.remove();
}
}
);
deleteModal.open(); deleteModal.open();
break; break;
case 'view': case 'view':
@ -42,9 +57,16 @@ class CorpusList extends RessourceList {
} }
usersPatchHandler(patch) { usersPatchHandler(patch) {
let re = new RegExp(`^/users/${this.userId}/corpora/([A-Za-z0-9]*)`); let corpusId;
let filteredPatch = patch.filter(operation => re.test(operation.path)); let filteredPatch;
for (let operation of filteredPatch) { let match;
let operation;
let re;
let valueName;
re = new RegExp(`^/users/${this.userId}/corpora/([A-Za-z0-9]*)`);
filteredPatch = patch.filter(operation => re.test(operation.path));
for (operation of filteredPatch) {
switch(operation.op) { switch(operation.op) {
case 'add': case 'add':
re = new RegExp(`^/users/${this.userId}/corpora/([A-Za-z0-9]*)$`); re = new RegExp(`^/users/${this.userId}/corpora/([A-Za-z0-9]*)$`);
@ -53,14 +75,14 @@ class CorpusList extends RessourceList {
case 'remove': case 'remove':
re = new RegExp(`^/users/${this.userId}/corpora/([A-Za-z0-9]*)$`); re = new RegExp(`^/users/${this.userId}/corpora/([A-Za-z0-9]*)$`);
if (re.test(operation.path)) { if (re.test(operation.path)) {
let [match, corpusId] = operation.path.match(re); [match, corpusId] = operation.path.match(re);
this.remove(corpusId); this.remove(corpusId);
} }
break; break;
case 'replace': case 'replace':
re = new RegExp(`^/users/${this.userId}/corpora/([A-Za-z0-9]*)/(status|description|title)$`); re = new RegExp(`^/users/${this.userId}/corpora/([A-Za-z0-9]*)/(status|description|title)$`);
if (re.test(operation.path)) { if (re.test(operation.path)) {
let [match, corpusId, valueName] = operation.path.match(re); [match, corpusId, valueName] = operation.path.match(re);
this.replace(corpusId, valueName, operation.value); this.replace(corpusId, valueName, operation.value);
} }
break; break;

View File

@ -9,12 +9,17 @@ class JobInputList extends RessourceList {
} }
onclick(event) { onclick(event) {
let jobInputElement = event.target.closest('tr[data-id]'); let jobInputElement;
let jobInputId;
let action;
let actionButtonElement;
jobInputElement = event.target.closest('tr[data-id]');
if (jobInputElement === null) {return;} if (jobInputElement === null) {return;}
let jobInputId = jobInputElement.dataset.id; jobInputId = jobInputElement.dataset.id;
let actionButtonElement = event.target.closest('.action-button[data-action]'); actionButtonElement = event.target.closest('.action-button[data-action]');
if (actionButtonElement === null) {return;} if (actionButtonElement === null) {return;}
let action = actionButtonElement.dataset.action; action = actionButtonElement.dataset.action;
switch (action) { switch (action) {
case 'download': case 'download':
window.location.href = `/jobs/${this.jobId}/inputs/${jobInputId}/download`; window.location.href = `/jobs/${this.jobId}/inputs/${jobInputId}/download`;

View File

@ -8,14 +8,23 @@ class JobList extends RessourceList {
} }
onclick(event) { onclick(event) {
let jobElement = event.target.closest('tr[data-id]'); let action;
if (jobElement === null) {throw 'Could not locate job element';} let actionButtonElement;
let jobId = jobElement.dataset.id; let deleteModal;
let actionButtonElement = event.target.closest('.action-button[data-action]'); let deleteModalElement;
let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action; let jobElement;
let jobId;
let tmp;
jobElement = event.target.closest('tr[data-id]');
if (jobElement === null) {return;}
jobId = jobElement.dataset.id;
actionButtonElement = event.target.closest('.action-button[data-action]');
action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
switch (action) { switch (action) {
case 'delete': case 'delete':
let deleteModalHTML = ` tmp = document.createElement('div');
tmp.innerHTML = `
<div class="modal"> <div class="modal">
<div class="modal-content"> <div class="modal-content">
<h4>Confirm job deletion</h4> <h4>Confirm job deletion</h4>
@ -27,10 +36,16 @@ class JobList extends RessourceList {
</div> </div>
</div> </div>
`.trim(); `.trim();
let deleteModalParentElement = document.querySelector('#modals'); deleteModalElement = document.querySelector('#modals').appendChild(tmp.firstChild);
deleteModalParentElement.insertAdjacentHTML('beforeend', deleteModalHTML); deleteModal = M.Modal.init(
let deleteModalElement = deleteModalParentElement.lastChild; deleteModalElement,
let deleteModal = M.Modal.init(deleteModalElement, {onCloseEnd: () => {deleteModal.destroy(); deleteModalElement.remove();}}); {
onCloseEnd: () => {
deleteModal.destroy();
deleteModalElement.remove();
}
}
);
deleteModal.open(); deleteModal.open();
break; break;
case 'view': case 'view':
@ -42,25 +57,34 @@ class JobList extends RessourceList {
} }
usersPatchHandler(patch) { usersPatchHandler(patch) {
let re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)`); let filteredPatch;
let filteredPatch = patch.filter(operation => re.test(operation.path)); let jobId;
for (let operation of filteredPatch) { let match;
let operation;
let re;
let valueName;
re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)`);
filteredPatch = patch.filter(operation => re.test(operation.path));
for (operation of filteredPatch) {
switch(operation.op) { switch(operation.op) {
case 'add': case 'add':
re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)$`); re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)$`);
if (re.test(operation.path)) {this.add(operation.value);} if (re.test(operation.path)) {
this.add(operation.value);
}
break; break;
case 'remove': case 'remove':
re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)$`); re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)$`);
if (re.test(operation.path)) { if (re.test(operation.path)) {
let [match, jobId] = operation.path.match(re); [match, jobId] = operation.path.match(re);
this.remove(jobId); this.remove(jobId);
} }
break; break;
case 'replace': case 'replace':
re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)/(service|status|description|title)$`); re = new RegExp(`^/users/${this.userId}/jobs/([A-Za-z0-9]*)/(service|status|description|title)$`);
if (re.test(operation.path)) { if (re.test(operation.path)) {
let [match, jobId, valueName] = operation.path.match(re); [match, jobId, valueName] = operation.path.match(re);
this.replace(jobId, valueName, operation.value); this.replace(jobId, valueName, operation.value);
} }
break; break;

View File

@ -9,12 +9,17 @@ class JobResultList extends RessourceList {
} }
onclick(event) { onclick(event) {
let jobResultElement = event.target.closest('tr[data-id]'); let action;
let actionButtonElement;
let jobResultElement;
let jobResultId;
jobResultElement = event.target.closest('tr[data-id]');
if (jobResultElement === null) {return;} if (jobResultElement === null) {return;}
let jobResultId = jobResultElement.dataset.id; jobResultId = jobResultElement.dataset.id;
let actionButtonElement = event.target.closest('.action-button[data-action]'); actionButtonElement = event.target.closest('.action-button[data-action]');
if (actionButtonElement === null) {return;} if (actionButtonElement === null) {return;}
let action = actionButtonElement.dataset.action; action = actionButtonElement.dataset.action;
switch (action) { switch (action) {
case 'download': case 'download':
window.location.href = `/jobs/${this.jobId}/results/${jobResultId}`; window.location.href = `/jobs/${this.jobId}/results/${jobResultId}`;
@ -25,13 +30,19 @@ class JobResultList extends RessourceList {
} }
usersPatchHandler(patch) { usersPatchHandler(patch) {
let re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}/results/([A-Za-z0-9]*)`); let filteredPatch;
let filteredPatch = patch.filter(operation => re.test(operation.path)); let operation;
for (let operation of filteredPatch) { let re;
re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}/results/([A-Za-z0-9]*)`);
filteredPatch = patch.filter(operation => re.test(operation.path));
for (operation of filteredPatch) {
switch(operation.op) { switch(operation.op) {
case 'add': case 'add':
re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}/results/([A-Za-z0-9]*)$`); re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}/results/([A-Za-z0-9]*)$`);
if (re.test(operation.path)) {this.add(operation.value);} if (re.test(operation.path)) {
this.add(operation.value);
}
break; break;
default: default:
break; break;
@ -41,6 +52,7 @@ class JobResultList extends RessourceList {
preprocessRessource(jobResult) { preprocessRessource(jobResult) {
let description; let description;
if (jobResult.filename.endsWith('.pdf.zip')) { if (jobResult.filename.endsWith('.pdf.zip')) {
description = 'PDF files with text layer'; description = 'PDF files with text layer';
} else if (jobResult.filename.endsWith('.txt.zip')) { } else if (jobResult.filename.endsWith('.txt.zip')) {

View File

@ -8,14 +8,23 @@ class QueryResultList extends RessourceList {
} }
onclick(event) { onclick(event) {
let queryResultElement = event.target.closest('tr[data-id]'); let action;
let actionButtonElement;
let deleteModal;
let deleteModalElement;
let queryResultElement;
let queryResultId;
let tmp;
queryResultElement = event.target.closest('tr[data-id]');
if (queryResultElement === null) {return;} if (queryResultElement === null) {return;}
let queryResultId = queryResultElement.dataset.id; queryResultId = queryResultElement.dataset.id;
let actionButtonElement = event.target.closest('.action-button[data-action]'); actionButtonElement = event.target.closest('.action-button[data-action]');
let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action; action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action;
switch (action) { switch (action) {
case 'delete': case 'delete':
let deleteModalHTML = ` tmp = document.createElement('div');
tmp.innerHTML = `
<div class="modal"> <div class="modal">
<div class="modal-content"> <div class="modal-content">
<h4>Confirm query result deletion</h4> <h4>Confirm query result deletion</h4>
@ -27,10 +36,16 @@ class QueryResultList extends RessourceList {
</div> </div>
</div> </div>
`.trim(); `.trim();
let deleteModalParentElement = document.querySelector('#modals'); deleteModalElement = document.querySelector('#modals').appendChild(tmp.firstChild);
deleteModalParentElement.insertAdjacentHTML('beforeend', deleteModalHTML); deleteModal = M.Modal.init(
let deleteModalElement = deleteModalParentElement.lastChild; deleteModalElement,
let deleteModal = M.Modal.init(deleteModalElement, {onCloseEnd: () => {deleteModal.destroy(); deleteModalElement.remove();}}); {
onCloseEnd: () => {
deleteModal.destroy();
deleteModalElement.remove();
}
}
);
deleteModal.open(); deleteModal.open();
break; break;
case 'view': case 'view':
@ -42,25 +57,34 @@ class QueryResultList extends RessourceList {
} }
usersPatchHandler(patch) { usersPatchHandler(patch) {
let re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)`); let filteredPatch;
let filteredPatch = patch.filter(operation => re.test(operation.path)); let match;
for (let operation of filteredPatch) { let operation;
let queryResultId;
let re;
let valueName;
re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)`);
filteredPatch = patch.filter(operation => re.test(operation.path));
for (operation of filteredPatch) {
switch(operation.op) { switch(operation.op) {
case 'add': case 'add':
re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)$`); re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)$`);
if (re.test(operation.path)) {this.add(operation.value);} if (re.test(operation.path)) {
this.add(operation.value);
}
break; break;
case 'remove': case 'remove':
re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)$`); re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)$`);
if (re.test(operation.path)) { if (re.test(operation.path)) {
let [match, queryResultId] = operation.path.match(re); [match, queryResultId] = operation.path.match(re);
this.remove(queryResultId); this.remove(queryResultId);
} }
break; break;
case 'replace': case 'replace':
re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)/(corpus_title|description|query|title)$`); re = new RegExp(`^/users/${this.userId}/query_results/([A-Za-z0-9]*)/(corpus_title|description|query|title)$`);
if (re.test(operation.path)) { if (re.test(operation.path)) {
let [match, queryResultId, valueName] = operation.path.match(re); [match, queryResultId, valueName] = operation.path.match(re);
this.replace(queryResultId, valueName, operation.value); this.replace(queryResultId, valueName, operation.value);
} }
break; break;

View File

@ -8,14 +8,23 @@ class UserList extends RessourceList {
} }
onclick(event) { onclick(event) {
let userElement = event.target.closest('tr[data-id]'); let action;
let actionButtonElement;
let deleteModal;
let deleteModalElement;
let tmp;
let userElement;
let userId;
userElement = event.target.closest('tr[data-id]');
if (userElement === null) {return;} if (userElement === null) {return;}
let userId = userElement.dataset.id; userId = userElement.dataset.id;
let actionButtonElement = event.target.closest('.action-button[data-action]'); actionButtonElement = event.target.closest('.action-button[data-action]');
let action = (actionButtonElement === null) ? 'view' : actionButtonElement.dataset.action; action = (actionButtonElement === null) ? 'view' : actionButtonElement.dataset.action;
switch (action) { switch (action) {
case 'delete': case 'delete':
let deleteModalHTML = ` tmp = document.createElement('div');
tmp.innerHTML = `
<div class="modal"> <div class="modal">
<div class="modal-content"> <div class="modal-content">
<h4>Confirm user deletion</h4> <h4>Confirm user deletion</h4>
@ -27,10 +36,16 @@ class UserList extends RessourceList {
</div> </div>
</div> </div>
`.trim(); `.trim();
let deleteModalParentElement = document.querySelector('#modals'); deleteModalElement = document.querySelector('#modals').appendChild(tmp.firstChild);
deleteModalParentElement.insertAdjacentHTML('beforeend', deleteModalHTML); deleteModal = M.Modal.init(
let deleteModalElement = deleteModalParentElement.lastChild; deleteModalElement,
let deleteModal = M.Modal.init(deleteModalElement, {onCloseEnd: () => {deleteModal.destroy(); deleteModalElement.remove();}}); {
onCloseEnd: () => {
deleteModal.destroy();
deleteModalElement.remove();
}
}
);
deleteModal.open(); deleteModal.open();
break; break;
case 'edit': case 'edit':
@ -50,7 +65,7 @@ class UserList extends RessourceList {
id_: user.id, id_: user.id,
username: user.username, username: user.username,
email: user.email, email: user.email,
last_seen: user.last_seen.toLocaleString("en-US"), last_seen: new Date(user.last_seen).toLocaleString("en-US"),
role: user.role.name role: user.role.name
}; };
} }

View File

@ -68,4 +68,4 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}

View File

@ -92,9 +92,11 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock page_content %}
<!-- Modals --> {% block modals %}
{{ super() }}
<div id="delete-user-modal" class="modal"> <div id="delete-user-modal" class="modal">
<div class="modal-content"> <div class="modal-content">
<h3>Delete user</h3> <h3>Delete user</h3>
@ -105,8 +107,7 @@
<a href="{{ url_for('.delete_user', user_id=user.id) }}" class="modal-close waves-effect waves-light btn red"><i class="material-icons left">delete</i>Delete</a> <a href="{{ url_for('.delete_user', user_id=user.id) }}" class="modal-close waves-effect waves-light btn red"><i class="material-icons left">delete</i>Delete</a>
</div> </div>
</div> </div>
{% endblock %} {% endblock modals %}
{% block scripts %} {% block scripts %}
{{ super() }} {{ super() }}

View File

@ -35,7 +35,7 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}
{% block scripts %} {% block scripts %}
{{ super() }} {{ super() }}

View File

@ -52,4 +52,4 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}

View File

@ -45,4 +45,4 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}

View File

@ -29,4 +29,4 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}

View File

@ -28,4 +28,4 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}

View File

@ -23,4 +23,4 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}

View File

@ -32,13 +32,13 @@
{% block main_attribs %} class="background-color"{% endblock main_attribs %} {% block main_attribs %} class="background-color"{% endblock main_attribs %}
{% block main %} {% block main %}
{% block page_content %}{% endblock page_content %} {% block page_content %}{% endblock page_content %}
{% block modals %}
<div id="modals"> <div id="modals">
{% if current_user.is_authenticated %} {% block modals %}
{% include "_roadmap.html.j2" %} {% if current_user.is_authenticated %}
{% endif %} {% include "_roadmap.html.j2" %}
{% endif %}
{% endblock modals %}
</div> </div>
{% endblock modals %}
{% endblock main %} {% endblock main %}
{% block footer_attribs %} class="page-footer primary-variant-color"{% endblock footer_attribs %} {% block footer_attribs %} class="page-footer primary-variant-color"{% endblock footer_attribs %}

View File

@ -38,4 +38,4 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}

View File

@ -71,7 +71,11 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock page_content %}
{% block modals %}
{{ super() }}
<div id="progress-modal" class="modal"> <div id="progress-modal" class="modal">
<div class="modal-content"> <div class="modal-content">
<h4><i class="material-icons prefix">file_upload</i> Uploading file...</h4> <h4><i class="material-icons prefix">file_upload</i> Uploading file...</h4>
@ -83,4 +87,4 @@
<a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a> <a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a>
</div> </div>
</div> </div>
{% endblock %} {% endblock modals %}

View File

@ -70,17 +70,6 @@
<a class="btn modal-trigger red waves-effect waves-light" data-target="delete-corpus-modal"><i class="material-icons left">delete</i>Delete</a> <a class="btn modal-trigger red waves-effect waves-light" data-target="delete-corpus-modal"><i class="material-icons left">delete</i>Delete</a>
</div> </div>
</div> </div>
<div id="delete-corpus-modal" class="modal">
<div class="modal-content">
<h4>Confirm corpus deletion</h4>
<p>Do you really want to delete the corpus <span class="corpus-title"></span>? All files will be permanently deleted!</p>
</div>
<div class="modal-footer">
<a class="btn modal-close waves-effect waves-light" href="#!">Cancel</a>
<a class="btn modal-close red waves-effect waves-light" href="{{ url_for('corpora.delete_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
</div> </div>
<div class="col s12" id="corpus-files" data-corpus-id="{{ corpus.hashid }}" data-user-id="{{ corpus.user.hashid }}"> <div class="col s12" id="corpus-files" data-corpus-id="{{ corpus.hashid }}" data-user-id="{{ corpus.user.hashid }}">
@ -115,6 +104,20 @@
</div> </div>
{% endblock page_content %} {% endblock page_content %}
{% block modals %}
{{ super() }}
<div id="delete-corpus-modal" class="modal">
<div class="modal-content">
<h4>Confirm corpus deletion</h4>
<p>Do you really want to delete the corpus <span class="corpus-title"></span>? All files will be permanently deleted!</p>
</div>
<div class="modal-footer">
<a class="btn modal-close waves-effect waves-light" href="#!">Cancel</a>
<a class="btn modal-close red waves-effect waves-light" href="{{ url_for('corpora.delete_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
{% endblock modals %}
{% block scripts %} {% block scripts %}
{{ super() }} {{ super() }}
<script> <script>

View File

@ -48,4 +48,4 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}

View File

@ -43,7 +43,10 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock page_content %}
{% block modals %}
{{ super() }}
<div id="progress-modal" class="modal"> <div id="progress-modal" class="modal">
<div class="modal-content"> <div class="modal-content">
<h4><i class="material-icons prefix">file_upload</i> Uploading file...</h4> <h4><i class="material-icons prefix">file_upload</i> Uploading file...</h4>
@ -55,4 +58,4 @@
<a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a> <a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a>
</div> </div>
</div> </div>
{% endblock %} {% endblock modals %}

View File

@ -85,30 +85,6 @@
<a class="btn modal-trigger red waves-effect waves-light" data-target="delete-job-modal"><i class="material-icons left">delete</i>Delete</a> <a class="btn modal-trigger red waves-effect waves-light" data-target="delete-job-modal"><i class="material-icons left">delete</i>Delete</a>
</div> </div>
</div> </div>
<div id="delete-job-modal" class="modal">
<div class="modal-content">
<h4>Confirm deletion</h4>
<p>Do you really want to delete the job <span class="job-title"></span>? All associated files will be permanently deleted.</p>
</div>
<div class="modal-footer">
<a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a>
<a class="btn modal-close red waves-effect waves-light" href="{{ url_for('jobs.delete_job', job_id=job.id) }}"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
{% if current_user.is_administrator() %}
<div id="restart-job-modal" class="modal">
<div class="modal-content">
<h4>Confirm restart</h4>
<p>Do you really want to restart the job <span class="job-title"></span>? All log and result files will be permanently deleted.</p>
</div>
<div class="modal-footer">
<a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a>
<a class="btn modal-close red waves-effect waves-light" href="{{ url_for('jobs.restart', job_id=job.id) }}"><i class="material-icons left">restart</i>Restart</a>
</div>
</div>
{% endif %}
</div> </div>
<div class="col s12" id="job-inputs" data-job-id="{{ job.hashid }}" data-user-id="{{ job.user.hashid }}"> <div class="col s12" id="job-inputs" data-job-id="{{ job.hashid }}" data-user-id="{{ job.user.hashid }}">
@ -165,6 +141,33 @@
</div> </div>
{% endblock page_content %} {% endblock page_content %}
{% block modals %}
{{ super() }}
<div id="delete-job-modal" class="modal">
<div class="modal-content">
<h4>Confirm deletion</h4>
<p>Do you really want to delete the job <span class="job-title"></span>? All associated files will be permanently deleted.</p>
</div>
<div class="modal-footer">
<a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a>
<a class="btn modal-close red waves-effect waves-light" href="{{ url_for('jobs.delete_job', job_id=job.id) }}"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
{% if current_user.is_administrator() %}
<div id="restart-job-modal" class="modal">
<div class="modal-content">
<h4>Confirm restart</h4>
<p>Do you really want to restart the job <span class="job-title"></span>? All log and result files will be permanently deleted.</p>
</div>
<div class="modal-footer">
<a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a>
<a class="btn modal-close red waves-effect waves-light" href="{{ url_for('jobs.restart', job_id=job.id) }}"><i class="material-icons left">restart</i>Restart</a>
</div>
</div>
{% endif %}
{% endblock modals %}
{% block scripts %} {% block scripts %}
{{ super() }} {{ super() }}
<script> <script>

View File

@ -119,8 +119,14 @@
<p><a class="modal-trigger waves-effect waves-light btn" href="#" data-target="new-job-modal"><i class="material-icons left">add</i>New job</a></p> <p><a class="modal-trigger waves-effect waves-light btn" href="#" data-target="new-job-modal"><i class="material-icons left">add</i>New job</a></p>
</div> </div>
</div> </div>
</div>
</div>
</div>
{% endblock page_content %}
<div id="new-job-modal" class="modal"> {% block modals %}
{{ super() }}
<div id="new-job-modal" class="modal">
<div class="modal-content"> <div class="modal-content">
<h4>Select a service</h4> <h4>Select a service</h4>
<p>&nbsp;</p> <p>&nbsp;</p>
@ -166,11 +172,8 @@
<div class="modal-footer"> <div class="modal-footer">
<a href="#!" class="modal-close waves-effect waves-light btn-flat">Close</a> <a href="#!" class="modal-close waves-effect waves-light btn-flat">Close</a>
</div> </div>
</div>
</div>
</div>
</div> </div>
{% endblock %} {% endblock modals %}
{% block scripts %} {% block scripts %}
{{ super() }} {{ super() }}

View File

@ -53,4 +53,4 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}

View File

@ -215,4 +215,4 @@
<img src="{{ url_for('static', filename='images/parallax_lq/05_chapter_book_text_tale.jpg') }}" alt=""> <img src="{{ url_for('static', filename='images/parallax_lq/05_chapter_book_text_tale.jpg') }}" alt="">
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}

View File

@ -48,4 +48,4 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}

View File

@ -152,4 +152,4 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}

View File

@ -109,4 +109,4 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}

View File

@ -1,7 +1,7 @@
{% block doc %} {% block doc %}
<!DOCTYPE html> <!DOCTYPE html>
<html{% block html_attribs %}{% endblock html_attribs %}> <html{% block html_attribs %}{% endblock html_attribs %}>
{% block html %} {% block html %}
<head> <head>
{% block head %} {% block head %}
<title>{% block title %}{{title|default}}{% endblock title %}</title> <title>{% block title %}{{title|default}}{% endblock title %}</title>
@ -40,6 +40,6 @@
{% endblock scripts %} {% endblock scripts %}
{% endblock body %} {% endblock body %}
</body> </body>
{% endblock html %} {% endblock html %}
</html> </html>
{% endblock doc %} {% endblock doc %}

View File

@ -88,7 +88,7 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock page_content %}
{% block scripts %} {% block scripts %}
{{ super() }} {{ super() }}

View File

@ -65,7 +65,10 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock page_content %}
{% block modals %}
{{ super() }}
<div id="progress-modal" class="modal"> <div id="progress-modal" class="modal">
<div class="modal-content"> <div class="modal-content">
<h4><i class="material-icons prefix">file_upload</i> Uploading files...</h4> <h4><i class="material-icons prefix">file_upload</i> Uploading files...</h4>
@ -77,4 +80,4 @@
<a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a> <a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a>
</div> </div>
</div> </div>
{% endblock %} {% endblock modals %}

View File

@ -107,7 +107,10 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock page_content %}
{% block modals %}
{{ super() }}
<div id="progress-modal" class="modal"> <div id="progress-modal" class="modal">
<div class="modal-content"> <div class="modal-content">
<h4><i class="material-icons prefix">file_upload</i> Uploading files...</h4> <h4><i class="material-icons prefix">file_upload</i> Uploading files...</h4>
@ -119,8 +122,7 @@
<a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a> <a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a>
</div> </div>
</div> </div>
{% endblock %} {% endblock modals %}
{% block scripts %} {% block scripts %}
{{ super() }} {{ super() }}
@ -132,4 +134,4 @@
window.location.href = url.toString(); window.location.href = url.toString();
}); });
</script> </script>
{% endblock %} {% endblock scripts %}

View File

@ -134,7 +134,10 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock page_content %}
{% block modals %}
{{ super() }}
<div id="progress-modal" class="modal"> <div id="progress-modal" class="modal">
<div class="modal-content"> <div class="modal-content">
<h4><i class="material-icons left">file_upload</i>Uploading files...</h4> <h4><i class="material-icons left">file_upload</i>Uploading files...</h4>
@ -146,8 +149,7 @@
<a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a> <a href="#!" class="modal-close waves-effect waves-light btn red abort-request">Cancel</a>
</div> </div>
</div> </div>
{% endblock %} {% endblock modals %}
{% block scripts %} {% block scripts %}
{{ super() }} {{ super() }}
@ -159,4 +161,4 @@
window.location.href = url.toString(); window.location.href = url.toString();
}); });
</script> </script>
{% endblock %} {% endblock scripts %}

View File

@ -64,9 +64,10 @@
</div> </div>
</div> </div>
</div> </div>
{% endblock page_content %}
{% block modals %}
<!-- Modals --> {{ super() }}
<div class="modal" id="delete-account-modal"> <div class="modal" id="delete-account-modal">
<div class="modal-content"> <div class="modal-content">
<h4>Confirm deletion</h4> <h4>Confirm deletion</h4>
@ -77,4 +78,4 @@
<a href="{{ url_for('.delete') }}" class="btn red waves-effect waves-light"><i class="material-icons left">delete</i>Delete</a> <a href="{{ url_for('.delete') }}" class="btn red waves-effect waves-light"><i class="material-icons left">delete</i>Delete</a>
</div> </div>
</div> </div>
{% endblock page_content %} {% endblock modals %}