Index: openacs-4/packages/q-forms/tcl/form-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/q-forms/tcl/form-procs.tcl,v diff -u -N -r1.2 -r1.3 --- openacs-4/packages/q-forms/tcl/form-procs.tcl 8 Apr 2015 08:34:36 -0000 1.2 +++ openacs-4/packages/q-forms/tcl/form-procs.tcl 2 Jan 2017 10:30:48 -0000 1.3 @@ -2,9 +2,17 @@ routines for creating, managing input via html forms @creation-date 21 Nov 2010 - @cs-id $Id: + @Copyright (c) 2010-5 Benjamin Brink + @license GNU General Public License 2, see project home or http://www.gnu.org/licenses/gpl.html + @project home: http://github.com/tekbasse/q-forms + @address: po box 20, Marylhurst, OR 97036-0020 usa + @email: tekbasse@yahoo.com } +#agenda: +##code a proc called qf_bypass that does like qf_input hidden with sec_hash +## but emits no html tag to the form. + # use _ to clear a new default # use upvar to grab previous defaults and re-use (with qf_input only) # main namespace vars: @@ -14,6 +22,7 @@ # __form_ids_fieldset_open_list = list that contains form ids where a fieldset tag is open # __form_arr contains an array of forms. Each form built as a string by appending tags, indexed by form_id, for example __form_arr($id) # __qf_arr contains last attribute values of a tag (for all forms), indexed by {tag}_attribute, __form_last_id is in __qf_arr(form_id) +# __qf_hc_arr contains sh_key_id for each form_id # a blank id passed in anything other than qf_form assumes the current (most recent used form_id) # to fix: id for nonform tag should not be same as form_id. use an attribute "form_id" for assigning tags to specific forms. @@ -33,6 +42,9 @@ } { creates the form key for a more secure form transaction. Returns the security hash. See also qf_submit_key_accepted_p } { + upvar 1 __qf_hc_arr __qf_hc_arr + upvar 1 attributes_arr attributes_arr + # This proc is inspired from sec_random_token if { $instance_id eq "" } { # set instance_id package_id @@ -68,9 +80,11 @@ } append sec_hash_string $start_clicks $session_id $secure_p $client_ip $action_url $time_sec $key_id set sec_hash [ns_sha1 $sec_hash_string] + set sh_key_id [db_nextval qf_id_seq] db_dml qf_form_key_create {insert into qf_key_map - (instance_id,rendered_timestamp,sec_hash,key_id,session_id,action_url,secure_conn_p,client_ip) - values (:instance_id,:time_sec,:sec_hash,:key_id,:session_id,:action_url,:secure_p,:client_ip) } + (instance_id,sh_key_id,rendered_timestamp,sec_hash,key_id,session_id,action_url,secure_conn_p,client_ip) + values (:instance_id,:sh_key_id,:time_sec,:sec_hash,:key_id,:session_id,:action_url,:secure_p,:client_ip) } + set __qf_hc_arr($attributes_arr(form_id)) $sh_key_id return $sec_hash } @@ -80,6 +94,8 @@ } { Checks the form key against existing ones. Returns 1 if matches and unexpired, otherwise returns 0. } { + # sh_key_id is passed to qf_get_inputs_as_array to collect hidden name value pairs. + upvar 1 sh_key_id sh_key_id # This proc is inspired from sec_random_token if { $instance_id eq "" } { # set instance_id package_id @@ -104,19 +120,24 @@ } # the key_id is used to help generate unpredictable hashes, but isn't used at this level of input validation set accepted_p [db_0or1row qf_form_key_check_hash { - select session_id as session_id_i, action_url as action_url_i, secure_conn_p as secure_conn_p_i, client_ip as client_ip_i from qf_key_map - where instance_id =:instance_id and sec_hash =:sec_hash and submit_timestamp is null } ] + select session_id as session_id_i, action_url as action_url_i, secure_conn_p as secure_conn_p_i, client_ip as client_ip_i, sh_key_id + from qf_key_map + where instance_id=:instance_id + and sec_hash=:sec_hash + and submit_timestamp is null } ] if { !$accepted_p } { # there is nothing to compare. log current values: - ns_log Warning "qf_submit_key_accepted_p: is false. action_url '$action_url' sec_hash '$sec_hash'" + ns_log Warning "qf_submit_key_accepted_p.115: is false. action_url '${action_url}' sec_hash '${sec_hash}'" if { $connected_p } { - ns_log Warning "qf_submit_key_accepted_p: session_id '$session_id' secure_p '$secure_p' client_ip '$client_ip'" + ns_log Warning "qf_submit_key_accepted_p.117: session_id '${session_id}' secure_p '${secure_p}' client_ip '${client_ip}'" } } else { # Mark the key expired set submit_timestamp [ns_time] - db_dml qf_form_key_expire { update qf_key_map - set submit_timestamp = :submit_timestamp where instance_id =:instance_id and sec_hash =:sec_hash and submit_timestamp is null } + db_dml qf_form_key_expire { update qf_key_map set submit_timestamp=:submit_timestamp + where instance_id =:instance_id + and sec_hash=:sec_hash + and submit_timestamp is null } } return $accepted_p } @@ -143,7 +164,8 @@ set arg_arr(multiple_key_as_list) 0 set arg_arr(hash_check) 0 set arg_full_list [list duplicate_key_check multiple_key_as_list hash_check] - #set arg_list [list $arg1 $arg2 $arg3 $arg4 $arg5 $arg6 ] + #set arg_list \[list $arg1 $arg2 $arg3 $arg4 $arg5 $arg6 \] + set instance_id [ad_conn package_id] # collect args if { [llength $arg1] > 1 && $value1 eq "" } { set arg_list $arg1 @@ -160,10 +182,10 @@ foreach {name value} $arg_list { set attribute_index [lsearch -exact $arg_full_list $name] if { $attribute_index > -1 } { - set arg_arr($name) $value + set arg_arr(${name}) $value } else { if { $name ne "" } { - ns_log Error "qf_get_inputs_as_array: '${name}' is not a valid name for use with args." + ns_log Error "qf_get_inputs_as_array.170: '${name}' is not a valid name for use with args." } } } @@ -176,21 +198,21 @@ } else { set __form_size [ns_set size $__form] } - #ns_log Notice "qf_get_inputs_as_array: formsize $__form_size" + #ns_log Notice "qf_get_inputs_as_array.183: formsize $__form_size" for { set __form_counter_i 0 } { $__form_counter_i < $__form_size } { incr __form_counter_i } { regexp -nocase -- {^[a-z][a-z0-9_\.\:\(\)]*} [ns_set key $__form $__form_counter_i] __form_key # Why doesn't work for regexp -nocase -- {^[a-z][a-z0-9_\.\:\(\)]*$ } ? set __form_key_exists [info exists __form_key] - # ns_log Notice "qf_get_inputs_as_array: __form_key_exists = ${__form_key_exists}" + # ns_log Notice "qf_get_inputs_as_array.189: __form_key_exists = ${__form_key_exists}" # no inserting tcl commands etc! if { $__form_key_exists == 0 || ( $__form_key_exists == 1 && [string length $__form_key] == 0 ) } { # let's make this an error for now, so we log any attempts - # ns_log Notice "qf_get_inputs_as_array: __form_key_exists ${__form_key_exists} length __form_key [string length ${__form_key}]" - # ns_log Notice "qf_get_inputs_as_array(ref156: attempt to insert unallowed characters to user input '{__form_key}' as '[ns_set key $__form $__form_counter_i]' for counter ${__form_counter_i}." + # ns_log Notice "qf_get_inputs_as_array.194: __form_key_exists ${__form_key_exists} length __form_key \[string length ${__form_key}\]" + # ns_log Notice "qf_get_inputs_as_array.196: attempt to insert unallowed characters to user input '{__form_key}' as '\[ns_set key $__form $__form_counter_i\]' for counter ${__form_counter_i}." if { $__form_counter_i > 0 } { - ns_log Notice "qf_get_inputs_as_array: attempt to insert unallowed characters to user input '{__form_key}'." + ns_log Notice "qf_get_inputs_as_array.197: attempt to insert unallowed characters to user input '{__form_key}'." } } else { set __form_key [ad_quotehtml $__form_key] @@ -202,52 +224,109 @@ set __form_input_exists 1 # check for duplicate key? - if { $arg_arr(duplicate_key_check) && [info exists __form_buffer_arr($__form_key) ] } { - if { $__form_input ne $__form_buffer_arr($__form_key) } { + if { $arg_arr(duplicate_key_check) && [info exists __form_buffer_arr(${__form_key}) ] } { + if { $__form_input ne $__form_buffer_arr(${__form_key}) } { # which one is correct? log error - ns_log Error "qf_get_form_input: form input error. duplcate key provided for ${__form_key}" + ns_log Error "qf_get_form_input.212: form input error. duplcate key provided for '${__form_key}'" ad_script_abort # set __form_input_exists to -1 instead of ad_script_abort? } else { - ns_log Warning "qf_get_form_input: notice, form has a duplicate key with multiple values containing same info.." + ns_log Warning "qf_get_form_input.216: notice, form has a duplicate key with multiple values containing same info.." } } elseif { $arg_arr(multiple_key_as_list) } { - ns_log Notice "qf_get_inputs_as_array: A key has been posted with multible values. Values assigned to the key as a list." - if { [llength $__form_buffer_arr($__form_key)] > 1 } { + ns_log Notice "qf_get_inputs_as_array.219: A key has been posted with multible values. Values assigned to the key as a list." + if { [llength $__form_buffer_arr(${__form_key})] > 1 } { # value is a list, lappend - lappend __form_buffer_arr($__form_key) $__form_input + lappend __form_buffer_arr(${__form_key}) $__form_input } else { # convert the key value to a list - set __value_one $__form_buffer_arr($__form_key) - unset __form_buffer_arr($__form_key) - set __form_buffer_arr($__form_key) [list $__value_one $__form_input] + set __value_one $__form_buffer_arr(${__form_key}) + unset __form_buffer_arr(${__form_key}) + set __form_buffer_arr(${__form_key}) [list $__value_one $__form_input] } } else { - set __form_buffer_arr($__form_key) $__form_input - # ns_log Debug "qf_get_inputs_as_array: set ${form_array_name}($__form_key) '${__form_input}'." + set __form_buffer_arr(${__form_key}) $__form_input + # ns_log Debug "qf_get_inputs_as_array.231: set ${form_array_name}($__form_key) '${__form_input}'." } # next key-value pair } + } - if { $arg_arr(hash_check) } { - if { [info exists __form_buffer_arr(qf_security_hash) ] } { - set accepted_p [qf_submit_key_accepted_p $__form_buffer_arr(qf_security_hash) ] - if { $accepted_p } { - unset __form_buffer_arr(qf_security_hash) - array set __form_input_arr [array get __form_buffer_arr] - return $__form_input_exists + if { $__form_input_exists } { + if { $arg_arr(hash_check) } { + if { [info exists __form_buffer_arr(qf_security_hash) ] } { + set accepted_p [qf_submit_key_accepted_p $__form_buffer_arr(qf_security_hash) ] + if { $accepted_p } { + + # Are there any hidden name pairs to grab from db? + set name_value_lists [db_list_of_lists qf_name_value_pairs_r {select arg_name,arg_value + from qf_name_value_pairs + where instance_id=:instance_id + and sh_key_id=:sh_key_id} ] + # clear any external input and warn if it is different + foreach pair_list $name_value_lists { + set __form_key [lindex $pair_list 0] + set __form_input [lindex $pair_list 1] + if { [info exists __form_buffer_arr(${__form_key}) ] } { + set test [ad_unquotehtml $__form_buffer_arr(${__form_key})] + if { $test ne $__form_input } { + ns_log Warning "qf_get_inputs_as_array.12000: input of type 'hidden' from form does not match for name '${__form_key}'. Internal used. internal '${__form_input}' from form '${test}'" + array unset __form_buffer_arr $__form_key + } + } + } + foreach pair_list $name_value_lists { + set __form_key [lindex $pair_list 0] + set __form_input [lindex $pair_list 1] + # For consistency, this is a repeat of external form logic checks above. + + # check for duplicate key? + if { $arg_arr(duplicate_key_check) && [info exists __form_buffer_arr(${__form_key}) ] } { + if { $__form_input ne $__form_buffer_arr(${__form_key}) } { + # which one is correct? log error + ns_log Error "qf_get_form_input.312: form input error. duplcate key provided for '${__form_key}'" + ad_script_abort + # set __form_input_exists to -1 instead of ad_script_abort? + } else { + ns_log Warning "qf_get_form_input.316: notice, form has a duplicate key with multiple values containing same info.." + } + } elseif { $arg_arr(multiple_key_as_list) } { + ns_log Notice "qf_get_inputs_as_array.319: A key has been posted with multible values. Values assigned to the key as a list." + if { [llength $__form_buffer_arr(${__form_key})] > 1 } { + # value is a list, lappend + lappend __form_buffer_arr(${__form_key}) $__form_input + } else { + # convert the key value to a list + set __value_one $__form_buffer_arr(${__form_key}) + unset __form_buffer_arr(${__form_key}) + set __form_buffer_arr(${__form_key}) [list $__value_one $__form_input] + } + } else { + set __form_buffer_arr(${__form_key}) $__form_input + # ns_log Debug "qf_get_inputs_as_array.231: set ${form_array_name}($__form_key) '${__form_input}'." + } + + # next key-value pair + } + + unset __form_buffer_arr(qf_security_hash) + array set __form_input_arr [array get __form_buffer_arr] + return $__form_input_exists + } else { + ns_log Notice "qf_get_inputs_as_array.346: hash_check with form input of '$__form_buffer_arr(qf_security_hash)' did not match." + return 0 + } } else { - ns_log Notice "qf_get_inputs_as_array: hash_check with form input of '$__form_buffer_arr(qf_security_hash)' did not match." + set accepted_p 0 + ns_log Notice "qf_get_inputs_as_array.351: hash_check requires qf_security_hash, but was not included with form input." return 0 } } else { - set accepted_p 0 - ns_log Notice "qf_get_inputs_as_array: hash_check requires qf_security_hash, but was not included with form input." - return 0 + array set __form_input_arr [array get __form_buffer_arr] + return $__form_input_exists } } else { - array set __form_input_arr [array get __form_buffer_arr] return $__form_input_exists } } @@ -270,16 +349,37 @@ {value1 ""} args } { - Initiates a form with form tag and supplied attributes. Returns an id. A clumsy url based id is provided if not passed (not recommended). + Initiates a form with form tag and supplied attributes. + Returns an id. + A clumsy url-based id is provided if not passed (not recommended). If hash_check passed, creates a hash to be checked on submit for server-client transaction continuity. +
+ To create a form that uploads a file, set attribute enctype to "multipart/form-data", set method to "post". + Also, create an input tag with type attribute set to "file" to choose a file to upload, + and set name attribute to name of file as it will be received at the server along with + other input from the form. + + In the following example, name is set to "clientfile". + + After the form has been submitted, data can be retreived via ns_queryget (or qf_get_inputs_as_array ): + + set uploaded_filename \[ns_queryget clientfile \] + + set file_pathname_on_server \[ns_queryget clientfile.tmpfile \] +
+ For more info, see Naviserver documentation for ns_queryget
+ + @see qf_get_inputs_as_array } { # use upvar to set form content, set/change defaults # __qf_arr contains last attribute values of tag, indexed by {tag}_attribute, __form_last_id is in __qf_arr(form_id) + # __qf_hc_arr(form_id) contains value of hash_check. upvar 1 __form_ids_list __form_ids_list upvar 1 __form_arr __form_arr upvar 1 __form_ids_open_list __form_ids_open_list upvar 1 __qf_remember_attributes __qf_remember_attributes upvar 1 __qf_arr __qf_arr + upvar 1 __qf_hc_arr __qf_hc_arr # collect args if { [llength $arg1] > 1 && $value1 eq "" } { @@ -294,26 +394,31 @@ set arg_list [list ] } - set attributes_tag_list [list action class id method name style target title] + set attributes_tag_list [list action class id method name style target title encytype] set attributes_full_list $attributes_tag_list lappend attributes_full_list form_id hash_check key_id set attributes_list [list] foreach {attribute value} $arg_list { set attribute_index [lsearch -exact $attributes_full_list $attribute] if { $attribute_index > -1 } { - set attributes_arr($attribute) $value + set attributes_arr(${attribute}) $value if { [lsearch -exact $attributes_tag_list $attribute] > -1 } { lappend attributes_list $attribute } } else { - ns_log Error "qf_form: '${attribute}' is not a valid attribute." + ns_log Error "qf_form.337: '${attribute}' is not a valid attribute." } } if { ![info exists attributes_arr(method)] } { set attributes_arr(method) "post" lappend attributes_list "method" } + if { ![info exists attributes_arr(enctype)] && $attributes_arr(method) eq "post" } { + set attributes_arr(enctype) "application/x-www-form-urlencoded" + lappend attributes_list "enctype" + } + # if html5 should we default novalidate to novalidate? No for now. if { ![info exists __qf_remember_attributes] } { @@ -328,8 +433,8 @@ # use previous tag attribute values? if { $__qf_remember_attributes } { foreach attribute $attributes_list { - if { $attribute ne "id" && ![info exists attributes_arr($attribute)] && [info exists __qf_arr(form_$attribute)] } { - set attributes_arr($attribute) $__qf_arr(form_$attribute) + if { $attribute ne "id" && ![info exists attributes_arr(${attribute})] && [info exists __qf_arr(form_${attribute})] } { + set attributes_arr(${attribute}) $__qf_arr(form_${attribute}) } } } @@ -339,28 +444,30 @@ set id_exists [info exists attributes_arr(id) ] if { $id_exists == 0 || ( $id_exists == 1 && $attributes_arr(id) eq "" ) } { regsub {/} [ad_conn url] {-} form_key - append form_key "-[llength $__form_ids_list]" + append form_key "-[llength ${__form_ids_list}]" } else { # since a FORM id has to be unique, lets use it set form_key $attributes_arr(id) } set attributes_arr(form_id) $form_key - ns_log Notice "qf_form: generating form_id $attributes_arr(form_id)" + ns_log Notice "qf_form.380: generating form_id $attributes_arr(form_id)" } # prepare attributes to process set tag_attributes_list [list] foreach attribute $attributes_list { - set __qf_arr(form_$attribute) $attributes_arr($attribute) + set __qf_arr(form_${attribute}) $attributes_arr(${attribute}) # if a form tag requires an attribute, the following test needs to be forced true - if { $attributes_arr($attribute) ne "" } { - lappend tag_attributes_list $attribute $attributes_arr($attribute) + if { $attributes_arr(${attribute}) ne "" } { + lappend tag_attributes_list $attribute $attributes_arr(${attribute}) } } - set tag_html "\n" + append __form_arr(${form_id}) "\n" # remove form_id from __form_ids_open_list set __form_ids_open_list [lreplace $__form_ids_open_list $form_id_position $form_id_position] } @@ -888,18 +1016,18 @@ foreach {attribute value} $arg_list { set attribute_index [lsearch -exact $attributes_full_list $attribute] if { $attribute_index > -1 } { - set attributes_arr($attribute) $value + set attributes_arr(${attribute}) $value lappend attributes_list $attribute } elseif { $value eq "" } { # do nothing } else { - ns_log Error "qf_read: $attribute is not a valid attribute. invoke with attribute value pairs. Separate each with a space." + ns_log Error "qf_read.928: '${attribute}' is not a valid attribute. invoke with attribute value pairs. Separate each with a space." ad_script_abort } } if { ![info exists __form_ids_list] } { - ns_log Error "qf_read: invoked before qf_form or used in a different namespace than qf_form.." + ns_log Error "qf_read.934: invoked before qf_form or used in a different namespace than qf_form.." ad_script_abort } # normalize code using id instead of form_id @@ -925,7 +1053,7 @@ if { $specified_1 } { # a form specified in argument if { ![info exists __form_arr($attributes_arr(id)) ] } { - ns_log Warning "qf_read: unknown form_id $attributes_arr(id)" + ns_log Warning "qf_read.960: unknown form_id $attributes_arr(id)" } else { set form_s $__form_arr($attributes_arr(id)) } @@ -935,9 +1063,9 @@ # check if form_id is valid set form_id_position [lsearch $__form_ids_list $form_id] if { $form_id_position == -1 } { - ns_log Warning "qf_read: unknown form_id $form_id" + ns_log Warning "qf_read.970: unknown form_id '${form_id}'" } else { - lappend forms_list $__form_arr($form_id) + lappend forms_list $__form_arr(${form_id}) } } set form_s $forms_list @@ -946,6 +1074,108 @@ } +ad_proc -public qf_bypass { + args +} { + Places a name value pair in a temporary db cache for passing between form generation and form post. + qf_bypass is expected to be used in context of a form_id. Data is retrieved via qf_get_inputs_as_array. + Input is similar to qf_input. Acceptable attributes: name, value, form_id + Returns 1 if successful. Otherwise returns 0. +} { + upvar 1 __qf_arr __qf_arr + upvar 1 __qf_hc_arr __qf_hc_arr + upvar 1 __form_ids_list __form_ids_list + + if { ![info exists __form_ids_list] } { + ns_log Warning "qf_bypass.1083: invoked before qf_form or used in a different namespace than qf_form.." + set __form_ids_list [list [random]] + set __qf_arr(form_id) $__form_ids_list + } + # default to last modified form_id + if { ![info exists attributes_arr(form_id)] || $attributes_arr(form_id) eq "" } { + set attributes_arr(form_id) $__qf_arr(form_id) + } + # defaults + set arg_name "" + set arg_value "" + set success_p 1 + foreach {attribute value} $args { + switch -exact -- $attribute { + name { + set arg_name $value + } + value { + set arg_value $value + } + form_id { + if { $value in $__form_ids_list } { + set attriburtes_arr(form_id) $value + } else { + ns_log Notice "qf_bypass.1106: form_id '${value}' not found; Using last modified form form_id." + } + } + default { + ns_log Notice "qf_bypass.1110: attribute '${attribute}' unrecognized. skipped. value '${value}'" + } + } + } + if { $arg_name ne "" } { + # pass via db for integrity of internal references + set instance_id [ad_conn package_id] + set sh_key_id $__qf_hc_arr($attributes_arr(form_id)) + db_dml qf_name_value_pairs_c { insert into qf_name_value_pairs + (instance_id,sh_key_id,arg_name,arg_value) + values (:instance_id,:sh_key_id,:arg_name,:arg_value) } + } else { + set success_p 0 + } + return $success_p +} + +ad_proc -public qf_bypass_nv_list { + args_list + {form_id ""} +} { + Places name value pairs in a temporary db cache for passing between form generation and form post. + qf_bypass_nv_list is expected to be used in context of a form_id. Data is retrieved via qf_get_inputs_as_array. + +} { + upvar 1 __qf_arr __qf_arr + upvar 1 __qf_hc_arr __qf_hc_arr + upvar 1 __form_ids_list __form_ids_list + + if { ![info exists __form_ids_list] } { + ns_log Warning "qf_bhypass_nv_list.1140: invoked before qf_form or used in a different namespace than qf_form.." + set __form_ids_list [list [random]] + set __qf_arr(form_id) $__form_ids_list + } + # default to last modified form_id + if { ![info exists attributes_arr(form_id)] || $attributes_arr(form_id) eq "" } { + set attributes_arr(form_id) $__qf_arr(form_id) + } + if { $form_id ne "" } { + if { $form_id in $__form_ids_list } { + set attributes_arr(form_id) $form_id + } else { + ns_log Notice "qf_bypass_nv_list.1154: form_id '${form_id}' not known. Using last modified form." + } + } + + set instance_id [ad_conn package_id] + set sh_key_id $__qf_hc_arr($attributes_arr(form_id)) + foreach {arg_name arg_value} $args_list { + if { $arg_name ne "" } { + # pass via db for integrity of internal references + db_dml qf_name_value_pairs_c { insert into qf_name_value_pairs + (instance_id,sh_key_id,arg_name,arg_value) + values (:instance_id,:sh_key_id,:arg_name,:arg_value) } + } + } + return 1 +} + + + ad_proc -public qf_input { {arg1 ""} {value1 ""} @@ -963,7 +1193,7 @@ upvar 1 __qf_remember_attributes __qf_remember_attributes upvar 1 __qf_arr __qf_arr upvar 1 __form_ids_fieldset_open_list __form_ids_fieldset_open_list - + upvar 1 __qf_hc_arr __qf_hc_arr # collect args if { [llength $arg1] > 1 && $value1 eq "" } { set arg_list $arg1 @@ -985,47 +1215,49 @@ foreach {attribute value} $arg_list { set attribute_index [lsearch -exact $attributes_full_list $attribute] if { $attribute_index > -1 } { - set attributes_arr($attribute) $value + set attributes_arr(${attribute}) $value if { [lsearch -exact $attributes_tag_list $attribute] > -1 } { lappend attributes_list $attribute } } elseif { $value eq "" } { # do nothing } else { - ns_log Error "qf_input: '${attribute}' is not a valid attribute." + ns_log Error "qf_input.1027: '${attribute}' is not a valid attribute." } } if { ![info exists __qf_remember_attributes] } { - ns_log Notice "qf_input(L801): invoked before qf_form or used in a different namespace than qf_form.." + ns_log Notice "qf_input.1032: invoked before qf_form or used in a different namespace than qf_form.." set __qf_remember_attributes 0 } if { ![info exists __form_ids_list] } { - ns_log Warning "qf_input:(L805) invoked before qf_form or used in a different namespace than qf_form.." + ns_log Warning "qf_input.1036: invoked before qf_form or used in a different namespace than qf_form.." set __form_ids_list [list [random]] set __qf_arr(form_id) $__form_ids_list } # default to last modified form_id if { ![info exists attributes_arr(form_id)] || $attributes_arr(form_id) eq "" } { set attributes_arr(form_id) $__qf_arr(form_id) } + if { [lsearch $__form_ids_list $attributes_arr(form_id)] == -1 } { - ns_log Error "qf_input: unknown form_id $attributes_arr(form_id)" + ns_log Error "qf_input.1045: unknown form_id $attributes_arr(form_id)" ad_script_abort } # use previous tag attribute values? if { $__qf_remember_attributes } { foreach attribute $attributes_list { - if { $attribute ne "id" && $attribute ne "value" && ![info exists attributes_arr($attribute)] && [info exists __qf_arr(input_$attribute)] } { - set attributes_arr($attribute) $__qf_arr(input_$attribute) + if { $attribute ne "id" && $attribute ne "value" && ![info exists attributes_arr(${attribute})] && [info exists __qf_arr(input_${attribute})] } { + set attributes_arr(${attribute}) $__qf_arr(input_${attribute}) } } } # provide a blank value by default if { ![info exists attributes_arr(value)] } { set attributes_arr(value) "" + lappend attributes_list "value" } # convert a "selected" parameter to checked if { ([info exists attributes_arr(selected)] && $attributes_arr(selected) eq "1") && ![info exists attributes_arr(checked)] } { @@ -1037,7 +1269,7 @@ if { [info exists attributes_arr(label)] && [info exists attributes_arr(type) ] && $attributes_arr(type) ne "hidden" } { if { ![info exists attributes_arr(id) ] } { set attributes_arr(id) $attributes_arr(name) - append attributes_arr(id) "-[string range [clock clicks -milliseconds] end-3 end]-[string range [random ] 2 end]" + append attributes_arr(id) "-" [string range [clock clicks -milliseconds] end-3 end] "-" [string range [random ] 2 end] lappend attributes_list "id" } if { [info exists attributes_arr(title) ] } { @@ -1049,38 +1281,61 @@ set tag_attributes_list [list] set tag_suffix "" foreach attribute $attributes_list { - set __qf_arr(input_$attribute) $attributes_arr($attribute) + set __qf_arr(input_${attribute}) $attributes_arr(${attribute}) if { $attribute ne "checked" && $attribute ne "disabled" } { - lappend tag_attributes_list $attribute $attributes_arr($attribute) + lappend tag_attributes_list $attribute $attributes_arr(${attribute}) } else { - set tag_suffix " ${attribute}" + set tag_suffix " " + append tag_suffix $attribute # set to checked or disabled } } # by default, wrap the input with a label tag for better UI, part 2 if { [info exists attributes_arr(label)] && [info exists attributes_arr(type) ] && $attributes_arr(type) ne "hidden" } { if { $attributes_arr(type) eq "checkbox" || $attributes_arr(type) eq "radio" } { - set tag_html "" + append tag_html ">" $attributes_arr(label) "" } else { - set tag_html "" + append tag_html ">" $attributes_arr(label) "" } } else { - set tag_html "" + if { $attributes_arr(type) eq "hidden" } { + if { [info exists __qf_hc_arr($attributes_arr(form_id))] && $__qf_hc_arr($attributes_arr(form_id)) > 0 } { + # pass via db for integrity of internal references + set instance_id [ad_conn package_id] + set sh_key_id $__qf_hc_arr($attributes_arr(form_id)) + set arg_name_idx [lsearch -exact $tag_attributes_list name] + set arg_name [lindex $tag_attributes_list $arg_name_idx+1] + set arg_value_idx [lsearch -exact $tag_attributes_list value] + set arg_value [lindex $tag_attributes_list $arg_value_idx+1] + db_dml qf_name_value_pairs_c { insert into qf_name_value_pairs + (instance_id,sh_key_id,arg_name,arg_value) + values (:instance_id,:sh_key_id,:arg_name,:arg_value) } + } + # and create some honey for sweet tooths regardless. + } + set tag_html "" + } # set results __form_arr, we checked form_id above. - append __form_arr($attributes_arr(form_id)) "${tag_html}\n" - - return "${tag_html}\n" + append __form_arr($attributes_arr(form_id)) $tag_html "\n" + append tag_html "\n" + #ns_log Notice "qf_input.1116: tag_html '${tag_html}'" + return $tag_html } ad_proc -public qf_append { @@ -1117,16 +1372,16 @@ foreach {attribute value} $arg_list { set attribute_index [lsearch -exact $attributes_full_list $attribute] if { $attribute_index > -1 } { - set attributes_arr($attribute) $value + set attributes_arr(${attribute}) $value lappend attributes_list $attribute } else { - ns_log Error "qf_append: '${attribute}' is not a valid attribute." + ns_log Error "qf_append.1157: '${attribute}' is not a valid attribute." ad_script_abort } } if { ![info exists __form_ids_list] } { - ns_log Warning "qf_append:(L1209) invoked before qf_form or used in a different namespace than qf_form.." + ns_log Warning "qf_append.1163: invoked before qf_form or used in a different namespace than qf_form.." set __form_ids_list [list [random]] set __qf_arr(form_id) $__form_ids_list } @@ -1137,12 +1392,12 @@ lappend attributes_list form_id } if { [lsearch $__form_ids_list $attributes_arr(form_id)] == -1 } { - ns_log Error "qf_append: unknown form_id $attributes_arr(form_id)" + ns_log Error "qf_append.1174: unknown form_id $attributes_arr(form_id)" ad_script_abort } if { ![info exists attributes_arr(html)] } { set attributs_arr(html) "" - ns_log Notice "qf_append: no argument 'html'" + ns_log Notice "qf_append.1179: no argument 'html'" if { [lsearch -exact $attributes_list "html"] == -1 } { set attributes_arr(html) "" lappend attributes_list "html" @@ -1161,11 +1416,12 @@ } { set args_html "" foreach {attribute value} $args_list { - if { [string range $attribute 1 1] eq "-" } { + # following range 1 1 changed to 0 0. Provided in case someone puts a dash as prefix to attribute + if { [string range $attribute 0 0] eq "-" } { set $attribute [string range $attribute 1 end] } regsub -all -- {\"} $value {\"} value - append args_html " $attribute=\"$value\"" + append args_html " " ${attribute} "=\"" ${value} "\"" } return $args_html } @@ -1236,7 +1492,7 @@ foreach {attribute value} $arg_list { set attribute_index [lsearch -exact $attributes_full_list $attribute] if { $attribute_index > -1 } { - set attributes_arr($attribute) $value + set attributes_arr(${attribute}) $value lappend attributes_list $attribute if { [lsearch -exact $attributes_select_list $attribute] > -1 } { # create a list to pass to qf_select without it balking at unknown parameters @@ -1245,7 +1501,7 @@ } elseif { $value eq "" } { # do nothing } else { - ns_log Error "qf_choice: [string range $attribute 0 15] is not a valid attribute." + ns_log Error "qf_choice.1283: [string range ${attribute} 0 15] is not a valid attribute." ad_script_abort } } @@ -1256,7 +1512,7 @@ set attributes_arr(form_id) $__qf_arr(form_id) } if { [lsearch $__form_ids_list $attributes_arr(form_id)] == -1 } { - ns_log Error "qf_choice: unknown form_id $attributes_arr(form_id)" + ns_log Error "qf_choice.1294: unknown form_id '$attributes_arr(form_id)'" ad_script_abort } lappend select_list form_id $attributes_arr(form_id) @@ -1278,13 +1534,14 @@ if { $type eq "radio" } { # create wrapping tag set tag_wrapping "ul" - set args_html "<${tag_wrapping}" + set args_html "<" + append args_html $tag_wrapping foreach attribute $attributes_list { # ignore proc parameters that are not tag attributes for the tag_wrapping tag if { $attribute eq "id" || $attribute eq "style" || $attribute eq "class" } { # quoting unquoted double quotes in attribute values, so as to not inadvertently break the tag - regsub -all -- {\"} $attributes_arr($attribute) {\"} attributes_arr($attribute) - append args_html " $attribute=\"$attributes_arr($attribute)\"" + regsub -all -- {\"} $attributes_arr(${attribute}) {\"} attributes_arr(${attribute}) + append args_html " " $attribute "=\"" $attributes_arr(${attribute}) "\"" } } append args_html ">\n" @@ -1315,10 +1572,10 @@ qf_input $input_attributes_list qf_append form_id $attributes_arr(form_id) html "" } else { - ns_log Notice "qf_choice: list not even number of members, skipping rendering of value attribute with list: $input_attributes_list" + ns_log Notice "qf_choice.1353: list not even number of members, skipping rendering of value attribute with list: '${input_attributes_list}'" } } - append args_html "${tag_wrapping}>" + append args_html "" $tag_wrapping ">" qf_append form_id $attributes_arr(form_id) html $args_html } else { @@ -1371,14 +1628,14 @@ foreach {attribute value} $arg_list { set attribute_index [lsearch -exact $attributes_full_list $attribute] if { $attribute_index > -1 } { - set attributes_arr($attribute) $value + set attributes_arr(${attribute}) $value lappend attributes_list $attribute if { [lsearch -exact $attributes_select_list $attribute ] > -1 } { # create a list to pass to qf_select without it balking at unknown parameters lappend select_list $attribute $value } } else { - ns_log Error "qf_choices: [string range $attribute 0 15] is not a valid attribute. invoke with attribute value pairs. Separate each with a space." + ns_log Error "qf_choices.1416: [string range ${attribute} 0 15] is not a valid attribute. invoke with attribute value pairs. Separate each with a space." ad_script_abort } } @@ -1390,7 +1647,7 @@ set attributes_arr(form_id) $__qf_arr(form_id) } if { [lsearch $__form_ids_list $attributes_arr(form_id)] == -1 } { - ns_log Error "qf_choice: unknown form_id $attributes_arr(form_id)" + ns_log Error "qf_choice.1428: unknown form_id $attributes_arr(form_id)" ad_script_abort } lappend select_list form_id $attributes_arr(form_id) @@ -1410,13 +1667,14 @@ if { $type eq "checkbox" } { # create wrapping tag set tag_wrapping "ul" - set args_html "<${tag_wrapping}" + set args_html "<" + append args_html $tag_wrapping foreach attribute $attributes_list { # ignore proc parameters that are not tag attributes if { $attribute eq "id" || $attribute eq "style" || $attribute eq "class" } { # quoting unquoted double quotes in attribute values, so as to not inadvertently break the tag - regsub -all -- {\"} $attributes_arr($attribute) {\"} attributes_arr($attribute) - append args_html " $attribute=\"$attributes_arr($attribute)\"" + regsub -all -- {\"} $attributes_arr(${attribute}) {\"} attributes_arr(${attribute}) + append args_html " " $attribute "=\"" $attributes_arr(${attribute}) "\"" } } append args_html ">\n" @@ -1447,9 +1705,12 @@ qf_input $input_attributes_list qf_append form_id $attributes_arr(form_id) html "" } - qf_append form_id $attributes_arr(form_id) html "${tag_wrapping}>\n" + set tag_wrapping_arg "" + append tag_wrapping_arg $tag_wrapping ">\n" + qf_append form_id $attributes_arr(form_id) html $tag_wrapping_arg } else { set args_html [qf_select $select_list] } return $args_html } +