Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
kus-admin
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Кубота
kus-admin
Commits
ecd6089d
Commit
ecd6089d
authored
Jan 16, 2020
by
Иван Кубота
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
multiple and single questions with image
parent
352493fa
Pipeline
#525
canceled with stage
Changes
9
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
293 additions
and
20 deletions
+293
-20
index.js
bin/index.js
+34
-11
index.html
index.html
+2
-0
checkbox.js
public/js/controller/quizBits/checkbox.js
+1
-1
checkboxPhoto.js
public/js/controller/quizBits/checkboxPhoto.js
+67
-0
main.js
public/js/controller/quizBits/main.js
+125
-6
radioPhoto.js
public/js/controller/quizBits/radioPhoto.js
+51
-0
quizGenerator.js
public/js/controller/quizGenerator.js
+1
-1
generate.js
public/js/view/page/generate.js
+3
-1
main.css
public/main.css
+9
-0
No files found.
bin/index.js
View file @
ecd6089d
...
@@ -15,6 +15,7 @@ const options = yargs
...
@@ -15,6 +15,7 @@ const options = yargs
.
option
(
"v"
,
{
alias
:
"verbose"
,
describe
:
"print log"
,
type
:
"boolean"
})
.
option
(
"v"
,
{
alias
:
"verbose"
,
describe
:
"print log"
,
type
:
"boolean"
})
.
option
(
"n"
,
{
alias
:
"nolog"
,
describe
:
"no text log in object"
,
type
:
"boolean"
})
.
option
(
"n"
,
{
alias
:
"nolog"
,
describe
:
"no text log in object"
,
type
:
"boolean"
})
.
option
(
"d"
,
{
alias
:
"dir"
,
describe
:
"database dir"
,
type
:
"string"
})
.
option
(
"d"
,
{
alias
:
"dir"
,
describe
:
"database dir"
,
type
:
"string"
})
.
option
(
"f"
,
{
alias
:
"fake"
,
describe
:
"add fake images"
,
type
:
"boolean"
})
.
argv
;
.
argv
;
...
@@ -47,9 +48,26 @@ const sources = [
...
@@ -47,9 +48,26 @@ const sources = [
"js/controller/quizGenerator.js"
,
"js/controller/quizGenerator.js"
,
"js/controller/quizBits/checkbox.js"
,
"js/controller/quizBits/checkbox.js"
,
"js/controller/quizBits/radio.js"
"js/controller/quizBits/checkboxPhoto.js"
,
"js/controller/quizBits/radio.js"
,
"js/controller/quizBits/radioPhoto.js"
];
];
const
rand
=
function
(
a
,
b
){
if
(
Array
.
isArray
(
a
)){
return
a
[
Math
.
random
.
seeded
()
*
a
.
length
|
0
];
}
if
(
typeof
a
===
'object'
&&
'max'
in
a
){
b
=
a
.
max
;
a
=
a
.
min
||
0
;
}
a
=
Math
.
ceil
(
a
);
b
=
Math
.
floor
(
b
);
return
Math
.
floor
(
Math
.
random
.
seeded
()
*
(
b
-
a
+
1
))
+
a
;
return
(
r
-
a
)
*
(
b
-
a
)
|
0
;
};
var
js
=
sources
.
map
(
a
=>
'./public/'
+
a
).
map
(
n
=>
fs
.
readFileSync
(
n
)
+
''
).
join
(
'
\
n
\
n'
);
var
js
=
sources
.
map
(
a
=>
'./public/'
+
a
).
map
(
n
=>
fs
.
readFileSync
(
n
)
+
''
).
join
(
'
\
n
\
n'
);
if
(
options
.
dir
)
if
(
options
.
dir
)
...
@@ -58,24 +76,29 @@ const data = require("../db.js");
...
@@ -58,24 +76,29 @@ const data = require("../db.js");
const
body
=
'const window = {};'
+
js
+
'; return {quizGenerator, initDataProvider, seeded: Math.random.seeded}'
;
const
body
=
'const window = {};'
+
js
+
'; return {quizGenerator, initDataProvider, seeded: Math.random.seeded}'
;
var
ctx
=
new
Function
(
''
,
body
)();
var
ctx
=
new
Function
(
''
,
body
)();
//console.log(options);
//console.log(options);
data
.
after
=
function
()
{
data
.
after
=
function
(){
ctx
.
initDataProvider
(
data
);
if
(
options
.
fake
){
for
(
var
i
=
0
;
i
<
10
;
i
++
){
rand
(
Object
.
values
(
data
.
products
)).
image
=
'https://robohash.org/'
+
Math
.
random
().
toString
(
36
)
}
}
ctx
.
initDataProvider
(
data
);
if
(
options
.
seed
)
if
(
options
.
seed
)
ctx
.
seeded
.
setStringSeed
(
options
.
seed
);
ctx
.
seeded
.
setStringSeed
(
options
.
seed
);
const
result
=
ctx
.
quizGenerator
(
options
.
multiple
?
'checkbox'
:
'radio'
,
options
.
photo
);
const
result
=
ctx
.
quizGenerator
(
options
.
multiple
?
'checkbox'
:
'radio'
,
options
.
photo
);
if
(
options
.
verbose
){
if
(
options
.
verbose
){
console
.
log
(
result
.
log
.
join
(
'
\
n'
)
)
console
.
log
(
result
.
log
.
join
(
'
\
n'
)
)
}
else
{
}
else
{
if
(
options
.
nolog
)
if
(
options
.
nolog
)
delete
result
.
log
;
delete
result
.
log
;
console
.
log
(
'--- START ---
\
n
\
n'
+
JSON
.
stringify
(
result
,
null
,
2
)
+
'
\
n
\
n--- END ---'
)
console
.
log
(
'--- START ---
\
n
\
n'
+
JSON
.
stringify
(
result
,
null
,
2
)
+
'
\
n
\
n--- END ---'
)
}
}
if
(
options
.
output
)
if
(
options
.
output
)
fs
.
writeFileSync
(
options
.
output
,
JSON
.
stringify
(
result
,
null
,
2
)
)
fs
.
writeFileSync
(
options
.
output
,
JSON
.
stringify
(
result
,
null
,
2
)
)
};
};
...
...
index.html
View file @
ecd6089d
...
@@ -43,7 +43,9 @@
...
@@ -43,7 +43,9 @@
<script
src=
"js/controller/quizGenerator.js"
></script>
<script
src=
"js/controller/quizGenerator.js"
></script>
<script
src=
"js/controller/quizBits/checkbox.js"
></script>
<script
src=
"js/controller/quizBits/checkbox.js"
></script>
<script
src=
"js/controller/quizBits/checkboxPhoto.js"
></script>
<script
src=
"js/controller/quizBits/radio.js"
></script>
<script
src=
"js/controller/quizBits/radio.js"
></script>
<script
src=
"js/controller/quizBits/radioPhoto.js"
></script>
<script
src=
"main.js"
></script>
<script
src=
"main.js"
></script>
...
...
public/js/controller/quizBits/checkbox.js
View file @
ecd6089d
...
@@ -83,7 +83,7 @@ quizTypes.checkbox = [ ComponentsOfProduct = {
...
@@ -83,7 +83,7 @@ quizTypes.checkbox = [ ComponentsOfProduct = {
doNotTrim
:
true
doNotTrim
:
true
},
log
),
},
log
),
componentsWithProducts
=
qB
.
get
NotUniqComponentsWith
Products
(
products
,
2
);
componentsWithProducts
=
qB
.
get
ComponentsWithShared
Products
(
products
,
2
);
log
.
push
(
'Shared products count: '
+
componentsWithProducts
.
length
);
log
.
push
(
'Shared products count: '
+
componentsWithProducts
.
length
);
...
...
public/js/controller/quizBits/checkboxPhoto.js
0 → 100644
View file @
ecd6089d
quizTypes
.
checkboxPhoto
=
[
{
questionMinComponentsCount
:
2
,
probability
:
8
,
type
:
'What components are in it'
,
answers
:
{
min
:
3
,
max
:
6
},
correct
:
{
min
:
2
,
max
:
4
},
wrong
:
{
min
:
1
,
max
:
4
},
from
:
qB
.
prebuild
.
similarTaggedProductWithPhotoAndComponents
.
fn
,
question
(
income
,
log
){
return
'Какие ингредиенты входят в продукт, изображенный на картинке?'
},
answer
(
income
,
log
){
let
corrects
=
income
.
allCorrect
.
slice
(
0
,
rand
(
this
.
correct
))
.
map
(
a
=>
new
Answer
.
Correct
(
textFormat
(
a
.
name
))),
wrongs
=
income
.
allWrong
.
slice
(
0
,
rand
(
this
.
wrong
))
.
map
(
a
=>
new
Answer
.
Wrong
(
textFormat
(
a
.
name
)));
return
shuffle
(
corrects
.
concat
(
wrongs
)
.
slice
(
0
,
Math
.
min
(
this
.
answers
.
max
,
corrects
.
length
+
wrongs
.
length
)));
}
},
{
questionMinComponentsCount
:
2
,
probability
:
3000
,
type
:
'What components are NOT in it'
,
answers
:
{
min
:
3
,
max
:
6
},
correct
:
{
min
:
2
,
max
:
4
},
wrong
:
{
min
:
1
,
max
:
4
},
from
:
qB
.
prebuild
.
similarTaggedProductWithPhotoAndComponents
.
fn
,
question
(
income
,
log
){
return
'Какие ингредиенты НЕ входят в продукт, изображенный на картинке?'
},
answer
(
income
,
log
){
let
corrects
=
income
.
allWrong
.
slice
(
0
,
rand
(
this
.
correct
))
.
map
(
a
=>
new
Answer
.
Correct
(
textFormat
(
a
.
name
))),
wrongs
=
income
.
allCorrect
.
slice
(
0
,
rand
(
this
.
wrong
))
.
map
(
a
=>
new
Answer
.
Wrong
(
textFormat
(
a
.
name
)));
return
shuffle
(
corrects
.
concat
(
wrongs
)
.
slice
(
0
,
Math
.
min
(
this
.
answers
.
max
,
corrects
.
length
+
wrongs
.
length
)));
}
}
];
\ No newline at end of file
public/js/controller/quizBits/main.js
View file @
ecd6089d
...
@@ -5,7 +5,8 @@ const qB = {
...
@@ -5,7 +5,8 @@ const qB = {
single
,
single
,
connectedByTags
,
connectedByTags
,
minSimilarTags
,
minSimilarTags
,
doNotTrim
doNotTrim
,
withPhoto
},
log
)
{
},
log
)
{
let
filtered
=
Object
.
values
(
dP
.
products
);
let
filtered
=
Object
.
values
(
dP
.
products
);
...
@@ -15,6 +16,9 @@ const qB = {
...
@@ -15,6 +16,9 @@ const qB = {
log
.
push
(
`Have >=
${
minComponents
}
components: `
+
filtered
.
length
);
log
.
push
(
`Have >=
${
minComponents
}
components: `
+
filtered
.
length
);
if
(
!
filtered
.
length
)
return
;
if
(
single
){
if
(
single
){
amount
=
1
;
amount
=
1
;
}
}
...
@@ -112,6 +116,9 @@ const qB = {
...
@@ -112,6 +116,9 @@ const qB = {
},
},
getUniqComponents
:
function
(
products
)
{
getUniqComponents
:
function
(
products
)
{
return
Object
.
values
(
qB
.
getUniqComponentsHash
(
products
));
},
getUniqComponentsHash
:
function
(
products
)
{
const
hash
=
{};
const
hash
=
{};
products
.
forEach
(
products
.
forEach
(
p
=>
p
=>
...
@@ -122,11 +129,17 @@ const qB = {
...
@@ -122,11 +129,17 @@ const qB = {
)
)
);
);
return
Object
.
values
(
hash
)
;
return
hash
;
},
},
getNotUniqComponentsWithProducts
:
function
(
products
,
minSharedProductCount
)
{
getComponentsWithSharedProducts
:
function
(
products
,
minSharedProductCount
,
maxSharedProductCount
)
{
const
hash
=
{};
const
hash
=
{};
minSharedProductCount
=
minSharedProductCount
||
0
;
maxSharedProductCount
=
maxSharedProductCount
||
Infinity
;
products
.
forEach
(
products
.
forEach
(
p
=>
p
=>
p
p
...
@@ -139,7 +152,10 @@ const qB = {
...
@@ -139,7 +152,10 @@ const qB = {
);
);
return
Object
return
Object
.
values
(
hash
)
.
values
(
hash
)
.
filter
(
i
=>
i
.
length
>=
minSharedProductCount
)
.
filter
(
i
=>
i
.
length
>=
minSharedProductCount
&&
i
.
length
<=
maxSharedProductCount
)
.
map
(
i
=>
({
component
:
i
[
0
].
c
,
products
:
i
.
map
(({
p
})
=>
p
)}));
.
map
(
i
=>
({
component
:
i
[
0
].
c
,
products
:
i
.
map
(({
p
})
=>
p
)}));
},
},
...
@@ -152,7 +168,107 @@ const qB = {
...
@@ -152,7 +168,107 @@ const qB = {
);
);
},
},
getProductsWithTags
:
function
({
products
,
tags
,
minMatch
}){
if
(
minMatch
===
void
0
){
minMatch
=
tags
.
length
;
}
const
tHash
=
tags
.
reduce
((
s
,
t
)
=>
{
s
[
t
.
id
]
=
t
;
return
s
;},
{});
products
=
products
||
Object
.
values
(
dP
.
products
);
return
products
.
filter
(
p
=>
p
.
getTags
()
.
filter
(
t
=>
t
.
id
in
tHash
).
length
>=
minMatch
);
},
prebuild
:
{
prebuild
:
{
similarTaggedProductWithPhotoAndComponents
:
{
fn
:
function
(
log
)
{
this
.
getEmAll
=
true
;
this
.
products
=
{
min
:
2
};
const
possibilities
=
shuffle
(
qB
.
prebuild
.
similarTaggedProductWithPhoto
.
fn
.
call
(
this
,
log
)
);
if
(
!
possibilities
||
!
possibilities
.
length
)
return
false
;
for
(
let
i
=
0
,
_i
=
possibilities
.
length
;
i
<
_i
;
i
++
){
const
possibility
=
possibilities
[
i
];
const
components
=
possibility
.
correct
.
getComponents
();
const
other
=
qB
.
getUniqComponentsHash
(
possibility
.
all
.
filter
(
sP
=>
sP
!==
possibility
.
correct
))
components
.
forEach
(
c
=>
delete
other
[
normalizeText
(
c
.
name
)]);
if
(
Object
.
keys
(
other
).
length
>=
this
.
answers
.
min
){
log
.
push
(
'Take '
+
possibility
.
baseProduct
.
title
+
' with uniq components:'
);
components
.
forEach
(
c
=>
log
.
push
(
` >
${
c
.
name
}
`
)
);
log
.
push
(
''
);
log
.
push
(
'Other components in group tagged as '
+
possibility
.
baseProduct
.
getTags
().
map
(
t
=>
t
.
name
).
join
(
', '
)
+
':'
);
Object
.
values
(
other
).
forEach
(
c
=>
log
.
push
(
` >
${
c
.
name
}
`
)
);
const
c
=
rand
(
components
)
return
{
allCorrect
:
components
,
baseProduct
:
possibility
.
baseProduct
,
correct
:
c
,
wrong
:
shuffle
(
Object
.
values
(
other
)
).
slice
(
0
,
rand
(
this
.
answers
.
min
-
1
,
this
.
answers
.
max
-
1
)
),
allWrong
:
Object
.
values
(
other
)
};
}
}
return
false
;
}
},
similarTaggedProductWithPhoto
:
{
questionMinComponentsCount
:
Number
,
products
:
{
min
:
Number
,
max
:
Number
},
fn
:
function
(
log
)
{
let
allProducts
=
Object
.
values
(
dP
.
products
);
let
products
=
Object
.
values
(
dP
.
products
)
.
filter
(
p
=>
p
.
image
)
.
filter
(
p
=>
p
.
getComponents
().
length
>=
this
.
questionMinComponentsCount
)
log
.
push
(
`Products with image and >=
${
this
.
questionMinComponentsCount
}
components count:
${
products
.
length
}
`
);
if
(
products
.
length
===
0
){
rand
(
Object
.
values
(
dP
.
products
)).
image
=
'https://robohash.org/'
+
Math
.
random
().
toString
(
36
)
return
false
;
}
const
possibility
=
products
.
map
(
p
=>
{
const
similar
=
qB
.
getProductsWithTags
({
products
:
allProducts
,
tags
:
p
.
getTags
(),
minMatch
:
1
});
if
(
similar
.
length
+
1
>=
this
.
products
.
min
){
return
{
correct
:
p
,
baseProduct
:
p
,
wrong
:
similar
.
filter
(
sP
=>
sP
!==
p
).
slice
(
0
,
rand
(
this
.
products
.
min
-
1
,
this
.
products
.
max
-
1
)),
all
:
similar
};
}
else
{
return
false
;
}
})
.
filter
(
Boolean
);
log
.
push
(
`Possible count:
${
possibility
.
length
}
`
);
return
this
.
getEmAll
?
possibility
:
rand
(
possibility
);
}
},
similarTaggedProducts
:
{
similarTaggedProducts
:
{
// minimal components in product
// minimal components in product
questionCmpAmount
:
4
,
questionCmpAmount
:
4
,
...
@@ -172,8 +288,11 @@ const qB = {
...
@@ -172,8 +288,11 @@ const qB = {
},
log
);
},
log
);
for
(
let
i
=
0
,
_i
=
products
.
length
;
i
<
_i
;
i
++
){
for
(
let
i
=
0
,
_i
=
products
.
length
;
i
<
_i
;
i
++
){
const
product
=
products
[
i
],
cmps
=
product
const
product
=
products
[
i
];
/* if(this.withPhoto && !product.image)
continue;*/
const
cmps
=
product
.
getComponents
()
.
getComponents
()
.
filter
(
cmp
=>
products
.
filter
(
p
=>
p
.
containsComponent
(
cmp
)).
length
===
1
)
.
filter
(
cmp
=>
products
.
filter
(
p
=>
p
.
containsComponent
(
cmp
)).
length
===
1
)
...
...
public/js/controller/quizBits/radioPhoto.js
0 → 100644
View file @
ecd6089d
quizTypes
.
radioPhoto
=
[
{
questionMinComponentsCount
:
0
,
probability
:
10
,
type
:
'What is it'
,
products
:
{
min
:
4
,
max
:
6
},
from
:
qB
.
prebuild
.
similarTaggedProductWithPhoto
.
fn
,
question
(
income
,
log
){
return
'Какой продукт изображен на картинке?'
},
answer
(
income
,
log
){
return
shuffle
(
[
new
Answer
.
Correct
(
textFormat
(
income
.
correct
.
title
))]
.
concat
(
income
.
wrong
.
map
(
p
=>
new
Answer
.
Wrong
(
textFormat
(
p
.
title
)))))
}
},
{
questionMinComponentsCount
:
0
,
probability
:
8
,
type
:
'What describes it better'
,
products
:
{
min
:
3
,
max
:
5
},
from
:
qB
.
prebuild
.
similarTaggedProductWithPhoto
.
fn
,
question
(
income
,
log
){
return
'Какое из этих описаний относится к продукту, изображенному на картинке?'
},
answer
(
income
,
log
){
return
shuffle
(
[
new
Answer
.
Correct
(
textFormat
(
income
.
correct
.
description
))]
.
concat
(
income
.
wrong
.
map
(
p
=>
new
Answer
.
Wrong
(
textFormat
(
p
.
description
)))))
}
},
{
questionMinComponentsCount
:
2
,
probability
:
3
,
type
:
'What component is in it'
,
answers
:
{
min
:
4
,
max
:
6
},
from
:
qB
.
prebuild
.
similarTaggedProductWithPhotoAndComponents
.
fn
,
question
(
income
,
log
){
return
'Выберите один ингредиент, который входит в продукт, изображенный на картинке'
},
answer
(
income
,
log
){
return
shuffle
(
[
new
Answer
.
Correct
(
textFormat
(
income
.
correct
.
name
))]
.
concat
(
income
.
wrong
.
map
(
p
=>
new
Answer
.
Wrong
(
textFormat
(
p
.
name
)))))
}
}
];
\ No newline at end of file
public/js/controller/quizGenerator.js
View file @
ecd6089d
...
@@ -98,7 +98,7 @@ const quizGenerator = function(type, photo, subType) {
...
@@ -98,7 +98,7 @@ const quizGenerator = function(type, photo, subType) {
productId
:
source
.
baseProduct
.
id
,
productId
:
source
.
baseProduct
.
id
,
question
:
cfg
.
question
.
call
(
cfg
,
source
,
log
),
question
:
cfg
.
question
.
call
(
cfg
,
source
,
log
),
answers
,
answers
,
image
:
!
photo
?
null
:
tru
e
,
image
:
!
photo
?
null
:
source
.
baseProduct
.
imag
e
,
log
,
log
,
...
...
public/js/view/page/generate.js
View file @
ecd6089d
...
@@ -19,6 +19,7 @@ view.page.Generate = function() {
...
@@ -19,6 +19,7 @@ view.page.Generate = function() {
const
result
=
quizGenerator
(
type
,
photo
);
const
result
=
quizGenerator
(
type
,
photo
);
title
.
innerHTML
=
textFormat
(
result
.
question
,
true
);
title
.
innerHTML
=
textFormat
(
result
.
question
,
true
);
image
.
innerHTML
=
result
.
image
?
`<img src="
${
result
.
image
}
" alt="img"/>`
:
''
;
debug
.
value
=
result
.
log
.
join
(
'
\
n'
)
debug
.
value
=
result
.
log
.
join
(
'
\
n'
)
D
.
removeChildren
(
answers
);
D
.
removeChildren
(
answers
);
D
.
appendChild
(
answers
,
result
.
answers
.
map
(
(
a
)
=>
view
.
cmp
.
Answer
(
a
,
type
)
)
);
D
.
appendChild
(
answers
,
result
.
answers
.
map
(
(
a
)
=>
view
.
cmp
.
Answer
(
a
,
type
)
)
);
...
@@ -28,7 +29,7 @@ view.page.Generate = function() {
...
@@ -28,7 +29,7 @@ view.page.Generate = function() {
}
}
};
};
let
title
,
answers
,
debug
,
seedInput
,
setSeed
;
let
title
,
answers
,
debug
,
seedInput
,
image
;
this
.
dom
=
this
.
dom
=
div
({
cls
:
'generate-panel'
},
div
({
cls
:
'generate-panel'
},
...
@@ -65,6 +66,7 @@ view.page.Generate = function() {
...
@@ -65,6 +66,7 @@ view.page.Generate = function() {
div
({
cls
:
'generate-example'
},
div
({
cls
:
'generate-example'
},
title
=
div
({
cls
:
'generate-title'
}),
title
=
div
({
cls
:
'generate-title'
}),
image
=
div
({
cls
:
'generate-image'
}),
answers
=
div
({
cls
:
'generate-answers'
}),
answers
=
div
({
cls
:
'generate-answers'
}),
debug
=
D
.
textarea
({
cls
:
'generate-debug'
})
debug
=
D
.
textarea
({
cls
:
'generate-debug'
})
)
)
...
...
public/main.css
View file @
ecd6089d
...
@@ -228,4 +228,12 @@ textarea.generate-debug {
...
@@ -228,4 +228,12 @@ textarea.generate-debug {
}
}
.generate-seed-label
{
.generate-seed-label
{
margin
:
0
8px
0
32px
margin
:
0
8px
0
32px
}
.generate-example
{
position
:
relative
;
}
.generate-image
{
right
:
0
;
position
:
absolute
;
top
:
-100px
;
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment