Index: openacs-4/packages/xowf/resources/prototypes/TestItemComposite.form.page
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xowf/resources/prototypes/TestItemComposite.form.page,v
diff -u -r1.1.2.1 -r1.1.2.2
--- openacs-4/packages/xowf/resources/prototypes/TestItemComposite.form.page 8 Jul 2021 20:54:50 -0000 1.1.2.1
+++ openacs-4/packages/xowf/resources/prototypes/TestItemComposite.form.page 29 Jul 2021 12:47:36 -0000 1.1.2.2
@@ -1,7 +1,7 @@
# -*- tcl-*-
::xowiki::Form new \
-name en:TestItemComposite.form \
- -title "ShortTextItem" \
+ -title "CompositeItem" \
-anon_instances f \
-text {} \
-form {{
} text/html} \
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.151 -r1.7.2.152
--- openacs-4/packages/xowf/tcl/test-item-procs.tcl 15 Jul 2021 13:17:49 -0000 1.7.2.151
+++ openacs-4/packages/xowf/tcl/test-item-procs.tcl 29 Jul 2021 12:47:37 -0000 1.7.2.152
@@ -274,7 +274,12 @@
set can_shuffle false
set typeSpecificComponentSpec {{max_nr_submission_files {number,form_item_wrapper_CSSclass=form-inline,min=1,default=1,label=Maximale Anzahl von Abgaben}}}
}
-
+ section {
+ set interaction_class test_section
+ set options ""
+ set auto_correct false
+ set can_shuffle false
+ }
default {error "unknown question type: ${:question_type}"}
}
:log test_item-auto_correct=$auto_correct
@@ -314,9 +319,27 @@
} else {
set shuffleSpec ""
}
+
+ if {${:question_type} eq "section"} {
+ #
+ # Don't show "minutes" and "points" in the composite test item
+ # form but still define it, such we can compute and update it in
+ # convert_to_internal with little effort, since all "question"
+ # content is built based on included form fields.
+ #
+ set pointsSpec {
+ {minutes hidden}
+ {points hidden}
+ }
+ } else {
+ set pointsSpec {
+ {minutes number,form_item_wrapper_CSSclass=form-inline,min=1,default=2,label=#xowf.Minutes#}
+ {points number,form_item_wrapper_CSSclass=form-inline,min=0.0,step=0.1,label=#xowf.Points#}
+ }
+ }
+
:create_components [subst {
- {minutes number,form_item_wrapper_CSSclass=form-inline,min=1,default=2,label=#xowf.Minutes#}
- {points number,form_item_wrapper_CSSclass=form-inline,min=0.0,step=0.1,label=#xowf.Points#}
+ $pointsSpec
$shuffleSpec
$gradingSpec
{twocol boolean_checkbox,horizontal=true,label=#xowf.Twocol_layout#,default=f,form_item_wrapper_CSSclass=form-inline}
@@ -572,14 +595,6 @@
set twocol [:twocol_layout]
append form \
"\n"
- append fc \
- "@categories:off @cr_fields:hidden\n" \
- "{answer:[:dict_to_fc -type textarea $fc_dict]}"
#ns_log notice "text_interaction $form\n$fc"
${:object} set_property -new 1 form $form
@@ -661,6 +676,7 @@
dict set fc_dict answer $answer
dict set fc_dict descriptions $solution
dict set fc_dict render_hints $render_hints
+ dict set fc_dict substvalues $substvalues
set twocol [:twocol_layout]
append form \
@@ -994,10 +1010,26 @@
#
###########################################################
- Class create test_section -superclass {form_page} -parameter {
+ Class create test_section -superclass {TestItemField} -parameter {
{multiple true}
+ {form en:edit-interaction.wf}
}
+ test_section instproc initialize {} {
+
+ if {${:__state} ne "after_specs"} {
+ return
+ }
+ next
+ set widget [test_item set richtextWidget]
+ :create_components [subst {
+ {text {$widget,height=150px,label=#xowf.exercise-text#,plugins=OacsFs}}
+ {selection {form_page,form=en:edit-interaction.wf,multiple=true}}
+ }]
+
+ set :__initialized 1
+ }
+
test_section instproc pretty_value {v} {
return [${:object} property form ""]
}
@@ -1007,86 +1039,92 @@
# 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 the
- # prefix for the form-fields. This method must be most likely
- # extended for other question types.
+ # the form constraints.
#
- set form "\n"
+
+ ns_log notice "AGGREGATED FORM $aggregatedForm\nFC\n$aggregatedFC\n"
+
+ #
+ # Automatically compute the minutes and points of the composite
+ # field and update the form field.
+ #
+ set total_minutes [::xowf::test_item::question_manager total_minutes $question_infos]
+ set total_points [::xowf::test_item::question_manager total_points $question_infos]
+
+ [${:parent_field} get_named_sub_component minutes] value $total_minutes
+ [${:parent_field} get_named_sub_component points] value $total_points
+
+ append form \
+ "\n"
+
${:object} set_property -new 1 form $form
- ${:object} set_property -new 1 form_constraints $fc
+ ${:object} set_property -new 1 form_constraints $aggregatedFC
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
- #:msg "fc=$fc"
}
}
+
############################################################################
# Generic Assement interface
############################################################################
@@ -1257,10 +1295,11 @@
set fc [$form_obj get_property -name form_constraints]
#
- # Map "answer" to a generic name in the form "@answer@" and in the
- # form constraints.
+ # Map "answer" to a generic name "@answer@" in the form and in
+ # the form constraints.
#
set newName [:form_name_based_attribute_stem [$form_obj name]]
+ #ns_log notice "renaming form loader: MAP '[$form_obj name]' -> '$newName'"
regsub -all -- {@answer} $form @$newName form
set fc [:map_form_constraints $fc "answer" $newName]
@@ -3730,6 +3769,9 @@
# - exam_target_time
# - exam_base_time
#
+ # - percent_substitute_in_form
+ # - item_substitute_markup
+ #
# - describe_form
# - exam_summary
# - question_info_block
@@ -3996,31 +4038,27 @@
return $result
}
- :public method item_substitute_markup {
+ :public method percent_substitute_in_form {
-obj:object
- {-position:integer 0}
-form_obj:object
- {-do_substitutions:switch 1}
+ -position:integer
+ html
} {
#
- # Substitute everything item-specific in the text, including
- # markup (handling e.g. images resolving in the context of the
- # original question) and also percent-substitutions
+ # Perform percent substitution in the provided HTML,
+ # form_constraints and disabled_form_constraints and return the
+ # result as a dict.
#
- :assert_answer_instance $obj
- $obj do_substitutions $do_substitutions
- set html [$obj substitute_markup \
- -context_obj $form_obj \
- [$form_obj property form]]
- set fc [$form_obj property form_constraints]
- set dfc [$form_obj property disabled_form_constraints]
set form_name [$form_obj name]
set seed [lindex [$obj property seeds] $position]
-
- #ns_log notice "CHECK-AA $form_name seed <$seed> // seeds <[$obj property seeds]>"
set substvalues [$form_obj property substvalues]
+ #ns_log notice "CHECK-AA $form_name seed <$seed> // seeds <[$obj property seeds]> // subs '$substvalues'"
+
+ set fc [$form_obj property form_constraints]
+ set dfc [$form_obj property disabled_form_constraints]
+
if {$seed eq "" && $substvalues ne ""} {
- ns_log warning "item_substitute_markup cannot substitute percent variables in $form_name"
+ ns_log warning "percent_substitute_in_form cannot substitute percent variables in $form_name"
} else {
if {$substvalues ne ""} {
set html [:percent_substitute \
@@ -4040,6 +4078,38 @@
return [list form $html form_constraints $fc disabled_form_constraints $dfc]
}
+ :public method item_substitute_markup {
+ -obj:object
+ -form_obj:object
+ {-position:integer}
+ {-do_substitutions:switch 1}
+ } {
+ #
+ # Substitute everything item-specific in the text, including
+ # markup (handling e.g. images resolving in the context of the
+ # original question) and also percent-substitutions (if
+ # desired).
+ #
+ ns_log notice "=== item_substitute_markup [$form_obj name] do percent subst [info exists position]"
+ :assert_answer_instance $obj
+ $obj do_substitutions $do_substitutions
+ set html [$obj substitute_markup \
+ -context_obj $form_obj \
+ [$form_obj property form]]
+
+ if {[info exists position]} {
+ return [:percent_substitute_in_form \
+ -obj $obj \
+ -form_obj $form_obj \
+ -position $position \
+ $html]
+ } else {
+ set fc [$form_obj property form_constraints]
+ set dfc [$form_obj property disabled_form_constraints]
+ return [list form $html form_constraints $fc disabled_form_constraints $dfc]
+ }
+ }
+
:public method disallow_paste {form_obj:object} {
#
# This function changes the form_constraints of the provided
@@ -4083,6 +4153,7 @@
{-titleless_form:switch false}
{-obj:object}
{-user_answers:object,0..1 ""}
+ {-no_position:switch false}
form_objs
} {
#
@@ -4099,6 +4170,9 @@
set randomizationOk 1
set autoGrade 1
foreach form_obj $form_objs number $numbers {
+ #if {[info exists fixed_position]} {
+ # set position $fixed_position
+ #}
set form_obj [::xowf::test_item::renaming_form_loader rename_attributes $form_obj]
set form_title [$form_obj title]
set minutes [:question_property $form_obj minutes]
@@ -4137,28 +4211,34 @@
append full_form \
"$title
\n"
}
+
#
- # Resolve links in the context of the resolve_object
+ # The flag "no_position" is just provided for the composite
+ # form, since we are called there at form generation time,
+ # where the position is different from the position in the
+ # questionnairee. When the position is fixed, we do not provide
+ # it as an argument. As a consequence, the percent
+ # substitution is not performed, since it would return always
+ # very similar values based on the fixed position.
#
-
+ if {$no_position} {
+ set positionArg {}
+ } else {
+ set positionArg [list -position $position]
+ }
#ns_log notice "CHECK 0 user_answers <$user_answers> (obj is the inclass exam [$obj name])"
if {$user_answers eq ""} {
set user_answers $obj
}
+ #
+ # Resolve links in the context of the resolve_object
+ #
set d [:item_substitute_markup \
-obj $user_answers \
- -position $position \
+ {*}$positionArg \
-form_obj $form_obj]
append full_form [dict get $d form]
- #ns_log notice "CHECK [$obj serialize]"
- #ns_log notice "CHECK obj $obj form_obj $form_obj parent_obj [$obj parent_id]"
-
- #append full_form \
- # [$form_obj substitute_markup -context_obj $form_obj [$form_obj property form]]
-
- #ns_log notice "FORM=$full_form"
-
lappend title_infos [list full_title $title \
title $form_title \
minutes $minutes \
@@ -4168,12 +4248,12 @@
-fc [dict get $d form_constraints] \
-minutes $minutes \
-points $points \
- -position $position]
+ {*}$positionArg]
lappend full_disabled_fc [:add_to_fc \
-fc [dict get $d disabled_form_constraints] \
-minutes $minutes \
-points $points \
- -position $position]
+ {*}$positionArg]
incr position
set formAttributes [$form_obj instance_attributes]