How can you integrate a custom file browser/uploader with CKEditor?

官方文档不是很清楚-什么是正确的方式来集成一个自定义文件浏览器/上传器与 CKEditor?(v3-非 FCKEditor)

142853 次浏览

首先,在实例化 CKEditor 时注册自定义浏览器/上传器。您可以为图像浏览器指定不同的 URL,也可以为常规文件浏览器指定不同的 URL。

<script type="text/javascript">
CKEDITOR.replace('content', {
filebrowserBrowseUrl : '/browser/browse/type/all',
filebrowserUploadUrl : '/browser/upload/type/all',
filebrowserImageBrowseUrl : '/browser/browse/type/image',
filebrowserImageUploadUrl : '/browser/upload/type/image',
filebrowserWindowWidth  : 800,
filebrowserWindowHeight : 500
});
</script>

您的自定义代码将收到一个名为 CKEditorFuncNum 的 GET 参数。保存它-这是您的回调函数。假设你把它放入 $callback

当有人选择一个文件时,运行这个 JavaScript 通知 CKEditor 选择了哪个文件:

window.opener.CKEDITOR.tools.callFunction(<?php echo $callback; ?>,url)

其中“ URL”是他们选择的文件的 URL。可选的第三个参数可以是您希望在标准警报对话框中显示的文本,例如“非法文件”或其他内容。如果第三个参数是错误消息,则将 url 设置为空字符串。

CKEditor 的“上传”选项卡将在“上传”字段中提交一个文件-在 PHP 中,该文件将进入 $_ FILES [‘ upad’]。CKEditor 希望服务器输出的是一个完整的 JavaScript 块:

$output = '<html><body><script type="text/javascript">window.parent.CKEDITOR.tools.callFunction('.$callback.', "'.$url.'","'.$msg.'");</script></body></html>';
echo $output;

同样,您需要为它提供回调参数、文件的 URL 以及可选的消息。如果消息为空字符串,则不显示任何内容; 如果消息为错误,则 url 应为空字符串。

官方的 CKEditor 文档是不完整的,但是如果你遵循上面的内容,它会像冠军一样工作。

在 zerokspot 上的一篇题为 CKEditor 3.0中的自定义文件浏览器回调的文章处理了这个问题:

所以你要做的就是从文件开始 当您选择了一个文件时,浏览器 is to call this code with the right 回调号码(通常为1)和 所选文件的 URL:

window.opener.CKEDITOR.tools.callFunction(CKEditorFuncNum,url);

对于快速上传程序,这个过程是 非常相似。一开始我以为 编辑可能在监听 200 HTTP 返回代码,或许可以查看 进入某个头字段之类的 来确定 上传的文件,但然后通过 一些 Firebug 监控,我注意到了 上传之后发生的一切 密码如下:

<script type="text/javascript">
window.parent.CKEDITOR.tools.callFunction(CKEditorFuncNum,url, errorMessage); </script>

如果上载失败,请设置 errorMessage到某个非零长度 字符串并清空 url 和 Vice versa on success.

我花了一段时间想弄明白这个问题,这就是我所做的。我把它分解得很简单,因为这正是我所需要的。

在你的编辑器文本区域的正下方,像这样输入上传文件 > > > >

<form action="welcomeeditupload.asp" method="post" name="deletechecked">
<div align="center">
<br />
<br />
<label></label>
<textarea class="ckeditor" cols="80" id="editor1" name="editor1" rows="10"><%=(rslegschedule.Fields.Item("welcomevar").Value)%></textarea>
<script type="text/javascript">
//<![CDATA[
CKEDITOR.replace( 'editor1',
{
filebrowserUploadUrl : 'updateimagedone.asp'
});
//]]>
</script>
<br />
<br />
<br />
<input type="submit" value="Update">
</div>
</form>

然后添加你的上传文件,这里是我的,这是写在 ASP。如果你正在使用 PHP 等,只需用你的上传脚本替换 ASP,但要确保页面输出相同的东西。

<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<%
if Request("CKEditorFuncNum")=1 then
Set Upload = Server.CreateObject("Persits.Upload")
Upload.OverwriteFiles = False
Upload.SetMaxSize 5000000, True
Upload.CodePage = 65001


On Error Resume Next
Upload.Save "d:\hosting\belaullach\senate\legislation"


