diff --git a/DOCS.md b/DOCS.md
index bf5156a..6a1fbc6 100644
--- a/DOCS.md
+++ b/DOCS.md
@@ -146,6 +146,8 @@ map.tag(/* TAG элемента */); // Вернет экземпляр map дл
map.attach(/* событие */, /* функция */); // EventHandler
map.attribute(/* Имя */, /* Значение */); // Задание атрибута
map.add(/* HTML */);
+map.all(/* CSS-селектор */); // Вернет массив экземпляров map для выбранных элементов
+map.property(/* свойство элемента */[, /* значение */]);
/*
* Функция в attach может принимать параметр.
* Этот параметр - обьект Find, map которого был вызван
diff --git a/Find/Find.js b/Find/Find.js
index 40d5b2e..fd37302 100644
--- a/Find/Find.js
+++ b/Find/Find.js
@@ -31,6 +31,26 @@ class FindObjectMap {
this._num = num;
return this;
}
+ all(q) {
+ const o = this.root.querySelectorAll(q);
+ if (typeof o === "undefined") {
+ PrivateFind.error("Нет обьектов для селектора!");
+ return undefined;
+ }
+ let arr = new Array();
+ for (let i = 0; i < o.length; i ++) {
+ arr[i] = new FindObjectMap(o[i], this._app, this._num + 1)
+ }
+ return arr;
+ }
+ property(property, to) {
+ if (typeof to === "undefined") {
+ return this.root[property];
+ } else {
+ this.root[property] = to;
+ return this;
+ }
+ }
select(q) {
const o = this.root.querySelector(q);
if (typeof o === "undefined") {
@@ -39,6 +59,12 @@ class FindObjectMap {
}
return new FindObjectMap(o, this._app, this._num + 1);
}
+ status() {
+ if (typeof this.root === "object" && this.root !== null && this.root !== undefined) {
+ return true;
+ }
+ return false;
+ }
read() {
return this.root.innerHTML;
}
@@ -85,7 +111,7 @@ class FindObjectMap {
}
attach(event, func) {
this.root.addEventListener(event, () => {
- func(this._app);
+ func(this._app, this);
});
return this;
}
diff --git a/demos/Quiz/image.avif b/demos/Quiz/image.avif
new file mode 100644
index 0000000..af174b2
Binary files /dev/null and b/demos/Quiz/image.avif differ
diff --git a/demos/Quiz/index.js b/demos/Quiz/index.js
index f23a73a..b7118de 100644
--- a/demos/Quiz/index.js
+++ b/demos/Quiz/index.js
@@ -1,20 +1,33 @@
-const qestions = [
+const questions = [
{
- qestion: "Мой вопрос",
+ image: "image.avif",
+ question: "Мой вопрос",
variants: [
"Вариант 1",
"Вариант 2",
"Вариант 3"
],
correct: 0
+ },
+ {
+ question: "Мой вопрос",
+ variants: [
+ "Вариант 1",
+ "Вариант 2",
+ "Вариант 3"
+ ],
+ correct: [0, 1]
}
];
class Quiz extends Find.createApp() {
- constructor(qestions) {
+ constructor(questions) {
const root = Find.search('root');
super(root);
- this.qestions = qestions;
+ this.question_type = undefined;
+ this.questions = questions;
+ this.question = null;
+ this.correctCount = 0;
}
init() {
@@ -22,11 +35,12 @@ class Quiz extends Find.createApp() {
this.setMeta();
this.setCard();
this.stable();
- this.createQestions();
+ this.createQuestions();
}
setCard() {
this.add([
+ Find.content('
'),
Find.content(
`
`
@@ -52,63 +66,274 @@ class Quiz extends Find.createApp() {
setMeta() {
this.meta([
Find.content(''),
- Find.content('')
+ Find.content(''),
+ Find.content(
+ ``
+ )
]);
}
- createQestions() {
+ createQuestions() {
this.number = 0;
- for (let i = 0; i < this.qestions.length; i ++) {
- this.select('qestion' + this.number);
- this.setTitle();
- this.render();
- this.setForms(this.qestions[i]);
- this.setEvents(this.qestions[i])
- .then((result) => {
+ 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 ++;
- })
- .catch((error) => {
-
- });
- 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(
+ `
+
+ ${status.text}
+
`
+ )
+ );
}
}
- setEvents() {}
-
- setTitle() {
- this.title('Quiz qestion ' + this.number + ' - Find.js demo');
+ 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('');
+ });
}
- setForms(qe) {
+ 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(qe.qestion);
- for (let val in (qe.variants)) {
- content.add(
- Find.content(
- `
-
-
-
`
- )
+ title.text(que.question);
+
+ if (Array.isArray(que.correct)) {
+ this.question_type = 'checkbox';
+ } else {
+ this.question_type = 'radio';
+ }
+
+ let image = '';
+ if (typeof que.image !== "undefined") {
+ image = Find.content(
+ `
+
+
+ `
);
- content.id('text' + input_id).text(qe.variants[val]);
+ content.add(image);
+ }
+
+ for (let val in (que.variants)) {
+ if (Array.isArray(que.correct)) {
+ this.question_type = 'checkbox';
+ content.add(
+ Find.content(
+ `
+
`
+ )
+ );
+ } else {
+ content.add(
+ Find.content(
+ `
+
+
+
`
+ )
+ );
+ }
+ content.id('text' + input_id).text(que.variants[val]);
input_id ++;
}
}
- setEvents(r) {
+ 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(
+ `
+ Вы правильно ответили на ${user}
+ `
+ )
+ );
+ button.attach('click', () => location.reload());
}
}
-const quiz = new Quiz(qestions);
+const quiz = new Quiz(questions);
quiz.init();
\ No newline at end of file
diff --git a/demos/Quiz/nomodule-find.min.js b/demos/Quiz/nomodule-find.min.js
index 972aad7..e9c75bf 100644
--- a/demos/Quiz/nomodule-find.min.js
+++ b/demos/Quiz/nomodule-find.min.js
@@ -1 +1 @@
-class FindObjectMap{constructor(t,r,e){return this.root=t,"object"!=typeof this.root&&PrivateFind.error("Неизвестный root!"),this._app=r,this._num=e,this}select(t){const r=this.root.querySelector(t);if(void 0!==r)return new FindObjectMap(r,this._app,this._num+1);PrivateFind.error("Нет обьектов для селектора!")}read(){return this.root.innerHTML}text(t){return 0==arguments.length?this.root.textContent:(this.root.textContent=t,this)}html(t){return 0==arguments.length?this.root.innerHTML:(this.root.innerHTML=t,this)}add(t){const r=this.html();return this.html(r+String(t))}value(t){return 0==arguments.length?this.root.value:(this.root.value=t,this)}id(t){const r=this.root.querySelector("#"+t);if(void 0!==r)return new FindObjectMap(r,this._app,this._num+1);PrivateFind.error("No objects of selector")}tag(t){const r=this.root.getElementsByTagName(t);if(void 0!==r)return new FindObjectMap(r,this._app,this._num+1);PrivateFind.error("No objects of selector")}attach(t,r){return this.root.addEventListener(t,()=>{r(this._app)}),this}merge(){if(0!=this._num)return PrivateFind.error("Вы можете создавать merge-обьект только из корневого map(), но уровень вложенности данного map() равен "+String(this._num)+"!"),this;const t=this._app.getNumberOfGroupFromId(this._app.__id);return this._app.groups[t].html=new Array(this.read()),this}app(){return this._app}main(){return new FindObjectMap(this._app.root,this._app,0)}attribute(t,r){return this.root.setAttribute(t,r),this}}class Find{constructor(t){return this._lll="",this.root=t,this.iter=0,this.groups=new Array,this.groups_count=0,this._map=new FindObjectMap(this.root,this,0),this}static createApp(){return Find}static attach(t,r){return`${t}="${r.replace('"',""")}"`}static css(t){return``}static js(t){return`