Index: openacs-4/packages/xowiki/xowiki.info
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/xowiki.info,v
diff -u -r1.180.2.24 -r1.180.2.25
--- openacs-4/packages/xowiki/xowiki.info 21 Oct 2019 19:31:37 -0000 1.180.2.24
+++ openacs-4/packages/xowiki/xowiki.info 27 Oct 2019 17:58:53 -0000 1.180.2.25
@@ -10,7 +10,7 @@
t
xowiki
-
+
Gustaf Neumann
A xotcl-based enterprise wiki system with multiple object types
2017-08-06
@@ -55,7 +55,7 @@
BSD-Style
2
-
+
Index: openacs-4/packages/xowiki/tcl/form-field-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/form-field-procs.tcl,v
diff -u -r1.284.2.43 -r1.284.2.44
--- openacs-4/packages/xowiki/tcl/form-field-procs.tcl 22 Oct 2019 16:12:45 -0000 1.284.2.43
+++ openacs-4/packages/xowiki/tcl/form-field-procs.tcl 27 Oct 2019 17:58:53 -0000 1.284.2.44
@@ -61,6 +61,7 @@
default
object
slot
+
answer
correct_when
feedback_answer_correct
@@ -74,9 +75,6 @@
FormField proc fc_decode {string} {
return [string map [list __COMMA__ ,] $string]
}
- #FormField proc fc_decode_colon {string} {
- # return [string map [list __COLON__ :] $string]
- #}
FormField proc get_from_name {object name} {
#
@@ -651,7 +649,7 @@
}
FormField instproc answer_is_correct {} {
- #:log "${:name} ([:info class]): value=[:value], answer=[expr {[info exists :answer]?${:answer}:{NONE}}]"
+ #:log "CORRECT? ${:name} ([:info class]): value=[:value], answer=[expr {[info exists :answer]?${:answer}:{NONE}}]"
if {[info exists :correct_when]} {
set op [lindex ${:correct_when} 0]
if {[:procsearch answer_check=$op] ne ""} {
@@ -678,6 +676,36 @@
}
}
+ FormField instproc set_feedback {feedback_mode} {
+ set correct [:answer_is_correct]
+ :log "${:name} [:info class]: correct? $correct"
+ switch -- $correct {
+ 0 { return }
+ -1 { set result "incorrect"}
+ 1 { set result "correct" }
+ }
+ :form_widget_CSSclass $result
+ set :evaluated_answer_result $result
+
+ set feedback ""
+ if {[info exists :feedback_answer_$result]} {
+ set feedback [set :feedback_answer_$result]
+ } else {
+ set feedback [_ xowf.answer_$result]
+ }
+ if {$feedback_mode > 1} {
+ #:log "===$feedback_mode=[info exists :correct_when]============[:serialize]"
+ if {[info exists :correct_when]} {
+ append feedback " ${:correct_when}"
+ } elseif {[info exists :correction]} {
+ append feedback " ${:correction}"
+ }
+ }
+ :log "==== ${:name} setting feedback $feedback"
+ set :help_text $feedback
+ }
+
+
FormField instproc set_is_repeat_template {is_template} {
# :msg "${:name} set is_repeat_template $is_template"
if {$is_template} {
@@ -734,6 +762,7 @@
return $html
}
+
###########################################################
#
# helper method for extending slots:
@@ -2521,22 +2550,112 @@
###########################################################
#
- # ::xowiki::formfield::enumeration
+ # ::xowiki::formfield::ShuffleField
#
###########################################################
# abstract superclass for select and radio
- Class create enumeration -superclass FormField -parameter {
+ Class create ShuffleField -superclass FormField -parameter {
{options ""}
+ {shuffle:boolean false}
+ {shuffle_seed:integer 0}
+ } -ad_doc {
+
+ An abstract class for shuffling options and answers. The options
+ can be used a content of checkboxes, radioboxes and the like. This
+ is particular useful when creating quizzes.
+
+ @param shuffle turn shuffling on/off
+ @param shuffle_seed
+ In case, the shuffle_seed is "0", a different shuffling is
+ produced every call. When the seed is provided (e.g. a user_id)
+ then the shuffling is stable for this seed.
+ }
+ ShuffleField set abstract 1
+
+ ShuffleField instproc randomized_indices {length} {
+ #
+ # Produce a list of random indices.
+ #
+ # In case, the shuffle_seed is "0", a different shuffling is
+ # produced every call. When the seed is provided (e.g. a user_id)
+ # then the shuffling is stable for this seed.
+ #
+ if {${:shuffle_seed} != 0} {
+ expr {srand(${:shuffle_seed})}
+ }
+ #
+ # Produce shuffled indices between 0 and length-1.
+ #
+ set indices {}
+ for {set i 0} {$i < $length} {incr i} {
+ lappend indices $i
+ }
+ set shuffled {}
+ incr length
+ for {} {$length > 1} {incr length -1} {
+ set i [expr {int(($length-1) * rand())}]
+ lappend shuffled [lindex $indices $i]
+ set indices [lreplace $indices $i $i]
+ }
+ return $shuffled
+ }
+
+ ShuffleField instproc shuffle_options {} {
+ #
+ # Reorder :options and :answers when :shuffle is activated.
+ #
+ set length [llength ${:options}]
+ if {$length > 0} {
+ #
+ # There is something to shuffle.
+ #
+ #
+ # Produce a list of random indices.
+ #
+ set shuffled [:randomized_indices $length]
+
+ #
+ # Use the random indices for reordering the :options and
+ # :answers.
+ #
+ #ns_log notice "SHUFFLE ${:name} <$shuffled> <$indices>"
+ set option2 {}; set answer2 {}
+ foreach i $shuffled {
+ lappend option2 [lindex ${:options} $i]
+ lappend answer2 [lindex ${:answer} $i]
+ }
+ #ns_log notice "SHUFFLE ${:name} o2=$option2 answer2=$answer2"
+ set :options $option2
+ set :answer $answer2
+ }
+ }
+
+
+ ###########################################################
+ #
+ # ::xowiki::formfield::enumeration
+ #
+ ###########################################################
+
+ # abstract superclass for select and radio
+ Class create enumeration -superclass ShuffleField -parameter {
{category_tree}
}
enumeration set abstract 1
+
enumeration instproc initialize {} {
if {[info exists :category_tree]} {
:config_from_category_tree [:category_tree]
}
next
#
+ # Shuffle options when needed
+ #
+ if {${:shuffle}} {
+ :shuffle_options
+ }
+ #
# 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.
@@ -2559,6 +2678,27 @@
}
}
+ enumeration instproc answer_is_correct {} {
+ :log "enumeration CORRECT? ${:name} (value=[:value], answer=[expr {[info exists :answer]?${:answer}:{NONE}}]"
+ if {![info exists :answer]} {
+ return 0
+ } else {
+ set value [:value]
+ :log "enumeration CORRECT? answers [llength ${:answer}] options [llength ${:options}]"
+ set :correction {}
+ foreach o ${:options} a ${:answer} {
+ lassign $o label v
+ if {$a} {
+ lappend :correction [expr {$v in $value}]
+ } else {
+ lappend :correction [expr {$v ni $value}]
+ }
+ :log "enumeration CORRECT? '$value' <$a> $v == $a => ${:correction}"
+ }
+ return [expr {0 ni ${:correction} ? 1 : -1}]
+ }
+ }
+
enumeration instproc pretty_value {v} {
if {[info exists :category_label($v)]} {
return [set :category_label($v)]
@@ -2578,6 +2718,7 @@
}
}
}
+
enumeration instproc config_from_category_tree {tree_name} {
# Get the options of a select or radio from the specified
# category tree.
@@ -2590,7 +2731,8 @@
#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] \
+ 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,
@@ -2670,7 +2812,8 @@
###########################################################
Class create checkbox -superclass enumeration -parameter {
- {horizontal false}
+ {horizontal:boolean false}
+ {richtext:boolean false}
}
checkbox instproc initialize {} {
set :multiple true
@@ -2686,7 +2829,6 @@
# - view mode: the fields were deactivated (made insensitive);
# this means: keep the old value
- #:msg "${:name} disabled=[info exists :disabled]"
if {[info exists :disabled]} {
return $default
} else {
@@ -2701,24 +2843,99 @@
type checkbox \
name ${:name}
- foreach o ${:options} {
+ set answer [expr {[info exists :evaluated_answer_result] ? ${:answer} : ""}]
+ set CSSclasses {"" "" t correct f incorrect}
+
+ foreach o ${:options} a $answer {
lassign $o label rep
set id ${:id}:$rep
set atts [list {*}$base_atts id $id value $rep]
if {$rep in $value} {lappend atts checked checked}
-
- set label_class [expr {${:horizontal} ? "checkbox-inline" : ""}]
+ set label_class [dict get $CSSclasses $a]
+ if {${:horizontal}} {append label_class " checkbox-inline"}
::html::label -for $id -class $label_class {
::html::input $atts {}
- ::html::t " $label "
+ if {${:richtext}} {
+ ::html::div -class richtext-label {
+ ::html::t -disableOutputEscaping $label
+ }
+ } else {
+ ::html::t " $label "
+ }
}
if {!${:horizontal}} {
html::br
}
}
}
+ ###########################################################
+ #
+ # ::xowiki::formfield::text_fields
+ #
+ ###########################################################
+ Class create text_fields -superclass {CompoundField ShuffleField} -parameter {
+ } -ad_doc {
+
+ Provide multiple text and short text entries. This field is a
+ compound field which create for every text field a sub
+ component. When the components are rendered, the items can be
+ shuffled.
+
+ }
+
+ text_fields instproc initialize {} {
+
+ next
+ set fields {}
+ set answers [expr {[info exists :answer] ? ${:answer} : ""}]
+ foreach option ${:options} a $answers {
+ lassign $option text rep
+ lappend fields [list $rep "text,correct_when=[::xowiki::formfield::FormField fc_encode $a],disabled=${:disabled}"]
+ }
+
+ #:log "TEXT text_fields fields <$fields>"
+ :create_components $fields
+ #:log "TEXT text_fields components <${:components}>"
+
+ }
+
+ text_fields instproc answer_is_correct {} {
+ :log "text_fields CORRECT? ${:name}"
+ foreach c ${:components} {
+ $c set_feedback [${:object} set __feedback_mode]
+ }
+ return 0
+ }
+
+ text_fields instproc get_text_entry {componentName} {
+ set wantedRep [lindex [split $componentName .] end]
+ foreach option ${:options} {
+ lassign $option text rep
+ if {$rep eq $wantedRep} {
+ return $text
+ }
+ }
+ return ""
+ }
+
+ text_fields instproc render_input {} {
+ #
+ # Render content within in a fieldset, but with labels etc.
+ #
+ html::ul [:get_attributes id {CSSclass class}] {
+ foreach c ${:components} {
+ html::li {
+ html::t -disableOutputEscaping [:get_text_entry [$c name]]
+ $c render
+ #:log [$c serialize]
+ }
+ }
+ }
+ }
+
+
###########################################################
#
# ::xowiki::formfield::select