FCKeditor开发总结(富文本编辑器)

1. 建立Java下的FCKEditor
下载Java的例程,按照例程里的相关配置文件就可以完全建立。
2. 各种环境下使用
2.1. JavaScript
<script type="text/javascript">
var oFCKeditor = new FCKeditor('FCKeditor1');
oFCKeditor.BasePath = "/fckeditor/";
oFCKeditor.Create();
</script>


<html>
<head>
<title>FCKeditor - Sample</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="robots" content="noindex, nofollow">
<script type="text/javascript" src="fckeditor/fckeditor.js"></script>
<script type="text/javascript">
window.onload = function()
{
var oFCKeditor = new FCKeditor( 'MyTextarea' ) ;
oFCKeditor.BasePath = "/fckeditor/" ;
oFCKeditor.ReplaceTextarea() ;
}
</script>
</head>
<body>
<textarea id="MyTextarea" name="MyTextarea">This is <b>the</b> initial value.</textarea>
</body>
</html>
2.2. Java
FCKeditor contentEditor = new FCKeditor(request, "ContentEditor");
contentEditor.setValue("添加详细内容");
FCKeditorConfig contentEditorConfig = contentEditor.getConfig();
contentEditorConfig.put("SkinPath",path+"/fckeditor/editor/skins/office2003/");
contentEditor.setWidth("800px");
contentEditor.setHeight("500px");
out.print(contentEditor);
2.2.1. FCKeditor类说明
两种构造方法:
FCKeditor(javax.servlet.http.HttpServletRequest request, java.lang.String instanceName)
Just a wrapper to FCKeditor.
FCKeditor(javax.servlet.http.HttpServletRequest request, java.lang.String instanceName, java.lang.String width, java.lang.String height, java.lang.String toolbarSet, java.lang.String value, java.lang.String basePath)
例如如下所示:
FCKeditor abstractEditor = new FCKeditor(request, "AbstractEditor","800px","200px","Basic","添加摘要","");
FCKeditorConfig abstractEditorConfig = abstractEditor.getConfig();
abstractEditorConfig.put("SkinPath",path+"/fckeditor/editor/skins/office2003/");
out.print(abstractEditor);
BasePath:编辑器的基路径,默认为/Fckeditor/文件夹,注意,尽量不要使用相对路径.最用相对于站点根路径的表示方法,要以/结尾。


2.3. 其他
参照http://docs.fckeditor.net/FCKeditor_2.x/Developers_Guide


3. 配置FCKEditor
3.1. 直接配置fckconfig.js
FCKConfig.CustomConfigurationsPath = '' ;
可以配置自己的配置文件:FCKConfig.CustomConfigurationsPath = '/myconfig.js' ;
3.2. 使用Js对象配置
var oFCKeditor = new FCKeditor( "FCKeditor1" ) ;
oFCKeditor.Config["CustomConfigurationsPath"] = "/myconfig.js" ;
oFCKeditor.Create() ;
3.3. 使用Java对象配置
FCKeditor contentEditor = new FCKeditor(request, "ContentEditor");
contentEditor.setValue("添加详细内容");
FCKeditorConfig contentEditorConfig = contentEditor.getConfig();
contentEditorConfig.put("SkinPath",path+"/fckeditor/editor/skins/office2003/");
contentEditor.setWidth("800px");
contentEditor.setHeight("500px");
out.print(contentEditor);


4. 上传文件问题
4.1. 配置步骤
4.1.1. 在Web.xml里添加
<!-- rich text fckditor -->
<servlet>
<servlet-name>Connector</servlet-name>
<servlet-class>
cn.winjoys.knowledge.fckeditor.ConnectorServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>Connector</servlet-name>
<!-- Do not wrap this line otherwise Glassfish will fail to load this file -->
<url-pattern>
/fckeditor/editor/filemanager/connectors/*
</url-pattern>
</servlet-mapping>
4.1.2. 新建一个 fckeditor.properties 文件 in your classpath
在Demo里有提到过。
connector.userActionImpl=net.fckeditor.requestcycle.impl.UserActionImpl
4.1.3. 解决上传中文乱码的问题
新建一个cn.winjoys.knowledge.fckeditor.ConnectorServlet
然后修改部分代码
package cn.winjoys.knowledge.fckeditor;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.fckeditor.connector.Messages;
import net.fckeditor.handlers.CommandHandler;
import net.fckeditor.handlers.ConnectorHandler;
import net.fckeditor.handlers.ExtensionsHandler;
import net.fckeditor.handlers.RequestCycleHandler;
import net.fckeditor.handlers.ResourceTypeHandler;
import net.fckeditor.response.UploadResponse;
import net.fckeditor.response.XmlResponse;
import net.fckeditor.tool.Utils;
import net.fckeditor.tool.UtilsFile;
import net.fckeditor.tool.UtilsResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Servlet to upload and browse files.<br />
*
* This servlet accepts 4 commands which interact with the server-side
* filesystem.<br />
* The allowed commands are:
* <ul>
* <li><code>GetFolders</code>: Retrieves a list of folders in the current
* folder</li>
* <li><code>GetFoldersAndFiles</code>: Retrives a list of files and folders
* in the current folder</li>
* <li><code>CreateFolder</code>: Creates a new folder in the current folder</li>
* <li><code>FileUpload</code>: Stores an uploaded file into the current
* folder. (must be sent with POST)</li>
* </ul>
*
* @version $Id: ConnectorServlet.java 2101 2008-06-22 22:00:48Z mosipov $
*/
public class ConnectorServlet extends HttpServlet {

private static final long serialVersionUID = -5742008970929377161L;
private static final Logger logger = LoggerFactory
.getLogger(ConnectorServlet.class);

/**
* Initialize the servlet: <code>mkdir</code> <DefaultUserFilesPath>
*/
public void init() throws ServletException, IllegalArgumentException {
String realDefaultUserFilesPath = getServletContext().getRealPath(
ConnectorHandler.getDefaultUserFilesPath());

File defaultUserFilesDir = new File(realDefaultUserFilesPath);
UtilsFile.checkDirAndCreate(defaultUserFilesDir);

logger.info("ConnectorServlet successfully initialized!");
}

/**
* Manage the <code>GET</code> requests (<code>GetFolders</code>,
* <code>GetFoldersAndFiles</code>, <code>CreateFolder</code>).<br/>
*
* The servlet accepts commands sent in the following format:<br/>
* <code>connector?Command=<CommandName>&Type=<ResourceType>&CurrentFolder=<FolderPath></code>
* <p>
* It executes the commands and then returns the result to the client in XML
* format.
* </p>
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
logger.debug("Entering ConnectorServlet#doGet");

response.setCharacterEncoding("UTF-8");
response.setContentType("application/xml; charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
PrintWriter out = response.getWriter();

String commandStr = request.getParameter("Command");
String typeStr = request.getParameter("Type");
String currentFolderStr = request.getParameter("CurrentFolder");

logger.debug("Parameter Command: {}", commandStr);
logger.debug("Parameter Type: {}", typeStr);
logger.debug("Parameter CurrentFolder: {}", currentFolderStr);

XmlResponse xr;

if (!RequestCycleHandler.isEnabledForFileBrowsing(request))
xr = new XmlResponse(XmlResponse.EN_ERROR,
Messages.NOT_AUTHORIZED_FOR_BROWSING);
else if (!CommandHandler.isValidForGet(commandStr))
xr = new XmlResponse(XmlResponse.EN_ERROR, Messages.INVALID_COMMAND);
else if (typeStr != null && !ResourceTypeHandler.isValid(typeStr))
xr = new XmlResponse(XmlResponse.EN_ERROR, Messages.INVALID_TYPE);
else if (!UtilsFile.isValidPath(currentFolderStr))
xr = new XmlResponse(XmlResponse.EN_ERROR,
Messages.INVALID_CURRENT_FOLDER);
else {
CommandHandler command = CommandHandler.getCommand(commandStr);
ResourceTypeHandler resourceType = ResourceTypeHandler
.getDefaultResourceType(typeStr);

String typePath = UtilsFile.constructServerSidePath(request,
resourceType);
String typeDirPath = getServletContext().getRealPath(typePath);

File typeDir = new File(typeDirPath);
UtilsFile.checkDirAndCreate(typeDir);

File currentDir = new File(typeDir, currentFolderStr);

if (!currentDir.exists())
xr = new XmlResponse(XmlResponse.EN_INVALID_FOLDER_NAME);
else {

xr = new XmlResponse(command, resourceType, currentFolderStr,
UtilsResponse.constructResponseUrl(request,
resourceType, currentFolderStr, true,
ConnectorHandler.isFullUrl()));

if (command.equals(CommandHandler.GET_FOLDERS))
xr.setFolders(currentDir);
else if (command.equals(CommandHandler.GET_FOLDERS_AND_FILES))
xr.setFoldersAndFiles(currentDir);
else if (command.equals(CommandHandler.CREATE_FOLDER)) {

//---------修改新建文件夹中文乱码
String temStr = request.getParameter("NewFolderName");
temStr = new String(temStr.getBytes("iso8859-1"), "utf-8");
//---------完毕

String newFolderStr = UtilsFile.sanitizeFolderName(temStr);
logger.debug("Parameter NewFolderName: {}", newFolderStr);

File newFolder = new File(currentDir, newFolderStr);
int errorNumber = XmlResponse.EN_UKNOWN;

if (newFolder.exists())
errorNumber = XmlResponse.EN_ALREADY_EXISTS;
else {
try {
errorNumber = (newFolder.mkdir()) ? XmlResponse.EN_OK
: XmlResponse.EN_INVALID_FOLDER_NAME;
} catch (SecurityException e) {
errorNumber = XmlResponse.EN_SECURITY_ERROR;
}
}
xr.setError(errorNumber);
}
}
}

out.print(xr);
out.flush();
out.close();
logger.debug("Exiting ConnectorServlet#doGet");
}

/**
* Manage the <code>POST</code> requests (<code>FileUpload</code>).<br />
*
* The servlet accepts commands sent in the following format:<br />
* <code>connector?Command=<FileUpload>&Type=<ResourceType>&CurrentFolder=<FolderPath></code>
* with the file in the <code>POST</code> body.<br />
* <br>
* It stores an uploaded file (renames a file if another exists with the
* same name) and then returns the JavaScript callback.
*/
@SuppressWarnings("unchecked")
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
logger.debug("Entering Connector#doPost");

response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
PrintWriter out = response.getWriter();

String commandStr = request.getParameter("Command");
String typeStr = request.getParameter("Type");
String currentFolderStr = request.getParameter("CurrentFolder");

logger.debug("Parameter Command: {}", commandStr);
logger.debug("Parameter Type: {}", typeStr);
logger.debug("Parameter CurrentFolder: {}", currentFolderStr);

UploadResponse ur;

// if this is a QuickUpload request, 'commandStr' and 'currentFolderStr'
// are empty
if (Utils.isEmpty(commandStr) && Utils.isEmpty(currentFolderStr)) {
commandStr = "QuickUpload";
currentFolderStr = "/";
}

if (!RequestCycleHandler.isEnabledForFileUpload(request))
ur = new UploadResponse(UploadResponse.SC_SECURITY_ERROR, null,
null, Messages.NOT_AUTHORIZED_FOR_UPLOAD);
else if (!CommandHandler.isValidForPost(commandStr))
ur = new UploadResponse(UploadResponse.SC_ERROR, null, null,
Messages.INVALID_COMMAND);
else if (typeStr != null && !ResourceTypeHandler.isValid(typeStr))
ur = new UploadResponse(UploadResponse.SC_ERROR, null, null,
Messages.INVALID_TYPE);
else if (!UtilsFile.isValidPath(currentFolderStr))
ur = UploadResponse.UR_INVALID_CURRENT_FOLDER;
else {
ResourceTypeHandler resourceType = ResourceTypeHandler
.getDefaultResourceType(typeStr);

String typePath = UtilsFile.constructServerSidePath(request,
resourceType);
String typeDirPath = getServletContext().getRealPath(typePath);

File typeDir = new File(typeDirPath);
UtilsFile.checkDirAndCreate(typeDir);

File currentDir = new File(typeDir, currentFolderStr);

if (!currentDir.exists())
ur = UploadResponse.UR_INVALID_CURRENT_FOLDER;
else {

String newFilename = null;
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//-----------修改上传中文名乱码
upload.setHeaderEncoding("UTF-8");
//-----------完毕
try {

List<FileItem> items = upload.parseRequest(request);

// We upload only one file at the same time
FileItem uplFile = items.get(0);
String rawName = UtilsFile.sanitizeFileName(uplFile
.getName());
String filename = FilenameUtils.getName(rawName);
String baseName = FilenameUtils.removeExtension(filename);
String extension = FilenameUtils.getExtension(filename);

//-----------修改上传文件名字,用UUID方法
filename = UUID.randomUUID().toString() + "." + extension;
//-----------完毕

//-----------添加限制上传大小方法
//-----------如果这个文件的扩展名不允许上传

if (!ExtensionsHandler.isAllowed(resourceType, extension))
ur = new UploadResponse(
UploadResponse.SC_INVALID_EXTENSION);

//-----------如果超出大小1000M
else if (uplFile.getSize() > 1000000 * 1024)
//-----------传递一个自定义的错误码
ur = new UploadResponse(204);

//-----------如果不存在以上情况,则保存
else {

// construct an unique file name
File pathToSave = new File(currentDir, filename);

int counter = 1;
while (pathToSave.exists()) {
newFilename = baseName.concat("(").concat(
String.valueOf(counter)).concat(")")
.concat(".").concat(extension);
pathToSave = new File(currentDir, newFilename);
counter++;
}

if (Utils.isEmpty(newFilename))
ur = new UploadResponse(UploadResponse.SC_OK,
UtilsResponse.constructResponseUrl(request,
resourceType, currentFolderStr,
true, ConnectorHandler.isFullUrl())
.concat(filename));
else
ur = new UploadResponse(UploadResponse.SC_RENAMED,
UtilsResponse.constructResponseUrl(request,
resourceType, currentFolderStr,
true, ConnectorHandler.isFullUrl())
.concat(newFilename), newFilename);

// secure image check
if (resourceType.equals(ResourceTypeHandler.IMAGE)
&& ConnectorHandler.isSecureImageUploads()) {
if (UtilsFile.isImage(uplFile.getInputStream()))
uplFile.write(pathToSave);
else {
uplFile.delete();
ur = new UploadResponse(
UploadResponse.SC_INVALID_EXTENSION);
}
} else
uplFile.write(pathToSave);

}
} catch (Exception e) {
ur = new UploadResponse(UploadResponse.SC_SECURITY_ERROR);
}
}

}

out.print(ur);
out.flush();
out.close();

logger.debug("Exiting Connector#doPost");
}

}

