Index: openacs-4/packages/xowf/tcl/test-item-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowf/tcl/test-item-procs.tcl,v diff -u -r1.7.2.3 -r1.7.2.4 --- openacs-4/packages/xowf/tcl/test-item-procs.tcl 4 Jul 2019 18:01:25 -0000 1.7.2.3 +++ openacs-4/packages/xowf/tcl/test-item-procs.tcl 15 Oct 2019 21:24:26 -0000 1.7.2.4 @@ -17,29 +17,58 @@ next } -} -namespace eval ::xowiki::formfield { + ########################################################### + # + # ::xowiki::formfield::TestItemField + # + ########################################################### + Class create TestItemField -superclass FormGeneratorField -parameter { + {feedback_level full} + {auto_correct:boolean false} + } -ad_doc { + Abstract class for defining common attributes for all Test Item + fields. + + @param feedback_level "full", or "none" + @param auto_correct boolean to let user add auto correction fields + } + TestItemField set abstract 1 + + ########################################################### # # ::xowiki::formfield::test_item # ########################################################### - Class create test_item -superclass FormGeneratorField -parameter { + Class create test_item -superclass TestItemField -parameter { {question_type mc} {nr_choices 5} - {feedback_level full} + {grading exact} + } -ad_doc { + + Wrapper for complex test items, containing specification for + minutes, grading scheme, feedback levels, handling different types + of questions ("interactions" in the terminology of QTI). When such + a question is saved, a HTML form is generated, which is used as a + question. + + @param feedback_level "full", or "none" + @param grading one of "exact", "partial", or "none" + @param nr_choices number of choices + @param question_type "mc", "sc", "ot", or "te" } - + # # 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 set xinha(javascript) [::xowiki::formfield::FormField fc_encode { + xinha_config.toolbar = [ + ['popupeditor', 'bold','italic','createlink','insertimage','separator'], + ['killword','removeformat','htmlmode'] + ]; }] + test_item set richtextWidget {richtext,editor=ckeditor4,ck_package=standard,extraPlugins=} test_item instproc feed_back_definition {auto_correct} { # @@ -48,90 +77,101 @@ # what's wrong, we can't provide different feedback for right or # wrong. # - :instvar inplace feedback_level - if {$feedback_level eq "none"} { + if {${:feedback_level} eq "none"} { return "" } - set widget "richtext,editor=ckeditor4,height=150px" + set widget [test_item set richtextWidget] if {$auto_correct} { return [subst { - {feedback_correct {$widget,label=#xowf.feedback_correct#}} - {feedback_incorrect {$widget,label=#xowf.feedback_incorrect#}} + {feedback_correct {$widget,height=150px,label=#xowf.feedback_correct#}} + {feedback_incorrect {$widget,height=150px,label=#xowf.feedback_incorrect#}} }] } return [subst { - {feedback {$widget,label=#xowf.feedback#}} + {feedback {$widget,label=Korrekturhinweis}} }] } # - # test_item is the wrapper for interaction to be used in + # "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 + if {${:__state} ne "after_specs"} { + return + } set options "" # # Provide some settings for name short-cuts # - switch -- [:question_type] { + switch -- ${:question_type} { mc { # we should support as well: minChoices, maxChoices, shuffle set interaction_class mc_interaction set options nr_choices=[:nr_choices] + set auto_correct true } sc { # we should support as well: minChoices, maxChoices, shuffle set interaction_class mc_interaction set options nr_choices=[:nr_choices],multiple=false + set auto_correct true } - ot { set interaction_class text_interaction } - default {error "unknown question type: [:question_type]"} + ot { + set interaction_class text_interaction + set auto_correct ${:auto_correct} + } + te { + set interaction_class text_entry_interaction + #set options nr_choices=[:nr_choices] + set auto_correct ${:auto_correct} + } + 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 - + :log test_item-auto_correct=$auto_correct # - # handle feedback_level + # 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 + set :feedback_level $feedback_level_property } } - # + if {${:grading} ne "none"} { + if {${:grading} ni {exact partial}} { + error "invalid grading '$grading'; valid are 'exact' or 'partial'" + } + set options "{exact exact} {partial partial}" + set gradingSpec [subst {grading {select,options=$options,default=${:grading},label=#xowf.Grading-Schema#}}] + } else { + set gradingSpec "" + } + :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}} + {minutes number,min=1,default=2,label=#xowf.Minutes#} + $gradingSpec + {interaction {$interaction_class,$options,feedback_level=${:feedback_level},auto_correct=${:auto_correct}}} [: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} + Class create mc_interaction -superclass TestItemField -parameter { {shuffle false} {nr_choices 5} {multiple true} @@ -158,7 +198,6 @@ 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 # @@ -169,9 +208,10 @@ # # create component structure # + set widget [test_item set richtextWidget] :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}} + {text {$widget,required,height=150px,label=#xowf.exercise-text#}} + {mc {mc_choice,feedback_level=${:feedback_level},label=#xowf.alternative#,multiple=[:multiple],repeat=1..${:nr_choices}}} }] set :__initialized 1 } @@ -181,16 +221,16 @@ # 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 @@ -272,9 +311,7 @@ # ########################################################### - Class create mc_choice -superclass FormGeneratorField -parameter { - {feedback_level full} - {inplace true} + Class create mc_choice -superclass TestItemField -parameter { {multiple true} } @@ -295,21 +332,23 @@ } else { set feedback_fields "" } + + set widget [test_item set richtextWidget] if {[:multiple]} { - # We are in a multiple choice item; provide for editing a radio + # We are in a multiple-choice item; provide for editing a radio # group per alternative. :create_components [subst { - {text {richtext,editor=ckeditor4,$text_config}} + {text {$widget,$text_config}} {correct {boolean,horizontal=true,label=#xowf.correct#}} $feedback_fields }] } else { - # We are in a single choice item; provide for editing a single + # 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}} + {text {$widget,$text_config}} {correct {radio,label=#xowf.correct#,forced_name=$groupname.correct,options={"" ${:name}}}} $feedback_fields }] @@ -325,24 +364,29 @@ # ########################################################### - Class create text_interaction -superclass FormGeneratorField -parameter { - {feedback_level full} - {inplace true} + Class create text_interaction -superclass TestItemField -parameter { } - text_interaction set auto_correct false + #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 component structure. # - # "inplace" is ignored + set widget [test_item set richtextWidget] + + if {${:auto_correct}} { + set autoCorrectSpec {{correct_when {text,label=#xowf.correct_when#}}} + } else { + set autoCorrectSpec "" + } + :create_components [subst { - {text {richtext,required,editor=ckeditor4,height=150px,label=#xowf.exercise-text#,plugins=OacsFs}} - {lines {numeric,default=10,size=3,label=#xowf.lines#}} - {columns {numeric,default=60,size=3,label=#xowf.columns#}} + {text {$widget,label=#xowf.exercise-text#,plugins=OacsFs}} + {lines {number,min=1,default=10,label=#xowf.answer_lines#}} + {columns {number,min=1,max=80,default=60,label=#xowf.answer_columns#}} + $autoCorrectSpec }] set :__initialized 1 } @@ -351,51 +395,175 @@ set intro_text [:get_named_sub_component_value text] set lines [:get_named_sub_component_value lines] set columns [:get_named_sub_component_value columns] + + if {${:auto_correct}} { + set correct_when [:get_named_sub_component_value correct_when] + set correct_when [::xowiki::formfield::FormField fc_encode correct_when=$correct_when], + #ns_log notice "correct_when <$correct_when>" + + } else { + set correct_when "" + } + append form \ "