Index: openacs-4/packages/richtext-ckeditor5/richtext-ckeditor5.info =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/richtext-ckeditor5/richtext-ckeditor5.info,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/richtext-ckeditor5/richtext-ckeditor5.info 5 Dec 2017 15:51:26 -0000 1.1 @@ -0,0 +1,33 @@ + + + + + Richtext CKeditor5 + Richtext CKeditor5 + f + t + f + f + + + Gustaf Neumann + Richtext editor plugin for integrating CKeditor 5 + with the acs-templating richtext widget + 2017-12-05 + 0 + + + + + + + + + + + + + + + Index: openacs-4/packages/richtext-ckeditor5/lib/file-browser.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/richtext-ckeditor5/lib/file-browser.adp,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/richtext-ckeditor5/lib/file-browser.adp 5 Dec 2017 15:51:26 -0000 1.1 @@ -0,0 +1,88 @@ + + + + + @title@ + + + + + +

@page_title@

+ + +
+ +
+ @images.alt@ +
+
+
+
+ +

@no_attachment@

+
+ +

+ + + + + Index: openacs-4/packages/richtext-ckeditor5/lib/file-browser.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/richtext-ckeditor5/lib/file-browser.tcl,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/richtext-ckeditor5/lib/file-browser.tcl 5 Dec 2017 15:51:26 -0000 1.1 @@ -0,0 +1,27 @@ +ad_include_contract { +} { + {object_id:naturalnum} + {type:word} + {CKEditorFuncNum ""} + {CKEditor:word ""} + {langCode en} +} + +set title "Browse Attached Images" +set page_title "Selectable Images" +set no_attachment "No Attachment Available" + +template::multirow create images src alt + +foreach tuple [attachments::get_attachments -object_id $object_id] { + lassign $tuple image_id . + template::multirow append images \ + /acs-content-repository/ckfinder/view?image_id=$image_id "" +} + +# +# Local variables: +# mode: tcl +# tcl-indent-level: 4 +# indent-tabs-mode: nil +# End: Index: openacs-4/packages/richtext-ckeditor5/tcl/ckfinder-init.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/richtext-ckeditor5/tcl/ckfinder-init.tcl,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/richtext-ckeditor5/tcl/ckfinder-init.tcl 5 Dec 2017 15:51:26 -0000 1.1 @@ -0,0 +1,246 @@ +# +# 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. +# +# NOTE: the delivery of files performs two permission checks, once in +# the request processor (checking the site nodes) and once for the +# concrete image. In order to make uploaded images readable by "The +# Public", make sure that the package_id pointed to by the CKFinderURL +# (per default /acs-content-repository) offers as well read +# permissions to the public. + +# 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 ckeditor5 +# plugins "uploadimage" +# }} +# +# For attaching the images, make sure to pass the property +# "displayed_object_id" on the page, where the richtext form is +# displayed. +# + +# +# 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. +# This corresponds to "responseType=json" in the uploadUrl. +# + +ns_register_proc POST $::richtext::ckeditor5::ckfinder_url/uploadimage { + # + # Image upload handler (for "uploadimage" plugin) + # + set complaints [::richtext::ckeditor5::ckfinder::query_page_contract { + {object_id:naturalnum} + {type:word} + }] + + if {[llength $complaints] == 0 && $type eq "Images"} { + + set form [ns_getform] + set d [::richtext::ckeditor5::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] \ + -image \ + ] + set success [dict get $d success] + if {$success eq "1"} { + # + # Successful operation + # + set view_url [export_vars \ + -base $::richtext::ckeditor5::ckfinder_url/view { + {image_id "[dict get $d file_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 + # + dict set d errMsg "invalid query parameter // $complaints" + set success 0 + } + + if {$success eq "0"} { + set reply [subst {{ + "uploaded": $success, + "error": { + "message": "[dict get $d errMsg]", + } + }}] + } + ns_log notice $reply + + ns_return 200 text/plain $reply +} + + +ns_register_proc POST $::richtext::ckeditor5::ckfinder_url/upload { + # + # Upload handler (for the standard "filebrowser" plugin) + # + set complaints [::richtext::ckeditor5::ckfinder::query_page_contract { + {object_id:naturalnum} + {type:word} + {CKEditorFuncNum ""} + {command:word ""} + {CKEditor:word ""} + {langCode en} + }] + + if {[llength $complaints] == 0 && $type eq "Files"} { + + set form [ns_getform] + set d [::richtext::ckeditor5::ckfinder::file_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::ckeditor5::ckfinder_url/view { + {image_id "[dict get $d file_id]"} + }] + set reply [subst { + + }] + } 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 + # + dict set d errMsg "invalid query parameter // $complaints" + set success 0 + } + + if {$success eq "0"} { + set reply [subst {[dict get $d errMsg]}] + } + ns_log notice $reply + ns_return 200 text/html $reply +} + +ns_register_proc GET $::richtext::ckeditor5::ckfinder_url/browse { + # + # File-browser (for the standard "filebrowser" plugin) + # + set complaints [::richtext::ckeditor5::ckfinder::query_page_contract { + {object_id:naturalnum} + {type:word} + {CKEditorFuncNum ""} + {CKEditor:word ""} + {langCode en} + }] + + permission::require_permission \ + -party_id [ad_conn user_id] \ + -object_id $object_id \ + -privilege read + + set reply [template::adp_include \ + /packages/richtext-ckeditor5/lib/file-browser [subst { + object_id "$object_id" + type "$type" + CKEditorFuncNum "$CKEditorFuncNum" + CKEditor "$CKEditor" + langCode "$langCode" + }]] + + ns_return 200 text/html $reply +} + +# +# View handler +# + +ns_register_proc GET $::richtext::ckeditor5::ckfinder_url/view { + # + # View function (for "filebrowser" and "uploadimage" plugins) + # + set ::template::parse_level [info level] + ad_try { + # + # Use the standard page_contract + # + ad_page_contract { + } { + {image_id:naturalnum ""} + } + ::richtext::ckeditor5::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-ckeditor5/tcl/ckfinder-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/richtext-ckeditor5/tcl/ckfinder-procs.tcl,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/richtext-ckeditor5/tcl/ckfinder-procs.tcl 5 Dec 2017 15:51:26 -0000 1.1 @@ -0,0 +1,224 @@ +ad_library { + + CKEditor 5 helper for ckfinder interface (not complete) + + This script defines the following public procs: + + ::richtext::ckeditor5::ckfinder::image_attach + ::richtext::ckeditor5::ckfinder::return_file + + @author Gustaf Neumann + @creation-date 15 Aug 2017 + @cvs-id $Id: ckfinder-procs.tcl,v 1.1 2017/12/05 15:51:26 gustafn Exp $ + + NOTE: the delivery of files performs two permission checks, once + in the requestprocessor (the site nodes) and once for the concrete image. + If one whishes to make uploaded images readable by "The Public", make + sure that the / + +} + +namespace eval ::richtext::ckeditor5::ckfinder { + + ad_proc -public file_attach { + -import_file + -mime_type + -object_id + {-privilege read} + -user_id + -peeraddr + -package_id + {-image:boolean} + } { + + Insert the provided image file to the content repository as a + new item and attach the image to the specified object_id via + the attachment API. This makes sure that the image will be + deleted from the content repository, when the provided + object_id is deleted. + + The user must have at least "read" privileges on the object, + but other stronger privileges can be supplied via parameter. + + } { + permission::require_permission \ + -party_id $user_id \ + -object_id $object_id \ + -privilege $privilege + + if {$image_p} { + # + # Check if we can handle the mime type. Currently, only the + # following four mime types are supported, since these are + # supported by "ns_imgsize", which is used to determine the + # dimensions of the image. + # + switch -- $mime_type { + image/jpg - + image/jpeg - + image/gif - + image/png { + set ext .[lindex [split $mime_type /] 1] + lassign [ns_imgsize $import_file] width height + set success 1 + } + default { + ns_log warning "image_attach: can't handle image type '$mime_type'" + return [list \ + success 0 \ + errMsg "can't handle image type '$mime_type'"] + } + } + } else { + set width 0 + set height 0 + set success 1 + } + # + # Create a new item without child_rels + # + set name $object_id-[clock clicks -microseconds] + set item_id [::xo::db::sql::content_item new \ + -name $name \ + -parent_id [require_root_folder] \ + -context_id $object_id \ + -creation_user $user_id \ + -creation_ip $peeraddr \ + -item_subtype "content_item" \ + -storage_type "file" \ + -package_id $package_id \ + -with_child_rels f] + + # + # Create a revision for the fresh content_item + # + set revision_id [xo::dc nextval acs_object_id_seq] + content::revision::new \ + -revision_id $revision_id \ + -item_id $item_id \ + -title $name \ + -is_live t \ + -creation_user $user_id \ + -creation_ip $peeraddr \ + -content_type "content_revision" \ + -package_id $package_id \ + -tmp_filename $import_file \ + -mime_type $mime_type + + # + # Attach the image to the object via the attachments API + # + attachments::attach \ + -object_id $object_id \ + -attachment_id $revision_id + + return [list \ + success $success \ + name $name \ + file_id $revision_id \ + width $width \ + height $height \ + ] + } + + ad_proc -public return_file { + -revision_id + -user_id + } { + + Return the file with the specified revision_id to the + user. The user must have at read permissions to obtain the + file (image). + + } { + permission::require_permission \ + -party_id $user_id \ + -object_id $revision_id \ + -privilege read + + set file_path [content::revision::get_cr_file_path \ + -revision_id $revision_id] + set mime_type [db_string get_mime_type { + select mime_type from cr_revisions where revision_id = :revision_id + }] + ad_returnfile_background 200 $mime_type $file_path + } + + ad_proc -private require_root_folder { + {-parent_id -100} + {-name attachments} + } { + + Helper function to find the root folder for ckfinder + attachments. + + } { + set root_folder_id [content::item::get_id \ + -root_folder_id $parent_id \ + -item_path $name] + if {$root_folder_id eq ""} { + set root_folder_id [content::item::new \ + -name $name \ + -parent_id $parent_id] + } + return $root_folder_id + } + + + ad_proc -private query_page_contract { + {-level 1} + params + } { + + Helper function similar to ad_page_contract, but works only on + query variables. + + @result return a list of complaints, which is empty in case of success + + } { + # + # Process params provided by the query + # + foreach p [split [ns_conn query] &] { + lassign [split $p =] var value + set param($var) $value + } + #ns_log notice "provided params [array get param]" + # + # Process params as specified in the page contract + # + foreach p $params { + lassign $p spec default + lassign [split $spec :] name filters + #ns_log notice "param $name exists [info exists param($name)]" + if {[info exists param($name)]} { + set value $param($name) + # + # Call every page contract filter for this + # parameter. On failures, complaints are added to a + # global variable which is picked-up later. + # + foreach filter [split $filters ,] { + ad_page_contract_filter_invoke $filter $name value + } + } else { + set param($name) $default + } + uplevel $level [list set $name $param($name)] + } + if {[info exists ::ad_page_contract_complaints]} { + set complaints [ad_complaints_get_list] + } else { + set complaints "" + } + return $complaints + } + +} + +# +# Local variables: +# mode: tcl +# tcl-indent-level: 4 +# indent-tabs-mode: nil +# End: Index: openacs-4/packages/richtext-ckeditor5/tcl/richtext-init.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/richtext-ckeditor5/tcl/richtext-init.tcl,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/richtext-ckeditor5/tcl/richtext-init.tcl 5 Dec 2017 15:51:26 -0000 1.1 @@ -0,0 +1 @@ +template::util::richtext::register_editor ckeditor5 Index: openacs-4/packages/richtext-ckeditor5/tcl/richtext-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/richtext-ckeditor5/tcl/richtext-procs.tcl,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/richtext-ckeditor5/tcl/richtext-procs.tcl 5 Dec 2017 15:51:26 -0000 1.1 @@ -0,0 +1,389 @@ +ad_library { + + CKEditor 5 integration with the richtext widget of acs-templating. + + In addition to the richttext widget properties, + https://openacs.org/api-doc/proc-view?proc=template::widget::richtext&source_p=1 + the CKEditor 5 allows us to specify a editor class + + Note: CKEditor 5 no longer comes with a configuration setting to change its height. + https://stackoverflow.com/questions/46559354/how-to-set-the-height-of-ckeditor-5-classic-editor/46559355#46559355 + + The current release 1.0.0-alpha.2 not for easy imaging support "Coming soon" + + This script defines in essence following two procs: + + ::richtext-ckeditor5::initialize_widget + ::richtext-ckeditor5::render_widgets + + @author Gustaf Neumann + @creation-date 2 Dec 2017 + @cvs-id $Id: richtext-procs.tcl,v 1.1 2017/12/05 15:51:26 gustafn Exp $ +} + +namespace eval ::richtext::ckeditor5 { + + set package_id [apm_package_id_from_key "richtext-ckeditor5"] + + # ns_section ns/server/${server}/acs/richtext-ckeditor + # ns_param CKEditorVersion 1.0.0-alpha.2 + # 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 1.0.0-alpha.2] + 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 ""] + set JSEditorClass [parameter::get \ + -package_id $package_id \ + -parameter JSEditorClass \ + -default ClassicEditor] + # ClassicEditor | BalloonEditor | InlineEditor + + # + # The cp_package might be basic, standard, of full; + # + # Use "custom" for customized downloads, expand the downloaded zip file in + # richtext-ckeditor5/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 "classic"] + + ad_proc initialize_widget { + -form_id + -text_id + {-options {}} + } { + + Initialize an CKEditor richtext editor widget. + + } { + ns_log notice "initialize CKEditor instance with <$options>" + + # 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 + # ckeditor5}" or via the package parameter "RichTextEditor" of + # acs-templating. + # + # The following options handled by the CKEditor integration + # can be specified in the widget spec of the richtext widget: + # + # plugins skin customConfig spellcheck + # + set ckOptionsList {} + + if {![dict exists $options spellcheck]} { + set package_id [apm_package_id_from_key "richtext-ckeditor5"] + dict set options spellcheck [parameter::get \ + -package_id $package_id \ + -parameter "SCAYT" \ + -default "false"] + } + # For the native spellchecker, one has to hold "ctrl" or "cmd" + # with the right click. + + lappend ckOptionsList \ + "language: '[lang::conn::language]'" \ + "disableNativeSpellChecker: false" \ + "scayt_autoStartup: [dict get $options spellcheck]" + + # + # 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 + } + } + if {[info exists displayed_object_id]} { + # + # If we have a displayed_object_id, configure it for the + # plugins "filebrowser" and "uploadimage". + # + set image_upload_url [export_vars \ + -base $::richtext::ckeditor5::ckfinder_url/uploadimage { + {object_id $displayed_object_id} {type Images} + }] + set file_upload_url [export_vars \ + -base $::richtext::ckeditor5::ckfinder_url/upload { + {object_id $displayed_object_id} {type Files} {command QuickUpload} + }] + set file_browse_url [export_vars \ + -base $::richtext::ckeditor5::ckfinder_url/browse { + {object_id $displayed_object_id} {type Files} + }] + lappend ckOptionsList \ + "imageUploadUrl: '$image_upload_url'" \ + "filebrowserBrowseUrl: '$file_browse_url'" \ + "filebrowserUploadUrl: '$file_upload_url'" \ + "filebrowserWindowWidth: '800'" \ + "filebrowserWindowHeight: '600'" + } + + set plugins [split $::richtext::ckeditor5::standard_plugins ,] + if {[dict exists $options plugins]} { + lappend plugins {*}[split [dict get $options plugins] ,] + } + if {[llength $plugins] > 0} { + lappend ckOptionsList "plugins: \[ [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]'" + } + if {[dict exists $options extraAllowedContent]} { + lappend ckOptionsList \ + "extraAllowedContent: '[dict get $options extraAllowedContent]'" + } + # + # For the time being, set the global variable + # ::richtext::ckeditor5::JSEditorClass of the JavaScript + # editor class to the provided value, since we need this value + # for computing the richt CDN url. + # + if {[dict exists $options JSEditorClass]} { + set ::richtext::ckeditor5::JSEditorClass [dict get $options JSEditorClass] + } + set JSEditorClass $::richtext::ckeditor5::JSEditorClass + + set ckOptions [join $ckOptionsList ", "] + + # + # Add the configuration via body script + # + ns_log notice "initialize_widget: $JSEditorClass.create(document.querySelector( '#$text_id', {$ckOptions} )" + template::add_script -section body -script [subst { + $JSEditorClass + .create( document.querySelector( '#$text_id', {$ckOptions} )) + .catch( error => { + console.error( error ); + } ); + }] + + # + # Load the editor and everything necessary to the current page. + # + ::richtext::ckeditor5::add_editor + + # + # do we need render_widgets? + # + return "" + } + + + ad_proc render_widgets {} { + + Render the ckeditor5 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 variables + + ::acs_blank_master(ckeditor5) + ::acs_blank_master__htmlareas + + } { + # + # In case no ckeditor5 instances are created, nothing has to be + # done. + # + if {![info exists ::acs_blank_master(ckeditor5)]} { + 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. + # + } + + ad_proc ::richtext::ckeditor5::version_info { + {-ck_package ""} + {-version ""} + } { + + 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 + # namespaced variables as default. + # + if {$version eq ""} { + set version ${::richtext::ckeditor5::version} + } + if {$ck_package eq ""} { + switch ${::richtext::ckeditor5::JSEditorClass} { + ClassicEditor { set ck_package classic} + BalloonEditor { set ck_package balloon} + InlineEditor { set ck_package inline} + default { set ck_package ${::richtext::ckeditor5::ck_package}} + } + } + ns_log notice "CKeditor setting ck_package to <${::richtext::ckeditor5::ck_package}> editorclass $::richtext::ckeditor5::JSEditorClass" + set ::richtext::ckeditor5::ck_package ${::richtext::ckeditor5::ck_package} + + set suffix ckeditor5/$version/$ck_package/ckeditor.js + set resources $::acs::rootdir/packages/richtext-ckeditor5/www/resources + if {[file exists $resources/$suffix]} { + lappend result file $resources/$suffix + lappend result resources /resources/richtext-ckeditor5/$suffix + } + lappend result cdn "//cdn.ckeditor.com/$suffix" + ns_log notice "CKEditor path <$result> " + # https://cdn.ckeditor.com/ckeditor5/1.0.0-alpha.2/classic/ckeditor.js + + return $result + } + + ad_proc ::richtext::ckeditor5::add_editor { + {-ck_package ""} + {-version ""} + } { + + 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 version_info [::richtext::ckeditor5::version_info \ + -ck_package $ck_package \ + -version $version] + + if {[dict exists $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 + security::csp::require style-src cdn.ckeditor.com + security::csp::require img-src cdn.ckeditor.com + } + + # + # add required general directives for content security policies + # + #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::ckeditor5::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 + 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. + + } { + # + # If no version or ck editor package are specified, use the + # namespaced variables as default. + # + if {$version eq ""} { + set version ${::richtext::ckeditor5::version} + } + if {$ck_package eq ""} { + set ck_package ${::richtext::ckeditor5::ck_package} + } + + set download_url http://download.cksource.com/CKEditor/CKEditor/CKEditor%20${version}/ckeditor_${version}_${ck_package}.zip + set resources $::acs::rootdir/packages/richtext-ckeditor5/www/resources + + # + # Do we have unzip installed? + # + set unzip [::util::which unzip] + if {$unzip eq ""} { + error "can't install CKeditor locally; no unzip program found on PATH" + } + + # + # Do we have a writable output directory under resources? + # + if {![file isdirectory $resources/$version]} { + file mkdir $resources/$version + } + if {![file writable $resources/$version]} { + error "directory $resources/$version is not writable" + } + + # + # So far, everything is fine, download the editor package + # + set result [util::http::get -url $download_url -spool] + #ns_log notice "GOT $result" + if {[dict get $result status] == 200} { + # + # The Download was successful, unzip it and let the + # directory structure look similar as on the CDN. + # + set fn [dict get $result file] + set output [exec $unzip -o $fn -d $resources/$version] + file rename -- \ + $resources/$version/ckeditor \ + $resources/$version/$ck_package + } else { + error "download of $download_url failed, HTTP status: [dict get $result status]" + } + } + + ad_proc -public get_tag {-options} { + Return the tag for rendering + } { + ns_log notice "=== get_tag $options" + if {[dict exists $options editor] + && [dict get $options editor] eq "ckeditor5" + && [dict exists $options JSEditorClass] + && [dict get $options JSEditorClass] ne "ClassicEditor" + } { + set edit_item_tag div + } + } + +} + + +# Local variables: +# mode: tcl +# tcl-indent-level: 4 +# indent-tabs-mode: nil +# End: Index: openacs-4/packages/richtext-ckeditor5/www/sitewide-admin/download.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/richtext-ckeditor5/www/sitewide-admin/download.tcl,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/richtext-ckeditor5/www/sitewide-admin/download.tcl 5 Dec 2017 15:51:27 -0000 1.1 @@ -0,0 +1,11 @@ +ad_page_contract { + @author Gustaf Neumann + + @creation-date Jan 04, 2017 +} { + {ck_package:word,notnull ""} + {version:word,notnull ""} +} + +::richtext::ckeditor4::download -ck_package $ck_package -version $version +ad_returnredirect . Index: openacs-4/packages/richtext-ckeditor5/www/sitewide-admin/index.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/richtext-ckeditor5/www/sitewide-admin/index.adp,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/richtext-ckeditor5/www/sitewide-admin/index.adp 5 Dec 2017 15:51:27 -0000 1.1 @@ -0,0 +1,20 @@ + +@title;literal@ +@context;literal@ + +

@title;noquote@

+

+The current version of CKEditor is @version@. +

This version of CKEditor is installed locally +under @resources@ +

In the current installation, this version of KEditor can be used via CDN @cdn@. + +

Do you want to download + version @version@ of CKEditor to your file system?

+ + +

The directory @path@ is NOT writable for the server. In + order to be able to download the CKEditor via this web interface, + please change the permissions so that OpenACS can write to it.

+
+. \ No newline at end of file Index: openacs-4/packages/richtext-ckeditor5/www/sitewide-admin/index.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/richtext-ckeditor5/www/sitewide-admin/index.tcl,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/richtext-ckeditor5/www/sitewide-admin/index.tcl 5 Dec 2017 15:51:27 -0000 1.1 @@ -0,0 +1,16 @@ +set title "Richtext CKEditor Sitewide Admin" +set context [list $title] +set version $::richtext::ckeditor4::version + +# +# Get version info about CKEditor. If not locally installed, offer a +# link for download. +# +set version_info [::richtext::ckeditor4::version_info] +if {[dict exists $version_info resources]} { + set resources [dict get $version_info resources] +} +set cdn [dict get $version_info cdn] + +set path $::acs::rootdir/packages/richtext-ckeditor4/www +set writable [file writable $path]