4.1.4. 限制上传文件类型
根据 net.fckeditor.handlers 包下的default.properties 的配置 。default.properties有许多的基本设置。
在我们新建的fckeditor.properties设置,用以覆盖defualt.properties里的设置
4.2. FCKeditor无法打开浏览服务器的问题
4.2.1. 解决方法
配置:
fckconfig.js中
var _FileBrowserLanguage = 'php' ; // asp | aspx | cfm | lasso | perl | php | py
改成PHP,默认是ASP,也就是会出现你那个XML提示
另外:
fckeditor/editor/filemanager/browser/default/connectors/php/config.php
中的,
$Config['Enabled'] = true ;//这个默认是false

$Config['UserFilesPath'] = '/myphppro/' ;//这个值相对于网站根目录
你的e:\ftp\www\,那么新建个文件夹myphppro就是这个配置了,呵呵!~
基本上完成上面的,就可以正确的浏览到服务器上的文件。为了方便分类存放,FCK默认会自动创建相应的目录,如image ……,废话到此结束,试试看!
但是通过查看发现,没有JSP方法,所以在Java里就不要使用浏览服务器文件这个功能。
4.2.2. 通常解决方法(Java)
这个问题通常的解决方式是禁止浏览服务器文件,避免不必要的安全问题。
FCKConfig.LinkBrowser = false ;
FCKConfig.LinkBrowserURL = FCKConfig.BasePath + 'filemanager/browser/default/browser.html?Connector=' + encodeURIComponent( FCKConfig.BasePath + 'filemanager/connectors/' + _FileBrowserLanguage + '/connector.' + _FileBrowserExtension ) ;
FCKConfig.LinkBrowserWindowWidth = FCKConfig.ScreenWidth * 0.7 ; // 70%
FCKConfig.LinkBrowserWindowHeight = FCKConfig.ScreenHeight * 0.7 ; // 70%

