一个多用户的系统,上传图像文件等,希望不同用户的图像上传到它专有的目录里。我最初查到在PHP版的FCKEditor是通过设置$Config('UserFilesPath')来实现,但Rails版的FCKEditor没有此项设置(搜索UserFilesPath关键字后做出此判断)。接着,我查看了FCKEditor关键的fckeditor_controller.rb的源代码,似乎它并不支持此项设置。再看javaeye是怎么用FCKEditor的,发现它放弃了FCKEditor的上传功能。google了半天,除了那些转来转去的相同内容的帖子之外(搞不懂有了google之后,怎么还会有人费劲去转帖别人的文章),一点营养也没有。在JavaEye发了个求助帖,没人理 :-( 。 传说中高手云集的JavaEye,其Rails版块真是冷清,给人阴飕飕的感觉。没办法,自己改源代码吧。
1.修改fckeditor_controller.rb,把它那几个private方法修改如下:
private
def current_directory_path
base_dir = "#{RAILS_ROOT}/public"
#TODO 在创建用户时,就建立好目录。这时可以去掉这部份代码,提高运行效率。
("#{params[:uploaded]||UPLOADED}/#{params[:Type]}").split('/').each do |s|
next if s==''
base_dir += '/' + s
Dir.mkdir(base_dir,0775) unless File.exists?(base_dir)
end
check_path("#{base_dir}#{params[:CurrentFolder]}")
end
def upload_directory_path
uploaded = @request.relative_url_root.to_s+"#{params[:uploaded]||UPLOADED}/#{params[:Type]}"
"#{uploaded}#{params[:CurrentFolder]}"
end
def check_file(file)
# check that the file is a tempfile object
unless "#{file.class}" == "Tempfile" || "#{file.class}" == "StringIO"
@errorNumber = 403
throw Exception.new
end
file
end
def check_path(path)
exp_path = File.expand_path path
if exp_path !~ %r[^#{File.expand_path(RAILS_ROOT)}/public#{params[:uploaded]||UPLOADED}]
@errorNumber = 403
throw Exception.new
end
path
end
另外,它前面的常量UPLOADED_ROOT也没用了,可以删掉。
2. 在上面的代码中
params[:uploaded]是关键,它就是我们动态定义的上传目录。该值来自于FCKEditor的一些html页面,它是通过get参数传入的。修改browser.html文件(如下粗体部份),在它的url请求中把我们定义目录加入到get参数列中,这样它就可以传到fckeditor_controller.rb里了
。
var sServerPath = GetUrlParam( 'ServerPath' ) ;
if ( sServerPath.length > 0 )
oConnector.ConnectorUrl += 'ServerPath=' + escape( sServerPath ) + '&' ;
var sUploaded = GetUrlParam( 'uploaded' ) ;
if ( sUploaded.length > 0 )
oConnector.ConnectorUrl += 'uploaded=' + escape( sUploaded ) + '&' ;
oConnector.ResourceType = GetUrlParam( 'Type' ) ;
oConnector.ShowAllTypes = ( oConnector.ResourceType.length == 0 ) ;
3. 上面的GetUrlParam( 'uploaded' ) 的值来自于fckcustom.js。修改fckcustom.js(如下粗体部份),把uploaded加入到get参数列中。
// CHANGE FOR APPS HOSTED IN SUBDIRECTORY
FCKRelativePath = '';
// DON'T CHANGE THESE
FCKConfig.LinkBrowserURL = FCKConfig.BasePath + 'filemanager/browser/default/browser.html?Connector='+FCKRelativePath+'/fckeditor/command';
FCKConfig.ImageBrowserURL = FCKConfig.BasePath + 'filemanager/browser/default/browser.html?uploaded='+FCKConfig.uploaded+'&Type=Image&Connector='+FCKRelativePath+'/fckeditor/command';
FCKConfig.FlashBrowserURL = FCKConfig.BasePath + 'filemanager/browser/default/browser.html?uploaded='+FCKConfig.uploaded+'&Type=Flash&Connector='+FCKRelativePath+'/fckeditor/command';
FCKConfig.LinkUploadURL = FCKRelativePath+'/fckeditor/upload';
FCKConfig.ImageUploadURL = FCKRelativePath+'/fckeditor/upload?Type=Image&uploaded='+FCKConfig.uploaded;
FCKConfig.FlashUploadURL = FCKRelativePath+'/fckeditor/upload?Type=Flash&uploaded='+FCKConfig.uploaded;
FCKConfig.AllowQueryStringDebug = false;
FCKConfig.SpellChecker = 'SpellerPages';
// ONLY CHANGE BELOW HERE
FCKConfig.SkinPath = FCKConfig.BasePath + 'skins/silver/';
FCKConfig.AutoDetectLanguage = false ;
FCKConfig.DefaultLanguage = 'zh-cn' ;
FCKConfig.FontNames = '微软雅黑;宋体;黑体;隶书;楷体_GB2312;Arial;Comic Sans MS;Courier New;Tahoma;Times New Roman;Verdana' ;
FCKConfig.ToolbarSets["Simple"] = [
['Source','-','FitWindow','Preview','-','Templates'],
['PasteText','PasteWord'],
['Undo','Redo','Find','Replace'],
'/',
['RemoveFormat','Bold','Italic','Underline','StrikeThrough'],
['OrderedList','UnorderedList','Outdent','Indent'],
['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],
['TextColor','BGColor'],
['Link','Unlink','Anchor'],
['Image','Flash','Table','Rule','Smiley'],
'/',
['Style','FontFormat','FontName','FontSize']
] ;
4. 上面FCKConfig.uploaded的值来自于fckeditor.rb。在fckeditor.rb中加入一句(如下粗体所示)。
javascript_tag( "var oFCKeditor = new FCKeditor('#{id}', '#{width}', '#{height}', '#{toolbarSet}');\n"+
"oFCKeditor.BasePath = \"#{base_path}\"\n"+
"oFCKeditor.Config['CustomConfigurationsPath'] = '../../fckcustom.js';\n"+
"oFCKeditor.Config['uploaded'] = '#{options[:path]}';\n"+
"oFCKeditor.ReplaceTextarea();\n")
5.
不过上面oFCKeditor.Config['uploaded']的值要传到fckcustom.js的FCKConfig.uploaded里,还需要修改fckeditorcode_gecko.js和fckeditorcode_ie.js(这两个文件对javascript进行了压缩处理,修改起来较难操作)。我是参考了oFCKeditor.Config['CustomConfigurationsPath'] 这个参数的载入实现,才找到这种鸟不生蛋的地方。搜索这两个文件的关键字
CustomConfigurationsPath,找到如下一行,然后加入一个else if判断(如下粗体所示)。
if (D=='CustomConfigurationsPath') FCKConfig[D]=E;else if (D=='uploaded') FCKConfig[D]=E;else if (E.toLowerCase()=="true") this.PageConfig[D]=true;
6.最后在fckeditor.rb里的#{options[:path]}来自于我们前台的view了。如下粗体所示,把标准的fckedit
or_textarea新增加了一个参数,其中params[:user_id]是把用户的ID值做为目录名。这样就实现了动态改变FCKEditor的上传目录。<%=fckeditor_textarea(:topic, :content, :ajax => true, :toolbarSet => 'Simple', :height => '400px', :path => "/uploads/#{params[:user_id]}") %>
修改完后需要重启WEB服务,最后别忘记把public/javascripts/fckeditor和vendor/plugins/fckeditor/public/javascripts同步一下,原因见http://www.blogjava.net/chengang/archive/2007/09/24/147867.html