itstarting:IT进行时

想自己所想,做自己所爱

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  28 随笔 :: 3 文章 :: 55 评论 :: 0 Trackbacks

以前公司购买过eWebEditor,功能应该还是不错的,但即便到了现在,也还仅是一个IE only的版本,无法满足现在差异化的需求。故前段时间下了最新的FCKeditor2.3.3版本下来(当然了,连带java的integration),demo来看看,发现有几个地方非常不爽:
1、上载的文件,只能放在URL可及的地方(如默认只能放到嵌入应用路径的/UserFiles/下);
2、没有明确的上载视频的按钮;
3、图片、FLASH、附件上载等,步骤多,复杂度高(想想,用户不都是高手)。

怎么办呢,改!

一、第一个就是增加一个FileLocatorServlet,思路很简单:通过这个服务来定位文件,而不是之间产生链接,既是安全的考虑,也是应用集群的一个重要考虑点。而且原来的几个servlet的配置罗嗦且重叠,难以让人产生美感。所谓代码胜千言,通过下面的web.xml大家应该可以看出修理的要点:

  1 <? xml version="1.0" encoding="ISO-8859-1" ?>
  2
  3 <! DOCTYPE web-app
  4   PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
  5   "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd" >
  6
  7 < web-app >
  8    < display-name > FCKeditor Test Application </ display-name >   
  9      < context-param >
 10          <!--  setting the FCKecitor context based parameters  -->
 11          <!--  baseDir means the root of the uploaded file/image/flash stored 
 12              the prefix of 'file:/' means strore in a file system root that cannot get from webapp url
 13          -->
 14          < param-name > baseDir </ param-name >
 15          < param-value > file:/C:/Temp/FCKeditorUpload/ </ param-value >
 16      </ context-param >  
 17
 18      < context-param >
 19          <!--  
 20              if the baseDir prefix by 'file:/',please set it.
 21          -->
 22          < param-name > fileLocator </ param-name >
 23          < param-value > /editor/filemanager/browser/default/service/jsp/filelocator </ param-value >
 24      </ context-param >  
 25
 26      < context-param >
 27          <!--  
 28              debug setting,true means verbose output to the console.
 29          -->
 30          < param-name > debug </ param-name >
 31          < param-value > true </ param-value >
 32      </ context-param >  
 33
 34      < context-param >
 35          <!--  
 36              enabled setting,true means upload enabled.
 37          -->
 38          < param-name > enabled </ param-name >
 39          < param-value > true </ param-value >
 40      </ context-param >  
 41
 42      < context-param >
 43          <!--  
 44              encoding,the response encoding of the file/image/flash,default is UTF-8
 45          -->
 46          < param-name > encoding </ param-name >
 47          < param-value > UTF-8 </ param-value >
 48      </ context-param >  
 49
 50      < context-param >
 51          <!--  
 52              contentTypeMapping,a map for the response ContentType
 53          -->
 54          < param-name > contentTypeMapping </ param-name >
 55          < param-value > doc=application/vnd.ms-word
 56         |xls=application/vnd.ms-excel
 57         |jpg=image/jpeg
 58         |gif=image/gif
 59         |swf=application/x-shockwave-flash
 60         |avi=video/x-msvideo
 61          </ param-value >
 62      </ context-param >  
 63
 64      < context-param >
 65          <!--  
 66              allowedExtensionsFile,the logic is 'Not allowed means deny.'
 67          -->
 68          < param-name > allowedExtensionsFile </ param-name >
 69          < param-value > doc|xls|pdf|avi </ param-value >
 70      </ context-param >  
 71
 72      < context-param >
 73          <!--  
 74              allowedExtensionsImage,the logic is 'Not allowed means deny.'
 75          -->
 76          < param-name > allowedExtensionsImage </ param-name >
 77          < param-value > jpg|gif|png </ param-value >
 78      </ context-param >  
 79
 80      < context-param >
 81          <!--  
 82              allowedExtensionsFlash,the logic is 'Not allowed means deny.'
 83          -->
 84          < param-name > allowedExtensionsFlash </ param-name >
 85          < param-value > swf|fla </ param-value >
 86      </ context-param >
 87
 88      < servlet >
 89          < servlet-name > Connector </ servlet-name >
 90          < servlet-class > com.fredck.FCKeditor.connector.ConnectorServlet </ servlet-class >
 91          < load-on-startup > 1 </ load-on-startup >
 92      </ servlet >
 93     
 94      < servlet >
 95          < servlet-name > FileLocator </ servlet-name >
 96          < servlet-class > com.fredck.FCKeditor.service.FileLocatorServlet </ servlet-class >
 97          < load-on-startup > 1 </ load-on-startup >
 98      </ servlet >
 99
