Index: openacs-4/packages/xowiki/tcl/form-field-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/form-field-procs.tcl,v diff -u -r1.241 -r1.242 --- openacs-4/packages/xowiki/tcl/form-field-procs.tcl 27 Oct 2014 16:42:04 -0000 1.241 +++ openacs-4/packages/xowiki/tcl/form-field-procs.tcl 27 Apr 2015 15:28:22 -0000 1.242 @@ -10,7 +10,7 @@ # Second approximation for form fields. # FormFields are objects, which can be outputed as well in ad_forms - # or asHTML included in wiki pages. FormFields support + # or asHTML included in wiki pages. FormFields support # # - validation # - help_text @@ -20,7 +20,7 @@ # and inherit properties of the original datatypes via slots # (e.g. for boolean entries). FormFields can be subclassed # to ensure tailorability and high reuse. - # + # # todo: at some later time, this could go into xotcl-core ########################################################### @@ -29,22 +29,22 @@ # ########################################################### Class create FormField -superclass ::xo::tdom::Object -parameter { - {required false} - {display_field true} - {hide_value false} + {required false} + {display_field true} + {hide_value false} {inline false} {mode edit} {disabled} {show_raw_value} {CSSclass} {style} - {type text} - {label} - {name} - {id} + {type text} + {label} + {name} + {id} {title} - {value ""} - {spec ""} + {value ""} + {spec ""} {help_text ""} {error_msg ""} {validator ""} @@ -139,7 +139,7 @@ my instvar label return [_ acs-templating.Element_is_required] } - # + # #my msg "++ [my name] [my info class] validator=[my validator] ([llength [my validator]]) value=$value" foreach validator [my validator] { set errorMsg "" @@ -152,9 +152,9 @@ #my msg "++ [my name]: field-level validator exists '$validator_method' ? [expr {$proc_info ne {}}]" if {$proc_info ne ""} { # we have a slot checker, call it - #my msg "++ call-field level validator $validator_method '$value'" + #my msg "++ call-field level validator $validator_method '$value'" set success [my validation_check $validator_method $value] - } + } if {$success == 1} { # the previous check was ok, check now for a validator on the # object level @@ -163,7 +163,7 @@ #my msg "++ [my name]: page-level validator exists ? [expr {$proc_info ne {}}]" if {$proc_info ne ""} { set success [$obj $validator_method $value] - #my msg "++ call page-level validator $validator_method '$value' returns $success" + #my msg "++ call page-level validator $validator_method '$value' returns $success" } } if {$success == 0} { @@ -226,7 +226,7 @@ } return $success } - + FormField set cond_regexp {^([^=?]+)[?]([^:]*)[:](.*)$} FormField proc get_single_spec {-package_id -object string} { @@ -256,7 +256,7 @@ FormField instproc behavior {mixin} { # - # Specify the behavior of a form field via + # Specify the behavior of a form field via # per object mixins # set obj [my object] @@ -306,10 +306,10 @@ } if {[catch { # - # We want to allow a programmer to use e.g. options=[xowiki::locales] + # We want to allow a programmer to use e.g. options=[xowiki::locales] # # Note: do not allow users to use [] via forms, since they might - # execute arbitrary commands. The validator for the form fields + # execute arbitrary commands. The validator for the form fields # makes sure, that the input specs are free from square brackets. # if {[string match {\[*\]} $value]} { @@ -321,9 +321,9 @@ } } default { - # Check, if the spec value $s is a class. + # Check, if the spec value $s is a class. set old_class [my info class] - # Don't allow to use namespaced values, since we would run + # Don't allow to use namespaced values, since we would run # into a recursive loop for richtext::wym (could be altered there as well). if {[my isclass ::xowiki::formfield::$s] && ![string match "*:*" $s]} { my class ::xowiki::formfield::$s @@ -397,11 +397,11 @@ append spec " {label " [list $label] "} " if {[my exists html]} { - append spec " {html {" + append spec " {html {" foreach {key value} [array get html] { append spec $key " " [list $value] " " } - append spec "}} " + append spec "}} " } if {[my exists options]} { @@ -424,7 +424,7 @@ FormField instproc render {} { # In case, we use an asHTML of a FormField, we use this - # render definition + # render definition if {[my inline]} { # with label, error message, help text my render_form_widget @@ -434,7 +434,7 @@ } my set __rendered 1 } - + FormField instproc render_form_widget {} { # This method provides the form-widget wrapper set CSSclass [my form_widget_CSSclass] @@ -472,8 +472,8 @@ FormField instproc render_input {} { # - # This is the most general widget content renderer. - # If no special renderer is defined, we fall back to this one, + # This is the most general widget content renderer. + # If no special renderer is defined, we fall back to this one, # which is in most cases a simple input fied of type string. # if {[my mode] ne "edit"} { @@ -509,7 +509,7 @@ ::html::input [list type hidden name [my name] value [my set value]] {} } my set __rendered 1 - } + } FormField instproc render_item {} { ::html::div -class [my form_item_wrapper_CSSclass] { @@ -563,7 +563,7 @@ } FormField instproc localize {v} { - # We localize in pretty_value the message keys in the + # We localize in pretty_value the message keys in the # language of the item (not the connection item). if {[regexp "^#(.*)#$" $v _ key]} { return [lang::message::lookup [my locale] $key] @@ -680,7 +680,7 @@ if {$entry_name eq ""} return if {[my set value] eq ""} return my instvar object value - + array set "" [$object item_ref -default_lang [$object lang] -parent_id $parent_id $entry_name] set label [my label] ;# the label is used for alt und title @@ -690,7 +690,7 @@ # parent object as label. set label [[my object] title] } - + set l [::xowiki::Link create new -destroy_on_cleanup \ -page $object -type "image" -lang $(prefix) \ [list -stripped_name $(stripped_name)] [list -label $label] \ @@ -705,7 +705,7 @@ foreach option { href cssclass - float width height + float width height padding padding-right padding-left padding-top padding-bottom margin margin-left margin-right margin-top margin-bottom border border-width position top botton left right @@ -719,14 +719,14 @@ ########################################################### # - # helper method for extending slots: - # either, we make a meta class for form-fields, or this should + # helper method for extending slots: + # either, we make a meta class for form-fields, or this should # should go into xotcl-core # ########################################################### ::Serializer exportMethods { - ::xotcl::Class instproc extend_slot_default + ::xotcl::Class instproc extend_slot_default } Class instproc extend_slot_default {name value} { # Search for the slot. If the slot exists, extend it's default @@ -748,7 +748,7 @@ # ########################################################### - Class create submit_button -superclass FormField + Class create submit_button -superclass FormField submit_button instproc initialize {} { my set type submit my set value [::xo::localize [_ xowiki.Form-submit_button]] @@ -778,7 +778,13 @@ link_label } file instproc check=virus {value} { - if {[my viruscheck] && $value ne "" && [::xowiki::virus check [my set tmpfile]]} { + set tmpfile [my set tmpfile] + # In case of an upgrade script, the (uploaded) tmp file might not exist + if {[my viruscheck] + && $value ne "" + && [file exists $tmpfile] + && [::xowiki::virus check $tmpfile] + } { #util_user_message -message "uploaded file contains a virus; upload rejected" return 0 } @@ -828,7 +834,7 @@ return [my get_old_value] } return [my set value] - } + } return [next] } @@ -848,7 +854,7 @@ array set entry_info [my entry_info $value] set content_type [my set content-type] - if {$content_type eq "application/octetstream" + if {$content_type eq "application/octetstream" || $content_type eq "application/force-download" } { set content_type [::xowiki::guesstype $value] @@ -863,7 +869,7 @@ $file_object set title $value $file_object save } else { - # create a new file + # create a new file #my msg "new file" set file_object [::xowiki::File new -destroy_on_cleanup \ -title $value \ @@ -923,7 +929,7 @@ append href &revision_id=$revision_id } } - + # # The HTML5 handling of "required" would force us to upload in # every form the file again. To implement the sticky option, we @@ -944,15 +950,15 @@ ::html::input -type hidden -name $id -id $id -value $value ::html::span -class file-control -id __a$id { ::html::a -href $href {::html::t [my label_or_value $fn] } - + # Show the clear button just when # - there is something to clear, and # - the formfield is not disabled, and # - the form-field is not sticky (default) - + set disabled [expr {[my exists disabled] && [my disabled] != "false"}] if {$value ne "" && !$disabled && ![my sticky] } { - ::html::input -type button -value clear \ + ::html::input -type button -value [_ xowiki.clear] \ -onClick "document.getElementById('$id').value = ''; document.getElementById('__a$id').style.display = 'none';" } } @@ -1010,7 +1016,7 @@ Class create image -superclass file -parameter { href cssclass - float width height + float width height padding padding-right padding-left padding-top padding-bottom margin margin-left margin-right margin-top margin-bottom border border-width position top botton left right @@ -1060,7 +1066,7 @@ # ::xowiki::formfield::inform # ########################################################### - + Class create inform -superclass FormField inform instproc initialize {} { my type hidden @@ -1095,7 +1101,7 @@ # ########################################################### - Class create color -superclass text + Class create color -superclass text color instproc initialize {} { next my type color @@ -1107,22 +1113,46 @@ # ########################################################### - Class create datetime -superclass text + Class create datetime -superclass text datetime instproc initialize {} { next my type datetime } - # names for HTML5 types - # date, month - # already in use, should redefine accordingly when avail ########################################################### # + # ::xowiki::formfield::h5date + # + # HTML 5 input type "date", to avoid naming conflict with + # pre-existing formfield of type "date" + ########################################################### + Class create h5date -superclass text + h5date instproc initialize {} { + next + my type date + } + + ########################################################### + # + # ::xowiki::formfield::h5time + # + # HTML 5 input type "time", to avoid naming conflict with + # pre-existing formfield of type "time" + ########################################################### + Class create h5time -superclass text + h5time instproc initialize {} { + next + my type time + } + + + ########################################################### + # # ::xowiki::formfield::datetime-local # ########################################################### - Class create datetime-local -superclass text + Class create datetime-local -superclass text datetime-local instproc initialize {} { next my type datetime-local @@ -1134,7 +1164,7 @@ # ########################################################### - Class create time -superclass text + Class create time -superclass text time instproc initialize {} { next my type time @@ -1146,7 +1176,7 @@ # ########################################################### - Class create week -superclass text + Class create week -superclass text week instproc initialize {} { next my type datetime @@ -1158,7 +1188,7 @@ # ########################################################### - Class create email -superclass text + Class create email -superclass text email instproc initialize {} { next my type email @@ -1170,7 +1200,7 @@ # ########################################################### - Class create search -superclass text + Class create search -superclass text search instproc initialize {} { next my type search @@ -1181,7 +1211,7 @@ # ########################################################### - Class create tel -superclass text + Class create tel -superclass text tel instproc initialize {} { next my type tel @@ -1230,7 +1260,7 @@ # ########################################################### - Class create password -superclass text + Class create password -superclass text password instproc initialize {} { next my set widget_type password @@ -1244,7 +1274,7 @@ Class create numeric -superclass text -parameter { {format %.2f} - } -extend_slot_default validator numeric + } -extend_slot_default validator numeric numeric instproc initialize {} { next my set widget_type numeric @@ -1436,6 +1466,7 @@ } textarea instproc initialize {} { my set widget_type text(textarea) + my set booleanHTMLAttributes {required readonly disabled formnovalidate} foreach p [list rows cols style] {if {[my exists $p]} {my set html($p) [my $p]}} if {![my istype ::xowiki::formfield::richtext] && [my exists editor]} { # downgrading @@ -1447,7 +1478,7 @@ } textarea instproc render_input {} { - set booleanAtts [my booleanAttributes required readonly disabled formnovalidate] + set booleanAtts [my booleanAttributes {*}[my set booleanHTMLAttributes]] ::html::textarea [my get_attributes id name cols rows style wrap placeholder {CSSclass class} \ {*}$booleanAtts] { ::html::t [my value] @@ -1485,15 +1516,15 @@ Class create richtext -superclass textarea \ -extend_slot_default validator safe_html \ -parameter { - plugins + plugins folder_id script_dir {displayMode standard} width height {wiki false} } - + richtext instproc editor {args} { # # TODO: this should be made a slot setting @@ -1519,7 +1550,7 @@ #my msg "MIXIN $editor: [my info precedence]" my reset_parameter my set __initialized 1 - } + } my set editor $editor } @@ -1531,11 +1562,16 @@ standard {} default {error "value '[my set displayMode]' invalid: valid entries for displayMode are inplace, inline or standard (default)"} } + # + # Don't set HTML5 attribute required, since this does not match + # well with Richtext Editors (at least ckeditor4 has problems, + # other probably as well). + # + my set booleanHTMLAttributes {readonly disabled formnovalidate} next if {![my exists editor]} { - # set the default editor; TODO: should be a parameter - my set editor xinha - #my set editor ckeditor4 + my set editor [parameter::get_global_value -package_key xowiki \ + -parameter PreferredRichtextEditor -default xinha] #my msg "setting default of [my name] to [my set editor]" } if {![my exists __initialized]} { @@ -1550,9 +1586,7 @@ #my msg "[my get_attributes id style {CSSclass class}]" ::html::div [my get_attributes id style {CSSclass class}] { if {[my wiki]} { - [my object] set unresolved_references 0 - [my object] set __unresolved_references [list] - #::html::t -disableOutputEscaping [[my object] substitute_markup [list [my value] text/html]] + [my object] references clear ::html::t -disableOutputEscaping [[my object] substitute_markup [my value]] } else { ::html::t -disableOutputEscaping [my value] @@ -1634,7 +1668,7 @@ }); editor.setData(calc_wiki_image_links_to_image_tags(editor.getData())); } - + function calc_image_tags_to_wiki_image_links (form) { var calc = function() { var wiki_link = $(this).attr('alt'); @@ -1643,15 +1677,15 @@ $(form).find('iframe').each(function() { $(this).contents().find('img[type="wikilink"]').each(calc); }); - + $(form).find('textarea.ckeip').each(function() { var contents = $('
'+this.value+'
'); contents.find('img[type="wikilink"]').each(calc); this.value = contents.html(); }); return true; } - + function calc_wiki_image_links_to_image_tags (data) { var pathname = window.location.pathname; pathname = pathname.substr(pathname.lastIndexOf("/")+1,pathname.length) @@ -1688,9 +1722,9 @@ ::xo::Page requireCSS "/resources/xowiki/jquery-ui-1.8.17.custom.css" # In contrary to the doc, ckeditor names instances after the id, - # not the name. + # not the name. set id [my id] - set name [my name] + set name [my name] set package_id [[my object] package_id] #my extraPlugins {timestamp xowikiimage} @@ -1700,7 +1734,7 @@ } else { set ready_callback "/*none*/;" } - + set options [subst { toolbar : '[my toolbar]', uiColor: '[my uiColor]', @@ -1778,25 +1812,26 @@ Class create richtext::ckeditor4 -superclass richtext -parameter { {editor ckeditor4} {mode wysiwyg} - {skin kama} + {skin bootstrapck} {toolbar Full} {CSSclass xowiki-ckeditor} {uiColor ""} {CSSclass xowiki-ckeditor} {customConfig "config.js"} {callback "/* callback code */"} {destroy_callback "/* callback code */"} - {extraPlugins ""} + {submit_callback ""} + {extraPlugins "xowikiimage"} {templatesFiles ""} {templates ""} {contentsCss /resources/xowiki/ck_contents.css} {imageSelectorDialog /xowiki/ckeditor-images/} + {additionalConfigOptions ""} } richtext::ckeditor4 set editor_mixin 1 richtext::ckeditor4 instproc initialize {} { switch -- [my set displayMode] { inplace { my append help_text " #xowiki.ckeip_help#" } - inline { if {![my exists default]} {my set default " "} } } next my set widget_type richtext @@ -1816,7 +1851,7 @@ editor.setData(calc_wiki_image_links_to_image_tags(editor.getData())); } } - + function calc_image_tags_to_wiki_image_links (form) { var calc = function() { var wiki_link = $(this).attr('alt'); @@ -1825,24 +1860,25 @@ $(form).find('iframe').each(function() { $(this).contents().find('img[type="wikilink"]').each(calc); }); - + $(form).find('textarea.ckeip').each(function() { var contents = $('
'+this.value+'
'); contents.find('img[type="wikilink"]').each(calc); this.value = contents.html(); }); return true; } - + function calc_image_tags_to_wiki_image_links_inline (e) { - var data = $('
'+e.editor.getData()+'
'); + var data = $('
'+CKEDITOR.instances[e].getData()+'
'); data.find('img[type="wikilink"]').each( function() { var wiki_link = $(this).attr('alt'); $(this).replaceWith('[['+wiki_link+']]'); }); - document.getElementById(e.editor.config.textarea_id).innerHTML=data.html(); + CKEDITOR.instances[e].setData(data.html()); + CKEDITOR.instances[e].updateElement(); } - + function calc_wiki_image_links_to_image_tags (data) { var pathname = window.location.pathname; pathname = pathname.substr(pathname.lastIndexOf("/")+1,pathname.length) @@ -1854,7 +1890,7 @@ } } } - + richtext::ckeditor4 instproc pathNames {fileNames} { set result [list] foreach fn $fileNames { @@ -1866,44 +1902,43 @@ } return $result } - + richtext::ckeditor4 instproc render_input {} { set disabled [expr {[my exists disabled] && [my disabled] != "false"}] set is_repeat_template [expr {[my exists is_repeat_template] && [my set is_repeat_template] == "true"}] # my msg "[my id] [my name] - $is_repeat_template" - - # if value is empty, we need something to be clickable for display mode inline or inplace - if {[my value] eq "" && [my set displayMode] in {inline inplace}} { + + # if value is empty, we need something to be clickable for display mode inplace + if {[my value] eq "" && [my set displayMode] eq "inplace"} { my value " " } - + if {![my istype ::xowiki::formfield::richtext] || ($disabled && !$is_repeat_template)} { my render_richtext_as_div } else { ::xo::Page requireJS "/resources/xowiki/jquery/jquery.min.js" ::xo::Page requireJS "/resources/xowiki/ckeditor4/ckeditor.js" ::xo::Page requireJS "/resources/xowiki/ckeditor4/adapters/jquery.js" - ::xo::Page requireJS "/resources/xowiki/jquery-ui-1.8.17.custom.min.js" - ::xo::Page requireCSS "/resources/xowiki/jquery-ui-1.8.17.custom.css" - + #::xo::Page requireJS "/resources/xowiki/jquery-ui-1.8.17.custom.min.js" + #::xo::Page requireCSS "/resources/xowiki/jquery-ui-1.8.17.custom.css" + # In contrary to the doc, ckeditor4 names instances after the id, - # not the name. + # not the name. set id [my id] - set name [my name] + set name [my name] set package_id [[my object] package_id] - my extraPlugins {timestamp xowikiimage tlflrn} - # my extraPlugins {timestamp} if {[my set displayMode] eq "inline"} {my lappend extraPlugins sourcedialog} - + if {"xowikiimage" in [my extraPlugins]} { my js_image_helper set ready_callback {xowiki_image_callback(e.editor);} } else { set ready_callback "/*none*/;" - set blur_callback "/*none*/;" + set submit_callback "/*none*/;" } - + set options [subst { + [my set additionalConfigOptions] toolbar : '[my toolbar]', uiColor: '[my uiColor]', language: '[lang::conn::language]', @@ -1925,17 +1960,17 @@ if {[my templates] ne ""} { append options " , templates: '[my templates]'\n" } - + #set parent [[[my object] package_id] get_page_from_item_or_revision_id [[my object] parent_id]];# ??? - + if {[my set displayMode] eq "inplace"} { if {!$is_repeat_template} { set callback [my callback] set destroy_callback [my destroy_callback] - + my lappend CSSclass ckeip ::xo::Page requireJS "/resources/xowiki/ckeip.js" - + ::xo::Page requireJS [subst -nocommands { function load_$id () { \$( '\#$id' ).ckeip(function() { $callback }, { @@ -1947,48 +1982,62 @@ }); } \$(document).ready(function() { - load_$id (); + if (\$('#$id').parents('.repeatable').length != 0) { + if (\$('#$id').is(':visible')) { + load_$id (); + } + } else { + //this is not inside a repeatable container, load normally + load_$id (); + } } ); }] } my render_richtext_as_div } elseif {[my set displayMode] eq "inline"} { if {!$is_repeat_template} { if {"xowikiimage" in [my extraPlugins]} { - set ready_callback "xowiki_image_callback(CKEDITOR.instances\['ckinline_$id'\]);" - set blur_callback "calc_image_tags_to_wiki_image_links_inline(e);" + set ready_callback "xowiki_image_callback(CKEDITOR.instances\['$id'\]);" + set submit_callback "calc_image_tags_to_wiki_image_links_inline('$id');" } - - ::xo::Page requireJS [subst -nocommands { + + set submit_callback "$submit_callback [my submit_callback]" + ::xo::Page requireJS [subst { function load_ckinline_$id () { - CKEDITOR.inline('ckinline_$id', { + CKEDITOR.inline('$id', { on: { - blur: function(e) { - $blur_callback + instanceReady: function(e) { + \$(e.editor.element.\$).attr('title', '[my set label]'); + \$(e.editor.element.\$.form).submit(function(e) { + $submit_callback + }); } }, $options }); } \$(document).ready(function() { - load_ckinline_$id (); + if (\$('#$id').parents('.repeatable').length != 0) { + if (\$('#$id').is(':visible')) { + load_ckinline_$id (); + } + } else { + //this is not inside a repeatable container, load normally + load_ckinline_$id (); + } $ready_callback - }); + }); }] } - my set style "display:none;" next - ::html::div "id ckinline_[my set id] name [my set name] class xowiki-ckeditor contenteditable true" { - ::html::t -disableOutputEscaping [my value] - } } else { if {!$is_repeat_template} { set callback [my callback] ::xo::Page requireJS [subst -nocommands { function load_$id () { \$( '#$id' ).ckeditor(function() { $callback }, { $options - }); + }); } \$(document).ready(function() { load_$id (); @@ -1999,8 +2048,8 @@ next } } - } - + } + ########################################################### # # ::xowiki::formfield::richtext::wym @@ -2043,7 +2092,7 @@ } } regsub -all {[.:]} [my id] {\\\\&} JID - + # possible skins are per in the distribution: "default", "sliver", "minimal" and "twopanels" set config [list "skin: '[my skin]'"] @@ -2070,7 +2119,7 @@ jQuery("#$JID").wymeditor($config); }); }] - + next } } @@ -2092,13 +2141,13 @@ richtext::xinha set editor_mixin 1 richtext::xinha instproc initialize {} { switch -- [my set displayMode] { - inplace { + inplace { ::xo::Page requireJS "/resources/xowiki/xinha-inplace.js" if {![info exists ::__xinha_inplace_init_done]} { template::add_body_handler -event onload -script "xinha.inplace.init();" - set ::__xinha_inplace_init_done 1 + set ::__xinha_inplace_init_done 1 } - } + } inline { error "inline is not supported for xinha"} } @@ -2111,18 +2160,18 @@ -package_key "acs-templating" -parameter "XinhaDefaultPlugins"]] } my set options [my get_attributes editor plugins width height folder_id script_dir javascript wiki_p] - # for the time being, we can't set the defaults via parameter, + # for the time being, we can't set the defaults via parameter, # but only manually, since the editor is used as a mixin, the parameter # would have precedence over the defaults of subclasses - if {![my exists slim]} {my set slim false} + if {![my exists slim]} {my set slim false} if {![my exists style]} {my set style "width: 100%;"} if {![my exists height]} {my set height 350px} if {![my exists wiki_p]} {my set wiki_p 1} if {[my set slim]} { my lappend options javascript { - xinha_config.toolbar = [['popupeditor', 'formatblock', 'bold','italic','createlink','insertimage'], + xinha_config.toolbar = [['popupeditor', 'formatblock', 'bold','italic','createlink','insertimage'], ['separator','insertorderedlist','insertunorderedlist','outdent','indent'], - ['separator','killword','removeformat','htmlmode'] + ['separator','killword','removeformat','htmlmode'] ]; } } @@ -2133,13 +2182,13 @@ if {![my istype ::xowiki::formfield::richtext] || $disabled} { my render_richtext_as_div } else { - # we use for the time being the initialization of xinha based on + # we use for the time being the initialization of xinha based on # the site master set ::acs_blank_master(xinha) 1 set quoted [list] foreach e [my plugins] {lappend quoted '$e'} set ::acs_blank_master(xinha.plugins) [join $quoted ", "] - + array set o [my set options] set xinha_options "" foreach e {width height folder_id fs_package_id file_types attach_parent_id wiki_p package_id} { @@ -2244,7 +2293,7 @@ set package_id [[my object] package_id] set tree_ids [::xowiki::Category get_mapped_trees -object_id $package_id -locale [my locale] \ -names $tree_name -output tree_id] - + # In case there are multiple trees with the same name, # take the first one. # @@ -2255,7 +2304,7 @@ return } set subtree_id "" - set options [list] + set options [list] foreach category [::xowiki::Category get_category_infos \ -subtree_id $subtree_id -tree_id $tree_id] { @@ -2407,7 +2456,7 @@ ::xowiki::Includelet require_YUI_JS -ajaxhelper $ajaxhelper "utilities/utilities.js" ::xowiki::Includelet require_YUI_JS -ajaxhelper $ajaxhelper "selector/selector-min.js" ::xo::Page requireJS "/resources/xowiki/yui-selection-area.js" - + set js "" foreach o [my options] { lassign $o label rep @@ -2416,9 +2465,9 @@ append js "YAHOO.xo_sel_area.DDApp.values\['$js_label'\] = '$js_rep';\n" append js "YAHOO.xo_sel_area.DDApp.dict\['$js_rep'\] = '$js_label';\n" } - + ::html::div -class workarea { - ::html::h3 { ::html::t "Selection"} + ::html::h3 { ::html::t "#xowiki.Selection#"} set values "" foreach v [my value] { append values $v \n @@ -2427,14 +2476,14 @@ my CSSclass selection my set cols 30 set atts [my get_attributes id name disabled {CSSclass class}] - + # TODO what todo with DISABLED? ::html::textarea [my get_attributes id name cols rows style {CSSclass class} disabled] { ::html::t $values } } ::html::div -class workarea { - ::html::h3 { ::html::t "Candidates"} + ::html::h3 { ::html::t "#xowiki.Candidates#"} ::html::ul -id [my id]_candidates -class region { #my msg [my options] foreach o [my options] { @@ -2472,7 +2521,7 @@ #my compute_options next } - + abstract_page instproc fetch_entry_label {entry_label item_id} { # The following is a temporary solution, only working with cr-item attributes # We should support as well user level instance attributes. @@ -2490,7 +2539,7 @@ } return "" } - + abstract_page instproc pretty_value {v} { my instvar package_id set object [my object] @@ -2522,7 +2571,7 @@ #my log "comparing '$value' with '$v'" if {$value eq $v} { if {[my as_box]} { - return [$object include [list $value -decoration rightbox]] + return [$object include [list $value -decoration rightbox]] } set href [$package_id pretty_link -parent_id $parent_id $value] return "$label" @@ -2560,7 +2609,7 @@ #set form_obj [[my object] resolve_included_page_name $form_name] if {$form_objs eq ""} {error "Cannot lookup Form '$form_name'"} - + set form_object_item_ids [list] foreach form_obj $form_objs {lappend form_object_item_ids [$form_obj item_id]} } @@ -2570,7 +2619,7 @@ if {![my exists form]} { return } - + array set wc {tcl true h "" vars "" sql ""} if {[info exists where]} { array set wc [::xowiki::FormPage filter_expression $where &&] @@ -2705,9 +2754,9 @@ Class create HH24 -superclass select HH24 instproc initialize {} { my options { - {00 0} {01 1} {02 2} {03 3} {04 4} {05 5} {06 6} {07 7} {08 8} {09 9} - {10 10} {11 11} {12 12} {13 13} {14 14} {15 15} {16 16} {17 17} {18 18} {19 19} - {20 20} {21 21} {22 22} {23 23} + {00 0} {01 1} {02 2} {03 3} {04 4} {05 5} {06 6} {07 7} {08 8} {09 9} + {10 10} {11 11} {12 12} {13 13} {14 14} {15 15} {16 16} {17 17} {18 18} {19 19} + {20 20} {21 21} {22 22} {23 23} } next } @@ -2730,7 +2779,7 @@ } MI instproc initialize {} { my options { - {00 0} {05 5} {10 10} {15 15} {20 20} {25 25} + {00 0} {05 5} {10 10} {15 15} {20 20} {25 25} {30 30} {35 35} {40 40} {45 45} {50 50} {55 55} } next @@ -2746,7 +2795,7 @@ MM instproc initialize {} { my options { {01 1} {02 2} {03 3} {04 4} {05 5} {06 6} {07 7} {08 8} {09 9} {10 10} - {11 11} {12 12} + {11 11} {12 12} } next } @@ -2812,7 +2861,7 @@ ########################################################### Class create youtube_url -superclass text youtube_url set urlre {^http://www.youtube.com/watch[?]v=([^?]+)([?]?)} - + youtube_url instproc initialize {} { next if {[my help_text] eq ""} {my help_text "#xowiki.formfield-youtube_url-help_text#"} @@ -2841,7 +2890,7 @@ -extend_slot_default validator image_check \ -parameter { href cssclass - {float left} width height + {float left} width height padding {padding-right 10px} padding-left padding-top padding-bottom margin margin-left margin-right margin-top margin-bottom border border-width position top botton left right @@ -2874,7 +2923,7 @@ if {[regexp {^file://(.*)$} $value _ path]} { set f [open $path r] fconfigure $f translation binary - set img [read $f] + set img [read $f] close $f } elseif {[catch { set r [::xo::HttpRequest new -url $value -volatile] @@ -2929,7 +2978,7 @@ return "Cannot resolve symbolic link '$v'" } set link_type [$object get_property_from_link_page link_type] - $object lappend references [list $item_id $link_type] + $object references resolved [list $item_id $link_type] # # resetting esp. the item-id is dangerous. Therefore we reset it immediately after the rendering @@ -3011,7 +3060,7 @@ foreach {n1 value1} $v1 {n2 value2} $v2 { set f [my set component_index($n1)] if {![$f same_value $value1 $value2]} { return 0 } - } + } return 1 } @@ -3053,7 +3102,7 @@ } } } - + CompoundField instproc get_compound_value {} { # Set the internal representation based on the components values. set value [list] @@ -3166,18 +3215,37 @@ } } + CompoundField instproc pretty_value {v} { + # + # Typically, subtypes of CompoundFields should define their own + # "pretty_value". This is a simple renderer that provides a + # default behavior. + # + set ff [dict create {*}$v] + set html "\n" + return $html + } + CompoundField instproc has_instance_variable {var value} { set r [next] if {$r} {return 1} - foreach c [my components] { + foreach c [my components] { set r [$c has_instance_variable $var $value] if {$r} {return 1} } return 0 } CompoundField instproc convert_to_internal {} { - foreach c [my components] { + foreach c [my components] { $c convert_to_internal } # Finally, update the compound value entry with the compound @@ -3294,7 +3362,7 @@ -name [my name].$name -id [my id].$name \ -locale [my locale] -object [my object] \ -value $element] - $c set_disabled [my exists disabled] + $c set_disabled 1; # this is a dummy field, never query for its value if {$c ni [my components]} {my lappend components $c} continue } @@ -3322,7 +3390,7 @@ # instances of this class can be used as flyweight # objects. Otherwise, we get side-effects when # we render the input widget. - foreach c [my components] { + foreach c [my components] { $c value "" } return @@ -3357,7 +3425,7 @@ $c value $value_part } } - + date instproc get_compound_value {} { # Set the internal representation of the date based on the components values. # Internally, the ansi date format is used. @@ -3383,12 +3451,12 @@ #my msg "$year-$month-$day ${hour}:${min}:${sec}" if {[catch {set ticks [clock scan "$year-$month-$day ${hour}:${min}:${sec}"]}]} { set ticks 0 ;# we assume that the validator flags these values - } + } # TODO: TZ??? #my msg "DATE [my name] get_compound_value returns [clock format $ticks -format {%Y-%m-%d %T}]" return [clock format $ticks -format "%Y-%m-%d %T"] } - + date instproc same_value {v1 v2} { if {$v1 eq $v2} {return 1} return 0 @@ -3397,7 +3465,7 @@ date instproc pretty_value {v} { my instvar display_format # - # Internally, we use the ansi date format. For displaying the date, + # Internally, we use the ansi date format. For displaying the date, # use the specified display format and present the time localized. # # Drop of the value after the "." we assume to have a date in the local zone @@ -3446,7 +3514,7 @@ ########################################################### Class create boolean_image -superclass FormField -parameter { - {default t} + {default t} {t_img_url /resources/xowiki/examples/check_richtig.png} {f_img_url /resources/xowiki/examples/check_falsch.png} {CSSclass img_boolean} @@ -3468,7 +3536,7 @@ ::xo::Page requireJS { function toggle_img_boolean (element,t_img_url,f_img_url) { var input = $(element).next(); - var state = input.val()== "t"; + var state = input.val()== "t"; if (state) { input.val('f'); $(element).attr('src',f_img_url); @@ -3534,14 +3602,21 @@ # # ::xowiki::formfield::event # + # This formfield is rendered following the conventions of the + # h-event of microformats2. + # + # See: http://microformats.org/wiki/h-event + # ########################################################### Class create event -superclass CompoundField -parameter { {multiday false} + {calendar} + {time_label #xowiki.event-time#} } event instproc initialize {} { - #my msg "event initialize [my exists __initialized], multi=[my multiday] state=[my set __state]" + #my log "event initialize [my exists __initialized], multi=[my multiday] state=[my set __state]" if {[my set __state] ne "after_specs"} return my set widget_type event if {[my multiday]} { @@ -3552,11 +3627,13 @@ set dtend_display_format %X } my create_components [subst { - {summary {richtext,required,editor=wym,height=150px,label=#xowiki.event-title_of_event#}} - {dtstart {date,required,format=DD_MONTH_YYYY_#xowiki.event-hour_prefix#_HH24_MI, + {title {text,label=#xowiki.event-title_of_event#}} + {summary {richtext,height=150px,label=#xowiki.event-summary_of_event#}} + {dtstart {date,required,format=DD_MONTH_YYYY_#xowiki.event-hourprefix#_HH24_MI, default=now,label=#xowiki.event-start_of_event#,display_format=%Q_%X}} {dtend date,format=$dtend_format,default=now,label=#xowiki.event-end_of_event#,display_format=$dtend_display_format} {location text,label=#xowiki.event-location#} + {cal_item_id hidden} }] my set __initialized 1 } @@ -3579,20 +3656,31 @@ } event instproc pretty_value {v} { - array set {} [my value] + #array set {} [my value] set dtstart [my get_component dtstart] set dtstart_val [$dtstart value] set dtstart_iso [::xo::ical clock_to_iso [clock scan $dtstart_val]] + set dtstart_pretty [$dtstart pretty_value $dtstart_val] set dtend [my get_component dtend] set dtend_val [$dtend value] set dtend_txt "" if {$dtend_val ne ""} { set dtend_iso [::xo::ical clock_to_iso [clock scan $dtend_val]] - set dtend_txt " - [$dtend pretty_value $dtend_val]" + set dtend_txt " - " } - set summary_txt "[[my get_component summary] value]" + set time_label [my time_label] + if {[regexp {^#(.+)#$} $time_label _ msg_key]} { + set time_label [lang::message::lookup [my locale] $msg_key] + } + + set title_val [[my get_component title] value] + if {$title_val eq ""} { + set title_val [[my object] property _title] + } + set summary_val [[my get_component summary] value] + set location [my get_component location] set location_val [$location value] set location_txt "" @@ -3601,18 +3689,105 @@ if {[regexp {^#(.+)#$} $location_label _ msg_key]} { set location_label [lang::message::lookup [my locale] $msg_key] } - set location_txt "$location_label: $location_val" + set location_txt "$location_label:$location_val" } - append result \ - "
" \ - $summary_txt " " \ - "[$dtstart pretty_value $dtstart_val]" \ - $dtend_txt
\ - $location_txt \ - "
" + append result \n\ + "
" \n\ + "

$title_val

" \n\ + "

$summary_val

" "
" \n\ + "" \n\ + "" \n\ + $location_txt \n\ + "
$time_label: $dtend_txt
" \n\ + "
" \n return $result } + + event instproc convert_to_internal {} { + if {[my exists calendar]} { + # + # Check, if the calendar package is available + # + if {[info commands ::calendar::item::new] eq ""} { + error "the calendar package is not available" + } + + # + # Check, if the calendar_id can be determined + # + set calendar_id "" + if {[string is integer -strict [my calendar]]} { + set calendar_id [my calendar] + if {[calendar::name $calendar_id] eq ""} { + set calendar_id "" + } + } + if {$calendar_id eq ""} { + error "calendar '[my calendar] has no valid calendar_id" + } + + # + # Get the values for the calendar item + # + set dtstart_val [[my get_component dtstart] value] + set dtend_val [[my get_component dtend] value] + set title_val [[my get_component title] value] + set title_val [[my get_component title] value] + set summary_val [[my get_component summary] value] + set cal_item_id [[my get_component cal_item_id] value] + + # + # Check, if the cal_item_id is valid. If not, ignore it + # + if {$cal_item_id ne ""} { + # if the object does not exist, it was probably deleted manually + if {![acs_object::object_p -id $cal_item_id]} { + set cal_item_id "" + } else { + acs_object::get -object_id $cal_item_id -array row + if {$row(object_type) ne "cal_item"} { + ns_log warning "event: the associated entry $cal_item_id is not a calendar item, ignore the old association" + set cal_item_id "" + } + } + } + + # + # update values via transaction queue + # + set queue ::__xowiki__transaction_queue([[my object] item_id]) + lappend $queue [list [self] update_calendar -cal_item_id $cal_item_id -calendar_id $calendar_id \ + -start $dtstart_val -end $dtend_val -name $title_val -description $summary_val] + } + + next + } + + event instproc update_calendar {-cal_item_id -calendar_id -start -end -name -description} { + # + # If we have already a valid cal_item_id (checked previously) + # update the entry. Otherwise create a new calender item and + # update the instance variables. + # + if {$cal_item_id ne ""} { + #my log "===== [list calendar::item::edit -start_date $start -end_date $end -cal_item_id $cal_item_id ...]" + calendar::item::edit -cal_item_id $cal_item_id -start_date $start \ + -end_date $end -name $name -description $description + } else { + #my log "===== [list calendar::item::new -start_date $start -end_date $end -calendar_id $calendar_id ...]" + set cal_item_id [calendar::item::new -start_date $start -end_date $end \ + -name $name -description $description -calendar_id $calendar_id] + [my get_component cal_item_id] value $cal_item_id + # + # The following line is required when used in transaction to + # update the instance attributes + # + [my object] set_property event [my get_compound_value] + } + } + + } namespace eval ::xowiki::formfield { @@ -3636,7 +3811,7 @@ } } -::xo::library source_dependent +::xo::library source_dependent # # Local variables: