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 -N --- openacs-4/packages/xowiki/tcl/xowiki-www-procs.tcl 17 Aug 2012 08:00:21 -0000 1.307 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,2127 +0,0 @@ -::xo::library doc { - XoWiki - www procs. These procs are the methods called on xowiki pages via - the web interface. - - @creation-date 2006-04-10 - @author Gustaf Neumann - @cvs-id $Id: xowiki-www-procs.tcl,v 1.307 2012/08/17 08:00:21 neophytosd Exp $ -} - -::xo::library require xowiki-procs - -namespace eval ::xowiki { - # - # This block contains the externally callable methods. We use as - # naming convention dashes as separators. - # - - # - # externally callable method: clipboard-add - # - Page instproc clipboard-add {} { - my instvar package_id - - if {![my exists_form_parameter "objects"]} { - my msg "nothing to copy" - } - set ids [list] - foreach page_name [my form_parameter objects] { - # the page_name is the name exactly as stored in the content repository - set item_id [::xo::db::CrClass lookup -name $page_name -parent_id [my item_id]] - if {$item_id == 0} { - # when the pasted item was from a child-resources includelet - # included on e.g. a plain page. we look for a sibling. - set item_id [::xo::db::CrClass lookup -name $page_name -parent_id [my parent_id]] - } - #my msg "want to copy $page_name // $item_id" - if {$item_id ne 0} {lappend ids $item_id} - } - ::xowiki::clipboard add $ids - ::$package_id returnredirect [my query_parameter "return_url" [::xo::cc url]] - } - - # - # externally callable method: clipboard-clear - # - Page instproc clipboard-clear {} { - my instvar package_id - ::xowiki::clipboard clear - ::$package_id returnredirect [my query_parameter "return_url" [::xo::cc url]] - } - - # - # externally callable method: clipboard-content - # - Page instproc clipboard-content {} { - my instvar package_id - set clipboard [::xowiki::clipboard get] - if {$clipboard eq ""} { - util_user_message -message "Clipboard empty" - } else { - foreach item_id $clipboard { - if {[::xo::db::CrClass get_instance_from_db -item_id $item_id] ne ""} { - util_user_message -message [$item_id pretty_link] - } else { - util_user_message -message "item $item_id deleted" - } - } - } - ::$package_id returnredirect [my query_parameter "return_url" [::xo::cc url]] - } - - # - # externally callable method: clipboard-copy - # - Page instproc clipboard-copy {} { - my instvar package_id - set clipboard [::xowiki::clipboard get] - set item_ids [::xowiki::exporter include_needed_objects $clipboard] - set content [::xowiki::exporter marshall_all $item_ids] - if {[catch {namespace eval ::xo::import $content} error]} { - my msg "Error: $error\n$::errorInfo" - return - } - set msg [$package_id import -replace 0 -create_user_ids 1 \ - -parent_id [my item_id] -objects $item_ids] - util_user_message -html -message $msg - ::xowiki::clipboard clear - ::$package_id returnredirect [my query_parameter "return_url" [::xo::cc url]] - } - - # - # externally callable method: clipboard-export - # - Page instproc clipboard-export {} { - my instvar package_id - set clipboard [::xowiki::clipboard get] - ::xowiki::exporter export $clipboard - ::xowiki::clipboard clear - #::$package_id returnredirect [my query_parameter "return_url" [::xo::cc url]] - } - - - # - # externally callable 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} - } - } - } - - # load the instance attributes from the form parameters - 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 callable 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 callable method: csv-dump - # - - Page instproc csv-dump {} { - if {![my is_form]} { - error "not called on a form" - } - set form_item_id [my item_id] - set items [::xowiki::FormPage get_form_entries \ - -base_item_ids $form_item_id -form_fields "" -initialize false \ - -publish_status all -package_id [my package_id]] - # collect all instances attributes of all items - foreach i [$items children] {array set vars [$i set instance_attributes]} - array set vars [list _name 1 _last_modified 1 _creation_user 1] - set attributes [lsort -dictionary [array names vars]] - # make sure, we the includelet honors the cvs generation - set includelet_key name:form-usages,form_item_ids:$form_item_id,field_names:[join $attributes " "], - ::xo::cc set queryparm(includelet_key) $includelet_key - # call the includelet - my view [my include [list form-usages -field_names $attributes \ - -extra_form_constraints _creation_user:numeric,format=%d \ - -form_item_id [my item_id] -generate csv]] - } - - # - # externally callable 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 - } - } - - # - # externally callable 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 callable method: diff - # - - 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 - } - - # - # externally callable 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 fn [::xo::backslash_escape \" [my query_parameter filename]] - ns_set put [ns_conn outputheaders] Content-Disposition "attachment;filename=\"$fn\"" - } - #my log "--F FILE=[my full_file_name] // $mime_type" - set geometry [::xo::cc query_parameter geometry ""] - if {[string match image/* $mime_type] && $geometry ne ""} { - if {![file isdirectory /tmp/$geometry]} { - file mkdir /tmp/$geometry - } - set scaled_image /tmp/$geometry/[my revision_id] - if {![file readable $scaled_image]} { - set cmd [::util::which convert] - if {$cmd ne ""} { - if {![catch {exec $cmd -geometry $geometry -interlace None -sharpen 1x2 \ - [my full_file_name] $scaled_image}]} { - return $scaled_image - } - } - } else { - return $scaled_image - } - } - return [my full_file_name] - } - - # - # We handle delegation to target for most methods in - # Package->invoke. Otherwise, we would have to implement several - # forwarder methods like the following: - # - -# FormPage instproc download {} { -# # If there is a link to a file, it can be downloaded as well -# set target [my get_target_from_link_page] -# if {$target ne "" && [$target istype ::xowiki::File]} { -# $target download -# } else { -# [my package_id] error_msg "Method 'download' not implemented for this kind of object" -# } -# } - - # - # helper methods for externally callable 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 callable 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 { - # 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] - - # 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 {$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 - } - - FormPage instproc edit { - {-validation_errors ""} - {-disable_input_fields 0} - {-view true} - } { - my instvar page_template doc root package_id - #my log "edit [self args]" - - ::xowiki::Form requireFormCSS - my include_header_info -prefix form_edit - if {[::xo::cc mobile]} {my include_header_info -prefix mobile} - - set form [my get_form] - set anon_instances [my get_anon_instances] - #my log form=$form - #my log anon_instances=$anon_instances - - set field_names [my field_names -form $form] - #my msg 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 - } - #my 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 [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 log "__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. 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 [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]$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 log "[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 log "my is_new_entry [my name] = [my is_new_entry [my name]]" - if {[my is_new_entry [my name]]} { - if {$anon_instances} { - set basename [::xowiki::autoname basename [$page_template name]] - set name [::xowiki::autoname new -name $basename -parent_id [my parent_id]] - #my 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 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 - #my msg "orig fcn $fcn, root $root [$root nodeType] [$root nodeName]" - - set formNode [lindex [$root selectNodes //form] 0] - if {$formNode eq ""} { - my msg "no form found in page [$page_template name]" - 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::input -type hidden -name __object_name -value [my name] - ::html::input -type hidden -name __form_action -value save-form-data - ::html::input -type hidden -name __current_revision_id -value [my revision_id] - - # 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 - $rootNode 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)"] - } - - if {$formNode ne ""} { - 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}] - $formNode setAttribute action $url method POST - if {$has_file} {$formNode setAttribute enctype multipart/form-data} - Form add_dom_attribute_value $formNode 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 1} - # (b) disable input in HTML-specified fields - set disabled [Form dom_disable_input_fields $rootNode] - # - # 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. - # - $rootNode 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 callable method: list - # - Page instproc list {} { - if {[my is_form]} { - # The following line is here to provide a short description for - # larger form-usages (a few MB) where otherwise - # "ad_html_text_convert" in Page.get_description tend to use forever - # (at least in Tcl 8.5) - my set description "form-usages for [my name] [my title]" - - return [my view [my include [list form-usages -form_item_id [my item_id]]]] - } - if {[my is_folder_page]} { - return [my view [my include [list child-resources]]] - } - #my msg "method list undefined for this kind of object" - [my package_id] returnredirect [::xo::cc url] - } - - # - # externally callable method: make-live-revision - # - - 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 callable 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 callable method: save-attributes - # - - Page ad_instproc save-attributes {} { - The method save-attributes is typically callable 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 callable 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 callable 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 callable 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 callable 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 - # wiki pages (see include), since it contains full framing, etc. - my instvar item_id - ::xowiki::Page set recursion_count 0 - set page_package_id [my package_id] - set context_package_id [::xo::cc package_id] - - #my msg "page_package_id=$page_package_id, context_package_id=$context_package_id" - - set template_file [my query_parameter "template_file" \ - [::$context_package_id get_parameter template_file view-default]] - - if {[my isobject ::xowiki::$template_file]} { - $template_file before_render [self] - } - - # - # set up template variables - # - set object_type [$page_package_id get_parameter object_type [my info class]] - set rev_link [$page_package_id make_link -with_entities 0 [self] revisions] - - if {[$context_package_id query_parameter m ""] eq "edit"} { - set view_link [$page_package_id make_link -with_entities 0 [self] view return_url] - set edit_link "" - } else { - set edit_link [$page_package_id make_link -with_entities 0 [self] edit return_url] - set view_link "" - } - set delete_link [$page_package_id make_link -with_entities 0 [self] delete return_url] - if {[my exists __link(new)]} { - set new_link [my set __link(new)] - } else { - set new_link [my new_link $page_package_id] - } - - set admin_link [$context_package_id make_link -privilege admin -link admin/ $context_package_id {} {}] - set index_link [$context_package_id make_link -privilege public -link "" $context_package_id {} {}] - set import_link [$context_package_id make_link -privilege admin -link "" $context_package_id {} {}] - set page_show_link [$page_package_id make_link -privilege admin [self] show-object return_url] - - set notification_subscribe_link "" - if {[$context_package_id get_parameter "with_notifications" 1]} { - if {[::xo::cc user_id] != 0} { ;# notifications require login - set notifications_return_url [expr {[info exists return_url] ? $return_url : [ad_return_url]}] - set notification_type [notification::type::get_type_id -short_name xowiki_notif] - set notification_text "Subscribe the XoWiki instance" - set notification_subscribe_link \ - [export_vars -base /notifications/request-new \ - {{return_url $notifications_return_url} - {pretty_name $notification_text} - {type_id $notification_type} - {object_id $context_package_id}}] - set notification_image \ - "$notification_text" - } - } - - # the menubar is work in progress - set mb [$context_package_id get_parameter "MenuBar" 0] - if {$mb ne "0" && [info command ::xowiki::MenuBar] ne ""} { - - set clipboard_size [::xowiki::clipboard size] - set clipboard_label [expr {$clipboard_size ? "Clipboard ($clipboard_size)" : "Clipboard"}] - # - # Define standard xowiki menubar - # - - set mb [::xowiki::MenuBar create ::__xowiki__MenuBar -id menubar] - $mb add_menu -name Package -label [$context_package_id instance_name] - $mb add_menu -name New - $mb add_menu -name Clipboard -label $clipboard_label - $mb add_menu -name Page - $mb add_menu_item -name Package.Startpage \ - -item [list text #xowiki.index# url $index_link] - $mb add_menu_item -name Package.Subscribe \ - -item [list text #xowiki.subscribe# url $notification_subscribe_link] - $mb add_menu_item -name Package.Notifications \ - -item [list text #xowiki.notifications# url /notifications/manage] - $mb add_menu_item -name Package.Admin \ - -item [list text #xowiki.admin# url $admin_link] - $mb add_menu_item -name Package.ImportDump \ - -item [list url $import_link] - $mb add_menu_item -name New.Page \ - -item [list text #xowiki.new# url $new_link] - $mb add_menu_item -name Page.Edit \ - -item [list text #xowiki.edit# url $edit_link] - $mb add_menu_item -name Page.Revisions \ - -item [list text #xowiki.revisions# url $rev_link] - $mb add_menu_item -name Page.Delete \ - -item [list text #xowiki.delete# url $delete_link] - if {[acs_user::site_wide_admin_p]} { - $mb add_menu_item -name Page.Show \ - -item [list text "Show Object" url $page_show_link] - } - } - - # the content may be passed by other methods (e.g. edit) to - # make use of the same templating machinery below. - if {$content eq ""} { - set content [my render] - #my msg "--after render" - } - - # - # these variables can be influenced via set-parameter - # - set autoname [$page_package_id get_parameter autoname 0] - - # - # setup top includeletes and footers - # - - set footer [my htmlFooter -content $content] - set top_includelets "" - set vp [string trim [$context_package_id get_parameter "top_includelet" ""]] - if {$vp ne "" && $vp ne "none"} { - set top_includelets [my include $vp] - } - - if {$mb ne "0"} { - # - # The following block should not be here, but in the templates - # - set left_side "
\n - [my include {folders -style folders}]\n -
" - - # - # At this place, the menu should be complete, we can render it - # - - #set content [$mb render-yui]$content - append top_includelets \n "
" [$mb render-yui] - - set content "$left_side\n
$content
" - } - - if {[$context_package_id get_parameter "with_user_tracking" 1]} { - my record_last_visited - } - - # Deal with the views package (many thanks to Malte for this snippet!) - if {[$context_package_id get_parameter with_views_package_if_available 1] - && [apm_package_installed_p "views"]} { - views::record_view -object_id $item_id -viewer_id [::xo::cc user_id] - array set views_data [views::get -object_id $item_id] - } - - # import title, name and text into current scope - my instvar title name text - - if {[my exists_query_parameter return_url]} { - set return_url [my query_parameter return_url] - } - - #my log "--after notifications [info exists notification_image]" - - set master [$context_package_id get_parameter "master" 1] - #if {[my exists_query_parameter "edit_return_url"]} { - # set return_url [my query_parameter "edit_return_url"] - #} - #my log "--after options master=$master" - - if {$master} { - set context [list $title] - #my msg "$context_package_id title=[$context_package_id instance_name] - $title" - #my msg "::xo::cc package_id = [::xo::cc package_id] ::xo::cc url= [::xo::cc url] " - ::xo::Page set_property doc title "[$context_package_id instance_name] - $title" - # We could offer a user to translate the current page to his preferred language - # - # set create_in_req_locale_link "" - # if {[$context_package_id get_parameter use_connection_locale 0]} { - # $context_package_id get_lang_and_name -path [$context_package_id set object] req_lang req_local_name - # set default_lang [$page_package_id default_language] - # if {$req_lang ne $default_lang} { - # set l [Link create new -destroy_on_cleanup \ - # -page [self] -type language -stripped_name $req_local_name \ - # -name ${default_lang}:$req_local_name -lang $default_lang \ - # -label $req_local_name -parent_id [my parent_id] -item_id 0 \ - # -package_id $context_package_id -init \ - # -return_only undefined] - # $l render - # } - # } - - #my log "--after context delete_link=$delete_link " - #$context_package_id instvar folder_id ;# this is the root folder - #set template [$folder_id get_payload template] - set template [$context_package_id get_parameter "template" ""] - set page [self] - - foreach css [$context_package_id get_parameter extra_css ""] {::xo::Page requireCSS -order 10 $css} - # refetch template_file, since it might have been changed via set-parameter - # the cache flush (next line) is not pretty here and should be supported from xotcl-core - catch {::xo::cc unset cache([list $context_package_id get_parameter template_file])} - set template_file [my query_parameter "template_file" \ - [::$context_package_id get_parameter template_file view-default]] - # if the template_file does not have a path, assume it in xowiki/www - if {![regexp {^[./]} $template_file]} { - set template_file /packages/xowiki/www/$template_file - } - - # - # initialize and set the template variables, to be used by - # a. adp_compile/ adp_eval - # b. return_page/ adp_include - # - - set header_stuff [::xo::Page header_stuff] - if {[info command ::template::head::add_meta] ne ""} { - set meta(language) [my lang] - set meta(description) [my description] - set meta(keywords) "" - if {[my istype ::xowiki::FormPage]} { - set meta(keywords) [string trim [my property keywords]] - if {[my property html_title] ne ""} { - ::xo::Page set_property doc title [my property html_title] - } - } - if {$meta(keywords) eq ""} { - set meta(keywords) [$context_package_id get_parameter keywords ""] - } - foreach i [array names meta] { - # don't set empty meta tags - if {$meta($i) eq ""} continue - template::head::add_meta -name $i -content $meta($i) - } - } - - # - # pass variables for properties doc and body - # example: ::xo::Page set_property body class "yui-skin-sam" - # - array set property_body [::xo::Page get_property body] - array set property_doc [::xo::Page get_property doc] - - if {$page_package_id != $context_package_id} { - set page_context [$page_package_id instance_name] - } - - if {$template ne ""} { - set __including_page $page - set __adp_stub [acs_root_dir]/packages/xowiki/www/view-default - set template_code [template::adp_compile -string $template] - # - # make sure that and tags are processed - # - append template_code { - if { [info exists __adp_master] } { - set __adp_output [template::adp_parse $__adp_master \ - [concat [list __adp_slave $__adp_output] \ - [array get __adp_properties]]] - } - } - if {[catch {set content [template::adp_eval template_code]} errmsg]} { - ns_return 200 text/html "Error in Page $name: $errmsg
$template" - } else { - ns_return 200 text/html $content - } - } else { - # use adp file - #my log "use adp" - set package_id $context_package_id - $context_package_id return_page -adp $template_file -variables { - name title item_id context header_stuff return_url - content footer package_id page_package_id page_context - rev_link edit_link delete_link new_link admin_link index_link view_link - notification_subscribe_link notification_image - top_includelets page views_data property_body property_doc - } - } - } else { - ns_return 200 [::xo::cc get_parameter content-type text/html] $content - } - } -} - -################################################################################## - -namespace eval ::xowiki { - - # - # This block implements the interfacing between form-fields and Pages - # - - 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 - } - - Page proc find_slot {-start_class:required name} { - foreach cl [concat $start_class [$start_class info heritage]] { - set slotobj ${cl}::slot::$name - if {[my isobject $slotobj]} { - #my msg $slotobj - return $slotobj - } - } - return "" - } - - Page instproc find_slot {-start_class name} { - if {![info exists start_class]} { - set start_class [my info class] - } - return [::xowiki::Page find_slot -start_class $start_class $name] - } - - Page instproc create_raw_form_field { - -name - {-slot ""} - {-spec ""} - {-configuration ""} - } { - set save_slot $slot - if {$slot eq ""} { - # We have no slot, so create a minimal slot. This should only happen for instance attributes - set slot [::xo::Attribute new -pretty_name $name -datatype text -noinit] - $slot destroy_on_cleanup - } - - set spec_list [list] - if {[$slot exists spec]} {lappend spec_list [$slot set spec]} - if {$spec ne ""} {lappend spec_list $spec} - #my msg "[self args] spec_list $spec_list" - #my msg "$name, spec_list = '[join $spec_list ,]'" - - if {[$slot exists pretty_name]} { - set label [$slot set pretty_name] - } else { - set label $name - my log "no pretty_name for variable $name in slot $slot" - } - - if {[$slot exists default]} { - #my msg "setting ff $name default = [$slot default]" - set default [$slot default] - } else { - set default "" - } - set f [::xowiki::formfield::FormField new -name $name \ - -id [::xowiki::Includelet html_id F.[my name].$name] \ - -locale [my nls_language] \ - -label $label \ - -type [expr {[$slot exists datatype] ? [$slot set datatype] : "text"}] \ - -help_text [expr {[$slot exists help_text] ? [$slot set help_text] : ""}] \ - -validator [expr {[$slot exists validator] ? [$slot set validator] : ""}] \ - -required [expr {[$slot exists required] ? [$slot set required] : "false"}] \ - -default $default \ - -spec [join $spec_list ,] \ - -object [self] \ - -slot $save_slot \ - ] - - $f destroy_on_cleanup - eval $f configure $configuration - return $f - } - - PageInstance instproc create_raw_form_field { - -name - {-slot ""} - {-spec ""} - {-configuration ""} - } { - set short_spec [my get_short_spec $name] - #my msg "create form-field '$name', short_spec = '$short_spec', slot=$slot" - set spec_list [list] - if {$spec ne ""} {lappend spec_list $spec} - if {$short_spec ne ""} {lappend spec_list $short_spec} - #my msg "$name: short_spec '$short_spec', spec_list 1 = '[join $spec_list ,]'" - set f [next -name $name -slot $slot -spec [join $spec_list ,] -configuration $configuration] - #my msg "created form-field '$name' $f [$f info class] validator=[$f validator]" ;#p=[$f info precedence] - return $f - } - - - 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. - if {$category_spec eq ""} {return [list]} - - # a value of "off" turns the off as well - foreach f [split $category_spec ,] { - if {$f eq "off"} {return [list]} - } - - set category_fields [list] - set container_object_id [my package_id] - set category_trees [category_tree::get_mapped_trees $container_object_id] - set category_ids [category::get_mapped_categories [my item_id]] - #my msg "mapped category ids=$category_ids" - - foreach category_tree $category_trees { - foreach {tree_id tree_name subtree_id assign_single_p require_category_p} $category_tree break - - 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] { - foreach {category_id category_name deprecated_p level} $category break - if {[lsearch $category_ids $category_id] > -1} {lappend value $category_id} - set category_name [ad_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 [my nls_language] \ - -label $tree_name \ - -type select \ - -value $value \ - -required $require_category_p] - #my msg "category field [my name] created, value '$value'" - $f destroy_on_cleanup - $f options $options - $f multiple [expr {!$assign_single_p}] - lappend category_fields $f - } - return $category_fields - } - - FormPage instproc get_form_value {att} { - # - # Return the value contained in an HTML input field of the FORM - # provided via the instance variable root. - # - my instvar root item_id - set fields [$root selectNodes "//form//*\[@name='$att'\]"] - if {$fields eq ""} {return ""} - foreach field $fields { - # - # Handling first TEXTARA - # - 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 { - #my msg "get_form_value not implemented for $type" - } - radio { - #my msg "get_form_value not implemented for $type" - } - hidden - - password - - text { - if {[$field hasAttribute value]} { - return [$field getAttribute value] - } - } - default { - #my log "can't handle $type so far $att=$value" - } - } - } - return "" - } - - FormPage instproc set_form_value {att value} { - #my msg "set_form_value '$att' to '$value'" - # - # Feed the provided value into an HTML form provided via the - # instance variable root. - # - my instvar root item_id - set fields [$root selectNodes "//form//*\[@name='$att'\]"] - #my 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 differntiate - # 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 thats HTML, anyhow. - switch $type { - checkbox { - #my msg "$att: CHECKBOX value='$value', [$field hasAttribute checked], [$field hasAttribute value]" - if {[$field hasAttribute value]} { - set form_value [$field getAttribute value] - #my msg "$att: form_value=$form_value, my value=$value" - if {[lsearch -exact $value $form_value] > -1} { - $field setAttribute checked true - } elseif {[$field hasAttribute checked]} { - $field removeAttribute checked - } - } else { - #my 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] - #my 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 {my log "can't handle $type so far $att=$value"} - } - } - } - - FormPage ad_instproc set_form_data {form_fields} { - Store the instance attributes or default values in the form. - } { - ::require_html_procs - - array set __ia [my instance_attributes] - foreach f $form_fields { - set att [$f name] - # just handle fields of the form entry - if {![my exists __field_in_form($att)]} continue - #my msg "set form_value to form-field $att __ia($att) [info exists __ia($att)]" - if {[info exists __ia($att)]} { - #my msg "my set_form_value from ia $att '$__ia($att)', external='[$f convert_to_external $__ia($att)]' f.value=[$f value]" - my set_form_value $att [$f convert_to_external $__ia($att)] - } else { - # do we have a value in the form? If yes, keep it. - set form_value [my get_form_value $att] - #my 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 - my set_form_value $att [$f convert_to_external [$f value]] - } - } - } - } - - Page instproc mutual_overwrite_occurred {} { - util_user_message -html \ - -message "User [::xo::get_user_name [my set modifying_user]] has modifyed this page \ - while you were editing it.\ - Open modified page in new window or press OK again to save this page." - # return 1 to flag validation error, 0 to ignore this fact - return 1 - } - - Page ad_instproc get_form_data {-field_names form_fields} { - - Get the values from the form and store it in the form fields and - finally as instance attributes. If the field names are not - specified, all form parameters are used. - - } { - set validation_errors 0 - set category_ids [list] - array set containers [list] - my instvar __ia package_id - set cc [$package_id context] - if {[my exists instance_attributes]} { - array unset __ia - array set __ia [my set instance_attributes] - } - - if {![info exists field_names]} { - set field_names [$cc array names form_parameter] - #my log "form-params=[$cc array get form_parameter]" - } - #my msg "fields $field_names // $form_fields" - #foreach f $form_fields { my msg "... $f [$f name]" } - - # - # We have a form and get all form input from the fields of the - # from into form field objects. - # - foreach att $field_names { - #my msg "getting att=$att" - set processed($att) 1 - switch -glob -- $att { - __category_* { - set f [my lookup_form_field -name $att $form_fields] - set value [$f value [$cc form_parameter $att]] - foreach v $value {lappend category_ids $v} - } - __* { - # other internal variables (like __object_name) are ignored - } - _* { - # instance attribute fields - set f [my lookup_form_field -name $att $form_fields] - set value [$f value [string trim [$cc form_parameter $att]]] - set varname [string range $att 1 end] - # get rid of strange utf-8 characters hex C2AD (firefox bug?) - # ns_log notice "FORM_DATA var=$varname, value='$value' s=$s" - if {$varname eq "text"} {regsub -all "­" $value "" value} - #ns_log notice "FORM_DATA var=$varname, value='$value'" - if {![string match *.* $att]} {my set $varname $value} - } - default { - # user form content fields - if {[regexp {^(.+)[.](tmpfile|content-type)} $att _ file field]} { - set f [my lookup_form_field -name $file $form_fields] - $f $field [string trim [$cc form_parameter $att]] - } else { - set f [my lookup_form_field -name $att $form_fields] - set value [$f value [string trim [$cc form_parameter $att]]] - #my msg "value of $att ($f) = '$value' exists=[$cc exists_form_parameter $att]" - if {![string match *.* $att]} {set __ia($att) $value} - if {[$f exists is_category_field]} {foreach v $value {lappend category_ids $v}} - } - } - } - if {[string match *.* $att]} { - foreach {container component} [split $att .] break - lappend containers($container) $component - } - } - - #my msg "containers = [array names containers]" - #my msg "ia=[array get __ia]" - # - # In a second iteration, combine the values from the components - # of a container to the value of the container. - # - foreach c [array names containers] { - switch -glob -- $c { - __* {} - _* { - set f [my lookup_form_field -name $c $form_fields] - set processed($c) 1 - my set [string range $c 1 end] [$f value] - } - default { - set f [my lookup_form_field -name $c $form_fields] - set processed($c) 1 - #my msg "compute value of $c" - set __ia($c) [$f value] - #my msg "__ia($c) is set to '$__ia($c)'" - } - } - } - - # - # The first round was a processing based on the transmitted input - # fields of the forms. Now we use the formfields to complete the - # data and to validate it. - # - foreach f $form_fields { - #my msg "validate $f [$f name] [info exists processed([$f name])]" - set att [$f name] - - # Certain form field types (e.g. checkboxes) are not transmitted, if not - # checked. Therefore, we have not processed these fields above and - # have to do it now. - - if {![info exists processed($att)]} { - #my msg "form field $att not yet processed" - switch -glob -- $att { - __* { - # other internal variables (like __object_name) are ignored - } - _* { - # instance attribute fields - set varname [string range $att 1 end] - set default "" - if {[my exists $varname]} {set default [my set $varname]} - set v [$f value_if_nothing_is_returned_from_form $default] - set value [$f value $v] - if {$v ne $default} { - if {![string match *.* $att]} {my set $varname $value} - } - } - default { - # user form content fields - set default "" - # The reason, why we set in the next line the default to - # the old value is due to "show-solution" in the qti - # use-case. Maybe one should alter this use-case to - # simplify the semantics here. - if {[info exists __ia($att)]} {set default $__ia($att)} - set v [$f value_if_nothing_is_returned_from_form $default] - #my msg "value_if_nothing_is_returned_from_form '$default' => '$v' (type=[$f info class])" - set value [$f value $v] - if {![string match *.* $att]} {set __ia($att) $value} - } - } - } - - # - # Run validators - # - set validation_error [$f validate [self]] - if {$validation_error ne ""} { - #my msg "validation of $f [$f name] with value '[$f value]' returns '$validation_error'" - $f error_msg $validation_error - incr validation_errors - } - } - #my msg "validation returns $validation_errors errors" - set current_revision_id [::xo::cc form_parameter __current_revision_id ""] - if {$validation_errors == 0 && $current_revision_id ne "" && $current_revision_id != [my revision_id]} { - set validation_errors [my mutual_overwrite_occurred] - } - - if {$validation_errors == 0} { - # - # Postprocess based on form fields based on form-fields methods. - # - foreach f $form_fields { - $f convert_to_internal - } - } else { - my log validation_errors=$validation_errors - - # There were validation erros. Reset the value for form-fields - # of type "file" to avoid confusions, since a file-name was - # provided, but the file was not uploaded due to the validation - # error. If we would not reset the value, the provided name - # would cause an interpretation of an uploaded empty file. Maybe - # a new method "reset-to-default" would be a good idea. - foreach f $form_fields { - if {[$f type] eq "file"} { - $f set value "" - } - } - } - - my instance_attributes [array get __ia] - #my msg category_ids=$category_ids - return [list $validation_errors [lsort -unique $category_ids]] - } - - FormPage instproc form_field_as_html {{-mode edit} before name form_fields} { - set found 0 - foreach f $form_fields { - if {[$f name] eq $name} {set found 1; break} - } - if {!$found} { - set f [my create_raw_form_field -name $name -slot [my find_slot $name]] - } - - #my msg "$found $name mode=$mode type=[$f set type] value=[$f value] disa=[$f exists disabled]" - if {$mode eq "edit" || [$f display_field]} { - set html [$f asHTML] - } else { - set html @$name@ - } - #my msg "$name $html" - return ${before}$html - } - - Page instproc create_form_field {{-cr_field_spec ""} {-field_spec ""} field_name} { - switch -glob -- $field_name { - __* {} - _* { - set varname [string range $field_name 1 end] - return [my create_raw_form_field -name $field_name \ - -spec $cr_field_spec \ - -slot [my find_slot $varname]] - } - default { - return [my create_raw_form_field -name $field_name \ - -spec $field_spec \ - -slot [my find_slot $field_name]] - } - } - } - - Page instproc create_form_fields {field_names} { - set form_fields [my create_category_fields] - foreach att $field_names { - if {[string match "__*" $att]} continue - lappend form_fields [my create_form_field $att] - } - return $form_fields - } - - FormPage instproc create_form_field {{-cr_field_spec ""} {-field_spec ""} field_name} { - if {$cr_field_spec eq ""} {set cr_field_spec [my get_short_spec @cr_fields]} - if {$field_spec eq ""} {set field_spec [my get_short_spec @fields]} - return [next -cr_field_spec $cr_field_spec -field_spec $field_spec $field_name] - } - - FormPage instproc create_form_fields {field_names} { - set form_fields [my create_category_fields] - foreach att $field_names { - if {[string match "__*" $att]} continue - lappend form_fields [my create_form_field \ - -cr_field_spec [my get_short_spec @cr_fields] \ - -field_spec [my get_short_spec @fields] $att] - } - return $form_fields - } - - FormPage instproc field_names {{-form ""}} { - my instvar package_id - foreach {form_vars needed_attributes} [my field_names_from_form -form $form] break - #my msg "form=$form, form_vars=$form_vars needed_attributes=$needed_attributes" - my array unset __field_in_form - my array unset __field_needed - if {$form_vars} {foreach v $needed_attributes {my set __field_in_form($v) 1}} - foreach v $needed_attributes {my set __field_needed($v) 1} - - # - # Remove the fields already included in auto_fields form the needed_attributes. - # The final list field_names determines the order of the fields in the form. - # - set auto_fields [list _name _page_order _title _creator _assignee _text _description _nls_language] - set reduced_attributes $needed_attributes - - foreach f $auto_fields { - set p [lsearch $reduced_attributes $f] - if {$p > -1} { - #if {$form_vars} { - #set auto_field_in_form($f) 1 - #} - set reduced_attributes [lreplace $reduced_attributes $p $p] - } - } - #my msg reduced_attributes(after)=$reduced_attributes - #my msg fields_from_form=[my array names __field_in_form] - - set field_names [list _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 [list _text _description _nls_language] { lappend field_names $fn } - #my msg final-field_names=$field_names - return $field_names - } - - Page instproc field_names {{-form ""}} { - array set dont_modify [list item_id 1 revision_id 1 object_id 1 object_title 1 page_id 1 name 1] - set field_names [list] - foreach field_name [[my info class] array names db_slot] { - if {[info exists dont_modify($field_name)]} continue - lappend field_names _$field_name - } - #my msg field_names=$field_names - return $field_names - } - - FormPage instproc post_process_form_fields {form_fields} { - # We offer here the possibility to iterate over the form fields before it - # before they are rendered - } - - FormPage instproc post_process_dom_tree {dom_doc dom_root form_fields} { - # Part of the input fields comes from HTML, part comes via $form_fields - # We offer here the possibility to iterate over the dom tree before it - # is presented; can be overloaded - } - - FormPage instproc load_values_into_form_fields {form_fields} { - array set __ia [my set instance_attributes] - foreach f $form_fields { - set att [$f name] - switch -glob $att { - __* {} - _* { - set varname [string range $att 1 end] - $f value [$f convert_to_external [my set $varname]] - } - default { - if {[info exists __ia($att)]} { - #my msg "setting $f ([$f info class]) value $__ia($att)" - $f value [$f convert_to_external $__ia($att)] - } - } - } - } - } - - FormPage instproc render_form_action_buttons {{-CSSclass ""}} { - ::html::div -class form-button { - set f [::xowiki::formfield::submit_button new -destroy_on_cleanup \ - -name __form_button_ok \ - -CSSclass $CSSclass] - $f render_input - } - } - - FormPage instproc form_fields_sanity_check {form_fields} { - foreach f $form_fields { - if {[$f exists 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] - && [lsearch [$f info mixin] ::xowiki::formfield::omit] > -1} { - # 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 - #my msg "$f [$f name] [$f info class] [$f info mixin]" - } - } - } - - 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 "" - } else { - ns_log notice "Zen-state: pre 5.3.1, use backward compatible form css file" - Form set extraCSS "zen-forms-backward-compatibility.css" - } - Form proc requireFormCSS {} { - #my msg requireFormCSS - set css [my set extraCSS] - if {$css ne ""} { - ::xo::Page requireCSS $css - } - } - -} -::xo::library source_dependent -