• Publicity: Public Only All

richtext-procs.tcl

Xinha integration with the richtext widget of acs-templating. This script defines the following two procs: ::richtext-xinha::initialize_widget ::richtext-xinha::render_widgets

Location:
packages/richtext-xinha/tcl/richtext-procs.tcl
Created:
1 Jan 2016
Author:
Gustaf Neumann
CVS Identification:
$Id: richtext-procs.tcl,v 1.4.2.9 2024/08/17 17:07:30 gustafn Exp $

Procedures in this file

Detailed information

richtext::xinha::add_editor (public)

 richtext::xinha::add_editor [ -conf conf ] [ -version version ] \
    [ -order order ]

Add the necessary JavaScript and other files to the current page. The naming is modeled after "add_script", "add_css", ... but is intended to care about everything necessary, including the content security policies. Similar naming conventions should be used for other editors as well. This function can be as well used from other packages, such e.g. from the xowiki form-fields, which provide a much higher customization.

Switches:
-conf (optional)
-version (optional)
-order (optional, defaults to "10")

Partial Call Graph (max 5 caller/called nodes):
%3 richtext::xinha::initialize_widget richtext::xinha::initialize_widget (public) richtext::xinha::add_editor richtext::xinha::add_editor richtext::xinha::initialize_widget->richtext::xinha::add_editor richtext::xinha::resource_info richtext::xinha::resource_info (public) richtext::xinha::add_editor->richtext::xinha::resource_info security::csp::require security::csp::require (public) richtext::xinha::add_editor->security::csp::require template::add_body_script template::add_body_script (public) richtext::xinha::add_editor->template::add_body_script

Testcases:
No testcase defined.

richtext::xinha::initialize_widget (public)

 richtext::xinha::initialize_widget [ -form_id form_id ] \
    [ -text_id text_id ] [ -options options ]

Initialize an Xinha richtext editor widget.

Switches:
-form_id (optional)
-text_id (optional)
-options (optional)

Partial Call Graph (max 5 caller/called nodes):
%3 _ _ (public) ad_conn ad_conn (public) lang::conn::language lang::conn::language (public) richtext::xinha::add_editor richtext::xinha::add_editor (public) template::element template::element (public) richtext::xinha::initialize_widget richtext::xinha::initialize_widget richtext::xinha::initialize_widget->_ richtext::xinha::initialize_widget->ad_conn richtext::xinha::initialize_widget->lang::conn::language richtext::xinha::initialize_widget->richtext::xinha::add_editor richtext::xinha::initialize_widget->template::element

Testcases:
No testcase defined.

richtext::xinha::render_widgets (public)

 richtext::xinha::render_widgets

Render the xinha rich-text widgets. This function is created at a time when all rich-text widgets of this page are already initialized. The function is controlled via the global variable ::acs_blank_master(xinha)

Partial Call Graph (max 5 caller/called nodes):
%3

Testcases:
No testcase defined.

richtext::xinha::resource_info (public)

 richtext::xinha::resource_info [ -version version ]

Get information about available version(s) of Xinha, either from the local filesystem, or from CDN.

Switches:
-version (optional)

Partial Call Graph (max 5 caller/called nodes):
%3 richtext::xinha::add_editor richtext::xinha::add_editor (public) richtext::xinha::resource_info richtext::xinha::resource_info richtext::xinha::add_editor->richtext::xinha::resource_info richtext::xinha::download richtext::xinha::download (private) richtext::xinha::download->richtext::xinha::resource_info acs_package_root_dir acs_package_root_dir (public) richtext::xinha::resource_info->acs_package_root_dir parameter::get_global_value parameter::get_global_value (public) richtext::xinha::resource_info->parameter::get_global_value

Testcases:
No testcase defined.
[ hide source ] | [ make this the default ]

Content File Source

ad_library {

    Xinha integration with the richtext widget of acs-templating.

    This script defines the following two procs:

       ::richtext-xinha::initialize_widget
       ::richtext-xinha::render_widgets

    @author Gustaf Neumann
    @creation-date 1 Jan 2016
    @cvs-id $Id: richtext-procs.tcl,v 1.4.2.9 2024/08/17 17:07:30 gustafn Exp $
}

namespace eval ::richtext::xinha {
    variable parameter_info

    #
    # The Xinha configuration can be tailored via the NaviServer
    # config file:
    #
    # ns_section ns/server/${server}/acs/richtext-xinha
    #        ns_param XinhaVersion   1.5.6
    #        ns_param StandardPlugins TableOperations
    #
     set parameter_info {
         package_key richtext-xinha
         parameter_name XinhaVersion
         default_value 1.5.6
     }

    set package_id [apm_package_id_from_key "richtext-xinha"]
    set ::richtext::xinha::standard_plugins [parameter::get \
                                                 -package_id $package_id \
                                                 -parameter XinhaDefaultPlugins \
                                                 -default ""]

    d_proc initialize_widget {
        -form_id
        -text_id
        {-options {}}
    } {
        Initialize an Xinha richtext editor widget.
    } {
        ns_log debug "initialize XINHA instance with <$options>"

        # The richtext widget might be specified by "options {editor
        # xinha}" or via the package parameter "RichTextEditor" of
        # acs-templating.
        #
        # The following options can be specified in the widget spec of
        # the richtext widget:
        #
        #      editor plugins width height folder_id fs_package_id
        #
        if {[dict exists $options plugins]} {
            set plugins [dict get $options plugins]
        } else {
            set plugins $::richtext::xinha::standard_plugins
        }

        set xinha_plugins [list]
        set oacs_plugins [list]
        foreach e $plugins {
            if {$e in {OacsFs OacsAttach}} {
                lappend oacs_plugins '$e'
            } else {
                lappend xinha_plugins '$e'
            }
        }
        if {[llength $oacs_plugins] > 0} {
            lappend xinha_plugins \
                [subst {{ from: '/resources/richtext-xinha/openacs-plugins', load: \[[join $oacs_plugins ,]\] }}]
        }
        set xinha_plugins [join $xinha_plugins ,]

        set xinha_options ""
        foreach e {width height folder_id fs_package_id script_dir file_types attach_parent_id wiki_p} {
            if {[dict exists $options $e]} {
                append xinha_options "xinha_config.$e = '[dict get $options $e]';\n"
            }
        }

        # DAVEB find out if there is a key datatype in the form.
        # We look for a key element in the form and use it e.g. as the
        # possible parent_id of a potential attachment.
        if {[info exists ::af_key_name($form_id)]} {
            set key [template::element get_value $form_id $::af_key_name($form_id)]
            append xinha_options "xinha_config.key = '$key';\n"
        }

        #
        # Pass as well the actual package_id to xinha (for e.g. plugins)
        #
        append xinha_options "xinha_config.package_id = '[ad_conn package_id]';\n"

        if {[dict exists $options javascript]} {
            append xinha_options [dict get $options javascript] \n
        }

        set editor_ids '[join [list $text_id {*}$::acs_blank_master__htmlareas"','"]'

        #
        # Add the configuration via body script
        #
        set conf [subst {
            xinha_options =
            {
                _editor_lang: "[lang::conn::language]",
                xinha_editors:  \[ $editor_ids \],
                xinha_plugins:  \[ $xinha_plugins \],
                xinha_config: function(xinha_config)
                {
                    $xinha_options
                }
            }
        }]

        #
        # Load the editor and everything necessary to the current page.
        #
        ::richtext::xinha::add_editor -conf $conf

        #
        # do we need render_widgets?
        #
        return ""
    }


    ad_proc render_widgets {} {

        Render the xinha rich-text widgets. This function is created
        at a time when all rich-text widgets of this page are already
        initialized. The function is controlled via the global
        variable ::acs_blank_master(xinha)

    } {
        #
        # In case no xinha instances are created, nothing has to be
        # done (i.e. the plain text area will be shown)
        #
        if {![info exists ::acs_blank_master(xinha)]} {
            return
        }
        #
        # Since "template::head::add_javascript -src ..." prevents
        # loading the same resource multiple times, we can perform the
        # load in the per-widget initialization and we are done here.
        #
    }