100      < servlet >
101          < servlet-name > SimpleUploader </ servlet-name >
102          < servlet-class > com.fredck.FCKeditor.uploader.SimpleUploaderServlet </ servlet-class >
103          < load-on-startup > 1 </ load-on-startup >
104      </ servlet >
105
106    < servlet-mapping >
107      < servlet-name > Connector </ servlet-name >
108      < url-pattern > /editor/filemanager/browser/default/connectors/jsp/connector </ url-pattern >
109    </ servlet-mapping >
110   
111    < servlet-mapping >
112      < servlet-name > SimpleUploader </ servlet-name >
113      < url-pattern > /editor/filemanager/upload/simpleuploader </ url-pattern >
114    </ servlet-mapping >   
115   
116    < servlet-mapping >
117      < servlet-name > FileLocator </ servlet-name >
118      < url-pattern > /editor/filemanager/browser/default/service/jsp/filelocator </ url-pattern >
119    </ servlet-mapping >   
120
121 </ web-app >

连带FCKeditorConfigurations.java一并修理,配置统一且singleton。关键代码为:

 1
 2      /**
 3      * Make the configuration sigleton
 4      *  @param  sc
 5      *  @return  the static configuration map
 6       */

 7      public   static  Map getContextConfigurationsInstance(ServletContext sc) {
 8          if (contextConfigurations == null ) {
 9             initContextConfigurations(sc);
10         }

11          return  contextConfigurations;
12     }

13     
14      /**
15      * Init all the FCKeditor configuration.
16      * add by zhengxq
17      *  @param  sc
18       */

19      private   static   void  initContextConfigurations(ServletContext sc) {
20          if  (debug)
21             System.out.println( " \r\n---- FCKeditorConfigurations for java initialization started ---- " );
22         
23         String baseDir  =  sc.getInitParameter( " baseDir " );
24         String fileLocator  =  sc.getInitParameter( " fileLocator " );
25         String debugStr  =  sc.getInitParameter( " debug " );
26         String enabledStr  =  sc.getInitParameter( " enabled " );        
27         String encoding  =  sc.getInitParameter( " encoding " );
28         String contentTypeMapping  =  sc.getInitParameter( " contentTypeMapping " );
29         String AllowedExtensionsFile  =  sc.getInitParameter( " allowedExtensionsFile " );
30         String AllowedExtensionsImage  =  sc.getInitParameter( " allowedExtensionsImage " );
31         String AllowedExtensionsFlash  =  sc.getInitParameter( " allowedExtensionsFlash " );
32         
33         debug  =  ( new  Boolean(debugStr)).booleanValue();
34         encoding  =  (encoding == null   ||  encoding.length() == 0 ) ? " UTF-8 " :encoding;
35         
36          if (baseDir == null   ||  baseDir.length() == 0 ) baseDir  =  defaultBaseDir;
37         String realBaseDir  =  defaultBaseDir;
38          if  (baseDir.startsWith(fileSystemUriPrefix))  {
39             realBaseDir  =  baseDir.substring(fileSystemUriPrefix.length());            
40         }
  else   {
41             realBaseDir  =  sc.getRealPath(baseDir);
42             fileLocator  =   null ; // no use and should set null
43         }

44         File baseFile = new  File(realBaseDir);
45          if ( ! baseFile.exists()) {
46             baseFile.mkdir();
47         }

48         contextConfigurations  =   new  HashMap();
49         contextConfigurations.put( " baseDir " ,baseDir);
50         contextConfigurations.put( " realBaseDir " ,realBaseDir);
51         contextConfigurations.put( " fileLocator " ,fileLocator);
52         contextConfigurations.put( " debug " ,debugStr);
53         contextConfigurations.put( " enabled " ,enabledStr);
54         contextConfigurations.put( " encoding " ,encoding);
55         contextConfigurations.put( " contentTypeMapping " ,contentTypeMappingToMap(contentTypeMapping));
56         contextConfigurations.put( " allowedExtensionsFile " ,stringToArrayList(AllowedExtensionsFile));
57         contextConfigurations.put( " allowedExtensionsImage " ,stringToArrayList(AllowedExtensionsImage));
58         contextConfigurations.put( " allowedExtensionsFlash " ,stringToArrayList(AllowedExtensionsFlash));
59         
60          if  (debug)
61             System.out.println( " \r\n---- FCKeditorConfigurations for java initialization end ---- " );
62         
63     }


FileLocatorServlet.java也很简单,无非就是文件的物理定位和文件流的输出:

 1 String type  =  request.getParameter( " Type " );
 2         String fileName  =  request.getParameter( " FileName " );
 3
 4         String realFilePath  =  config.get( " realBaseDir " +  type  +   " / "   +  fileName;
 5         File file  =   new  File(realFilePath);
 6          if  (file.exists())  {
 7             response.setHeader( " Content-Transfer-Encoding " " base64 " );
 8             response.setHeader( " Cache-Control " " no-store " );
 9             response.setHeader( " Pragma " " no-cache " );
10             response.setDateHeader( " Expires " 0 );
11             response.setContentType(getContentTypeByFileExt(fileName.substring(fileName.lastIndexOf( " . " ))));
12             
13             ServletOutputStream out  =  response.getOutputStream();            
14             InputStream in  =   new  FileInputStream(file);
15             BufferedInputStream bis  =   new  BufferedInputStream(in);
16             BufferedOutputStream bos  =   new  BufferedOutputStream(out);
17              byte [] buff  =   new   byte [ 2048 ];
18              int  bytesRead;
19              while  ( - 1   !=  (bytesRead  =  bis.read(buff,  0 , buff.length)))  {
20                 bos.write(buff,  0 , bytesRead);
21             }

22              if  (bis  !=   null {
23                 bis.close();
24             }

25              if  (bos  !=   null {
26                 bos.close();
27             }

28         }
  else   {
29              throw   new  FileNotFoundException(fileName);
30         }

上述改动已经提交给了FCKeditor,如果大家真的有兴趣,可以去找里面我所提交的patch。

二、至于上述的2、3问题,同样,动手即可解决,在此略过。

过程中倒是碰到几个有意思的问题,成了花絮,其实也是使用FCKeditor的一些心得,写写可能还有点意思:
1、如何取得FCKeditor的值?
答案:这是我们常常干的事情:取得这个值并赋值给某个hidden,再合法性检查+submit等。怎么取得呢?这样:

1      var  oEditor  =  FCKeditorAPI.GetInstance('editor') ;
2      // Get the editor contents in XHTML.
3      // alert( oEditor.GetXHTML(true) ) ;    // "true" means you want it formatted.
4     document.all( " tip.c_content " ).value = oEditor.GetXHTML( true );

2、如何使得FCKeditor接收tab键?
答案:我们希望界面元素按照外面的安排进行tab切换,但FCKeditor怎么能做到呢?也有办法:

1 function  focusIframeOnTab(caller, tabTargetId, callEvent) {
2                  //  If keypress TAB and not SHIFT+TAB 
3                  if (callEvent.keyCode  ==   9   &&   ! callEvent.shiftKey)
4                     document.getElementById(tabTargetId).contentWindow.focus();
5             }

光光有个函数顶个什么用,还要这样:在之前的那个界面元素中加上下面的事件,如使用struts的tag的化,这样就可以了:

< html:text  property ="tip.c_title"  style ="width:450px"  tabindex ="1"  onkeydown ="focusIframeOnTab(this, 'editor___Frame',event);if(!document.all) return false;" />

这点是google了半天最终在FCKeditor的FAQ中找到的,看来以后用开源的软件第一件事情就是看FAQ,错不了!

3、如何希望在FCKeditor加载完毕后做点什么事情?
答案:也很简单,编写自己的FCKeditor_OnComplete函数,如:

function  FCKeditor_OnComplete( editorInstance )  {
                window.status 
=  editorInstance.Description ;
            }


4、如果在图片、FLASH等界面中上载了东西后,希望能告诉自己的表单,怎么做?
答案:这个花了我不少看代码和调试时间!其实这里的关键就是如何获取嵌入FCKeditor的那个window,这样就可以了,在对应的js文件(如editor\dialog\fck_image\fck_image.js)中的ok方法的最后加入:


    
// edit by zhengxq
     try {        
        
var  obj  =  window.dialogArguments.Editor.parent.document;
        obj.getElementById(
" tip.c_tip_has_pic " ).value  =   " 1 " ;
    }
catch (e) {}     

关键就是:window.dialogArguments.Editor.parent.document,这个能够找到对应窗口的引用,有了这个,还不会控制吗?!

posted on 2007-03-11 20:20 IT进行时 阅读(6837) 评论(12)  编辑  收藏 所属分类: Java Tips

评论

# re: FCKeditor的几点重要改进和使用心得,值得分享 2007-03-11 21:22 祎恬凡
谢谢搂住共享!q是多少,好随时请教阿!
  回复  更多评论
  

# re: FCKeditor的几点重要改进和使用心得,值得分享 2007-03-12 09:36 darkbluefeeling
不认同FileLocatorServlet.java的做法。web的集群已经是非常成熟的技术,不存在你提到的风险,而且web服务器处理这行静态文件效率非常高。楼主这样把静态文件丢给应用服务器去做,如果访问量比较高的话,问题会非常多。  回复  更多评论
  

# re: FCKeditor的几点重要改进和使用心得,值得分享 2007-03-12 17:11 IT进行时
to darkbluefeeling:
谢谢反馈!
据我所知,对于基于session上载的文件,一般的app中间件(包括IBM WAS5/6)都不具备集群同步的能力,难道你另有高招?请不吝赐教。  回复  更多评论
  

# re: FCKeditor的几点重要改进和使用心得,值得分享[未登录] 2007-03-13 10:28 jacky
我也是类似的修改了.  回复  更多评论
  

# re: FCKeditor的几点重要改进和使用心得,值得分享 2007-07-14 11:10 gok
请问楼上知不知道怎样截获FCKeditor的文本编辑区的按键事件,我弄了很久,都没有成功。  回复  更多评论
  

# re: FCKeditor的几点重要改进和使用心得,值得分享 2007-11-30 11:22 IT进行时
有基于二次开发的API的,可以找找看。  回复  更多评论
  

# re: FCKeditor的几点重要改进和使用心得,值得分享 2008-02-18 23:07 FastUnit
收藏。  回复  更多评论
  

# re: FCKeditor的几点重要改进和使用心得,值得分享 2008-03-22 21:38 flyfan
刚学用FCKeditor,你的文章受益不浅,转贴了  回复  更多评论
  

# re: FCKeditor的几点重要改进和使用心得,值得分享 2010-03-10 10:43 王彬
我问个问题,FCKeditor编辑器里面的内容我怎么添加到隐藏的textarea里
  回复  更多评论
  

# re: FCKeditor的几点重要改进和使用心得,值得分享 2010-03-10 11:10 IT进行时
to 王彬:

文档你可能没看清楚,或者我没理解你的意思。
如果要添加到textarea,意味着两步:

//1、取得fckeditor实例;
var oEditor = FCKeditorAPI.GetInstance('editor') ;

//2、取得fckeditor的值并赋予textarea:
// "true" means you want it formatted.
document.getElementById(你的textarea对象).value = oEditor.GetXHTML( true );   回复  更多评论
  

# re: FCKeditor的几点重要改进和使用心得,值得分享 2010-03-10 11:33 王彬
@IT进行时
直接在window.onload这个js里面加吗
还是加载后加个function方法,我觉得我的主要问题应该是他没有实时把编辑器里面的内容写到textarea里  回复  更多评论
  

# re: FCKeditor的几点重要改进和使用心得,值得分享 2011-08-05 11:05 后生
我想在FCK上实现,光标在“源代码”按钮【左上角】后,能够在源代码下相同。。。

例如在设计模式时,光标在文章最后。
现在点击源代码按钮后,光标也在源代码最后~  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: