Class ::xowiki::formfield::CompoundField (public)
::xotcl::Class ::xowiki::formfield::CompoundField
- Testcases:
- No testcase defined.
Source code: namespace eval ::xowiki::formfield {} ::nsf::object::alloc ::xotcl::Class ::xowiki::formfield::CompoundField {set :__default_metaclass ::xotcl::Class set :__default_superclass ::xotcl::Object} ::xowiki::formfield::CompoundField instproc check=compound value { #: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 } ::xowiki::formfield::CompoundField instproc specs_unmodified spec_list { expr {${:__state} eq "after_specs" && [info exists :structure] && ${:structure} eq $spec_list } } ::xowiki::formfield::CompoundField instproc reset_on_validation_error args { # # 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 } } ::xowiki::formfield::CompoundField instproc set_is_repeat_template is_template { # :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 } } ::xowiki::formfield::CompoundField instproc get_named_sub_component_value {-from_repeat:switch {-default ""} args} { 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 } ::xowiki::formfield::CompoundField instproc named_sub_components {} { # 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 } ::xowiki::formfield::CompoundField instproc pretty_value v { # # 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 } ::xowiki::formfield::CompoundField instproc set_compound_value value { 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] } } } ::xowiki::formfield::CompoundField instproc has_instance_variable {var value} { set r [next] if {$r} {return 1} foreach c ${:components} { set r [$c has_instance_variable $var $value] if {$r} {return 1} } return 0 } ::xowiki::formfield::CompoundField instproc leaf_components {} { 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 } ::xowiki::formfield::CompoundField instproc object args { 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" } } } ::xowiki::formfield::CompoundField instproc exists_named_sub_component args { # 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 } ::xowiki::formfield::CompoundField instproc render_input {} { # # 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 } } } ::xowiki::formfield::CompoundField instproc make_correct {} { foreach c ${:components} { $c make_correct } } ::xowiki::formfield::CompoundField instproc convert_to_internal {} { 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] } ::xowiki::formfield::CompoundField instproc get_compound_value {} { # # 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 } ::xowiki::formfield::CompoundField instproc create_components spec_list { #: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 } } ::xowiki::formfield::CompoundField instproc same_value {v1 v2} { 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 } ::xowiki::formfield::CompoundField instproc validate obj:object { # 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 "" } ::xowiki::formfield::CompoundField instproc get_component component_name { set key component_index(${:name}.$component_name) if {[info exists :$key]} { return [set :$key] } error "no component named $component_name of compound field ${:name}" } ::xowiki::formfield::CompoundField instproc generate_fieldnames {{-prefix "v-"} n} { set names [list] for {set i 1} {$i <= $n} {incr i} {lappend names $prefix$i} return $names } ::xowiki::formfield::CompoundField instproc set_disabled disable { #:msg "${:name} set disabled $disable" next foreach c ${:components} { $c set_disabled $disable } } ::xowiki::formfield::CompoundField instproc add_component entry { # # 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 } ::xowiki::formfield::CompoundField instproc add_statistics {{-options ""}} { foreach c ${:components} { $c add_statistics -options $options } } ::xowiki::formfield::CompoundField instproc value value:optional { if {[info exists value]} { #:msg "${:name}: setting compound value => '$value'" :set_compound_value $value } return [:get_compound_value] } ::xowiki::formfield::CompoundField instproc convert_to_external internal { #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 } ::xowiki::formfield::CompoundField instproc get_named_sub_component args { # 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 } ::xowiki::formfield::CompoundField instparametercmd components ::xowiki::formfield::CompoundField instparametercmd validator ::xowiki::formfield::CompoundField instparametercmd CSSclass ::nsf::relation::set ::xowiki::formfield::CompoundField superclass ::xowiki::formfield::FormField ::nx::slotObj -container slot ::xowiki::formfield::CompoundField ::xowiki::formfield::CompoundField::slot eval {set :__parameter { {components ""} {CSSclass compound-field} }} ::nsf::object::alloc ::xotcl::Attribute ::xowiki::formfield::CompoundField::slot::validator {set :accessor public set :configurable true set :convert false set :default compound set :defaultmethods {} set :disposition alias set :domain ::xowiki::formfield::CompoundField set :incremental false set :manager ::xowiki::formfield::CompoundField::slot::validator set :methodname validator set :multiplicity 1..1 set :name validator set :per-object false set :position 0 set :required false set :substdefault 0b111 set :trace none : init} ::nsf::object::alloc ::xotcl::Attribute ::xowiki::formfield::CompoundField::slot::components {set :accessor public set :configurable true set :convert false set :default {} set :defaultmethods {} set :disposition alias set :domain ::xowiki::formfield::CompoundField set :incremental 0 set :manager ::xowiki::formfield::CompoundField::slot::components set :methodname components set :multiplicity 1..1 set :name components set :per-object false set :position 0 set :required false set :substdefault 0b111 set :trace none : init} ::nsf::object::alloc ::xotcl::Attribute ::xowiki::formfield::CompoundField::slot::CSSclass {set :accessor public set :configurable true set :convert false set :default compound-field set :defaultmethods {} set :disposition alias set :domain ::xowiki::formfield::CompoundField set :incremental 0 set :manager ::xowiki::formfield::CompoundField::slot::CSSclass set :methodname CSSclass set :multiplicity 1..1 set :name CSSclass set :per-object false set :position 0 set :required false set :substdefault 0b111 set :trace none : init}XQL Not present: Generic, PostgreSQL, Oracle