ad_library { Rich text input widget and datatype for OpenACS templating system. @author Lars Pind (lars@pinds.com) @creation-date 2003-01-27 } namespace eval template {} namespace eval template::data {} namespace eval template::data::transform {} namespace eval template::data::validate {} namespace eval template::util {} namespace eval template::util::richtext {} namespace eval template::widget {} namespace eval template::data::to_sql {} namespace eval template::data::from_sql {} ad_proc -public template::util::richtext { command args } { Dispatch procedure for the richtext object } { template::util::richtext::$command {*}$args } ad_proc -public template::util::richtext::create { {contents {}} {format {}} } { Create a richtext widget @param contents The text content of the widget @param format How that text is formatted (text, html, etc) @return Two-element list of the joined parameters } { return [list $contents $format] } ad_proc -public template::util::richtext::acquire { type { value "" } } { Create a new richtext value with some predefined value Basically, create and set the richtext value } { set richtext_list [template::util::richtext::create] return [template::util::richtext::set_property $type $richtext_list $value] } ad_proc -public template::util::richtext::formats {} { Returns a list of valid richtext formats } { return { text/enhanced text/markdown text/plain text/html text/fixed-width } } ad_proc -public template::util::richtext::format_options {} { Returns a formatting option list } { return [list \ [list [_ acs-templating.Enhanced_Text] text/enhanced] \ [list [_ acs-templating.Markdown_Text] text/markdown] \ [list [_ acs-templating.Plain_Text] text/plain] \ [list [_ acs-templating.Fixed_width_Text] text/fixed-width] \ [list [_ acs-templating.HTML] text/html]] } ad_proc -public template::data::validate::richtext { value_ref message_ref } { Validate richtext after form submission. @param value_ref Reference variable to the submitted value @param message_ref Reference variable for returning an error message @return True (1) if the submitted data is valid, false (0) if not } { upvar 2 $message_ref message $value_ref richtext_list lassign $richtext_list contents format 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 { $format in { text/enhanced text/html } } { set check_result [ad_html_security_check $contents] if { $check_result ne "" } { set message $check_result return 0 } } return 1 } ad_proc -public template::data::transform::richtext { element_ref } { Transform the previously-validated submitted data into a two-element list as defined by the richtext datatype. @param element_ref Reference variable to the form element @return Two-element list defined by the richtext datatype } { upvar $element_ref element set element_id $element(id) set contents [ns_queryget $element_id] set format [ns_queryget $element_id.format] if { $contents eq "" } { # We need to return the empty list in order for form builder to think of it # as a non-value in case of a required element. return [list] } else { return [list [list $contents $format]] } } ad_proc -public template::util::richtext::set_property { what richtext_list value } { Set a property of the richtext datatype. @param what One of
Implements the richtext widget, which offers rich text editing options. This version integrates support for the xinha and tinymce editors out of the box, but other richtext editors can be used including and configuring them in your custom template. If the acs-templating.UseHtmlAreaForRichtextP parameter is set to true (1), this will use the WYSIWYG editor widget set in the acs-templating.RichTextEditor parameter. Otherwise, it will use a normal textarea, with a drop-down to select a format. The available formats are:
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 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 specifying 'editor xinha' in the options of the widget spec. The following options for xinha may be specified:
GetHtml CharacterMap ContextMenu FullScreen
ListType TableOperations EditTag LangMarks Abbreviation
These options are used by the OacsFs plugin
xinha_config
.
Example to use xinha with only a few controls:
{options {editor xinha plugins {OacsFs} height 350px javascript { xinha_config.toolbar = [ ['popupeditor', 'bold','italic','createlink','insertimage','separator'], ['killword','removeformat'] ]; }}}
Example for the use of the xinha widget with options:
text:richtext(richtext),nospell,optional {label #xowiki.content#} {options {editor xinha plugins OacsFs height 350px file_types %pdf%}} {html {rows 15 cols 50 style {width: 100%}}}
Caveat: the three adp-files needed for the OpenACS file selector (insert-image, insert-ilink and file-selector) are currently part of the xowiki package, since acs-templating is per default not mounted. This is hopefully only a temporal situation and we find a better place.
Example for the use of the tinymce widget with options:
text:richtext(richtext),nospell,optional {label #acs-subsite.Biography#} {options {theme simple plugins "oacsimage,oacslink,style"}} {html {rows 15 cols 50 style {width: 100%}}}
See TinyMCE documentation for a full list of available options
Caveat: the scripts needed for the oacsimage and oacslink plugins require acs-templating to be mounted. This is a temporary situation until we find a better way to handle plugins.
Example for the use of a custom editor widget:
text:richtext(richtext),nospell,optional {label #acs-subsite.Biography#} {options {editor custom ...custom configuration...}} {html {rows 15 cols 50 style {width: 100%}}}
If provided with a WYSIWYG editor different than 'xinha' or 'tinymce', system will just collect formfield ids and supplied options for the richtext field and will provide them as-is to the blank-master environment. When using a custom editor, funcional meaning of the options is totally up to the user.
Note that the richtext editors interact with blank-master.tcl
and
blank-master.adp
.
Derived from the htmlarea richtext widget for htmlarea by lars@pinds.com
modified for RTE http://www.kevinroth.com/ by davis@xarg.net
xinha and ckeditor4 support by gustaf.neumann@wu-wien.ac.at
tinymce support by oct@openacs.org
} {
upvar $element_reference element
set output ""
#ns_log notice "widget::richtext: richtext-options? [info exists element(options)] HTML? [info exists element(html)]"
if { [info exists element(html)] } {
array set attributes $element(html)
}
array set attributes $tag_attributes
if { [info exists element(value)] } {
set contents [template::util::richtext::get_property contents $element(value)]
set format [template::util::richtext::get_property format $element(value)]
} else {
set contents {}
set format {}
}
array set options [expr {[info exists element(options)] ? $element(options) : ""}]
if { $element(mode) eq "edit" } {
set attributes(id) $element(id)
set package_id_templating [apm_package_id_from_key "acs-templating"]
set user_agent [string tolower [ns_set get [ns_conn headers] User-Agent]]
if {[string first "safari" $user_agent] != -1} {
if {[regexp {version/([0-9]+)[.]} $user_agent _ user_agent_version]
&& $user_agent_version < 3} {
set element(htmlarea_p) false
}
} elseif {[string first "opera" $user_agent] != -1} {
if {[regexp {^[^/]+/([0-9]+)[.]} $user_agent _ user_agent_version]
&& $user_agent_version < 9} {
set element(htmlarea_p) false
}
}
if { [info exists element(htmlarea_p)] && $element(htmlarea_p) ne "" } {
set htmlarea_p [template::util::is_true $element(htmlarea_p)]
} else {
set htmlarea_p [parameter::get \
-package_id $package_id_templating \
-parameter "UseHtmlAreaForRichtextP" \
-default 0]
}
set edit_item_tag [::template::util::richtext::get_tag -options [array get options]]
set format_menu [menu $element(id).format [template::util::richtext::format_options] $format {}]
set output [textarea_internal $element(id) attributes $contents "edit" $edit_item_tag]
# Spell-checker
array set spellcheck [template::util::spellcheck::spellcheck_properties \
-element_ref element]
#ns_log notice "widget::richtext: $htmlarea_p, spellcheck [array get spellcheck] OPTIONS [array get options]"
if { $htmlarea_p } {
# figure out, which rich text editor to use
set richtextEditor [expr {[info exists options(editor)] ?
$options(editor) : [parameter::get \
-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)
#
# 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 "widget::richtext: ::template::util::richtext::initialize_widget -> $result"
if {[dict get $result success] == 1} {
#
# 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.
#
} else {
# 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]
}
#
# The following trick with document.write is for providing
# reasonable behavior when JavaScript is turned completely
# off.
#
append output \
"\n\n\n" \
""
if { $spellcheck(render_p) } {
append output [subst {