Dim picture
For Each File in Upload.Files
Ext = UCase(Right(File.Path, 3))
If Ext <> "JPG" Then
If Ext <> "BMP" Then
Response.Write "File " & File.Path & " is not a .jpg or .bmp file." & "<BR>"
Response.write "You can only upload .jpg or .bmp files." & "<BR>" & "<BR>"
End if
Else
File.SaveAs Server.MapPath(("/senate/legislation") & "/" & File.fileName)
f1=File.fileName
End If
Next
End if


fnm="/senate/legislation/"&f1
imgop = "<html><body><script type=""text/javascript"">window.parent.CKEDITOR.tools.callFunction('1','"&fnm&"');</script></body></html>;"
'imgop="callFunction('1','"&fnm&"',"");"
Response.write imgop
%>

I have posted one small tutorial about integrating the FileBrowser available in old FCKEditor into CKEditor.

Http://www.mixedwaves.com/2010/02/integrating-fckeditor-filemanager-in-ckeditor/

它包含这样做的一步一步的指示,并且非常简单。我希望任何人在搜索这将发现这个教程有帮助。

这是我使用过的方法,非常简单,而且运行良好。

In the CK editor root directory there is a file named config.js

我添加了这个(您不需要 querystring,这只是用于我们的文件管理器)。我还包括一些皮肤和改变默认按钮显示:

CKEDITOR.editorConfig = function(config) {


config.skin = 'v2';
config.startupFocus = false;
config.filebrowserBrowseUrl = '/admin/content/filemanager.aspx?path=Userfiles/File&editor=FCK';
config.filebrowserImageBrowseUrl = '/admin/content/filemanager.aspx?type=Image&path=Userfiles/Image&editor=FCK';
config.toolbar_Full =
[
['Source', '-', 'Preview', '-'],
['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Print', 'SpellChecker'], //, 'Scayt'
['Undo', 'Redo', '-', 'Find', 'Replace', '-', 'SelectAll', 'RemoveFormat'],
'/',
['Bold', 'Italic', 'Underline', 'Strike', '-', 'Subscript', 'Superscript'],
['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', 'Blockquote'],
['JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'],
['Link', 'Unlink', 'Anchor'],
['Image', 'Flash', 'Table', 'HorizontalRule', 'SpecialChar'],
'/',
['Styles', 'Format', 'Templates'],
['Maximize', 'ShowBlocks']
];


};

然后,我们的文件管理员称之为:

opener.SetUrl('somefilename');

我自己刚刚经历了一个学习过程。我弄明白了,但我同意文档的写法让我有点害怕。对我来说最大的“顿悟”时刻是理解为浏览,所有 CKEditor 所做的就是打开一个新窗口,并在 URL 中提供一些参数。它允许您添加其他参数,但建议您在值上使用 encodeURIComponent ()。

我调用浏览器和上传器

