$ = jQuery
class Binding
constructor: (@handler, @element) ->
$(@element).data(@handler, this)
class EduModule extends Binding
constructor: (element) ->
super 'edumodule', element
$("[name=teacher-toggle]").change (ev) =>
if $(ev.target).is(":checked")
$(".teacher", @element).addClass "show"
else
$(".teacher", @element).removeClass "show"
class Excercise extends Binding
constructor: (element) ->
super 'excercise', element
# just save the html to reset the excercise
$(@element).data("excercise-html", $(@element).html())
$(".check", @element).click =>
@check()
$('.solutions', @element).click =>
@show_solutions()
$('.reset', @element).click =>
@reset()
reset: ->
$(@element).html($(@element).data('excercise-html'))
excercise @element
piece_correct: (qpiece) ->
$(qpiece).removeClass('incorrect').addClass('correct')
piece_incorrect: (qpiece) ->
$(qpiece).removeClass('correct').addClass('incorrect')
check: ->
scores = []
$(".question", @element).each (i, question) =>
scores.push(@check_question question)
score = [0, 0]
$.each scores, (i, s) ->
score[0] += s[0]
score[1] += s[1]
@show_score(score)
show_solutions: ->
@reset()
$(".question", @element).each (i, question) =>
@solve_question question
# Parses a list of values, separated by space or comma.
# The list is read from data attribute of elem using data_key
# Returns a list with elements
# eg.: things_i_need: "house bike tv playstation"
# yields ["house", "bike", "tv", "playstation"]
# If optional numbers argument is true, returns list of numbers
# instead of strings
get_value_list: (elem, data_key, numbers) ->
vl = $(elem).attr("data-" + data_key).split(/[ ,]+/).map($.trim) #.map((x) -> parseInt(x))
if numbers
vl = vl.map((x) -> parseInt(x))
return vl
# Parses a list of values, separated by space or comma.
# The list is read from data attribute of elem using data_key
# Returns a 2-element list with mandatory and optional
# items. optional items are marked with a question mark on the end
# eg.: things_i_need: "house bike tv? playstation?"
# yields [[ "house", "bike"], ["tv", "playstation"]]
get_value_optional_list: (elem, data_key) ->
vals = @get_value_list(elem, data_key)
mandat = []
opt = []
for v in vals
if v.slice(-1) == "?"
opt.push v.slice(0, -1)
else
mandat.push v
return [mandat, opt]
show_score: (score) ->
$(".message", @element).text("Wynik: #{score[0]} / #{score[1]}")
draggable_equal: ($draggable1, $draggable2) ->
return false
draggable_accept: ($draggable, $droppable) ->
dropped = $droppable.closest("ul, ol").find(".draggable")
for d in dropped
if @draggable_equal $draggable, $(d)
return false
return true
draggable_move: ($draggable, $placeholder, ismultiple) ->
$added = $draggable.clone()
$added.data("original", $draggable.get(0))
if not ismultiple
$draggable.addClass('disabled').draggable('disable')
$placeholder.after($added)
if not $placeholder.hasClass('multiple')
$placeholder.hide()
$added.append('x')
$('.remove', $added).click (ev) =>
$added.prev(".placeholder:not(.multiple)").show()
if not ismultiple
$($added.data('original')).removeClass('disabled').draggable('enable')
$added.remove()
dragging: (ismultiple, issortable) ->
$(".question", @element).each (i, question) =>
draggable_opts =
revert: 'invalid'
helper: 'clone'
$(".draggable", question).draggable(draggable_opts)
self = this
$(".placeholder", question).droppable
accept: (draggable) ->
$draggable = $(draggable)
is_accepted = true
if not $draggable.is(".draggable")
is_accepted = false
if is_accepted
is_accepted= self.draggable_accept $draggable, $(this)
if is_accepted
$(this).addClass 'accepting'
else
$(this).removeClass 'accepting'
return is_accepted
drop: (ev, ui) =>
$(ev.target).removeClass 'accepting dragover'
@draggable_move $(ui.draggable), $(ev.target), ismultiple
# $added = $(ui.draggable).clone()
# $added.data("original", ui.draggable)
# if not ismultiple
# $(ui.draggable).addClass('disabled').draggable('disable')
# $(ev.target).after(added)
# if not $(ev.target).hasClass('multiple')
# $(ev.target).hide()
# $added.append('x')
# $('.remove', added).click (ev) =>
# $added.prev(".placeholder:not(.multiple)").show()
# if not ismultiple
# $added.data('original').removeClass('disabled').draggable('enable')
# $(added).remove()
over: (ev, ui) ->
$(ev.target).addClass 'dragover'
out: (ev, ui) ->
$(ev.target).removeClass 'dragover'
class Wybor extends Excercise
constructor: (element) ->
super element
check_question: (question) ->
all = 0
good = 0
solution = @get_value_list(question, 'solution')
$(".question-piece", question).each (i, qpiece) =>
piece_no = $(qpiece).attr 'data-no'
piece_name = $(qpiece).attr 'data-name'
if piece_name
should_be_checked = solution.indexOf(piece_name) >= 0
else
should_be_checked = solution.indexOf(piece_no) >= 0
is_checked = $("input", qpiece).is(":checked")
if should_be_checked
all += 1
if is_checked
if should_be_checked
good += 1
@piece_correct qpiece
else
@piece_incorrect qpiece
else
$(qpiece).removeClass("correct,incorrect")
return [good, all]
solve_question: (question) ->
solution = @get_value_list(question, 'solution')
$(".question-piece", question).each (i, qpiece) =>
piece_no = $(qpiece).attr 'data-no'
piece_name = $(qpiece).attr 'data-name'
if piece_name
should_be_checked = solution.indexOf(piece_name) >= 0
else
should_be_checked = solution.indexOf(piece_no) >= 0
console.log("check " + $("input[type=checkbox]", qpiece).attr("id") + " -> " + should_be_checked)
$("input[type=checkbox]", qpiece).prop 'checked', should_be_checked
class Uporzadkuj extends Excercise
constructor: (element) ->
super element
$('ol, ul', @element).sortable({ items: "> li" })
check_question: (question) ->
positions = @get_value_list(question, 'original', true)
sorted = positions.sort()
pkts = $('.question-piece', question)
correct = 0
all = 0
for pkt in [0...pkts.length]
all += 1
if pkts.eq(pkt).data('pos') == sorted[pkt]
correct += 1
@piece_correct pkts.eq(pkt)
else
@piece_incorrect pkts.eq(pkt)
return [correct, all]
solve_question: (question) ->
positions = @get_value_list(question, 'original', true)
sorted = positions.sort()
pkts = $('.question-piece', question)
pkts.sort (a, b) ->
q = $(a).data('pos')
w = $(b).data('pos')
return 1 if q < w
return -1 if q > w
return 0
parent = pkts.eq(0).parent()
for p in pkts
parent.prepend(p)
# XXX propozycje="1/0"
class Luki extends Excercise
constructor: (element) ->
super element
@dragging false, false
check: ->
all = 0
correct = 0
$(".placeholder + .question-piece", @element).each (i, qpiece) =>
$placeholder = $(qpiece).prev(".placeholder")
if $placeholder.data('solution') == $(qpiece).data('no')
@piece_correct qpiece
correct += 1
else
@piece_incorrect qpiece
all += 1
@show_score [correct, all]
solve_question: (question) ->
$(".placeholder", question).each (i, placeholder) =>
$qp = $(".question-piece[data-no=" + $(placeholder).data('solution') + "]", question)
@draggable_move $qp, $(placeholder), false
class Zastap extends Excercise
constructor: (element) ->
super element
$(".paragraph", @element).each (i, par) =>
@wrap_words $(par), $('')
@dragging false, false
check: ->
all = 0
correct = 0
$(".paragraph", @element).each (i, par) =>
$(".placeholder", par).each (j, qpiece) =>
$qp = $(qpiece)
$dragged = $qp.next(".draggable")
if $qp.data("solution")
if $dragged and $qp.data("solution") == $dragged.data("no")
@piece_correct $dragged
correct += 1
# else -- we dont mark enything here, so not to hint user about solution. He sees he hasn't used all the draggables
all += 1
@show_score [correct, all]
show_solutions: ->
@reset()
$(".paragraph", @element).each (i, par) =>
$(".placeholder[data-solution]", par).each (j, qpiece) =>
$qp = $(qpiece)
$dr = $(".draggable[data-no=" + $qp.data('solution') + "]", @element)
@draggable_move $dr, $qp, false
wrap_words: (element, wrapper) ->
# This function wraps each word of element in wrapper, but does not descend into child-tags of element.
# It doesn't wrap things between words (defined by ignore RE below). Warning - ignore must begin with ^
ignore = /^[ \t.,:;()]+/
insertWrapped = (txt, elem) ->
nw = wrapper.clone()
$(document.createTextNode(txt))
.wrap(nw).parent().attr("data-original", txt).insertBefore(elem)
for j in [element.get(0).childNodes.length-1..0]
chld = element.get(0).childNodes[j]
if chld.nodeType == document.TEXT_NODE
len = chld.textContent.length
wordb = 0
i = 0
while i < len
space = ignore.exec(chld.textContent.substr(i))
if space?
if wordb < i
insertWrapped(chld.textContent.substr(wordb, i-wordb), chld)
$(document.createTextNode(space[0])).insertBefore(chld)
i += space[0].length
wordb = i
else
i = i + 1
if wordb < len - 1
insertWrapped(chld.textContent.substr(wordb, len - 1 - wordb), chld)
$(chld).remove()
class Przyporzadkuj extends Excercise
is_multiple: ->
for qp in $(".question-piece", @element)
if $(qp).data('solution').split(/[ ,]+/).length > 1
return true
return false
constructor: (element) ->
super element
@multiple = @is_multiple()
@dragging @multiple, true
draggable_equal: (d1, d2) ->
return d1.data("no") == d2.data("no")
check_question: (question) ->
# subjects placed in predicates
count = 0
all = 0
all_multiple = 0
for qp in $(".predicate .question-piece", question)
pred = $(qp).closest("[data-predicate]")
v = @get_value_optional_list qp, 'solution'
mandatory = v[0]
optional = v[1]
all_multiple += mandatory.length + optional.length
pn = pred.attr('data-predicate')
if mandatory.indexOf(pn) >= 0 or optional.indexOf(pn) >= 0
count += 1
@piece_correct qp
else
@piece_incorrect qp
all += 1
if @multiple
for qp in $(".subject .question-piece", question)
v = @get_value_optional_list qp, 'solution'
mandatory = v[0]
optional = v[1]
all_multiple += mandatory.length + optional.length
return [count, all_multiple]
else
return [count, all]
solve_question: (question) ->
for qp in $(".subject .question-piece", question)
v = @get_value_optional_list qp, 'solution'
mandatory = v[0]
optional = v[1]
for m in mandatory.concat(optional)
$pr = $(".predicate [data-predicate=" + m + "]", question)
$ph = $pr.find ".placeholder"
@draggable_move $(qp), $ph, @multiple
class PrawdaFalsz extends Excercise
constructor: (element) ->
super element
for qp in $(".question-piece", @element)
$(".true", qp).click (ev) ->
ev.preventDefault()
$(this).closest(".question-piece").data("value", "true")
$(this).addClass('chosen').siblings('a').removeClass('chosen')
$(".false", qp).click (ev) ->
ev.preventDefault()
$(this).closest(".question-piece").data("value", "false")
$(this).addClass('chosen').siblings('a').removeClass('chosen')
check_question: ->
all = 0
good = 0
for qp in $(".question-piece", @element)
if $(qp).data("solution").toString() == $(qp).data("value")
good += 1
@piece_correct qp
else
@piece_incorrect qp
all += 1
return [good, all]
show_solutions: ->
reset()
for qp in $(".question-piece", @element)
if $(qp).data('solution') == 'true'
$(".true", qp).click()
else
$(".false", qp).click()
##########
excercise = (ele) ->
es =
wybor: Wybor
uporzadkuj: Uporzadkuj
luki: Luki
zastap: Zastap
przyporzadkuj: Przyporzadkuj
prawdafalsz: PrawdaFalsz
cls = es[$(ele).attr('data-type')]
new cls(ele)
window.edumed =
'EduModule': EduModule
$(document).ready () ->
new EduModule($("#book-text"))
$(".excercise").each (i, el) ->
excercise(this)