:::xo::db::require package xowiki namespace eval ::xowiki::formfield { ########################################################### # # ::xowiki::formfield::FormGeneratorField # ########################################################### Class create FormGeneratorField -superclass CompoundField -parameter { } FormGeneratorField set abstract 1 FormGeneratorField instproc pretty_value {v} { return [${:object} property form ""] } FormGeneratorField instproc render_input {} { ::xo::Page requireCSS /resources/xowf/myform.css next } } namespace eval ::xowiki::formfield { ########################################################### # # ::xowiki::formfield::test_item # ########################################################### Class create test_item -superclass FormGeneratorField -parameter { {question_type mc} {nr_choices 5} {feedback_level full} } # # provide a default setting for xinha JavaScript for test-items # test_item set xinha(javascript) [::xowiki::formfield::FormField fc_encode { xinha_config.toolbar = [ ['popupeditor', 'bold','italic','createlink','insertimage','separator'], ['killword','removeformat','htmlmode'] ]; }] test_item instproc feed_back_definition {auto_correct} { # # Return the definition of the feed_back widgets depending on the # value of auto_correct. If we can't determine automatically, # what's wrong, we can't provide different feedback for right or # wrong. # :instvar inplace feedback_level if {$feedback_level eq "none"} { return "" } set widget "richtext,editor=ckeditor4,height=150px" if {$auto_correct} { return [subst { {feedback_correct {$widget,label=#xowf.feedback_correct#}} {feedback_incorrect {$widget,label=#xowf.feedback_incorrect#}} }] } return [subst { {feedback {$widget,label=#xowf.feedback#}} }] } # # test_item is the wrapper for interaction to be used in # evaluations. Different wrapper can be defined in a similar way for # questionairs, which might need less input fields. # test_item instproc initialize {} { if {${:__state} ne "after_specs"} return :instvar inplace feedback_level set options "" # # Provide some settings for name short-cuts # switch -- [:question_type] { mc { # we should support as well: minChoices, maxChoices, shuffle set interaction_class mc_interaction set options nr_choices=[:nr_choices] } sc { # we should support as well: minChoices, maxChoices, shuffle set interaction_class mc_interaction set options nr_choices=[:nr_choices],multiple=false } ot { set interaction_class text_interaction } default {error "unknown question type: [:question_type]"} } set auto_correct [expr {[$interaction_class exists auto_correct] && [$interaction_class set auto_correct] == false ? 0 : 1}] # For the time being, we set inplace to false, otherwise we can't # currently edit empty fields set inplace true # # handle feedback_level # # The object might be a form, just use the property, if we are on # a FormPage. if {[${:object} istype ::xowiki::FormPage]} { set feedback_level_property [${:object} property feedback_level] if {$feedback_level_property ne ""} { set feedback_level $feedback_level_property } } # :create_components [subst { {minutes numeric,size=2,label=#xowf.Minutes#} {grading {select,options={exact exact} {partial partial},default=exact,label=#xowf.Grading-Schema#}} {interaction {$interaction_class,$options,feedback_level=$feedback_level,inplace=$inplace}} [:feed_back_definition $auto_correct] }] set :__initialized 1 } } namespace eval ::xowiki::formfield { ########################################################### # # ::xowiki::formfield::mc_interaction # ########################################################### Class create mc_interaction -superclass FormGeneratorField -parameter { {feedback_level full} {inplace false} {shuffle false} {nr_choices 5} {multiple true} } mc_interaction instproc set_compound_value {value} { set r [next] if {![:multiple]} { # For single choice questions, we have a fake-field for denoting # the correct entry. We have to distribute this to the radio # element, which is rendered. set correct_field_name [:get_named_sub_component_value correct] if {$correct_field_name ne ""} { foreach c [:components] { if {[$c name] eq $correct_field_name} { ${c}::correct value $correct_field_name } } } } return $r } mc_interaction instproc initialize {} { if {${:__state} ne "after_specs"} return test_item instvar {xinha(javascript) javascript} :instvar feedback_level inplace input_field_names nr_choices # # build choices # if {![:multiple]} { append choices "{correct radio,omit}\n" } # # create component structure # :create_components [subst { {text {richtext,required,height=150px,editor=ckeditor4,label=#xowf.exercise-text#}} {mc {mc_choice,feedback_level=$feedback_level,label=#xowf.alternative#,multiple=[:multiple],repeat=1..$nr_choices}} }] set :__initialized 1 } mc_interaction set auto_correct true mc_interaction instproc convert_to_internal {} { # # Build a form from the components of the exercise on the fly. # Actually, this methods computes the properties "form" and # "form_constraints" based on the components of this form field. # set form "
\n" #ns_log notice FORM=$form #ns_log notice FC=$fc ${:object} set_property -new 1 form $form ${:object} set_property -new 1 form_constraints $fc set anon_instances true ;# TODO make me configurable ${:object} set_property -new 1 anon_instances $anon_instances ${:object} set_property -new 1 auto_correct [[self class] set auto_correct] ${:object} set_property -new 1 has_solution true } ########################################################### # # ::xowiki::formfield::mc_choice # ########################################################### Class create mc_choice -superclass FormGeneratorField -parameter { {feedback_level full} {inplace true} {multiple true} } mc_choice instproc initialize {} { if {${:__state} ne "after_specs"} return if {1} { test_item instvar {xinha(javascript) javascript} set text_config [subst {height=100px,label=Text}] } else { set text_config [subst {editor=wym,height=100px,label=Text}] } if {[:feedback_level] eq "full"} { set feedback_fields { {feedback_correct {textarea,cols=60,label=#xowf.feedback_correct#}} {feedback_incorrect {textarea,cols=60,label=#xowf.feedback_incorrect#}} } } else { set feedback_fields "" } if {[:multiple]} { # We are in a multiple choice item; provide for editing a radio # group per alternative. :create_components [subst { {text {richtext,editor=ckeditor4,$text_config}} {correct {boolean,horizontal=true,label=#xowf.correct#}} $feedback_fields }] } else { # We are in a single choice item; provide for editing a single # radio group spanning all entries. Use as name for grouping # the form-field name minus the last segment. regsub -all {[.][^.]+$} [:name] "" groupname :create_components [subst { {text {richtext,editor=ckeditor4,$text_config}} {correct {radio,label=#xowf.correct#,forced_name=$groupname.correct,options={"" [:name]}}} $feedback_fields }] } set :__initialized 1 } } namespace eval ::xowiki::formfield { ########################################################### # # ::xowiki::formfield::text_interaction # ########################################################### Class create text_interaction -superclass FormGeneratorField -parameter { {feedback_level full} {inplace true} } text_interaction set auto_correct false text_interaction instproc initialize {} { if {${:__state} ne "after_specs"} return test_item instvar {xinha(javascript) javascript} :instvar feedback_level inplace input_field_names # # create component structure # :create_components [subst { {text {richtext,required,editor=ckeditor4,height=150px,label=#xowf.exercise-text#,plugins=OacsFs,javascript=$javascript,inplace=$inplace}} {lines {numeric,default=10,size=3,label=#xowf.lines#}} {columns {numeric,default=60,size=3,label=#xowf.columns#}} }] set :__initialized 1 } text_interaction instproc convert_to_internal {} { set form "\n" ${:object} set_property -new 1 form $form ${:object} set_property -new 1 form_constraints $fc set anon_instances true ;# TODO make me configurable ${:object} set_property -new 1 anon_instances $anon_instances ${:object} set_property -new 1 auto_correct [[self class] set auto_correct] ${:object} set_property -new 1 has_solution false } } namespace eval ::xowiki::formfield { ########################################################### # # ::xowiki::formfield::test_section # ########################################################### Class create test_section -superclass {form_page} -parameter { {multiple true} } test_section instproc pretty_value {v} { return [${:object} property form ""] } test_section instproc convert_to_internal {} { # # Build a complex form composed of the specified form pages names # contained in the value of this field. The form-fields have to # be renamed. This affects the input field names in the form and # the form constraints. We use the item-id contained pages as a the # prefix for the form-fields. This method must be most likely # extended for other question types. # set form "\n" ${:object} set_property -new 1 form $form ${:object} set_property -new 1 form_constraints $fc set anon_instances true ;# TODO make me configurable ${:object} set_property -new 1 anon_instances $anon_instances # for mixed test sections (e.g. text interaction and mc), we have # to combine the values of the items ${:object} set_property -new 1 auto_correct true ;# should be computed ${:object} set_property -new 1 has_solution true ;# should be computed #my msg "fc=$fc" } } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: