diff --git a/api/js/etemplate/et2_widget_htmlarea.js b/api/js/etemplate/et2_widget_htmlarea.js index be8f957961..21faf883d1 100644 --- a/api/js/etemplate/et2_widget_htmlarea.js +++ b/api/js/etemplate/et2_widget_htmlarea.js @@ -312,3 +312,31 @@ var et2_htmlarea = (function(){ "use strict"; return et2_inputWidget.extend([et2 });}).call(this); et2_register_widget(et2_htmlarea, ["htmlarea"]); +jQuery.extend(et2_htmlarea, +{ + /** + * Build VfsSelect widget for CKEditor Browse Server button + * @param {array} _data + */ + buildVfsSelectForCKEditor: function(_data) + { + if (!_data) return; + var et2 = app[egw(window).app_name()].et2; + + var vfsSelect = et2_createWidget('vfs-select', { + id:'upload', + mode: 'open', + name: '', + button_caption:"Link", + button_label:"Link", + dialog_title: "Link file", + method: "ckeditor" + }, et2); + jQuery(vfsSelect.getDOMNode()).on('change', function (){ + CKEDITOR.tools.callFunction(_data.funcNum, vfsSelect.get_value()); + }); + + // start the file selector dialog + vfsSelect.click(); + } +}); \ No newline at end of file diff --git a/api/js/etemplate/et2_widget_vfs.js b/api/js/etemplate/et2_widget_vfs.js index 2f34af828d..c22595b701 100644 --- a/api/js/etemplate/et2_widget_vfs.js +++ b/api/js/etemplate/et2_widget_vfs.js @@ -870,7 +870,9 @@ var et2_vfsSelect = (function(){ "use strict"; return et2_inputWidget.extend( type: "string", description: "Server side callback to process selected value(s) in \n\ app.class.method or class::method format. The first parameter will \n\ - be Method ID, the second the file list." + be Method ID, the second the file list. 'ckeditor' is reserved and it \n\ + means it should use download_baseUrl instead of path in value (no method\n\ + will be actually executed)." }, "method_id": { name: "Method ID", @@ -965,7 +967,8 @@ var et2_vfsSelect = (function(){ "use strict"; return et2_inputWidget.extend( label: this.options.button_label, path: this.options.path || null, mime: this.options.mime || null, - name: this.options.name + name: this.options.name, + method: this.options.method }; var callback = _callback || this._buildDialog; egw(window).json( @@ -1024,11 +1027,12 @@ var et2_vfsSelect = (function(){ "use strict"; return et2_inputWidget.extend( files = _value.path; break; default: + if (self.options.method === 'ckeditor') _value.path = _data.content.download_baseUrl; files = _value.path+'/'+_value.name; break; } self.value = files; - if (self.options.method) + if (self.options.method && self.options.method !== 'ckeditor') { egw(window).json( self.options.method, @@ -1060,6 +1064,9 @@ var et2_vfsSelect = (function(){ "use strict"; return et2_inputWidget.extend( // for dialog template our best shot is to inherit its parent etemplate_exec_id. this.dialog.template.etemplate_exec_id = etemplate2.getByApplication(egw(window).app_name())[0].etemplate_exec_id; app.vfsSelectUI.et2 = this.dialog.template.widgetContainer; + // Keep the dialog always at the top, seems CKEDITOR dialogs have very + // high z-index set. + this.dialog.div.parent().css({"z-index": 100000}); app.vfsSelectUI.vfsSelectWidget = this; this.dialog.div.on('load', function(e) { app.vfsSelectUI.et2_ready(app.vfsSelectUI.et2, 'api.vfsSelectUI'); diff --git a/api/src/Etemplate/Widget/Vfs.php b/api/src/Etemplate/Widget/Vfs.php index ad822249e7..7fafabd9da 100644 --- a/api/src/Etemplate/Widget/Vfs.php +++ b/api/src/Etemplate/Widget/Vfs.php @@ -522,6 +522,14 @@ class Vfs extends File $sel_options = array_merge($sel_options, array( 'app' => self::get_apps() )); + + if ($content['method'] === 'ckeditor') + { + $download_baseUrl = \EGroupware\Api\Vfs::download_url($content['path']); + if ($download_baseUrl[0] == '/') $download_baseUrl = \EGroupware\Api\Egw::link($download_baseUrl); + $content['download_baseUrl'] = $download_baseUrl; + } + Api\Cache::setSession('filemanger', 'select_path', $content['path']); // Response $response->data(array( diff --git a/api/src/Html/CkEditorConfig.php b/api/src/Html/CkEditorConfig.php index 7bfdbd0c6f..4b2f1e51e1 100644 --- a/api/src/Html/CkEditorConfig.php +++ b/api/src/Html/CkEditorConfig.php @@ -60,6 +60,15 @@ class CkEditorConfig 'px' => 'px: display pixels', ); + /** + * Functions that can be called via menuaction + * + * @var array + */ + var $public_functions = array( + 'vfsSelectHelper' => true, + ); + /** * Get available CKEditor Skins * @@ -249,8 +258,10 @@ class CkEditorConfig */ private static function get_filebrowserBrowseUrl($start_path = '') { - return $GLOBALS['egw_info']['server']['webserver_url'].'/index.php?menuaction=filemanager.filemanager_select.select&mode=open&method=ckeditor_return' - .($start_path != '' ? '&path='.$start_path : ''); + return \EGroupware\Api\Egw::link('/index.php',array( + 'menuaction' => 'api.EGroupware\\Api\\Html\\CkEditorConfig.vfsSelectHelper', + 'path' => $start_path + )); } /** @@ -508,4 +519,21 @@ class CkEditorConfig // tell framework CK Editor needs eval and inline javascript :( ContentSecurityPolicy::add('script-src', $attrs); } + + /** + * It helps to get CKEditor Browse server button to open VfsSelect widget + * in client side. + * @todo Once the ckeditor allows to overrride the Browse Server button handler + * we should remove this function and handle everything in htmlarea widget in + * client side. + */ + public function vfsSelectHelper() + { + $tmp = new \EGroupware\Api\Etemplate('api.vfsSelectUI'); + $response = \EGroupware\Api\Json\Response::get(); + $response->call('window.opener.et2_htmlarea.buildVfsSelectForCKEditor', + array('funcNum' => $_GET['CKEditorFuncNum'])); + $response->call('window.close'); + $tmp->exec('',array()); + } }