This repository has been archived on 2025-01-01. You can view files and clone it, but cannot push or open issues or pull requests.
moodle-local_treestudyplan/amd/src/util/mform-helper.js
2024-03-25 23:42:40 +01:00

213 lines
8 KiB
JavaScript

/*eslint no-var: "error"*/
/*eslint no-console: "off"*/
/*eslint no-bitwise: "off"*/
/*eslint-disable no-trailing-spaces*/
/*eslint-env es6*/
// Put this file in path/to/plugin/amd/src
import {call} from 'core/ajax';
import {processCollectedJavascript} from 'core/fragment';
import {replaceNodeContents} from 'core/templates';
import notification from 'core/notification';
import {load_strings} from './string-helper';
import Debugger from './debugger';
//import {markFormSubmitted} from 'core_form/changechecker'; // Moodle 4.00+ only
//import {notifyFormSubmittedByJavascript} from 'core_form/events'; // Moodle 4.00+ only
/* Moodle 3.11 safe import for when needed
let markFormSubmitted = () => {};
let notifyFormSubmittedByJavascript = () => {};
import('core_form/changechecker').then((ns) => {
debug.info(ns);
if(ns.markFormSubmitted) {
markFormSubmitted = ns.markFormSubmitted;
}
if(ns.notifyFormSubmittedByJavascript) {
notifyFormSubmittedByJavascript = ns.notifyFormSubmittedByJavascript;
}
}).catch(()=>{});
*/
/**
* Create a random UUID in both secure and insecure contexts
* @returns UUID
*/
function create_uuid() {
if (crypto.randomUUID !== undefined ) {
return crypto.randomUUID();
} else {
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
);
}
}
export default {
install(Vue/*,options*/){
let debug = new Debugger("treestudyplan-mform-helper");
let strings = load_strings({
editmod: {
save$core: "save$core",
cancel$core: "cancel$core",
}
});
Vue.component('mform', {
props: {
name: {
type: String,
},
params: {
type: Object,
},
title: {
type: String,
default: "",
},
variant: {
type: String,
default: "primary",
},
type: {
type: String,
default: "link",
}
},
data() {
return {
content: "",
loading: true,
uuid: create_uuid(),
text: strings,
submitok: false,
observer: null,
inputs: [],
};
},
computed: {
},
methods: {
openForm() {
const self = this;
self.$refs["editormodal"].show();
},
onShown() {
const self = this;
debug.info(`Loading form "${self.name}" with params`,self.params);
self.loading = false;
call([{
methodname: 'local_treestudyplan_get_mform',
args: {formname: self.name, params: JSON.stringify(self.params)}
}])[0].then((data)=>{
const html = data.html;
self.loading = false;
// Process the collected javascript;
const js = processCollectedJavascript(data.javascript);
replaceNodeContents(self.$refs["content"], html, js);
self.initListenChanges();
}).catch(notification.exception);
},
onSave() {
const self = this;
let form = this.$refs["content"].getElementsByTagName("form")[0];
// markFormSubmitted(form); // Moodle 4.00+ only
// We call this, so other modules can update the form with the latest state.
form.dispatchEvent(new Event("save-form-state"));
// Tell all form fields we are about to submit the form.
// notifyFormSubmittedByJavascript(form); // Moodle 4.00+ only
const formdata = new FormData(form);
const data = new URLSearchParams(formdata).toString();
if(this.checkSave()){
call([{
methodname: 'local_treestudyplan_submit_mform',
args: {formname: self.name, params: JSON.stringify(self.params), formdata: data}
}])[0].then((response)=>{
const updatedplan = JSON.parse(response.data);
self.$emit("saved",updatedplan,formdata);
}).catch(notification.exception);
}
/* No error if we cannot save, since it would just be to handle the edge case
where someone clicks on the save button before
an invalid input got a chance to update. */
},
checkSave() {
let canSave = true;
this.inputs.forEach(el => {
el.focus();
el.blur();
if (el.classList.contains("is-invalid")) {
canSave = false;
}
},this);
this.submitok = canSave;
return canSave;
},
initListenChanges() {
const content = this.$refs["content"];
this.inputs = content.querySelectorAll("input.form-control");
// Check if save needs to be blocked immediately. (delay call by a few ms)
setTimeout(this.checkSave, 100);
// Disconnect any existing observer.
if(this.observer) {
this.observer.disconnect();
}
// Initialize new observer and callback.
this.observer = new MutationObserver((mutationList) => {
for(const mix in mutationList){
const mutation = mutationList[mix];
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
this.checkSave();
}
}
});
// Connect the observer to the form inputs.
this.inputs.forEach(el => {
this.observer.observe(el,{ attributes: true });
},this);
},
},
unmount() {
if(this.observer) {
this.observer.disconnect();
}
},
template: `
<span class='mform-container'>
<b-button :variant="variant" v-if='type == "button"' @click.prevent='openForm'
><slot><i class='fa fa-gear'></i></slot></b-button>
<a variant="variant" v-else href='#' @click.prevent='openForm'
><slot><i class='fa fa-gear'></i></slot></a>
<b-modal
ref="editormodal"
scrollable
centered
size="xl"
id="'modal-'+uuid"
@shown="onShown"
@ok="onSave"
:ok-disabled="!submitok"
:title="title"
:ok-title="text.save$core"
><div :class="'s-mform-content'" ref="content"
><div class="d-flex justify-content-center mb-3"
><b-spinner variant="primary"></b-spinner
></div
></div
></b-modal>
</span>
`,
});
}
};