CKEDITOR.replace( 'body',
{
filebrowserBrowseUrl: 'browse.php?type=Images&dir=' +
encodeURIComponent('content/images'),
filebrowserUploadUrl: 'upload.php?type=Files&dir=' +
encodeURIComponent('content/images')
}

对于 browser,在打开的窗口(Browse.php)中,使用 php & js 提供一个选项列表,然后在提供的 onclick 处理程序中,调用带有两个参数的 CKEditor 函数,所选图像的 url/path 和 CKEditor 在 url 中提供的 CKEditorFuncNum:

function myOnclickHandler(){
//..
window.opener.CKEDITOR.tools.callFunction(<?php echo $_GET['CKEditorFuncNum']; ?>, pathToImage);
window.close();
}

类似地,上传器只是调用您提供的 URL,例如 上传,然后再次提供 $_ GET [‘ CKEditorFuncNum’] 一个 iframe,这样,在从 $_ FILES 保存文件之后,将反馈传递给 CKEditor,如下所示:

$funcNum = $_GET['CKEditorFuncNum'];
exit("<script>window.parent.CKEDITOR.tools.callFunction($funcNum, '$filePath', '$errorMessage');</script>");

Below is a simple to understand custom browser script. While it does not allow users to navigate around in the server, it does allow you to indicate which directory to pull image files from when calling the browser.

这些都是相当基本的编码,所以应该可以在所有相对现代的浏览器中工作。

CKEditor 只是打开一个新窗口,其中包含提供的 URL

/*
in CKeditor **use encodeURIComponent()** to add dir param to the filebrowserBrowseUrl property


Replace content/images with directory where your images are housed.
*/
CKEDITOR.replace( 'editor1', {
filebrowserBrowseUrl: '**browse.php**?type=Images&dir=' + encodeURIComponent('content/images'),
filebrowserUploadUrl: 'upload.php?type=Files&dir=' + encodeURIComponent('content/images')
});

// ========= complete code below for browse.php

<?php
header("Content-Type: text/html; charset=utf-8\n");
header("Cache-Control: no-cache, must-revalidate\n");
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");


// e-z params
$dim = 150;         /* image displays proportionally within this square dimension ) */
$cols = 4;          /* thumbnails per row */
$thumIndicator = '_th'; /* e.g., *image123_th.jpg*) -> if not using thumbNails then use empty string */
?>
<!DOCTYPE html>
<html>
<head>
<title>browse file</title>
<meta charset="utf-8">


<style>
html,
body {padding:0; margin:0; background:black; }
table {width:100%; border-spacing:15px; }
td {text-align:center; padding:5px; background:#181818; }
img {border:5px solid #303030; padding:0; verticle-align: middle;}
img:hover { border-color:blue; cursor:pointer; }
</style>


</head>




<body>


<table>


<?php


$dir = $_GET['dir'];


$dir = rtrim($dir, '/'); // the script will add the ending slash when appropriate


$files = scandir($dir);


$images = array();


foreach($files as $file){
// filter for thumbNail image files (use an empty string for $thumIndicator if not using thumbnails )
if( !preg_match('/'. $thumIndicator .'\.(jpg|jpeg|png|gif)$/i', $file) )
continue;


$thumbSrc = $dir . '/' . $file;
$fileBaseName = str_replace('_th.','.',$file);


$image_info = getimagesize($thumbSrc);
$_w = $image_info[0];
$_h = $image_info[1];


if( $_w > $_h ) {       // $a is the longer side and $b is the shorter side
$a = $_w;
$b = $_h;
} else {
$a = $_h;
$b = $_w;
}


$pct = $b / $a;     // the shorter sides relationship to the longer side


if( $a > $dim )
$a = $dim;      // limit the longer side to the dimension specified


$b = (int)($a * $pct);  // calculate the shorter side


$width =    $_w > $_h ? $a : $b;
$height =   $_w > $_h ? $b : $a;


// produce an image tag
$str = sprintf('<img src="%s" width="%d" height="%d" title="%s" alt="">',
$thumbSrc,
$width,
$height,
$fileBaseName
);


// save image tags in an array
$images[] = str_replace("'", "\\'", $str); // an unescaped apostrophe would break js


}


$numRows = floor( count($images) / $cols );


// if there are any images left over then add another row
if( count($images) % $cols != 0 )
$numRows++;




// produce the correct number of table rows with empty cells
for($i=0; $i<$numRows; $i++)
echo "\t<tr>" . implode('', array_fill(0, $cols, '<td></td>')) . "</tr>\n\n";


?>
</table>




<script>


// make a js array from the php array
images = [
<?php


foreach( $images as $v)
echo sprintf("\t'%s',\n", $v);


?>];


tbl = document.getElementsByTagName('table')[0];


td = tbl.getElementsByTagName('td');


// fill the empty table cells with data
for(var i=0; i < images.length; i++)
td[i].innerHTML = images[i];




// event handler to place clicked image into CKeditor
tbl.onclick =


function(e) {


var tgt = e.target || event.srcElement,
url;


if( tgt.nodeName != 'IMG' )
return;


url = '<?php echo $dir;?>' + '/' + tgt.title;


this.onclick = null;


window.opener.CKEDITOR.tools.callFunction(<?php echo $_GET['CKEditorFuncNum']; ?>, url);


window.close();
}
</script>
</body>
</html>

首先,在实例化 CKEditor 时注册自定义浏览器/上传器。

<script type="text/javascript">
CKEDITOR.replace('content', {
filebrowserUploadUrl: "Upload File Url",//http://localhost/phpwork/test/ckFileUpload.php
filebrowserWindowWidth  : 800,
filebrowserWindowHeight : 500
});
</script>

上传文件的代码(ckFileUpload.php)并将上传文件放在项目的根目录中。

// HERE SET THE PATH TO THE FOLDERS FOR IMAGES AND AUDIO ON YOUR SERVER (RELATIVE TO THE ROOT OF YOUR WEBSITE ON SERVER)


$upload_dir = array(
'img'=> '/phpwork/test/uploads/editor-images/',
'audio'=> '/phpwork/ezcore_v1/uploads/editor-images/'
);


// HERE PERMISSIONS FOR IMAGE
$imgset = array(
'maxsize' => 2000,     // maximum file size, in KiloBytes (2 MB)
'maxwidth' => 900,     // maximum allowed width, in pixels
'maxheight' => 800,    // maximum allowed height, in pixels
'minwidth' => 10,      // minimum allowed width, in pixels
'minheight' => 10,     // minimum allowed height, in pixels
'type' => array('bmp', 'gif', 'jpg', 'jpeg', 'png'),  // allowed extensions
);


// HERE PERMISSIONS FOR AUDIO
$audioset = array(
'maxsize' => 20000,    // maximum file size, in KiloBytes (20 MB)
'type' => array('mp3', 'ogg', 'wav'),  // allowed extensions
);


// If 1 and filename exists, RENAME file, adding "_NR" to the end of filename (name_1.ext, name_2.ext, ..)
// If 0, will OVERWRITE the existing file
define('RENAME_F', 1);


$re = '';
if(isset($_FILES['upload']) && strlen($_FILES['upload']['name']) >1) {
define('F_NAME', preg_replace('/\.(.+?)$/i', '', basename($_FILES['upload']['name'])));  //get filename without extension


// get protocol and host name to send the absolute image path to CKEditor
$protocol = !empty($_SERVER['HTTPS']) ? 'https://' : 'http://';
$site = $protocol. $_SERVER['SERVER_NAME'] .'/';
$sepext = explode('.', strtolower($_FILES['upload']['name']));
$type = end($sepext);    // gets extension
$upload_dir = in_array($type, $imgset['type']) ? $upload_dir['img'] : $upload_dir['audio'];
$upload_dir = trim($upload_dir, '/') .'/';


//checkings for image or audio
if(in_array($type, $imgset['type'])){
list($width, $height) = getimagesize($_FILES['upload']['tmp_name']);  // image width and height
if(isset($width) && isset($height)) {
if($width > $imgset['maxwidth'] || $height > $imgset['maxheight']) $re .= '\\n Width x Height = '. $width .' x '. $height .' \\n The maximum Width x Height must be: '. $imgset['maxwidth']. ' x '. $imgset['maxheight'];
if($width < $imgset['minwidth'] || $height < $imgset['minheight']) $re .= '\\n Width x Height = '. $width .' x '. $height .'\\n The minimum Width x Height must be: '. $imgset['minwidth']. ' x '. $imgset['minheight'];
if($_FILES['upload']['size'] > $imgset['maxsize']*1000) $re .= '\\n Maximum file size must be: '. $imgset['maxsize']. ' KB.';
}
}
else if(in_array($type, $audioset['type'])){
if($_FILES['upload']['size'] > $audioset['maxsize']*1000) $re .= '\\n Maximum file size must be: '. $audioset['maxsize']. ' KB.';
}
else $re .= 'The file: '. $_FILES['upload']['name']. ' has not the allowed extension type.';


//set filename; if file exists, and RENAME_F is 1, set "img_name_I"
// $p = dir-path, $fn=filename to check, $ex=extension $i=index to rename
function setFName($p, $fn, $ex, $i){
if(RENAME_F ==1 && file_exists($p .$fn .$ex)) return setFName($p, F_NAME .'_'. ($i +1), $ex, ($i +1));
else return $fn .$ex;
}


$f_name = setFName($_SERVER['DOCUMENT_ROOT'] .'/'. $upload_dir, F_NAME, ".$type", 0);
$uploadpath = $_SERVER['DOCUMENT_ROOT'] .'/'. $upload_dir . $f_name;  // full file path


// If no errors, upload the image, else, output the errors
if($re == '') {
if(move_uploaded_file($_FILES['upload']['tmp_name'], $uploadpath)) {
$CKEditorFuncNum = $_GET['CKEditorFuncNum'];
$url = $site. $upload_dir . $f_name;
$msg = F_NAME .'.'. $type .' successfully uploaded: \\n- Size: '. number_format($_FILES['upload']['size']/1024, 2, '.', '') .' KB';
$re = in_array($type, $imgset['type']) ? "window.parent.CKEDITOR.tools.callFunction($CKEditorFuncNum, '$url', '$msg')"  //for img
: 'var cke_ob = window.parent.CKEDITOR; for(var ckid in cke_ob.instances) { if(cke_ob.instances[ckid].focusManager.hasFocus) break;} cke_ob.instances[ckid].insertHtml(\'<audio src="'. $url .'" controls></audio>\', \'unfiltered_html\'); alert("'. $msg .'"); var dialog = cke_ob.dialog.getCurrent();  dialog.hide();';
}
else $re = 'alert("Unable to upload the file")';
}
else $re = 'alert("'. $re .'")';
}


@header('Content-type: text/html; charset=utf-8');
echo '<script>'. $re .';</script>';

编辑器文件不清楚后,做了很多研发自定义文件上传最后我找到了这个解决方案。它为我工作,我希望它将有助于其他人以及。

对于那些想知道 Servlet/JSP 实现的人来说,这里是你如何做到这一点的... 我将在下面解释上传图片。

1)首先确定你已经把 文件浏览器上传图片变量加到你的 Js 文件。让你也有 上传图片文件浏览器文件夹内的插件文件夹。

2)这部分就是我犯错的地方:

CkEditor 网站的文档显示,您需要使用以下两种方法:

function getUrlParam( paramName ) {
var reParam = new RegExp( '(?:[\?&]|&)' + paramName + '=([^&]+)', 'i' );
var match = window.location.search.match( reParam );
return ( match && match.length > 1 ) ? match[1] : null;
}
function returnFileUrl() {
var funcNum = getUrlParam( 'CKEditorFuncNum' );
var fileUrl = 'https://patiliyo.com/wp-content/uploads/2017/07/ruyada-kedi-gormek.jpg';
window.opener.CKEDITOR.tools.callFunction( funcNum, fileUrl );
window.close();
}

What they don't mention is that these methods have to be on a 不同的页面,而不是您点击 浏览服务器按钮的页面。

所以如果你有 在 page Editor. jsp 中初始化的 ckEditor,那么你需要创建一个 文件浏览器(带有基本的 html/css/javascript)

editor.jsp (all you need is this in your script tag) This page will open filebrowser.jsp in a mini window when you click on the browse server button.

CKEDITOR.replace( 'editor', {
filebrowserBrowseUrl: '../filebrowser.jsp', //jsp page with jquery to call servlet and get image files to view
filebrowserUploadUrl: '../UploadImage', //servlet


});

filebrowser.jsp (is the custom file browser you built which will contain the methods mentioned above)

<head>
<script src="../../ckeditor/ckeditor.js"></script>
</head>
<body>
<script>




function getUrlParam( paramName ) {
var reParam = new RegExp( '(?:[\?&]|&)' + paramName + '=([^&]+)', 'i' );
var match = window.location.search.match( reParam );
return ( match && match.length > 1 ) ? match[1] : null;
}


function returnFileUrl() {
var funcNum = getUrlParam( 'CKEditorFuncNum' );
var fileUrl = 'https://patiliyo.com/wp-content/uploads/2017/07/ruyada-kedi-gormek.jpg';
window.opener.CKEDITOR.tools.callFunction( funcNum, fileUrl );
window.close();
}




//when this window opens it will load all the images which you send from the FileBrowser Servlet.
getImages();
function getImages(){
$.get("../FileBrowser", function(responseJson) {
//do something with responseJson (like create <img> tags and update the src attributes)
});
}


//you call this function and pass 'fileUrl' when user clicks on an image that you loaded into this window from a servlet
returnFileUrl();
</script>
</body>

3) The FileBrowser Servlet

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Images i = new Images();
List<ImageObject> images = i.getImages(); //get images from your database or some cloud service or whatever (easier if they are in a url ready format)
String json = new Gson().toJson(images);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(json);
}

4) UploadImage Servlet

返回到 ckEditor 的 config.js 文件并添加以下代码行:

//https://docs.ckeditor.com/ckeditor4/latest/guide/dev_file_upload.html
config.uploadUrl = '/UploadImage';

Then you can drag and drop files also:

   protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {




Images i = new Images();


//do whatever you usually do to upload your image to your server (in my case i uploaded to google cloud storage and saved the url in a database.


//Now this part is important. You need to return the response in json format. And it has to look like this:


//      https://docs.ckeditor.com/ckeditor4/latest/guide/dev_file_upload.html
//      response must be in this format:
//      {
//          "uploaded": 1,
//          "fileName": "example.png",
//          "url": "https://www.cats.com/example.png"
//      }


String image = "https://www.cats.com/example.png";
ImageObject objResponse = i.getCkEditorObjectResponse(image);
String json = new Gson().toJson(objResponse);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(json);
}
}

就这些了,希望能有所帮助。