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的更多相关文章

  1. tinymce原装插件源码分析(一)-hr

    tinymce简介 tinymce是一款能方便无限扩展的网页富文本编辑器. tinymce原装插件已经十分丰富,对于文本编辑(blog等文章)是绰绰有余,但是应对一些复杂的应用,比如在上面开发html ...

  2. tinymce原装插件源码分析(五)-searchreplace

    searchreplace 功能:查找和替换 代码注释见: https://www.xunhanliu.top/static/js/tinymce/plugins/searchreplace/plug ...

  3. tinymce原装插件源码分析(四)-fullscreen

    fullscreen 作为一款文本编辑器,全屏功能是非常有必要的.在插件中主要是修改一些css style和触发resize事件. style问题(反例): 见github源码:https://git ...

  4. tinymce原装插件源码分析(三)-code

    code: 用于显示源码.主要包含一个弹框.设置显示内容以及内容的更新. function showDialog() { var win = editor.windowManager.open({ t ...

  5. tinymce原装插件源码分析(七)-使能css、script

    在tinymce中使用css个script tinymce的编辑器中css和script默认是不起作用的.(编辑器主要面向写文章使用,考虑到xss攻击,默认是不启用的) 需要修改tinymce.js中 ...

  6. tinymce原装插件源码分析(六)-preview

    priview 此插件文件结构比较简单,按钮注册.editor.windowManager.open.窗口出现之前的渲染数据的准备.页面代码的准备. 注意: 1.preview的默认宽高设置: 2.c ...

  7. Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题

    4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...

  8. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

  9. 十、Spring之BeanFactory源码分析(二)

    Spring之BeanFactory源码分析(二) 前言 在前面我们简单的分析了BeanFactory的结构,ListableBeanFactory,HierarchicalBeanFactory,A ...

随机推荐

  1. I'm studying Bootstrap! loading...

    最近在学习bootstrap框架. Bootstrap框架是目前前端最受欢迎的框架,出于Twitter公司!搞前端你说你不会Bootstrap都不好意思见人呢. Bootstrap是基于Html Cs ...

  2. 路飞学城Python-Day40(第四模块复习题)

    数据库 一.简答题 1.说说你所知道的MySQL数据库存储引擎,InnoDB存储引擎和MyISM存储引擎的区别? 1.InnoDB存储引擎(MySQL默认存储引擎),支持事务,其设计目标主要面向联机事 ...

  3. Pyhton学习——Day39

    # CSS的常用属性# 1 颜色属性# <div style="color:rgb(255,0,0)">ppppp</div># 2 字体属性# font- ...

  4. luoguP1002

    p1002 题意: 从坐标A到坐标B的可能路线(有一些点不能走)情况,很明显可以看出用dp做 m[i][j]=m[i-1][j]+m[i][j-1](注意处理不能走的点) 自己在初始化时犯了错,第1行 ...

  5. easyUI datagarid单元格动态合并

    第二列根据第一列合并,第三列根据第二列合并.层级关系. /* * tableID表格的id * colList要合并的字段例如:"overcount,totalcount" */ ...

  6. android handler传递数据

    起因:在android使用get请求获取验证码时需要重开一个线程,这就造成了我无法获取到从服务器后台返回的数据 解决方法:创建全局变量,将返回的数据解析后返回给handler,再在handler中将数 ...

  7. 为什么在index.jsp里面引入了common.js,在item-add.jsp以及其他一些jsp文件里面就不需要引入common.jsne ?

    那是因为,index.jsp页面的根节点是body,hrml.是一个完整的网页.那我们再看item-add.jsp页面,他节点是div,只是一个html的片段,并不是一个完整的网页,在easyUI中, ...

  8. frp(升级版)教程

    注:之前的教程是按照官网文档亲自实践操作汇总而成的,所需的软件也是从官网下载的. 但是有一个问题,若是运行在有公网IP的frps程序被其他人所知道,他们就可以直接在他们电脑上运行frpc客户端, 简而 ...

  9. JS[获取两个日期中所有的月份]

    //------[获取两个日期中所有的月份中] function getMonthBetween(start,end){ var result = []; var s = start.split(&q ...

  10. django-1-框架介绍

    <<<python虚拟环境>>> 用django框架做web开发必须要用到python虚拟环境,而且一个虚拟环境只能创建一个django项目,如果创建多个djang ...