- Publicity: Public Only All
element-procs.tcl
Form element procedures for the OpenACS Templating System
- Location:
- packages/acs-templating/tcl/element-procs.tcl
- Authors:
- Karl Goldstein <karlg@arsdigita.com>
- Stanislav Freidin <sfreidin@arsdigita.com>
- CVS Identification:
$Id: element-procs.tcl,v 1.40 2024/10/01 12:44:32 gustafn Exp $
Procedures in this file
- element (public, deprecated)
- template::element (public)
- template::element::copy_value_to_values_if_defined (private)
- template::element::create (public)
- template::element::error_p (public)
- template::element::exists (public)
- template::element::get_opts (private)
- template::element::get_property (public)
- template::element::get_reference (private)
- template::element::get_value (public)
- template::element::get_values (public)
- template::element::options (private)
- template::element::querygetall (public)
- template::element::render (private)
- template::element::render_help (private)
- template::element::set_error (public)
- template::element::set_properties (public)
- template::element::set_value (public)
- template::element::set_values (public)
- template::element::validate (private)
Detailed information
element (public, deprecated)
element command form_id element_id [ args... ]
Deprecated. Invoking this procedure generates a warning.
element is really template::element although when in the "template" namespace you may omit the template:: qualifier. See the template::form API for creating the form element container. DEPRECATED: please use the properly namespaced api
- Parameters:
- command (required)
- form_id (required)
- element_id (required)
- See Also:
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element (public)
template::element command form_id element_id [ args... ]
Manage elements of form objects.
see the individual commands for further information.
- Parameters:
- command (required)
- one of create, error_p, exists, get_property, get_value, get_values, querygetall, set_error, set_properties, set_value
- form_id (required)
- string identifying the form
- element_id (required)
- string identifying the element
- See Also:
- template::element::create
- template::element::error_p
- template::element::exists
- template::element::get_property
- template::element::get_value
- template::element::get_values
- template::element::querygetall
- template::element::set_error
- template::element::set_properties
- template::element::set_value
- template::form
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- template_widget_file
template::element::copy_value_to_values_if_defined (private)
template::element::copy_value_to_values_if_defined
define values from value, if the latter is more defined
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::create (public)
template::element::create form_id element_id [ args... ]
Append an element to a form object. If a submission is in progress, values for the element are prepared and validated.
- Parameters:
- Options:
- form_id (required)
- The identifier of the form to which the element is to be added. The form must have been previously created with a form create statement.
- element_id (required)
- A keyword identifier for the element that is unique in the context of the form.
- -widget
- The name of an input widget for the element. Valid widgets must have a rendering procedure defined in the template::widget namespace.
- -datatype
- The name of a datatype for the element values. Valid datatypes must have a validation procedure defined in the template::data::validate namespace.
- -label
- The label for the form element.
- -html
- A list of name-value attribute pairs to include in the HTML tag for widget. Typically used for additional formatting options, such as cols or rows, or for JavaScript handlers.
- -maxlength
- The maximum allowable length in bytes. Will be checked using 'string bytelength'. Will also cause 'input' widgets (text, integer, etc.) to get a maxlength="..." attribute.
- -options
- A list of options for select lists and button groups (check boxes or radio buttons). The list contains two-element lists in the form { {label value} {label value} {label value} ...}
- -fieldset
- A list of name-value attribute pairs to include in the HTML tag for checkboxes and radio FIELDSET.
- -legend
- A list of name-value attribute pairs to include in the HTML tag for checkboxes and radio LEGEND.
- -legendtext
- A text for the LEGEND tag to include in the checkboxes and radio FIELDSET block
- -value
- The default value of the element
- -values
- The default values of the element, where multiple values are allowed (checkbox groups and multiselect widgets)
- -validate
- A list of custom validation blocks in the form {name { script } { message } name { script } { message } ...} where name is a unique identifier for the validation step, expression is a block to Tcl code (script) that should set the result to 1 or 0, and message is to be displayed to the user when the validation step fails, that is, if the expression evaluates to 0. Use the special variable $value to refer to the value entered by the user in that field. Note that e.g. in ad_form, all blocks are substituted, therefore, the script might require escaping.
- -sign
- Specify for a hidden widget that its value should be signed
- -help_text
- Text displayed with the element
- -help
- Display helpful hints (date widget only?)
- -optional
- A flag indicating that no value is required for this element. If a default value is specified, the default is used instead.
- -mode
- Valid values are 'display', 'edit', and the empty string. If set to 'display', the element will render as static HTML which doesn't allow editing of the value, instead of the HTML form element (e.g. <input>) which would otherwise get used. If set to 'edit', the element is as normal, allowing the user to edit the contents. If set to the empty string or not specified at all, the form's 'mode' setting is used instead.
- -nospell
- A flag indicating that no spell-checking should be performed on this element. This overrides the 'SpellcheckFormWidgets' parameter.
- -noquote
- A flag indicating that no value should not be quoted in a form. In addition, the nonquoted inform field is not transmitted as a hidden field (which can be attacked via noquote). Currently only supported by the "inform" widget type.
- -before_html
- A chunk of HTML displayed immediately before the rendered element.
- -after_html
- A chunk of HTML displayed immediately after the rendered element.
- -display_value
- Alternative value used when the element is in display mode. If specified, this value is used when the mode is set to 'display', instead of asking the element widget to render itself in display mode.
- -multiple
- A flag indicating that more than one value is expected from the input element
- -format
- Many form elements allow one to specify a format, e.g. a way the element should be displayed or interpret its value. Refer to the specific widgets for the actual behavior.
- -section
- Specify to which form section this element belongs
- -htmlarea_p
- Only relevant for textarea kind of elements, tells if the element is supposed to be rendered as a richtext editor or not.
- See Also:
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- template_widget_file
template::element::error_p (public)
template::element::error_p form_id element_id
Return true if the named element has an error set. Helpful for client code that wants to avoid overwriting an initial error message.
- Parameters:
- form_id (required)
- The identifier of the form containing the element.
- element_id (required)
- The unique identifier of the element with which the error message should be associated in the form template.
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::exists (public)
template::element::exists form_id element_id
Determine if an element exists in a specified form
- Parameters:
- form_id (required)
- The identifier of the form containing the element.
- element_id (required)
- The unique identifier of the element within the form.
- Returns:
- 1 if the element exists in the form, or 0 otherwise
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::get_opts (private)
template::element::get_opts [ -widget widget ] [ -datatype datatype ] \ [ -label label ] [ -html html ] [ -maxlength maxlength ] \ [ -options options ] [ -fieldset fieldset ] [ -legend legend ] \ [ -legendtext legendtext ] [ -value value ] [ -values values ] \ [ -validate validate ] [ -sign ] [ -help_text help_text ] \ [ -help ] [ -optional ] [ -mode mode ] [ -nospell ] [ -noquote ] \ [ -before_html before_html ] [ -after_html after_html ] \ [ -display_value display_value ] [ -multiple ] [ -format format ] \ [ -section section ] [ -htmlarea_p htmlarea_p ] [ args... ]
template::element::create syntax requires first two non-positional arguments (form and element name), then a set of named-argument flags to transform into options. This is not the native Tcl syntax, where named-arguments come before unnamed ones. To use native Tcl argument parsing for remaining flags, we create this internal utility.
- Switches:
- -widget (optional)
- -datatype (optional)
- -label (optional)
- -html (optional)
- -maxlength (optional)
- -options (optional)
- -fieldset (optional)
- -legend (optional)
- -legendtext (optional)
- -value (optional)
- -values (optional)
- -validate (optional)
- -sign (optional, boolean)
- -help_text (optional)
- -help (optional, boolean)
- -optional (optional, boolean)
- -mode (optional)
- -nospell (optional, boolean)
- -noquote (optional, boolean)
- -before_html (optional)
- -after_html (optional)
- -display_value (optional)
- -multiple (optional, boolean)
- -format (optional)
- -section (optional)
- -htmlarea_p (optional)
- Returns:
- a dict of options
- See Also:
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::get_property (public)
template::element::get_property form_id element_id property
Retrieves the specified property of the element, such as value, datatype, widget, etc.
- Parameters:
- form_id (required)
- The identifier of the form containing the element.
- element_id (required)
- The unique identifier of the element.
- property (required)
- The property to be retrieved
- Returns:
- The value of the property, or "" if the property does not exist
- See Also:
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::get_reference (private)
template::element::get_reference
Gets a reference to the array containing the properties of an element, and throws and error if the element does not exist. Called at the beginning of several of the element commands.
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::get_value (public)
template::element::get_value form_id element_id
Retrieves the current value of an element. Typically used following a valid form submission to retrieve the submitted value.
- Parameters:
- form_id (required)
- The identifier of the form containing the element.
- element_id (required)
- The unique identifier of the element.
- Returns:
- The current value of the element.
- See Also:
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::get_values (public)
template::element::get_values form_id element_id
Retrieves the list current values for an element. Typically used following a valid form submission where multiple values may have been submitted for a single element (i.e. for a checkbox group or multiple select box).
- Parameters:
- form_id (required)
- The identifier of the form containing the element.
- element_id (required)
- The unique identifier of the element.
- Returns:
- A list of current values for the element.
- See Also:
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::options (private)
template::element::options form_id element_id tag_attributes
Prepares a multirow data source for use within a formgroup
- Parameters:
- form_id (required)
- The identifier of the form containing the element.
- element_id (required)
- The unique identifier of the element within the form.
- tag_attributes (required)
- A name-value list of additional HTML attributes to include in the INPUT tags for each radio button or checkbox, such as JavaScript handlers or special formatting.
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::querygetall (public)
template::element::querygetall element_ref
Get all values for an element, performing any transformation defined for the datatype.
- Parameters:
- element_ref (required)
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::render (private)
template::element::render form_id element_id tag_attributes
Generate the HTML for a particular form widget.
- Parameters:
- form_id (required)
- The identifier of the form containing the element.
- element_id (required)
- The unique identifier of the element within the form.
- tag_attributes (required)
- A name-value list of additional HTML attributes to include in the tag, such as JavaScript handlers or special formatting (i.e. ROWS and COLS for a TEXTAREA).
- Returns:
- A string containing the HTML for an INPUT, SELECT or TEXTAREA form element.
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::render_help (private)
template::element::render_help form_id element_id tag_attributes
Render the -help_text text
- Parameters:
- form_id (required)
- The identifier of the form containing the element.
- element_id (required)
- The unique identifier of the element within the form.
- tag_attributes (required)
- Reserved for future use.
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::set_error (public)
template::element::set_error form_id element_id message
Manually set an error message for an element. This may be used to implement validation filters that involve more than one form element ("Sorry, blue is not available for the model you selected, please choose another color.")
- Parameters:
- form_id (required)
- The identifier of the form containing the element.
- element_id (required)
- The unique identifier of the element with which the error message should be associated in the form template.
- message (required)
- The text of the error message.
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- template_widget_file
template::element::set_properties (public)
template::element::set_properties form_id element_id [ args... ]
Modify properties of an existing element. The same options may be used as with the create command. Most commonly used to set the default value for an element when a form page is initially requested.
- Parameters:
- form_id (required)
- The identifier of the form containing the element.
- element_id (required)
- The unique identifier of the element.
- See Also:
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::set_value (public)
template::element::set_value form_id element_id value
Sets the value of an element
- Parameters:
- form_id (required)
- The identifier of the form containing the element.
- element_id (required)
- The unique identifier of the element.
- value (required)
- The value to apply
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::set_values (public)
template::element::set_values form_id element_id values
Sets the list of values of an element
- Parameters:
- form_id (required)
- The identifier of the form containing the element.
- element_id (required)
- The unique identifier of the element.
- values (required)
- The list of values to apply
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
template::element::validate (private)
template::element::validate form_id element_id
Validates element values according to 3 criteria:
- required elements must have a not-null value;
- values must match the element's declared datatype;
- values must pass all special validation filters specified with the -validate option when the element was created.
If validation fails for any reason, one or more messages are added to the error list for the form, causing the submission to be invalidated and returned to the user for correction.
- Parameters:
- form_id (required)
- The identifier of the form containing the element.
- element_id (required)
- The unique identifier of the element.
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- No testcase defined.
Content File Source
ad_library { Form element procedures for the OpenACS Templating System @author Karl Goldstein (karlg@arsdigita.com) @author Stanislav Freidin (sfreidin@arsdigita.com) @cvs-id $Id: element-procs.tcl,v 1.40 2024/10/01 12:44:32 gustafn Exp $ } # Copyright (C) 1999-2000 ArsDigita Corporation # # This is free software distributed under the terms of the GNU Public # License. Full text of the license is available from the GNU Project: # http://www.fsf.org/copyleft/gpl.html namespace eval template {} namespace eval template::element {} ad_proc -deprecated element { command form_id element_id args } { element is really template::element although when in the "template" namespace you may omit the template:: qualifier. See the template::form API for creating the form element container. DEPRECATED: please use the properly namespaced api @see template::element @see template::form @see template::element } - ad_proc -public template::element { command form_id element_id args } { Manage elements of form objects. <p> see the individual commands for further information. @param command one of create, error_p, exists, get_property, get_value, get_values, querygetall, set_error, set_properties, set_value @param form_id string identifying the form @param element_id string identifying the element @see template::element::create @see template::element::error_p @see template::element::exists @see template::element::get_property @see template::element::get_value @see template::element::get_values @see template::element::querygetall @see template::element::set_error @see template::element::set_properties @see template::element::set_value @see template::form } { template::element::$command $form_id $element_id {*}$args } d_proc -private template::element::get_opts { -widget -datatype -label -html -maxlength -options -fieldset -legend -legendtext -value -values -validate -sign:boolean -help_text -help:boolean -optional:boolean -mode -nospell:boolean -noquote:boolean -before_html -after_html -display_value -multiple:boolean -format -section -htmlarea_p args } { template::element::create syntax requires first two non-positional arguments (form and element name), then a set of named-argument flags to transform into options. This is not the native Tcl syntax, where named-arguments come before unnamed ones. To use native Tcl argument parsing for remaining flags, we create this internal utility. @see template::element::create @return a dict of options } { set opts [list] # ## These are the documented options we expect in widgets. We know ## exactly which are key value pairs and which ones are one-valued ## booleans # set flags { widget datatype label html maxlength options fieldset legend legendtext value values validate help_text mode before_html after_html display_value format section htmlarea_p } set booleans { sign help optional nospell noquote multiple } foreach flag $flags { if {[info exists $flag]} { dict set opts $flag [set $flag] } } foreach boolean $booleans { if {[set ${boolean}_p]} { dict set opts $boolean 1 } } # ## If additional args are found, we might deal with custom options ## from user-defined widgets. We treat all of those as name value ## pairs. ## TODO: one could consider having custom argument parsers for ## those widgets. # while {[llength $args] > 0} { set arg [string range [lindex $args 0] 1 end] if {![dict exists $opts $arg]} { # Collect this name value pair as a custom option set name $arg set value [lindex $args 1] dict set opts $name $value #ad_log notice "Collecting custom option for template::element name=$name, value=$value" } if {$arg in $booleans} { # When this is one of the known booleans, just skip one # argument. set args [lrange $args 1 end] } else { # In all other cases, skip 2 arguments (treat options as # name value pairs). set args [lrange $args 2 end] } } # After parsing of custom arguments, the list should be # empty. That we still have stuff in there means something is not # ok with the element specs. if {[llength $args] > 0} { ad_log warning "Ignoring undocumented args for template::element $args" } return $opts } ad_proc -public template::element::create { form_id element_id args } { Append an element to a form object. If a submission is in progress, values for the element are prepared and validated. @param form_id The identifier of the form to which the element is to be added. The form must have been previously created with a <tt>form create</tt> statement. @param element_id A keyword identifier for the element that is unique in the context of the form. @option widget The name of an input widget for the element. Valid widgets must have a rendering procedure defined in the <tt>template::widget</tt> namespace. @option datatype The name of a datatype for the element values. Valid datatypes must have a validation procedure defined in the <tt>template::data::validate</tt> namespace. @option label The label for the form element. @option html A list of name-value attribute pairs to include in the HTML tag for widget. Typically used for additional formatting options, such as <tt>cols</tt> or <tt>rows</tt>, or for JavaScript handlers. @option maxlength The maximum allowable length in bytes. Will be checked using 'string bytelength'. Will also cause 'input' widgets (text, integer, etc.) to get a maxlength="..." attribute. @option options A list of options for select lists and button groups (check boxes or radio buttons). The list contains two-element lists in the form { {label value} {label value} {label value} ...} @option fieldset A list of name-value attribute pairs to include in the HTML tag for checkboxes and radio FIELDSET. @option legend A list of name-value attribute pairs to include in the HTML tag for checkboxes and radio LEGEND. @option legendtext A text for the LEGEND tag to include in the checkboxes and radio FIELDSET block @option value The default value of the element @option values The default values of the element, where multiple values are allowed (checkbox groups and multiselect widgets) @option validate A list of custom validation blocks in the form {name { script } { message } \ name { script } { message } ...} where name is a unique identifier for the validation step, expression is a block to Tcl code (script) that should set the result to 1 or 0, and message is to be displayed to the user when the validation step fails, that is, if the expression evaluates to 0. Use the special variable <tt>$value</tt> to refer to the value entered by the user in that field. Note that e.g. in ad_form, all blocks are substituted, therefore, the script might require escaping. @option sign Specify for a hidden widget that its value should be signed @option help_text Text displayed with the element @option help Display helpful hints (date widget only?) @option optional A flag indicating that no value is required for this element. If a default value is specified, the default is used instead. @option mode Valid values are 'display', 'edit', and the empty string. If set to 'display', the element will render as static HTML which doesn't allow editing of the value, instead of the HTML form element (e.g. <input>) which would otherwise get used. If set to 'edit', the element is as normal, allowing the user to edit the contents. If set to the empty string or not specified at all, the form's 'mode' setting is used instead. @option nospell A flag indicating that no spell-checking should be performed on this element. This overrides the 'SpellcheckFormWidgets' parameter. @option noquote A flag indicating that no value should not be quoted in a form. In addition, the nonquoted inform field is not transmitted as a hidden field (which can be attacked via noquote). Currently only supported by the "inform" widget type. @option before_html A chunk of HTML displayed immediately before the rendered element. @option after_html A chunk of HTML displayed immediately after the rendered element. @option display_value Alternative value used when the element is in display mode. If specified, this value is used when the mode is set to 'display', instead of asking the element widget to render itself in display mode. @option multiple A flag indicating that more than one value is expected from the input element @option format Many form elements allow one to specify a format, e.g. a way the element should be displayed or interpret its value. Refer to the specific widgets for the actual behavior. @option section Specify to which form section this element belongs @option htmlarea_p Only relevant for textarea kind of elements, tells if the element is supposed to be rendered as a richtext editor or not. @see template::widget @see template::data::validate @see template::form::create @see template::form::section } { set level [template::adp_level] # add the element to the element list upvar #$level $form_id:elements elements $form_id:properties form_properties if { ! [info exists elements] } { error "Form $form_id does not exist" } lappend elements $form_id:$element_id lappend form_properties(element_names) $element_id # add the reference to the elements lookup array for the form upvar #$level $form_id:$element_id opts if {[info exists opts]} { error "Element '$element_id' already exists in form '$form_id'." } set opts(id) $element_id set opts(form_id) $form_id # ensure minimal defaults for element parameters variable defaults array set opts $defaults # By default, the form/edit mode is set to the empty string # Can be set to something else if you want set opts(mode) {} # set the form section set opts(section) $form_properties(section) if { $opts(section) ne "" } { array set opts {sec_fieldset "" sec_legend "" sec_legendtext ""} if {[info exists form_properties(sec_fieldset)]} {set opts(sec_fieldset) $form_properties(sec_fieldset)} if {[info exists form_properties(sec_legend)]} {set opts(sec_legend) $form_properties(sec_legend)} if {[info exists form_properties(sec_legendtext)]} {set opts(sec_legendtext) $form_properties(sec_legendtext)} } if {[llength $args] > 0} { array set opts [::template::element::get_opts {*}$args] } # set a name if none specified if { ! [info exists opts(name)] } { set opts(name) $opts(id) } # set a label if none specified if { ! [info exists opts(label)] } { set opts(label) $element_id } # If the widget is a submit widget, remember it # All submit widgets are optional if { $opts(widget) eq "submit" || $opts(widget) eq "button" } { set form_properties(has_submit) 1 set opts(optional) 1 if { ! [info exists opts(value)] } { set opts(value) $opts(label) } if { ! [info exists opts(label)] } { set opts(label) $opts(value) } } # If the widget is a checkbox or radio widget, set attributes if { $opts(widget) eq "radio" || $opts(widget) eq "checkbox" } { # If there's no legend text, no point to generate the fieldset if { ![info exists opts(legendtext)] } { if { [info exists opts(legend)] || [info exists opts(fieldset)] } { ns_log Warning "template::element::create (form: $form_id, element: $opts(name)): you set fieldset and/or legend properties but not the legendtext one. You must provide text for the legend tag." } } else { # set fieldset attributes if { ![info exists opts(fieldset)] } { set opts(fieldset) {} } array set fs_attributes $opts(fieldset) set fs_options "" if {![info exists fs_attributes(class)]} { append fs_options " class=\"form-fieldset\"" } foreach name [array names fs_attributes] { if {$fs_attributes($name) eq ""} { append fs_options " $name" } else { append fs_options " $name=\"$fs_attributes($name)\"" } } set opts(fieldset) $fs_options # set legend attributes if { ![info exists opts(legend)] } { set opts(legend) "" } array set lg_attributes $opts(legend) set lg_options "" foreach name [array names lg_attributes] { if {$lg_attributes($name) eq ""} { append lg_options " $name" } else { append lg_options " $name=\"$lg_attributes($name)\"" } } set opts(legend) $lg_options } } # Remember that the element has not been rendered yet set opts(is_rendered) f copy_value_to_values_if_defined # check for submission if { [template::form is_submission $form_id] || [info exists opts(param)] } { if {[info exists opts(param)]} { ad_log warning "Outdated and deprecated form options detected," \ "The usage of opts(param) will be removed in versions past 5.10.1" } validate $form_id $element_id } elseif { [ns_queryget "__edit"] ne "" } { # If the magic __edit button was hit, try to get values from the form still # but don't do any validation set opts(values) [querygetall opts] ad_log warning "This if-branch is insecure since it bypasses validation." \ "the branch is deactivated rigjt now, and there is no know usage" \ "of the __edit flag. If you still need it, uncomment the following line" \ "and contact webmaster@openacs.org" error "Outdated and vulnerable code detected, contact webmaster@openacs.org" # be careful not to clobber a default value if one has been specified if { [llength $opts(values)] || ! [info exists opts(value)] } { set opts(value) [lindex $opts(values) 0] } } if { $opts(widget) eq "hidden" && [info exists opts(sign)] && $opts(sign) } { if {[info exists opts(value)] } { set val $opts(value) } else { set val "" } template::element::create $opts(form_id) $opts(id):sig \ -datatype text \ -widget hidden \ -section $opts(section) \ -value [ad_sign $val] } } ad_proc -public template::element::set_properties { form_id element_id args } { Modify properties of an existing element. The same options may be used as with the create command. Most commonly used to set the default value for an element when a form page is initially requested. @param form_id The identifier of the form containing the element. @param element_id The unique identifier of the element. @see template::element::create } { get_reference # create a reference to opts as expected by get_opts upvar 0 element opts template::util::get_opts $args if { $opts(widget) eq "hidden" && [info exists opts(sign)] && $opts(sign) && [info exists opts(value)] } { if { [template::element::exists $form_id $element_id:sig] } { template::element::set_properties $form_id $element_id:sig \ -value [ad_sign $opts(value)] } else { template::element::create $form_id $element_id:sig \ -datatype text \ -widget hidden \ -value [ad_sign $opts(value)] } } copy_value_to_values_if_defined } ad_proc -public template::element::set_value { form_id element_id value } { Sets the value of an element @param form_id The identifier of the form containing the element. @param element_id The unique identifier of the element. @param value The value to apply } { get_reference set element(value) $value set element(values) [list $value] } ad_proc -public template::element::set_values { form_id element_id values } { Sets the list of values of an element @param form_id The identifier of the form containing the element. @param element_id The unique identifier of the element. @param values The list of values to apply } { get_reference set element(values) $values } ad_proc -public template::element::get_value { form_id element_id } { Retrieves the current value of an element. Typically used following a valid form submission to retrieve the submitted value. @param form_id The identifier of the form containing the element. @param element_id The unique identifier of the element. @return The current value of the element. @see template::element::get_values } { get_reference if { [info exists element(value)] } { regsub {<script>} $element(value) {\<\s\c\r\i\p\t\>} element(value) return $element(value) } else { return "" } } ad_proc -public template::element::get_values { form_id element_id } { Retrieves the list current values for an element. Typically used following a valid form submission where multiple values may have been submitted for a single element (i.e. for a checkbox group or multiple select box). @param form_id The identifier of the form containing the element. @param element_id The unique identifier of the element. @return A list of current values for the element. @see template::element::get_value } { get_reference regsub {<script>} $element(values) {\<\s\c\r\i\p\t\>} element(values) return $element(values) } ad_proc -public template::element::get_property { form_id element_id property } { Retrieves the specified property of the element, such as value, datatype, widget, etc. @param form_id The identifier of the form containing the element. @param element_id The unique identifier of the element. @param property The property to be retrieved @return The value of the property, or "" if the property does not exist @see template::element::set_properties } { get_reference if { ![info exists element($property)] } { return "" } else { return $element($property) } } ad_proc -private template::element::validate { form_id element_id } { Validates element values according to 3 criteria: <ol> <li>required elements must have a not-null value; <li>values must match the element's declared datatype; <li>values must pass all special validation filters specified with the -validate option when the element was created. </ol> <p> If validation fails for any reason, one or more messages are added to the error list for the form, causing the submission to be invalidated and returned to the user for correction. @param form_id The identifier of the form containing the element. @param element_id The unique identifier of the element. } { set level [template::adp_level] # use an array to hold error messages for this form upvar #$level $form_id:error formerror $form_id:$element_id element # set values [querygetall $element(id) $element(datatype)] set values [querygetall element] set is_optional [info exists element(optional)] # if the element is optional and the value is an empty string, then ignore if { $is_optional && [lindex $values 0] eq "" } { set values [list] # also clobber the value(s) for a submit widget if {$element(widget) eq "submit"} { if { [info exists element(value)] } { unset element(value) } if { [info exists element(values)] } { unset element(values) } } } # if no values were submitted then look for values specified in the # declaration (either values or value) if { [llength $values] == 0 && [info exists element(values)] } { set values $element(values) } # set a label for use in the template set label $element(label) if {$label eq ""} { set label $element(name) } # Element shouldn't be validated if it's an inform widget, or the # element is not in edit mode. The element will be in edit mode if # its mode is either blank or set to 'edit'. set is_inform [expr {$element(widget) eq "inform" || ($element(mode) ne "edit" && $element(mode) ne "" )}] # Check for required element if { ! $is_inform && ! $is_optional && ![llength $values] } { # no value was submitted for a required element set formerror($element_id) [_ acs-templating.Element_is_required] set formerror($element_id:required) [_ acs-templating.Element_is_required] if {$element(widget) in {hidden submit}} { ad_log warning "template::element::validate: No value for $element(widget) element $label" } } # Prepare custom validation filters if { [info exists element(validate)] } { set v_length [llength $element(validate)] if { $v_length == 2 } { # a single anonymous validation check was specified set element(validate) [linsert $element(validate) 0 "anonymous"] } elseif { $v_length % 3 } { error "Invalid number of parameters to validate option: $element(validate) (Length is $v_length)" } } else { set element(validate) [list] } set v_errors [list] foreach value $values { # # Something was submitted, now check if it is valid. # if { $is_optional && $value eq "" } { # # This is an optional field and it's empty... Skip # validation (else things like the integer test will # fail). # continue } if { [info exists element(maxlength)] } { # # A maximum length was specified for this element. Make # sure it is respected first. # # Tcl9 does not include "string bytelength". Use idiom # from Rolf Ade's Tcl9 migration guide instead. #set value_bytelength [string bytelength $value] set value_bytelength [string length [encoding convertto utf-8 $value]] if { $value_bytelength > $element(maxlength) } { # # The element is too long. # set excess_no_bytes [expr { $value_bytelength - $element(maxlength) }] if { $excess_no_bytes == 1 } { set message [_ acs-templating.Element_is_too_long_Singular] } else { set message [_ acs-templating.Element_is_too_long_Plural] } lappend v_errors $message set formerror($element_id:maxlength) $message } } if { ! [template::data::validate $element(datatype) value message] } { # # The submission is formally invalid according to datatype # validation. # lappend v_errors $message set formerror($element_id:data) $message if { $element(widget) in {hidden submit} } { ad_log warning "template::element::validate: Invalid value for $element(widget) element $label: $message" } } else { # # The submission is formally valid. Now go through the # custom user-defined validation. # foreach { v_name v_code v_message } $element(validate) { if { ! [eval $v_code] } { # # Value is invalid according to custom validation # code. Do some expansion on $value, ${value}, # $label, and ${label} # set v_message [util::var_subst_quotehtml $v_message] lappend v_errors $v_message set formerror($element_id:$v_name) $v_message } } } } if { [llength $v_errors] } { # concatenate all validation errors encountered while looping over values set formerror($element_id) [join $v_errors "<br>\n"] } # make the value be the previously submitted value when returning the form set element(values) $values # be careful not to clobber a default value if one has been specified if { [llength $values] || ! [info exists element(value)] } { set element(value) [lindex $values 0] } } ad_proc -public template::element::set_error { form_id element_id message } { Manually set an error message for an element. This may be used to implement validation filters that involve more than one form element ("Sorry, blue is not available for the model you selected, please choose another color.") @param form_id The identifier of the form containing the element. @param element_id The unique identifier of the element with which the error message should be associated in the form template. @param message The text of the error message. } { set level [template::adp_level] upvar #$level $form_id:error formerror # set the message set formerror($element_id) $message } ad_proc -public template::element::error_p { form_id element_id } { Return true if the named element has an error set. Helpful for client code that wants to avoid overwriting an initial error message. @param form_id The identifier of the form containing the element. @param element_id The unique identifier of the element with which the error message should be associated in the form template. } { set level [template::adp_level] upvar #$level $form_id:error formerror # set the message return [info exists formerror($element_id)] } ad_proc -public template::element::querygetall { element_ref } { Get all values for an element, performing any transformation defined for the datatype. } { upvar $element_ref element set datatype $element(datatype) set transform_proc "::template::data::transform::$datatype" if {[namespace which $transform_proc] eq ""} { set values [ns_querygetall $element(id)] # QUIRK: ns_querygetall returns a single-element list {{}} for no values if { [string equal $values {{}}] } { set values [list] } } else { set values [template::data::transform::$datatype element] } # Spell-checker array set spellcheck [template::util::spellcheck::spellcheck_properties -element_ref element] if { $spellcheck(perform_p) } { set values [template::data::transform::spellcheck -element_ref element -values $values] } return $values } ad_proc -public template::element::exists { form_id element_id } { Determine if an element exists in a specified form @param form_id The identifier of the form containing the element. @param element_id The unique identifier of the element within the form. @return 1 if the element exists in the form, or 0 otherwise } { set level [template::adp_level] upvar #$level $form_id:$element_id element_properties return [info exists element_properties] } ad_proc -private template::element::get_reference {} { Gets a reference to the array containing the properties of an element, and throws and error if the element does not exist. Called at the beginning of several of the element commands. } { uplevel { set level [template::adp_level] upvar #$level $form_id:$element_id element if { ! [array exists element] } { error "Element \"$element_id\" does not exist in form \"$form_id\"" } } } ad_proc -private template::element::render { form_id element_id tag_attributes } { Generate the HTML for a particular form widget. @param form_id The identifier of the form containing the element. @param element_id The unique identifier of the element within the form. @param tag_attributes A name-value list of additional HTML attributes to include in the tag, such as JavaScript handlers or special formatting (i.e. ROWS and COLS for a TEXTAREA). @return A string containing the HTML for an INPUT, SELECT or TEXTAREA form element. } { get_reference # Remember that the element has been rendered already set element(is_rendered) t if { $element(mode) ne "edit" && [info exists element(display_value)] && $element(widget) ne "hidden" } { return "$element(before_html) $element(display_value) $element(after_html)" } else { return "[string trim "$element(before_html) [template::widget::$element(widget) element $tag_attributes] $element(after_html)"]" } } ad_proc -private template::element::render_help { form_id element_id tag_attributes } { Render the -help_text text @param form_id The identifier of the form containing the element. @param element_id The unique identifier of the element within the form. @param tag_attributes Reserved for future use. } { get_reference return $element(help_text) } ad_proc -private template::element::options { form_id element_id tag_attributes } { Prepares a multirow data source for use within a formgroup @param form_id The identifier of the form containing the element. @param element_id The unique identifier of the element within the form. @param tag_attributes A name-value list of additional HTML attributes to include in the INPUT tags for each radio button or checkbox, such as JavaScript handlers or special formatting. } { get_reference if { ! [info exists element(options)] } { error "No options specified for element $element_id in form $form_id" } # Remember that the element has been rendered already set element(is_rendered) t # render the widget once with a placeholder for value set element(value) "\$value" lappend tag_attributes "\$checked" "" set widget "$element(before_html) [template::widget::$element(widget) element $tag_attributes] $element(after_html)" set options $element(options) if { [info exists element(values)] } { template::util::list_to_lookup $element(values) values } # the data source is named formgroup by convention upvar #$level formgroup:rowcount rowcount set rowcount [llength $options] # Create a widget entry for each checkbox in the group for { set i 1 } { $i <= $rowcount } { incr i } { upvar #$level formgroup:$i formgroup set option [lindex $options $i-1] set value [lindex $option 1] if { ![info exists values($value)] } { set checked "" } else { set checked "checked=\"checked\"" } set formgroup(label) [lindex $option 0] set formgroup(widget) [subst $widget] set formgroup(rownum) $i set formgroup(checked) $checked set formgroup(option) $value } } ad_proc -private template::element::copy_value_to_values_if_defined {} { define values from value, if the latter is more defined } { upvar opts opts # opts(values) is always defined, init to "" from template::element::defaults if { [info exists opts(value)] && [llength $opts(values)] == 0 } { # # GN: the following test is broken, since "opts(value)" is never # empty; ... but changing this to a comparison with $opts(value) # breaks eg ad_form. # if { [string equal opts(value) {}] } { set opts(values) [list] } else { set opts(values) [list $opts(value)] } } } # Local variables: # mode: tcl # tcl-indent-level: 4 # indent-tabs-mode: nil # End: