- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables
Class ::xowiki::FormPage
::xowiki::FormPage create ...
Defined in
Class Relations
::xo::db::CrClass create ::xowiki::FormPage \ -superclass ::xowiki::PageInstanceMethods (to be applied on the object)
compute_filter_clauses (scripted, public)
xowiki::FormPage 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)
- 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 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 (optional, defaults to
"0"
)- -object (required)
- -initialize (optional, boolean, defaults to
"true"
)- Returns:
- cr item object
- 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 $objectfilter_expression (scripted)
xowiki::FormPage filter_expression
- 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 $resultget_all_children (scripted)
xowiki::FormPage get_all_children
- 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 $resultget_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 $resultget_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 $itemsget_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_refsget_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_fieldssql_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> combine_data_and_form_field_default \ is_new form_field data_valueCombine 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 (required)
- is this a new entry?
- form_field (required)
- object id of the form field
- data_value (required)
- the data from the instance attributes.
- 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 0condition=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 { } [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_fieldscreate_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_fieldscreate_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_fieldsdemarshall (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 $rexists_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> extra_html_fieldsShould 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}]
- 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 from 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_namesfield_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 -- $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}$htmlform_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 $valueget_property (scripted, public)
<instance of xowiki::FormPage> 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)
- 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$valuegroup_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_idhstore_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 } } nextis_folder_page (scripted, public)
<instance of xowiki::FormPage> 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 (optional, defaults to
"true"
)- return true, if the current page is a link to a folder.
- Returns:
- boolean
- 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 $resultlappend_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> load_values_into_form_fields \ form_fieldsLoad 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 (required)
- 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_valuesmarshall (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 $rmime_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 overloadedpost_process_form_fields (scripted)
# We offer here the possibility to iterate over the form fields # before they are renderedpretty_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> property name [ default ]Retrieve a FormPage property.
- Parameters:
- name (required)
- property name. Names starting with _ refer to object's members, rather than instance attributes.
- default (optional)
- fallback value when property is not set.
- 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 $defaultrender_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 -- $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 $HTMLrender_form_action_buttons (scripted)
set f [::xowiki::formfield::submit_button new -name __form_button_ok -CSSclass $CSSclass -destroy_on_cleanup ] ::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'> </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'> </a>" is_richtext true} } else { return {text "<a title='link' class='link-icon'> </a>" is_richtext true} } } default { return [list text [$page_template title] is_richtext false] } }render_thumbnails (scripted, public)
<instance of xowiki::FormPage> render_thumbnails upload_infoRenderer of the thumbnail file(s). This method is a stub to be refined (e.g. in xowf).
- Parameters:
- upload_info (required)
- dict containing the "file_object" and "file_name"
- Returns:
- HTML content
- 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_valuessetCSSDefaults (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> set_form_data form_fieldsStore 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 (required)
- 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> set_live_revision \ -revision_id revision_id [ -publish_status publish_status ]
- Switches:
- -revision_id (required)
- -publish_status (optional, defaults to
"ready"
)- one of 'live', 'ready' or 'production'
- 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_indexset_property (scripted, public)
<instance of xowiki::FormPage> set_property [ -new new ] name \ valueStores a value as FormPage property
- Switches:
- -new (optional, defaults to
"0"
)- 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 (required)
- property name. Names starting with _ indicate an object variable rather than a property stored in instance_attributes
- value (required)
- property value
- Returns:
- value (eventually converted to a has-notation message key)
- 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 $valueset_publish_status (scripted)
if {$value ni {production ready}} { error "invalid value '$value'; use 'production' or 'ready'" } set :publish_status $valuestate (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> update_attribute_from_slot \ [ -revision_id revision_id ] slot valueTailored 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 (required, object)
- value (required)
- 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> update_item_indexTailored version of CrItem.update_item_index to keep insert_xowiki_form_instance_item_index in sync after updates.
- 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> 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 (optional, defaults to
"0"
)- -view (optional, boolean, defaults to
"true"
)- 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:0..n] { 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 -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> www-file-uploadThis 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)
- 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] # # Filename is sanitized. If the filename contains only invalid # characters, "ad_sanitize_filename" might return empty, and we # complain. # set fileName [ad_sanitize_filename [ns_queryget name [ns_queryget upload]]] if {[string length $fileName] == 0} { ad_return_complaint 1 [_ acs-templating.Invalid_filename] ad_script_abort } 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_abortwww-toggle-modebutton (scripted, public)
<instance of xowiki::FormPage> www-toggle-modebuttonAJAX 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"
- 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 okxowiki_form_page_id (setter)
- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables