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. HDU 1052 Tian Ji -- The Horse Racing【贪心在动态规划中的运用】

    算法分析: 这个问题很显然可以转化成一个二分图最佳匹配的问题.把田忌的马放左边,把齐王的马放右边.田忌的马A和齐王的B之间,如果田忌的马胜,则连一条权为200的边:如果平局,则连一条权为0的边:如果输 ...

  2. 手游服务器端接入google的SDK

    在接入google的SDK之前,当然先要用你的google开发者账号要去申请你接入的应用,这些步骤就直接省略了具体的步骤可以查看这篇博文:http://blog.csdn.net/hjun01/art ...

  3. NGUI 使用Grid自动排列UI

    1,NGUI->Create Grid 2,把需要排列的UI放到Grid下边,对Grid进行参数设置

  4. 动态生成的dom元素绑定事件

    要求:要绑定到父元素上$(".school_Inlists").on("click",".chose_Inbtn",function(){ ...

  5. 路飞学城Python-Day27(复习)

    简单的socket通信 import socket client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect( ...

  6. Pyhton学习——Day30

    # 内核态# 用户态# 操作系统的运行是在BOIS启动盘读取代码,从硬盘读取到内存中,被操作系统的内核中,一直存在在内存中# 计算机系统的三层结构:应用软件-->操作系统-->硬件# 一般 ...

  7. 【XSY2689】王子 - 网络流

    复活!qwq 题目来源:2018冬令营模拟测试赛(九) 题意: [背景描述]     不是所有王子都会遇见自己的中关村,主公,公主. 从前有个王子姓王,王王子遇到了一位美丽的公主,她的名字当然是公公主 ...

  8. PHP内置SOAP扩展客户端的使用例子

    SOAP已经是属于OUT范畴的技术了,不过因为历史原因,时不时还是会用到它,以前都是用NuSOAP,现在准备试试PHP内置的SOAP扩展.由于文本只打算说说客户端的用法,所以得先找一些能直接用的服务端 ...

  9. html全屏显示

    JavaScript代码: function toggleFullScreen() { if (!document.fullscreenElement && // alternativ ...

  10. 小学生都能学会的python(字典{ })

    小学生都能学会的python(字典{ }) 1. 什么是字典 dict. 以{}表示. 每一项用逗号隔开, 内部元素用key:value的形式来保存数据 {"jj":"林 ...