FCKConfig.ImageBrowser = false ;
FCKConfig.ImageBrowserURL = FCKConfig.BasePath + 'filemanager/browser/default/browser.html?Type=Image&Connector=' + encodeURIComponent( FCKConfig.BasePath + 'filemanager/connectors/' + _FileBrowserLanguage + '/connector.' + _FileBrowserExtension ) ;
FCKConfig.ImageBrowserWindowWidth = FCKConfig.ScreenWidth * 0.7 ; // 70% ;
FCKConfig.ImageBrowserWindowHeight = FCKConfig.ScreenHeight * 0.7 ; // 70% ;

FCKConfig.FlashBrowser = false ;
FCKConfig.FlashBrowserURL = FCKConfig.BasePath + 'filemanager/browser/default/browser.html?Type=Flash&Connector=' + encodeURIComponent( FCKConfig.BasePath + 'filemanager/connectors/' + _FileBrowserLanguage + '/connector.' + _FileBrowserExtension ) ;
FCKConfig.FlashBrowserWindowWidth = FCKConfig.ScreenWidth * 0.7 ; //70% ;
FCKConfig.FlashBrowserWindowHeight = FCKConfig.ScreenHeight * 0.7 ; //70% ;
或者如下设置:
FCKeditor contentEditor = new FCKeditor(request, "ContentEditor");
contentEditor.setValue("添加详细内容");
FCKeditorConfig contentEditorConfig = contentEditor.getConfig();
contentEditorConfig.put("SkinPath",path+"/fckeditor/editor/skins/office2003/");
contentEditorConfig.put("ImageBrowser","false");
contentEditor.setWidth("800px");
contentEditor.setHeight("500px");
out.print(contentEditor);

