浏览代码

Merge pull request #1 from xinyvz/master

Master
WeizhongTu 10 年之前
父节点
当前提交
c92b7ce80a

+ 0 - 59
.gitignore

@@ -1,59 +0,0 @@
-#### joe made this: http://goel.io/joe
-
-#####=== Python ===#####
-
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-env/
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-*.egg-info/
-.installed.cfg
-*.egg
-
-# PyInstaller
-#  Usually these files are written by a python script from a template
-#  before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.coverage
-.cache
-nosetests.xml
-coverage.xml
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-target/
-

二进制
DjangoUeditor/__init__.pyc


二进制
DjangoUeditor/__pycache__/__init__.cpython-34.pyc


二进制
DjangoUeditor/__pycache__/commands.cpython-34.pyc


二进制
DjangoUeditor/__pycache__/models.cpython-34.pyc


二进制
DjangoUeditor/__pycache__/settings.cpython-34.pyc


二进制
DjangoUeditor/__pycache__/urls.cpython-34.pyc


二进制
DjangoUeditor/__pycache__/views.cpython-34.pyc


二进制
DjangoUeditor/__pycache__/widgets.cpython-34.pyc


+ 1 - 1
DjangoUeditor/commands.py

@@ -1,6 +1,6 @@
 # coding:utf-8
 import urllib
-import settings as USettings
+import DjangoUeditor.settings as USettings
 
 
 class UEditorEventHandler(object):

二进制
DjangoUeditor/commands.pyc


二进制
DjangoUeditor/forms.pyc


+ 1 - 1
DjangoUeditor/models.py

@@ -1,7 +1,7 @@
 #coding: utf-8
 from django.db import models
 from django.contrib.admin import widgets as admin_widgets
-from widgets import UEditorWidget,AdminUEditorWidget
+from .widgets import UEditorWidget,AdminUEditorWidget
 
 
 class UEditorField(models.TextField):

二进制
DjangoUeditor/models.pyc


+ 2 - 2
DjangoUeditor/settings.py

