Index: openacs-4/packages/xowf/lib/inclass-exam-answer.wf =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowf/lib/Attic/inclass-exam-answer.wf,v diff -u -r1.1.2.39 -r1.1.2.40 --- openacs-4/packages/xowf/lib/inclass-exam-answer.wf 2 May 2021 11:06:57 -0000 1.1.2.39 +++ openacs-4/packages/xowf/lib/inclass-exam-answer.wf 25 May 2021 20:08:20 -0000 1.1.2.40 @@ -227,23 +227,27 @@ return [done_form_loader $ctx $form_name] } - set item_nr [$obj property position] + set item_nr [:current_position $obj] + #:msg "working_form_loader item_nr $item_nr [$obj instance_attributes]" set parent_id [$obj parent_id] - #:msg "working_form_loader item_nr $item_nr [$obj instance_attributes]" set parent_obj [::xo::db::CrClass get_instance_from_db -item_id $parent_id] # # In case shuffling is required, fetch via the shuffled position. # + #:msg "============ working_form_loader load form on pos $position" + set shuffle_id [expr {[$parent_obj property shuffle_items 0] ? [$obj creation_user] : -1}] set position [${:QM} shuffled_index -shuffle_id $shuffle_id $parent_obj $item_nr] - #:msg "============ working_form_loader load form on pos $position" + #ns_log notice "============ working_form_loader: position based on item_nr $item_nr and shuffle $shuffle_id -> $position" # # Load the form. # set form_obj [${:QM} nth_question_obj $parent_obj $position] + #ns_log notice "load form => $form_obj (position $position [$form_obj name])" + # # Substitute markup in the constant part of the form in the context # of the original form object, setting the resolve context in the @@ -257,6 +261,13 @@ $form_obj set_property form [dict get $d form] # + # Add __current_item_nr as hidden form field to detect and handle + # cases, where actual form-data divergates from data in the + # database. + # + $obj proc extra_html_fields {} [list ::html::input -type hidden -name __current_item_nr -value $item_nr] + + # # Update IP address each time the form is loaded. # if {[$obj state] in {"initial" "working"}} { @@ -268,13 +279,20 @@ # :set_title $obj -position $position -item_nr $item_nr -for_question -with_minutes + ns_log notice "============ working_form_loader: set title -position $position -item_nr $item_nr " + # # Disallow paste if required # if {![$parent_obj property allow_paste true]} { ${:QM} disallow_paste $form_obj } + #$form_obj lappend form_constraints {__item_nr:hidden} + + #ns_log notice "============ working_form_loader: [$form_obj serialize] " + ns_log notice "============ working_form_loader returns [$form_obj name] " + return $form_obj } @@ -343,7 +361,7 @@ #ns_log notice "SETTING $obj title [join $title { · }]" $obj title [join $title " · "] #:msg title=[join $title " · "] - + #:msg set_title-set_parameter-MenuBar-[$obj state] :plain_template -prevent_multiple_tabs $prevent_multiple_tabs $obj @@ -385,7 +403,7 @@ # active, and is the feature set in the workflow parameters? # if {$prevent_multiple_tabs && [info exists :prevent_multiple_tabs] && ${:prevent_multiple_tabs}} { - ns_log notice "!!! prevent multiple tabs" + #ns_log notice "!!! prevent multiple tabs" xowf::test_item::answer_manager prevent_multiple_tabs -cookie_name "tab_counter_[$obj item_id]" } } @@ -435,6 +453,27 @@ -form_constraints $summary_fc] } +:proc current_position {obj} { + if {[$obj form_parameter __form_action ""] eq "save-form-data"} { + # + # In case there was an mutual overwrite, the position as provided + # by the instance attributes might deviate from the position, + # based on which the actual form data was generated. So, for + # validating and updating one has to change the position to the + # one from the form data (when this differs). Note, that the + # randomizer depends on property "position" as well. + # + set current_item_nr [$obj form_parameter __current_item_nr] + set position [$obj property position] + if {$current_item_nr ne "" && $current_item_nr ne $position} { + ns_log warning "working_form_loader: position provided by form differs from stored data." \ + "Use position from form data $current_item_nr instead of $position" + $obj set_property position $current_item_nr + } + } + return [$obj property position] +} + :proc addSignature {obj} { set answerAttributes [xowf::test_item::renaming_form_loader \ answer_attributes [$obj instance_attributes]] @@ -495,7 +534,9 @@ # user, which is not necessarily the nth question in the list of # questions due to shuffling. # - set current_position [:property position] + set current_position0 [:property position] + set current_position [$container current_position [self]] + ns_log notice "============ object-specific old current_position $current_position0 new current_position $current_position" set actions {} if {${:state} ne "done"} { @@ -570,6 +611,19 @@ ns_return 200 text/plain OK ad_script_abort } + + # + # Do NOT allow edits from multiple browser instances or tabs. + # + :proc mutual_overwrite_occurred {} { + next + ns_log warning "mutual_overwrite_occurred [self] ${:name}: user [::xo::cc user_id] => auto-close window" + template::add_body_script -script [subst { + alert('Not allowed to have two browser instances or tabs open!'); + window.open("about:blank", "_self").close(); + }] + } + }