Enhance UI with improved state management and button functionality
This commit is contained in:
parent
294cb6853d
commit
8fd1415ef8
@ -5,7 +5,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<script>
|
<script>
|
||||||
const data = {
|
const data = {
|
||||||
type: 'iframe',
|
type: 'spec',
|
||||||
title: 'Contact Form',
|
title: 'Contact Form',
|
||||||
items: [{
|
items: [{
|
||||||
type: 'text',
|
type: 'text',
|
||||||
@ -23,6 +23,9 @@
|
|||||||
optValues: ['Option 1', 'Option 2', 'Option 3']
|
optValues: ['Option 1', 'Option 2', 'Option 3']
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
window.addEventListener('message', (event) => {
|
||||||
|
console.log(event.data);
|
||||||
|
});
|
||||||
window.onload = () => {
|
window.onload = () => {
|
||||||
const iframe = document.getElementById('iframe');
|
const iframe = document.getElementById('iframe');
|
||||||
iframe.contentWindow.postMessage(data, window.origin);
|
iframe.contentWindow.postMessage(data, window.origin);
|
||||||
|
172
src/App.vue
172
src/App.vue
@ -30,12 +30,18 @@
|
|||||||
return {
|
return {
|
||||||
title: undefined,
|
title: undefined,
|
||||||
items: [],
|
items: [],
|
||||||
|
currentTitle: undefined,
|
||||||
currentIdx: undefined,
|
currentIdx: undefined,
|
||||||
currentItem: undefined,
|
currentItem: undefined,
|
||||||
currentAnswer: undefined,
|
currentAnswer: undefined,
|
||||||
currentAnswerValue: undefined,
|
currentAnswerValue: undefined,
|
||||||
currentRefilled: false,
|
currentRefilled: false,
|
||||||
timestamp: undefined,
|
timestamp: undefined,
|
||||||
|
uiStatus: {
|
||||||
|
backButtonDisabled: true,
|
||||||
|
nextButtonText: 'Next',
|
||||||
|
nextButtonStatus: 'primary',
|
||||||
|
},
|
||||||
settings: {
|
settings: {
|
||||||
allowBack: true,
|
allowBack: true,
|
||||||
},
|
},
|
||||||
@ -44,7 +50,7 @@
|
|||||||
created() {
|
created() {
|
||||||
window.addEventListener('message', (event) => {
|
window.addEventListener('message', (event) => {
|
||||||
const data = event.data;
|
const data = event.data;
|
||||||
if (event.source === window.parent && data && data.type === 'iframe') {
|
if (event.source === window.parent && data && data.type === 'spec') {
|
||||||
this.settings = Object.assign(this.settings, data.settings);
|
this.settings = Object.assign(this.settings, data.settings);
|
||||||
this.items = structuredClone(data.items);
|
this.items = structuredClone(data.items);
|
||||||
this.title = data.title;
|
this.title = data.title;
|
||||||
@ -53,8 +59,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.currentIdx = 0;
|
this.currentIdx = 0;
|
||||||
this.currentItem = this.items[this.currentIdx];
|
this.updateItem();
|
||||||
this.timestamp = new Date().getTime();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -62,20 +67,39 @@
|
|||||||
isReady() {
|
isReady() {
|
||||||
return this.items && this.title;
|
return this.items && this.title;
|
||||||
},
|
},
|
||||||
displayTitle() {
|
|
||||||
return `${this.currentIdx + 1}. ${this.items[this.currentIdx].title}`;
|
|
||||||
},
|
|
||||||
nextButtonText() {
|
|
||||||
return this.currentIdx === this.items.length - 1 ? 'Submit' : 'Next';
|
|
||||||
},
|
|
||||||
nextButtonStatus() {
|
|
||||||
return this.currentIdx === this.items.length - 1 ? 'submit' : '';
|
|
||||||
},
|
|
||||||
backButtonStatus() {
|
|
||||||
return this.currentIdx === 0 ? 'disabled' : '';
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
updateBackButton() {
|
||||||
|
this.uiStatus.backButtonDisabled = !this.settings.allowBack || (this.currentIdx === 0);
|
||||||
|
},
|
||||||
|
updateNextButton() {
|
||||||
|
if (this.currentIdx === this.items.length - 1) {
|
||||||
|
this.uiStatus.nextButtonText = 'Submit';
|
||||||
|
this.uiStatus.nextButtonStatus = 'success';
|
||||||
|
} else {
|
||||||
|
this.uiStatus.nextButtonText = 'Next';
|
||||||
|
this.uiStatus.nextButtonStatus = 'primary';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateTitle() {
|
||||||
|
this.currentTitle = this.currentItem ?
|
||||||
|
`${this.currentIdx + 1}. ${this.currentItem.title}` : '';
|
||||||
|
},
|
||||||
|
updateItem() {
|
||||||
|
this.currentItem = this.items[this.currentIdx];
|
||||||
|
this.currentAnswer = this.items[this.currentIdx].answer;
|
||||||
|
this.currentRefilled = (this.currentItem.answer !== undefined);
|
||||||
|
this.timestamp = new Date().getTime();
|
||||||
|
this.updateTitle();
|
||||||
|
this.updateBackButton();
|
||||||
|
this.updateNextButton();
|
||||||
|
},
|
||||||
|
iterOptions() {
|
||||||
|
return this.currentItem.optTexts.map((optText, index) => [
|
||||||
|
optText,
|
||||||
|
this.currentItem.optValues ? this.currentItem.optValues[index] : optText,
|
||||||
|
]);
|
||||||
|
},
|
||||||
clickNext() {
|
clickNext() {
|
||||||
const item = this.items[this.currentIdx];
|
const item = this.items[this.currentIdx];
|
||||||
item.answer = this.currentAnswer;
|
item.answer = this.currentAnswer;
|
||||||
@ -86,29 +110,29 @@
|
|||||||
this.submit();
|
this.submit();
|
||||||
} else {
|
} else {
|
||||||
this.currentIdx++;
|
this.currentIdx++;
|
||||||
this.currentAnswer = null;
|
this.updateItem();
|
||||||
this.currentItem = this.items[this.currentIdx];
|
}
|
||||||
this.currentRefilled = (this.currentItem.answer !== undefined);
|
},
|
||||||
this.timestamp = new Date().getTime();
|
autoNext() {
|
||||||
|
if (this.currentIdx < this.items.length - 1) {
|
||||||
|
this.clickNext();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clickBack() {
|
clickBack() {
|
||||||
if (this.currentIdx > 0) {
|
if (this.currentIdx > 0) {
|
||||||
this.currentIdx--;
|
this.currentIdx--;
|
||||||
this.currentAnswer = this.items[this.currentIdx].answer;
|
this.updateItem();
|
||||||
this.currentItem = this.items[this.currentIdx];
|
|
||||||
this.currentRefilled = (this.currentItem.answer !== undefined);
|
|
||||||
this.timestamp = new Date().getTime();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
submit() {
|
submit() {
|
||||||
const results = this.items.map((item, index) => ({
|
const results = this.items.map((item, index) => ({
|
||||||
index: index,
|
index: index,
|
||||||
title: item.title,
|
title: item.title,
|
||||||
answer: item.answer,
|
answer: item.answer || '',
|
||||||
refilled: item.refilled,
|
refilled: item.refilled,
|
||||||
responseTime: item.responseTime,
|
responseTime: item.responseTime,
|
||||||
}));
|
}));
|
||||||
|
window.parent.postMessage({ type: 'response', results }, window.origin);
|
||||||
const elem = document.createElement('a');
|
const elem = document.createElement('a');
|
||||||
elem.href = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(results));
|
elem.href = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(results));
|
||||||
elem.download = 'results.json';
|
elem.download = 'results.json';
|
||||||
@ -119,75 +143,53 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="container" v-if="isReady">
|
<div v-if="!isReady">Loading...</div>
|
||||||
<span class="display-title">{{ displayTitle }}</span>
|
<div id="container" v-if="isReady">
|
||||||
<template v-if="currentItem.type === 'text'">
|
<span id="display-title">{{ currentTitle }}</span>
|
||||||
<div class="item text">
|
<div id="display-content">
|
||||||
<input type="text" v-model="currentAnswer">
|
<template v-if="currentItem.type === 'text'">
|
||||||
</div>
|
<el-input v-model="currentAnswer" style="width: 240px" placeholder="Please input" />
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="currentItem.type === 'radio'">
|
<template v-else-if="currentItem.type === 'radio'">
|
||||||
<div class="item radio" v-for="(optText, index) in currentItem.optTexts" :key="index">
|
<div>
|
||||||
<input type="radio" :id="index" :value="currentItem.optValues[index]" v-model="currentAnswer">
|
<el-radio-group
|
||||||
<label :for="index">{{ optText }}</label>
|
v-model="currentAnswer"
|
||||||
</div>
|
v-for="[optText, optValue] in iterOptions()"
|
||||||
</template>
|
:key="optValue"
|
||||||
|
@change="autoNext"
|
||||||
<button
|
>
|
||||||
v-if="settings.allowBack"
|
<el-radio-button :label="optText" :value="optValue" />
|
||||||
@click="clickBack"
|
</el-radio-group>
|
||||||
:class="backButtonStatus">Back</button>
|
</div>
|
||||||
<button @click="clickNext" :class="nextButtonStatus">{{ nextButtonText }}</button>
|
</template>
|
||||||
|
</div>
|
||||||
|
<div id="display-buttons">
|
||||||
|
<el-button-group>
|
||||||
|
<el-button type="primary" round :disabled="uiStatus.backButtonDisabled" @click="clickBack">
|
||||||
|
<el-icon class="el-icon--left"><ArrowLeft /></el-icon>Back
|
||||||
|
</el-button>
|
||||||
|
<el-button :type="uiStatus.nextButtonStatus" round @click="clickNext">
|
||||||
|
{{ uiStatus.nextButtonText }}<el-icon class="el-icon--right"><ArrowRight /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-button-group>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.container {
|
#container {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
button {
|
#display-title {
|
||||||
background-color: #008CBA;
|
|
||||||
border: none;
|
|
||||||
color: white;
|
|
||||||
padding: 10px 20px;
|
|
||||||
text-align: center;
|
|
||||||
text-decoration: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 18px;
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
button.submit {
|
|
||||||
background-color: #4CAF50;
|
|
||||||
}
|
|
||||||
button.disabled {
|
|
||||||
background-color: #cccccc;
|
|
||||||
}
|
|
||||||
input[type=text] {
|
|
||||||
width: 100%;
|
|
||||||
padding: 12px 18px;
|
|
||||||
margin: 8px 20px 20px 0px;
|
|
||||||
display: inline-block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: 2px solid #ccc;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
input[type=radio] {
|
|
||||||
margin-bottom: 4px;
|
|
||||||
margin-right: 10px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
label {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
.item {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.display-title {
|
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
#display-content {
|
||||||
|
margin-top: 1ex;
|
||||||
|
margin-bottom: 2ex;
|
||||||
|
}
|
||||||
|
#display-buttons {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
Loading…
Reference in New Issue
Block a user