5. FCKeditor添加自定义工具栏的问题
我们今天来做一个非常简单的工具按钮,就是点击这个按钮后会弹出一个对话框,只有一个输入框,我们输入的任何内容都会被插入到编辑器中去。这个工具按钮我们就叫做:MyToolBar吧,呵~~~

5.1. 修改fckconfig.js文件
(位于FCKeditor_2.5.zip压缩包解压后的fckeditor目录下)
1.我们找到FCKConfig.ToolbarSets["Default"]这一行,在最后即'About'后添加一个工具按钮MyToolBar,名称为MyToolBar;
2.找到FCKConfig.DefaultLanguage,修改语言为:zh-cn;
3.找到FCKConfig.AutoDetectLanguage,设置为false,即关闭语言的自动检测功能;

5.2. 修改zh-cn.js文件
(位于editor\lang目录下)
1.在最后加入:MyToolBar : "我的自定义工具栏"
2.注意它前面的一个最后要加多一个逗号;

5.3. 修改源码
1.打开文件fckregexlib.js(位于editor\_source\internals);
2.找到NamedCommands这一行,在最后加入:MyToolBar
3.然后再打开同目录下的fckcommands.js文件;
4.找到FCKCommands.GetCommand函数,在其中加入:

case 'MyToolBar' : oCommand = new FCKDialogCommand( 'MyToolBar', FCKLang.MyToolBar , 'dialog/MyToolBar.html', 450, 400 ) ; break ;

5.然后再打开同目录下的fcktoolbaritems.js文件;
6.找到FCKToolbarItems.GetItem函数,在其中加入:

case 'MyToolBar' : oItem = new FCKToolbarButton( 'MyToolBar' , FCKLang.MyToolBar, null, null, null, true, 72 ) ; break ;
这里72是表示skins目录下各个皮肤目录中fck_strip.gif图片文件中的图片索引,我们这里用和命令ShowBlocks一样的图标(一个问号图片)。

5.4. 建立模式对话框文件
1.打开目录editor\dialog,在其下建立文件:MyToolBar.html
2.内容如下:

01 <html>...</html><html xmlns="http://www.w3.org/1999/xhtml">
02 <head>...</head><head>
03 <title></title>
04 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
05 <meta content="noindex, nofollow" name="robots" />
06 <script src="common/fck_dialog_common.js" type="text/javascript"></script>
07 <script type="text/javascript">
08
09 var oEditor = window.parent.InnerDialogLoaded() ;
10
11 window.onload = function()
12 ...{
13 window.parent.SetOkButton( true ) ;
14 window.parent.SetAutoSize( true ) ;
15 }
16
17 function Ok()
18 ...{
19 var oActiveEl = oEditor.FCK.EditorDocument.createElement( 'SPAN' ) ;
20 oActiveEl.innerHTML = GetE('txtName').value ;
21 oEditor.FCKUndo.SaveUndoStep() ;
22 oActiveEl = oEditor.FCK.InsertElement( oActiveEl ) ;
23
24 return true ;
25 }
26 </script>
27 </head>
28 <body>...</body><body style="overflow: hidden">
29 <table width="100%" style="height: 100%">
30 <tr>
31 <td align="center">
32 <table cellspacing="0" cellpadding="0" border="0">
33 <tr><td>请输入文字:<input id="txtName" type="text"/></td></tr>
34 </table>
35 </td>
36 </tr>
37 </table>
38 </body>
39 </html>


5.5. 打包修改后的源代码
官方网站下载页面给出的那个压缩程序(.net写的)有问题,在运行的时候总是报错:Unhandled Exception: System.NullReferenceException: Object reference not set。然后在fckeditor论坛上找相关的帖子时发现另外一个地方可以下载,呵呵,一样是官方的,不过是php编译后的可执行程序。在windows下可以直接运行,非常方便。大家可以到这里下载:http://dev.fckeditor.net/browser/FCKpackager/trunk/fckpackager.exe。注意这个是下载页面,然后在页面在最下方点那个“downloading”下载即可!注意下下来的文件就是一个可执行程序fckpackager.exe。
1.copy这个程序(fckpackager.exe)到fckeditor目录下。
2.打开一个DOS窗口,定位到当前目录;
3.运行fckpackager命令即可。
4.命令运行后,DOS窗口会列出一长串的JS清单,然后最后会显示:
Number of files processed: 84
Original size............: 568,563 bytes
Output file size.........: 240,124 bytes (42.23% of original)

The generation of 2 files has been completed in 3.3316287994 seconds.
这样就表示文件已经压缩成功了!

5.6. 查看运行效果
打开目录_samples\html下的sample01.html文件,我们就可以在页面上的最后一个工具栏发现我们刚添加的这个按钮命令了。

5.7. 添加上下文菜单
我们在使用FCKeditor来添加一个单行输入框的时候,添加成功后会发现在编辑区域我们通过在该input员素上点右键就可以很方便的来编辑我们刚才输入的内容。这就是fckeditor中的contextmenu了,我们也可以非常方便的为我们自定义的工具栏来添加上下文菜单。
1.打开源文件夹中internals目录下的fck_contextmenu.js文件;
2.找到函数FCK_ContextMenu_GetListener,在最后加入一指定的CASE代码,具体的视自己的情况而写;
3.修改fckconfig.js在FCKConfig.ContextMenu的最后加入一菜单名称,注意要和你的第二步中的case的条件名称一样;
4.另外在zh-cn.js中添加一个上下文菜单的中文名称,然后在第二步中的代码中的menu.AddItem处使用该名称,通常的命名规范就是你的工具按钮的命令名称后加一个Prop;

通过这几步后就可以很方便的添加一个上下文菜单了,我前面的一篇文章也提到了这个,可以参考一下。
6. 参考资料
 http://www.iteye.com/topic/150487
 http://www.iteye.com/topic/266863
 http://www.iteye.com/topic/54509
 http://www.xoolong.com/bbs/simple/index.php?t88.html
 http://docs.fckeditor.net/FCKeditor_2.x/Developers_Guide
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值