Index: openacs-4/contrib/misc/wizard-procs-doc.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/misc/wizard-procs-doc.html,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/contrib/misc/wizard-procs-doc.html 10 Jul 2003 16:30:52 -0000 1.1 @@ -0,0 +1,199 @@ + + +
+ +ex. + template::wizard create -action "wizard" -name my_wizard -params { + my_param1 my_param2 + } -steps { + 1 -label "Step 1" -url "step1" + 2 -label "Step 2" -url "step2" + 3 -label "Step 3" -url "step3" + } ++
Add the "template::wizard get_current_step" on wizard.tcl. + Make sure that you call any "template::wizard set_param" if needed before + calling get_current_step. get_current_step will redirect to the wizard -action + properly setting all -params value and its other needed http state vars
+ +Note: the wizard will rewrite the url always. Only self submitting forms + are preserved. Once the form is finished processing the wizard will take + over and rewrite the url.
+ex. + <include src="@wizard:current_url@"> ++
+ template::wizard submit myform -buttons {back next} ++ On the last step you may want to use the following on step3.tcl +
+ template::wizard submit myform -buttons {back next} ++ The following values are acceptable for the buttons: back, next and finish. + Back buttons are not rendered if the step is the first step, like wise next + buttons are not displayed if its the last step. Finish can appear on any step + and will finish the current wizard even if not all steps are done. +
+ <multiple name="wizard"> + <if "@wizard.id@" eq "wizard:current_id"> + @wizard.label@ - you are at this step <br> + </if> + <else> + @wizard.label@ <br> + </else> + </multiple> ++
Use "template::wizard set_param myparam_name" to set it. Normally you place + this in the steps of the wizard where the form has been processed. A param + is normally used when you want to reuse a value across the steps.
+ +Note: if you are to use "template::wizard set_param" on a wizard file ex. + (wizard.tcl). Make sure to do it before "template::wizard get_current_step". + So when "template::wizard get_current_step" redirects it will properly set + the correct values of the param to the new value. +
+ template::wizard create -action "wizard" -name my_wizard -params { + my_param1 my_param2 + } -steps { + 1 -label "Step 1" -url "step1" + 2 -label "Step 2" -url "step2" + 3 -label "Step 3" -url "step3" + } ++ You can access my_param1 and/or my_param2 on any step1.tcl, step2.tcl, or step3.tcl + by using "ad_page_contract" or "template::wizard get_param" +
ex. + ad_page_contract { + gets the wizard params + } { + my_param1 + my_param2 + } ++ or +
+ set my_param1 [template::wizard get_param my_param1] + set my_param2 [template::wizard get_param my_param2] ++ Note: "template::wizard get_param" has the advantage of getting the + param value during the response time. What does this mean? It will properly + get the current value of the param which was set by "template::wizard set_param", + while ad_page_contract will not pick that up since it will get what is the request + http var value. This is because "template::wizard get_param" gets the value + from the tcl var while ad_page_contract gets the value from the http var. + So while processing in tcl that value may change. +
+ <multiple name="wizard"> + <a href="[template::wizard get_forward_url @wizard.id@"> + @wizard.label@ <br> + </a> + </multiple> ++ Note: that this is not a very wise thing to do especially if the latter steps + will depend on the inputs from the earlier steps. You can however do checking + on each step. +
There are situations where in you would like to build a wizard when you can + go back several steps and jump back to the step furthest you have been.
+ +On your wizard.adp you can do the following
++ <multiple name="wizard"> + <if "@wizard.id@" le "wizard:visited_step"> + <a href="[template::wizard get_forward_url @wizard.id@"> + @wizard.label@ <br> + </a> + </if> + <else> + @wizard.label@ <br> + </else> + </multiple> ++ Note: that this is not a very wise thing to do especially if the latter steps + will depend on the inputs from the earlier steps. You can however do checking + on each step. +
Yes you can use another wizard a step of a wizard. This will act as a subwizard.
+ +Note: That visited steps will loose its value when moving from one subwizard to + another subwizard in the same level. In order to preserve this you must call + "template::wizard load_last_visited_step -key $yourkey" before "template::wizard get_current_step", + after "get_current_step" call "template::wizard save_last_visited_step -key $yourkey" +
+ +Also the wizard params name is present across the curent wizards being used, + so the developer has to be aware not to use the same names with different + purpose. For example on main wizard with have a param called "name" for + the user name. And on on sub wizard we have the param again called "name" + but used for the file name. +
+example: + template::wizard create -action "wizard" -name my_wizard -params { + my_param1 my_param2 + } -steps { + 1 -label "Step 1" -url "step1" + 2 -label "Step 2" -url "step2" + 3 -label "Step 3" -url "step3" + } ++
Get a wizard's param value
++ "template::wizard get_param" has the advantage over ad_page_contract of getting the + param value during the response time. What does this mean? It will properly + get the current value of the param which was set by "template::wizard set_param", + while ad_page_contract will not pick that up since it will get what is the request + http var value. This is because "template::wizard get_param" gets the value + from the tcl var while ad_page_contract gets the value from the http var. + So while processing in tcl that value may change. +
+} { + + set level [template::adp_level] + + upvar #$level wizard:params params + + if { [info exists params($name)] } { + set value $params($name) + } else { + set value [ns_queryget $name] + } + return $value + +} + + +ad_proc -public template::wizard::set_param { name value } { +Set a wizard's param for passthrough
+ +Normally you place this in the steps of the wizard where the + form has been processed. A param + is normally used when you want to reuse a value across the steps.
+ +Note: if you are to use "template::wizard set_param" on a wizard file ex. + (wizard.tcl). Make sure to do it before "template::wizard get_current_step". + So when "template::wizard get_current_step" redirects it will properly set + the correct values of the param to the new value.
+} { + + set level [template::adp_level] + + upvar #$level wizard:params params + set params($name) $value + +} + + +ad_proc -public template::wizard::set_finish_url { finish_url } { +if the finish url is set, when a the finish button is pressed + it will redirect to this url
+} { + get_reference + set wizard_finish_url $finish_url + +} + + +ad_proc -private template::wizard::add { step_id args } { + Append a step to a wizard +} { + get_reference + + lappend steps $step_id + + # add the reference to the steps lookup array for the wizard + upvar #$level wizard:$step_id opts wizard:rowcount rowcount + incr rowcount + set opts(id) $step_id + set opts(rownum) $rowcount + set opts(link) [get_forward_url $opts(id)] + + # copy the reference for access as a multirow data source as well + upvar #$level wizard:$rowcount props + + template::util::get_opts $args + + array set props [array get opts] +} + + +ad_proc -public template::wizard::get_current_step {} { +Set the step to display for this particular request This is + determined by the wizard_step parameter. If not set, the first step + is used.
+ +Make sure that you call any "template::wizard set_param" if needed before + calling get_current_step. get_current_step will redirect to the wizard -action + properly setting all -params value and its other needed http state vars
+ +The wizard will rewrite the url always. Only self submitting forms + are preserved. Once the form is finished processing the wizard will take + over and rewrite the url.
+} { + get_reference + + upvar #$level wizard:current_id current_id + set current_id [ns_queryget wizard_step${wizard_name} [lindex $steps 0]] + + upvar #$level wizard:visited_step visited_step + set visited_step [get_visited_step] + + # if there is no step state, we are likely in the first step. + # lets redirect with the proper state vars + if {[string equal [ns_queryget wizard_step${wizard_name}] ""]} { + template::forward [get_forward_url $current_id] + } + + # get a reference to the step + upvar #$level wizard:$current_id step + + upvar #$level wizard:current_url current_url + + # lets see if this step exists, if not we are finished with wizard and pass the steps + if [info exists step(url)] { + set current_url $step(url) + } else { + # if we have set_finish_url then we redirect to that url when we are finished + # otherwise increment the parent wizard step + if {[info exists wizard_finish_url]} { + template::forward $wizard_finish_url + } else { + + # lets set the current wizard name to the parent wizard + set parent_wizard [lindex $wizards 0] + set wizard_name $parent_wizard + + # lets now increment step of the parent wizard + set parent_step [expr [ns_queryget wizard_step${parent_wizard}] + 1] + template::forward [get_forward_url $parent_step] + } + + } + + # check for a "back" submission and forward immediately if so + # also check if we are backing up the current wizard or another wizard + + if { [ns_queryexists wizard_submit_back] && [string equal $wizard_name [ns_queryget wizard_name]]} { + + set last_index [expr [lsearch -exact $steps $current_id] - 1] + set last_id [lindex $steps $last_index] + template::forward [get_forward_url $last_id] + } +} + +ad_proc -private template::wizard::current_step {} { + convinience method to get the step for the http params or from the + wizard step definition +} { + + get_reference + + return [ns_queryget wizard_step${wizard_name} [lindex $steps 0]] +} + + +ad_proc -public template::wizard::get_visited_step {} { + get the last visited step +} { + + get_reference + + # lets create the visited steps for the current + # lets see if the current step is greater what we have visited + # otherwise we keep the current value + set last_visitedstep [get_param wizard_visitedstep${wizard_name}] + set current_step [current_step] + if { ($last_visitedstep < $current_step) || [string equal $last_visitedstep ""] } { + return $current_step + } else { + return $last_visitedstep + } + +} + +ad_proc -public template::wizard::set_visited_step {step_id} { + set the last visited step +} { + + get_reference + set_param wizard_visitedstep${wizard_name} $step_id +} + + +ad_proc -public template::wizard::get_current_name {} { + get the current wizard name +} { + + get_reference + + return $wizard_name +} + + +ad_proc -private template::wizard::get_wizards_levels {} { + internal helper proc to get the different levels of wizards + from current to parent +} { + variable parse_level + set level [expr $parse_level - 1] + + set levels {} + for {set i $level} {$i > 1} {set i [expr $i - 1]} { + upvar #$i wizard:name parent_wizard + if [info exists parent_wizard] { + lappend levels $i + } else { + break + } + } + + return $levels + +} + + +ad_proc -private template::wizard::get_wizards {} { + we will get all the wizards that we have passed through +} { + + set wizards {} + set levels [get_wizards_levels] + + foreach i $levels { + upvar #$i wizard:name parent_wizard + if [info exists parent_wizard] { + lappend wizards $parent_wizard + } + } + + return $wizards +} + + +ad_proc -public template::wizard::submit { form_id args } { +Add the appropriate buttons to the submit wizard + Also create a list of all the buttons + The optional -buttons parameter is a list of name-value pairs, + in form {name label} {name label...} + The valid button names are back, next, repeat, finish
+ +Also writes the params to the form as hidden elements to keep the + state of the wizard.
+ +The following values are acceptable for the buttons: back, next and finish. + Back buttons are not rendered if the step is the first step, like wise next + buttons are not displayed if its the last step. Finish can appear on any step + and will finish the current wizard even if not all steps are done.
+ +} { + + variable default_button_labels + + get_reference + upvar 2 wizard_submit_buttons buttons + set buttons [list] + + set param_level [template::adp_level] + upvar #$param_level wizard:params params + + template::util::get_opts $args + + # Handle the -buttons parameter + if { ![info exists opts(buttons)] } { + # jkyamog - is this really correct? when no buttons is present we put all of the buttons? + upvar 0 default_button_labels button_labels + } else { + foreach pair $opts(buttons) { + # If provided with just a name, use default label + if { [llength $pair] == 1 } { + set button_labels($pair) $default_button_labels($pair) + } else { + set button_labels([lindex $pair 0]) [lindex $pair 1] + } + } + } + + # Add a hidden element for the current wizard name + template::element create $form_id wizard_name -widget hidden -value $wizard_name -datatype keyword + + set current_id [current_step] + + # Add a hidden element with the current ID + template::element create $form_id wizard_step${wizard_name} -widget hidden -value $current_id -datatype keyword + + + set step_index [expr [lsearch -exact $steps $current_id] + 1] + + # If not the first one and it is allowed than add a "Back" button + if { $step_index > 1 && [info exists button_labels(back)] } { + template::element create $form_id wizard_submit_back -widget submit \ + -label $button_labels(back) -optional -datatype text + + lappend buttons wizard_submit_back + } + + # If iteration is allowed than add a "Repeat" button + upvar #$level wizard:$current_id step + if { [info exists step(repeat)] && [info exists button_labels(repeat)]} { + template::element create $form_id wizard_submit_repeat -widget submit \ + -label $button_labels(repeat) -optional -datatype text + lappend buttons wizard_submit_repeat + } + + # If not the last one than add a "Next" button + if { $step_index < [llength $steps] && [info exists button_labels(next)] } { + template::element create $form_id wizard_submit_next -widget submit \ + -label $button_labels(next) -optional -datatype text + lappend buttons wizard_submit_next + } + + # Always finish + if { [info exists button_labels(finish) ] } { + template::element create $form_id wizard_submit_finish -widget submit \ + -label $button_labels(finish) -optional -datatype text + lappend buttons wizard_submit_finish + } + + + # Create hidden variables for wizard parameters + set levels [get_wizards_levels] + lappend levels $level + + foreach onelevel $levels { + upvar #$onelevel wizard:properties properties + foreach param $properties(params) { + if { ![template::element::exists $form_id $param] } { + if { [info exists params($param)] } { + template::element create $form_id $param -widget hidden -datatype text -optional -param -value $params($param) + } else { + template::element create $form_id $param -widget hidden -datatype text -optional -param + } + } + } + + } + + # Create hidden variables for the other wizard steps and visited steps + foreach one_wizard $wizards { + if { ![template::element::exists $form_id wizard_step${one_wizard}] } { + template::element create $form_id wizard_step${one_wizard} -widget hidden \ + -datatype keyword -value [ns_queryget wizard_step${one_wizard}] + } + if { ![template::element::exists $form_id wizard_visitedstep${one_wizard}] } { + template::element create $form_id wizard_visitedstep${one_wizard} -widget hidden \ + -datatype keyword -value [ns_queryget wizard_visitedstep${one_wizard}] + } + } + +} + + +ad_proc -private template::wizard::get_reference {} { + Get a reference to the wizard steps (internal helper) +} { + + uplevel { + + variable parse_level + set level $parse_level + + upvar #$level wizard:steps steps wizard:properties properties wizard:name wizard_name wizard:wizards wizards wizard:finish_url wizard_finish_url + if { ! [info exists steps] } { + error "Wizard does not exist" + } + } +} + + +ad_proc -public template::wizard::exists {} { + @return 1 if a wizard is currently defined +} { + variable parse_level + + if { ![info exists parse_level] } { + return 0 + } + + upvar #$parse_level wizard:steps steps + + return [info exists steps] +} + + +ad_proc -public template::wizard::forward {} { + call when a step has been validated and completed. + checks which submit button was pressed and proceeds accordingly. +} { + + get_reference + + upvar #$level wizard:current_id current_id + set current_index [expr [lsearch -exact $steps $current_id] + 1] + + if { [ns_queryexists wizard_submit_next] } { + + # figure out the next step and go there + + set next_id [lindex $steps $current_index] + template::forward [get_forward_url $next_id] + + } elseif { [ns_queryexists wizard_submit_back] } { + + set last_id [lindex $steps [expr $current_index - 2]] + template::forward [get_forward_url $last_id] + + } elseif { [ns_queryexists wizard_submit_repeat] } { + + template::forward "[get_forward_url $current_id]&wizard_submit_repeat=t" + + } elseif { [ns_queryexists wizard_submit_finish] } { + +# template::forward $properties(action) +# NOTE : we are changing the behaviour of wizard, when its finish it will not reset and go back +# to step 1, it will blindly go forward and we will catch this on get_current_step + set next_id [expr $current_index + 1] + template::forward [get_forward_url $next_id] + } +} + +ad_proc -public template::wizard::get_forward_url { step_id } { + Build the redirect URL for the next step +} { + + get_reference + + set param_level [template::adp_level] + upvar #$param_level wizard:params params + + set url [ns_conn url]?wizard_step${wizard_name}=$step_id&wizard_name=$wizard_name + + # create the wizards and keep track of their steps too + foreach one_wizard $wizards { + append url "&wizard_step${one_wizard}=[ns_queryget wizard_step${one_wizard}]" + append url "&wizard_visitedstep${one_wizard}=[ns_queryget wizard_visitedstep${one_wizard}]" + } + + # check for passthrough parameters + + set levels [get_wizards_levels] + lappend levels $level + set allparams {} + + foreach onelevel $levels { + upvar #$onelevel wizard:properties properties + if { [info exists properties(params)] } { + foreach param $properties(params) { + + if { [info exists params($param)] } { + set value $params($param) + } else { + set value [ns_queryget $param] + } + # we will only append unique params + if {[lsearch $allparams $param] == -1} { + append url "&$param=[ns_urlencode $value]" + lappend allparams $param + } + } + } + } + + return $url +} + +ad_proc -public template::wizard::get_action_url {} { + Retreive the URL to the action +} + + get_reference + + return $properties(action) +} + + +ad_proc -public template::wizard::load_last_visited_step { + -key:required +} { + loads the last visited step from the db + + @creation-date june 2003 + @author Jun Yamog + + @param key unique identifier for a particular wizard normally the main object_id the wizard + is manipulating + + use this step before get_current_step +} { + + get_reference + + # check the old visited step on the the state manager + set visited_step [ad_get_client_property -default "" $key ${wizard_name}visited] + if {![string equal $visited_step ""]} { + template::wizard::set_visited_step $visited_step + } + +} + + +ad_proc -public template::wizard::save_last_visited_step { + -key:required +} { + saves the last visisted step to the db + + @creation-date june 2003 + @author Jun Yamog + + @param key unique identifier for a particular wizard normally the main object_id the wizard + is manipulating + + use this step after get_current_step +} { + + get_reference + + # save the state of the visited step for this wizard + if { ![string equal $key ""] } { + ad_set_client_property $key ${wizard_name}visited [template::wizard::get_visited_step] + } + +} +