Vue.component('click-by-click-assistant', {
props: ['pages', 'allowclose', 'pagination'],
data: function(){
return {
activePage: 0,
currentTransition:'',
dataStorage: []
}
},
template: '
' +
'
' +
'
' +
/** DEFAULT TEXT PAGE **/
'' +
'
' +
'
' +
'' +
'
'+
'
'+
'
'+
'
'+
'
'+
'
'+
'
'+
'
'+
'
' +
'
'+
'
' +
/** FORM PAGE **/
'' +
'
' +
'
' +
'' +
'
'+
'
'+
'
' +
'
' +
'
' +
'
' +
'' +
'
',
mounted: function(){
var self = this;
self.saveDataRequiredForSubmit();
self.$on('completeStep', function(){
if(WizardContainer !== undefined){
WizardContainer.completeStep();
}
self.$emit('close');
});
},
methods: {
/**
* @param {string} direction
*/
changePage: function(direction){
if(direction !== 'back' && direction !== 'next'){
return;
}
this.activePage = direction === 'next' ? this.activePage + 1 : this.activePage - 1;
this.currentTransition = direction;
},
link: function(link)
{
window.location.href = link;
},
/**
* saves all data that was defined on the building JSON file in order to submit it later
*/
saveDataRequiredForSubmit: function(){
var current;
for(var i = 0; i < this.pages.length; i++){
current = this.pages[i].dataRequiredForSubmit;
if(current === undefined || current.length === 0){
return;
}
this.setToStorage(current);
}
},
/**
* @param {Object} object
*/
setToStorage: function(object){
this.dataStorage.push(object);
},
/**
*
* @returns {Object}
*/
getStorage: function(){
return this.dataStorage;
},
/**
* clear storage, but keeps vue listener on this.dataStorage
*/
clearStorage: function(){
for (var member in this.dataStorage) {
delete this.dataStorage[member];
}
}
}
});
Vue.component('app-form',{
props: ['page'],
data: function () {
return {
rowId: 0,
surveyChoice: [],
showSurveyError: false,
formValid: true,
formWasValidated: false,
loading: false,
errorMsg: 'Bitte überprüfe die Eingabefelder'
}
},
template:
'',
methods:{
/**
* @param {Object} row
*/
addInputRow: function(row){
this.rowId++
row.id = this.rowId;
for(var k = 0; k < row.inputs.length; k++){
row.inputs[k].name += this.rowId;
}
this.page.form.push(row);
for(var i = 0; i < this.page.form.length -1; i++){
this.page.form[i].add.allow = false;
}
if(row.add.maximum === this.page.form.length){
this.allowAddOnLastRow(false);
}
},
/**
* @param {number} index
*/
removeInputRow: function(index){
if(this.page.form.length <= 1){
return;
}
this.page.form.splice(index, 1);
this.allowAddOnLastRow(true);
},
/**
* @param {string} decision
*/
allowAddOnLastRow: function(decision){
var lastIndex = this.page.form.length - 1;
this.page.form[lastIndex].add.allow = decision;
},
/**
* @param {Object} e
*/
processForm: function(e){
this.validateForm();
if(!this.formValid){
return;
}
if(!this.page.submitType){
throw new Error("Please define submitType in your JSON");
}
if(this.page.submitType === "save"){
this.$parent.setToStorage(this.filterDataFromSubmitEvent(e));
this.$parent.changePage("next");
return;
}
this.submitForm(e);
},
validateForm: function(){
if(this.page.submitType === 'survey'){
this.formValid = this.surveyChoice.length !== 0;
this.formWasValidated = true;
if(!this.formValid){
this.showSurveyError = true;
}
} else {
this.formValid = this.requiredRowsValid();
}
},
/**
* Checks if the required rows are valid
* @returns {boolean}
*/
requiredRowsValid: function(){
if(this.$refs === undefined){
console.error("Please define ref on child component");
return false;
}
if(this.$refs.row === undefined) {
return true;
}
var current;
for(var i = 0; i < this.$refs.row.length; i++){
current = this.$refs.row[i];
// case 1: if row has not been validated (no user input), form is valid in regard of this row
if(!current.rowWasValidated){
this.formWasValidated = false;
return true;
}
// case 2: if row is invalid, form is not valid
// rowValid only includes required inputs (filtered out on row component)
if(!current.rowValid){
this.formWasValidated = true;
return false;
}
}
return true; // if case1 or case2 didn't match, form valid
},
/**
* @param {Event} e
*/
submitForm: function(e){
var request = new XMLHttpRequest(),
self = this,
data,
responseJson;
data = this.prepareSubmitData(e);
request.open("POST", this.page.submitUrl + '', true);
request.addEventListener('load', function(event) {
if (request.status >= 200 && request.status < 300) {
console.log("POST " + request.statusText + " status: " + request.status);
responseJson = JSON.parse(request.responseText);
if(responseJson.page !== undefined) {
self.$parent.pages.push(responseJson.page);
}
self.$parent.clearStorage();
if(responseJson.dataRequiredForSubmit !== undefined){
self.$parent.setToStorage(responseJson.dataRequiredForSubmit);
}
self.$parent.changePage("next");
self.loading = false;
} else {
console.warn(request.statusText, request.responseText);
self.loading = false;
self.formValid = false;
self.formWasValidated = true;
responseJson = JSON.parse(request.responseText);
if(responseJson.error !== undefined) {
self.errorMsg = responseJson.error;
}
else {
self.errorMsg = 'Ooops, da ist etwas schief gelaufen. Bitte versuche es erneut.';
}
if(responseJson.dataRequiredForSubmit !== undefined){
self.$parent.setToStorage(responseJson.dataRequiredForSubmit);
}
}
});
self.loading = true;
request.send(data);
},
/**
* Combines all available data of all not-submitted pages
*
* @param {Object} e
*
* @returns {FormData}
*/
prepareSubmitData: function(e){
var submitData = new FormData(),
filteredEventData,
storageData;
filteredEventData = this.filterDataFromSubmitEvent(e);
storageData = JSON.parse(JSON.stringify(this.$parent.getStorage()));
if(storageData !== undefined && storageData.length > 0){
for(var i = 0; i < storageData.length; i++){
for(var key in storageData[i]){
submitData.append(key, storageData[i][key]);
}
}
}
if(filteredEventData !== undefined){
for(var filteredEventDataKey in filteredEventData){
submitData.append(filteredEventDataKey, filteredEventData[filteredEventDataKey]);
}
}
return submitData;
},
/**
* Serializes all data from a form submit event
*
* @param e
*
* @returns {Object}
*/
filterDataFromSubmitEvent: function(e){
var data = {},
checkedInSurvey = [],
current;
for(var i = 0; i < e.target.length; i++){
current = e.target[i];
if(current.tagName === "button" || current.tagName === "BUTTON"){
continue;
}
if(!current.name){
throw new Error("Please define names for all inputs");
}
if(this.page.type === "survey" && (current.tagName === "input" || current.tagName === "INPUT")){
if(current.checked){
checkedInSurvey.push(current.value);
}
data[current.name] = checkedInSurvey;
} else {
if(current.type === 'checkbox') {
if(current.checked){
data[current.name] = current.value;
}
}
else {
data[current.name] = current.value;
}
}
}
return data;
}
}
});
Vue.component('app-input-row',{
props: ['row', 'hasSiblings'],
data: function(){
return {
rowValid: true,
rowWasValidated: false
}
},
template:
'' +
'
' +
'
{{ row.add.text }}
' +
'
' +
'
',
methods:{
addRow: function(){
var newRow = JSON.parse(JSON.stringify(this.row)); // removes vue observable and makes it possible to change
this.$parent.addInputRow(newRow);
},
validateRow: function(){
this.rowValid = this.requiredInputsValid();
this.rowWasValidated = true;
if(this.rowValid){
this.$parent.validateForm();
}
},
/**
* Checks if the required Inputs are valid
*
* @returns {boolean}
*/
requiredInputsValid: function(){
if(this.$refs === undefined){
throw new Error("Please define ref on child component");
}
var valid = true,
current;
for(var i = 0; i < this.$refs.input.length; i++){
current = this.$refs.input[i];
if(!current.validation){
valid = true;
continue;
}
valid = current.validation && current.valid && current.wasValidated;
// row is invalid after first invalid input
if(!valid){
return false;
}
}
return valid;
}
}
});
Vue.component('app-input', {
props: ['type', 'validation', 'name', 'label', 'customErrorMsg', 'options', 'value', 'connectedTo'],
data: function () {
return {
inputValue: this.value ? this.value : '',
inputType: this.type,
inputErrorMsg: undefined,
valid: true,
wasValidated: false
}
},
template:
'' +
'' +
'' +
'
'+
'',
mounted: function(){
var self = this;
// listens to compare request "broadcast" from other component
self.$root.$on('compareConnected', function(data){
if(self.name !== data.connectedTo) {
return;
}
// "broadcasts" to every component listening
self.$root.$emit('comparisonResult', {
requestingInput: data.requestingInput.name,
valid: self.inputValue === data.requestingInput.inputValue && self.valid
})
});
self.$root.$on('comparisonResult', function(result){
if(self.name === result.requestingInput){
self.valid = result.valid;
}
});
},
methods: {
validateInput: function(){
if((this.inputValue.length === 0 && !this.wasValidated) || !this.validation){
// input is valid if it has a value and wasn't validated before (inputs do not get validated on page render)
// or if it's not necessary to validate
this.valid = true;
return;
}
switch(this.type){
case "email":
var regex = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
this.valid = regex.test(this.inputValue);
this.inputErrorMsg = this.customErrorMsg || "Adresse nicht gültig";
break;
case "text":
this.valid = this.inputValue.length >= 2;
this.inputErrorMsg = this.customErrorMsg || "Mindestens zwei Zeichen";
break;
case "password":
// "broadcasting" event to listening components
// In this case we compare if passwords match in connected fields -> "connectedTo" option in JSON
if(this.connectedTo !== undefined){
this.$root.$emit('compareConnected', {
connectedTo: this.connectedTo,
requestingInput: {
name: this.name,
inputValue: this.inputValue
}
});
this.inputErrorMsg = this.customErrorMsg || "Bitte wiederholen Sie das Passwort";
} else {
this.valid = this.inputValue.length >= 4;
this.inputErrorMsg = this.customErrorMsg || "Mindestens vier Zeichen";
}
break;
case "select":
// it's "selected/changed" (event) so it always has a valid value
break;
default:
break;
}
this.wasValidated = true;
this.$parent.validateRow();
},
togglePasswordVisibility: function(){
this.inputType = this.inputType === 'password' ? 'text' : 'password';
}
}
});
Vue.component('app-pagination', {
props: ["pages", "index"],
template: '' +
''
});
Vue.component('app-spinner',{
template: ''
});
Vue.component('app-media',{
props: ["media"],
template:
'' +
'
' +
'
' +
'
' +
'
'
});