- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables
Class ::xowiki::formfield::enumeration
::xowiki::formfield::enumeration create ... \
[ -category_tree category_tree ] \
[ -descriptions (default "") ]
Defined in
Class Relations
- class: ::xotcl::Class
- superclass: ::xowiki::formfield::ShuffleField
- subclass: ::xowiki::formfield::checkbox, ::xowiki::formfield::select, ::xowiki::formfield::radio
::xotcl::Class create ::xowiki::formfield::enumeration \ -superclass ::xowiki::formfield::ShuffleFieldMethods (to be applied on instances)
add_statistics (scripted)
#ns_log notice "???? add_statistics" # # Add generic statistics # next # # Enumeration specific statistics # #ns_log notice "[self] enumeration add_statistics (options $options) value <${:value}>" foreach v ${:value} { dict incr :result_statistics $v } #ns_log notice "${:name} ### answer ${:answer} value ${:value} correction ${:correction} " #ns_log notice [:serialize]answer_is_correct (scripted)
#:log "enumeration CORRECT? ${:name} (value=[:value], answer=[expr {[info exists :answer]?${:answer}:{NONE}}]" if {![info exists :answer]} { return 0 } else { # # The question was answered, therefore, we can count it in the # statistics. # :stats_record_count set value [:value] #:log "enumeration ${:name} CORRECT? answers [llength ${:answer}] options [llength ${:options}]" set :correction {} set r 0; set f 0; set rk 0; set fk 0; set W 0; set O 0; set R 0 foreach o ${:options} a ${:answer} { lassign $o label v #:log "enumeration ${:name} CORRECT? <$a> <$v in $value> -> [expr {$v in $value}]" # # A correct answer might be: # - a mark on a correct entry # - no mark on a wrong entry # if {$a} { incr r set correctly_answered [expr {$v in $value}] } else { set correctly_answered [expr {$v ni $value}] incr f #:log "enumeration ${:name} CORRECT? <$a> <$v ni $value> -> [expr {$v ni $value}]" } #:log "[self] ${:name} enumeration ${:name} CORRECT $o -> $correctly_answered" :stats_record_detail -label $label -value $v $correctly_answered lappend :correction $correctly_answered if {$correctly_answered} { incr R } else { incr W } if {$v in $value} { # # Marked entries: mark can be correct or wrong. # if {$a} { incr rk } else { incr fk } } set scores [:scores -r $r -f $f -rk $rk -fk $fk -R $R -W $W] set :correction_data [list item [list r $r f $f] marks [list rk $rk fk $fk] answers [list R $R W $W] scores $scores] } #:log "enumeration CHECKED CORRECT? ${:correction_data}" return [expr {0 ni ${:correction} ? 1 : -1}] }category_tree (setter)
config_from_category_tree (scripted)
# Get the options of a select or radio from the specified # category tree. # # We could config as well from the mapped category tree, # and get required and multiple from there.... # # The usage of the label does not seem to be very useful. # #set tree_id [category_tree::get_id $tree_name [:locale]] set package_id [${:object} package_id] set tree_ids [::xowiki::Category get_mapped_trees -object_id $package_id -locale ${:locale} -names $tree_name -output tree_id] # In case there are multiple trees with the same name, # take the first one. # set tree_id [lindex $tree_ids 0] if {$tree_id eq ""} { :msg "cannot lookup mapped category tree name '$tree_name'" return } set subtree_id "" set options [list] foreach category [::xowiki::Category get_category_infos -subtree_id $subtree_id -tree_id $tree_id] { lassign $category category_id category_name deprecated_p level set category_name [ns_quotehtml [lang::util::localize $category_name]] set :category_label($category_id) $category_name if { $level>1 } { set category_name "[string repeat {.} [expr {2*$level-4}]]..$category_name" } lappend options [list $category_name $category_id] } set :options $options if {[info exists :default] && ${:default} ne ""} { # # When a default is provided, and the default is a valid # name. Note that the "symbolic" default has to be provided # exactly like the label, and it might not be unique. # set optdict [concat {*}$options] if {[dict exists $optdict ${:default}]} { set :default [dict get $optdict ${:default}] } } set :is_category_field 1 # :msg label_could_be=$tree_name,existing=${:label} # if {![info exists :label]} { # :label $tree_name # }descriptions (setter)
get_labels (scripted)
if {${:multiple}} { set labels [list] foreach v $values { lappend labels [list [:get_entry_label $v] $v] } return $labels } else { return [list [list [:get_entry_label $values] $values]] }ggw (scripted)
return [expr {100.0 * ($R - $W*0.5) / ($R + $W) }]initialize (scripted)
if {[info exists :category_tree]} { :config_from_category_tree ${:category_tree} } if {[info exists :answer]} { set count 1 set :answer_value {} try { foreach a ${:answer} { if {$a} { lappend :answer_value $count } incr count } } on error {errorMsg} { ns_log error "${:name}: invalid answer value provided '${:answer}': must be list of booleans" error $errorMsg } #ns_log notice "???? answer ${:answer} -> ${:answer_value}" } next # # For required enumerations, the implicit default value is the # first entry of the options. This is as well the value, which is # returned from the browser in such cases. # if {${:required} && ${:value} eq ""} { set :value [lindex ${:options} 0 1] }make_correct (scripted)
if {[info exists :answer_value]} { set :value ${:answer_value} #ns_log notice "???? make_correct sets value ${:answer_value}" }pretty_value (scripted)
if {[info exists :category_label($v)]} { return [set :category_label($v)] } if {[info exists :multiple] && ${:multiple}} { foreach o ${:options} { lassign $o label value set labels($value) [:localize $label] } set values [list] foreach i $v {lappend values $labels($i)} return [join $values {, }] } else { foreach o ${:options} { lassign $o label value if {$value eq $v} {return [:localize $label]} } }render_input (scripted)
if {![::xotcl::self isnextcall]} { error "Abstract method render_input called" } else {::xotcl::next}render_label_classes (scripted)
# # Determine the values of the CSS classes for correct/incorrect # rendering. In statistics mode (when :result_statistics exists), # use the correct value of the alternative. Otherwise, use # the :correction of the actual value in the form field. # if {[info exists :result_statistics]} { set values ${:answer} #ns_log notice "==== radio answer $answer aw ${:answer_value} results ${:result_statistics}" } else { set values [expr {[info exists :correction] ? ${:correction} : ""}] } return [lmap v $values {dict get {"" "" 1 correct 0 incorrect t correct f incorrect} $v}]render_label_text (scripted)
# # Render a label text (typically of a checkbox or radio input) # either as richtext or as plain label. # if {${:richtext}} { ::html::div -class richtext-label { ::html::t -disableOutputEscaping $label if {[info exists :evaluated_answer_result] && "incorrect" in $CSSclass && $description ne "" } { html::div -class "help-block description" { html::t $description } } } } else { ::html::t " $label " }render_result_statistics (scripted)
# # In case, there are result_statistics, use a "progress bar" to # visualize correct answers per alternative ($rep). # if {[info exists :result_statistics] && [dict exists ${:result_statistics} count]} { # # result_count: how often was question answered (in general) # correct_count: how often was an alternative correctly answered # incorrect_count: how often was an alternative incorrectly answered # #set result_count [dict get ${:result_statistics} count] set alternative_counts [expr {[dict exists ${:result_statistics} $rep] ? [dict get ${:result_statistics} $rep] : ""}] set incorrect_count 0; set correct_count 0 if {$alternative_counts ne ""} { foreach key {0 1} var {incorrect_count correct_count} { if {[dict exists $alternative_counts $key]} { set $var [dict get $alternative_counts $key] } } } set answered_count [expr {$correct_count + $incorrect_count}] if {$answered_count > 0} { set with_pie_charts [::xo::cc query_parameter pie:boolean 0] if {$with_pie_charts} { if {![info exists ::__xotcl_highcharts_pie]} { if {[template::head::can_resolve_urn urn:ad:js:highcharts]} { # # The highcharts package is available # template::add_body_script -src urn:ad:js:highcharts } else { # # The highcharts package is not available, go straight to the CDN. # template::add_body_script -src "//code.highcharts.com/highcharts.js" security::csp::require script-src code.highcharts.com } } set graphID pie-[incr ::__xotcl_highcharts_pie] } ::html::div -class container { ::html::div -class row { ::html::span -class "col-sm-2" -style "font-size: x-small; float: right;" { ::html::t "$correct_count of $answered_count correct" } if {$with_pie_charts} { ::html::div -class "col-sm-2" -style "width: 400px; height:120px;" -id $graphID {} } else { ::html::div -class "progress col-sm-8" -style "padding: 0px 0px 0px 0px;" { set percentage [format %2.0f [expr {$correct_count * 100.0 / $answered_count}]] ::html::div -class "progress-bar progress-bar-success" -role "progressbar" -aria-valuenow $percentage -aria-valuemin "0" -aria-valuemax "100" -style "width:$percentage%" { if {$percentage > 0} { ::html::t "$percentage % correct" } } } } } } if {$with_pie_charts} { set startAngle [expr {$correct_count == 0 || $incorrect_count == 0 ? 90: 0}] template::add_body_script -script [subst [ns_trim { Highcharts.chart('$graphID', { chart: {type: 'pie'}, plotOptions: {pie: {size: 35, startAngle: $startAngle }}, title: {text: ''}, colors: \['green', 'red'\], credits: {enabled: false }, series: \[{name: 'Results', data: \[ {name:'correct', y: $correct_count}, {name:'incorrect', y: $incorrect_count}\]}\] }); }]] } } }scores (scripted, public)
<instance of xowiki::formfield::enumeration> scores [ -r r ] \ [ -f f ] [ -rk rk ] [ -fk fk ] [ -R R ] [ -W W ]
- Switches:
- -r (optional, defaults to
"0"
)- number of answers which are true
- -f (optional, defaults to
"0"
)- number of answers which are false
- -rk (optional, defaults to
"0"
)- number checkmarks to a true answer
- -fk (optional, defaults to
"0"
)- number checkmarks to a false answer
- -R (optional)
- number correct answered
- -W (optional)
- number incorrect answered
- Testcases:
- create_test_items
# # Now calculate the scores of different scoring schemes. # if {$r > 0} { # # Certain correction schemes divide by $r. We cannot use # these schemes in such cases. # if {$f == 0} { # # No penalty for marking a wrong solution, when there is # no wrong solution. # set wi1 [expr {max((100.0/$r) * $rk, 0)}] set wi2 [expr {max((100.0/$r) * $rk, 0)}] } else { set wi1 [expr {max((100.0/$r) * $rk - (100.0/$f) * $fk, 0)}] if {$f == 1} { # # Special rule when there is just one wrong solution. # set wi2 [expr {max((100.0/$r) * $rk - min(50.0, (100.0/$f)) * $fk, 0)}] } else { set wi2 $wi1 } } set canvas [expr {max(($rk * 100.0/$r) - ($fk * 100.0/$r), 0)}] set etk [expr {100.0 * (($r*1.0+$f) /$r) * ($rk - $fk) / ($R + $W) }] } else { set wi1 0.0 set wi2 0.0 set etk 0.0 set canvas 0.0 } set s1 [expr {100.0 * $R / ($R + $W) }] set s2 [expr {100.0 * ($R - $W/2.0) / ($R + $W) }] set ggw0 [expr {100.0 * ($R - $W) / ($R + $W) }] set ggw [:ggw $R $W] return [list wi1 $wi1 wi2 $wi2 s1 $s1 s2 $s2 etk $etk ggw0 $ggw0 ggw $ggw canvas $canvas]stats_record_detail (scripted)
set reporting_obj ::[${:object} parent_id] $reporting_obj stats_record_detail -label $label -value $value -name ${:name} -correctly_answered $correctly_answeredvalue_if_nothing_is_returned_from_form (scripted)
# Here we have to distinguish between two cases: # - edit mode: somebody has removed a mark from a check button; # this means: clear the field # - view mode: the fields were deactivated (made insensitive); # this means: keep the old value -> return default if {[:is_disabled]} { return $default } else { return "" }
- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables