Index: openacs-4/packages/xowiki/tcl/xowiki-www-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/xowiki-www-procs.tcl,v
diff -u -r1.275 -r1.276
--- openacs-4/packages/xowiki/tcl/xowiki-www-procs.tcl 28 Jun 2010 06:39:00 -0000 1.275
+++ openacs-4/packages/xowiki/tcl/xowiki-www-procs.tcl 28 Jun 2010 07:17:59 -0000 1.276
@@ -10,84 +10,931 @@
::xo::library require xowiki-procs
namespace eval ::xowiki {
+ #
+ # This block contains the externally called methods. We use as
+ # naming convention dashes as separators.
+ #
+ # externally called method: create-new
+ #
+
+ Page instproc create-new {
+ {-parent_id 0}
+ {-view_method edit}
+ {-name ""}
+ {-nls_language ""}
+ } {
+ my instvar package_id
+ set original_package_id $package_id
+
+ if {[my exists_query_parameter "package_instance"]} {
+ set package_instance [my query_parameter "package_instance"]
+ #
+ # Initialize the target package and set the variable package_id.
+ #
+ if {[catch {
+ ::xowiki::Package initialize \
+ -url $package_instance -user_id [::xo::cc user_id] \
+ -actual_query ""
+ } errorMsg]} {
+ ns_log error "$errorMsg\n$::errorInfo"
+ return [$original_package_id error_msg \
+ "Page '[my name]' invalid provided package instance=$package_instance
$errorMsg
"]
+ }
+ }
+
+ #
+ # collect some default values from query parameters
+ #
+ set default_variables [list]
+ foreach key {name title page_order last_page_id nls_language} {
+ if {[my exists_query_parameter $key]} {
+ lappend default_variables $key [my query_parameter $key]
+ }
+ }
+
+ # TODO: the following calls are here temporarily for posting
+ # content from manually added forms (e.g. linear forum). The
+ # following should be done:
+ # - create an includelet to create the form markup automatically
+ # - validate and transform input as usual
+ # We should probably allow as well controlling autonaming and
+ # setting of publish_status, and probhibit empty postings.
+
+ set text_to_html [my form_parameter "__text_to_html" ""]
+ foreach key {_text _name} {
+ if {[my exists_form_parameter $key]} {
+ set __value [my form_parameter $key]
+ if {[lsearch $text_to_html $key] > -1} {
+ set __value [ad_text_to_html $__value]
+ }
+ lappend default_variables [string range $key 1 end] $__value
+ switch $key {
+ _name {set name $__value}
+ }
+ }
+ }
+ set instance_attributes [list]
+ foreach {_att _value} [::xo::cc get_all_form_parameter] {
+ if {[string match _* $_att]} continue
+ lappend instance_attributes $_att $_value
+ }
+
+ #
+ # To create form_pages in different places than the form, one can
+ # provide provide parent_id and package_id.
+ #
+ # The following construct is more complex than necessary to
+ # provide backward compatibility. Note that the passed-in
+ # parent_id has priority over the other measures to obtain it.
+ #
+ if {$parent_id == 0} {
+ if {![my exists parent_id]} {my parent_id [$package_id folder_id]}
+ set fp_parent_id [my form_parameter "parent_id" [my query_parameter "parent_id" [my parent_id]]]
+ } else {
+ set fp_parent_id $parent_id
+ }
+ # In case the Form is inherited and package_id was not specified, we
+ # use the actual package_id.
+ set fp_package_id [my form_parameter "package_id" [my query_parameter "package_id" [my package_id]]]
+
+ ::xo::Package require $fp_package_id
+ set f [my create_form_page_instance \
+ -name $name \
+ -nls_language $nls_language \
+ -parent_id $fp_parent_id \
+ -package_id $fp_package_id \
+ -default_variables $default_variables \
+ -instance_attributes $instance_attributes \
+ -source_item_id [my query_parameter source_item_id ""]]
+
+ if {$name eq ""} {
+ $f save_new
+ } else {
+ set id [$fp_package_id lookup -parent_id $fp_parent_id -name $name]
+ if {$id == 0} {
+ $f save_new
+ } else {
+ ::xowiki::FormPage get_instance_from_db -item_id $id
+ $f copy_content_vars -from_object $id
+ $f item_id $id
+ $f save
+ }
+ }
+
+ foreach var {return_url template_file title detail_link text} {
+ if {[my exists_query_parameter $var]} {
+ set $var [my query_parameter $var]
+ }
+ }
+
+ set form_redirect [my form_parameter "__form_redirect" ""]
+ if {$form_redirect eq ""} {
+ set form_redirect [export_vars -base [$f pretty_link] \
+ [list [list m $view_method] return_url template_file title detail_link text]]
+ }
+ $package_id returnredirect $form_redirect
+ set package_id $original_package_id
+ }
+
+ #
+ # externally called method: create-or-use
+ #
+
+ Page instproc create-or-use {
+ {-parent_id 0}
+ {-view_method edit}
+ {-name ""}
+ {-nls_language ""}
+ } {
+ # can be overloaded
+ my create-new \
+ -parent_id $parent_id -view_method $view_method \
+ -name $name -nls_language $nls_language
+ }
+
+ #
+ # externally called method: delete
+ #
+
+ Page instproc delete {} {
+ my instvar package_id item_id name
+ # delete always via package
+ $package_id delete -item_id $item_id -name $name
+ }
+
+ PageTemplate instproc delete {} {
+ my instvar package_id item_id name
+ set count [my count_usages -publish_status all]
+ #my msg count=$count
+ if {$count > 0} {
+ append error_msg \
+ [_ xowiki.error-delete_entries_first [list count $count]] \
+ \
+ [my include [list form-usages -publish_status all -parent_id * -form_item_id [my item_id]]] \
+
+ $package_id error_msg $error_msg
+ } else {
+ next
+ }
+ }
- Page instproc htmlFooter {{-content ""}} {
+ #
+ # externally called method: delete-revision
+ #
+
+ Page instproc delete-revision {} {
+ my instvar revision_id package_id item_id
+ db_1row [my qn get_revision] "select latest_revision,live_revision from cr_items where item_id = $item_id"
+ # do real deletion via package
+ $package_id delete_revision -revision_id $revision_id -item_id $item_id
+ # Take care about UI specific stuff....
+ set redirect [my query_parameter "return_url" \
+ [export_vars -base [$package_id url] {{m revisions}}]]
+ if {$live_revision == $revision_id} {
+ # latest revision might have changed by delete_revision, so we have to fetch here
+ db_1row [my qn get_revision] "select latest_revision from cr_items where item_id = $item_id"
+ if {$latest_revision eq ""} {
+ # we are out of luck, this was the final revision, delete the item
+ my instvar package_id name
+ $package_id delete -name $name -item_id $item_id
+ } else {
+ ::xo::db::sql::content_item set_live_revision -revision_id $latest_revision
+ }
+ }
+ if {$latest_revision ne ""} {
+ # otherwise, "delete" did already the redirect
+ ::$package_id returnredirect [my query_parameter "return_url" \
+ [export_vars -base [$package_id url] {{m revisions}}]]
+ }
+ }
+
+ #
+ # externally called method: diff
+ #
+
+ Page instproc diff {} {
my instvar package_id
- if {[my exists __no_footer]} {return ""}
+ set compare_id [my query_parameter "compare_revision_id" 0]
+ if {$compare_id == 0} {
+ return ""
+ }
+ ::xo::Page requireCSS /resources/xowiki/xowiki.css
+ set my_page [::xowiki::Package instantiate_page_from_id -revision_id [my revision_id]]
+ $my_page volatile
- set footer ""
- set description [my get_description $content]
+ if {[catch {set html1 [$my_page render]} errorMsg]} {
+ set html2 "Error rendering [my revision_id]: $errorMsg"
+ }
+ set text1 [ad_html_text_convert -from text/html -to text/plain -- $html1]
+ set user1 [::xo::get_user_name [$my_page set creation_user]]
+ set time1 [$my_page set creation_date]
+ set revision_id1 [$my_page set revision_id]
+ regexp {^([^.]+)[.]} $time1 _ time1
+
+ set other_page [::xowiki::Package instantiate_page_from_id -revision_id $compare_id]
+ $other_page volatile
+ #$other_page absolute_links 1
+
+ if {[catch {set html2 [$other_page render]} errorMsg]} {
+ set html2 "Error rendering $compare_id: $errorMsg"
+ }
+ set text2 [ad_html_text_convert -from text/html -to text/plain -- $html2]
+ set user2 [::xo::get_user_name [$other_page set creation_user]]
+ set time2 [$other_page set creation_date]
+ set revision_id2 [$other_page set revision_id]
+ regexp {^([^.]+)[.]} $time2 _ time2
+
+ set title "Differences for [my set name]"
+ set context [list $title]
- if {[ns_conn isconnected]} {
- set url "[ns_conn location][::xo::cc url]"
- set package_url "[ns_conn location][$package_id package_url]"
+ # try util::html diff if it is available and works
+ if {[catch {set content [::util::html_diff -old $html2 -new $html1 -show_old_p t]}]} {
+ # otherwise, fall back to proven text based diff
+ set content [::xowiki::html_diff $text2 $text1]
}
- set tags ""
- if {[$package_id get_parameter "with_tags" 1] &&
- ![my exists_query_parameter no_tags] &&
- [::xo::cc user_id] != 0
- } {
- set tag_content [my include my-tags]
- set tag_includelet [my set __last_includelet]
- if {[$tag_includelet exists tags]} {
- set tags [$tag_includelet set tags]
+ ::xo::Page set_property doc title $title
+ array set property_doc [::xo::Page get_property doc]
+ set header_stuff [::xo::Page header_stuff]
+
+ $package_id return_page -adp /packages/xowiki/www/diff -variables {
+ content title context header_stuff
+ time1 time2 user1 user2 revision_id1 revision_id2 property_doc
+ }
+ }
+
+ proc html_diff {doc1 doc2} {
+ set out ""
+ set i 0
+ set j 0
+
+ #set lines1 [split $doc1 "\n"]
+ #set lines2 [split $doc2 "\n"]
+
+ regsub -all \n $doc1 "
" doc1
+ regsub -all \n $doc2 "
" doc2
+ set lines1 [split $doc1 " "]
+ set lines2 [split $doc2 " "]
+
+ foreach { x1 x2 } [list::longestCommonSubsequence $lines1 $lines2] {
+ foreach p $x1 q $x2 {
+ while { $i < $p } {
+ set l [lindex $lines1 $i]
+ incr i
+ #puts "R\t$i\t\t$l"
+ append out "$l\n"
+ }
+ while { $j < $q } {
+ set m [lindex $lines2 $j]
+ incr j
+ #puts "A\t\t$j\t$m"
+ append out "$m\n"
+ }
+ set l [lindex $lines1 $i]
+ incr i; incr j
+ #puts "B\t$i\t$j\t$l"
+ append out "$l\n"
}
+ }
+ while { $i < [llength $lines1] } {
+ set l [lindex $lines1 $i]
+ incr i
+ #puts "$i\t\t$l"
+ append out "$l\n"
+ }
+ while { $j < [llength $lines2] } {
+ set m [lindex $lines2 $j]
+ incr j
+ #puts "\t$j\t$m"
+ append out "$m\n"
+ }
+ return $out
+ }
+
+ #
+ # externally called method: download
+ #
+
+ File instproc download {} {
+ my instvar mime_type package_id
+ $package_id set mime_type $mime_type
+ set use_bg_delivery [expr {![catch {ns_conn contentsentlength}] &&
+ [info command ::bgdelivery] ne ""}]
+ $package_id set delivery \
+ [expr {$use_bg_delivery ? "ad_returnfile_background" : "ns_returnfile"}]
+ if {[my exists_query_parameter filename]} {
+ set filename [my query_parameter filename]
+ ns_set put [ns_conn outputheaders] Content-Disposition "attachment;filename=$filename"
+ }
+ #my log "--F FILE=[my full_file_name]"
+ return [my full_file_name]
+ }
+
+ #
+ # helper methods for externally called method: edit
+ #
+
+ Page instproc edit_set_default_values {} {
+ my instvar package_id
+ # set some default values if they are provided
+ foreach key {name title page_order last_page_id nls_language} {
+ if {[$package_id exists_query_parameter $key]} {
+ #my log "setting [self] set $key [$package_id query_parameter $key]"
+ my set $key [$package_id query_parameter $key]
+ }
+ }
+ }
+
+ Page instproc edit_set_file_selector_folder {} {
+ #
+ # setting up folder id for file selector (use community folder if available)
+ #
+ if {[info commands ::dotlrn_fs::get_community_shared_folder] ne ""} {
+ # ... we have dotlrn installed
+ set cid [::dotlrn_community::get_community_id]
+ if {$cid ne ""} {
+ # ... we are inside of a community, use the community folder
+ return [::dotlrn_fs::get_community_shared_folder -community_id $cid]
+ }
+ }
+ return ""
+ }
+
+ #
+ # externally called method: edit
+ #
+
+ Page instproc edit {
+ {-new:boolean false}
+ {-autoname:boolean false}
+ {-validation_errors ""}
+ } {
+ my instvar package_id item_id revision_id parent_id
+ #my msg "--edit new=$new autoname=$autoname, valudation_errors=$validation_errors, parent=[my parent_id]"
+ my edit_set_default_values
+ set fs_folder_id [my edit_set_file_selector_folder]
+
+ if {[$package_id exists_query_parameter "return_url"]} {
+ set submit_link [my query_parameter "return_url" "."]
+ set return_url $submit_link
} else {
- set tag_content ""
+ # before we used "." as default submit link (resulting in a "ad_returnredirect .").
+ # However, this does not seem to work in case we have folders in use....
+ #set submit_link "."
+ set submit_link [my pretty_link]
}
+ #my log "--u submit_link=$submit_link qp=[my query_parameter return_url]"
+ set object_type [my info class]
- if {[$package_id get_parameter "with_digg" 0] && [info exists url]} {
- append footer "" \
- [my include [list digg -description $description -url $url]] "
\n"
+ # We have to do template mangling here; ad_form_template writes
+ # form variables into the actual parselevel, so we have to be in
+ # our own level in order to access an pass these.
+ variable ::template::parse_level
+ lappend parse_level [info level]
+ set action_vars [expr {$new ? "{edit-new 1} object_type return_url" : "{m edit} return_url"}]
+ #my log "--formclass=[$object_type getFormClass -data [self]] ot=$object_type"
+
+ #
+ # Determine the package_id of some mounted xowiki instance to find
+ # the directory + URL, from where the scripts called from xinha
+ # can be used.
+ if {[$package_id info class] eq "::xowiki::Package"} {
+ # The actual instance is a plain xowiki instance, we can use it
+ set folder_spec [list script_dir [$package_id package_url]]
+ } else {
+ # The actual instance is not a plain xowiki instance, so, we try
+ # to find one, where the current user has at least read
+ # permissions. This act is required for sub-packages, which
+ # might not have the script dir.
+ set first_instance_id [::xowiki::Package first_instance -party_id [::xo::cc user_id] -privilege read]
+ if {$first_instance_id ne ""} {
+ ::xowiki::Package require $first_instance_id
+ set folder_spec [list script_dir [$first_instance_id package_url]]
+ }
}
- if {[$package_id get_parameter "with_delicious" 0] && [info exists url]} {
- append footer "" \
- [my include [list delicious -description $description -url $url -tags $tags]] \
- "
\n"
+ if {$fs_folder_id ne ""} {lappend folder_spec folder_id $fs_folder_id}
+
+ [$object_type getFormClass -data [self]] create ::xowiki::f1 -volatile \
+ -action [export_vars -base [$package_id url] $action_vars] \
+ -data [self] \
+ -folderspec $folder_spec \
+ -submit_link $submit_link \
+ -autoname $autoname
+
+ if {[info exists return_url]} {
+ ::xowiki::f1 generate -export [list [list return_url $return_url]]
+ } else {
+ ::xowiki::f1 generate
}
- if {[$package_id get_parameter "with_yahoo_publisher" 0] && [info exists package_url]} {
- set publisher [$package_id get_parameter "my_yahoo_publisher" \
- [::xo::get_user_name [::xo::cc user_id]]]
- append footer "" \
- [my include [list my-yahoo-publisher \
- -publisher $publisher \
- -rssurl "$package_url?rss"]] \
- "
\n"
+ ::xowiki::f1 instvar edit_form_page_title context formTemplate
+
+ if {[info exists item_id]} {
+ set rev_link [$package_id make_link [self] revisions]
+ set view_link [$package_id make_link [self] view]
}
+ if {[info exists last_page_id]} {
+ set back_link [$package_id url]
+ }
- append footer [my include my-references]
+ set index_link [$package_id make_link -privilege public -link "" $package_id {} {}]
+ ::xo::Page set_property doc title "[$package_id instance_name] - $edit_form_page_title"
+
+ array set property_doc [::xo::Page get_property doc]
+ set tmpl [acs_root_dir]/packages/[[my package_id] package_key]/www/edit
+ set edit_tmpl [expr {[file readable $tmpl] ? $tmpl : "/packages/xowiki/www/edit" }]
+ set html [$package_id return_page -adp $edit_tmpl \
+ -form f1 \
+ -variables {item_id parent_id edit_form_page_title context formTemplate
+ view_link back_link rev_link index_link property_doc}]
+ template::util::lpop parse_level
+ #my log "--edit html length [string length $html]"
+ return $html
+ }
+
+ FormPage instproc edit {
+ {-validation_errors ""}
+ {-disable_input_fields 0}
+ {-view true}
+ } {
+ my instvar page_template doc root package_id
+ ::xowiki::Form requireFormCSS
+ #my log "edit [self args]"
+
+ set form [my get_form]
+ set anon_instances [my get_from_template anon_instances f]
+ #my msg form=$form
+ #my msg anon_instances=$anon_instances
- if {[$package_id get_parameter "show_per_object_categories" 1]} {
- set html [my include my-categories]
- if {$html ne ""} {
- append footer $html
+ set field_names [my field_names -form $form]
+ #my log field_names=$field_names
+ set form_fields [my create_form_fields $field_names]
+
+ 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 ""
+ set formgiven 0
+ } else {
+ set formgiven 1
+ }
+
+ # 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 [my 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
}
- set categories_includelet [my set __last_includelet]
}
- append footer $tag_content
+ # include _text only, if explicitly needed (in form needed(_text)]"
- if {[$package_id get_parameter "with_general_comments" 0] &&
- ![my exists_query_parameter no_gc]} {
- append footer [my include my-general-comments]
+ if {![my exists __field_needed(_text)]} {
+ #my msg "setting text hidden"
+ set f [my lookup_form_field -name _text $form_fields]
+ $f config_from_spec hidden
}
- if {$footer ne ""} {
- # make sure, the
- append footer ""
+ if {[my exists_form_parameter __disabled_fields]} {
+ # Disable some form-fields since these are disabled in the form
+ # as well.
+ foreach name [my form_parameter __disabled_fields] {
+ set f [my lookup_form_field -name $name $form_fields]
+ $f disabled disabled
+ }
}
- return "\n"
+ #my show_fields $form_fields
+ #my msg "__form_action [my form_parameter __form_action {}]"
+ if {[my form_parameter __form_action ""] eq "save-form-data"} {
+ #my msg "we have to validate"
+ #
+ # we have to valiate and save the form data
+ #
+ foreach {validation_errors category_ids} [my get_form_data $form_fields] break
+
+ if {$validation_errors != 0} {
+ #my msg "$validation_errors errors in $form_fields"
+ #foreach f $form_fields { my 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
+ my set name [my form_parameter __object_name]
+ } else {
+ #
+ # we have no validation errors, so we can save the content
+ #
+ my save_data \
+ -use_given_publish_date [expr {[lsearch $field_names _publish_date] > -1}] \
+ [::xo::cc form_parameter __object_name ""] $category_ids
+
+ # The data might have references. We render do the rendering here
+ # 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 [my render -update_references true]
+ #my msg "after save refs=[expr {[my exists references]?[my set references] : {NONE}}]"
+
+ set redirect_method [my form_parameter __form_redirect_method "view"]
+ if {$redirect_method eq "__none"} {
+ return
+ } else {
+ if {$redirect_method ne "view"} {set qp "?m=$redirect_method"} {set qp ""}
+ set url [my pretty_link -lang en]$qp
+ set return_url [$package_id get_parameter return_url $url]
+ # We had query_parameter here. however, to be able to
+ # process the output of ::xo::cc set_parameter ...., we
+ # changed it to "parameter".
+ #my msg "[my name]: url=$url, return_url=$return_url"
+ $package_id returnredirect $return_url
+ return
+ }
+ }
+ } elseif {[my form_parameter __form_action ""] eq "view-form-data" && ![my exists __feedback_mode]} {
+ # We have nothing to save (maybe everything is read.only). Check
+ # __feedback_mode to prevent recursive loops.
+ set redirect_method [my form_parameter __form_redirect_method "view"]
+ #my log "__redirect_method=$redirect_method"
+ return [my view]
+ } else {
+ #
+ # display the current values
+ #
+ if {[my is_new_entry [my name]]} {
+ my set creator [::xo::get_user_name [::xo::cc user_id]]
+ my set nls_language [ad_conn locale]
+ #my set name [$package_id query_parameter name ""]
+ # TODO: maybe use __object_name to for POST url to make code
+ # more straightworward
+ #set n [$package_id query_parameter name \
+ # [::xo::cc form_parameter __object_name ""]]
+ #if {$n ne ""} {
+ # my name $n
+ #}
+ }
+
+ array set __ia [my set instance_attributes]
+ my 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
+
+ #my msg "my is_new_entry [my name] = [my is_new_entry [my name]]"
+ if {[my is_new_entry [my name]]} {
+ #my msg "anon_instances=$anon_instances"
+ if {$anon_instances} {
+ set basename [::xowiki::autoname basename [$page_template name]]
+ set name [::xowiki::autoname new -name $basename -parent_id [my parent_id]]
+ #my msg "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 var [list title detail_link text description] {
+ if {[my exists_query_parameter $var]} {
+ set value [my query_parameter $var]
+ switch -- $var {
+ detail_link {
+ set f [my lookup_form_field -name $var $form_fields]
+ $f value [$f convert_to_external $value]
+ }
+ title - text - description {
+ set f [my 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
+ my form_fields_sanity_check $form_fields
+ my post_process_form_fields $form_fields
+
+ # The following command would be correct, but does not work due to a bug in
+ # tdom.
+ # set form [my regsub_eval \
+ # [template::adp_variable_regexp] $form \
+ # {my form_field_as_html -mode edit "\\\1" "\2" $form_fields}]
+ # Due to this bug, we program around and replace the at-character
+ # by \x003 to avoid conflict withe the input and we replace these
+ # magic chars finally with the fields resulting from tdom.
+
+ set form [my substitute_markup $form]
+ set form [string map [list @ \x003] $form]
+ #my msg form=$form
+
+ dom parse -simple -html $form doc
+ $doc documentElement root
+
+ ::require_html_procs
+ $root firstChild fcn
+ #
+ # prepend some fields above the HTML contents of the form
+ #
+ $root insertBeforeFromScript {
+ ::html::input -type hidden -name __object_name -value [my name]
+ ::html::input -type hidden -name __form_action -value save-form-data
+
+ # insert automatic form fields on top
+ foreach att $field_names {
+ #if {$formgiven && ![string match _* $att]} continue
+ if {[my exists __field_in_form($att)]} continue
+ set f [my lookup_form_field -name $att $form_fields]
+ #my msg "insert auto_field $att"
+ $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
+ $root appendFromScript {
+ # append category fields
+ foreach f $form_fields {
+ #my 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
+ }
+ }
+
+ # insert unreported errors
+ foreach f $form_fields {
+ if {[$f set error_msg] ne "" && ![$f exists error_reported]} {
+ $f render_error_msg
+ }
+ }
+ # add a submit field(s) at bottom
+ my render_form_action_buttons -CSSclass [string trim "$button_class(wym) $button_class(xinha)"]
+ }
+
+ set form [lindex [$root selectNodes //form] 0]
+ if {$form eq ""} {
+ my msg "no form found in page [$page_template name]"
+ } else {
+ if {[my exists_query_parameter "return_url"]} {
+ set return_url [my query_parameter "return_url"]
+ }
+ set url [export_vars -base [my pretty_link] {{m "edit"} return_url}]
+ $form setAttribute action $url method POST
+ if {$has_file} {$form setAttribute enctype multipart/form-data}
+ Form add_dom_attribute_value $form class [$page_template css_class_name]
+ }
+
+ my set_form_data $form_fields
+ if {$disable_input_fields} {
+ # (a) disable explicit input fields
+ foreach f $form_fields {$f disabled disabled}
+ # (b) disable input in HTML-specified fields
+ set disabled [Form dom_disable_input_fields $root]
+ #
+ # Collect these variables in a hiddden 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.
+ #
+ $root appendFromScript {
+ ::html::input -type hidden -name "__disabled_fields" -value $disabled
+ }
+ }
+ my post_process_dom_tree $doc $root $form_fields
+ set html [$root asHTML]
+ set html [my regsub_eval \
+ {(^|[^\\])\x003([a-zA-Z0-9_:]+)\x003} $html \
+ {my form_field_as_html -mode edit "\\\1" "\2" $form_fields}]
+ # replace unbalanced @ characters
+ set html [string map [list \x003 @] $html]
+
+ #my log "calling VIEW with HTML [string length $html]"
+ if {$view} {
+ my view $html
+ } else {
+ return $html
+ }
}
-}
+ #
+ # externally called method: make-live-revision
+ #
-namespace eval ::xowiki {
-
+ Page instproc make-live-revision {} {
+ my instvar revision_id item_id package_id
+ #my log "--M set_live_revision($revision_id)"
+ ::xo::db::sql::content_item set_live_revision -revision_id $revision_id
+ set page_id [my query_parameter "page_id"]
+ ::xo::clusterwide ns_cache flush xotcl_object_cache ::$item_id
+ ::$package_id returnredirect [my query_parameter "return_url" \
+ [export_vars -base [$package_id url] {{m revisions}}]]
+ }
+
+ #
+ # externally called method: popular-tags
+ #
+
+ Page instproc popular-tags {} {
+ my instvar package_id item_id parent_id
+ set limit [my query_parameter "limit" 20]
+ set weblog_page [$package_id get_parameter weblog_page weblog]
+ set href [$package_id pretty_link $weblog_page]?summary=1
+
+ set entries [list]
+ db_foreach [my qn get_popular_tags] \
+ [::xo::db::sql select \
+ -vars "count(*) as nr, tag" \
+ -from "xowiki_tags" \
+ -where "item_id=$item_id" \
+ -groupby "tag" \
+ -orderby "nr" \
+ -limit $limit] {
+ lappend entries "$tag ($nr)"
+ }
+ ns_return 200 text/html "[_ xowiki.popular_tags_label]: [join $entries {, }]"
+ }
+
+ #
+ # externally called method: save-attributes
+ #
+
+ Page ad_instproc save-attributes {} {
+ The method save-attributes is typically called over the
+ REST interface. It allows to save attributes of a
+ page without adding a new revision.
+ } {
+ my instvar package_id
+ set field_names [my field_names]
+ set form_fields [list]
+ set query_field_names [list]
+
+ set validation_errors 0
+ foreach field_name $field_names {
+ if {[::xo::cc exists_form_parameter $field_name]} {
+ lappend form_fields [my create_form_field $field_name]
+ lappend query_field_names $field_name
+ }
+ }
+ #my show_fields $form_fields
+ foreach {validation_errors category_ids} \
+ [my get_form_data -field_names $query_field_names $form_fields] break
+ if {$validation_errors == 0} {
+ #
+ # we have no validation errors, so we can save the content
+ #
+ set update_without_revision [$package_id query_parameter replace 0]
+
+ foreach form_field $form_fields {
+ # fix richtext content in accordance with oacs conventions
+ if {[$form_field istype ::xowiki::formfield::richtext]} {
+ $form_field value [list [$form_field value] text/html]
+ }
+ }
+ if {$update_without_revision} {
+ # field-wise update without revision
+ set update_instance_attributes 0
+ foreach form_field $form_fields {
+ set s [$form_field slot]
+ if {$s eq ""} {
+ # empty slot means that we have an instance_attribute;
+ # we save all in one statement below
+ set update_instance_attributes 1
+ } else {
+ error "Not implemented yet"
+ my update_attribute_from_slot $s [$form_field value]
+ }
+ }
+ if {$update_instance_attributes} {
+ set s [my find_slot instance_attributes]
+ my update_attribute_from_slot $s [my instance_attributes]
+ }
+ } else {
+ #
+ # perform standard update (with revision)
+ #
+ my save_data \
+ -use_given_publish_date [expr {[lsearch $field_names _publish_date] > -1}] \
+ [::xo::cc form_parameter __object_name ""] $category_ids
+ }
+ $package_id returnredirect \
+ [my query_parameter "return_url" [my pretty_link]]
+ return
+ } else {
+ # todo: handle errors in a user friendly way
+ my log "we have $validation_errors validation_errors"
+ }
+ $package_id returnredirect \
+ [my query_parameter "return_url" [my pretty_link]]
+ }
+
+ #
+ # externally called method: revisions
+ #
+
+ Page instproc revisions {} {
+ my instvar package_id name item_id
+ set context [list [list [$package_id url] $name ] [_ xotcl-core.revisions]]
+ set title "[_ xotcl-core.revision_title] '$name'"
+ ::xo::Page set_property doc title $title
+ set content [next]
+ array set property_doc [::xo::Page get_property doc]
+ $package_id return_page -adp /packages/xowiki/www/revisions -variables {
+ content context {page_id $item_id} title property_doc
+ }
+ }
+
+ #
+ # externally called method: save-tags
+ #
+
+ Page instproc save-tags {} {
+ my instvar package_id item_id revision_id
+ ::xowiki::Page save_tags \
+ -user_id [::xo::cc user_id] \
+ -item_id $item_id \
+ -revision_id $revision_id \
+ -package_id $package_id \
+ [my form_parameter new_tags]
+
+ ::$package_id returnredirect \
+ [my query_parameter "return_url" [$package_id url]]
+ }
+
+ #
+ # externally called method: validate-attribute
+ #
+
+ Page instproc validate-attribute {} {
+ set field_names [my field_names]
+ set validation_errors 0
+
+ # get the first transmitted form field
+ foreach field_name $field_names {
+ if {[::xo::cc exists_form_parameter $field_name]} {
+ set form_fields [my create_form_field $field_name]
+ set query_field_names $field_name
+ break
+ }
+ }
+ foreach {validation_errors category_ids} \
+ [my get_form_data -field_names $query_field_names $form_fields] break
+ set error ""
+ if {$validation_errors == 0} {
+ set status_code 200
+ } else {
+ set status_code 406
+ foreach f $form_fields {
+ if {[$f error_msg] ne ""} {set error [::xo::localize [$f error_msg] 1]}
+ }
+ }
+ ns_return $status_code text/html $error
+ }
+
+ #
+ # externally called method: view
+ #
+
Page instproc view {{content ""}} {
# The method "view" is used primarily for the toplevel call, when
# the xowiki page is viewed. It is not intended for e.g. embedded
@@ -359,128 +1206,65 @@
}
}
+##################################################################################
namespace eval ::xowiki {
- Page instproc new_link {-name -title -nls_language -return_url -parent_id page_package_id} {
- if {[info exists parent_id] && $parent_id eq ""} {unset parent_id}
- return [$page_package_id make_link -with_entities 0 $page_package_id \
- edit-new object_type name title nls_language return_url parent_id autoname]
- }
+ #
+ # This block implements the interfacing between form-fields and Pages
+ #
- Page instproc edit_set_default_values {} {
- my instvar package_id
- # set some default values if they are provided
- foreach key {name title page_order last_page_id nls_language} {
- if {[$package_id exists_query_parameter $key]} {
- #my log "setting [self] set $key [$package_id query_parameter $key]"
- my set $key [$package_id query_parameter $key]
- }
- }
- }
+ FormPage proc get_table_form_fields {
+ -base_item
+ -field_names
+ -form_constraints
+ } {
- Page instproc edit_set_file_selector_folder {} {
- #
- # setting up folder id for file selector (use community folder if available)
- #
- if {[info commands ::dotlrn_fs::get_community_shared_folder] ne ""} {
- # ... we have dotlrn installed
- set cid [::dotlrn_community::get_community_id]
- if {$cid ne ""} {
- # ... we are inside of a community, use the community folder
- return [::dotlrn_fs::get_community_shared_folder -community_id $cid]
- }
+ array set __att [list publish_status 1]
+ foreach att [::xowiki::FormPage array names db_slot] {set __att($att) 1}
+ foreach att [list last_modified creation_user] {
+ set __att($att) 1
}
- return ""
- }
+
+ # 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.
- Page instproc edit {
- {-new:boolean false}
- {-autoname:boolean false}
- {-validation_errors ""}
- } {
- my instvar package_id item_id revision_id parent_id
- #my msg "--edit new=$new autoname=$autoname, valudation_errors=$validation_errors, parent=[my parent_id]"
- my edit_set_default_values
- set fs_folder_id [my edit_set_file_selector_folder]
+ set cr_field_spec ""
+ set field_spec [::xowiki::PageInstance get_short_spec_from_form_constraints \
+ -name @fields \
+ -form_constraints $form_constraints]
- if {[$package_id exists_query_parameter "return_url"]} {
- set submit_link [my query_parameter "return_url" "."]
- set return_url $submit_link
- } else {
- # before we used "." as default submit link (resulting in a "ad_returnredirect .").
- # However, this does not seem to work in case we have folders in use....
- #set submit_link "."
- set submit_link [my pretty_link]
- }
- #my log "--u submit_link=$submit_link qp=[my query_parameter return_url]"
- set object_type [my info class]
+ foreach field_name $field_names {
+ set short_spec [::xowiki::PageInstance get_short_spec_from_form_constraints \
+ -name $field_name \
+ -form_constraints $form_constraints]
- # We have to do template mangling here; ad_form_template writes
- # form variables into the actual parselevel, so we have to be in
- # our own level in order to access an pass these.
- variable ::template::parse_level
- lappend parse_level [info level]
- set action_vars [expr {$new ? "{edit-new 1} object_type return_url" : "{m edit} return_url"}]
- #my log "--formclass=[$object_type getFormClass -data [self]] ot=$object_type"
-
- #
- # Determine the package_id of some mounted xowiki instance to find
- # the directory + URL, from where the scripts called from xinha
- # can be used.
- if {[$package_id info class] eq "::xowiki::Package"} {
- # The actual instance is a plain xowiki instance, we can use it
- set folder_spec [list script_dir [$package_id package_url]]
- } else {
- # The actual instance is not a plain xowiki instance, so, we try
- # to find one, where the current user has at least read
- # permissions. This act is required for sub-packages, which
- # might not have the script dir.
- set first_instance_id [::xowiki::Package first_instance -party_id [::xo::cc user_id] -privilege read]
- if {$first_instance_id ne ""} {
- ::xowiki::Package require $first_instance_id
- set folder_spec [list script_dir [$first_instance_id package_url]]
+ switch -glob -- $field_name {
+ __* {error not_allowed}
+ _* {
+ set varname [string range $field_name 1 end]
+ if {![info exists __att($varname)]} {
+ error "unknown attribute $field_name"
+ }
+ set f [$base_item create_raw_form_field \
+ -name $field_name \
+ -slot [$base_item find_slot $varname] \
+ -spec $cr_field_spec,$short_spec]
+ $f set __base_field $varname
+ }
+ default {
+ set f [$base_item create_raw_form_field \
+ -name $field_name \
+ -slot "" \
+ -spec $field_spec,$short_spec]
+ }
}
+ lappend form_fields $f
}
-
- if {$fs_folder_id ne ""} {lappend folder_spec folder_id $fs_folder_id}
-
- [$object_type getFormClass -data [self]] create ::xowiki::f1 -volatile \
- -action [export_vars -base [$package_id url] $action_vars] \
- -data [self] \
- -folderspec $folder_spec \
- -submit_link $submit_link \
- -autoname $autoname
-
- if {[info exists return_url]} {
- ::xowiki::f1 generate -export [list [list return_url $return_url]]
- } else {
- ::xowiki::f1 generate
- }
-
- ::xowiki::f1 instvar edit_form_page_title context formTemplate
-
- if {[info exists item_id]} {
- set rev_link [$package_id make_link [self] revisions]
- set view_link [$package_id make_link [self] view]
- }
- if {[info exists last_page_id]} {
- set back_link [$package_id url]
- }
-
- set index_link [$package_id make_link -privilege public -link "" $package_id {} {}]
- ::xo::Page set_property doc title "[$package_id instance_name] - $edit_form_page_title"
-
- array set property_doc [::xo::Page get_property doc]
- set tmpl [acs_root_dir]/packages/[[my package_id] package_key]/www/edit
- set edit_tmpl [expr {[file readable $tmpl] ? $tmpl : "/packages/xowiki/www/edit" }]
- set html [$package_id return_page -adp $edit_tmpl \
- -form f1 \
- -variables {item_id parent_id edit_form_page_title context formTemplate
- view_link back_link rev_link index_link property_doc}]
- template::util::lpop parse_level
- #my log "--edit html length [string length $html]"
- return $html
+ return $form_fields
}
Page proc find_slot {-start_class:required name} {
@@ -493,6 +1277,7 @@
}
return ""
}
+
Page instproc find_slot {-start_class name} {
if {![info exists start_class]} {
set start_class [my info class]
@@ -567,151 +1352,8 @@
return $f
}
-}
-namespace eval ::xowiki {
- FormPage instproc new_link {-name -title -nls_language -parent_id -return_url page_package_id} {
- set template_id [my 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 -with_entities 0 -link $form $template_id \
- create-new return_url name title nls_language]
- }
-
- FormPage proc get_table_form_fields {
- -base_item
- -field_names
- -form_constraints
- } {
-
- array set __att [list publish_status 1]
- foreach att [::xowiki::FormPage array names db_slot] {set __att($att) 1}
- foreach att [list last_modified creation_user] {
- 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]
-
- switch -glob -- $field_name {
- __* {error not_allowed}
- _* {
- set varname [string range $field_name 1 end]
- if {![info exists __att($varname)]} {
- error "unknown attribute $field_name"
- }
- set f [$base_item create_raw_form_field \
- -name $field_name \
- -slot [$base_item find_slot $varname] \
- -spec $cr_field_spec,$short_spec]
- $f set __base_field $varname
- }
- default {
- set f [$base_item create_raw_form_field \
- -name $field_name \
- -slot "" \
- -spec $field_spec,$short_spec]
- }
- }
- lappend form_fields $f
- }
- return $form_fields
- }
-
- FormPage proc h_double_quote {value} {
- if {[regexp {[ ,\"\\=>]} $value]} {
- set value \"[string map [list \" \\\\\" \\ \\\\ ' \\\\'] $value]\"
- }
- return $value
- }
-
- FormPage proc filter_expression {
- {-sql true}
- input_expr
- logical_op
- } {
- array set tcl_op {= eq < < > > >= >= <= <=}
- array set sql_op {= = < < > > >= >= <= <=}
- array set op_map {contains,sql {$lhs_var like '%$rhs%'} contains,tcl {[lsearch $lhs_var {$rhs}] > -1}}
- #my msg unless=$unless
- #example for unless: wf_current_state = closed|accepted || x = 1
- 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)\s*([^=]?.*)$} $clause _ lhs op rhs_expr]} {
- set lhs [string trim $lhs]
- set rhs_expr [string trim $rhs_expr]
- if {[string range $lhs 0 0] eq "_"} {
- set lhs_var [string range $lhs 1 end]
- set rhs [split $rhs_expr |]
- if {[info exists op_map($op,sql)]} {
- lappend sql_clause [subst -nocommands $op_map($op,sql)]
- if {[my exists $lhs_var]} {
- set lhs_var "\[my set $lhs_var\]"
- lappend tcl_clause [subst -nocommands $op_map($op,tcl)]
- } else {
- my msg "ignoring unknown variable $lhs_var in expression"
- }
- } elseif {[llength $rhs]>1} {
- lappend sql_clause "$lhs_var in ('[join $rhs ',']')"
- # the following statement is only needed, when we rely on tcl-only
- lappend tcl_clause "\[lsearch -exact {$rhs} \[my 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 "\[my property $lhs\] $tcl_op($op) {$rhs}"
- }
- } else {
- set hleft [my h_double_quote $lhs]
- lappend vars $lhs ""
- if {$op eq "contains"} {
- #make approximate query
- set lhs_var instance_attributes
- set rhs $rhs_expr
- lappend sql_clause [subst -nocommands $op_map($op,sql)]
- }
- set lhs_var "\$__ia($lhs)"
- foreach rhs [split $rhs_expr |] {
- if {[info exists op_map($op,tcl)]} {
- lappend tcl_clause [subst -nocommands $op_map($op,tcl)]
- } else {
- lappend tcl_clause "$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=>[my h_double_quote $rhs]"
- }
- }
- }
- } else {
- my msg "ignoring $clause"
- }
- }
- if {[llength $tcl_clause] == 0} {set tcl_clause [list true]}
- #my msg sql=$sql_clause,tcl=$tcl_clause
- return [list tcl [join $tcl_clause $logical_op] h [join $h_clause ,] \
- vars $vars sql $sql_clause]
- #my msg $expression
- }
-
- FormPage instproc create_category_fields {} {
+ FormPage instproc create_category_fields {} {
set category_spec [my get_short_spec @categories]
# Per default, no category fields in FormPages, since the can be
# handled in more detail via form-fields.
@@ -868,11 +1510,7 @@
}
}
}
-}
-
-namespace eval ::xowiki {
-
FormPage ad_instproc set_form_data {form_fields} {
Store the instance attributes or default values in the form.
} {
@@ -898,11 +1536,7 @@
}
}
}
-}
-
-namespace eval ::xowiki {
-
Page ad_instproc get_form_data {-field_names form_fields} {
Get the values from the form and store it as
instance attributes. If the field names are not specified,
@@ -1083,10 +1717,7 @@
#my msg "$name $html"
return ${before}$html
}
-}
-namespace eval ::xowiki {
-
Page instproc create_form_field {{-cr_field_spec ""} {-field_spec ""} field_name} {
switch -glob -- $field_name {
__* {}
@@ -1243,767 +1874,6 @@
}
}
- Page instproc validate-attribute {} {
- set field_names [my field_names]
- set validation_errors 0
-
- # get the first transmitted form field
- foreach field_name $field_names {
- if {[::xo::cc exists_form_parameter $field_name]} {
- set form_fields [my create_form_field $field_name]
- set query_field_names $field_name
- break
- }
- }
- foreach {validation_errors category_ids} \
- [my get_form_data -field_names $query_field_names $form_fields] break
- set error ""
- if {$validation_errors == 0} {
- set status_code 200
- } else {
- set status_code 406
- foreach f $form_fields {
- if {[$f error_msg] ne ""} {set error [::xo::localize [$f error_msg] 1]}
- }
- }
- ns_return $status_code text/html $error
- }
-
- Page ad_instproc save-attributes {} {
- The method save-attributes is typically called over the
- REST interface. It allows to save attributes of a
- page without adding a new revision.
- } {
- my instvar package_id
- set field_names [my field_names]
- set form_fields [list]
- set query_field_names [list]
-
- set validation_errors 0
- foreach field_name $field_names {
- if {[::xo::cc exists_form_parameter $field_name]} {
- lappend form_fields [my create_form_field $field_name]
- lappend query_field_names $field_name
- }
- }
- #my show_fields $form_fields
- foreach {validation_errors category_ids} \
- [my get_form_data -field_names $query_field_names $form_fields] break
- if {$validation_errors == 0} {
- #
- # we have no validation errors, so we can save the content
- #
- set update_without_revision [$package_id query_parameter replace 0]
-
- foreach form_field $form_fields {
- # fix richtext content in accordance with oacs conventions
- if {[$form_field istype ::xowiki::formfield::richtext]} {
- $form_field value [list [$form_field value] text/html]
- }
- }
- if {$update_without_revision} {
- # field-wise update without revision
- set update_instance_attributes 0
- foreach form_field $form_fields {
- set s [$form_field slot]
- if {$s eq ""} {
- # empty slot means that we have an instance_attribute;
- # we save all in one statement below
- set update_instance_attributes 1
- } else {
- error "Not implemented yet"
- my update_attribute_from_slot $s [$form_field value]
- }
- }
- if {$update_instance_attributes} {
- set s [my find_slot instance_attributes]
- my update_attribute_from_slot $s [my instance_attributes]
- }
- } else {
- #
- # perform standard update (with revision)
- #
- my save_data \
- -use_given_publish_date [expr {[lsearch $field_names _publish_date] > -1}] \
- [::xo::cc form_parameter __object_name ""] $category_ids
- }
- $package_id returnredirect \
- [my query_parameter "return_url" [my pretty_link]]
- return
- } else {
- # todo: handle errors in a user friendly way
- my log "we have $validation_errors validation_errors"
- }
- $package_id returnredirect \
- [my query_parameter "return_url" [my pretty_link]]
- }
-
-
- FormPage instproc edit {
- {-validation_errors ""}
- {-disable_input_fields 0}
- {-view true}
- } {
- my instvar page_template doc root package_id
- ::xowiki::Form requireFormCSS
- #my log "edit [self args]"
-
- set form [my get_form]
- set anon_instances [my get_from_template anon_instances f]
- #my msg form=$form
- #my msg anon_instances=$anon_instances
-
- set field_names [my field_names -form $form]
- #my log field_names=$field_names
- set form_fields [my create_form_fields $field_names]
-
- 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 ""
- set formgiven 0
- } else {
- set formgiven 1
- }
-
- # 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 [my 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 {![my exists __field_needed(_text)]} {
- #my msg "setting text hidden"
- set f [my lookup_form_field -name _text $form_fields]
- $f config_from_spec hidden
- }
-
- if {[my exists_form_parameter __disabled_fields]} {
- # Disable some form-fields since these are disabled in the form
- # as well.
- foreach name [my form_parameter __disabled_fields] {
- set f [my lookup_form_field -name $name $form_fields]
- $f disabled disabled
- }
- }
-
- #my show_fields $form_fields
- #my msg "__form_action [my form_parameter __form_action {}]"
- if {[my form_parameter __form_action ""] eq "save-form-data"} {
- #my msg "we have to validate"
- #
- # we have to valiate and save the form data
- #
- foreach {validation_errors category_ids} [my get_form_data $form_fields] break
-
- if {$validation_errors != 0} {
- #my msg "$validation_errors errors in $form_fields"
- #foreach f $form_fields { my 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
- my set name [my form_parameter __object_name]
- } else {
- #
- # we have no validation errors, so we can save the content
- #
- my save_data \
- -use_given_publish_date [expr {[lsearch $field_names _publish_date] > -1}] \
- [::xo::cc form_parameter __object_name ""] $category_ids
-
- # The data might have references. We render do the rendering here
- # 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 [my render -update_references true]
- #my msg "after save refs=[expr {[my exists references]?[my set references] : {NONE}}]"
-
- set redirect_method [my form_parameter __form_redirect_method "view"]
- if {$redirect_method eq "__none"} {
- return
- } else {
- if {$redirect_method ne "view"} {set qp "?m=$redirect_method"} {set qp ""}
- set url [my pretty_link -lang en]$qp
- set return_url [$package_id get_parameter return_url $url]
- # We had query_parameter here. however, to be able to
- # process the output of ::xo::cc set_parameter ...., we
- # changed it to "parameter".
- #my msg "[my name]: url=$url, return_url=$return_url"
- $package_id returnredirect $return_url
- return
- }
- }
- } elseif {[my form_parameter __form_action ""] eq "view-form-data" && ![my exists __feedback_mode]} {
- # We have nothing to save (maybe everything is read.only). Check
- # __feedback_mode to prevent recursive loops.
- set redirect_method [my form_parameter __form_redirect_method "view"]
- #my log "__redirect_method=$redirect_method"
- return [my view]
- } else {
- #
- # display the current values
- #
- if {[my is_new_entry [my name]]} {
- my set creator [::xo::get_user_name [::xo::cc user_id]]
- my set nls_language [ad_conn locale]
- #my set name [$package_id query_parameter name ""]
- # TODO: maybe use __object_name to for POST url to make code
- # more straightworward
- #set n [$package_id query_parameter name \
- # [::xo::cc form_parameter __object_name ""]]
- #if {$n ne ""} {
- # my name $n
- #}
- }
-
- array set __ia [my set instance_attributes]
- my 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
-
- #my msg "my is_new_entry [my name] = [my is_new_entry [my name]]"
- if {[my is_new_entry [my name]]} {
- #my msg "anon_instances=$anon_instances"
- if {$anon_instances} {
- set basename [::xowiki::autoname basename [$page_template name]]
- set name [::xowiki::autoname new -name $basename -parent_id [my parent_id]]
- #my msg "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 var [list title detail_link text description] {
- if {[my exists_query_parameter $var]} {
- set value [my query_parameter $var]
- switch -- $var {
- detail_link {
- set f [my lookup_form_field -name $var $form_fields]
- $f value [$f convert_to_external $value]
- }
- title - text - description {
- set f [my 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
- my form_fields_sanity_check $form_fields
- my post_process_form_fields $form_fields
-
- # The following command would be correct, but does not work due to a bug in
- # tdom.
- # set form [my regsub_eval \
- # [template::adp_variable_regexp] $form \
- # {my form_field_as_html -mode edit "\\\1" "\2" $form_fields}]
- # Due to this bug, we program around and replace the at-character
- # by \x003 to avoid conflict withe the input and we replace these
- # magic chars finally with the fields resulting from tdom.
-
- set form [my substitute_markup $form]
- set form [string map [list @ \x003] $form]
- #my msg form=$form
-
- dom parse -simple -html $form doc
- $doc documentElement root
-
- ::require_html_procs
- $root firstChild fcn
- #
- # prepend some fields above the HTML contents of the form
- #
- $root insertBeforeFromScript {
- ::html::input -type hidden -name __object_name -value [my name]
- ::html::input -type hidden -name __form_action -value save-form-data
-
- # insert automatic form fields on top
- foreach att $field_names {
- #if {$formgiven && ![string match _* $att]} continue
- if {[my exists __field_in_form($att)]} continue
- set f [my lookup_form_field -name $att $form_fields]
- #my msg "insert auto_field $att"
- $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
- $root appendFromScript {
- # append category fields
- foreach f $form_fields {
- #my 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
- }
- }
-
- # insert unreported errors
- foreach f $form_fields {
- if {[$f set error_msg] ne "" && ![$f exists error_reported]} {
- $f render_error_msg
- }
- }
- # add a submit field(s) at bottom
- my render_form_action_buttons -CSSclass [string trim "$button_class(wym) $button_class(xinha)"]
- }
-
- set form [lindex [$root selectNodes //form] 0]
- if {$form eq ""} {
- my msg "no form found in page [$page_template name]"
- } else {
- if {[my exists_query_parameter "return_url"]} {
- set return_url [my query_parameter "return_url"]
- }
- set url [export_vars -base [my pretty_link] {{m "edit"} return_url}]
- $form setAttribute action $url method POST
- if {$has_file} {$form setAttribute enctype multipart/form-data}
- Form add_dom_attribute_value $form class [$page_template css_class_name]
- }
-
- my set_form_data $form_fields
- if {$disable_input_fields} {
- # (a) disable explicit input fields
- foreach f $form_fields {$f disabled disabled}
- # (b) disable input in HTML-specified fields
- set disabled [Form dom_disable_input_fields $root]
- #
- # Collect these variables in a hiddden 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.
- #
- $root appendFromScript {
- ::html::input -type hidden -name "__disabled_fields" -value $disabled
- }
- }
- my post_process_dom_tree $doc $root $form_fields
- set html [$root asHTML]
- set html [my regsub_eval \
- {(^|[^\\])\x003([a-zA-Z0-9_:]+)\x003} $html \
- {my form_field_as_html -mode edit "\\\1" "\2" $form_fields}]
- # replace unbalanced @ characters
- set html [string map [list \x003 @] $html]
-
- #my log "calling VIEW with HTML [string length $html]"
- if {$view} {
- my view $html
- } else {
- return $html
- }
- }
-
- File instproc download {} {
- my instvar mime_type package_id
- $package_id set mime_type $mime_type
- set use_bg_delivery [expr {![catch {ns_conn contentsentlength}] &&
- [info command ::bgdelivery] ne ""}]
- $package_id set delivery \
- [expr {$use_bg_delivery ? "ad_returnfile_background" : "ns_returnfile"}]
- if {[my exists_query_parameter filename]} {
- set filename [my query_parameter filename]
- ns_set put [ns_conn outputheaders] Content-Disposition "attachment;filename=$filename"
- }
- #my log "--F FILE=[my full_file_name]"
- return [my full_file_name]
- }
-
- Page instproc revisions {} {
- my instvar package_id name item_id
- set context [list [list [$package_id url] $name ] [_ xotcl-core.revisions]]
- set title "[_ xotcl-core.revision_title] '$name'"
- ::xo::Page set_property doc title $title
- set content [next]
- array set property_doc [::xo::Page get_property doc]
- $package_id return_page -adp /packages/xowiki/www/revisions -variables {
- content context {page_id $item_id} title property_doc
- }
- }
-
- Page instproc make-live-revision {} {
- my instvar revision_id item_id package_id
- #my log "--M set_live_revision($revision_id)"
- ::xo::db::sql::content_item set_live_revision -revision_id $revision_id
- set page_id [my query_parameter "page_id"]
- ::xo::clusterwide ns_cache flush xotcl_object_cache ::$item_id
- ::$package_id returnredirect [my query_parameter "return_url" \
- [export_vars -base [$package_id url] {{m revisions}}]]
- }
-
-
- Page instproc delete-revision {} {
- my instvar revision_id package_id item_id
- db_1row [my qn get_revision] "select latest_revision,live_revision from cr_items where item_id = $item_id"
- # do real deletion via package
- $package_id delete_revision -revision_id $revision_id -item_id $item_id
- # Take care about UI specific stuff....
- set redirect [my query_parameter "return_url" \
- [export_vars -base [$package_id url] {{m revisions}}]]
- if {$live_revision == $revision_id} {
- # latest revision might have changed by delete_revision, so we have to fetch here
- db_1row [my qn get_revision] "select latest_revision from cr_items where item_id = $item_id"
- if {$latest_revision eq ""} {
- # we are out of luck, this was the final revision, delete the item
- my instvar package_id name
- $package_id delete -name $name -item_id $item_id
- } else {
- ::xo::db::sql::content_item set_live_revision -revision_id $latest_revision
- }
- }
- if {$latest_revision ne ""} {
- # otherwise, "delete" did already the redirect
- ::$package_id returnredirect [my query_parameter "return_url" \
- [export_vars -base [$package_id url] {{m revisions}}]]
- }
- }
-
- Page instproc delete {} {
- my instvar package_id item_id name
- # delete always via package
- $package_id delete -item_id $item_id -name $name
- }
-
- PageTemplate instproc delete {} {
- my instvar package_id item_id name
- set count [my count_usages -publish_status all]
- #my msg count=$count
- if {$count > 0} {
- append error_msg \
- [_ xowiki.error-delete_entries_first [list count $count]] \
- \
- [my include [list form-usages -publish_status all -parent_id * -form_item_id [my item_id]]] \
-
- $package_id error_msg $error_msg
- } else {
- next
- }
- }
-
- Page instproc save-tags {} {
- my instvar package_id item_id revision_id
- ::xowiki::Page save_tags \
- -user_id [::xo::cc user_id] \
- -item_id $item_id \
- -revision_id $revision_id \
- -package_id $package_id \
- [my form_parameter new_tags]
-
- ::$package_id returnredirect \
- [my query_parameter "return_url" [$package_id url]]
- }
-
- Page instproc popular-tags {} {
- my instvar package_id item_id parent_id
- set limit [my query_parameter "limit" 20]
- set weblog_page [$package_id get_parameter weblog_page weblog]
- set href [$package_id pretty_link $weblog_page]?summary=1
-
- set entries [list]
- db_foreach [my qn get_popular_tags] \
- [::xo::db::sql select \
- -vars "count(*) as nr, tag" \
- -from "xowiki_tags" \
- -where "item_id=$item_id" \
- -groupby "tag" \
- -orderby "nr" \
- -limit $limit] {
- lappend entries "$tag ($nr)"
- }
- ns_return 200 text/html "[_ xowiki.popular_tags_label]: [join $entries {, }]"
- }
-
- Page instproc diff {} {
- my instvar package_id
-
- set compare_id [my query_parameter "compare_revision_id" 0]
- if {$compare_id == 0} {
- return ""
- }
- ::xo::Page requireCSS /resources/xowiki/xowiki.css
- set my_page [::xowiki::Package instantiate_page_from_id -revision_id [my revision_id]]
- $my_page volatile
-
- if {[catch {set html1 [$my_page render]} errorMsg]} {
- set html2 "Error rendering [my revision_id]: $errorMsg"
- }
- set text1 [ad_html_text_convert -from text/html -to text/plain -- $html1]
- set user1 [::xo::get_user_name [$my_page set creation_user]]
- set time1 [$my_page set creation_date]
- set revision_id1 [$my_page set revision_id]
- regexp {^([^.]+)[.]} $time1 _ time1
-
- set other_page [::xowiki::Package instantiate_page_from_id -revision_id $compare_id]
- $other_page volatile
- #$other_page absolute_links 1
-
- if {[catch {set html2 [$other_page render]} errorMsg]} {
- set html2 "Error rendering $compare_id: $errorMsg"
- }
- set text2 [ad_html_text_convert -from text/html -to text/plain -- $html2]
- set user2 [::xo::get_user_name [$other_page set creation_user]]
- set time2 [$other_page set creation_date]
- set revision_id2 [$other_page set revision_id]
- regexp {^([^.]+)[.]} $time2 _ time2
-
- set title "Differences for [my set name]"
- set context [list $title]
-
- # try util::html diff if it is available and works
- if {[catch {set content [::util::html_diff -old $html2 -new $html1 -show_old_p t]}]} {
- # otherwise, fall back to proven text based diff
- set content [::xowiki::html_diff $text2 $text1]
- }
-
- ::xo::Page set_property doc title $title
- array set property_doc [::xo::Page get_property doc]
- set header_stuff [::xo::Page header_stuff]
-
- $package_id return_page -adp /packages/xowiki/www/diff -variables {
- content title context header_stuff
- time1 time2 user1 user2 revision_id1 revision_id2 property_doc
- }
- }
-
- proc html_diff {doc1 doc2} {
- set out ""
- set i 0
- set j 0
-
- #set lines1 [split $doc1 "\n"]
- #set lines2 [split $doc2 "\n"]
-
- regsub -all \n $doc1 "
" doc1
- regsub -all \n $doc2 "
" doc2
- set lines1 [split $doc1 " "]
- set lines2 [split $doc2 " "]
-
- foreach { x1 x2 } [list::longestCommonSubsequence $lines1 $lines2] {
- foreach p $x1 q $x2 {
- while { $i < $p } {
- set l [lindex $lines1 $i]
- incr i
- #puts "R\t$i\t\t$l"
- append out "$l\n"
- }
- while { $j < $q } {
- set m [lindex $lines2 $j]
- incr j
- #puts "A\t\t$j\t$m"
- append out "$m\n"
- }
- set l [lindex $lines1 $i]
- incr i; incr j
- #puts "B\t$i\t$j\t$l"
- append out "$l\n"
- }
- }
- while { $i < [llength $lines1] } {
- set l [lindex $lines1 $i]
- incr i
- #puts "$i\t\t$l"
- append out "$l\n"
- }
- while { $j < [llength $lines2] } {
- set m [lindex $lines2 $j]
- incr j
- #puts "\t$j\t$m"
- append out "$m\n"
- }
- return $out
- }
-
- Page instproc default_instance_attributes {} {
- #
- # Provide the default list of instance attributes to derived
- # FormPages.
- #
- # We want to be able to create FormPages from all pages.
- # by defining this method, we allow derived applications
- # to provide their own set of instance attributes
- return [list]
- }
-
- Page instproc create-or-use {
- {-parent_id 0}
- {-view_method edit}
- {-name ""}
- {-nls_language ""}
- } {
- # can be overloaded
- my create-new \
- -parent_id $parent_id -view_method $view_method \
- -name $name -nls_language $nls_language
- }
-
- Page instproc create-new {
- {-parent_id 0}
- {-view_method edit}
- {-name ""}
- {-nls_language ""}
- } {
- my instvar package_id
- set original_package_id $package_id
-
- if {[my exists_query_parameter "package_instance"]} {
- set package_instance [my query_parameter "package_instance"]
- #
- # Initialize the target package and set the variable package_id.
- #
- if {[catch {
- ::xowiki::Package initialize \
- -url $package_instance -user_id [::xo::cc user_id] \
- -actual_query ""
- } errorMsg]} {
- ns_log error "$errorMsg\n$::errorInfo"
- return [$original_package_id error_msg \
- "Page '[my name]' invalid provided package instance=$package_instance$errorMsg
"]
- }
- }
-
- #
- # collect some default values from query parameters
- #
- set default_variables [list]
- foreach key {name title page_order last_page_id nls_language} {
- if {[my exists_query_parameter $key]} {
- lappend default_variables $key [my query_parameter $key]
- }
- }
-
- # TODO: the following calls are here temporarily for posting
- # content from manually added forms (e.g. linear forum). The
- # following should be done:
- # - create an includelet to create the form markup automatically
- # - validate and transform input as usual
- # We should probably allow as well controlling autonaming and
- # setting of publish_status, and probhibit empty postings.
-
- set text_to_html [my form_parameter "__text_to_html" ""]
- foreach key {_text _name} {
- if {[my exists_form_parameter $key]} {
- set __value [my form_parameter $key]
- if {[lsearch $text_to_html $key] > -1} {
- set __value [ad_text_to_html $__value]
- }
- lappend default_variables [string range $key 1 end] $__value
- switch $key {
- _name {set name $__value}
- }
- }
- }
- set instance_attributes [list]
- foreach {_att _value} [::xo::cc get_all_form_parameter] {
- if {[string match _* $_att]} continue
- lappend instance_attributes $_att $_value
- }
-
- #
- # To create form_pages in different places than the form, one can
- # provide provide parent_id and package_id.
- #
- # The following construct is more complex than necessary to
- # provide backward compatibility. Note that the passed-in
- # parent_id has priority over the other measures to obtain it.
- #
- if {$parent_id == 0} {
- if {![my exists parent_id]} {my parent_id [$package_id folder_id]}
- set fp_parent_id [my form_parameter "parent_id" [my query_parameter "parent_id" [my parent_id]]]
- } else {
- set fp_parent_id $parent_id
- }
- # In case the Form is inherited and package_id was not specified, we
- # use the actual package_id.
- set fp_package_id [my form_parameter "package_id" [my query_parameter "package_id" [my package_id]]]
-
- ::xo::Package require $fp_package_id
- set f [my create_form_page_instance \
- -name $name \
- -nls_language $nls_language \
- -parent_id $fp_parent_id \
- -package_id $fp_package_id \
- -default_variables $default_variables \
- -instance_attributes $instance_attributes \
- -source_item_id [my query_parameter source_item_id ""]]
-
- if {$name eq ""} {
- $f save_new
- } else {
- set id [$fp_package_id lookup -parent_id $fp_parent_id -name $name]
- if {$id == 0} {
- $f save_new
- } else {
- ::xowiki::FormPage get_instance_from_db -item_id $id
- $f copy_content_vars -from_object $id
- $f item_id $id
- $f save
- }
- }
-
- foreach var {return_url template_file title detail_link text} {
- if {[my exists_query_parameter $var]} {
- set $var [my query_parameter $var]
- }
- }
-
- set form_redirect [my form_parameter "__form_redirect" ""]
- if {$form_redirect eq ""} {
- set form_redirect [export_vars -base [$f pretty_link] \
- [list [list m $view_method] return_url template_file title detail_link text]]
- }
- $package_id returnredirect $form_redirect
- set package_id $original_package_id
- }
-
-
if {[apm_version_names_compare [ad_acs_version] 5.3.0] == 1} {
ns_log notice "Zen-state: 5.3.2 or newer"
Form set extraCSS ""