Index: openacs-4/packages/acs-templating/acs-templating.info =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/acs-templating.info,v diff -u -r1.56.2.10 -r1.56.2.11 --- openacs-4/packages/acs-templating/acs-templating.info 17 Dec 2015 19:57:07 -0000 1.56.2.10 +++ openacs-4/packages/acs-templating/acs-templating.info 3 Jan 2016 21:25:40 -0000 1.56.2.11 @@ -9,7 +9,7 @@ f t - + OpenACS Templating library. 2015-10-04 @@ -27,7 +27,7 @@ GPL version 2 3 - + Index: openacs-4/packages/acs-templating/tcl/richtext-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/tcl/richtext-procs.tcl,v diff -u -r1.52.2.8 -r1.52.2.9 --- openacs-4/packages/acs-templating/tcl/richtext-procs.tcl 7 Oct 2015 08:44:39 -0000 1.52.2.8 +++ openacs-4/packages/acs-templating/tcl/richtext-procs.tcl 3 Jan 2016 21:25:40 -0000 1.52.2.9 @@ -73,17 +73,15 @@ } { upvar 2 $message_ref message $value_ref richtext_list + lassign $richtext_list contents format - set contents [lindex $richtext_list 0] - set format [lindex $richtext_list 1] - if { $contents ne "" && [lsearch -exact [template::util::richtext::formats] $format] == -1 } { set message "Invalid format, '$format'." return 0 } # enhanced text and HTML needs to be security checked - if { [lsearch { text/enhanced text/html } $format] != -1 } { + if { $format in { text/enhanced text/html } } { set check_result [ad_html_security_check $contents] if { $check_result ne "" } { @@ -260,36 +258,107 @@ if { $htmlarea_p } { # Tell the blank-master to include the special stuff for htmlArea in the page header - global acs_blank_master__htmlareas - lappend acs_blank_master__htmlareas $attributes(id) + lappend ::acs_blank_master__htmlareas $attributes(id) } - append output [textarea_internal "$element(id)" attributes $contents] + append output [textarea_internal $element(id) attributes $contents] if { $htmlarea_p } { - append output "" + append output [subst {}] } else { - append output "
[_ acs-templating.Format]: [menu $element(id).format [template::util::richtext::format_options] $format attributes]" + append output \ + [subst {
[_ acs-templating.Format]:}] \ + [menu $element(id).format [template::util::richtext::format_options] $format attributes] } # Spell-checker array set spellcheck [template::util::spellcheck::spellcheck_properties -element_ref element] if { $spellcheck(render_p) } { - append output " [_ acs-templating.Spellcheck]: [menu "$element(id).spellcheck" [nsv_get spellchecker lang_options] $spellcheck(selected_option) attributes]" + append output \ + [subst { [_ acs-templating.Spellcheck]: }] \ + [menu "$element(id).spellcheck" [nsv_get spellchecker lang_options] \ + $spellcheck(selected_option) attributes] } } else { # Display mode if { [info exists element(value)] } { - append output [template::util::richtext::get_property html_value $element(value)] - append output "" - append output "" + append output \ + [template::util::richtext::get_property html_value $element(value)] \ + [subst {}] \ + [subst {}] } } return $output } +# ---------------------------------------------------------------------- +# +# Richtext plugin interface +# +# ---------------------------------------------------------------------- +ad_proc -public template::util::richtext::initialize_widget { + -form_id + -text_id + -editor + {-options {}} +} { + + Initialize a single text input (textarea with the id "text_id" + part of a form with "form_id") for the specified richtext editor + via a richtext-editor plugin (e.g. ckeditor4, tinymce, or xinha) + + @param form_id ID of the form containing the textarea + @param text_id ID of the textarea + @param editor Editor, which should be used + @param options Options passed in from the widget spec + + @return On success, this function returns a dict with success 1 + +} { + if {$editor ni $::template::util::richtext::editors} { + ns_log warning "richtext: no editor with name $editor is registered" + return {success 0} + } + + set result {success 1} + lappend result {*}[::richtext-${editor}::initialize_widget \ + -form_id $form_id \ + -text_id $text_id \ + -options $options] + return $result +} + +ad_proc -public template::util::richtext::register_editor { editor } { + + Make an rich-text editor known to the templating system. + + @param editor Editor to be registered + @return List of editors registered so far + +} { + lappend ::template::util::richtext::editors $editor +} + +ad_proc -public template::util::richtext::render_widgets { } { + + Render all rich-text editors with their their widget spefic + code. Every editor might have multiple instances on the page, + which are accessible to "render_widgets" via the global variable + acs_blank_master__htmlareas. This function can be used to perform + a single (customization) operation relevant for multiple widgets. + +} { + + ns_log debug "we have the following editors registered: $::template::util::richtext::editors" + + foreach editor $::template::util::richtext::editors { + ::richtext-${editor}::render_widgets + } +} + + ad_proc -public template::widget::richtext { element_reference tag_attributes } {

@@ -319,9 +388,11 @@ You can also parameterize the richtext widget with a 'htmlarea_p' attribute, which can be true or false, and which will override the parameter setting.

- The available integrated editors in wysigwig mode are xinha and tinymce. In - order to use xinha, one has to use 'editor xinha' in the options of the form - field. The following options for xinha may be specified: + The richtext widget can be extended with several plugins, which are OpenACS + packages named richtex-EDITOR. Plugins are available e.g. for xinha, tinymce + and ckeditor4. When the plugins are installed, one can use e.g. xinha + by sepcifying 'editor xinha' in the options of the widget spec. + The following options for xinha may be specified:

  • editor: xinha
  • height: height of the xinha widget (e.g. 350px) @@ -418,7 +489,7 @@

    Derived from the htmlarea richtext widget for htmlarea by lars@pinds.com
    modified for RTE http://www.kevinroth.com/ by davis@xarg.net
    - xinha support by gustaf.neumann@wu-wien.ac.at
    + xinha and ckeditor4 support by gustaf.neumann@wu-wien.ac.at
    tinymce support by oct@openacs.org } { @@ -482,150 +553,39 @@ -package_id $package_id_templating \ -parameter "RichTextEditor" \ -default "xinha"]}] + # # Tell the blank-master to include the special stuff # for the richtext widget in the page header + # set ::acs_blank_master($richtextEditor) 1 - + + # # Collect ids of richtext form fields + # lappend ::acs_blank_master__htmlareas $attributes(id) - set postTextArea "" - - if {$richtextEditor eq "xinha"} { - # Xinha is integrated in OpenACS: - # build speific javascript configurations from - # widget options and system parameters + # + # Try to initialize the widget via richtext plugins + # + set result [::template::util::richtext::initialize_widget \ + -form_id $element(form_id) \ + -text_id $attributes(id) \ + -editor $richtextEditor \ + -options [array get options]] + ns_log debug "::template::util::richtext::initialize_widget -> $result" + + if {[dict get $result success] == 1} { # - # The richtext widget is specified by "options {editor xinha}" - # The following options are supported: - # editor plugins width height folder_id fs_package_id + # Everything is set-up via the editor plugin. In + # general, we can pass back more information back from + # the plugins via the dict "result" without extending + # the interface, but that feature is not used yet. # - if {[info exists options(plugins)]} { - set plugins $options(plugins) - } else { - set plugins [parameter::get \ - -package_id $package_id_templating \ - -parameter "XinhaDefaultPlugins" \ - -default ""] - - # GetHtml CharacterMap ContextMenu FullScreen - # ListType TableOperations EditTag LangMarks Abbreviation - } - set quoted [list] - foreach e $plugins {lappend quoted '$e'} - set ::acs_blank_master(xinha.plugins) [join $quoted ", "] - - set xinha_options "" - foreach e {width height folder_id fs_package_id script_dir file_types attach_parent_id wiki_p} { - if {[info exists options($e)]} { - append xinha_options "xinha_config.$e = '$options($e)';\n" - } - } - append xinha_options "xinha_config.package_id = '[ad_conn package_id]';\n" - # DAVEB find out if there is a key datatype in the form - - if {[info exists ::af_key_name(${element(form_id)})]} { - append xinha_options "xinha_config.key = '[template::element get_value $element(form_id) $::af_key_name(${element(form_id)})]';\n" - } - if {[info exists options(javascript)]} { - append xinha_options $options(javascript) \n - } - set ::acs_blank_master(xinha.options) $xinha_options - - } elseif {$richtextEditor eq "tinymce"} { - - # TinyMCE is integrated in OpenACS: - # build speific javascript configurations from - # widget options and system parameters - - # get default configs - set tinymce_default_config { - {mode "exact" } - {relative_urls "false"} - {height "450px" } - {width "100%"} - {plugins "style,layer,table,save,iespell,preview,media,searchreplace,print,contextmenu,paste,fullscreen,noneditable,visualchars,xhtmlxtras" } - {browsers "msie,gecko,safari,opera" } - {apply_source_formatting "true" } - {paste_auto_cleanup_on_paste true} - {paste_convert_headers_to_strong true} - {fix_list_elements true} - {fix_table_elements true} - {theme "openacs"} - {theme_openacs_toolbar_location "top" } - {theme_openacs_toolbar_align "left" } - {theme_openacs_statusbar_location "bottom" } - {theme_openacs_resizing true} - {theme_openacs_disable "styleselect"} - {theme_openacs_buttons1_add_before "save,separator"} - {theme_openacs_buttons2_add "separator,preview,separator,forecolor,backcolor"} - {theme_openacs_buttons2_add_before "cut,copy,paste,pastetext,pasteword,separator,search,replace,separator"} - {theme_openacs_buttons3_add_before "tablecontrols,separator"} - {theme_openacs_buttons3_add "iespell,media,separator,print,separator,fullscreen"} - {extended_valid_elements "img[id|class|style|title|lang|onmouseover|onmouseout|src|alt|name|width|height],hr[id|class|style|title],span[id|class|style|title|lang]"} - {element_format "html"}} - set tinymce_configs_list [parameter::get \ - -package_id [apm_package_id_from_key "acs-templating"] \ - -parameter "TinyMCEDefaultConfig" \ - -default $tinymce_default_config] - set pairslist [list] - ns_log debug "tinymce: options [array get options]" - - foreach config_pair $tinymce_configs_list { - set config_key [lindex $config_pair 0] - if {[info exists options($config_key)]} { - # override default values with individual - # widget specification - set config_value $options($config_key) - unset options($config_key) - } else { - set config_value [lindex $config_pair 1] - } - ns_log debug "tinymce: key $config_key value $config_value" - if {$config_value eq "true" || $config_value eq "false"} { - lappend pairslist "${config_key}:${config_value}" - } else { - lappend pairslist "${config_key}:\"${config_value}\"" - } - } - - foreach name [array names options] { - ns_log debug "tinymce: NAME $name" - # add any additional options not specified in the - # default config - lappend pairslist "${name}:\"$options($name)\"" - } - - lappend pairslist "elements : \"[join $::acs_blank_master__htmlareas ","]\"" - set tinymce_configs_js [join $pairslist ","] - set ::acs_blank_master(tinymce.config) $tinymce_configs_js - - } elseif {$richtextEditor eq "ckeditor4"} { - # Editor is ckeditor4 - - # handled options: plugins skin customConfig - set ckOptionsList {} - if {[info exists options(plugins)]} { - lappend ckOptionsList "extraPlugins: '$options(plugins)'" - } - if {[info exists options(skin)]} { - lappend ckOptionsList "skin: '$options(skin)'" - } - if {[info exists options(customConfig)]} { - lappend ckOptionsList "customConfig: '$options(customConfig)'" - } - - set ckOptions [join $ckOptionsList ", "] - append postTextArea [subst { - - }] - } else { - # Editor is custom. - # Options will be passed as-is to the blank master - # and their meaning will be defined in the template - + # Editor is custom. All options are passed as-is to + # the blank master and their meaning will be defined + # in a custom template. + set ::acs_blank_master(${richtextEditor}.options) [array get options] } @@ -635,7 +595,7 @@ "\n

    " \ [subst {}] \ $format_menu "
    \n" \ - $postTextArea "" + "" if { $spellcheck(render_p) } { append output [subst {