%3 ::xowiki::formfield::FormField ::xowiki::formfield::FormField → fc_decode → fc_encode → get_from_name → get_single_spec → interprete_condition CSSclass_list_add add_statistics answer_check=AND answer_check=answer_words answer_check=btwn answer_check=contains answer_check=contains-not answer_check=eq answer_check=ge answer_check=gt answer_check=in answer_check=le answer_check=lt answer_check=match answer_is_correct asWidgetSpec behavior booleanAttributes config_from_spec convert_to_external convert_to_internal describe dict_to_fc dict_to_spec dict_value escape_message_keys field_value handle_transmit_always has_instance_variable init initialize interprete_single_spec is_disabled is_repeat_template_p leaf_components localize make_correct pretty_image pretty_value process_correct_when_modifier remove_omit render render_answer_statistics render_collapsed render_disabled_as_div render_error_msg render_form_widget render_help_text render_input render_item render_localizer render_modal render_result_statistics render_word_statistics repeat repeat_add_label resetBooleanAttributes reset_on_validation_error reset_parameter same_value set_disabled set_feedback set_is_repeat_template stats_record_count validate validation_check value_if_nothing_is_returned_from_form word_statistics ::xo::tdom::Object ::xo::tdom::Object ::xowiki::formfield::FormField->::xo::tdom::Object ::xowiki::formfield::CompoundField ::xowiki::formfield::CompoundField add_component add_statistics check=compound convert_to_external convert_to_internal create_components exists_named_sub_component generate_fieldnames get_component get_compound_value get_named_sub_component get_named_sub_component_value has_instance_variable leaf_components make_correct named_sub_components object pretty_value render_input reset_on_validation_error same_value set_compound_value set_disabled set_is_repeat_template specs_unmodified validate value ::xowiki::formfield::CompoundField->::xowiki::formfield::FormField ::xowiki::formfield::repeatContainer ::xowiki::formfield::repeatContainer check_nr_components component_item_spec convert_to_internal count_values initialize item_spec pretty_value render_input require_component set_compound_value trim_values validate ::xowiki::formfield::repeatContainer->::xowiki::formfield::CompoundField ::xowiki::formfield::mc_exercise ::xowiki::formfield::mc_exercise convert_to_internal initialize pretty_value render_input ::xowiki::formfield::mc_exercise->::xowiki::formfield::CompoundField ::xowiki::formfield::repeattest ::xowiki::formfield::repeattest initialize ::xowiki::formfield::repeattest->::xowiki::formfield::CompoundField ::xowiki::formfield::mc_alternative ::xowiki::formfield::mc_alternative initialize ::xowiki::formfield::mc_alternative->::xowiki::formfield::CompoundField ::xowiki::formfield::regression_test_compound_numeric ::xowiki::formfield::regression_test_compound_numeric initialize ::xowiki::formfield::regression_test_compound_numeric->::xowiki::formfield::CompoundField ::xowiki::formfield::comp_correct_when ::xowiki::formfield::comp_correct_when initialize ::xowiki::formfield::comp_correct_when->::xowiki::formfield::CompoundField ::xowiki::formfield::FormGeneratorField ::xowiki::formfield::FormGeneratorField pretty_value render_input ::xowiki::formfield::FormGeneratorField->::xowiki::formfield::CompoundField ::xowiki::formfield::date ::xowiki::formfield::date convert_to_external get_compound_value initialize pretty_value render_input same_value set_compound_value ::xowiki::formfield::date->::xowiki::formfield::CompoundField ::xowiki::formfield::regression_test_compound_with_repeat ::xowiki::formfield::regression_test_compound_with_repeat initialize ::xowiki::formfield::regression_test_compound_with_repeat->::xowiki::formfield::CompoundField ::xowiki::formfield::regression_test_mycompound ::xowiki::formfield::regression_test_mycompound initialize ::xowiki::formfield::regression_test_mycompound->::xowiki::formfield::CompoundField ::xowiki::formfield::CalendarField ::xowiki::formfield::CalendarField update_calendar ::xowiki::formfield::CalendarField->::xowiki::formfield::CompoundField ::xowiki::formfield::text_fields ::xowiki::formfield::text_fields answer_is_correct get_text_entry initialize pretty_value render_help_text render_input set_feedback td_pretty_value ::xowiki::formfield::text_fields->::xowiki::formfield::CompoundField ::xowiki::formfield::ShuffleField ::xowiki::formfield::ShuffleField ::xowiki::formfield::text_fields->::xowiki::formfield::ShuffleField ::xowiki::formfield::regression_test_compound_with_repeat2 ::xowiki::formfield::regression_test_compound_with_repeat2 initialize ::xowiki::formfield::regression_test_compound_with_repeat2->::xowiki::formfield::CompoundField ::xowiki::formfield::TestItemField ::xowiki::formfield::TestItemField QM attachments_widget comp_correct_when_from_value correct_when_spec correct_when_widget form_markup text_attachments twocol_layout ::xowiki::formfield::TestItemField->::xowiki::formfield::FormGeneratorField ::xowiki::formfield::event ::xowiki::formfield::event convert_to_internal get_compound_value initialize pretty_value ::xowiki::formfield::event->::xowiki::formfield::CalendarField ::xowiki::formfield::time_span ::xowiki::formfield::time_span initialize ::xowiki::formfield::time_span->::xowiki::formfield::CalendarField

Class ::xowiki::formfield::CompoundField

::xowiki::formfield::CompoundField[i] create ... \
           [ -CSSclass (default "compound-field") ] \
           [ -components (default "") ]

Class Relations

  • class: ::xotcl::Class[i]
  • superclass: ::xowiki::formfield::FormField[i]
  • subclass: ::xowiki::formfield::repeatContainer[i], ::xowiki::formfield::mc_exercise[i], ::xowiki::formfield::repeattest[i], ::xowiki::formfield::mc_alternative[i], ::xowiki::formfield::regression_test_compound_numeric[i], ::xowiki::formfield::comp_correct_when[i], ::xowiki::formfield::FormGeneratorField[i], ::xowiki::formfield::date[i], ::xowiki::formfield::regression_test_compound_with_repeat[i], ::xowiki::formfield::regression_test_mycompound[i], ::xowiki::formfield::CalendarField[i], ::xowiki::formfield::text_fields[i], ::xowiki::formfield::regression_test_compound_with_repeat2[i]
::xotcl::Class create ::xowiki::formfield::CompoundField \
     -superclass ::xowiki::formfield::FormField

Methods (to be applied on instances)

  • CSSclass (setter)

  • add_component (scripted)

    #
    # Add a single component dynamically to the list of already
    # existing components and return the component as result.
    #
    lappend :structure $entry
    lassign $entry name spec
    set c [::xowiki::formfield::FormField create [self]::$name  -name ${:name}.$name -id ${:id}.$name  -locale [:locale] -object ${:object}  -spec $spec]
    set :component_index(${:name}.$name$c
    lappend :components $c
    return $c
  • add_statistics (scripted)

    foreach c ${:components} {
      $c add_statistics -options $options
    }
  • check=compound (scripted)

    #:msg "check compound in ${:components}"
    foreach c ${:components} {
      set error [$c validate [self]]
      if {$error ne ""} {
        set msg "[$c label]: $error"
        :uplevel [list set errorMsg $msg]
        #util_user_message -message "Error in compound field [$c name]: $error"
        return 0
      }
    }
    return 1
  • components (setter)

  • convert_to_external (scripted)

    #ns_log notice "Compound ${:name} convert_to_external <$internal>"
    set result {}
    set c [lindex ${:components} 0]
    if {[$c is_repeat_template_p]} {
      foreach {name value} $internal {
        set value [$c convert_to_external [dict get $internal $name]]
        lappend result $name $value
      }
    } else {
      foreach c ${:components} {
        set name [$c name]
        if {[dict exists $internal $name]} {
          set value [$c convert_to_external [dict get $internal $name]]
        } else {
          set value ""
        }
        lappend result [$c name] $value
      }
    }
    #ns_log notice "Compound ${:name} convert_to_external -> $result"
    return $result
  • convert_to_internal (scripted)

    foreach c ${:components} {
      $c convert_to_internal
    }
    # Finally, update the compound value entry with the compound
    # internal representation; actually we could drop the instance
    # atts of the components from the "instance_attributes" ...
    ${:object} set_property -new 1 ${:name} [:get_compound_value]
  • create_components (scripted)

    #:log "create_components $spec_list"
    
    #
    # Omit after specs for compound fields to avoid multiple
    # recreations.
    #
    if {[:specs_unmodified $spec_list]} {
      return
    }
    
    #
    # Build a component structure based on a list of specs
    # of the form {name spec}.
    #
    set :structure $spec_list
    set :components [list]
    foreach entry $spec_list {
      #:log "create_components creates form-field for spec '$entry'"
      lassign $entry name spec
      if {$name eq ""} {
        continue
      }
      #
      # create for each component a form field
      #
      set c [::xowiki::formfield::FormField create [self]::$name  -name ${:name}.$name -id ${:id}.$name  -locale [:locale] -object ${:object}  -spec $spec]
      set :component_index(${:name}.$name$c
      $c set parent_field [self]
      lappend :components $c
    }
  • exists_named_sub_component (scripted)

    # Iterate along the argument list to check components of a deeply
    # nested structure. For example,
    #
    #    :check_named_sub_component a b
    #
    # returns 0 or one depending whether there exists a component "a"
    # with a subcomponent "b".
    set component_name ${:name}
    set sub [self]
    foreach e $args {
      append component_name .$e
      if {![$sub exists component_index($component_name)]} {
        return 0
      }
      set sub [$sub set component_index($component_name)]
    }
    return 1
  • generate_fieldnames (scripted)

    set names [list]
    for {set i 1} {$i <= $n} {incr i} {lappend names $prefix$i}
    return $names
  • get_component (scripted)

    set key component_index(${:name}.$component_name)
    if {[info exists :$key]} {
      return [set :$key]
    }
    error "no component named $component_name of compound field ${:name}"
  • get_compound_value (scripted)

    #
    # returns the internal representation based on the components values.
    #
    set cc [[${:object} package_id] context]
    
    set value [list]
    foreach c ${:components} {
      lappend value [$c name] [$c value]
    }
    #:log "${:name}: get_compound_value returns value=$value"
    return $value
  • get_named_sub_component (scripted)

    # Iterate along the argument list to get components of a deeply
    # nested structure. For example,
    #
    #    :get_named_sub_component a b
    #
    # returns the object of the subcomponent "b" of component "a"
    set component_name ${:name}
    set sub [self]
    foreach e $args {
      append component_name .$e
      #:msg "check $sub set component_index($component_name)"
      set sub [$sub set component_index($component_name)]
    }
    return $sub
  • get_named_sub_component_value (scripted, public)

     <instance of xowiki::formfield::CompoundField[i]> get_named_sub_component_value \
        [ -from_repeat ] [ -default default ] args [ args... ]

    Return the value of a named subcomponent. When the named subcomponent is a repeated item, and the value of the 0th element of the repeat (the template element) is omitted from the returned value.

    Switches:
    -from_repeat
    (optional)
    skip template element from repeated values
    -default
    (optional)
    default value, when component is not found
    Parameters:
    args - space separated path of elements names in a potentially nested component structure (similar to dict)

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_create_test_items create_test_items (test xowf) xowiki::formfield::CompoundField instproc get_named_sub_component_value xowiki::formfield::CompoundField instproc get_named_sub_component_value test_create_test_items->xowiki::formfield::CompoundField instproc get_named_sub_component_value

    Testcases:
    create_test_items
    if {[:exists_named_sub_component {*}$args]} {
      set result [[:get_named_sub_component {*}$args] value]
      if {$from_repeat} {
        if {[lindex [split [lindex $result 0] .] end] eq "0"} {
          set result [lrange $result 2 end]
        }
      }
    } else {
      set result $default
    }
    return $result
  • has_instance_variable (scripted)

    set r [next]
    if {$r} {return 1}
    foreach c ${:components} {
      set r [$c has_instance_variable $var $value]
      if {$r} {return 1}
    }
    return 0
  • leaf_components (scripted)

    set leaf_components {}
    foreach c ${:components} {
      if {[self class] in [[$c info class] info heritage]} {
        lappend leaf_components {*}[$c leaf_components]
      } else {
        lappend leaf_components $c
      }
    }
    return $leaf_components
  • make_correct (scripted)

    foreach c ${:components} {
      $c make_correct
    }
  • named_sub_components (scripted)

    # Iterate along the argument list to check components of a deeply
    # nested structure.
    set component_names [array names :component_index]
    foreach c ${:components} {
      lappend component_names {*}[$c array names component_index]
    }
    return $component_names
  • object (scripted)

    set l [llength $args]
    switch $l {
      0 {
        #
        # Called without args, return the current value
        #
        return ${:object}
      }
      1 {
        #
        # Called with a single value, set object for all components
        #
        foreach c ${:components} {
          $c object [lindex $args 0]
        }
    
        set :object [lindex $args 0]
      }
      default {
        error "wrong number of arguments"
      }
    }
  • pretty_value (scripted)

    #
    # Typically, subtypes of CompoundFields should define their own
    # "pretty_value". This is a simple renderer that provides a
    # default behavior.
    #
    set ff [dict create {*}$v]
    set html "<ul class='CompoundField'>\n"
    foreach c [lsort ${:components}] {
      set componentName [$c set name]
      if {[dict exists $ff $componentName]} {
        set componentLabel [string range $componentName [string length ${:name}]+1 end]
        append html "<li><span class='name'>$componentLabel:</span> "  "[$c pretty_value [dict get $ff $componentName]]</li>\n"
      }
    }
    append html "</ul>\n"
    return $html
  • render_input (scripted)

    #
    # Render content within in a fieldset, but with labels etc.
    #
    :CSSclass_list_add CSSclass [namespace tail [:info class]]
    :CSSclass_list_add CSSclass "align-items-center"
    html::fieldset [:get_attributes id {CSSclass class}] {
      foreach c ${:components} { $c render }
    }
  • reset_on_validation_error (scripted)

    #
    # We actually want to reset all the leaf components
    #
    ns_log debug "reset_on_validation_error COMPOUND"
    foreach f [:leaf_components] {
      $f reset_on_validation_error {*}$args
    }
  • same_value (scripted)

    if {$v1 eq $v2} {return 1}
    foreach {n1 value1} $v1 {n2 value2} $v2  {
      set f [set :component_index($n1)]
      if {![$f same_value $value1 $value2]} { return 0 }
    }
    return 1
  • set_compound_value (scripted)

    if {![string is list $value] || ([llength $value] % 2) == 1} {
      # this branch could be taken, when the field was retyped
      ns_log notice "CompoundField: value '$value' is not avalid dict"
      return
    }
    # set the value parts for each components
    foreach c ${:components} {
      # Set only those parts, for which attribute values pairs are
      # given.  Components might have their own default values, which
      # we do not want to overwrite ...
      set cname [$c name]
      if {[dict exists $value $cname]} {
        $c value [dict get $value $cname]
      }
    }
  • set_disabled (scripted)

    #:msg "${:name} set disabled $disable"
    next
    
    foreach c ${:components} {
      $c set_disabled $disable
    }
  • set_is_repeat_template (scripted)

    # :msg "${:name} set is_repeat_template $is_template"
    if {$is_template} {
      set :is_repeat_template true
    } else {
      unset -nocomplain :is_repeat_template
    }
    foreach c ${:components} {
      $c set_is_repeat_template $is_template
    }
  • specs_unmodified (scripted)

    expr {${:__state} eq "after_specs"
          && [info exists :structure] && ${:structure} eq $spec_list
        }
  • validate (scripted)

    # Delegate validate to the components. If a validation of a
    # component fails, report the error message back.
    foreach c ${:components} {
      set result [$c validate $obj]
      #ns_log notice "CompoundField validate on [$c name] returns '$result' [info exists errorMsg]"
      if {$result ne ""} {
        return $result
      }
    }
    return ""
  • validator (setter)

  • value (scripted)

    if {[info exists value]} {
      #:msg "${:name}: setting compound value => '$value'"
      :set_compound_value $value
    }
    return [:get_compound_value]