339 lines
10 KiB
JavaScript
339 lines
10 KiB
JavaScript
const questions = [
|
||
{
|
||
image: "image.avif",
|
||
question: "Мой вопрос",
|
||
variants: [
|
||
"Вариант 1",
|
||
"Вариант 2",
|
||
"Вариант 3"
|
||
],
|
||
correct: 0
|
||
},
|
||
{
|
||
question: "Мой вопрос",
|
||
variants: [
|
||
"Вариант 1",
|
||
"Вариант 2",
|
||
"Вариант 3"
|
||
],
|
||
correct: [0, 1]
|
||
}
|
||
];
|
||
|
||
class Quiz extends Find.createApp() {
|
||
constructor(questions) {
|
||
const root = Find.search('root');
|
||
super(root);
|
||
this.question_type = undefined;
|
||
this.questions = questions;
|
||
this.question = null;
|
||
this.correctCount = 0;
|
||
}
|
||
|
||
init() {
|
||
this.select('com.find.demos.quiz');
|
||
this.setMeta();
|
||
this.setCard();
|
||
this.stable();
|
||
this.createQuestions();
|
||
}
|
||
|
||
setCard() {
|
||
this.add([
|
||
Find.content('<div id="message"></div>'),
|
||
Find.content(
|
||
`<div class="card">
|
||
<div class="card-header">
|
||
<p class="card-header-title">
|
||
<span id="title">
|
||
Загрузка...
|
||
</span>
|
||
</p>
|
||
</div>
|
||
<div class="card-content">
|
||
<div class="content" id="content"></div>
|
||
<button
|
||
class="button"
|
||
style="width: 100%;"
|
||
id="test_select"
|
||
>Проверить</button>
|
||
</div>
|
||
</div>`
|
||
)
|
||
]);
|
||
}
|
||
|
||
setMeta() {
|
||
this.meta([
|
||
Find.content('<meta name="viewport" content="width=device-width, initial-scale=1">'),
|
||
Find.content('<style>body { margin: 20px; } </style>'),
|
||
Find.content(
|
||
`<style>
|
||
.fit-image {
|
||
object-fit: contain;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
</style>`
|
||
)
|
||
]);
|
||
}
|
||
|
||
createQuestions() {
|
||
this.number = 0;
|
||
this.questionsWaiter(null);
|
||
}
|
||
|
||
questionsWaiter(status) {
|
||
const results = [
|
||
{
|
||
source: "no_select",
|
||
text: "Не выбран не один вариант!",
|
||
type: "error"
|
||
},
|
||
{
|
||
source: "incorrect",
|
||
text: "Неправильный ответ!",
|
||
type: "error"
|
||
},
|
||
{
|
||
source: "correct",
|
||
text: "Правильный ответ!",
|
||
type: "success"
|
||
}
|
||
];
|
||
|
||
const isEnd = (this.questions.length === this.number);
|
||
if (!isEnd) this.question = this.questions[this.number];
|
||
this.select('question' + this.number);
|
||
this.setTitle();
|
||
this.render();
|
||
this.setStatus(status);
|
||
this.setForms(isEnd);
|
||
this.attachDeleteButton();
|
||
if (isEnd) return;
|
||
this.setEvents().then((result) => {
|
||
if (result !== 'no_select') {
|
||
this.number ++;
|
||
}
|
||
|
||
let obj = undefined;
|
||
for (obj of results) {
|
||
if (obj.source == result) break;
|
||
}
|
||
|
||
this.questionsWaiter(obj);
|
||
});
|
||
}
|
||
|
||
setStatus(status) {
|
||
const root = this.component();
|
||
const message = root.id('message');
|
||
if (status !== null) {
|
||
const elem = status.type === 'error' ?
|
||
'is-danger' :
|
||
'is-success';
|
||
message.html(
|
||
Find.content(
|
||
`<div
|
||
class="notification ${elem}"
|
||
style="margin-bottom: 10px;">
|
||
<button class="delete" id="delete-info"></button>
|
||
${status.text}
|
||
</div>`
|
||
)
|
||
);
|
||
}
|
||
}
|
||
|
||
attachDeleteButton() {
|
||
const root = this.component();
|
||
const button = root.id('delete-info');
|
||
if (button.status()) button.attach('click', app => {
|
||
const root = app.component();
|
||
root.id("message").html('<!-- deleted -->');
|
||
});
|
||
}
|
||
|
||
setEvents() {
|
||
const root = this.component();
|
||
const que = this.question;
|
||
const main = this;
|
||
return new Promise((resolve, reject) => {
|
||
const get_select = function() {
|
||
const button = root.id('test_select');
|
||
button.attach('click', () => {
|
||
const name = 'question';
|
||
const type = main.question_type;
|
||
let correct = false;
|
||
|
||
if (type === 'radio') {
|
||
const elem = root.select(`input[name="${name}"]:checked`);
|
||
|
||
if (!elem.status()) {
|
||
resolve('no_select');
|
||
return;
|
||
}
|
||
|
||
const answer = Number(elem.value());
|
||
|
||
if (answer === que.correct) correct = true;
|
||
} else {
|
||
const elements = root.all('input[type="checkbox"]:checked');
|
||
|
||
if (elements.length === 0) {
|
||
resolve('no_select');
|
||
return;
|
||
}
|
||
|
||
const answer = elements.map(elem => Number(elem.property('id').slice(7)));
|
||
|
||
let correct_count = 0;
|
||
for (let i = 0; i < que.correct.length; i ++) {
|
||
|
||
if (
|
||
answer[i] === undefined ||
|
||
answer[i] === null
|
||
) break;
|
||
|
||
if (answer[i] === que.correct[i]) {
|
||
correct_count ++;
|
||
}
|
||
}
|
||
|
||
if (correct_count === que.correct.length) {
|
||
correct = true;
|
||
}
|
||
}
|
||
|
||
if (correct) {
|
||
main.correctCount ++;
|
||
resolve('correct');
|
||
} else {
|
||
resolve('incorrect');
|
||
}
|
||
});
|
||
};
|
||
try {
|
||
get_select();
|
||
} catch (err) {
|
||
reject(err);
|
||
}
|
||
});
|
||
}
|
||
|
||
setTitle() {
|
||
const isEnd = (this.questions.length === this.number);
|
||
if (!isEnd) {
|
||
this.title(`Quiz вопрос ${String(this.number + 1)}/${this.questions.length} - Find.js демо`);
|
||
} else {
|
||
this.title('Результаты!');
|
||
}
|
||
}
|
||
|
||
setForms(isDone) {
|
||
if (isDone) {
|
||
this.viewResults();
|
||
return;
|
||
}
|
||
|
||
const que = this.question;
|
||
let input_id = 0;
|
||
const root = this.component();
|
||
const content = root.id("content");
|
||
const title = root.id("title");
|
||
title.text(que.question);
|
||
|
||
if (Array.isArray(que.correct)) {
|
||
this.question_type = 'checkbox';
|
||
} else {
|
||
this.question_type = 'radio';
|
||
}
|
||
|
||
let image = '<!-- no image -->';
|
||
if (typeof que.image !== "undefined") {
|
||
image = Find.content(
|
||
`<figure
|
||
class="fit-image"
|
||
style="margin-bottom: 20px;">
|
||
<img
|
||
src="${que.image}"
|
||
style="border-radius: 20px;"
|
||
alt="Изображение к вопросу">
|
||
</img>
|
||
</figure>`
|
||
);
|
||
content.add(image);
|
||
}
|
||
|
||
for (let val in (que.variants)) {
|
||
if (Array.isArray(que.correct)) {
|
||
this.question_type = 'checkbox';
|
||
content.add(
|
||
Find.content(
|
||
`<label class="checkbox">
|
||
<input
|
||
type="checkbox"
|
||
id="variant${input_id}"
|
||
value="${input_id}"
|
||
name="question">
|
||
</input>
|
||
<span
|
||
class="has-text-weight-medium"
|
||
id="text${input_id}">
|
||
</span>
|
||
</label>
|
||
<br />`
|
||
)
|
||
);
|
||
} else {
|
||
content.add(
|
||
Find.content(
|
||
`<input
|
||
type="radio"
|
||
id="variant${input_id}"
|
||
value="${input_id}"
|
||
name="question">
|
||
<label class="radio" for="variant${input_id}">
|
||
<span class="has-text-weight-medium" id="text${input_id}"></span>
|
||
</label>
|
||
</input>
|
||
<br />`
|
||
)
|
||
);
|
||
}
|
||
content.id('text' + input_id).text(que.variants[val]);
|
||
input_id ++;
|
||
}
|
||
}
|
||
|
||
viewResults() {
|
||
const root = this.component();
|
||
const button = root.id("test_select");
|
||
const content = root.id("content");
|
||
const title = root.id("title");
|
||
let text = 'Попробовать снова';
|
||
let out = ` - ${this.correctCount / (this.questions.length / 100)}%`;
|
||
const user =
|
||
this.correctCount !== this.questions.length ?
|
||
`${this.correctCount} вопросов из ${this.questions.length}.` :
|
||
'все вопросы!';
|
||
|
||
if (this.correctCount > (this.questions.length / 2)) {
|
||
text = 'На главную';
|
||
}
|
||
title.text(`Ваш результат ${out}`);
|
||
button.text(text);
|
||
content.html(
|
||
Find.content(
|
||
`<span class="has-text-weight-bold">
|
||
Вы правильно ответили на ${user}
|
||
</span>`
|
||
)
|
||
);
|
||
button.attach('click', () => location.reload());
|
||
}
|
||
}
|
||
|
||
const quiz = new Quiz(questions);
|
||
quiz.init(); |