ojuso-map/assets/js/form_casestudy_drafts.js

252 lines
6.3 KiB
JavaScript

"use strict";
//
// UI ELEMENTS
//
class SaveButton {
constructor(div) {
this.root = div
this.root.className = "savebutton"
this.root.style.display = "block"
this.element = {
root: this.root,
button: this.root.querySelector('.savebutton--button'),
icon: this.root.querySelector('.savebutton--icon'),
details: this.root.querySelector('.savebutton--details')
}
this.switchStateInitial()
}
changeState(data) {
var data = data || {}
this.element.button.innerText = data.buttonText || "Save"
this.element.button.disabled = data.buttonClickable === false ? true : false
this.element.icon.className = 'savebutton--icon ' + (data.iconClasses || "")
this.element.details.innerText = data.detailsText || ""
}
switchStateInitial() {
this.changeState({
buttonClickable: false
})
}
switchStateUnsaved() {
this.changeState({
detailsText: django.gettext("You have unsaved changes. Click here to save a draft, which you can access next time you are here.")
})
}
switchStateSaving() {
this.changeState({
buttonText: django.gettext("Saving..."),
iconClasses: "fa fa-spinner fa-spin"
})
}
switchStateSaveSuccess() {
this.changeState({
buttonText: django.gettext("Saved"),
detailsText: django.gettext("Saved successfully."),
iconClasses: "fa fa-check",
buttonClickable: false
})
}
switchStateSaveFailed(reason = "") {
this.changeState({
detailsText: django.gettext("Save failed! ") + reason,
iconClasses: "fa fa-exclamation-triangle savebutton--icon-failed"
})
}
}
class DraftPrompt {
constructor(opts) {
this.restoreDraft = opts.restoreFn
this.deleteDraft = opts.deleteFn
this.root = opts.root
this.element = {
root: this.root,
restore: this.root.querySelector('.draftprompt--restore'),
delete: this.root.querySelector('.draftprompt--delete'),
details: this.root.querySelector('.draftprompt--details')
}
// Restore should restore, then hide the prompt
this.element.restore.addEventListener('click', () => {
this.restoreDraft()
this.switchStateHidden()
})
// Delete button will delete the draft
this.element.delete.addEventListener('click', () => {
if (window.confirm(django.gettext('Are you sure you want to delete your draft?'))) {
this.switchStateDeleting()
this.deleteDraft().then(ok => ok ?
this.switchStateHidden() :
this.switchStateDeleteFailed()
)
}
})
this.switchStateShown()
}
changeState(data) {
var data = data || {}
this.element.root.style.display = data.visible ? "block" : "none"
this.element.details.innerHTML = data.detailsText || ""
}
switchStateHidden() {
this.changeState({
visible: false
})
}
switchStateShown() {
this.changeState({
visible: true
})
}
switchStateDeleting() {
this.changeState({
visible: true,
details: '<i classs="fa fa-spinner fa-spin"></i>'
})
}
switchStateDeleteFailed() {
this.changeState({
details: django.gettext("Delete failed!")
})
}
}
//
// API UTILITIES
//
function apiGetDraft() {
return fetch('/en-gb/case-study/draft', {
method: 'GET',
credentials: "same-origin",
headers: {
"X-CSRFToken": jQuery("[name=csrfmiddlewaretoken]").val(),
}
})
}
function apiPutDraft(formSaver) {
if (!formSaver) {
throw new Error("apiPutDraft: parameter not provided")
}
return fetch('/en-gb/case-study/draft', {
method: 'PUT',
credentials: "same-origin",
headers: {
"X-CSRFToken": jQuery("[name=csrfmiddlewaretoken]").val(),
"Accept": "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({ version: 1, data: formSaver.serialise() })
})
}
function apiDeleteDraft() {
return fetch('/en-gb/case-study/draft', {
method: 'DELETE',
credentials: "same-origin",
headers: {
"X-CSRFToken": jQuery("[name=csrfmiddlewaretoken]").val(),
}
})
}
//
// GNARLY BITS TYING API & UI STUFF TOGETHER
//
function showDraftPrompt(formSaver, serialisedForm) {
let prompt = new DraftPrompt({
root: document.querySelector('.draftprompt'),
restoreFn: () => formSaver.deserialise(serialisedForm),
deleteFn: () => apiDeleteDraft().then(response => response.ok)
})
}
function initDrafts() {
const formSaver = new FormSaver({
formId: 'case-study-form',
except: [ 'csrfmiddlewaretoken' ]
})
// Use whether the form has errors as a proxy for whether the server has
// returned us data in the form. In this case, don't show a draft.
const formHasErrors = document.getElementById('form_errors').value === 'true' ? true : false
if (!formHasErrors) {
// Get the previous draft, if any
apiGetDraft()
.then(response => {
if (response.status == 404) {
console.log("No draft stored on server");
} else if (response.ok) {
response.json().then(json => {
// Handle the case where we didn't get a response
if (!json) return
if (json.version !== 1) {
throw new Error("Bad JSON response version")
}
showDraftPrompt(formSaver, json.data.form)
});
} else {
throw new Error("Error getting draft", response)
}
})
.catch(err => {
console.error(err);
})
}
// Init the button controller
var button = new SaveButton(document.querySelector('.savebutton'))
// Dirty forms set up
$('#case-study-form').dirtyForms();
$('#case-study-form').on('dirty.dirtyforms', ev => {
button.switchStateUnsaved()
});
// Save button
button.element.button.addEventListener('click', evt => {
button.switchStateSaving()
apiPutDraft(formSaver).then(response => {
if (response.ok) {
button.switchStateSaveSuccess();
$('#case-study-form').dirtyForms('setClean');
document.querySelector('.draftprompt').style.display = "none"
} else {
button.switchStateSaveFailed();
}
}).catch(err => {
console.error(err);
button.switchStateSaveFailed();
})
})
}
// https://github.com/snikch/jquery.dirtyforms