# -*- Tcl -*- # # Workflow template for answering online exams. The workflow is # typically controlled from a parent workflow that a teacher can use # to create the exam, to try it out and to publish it # (oneline-exam.wf). # # This workflow is similar to the classical "iterate.wf" but is more # configurable (the answer forms are passed via template # variables). The workflow uses a form-loader which renames the input # fields to avoid potential name clashes. # # Template variables: # @wfTitle@ # @wfQuestionNames@ # @wfQuestionTitles@ # @wfID@ my set autoname 1 my set debug 1 set pages [list @wfQuestionNames@] set titles [list @wfQuestionTitles@] ######################################################################## # # Properties # # pages: the form pages used as inout forms # position: the current page in the exam # return_url: when the exam is finished, the user proceeds to this url # try_out_mode: a teacher can try the exam in this mode # current_form: used internally to keep the current form # ip: ip address of the user, kept in the instance attribute as record # ######################################################################## Property pages -default $pages Property titles -default $titles Property position -default 0 -allow_query_parameter true Property return_url -default "" -allow_query_parameter true Property try_out_mode -default 0 -allow_query_parameter true Property current_form -default "" Property ip -default [expr {[ns_conn isconnected] ? [ad_conn peeraddr] : "nowhere"}] Condition more_ahead \ -expr {[$obj property position] < [llength [$obj property pages]]-1} Condition more_before \ -expr {[$obj property position] > 0} set page_count 1 set page_actions {} foreach page $pages { Action $page_count \ -next_state working \ -label "$page_count" \ -proc activate {obj} [list my goto_page [expr {$page_count -1}]] lappend page_actions $page_count incr page_count } ######################################################################## # # Action definitions # ######################################################################## Action allocate -proc activate {obj} { #my msg "allocate $obj" # Called, when we try to create or use a workflow instance # via a workflow definition ($obj is a workflow definition) $obj set_property -new 1 name ___[::xo::cc set untrusted_user_id] } Action initialize -proc activate {obj} { # called, after workflow instance was created $obj set_property -new 1 _title "@wfTitle@" set parent_id [$obj parent_id] set package_id [$obj package_id] # make sure to create the parent (the controlling workflow) ::xo::db::CrClass get_instance_from_db -item_id $parent_id set parent_state [$parent_id state] # # Don't allow one to enter values when the state of the master workflow # is not published (e.g. trial mode, or closed) or when try-out-mode # is not set # if {$parent_state ne "published" && [$obj property try_out_mode 0] == 0} { #my msg "LOCKED" set current_state [$obj property _state] set lockin_state [expr {$current_state eq "initial" ? "initial" : "done"}] set lockin_msg(initial) "Die Prüfung ist von der Aufsicht nicht freigegeben!" set lockin_msg(done) "Die Prüfungszeit ist abgelaufen!" foreach a [Action info instances] { if {[namespace tail $a] eq "logout"} continue $a next_state $lockin_state $a proc activate {obj} [list util_user_message -message $lockin_msg($lockin_state)] $a set_property position 0 $a set_property current_form "" } } else { #my msg "not LOCKED" } } Action instproc goto_page {position} { set pages [my property pages] my set_property position $position my set_property current_form [lindex $pages $position] } Action instproc set_page {increment} { set pages [my property pages] set position [my property position 0] incr position $increment if {$position < 0} { set position 0 } elseif {$position >= [llength $pages]} { set position [expr {[llength $pages] - 1}] } my set_property position $position my set_property current_form [lindex $pages $position] } Action prev \ -next_state working \ -label "Vorherige Frage" \ -proc activate {obj} {my set_page -1} Action next \ -next_state working \ -label "Nächste Frage" \ -proc activate {obj} {my set_page 1} Action abgabe \ -next_state done \ -label "Abgabe" Action save \ -label "Antwort zwischenspeichern" Action logout \ -label "Prüfung verlassen" \ -proc activate {obj} { set pid [$obj package_id] set try_out_mode [$obj property try_out_mode 0] set return_url [$obj property return_url .] #my msg "tryout $try_out_mode return_url $return_url" if {$try_out_mode} { ad_returnredirect $return_url } else { ::xo::cc set_parameter return_url /register/logout?return_url=$return_url } } Action start \ -next_state working \ -label Beginnen \ -proc activate {obj} { $obj set_property position 0 $obj set_property current_form [lindex [$obj property pages] 0] } Action start_again \ -label "Erste Frage" \ -next_state working -proc activate {obj} { $obj set_property position 0 $obj set_property current_form [lindex [$obj property pages] 0] } ######################################################################## # # State definitions # ######################################################################## State parameter { {view_method edit} {extra_js { /resources/xowiki/jquery/jquery.js ../file:seal.js?m=download }} {extra_css { ../file:seal.js?m=download }}} State working working set page_actions $page_actions working proc actions {} { set actions "" if {[more_before]} {lappend actions prev} set actions [concat $actions [my set page_actions]] if {[more_ahead]} {lappend actions next} lappend actions save abgabe } State initial \ -actions {start logout} \ -form "../en:exam-start" set done_actions [concat $page_actions {start_again logout}] State done \ -actions $done_actions \ -form "../en:exam-done" \ -form_loader summary_form :object-specific { set ctx [:wf_context] set working_state_object [$ctx wf_definition_object working] $working_state_object set form [:property current_form] # fallback if the current_form isn't set if {[$working_state_object set form] eq ""} { $working_state_object set form [lindex [:property pages] 0] } ######################################################################## # # Helper methods for the workflow context # ######################################################################## # # Overload default form loader to rename the input fields # to avoid name clashes # $ctx proc default_load_form_id {form_name} { #my msg "renaming_form_loader $form_name" set form_id [next] ::xo::db::CrClass get_instance_from_db -item_id $form_id set form [$form_id get_property -name form] set prefix [lindex [split [$form_id name] :] end]-a set counter 0 set fc [my get_form_constraints] lappend fc @cr_fields:hidden dom parse -simple -html $form doc $doc documentElement root if {$root ne ""} { $root setAttribute id "online-exam-answer" foreach node [$root selectNodes "//textarea|//input"] { set newName $prefix[incr counter] $node setAttribute name $newName #lappend fc $newName:richtext,editor=xinha,slim=true } $form_id set_property form [$root asHTML] } # Currently, the computation and setting of the form_constraints has # no effect, when the input field is provided raw in the form # (e.g. as a handcoded textarea). We set it anyhow here for future # use $form_id set_property -new 1 form_constraints $fc my set_title -question 1 return $form_id } # # set title with question and user information # $ctx proc set_title {{-question 1}} { set t [list ] set state [${:object} state] set position [${:object} property position] if {$question && $state eq "working"} {lappend title "Frage [expr {$position + 1}] [lindex [${:object} property titles] $position]"} lappend title \ "@wfTitle@" \ "IP: [${:object} property ip]" ${:object} title [join $title " / "] } # # Form loader for summary # $ctx proc summary_form {form_title} { #my msg "summary_form_loader $form_title" my set_title -question 0 set state [${:object} property _state] set summary_form "" set counter 0 foreach form_name [${:object} property pages] { set form_id [my default_load_form_id $form_name] set title [lindex [${:object} property titles] $counter] append summary_form "

Frage [incr counter]: $title

" \n append summary_form [$form_id property form] \n
\n } # disable all input fields and remove wrapping form regsub -all {