ad_library { routines for creating, managing input via html forms @creation-date 21 Nov 2010 @cs-id $Id: } # use _ to clear a new default # use upvar to grab previous defaults and re-use (with qf_input only) # main namespace vars: # __form_input_arr = array that contains existing form input and defaults, only one form can be posted at a time # __form_ids_list = list that contains existing form ids # __form_ids_open_list = list that contains ids of forms that are not closed # __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) # 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. #use following to limit access to page requests via post.. to reduce vulnerability to url hack and insertion attacks from web: #if { [ad_conn method] != POST } { # ad_script_abort #} #also see patch: http://openacs.org/forums/message-view?message_id=182057 ad_proc -public qf_get_inputs_as_array { {form_array_name "__form_input_arr"} {duplicate_key_check "0"} } { get inputs from form submission, quotes all input values. use ad_unquotehtml to unquote a value. if duplicate_key_check is 1, checks if an existing key/value pair already exists, otherwise just overwrites. Overwriting is programmatically useful to overwrite preset defaults, for example. } { upvar 1 $form_array_name __form_input_arr # get form variables passed with connection set __form [ns_getform] if { $__form eq "" } { set __form_size 0 } else { set __form_size [ns_set size $__form] } #ns_log Notice "qf_get_inputs_as_array: 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}" # 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 Debug "qf_get_inputs_as_array: 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: attempt to insert unallowed characters to user input '{__form_key}'." } else { set __form_key [ad_quotehtml $__form_key] # The name of the argument passed in the form # no legitimate argument should be affected by quoting: # This is the value set __form_input [ad_quotehtml [ns_set value $__form $__form_counter_i]] # check for duplicate key? if { $duplicate_key_check && [info exists __form_input_arr($__form_key) ] } { if { $__form_input ne $__form_input_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}" ad_script_abort } else { ns_log Warning "qf_get_form_input: notice, form has two keys with same info.." } } else { set __form_input_arr($__form_key) $__form_input # ns_log Debug "qf_get_inputs_as_array: set ${form_array_name}($__form_key) '${__form_input}'." } # next key-value pair } } } ad_proc -public qf_remember_attributes { {arg1 "1"} } { changes qf_* form building procs to use the previous attribute values used with the last tag of same type (input,select,button etc). passing anything other than 0 defaults to 1 (true). } { upvar __qf_remember_attributes __qf_remember_attributes if { $arg1 eq 0 } { set __qf_remember_attributes 0 } else { set __qf_remember_attributes 1 } } ad_proc -public qf_form { {arg1 ""} {arg2 ""} {arg3 ""} {arg4 ""} {arg5 ""} {arg6 ""} {arg7 ""} {arg8 ""} {arg9 ""} {arg10 ""} {arg11 ""} {arg12 ""} {arg13 ""} {arg14 ""} {arg15 ""} {arg16 ""} {arg17 ""} {arg18 ""} } { initiates a form with form tag and supplied attributes. Returns an id. A clumsy url based id is provided if not passed (not recommended). } { # 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) 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 # if proc was passed a list of parameters, parse if { [llength $arg1] > 1 && [llength $arg2] == 0 } { set arg1_list $arg1 set lposition 1 foreach arg $arg1_list { set arg${lposition} $arg incr lposition } unset arg1_list } set attributes_tag_list [list action class id method name style target title] set attributes_full_list $attributes_tag_list lappend attributes_tag_list form_id set arg_list [list $arg1 $arg2 $arg3 $arg4 $arg5 $arg6 $arg7 $arg8 $arg9 $arg10 $arg11 $arg12 $arg13 $arg14 $arg15 $arg16 $arg17 $arg18] 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 if { [lsearch -exact $attributes_tag_list $attribute] > -1 } { lappend attributes_list $attribute } } elseif { $value eq "" } { # ignore } else { ns_log Error "qf_form: $attribute is not a valid attribute. invoke with attribute value pairs. Separate each with a space." } } if { ![info exists attributes_arr(method)] } { set attributes_arr(method) "post" } if { ![info exists __qf_remember_attributes] } { set __qf_remember_attributes 0 } if { ![info exists __form_ids_list] } { set __form_ids_list [list] } if { ![info exists __form_ids_open_list] } { set __form_ids_open_list [list] } # 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) } } } # every form gets a form_id set form_id_exists [info exists attributes_arr(form_id) ] if { $form_id_exists == 0 || ( $form_id_exists == 1 && $attributes_arr(form_id) eq "" ) } { 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]" } 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)" } # prepare attributes to process set tag_attributes_list [list] foreach attribute $attributes_list { 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) } } set tag_html "
\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] } } } ad_proc -public qf_read { {arg1 ""} {arg2 ""} } { returns the content of forms. If a form is not closed, returns the form in its partial state of completeness. If a form_id is supplied, returns the content of a specific form. Defaults to return all forms in a list. } { # use upvar to set form content, set/change defaults upvar 1 __form_ids_list __form_ids_list upvar 1 __form_arr __form_arr set attributes_full_list [list form_id] set arg_list [list $arg1 $arg2] 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 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." 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.." ad_script_abort } # normalize code using id instead of form_id if { [info exists attributes_arr(form_id)] } { set attributes_arr(id) $attributes_arr(form_id) unset attributes_arr(form_id) } # defaults to all form ids set form_id_exists [info exists attributes_arr(id)] if { $form_id_exists == 0 || ( $form_id_exists == 1 && $attributes_arr(form_id) eq "" ) } { # note, attributes_arr(id) might become a list or a scalar.. if { [llength $__form_ids_list ] == 1 } { set specified_1 1 set attributes_arr(form_id) [lindex $__form_ids_list 0] } else { set specified_1 0 set attributes_arr(form_id) $__form_ids_list } } else { set specified_1 1 } if { $specified_1 } { # a form specified in argument if { ![info exists __form_arr($attributes_arr(form_id)) ] } { ns_log Warning "qf_read: unknown form_id $attributes_arr(form_id)" } else { set form_s $__form_arr($attributes_arr(form_id)) } } else { set forms_list [list] foreach form_id $attributes_arr(form_id) { # 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" } else { lappend forms_list $__form_arr($form_id) } } set form_s $forms_list } return $form_s } ad_proc -public qf_input { {arg1 ""} {arg2 ""} {arg3 ""} {arg4 ""} {arg5 ""} {arg6 ""} {arg7 ""} {arg8 ""} {arg9 ""} {arg10 ""} {arg11 ""} {arg12 ""} {arg13 ""} {arg14 ""} {arg15 ""} {arg16 ""} {arg17 ""} {arg18 ""} {arg19 ""} {arg20 ""} {arg21 ""} {arg22 ""} {arg23 ""} {arg24 ""} {arg25 ""} {arg26 ""} {arg27 ""} {arg28 ""} {arg29 ""} {arg30 ""} {arg31 ""} {arg32 ""} } { creates a form input tag, supplying attributes where nonempty values are supplied. when using CHECKED, set the attribute to 1. allowed attributes: type accesskey align alt border checked class id maxlength name readonly size src tabindex value. other allowed: form_id label. label is used to wrap the input tag with a label tag containing a label that is associated with the input. checkbox and radio inputs present label after input tag, other inputs are preceeded by label. Omit label attribute to not use this feature. } { # 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) upvar 1 __form_ids_list __form_ids_list upvar 1 __form_arr __form_arr 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 set attributes_tag_list [list type accesskey align alt border checked class id maxlength name readonly size src tabindex value] set attributes_full_list $attributes_tag_list lappend attributes_full_list form_id label set arg_list [list $arg1 $arg2 $arg3 $arg4 $arg5 $arg6 $arg7 $arg8 $arg9 $arg10 $arg11 $arg12 $arg13 $arg14 $arg15 $arg16 $arg17 $arg18 $arg19 $arg20 $arg21 $arg22 $arg23 $arg24 $arg25 $arg26 $arg27 $arg28 $arg29 $arg30 $arg31 $arg32] 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 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. invoke with attribute value pairs. Separate each with a space." } } if { ![info exists __qf_remember_attributes] } { ns_log Error "qf_input(L801): invoked before qf_form or used in a different namespace than qf_form.." ad_script_abort } if { ![info exists __form_ids_list] } { ns_log Error "qf_input:(L805) invoked before qf_form or used in a different namespace than qf_form.." ad_script_abort } # 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)" 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) } } } # provide a blank value by default if { ![info exists attributes_arr(value)] } { set attributes_arr(value) "" } # prepare attributes to process set tag_attributes_list [list] foreach attribute $attributes_list { set __qf_arr(input_$attribute) $attributes_arr($attribute) lappend tag_attributes_list $attribute $attributes_arr($attribute) } # by default, wrap the input with a label tag for better UI if { [info exists attributes_arr(id) ] && [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 "" } else { set tag_html "" } } else { set tag_html "" } # set results __form_arr, we checked form_id above. append __form_arr($attributes_arr(form_id)) "${tag_html}\n" return } ad_proc -public qf_append { {arg1 ""} {arg2 ""} {arg3 ""} {arg4 ""} {arg5 ""} {arg6 ""} } { @param@ html @param@ form_id inserts html in a form by appending supplied html. if form_id supplied, appends form with supplied form_id. } { # 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) upvar 1 __form_ids_list __form_ids_list upvar 1 __form_arr __form_arr upvar 1 __qf_arr __qf_arr upvar 1 __form_ids_fieldset_open_list __form_ids_fieldset_open_list set attributes_full_list [list html form_id] set arg_list [list $arg1 $arg2 $arg3 $arg4 $arg5 $arg6] 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 lappend attributes_list $attribute } elseif { $value eq "" } { # do nothing } else { ns_log Error "qf_insert_html: $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_insert_html: invoked before qf_form or used in a different namespace than qf_form.." ad_script_abort } # default to last modified form_id set form_id_exists [info exists attributes_arr(form_id)] if { $form_id_exists == 0 || ( $form_id_exists == 1 && $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_insert_html: unknown form_id $attributes_arr(form_id)" ad_script_abort } # set results __form_arr, we checked form_id above. append __form_arr($attributes_arr(form_id)) $attributes_arr(html) return } ad_proc -private qf_insert_attributes { args_list } { returns args_list of tag attribute pairs (attribute,value) as html to be inserted into a tag } { set args_html "" foreach {attribute value} $args_list { if { [string range $attribute 1 1] eq "-" } { set $attribute [string range $attribute 1 end] } regsub -all -- {\"} $value {\"} value append args_html " $attribute=\"$value\"" } return $args_html } ad_proc -public qf_choice { {arg1 ""} {arg2 ""} {arg3 ""} {arg4 ""} {arg5 ""} {arg6 ""} {arg7 ""} {arg8 ""} {arg9 ""} {arg10 ""} {arg11 ""} {arg12 ""} {arg13 ""} {arg14 ""} {arg15 ""} {arg16 ""} {arg17 ""} {arg18 ""} {arg19 ""} {arg20 ""} {arg21 ""} {arg22 ""} {arg23 ""} {arg24 ""} } { returns html of a select/option bar or radio button list (where only 1 value is returned to a posted form). set "type" to "select" for select bar, or "radio" for radio buttons required attributes: name, value "selected" is not required, default is not selected, set "selected" to 1 to indicate item selected. if label not provided, value is used for label. "value" argument is a list_of_lists, each list item contains attribute/value pairs for a radio or option/bar item where the list_of_lists represents a list of OPTION tag attribute/value pairs. } { # 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) upvar 1 __form_ids_list __form_ids_list upvar 1 __form_arr __form_arr upvar 1 __qf_remember_attributes __qf_remember_attributes upvar 1 __qf_arr __qf_arr upvar 1 __form_ids_select_open_list __form_ids_select_open_list set attributes_select_list [list value accesskey align class cols name readonly rows style tabindex title wrap] set attributes_full_list $attributes_select_list lappend attributes_full_list type form_id id set arg_list [list $arg1 $arg2 $arg3 $arg4 $arg5 $arg6 $arg7 $arg8 $arg9 $arg10 $arg11 $arg12 $arg13 $arg14 $arg15 $arg16 $arg17 $arg18 $arg19 $arg20 $arg21 $arg22 $arg23 $arg24] set attributes_list [list] set select_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 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 } } elseif { $value eq "" } { # do nothing } else { ns_log Error "qf_select: [string range $attribute 0 15] is not a valid attribute. invoke with attribute value pairs. Separate each with a space." ad_script_abort } } # for passing select_list, we need to change id with form_id, since we left those off, we can just add form_id as id: if { [info exists $attributes_arr(form_id) ] } { lappend select_list id $attributes_arr(form_id) } # if attributes_arr(type) = select, then items are option tags wrapped by a select tag # if attributes_arr(type) = radio, then items are input tags, wrapped in a list for now # if needing to paginate radio buttons, build the radio buttons using qf_input directly. if { $attributes_arr(type) ne "radio" } { set type "select" } else { set type "radio" } # call qf_select if type is "select" instead of duplicating purpose of that code if { $type eq "radio" } { # create wrapping tag set tag_wrapping "ul" set args_html "<${tag_wrapping}" foreach {attribute value} $args_list { # ignore proc parameters that are not tag attributes if { $attribute ne "value" } { if { [string range $attribute 1 1] eq "-" } { set $attribute [string range $attribute 1 end] } # quoting unquoted double quotes in attribute values, so as to not inadvertently break the tag regsub -all -- {\"} $value {\"} value append args_html " $attribute=\"$value\"" } } append args_html ">\n" qf_insert_html $attributes_arr(form_id) $args_html set args_html "" # verify this is a list of lists. set list_length [llength $attributes_arr(value)] # test on the second input, less chance its a special case set second_input_attributes_count [llength [index $attributes_arr(value) 1]] if { $list_length > 1 && $second_input_attributes_count < 2 } { # a list was passed instead of a list of lists. Adjust.. set attributes_arr(value) [list $attributes_arr(value)] } foreach input_attributes_list $attributes_arr(value) { lappend input_attributes_list form_id $attribute_arr(form_id) qf_input $input_attributes_list } append args_html "${tag_wrapping}>" qf_insert_html $attributes_arr(form_id) $args_html } else { set args_html [qf_select $arg1 $arg2 $arg3 $arg4 $arg5 $arg6 $arg7 $arg8 $arg9 $arg10 $arg11 $arg12 $arg13 $arg14 $arg15 $arg16 $arg17 $arg18 $arg19 $arg20 $arg21 $arg22 $arg23 $arg24] } return $args_html } ad_proc -public qf_choices { {arg1 ""} {arg2 ""} {arg3 ""} {arg4 ""} {arg5 ""} {arg6 ""} {arg7 ""} {arg8 ""} {arg9 ""} {arg10 ""} {arg11 ""} {arg12 ""} {arg13 ""} {arg14 ""} {arg15 ""} {arg16 ""} {arg17 ""} {arg18 ""} {arg19 ""} {arg20 ""} {arg21 ""} {arg22 ""} {arg23 ""} {arg24 ""} } { returns html of a select/option bar or radio button list (where only 1 value is returned to a posted form). set "type" to "select" for select bar, or "checkbox" for checkboxes required attributes: name, value "selected" is not required, default is not selected, set "selected" to 1 to indicate item selected. if label not provided, value is used for label. "value" argument is a list_of_lists, each list item contains attribute/value pairs for a radio or option/bar item where the list_of_lists represents a list of OPTION tag attribute/value pairs. if label not provided, value is used for label. } { # 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) upvar 1 __form_ids_list __form_ids_list upvar 1 __form_arr __form_arr upvar 1 __qf_remember_attributes __qf_remember_attributes upvar 1 __qf_arr __qf_arr upvar 1 __form_ids_select_open_list __form_ids_select_open_list set attributes_select_list [list value accesskey align class cols name readonly rows style tabindex title wrap] set attributes_full_list $attributes_select_list lappend attributes_full_list type form_id id set arg_list [list $arg1 $arg2 $arg3 $arg4 $arg5 $arg6 $arg7 $arg8 $arg9 $arg10 $arg11 $arg12 $arg13 $arg14 $arg15 $arg16 $arg17 $arg18 $arg19 $arg20 $arg21 $arg22 $arg23 $arg24] set attributes_list [list] set select_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 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 } } elseif { $value eq "" } { # do nothing } else { ns_log Error "qf_select: [string range $attribute 0 15] is not a valid attribute. invoke with attribute value pairs. Separate each with a space." ad_script_abort } } # for passing select_list, we need to change id with form_id, since we left those off, we can just add form_id as id: if { [info exists $attributes_arr(form_id) ] } { lappend select_list id $attributes_arr(form_id) } # if attributes_arr(type) = select, then items are option tags wrapped by a select tag # if attributes_arr(type) = checkbox, then items are input tags, wrapped in a list for now # if needing to paginate checkboxes, build the checkboxes using qf_input directly. if { $attributes_arr(type) ne "checkbox" } { set type "select" } else { set type "checkbox" } # call qf_select if type is "select" instead of duplicating purpose of that code if { $type eq "checkbox" } { # create wrapping tag set tag_wrapping "ul" set args_html "<${tag_wrapping}" foreach {attribute value} $args_list { # ignore proc parameters that are not tag attributes if { $attribute ne "value" } { if { [string range $attribute 1 1] eq "-" } { set $attribute [string range $attribute 1 end] } # quoting unquoted double quotes in attribute values, so as to not inadvertently break the tag regsub -all -- {\"} $value {\"} value append args_html " $attribute=\"$value\"" } } append args_html ">\n" qf_insert_html $attributes_arr(form_id) $args_html set args_html "" # verify this is a list of lists. set list_length [llength $attributes_arr(value)] # test on the second input, less chance its a special case set second_input_attributes_count [llength [index $attributes_arr(value) 1]] if { $list_length > 1 && $second_input_attributes_count < 2 } { # a list was passed instead of a list of lists. Adjust.. set attributes_arr(value) [list $attributes_arr(value)] } foreach input_attributes_list $attributes_arr(value) { lappend input_attributes_list form_id $attribute_arr(form_id) qf_input $input_attributes_list } append args_html "${tag_wrapping}>" qf_insert_html $attributes_arr(form_id) $args_html } else { set args_html [qf_select $arg1 $arg2 $arg3 $arg4 $arg5 $arg6 $arg7 $arg8 $arg9 $arg10 $arg11 $arg12 $arg13 $arg14 $arg15 $arg16 $arg17 $arg18 $arg19 $arg20 $arg21 $arg22 $arg23 $arg24] } return $args_html }