Class ::xowiki::formfield::repeatContainer (public)

 ::xotcl::Class ::xowiki::formfield::repeatContainer[i]

Defined in

Testcases:
No testcase defined.
Source code:
namespace eval ::xowiki::formfield {}
::nsf::object::alloc ::xotcl::Class ::xowiki::formfield::repeatContainer {set :__default_metaclass ::xotcl::Class
   set :__default_superclass ::xotcl::Object}
::xowiki::formfield::repeatContainer instproc count_values values {
    set count 1
    set highestCount 1
    if {![:required]} {set highestCount [:min]}
    # The first pair is the default from the template field (.0)
    set default [lindex $values 1]
    foreach f [lrange ${:components} 1 end] {name value} [lrange $values 2 end] {
      if {[$f required] || ($value ne "" && ![$f same_value $value $default])} {set highestCount $count}
      incr count
    }
    return $highestCount
  }
::xowiki::formfield::repeatContainer instproc item_spec {} {
    #
    # Return the spec of a contained item, which is a subset of the
    # container spec.
    #
    set result {}
    set is_required false
    foreach s [split [:spec] ,] {
      # don't propagate "repeat" and "label" properties
      if { [string match "repeat=*" $s] || [string match "label=*" $s] } continue
      if { "required" eq $s} {set is_required true; continue}
      if { "disabled" eq $s} {:set_disabled true}
      lappend result $s
    }
    return [list $is_required [join $result ,]]
  }
::xowiki::formfield::repeatContainer instproc check_nr_components {neededComponents availableComponents} {
    if {$neededComponents > $availableComponents} {
      lassign [:item_spec] isRequired itemSpec
      for {set i $availableComponents} {$i < $neededComponents} {incr i} {
        :require_component $i
      }
    }
  }
::xowiki::formfield::repeatContainer instproc component_item_spec {i itemSpec isRequired} {
    #
    # Return a single itemspec suited for the nth component, derived
    # from the repeatable formfield spec.
    #
    if {$i <= [:min] && $isRequired} {
      set componentItemSpec [list $i $itemSpec,required,label=$i]
    } else {
      set componentItemSpec [list $i $itemSpec,label=$i]
    }
    return $componentItemSpec
  }
::xowiki::formfield::repeatContainer instproc pretty_value v {
    #
    # Simple renderer for repeated values
    #
    set ff [dict create {*}$v]
    set html "<ol class='repeatContainer'>\n"

    :set_compound_value $v
    foreach c [lrange ${:components} 1 [:count_values $v]] {
      if {[dict exists $ff [$c set name]]} {
        append html "<li>[$c pretty_value [dict get $ff [$c set name]]]</li>\n"
      }
    }
    append html "</ol>\n"
    return $html
  }
::xowiki::formfield::repeatContainer instproc set_compound_value value {
    #
    # Before setting compound values, check if we have the repeat
    # structure already set.
    #
    set neededComponents [expr {[llength $value] / 2}]
    set availableComponents [llength ${:components}]
    #:log "repeatContainer set_compound_value <$value> have $availableComponents needed $neededComponents"
    :check_nr_components $neededComponents $availableComponents
    next
  }
::xowiki::formfield::repeatContainer instproc json_value value {
    if {[catch {dict size $value}]} {
      return [list string $value]
    }
    set occurrences {}
    dict for {name v} $value {
      set prefix ${:name}.
      if {[string first $prefix $name] != 0} {
        return [list string $value]
      }
      set index [string range $name [string length $prefix] end]
      if {![regexp {^(0|[1-9][0-9]*)$} $index]} {
        return [list string $value]
      }
      # Occurrence zero is the client-side template, not content.
      if {$index > 0} {
        lappend occurrences [list $index $name $v]
      }
    }
    set entries {}
    set i 0
    foreach occurrence [lsort -integer -index 0 $occurrences] {
      lassign $occurrence index name v
      set c ""
      foreach component ${:components} {
        if {[$component name] eq $name} {
          set c $component
          break
        }
      }
      if {$c eq ""} {
        set c [:require_component $index]
      }
      lassign [$c json_value $v] type payload
      lappend entries $i $type $payload
      incr i
    }
    return [list array $entries]
  }
::xowiki::formfield::repeatContainer instproc render_input {} {
    #
    # Render content of the container within in a fieldset,
    # without labels for the contained items.
    #
    html::fieldset [:get_attributes id {CSSclass class}] {
      set i 0
      set clientData [subst {{"min":${:min},"max":${:max}, "name":"${:name}"}}]
      set CSSclass   "[:form_widget_CSSclass] repeatable"

      set providedValues [:count_values [:value]]
      if {${:min} > $providedValues} {
        set nrItems ${:min}
      } else {
        set nrItems $providedValues
      }
      incr nrItems

      set containerIsDisabled [:is_disabled]
      set containerIsPrototype [string match "*.0*" ${:name}]
      set isPrototypeElement 0
      foreach c ${:components} {
        set atts [list class $CSSclass]
        lappend atts data-repeat $clientData
        if {$i == 0 || $i >= $nrItems} {
          lappend atts style "display: none;"
        }
        ::html::div $atts {
          #
          # Compound fields - link not shown if we are not rendering
          # for the template and copy the template afterwards.
          #
          if {!$containerIsDisabled || $containerIsPrototype} {
            set del_id "repeat-del-link-[$c set id]"
            ::html::a -href "#"  -id $del_id  -title ${:repeat_remove_label}  -class "delete-item-button repeat-del-link" {
                  html::t ""
                }
            template::add_event_listener  -id $del_id  -script [subst {xowiki.repeat.delItem(this,'$clientData');}]
          }
          $c render_input
        }
        incr i
      }
      #ns_log notice "repeat container $c [$c name] isDisabled $containerIsDisabled containerIsPrototype $containerIsPrototype"
      if {!$containerIsDisabled || $containerIsPrototype } {
        set hidden [expr {[:count_values [:value]] == ${:max} ? "display: none;" : ""}]
        set add_id "repeat-add-link-[:id]"
        #ns_log notice "... add another for ${:name}"
        html::a -href "#"  -id $add_id  -style $hidden  -class "repeat-add-link" {
              html::t ${:repeat_add_label}
            }
        template::add_event_listener  -id $add_id  -script [subst {xowiki.repeat.newItem(this,'$clientData');}]
      }
    }
  }
::xowiki::formfield::repeatContainer instproc convert_to_internal {} {
    set values [:value]
    :trim_values
    set r [next]
    #:msg name=${:name},value=[:get_compound_value]

    #
    # remove "unneeded" entries from instance attributes
    #
    ${:object} instvar instance_attributes
    foreach {name value} $values {
      if {[dict exists $instance_attributes $name]} {
        dict unset instance_attributes $name
      }
    }
    return $r
  }
::xowiki::formfield::repeatContainer instproc validate obj:object {
    foreach c [lrange ${:components} 1 [:count_values [:value]]] {
      set result [$c validate $obj]
      if {$result ne ""} {
        return $result
      }
    }
    return ""
  }
::xowiki::formfield::repeatContainer instproc initialize {} {
    ::xo::Page requireJS "/resources/xowiki/repeat.js"
    ::xo::Page requireJS urn:ad:js:jquery

    if {[info exists :__initialized_repeat]} {return}
    next

    set :__initialized_repeat 1
    #
    # Derive the spec of the contained items from the spec of the
    # container.
    #
    lassign [:item_spec] isRequired itemSpec

    #
    # Use item .0 as template for other items in .js (e.g. blank an
    # item with the template, when it is deleted. By using a
    # potentially compound item as template, we are able to preserve
    # default values for subfields without knowing the detailed
    # structure).
    #
    set componentItemSpecs [list [list 0 $itemSpec]]

    #
    # We use dynamic repeat fields. The number of fields generated on
    # the server side is the minimum, while the rest will be created
    # on demand via javascript.
    #
    set max [:min]

    for {set i 1} {$i <= $max} {incr i} {
      set componentItemSpec [:component_item_spec $i $itemSpec $isRequired]
      #ns_log notice "dynamic repeat componentItemSpec $componentItemSpec"
      lappend componentItemSpecs $componentItemSpec
    }
    :create_components $componentItemSpecs

    #
    # Deactivate template item
    #
    set componentList ${:components}
    if {[llength $componentList] > 0} {
      [lindex $componentList 0] set_disabled true
      [lindex $componentList 0] set_is_repeat_template true
    }
  }
::xowiki::formfield::repeatContainer instproc trim_values {} {
    # Trim trailing values identical to default.
    # Trimming the components list seems sufficient.
    set count [:count_values [:value]]
    set :components [lrange ${:components} 0 $count]
  }
::xowiki::formfield::repeatContainer instproc require_component i {
    #
    # Require the nth component of a repeat field
    #
    lassign [:item_spec] isRequired itemSpec
    set componentItemSpec [:component_item_spec $i $itemSpec $isRequired]
    #ns_log notice "dynamic repeat field: add component on the fly: $componentItemSpec"
    :add_component $componentItemSpec
  }
::xowiki::formfield::repeatContainer instparametercmd repeat_add_label
::xowiki::formfield::repeatContainer instparametercmd min
::xowiki::formfield::repeatContainer instparametercmd repeat_remove_label
::xowiki::formfield::repeatContainer instparametercmd max
::nsf::relation::set ::xowiki::formfield::repeatContainer superclass ::xowiki::formfield::CompoundField

::nx::slotObj -container slot ::xowiki::formfield::repeatContainer
::xowiki::formfield::repeatContainer::slot eval {set :__parameter {
    {min 1}
    {max 5}
    {repeat_add_label "#xowiki.form-repeatable-add#"}
    {repeat_remove_label "#xowiki.delete#"}
  }}

::nsf::object::alloc ::xotcl::Attribute ::xowiki::formfield::repeatContainer::slot::repeat_add_label {set :accessor public
   set :configurable true
   set :convert false
   set :default #xowiki.form-repeatable-add#
   set :defaultmethods {}
   set :disposition alias
   set :domain ::xowiki::formfield::repeatContainer
   set :incremental 0
   set :manager ::xowiki::formfield::repeatContainer::slot::repeat_add_label
   set :methodname repeat_add_label
   set :multiplicity 1..1
   set :name repeat_add_label
   set :per-object false
   set :position 0
   set :required false
   set :substdefault 0b111
   set :trace none
   : init}

::nsf::object::alloc ::xotcl::Attribute ::xowiki::formfield::repeatContainer::slot::min {set :accessor public
   set :configurable true
   set :convert false
   set :default 1
   set :defaultmethods {}
   set :disposition alias
   set :domain ::xowiki::formfield::repeatContainer
   set :incremental 0
   set :manager ::xowiki::formfield::repeatContainer::slot::min
   set :methodname min
   set :multiplicity 1..1
   set :name min
   set :per-object false
   set :position 0
   set :required false
   set :substdefault 0b111
   set :trace none
   : init}

::nsf::object::alloc ::xotcl::Attribute ::xowiki::formfield::repeatContainer::slot::repeat_remove_label {set :accessor public
   set :configurable true
   set :convert false
   set :default #xowiki.delete#
   set :defaultmethods {}
   set :disposition alias
   set :domain ::xowiki::formfield::repeatContainer
   set :incremental 0
   set :manager ::xowiki::formfield::repeatContainer::slot::repeat_remove_label
   set :methodname repeat_remove_label
   set :multiplicity 1..1
   set :name repeat_remove_label
   set :per-object false
   set :position 0
   set :required false
   set :substdefault 0b111
   set :trace none
   : init}

::nsf::object::alloc ::xotcl::Attribute ::xowiki::formfield::repeatContainer::slot::max {set :accessor public
   set :configurable true
   set :convert false
   set :default 5
   set :defaultmethods {}
   set :disposition alias
   set :domain ::xowiki::formfield::repeatContainer
   set :incremental 0
   set :manager ::xowiki::formfield::repeatContainer::slot::max
   set :methodname max
   set :multiplicity 1..1
   set :name max
   set :per-object false
   set :position 0
   set :required false
   set :substdefault 0b111
   set :trace none
   : init}
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: