【原创】【2】rich editor系列教程。了解document.execommand操作,保存丢失的range,实时反馈样式给工具栏
【原创】【2】rich editor系列教程。了解document.execommand操作,保存丢失的range,实时反馈样式给工具栏
索引目录:http://www.cnblogs.com/henryli/p/3439642.html
浏览器提供了document.execommand的一系列命令来实现文本、格式、插入等操作,当然,浏览器厂商支持不一致、或者跟预想结果不一样。导致了前端coder需要耗费更大的精力去实现一个兼容、统一的富文本编辑。
使用较多的浏览器api:
- execCommand ,设置格式样式等命令
- queryCommandState,查询命令返回结果。ps(根据这个,可以实现当前选区格式的实时反馈)
- queryCommandEnabled,返回布尔值,查询execCommand 命令是否可用,也就是是否可以成功执行当前命令
- queryCommandSupported 返回表明当前命令是否在当前区域上支持的 Boolean 值。
execCommand 命令总共有这些:
var CommandList = ["2D-Position", "absolutePosition", "backColor", "blockDirLTR", "blockDirRTL", "bold", "browseMode", "clearAuthenticationCache", "contentReadOnly", "copy", "createBookmark", "createLink", "cut", "decreaseFontSize", "delete", "dirLTR", "dirRTL", "editMode", "fontName", "fontSize", "foreColor", "formatBlock", "enableInlineTableEditing", "enableObjectResizing", "forwardDelete", "heading", "increaseFontSize", "indent", "inlineDirLTR", "inlineDirRTL", "insertButton", "insertFieldset", "insertIFrame", "insertInputButton", "insertInputCheckbox", "insertInputFileUpload", "insertInputHidden", "insertInputImage", "insertInputPassword", "insertInputRadio", "insertInputReset", "insertInputSubmit", "insertInputText", "insertMarquee", "insertBrOnReturn", "insertHorizontalRule", "insertImage", "insertHTML", "insertLineBreak", "insertOrderedList", "insertUnorderedList", "insertParagraph", "insertSelectDropdown", "insertSelectListbox", "insertTextArea", "insertText", "italic", "justifyCenter", "justifyLeft", "justifyRight", "justifyFull", "justifyNone", "liveResize", "multipleSelection", "open", "overWrite", "outdent", "paste", "playImage", "print", "redo", "removeFormat", "refresh", "removeParaFormat", "selectAll", "saveAs", "sizeToControl", "sizeToControlHeight", "sizeToControlWidth", "stop", "stopImage", "strikeThrough", "subscript", "superscript", "unBookmark", "underline", "undo", "unlink", "useCSS", "hiliteColor", "unselect", "styleWithCSS"]
其中有上一篇用到的insertBrOnReturn和insertHTML。有了命令列表我们可以做一个测试页,测试命令是否受浏览器支持。当然其中还是一部分是暂时还没有任何浏览器支持的,rich editor也只用到其中的一部分命令。
命令styleWithCSS,设置为true,如果浏览器支持,则改变格式使用表情的行内元素设置,反之使用b、i、u、font等标签设置,对于富文本来说,自然是使用标签来设置,行内样式权重过大,也不“语义”。
设置文本、段落格式、样式需要用到:bold、italic、underline、strikethrough、superscript、subscript、removeformat、forecolor、backcolor、fontfamily、fontsize、justifyleft、justifycenter、justifyright、indent、outdent
链接相关:createlink、unlink
插入设置内容:insertorderedlist、insertunorderedlist、insertImage、insertHTML、insertText
常用操作: selectAll、redo、undo、paste、print、copy
其中有些命令与我们预期的不一样:
- fontsize,预期可以设置px、em文本大小,但浏览器却统一口径,只给了<font size="[0-7]"></font>,font未来要被废弃,而且无法设置自定义大小,需求兼容修正
- undo、redo,如果是使用iframe作为编辑器,iframe的document的undo、redo是“完整的”,如果是div,那么将与页面的操作重叠,需要定制一套undo、redo功能
- 待续
当鼠标选择了编辑器以外的内容,这时候选择已经丢失了,使用插入图片、文本格式,如何保证操作的是编辑器的最后选择的选区呢?
ie总是考虑的更加完善,给开发者提供了很好的api。提供了bookmark的功能;同时,ie提供了onbeforedeactivate和onactivate,来监听blur之前、focus之前的操作,在这个时间段,来获取书签和设置选区的书签最好不过了
支持标准selection、range的浏览器就稍微麻烦了,需要我们把光标更改的时候,保存range到变量中,在需要的时候,设置回来。chrome跟ie 本身就支持document.onselectionchange,首选由ie支持的,绑定此方法,就可以监听选区改变了,
//ie绑定获取书签,设置书签方法
if ('onbeforedeactivate' in ifrWinOrEditor && document.selection) {
var ieRangeBookMark;
ifrWinOrEditor.attachEvent('onbeforedeactivate', function() {
doc.selection.getBookmark();
});
ifrWinOrEditor.attachEvent('onactivate', function() {
doc.selection.moveToBookmark(ieRangeBookMark);
});
} else {
//反之当选区更改的时候保存range
self._console('bind selectionchange');
if ('onselectionchange' in doc) {
Utils.bind(doc, 'selectionchange', function() {
self.saveRange();
});
} else {
Utils.bind(doc, 'mouseup', function() {
self.saveRange();
});
Utils.bind(doc, 'keyup', function(e) {
self.saveRange();
});
}
}
saveLastRange: function() {
this.getRange() && (this.lastRange = this.getRange().range);
},
setLastRange: function() {
if (this.lastRange && this.getRange()) {
var selection = this.getRange().selection;
if (selection.removeAllRanges) {
selection.removeAllRanges();
selection.addRange(this.lastRange);
}
}
}
最终还需要判断当前的selection是否在编辑器中,因为当div作为编辑器,此时的选区可能在页面其他地方。ie支持Element.contains来判断是否包含某元素,而w3c使用compareDocumentPosition来判断,判断的代码直接放在getRange中,这样非编辑器中的选区,返回的是null。代码如下:
//如果是div编辑器,要判断range是否在编辑器中
if (this.editor != node) {
var isChild;
if (this.editor.contains) {
isChild = this.editor.contains(node);
} else {
isChild = this.editor.compareDocumentPosition(node) == 20;
}
if (!isChild) {
range = text = selection = null;
}
}
demo已完成;点击下载
预览图:
update @ 2013-11-25 15:37:11
BY henry
mail : liyaohui.henry@gmail.com
【原创】【2】rich editor系列教程。了解document.execommand操作,保存丢失的range,实时反馈样式给工具栏的更多相关文章
- 【原创】【1】rich editor系列教程。前期准备,兼容
[1]前期准备,兼容 索引目录:http://www.cnblogs.com/henryli/p/3439642.html rich editor的原理无非是启用iframe的编辑模式或者div的co ...
- SpringBoot系列教程JPA之指定id保存
原文链接: 191119-SpringBoot系列教程JPA之指定id保存 前几天有位小伙伴问了一个很有意思的问题,使用 JPA 保存数据时,即便我指定了主键 id,但是新插入的数据主键却是 mysq ...
- Influx Sql系列教程二:retention policy 保存策略
retention policy这个东西相比较于传统的关系型数据库(比如mysql)而言,是一个比较新的东西,在将表之前,有必要来看一下保存策略有什么用,以及可以怎么用 I. 基本操作 1. 创建re ...
- 【原创】【目录】实现rich editor(富文本编辑器)教程,深入理解selectiona/range操作与浏览器差异
日常工作中,接触富文本编辑的次数还是很多,特发此教程,希望可以改变富文本编辑的技术门槛较高的现状,解决这部分的坑. 前提准备,兼容获取range,统一回车行为,前期准备工作 了解document.ex ...
- SpringBoot 系列教程 JPA 错误姿势之环境配置问题
191218-SpringBoot 系列教程 JPA 错误姿势之环境配置问题 又回到 jpa 的教程上了,这一篇源于某个简单的项目需要读写 db,本想着直接使用 jpa 会比较简单,然而悲催的是实际开 ...
- Influx Sql系列教程九:query数据查询基本篇二
前面一篇介绍了influxdb中基本的查询操作,在结尾处提到了如果我们希望对查询的结果进行分组,排序,分页时,应该怎么操作,接下来我们看一下上面几个场景的支持 在开始本文之前,建议先阅读上篇博文: 1 ...
- Influx Sql系列教程八:query数据查询基本篇
前面几篇介绍了InfluxDB的添加,删除修改数据,接下来进入查询篇,掌握一定的SQL知识对于理解本篇博文有更好的帮助,下面在介绍查询的基础操作的同时,也会给出InfluxSql与SQL之间的一些差别 ...
- Influx Sql系列教程七:delete 删除数据
前面介绍了使用insert实现新增和修改记录的使用姿势,接下来我们看一下另外一个简单的使用方式,如何删除数据 1. delete 语句 delete的官方语法如下 DELETE FROM <me ...
- Influx Sql系列教程六:insert 修改数据
在influxdb中没有专门的修改数据的update语句,对于influxdb而言,如果想修改数据,还是得使用我们前面的说到的insert来实现,那么怎么判断一条insert语句是插入还是修改呢? 1 ...
随机推荐
- python4 - 字典
字典 定义:字典是无序的,它不能通过偏移来存取,只能通过键来存取. 特点:内部没有顺序,通过键来读取内容,可嵌套,方便我们组织多种数据结构,并且可以原地修改里面的内容,属于可变类型. 创建字典.{}, ...
- Java基础知识:Java实现Map集合二级联动4
comboBox.setModel(new DefaultComboBoxModel(getProvince())); // 添加省份信息 final JLabel label = new JLabe ...
- Python 3 利用 Dlib 实现摄像头人脸检测特征点标定
0. 引言 利用 Python 开发,借助 Dlib 库捕获摄像头中的人脸,进行实时人脸 68 个特征点标定: 支持多张人脸: 有截图功能: 图 1 工程效果示例( gif ) 图 2 工程效果示例( ...
- Parcel 打包器简单使用记录
本文是构造 UI 轮子过程中搭建项目初始化时使用 Parcel 作为打包器的简要使用记录. 安装 参考 官方文档 使用 npm 进行 parcel-bundler 的安装. npm i -D parc ...
- c字符数组里的中文
char *p ="你abc"; strlen(p); //6 utf-8编码中
- Jenkins 自动化测试
学习 Jenkins 自动化测试的系列文章 Robot Framework 概念 Robot Framework 安装 Pycharm + Robot Framework 环境搭建 Robot Fra ...
- 袋鼠云研发手记 | 数栈·开源:Github上400+Star的硬核分布式同步工具FlinkX
作为一家创新驱动的科技公司,袋鼠云每年研发投入达数千万,公司80%员工都是技术人员,袋鼠云产品家族包括企业级一站式数据中台PaaS数栈.交互式数据可视化大屏开发平台Easy[V]等产品也在迅速迭代.在 ...
- python常用快捷键
最重要的快捷键1. ctrl+shift+A:万能命令行2. shift两次:查看资源文件 新建工程第一步操作1. module设置把空包分层去掉,compact empty middle packa ...
- React 初学
React.createClass({}); getInitialState,this.setState({}); {}解读代码块,外层不要加引号,比如onChange={this.handleCha ...
- Java:有关try、catch和finally的学习(供自己参考)
Java:有关try.catch和finally的学习 在看到书本的时候对finally的介绍是:不论是否在try块中产生异常,都会执行finally.当时对这句话的理解不够深,误以为在try...c ...