Index: openacs-4/packages/richtext-ckeditor4/richtext-ckeditor4.info
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/richtext-ckeditor4/richtext-ckeditor4.info,v
diff -u -N -r1.2 -r1.3
--- openacs-4/packages/richtext-ckeditor4/richtext-ckeditor4.info 7 Aug 2017 23:48:14 -0000 1.2
+++ openacs-4/packages/richtext-ckeditor4/richtext-ckeditor4.info 16 Aug 2017 13:10:20 -0000 1.3
@@ -9,14 +9,14 @@
f
f
-
+
Gustaf Neumann
Richtext editor plugin for integrating CKeditor 4 with acs-templating
2017-08-06
2
-
+
Index: openacs-4/packages/richtext-ckeditor4/tcl/ckfinder-init.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/richtext-ckeditor4/tcl/ckfinder-init.tcl,v
diff -u -N
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/richtext-ckeditor4/tcl/ckfinder-init.tcl 16 Aug 2017 13:10:20 -0000 1.1
@@ -0,0 +1,142 @@
+#
+# This is a minimal AJAX based ckfinder interface.
+#
+# It supports currently just the drag and drop interface of the
+# "uploadimage" plugin. Dropped images are uploaded to the content
+# repository and attached to the displayed object_id via the
+# attachment package.
+#
+# Since it is not clear, what is the best place for mounting the
+# package (the richtext-* is a singleton package, what should be done
+# e.g. on host-node mapped subsites? Should we add some support to
+# acs-subsite or acs-content-repository), we just register the few
+# URLs .../upload and .../view via ns_register_proc. This might change
+# in the future.
+#
+# This interface can be used obtaining a customized version of
+# ckeditor containing he "uploadimage" plugin. When this is installed,
+# it can be used e.g. with a widget spec like the following
+#
+# {text:richtext(richtext)
+# {html {...}}
+# {label "...."}
+# {options {
+# editor ckeditor4
+# plugins "uploadimage"
+# }}
+#
+# For attaching the images, make sure to pass the property
+# "displayed_object_id" on the page, where the richtext form is
+# displayed.
+#
+
+#
+# Upload handler
+#
+ns_register_proc POST $::richtext::ckeditor4::ckfinder_url/upload {
+ #
+ # We need here a small helper for input checking using the usual
+ # checkers for two reasons:
+ #
+ # 1) The way ckfinder is recommended to work relies on the
+ # separate processing of QUERY and POST variables of an
+ # request. The traditional OpenACS input handling does NOT
+ # support both types of variables at the same time. so we use
+ # here a small helper, such we can use at least the
+ # traditional calling conventions and page contract filters.
+ #
+ # 2) The classical page_contract cannot be configured to interact
+ # properly with AJAX, at least not with a predefined AJAX
+ # interface expecting always a certain JSON array as result.
+ #
+ set complaints [::richtext::ckeditor4::ckfinder::query_page_contract {
+ {object_id:naturalnum}
+ {type:word}
+ }]
+
+ if {[llength $complaints] == 0 && $type eq "Images"} {
+
+ set form [ns_getform]
+ set d [::richtext::ckeditor4::ckfinder::image_attach \
+ -object_id $object_id \
+ -import_file [ns_set get $form upload.tmpfile] \
+ -mime_type [ns_set get $form upload.content-type] \
+ -user_id [ad_conn user_id] \
+ -peeraddr [ad_conn peeraddr] \
+ -package_id [ad_conn package_id] \
+ ]
+ set success [dict get $d success]
+ if {$success eq "1"} {
+ #
+ # Successful operation
+ #
+ set view_url [export_vars \
+ -base $::richtext::ckeditor4::ckfinder_url/view {
+ {image_id "[dict get $d image_id]"}
+ }]
+ set reply [subst {{
+ "uploaded": [dict get $d success],
+ "fileName": "[dict get $d name]",
+ "url": "$view_url",
+ "width": [dict get $d width],
+ "height": [dict get $d height]
+ }}]
+ } else {
+ #
+ # ckfinder::image_attach returned an error
+ #
+ set errMsg [dict get $d errMsg]
+ }
+ } else {
+ #
+ # Either page contract failed or invalid value for 'type' was
+ # specified
+ #
+ set errMsg "invalid query parameter for 'type' // $complaints"
+ }
+
+ if {$success eq "0"} {
+ set reply [subst {{
+ "uploaded": [dict get $d success],
+ "error": {
+ "message": "[dict get $d errMsg]",
+ }
+ }}]
+ }
+ ns_log notice $reply
+
+ ns_return 200 text/plain $reply
+}
+
+#
+# View handler
+#
+
+ns_register_proc GET $::richtext::ckeditor4::ckfinder_url/view {
+ set ::template::parse_level [info level]
+ ad_try {
+ #
+ # Use the standard page_contract
+ #
+ ad_page_contract {
+ } {
+ {image_id:naturalnum ""}
+ }
+ ::richtext::ckeditor4::ckfinder::return_file \
+ -revision_id $image_id \
+ -user_id [ad_conn user_id]
+
+ } ad_script_abort val {
+ #
+ # The page contract has probably failed, no need to raise an
+ # exception.
+ #
+ }
+}
+
+#
+# Local variables:
+# mode: tcl
+# tcl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
Index: openacs-4/packages/richtext-ckeditor4/tcl/richtext-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/richtext-ckeditor4/tcl/richtext-procs.tcl,v
diff -u -N -r1.2 -r1.3
--- openacs-4/packages/richtext-ckeditor4/tcl/richtext-procs.tcl 7 Aug 2017 23:48:14 -0000 1.2
+++ openacs-4/packages/richtext-ckeditor4/tcl/richtext-procs.tcl 16 Aug 2017 13:10:20 -0000 1.3
@@ -5,35 +5,66 @@
This script defines the following two procs:
::richtext-ckeditor4::initialize_widget
- ::richtext-ckeditor4::render_widgets
-
+ ::richtext-ckeditor4::render_widgets
+
@author Gustaf Neumann
@creation-date 1 Jan 2016
@cvs-id $Id$
}
namespace eval ::richtext::ckeditor4 {
- set version 4.7.1
- set ck_package standard
-
+ set package_id [apm_package_id_from_key "richtext-ckeditor4"]
+
+ # ns_section ns/server/${server}/acs/richtext-ckeditor
+ # ns_param CKEditorVersion 4.7.1
+ # ns_param CKEditorPackage standard
+ # ns_param CKFinderURL /acs-content-repository/ckfinder
+ # ns_param StandardPlugins "uploadimage"
+ #
+ set version [parameter::get \
+ -package_id $package_id \
+ -parameter CKEditorVersion \
+ -default 4.7.1]
+ set ckfinder_url [parameter::get \
+ -package_id $package_id \
+ -parameter CKFinderURL \
+ -default /acs-content-repository/ckfinder]
+ set standard_plugins [parameter::get \
+ -package_id $package_id \
+ -parameter StandardPlugins \
+ -default ""]
+
+ #
+ # The cp_package might be basic, standard, of full;
+ #
+ # Use "custom" for customized downloads, expand the downloaded zip file in
+ # richtext-ckeditor4/www/resources/$version
+ # and rename the expanded top-folder from "ckeditor" to "custom"
+ #
+ set ck_package [parameter::get \
+ -package_id $package_id \
+ -parameter CKEditorPackage \
+ -default "standard"]
+
ad_proc initialize_widget {
-form_id
-text_id
{-options {}}
} {
-
+
Initialize an CKEditor richtext editor widget.
-
+
} {
ns_log debug "initialize CKEditor instance with <$options>"
- # allow per default all classes, unless the user has specified
+ # Allow per default all CSS-classes, unless the user has specified
# it differently
if {![dict exists $options extraAllowedContent]} {
dict set options extraAllowedContent {*(*)}
}
-
+
+ #
# The richtext widget might be specified by "options {editor
# ckeditor4}" or via the package parameter "RichTextEditor" of
# acs-templating.
@@ -44,37 +75,58 @@
# plugins skin customConfig spellcheck
#
set ckOptionsList {}
-
+
if {![dict exists $options spellcheck]} {
+ set package_id [apm_package_id_from_key "richtext-ckeditor4"]
dict set options spellcheck [parameter::get \
- -package_id [apm_package_id_from_key "richtext-ckeditor4"] \
+ -package_id $package_id \
-parameter "SCAYT" \
-default "false"]
}
-
# For the native spellchecker, one has to hold "ctrl" or "cmd"
# with the right click.
-
+
+ #
+ # Get the property "displayed_object_id" from the call stack
+ #
+ for {set l 0} {$l < [info level]} {incr l} {
+ set propVar __adp_properties(displayed_object_id)
+ if {[uplevel #$l [list info exists $propVar]]} {
+ set displayed_object_id [uplevel #$l [list set $propVar]]
+ break
+ }
+ }
+ set upload_url [export_vars \
+ -base $::richtext::ckeditor4::ckfinder_url/upload {
+ {object_id $displayed_object_id} {type Images}
+ }]
lappend ckOptionsList \
"language: '[lang::conn::language]'" \
"disableNativeSpellChecker: false" \
- "scayt_autoStartup: [dict get $options spellcheck]"
+ "scayt_autoStartup: [dict get $options spellcheck]" \
+ "imageUploadUrl: '$upload_url'"
+ set plugins [split $::richtext::ckeditor4::standard_plugins ,]
if {[dict exists $options plugins]} {
- lappend ckOptionsList "extraPlugins: '[dict get $options plugins]'"
+ lappend plugins {*}[split [dict get $options plugins] ,]
}
+ if {[llength $plugins] > 0} {
+ lappend ckOptionsList "extraPlugins: '[join $plugins ,]'"
+ }
if {[dict exists $options skin]} {
lappend ckOptionsList "skin: '[dict get $options skin]'"
}
if {[dict exists $options customConfig]} {
- lappend ckOptionsList "customConfig: '[dict get $options customConfig]'"
+ lappend ckOptionsList \
+ "customConfig: '[dict get $options customConfig]'"
}
if {[dict exists $options extraAllowedContent]} {
- lappend ckOptionsList "extraAllowedContent: '[dict get $options extraAllowedContent]'"
+ lappend ckOptionsList \
+ "extraAllowedContent: '[dict get $options extraAllowedContent]'"
}
set ckOptions [join $ckOptionsList ", "]
-
+
#
# Add the configuration via body script
#
@@ -86,7 +138,7 @@
# Load the editor and everything necessary to the current page.
#
::richtext::ckeditor4::add_editor
-
+
#
# do we need render_widgets?
#
@@ -102,7 +154,7 @@
::acs_blank_master(ckeditor4)
::acs_blank_master__htmlareas
-
+
} {
#
# In case no ckeditor4 instances are created, nothing has to be
@@ -125,7 +177,7 @@
Get information about available version(s) of CKEditor, either
from the local file system, or from CDN.
-
+
} {
#
# If no version or ck editor package are specified, use the
@@ -140,7 +192,8 @@
set suffix $version/$ck_package/ckeditor.js
set resources $::acs::rootdir/packages/richtext-ckeditor4/www/resources
-
+ ns_log notice "ACS::ROOT <$::acs::rootdir>"
+ ns_log notice "CHECK <$resources/$suffix>"
if {[file exists $resources/$suffix]} {
lappend result file $resources/$suffix
lappend result resources /resources/richtext-ckeditor4/$suffix
@@ -149,7 +202,7 @@
return $result
}
-
+
ad_proc ::richtext::ckeditor4::add_editor {
{-ck_package ""}
{-version ""}
@@ -164,14 +217,15 @@
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 version_info [::richtext::ckeditor4::version_info \
-ck_package $ck_package \
-version $version]
if {[dict exists $version_info resources]} {
- template::head::add_javascript -src [dict get $version_info resources]
+ template::head::add_javascript \
+ -src [dict get $version_info resources]
} else {
template::head::add_javascript -src [dict get $version_info cdn]
security::csp::require script-src cdn.ckeditor.com
@@ -184,13 +238,16 @@
#
security::csp::require script-src 'unsafe-eval'
security::csp::require -force script-src 'unsafe-inline'
+
+ # this is needed currently for "imageUploadUrl"
+ security::csp::require img-src data:
}
-
+
ad_proc ::richtext::ckeditor4::download {
{-ck_package ""}
{-version ""}
} {
-
+
Download the CKeditor 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
@@ -199,7 +256,7 @@
Notice, that for this automated download, the "unzip" program
must be installed and $::acs::rootdir/packages/www must be
writable by the web server.
-
+
} {
#
# If no version or ck editor package are specified, use the
@@ -220,9 +277,9 @@
#
set unzip [::util::which unzip]
if {$unzip eq ""} {
- error "can't install CKeditor locally; no unzip program found on PATH"
+ error "can't install CKeditor locally; no unzip program found on PATH"
}
-
+
#
# Do we have a writable output directory under resources?
#
@@ -245,14 +302,17 @@
#
set fn [dict get $result file]
set output [exec $unzip -o $fn -d $resources/$version]
- file rename -- $resources/$version/ckeditor $resources/$version/$ck_package
+ file rename -- \
+ $resources/$version/ckeditor \
+ $resources/$version/$ck_package
} else {
error "download of $download_url failed, HTTP status: [dict get $result status]"
}
}
}
+
# Local variables:
# mode: tcl
# tcl-indent-level: 4