tinymce原装插件源码分析(二)-link
link
功能描述如下:
- 单纯放置光标:
1、如果光标放到了<a>上,读取a标签的内容,并弹框显示,确定的时候,更新当前a标签。
2、否则,就创建弹框,确定的时候,按照参数添加a标签。
- seletion:
1、部分或全部选择<a>的时候,与上面的1一样,更新。
2、选择非文字的<span>、<p>等,会读取选择的文字,并弹框,把显示文字字段填成选择的文字,根据修改,把选择的文字修改成<a>。
当然实际上link的功能不止这些。还有锚点等功能。这需要看源码的条件判断,才能解锁新的功能。
这里涉及到弹框及选择部分文字的读取。
plugin.js
editor.addButton('link', {
icon: 'link',
tooltip: 'Insert/edit link',
shortcut: 'Meta+K', //快捷键 ctl+K
onclick: createLinkList(showDialog),
stateSelector: 'a[href]'
});
在hr中,按钮的动作是使用cmd参数指定指令名来触发指令。这里直接绑定了click函数。注:stateSelector在代码中未进行处理,见 L31976- L31991。
click函数:createLinkList依赖于link_list配置(默认未配置),所以实际上,只调用了showDialog函数(核心)。
function showDialog(linkList) {
selectedElm = selection.getNode();
anchorElm = dom.getParent(selectedElm, 'a[href]'); //如果当前是a,就返回当前,否则一直找,直到找到父亲。找不到就返回null
onlyText = isOnlyTextSelected(); //跨元素的时候会返回false,否则返回true
。。。。此处省略n行。 这里面有一堆条件,都是新的功能触发。都是与setting设置有关。 win = editor.windowManager.open({
title: 'Insert link',
data: data,
body: [
{ //地址
name: 'href',
type: 'filepicker',
filetype: 'file',
size: 40,
autofocus: true,
label: 'Url',
onchange: urlChange,
onkeyup: updateText
},
textListCtrl, //显示文字
linkTitleCtrl, //标题
buildAnchorListControl(data.href),
linkListCtrl,
relListCtrl,
targetListCtrl,
classListCtrl
],
onSubmit: function(e) {
/*eslint dot-notation: 0*/ //点击确定后,会触发此函数
var href; data = tinymce.extend(data, e.data);
href = data.href; // Delay confirm since onSubmit will move focus
function delayedConfirm(message, callback) {
var rng = editor.selection.getRng(); window.setTimeout(function() {
editor.windowManager.confirm(message, function(state) {
editor.selection.setRng(rng);
callback(state);
});
}, 0);
}
function insertLink() {
//最终的插入a的操作
}
if (!href) { //如果连接为空的时候,不进行link添加操作,并返回
editor.execCommand('unlink');
return;
}
// 此处省略email链接的处理,与下面的一个条件类似。
// Is not protocol prefixed
if ((editor.settings.link_assume_external_targets && !/^\w+:/i.test(href)) ||
(!editor.settings.link_assume_external_targets && /^\s*www[\.|\d\.]/i.test(href))) {
delayedConfirm(
'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?',
function(state) {
if (state) {
href = 'http://' + href;
} insertLink();
}
); return;
} insertLink();
}
});
}
核心 1: editor.windowManager.open
打开一个model对话框,这里需要注意参数body的写法,内部是一个列表,每写一个元素,会生成一行form表单。
上面三个红框内部的数据描述分别是:
注意下type和name。这里显示成中文,请参见langs文件夹下的zh_CN,js 。它是一个字典,来替换显示的关键字的。
当url数据有‘问题’的时候,巧妙的使用了:
window.setTimeout(function() {
editor.windowManager.confirm(message, function(state) {
editor.selection.setRng(rng);
callback(state);
});
}, 0);
来重新修改url。
解锁新技能- 添加anchor
观察plugin.js L73下面的函数:
function buildAnchorListControl(url) {
var anchorList = []; tinymce.each(editor.dom.select('a:not([href])'), function(anchor) { //找其他没有href但有id属性的<a>,然后把他们的id列在上图的锚点处。
var id = anchor.name || anchor.id; if (id) {
anchorList.push({
text: id,
value: '#' + id,
selected: url.indexOf('#' + id) != -1
});
}
}); if (anchorList.length) {
anchorList.unshift({text: 'None', value: ''}); return {
name: 'anchor',
type: 'listbox',
label: 'Anchors',
values: anchorList,
onselect: linkListChangeHandler
};
}
}
核心二-insertLink:
function insertLink() {
var linkAttrs = {
href: href,
target: data.target ? data.target : null,
rel: data.rel ? data.rel : null,
"class": data["class"] ? data["class"] : null,
title: data.title ? data.title : null
}; if (anchorElm) { //把光标放到了a标签处或选择a
editor.focus(); if (onlyText && data.text != initialText) {
if ("innerText" in anchorElm) {
anchorElm.innerText = data.text;
} else {
anchorElm.textContent = data.text;
}
} dom.setAttribs(anchorElm, linkAttrs); selection.select(anchorElm);
editor.undoManager.add();//操作可被undo
} else { //未选择a
if (onlyText) { //未跨元素
editor.insertContent(dom.createHTML('a', linkAttrs, dom.encode(data.text))); //直接插入新元素即可。
} else { //跨元素了
editor.execCommand('mceInsertLink', false, linkAttrs);
}
}
}
涉及到的命令:
mceInsertLink (在选择位置处,可能跨元素,插入a)、unlink、
有用的函数:
editor.windowManager.open(打开一个包含指定form表单的model窗口)、editor.windowManager.confirm(内部封装了MessageBox.msgBox)、editor.insertContent(内部调用了mceInsertContent命令)、及此plugin的buildListItems(构建editor.windowManager.open中body中某个元素的value参数的)。
补:
stateSelector: 'a[href]': 功能是: 鼠标放在了这个元素上,'link'按钮会有加灰底提示。
tinymce原装插件源码分析(二)-link的更多相关文章
- tinymce原装插件源码分析(一)-hr
tinymce简介 tinymce是一款能方便无限扩展的网页富文本编辑器. tinymce原装插件已经十分丰富,对于文本编辑(blog等文章)是绰绰有余,但是应对一些复杂的应用,比如在上面开发html ...
- tinymce原装插件源码分析(五)-searchreplace
searchreplace 功能:查找和替换 代码注释见: https://www.xunhanliu.top/static/js/tinymce/plugins/searchreplace/plug ...
- tinymce原装插件源码分析(四)-fullscreen
fullscreen 作为一款文本编辑器,全屏功能是非常有必要的.在插件中主要是修改一些css style和触发resize事件. style问题(反例): 见github源码:https://git ...
- tinymce原装插件源码分析(三)-code
code: 用于显示源码.主要包含一个弹框.设置显示内容以及内容的更新. function showDialog() { var win = editor.windowManager.open({ t ...
- tinymce原装插件源码分析(七)-使能css、script
在tinymce中使用css个script tinymce的编辑器中css和script默认是不起作用的.(编辑器主要面向写文章使用,考虑到xss攻击,默认是不启用的) 需要修改tinymce.js中 ...
- tinymce原装插件源码分析(六)-preview
priview 此插件文件结构比较简单,按钮注册.editor.windowManager.open.窗口出现之前的渲染数据的准备.页面代码的准备. 注意: 1.preview的默认宽高设置: 2.c ...
- Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题
4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...
- 框架-springmvc源码分析(二)
框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...
- 十、Spring之BeanFactory源码分析(二)
Spring之BeanFactory源码分析(二) 前言 在前面我们简单的分析了BeanFactory的结构,ListableBeanFactory,HierarchicalBeanFactory,A ...
随机推荐
- I'm studying Bootstrap! loading...
最近在学习bootstrap框架. Bootstrap框架是目前前端最受欢迎的框架,出于Twitter公司!搞前端你说你不会Bootstrap都不好意思见人呢. Bootstrap是基于Html Cs ...
- 路飞学城Python-Day40(第四模块复习题)
数据库 一.简答题 1.说说你所知道的MySQL数据库存储引擎,InnoDB存储引擎和MyISM存储引擎的区别? 1.InnoDB存储引擎(MySQL默认存储引擎),支持事务,其设计目标主要面向联机事 ...
- Pyhton学习——Day39
# CSS的常用属性# 1 颜色属性# <div style="color:rgb(255,0,0)">ppppp</div># 2 字体属性# font- ...
- luoguP1002
p1002 题意: 从坐标A到坐标B的可能路线(有一些点不能走)情况,很明显可以看出用dp做 m[i][j]=m[i-1][j]+m[i][j-1](注意处理不能走的点) 自己在初始化时犯了错,第1行 ...
- easyUI datagarid单元格动态合并
第二列根据第一列合并,第三列根据第二列合并.层级关系. /* * tableID表格的id * colList要合并的字段例如:"overcount,totalcount" */ ...
- android handler传递数据
起因:在android使用get请求获取验证码时需要重开一个线程,这就造成了我无法获取到从服务器后台返回的数据 解决方法:创建全局变量,将返回的数据解析后返回给handler,再在handler中将数 ...
- 为什么在index.jsp里面引入了common.js,在item-add.jsp以及其他一些jsp文件里面就不需要引入common.jsne ?
那是因为,index.jsp页面的根节点是body,hrml.是一个完整的网页.那我们再看item-add.jsp页面,他节点是div,只是一个html的片段,并不是一个完整的网页,在easyUI中, ...
- frp(升级版)教程
注:之前的教程是按照官网文档亲自实践操作汇总而成的,所需的软件也是从官网下载的. 但是有一个问题,若是运行在有公网IP的frps程序被其他人所知道,他们就可以直接在他们电脑上运行frpc客户端, 简而 ...
- JS[获取两个日期中所有的月份]
//------[获取两个日期中所有的月份中] function getMonthBetween(start,end){ var result = []; var s = start.split(&q ...
- django-1-框架介绍
<<<python虚拟环境>>> 用django框架做web开发必须要用到python虚拟环境,而且一个虚拟环境只能创建一个django项目,如果创建多个djang ...