editor.js, UE.Utils, UE.EventBase, UE.browser, core/dom/dtd.js, UE.dom.domUtils, UE.dom.Range, core/dom/Selection.js, plugins/serialize.js
编辑器主类,包含编辑器提供的大部分公用接口
UEditor编辑器类
创建一个跟编辑器实例
当编辑器ready后执行传入的fn,如果编辑器已经完成ready,就马上执行fn,fn的中的this是编辑器实例。
大部分的实例接口都需要放在该方法内部执行,否则在IE下可能会报错。
var editor = new UE.ui.Editor();
editor.render("myEditor");
editor.ready(function(){
editor.setContent("欢迎使用UEditor!");
})
销毁编辑器实例对象
渲染编辑器的DOM到指定容器,必须且只能调用一次
同步编辑器的数据,为提交数据做准备,主要用于你是手动提交的情况
后台取得数据得键值使用你容器上得name属性,如果没有就使用参数传入的textarea
editor.sync();
form.sumbit(); //form变量已经指向了form元素
设置编辑器高度
获取编辑器内容
getContent默认是会现调用hasContents来判断编辑器是否为空,如果是,就直接返回空字符串
你也可以传入一个fn来接替hasContents的工作,定制判断的规则
editor.getContent(function(){
return false //编辑器没有内容 ,getContent直接返回空
})
取得完整的html代码,可以直接显示成完整的html文档
得到编辑器的纯文本内容,但会保留段落格式
获取编辑器中的纯文本内容,没有段落格式
将html设置到编辑器中, 如果是用于初始化时给编辑器赋初值,则必须放在ready方法内部执行
var editor = new UE.ui.Editor()
editor.ready(function(){
//需要ready后执行,否则可能报错
editor.setContent("欢迎使用UEditor!");
})
让编辑器获得焦点,toEnd确定focus位置
执行编辑命令cmdName,完成富文本编辑效果
根据传入的command命令,查选编辑器当前的选区,返回命令的状态
根据传入的command命令,查选编辑器当前的选区,根据命令返回相关的值
检查编辑区域中是否有内容,若包含tags中的节点类型,直接返回true
默认有文本内容,或者有以下节点都不认为是空
{table:1,ul:1,ol:1,dl:1,iframe:1,area:1,base:1,col:1,hr:1,img:1,embed:1,input:1,link:1,meta:1,param:1}
editor.hasContents(['span']) //如果编辑器里有这些,不认为是空
重置编辑器,可用来做多个tab使用同一个编辑器实例
设置当前编辑区域可以编辑
设置当前编辑区域不可编辑,except中的命令除外
//禁用工具栏中除加粗和插入图片之外的所有功能
editor.disable(['bold','insertimage']);//可以是单一的String,也可以是Array
显示编辑器
隐藏编辑器
根据制定的路径,获取对应的语言资源
editor.getLang('contextMenu.delete') //如果当前是中文,那返回是的是删除
得到dialog实例对象
var dialog = editor.getDialog("insertimage");
dialog.open(); //打开dialog
dialog.close(); //关闭dialog
UEditor中采用的浏览器判断模块
检测浏览器是否为IE
检测浏览器是否为Opera
检测浏览器是否为webkit内核
检测浏览器是否为mac系统下的浏览器
检测浏览器是否处于怪异模式
检测浏览器是否处为gecko内核
检测浏览器是否为 IE9 模式
检测浏览器是否为 IE8 浏览器
检测浏览器是否为 IE8 模式
检测浏览器是否运行在 兼容IE7模式
检测浏览器是否IE6模式或怪异模式
检测浏览器是否为chrome
检测浏览器是否为safari
浏览器版本判断
IE系列返回值为5,6,7,8,9,10等
gecko系列会返回10900,158900等.
webkit系列会返回其build号 (如 522等).
if ( UE.browser.ie && UE.browser.version == 6 ){
alert( "Ouch!居然是万恶的IE6!" );
}
是否是兼容模式的浏览器
if ( UE.browser.isCompatible ){
alert( "你的浏览器相当不错哦!" );
}
editor.js
UEditor封装使用的静态工具函数
遍历数组,对象,nodeList
UE.utils.each([1,2],function(v,i){
console.log(v)//值
console.log(i)//索引
})
UE.utils.each(document.getElementsByTagName('*'),function(n){
console.log(n.tagName)
})
将source对象中的属性扩展到target对象上
模拟继承机制,subClass继承superClass
function SuperClass(){
this.name = "小李";
}
SuperClass.prototype = {
hello:function(str){
console.log(this.name + str);
}
}
function SubClass(){
this.name = "小张";
}
UE.utils.inherits(SubClass,SuperClass);
var sub = new SubClass();
sub.hello("早上好!"); ==> "小张早上好!"
用指定的context作为fn上下文,也就是this
创建延迟delay执行的函数fn
function test(){
console.log("延迟输出!");
}
//非互斥延迟执行
var testDefer = UE.utils.defer(test,1000);
testDefer(); => "延迟输出!";
testDefer(); => "延迟输出!";
//互斥延迟执行
var testDefer1 = UE.utils.defer(test,1000,true);
testDefer1(); => //本次不执行
testDefer1(); => "延迟输出!";
查找元素item在数组array中的索引, 若找不到返回-1
移除数组array中的元素item
删除字符串str的首尾空格
将字符串list(以','分隔)或者数组list转成哈希对象
将str中的html符号转义,默认将转义&<">四个字符,可自定义reg来确定需要转义的字符
var html = 'You say:"你好!Baidu & UEditor!"';
UE.utils.unhtml(html); ==> <body>You say:"你好!Baidu & UEditor!"</body>
UE.utils.unhtml(html,/[<>]/g) ==> <body>You say:"你好!Baidu & UEditor!"</body>
unhtml
将str中的转义字符还原成html字符
将css样式转换为驼峰的形式。如font-size => fontSize
动态加载文件到doc中,并依据obj来设置属性,加载成功后执行回调函数fn
//指定加载到当前document中一个script文件,加载成功后执行function
utils.loadFile( document, {
src:"test.js",
tag:"script",
type:"text/javascript",
defer:"defer"
}, function () {
console.log('加载成功!')
});
判断obj对象是否为空
UE.utils.isEmptyObject({}) ==>true
UE.utils.isEmptyObject([]) ==>true
UE.utils.isEmptyObject("") ==>true
统一将颜色值使用16进制形式表示
rgb(255,255,255) => "#ffffff"
深度克隆对象,从source到target
转换cm/pt到px
DomReady方法,回调函数将在dom树ready完成后执行
动态添加css样式
判断str是否为字符串
判断array是否为数组
判断obj对象是否为方法
判断obj对象是否为数字
editor.js, UE.Utils
UE采用的事件基类,继承此类的对应类将获取addListener,removeListener,fireEvent方法。
在UE中,Editor以及所有ui实例都继承了该类,故可以在对应的ui对象以及editor对象上使用上述方法。
注册事件监听器
editor.addListener('selectionchange',function(){
console.log("选区已经变化!");
})
editor.addListener('beforegetcontent aftergetcontent',function(type){
if(type == 'beforegetcontent'){
//do something
}else{
//do something
}
console.log(this.getContent) // this是注册的事件的编辑器实例
})
移除事件监听器
//changeCallback为方法体
editor.removeListener("selectionchange",changeCallback);
触发事件
editor.fireEvent("selectionchange");
editor.js, UE.Utils, UE.browser, core/dom/dtd.js
UEditor封装的底层dom操作库
获取节点A相对于节点B的位置关系
switch (returnValue) {
case 0: //相等,同一节点
case 1: //无关,节点不相连
case 2: //跟随,即节点A头部位于节点B头部的后面
case 4: //前置,即节点A头部位于节点B头部的前面
case 8: //被包含,即节点A被节点B包含
case 10://组合类型,即节点A满足跟随节点B且被节点B包含。实际上,如果被包含,必定跟随,所以returnValue事实上不会存在8的情况。
case 16://包含,即节点A包含节点B
case 20://组合类型,即节点A满足前置节点A且包含节点B。同样,如果包含,必定前置,所以returnValue事实上也不会存在16的情况
}
返回节点node在父节点中的索引位置
检测节点node是否在节点doc的树上,实质上是检测是否被doc包含
查找node节点的祖先节点
通过tagName查找node节点的祖先节点
查找节点node的祖先节点集合
在节点node后面插入新节点newNode
删除节点node,并根据keepChildren指定是否保留子节点
取得node节点在dom树上的下一个节点,即多叉树遍历
isBookmarkNode
- UE.dom.domUtils.isBookmarkNode(node) ⇒ true|false
检测节点node是否属于bookmark节点
getWindow
- UE.dom.domUtils.getWindow(node) ⇒ window对象
获取节点node所在的window对象
getCommonAncestor
- UE.dom.domUtils.getCommonAncestor(nodeA,nodeB) ⇒ Element
得到nodeA与nodeB公共的祖先节点
clearEmptySibling
- UE.dom.domUtils.clearEmptySibling(node)
- UE.dom.domUtils.clearEmptySibling(node,ignoreNext) //ignoreNext指定是否忽略右边空节点
- UE.dom.domUtils.clearEmptySibling(node,ignoreNext,ignorePre) //ignorePre指定是否忽略左边空节点
清除node节点左右兄弟为空的inline节点
<b></b>>xxxx<b>bb</b> --> xxxxbbb>
将一个文本节点node拆分成两个文本节点,offset指定拆分位置
检测节点node是否为空节点(包括空格、换行、占位符等字符)
获取元素element相对于viewport的位置坐标
为元素element绑定原生DOM事件,type为事件类型,handler为处理函数
UE.dom.domUtils.on(document.body,"click",function(e){
//e为事件对象,this为被点击元素对戏那个
})
UE.dom.domUtils.on(document.body,["click","mousedown"],function(evt){
//evt为事件对象,this为被点击元素对象
})
on
解除原生DOM事件绑定
比较节点nodeA与节点nodeB是否具有相同的标签名、属性名以及属性值
<span style="font-size:12px">ssss</span> and bbbbbspan> => true
<span style="font-size:13px">ssss</span> and bbbbbspan> => false
判断节点nodeA与节点nodeB的元素属性是否一致
检查节点node是否为块元素
检测node节点是否为body节点
以node节点为中心,将该节点的指定祖先节点parent拆分成2块
>ooo>是node节点
>xxxx>ooo>xxx
> ==> >xxx
>>ooo>>xxx
>
>xxxxx>xxxx>ooo>xxxxxx>
> => >xxxxx>xxxx>
>>ooo>>>xxxxxx>
>
检查节点node是否是空inline节点
<b><i></i>b> => 1
<b><i></i>u></b> => 1
<b></b> => 1
<b>xx<i></i>b> => 0
删除node节点下的左右空白文本子节点
合并node节点下相同的子节点
UE.dom.domUtils.mergeChild(node,tagName) //tagName要合并的子节点的标签
<p><span style="font-size:12px;">xx<span style="font-size:12px;">aa</span>xxspan></p>
==> UE.dom.domUtils.mergeChild(node,'span')
<p><span style="font-size:12px;">xxaaxx</span>p>
原生方法getElementsByTagName的封装
将节点node合并到父节点上
<span style="color:#fff"><span style="font-size:12px">xxx</span>span> ==> <span style="color:#fff;font-size:12px">xxx</span>
合并节点node的左右兄弟节点
<b>xxxx</b>ooob><b>xxxx</b> ==> xxxxoooxxxxb>
设置节点node及其子节点不会被选中
删除节点node上的属性attrNames,attrNames为属性名称数组
//Before remove
<span style="font-size:14px;" id="test" name="followMe">xxxxx</span>
//Remove
UE.dom.domUtils.removeAttributes(node,["id","name"]);
//After remove
<span style="font-size:14px;">xxxxx</span>
在doc下创建一个标签名为tag,属性为attrs的元素
为节点node添加属性attrs,attrs为属性键值对
获取元素element的计算样式
getComputedStyle(document.body,"font-size") => "15px"
getComputedStyle(form,"color") => "#ffccdd"
在元素element上删除classNames,支持同时删除多个
//执行方法前的dom结构
<span class="test1 test2 test3">xxx</span>
//执行方法
UE.dom.domUtils.removeClasses(element,["test1","test3"])
//执行方法后的dom结构
<span class="test2">xxx</span>
在元素element上增加一个样式类className,支持以空格分开的多个类名
如果相同的类名将不会添加
判断元素element是否包含样式类名className,支持以空格分开的多个类名,多个类名顺序不同也可以比较
获取元素element的某个样式值
为元素element设置样式属性值
为元素element设置样式属性值
对于nodelist用filter进行过滤
UE.dom.domUtils.filterNodeList(document.getElementsByTagName('*'),'div p') //返回第一个是div或者p的节点
UE.dom.domUtils.filterNodeList(document.getElementsByTagName('*'),function(n){return n.getAttribute('src')})
//返回第一个带src属性的节点
UE.dom.domUtils.filterNodeList(document.getElementsByTagName('*'),'i',true) //返回数组,里边都是i节点
editor.js, UE.Utils, UE.browser, UE.dom.domUtils, core/dom/dtd.js
Range范围实现类,本类是UEditor底层核心类,统一w3cRange和ieRange之间的差异,包括接口和属性
创建一个跟document绑定的空的Range实例
克隆选中的内容到一个fragment里,如果选区是空的将返回null
删除当前选区范围中的所有内容并返回range实例,这时的range已经变成了闭合状态
DOM Element :
<b>x<i>x[x<i>xx]x</b>
//执行方法后
<b>x<i>x<i>|x</b>
注意range改变了
range.startContainer => b
range.startOffset => 2
range.endContainer => b
range.endOffset => 2
range.collapsed => true
将当前的内容放到一个fragment里并返回这个fragment,这时的range已经变成了闭合状态
DOM Element :
<b>x<i>x[x<i>xx]x</b>
//执行方法后
返回的fragment里的 dom结构是
<i>x<i>xx
dom树上的结构是
<b>x<i>x<i>|x</b>
注意range改变了
range.startContainer => b
range.startOffset => 2
range.endContainer => b
range.endOffset => 2
range.collapsed => true
设置range的开始位置位于node节点内,偏移量为offset
如果node是elementNode那offset指的是childNodes中的第几个,如果是textNode那offset指的是nodeValue的第几个字符
设置range的结束位置位于node节点,偏移量为offset
如果node是elementNode那offset指的是childNodes中的第几个,如果是textNode那offset指的是nodeValue的第几个字符
将Range开始位置设置到node节点之后
<b>xx<i>x|x</i>xb>
执行setStartAfter(i)后
range.startContainer =>b
range.startOffset =>2
将Range开始位置设置到node节点之前
<b>xx<i>x|x</i>xb>
执行setStartBefore(i)后
range.startContainer =>b
range.startOffset =>1
将Range结束位置设置到node节点之后
<b>xx<i>x|x</i>xb>
setEndAfter(i)后
range.endContainer =>b
range.endtOffset =>2
将Range结束位置设置到node节点之前
<b>xx<i>x|x</i>xb>
执行setEndBefore(i)后
range.endContainer =>b
range.endtOffset =>1
将Range开始位置设置到node节点内的开始位置
将Range开始位置设置到node节点内的结束位置
将Range结束位置设置到node节点内的开始位置
将Range结束位置设置到node节点内的结束位置
选中完整的指定节点,并返回包含该节点的range
选中node内部的所有节点,并返回对应的range
<b>xx[x<i>xxx</i>]xxxb>
执行后
<b>[xxx<i>xxx</i>xxx]b>
range.startContainer =>b
range.startOffset =>0
range.endContainer =>b
range.endOffset =>3
克隆一个新的range对象
让选区闭合到尾部,若toStart为真,则闭合到头部
adjustmentBoundary
调整range的边界,使其"收缩"到最小的位置
<b>xx[</b>xxxxx] ==> xxb>[xxxxx]
<b>x[xx</b>]xxx> ==> <b>x[xx]</b>xxx>
[<b><i>xxxx</i>xxxxxxxb>] ==> <b><i>[xxxx</i>xxxxxxx]b>
获取当前range所在位置的公共祖先节点,当前range位置可以位于文本节点内,也可以包含整个元素节点,也可以位于两个节点之间
<b>xx[xx<i>xx]x</i>xxxb> ==>getCommonAncestor() ==> b
<b>[<img/>]</b>
range.startContainer ==> b
range.startOffset ==> 0
range.endContainer ==> b
range.endOffset ==> 1
range.getCommonAncestor() ==> b
range.getCommonAncestor(true) ==> img
<b>xxx|xx</b>
range.startContainer ==> textNode
range.startOffset ==> 3
range.endContainer ==> textNode
range.endOffset ==> 3
range.getCommonAncestor() ==> textNode
range.getCommonAncestor(null,true) ==> b
调整边界容器,如果是textNode,就调整到elementNode上
DOM Element :
<b>|xxx</b>
startContainer = xxx; startOffset = 0
//执行后本方法后
startContainer = <b>; startOffset = 0
Dom Element :
<b>xx|x</b>
startContainer = xxx; startOffset = 2
//执行本方法后,xxx被实实在在地切分成两个TextNode
startContainer = <b>; startOffset = 1
如果选区在文本的边界上,就扩展选区到文本的父节点上
Dom Element :
<b> |xxx</b>
startContainer = xxx; startOffset = 0
//本方法执行后
startContainer = <b>; startOffset = 0
Dom Element :
<b> xxx| </b>
startContainer = xxx; startOffset = 3
//本方法执行后
startContainer = <b>; startOffset = 1
在当前选区的开始位置前插入一个节点或者fragment,range的开始位置会在插入节点的前边
Range :
xxx[x<p>xxxx</p>xxxx]xsdfsdfp>
待插入Node :
<p>ssss</p>
执行本方法后的Range :
xxx[<p>ssss</p>xxxxxp>xxxx]x<p>sdfsdf</p>
设置光标闭合位置,toEnd设置为true时光标将闭合到选区的结尾
创建当前range的一个书签,记录下当前range的位置,方便当dom树改变时,还能找回原来的选区位置
移动边界到书签位置,并删除插入的书签节点
调整range的边界,使其"放大"到最近的父block节点
<p><span>xxx</span>x[xb>xxxxx]</p>xxxp> ==> [<p><span>xxx</span>xxb>xxxxx</p>]xxxp>
shrinkBoundary
调整Range的边界,使其"缩小"到最合适的位置
<b>xx[</b>xxxxx] ==> xxb>[xxxxx]
<b>x[xx</b>]xxx> ==> <b>x[xx</b>]xxx>
给range选区中的内容添加给定的标签,主要用于inline标签
>xxxx[xxxx]x
> ==> range.applyInlineStyle("strong") ==> >xxxx[>xxxx>]x
>
>xx[dd>yyyy>]x
> ==> range.applyInlineStyle("strong") ==> >xx[>ddyyyy>]x
>
>xxxx[xxxx]x
> ==> range.applyInlineStyle("strong",{"style":"font-size:12px"}) ==> >xxxx[ style="font-size:12px">xxxx>]x
>
对当前range选中的节点,去掉给定的标签节点,但标签中的内容保留,主要用于处理inline元素
xx[x>xxx>yyy>zz]z> => range.removeInlineStyle(["em"]) => xx[x>xxxyyyzz]z>
得到一个自闭合的节点,常用于获取自闭和的节点,例如图片节点
<b>xxxx[<img />]xxx</b>
根据当前range选中内容节点(在页面上表现为反白显示)
滚动条跳到当然range开始的位置
UE.Utils
UEditor内置的ajax请求模块
发出ajax请求,ajaxOpt中默认包含method,timeout,async,data,onsuccess以及onerror等六个,支持自定义添加参数
UE.ajax.request('http://www.xxxx.com/test.php',{
//可省略,默认POST
method:'POST',
//可以自定义参数
content:'这里是提交的内容',
//也可以直接传json,但是只能命名为data,否则当做一般字符串处理
data:{
name:'UEditor',
age:'1'
}
onsuccess:function(xhr){
console.log(xhr.responseText);
},
onerror:function(xhr){
console.log(xhr.responseText);
}
})
UEditor的顶部命名空间
提供一个全局的方法得到编辑器实例
UE.getEditor('containerId',{onready:function(){//创建一个编辑器实例
this.setContent('hello')
}});
UE.getEditor('containerId'); //返回刚创建的实例
编辑器加载完成事件(核心),在编辑器准备好所有运行条件时触发,大部分场景可以使用editor.ready(fn)取代。
editor.addListener("ready",function(){
//this为editor实例
this.setContent("欢迎使用UEditor!");
})
//同如下接口方式调用
editor.ready(function(){
this.setContent("欢迎使用UEditor!");
})
选区变化事件(核心),当选区出现变化时触发。
在UEditor中,任何涉及到光标改变的操作都会触发选区变化事件,该事件主要用来实现工具栏状态反射。
editor.addListener("selectionChange",function(){
//this为editor实例
})
内容变化事件(核心),当编辑区域中的文本内容出现变化时触发
粘贴事件(核心),当使用ctr+v快捷键粘贴(包括Chrome、FF浏览器的右键粘贴)时会触发本事件
editor.addListener("beforePaste",function(type,data){
//beforePaste事件监听区别于afterPaste事件监听最主要的一个方面是存在一个data参数,
//该data参数是一个对象,包含属性html。
//若用户在此处更改该html的值时,将会影响粘贴到编辑器中的内容,主要用于粘贴时需要特殊处理的一些场景。
console.log(this.getContent) //this都是当前编辑器的实例
//before事件才用这个参数,用来在写出编辑器之前对粘贴进来的内容进行最后的修改
data.html = "我把粘贴内容改成了这句话";
})
设置内容事件(核心),当调用setContent方法时触发
editor.addListener("beforeSetContent",function(type,data){
//beforeSetContent事件监听区别于afterSetContent事件监听最主要的一个方面是存在一个data参数,
//该data参数是一个对象,包含属性html。
//若用户在此处更改该html的值时,将会影响设置到编辑器中的内容,主要用于设置内容时需要特殊处理的一些场景。
data.html = "我把设置内容改成了这句话";
})
getAllHtml事件,当调用getAllHtml方法时触发
editor.addListener("getAllHtml",function(type,data){
//data是document中head部分html的封装,可通过data.html来获取对应字符串。
//需要修改的话得重新赋值data.html = '