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());
+ }
}