226 lines
6.8 KiB
JavaScript
226 lines
6.8 KiB
JavaScript
class MultipleFilesWidget {
|
|
constructor(div) {
|
|
this.root = div
|
|
this.fieldName = this.root.getAttribute('data-field')
|
|
this.fileList = []
|
|
this.element = {
|
|
list: this.root.querySelector('.filewidget--list'),
|
|
uploadButton: this.root.querySelector('.filewidget--input'),
|
|
field: document.querySelector(`[name="${this.fieldName}"]`)
|
|
}
|
|
|
|
const self = this
|
|
|
|
// Set up jquery-fileupload
|
|
$(this.element.uploadButton).fileupload({
|
|
dataType: 'json',
|
|
paramName: 'file',
|
|
done: function (e, data) {
|
|
// process server response
|
|
if (data.result.is_valid) {
|
|
self.fileFinished.bind(self)(data.result)
|
|
} else {
|
|
self.fileFailed.bind(self)(data)
|
|
}
|
|
},
|
|
add: function (e, data) {
|
|
$.each(data.files, (index, file) => {
|
|
self.addFile.bind(self)(null, file.name, self.setFileInProgress.bind(self))
|
|
})
|
|
|
|
data.process().done(function () {
|
|
data.submit()
|
|
})
|
|
},
|
|
progress: function(e, data) {
|
|
console.log('progress event')
|
|
console.log(e, data)
|
|
}
|
|
})
|
|
|
|
// If there is something in the field, we need to restore our state
|
|
if (this.element.field.value) {
|
|
this.rebuildListFromField()
|
|
}
|
|
|
|
// Set up listening for restore
|
|
this.element.field.addEventListener('change', evt => {
|
|
this.rebuildListFromField()
|
|
})
|
|
}
|
|
|
|
rebuildListFromField() {
|
|
let idList = this.element.field.value.split(",")
|
|
for (let id of idList) {
|
|
this.addFile(id, `Saved upload (id ${id})`, this.setFileDone.bind(this))
|
|
}
|
|
this.viewFileList()
|
|
}
|
|
|
|
addFile(id, name, stateFunc) {
|
|
let li = document.createElement('li')
|
|
li.className = 'filewidget--file'
|
|
li.innerHTML =
|
|
`<i class='filewidget--file--icon'></i> <span class='filewidget--file--name'></span>
|
|
<span class='filewidget--file--actions'></span>`
|
|
|
|
let file = {
|
|
root: li,
|
|
element: {
|
|
icon: li.querySelector('.filewidget--file--icon'),
|
|
name: li.querySelector('.filewidget--file--name'),
|
|
actions: li.querySelector('.filewidget--file--actions'),
|
|
},
|
|
name: name,
|
|
id: id || null,
|
|
}
|
|
|
|
stateFunc(file)
|
|
|
|
this.fileList.push(file)
|
|
this.viewFileList()
|
|
}
|
|
|
|
removeFile(file) {
|
|
// Remove file from display
|
|
this.element.list.removeChild(file.root)
|
|
|
|
// Remove file from fileList
|
|
this.fileList = this.fileList.filter(cmpFile => cmpFile === file)
|
|
}
|
|
|
|
fileFinished(serverResponse) {
|
|
// Using data, find the file
|
|
let file = this.fileList.filter(file => file.name === serverResponse.name)[0]
|
|
|
|
// Set the ID
|
|
file.id = serverResponse.id
|
|
|
|
// Set the file state now it's finished
|
|
this.setFileDone(file)
|
|
this.viewFileList()
|
|
|
|
// Do this last tho
|
|
this.updateFormField()
|
|
}
|
|
|
|
fileFailed(serverResponse) {
|
|
let errors = Object.values(serverResponse.result.errors).join(' ')
|
|
|
|
console.error('File upload failed: ' + errors)
|
|
console.error(serverResponse)
|
|
|
|
// Using data, find the file
|
|
let file = this.fileList.filter(file => file.name === serverResponse.files[0].name)[0]
|
|
|
|
// Set the file state now it's finished
|
|
this.setFileFailed(file, errors)
|
|
this.viewFileList()
|
|
}
|
|
|
|
//
|
|
// Update the field that keeps track of file IDs
|
|
//
|
|
|
|
updateFormField() {
|
|
let oldVal = this.element.field.value
|
|
this.element.field.value = this.fileList.filter(f => f.id != null)
|
|
.map(f => f.id)
|
|
.toString()
|
|
|
|
// Mark form as dirty
|
|
if (this.element.field.value !== oldVal) {
|
|
document.getElementById('case-study-form').dispatchEvent(new Event('dirty'))
|
|
}
|
|
}
|
|
|
|
//
|
|
// Manage the state of individual files in the widget
|
|
//
|
|
|
|
setFileState(file, state) {
|
|
file.element.icon.classList = `filewidget--file--icon ${state.iconClassList}`
|
|
file.element.name.innerText = state.fileName
|
|
file.element.actions.innerHTML = state.actions || ''
|
|
}
|
|
|
|
setFileFailed(file, errors) {
|
|
this.setFileState(file, {
|
|
iconClassList: 'fa fa-exclamation-triangle',
|
|
fileName: `FAILED: ${errors} ('${file.name}')`
|
|
})
|
|
}
|
|
|
|
setFileInProgress(file) {
|
|
this.setFileState(file, {
|
|
iconClassList: 'fa fa-spinner fa-spin',
|
|
fileName: `${file.name} (uploading...)`
|
|
})
|
|
}
|
|
|
|
setFileDeletingInProgress(file) {
|
|
this.setFileState(file, {
|
|
iconClassList: 'fa fa-spinner fa-spin',
|
|
fileName: `Deleting...`
|
|
})
|
|
}
|
|
|
|
setFileDeletingFailed(file) {
|
|
this.setFileState(file, {
|
|
iconClassList: 'fa fa-exclamation-triangle',
|
|
fileName: `${file.name} (delete failed!)`
|
|
})
|
|
}
|
|
|
|
setFileDone(file) {
|
|
this.setFileState(file, {
|
|
iconClassList: 'fa fa-file-o',
|
|
fileName: `${file.name}`,
|
|
actions: '<a title="Remove"><i class="fa fa-times"></i></a>'
|
|
})
|
|
|
|
file.element.actions.querySelector('a').addEventListener('click', () => {
|
|
this.setFileDeletingInProgress(file)
|
|
|
|
return fetch(`/files/delete/${file.id}/`, {
|
|
method: 'POST',
|
|
credentials: "same-origin",
|
|
headers: {
|
|
"X-CSRFToken": jQuery("[name=csrfmiddlewaretoken]").val(),
|
|
}
|
|
}).then(response => {
|
|
if (response.ok) {
|
|
this.removeFile(file)
|
|
} else {
|
|
this.setFileDeletingFailed(file)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
//
|
|
// Redraw the file list
|
|
//
|
|
|
|
viewFileList() {
|
|
for (let file of this.fileList) {
|
|
// Check if it's appended to the list
|
|
if (!this.element.list.contains(file.root)) {
|
|
this.element.list.appendChild(file.root)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$(function() {
|
|
window.official_project_documents = new MultipleFilesWidget(
|
|
document.querySelector('[data-field=official_project_documents_files]')
|
|
)
|
|
window.other_documents = new MultipleFilesWidget(
|
|
document.querySelector('[data-field=other_documents_files]')
|
|
)
|
|
window.shapefiles = new MultipleFilesWidget(
|
|
document.querySelector('[data-field=shapefiles_files]')
|
|
)
|
|
})
|