@@ -94,8 +94,8 @@ UEditorUploadSettings={
 #更新配置:从用户配置文件settings.py重新读入配置UEDITOR_SETTINGS,覆盖默认
 def UpdateUserSettings():
     UserSettings=getattr(gSettings,"UEDITOR_SETTINGS",{}).copy()
-    if UserSettings.has_key("config"):UEditorSettings.update(UserSettings["config"])
-    if UserSettings.has_key("upload"):UEditorUploadSettings.update(UserSettings["upload"])
+    if "config" in UserSettings: UEditorSettings.update(UserSettings["config"])
+    if "upload" in UserSettings: UEditorUploadSettings.update(UserSettings["upload"])
 
 #读取用户Settings文件并覆盖默认配置
 UpdateUserSettings()

二进制
DjangoUeditor/settings.pyc


+ 1 - 1
DjangoUeditor/urls.py

@@ -5,7 +5,7 @@ if VERSION[0:2]>(1,3):
 else:
     from django.conf.urls.defaults import patterns, url
 
-from views import get_ueditor_controller
+from .views import get_ueditor_controller
 
 urlpatterns = patterns('',
     url(r'^controller/$',get_ueditor_controller)

二进制
DjangoUeditor/urls.pyc


二进制
DjangoUeditor/utils.pyc


+ 15 - 8
DjangoUeditor/views.py

@@ -1,10 +1,12 @@
 #coding:utf-8
+from importlib import import_module
 from django.http import HttpResponse
-import settings as USettings
+import DjangoUeditor.settings as USettings
 import os
 import json
 from django.views.decorators.csrf import csrf_exempt
-import datetime,random
+from datetime import datetime
+import random
 import urllib
 
 def get_path_format_vars():
@@ -24,7 +26,7 @@ def save_upload_file(PostFile,FilePath):
         f = open(FilePath, 'wb')
         for chunk in PostFile.chunks():
             f.write(chunk)
-    except Exception,E:
+    except Exception as E:
         f.close()
         return u"写入文件错误:"+ E.message
     f.close()
@@ -193,10 +195,15 @@ def UploadFile(request):
     #所有检测完成后写入文件
     if state=="SUCCESS":
         if action=="uploadscrawl":
-            state=save_scrawl_file(request,os.path.join(OutputPath,OutputFile))
+            state=save_scrawl_file(request, os.path.join(OutputPath,OutputFile))
         else:
             #保存到文件中,如果保存错误,需要返回ERROR
-            state=save_upload_file(file,os.path.join(OutputPath,OutputFile))
+            upload_module_name = USettings.UEditorUploadSettings.get("upload_module", None)
+            if upload_module_name:
+                mod = import_module(upload_module_name)
+                state = mod.upload(file, OutputPathFormat)
+            else:
+                state = save_upload_file(file, os.path.join(OutputPath, OutputFile))
 
     #返回数据
     return_info = {
@@ -248,9 +255,9 @@ def catcher_remote_image(request):
                     f.write(remote_image.read())
                     f.close()
                     state="SUCCESS"
-                except Exception,E:
+                except Exception as E:
                     state=u"写入抓取图片文件错误:%s" % E.message
-            except Exception,E:
+            except Exception as E:
                 state=u"抓取图片错误:%s" % E.message
 
             catcher_infos.append({
@@ -293,7 +300,7 @@ def save_scrawl_file(request,filename):
         f.write(base64.decodestring(content))
         f.close()
         state="SUCCESS"
-    except Exception,E:
+    except Exception as E:
         state="写入图片文件错误:%s" % E.message
     return state
 

二进制
DjangoUeditor/views.pyc


+ 5 - 4
DjangoUeditor/widgets.py

@@ -5,8 +5,8 @@ from django.contrib.admin.widgets import AdminTextareaWidget
 from django.template.loader import render_to_string
 from django.utils.safestring import mark_safe
 from django.utils.http import urlencode
-import settings as USettings
-from  commands import *
+import DjangoUeditor.settings as USettings
+from  .commands import *
 
 # 修正输入的文件路径,输入路径的标准格式:abc,不需要前后置的路径符号
 #如果输入的路径参数是一个函数则执行,否则可以拉接受时间格式化,用来生成如file20121208.bmp的重命名格式
@@ -63,10 +63,11 @@ class UEditorWidget(forms.Textarea):
         #以下处理工具栏设置,将normal,mini等模式名称转化为工具栏配置值
         if toolbars == "full":
             del self.ueditor_settings['toolbars']
-        elif isinstance(toolbars, basestring) and toolbars in USettings.TOOLBARS_SETTINGS:
+        elif isinstance(toolbars, str) and toolbars in USettings.TOOLBARS_SETTINGS:
             self.ueditor_settings["toolbars"]=USettings.TOOLBARS_SETTINGS[toolbars]
         else:
-            raise ValueError('toolbars should be a string defined in DjangoUeditor.settings.TOOLBARS_SETTINGS, options are full(default), besttome, mini and normal!')
+            self.ueditor_settings["toolbars"] = toolbars
+            # raise ValueError('toolbars should be a string defined in DjangoUeditor.settings.TOOLBARS_SETTINGS, options are full(default), besttome, mini and normal!')
         self.ueditor_settings.update(settings)
         super(UEditorWidget, self).__init__(attrs)
 

二进制
DjangoUeditor/widgets.pyc


+ 0 - 0
build/lib/DjangoUeditor/__init__.py


+ 182 - 0
build/lib/DjangoUeditor/commands.py

@@ -0,0 +1,182 @@
+# coding:utf-8
+import urllib
+import settings as USettings
+
+
+class UEditorEventHandler(object):
+    """用来处理UEditor的事件侦听"""
+    def on_selectionchange(self):
+        return ""
+    def on_contentchange(self):
+        return ""
+    def render(self,editorID):
+        jscode="""
+            %(editor)s.addListener('%(event)s', function () {
+                %(event_code)s
+        });"""
+        event_codes=[]
+        #列出所有on_打头的方法,然后在ueditor中进行侦听
+        events=filter(lambda x: x[0:3]=="on_", dir(self))
+        for event in events:
+            try:
+                event_code=getattr(self,event)()
+                if event_code:
+                    event_code=event_code % {"editor":editorID}
+                    event_codes.append(jscode % {"editor":editorID,"event":event[3:],"event_code":event_code})
+            except:
+                pass
+
+        if len(event_codes)==0:
+            return ""
+        else:
+            return "\n".join(event_codes)
+
+class UEditorCommand(object):
+    """
+    为前端增加按钮,下拉等扩展,
+    """
+    def __init__(self,**kwargs):
+        self.uiName=kwargs.pop("uiName","")
+        self.index=kwargs.pop("index",0)
+        self.title=kwargs.pop("title",self.uiName)
+        self.ajax_url=kwargs.pop("ajax_url","")
+
+    def render_ui(self,editor):
+        """" 创建ueditor的ui扩展对象的js代码,如button,combo等  """
+        raise NotImplementedError
+
+
+
+    def render_ajax_command(self):
+        """"生成通过ajax调用后端命令的前端ajax代码"""
+        if not self.ajax_url: return ""
+
+        return u"""
+            UE.ajax.request( '%(ajax_url)s', {
+                 data: {
+                     name: 'ueditor'
+                 },
+                 onsuccess: function ( xhr ) {%(ajax_success)s},
+                 onerror: function ( xhr ){ %(ajax_error)s }
+            });
+        """ % {
+            "ajax_url":self.ajax_url,
+            "ajax_success":self.onExecuteAjaxCommand("success"),
+            "ajax_error":self.onExecuteAjaxCommand("error")
+        }
+
+    def render_command(self):
+        """" 返回注册命令的js定义  """
+        cmd=self.onExecuteCommand()
+        ajax_cmd=self.render_ajax_command()
+        queryvalue_command=self.onExecuteQueryvalueCommand()
+        cmds=[]
+        if cmd or ajax_cmd:
+            cmds.append( u"""execCommand: function() {
+                    %(exec_cmd)s
+                    %(exec_ajax_cmd)s
+                }
+            """ % {"exec_cmd":cmd,"exec_ajax_cmd":ajax_cmd},)
+
+        if queryvalue_command:
+            cmds.append(u"""queryCommandValue:function(){
+                    %s
+                }""" % queryvalue_command)
+        if len(cmds)>0:
+            return u"""
+            editor.registerCommand(uiName, {
+                    %s
+                });
+            """ % ",".join(cmds)
+        else:
+            return ""
+
+    def render(self,editorID):
+        return u"""
+        UE.registerUI("%(uiName)s", function(editor, uiName) {
+            %(registerCommand)s
+            %(uiObject)s
+        },%(index)s,"%(editor)s");
+        """ % {
+                "registerCommand":self.render_command(),
+                "uiName":self.uiName,
+                "uiObject":self.render_ui(editorID),
+                "index":self.index,
+                "editor":editorID
+            }
+
+    def onExecuteCommand(self):
+        """ 返回执行Command时的js代码 """
+        return ""
+    def onExecuteAjaxCommand(self,state):
+        """ 返回执行Command时发起Ajax调用成功与失败的js代码 """
+        return ""
+    def onExecuteQueryvalueCommand(self):
+        """" 返回执行QueryvalueCommand时的js代码 """
+        return ""
+
+class UEditorButtonCommand(UEditorCommand):
+    def __init__(self,**kwargs):
+        self.icon = kwargs.pop("icon", "")
+        super(UEditorButtonCommand, self).__init__(**kwargs)
+
+    def onClick(self):
+        """"按钮单击js代码,默认执行uiName命令,默认会调用Command """
+        return """
+            editor.execCommand(uiName);
+        """
+    def render_ui(self,editorID):
+        """         创建button的js代码:        """
+        return """
+            var btn = new UE.ui.Button({
+                name: uiName,
+                title: "%(title)s",
+                cssRules: "background-image:url('%(icon)s')!important;",
+                onclick: function() {
+                    %(onclick)s
+                }
+            });
+            return btn
+        """ % {
+                "icon": urllib.basejoin(USettings.gSettings.MEDIA_URL , self.icon),
+                "onclick": self.onClick(),
+                "title": self.title
+            }
+
+
+class UEditorComboCommand(UEditorCommand):
+    def __init__(self,**kwargs):
+        self.items = kwargs.pop("items", [])
+        self.initValue=kwargs.pop("initValue","")
+
+        super(UEditorComboCommand, self).__init__(**kwargs)
+
+    def get_items(self):
+        return self.items
+
+    def onSelect(self):
+        return ""
+
+    def render_ui(self,editorID):
+        """         创建combo的js代码:        """
+        return """
+        var combox = new UE.ui.Combox({
+            editor:editor,
+            items:%(items)s,
+            onselect:function (t, index) {
+                %(onselect)s
+            },
+            title:'%(title)s',
+            initValue:'%(initValue)s'
+        });
+        return combox;
+        """ % {
+                "title":self.title,
+                "items":str(self.get_items()),
+                "onselect": self.onSelect(),
+                "initValue":self.initValue
+        }
+
+
+class UEditorDialogCommand(UEditorCommand):
+    pass

+ 34 - 0
build/lib/DjangoUeditor/forms.py

@@ -0,0 +1,34 @@
+#coding: utf-8
+
+from django import forms
+from widgets import UEditorWidget
+from DjangoUeditor.models import UEditorField as ModelUEditorField
+
+class UEditorField(forms.CharField):
+    def __init__(self,label,width=600, height=300, toolbars="full",imagePath="", filePath="",upload_settings={},settings={},command=None ,event_handler=None,*args,**kwargs):
+        uSettings=locals().copy()
+        del uSettings["self"],uSettings["label"],uSettings["args"],uSettings["kwargs"]
+        kwargs["widget"]=UEditorWidget(attrs=uSettings)
+        kwargs["label"]=label
+        super(UEditorField,self).__init__( *args, **kwargs)
+
+def UpdateUploadPath(model_form,model_inst=None):
+    """ 遍历model字段,如果是UEditorField则需要重新计算路径 """
+    if model_inst is not  None:
+        try:
+            for field in model_inst._meta.fields:
+                if isinstance(field, ModelUEditorField):
+                    model_form.__getitem__(field.name).field.widget.recalc_path(model_inst)
+        except:
+            pass
+
+class UEditorModelForm(forms.ModelForm):
+    def __init__(self,*args,**kwargs):
+        super(UEditorModelForm,self).__init__(*args,**kwargs)
+        try:
+            if kwargs.has_key("instance"):
+                UpdateUploadPath(self,kwargs["instance"])
+            else:
+                UpdateUploadPath(self,None)
+        except Exception:
+            pass

+ 33 - 0
build/lib/DjangoUeditor/models.py

@@ -0,0 +1,33 @@
+#coding: utf-8
+from django.db import models
+from django.contrib.admin import widgets as admin_widgets
+from widgets import UEditorWidget,AdminUEditorWidget
+
+
+class UEditorField(models.TextField):
+    """
+    百度HTML编辑器字段,初始化时,可以提供以下参数
+        initial:初始内容
+        toolbars:提供工具按钮列表,取值为列表,如['bold', 'italic'],取值为:mini,normal,full,代表小,一般,全部
+        imagePath:图片上传的路径,如"images/",实现上传到"{{MEDIA_ROOT}}/images"文件夹
+        filePath:附件上传的路径,如"files/",实现上传到"{{MEDIA_ROOT}}/files"文件夹
+    """
+    def __init__(self,verbose_name=None, width=600, height=300, toolbars="full",imagePath="", filePath="",upload_settings={},settings={},command=None,event_handler=None ,**kwargs):
+        self.ueditor_settings=locals().copy()
+        kwargs["verbose_name"]=verbose_name
+        del self.ueditor_settings["self"],self.ueditor_settings["kwargs"],self.ueditor_settings["verbose_name"]
+        super(UEditorField,self).__init__(**kwargs)
+
+    def formfield(self,**kwargs):
+        defaults = {'widget': UEditorWidget(attrs=self.ueditor_settings)}
+        defaults.update(kwargs)
+        if defaults['widget'] == admin_widgets.AdminTextareaWidget:
+            defaults['widget'] = AdminUEditorWidget(attrs=self.ueditor_settings)
+        return super(UEditorField, self).formfield(**defaults)
+
+#以下支持south
+try:
+    from south.modelsinspector import add_introspection_rules
+    add_introspection_rules([], ["^DjangoUeditor\.models\.UEditorField"])
+except:
+    pass

+ 112 - 0
build/lib/DjangoUeditor/settings.py

@@ -0,0 +1,112 @@
+#coding:utf-8
+from django.conf import settings as gSettings   #全局设置
+
+#工具栏样式,可以添加任意多的模式
+TOOLBARS_SETTINGS={
+    "besttome":[['source','undo', 'redo','bold', 'italic', 'underline','forecolor', 'backcolor','superscript','subscript',"justifyleft","justifycenter","justifyright","insertorderedlist","insertunorderedlist","blockquote",'formatmatch',"removeformat",'autotypeset','inserttable',"pasteplain","wordimage","searchreplace","map","preview","fullscreen"], ['insertcode','paragraph',"fontfamily","fontsize",'link', 'unlink','insertimage','insertvideo','attachment','emotion',"date","time"]],
+    "mini":[['source','|','undo', 'redo', '|','bold', 'italic', 'underline','formatmatch','autotypeset', '|', 'forecolor', 'backcolor','|', 'link', 'unlink','|','simpleupload','attachment']],
+    "normal":[['source','|','undo', 'redo', '|','bold', 'italic', 'underline','removeformat', 'formatmatch','autotypeset', '|', 'forecolor', 'backcolor','|', 'link', 'unlink','|','simpleupload', 'emotion','attachment', '|','inserttable', 'deletetable', 'insertparagraphbeforetable', 'insertrow', 'deleterow', 'insertcol', 'deletecol', 'mergecells', 'mergeright', 'mergedown', 'splittocells', 'splittorows', 'splittocols']]
+}
+
+#默认的Ueditor设置,请参见ueditor.config.js
+UEditorSettings={
+    "toolbars":TOOLBARS_SETTINGS["normal"],
+    "autoFloatEnabled":False,
+    "defaultPathFormat":"%(basename)s_%(datetime)s_%(rnd)s.%(extname)s"   #默认保存上传文件的命名方式
+}
+#请参阅php文件夹里面的config.json进行配置
+UEditorUploadSettings={
+   #上传图片配置项
+    "imageActionName": "uploadimage", #执行上传图片的action名称
+    "imageMaxSize": 10485760, #上传大小限制,单位B,10M
+    "imageFieldName": "upfile", #* 提交的图片表单名称 */
+    "imageUrlPrefix":"",
+    "imagePathFormat":"",
+    "imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], #上传图片格式显示
+
+    #涂鸦图片上传配置项 */
+    "scrawlActionName": "uploadscrawl", #执行上传涂鸦的action名称 */
+    "scrawlFieldName": "upfile", #提交的图片表单名称 */
+    "scrawlMaxSize": 10485760, #上传大小限制,单位B  10M
+    "scrawlUrlPrefix":"",
+    "scrawlPathFormat":"",
+
+    #截图工具上传 */
+    "snapscreenActionName": "uploadimage", #执行上传截图的action名称 */
+    "snapscreenPathFormat":"",
+    "snapscreenUrlPrefix":"",
+
+    #抓取远程图片配置 */
+    "catcherLocalDomain": ["127.0.0.1", "localhost", "img.baidu.com"],
+    "catcherPathFormat":"",
+    "catcherActionName": "catchimage", #执行抓取远程图片的action名称 */
+    "catcherFieldName": "source", #提交的图片列表表单名称 */
+    "catcherMaxSize": 10485760, #上传大小限制,单位B */
+    "catcherAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], #抓取图片格式显示 */
+    "catcherUrlPrefix":"",
+    #上传视频配置 */
+    "videoActionName": "uploadvideo", #执行上传视频的action名称 */
+    "videoPathFormat":"",
+    "videoFieldName": "upfile", # 提交的视频表单名称 */
+    "videoMaxSize": 102400000, #上传大小限制,单位B,默认100MB */
+    "videoUrlPrefix":"",
+    "videoAllowFiles": [
+        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
+        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid"], #上传视频格式显示 */
+
+    #上传文件配置 */
+    "fileActionName": "uploadfile", #controller里,执行上传视频的action名称 */
+    "filePathFormat":"",
+    "fileFieldName": "upfile",#提交的文件表单名称 */
+    "fileMaxSize": 204800000, #上传大小限制,单位B,200MB */
+    "fileUrlPrefix": "",#文件访问路径前缀 */
+    "fileAllowFiles": [
+        ".png", ".jpg", ".jpeg", ".gif", ".bmp",
+        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
+        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
+        ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
+        ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
+    ], #上传文件格式显示 */
+
+    #列出指定目录下的图片 */
+    "imageManagerActionName": "listimage", #执行图片管理的action名称 */
+    "imageManagerListPath":"",
+    "imageManagerListSize": 30, #每次列出文件数量 */
+    "imageManagerAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], #列出的文件类型 */
+    "imageManagerUrlPrefix": "",#图片访问路径前缀 */
+
+    #列出指定目录下的文件 */
+    "fileManagerActionName": "listfile", #执行文件管理的action名称 */
+    "fileManagerListPath":"",
+    "fileManagerUrlPrefix": "",
+    "fileManagerListSize": 30, #每次列出文件数量 */
+    "fileManagerAllowFiles": [
+        ".png", ".jpg", ".jpeg", ".gif", ".bmp",".tif",".psd"
+        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
+        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
+        ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
+        ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml",
+        ".exe",".com",".dll",".msi"
+    ] #列出的文件类型 */
+}
+
+
+#更新配置:从用户配置文件settings.py重新读入配置UEDITOR_SETTINGS,覆盖默认
+def UpdateUserSettings():
+    UserSettings=getattr(gSettings,"UEDITOR_SETTINGS",{}).copy()
+    if UserSettings.has_key("config"):UEditorSettings.update(UserSettings["config"])
+    if UserSettings.has_key("upload"):UEditorUploadSettings.update(UserSettings["upload"])
+
+#读取用户Settings文件并覆盖默认配置
+UpdateUserSettings()
+
+
+#取得配置项参数
+def GetUeditorSettings(key,default=None):
+    if UEditorSettings.has_key(key):
+        return UEditorSettings[key]
+    else:
+        return default
+
+
+

+ 12 - 0
build/lib/DjangoUeditor/urls.py

@@ -0,0 +1,12 @@
+#coding:utf-8
+from django import VERSION
+if VERSION[0:2]>(1,3):
+    from django.conf.urls import patterns, url
+else:
+    from django.conf.urls.defaults import patterns, url
+
+from views import get_ueditor_controller
+
+urlpatterns = patterns('',
+    url(r'^controller/$',get_ueditor_controller)
+)

+ 122 - 0
build/lib/DjangoUeditor/utils.py

@@ -0,0 +1,122 @@
+#coding: utf-8
+
+#文件大小类
+class FileSize():
+    SIZE_UNIT={"Byte":1,"KB":1024,"MB":1048576,"GB":1073741824,"TB":1099511627776L}
+    def __init__(self,size):
+        self.size=long(FileSize.Format(size))
+
+    @staticmethod
+    def Format(size):
+        import re
+        if isinstance(size,int) or isinstance(size,long):
+            return size
+        else:
+            if not isinstance(size,str):
+                return 0
+            else:
+                oSize=size.lstrip().upper().replace(" ","")
+                pattern=re.compile(r"(\d*\.?(?=\d)\d*)(byte|kb|mb|gb|tb)",re.I)
+                match=pattern.match(oSize)
+                if match:
+                    m_size, m_unit=match.groups()
+                    if m_size.find(".")==-1:
+                        m_size=long(m_size)
+                    else:
+                        m_size=float(m_size)
+                    if m_unit!="BYTE":
+                        return m_size*FileSize.SIZE_UNIT[m_unit]
+                    else:
+                        return m_size
+                else:
+                    return 0
+
+    #返回字节为单位的值
+    @property
+    def size(self):
+        return self.size
+    @size.setter
+    def size(self,newsize):
+        try:
+            self.size=long(newsize)
+        except:
+            self.size=0
+
+    #返回带单位的自动值
+    @property
+    def FriendValue(self):
+        if self.size<FileSize.SIZE_UNIT["KB"]:
+            unit="Byte"
+        elif self.size<FileSize.SIZE_UNIT["MB"]:
+            unit="KB"
+        elif self.size<FileSize.SIZE_UNIT["GB"]:
+            unit="MB"
+        elif self.size<FileSize.SIZE_UNIT["TB"]:
+            unit="GB"
+        else:
+            unit="TB"
+
+        if (self.size % FileSize.SIZE_UNIT[unit])==0:
+            return "%s%s" % ((self.size / FileSize.SIZE_UNIT[unit]),unit)
+        else:
+            return "%0.2f%s" % (round(float(self.size) /float(FileSize.SIZE_UNIT[unit]) ,2),unit)
+
+    def __str__(self):
+        return self.FriendValue
+
+    #相加
+    def __add__(self, other):
+        if isinstance(other,FileSize):
+            return FileSize(other.size+self.size)
+        else:
+            return FileSize(FileSize(other).size+self.size)
+    def __sub__(self, other):
+        if isinstance(other,FileSize):
+            return FileSize(self.size-other.size)
+        else:
+            return FileSize(self.size-FileSize(other).size)
+    def __gt__(self, other):
+        if isinstance(other,FileSize):
+            if self.size>other.size:
+                return True
+            else:
+                return False
+        else:
+            if self.size>FileSize(other).size:
+                return True
+            else:
+                return False
+    def __lt__(self, other):
+        if isinstance(other,FileSize):
+            if other.size>self.size:
+                return True
+            else:
+                return False
+        else:
+            if FileSize(other).size > self.size:
+                return True
+            else:
+                return False
+    def __ge__(self, other):
+        if isinstance(other,FileSize):
+            if self.size>=other.size:
+                return True
+            else:
+                return False
+        else:
+            if self.size>=FileSize(other).size:
+                return True
+            else:
+                return False
+    def __le__(self, other):
+        if isinstance(other,FileSize):
+            if other.size>=self.size:
+                return True
+            else:
+                return False
+        else:
+            if FileSize(other).size >= self.size:
+                return True
+            else:
+                return False
+

+ 295 - 0
build/lib/DjangoUeditor/views.py

@@ -0,0 +1,295 @@
+#coding:utf-8
+from django.http import HttpResponse
+import settings as USettings
+import os
+import json
+from django.views.decorators.csrf import csrf_exempt
+import datetime,random
+import urllib
+
+#保存上传的文件
+def save_upload_file(PostFile,FilePath):
+    try:
+        f = open(FilePath, 'wb')
+        for chunk in PostFile.chunks():
+            f.write(chunk)
+    except Exception,E:
+        f.close()
+        return u"写入文件错误:"+ E.message
+    f.close()
+    return u"SUCCESS"
+
+
+@csrf_exempt
+def get_ueditor_settings(request):
+    return HttpResponse(json.dumps(USettings.UEditorUploadSettings,ensure_ascii=False), content_type="application/javascript")
+
+def get_ueditor_controller(request):
+    """获取ueditor的后端URL地址    """
+
+    action=request.GET.get("action","")
+    reponseAction={
+        "config":get_ueditor_settings,
+        "uploadimage":UploadFile,
+        "uploadscrawl":UploadFile,
+        "uploadvideo":UploadFile,
+        "uploadfile":UploadFile,
+        "catchimage":catcher_remote_image,
+        "listimage":list_files,
+        "listfile":list_files
+    }
+    return reponseAction[action](request)
+
+
+@csrf_exempt
+def list_files(request):
+    """列出文件"""
+    if request.method!="GET":
+        return  HttpResponse(json.dumps(u"{'state:'ERROR'}") ,content_type="application/javascript")
+    #取得动作
+    action=request.GET.get("action","listimage")
+
+    allowFiles={
+        "listfile":USettings.UEditorUploadSettings.get("fileManagerAllowFiles",[]),
+        "listimage":USettings.UEditorUploadSettings.get("imageManagerAllowFiles",[])
+    }
+    listSize={
+        "listfile":USettings.UEditorUploadSettings.get("fileManagerListSize",""),
+        "listimage":USettings.UEditorUploadSettings.get("imageManagerListSize","")
+    }
+    listpath={
+        "listfile":USettings.UEditorUploadSettings.get("fileManagerListPath",""),
+        "listimage":USettings.UEditorUploadSettings.get("imageManagerListPath","")
+    }
+    #取得参数
+    list_size=long(request.GET.get("size",listSize[action]))
+    list_start=long(request.GET.get("start",0))
+
+    files=[]
+    root_path=os.path.join(USettings.gSettings.MEDIA_ROOT,listpath[action]).replace("\\","/")
+    files=get_files(root_path,root_path,allowFiles[action])
+
+    if (len(files)==0):
+        return_info={
+            "state":u"未找到匹配文件!",
+            "list":[],
+            "start":list_start,
+            "total":0
+        }
+    else:
+        return_info={
+            "state":"SUCCESS",
+            "list":files[list_start:list_start+list_size],
+            "start":list_start,
+            "total":len(files)
+        }
+
+    return HttpResponse(json.dumps(return_info),content_type="application/javascript")
+
+
+def get_files(root_path,cur_path, allow_types=[]):
+    files = []
+    items = os.listdir(cur_path)
+    for item in items:
+        item=unicode(item)
+        item_fullname = os.path.join(root_path,cur_path, item).replace("\\", "/")
+        if os.path.isdir(item_fullname):
+            files.extend(get_files(root_path,item_fullname, allow_types))
+        else:
+            ext = os.path.splitext(item_fullname)[1]
+            is_allow_list= (len(allow_types)==0) or (ext in allow_types)
+            if is_allow_list:
+                files.append({
+                    "url":urllib.basejoin(USettings.gSettings.MEDIA_URL ,os.path.join(os.path.relpath(cur_path,root_path),item).replace("\\","/" )),
+                    "mtime":os.path.getmtime(item_fullname)
+                })
+
+    return files
+
+
+@csrf_exempt
+def UploadFile(request):
+    """上传文件"""
+    if not request.method=="POST":
+        return  HttpResponse(json.dumps(u"{'state:'ERROR'}"),content_type="application/javascript")
+
+    state="SUCCESS"
+    action=request.GET.get("action")
+    #上传文件
+    upload_field_name={
+        "uploadfile":"fileFieldName","uploadimage":"imageFieldName",
+        "uploadscrawl":"scrawlFieldName","catchimage":"catcherFieldName",
+        "uploadvideo":"videoFieldName",
+    }
+    UploadFieldName=request.GET.get(upload_field_name[action],USettings.UEditorUploadSettings.get(action,"upfile"))
+
+    #上传涂鸦,涂鸦是采用base64编码上传的,需要单独处理
+    if action=="uploadscrawl":
+        upload_file_name="scrawl.png"
+        upload_file_size=0
+    else:
+        #取得上传的文件
+        file=request.FILES.get(UploadFieldName,None)
+        if file is None:return  HttpResponse(json.dumps(u"{'state:'ERROR'}") ,content_type="application/javascript")
+        upload_file_name=file.name
+        upload_file_size=file.size
+
+    #取得上传的文件的原始名称
+    upload_original_name,upload_original_ext=os.path.splitext(upload_file_name)
+
+    #文件类型检验
+    upload_allow_type={
+        "uploadfile":"fileAllowFiles",
+        "uploadimage":"imageAllowFiles",
+        "uploadvideo":"videoAllowFiles"
+    }
+    if upload_allow_type.has_key(action):
+        allow_type= list(request.GET.get(upload_allow_type[action],USettings.UEditorUploadSettings.get(upload_allow_type[action],"")))
+        if not upload_original_ext  in allow_type:
+            state=u"服务器不允许上传%s类型的文件。" % upload_original_ext
+
+    #大小检验
+    upload_max_size={
+        "uploadfile":"filwMaxSize",
+        "uploadimage":"imageMaxSize",
+        "uploadscrawl":"scrawlMaxSize",
+        "uploadvideo":"videoMaxSize"
+    }
+    max_size=long(request.GET.get(upload_max_size[action],USettings.UEditorUploadSettings.get(upload_max_size[action],0)))
+    if  max_size!=0:
+        from utils import FileSize
+        MF=FileSize(max_size)
+        if upload_file_size>MF.size:
+            state=u"上传文件大小不允许超过%s。" % MF.FriendValue
+
+    #检测保存路径是否存在,如果不存在则需要创建
+    upload_path_format={
+        "uploadfile":"filePathFormat",
+        "uploadimage":"imagePathFormat",
+        "uploadscrawl":"scrawlPathFormat",
+        "uploadvideo":"videoPathFormat"
+    }
+
+    path_format_var={
+        "basename":upload_original_name,
+        "extname":upload_original_ext[1:],
+        "filename":upload_file_name,
+        "time":datetime.datetime.now().strftime("%H%M%S"),
+        "datetime":datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
+        "rnd":random.randrange(100,999)
+    }
+    #取得输出文件的路径
+    OutputPathFormat,OutputPath,OutputFile=get_output_path(request,upload_path_format[action],path_format_var)
+
+    #所有检测完成后写入文件
+    if state=="SUCCESS":
+        if action=="uploadscrawl":
+            state=save_scrawl_file(request,os.path.join(OutputPath,OutputFile))
+        else:
+            #保存到文件中,如果保存错误,需要返回ERROR
+            state=save_upload_file(file,os.path.join(OutputPath,OutputFile))
+
+    #返回数据
+    return_info = {
+        'url': urllib.basejoin(USettings.gSettings.MEDIA_URL , OutputPathFormat) ,                # 保存后的文件名称
+        'original': upload_file_name,                  #原始文件名
+        'type': upload_original_ext,
+        'state': state,                         #上传状态,成功时返回SUCCESS,其他任何值将原样返回至图片上传框中
+        'size': upload_file_size
+    }
+    return HttpResponse(json.dumps(return_info,ensure_ascii=False),content_type="application/javascript")
+
+@csrf_exempt
+def catcher_remote_image(request):
+    """远程抓图,当catchRemoteImageEnable:true时,
+        如果前端插入图片地址与当前web不在同一个域,则由本函数从远程下载图片到本地
+    """
+    if not request.method=="POST":
+        return  HttpResponse(json.dumps( u"{'state:'ERROR'}"),content_type="application/javascript")
+
+    state="SUCCESS"
+
+    allow_type= list(request.GET.get("catcherAllowFiles",USettings.UEditorUploadSettings.get("catcherAllowFiles","")))
+    max_size=long(request.GET.get("catcherMaxSize",USettings.UEditorUploadSettings.get("catcherMaxSize",0)))
+
+    remote_urls=request.POST.getlist("source[]",[])
+    catcher_infos=[]
+    path_format_var={
+        "time":datetime.datetime.now().strftime("%H%M%S"),
+        "date":datetime.datetime.now().strftime("%Y%m%d"),
+        "datetime":datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
+        "rnd":random.randrange(100,999)
+    }
+    for remote_url in remote_urls:
+        #取得上传的文件的原始名称
+        remote_file_name=os.path.basename(remote_url)
+        remote_original_name,remote_original_ext=os.path.splitext(remote_file_name)
+        #文件类型检验
+        if remote_original_ext  in allow_type:
+            path_format_var.update({
+                "basename":remote_original_name,
+                "extname":remote_original_ext[1:],
+                "filename":remote_original_name
+            })
+            #计算保存的文件名
+            o_path_format,o_path,o_file=get_output_path(request,"catcherPathFormat",path_format_var)
+            o_filename=os.path.join(o_path,o_file).replace("\\","/")
+            #读取远程图片文件
+            try:
+                remote_image=urllib.urlopen(remote_url)
+                 #将抓取到的文件写入文件
+                try:
+                    f = open(o_filename, 'wb')
+                    f.write(remote_image.read())
+                    f.close()
+                    state="SUCCESS"
+                except Exception,E:
+                    state=u"写入抓取图片文件错误:%s" % E.message
+            except Exception,E:
+                state=u"抓取图片错误:%s" % E.message
+
+            catcher_infos.append({
+                "state":state,
+                "url":urllib.basejoin(USettings.gSettings.MEDIA_URL , o_path_format),
+                "size":os.path.getsize(o_filename),
+                "title":os.path.basename(o_file),
+                "original":remote_file_name,
+                "source":remote_url
+            })
+
+    return_info={
+        "state":"SUCCESS" if len(catcher_infos) >0 else "ERROR",
+        "list":catcher_infos
+    }
+
+    return HttpResponse(json.dumps(return_info,ensure_ascii=False),content_type="application/javascript")
+
+
+def get_output_path(request,path_format,path_format_var):
+    #取得输出文件的路径
+    OutputPathFormat=(request.GET.get(path_format,USettings.UEditorSettings["defaultPathFormat"]) % path_format_var).replace("\\","/")
+    #分解OutputPathFormat
+    OutputPath,OutputFile=os.path.split(OutputPathFormat)
+    OutputPath=os.path.join(USettings.gSettings.MEDIA_ROOT,OutputPath)
+    if not OutputFile:#如果OutputFile为空说明传入的OutputPathFormat没有包含文件名,因此需要用默认的文件名
+        OutputFile=USettings.UEditorSettings["defaultPathFormat"] % path_format_var
+        OutputPathFormat=os.path.join(OutputPathFormat,OutputFile)
+    if not os.path.exists(OutputPath):
+        os.makedirs(OutputPath)
+    return ( OutputPathFormat,OutputPath,OutputFile)
+
+#涂鸦功能上传处理
+@csrf_exempt
+def save_scrawl_file(request,filename):
+    import base64
+    try:
+        content=request.POST.get(USettings.UEditorUploadSettings.get("scrawlFieldName","upfile"))
+        f = open(filename, 'wb')
+        f.write(base64.decodestring(content))
+        f.close()
+        state="SUCCESS"
+    except Exception,E:
+        state="写入图片文件错误:%s" % E.message
+    return state
+
+

+ 151 - 0
build/lib/DjangoUeditor/widgets.py

@@ -0,0 +1,151 @@
+# coding:utf-8
+from django import forms
+from django.conf import settings
+from django.contrib.admin.widgets import AdminTextareaWidget
+from django.template.loader import render_to_string
+from django.utils.safestring import mark_safe
+from django.utils.http import urlencode
+import settings as USettings
+from  commands import *
+
+# 修正输入的文件路径,输入路径的标准格式:abc,不需要前后置的路径符号
+#如果输入的路径参数是一个函数则执行,否则可以拉接受时间格式化,用来生成如file20121208.bmp的重命名格式
+def calc_path(OutputPath, instance=None):
+    if callable(OutputPath):
+        try:
+            OutputPath = OutputPath(instance)
+        except:
+            OutputPath = ""
+    else:
+        try:
+            import datetime
+            OutputPath = datetime.datetime.now().strftime(OutputPath)
+        except:
+            pass
+
+    return OutputPath
+
+#width=600, height=300, toolbars="full", imagePath="", filePath="", upload_settings={},
+                # settings={},command=None,event_handler=None
+class UEditorWidget(forms.Textarea):
+    def __init__(self,attrs=None):
+
+        params=attrs.copy()
+
+        width=params.pop("width")
+        height=params.pop("height")
+        toolbars=params.pop("toolbars","full")
+        imagePath=params.pop("imagePath","")
+        filePath=params.pop("filePath","")
+        upload_settings=params.pop("upload_settings",{})
+        settings=params.pop("settings",{})
+        command=params.pop("command",None)
+        event_handler=params.pop("event_handler",None)
+
+        #扩展命令
+        self.command=command
+        self.event_handler=event_handler
+        #上传路径
+        self.upload_settings = upload_settings.copy()
+        self.upload_settings.update({
+            "imagePathFormat": imagePath,
+            "filePathFormat": filePath
+        })
+        #保存
+        self._upload_settings =self.upload_settings.copy()
+        self.recalc_path(None)
+
+        self.ueditor_settings ={
+            'toolbars':toolbars,
+            'initialFrameWidth':width,
+            'initialFrameHeight':height
+        }
+        #以下处理工具栏设置,将normal,mini等模式名称转化为工具栏配置值
+        try:
+            if type(toolbars)==str:
+                if toolbars =="full":
+                    del self.ueditor_settings['toolbars']
+                else:
+                    self.ueditor_settings["toolbars"]=USettings.TOOLBARS_SETTINGS[toolbars]
+        except:
+            pass
+        self.ueditor_settings.update(settings)
+        super(UEditorWidget, self).__init__(attrs)
+
+    def recalc_path(self, model_inst):
+        """计算上传路径,允许是function"""
+        try:
+            uSettings = self.upload_settings
+            if self._upload_settings.has_key("filePathFormat"):
+                uSettings['filePathFormat'] = calc_path(self._upload_settings['filePathFormat'], model_inst)
+            if self._upload_settings.has_key("imagePathFormat"):
+                uSettings['imagePathFormat'] = calc_path(self._upload_settings['imagePathFormat'], model_inst)
+            if self._upload_settings.has_key("scrawlPathFormat"):
+                uSettings['scrawlPathFormat'] = calc_path(self._upload_settings['scrawlPathFormat'], model_inst)
+            if self._upload_settings.has_key("videoPathFormat"):
+                uSettings['videoPathFormat'] = calc_path(self._upload_settings['videoPathFormat'], model_inst),
+            if self._upload_settings.has_key("snapscreenPathFormat"):
+                uSettings['snapscreenPathFormat'] = calc_path(self._upload_settings['snapscreenPathFormat'], model_inst)
+            if self._upload_settings.has_key("catcherPathFormat"):
+                uSettings['catcherPathFormat'] = calc_path(self._upload_settings['catcherPathFormat'], model_inst)
+            if self._upload_settings.has_key("imageManagerListPath"):
+                uSettings['imageManagerListPath'] = calc_path(self._upload_settings['imageManagerListPath'], model_inst)
+            if self._upload_settings.has_key("fileManagerListPath"):
+                uSettings['fileManagerListPath'] = calc_path(self._upload_settings['fileManagerListPath'], model_inst)
+            #设置默认值,未指定涂鸦、截图、远程抓图、图片目录时,默认均等于imagePath
+            if uSettings['imagePathFormat']!="":
+                uSettings['scrawlPathFormat']=uSettings['scrawlPathFormat'] if self._upload_settings.has_key("scrawlPathFormat") else uSettings['imagePathFormat']
+                uSettings['videoPathFormat']=uSettings['videoPathFormat'] if self._upload_settings.has_key("videoPathFormat") else uSettings['imagePathFormat']
+                uSettings['snapscreenPathFormat']=uSettings['snapscreenPathFormat'] if self._upload_settings.has_key("snapscreenPathFormat") else uSettings['imagePathFormat']
+                uSettings['catcherPathFormat']=uSettings['catcherPathFormat'] if self._upload_settings.has_key("catcherPathFormat") else uSettings['imagePathFormat']
+                uSettings['imageManagerListPath']=uSettings['imageManagerListPath'] if self._upload_settings.has_key("imageManagerListPath") else uSettings['imagePathFormat']
+            if uSettings['filePathFormat']!="":
+                uSettings['fileManagerListPath']=uSettings['fileManagerListPath'] if self._upload_settings.has_key("fileManagerListPath") else uSettings['filePathFormat']
+        except:
+            pass
+
+
+    def render(self, name, value, attrs=None):
+        if value is None: value = ''
+        #传入模板的参数
+        editor_id="id_%s" % name.replace("-", "_")
+        uSettings={
+            "name": name.replace("-", "_"),
+            "id": editor_id,
+            "value":value
+        }
+        if isinstance(self.command,list):
+            cmdjs=""
+            if isinstance(self.command,list):
+                for cmd in self.command:
+                    cmdjs=cmdjs+cmd.render(editor_id)
+            else:
+                cmdis=self.command.render(editor_id)
+            uSettings["commands"]=cmdjs
+
+
+        uSettings["settings"] = self.ueditor_settings.copy()
+        uSettings["settings"].update({
+            "serverUrl": "/ueditor/controller/?%s" % urlencode(self._upload_settings)
+        })
+        #生成事件侦听
+        if self.event_handler:
+            uSettings["bindEvents"]=self.event_handler.render(editor_id)
+
+        context = {
+            'UEditor': uSettings,
+            'STATIC_URL': settings.STATIC_URL,
+            'STATIC_ROOT': settings.STATIC_ROOT,
+            'MEDIA_URL': settings.MEDIA_URL,
+            'MEDIA_ROOT': settings.MEDIA_ROOT
+        }
+        return mark_safe(render_to_string('ueditor.html', context))
+
+    class Media:
+        js = ("ueditor/ueditor.config.js",
+              "ueditor/ueditor.all.min.js")
+
+
+class AdminUEditorWidget(AdminTextareaWidget,UEditorWidget ):
+    def __init__(self, **kwargs):
+        super(AdminUEditorWidget, self).__init__(**kwargs)

二进制
manage.pyc