    d_proc ::richtext::xinha::resource_info {
        {-version ""}
    } {

        Get information about available version(s) of Xinha, either
        from the local filesystem, or from CDN.

    } {
        variable parameter_info

        #
        # If no version or Xinha package are specified, use the
        # configured version.
        #
        if {$version eq ""} {
            dict with parameter_info {
                set version [::parameter::get_global_value \
                                 -package_key $package_key \
                                 -parameter $parameter_name \
                                 -default $default_value]
            }
        }

        #
        # Setup variables for access via CDN vs. local resources.
        #
        set resourceDir [acs_package_root_dir richtext-xinha/www/resources]
        set cdn //s3-us-west-1.amazonaws.com/xinha

        if {[file exists $resourceDir/$version]} {
            set prefix  /resources/richtext-xinha/$version/xinha
            set cdnHost ""
        } else {
            set prefix $cdn/xinha-$version
            set cdnHost s3-us-west-1.amazonaws.com
        }

        #
        # Return the dict with at least the required fields
        #
        lappend result \
            resourceName "Xinha $version" \
            resourceDir $resourceDir \
            cdn $cdn \
            cdnHost $cdnHost \
            prefix $prefix \
            cssFiles {} \
            jsFiles  {} \
            extraFiles {} \
            downloadURLs https://s3-us-west-1.amazonaws.com/xinha/releases/xinha-$version.zip \
            cspMap {} \
            urnMap {} \
            parameterInfo $parameter_info \
            configuredVersion $version

        return $result
    }

    d_proc ::richtext::xinha::add_editor {
        {-conf ""}
        {-version ""}
        {-order 10}
    } {

        Add the necessary JavaScript and other files to the current
        page. The naming is modeled after "add_script""add_css",
        ... but is intended to care about everything necessary,
        including the content security policies. Similar naming
        conventions should be used for other editors as well.

        This function can be as well used from other packages, such
        e.g. from the xowiki form-fields, which provide a much higher
        customization.

    } {
        set resource_info [::richtext::xinha::resource_info -version $version]
        set version [dict $get resource_info configuredVersion]
        set prefix [dict get $resource_info prefix]

        if {[dict exists $resource_info cdnHost] && [dict get $resource_info cdnHost] ne ""} {
            security::csp::require connect-src [dict get $resource_info cdnHost]
            security::csp::require script-src  [dict get $resource_info cdnHost]
            security::csp::require style-src   [dict get $resource_info cdnHost]
            security::csp::require img-src     [dict get $resource_info cdnHost]
        }

        #
        # Add required general directives for content security policies.
        #
        security::csp::require script-src 'unsafe-eval'
        security::csp::require -force script-src 'unsafe-inline'

        template::add_body_script -src $prefix/XinhaEasy.js -script $conf
    }

    d_proc -private ::richtext::xinha::download {
        {-version ""}
    } {

        Download the Xinha package in the specified version and put
        it into a directory structure similar to the CDN structure to
        allow installation of multiple versions. When the local
        structure is available, it will be used by initialize_widget.

        Notice, that for this automated download, the "unzip" program
        must be installed and $::acs::rootdir/packages/www must be
        writable by the web server.

    } {
        set resource_info [::richtext::xinha::resource_info -version $version]
        set version [dict get $resource_info configuredVersion]

        ::util::resources::download -resource_info $resource_info
        set resourceDir [dict get $resource_info resourceDir]

        #
        # Do we have unzip installed?
        #
        set unzip [::util::which unzip]
        if {$unzip eq ""} {
            error "can't install Xinha locally; no unzip program found on PATH"
        }

        #
        # Do we have a writable output directory under resourceDir?
        #
        if {![file isdirectory $resourceDir/$version]} {
            file mkdir $resourceDir/$version
        }
        if {![file writable $resourceDir/$version]} {
            error "directory $resourceDir/$version is not writable"
        }

        #
        # So far, everything is fine, unpack the editor package.
        #
        foreach url [dict get $resource_info downloadURLs] {
            set fn [file tail $url]
            util::unzip -overwrite \
                -source $resourceDir/$version/$fn \
                -destination $resourceDir/$version
        }
    }

}

# Local variables:
#    mode: tcl
#    tcl-indent-level: 4
#    indent-tabs-mode: nil
# End: