Python的Flask站点中集成xhEditor文本编辑器的教程
作者:digwtx 发布时间:2023-04-05 00:41:06
xhEditor简介
xhEditor是一个基于jQuery开发的简单迷你并且高效的可视化HTML编辑器,基于网络访问并且兼容IE 6.0+, Firefox 3.0+, Opera 9.6+, Chrome 1.0+, Safari 3.22+。
xhEditor曾经是我比较喜欢的编辑器,也是率先支持拖拽上传的编辑器之一。xhEditor在当年是优秀的编辑器,功能足够强大,使用体验也相当好,拖拽上传是我最喜欢的功能,只可惜已经停止开发了。xhEditor最后的稳定版本是1.1.14,至今已超过2年未更新(2013年发布了开发版本1.2.1),作者已经停止开发和维护了,社区论坛完全不能打开。
由于xhEditor基于jQuery开发,而对于新版本的jQuery,它并不能很好的支持,只有1.4版本的jQuery是支持得最好的。
虽然已经不再更新了,但在一些需要富文本编辑器的场合,她还是可以完全胜任的。
本文以1.1.14版本为例,讲述如何在Flask项目中使用xhEditor编辑器,并实现图片上传、文件上传的后端功能。
xhEditor主要特点:
精简迷你:初始加载4个文件,包括:1个js(50k)+2个css(10k)+1个图片(5k),总共65k。若js和css文件进行gzip压缩传输,可以进一步缩减为24k左右。
使用简单:简单的调用方式,加一个class属性就能将您的textarea立马变成一个功能丰富的可视化编辑器。
无障碍访问:提供WAI-ARIA全面支持,全键盘精细操作,全程语音向导,提供完美无障碍访问体验,让残疾人也能够谱写精彩人生。
内置Ajax上传:内置强大的Ajax上传,包括HTML4和HTML5上传支持(多文件上传、真实上传进度及文件拖放上传),剪切板上传及远程抓取上传,追求完美的用户上传体验。
Word自动清理:实现Word代码自动检测并清理,提供高效完美的Word代码过滤方案,生成代码最优化精简,但是却不丢失任何细节效果。
UBB可视化编辑:提供完美的UBB可视化编辑解决方案,在您获得安全高效代码存储的同时,又能享受可视化编辑的便捷。
在Flask项目中使用xhEditor
首先我们需要到xhEditor官网下载1.1.14版本的xhEditor编辑器,下载之后解压到
Flask项目的static/xheditor目录。
xhEditor提供2种初始化方式:Class初始化和JavaScript初始化。Class初始化只需要给textarea设置值为xheditor的class属性,它就会自动变成xhEditor编辑器,一个页面可以同时同在多个编辑器,而且这个类属性可以添加参数。(PS:CKEditor也有这个功能)
对于这两种初始化方式,官网有提供设置很方便的设置向导,使得配置相对比较简单。
示例代码:
<head>
<script type="text/javascript" charset="utf-8" src="{{ url_for('static', filename='xheditor/jquery/jquery-1.4.4.min.js') }}"></script>
<script type="text/javascript" charset="utf-8" src="{{ url_for('static', filename='xheditor/xheditor-1.1.14-zh-cn.min.js') }}"></script>
<style>.xheditor {width: 640px; height:320px;}</style>
</head>
<body>
<textarea id="content" name="content" class="xheditor {tools:'mfull'}"></textarea>
</body>
现在,我们就拥有一个xhEditor编辑器了。
开启上传功能
xhEditor的上传功能需要设置几个参数(以图片上传为例):
upImgUrl : 图片文件上传接收URL,例:/upload/,可使用内置变量{editorRoot}
upImgExt : 图片上传前限制本地文件扩展名,默认:jpg,jpeg,gif,png
这里假设上传文件接收URL为/upload/,我们的编辑器初始化代码就变成:
<textarea class="xheditor {tools:'mfull',upImgUrl:'/upload/'}"></textarea>
其他类型的文件上传设置类推。
Flask处理上传请求
xhEditor支持2种上传方式:标准HTML4上传和HTML5上传。
HTML4上传使用标准的表单上传域,上传文件域的name为:filedata
HTML5上传的整个POST数据流就是上传的文件完整数据,而本地文件名等信息储
存于HTTP_CONTENT_DISPOSITION这个服务器变量中
返回内容必需是标准的json字符串,结构可以是如下:
{"err":"","msg":"200906030521128703.gif"} 或者
{"err":"","msg":{"url":"200906030521128703.jpg","localfile":"test.jpg","id":"1"}}
注:若选择结构2,则url变量是必有。
文件上传处理示例代码:
def gen_rnd_filename():
filename_prefix = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
return '%s%s' % (filename_prefix, str(random.randrange(1000, 10000)))
@app.route('/upload/', methods=['GET', 'POST'])
def upload():
'''文件上传函数
本函数未做上传类型判断及上传大小判断。
'''
result = {"err": "", "msg": {"url": "", "localfile": ""}}
if request.method == 'POST' and 'filedata' in request.files:
# 传统上传模式,IE浏览器使用这种模式
fileobj = request.files['filedata']
fname, fext = os.path.splitext(fileobj.filename)
rnd_name = '%s%s' % (gen_rnd_filename(), fext)
fileobj.save(os.path.join(app.static_folder, 'upload', rnd_name))
result["msg"]["localfile"] = fileobj.filename
result["msg"]["url"] = '!%s' % \
url_for('static', filename='%s/%s' % ('upload', rnd_name))
elif 'CONTENT_DISPOSITION' in request.headers:
# HTML5上传模式,FIREFOX等默认使用此模式
pattern = re.compile(r"""\s.*?\s?filename\s*=\s*['|"]?([^\s'"]+).*?""", re.I)
_d = request.headers.get('CONTENT_DISPOSITION').encode('utf-8')
if urllib.quote(_d).count('%25') > 0:
_d = urllib.unquote(_d)
filenames = pattern.findall(_d)
if len(filenames) == 1:
result["msg"]["localfile"] = urllib.unquote(filenames[0])
fname, fext = os.path.splitext(filenames[0])
img = request.data
rnd_name = '%s%s' % (gen_rnd_filename(), fext)
with open(os.path.join(app.static_folder, 'upload', rnd_name), 'wb') as fp:
fp.write(img)
result["msg"]["url"] = '!%s' % \
url_for('static', filename='%s/%s' % ('upload', rnd_name))
return json.dumps(result)
远程抓图
一般情况下,当复制站外的图片时,我们希望可以把图片保存到本地,远程抓图就可以完成这个事情。
启用远程抓图功能,需要设置2个参数:
localUrlTest : 非本站域名测试正则表达式
remoteImgSaveUrl : 远程图片抓取接收程序URL
设置这2个参数之后,我们的编辑器初始化代码变成:
<textarea class="xheditor {tools:'mfull',upImgUrl:'/upload/',localUrlTest:/^https?:\/\/[^\/]*?(localhost:?\d*)\//i,remoteImgSaveUrl:'/uploadremote/'}"></textarea>
这里表示抓取除localhost之外其它域名的图片。
远程抓图处理示例代码:
def gen_rnd_filename():
filename_prefix = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
return '%s%s' % (filename_prefix, str(random.randrange(1000, 10000)))
@app.route('/uploadremote/', methods=['POST'])
def uploadremote():
"""
xheditor保存远程图片简单实现
URL用"|"分隔,返回的字符串也是用"|"分隔
返回格式是字符串,不是JSON格式
"""
localdomain_re = re.compile(r'https?:\/\/[^\/]*?(localhost:?\d*)\/', re.I)
imageTypes = {'gif': '.gif', 'jpeg': '.jpg', 'jpg': '.jpg', 'png': '.png'}
urlout = []
result = ''
srcUrl = request.form.get('urls')
if srcUrl:
urls = srcUrl.split('|')
for url in urls:
if not localdomain_re.search(url.strip()):
downfile = urllib.urlopen(url)
fext = imageTypes[downfile.headers.getsubtype().lower()]
rnd_name = '%s%s' % (gen_rnd_filename(), fext)
with open(os.path.join(app.static_folder, 'upload', rnd_name), 'wb') as fp:
fp.write(downfile.read())
urlreturn = url_for('static', filename='%s/%s' % ('upload', rnd_name))
urlout.append(urlreturn)
else:
urlout.append(url)
result = '|'.join(urlout)
return result


猜你喜欢
- 今天在使用ORDER BY的过程中出现了一点问题,发现之前对ORDER BY理解是错误的。 之前在w3s网站上看到ORDER BY的用法,以
- 这一篇笔记介绍 Django 系统 model 的外键处理,ForeignKey 以及相应的处理方法。这是一种一对多的字段类型,表示两张表之
- 一、场景说明在面试接口自动化时,经常会问,其他接口调用的前提条件是当前用户必须是登录状态,如何处理接口依赖?在此之前我们介绍过session
- 轮播图的根本其实就是缓动函数的封装,如果说轮播图是一辆跑动的汽车,那么缓动函数就是它的发动机,今天本文章就带大家由简入繁,封装属于自己的缓动
- 本文实例讲述了MHA实现mysql主从数据库手动切换的方法,分享给大家供大家参考。具体方法如下:一、准备工作1、分别在Master和Slav
- models.py:from django.db import models # 出版社class Publisher(models.Mod
- 公司在codereview的时候限制了看代码的时间,实际上不少代码属于框架自动生成,并不需要花费太多时间看,为了达标,需要刷点时间(鼠标点击
- 起源当同一个远程服务器有多个人使用的时候,想知道服务器是否有人在用,我们不能直接的去登录,因为这样可能会把对方挤下来,这并不友好,所以这里提
- 所谓网络爬虫,通俗的讲,就是通过向我们需要的URL发出http请求,获取该URL对应的http报文主体内容,之后提取该报文主体中我们所需要的
- 我们在网页开发过程中经常会有打印页面的需求,通过JS来实现的方法有很多,这里我做了一个整理,供大家参考。方式一:window.print()
- 前言在进行一个应用系统的开发过程中,从上到下一般需要四个构件:客户端-业务逻辑层-数据访问层-数据库,其中数据访问层是一个底层、核心的技术。
- Python + OpenCV 直接上代码import cv2 import numpy as np from matplotlib imp
- 为什么要实现分页?在大部分网站中分页的功能都是必要的,尤其是在后台管理中分页更是不可或缺分页能带给用户更好的体验,也能减轻服务器的压力对于分
- 问题:编写一个在1,2,…,9(顺序不能变)数字之间插入+或-或什么都不插入,使得计算结果总是100的程序,并输出所有的可能性。例如:1 +
- 操作 redisimport redisredisPool = redis.ConnectionPool(host='192.168
- 这是官方对SubFolders的介绍:返回由指定文件夹中所有子文件夹(包括隐藏文件夹和系统文件夹)组成的 Folders 集合。object
- 本文实例讲述了Python实现基于PIL和tesseract的验证码识别功能。分享给大家供大家参考,具体如下:之前搞这个搞了一段时间,后面遇
- 如果你退出 Python 解释器并重新进入,你做的任何定义(变量和方法)都会丢失。因此,如果你想要编写一些更大的程序,为准备解释器输入使用一
- 起步上一篇 《Python 的枚举类型》 文末说有机会的话可以看看它的源码。那就来读一读,看看枚举的几个重要的特性是如何实现的。要想阅读这部
- 上次更新到pygame实现俄罗斯方块游戏(基础篇3)现在继续一、定义玩家类定义玩家类是为了便于进行手动和机器模式或各种不同机器人模式的混合使