%3 ::xowiki::FormPage ::xowiki::FormPage → compute_filter_clauses → fetch_object → filter_expression → get_all_children → get_folder_children → get_form_entries → get_super_folders → get_table_form_fields → sql_value action_url adp_subst combine_data_and_form_field_default compute_link_properties condition=in_state condition=is_true configure_page=regression_test create_category_fields create_form_field create_form_fields create_form_fields_from_names demarshall exists_property extra_html_fields field_names field_names_from_form footer form_field_as_html form_fields_sanity_check get_anon_instances get_form_constraints get_form_value get_parameter get_property get_value group_assign group_require hstore_attributes include_header_info initialize initialize_loaded_object is_folder_page is_form is_link_page langstring lappend_property load_values_into_form_fields map_value map_values marshall new_link notification_render post_process_dom_tree post_process_form_fields pretty_name property render_content render_form_action_buttons render_icon render_thumbnails reverse_map_value reverse_map_values setCSSDefaults set_content set_form_data set_form_value set_live_revision set_property set_publish_status update update_attribute_from_slot update_item_index update_langstring_property www-edit www-file-upload www-toggle-modebutton ::xowiki::PageInstance ::xowiki::PageInstance → get_list_from_form_constraints → get_short_spec_from_form_constraints adp_subst count_usages create_raw_form_field demarshall field_names_from_form_constraints get_field_label get_field_type get_form get_form_constraints get_from_template get_short_spec get_template_object render_content template_vars update widget_spec_from_folder_object www-use-template ::xowiki::FormPage->::xowiki::PageInstance ::xowiki::Page ::xowiki::Page → container_already_rendered → find_slot → get_tags → import → quoted_html_content → save_tags __debug_known_field_names add_computed_instance_attributes adp_subst anchor anchor_parent_id build_instance_attribute_map build_name can_be_linked can_contain can_link can_save category_export category_import changed_redirect_url check_adp_include_path check_unresolved_references condition=is_folder_page condition=match condition=regexp content_header_append content_header_get copy_content_vars create_form_field create_form_fields create_form_fields_from_form_constraints create_form_page_instance create_link create_raw_form_field css_class_name default_instance_attributes demarshall detail_link div edit_set_default_values edit_set_file_selector_folder error_during_render error_in_includelet evaluate_form_field_condition exists_form_parameter exists_query_parameter field_names find_slot footer form_field_exists form_field_flush_cache form_field_index form_parameter get_anchor_and_query get_content get_description get_folder get_form_data get_html_from_content get_ids_for_bulk_actions get_instance_attributes get_nls_language_from_lang get_parent_object get_property_from_link_page get_query_parameter_return_url get_rich_text_spec get_target_from_link_page htmlFooter include include_content initialize_loaded_object instantiate_includelet is_folder_page is_form is_link_page is_new_entry is_unprefixed item_ref lang lookup_cached_form_field lookup_form_field map_categories map_party marshall mutual_overwrite_occurred new_link normalize_internal_link_name notification_detail_link notification_notify notification_render notification_subject physical_item_id physical_package_id physical_parent_id pretty_link pretty_name query_parameter record_last_visited references references_update regsub_eval rename render render_content render_icon render_includelet reset_resolve_context resolve_included_page_name return_redirect_without_params reverse_map_party reverse_map_party_attribute save save_data save_new search_render self_link_ids serialize_relocatable set_content set_resolve_context show_fields stats_record_count stats_record_detail substitute_markup translate unescape unset_temporary_instance_variables update update_publish_status validate=form_constraints validate=form_input_fields validate=name validate=page_order www-autosave-attribute www-bulk-delete www-clipboard-add www-clipboard-clear www-clipboard-content www-clipboard-copy www-clipboard-export www-create-new www-create-or-use www-csv-dump www-delete www-delete-revision www-diff www-duplicate www-edit www-list www-make-live-revision www-popular-tags www-revisions www-save-attributes www-save-tags www-toggle-publish-status www-validate-attribute www-view ::xowiki::PageInstance->::xowiki::Page ::xo::db::CrItem ::xo::db::CrItem ::xowiki::Page->::xo::db::CrItem

Class ::xowiki::FormPage

::xowiki::FormPage[i] create ...

Class Relations

  • class: ::xo::db::CrClass[i]
  • superclass: ::xowiki::PageInstance[i]
::xo::db::CrClass create ::xowiki::FormPage \
     -superclass ::xowiki::PageInstance

Methods (to be applied on the object)

  • compute_filter_clauses (scripted, public)

     xowiki::FormPage[i] compute_filter_clauses [ -unless unless ] \
        [ -where where ]

    Compute from "-unless" or "-where" specs the "tcl", "sql" and optional "hstore" query fragments.

    Switches:
    -unless
    (optional)
    -where
    (optional)
    Returns:
    dict containing "init_vars", "uc" (unless clauses) and "wc" (where clauses)

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_create_composite_test_item create_composite_test_item (test xowf) xowiki::FormPage proc compute_filter_clauses xowiki::FormPage proc compute_filter_clauses test_create_composite_test_item->xowiki::FormPage proc compute_filter_clauses

    Testcases:
    create_composite_test_item
    
    set init_vars [list]
    set uc {tcl false h "" vars "" sql ""}
    if {[info exists unless]} {
      set uc [dict merge $uc [:filter_expression $unless ||]]
      set init_vars [list {*}$init_vars {*}[dict get $uc vars]]
    }
    set wc {tcl true h "" vars "" sql ""}
    if {[info exists where]} {
      set wc [dict merge $wc [:filter_expression $where &&]]
      set init_vars [list {*}$init_vars {*}[dict get $wc vars]]
    }
    return [list init_vars $init_vars uc $uc wc $wc]
  • fetch_object (scripted, public)

     xowiki::FormPage[i] fetch_object -item_id item_id  \
        [ -revision_id revision_id ] -object object  \
        [ -initialize on|off ]

    Load a content item into the specified object. If revision_id is provided, the specified revision is returned, otherwise the live revision of the item_id. If the object does not exist, we create it.

    Switches:
    -item_id
    (required)
    -revision_id
    (defaults to "0") (optional)
    -object
    (required)
    -initialize
    (boolean) (defaults to "true") (optional)
    Returns:
    cr item object

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_link_tests link_tests (test xowiki) xowiki::FormPage proc fetch_object xowiki::FormPage proc fetch_object test_link_tests->xowiki::FormPage proc fetch_object test_path_resolve path_resolve (test xowiki) test_path_resolve->xowiki::FormPage proc fetch_object test_xowiki_test_cases xowiki_test_cases (test xowiki) test_xowiki_test_cases->xowiki::FormPage proc fetch_object db_exec db_exec (public) xowiki::FormPage proc fetch_object->db_exec db_with_handle db_with_handle (public) xowiki::FormPage proc fetch_object->db_with_handle

    Testcases:
    xowiki_test_cases, link_tests, path_resolve
    #ns_log notice "=== fetch_object $item_id"
    #
    # We handle here just loading object instances via item_id, since
    # only live_revisions are kept in xowiki_form_instance_item_index.
    # The loading via revision_id happens as before in CrClass.
    #
    if {$item_id == 0} {
      return [next]
    }
    
    if {![nsf::is object $object]} {
      # if the object does not yet exist, we have to create it
      :create $object
    }
    
    db_with_handle db {
      set sql [::xo::dc prepare -handle $db -argtypes integer {
        select * from xowiki_form_instance_item_view where item_id = :item_id
      }]
      set selection [db_exec 0or1row $db dbqd..Formpage-fetch_object $sql]
    }
    
    if {$selection eq ""} {
      error [subst {
        The form page with item_id $item_id was not found in the
        xowiki_form_instance_item_index.  Consider 'DROP TABLE
        xowiki_form_instance_item_index CASCADE;' and restart server
        (the table is rebuilt automatically, but this could take a
        while, when the number of pages is huge).
      }]
    }
    
    $object mset [ns_set array $selection]
    
    if {$initialize} {
      $object initialize_loaded_object
    }
    return $object
  • filter_expression (scripted)

     xowiki::FormPage[i] filter_expression

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_xowiki xowiki (test ) xowiki::FormPage proc filter_expression xowiki::FormPage proc filter_expression test_xowiki->xowiki::FormPage proc filter_expression test_xowiki_test_cases xowiki_test_cases (test ) test_xowiki_test_cases->xowiki::FormPage proc filter_expression xowiki::hstore::double_quote xowiki::hstore::double_quote (public) xowiki::FormPage proc filter_expression->xowiki::hstore::double_quote

    Testcases:
    xowiki_test_cases, xowiki
    #ns_log notice "filter_expression '$input_expr' $logical_op"
    
    #
    # example for unless: wf_current_state = closed|accepted || x = 1
    #
    
    array set tcl_op {= eq < < > > >= >= <= <=}
    array set sql_op {= =  < < > > >= >= <= <=}
    array set op_map {
      contains,sql {$lhs_var like '%$sql_rhs%'}
      contains,tcl {{$rhs} in $lhs_var}
      matches,sql {$lhs_var like '$sql_rhs'}
      matches,tcl {[string match "$rhs" $lhs_var]}
    }
    
    set tcl_clause [list]
    set h_clause [list]
    set vars [list]
    set sql_clause [list]
    foreach clause [split [string map [list $logical_op \x00] $input_expr] \x00] {
      if {[regexp {^(.*[^<>])\s*([=<>]|<=|>=|contains|matches)\s*([^=]?.*)$} $clause _ lhs op rhs_expr]} {
        set lhs [string trim $lhs]
        set rhs_expr [string trim $rhs_expr]
        if {[string index $lhs 0] eq "_"} {
          #
          # Comparison with field names starting with "_"
          #
          set lhs_var [string range $lhs 1 end]
          set rhs [split $rhs_expr |]
          set sql_rhs [:sql_value $rhs]
          #:msg "check op '$op' in SQL [info exists op_map($op,sql)]"
          if {[info exists op_map($op,sql)]} {
            lappend sql_clause [subst -nocommands $op_map($op,sql)]
            if {[info exists :db_slot($lhs_var)]} {
              set lhs_var "\[set :$lhs_var\]"
              lappend tcl_clause [subst -nocommands $op_map($op,tcl)]
            } else {
              :msg "ignoring unknown variable '$lhs_var' in expression (have '[lsort [array names :db_slot]]')"
            }
          } elseif {[llength $rhs]>1} {
            lappend sql_clause "$lhs_var in ([ns_dbquotelist $rhs])"
            # the following statement is only needed, when we rely on tcl-only
            lappend tcl_clause "\[lsearch -exact {$rhs} \[:property $lhs\]\] > -1"
          } else {
            lappend sql_clause "$lhs_var $sql_op($op) '$rhs'"
            # the following statement is only needed, when we rely on tcl-only
            lappend tcl_clause "\[:property $lhs\] $tcl_op($op) {$rhs}"
          }
        } else {
          #
          # Field names referring to instance attributes.
          #
          set hleft [::xowiki::hstore::double_quote $lhs]
          lappend vars $lhs ""
          if {$op eq "contains"} {
            #make approximate query
            set lhs_var instance_attributes
            set sql_rhs $rhs_expr
            lappend sql_clause [subst -nocommands $op_map($op,sql)]
          }
          set lhs_var "\[dict get \$__ia $lhs\]"
          set tcl_rhs_clauses {}
          foreach rhs [split $rhs_expr |] {
            set sql_rhs [:sql_value $rhs]
            if {[info exists op_map($op,tcl)]} {
              lappend tcl_rhs_clauses [subst -nocommands $op_map($op,tcl)]
            } else {
              lappend tcl_rhs_clauses "$lhs_var $tcl_op($op) {$rhs}"
            }
            if {$op eq "="} {
              # TODO: think about a solution for other operators with
              # hstore maybe: extracting it by a query via hstore and
              # compare in plain SQL
              lappend h_clause "$hleft=>[::xowiki::hstore::double_quote $rhs]"
            }
          }
          lappend tcl_clause ([join $tcl_rhs_clauses ||])
        }
      } else {
        :msg "ignoring $clause"
      }
    }
    if {[llength $tcl_clause] == 0} {
      set tcl_clause [list true]
    }
    #:msg sql=$sql_clause,tcl=$tcl_clause
    set result [list  tcl [join $tcl_clause $logical_op]  h [join $h_clause ,]  vars $vars  sql $sql_clause]
    #:msg "filter_expression -sql $sql inp '$input_expr' log '$logical_op' -> $result"
    
    return $result
  • get_all_children (scripted)

     xowiki::FormPage[i] get_all_children

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_includelet_childresources includelet_childresources (test ) xowiki::FormPage proc get_all_children xowiki::FormPage proc get_all_children test_includelet_childresources->xowiki::FormPage proc get_all_children test_xowiki xowiki (test ) test_xowiki->xowiki::FormPage proc get_all_children ad_log ad_log (public) xowiki::FormPage proc get_all_children->ad_log

    Testcases:
    includelet_childresources, xowiki
    
    set folder [::xo::db::CrClass get_instance_from_db -item_id $folder_id -revision_id 0]
    set package_id [$folder package_id]
    
    set publish_status_clause [::xowiki::Includelet publish_status_clause $publish_status]
    set result [::xo::OrderedComposite new -destroy_on_cleanup]
    $result set folder_ids ""
    
    set list_of_folders [list $folder_id]
    set inherit_folders [FormPage get_super_folders $package_id $folder_id]
    #:log inherit_folders=$inherit_folders
    
    foreach item_ref $inherit_folders {
      set folder [::xo::cc cache [list ::$package_id get_page_from_item_ref $item_ref]]
      if {$folder eq ""} {
        ad_log error "Could not resolve parameter folder page '$item_ref' of FormPage [self]."
      } else {
        lappend list_of_folders [$folder item_id]
      }
    }
    
    if {$include_child_folders eq "direct"} {
      #
      # Get all children of the current folder on the first level and
      # append it to the list_of_folders.
      #
      set folder_form [::$package_id instantiate_forms -forms en:folder.form]
      set child_folders [xo::dc list -prepare integer,integer get_child_folders {
        select item_id from xowiki_form_instance_item_index
        where parent_id = :folder_id
        and page_template = :folder_form
      }]
      foreach f $child_folders {
        ::xo::db::CrClass get_instance_from_db -item_id $f
      }
      lappend list_of_folders {*}$child_folders
    }
    
    $result set folder_ids $list_of_folders
    
    foreach folder_id $list_of_folders {
      foreach object_type $object_types {
        set attributes [list revision_id creation_user title parent_id page_order  "to_char(last_modified,'YYYY-MM-DD HH24:MI') as last_modified" ]
        set base_table [$object_type set table_name]i
        if {$object_type eq "::xowiki::FormPage"} {
          set attributes "bt.* $attributes"
        }
        set items [$object_type get_instances_from_db  -folder_id $folder_id  -with_subtypes false  -initialize $initialize  -select_attributes $attributes  -where_clause "$extra_where_clause $publish_status_clause"  -base_table $base_table]
    
        foreach i [$items children] {
          $result add $i
        }
      }
    }
    return $result
  • get_folder_children (scripted)

    set publish_status_clause [::xowiki::Includelet publish_status_clause $publish_status]
    set result [::xo::OrderedComposite new -destroy_on_cleanup]
    
    foreach object_type $object_types {
      set attributes [list revision_id creation_user title parent_id page_order  "to_char(last_modified,'YYYY-MM-DD HH24:MI') as last_modified" ]
      set base_table [$object_type set table_name]i
      if {$object_type eq "::xowiki::FormPage"} {
        set attributes "bt.* $attributes"
      }
      set items [$object_type get_instances_from_db  -folder_id $folder_id  -with_subtypes false  -select_attributes $attributes  -where_clause "$extra_where_clause $publish_status_clause"  -base_table $base_table  -initialize $initialize]
    
      foreach i [$items children] {
        $result add $i
      }
    }
    return $result
  • get_form_entries (scripted)

    #
    # Get query attributes for all tables (to allow e.g. sorting by time)
    #
    # The basic essential fields item_id, name, object_type and
    # publish_status are always automatically fetched from the
    # instance_select_query. Add the query attributes, we want to
    # obtain as well automatically.
    #
    # "-parent_id *"  means to get instances, regardless of
    # parent_id. Under the assumption, page_template constrains
    # the query enough to make it fast...
    #
    # "-from_package_ids {}" means get pages from the instance
    # provided via package_id, "*" means from all
    # packages. Furthermore, a list of package_ids can be given.
    #
    # "-always_queried_attributes *" means to obtain enough attributes
    # to allow a save operations etc. on the instances.
    #
    
    set sql_atts {
      item_id name publish_status object_type
      parent_id revision_id instance_attributes
      creation_date creation_user last_modified
      package_id title page_template state assignee
    }
    
    if {$always_queried_attributes eq "*"} {
      lappend sql_atts  object_type object_id  description publish_date mime_type nls_language text  creator page_order page_id  page_instance_id xowiki_form_page_id
    } else {
      foreach att $always_queried_attributes {
        set name [string range $att 1 end]
        lappend sql_atts $name
      }
    }
    
    #
    # Compute the list of field_names from the already covered sql
    # attributes
    #
    set covered_attributes [list _name _publish_status _item_id _object_type]
    foreach att $sql_atts {
      #regexp {[.]([^ ]+)} $att _ name
      lappend covered_attributes _$att
    }
    
    #
    # Collect SQL attributes from form_fields
    #
    foreach f $form_fields {
      if {![$f exists __base_field]} continue
      set field_name [$f name]
      if {$field_name in $covered_attributes} {
        continue
      }
      lappend sql_atts [$f set __base_field]
    }
    #:msg sql_atts=$sql_atts
    
    #
    # Build parts of WHERE clause
    #
    set publish_status_clause [::xowiki::Includelet publish_status_clause  -base_table "" $publish_status]
    #
    # Build filter clause (uses hstore if configured)
    #
    set filter_clause ""
    array set wc $h_where
    array set uc $h_unless
    set use_hstore [expr {[::xo::dc has_hstore] &&
                          [::$package_id get_parameter use_hstore:boolean 0]
                        }]
    #
    # Deactivating hstore optimization for now, must be further
    # completed and debugged before activating it again.
    #
    if {$wc(h) ne "" || $uc(h) ne ""} {
      ns_log notice "hstore available $use_hstore, but deactivating anyway for now (wc $wc(h) uc $uc(h) )"
    }
    
    set use_hstore 0
    if {$use_hstore} {
      if {$wc(h) ne ""} {
        set filter_clause " and '$wc(h)' <@ hkey"
      }
      if {$uc(h) ne ""} {
        set filter_clause " and not '$uc(h)' <@ hkey"
      }
    }
    if {$wc(sql) ne ""} {
      #:log "... wc SQL '$wc(sql)'"
      foreach filter $wc(sql) {
        append filter_clause " and $filter"
      }
    }
    if {$uc(sql) ne ""} {
      #:log "... uc SQL '$uc(sql)'"
      foreach filter $uc(sql) {
        append filter_clause " and not $filter"
      }
    }
    #:log filter_clause=$filter_clause
    
    #
    # Build package clause
    #
    if {$from_package_ids eq ""} {
      set package_clause "and package_id = :package_id"
    } elseif {$from_package_ids eq "*"} {
      set package_clause ""
    } elseif {[llength $from_package_ids] == 1} {
      set package_clause "and package_id = :from_package_ids"
    } else {
      set package_clause "and package_id in ([ns_dbquotelist $from_package_ids])"
    }
    
    if {$parent_id eq "*"} {
      # instance_select_query expects "" for all parents, but for the semantics
      # of this method, "*" looks more appropriate
      set parent_id ""
    }
    
    set parent_clause ""
    if {$parent_id ne ""} {
      set parent_clause " and parent_id = :parent_id"
    }
    
    if {[llength $base_item_ids] == 0} {
      error "base_item_ids must not be empty"
    }
    #
    # transform all into an SQL query
    #
    if {$page_number ne ""} {
      set limit $page_size
      set offset [expr {$page_size*($page_number-1)}]
    } else {
      set limit ""
      set offset ""
    }
    set sql [::xo::dc select  -vars [join $sql_atts ", "]  -from xowiki_form_instance_item_view  -where " page_template in ([ns_dbquotelist $base_item_ids])  $publish_status_clause $filter_clause $package_clause $parent_clause  $extra_where_clause"  -orderby $orderby  -limit $limit -offset $offset]
    #ns_log notice "get_form_entries:\n[string map [list :parent_id $parent_id :package_id $package_id] $sql]"
    
    #
    # When we query all attributes, we return objects named after the
    # item_id (like for single fetches)
    #
    set named_objects [expr {$always_queried_attributes eq "*"}]
    set items [::xowiki::FormPage instantiate_objects -sql $sql  -named_objects $named_objects -object_named_after "item_id"  -object_class ::xowiki::FormPage -initialize $initialize]
    
    #:log "$use_hstore wc tcl $wc(tcl) uc tcl $uc(tcl)"
    if {!$use_hstore && ($wc(tcl) != "true" || $uc(tcl) != "true")} {
    
      set init_vars $wc(vars)
      foreach p [$items children] {
        $p set __ia [dict merge $init_vars [$p instance_attributes]]
    
        if {$wc(tcl) != "true"} {
          if {![nsf::directdispatch $p -frame object ::expr $wc(tcl)]} {
            #:log "WC check '$wc(tcl)' [$p name] => where DELETE"
            $items delete $p
            continue
          }
        }
        if {$uc(tcl) != "true"} {
          if {[nsf::directdispatch $p -frame object ::expr $uc(tcl)]} {
            #:log "UC check '$uc(tcl)' on [$p name] => unless DELETE"
            $items delete $p
          }
        }
      }
    }
    return $items
  • get_super_folders (scripted)

    #
    # Compute the set of folder_refs configured in the referenced
    # folders.  Get first the folder_refs configured in the actual
    # folder, which are not yet in aggregated_folder_refs.
    #
    set additional_folder_refs ""
    set folder [::xo::db::CrClass get_instance_from_db -item_id $folder_id -revision_id 0]
    if {[$folder istype ::xowiki::FormPage]} {
      foreach ref [$folder property inherit_folders] {
        if {$ref ni $aggregated_folder_refs} {lappend additional_folder_refs $ref}
      }
    }
    #
    # Process the computed additional folder refs recursively to obtain
    # the transitive set of configured item_refs (pointing to folders).
    #
    lappend aggregated_folder_refs {*}$additional_folder_refs
    foreach item_ref $additional_folder_refs {
      set page [::$package_id get_page_from_item_ref $item_ref]
      if {$page eq ""} {error "configured inherited folder $item_ref cannot be resolved"}
      set aggregated_folder_refs  [FormPage get_super_folders $package_id [$page item_id] $aggregated_folder_refs]
    }
    return $aggregated_folder_refs
  • get_table_form_fields (scripted)

    
    set __att {publish_status 1}
    foreach att [list last_modified creation_user {*}[::xowiki::FormPage array names db_slot]] {
      dict set __att $att 1
    }
    
    # set cr_field_spec [::xowiki::PageInstance get_short_spec_from_form_constraints  #                            -name @cr_fields  #                            -form_constraints $form_constraints]
    # if some fields are hidden in the form, there might still be values (creation_user, etc)
    # maybe filter hidden? ignore for the time being.
    
    set cr_field_spec ""
    set field_spec [::xowiki::PageInstance get_short_spec_from_form_constraints  -name @fields  -form_constraints $form_constraints]
    
    foreach field_name $field_names {
      set short_spec [::xowiki::PageInstance get_short_spec_from_form_constraints  -name $field_name  -form_constraints $form_constraints]
      #:log "short_spec of $field_name <$short_spec> field_spec <$field_spec> cr_field_spec <$cr_field_spec>"
    
      switch -glob -- $field_name {
        __* {error not_allowed}
        _* {
          set varname [string range $field_name 1 end]
          if {![dict exists $__att $varname]} {
            error "unknown attribute $field_name"
          }
          #:log "create_raw_form_field of $field_name <$cr_field_spec,$short_spec>"
          set f [$base_item create_raw_form_field  -omit_field_name_spec true  -name $field_name  -slot [$base_item find_slot $varname]  -spec $cr_field_spec,$short_spec  -nls_language $nls_language  ]
          #:log "---> $f <[$f label]>"
          $f set __base_field $varname
        }
        default {
          set f [$base_item create_raw_form_field  -omit_field_name_spec true  -name $field_name  -slot ""  -spec $field_spec,$short_spec  -nls_language $nls_language  ]
        }
      }
      lappend form_fields $f
    }
    return $form_fields
  • sql_value (scripted)

    #
    # Transform wild-card * into SQL wild-card.
    #
    return [string map {* %} $input]

Methods (to be applied on instances)

  • action_url (scripted)

    #
    # Can be overloaded.
    #
    return [:pretty_link]
  • adp_subst (scripted)

    # Get the default field specs once and pass it to every field creation
    set field_spec [:get_short_spec @fields]
    set cr_field_spec [:get_short_spec @cr_fields]
    # Iterate over the variables for substitution
    set content [:regsub_eval -noquote true  [template::adp_variable_regexp$content"  {:get_value -field_spec $field_spec -cr_field_spec $cr_field_spec "\\\1" "\2"}]
    return [string range $content 1 end]
  • assignee (setter)

  • combine_data_and_form_field_default (scripted, public)

     <instance of xowiki::FormPage[i]> combine_data_and_form_field_default \
        is_new form_field data_value

    Combine the value of the form field (e.g. determined by the default) with the value in the instance attributes. This function decides, whether it should honor the data value or the form field value for e.g. rendering forms.

    Parameters:
    is_new - is this a new entry?
    form_field - object id of the form field
    data_value - the data from the instance attributes.

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_create_form_with_form_instance create_form_with_form_instance (test xowiki) xowiki::FormPage instproc combine_data_and_form_field_default xowiki::FormPage instproc combine_data_and_form_field_default test_create_form_with_form_instance->xowiki::FormPage instproc combine_data_and_form_field_default

    Testcases:
    create_form_with_form_instance
    set form_field_value [$form_field value]
    if {$is_new && $form_field_value ne "" && $data_value eq ""} {
      #
      # On fresh entries, take the default value in case the old
      # value is blank.
      #
    } else {
      #
      # Reset for form field value to the external
      # representation of the data value.
      #
      $form_field value [$form_field convert_to_external $data_value]
    }
    #ns_log notice "combine_data_and_form_field_default $is_new form_field [$form_field name] data_value <$data_value> final <[$form_field value]>"
  • compute_link_properties (scripted)

    set package_id ${:package_id}
    set page [::$package_id get_page_from_item_ref  -default_lang [:lang]  -parent_id ${:parent_id}  $item_ref]
    if {$page ne ""} {
      set item_id [$page item_id]
      set link_type [expr {[$page is_folder_page] ? "folder_link" : "link"}]
      set cross_package [expr {$package_id != [$page package_id]}]
    } else {
      set item_id 0
      set link_type "unresolved"
      set cross_package 0
    }
    #:msg [list item_ref $item_ref item_id $item_id link_type $link_type cross_package $cross_package]
    return [list item_ref $item_ref item_id $item_id link_type $link_type cross_package $cross_package]
  • condition=in_state (scripted)

    # possible values can be or-ed together (e.g. initial|final)
    foreach v [split $value |] {
      #:msg "check [:state] eq $v"
      if {[:state] eq $v} {return 1}
    }
    return 0
  • condition=is_true (scripted)

    #
    # This condition maybe called from the policy rules.
    # The passed value is a tuple of the form
    #     {property-name operator property-value}
    #
    lassign $value property_name op property_value
    if {![info exists property_value]} {
      return 0
    }
    
    #:log "$value => [:adp_subst $value]"
    array set wc [::xowiki::FormPage filter_expression [:adp_subst $value] &&]
    #:log "wc= [array get wc]"
    set __ia [dict merge $wc(vars) [:instance_attributes]]
    #:log "expr $wc(tcl) returns => [expr $wc(tcl)]"
    return [expr $wc(tcl)]
  • configure_page=regression_test (scripted)

    set :description "foo"
  • create_category_fields (scripted)

    set category_spec [:get_short_spec @categories]
    # Per default, no category fields in FormPages, since the can be
    # handled in more detail via form-fields.
    if {$category_spec eq ""} {return ""}
    
    # a value of "off" turns the off as well
    foreach f [split $category_spec ,] {
      if {$f eq "off"} {return ""}
    }
    
    set category_fields [list]
    set container_object_id ${:package_id}
    set category_trees [category_tree::get_mapped_trees $container_object_id]
    set category_ids [category::get_mapped_categories ${:item_id}]
    #:msg "mapped category ids=$category_ids"
    
    foreach category_tree $category_trees {
      lassign $category_tree tree_id tree_name subtree_id assign_single_p require_category_p
    
      set options [list]
      #if {!$require_category_p} {lappend options [list "--" ""]}
      set value [list]
      foreach category [::xowiki::Category get_category_infos  -subtree_id $subtree_id -tree_id $tree_id] {
        lassign $category category_id category_name deprecated_p level
        if {$category_id in $category_ids} {lappend value $category_id}
        set category_name [ns_quotehtml [lang::util::localize $category_name]]
        if { $level>1 } {
          set category_name "[string repeat {&nbsp;} [expr {2*$level-4}]]..$category_name"
        }
        lappend options [list $category_name $category_id]
      }
      set f [::xowiki::formfield::FormField new  -name "__category_${tree_name}_$tree_id"  -locale [:nls_language]  -label $tree_name  -type select  -value $value  -required $require_category_p]
      #:msg "category field ${:name} created, value '$value'"
      $f destroy_on_cleanup
      $f options $options
      $f multiple [expr {!$assign_single_p}]
      lappend category_fields $f
    }
    return $category_fields
  • create_form_field (scripted)

    if {$cr_field_spec eq ""} {set cr_field_spec [:get_short_spec @cr_fields]}
    if {$field_spec eq ""} {set field_spec [:get_short_spec @fields]}
    return [next -cr_field_spec $cr_field_spec -field_spec $field_spec $field_name]
  • create_form_fields (scripted)

    set form_fields [:create_category_fields]
    foreach att $field_names {
      if {[string match "__*" $att]} continue
    
      if {[:form_field_exists $att]} {
        #ns_log notice "... found form-field $att"
        lappend form_fields [:lookup_form_field -name $att {}]
    
      } else {
        #ns_log notice "... create form-field for $att"
        lappend form_fields [:create_form_field  -cr_field_spec [:get_short_spec @cr_fields]  -field_spec [:get_short_spec @fields] $att]
      }
    }
    return $form_fields
  • create_form_fields_from_names (scripted)

    #
    # Create form-fields from field names. When "-lookup" is
    # specified, the code tries to reuseexisting form-field instead of
    # creating/recreating it.
    #
    # Since create_raw_form_field uses destroy_on_cleanup, we do not
    # have to care here about destroying the objects.
    #
    set form_fields {}
    foreach field_name $field_names {
      if {$lookup && [:form_field_exists $field_name]} {
        #:msg "... found form_field for $field_name"
        lappend form_fields [:lookup_form_field -name $field_name {}]
      } else {
        #:msg "create '$spec_name' with spec '$short_spec'"
        lappend form_fields [:create_raw_form_field  -name $field_name  -form_constraints $form_constraints  ]
      }
    }
    if {$set_values} {
      :load_values_into_form_fields $form_fields
    }
    return $form_fields
  • demarshall (scripted)

    # reverse map assignees
    :reverse_map_party_attribute -attribute assignee -create_user_ids $create_user_ids
    #
    # The function will compute the category_ids, which are were used
    # to categorize these objects in the source instance.
    set category_ids [list]
    
    #:msg "${:name} check cm=[info exists ::__xowiki_reverse_category_map] && iam=[info exists :__instance_attribute_map]"
    
    if {[info exists ::__xowiki_reverse_category_map]
        && [info exists :__instance_attribute_map]
      } {
      #:msg "we have a instance_attribute_map"
    
      #
      # replace all symbolic category values by the mapped IDs
      #
      set ia [list]
      array set use ${:__instance_attribute_map}
      array set multiple_index [list category 2 party_id 1 file 1]
      foreach {name value} [:instance_attributes] {
        #:msg "use($name) --> [info exists use($name)]"
        if {[info exists use($name)]} {
          #:msg "try to map value '$value' (category tree: $use($name))"
          set map_type [lindex $use($name) 0]
          set multiple [lindex $use($name) $multiple_index($map_type)]
          if {$multiple eq ""} {set multiple 1}
          if {$multiple} {
            lappend ia $name [:reverse_map_values  -creation_user $creation_user -create_user_ids $create_user_ids  $map_type $value category_ids]
          } else {
            lappend ia $name [:reverse_map_value  -creation_user $creation_user -create_user_ids $create_user_ids  $map_type $value category_ids]
          }
        } else {
          # nothing to map
          lappend ia $name $value
        }
      }
      set :instance_attributes $ia
      #:msg  "${:name} saving instance_attributes $ia"
    }
    set r [next]
    set :__category_ids [lsort -unique $category_ids]
    return $r
  • exists_property (scripted)

    if {[regexp {^_([^_].*)$} $name _ varname]} {
      return [info exists :$varname]
    }
    return [dict exists ${:instance_attributes} $name]
  • extra_html_fields (scripted, public)

     <instance of xowiki::FormPage[i]> extra_html_fields

    Should be overloaded to provide extra content to some forms. This method can be used to add additional (e.g. hidden) HTML input fields to form pages. Example: ::html::input -type hidden -name __object_name -value [::security::parameter::signed ${:name}]

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

    Testcases:
    create_test_items
    return ""
  • field_names (scripted)

    #ns_log notice "=== field_names form <$form>"
    #
    # Ge the field-names mentioned in form (the provided form has
    # always highest precedence).
    #
    lassign [:field_names_from_form -form $form] form_vars needed_attributes
    #
    # In case, we have no form, get the field-names from the form
    # constraints.
    #
    if {[llength $needed_attributes] == 0} {
      set needed_attributes [:field_names_from_form_constraints]
    }
    #:log "form=$form, form_vars=$form_vars needed_attributes=$needed_attributes"
    
    set :__field_in_form ""
    set :__field_needed ""
    if {$form_vars} {
      foreach v $needed_attributes {
        dict set :__field_in_form $v 1
      }
    }
    foreach v $needed_attributes {
      dict set :__field_needed $v 1
    }
    
    #
    # Remove the fields already included in auto_fields form the needed_attributes.
    # The final list field_names determines the order of the fields in the form.
    #
    set auto_fields [list _name _page_order _title _creator _assignee _text _description _nls_language]
    set reduced_attributes $needed_attributes
    
    foreach f $auto_fields {
      set p [lsearch -exact $reduced_attributes $f]
      if {$p > -1} {
        set reduced_attributes [lreplace $reduced_attributes $p $p]
      }
    }
    #:msg reduced_attributes(after)=$reduced_attributes
    #:msg fields_from_form=[dict keys ${:__field_in_form}]
    
    set field_names _name
    if {[::${:package_id} show_page_order]}  {
      lappend field_names _page_order
    }
    lappend field_names _title _creator _assignee
    foreach fn $reduced_attributes {
      lappend field_names $fn
    }
    foreach fn {_text _description _nls_language} {
      lappend field_names $fn
    }
    #:msg final-field_names=$field_names
    return $field_names
  • field_names_from_form (scripted)

    #
    # This method returns the form attributes (including _*).
    #
    set allvars [list {*}[[:info class] array names db_slot]  {*}[::xo::db::CrClass set common_query_atts]]
    
    set template [:get_html_from_content [:get_from_template text]]
    #:msg template=$template
    
    #set field_names [list _name _title _description _creator _nls_language _page_order]
    set field_names [list]
    if {$form eq ""} {set form [:get_form]}
    if {$form eq ""} {
      foreach {var _} [:template_vars $template] {
        #if {[string match _* $var]} continue
        if {$var ni $allvars && $var ni $field_names} {
          lappend field_names $var
        }
      }
      set from_HTML_form 0
    } else {
      foreach {match 1 att} [regexp -all -inline [template::adp_variable_regexp$form] {
        #if {[string match _* $att]} continue
        lappend field_names $att
      }
      #ns_log notice "field_names_from_form: [:serialize]"
      dom parse -html -simple $form doc
      $doc documentElement root
      set fields [$root selectNodes "//*\[@name != ''\]"]
      foreach field $fields {
        set node_name [$field nodeName]
        if {$node_name ne "input"
            && $node_name ne "textarea"
            && $node_name ne "select"
          } continue
        set att [$field getAttribute name]
        #if {[string match _* $att]} continue
        if {$att ni $field_names} { lappend field_names $att }
      }
      set from_HTML_form 1
    }
    return [list $from_HTML_form $field_names]
  • footer (scripted)

    if {[info exists :__no_form_page_footer]} {
      next
    } else {
      set is_form [:property is_form__ 0]
      if {[:is_form]} {
        return [:include [list form-menu -form_item_id ${:item_id}  -buttons [list new answers [list form ${:page_template}]]]]
      } else {
        return [:include [list form-menu -form_item_id ${:page_template} -buttons form]]
      }
    }
  • form_field_as_html (scripted)

    set found 0
    foreach f $form_fields {
      if {[$f name] eq $name} {set found 1; break}
    }
    if {!$found} {
      set f [:create_raw_form_field -name $name -slot [:find_slot $name]]
    }
    #:log "found $name in $form_fields -> $found [$f info class]"
    
    if {$mode eq "edit" || [$f display_field]} {
      set html [$f asHTML]
    } else {
      set html @$name@
    }
    #:msg "RESULT: $name <$html>"
    return ${before}$html
  • form_fields_sanity_check (scripted)

    foreach f $form_fields {
      if {[$f is_disabled]} {
        # don't mark disabled fields as required
        if {[$f required]} {
          $f required false
        }
        #don't show the help-text, if you cannot input
        if {[$f help_text] ne ""} {
          $f help_text ""
        }
      }
      if {[$f exists transmit_field_always]
          && "::xowiki::formfield::omit" in [$f info mixin]} {
        # Never omit these fields, this would cause problems with
        # autonames and empty languages. Set these fields to hidden
        # instead.
        $f remove_omit
        $f class ::xowiki::formfield::hidden
        $f initialize
        #:msg "$f [$f name] [$f info class] [$f info mixin]"
      }
    }
  • get_anon_instances (scripted)

    # maybe overloaded from WorkFlow
    :get_from_template anon_instances f
  • get_form_constraints (scripted)

    #
    # This method os likely to be overloaded, maybe by xowf.
    #
    #:msg "is_form=[:is_form]"
    if {$trylocal && [:is_form]} {
      return [:property form_constraints]
    } else {
      #:msg "get_form_constraints returns '[:get_from_template form_constraints]'"
      return [:get_from_template form_constraints]
    }
  • get_form_value (scripted)

    #
    # Return the value contained in an HTML input field of the FORM
    # provided via the instance variable root.
    #
    set fields [${:root} selectNodes "//form//*\[@name='$att'\]"]
    if {$fields eq ""} {return ""}
    foreach field $fields {
      #
      # Handling first TEXTAREA
      #
      if {[$field nodeName] eq "textarea"} {
        return [$field nodeValue]
      }
      if {[$field nodeName] ne "input"} continue
      #
      # Handling now just INPUT types (only one needed so far)
      #
      set type [expr {[$field hasAttribute type] ? [$field getAttribute type] : "text"}]
      switch -- $type {
        checkbox {
          #:msg "get_form_value not implemented for $type"
        }
        radio {
          #:msg "get_form_value not implemented for $type"
        }
        hidden -
        password -
        text {
          if {[$field hasAttribute value]} {
            return [$field getAttribute value]
          }
        }
        default {
          #:log "can't handle $type so far $att=$value"
        }
      }
    }
    return ""
  • get_parameter (scripted)

    #
    # Try to get the parameter from the parameter_page provided as
    # property "ParameterPages".
    #
    set value [::${:package_id} get_parameter_from_parameter_page  -parameter_page_name [:property ParameterPages]  $attribute]
    if {$value eq {}} {set value [next $attribute $default]}
    return $value
  • get_property (scripted, public)

     <instance of xowiki::FormPage[i]> get_property [ -source source ] \
        -name name  [ -default default ]

    Retrieves a FormPage property

    Switches:
    -source
    (optional)
    page name to be resolved and used instead this FormPage to fetch the property
    -name
    (required)
    -default
    (optional)

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

    Testcases:
    create_test_items
    if {![info exists source]} {
      set page [self]
    } else {
      set page [:resolve_included_page_name $source]
    }
    return [$page property $name $default]
  • get_value (scripted)

    #
    # Read a property (instance attribute) and return
    # its pretty value in variable substitution.
    #
    # We check for special variable names here (such as current_user
    # or current_url). We provide a value from the current connection
    # context.
    if {$varname eq "current_user"} {
      set value [::xo::cc set untrusted_user_id]
    
    } elseif {$varname eq "current_url"} {
      set value [::xo::cc url]
    
    } else {
      #
      # First check to find an existing form-field with that name
      #
      set f [::xowiki::formfield::FormField get_from_name [self$varname]
      if {$f ne ""} {
        #
        # The form field exists already, we just fill in the actual
        # value (needed e.g. in weblogs, when the same form field is
        # used for multiple page instances in a single request)
        #
        set value [$f value [:property $varname]]
      } else {
        #
        # create a form-field from scratch
        #
        set value [:property $varname]
        set f [:create_form_field -cr_field_spec $cr_field_spec -field_spec $field_spec $varname]
        $f value $value
      }
    
      if {[$f hide_value]} {
        set value ""
      } elseif {![$f exists show_raw_value]} {
        set value [$f pretty_value $value]
      }
    }
    return $before$value
  • group_assign (scripted)

    set old_members [group::get_members -group_id $group_id]
    foreach m $members {
      if {$m ni $old_members} {
        #:msg "we have to add $m"
        group::add_member -group_id $group_id -user_id $m  -rel_type $rel_type -member_state $member_state
      }
    }
    foreach m $old_members {
      if {$m ni $members} {
        #:msg "we have to remove $m"
        group::remove_member -group_id $group_id -user_id $m
      }
    }
  • group_require (scripted)

    #
    # Create a group if necessary associated to the current form
    # page. Since the group_names are global, the group name contains
    # the parent_id of the FormPage.
    #
    set group_name "fpg-${:parent_id}-${:name}"
    set group_id [group::get_id -group_name $group_name]
    if {$group_id eq ""} {
      # group::new does not flush the cache - sigh!  Therefore, we have
      # to flush the old cache entry here manually.
      ::acs::clusterwide ns_cache flush util_memoize  "group::get_id_not_cached -group_name $group_name -subsite_id {} -application_group_id {}"
      set group_id [group::new -group_name $group_name]
    }
    return $group_id
  • hstore_attributes (scripted)

    # Per default, we save all instance attributes in hstore, but a
    # subclass/object might have different requirements.
    return ${:instance_attributes}
  • include_header_info (scripted)

    if {$css eq ""} {set css [:get_from_template ${prefix}_css]}
    if {$js eq ""}  {set js [:get_from_template ${prefix}_js]}
    foreach line [split $js \n] {
      set line [string trim $line]
      if {$line ne ""} {
        ::xo::Page requireJS $line
      }
    }
    foreach line [split $css \n] {
      set line [string trim $line]
      if {$line eq ""} continue
      set order 1
      if {[llength $line]>1} {
        set e1 [lindex $line 0]
        if {[string is integer -strict $e1]} {
          set order $e1
          set line [lindex $line 1]
        }
      }
      ::xo::Page requireCSS -order $order $line
    }
  • initialize (scripted)

    # can be overloaded
  • initialize_loaded_object (scripted)

    #:msg "${:name} [:info class]"
    if {[info exists :page_template]} {
      set p [::xo::db::CrClass get_instance_from_db -item_id ${:page_template}]
      #
      # The Form might come from a different package type (e.g. a
      # workflow) make sure, the source package is available.
      #
      # Note that global pages (site_wide_pages) might not belong to
      # a package and have therefore an empty package_id.
      #
      set package_id [$p package_id]
      if {$package_id ne ""} {
        ::xo::Package require $package_id
      }
    }
    next
  • is_folder_page (scripted, public)

     <instance of xowiki::FormPage[i]> is_folder_page \
        [ -include_folder_links include_folder_links ]

    Check, if FormPage is a folder. A FormPage is a folder when its page template is the folder.form or if this is a link pointing to a folder.

    Switches:
    -include_folder_links
    (defaults to "true") (optional)
    return true, if the current page is a link to a folder.
    Returns:
    boolean

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_xowiki_test_cases xowiki_test_cases (test xowiki) xowiki::FormPage instproc is_folder_page xowiki::FormPage instproc is_folder_page test_xowiki_test_cases->xowiki::FormPage instproc is_folder_page

    Testcases:
    xowiki_test_cases
    #
    # Make sure, the page_template is instantiated
    #
    if {![nsf::is object ::${:page_template}]} {
      ::xo::db::CrClass get_instance_from_db -item_id ${:page_template}
    }
    set page_template_name [${:page_template} name]
    if {$page_template_name eq "en:folder.form"} {
      return 1
    } elseif {$include_folder_links && $page_template_name eq "en:link.form"} {
      set link_type [:get_property_from_link_page link_type]
      return [expr {$link_type eq "folder_link"}]
    } else {
      return 0
    }
  • is_form (scripted)

    return [:exists_property form_constraints]
  • is_link_page (scripted)

    #
    # Make sure, the page_template is instantiated
    #
    if {![nsf::is object ::${:page_template}]} {
      ::xo::db::CrClass get_instance_from_db -item_id ${:page_template}
    }
    return [expr {[${:page_template} name] eq "en:link.form"}]
  • langstring (scripted)

    set result $default
    if {[:exists_property langstring]} {
      set d [:property langstring]
      if {[dict exists $d $attname $lang]} {
        set result [dict get $d $attname $lang]
      }
    }
    return $result
  • lappend_property (scripted)

    #
    # lappend the specified value to the named property. If the
    # property does not exists, create a new one.
    #
    if {[:exists_property $name]} {
      :set_property $name [concat [:get_property -name $name$value]
    } else {
      :set_property -new 1 $name $value
    }
  • load_values_into_form_fields (scripted, public)

     <instance of xowiki::FormPage[i]> load_values_into_form_fields \
        form_fields

    Load either the instance variables or the instance attributes into the provided form-fields. The function sets the values based on the default values and the values for the current object.

    Parameters:
    form_fields

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_create_form_with_form_instance create_form_with_form_instance (test xowiki) xowiki::FormPage instproc load_values_into_form_fields xowiki::FormPage instproc load_values_into_form_fields test_create_form_with_form_instance->xowiki::FormPage instproc load_values_into_form_fields test_create_form_with_numeric create_form_with_numeric (test xowiki) test_create_form_with_numeric->xowiki::FormPage instproc load_values_into_form_fields _ _ (public) xowiki::FormPage instproc load_values_into_form_fields->_

    Testcases:
    create_form_with_form_instance, create_form_with_numeric
    set is_new [:is_new_entry ${:name}]
    
    foreach f $form_fields {
      set att [$f name]
      switch -glob $att {
        __* {}
        _* {
          set varname [string range $att 1 end]
          :combine_data_and_form_field_default $is_new $f [set :$varname]
        }
        default {
          #:log "load_values_into_form_field $att"  "exists [dict exists ${:instance_attributes} $att]"  "in [dict keys ${:instance_attributes}]"
          if {[dict exists ${:instance_attributes} $att]} {
            :combine_data_and_form_field_default $is_new $f [dict get ${:instance_attributes} $att]
          }
        }
      }
    }
  • map_value (scripted)

    :log "map_value $map_type$value"
    if {$map_type eq "category" && $value ne ""} {
      #
      # map a category item
      #
      return [dict get ${:__category_map} $value]
    } elseif {$map_type eq "party_id" && $value ne ""} {
      #
      # map a party_id
      #
      return [:map_party -property $map_type $value]
    } elseif {$map_type eq "file" && [llength $value] % 2 == 0} {
      #
      # drop revision_id from file value
      #
      set result {}
      foreach {a v} $value {
        if {$a eq "revision_id"} continue
        lappend result $a $v
      }
      return $result
    } else {
      return $value
    }
  • map_values (scripted)

    # Map a list of values (for multi-valued form fields)
    # :log "map_values $map_type, $values"
    set mapped_values [list]
    foreach value $values {lappend mapped_values [:map_value $map_type $value]}
    return $mapped_values
  • marshall (scripted)

    #
    # Handle mapping from IDs to symbolic representations in
    # form-field values. We perform the mapping on xowiki::FormPages
    # and not on xowiki::Forms, since a single xowiki::FormPages might
    # use different xowiki::Forms in its life-cycle.
    #
    # Note that only types of form-fields implied by the derived form
    # constraints are recognized. E.g. In workflows, it might be
    # necessary to move e.g. category definitions into the global form
    # constraints.
    #
    if {$mode eq "copy" && ![string match "*revision_id*" ${:instance_attributes}]} {
      return [next]
    }
    set form_fields [:create_form_fields_from_form_constraints  [:get_form_constraints]]
    :build_instance_attribute_map $form_fields
    
    # In case we have a mapping from IDs to external values, use it
    # and rewrite instance attributes. Note that the marshalled
    # objects have to be flushed from memory later since the
    # representation of instances_attributes is changed by this
    # method.
    #
    if {[info exists :__instance_attribute_map]} {
      # :log "+++ we have an instance_attribute_map for ${:name}"
      # :log "+++ starting with instance_attributes [:instance_attributes]"
      array set multiple_index [list category 2 party_id 1 file 1]
      set ia [list]
      foreach {name value} [:instance_attributes] {
        #:log "marshall check $name $value [info exists use($name)]"
        if {[dict exists ${:__instance_attribute_map} $name]} {
          set use_name [dict get ${:__instance_attribute_map} $name]
          set map_type [lindex $use_name 0]
          set multiple [lindex $use_name $multiple_index($map_type)]
          #:log "+++ marshall check $name $value use <$use($name)> m=?$multiple"
          if {$multiple} {
            lappend ia $name [:map_values $map_type $value]
          } else {
            lappend ia $name [:map_value $map_type $value]
          }
        } else {
          # nothing to map
          lappend ia $name $value
        }
      }
      set :instance_attributes $ia
      #:log "+++ setting instance_attributes $ia"
    }
    set old_assignee [:assignee]
    set :assignee  [:map_party -property assignee $old_assignee]
    set r [next]
    set :assignee  $old_assignee
    return $r
  • mime_type (setter)

  • new_link (scripted)

    if {[info exists object_type]} {
      next
    } else {
      set template_id ${:page_template}
      if {![info exists parent_id]} {
        set parent_id [::$page_package_id folder_id]
      }
      set form [::$page_package_id pretty_link -parent_id $parent_id [::$template_id name]]
      return [::$page_package_id make_link -link $form $template_id  create-new return_url name title nls_language]
    }
  • notification_render (scripted)

    if {[:is_link_page] || [:is_folder_page]} {
      return ""
    } else {
      return [next]
    }
  • post_process_dom_tree (scripted)

    # Part of the input fields comes from HTML, part comes via $form_fields
    # We offer here the possibility to iterate over the dom tree before it
    # is presented; can be overloaded
  • post_process_form_fields (scripted)

    # We offer here the possibility to iterate over the form fields
    # before they are rendered
  • pretty_name (scripted)

    set anon_instances [:get_from_template anon_instances f]
    if {$anon_instances} {
      return ${:title}
    }
    return ${:name}
  • property (scripted, public)

     <instance of xowiki::FormPage[i]> property name [ default ]

    Retrieve a FormPage property.

    Parameters:
    name - property name. Names starting with _ refer to object's members, rather than instance attributes.
    default (optional) - fallback value when property is not set.

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_xowiki_test_cases xowiki_test_cases (test xowiki) xowiki::FormPage instproc property xowiki::FormPage instproc property test_xowiki_test_cases->xowiki::FormPage instproc property

    Testcases:
    xowiki_test_cases
    if {[regexp {^_([^_].*)$} $name _ varname]} {
      if {[info exists :$varname]} {
        return [set :$varname]
      }
    } elseif {[dict exists ${:instance_attributes} $name]} {
      return [dict get ${:instance_attributes} $name]
    }
    return $default
  • render_content (scripted)

    #
    # Produce an HTML rendering from the FormPage.
    #
    #set package_id ${:package_id}
    :include_header_info -prefix form_view
    if {[::xo::cc mobile]} {
      :include_header_info -prefix mobile
    }
    set text [:get_from_template text]
    if {$text ne ""} {
      catch {set text [lindex $text 0]}
    }
    if {$text ne ""} {
      #:log "we have a template text='$text'"
      #
      # We have a template, this is the first preference.
      #
      set HTML [next]
    } else {
      #:log "we have a form '[:get_form]'"
      #
      # Fall back to the form, fill it out and compute HTML from this.
      #
      set form [:get_form]
      if {$form eq ""} {
        return ""
      }
    
      lassign [:field_names_from_form -form $form] form_vars field_names
      set :__field_in_form ""
      if {$form_vars} {
        foreach v $field_names {
          dict set :__field_in_form $v 1
        }
      }
      set form_fields [:create_form_fields $field_names]
      foreach n $field_names f $form_fields {
        dict set :__form_fields $n $f
      }
    
      :load_values_into_form_fields $form_fields
    
      # deactivate form-fields and do some final sanity checks
      foreach f $form_fields {$f set_disabled 1}
      :form_fields_sanity_check $form_fields
      :post_process_form_fields $form_fields
    
      set form [:regsub_eval   [template::adp_variable_regexp$form  {:form_field_as_html -mode display "\\\1" "\2" $form_fields}]
    
      # we parse the form just for the margin-form.... maybe regsub?
      dom parse -html -simple $form :doc
      ${:doc} documentElement :root
      set form_node [lindex [${:root} selectNodes //form] 0]
    
      Form add_dom_attribute_value $form_node role form
      Form add_dom_attribute_value $form_node class [${:page_template} css_class_name]
      # The following two commands are for non-generated form contents
      :set_form_data $form_fields
      Form dom_disable_input_fields ${:root}
      # Return finally the result
      set HTML [${:root} asHTML]
    }
    
    return $HTML
  • render_form_action_buttons (scripted)

    set f [::xowiki::formfield::submit_button new -destroy_on_cleanup  -name __form_button_ok  -CSSclass $CSSclass]
    
    ::html::div [expr {[$f exists form_button_wrapper_CSSclass]
                       ? [list class [$f form_button_wrapper_CSSclass]]
                       : {} }] {
                         $f render_input
                       }
  • render_icon (scripted)

    set page_template ${:page_template}
    if {[$page_template istype ::xowiki::FormPage]} {
      return [list text [$page_template property icon_markup] is_richtext true]
    }
    switch [$page_template name] {
      en:folder.form {
        return {text "<a title='folder' class='folder-open-icon'>&nbsp;</a>" is_richtext true}
      }
      en:link.form {
        set link_type [:get_property_from_link_page link_type "unresolved"]
        if {$link_type eq "unresolved"} {
          return {text "<a title='broken link' class='broken-link-icon'>&nbsp;</a>" is_richtext true}
        } else {
          return {text "<a title='link' class='link-icon'>&nbsp;</a>" is_richtext true}
        }
      }
      default {
        return [list text [$page_template title] is_richtext false]
      }
    }
  • render_thumbnails (scripted, public)

     <instance of xowiki::FormPage[i]> render_thumbnails upload_info

    Renderer of the thumnail file(s). This method is a stub to be refined (e.g. in xowf).

    Parameters:
    upload_info - dict containing the "file_object" and "file_name"
    Returns:
    HTML content

    Partial Call Graph (max 5 caller/called nodes):
    %3

    Testcases:
    No testcase defined.
    return "[dict get $upload_info file_name] created"
  • reverse_map_value (scripted)

    # Perform the inverse function of map_value. During export, internal
    # representations are exchanged by string representations, which are
    # mapped here again to internal representations
    :upvar $category_ids_name category_ids
    if {[info exists ::__xowiki_reverse_category_map($value)]} {
      #:msg "map value '$value' (category tree: $use($name)) of ${:name} to an ID"
      lappend category_ids $::__xowiki_reverse_category_map($value)
      return $::__xowiki_reverse_category_map($value)
    } elseif {$map_type eq "party_id"} {
      return [:reverse_map_party  -entry $value  -default_party $creation_user  -create_user_ids $create_user_ids]
    } elseif {$value eq ""} {
      return ""
    } else {
      :msg "cannot map value '$value' (map_type $map_type) of ${:name} to an ID; maybe there is some same_named category tree with fewer entries..."
      :msg "reverse category map has values [lsort [array names ::__xowiki_reverse_category_map]]"
      return ""
    }
  • reverse_map_values (scripted)

    # Apply reverse_map_value to a list of values (for multi-valued
    # form fields)
    :upvar $category_ids_name category_ids
    set mapped_values [list]
    foreach value $values {
      lappend mapped_values [:reverse_map_value  -creation_user $creation_user -create_user_ids $create_user_ids  $map_type $value category_ids]
    }
    return $mapped_values
  • setCSSDefaults (scripted)

    ad_log warning "deprecated method setCSSDefaults was called. The call should be removed"
  • set_content (scripted)

    if {$text eq ""} {
      set :text $text
    } else {
      next
    }
  • set_form_data (scripted, public)

     <instance of xowiki::FormPage[i]> set_form_data form_fields

    Store the instance attributes or default values into the form via set_form_value. This function iterates over the provided form-fields and checks, if these are known fields in the current form. These known field names are defined via the method "field_names" that extracts these names from a form. If one wants to load all values from an FormPage into the provided form-fields, use method "load_values_into_form_fields" instead.

    Parameters:
    form_fields

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_create_form_with_form_instance create_form_with_form_instance (test xowiki) xowiki::FormPage instproc set_form_data xowiki::FormPage instproc set_form_data test_create_form_with_form_instance->xowiki::FormPage instproc set_form_data xo::require_html_procs xo::require_html_procs (public) xowiki::FormPage instproc set_form_data->xo::require_html_procs

    Testcases:
    create_form_with_form_instance
    ::xo::require_html_procs
    
    foreach f $form_fields {
      set att [$f name]
      # just handle fields of the form entry
      if {![dict exists ${:__field_in_form} $att]} continue
      #:msg "set form_value to form-field $att [dict exists ${:instance_attributes} $att]"
      if {[dict exists ${:instance_attributes} $att]} {
        #:msg "my set_form_value from ia $att '[dict get ${:instance_attributes} $att]', external='[$f convert_to_external [dict get ${:instance_attributes} $att]]' f.value=[$f value]"
        :set_form_value $att [$f convert_to_external [dict get ${:instance_attributes} $att]]
      } else {
        # do we have a value in the form? If yes, keep it.
        set form_value [:get_form_value $att]
        #:msg "no instance attribute, set form_value $att '[$f value]' form_value=$form_value"
        if {$att eq ""} {
          # we have no instance attributes, use the default value from the form field
          :set_form_value $att [$f convert_to_external [$f value]]
        }
      }
    }
  • set_form_value (scripted)

    #:msg "set_form_value '$att' to '$value'"
    #
    # Feed the provided value into an HTML form provided via the
    # instance variable root.
    #
    set fields [${:root} selectNodes "//form//*\[@name='$att'\]"]
    #:msg "found field = $fields xp=//*\[@name='$att'\]"
    
    foreach field $fields {
      #
      # We handle textarea and input fields
      #
      if {[$field nodeName] eq "textarea"} {
        #
        # For TEXTAREA, delete the existing content and insert the new
        # content as text
        #
        foreach node [$field childNodes] {$node delete}
        $field appendFromScript {::html::t $value}
      }
      if {[$field nodeName] ne "input"} continue
      #
      # We handle now only INPUT types, but we have to differentiate
      # between different kinds of inputs.
      #
      set type [expr {[$field hasAttribute type] ? [$field getAttribute type] : "text"}]
      # the switch should be really different objects ad classes...., but that's HTML, anyhow.
      switch -- $type {
        checkbox {
          #:msg "$att: CHECKBOX value='$value', [$field hasAttribute checked], [$field hasAttribute value]"
          if {[$field hasAttribute value]} {
            set form_value [$field getAttribute value]
            #:msg "$att: form_value=$form_value, my value=$value"
            if {$form_value in $value} {
              $field setAttribute checked true
            } elseif {[$field hasAttribute checked]} {
              $field removeAttribute checked
            }
          } else {
            #:msg "$att: CHECKBOX entry has no value"
            if {[catch {set f [expr {$value ? 1 : 0}]}]} {set f 1}
            if {$value eq "" || $f == 0} {
              if {[$field hasAttribute checked]} {
                $field removeAttribute checked
              }
            } else {
              $field setAttribute checked true
            }
          }
        }
        radio {
          set inputvalue [$field getAttribute value]
          #:msg "radio: compare input '$inputvalue' with '$value'"
          if {$inputvalue eq $value} {
            $field setAttribute checked true
          }
        }
        hidden -
        password -
        text {
          if { ![$field getAttribute rep "0"] } {
            $field setAttribute value $value
          }
        }
        default {:log "can't handle $type so far $att=$value"}
      }
    }
  • set_live_revision (scripted, public)

     <instance of xowiki::FormPage[i]> set_live_revision \
        -revision_id revision_id  [ -publish_status publish_status ]
    Switches:
    -revision_id
    (required)
    -publish_status
    (defaults to "ready") (optional)
    one of 'live', 'ready' or 'production'

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_create_folder_with_page create_folder_with_page (test xowf) xowiki::FormPage instproc set_live_revision xowiki::FormPage instproc set_live_revision test_create_folder_with_page->xowiki::FormPage instproc set_live_revision test_create_workflow_with_instance create_workflow_with_instance (test xowf) test_create_workflow_with_instance->xowiki::FormPage instproc set_live_revision xowiki::update_item_index xowiki::update_item_index (public) xowiki::FormPage instproc set_live_revision->xowiki::update_item_index

    Testcases:
    create_folder_with_page, create_workflow_with_instance
    next
    
    # Fetch fresh instance from db so that we have actual values
    # from the live revision for the update of the item_index.
    
    set page [::xo::db::CrClass get_instance_from_db -revision_id $revision_id]
    $page publish_status $publish_status
    $page update_item_index
  • set_property (scripted, public)

     <instance of xowiki::FormPage[i]> set_property [ -new new ] name \
        value

    Stores a value as FormPage property

    Switches:
    -new
    (defaults to "0") (optional)
    boolean flag telling if the property is new. Setting a value on a non-existing property without specifying this flag will result in an error.
    Parameters:
    name - property name. Names starting with _ indicate an object variable rather than a property stored in instance_attributes
    value - property value
    Returns:
    value (eventually converted to a has-notation message key)

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_create_form_with_form_instance create_form_with_form_instance (test xowiki) xowiki::FormPage instproc set_property xowiki::FormPage instproc set_property test_create_form_with_form_instance->xowiki::FormPage instproc set_property

    Testcases:
    create_form_with_form_instance
    if {[string match "_*" $name]} {
      set key [string range $name 1 end]
    
      if {!$new && ![info exists :$key]} {
        error "property '$name' ($key) does not exist.  you might use flag '-new 1' for set_property to create new properties"
      }
      set :$key $value
    
    } else {
    
      if {!$new && ![dict exists ${:instance_attributes} $name]} {
        error "property '$name' does not exist.  you might use flag '-new 1' for set_property to create new properties"
      }
      dict set :instance_attributes $name $value
    }
    return $value
  • set_publish_status (scripted)

    if {$value ni {production ready}} {
      error "invalid value '$value'; use 'production' or 'ready'"
    }
    set :publish_status $value
  • state (setter)

  • update (scripted)

    ::xo::dc transaction {
      next
      :instvar object_id state assignee
      ::xo::dc dml update_xowiki_form_page {update xowiki_form_page
        set state = :state,assignee = :assignee where xowiki_form_page_id = :object_id
      }
    }
  • update_attribute_from_slot (scripted, public)

     <instance of xowiki::FormPage[i]> update_attribute_from_slot \
        [ -revision_id revision_id ] slot value

    Tailored version of update_attribute_from_slot to keep insert_xowiki_form_instance_item_index in sync after single attribute updates.

    Switches:
    -revision_id
    (optional)
    Parameters:
    slot
    value

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_slot_interactions slot_interactions (test xowiki) xowiki::FormPage instproc update_attribute_from_slot xowiki::FormPage instproc update_attribute_from_slot test_slot_interactions->xowiki::FormPage instproc update_attribute_from_slot xowiki::update_item_index xowiki::update_item_index (public) xowiki::FormPage instproc update_attribute_from_slot->xowiki::update_item_index

    Testcases:
    slot_interactions
    #
    # Perform first the regular operations.
    #
    next
    #
    # Make sure to update update_item_index when the attribute is
    # contained in the xowiki_form_instance_item_index.
    #
    set colName [$slot column_name]
    
    if {$colName in {
      package_id
      parent_id
      publish_status
      page_template
      assignee
      state
    }} {
      ::xowiki::update_item_index -item_id ${:item_id} -$colName $value
    } elseif {
              $colName eq "instance_attributes"
              && [::xo::dc has_hstore]
              && [::${:package_id} get_parameter use_hstore:boolean 0]
            } {
      ::xowiki::update_item_index -item_id ${:item_id} -hstore_attributes $value
    }
  • update_item_index (scripted, public)

     <instance of xowiki::FormPage[i]> update_item_index

    Tailored version of CrItem.update_item_index to keep insert_xowiki_form_instance_item_index in sync after updates.

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_link_tests link_tests (test xowiki) xowiki::FormPage instproc update_item_index xowiki::FormPage instproc update_item_index test_link_tests->xowiki::FormPage instproc update_item_index xowiki::hstore::dict_as_hkey xowiki::hstore::dict_as_hkey (public) xowiki::FormPage instproc update_item_index->xowiki::hstore::dict_as_hkey

    Testcases:
    link_tests
    :instvar name item_id package_id parent_id publish_status  page_template instance_attributes assignee state
    
    set useHstore [::$package_id get_parameter use_hstore:boolean 0]
    set updateVars {name = :name, package_id = :package_id,
      parent_id = :parent_id, publish_status = :publish_status,
      page_template = :page_template, assignee = :assignee,
      state = :state}
    
    if {$useHstore} {
      set hkey [::xowiki::hstore::dict_as_hkey [:hstore_attributes]]
      append updateVars ", hkey = '$hkey'"
    }
    
    set rows [xo::dc dml update_xowiki_form_instance_item_index [subst {
      update xowiki_form_instance_item_index
      set $updateVars
      where item_id = :item_id
    }]]
    
    if {$rows ne "" && $rows < 1} {
      set insertVars {item_id, name, package_id, parent_id, publish_status,
        page_template, assignee, state
      }
      set insertValues {:item_id, :name, :package_id, :parent_id, :publish_status,
        :page_template, :assignee, :state
      }
      if {$useHstore} {
        append insertVars {, hkey}
        append insertValues ", '$hkey'"
      }
    
      ::xo::dc dml insert_xowiki_form_instance_item_index [subst {
        insert into xowiki_form_instance_item_index
        ($insertVars) values ($insertValues)
      }]
    }
  • update_langstring_property (scripted)

    :set_property $attname [:langstring $attname $lang [:property $attname]]
  • www-edit (scripted, public)

     <instance of xowiki::FormPage[i]> www-edit \
        [ -validation_errors validation_errors ] \
        [ -disable_input_fields disable_input_fields ] [ -view on|off ]

    This web-callable method renders a form page in "edit" mode (i.e. provide input fields). The following query parameters can be used to influene the results "return_url", "title", "detail_link", "text", and "description".

    Switches:
    -validation_errors
    (optional)
    -disable_input_fields
    (defaults to "0") (optional)
    -view
    (boolean) (defaults to "true") (optional)

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_create_workflow_with_instance create_workflow_with_instance (test xowf) xowiki::FormPage instproc www-edit xowiki::FormPage instproc www-edit test_create_workflow_with_instance->xowiki::FormPage instproc www-edit ad_log ad_log (public) xowiki::FormPage instproc www-edit->ad_log ad_urlencode_url ad_urlencode_url (public) xowiki::FormPage instproc www-edit->ad_urlencode_url dom dom xowiki::FormPage instproc www-edit->dom export_vars export_vars (public) xowiki::FormPage instproc www-edit->export_vars html::CSRFToken html::CSRFToken xowiki::FormPage instproc www-edit->html::CSRFToken

    Testcases:
    create_workflow_with_instance
    #:log "edit [self args]"
    
    :include_header_info -prefix form_edit
    if {[::xo::cc mobile]} {
      :include_header_info -prefix mobile
    }
    
    set form [:get_form]
    set anon_instances [:get_anon_instances]
    #:log form=$form
    #:log anon_instances=$anon_instances
    
    set field_names [:field_names -form $form]
    #:log field_names=$field_names
    set form_fields [:create_form_fields $field_names]
    #foreach f0 $form_fields {
    #  ns_log notice "... created ff [$f0 name] [$f0 info class] '[$f0 value]'"
    #}
    
    if {$form eq ""} {
      #
      # Since we have no form, we create it on the fly
      # from the template variables and the form field specifications.
      #
      set form "<form></form>"
      set formgiven 0
    } else {
      set formgiven 1
    }
    #:log formgiven=$formgiven
    
    # check name field:
    #  - if it is for anon instances, hide it,
    #  - if it is required but hidden, show it anyway
    #    (might happen, when e.g. set via @cr_fields ... hidden)
    set name_field [:lookup_form_field -name _name $form_fields]
    
    if {$anon_instances} {
      #$name_field config_from_spec hidden
    } else {
      if {[$name_field istype ::xowiki::formfield::hidden]
          && [$name_field required] == true
        } {
        $name_field config_from_spec text,required
        $name_field type text
      }
    }
    
    #
    # Include _text only, if explicitly needed (in form
    # needed(_text))".
    #
    if {![dict exists ${:__field_needed} _text]} {
      #:msg "setting text hidden"
      set f [:lookup_form_field -name _text $form_fields]
      $f config_from_spec hidden
    }
    
    if {[:exists_form_parameter __disabled_fields]} {
      #
      # Disable some form-fields since these are disabled in the form
      # as well.
      #
      foreach name [:form_parameter __disabled_fields] {
        set f [:lookup_form_field -name $name $form_fields]
        $f set_disabled true
      }
    }
    
    #:show_fields $form_fields
    #:log "__form_action [:form_parameter __form_action {}]"
    
    if {[:form_parameter __form_action ""] eq "save-form-data"} {
      #
      # We want to save the form data, so we have to validate.
      #
      #:log "we have to validate"
      #
      # In case we are triggered internally, we might not have a
      # a connection. Therefore, do not validate the CSRF token.
      #
      if {![::${:package_id} exists __batch_mode]} {
        security::csrf::validate
      }
    
      lassign [:get_form_data $form_fields] validation_errors category_ids
      if {$validation_errors != 0} {
        #
        # We have validation errors.
        #
        #:log "$validation_errors validation errors in $form_fields"
        #foreach f $form_fields { :log "$f: [$f name] '[$f set value]' err: [$f error_msg] " }
        #
        # In case we are triggered internally, we might not have a
        # a connection, so we don't present the form with the
        # error messages again, but we return simply the validation
        # problems.
        #
        if {[::${:package_id} exists __batch_mode]} {
          set errors [list]
          foreach f $form_fields {
            if {[$f error_msg] ne ""} {
              lappend errors [list field [$f name] value [$f set value] error [$f error_msg]]
            }
          }
          set evaluation_errors ""
          if {[::${:package_id} exists __evaluation_error]} {
            set evaluation_errors "\nEvaluation error: [::${:package_id} set __evaluation_error]"
            ::${:package_id} unset __evaluation_error
          }
          error "[llength $errors] validation error(s): $errors $evaluation_errors"
        }
        #
        # Reset the name in error cases to the original one.
        #
        set :name [:form_parameter __object_name:signed,convert]
      } else {
        #
        # We have no validation errors, so we can save the content.
        #
        :save_data  -use_given_publish_date [expr {"_publish_date" in $field_names}]  [::xo::cc form_parameter __object_name:signed,convert ""$category_ids
    
        #
        # The data might have references. Perform the rendering here to compute
        # the references instead on every view (which would be safer, but slower). This is
        # roughly the counterpart to edit_data and save_data in ad_forms.
        #
        set content [:render -update_references all]
        #:log "after save refs=[expr {[info exists :references]?${:references} : {NONE}}]"
    
        set redirect_method [:form_parameter __form_redirect_method:wordchar "view"]
        #:log "redirect_method $redirect_method"
    
        if {$redirect_method eq "__none"} {
          return
        } else {
          if {$redirect_method ne "view"} {
            set qp "?m=$redirect_method"
          } else {
            set qp ""
          }
          set url [:pretty_link]$qp
          #
          # The method query_parameter uses now "::xo::cc set_parameter ...."
          # with highest precedence
          #
          set return_url [::${:package_id} query_parameter return_url:localurl $url]
    
          #:log "${:name}: url=$url, return_url=$return_url"
          ::${:package_id} returnredirect $return_url
    
          return
        }
      }
    } elseif {[:form_parameter __form_action ""] eq "view-form-data"
              && ![info exists :__feedback_mode]
            } {
      #
      # We have nothing to save (maybe everything is read-only). Check
      # __feedback_mode to prevent recursive loops.
      #
      set redirect_method [:form_parameter __form_redirect_method:wordchar "view"]
      #:log "__redirect_method=$redirect_method"
      return [:www-view]
    } else {
      #
      # Build the input form and display the current values.
      #
      #:log "form_action is something different: <[:form_parameter __form_action {}]>"
      if {[:is_new_entry ${:name}]} {
        set :creator [::xo::get_user_name [::xo::cc user_id]]
        set :nls_language [::${:package_id} default_locale]
      }
    
      #array set __ia ${:instance_attributes}
      :load_values_into_form_fields $form_fields
    
      foreach f $form_fields {
        set ff([$f name]) $f
      }
    
      #
      # For named entries, just set the entry fields to empty,
      # without changing the instance variables
      #
      #:log "my is_new_entry ${:name} = [:is_new_entry ${:name}]"
      if {[:is_new_entry ${:name}]} {
    
        if {$anon_instances} {
          set basename [::xowiki::autoname basename [${:page_template} name]]
          set name [::xowiki::autoname new -name $basename -parent_id ${:parent_id}]
          #:log "generated name=$name, page_template-name=[${:page_template} name]"
          $ff(_name) value $name
        } else {
          $ff(_name) value [$ff(_name) default]
        }
        if {![$ff(_title) istype ::xowiki::formfield::hidden]} {
          $ff(_title) value [$ff(_title) default]
        }
        foreach param [list title detail_link:localurl text description] {
          regexp {^([^:]+):?} $param . var
          if {[:exists_query_parameter $var]} {
            set value [:query_parameter $param]
            switch -- $var {
              detail_link {
                set f [:lookup_form_field -name $var $form_fields]
                $f value [$f convert_to_external $value]
              }
              title - text - description {
                set f [:lookup_form_field -name _$var $form_fields]
              }
            }
            $f value [$f convert_to_external $value]
          }
        }
      }
    
      $ff(_name) set transmit_field_always 1
      $ff(_nls_language) set transmit_field_always 1
    }
    
    #
    # Some final sanity checks.
    #
    :form_fields_sanity_check $form_fields
    :post_process_form_fields $form_fields
    
    #
    # "dom parse -html" has two problems with ADP tags like "<adp:icon ...>":
    # a) If the tag name contains a colon or underscore, the tag is
    #    treated like plain text, i.e. "<" and ">" are converted into
    #    HTML entities.
    # b) These tags have to be closed "<adp:icon ...>" is invalid.
    #    Several existomg ADP tags have not closing tag.
    #
    # Therefore, we resolve the ADP tags before parsing the text by
    # tdom. There should be some framework support to do this in
    # general, but until we have this, resolve this problem here locally.
    #
    set form [::template::adp_parse_tags [:substitute_markup $form]]
    
    #
    # The following command would be correct, but does not work due to a bug in
    # tdom.
    # set form [:regsub_eval   #              [template::adp_variable_regexp] $form  #              {:form_field_as_html -mode edit "\\\1" "\2" $form_fields}]
    # Due to this bug, we program around and replace the at-character
    # by \x03 to avoid conflict with the input and we replace these
    # magic chars finally with the fields resulting from tdom.
    
    set form [string map [list @ \x03] $form]
    #:msg form=$form
    
    dom parse -simple -html $form :doc
    ${:doc} documentElement :root
    
    if {${:root} eq ""} {
      error "form '$form' is not valid"
    }
    
    ::xo::require_html_procs
    ${:root} firstChild fcn
    #:msg "orig fcn $fcn, root ${:root} [${:root} nodeType] [${:root} nodeName]"
    
    set formNode [lindex [${:root} selectNodes //form] 0]
    if {$formNode eq ""} {
      :msg "no form found in page [${:page_template} name]"
      ns_log notice "no form found in page [${:page_template} name]\n$form"
      set rootNode ${:root}
      $rootNode firstChild fcn
    } else {
      set rootNode $formNode
      $rootNode firstChild fcn
      # Normally, the root node is the formNode, fcn is the first
      # child (often a TEXT_NODE), but ic can be even empty.
    }
    
    
    #
    # Prepend some fields above the HTML contents of the form.
    #
    $rootNode insertBeforeFromScript {
      ::html::div {
        ::html::input -type hidden -name __object_name -value [::security::parameter::signed ${:name}]
        ::html::input -type hidden -name __form_action -value save-form-data
        ::html::input -type hidden -name __current_revision_id -value ${:revision_id}
        :extra_html_fields
        ::html::CSRFToken
      }
      #
      # Insert automatic form fields on top.
      #
      foreach att $field_names {
        #if {$formgiven && ![string match _* $att]} continue
        if {[dict exists ${:__field_in_form} $att]} continue
        set f [:lookup_form_field -name $att $form_fields]
        #:log "insert auto_field $att $f ([$f info class])"
        $f render_item
      }
    } $fcn
    #
    # Append some fields after the HTML contents of the form.
    #
    set button_class(wym) ""
    set button_class(xinha) ""
    set has_file 0
    $rootNode appendFromScript {
      # append category fields
      foreach f $form_fields {
        #:msg "[$f name]: is wym? [$f has_instance_variable editor wym]"
        if {[string match "__category_*" [$f name]]} {
          $f render_item
        } elseif {[$f has_instance_variable editor wym]} {
          set button_class(wym) "wymupdate"
        } elseif {[$f has_instance_variable editor xinha]} {
          set button_class(xinha) "xinhaupdate"
        }
        if {[$f has_instance_variable type file]} {
          set has_file 1
        }
      }
    
      #
      # Add a submit field(s) at bottom.
      #
      :render_form_action_buttons -CSSclass [string trim "$button_class(wym) $button_class(xinha)"]
    }
    
    if {$formNode ne ""} {
    
      if {[:exists_query_parameter "return_url"]} {
        set return_url [:query_parameter return_url:localurl]
      } else {
        #
        # When no return_url is specified and we edit a page different
        # from the invoked page, we use the calling page for default
        # redirection.  We do not want to redirect to some "embedded"
        # object after the edit. This happens if one edits e.g. a page
        # through a link.
        #
        if {[::xo::cc exists invoke_object]
            && [::xo::cc invoke_object] ne [self]
          } {
          #:log "=== no return_url specified, using [::xo::cc url] or [[::${:package_id} context] url]"
          set return_url [::xo::cc url]
          set return_url [ad_urlencode_url $return_url]
        }
      }
      set m [:form_parameter __form_redirect_method:wordchar "edit"]
      set url [export_vars -no_base_encode -base [:action_url] {m return_url}]
      #:log "=== setting action <$url> for form-action my-name ${:name}"
      $formNode setAttribute action $url method POST role form
      if {$has_file} {$formNode setAttribute enctype multipart/form-data}
      Form add_dom_attribute_value $formNode class [${:page_template} css_class_name]
    }
    
    :set_form_data $form_fields
    if {$disable_input_fields} {
      #
      # (a) Disable explicit input fields.
      #
      foreach f $form_fields {$f set_disabled true}
      #
      # (b) Disable input in HTML-specified fields.
      #
      set disabled [Form dom_disable_input_fields $rootNode]
      #
      # Collect these variables in a hidden field to be able to
      # distinguish later between e.g. un unchecked checkmark and an
      # disabled field. Maybe, we have to add the fields from case (a)
      # as well.
      #
      $rootNode appendFromScript {
        ::html::input -type hidden -name "__disabled_fields" -value $disabled
      }
    }
    :post_process_dom_tree ${:doc} ${:root} $form_fields
    
    set html [${:root} asHTML]
    set html [:regsub_eval   {(^|[^\\])\x03([[:alnum:]_:]+)\x03} $html  {:form_field_as_html -mode edit "\\\1" "\2" $form_fields}]
    #
    # Replace unbalanced @ characters.
    #
    set html [string map [list \x03 @] $html]
    
    #
    # Handle unreported errors (in the future...). Unreported errors
    # might occur, when a form-field was rendered above without
    # "render_item". This can happen with inline rendering of the
    # input fields where validation errors occur. Inline rendering
    # happens very seldom (I know not a single occurrence in the
    # wild). For such cases, one should define an extra field in the
    # form with an idea, reparse the tree and insert the errors
    # there. But first look, if we find a single occurrence.
    #
    set unprocessed {}
    foreach f $form_fields {
      if {[$f set error_msg] ne ""
          && ![$f exists error_reported]
        } {
        ns_log notice "form-field [$f name] has unprocessed error msg '[$f set error_msg]'"
        #$f render_error_msg
        lappend unprocessed [$f name]
      }
    }
    #ns_log notice "=============== $unprocessed unprocessed error messages"
    if {[llength $unprocessed] > 0} {
      ad_log warning "form has [llength $unprocessed] unprocessed "  "error messages in fields $unprocessed"
    }
    
    #:log "calling VIEW with HTML [string length $html]"
    if {$view} {
      :www-view $html
    } else {
      return $html
    }
  • www-file-upload (scripted, public)

     <instance of xowiki::FormPage[i]> www-file-upload

    This web-callable method can be used for uploading files using the current object as parent object for the new content. This method is typically called via drop-zone in a POST request, where the FormPage is a folder (which is treated as parent object)

    Partial Call Graph (max 5 caller/called nodes):
    %3 ad_script_abort ad_script_abort (public) security::csrf::validate security::csrf::validate (public) xowiki::FormPage instproc www-file-upload xowiki::FormPage instproc www-file-upload xowiki::FormPage instproc www-file-upload->ad_script_abort xowiki::FormPage instproc www-file-upload->security::csrf::validate

    Testcases:
    No testcase defined.
    
    if {[ns_conn method] ne "POST"} {
      error "method should be called via POST"
    }
    
    #
    # Get the disposition via query parameter.  We have currently the
    # following disposition classes defined (see
    # xowiki-uploader-procs.tcl)
    #
    #   - ::xowiki::UploadFile
    #   - ::xowiki::UploadPhotoForm
    #   - ::xowiki::UploadFileIconified
    #
    ::security::csrf::validate
    
    set disposition [:query_parameter disposition:wordchar File]
    set fileName [:query_parameter name:graph [ns_queryget upload]]
    
    set dispositionClass ::xowiki::UploadFile
    if {[info commands ::xowiki::Upload$disposition] ne ""} {
      set dispositionClass ::xowiki::Upload$disposition
    }
    
    #ns_log notice "disposition class '$dispositionClass'"
    set dispositionObject [$dispositionClass new  -file_name $fileName  -content_type [ns_queryget upload.content-type]  -tmpfile [ns_queryget upload.tmpfile]  -parent_object [self]]
    set result [$dispositionObject store_file]
    $dispositionObject destroy
    ns_return [dict get $result status_code] text/plain [dict get $result message]
    ad_script_abort
  • www-toggle-modebutton (scripted, public)

     <instance of xowiki::FormPage[i]> www-toggle-modebutton

    AJAX called function, called via POST. The function toggles the state of a button in the backend. The client provides the name of the button as form field named "button". If none is provided, the button is named as default "admin"

    Partial Call Graph (max 5 caller/called nodes):
    %3

    Testcases:
    No testcase defined.
    #
    # Check, if this function was called via POST
    #
    if {[ns_conn method] ne "POST"} {
      error "method should be called via POST"
    }
    
    #
    # Get the toggle name. Modebuttons are named like:
    #
    #    ::xowiki::mode::admin
    #
    set button [ns_queryget button admin]
    ::xowiki::mode::$button toggle
    ns_return 200 text/plain ok
  • xowiki_form_page_id (setter)