最近在做商城后台管理的项目, 商品详情需要使用富文本编辑器, 需要上传图片和上传视频的功能.
富文本选择: wangEditor , froalaEditor 我个人是喜欢froala的,图片和视频都是可以调整大小还可以粘贴图片,无奈需要收费, 公司也不会同意破解, 客户估计也不会出这个钱, 所以没办法只能使用wangEditor.
我是把wangeditor 封装成一个组件,这些都不用细说了. oos 上传服务 也都封装好的.
主要是要修改wangeditor 的源码,达到oos上传的目的
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.wangEditor = factory());
}(this, (function () { 'use strict';
/*
poly-fill
*/
var polyfill = function () {
// Object.assign
if (typeof Object.assign != 'function') {
Object.assign = function (target, varArgs) {
// .length of function is 2
if (target == null) {
// TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) {
// Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
};
}
// IE 中兼容 Element.prototype.matches
if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.matchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector || Element.prototype.webkitMatchesSelector || function (s) {
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
i = matches.length;
while (--i >= 0 && matches.item(i) !== this) {}
return i > -1;
};
}
};
/*
DOM 操作 API
*/
// 根据 html 代码片段创建 dom 对象
function createElemByHTML(html) {
var div = void 0;
div = document.createElement('div');
div.innerHTML = html;
return div.children;
}
// 是否是 DOM List
function isDOMList(selector) {
if (!selector) {
return false;
}
if (selector instanceof HTMLCollection || selector instanceof NodeList) {
return true;
}
return false;
}
// 封装 document.querySelectorAll
function querySelectorAll(selector) {
var result = document.querySelectorAll(selector);
if (isDOMList(result)) {
return result;
} else {
return [result];
}
}
// 记录所有的事件绑定
var eventList = [];
// 创建构造函数
function DomElement(selector) {
if (!selector) {
return;
}
// selector 本来就是 DomElement 对象,直接返回
if (selector instanceof DomElement) {
return selector;
}
this.selector = selector;
var nodeType = selector.nodeType;
// 根据 selector 得出的结果(如 DOM,DOM List)
var selectorResult = [];
if (nodeType === 9) {
// document 节点
selectorResult = [selector];
} else if (nodeType === 1) {
// 单个 DOM 节点
selectorResult = [selector];
} else if (isDOMList(selector) || selector instanceof Array) {
// DOM List 或者数组
selectorResult = selector;
} else if (typeof selector === 'string') {
// 字符串
selector = selector.replace('/\n/mg', '').trim();
if (selector.indexOf('<') === 0) {
// 如
selectorResult = createElemByHTML(selector);
} else {
// 如 #id .class
selectorResult = querySelectorAll(selector);
}
}
var length = selectorResult.length;
if (!length) {
// 空数组
return this;
}
// 加入 DOM 节点
var i = void 0;
for (i = 0; i < length; i++) {
this[i] = selectorResult[i];
}
this.length = length;
}
// 修改原型
DomElement.prototype = {
constructor: DomElement,
// 类数组,forEach
forEach: function forEach(fn) {
var i = void 0;
for (i = 0; i < this.length; i++) {
var elem = this[i];
var result = fn.call(elem, elem, i);
if (result === false) {
break;
}
}
return this;
},
// clone
clone: function clone(deep) {
var cloneList = [];
this.forEach(function (elem) {
cloneList.push(elem.cloneNode(!!deep));
});
return $(cloneList);
},
// 获取第几个元素
get: function get(index) {
var length = this.length;
if (index >= length) {
index = index % length;
}
return $(this[index]);
},
// 第一个
first: function first() {
return this.get(0);
},
// 最后一个
last: function last() {
var length = this.length;
return this.get(length - 1);
},
// 绑定事件
on: function on(type, selector, fn) {
// selector 不为空,证明绑定事件要加代理
if (!fn) {
fn = selector;
selector = null;
}
// type 是否有多个
var types = [];
types = type.split(/\s+/);
return this.forEach(function (elem) {
types.forEach(function (type) {
if (!type) {
return;
}
// 记录下,方便后面解绑
eventList.push({
elem: elem,
type: type,
fn: fn
});
if (!selector) {
// 无代理
elem.addEventListener(type, fn);
return;
}
// 有代理
elem.addEventListener(type, function (e) {
var target = e.target;
if (target.matches(selector)) {
fn.call(target, e);
}
});
});
});
},
// 取消事件绑定
off: function off(type, fn) {
return this.forEach(function (elem) {
elem.removeEventListener(type, fn);
});
},
// 获取/设置 属性
attr: function attr(key, val) {
if (val == null) {
// 获取值
return this[0].getAttribute(key);
} else {
// 设置值
return this.forEach(function (elem) {
elem.setAttribute(key, val);
});
}
},
// 添加 class
addClass: function addClass(className) {
if (!className) {
return this;
}
return this.forEach(function (elem) {
var arr = void 0;
if (elem.className) {
// 解析当前 className 转换为数组
arr = elem.className.split(/\s/);
arr = arr.filter(function (item) {
return !!item.trim();
});
// 添加 class
if (arr.indexOf(className) < 0) {
arr.push(className);
}
// 修改 elem.class
elem.className = arr.join(' ');
} else {
elem.className = className;
}
});
},
// 删除 class
removeClass: function removeClass(className) {
if (!className) {
return this;
}
return this.forEach(function (elem) {
var arr = void 0;
if (elem.className) {
// 解析当前 className 转换为数组
arr = elem.className.split(/\s/);
arr = arr.filter(function (item) {
item = item.trim();
// 删除 class
if (!item || item === className) {
return false;
}
return true;
});
// 修改 elem.class
elem.className = arr.join(' ');
}
});
},
// 修改 css
css: function css(key, val) {
var currentStyle = key + ':' + val + ';';
return this.forEach(function (elem) {
var style = (elem.getAttribute('style') || '').trim();
var styleArr = void 0,
resultArr = [];
if (style) {
// 将 style 按照 ; 拆分为数组
styleArr = style.split(';');
styleArr.forEach(function (item) {
// 对每项样式,按照 : 拆分为 key 和 value
var arr = item.split(':').map(function (i) {
return i.trim();
});
if (arr.length === 2) {
resultArr.push(arr[0] + ':' + arr[1]);
}
});
// 替换或者新增
resultArr = resultArr.map(function (item) {
if (item.indexOf(key) === 0) {
return currentStyle;
} else {
return item;
}
});
if (resultArr.indexOf(currentStyle) < 0) {
resultArr.push(currentStyle);
}
// 结果
elem.setAttribute('style', resultArr.join('; '));
} else {
// style 无值
elem.setAttribute('style', currentStyle);
}
});
},
// 显示
show: function show() {
return this.css('display', 'block');
},
// 隐藏
hide: function hide() {
return this.css('display', 'none');
},
// 获取子节点
children: function children() {
var elem = this[0];
if (!elem) {
return null;
}
return $(elem.children);
},
// 获取子节点(包括文本节点)
childNodes: function childNodes() {
var elem = this[0];
if (!elem) {
return null;
}
return $(elem.childNodes);
},
// 增加子节点
append: function append($children) {
return this.forEach(function (elem) {
$children.forEach(function (child) {
elem.appendChild(child);
});
});
},
// 移除当前节点
remove: function remove() {
return this.forEach(function (elem) {
if (elem.remove) {
elem.remove();
} else {
var parent = elem.parentElement;
parent && parent.removeChild(elem);
}
});
},
// 是否包含某个子节点
isContain: function isContain($child) {
var elem = this[0];
var child = $child[0];
return elem.contains(child);
},
// 尺寸数据
getSizeData: function getSizeData() {
var elem = this[0];
return elem.getBoundingClientRect(); // 可得到 bottom height left right top width 的数据
},
// 封装 nodeName
getNodeName: function getNodeName() {
var elem = this[0];
return elem.nodeName;
},
// 从当前元素查找
find: function find(selector) {
var elem = this[0];
return $(elem.querySelectorAll(selector));
},
// 获取当前元素的 text
text: function text(val) {
if (!val) {
// 获取 text
var elem = this[0];
return elem.innerHTML.replace(/<.*?>/g, function () {
return '';
});
} else {
// 设置 text
return this.forEach(function (elem) {
elem.innerHTML = val;
});
}
},
// 获取 html
html: function html(value) {
var elem = this[0];
if (value == null) {
return elem.innerHTML;
} else {
elem.innerHTML = value;
return this;
}
},
// 获取 value
val: function val() {
var elem = this[0];
return elem.value.trim();
},
// focus
focus: function focus() {
return this.forEach(function (elem) {
elem.focus();
});
},
// parent
parent: function parent() {
var elem = this[0];
return $(elem.parentElement);
},
// parentUntil 找到符合 selector 的父节点
parentUntil: function parentUntil(selector, _currentElem) {
var results = document.querySelectorAll(selector);
var length = results.length;
if (!length) {
// 传入的 selector 无效
return null;
}
var elem = _currentElem || this[0];
if (elem.nodeName === 'BODY') {
return null;
}
var parent = elem.parentElement;
var i = void 0;
for (i = 0; i < length; i++) {
if (parent === results[i]) {
// 找到,并返回
return $(parent);
}
}
// 继续查找
return this.parentUntil(selector, parent);
},
// 判断两个 elem 是否相等
equal: function equal($elem) {
if ($elem.nodeType === 1) {
return this[0] === $elem;
} else {
return this[0] === $elem[0];
}
},
// 将该元素插入到某个元素前面
insertBefore: function insertBefore(selector) {
var $referenceNode = $(selector);
var referenceNode = $referenceNode[0];
if (!referenceNode) {
return this;
}
return this.forEach(function (elem) {
var parent = referenceNode.parentNode;
parent.insertBefore(elem, referenceNode);
});
},
// 将该元素插入到某个元素后面
insertAfter: function insertAfter(selector) {
var $referenceNode = $(selector);
var referenceNode = $referenceNode[0];
if (!referenceNode) {
return this;
}
return this.forEach(function (elem) {
var parent = referenceNode.parentNode;
if (parent.lastChild === referenceNode) {
// 最后一个元素
parent.appendChild(elem);
} else {
// 不是最后一个元素
parent.insertBefore(elem, referenceNode.nextSibling);
}
});
}
};
// new 一个对象
function $(selector) {
return new DomElement(selector);
}
// 解绑所有事件,用于销毁编辑器
$.offAll = function () {
eventList.forEach(function (item) {
var elem = item.elem;
var type = item.type;
var fn = item.fn;
// 解绑
elem.removeEventListener(type, fn);
});
};
/*
配置信息
*/
var config = {
// 默认菜单配置
menus: ['head', 'bold', 'fontSize', 'fontName', 'italic', 'underline', 'strikeThrough', 'foreColor', 'backColor', 'link', 'list', 'justify', 'quote', 'emoticon', 'image', 'table', 'video', 'code', 'undo', 'redo'],
fontNames: ['宋体', '微软雅黑', 'Arial', 'Tahoma', 'Verdana'],
colors: ['#000000', '#eeece0', '#1c487f', '#4d80bf', '#c24f4a', '#8baa4a', '#7b5ba1', '#46acc8', '#f9963b', '#ffffff'],
// // 语言配置
// lang: {
// '设置标题': 'title',
// '正文': 'p',
// '链接文字': 'link text',
// '链接': 'link',
// '插入': 'insert',
// '创建': 'init'
// },
// 表情
emotions: [{
// tab 的标题
title: '默认',
// type -> 'emoji' / 'image'
type: 'image',
// content -> 数组
content: [{
alt: '[坏笑]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/50/pcmoren_huaixiao_org.png'
}, {
alt: '[舔屏]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/40/pcmoren_tian_org.png'
}, {
alt: '[污]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/3c/pcmoren_wu_org.png'
}]
}, {
// tab 的标题
title: '新浪',
// type -> 'emoji' / 'image'
type: 'image',
// content -> 数组
content: [{
src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/7a/shenshou_thumb.gif',
alt: '[草泥马]'
}, {
src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/60/horse2_thumb.gif',
alt: '[神马]'
}, {
src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/bc/fuyun_thumb.gif',
alt: '[浮云]'
}]
}, {
// tab 的标题
title: 'emoji',
// type -> 'emoji' / 'image'
type: 'emoji',
// content -> 数组
content: '? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?'.split(/\s/)
}],
// 编辑区域的 z-index
zIndex: 10000,
// 是否开启 debug 模式(debug 模式下错误会 throw error 形式抛出)
debug: false,
// 插入链接时候的格式校验
linkCheck: function linkCheck(text, link) {
// text 是插入的文字
// link 是插入的链接
return true; // 返回 true 即表示成功
// return '校验失败' // 返回字符串即表示失败的提示信息
},
// 插入网络图片的校验
linkImgCheck: function linkImgCheck(src) {
// src 即图片的地址
return true; // 返回 true 即表示成功
// return '校验失败' // 返回字符串即表示失败的提示信息
},
// 粘贴过滤样式,默认开启
pasteFilterStyle: true,
// 粘贴内容时,忽略图片。默认关闭
pasteIgnoreImg: false,
// 对粘贴的文字进行自定义处理,返回处理后的结果。编辑器会将处理后的结果粘贴到编辑区域中。
// IE 暂时不支持
pasteTextHandle: function pasteTextHandle(content) {
// content 即粘贴过来的内容(html 或 纯文本),可进行自定义处理然后返回
return content;
},
// onchange 事件
// onchange: function (html) {
// // html 即变化之后的内容
// console.log(html)
// },
// 是否显示添加网络图片的 tab
showLinkImg: true,
// 插入网络图片的回调
linkImgCallback: function linkImgCallback(url) {
// console.log(url) // url 即插入图片的地址
},
// 默认上传图片 max size: 5M
uploadImgMaxSize: 5 * 1024 * 1024,
// 配置一次最多上传几个图片
// uploadImgMaxLength: 5,
// 上传图片,是否显示 base64 格式
uploadImgShowBase64: false,
// 上传图片,server 地址(如果有值,则 base64 格式的配置则失效)
// uploadImgServer: '/upload',
// 自定义配置 filename
uploadFileName: '',
// 上传图片的自定义参数
uploadImgParams: {
// token: 'abcdef12345'
},
// 上传图片的自定义header
uploadImgHeaders: {
// 'Accept': 'text/x-json'
},
// 配置 XHR withCredentials
withCredentials: false,
// 自定义上传图片超时时间 ms
uploadImgTimeout: 10000,
// 上传图片 hook
uploadImgHooks: {
// customInsert: function (insertLinkImg, result, editor) {
// console.log('customInsert')
// // 图片上传并返回结果,自定义插入图片的事件,而不是编辑器自动插入图片
// const data = result.data1 || []
// data.forEach(link => {
// insertLinkImg(link)
// })
// },
before: function before(xhr, editor, files) {
// 图片上传之前触发
// 如果返回的结果是 {prevent: true, msg: 'xxxx'} 则表示用户放弃上传
// return {
// prevent: true,
// msg: '放弃上传'
// }
},
success: function success(xhr, editor, result) {
// 图片上传并返回结果,图片插入成功之后触发
},
fail: function fail(xhr, editor, result) {
// 图片上传并返回结果,但图片插入错误时触发
},
error: function error(xhr, editor) {
// 图片上传出错时触发
},
timeout: function timeout(xhr, editor) {
// 图片上传超时时触发
}
},
// 是否上传七牛云,默认为 false
qiniu: false
};
/*
工具
*/
// 和 UA 相关的属性
var UA = {
_ua: navigator.userAgent,
// 是否 webkit
isWebkit: function isWebkit() {
var reg = /webkit/i;
return reg.test(this._ua);
},
// 是否 IE
isIE: function isIE() {
return 'ActiveXObject' in window;
}
};
// 遍历对象
function objForEach(obj, fn) {
var key = void 0,
result = void 0;
for (key in obj) {
if (obj.hasOwnProperty(key)) {
result = fn.call(obj, key, obj[key]);
if (result === false) {
break;
}
}
}
}
// 遍历类数组
function arrForEach(fakeArr, fn) {
var i = void 0,
item = void 0,
result = void 0;
var length = fakeArr.length || 0;
for (i = 0; i < length; i++) {
item = fakeArr[i];
result = fn.call(fakeArr, item, i);
if (result === false) {
break;
}
}
}
// 获取随机数
function getRandom(prefix) {
return prefix + Math.random().toString().slice(2);
}
// 替换 html 特殊字符
function replaceHtmlSymbol(html) {
if (html == null) {
return '';
}
return html.replace(//gm, '>').replace(/"/gm, '"').replace(/(\r\n|\r|\n)/g, '
');
}
// 返回百分比的格式
// 判断是不是 function
function isFunction(fn) {
return typeof fn === 'function';
}
/*
bold-menu
*/
// 构造函数
function Bold(editor) {
this.editor = editor;
this.$elem = $(' ');
this.type = 'click';
// 当前是否 active 状态
this._active = false;
}
// 原型
Bold.prototype = {
constructor: Bold,
// 点击事件
onClick: function onClick(e) {
// 点击菜单将触发这里
var editor = this.editor;
var isSeleEmpty = editor.selection.isSelectionEmpty();
if (isSeleEmpty) {
// 选区是空的,插入并选中一个“空白”
editor.selection.createEmptyRange();
}
// 执行 bold 命令
editor.cmd.do('bold');
if (isSeleEmpty) {
// 需要将选取折叠起来
editor.selection.collapseRange();
editor.selection.restoreSelection();
}
},
// 试图改变 active 状态
tryChangeActive: function tryChangeActive(e) {
var editor = this.editor;
var $elem = this.$elem;
if (editor.cmd.queryCommandState('bold')) {
this._active = true;
$elem.addClass('w-e-active');
} else {
this._active = false;
$elem.removeClass('w-e-active');
}
}
};
/*
替换多语言
*/
var replaceLang = function (editor, str) {
var langArgs = editor.config.langArgs || [];
var result = str;
langArgs.forEach(function (item) {
var reg = item.reg;
var val = item.val;
if (reg.test(result)) {
result = result.replace(reg, function () {
return val;
});
}
});
return result;
};
/*
droplist
*/
var _emptyFn = function _emptyFn() {};
// 构造函数
function DropList(menu, opt) {
var _this = this;
// droplist 所依附的菜单
var editor = menu.editor;
this.menu = menu;
this.opt = opt;
// 容器
var $container = $('');
// 标题
var $title = opt.$title;
var titleHtml = void 0;
if ($title) {
// 替换多语言
titleHtml = $title.html();
titleHtml = replaceLang(editor, titleHtml);
$title.html(titleHtml);
$title.addClass('w-e-dp-title');
$container.append($title);
}
var list = opt.list || [];
var type = opt.type || 'list'; // 'list' 列表形式(如“标题”菜单) / 'inline-block' 块状形式(如“颜色”菜单)
var onClick = opt.onClick || _emptyFn;
// 加入 DOM 并绑定事件
var $list = $('
');
$container.append($list);
list.forEach(function (item) {
var $elem = item.$elem;
// 替换多语言
var elemHtml = $elem.html();
elemHtml = replaceLang(editor, elemHtml);
$elem.html(elemHtml);
var value = item.value;
var $li = $('');
if ($elem) {
$li.append($elem);
$list.append($li);
$li.on('click', function (e) {
onClick(value);
// 隐藏
_this.hideTimeoutId = setTimeout(function () {
_this.hide();
}, 0);
});
}
});
// 绑定隐藏事件
$container.on('mouseleave', function (e) {
_this.hideTimeoutId = setTimeout(function () {
_this.hide();
}, 0);
});
// 记录属性
this.$container = $container;
// 基本属性
this._rendered = false;
this._show = false;
}
// 原型
DropList.prototype = {
constructor: DropList,
// 显示(插入DOM)
show: function show() {
if (this.hideTimeoutId) {
// 清除之前的定时隐藏
clearTimeout(this.hideTimeoutId);
}
var menu = this.menu;
var $menuELem = menu.$elem;
var $container = this.$container;
if (this._show) {
return;
}
if (this._rendered) {
// 显示
$container.show();
} else {
// 加入 DOM 之前先定位位置
var menuHeight = $menuELem.getSizeData().height || 0;
var width = this.opt.width || 100; // 默认为 100
$container.css('margin-top', menuHeight + 'px').css('width', width + 'px');
// 加入到 DOM
$menuELem.append($container);
this._rendered = true;
}
// 修改属性
this._show = true;
},
// 隐藏(移除DOM)
hide: function hide() {
if (this.showTimeoutId) {
// 清除之前的定时显示
clearTimeout(this.showTimeoutId);
}
var $container = this.$container;
if (!this._show) {
return;
}
// 隐藏并需改属性
$container.hide();
this._show = false;
}
};
/*
menu - header
*/
// 构造函数
function Head(editor) {
var _this = this;
this.editor = editor;
this.$elem = $(' ');
this.type = 'droplist';
// 当前是否 active 状态
this._active = false;
// 初始化 droplist
this.droplist = new DropList(this, {
width: 100,
$title: $('设置标题
'),
type: 'list', // droplist 以列表形式展示
list: [{ $elem: $('H1
'), value: '' }, { $elem: $('H2
'), value: '' }, { $elem: $('H3
'), value: '' }, { $elem: $('H4
'), value: '' }, { $elem: $('H5
'), value: '' }, { $elem: $('
正文
'), value: '' }],
onClick: function onClick(value) {
// 注意 this 是指向当前的 Head 对象
_this._command(value);
}
});
}
// 原型
Head.prototype = {
constructor: Head,
// 执行命令
_command: function _command(value) {
var editor = this.editor;
var $selectionElem = editor.selection.getSelectionContainerElem();
if (editor.$textElem.equal($selectionElem)) {
// 不能选中多行来设置标题,否则会出现问题
// 例如选中的是
xxx
yyy
来设置标题,设置之后会成为 xxx
yyy
不符合预期
return;
}
editor.cmd.do('formatBlock', value);
},
// 试图改变 active 状态
tryChangeActive: function tryChangeActive(e) {
var editor = this.editor;
var $elem = this.$elem;
var reg = /^h/i;
var cmdValue = editor.cmd.queryCommandValue('formatBlock');
if (reg.test(cmdValue)) {
this._active = true;
$elem.addClass('w-e-active');
} else {
this._active = false;
$elem.removeClass('w-e-active');
}
}
};
/*
menu - fontSize
*/
// 构造函数
function FontSize(editor) {
var _this = this;
this.editor = editor;
this.$elem = $(' ');
this.type = 'droplist';
// 当前是否 active 状态
this._active = false;
// 初始化 droplist
this.droplist = new DropList(this, {
width: 160,
$title: $('字号
'),
type: 'list', // droplist 以列表形式展示
list: [{ $elem: $('x-small'), value: '1' }, { $elem: $('small'), value: '2' }, { $elem: $('normal'), value: '3' }, { $elem: $('large'), value: '4' }, { $elem: $('x-large'), value: '5' }, { $elem: $('xx-large'), value: '6' }],
onClick: function onClick(value) {
// 注意 this 是指向当前的 FontSize 对象
_this._command(value);
}
});
}
// 原型
FontSize.prototype = {
constructor: FontSize,
// 执行命令
_command: function _command(value) {
var editor = this.editor;
editor.cmd.do('fontSize', value);
}
};
/*
menu - fontName
*/
// 构造函数
function FontName(editor) {
var _this = this;
this.editor = editor;
this.$elem = $(' ');
this.type = 'droplist';
// 当前是否 active 状态
this._active = false;
// 获取配置的字体
var config = editor.config;
var fontNames = config.fontNames || [];
// 初始化 droplist
this.droplist = new DropList(this, {
width: 100,
$title: $('字体
'),
type: 'list', // droplist 以列表形式展示
list: fontNames.map(function (fontName) {
return { $elem: $('' + fontName + ''), value: fontName };
}),
onClick: function onClick(value) {
// 注意 this 是指向当前的 FontName 对象
_this._command(value);
}
});
}
// 原型
FontName.prototype = {
constructor: FontName,
_command: function _command(value) {
var editor = this.editor;
editor.cmd.do('fontName', value);
}
};
/*
panel
*/
var emptyFn = function emptyFn() {};
// 记录已经显示 panel 的菜单
var _isCreatedPanelMenus = [];
// 构造函数
function Panel(menu, opt) {
this.menu = menu;
this.opt = opt;
}
// 原型
Panel.prototype = {
constructor: Panel,
// 显示(插入DOM)
show: function show() {
var _this = this;
var menu = this.menu;
if (_isCreatedPanelMenus.indexOf(menu) >= 0) {
// 该菜单已经创建了 panel 不能再创建
return;
}
var editor = menu.editor;
var $body = $('body');
var $textContainerElem = editor.$textContainerElem;
var opt = this.opt;
// panel 的容器
var $container = $('');
var width = opt.width || 300; // 默认 300px
$container.css('width', width + 'px').css('margin-left', (0 - width) / 2 + 'px');
// 添加关闭按钮
var $closeBtn = $('');
$container.append($closeBtn);
$closeBtn.on('click', function () {
_this.hide();
});
// 准备 tabs 容器
var $tabTitleContainer = $('
');
var $tabContentContainer = $('');
$container.append($tabTitleContainer).append($tabContentContainer);
// 设置高度
var height = opt.height;
if (height) {
$tabContentContainer.css('height', height + 'px').css('overflow-y', 'auto');
}
// tabs
var tabs = opt.tabs || [];
var tabTitleArr = [];
var tabContentArr = [];
tabs.forEach(function (tab, tabIndex) {
if (!tab) {
return;
}
var title = tab.title || '';
var tpl = tab.tpl || '';
// 替换多语言
title = replaceLang(editor, title);
tpl = replaceLang(editor, tpl);
// 添加到 DOM
var $title = $('' + title + ' ');
$tabTitleContainer.append($title);
var $content = $(tpl);
$tabContentContainer.append($content);
// 记录到内存
$title._index = tabIndex;
tabTitleArr.push($title);
tabContentArr.push($content);
// 设置 active 项
if (tabIndex === 0) {
$title._active = true;
$title.addClass('w-e-active');
} else {
$content.hide();
}
// 绑定 tab 的事件
$title.on('click', function (e) {
if ($title._active) {
return;
}
// 隐藏所有的 tab
tabTitleArr.forEach(function ($title) {
$title._active = false;
$title.removeClass('w-e-active');
});
tabContentArr.forEach(function ($content) {
$content.hide();
});
// 显示当前的 tab
$title._active = true;
$title.addClass('w-e-active');
$content.show();
});
});
// 绑定关闭事件
$container.on('click', function (e) {
// 点击时阻止冒泡
e.stopPropagation();
});
$body.on('click', function (e) {
_this.hide();
});
// 添加到 DOM
$textContainerElem.append($container);
// 绑定 opt 的事件,只有添加到 DOM 之后才能绑定成功
tabs.forEach(function (tab, index) {
if (!tab) {
return;
}
var events = tab.events || [];
events.forEach(function (event) {
var selector = event.selector;
var type = event.type;
var fn = event.fn || emptyFn;
var $content = tabContentArr[index];
$content.find(selector).on(type, function (e) {
e.stopPropagation();
var needToHide = fn(e);
// 执行完事件之后,是否要关闭 panel
if (needToHide) {
_this.hide();
}
});
});
});
// focus 第一个 elem
var $inputs = $container.find('input[type=text],textarea');
if ($inputs.length) {
$inputs.get(0).focus();
}
// 添加到属性
this.$container = $container;
// 隐藏其他 panel
this._hideOtherPanels();
// 记录该 menu 已经创建了 panel
_isCreatedPanelMenus.push(menu);
},
// 隐藏(移除DOM)
hide: function hide() {
var menu = this.menu;
var $container = this.$container;
if ($container) {
$container.remove();
}
// 将该 menu 记录中移除
_isCreatedPanelMenus = _isCreatedPanelMenus.filter(function (item) {
if (item === menu) {
return false;
} else {
return true;
}
});
},
// 一个 panel 展示时,隐藏其他 panel
_hideOtherPanels: function _hideOtherPanels() {
if (!_isCreatedPanelMenus.length) {
return;
}
_isCreatedPanelMenus.forEach(function (menu) {
var panel = menu.panel || {};
if (panel.hide) {
panel.hide();
}
});
}
};
/*
menu - link
*/
// 构造函数
function Link(editor) {
this.editor = editor;
this.$elem = $(' ');
this.type = 'panel';
// 当前是否 active 状态
this._active = false;
}
// 原型
Link.prototype = {
constructor: Link,
// 点击事件
onClick: function onClick(e) {
var editor = this.editor;
var $linkelem = void 0;
if (this._active) {
// 当前选区在链接里面
$linkelem = editor.selection.getSelectionContainerElem();
if (!$linkelem) {
return;
}
// 将该元素都包含在选取之内,以便后面整体替换
editor.selection.createRangeByElem($linkelem);
editor.selection.restoreSelection();
// 显示 panel
this._createPanel($linkelem.text(), $linkelem.attr('href'));
} else {
// 当前选区不在链接里面
if (editor.selection.isSelectionEmpty()) {
// 选区是空的,未选中内容
this._createPanel('', '');
} else {
// 选中内容了
this._createPanel(editor.selection.getSelectionText(), '');
}
}
},
// 创建 panel
_createPanel: function _createPanel(text, link) {
var _this = this;
// panel 中需要用到的id
var inputLinkId = getRandom('input-link');
var inputTextId = getRandom('input-text');
var btnOkId = getRandom('btn-ok');
var btnDelId = getRandom('btn-del');
// 是否显示“删除链接”
var delBtnDisplay = this._active ? 'inline-block' : 'none';
// 初始化并显示 panel
var panel = new Panel(this, {
width: 300,
// panel 中可包含多个 tab
tabs: [{
// tab 的标题
title: '链接',
// 模板
tpl: '\n \n \n ',
// 事件绑定
events: [
// 插入链接
{
selector: '#' + btnOkId,
type: 'click',
fn: function fn() {
// 执行插入链接
var $link = $('#' + inputLinkId);
var $text = $('#' + inputTextId);
var link = $link.val();
var text = $text.val();
_this._insertLink(text, link);
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
},
// 删除链接
{
selector: '#' + btnDelId,
type: 'click',
fn: function fn() {
// 执行删除链接
_this._delLink();
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
}]
} // tab end
] // tabs end
});
// 显示 panel
panel.show();
// 记录属性
this.panel = panel;
},
// 删除当前链接
_delLink: function _delLink() {
if (!this._active) {
return;
}
var editor = this.editor;
var $selectionELem = editor.selection.getSelectionContainerElem();
if (!$selectionELem) {
return;
}
var selectionText = editor.selection.getSelectionText();
editor.cmd.do('insertHTML', ' \n ' + selectionText + '');
},
// 插入链接
_insertLink: function _insertLink(text, link) {
var editor = this.editor;
var config = editor.config;
var linkCheck = config.linkCheck;
var checkResult = true; // 默认为 true
if (linkCheck && typeof linkCheck === 'function') {
checkResult = linkCheck(text, link);
}
if (checkResult === true) {
editor.cmd.do('insertHTML', '' + text + '');
} else {
alert(checkResult);
}
},
// 试图改变 active 状态
tryChangeActive: function tryChangeActive(e) {
var editor = this.editor;
var $elem = this.$elem;
var $selectionELem = editor.selection.getSelectionContainerElem();
if (!$selectionELem) {
return;
}
if ($selectionELem.getNodeName() === 'A') {
this._active = true;
$elem.addClass('w-e-active');
} else {
this._active = false;
$elem.removeClass('w-e-active');
}
}
};
/*
italic-menu
*/
// 构造函数
function Italic(editor) {
this.editor = editor;
this.$elem = $(' ');
this.type = 'click';
// 当前是否 active 状态
this._active = false;
}
// 原型
Italic.prototype = {
constructor: Italic,
// 点击事件
onClick: function onClick(e) {
// 点击菜单将触发这里
var editor = this.editor;
var isSeleEmpty = editor.selection.isSelectionEmpty();
if (isSeleEmpty) {
// 选区是空的,插入并选中一个“空白”
editor.selection.createEmptyRange();
}
// 执行 italic 命令
editor.cmd.do('italic');
if (isSeleEmpty) {
// 需要将选取折叠起来
editor.selection.collapseRange();
editor.selection.restoreSelection();
}
},
// 试图改变 active 状态
tryChangeActive: function tryChangeActive(e) {
var editor = this.editor;
var $elem = this.$elem;
if (editor.cmd.queryCommandState('italic')) {
this._active = true;
$elem.addClass('w-e-active');
} else {
this._active = false;
$elem.removeClass('w-e-active');
}
}
};
/*
redo-menu
*/
// 构造函数
function Redo(editor) {
this.editor = editor;
this.$elem = $(' ');
this.type = 'click';
// 当前是否 active 状态
this._active = false;
}
// 原型
Redo.prototype = {
constructor: Redo,
// 点击事件
onClick: function onClick(e) {
// 点击菜单将触发这里
var editor = this.editor;
// 执行 redo 命令
editor.cmd.do('redo');
}
};
/*
strikeThrough-menu
*/
// 构造函数
function StrikeThrough(editor) {
this.editor = editor;
this.$elem = $(' ');
this.type = 'click';
// 当前是否 active 状态
this._active = false;
}
// 原型
StrikeThrough.prototype = {
constructor: StrikeThrough,
// 点击事件
onClick: function onClick(e) {
// 点击菜单将触发这里
var editor = this.editor;
var isSeleEmpty = editor.selection.isSelectionEmpty();
if (isSeleEmpty) {
// 选区是空的,插入并选中一个“空白”
editor.selection.createEmptyRange();
}
// 执行 strikeThrough 命令
editor.cmd.do('strikeThrough');
if (isSeleEmpty) {
// 需要将选取折叠起来
editor.selection.collapseRange();
editor.selection.restoreSelection();
}
},
// 试图改变 active 状态
tryChangeActive: function tryChangeActive(e) {
var editor = this.editor;
var $elem = this.$elem;
if (editor.cmd.queryCommandState('strikeThrough')) {
this._active = true;
$elem.addClass('w-e-active');
} else {
this._active = false;
$elem.removeClass('w-e-active');
}
}
};
/*
underline-menu
*/
// 构造函数
function Underline(editor) {
this.editor = editor;
this.$elem = $(' ');
this.type = 'click';
// 当前是否 active 状态
this._active = false;
}
// 原型
Underline.prototype = {
constructor: Underline,
// 点击事件
onClick: function onClick(e) {
// 点击菜单将触发这里
var editor = this.editor;
var isSeleEmpty = editor.selection.isSelectionEmpty();
if (isSeleEmpty) {
// 选区是空的,插入并选中一个“空白”
editor.selection.createEmptyRange();
}
// 执行 underline 命令
editor.cmd.do('underline');
if (isSeleEmpty) {
// 需要将选取折叠起来
editor.selection.collapseRange();
editor.selection.restoreSelection();
}
},
// 试图改变 active 状态
tryChangeActive: function tryChangeActive(e) {
var editor = this.editor;
var $elem = this.$elem;
if (editor.cmd.queryCommandState('underline')) {
this._active = true;
$elem.addClass('w-e-active');
} else {
this._active = false;
$elem.removeClass('w-e-active');
}
}
};
/*
undo-menu
*/
// 构造函数
function Undo(editor) {
this.editor = editor;
this.$elem = $(' ');
this.type = 'click';
// 当前是否 active 状态
this._active = false;
}
// 原型
Undo.prototype = {
constructor: Undo,
// 点击事件
onClick: function onClick(e) {
// 点击菜单将触发这里
var editor = this.editor;
// 执行 undo 命令
editor.cmd.do('undo');
}
};
/*
menu - list
*/
// 构造函数
function List(editor) {
var _this = this;
this.editor = editor;
this.$elem = $(' ');
this.type = 'droplist';
// 当前是否 active 状态
this._active = false;
// 初始化 droplist
this.droplist = new DropList(this, {
width: 120,
$title: $('设置列表
'),
type: 'list', // droplist 以列表形式展示
list: [{ $elem: $(' 有序列表'), value: 'insertOrderedList' }, { $elem: $(' 无序列表'), value: 'insertUnorderedList' }],
onClick: function onClick(value) {
// 注意 this 是指向当前的 List 对象
_this._command(value);
}
});
}
// 原型
List.prototype = {
constructor: List,
// 执行命令
_command: function _command(value) {
var editor = this.editor;
var $textElem = editor.$textElem;
editor.selection.restoreSelection();
if (editor.cmd.queryCommandState(value)) {
return;
}
editor.cmd.do(value);
// 验证列表是否被包裹在 之内
var $selectionElem = editor.selection.getSelectionContainerElem();
if ($selectionElem.getNodeName() === 'LI') {
$selectionElem = $selectionElem.parent();
}
if (/^ol|ul$/i.test($selectionElem.getNodeName()) === false) {
return;
}
if ($selectionElem.equal($textElem)) {
// 证明是顶级标签,没有被
包裹
return;
}
var $parent = $selectionElem.parent();
if ($parent.equal($textElem)) {
// $parent 是顶级标签,不能删除
return;
}
$selectionElem.insertAfter($parent);
$parent.remove();
},
// 试图改变 active 状态
tryChangeActive: function tryChangeActive(e) {
var editor = this.editor;
var $elem = this.$elem;
if (editor.cmd.queryCommandState('insertUnOrderedList') || editor.cmd.queryCommandState('insertOrderedList')) {
this._active = true;
$elem.addClass('w-e-active');
} else {
this._active = false;
$elem.removeClass('w-e-active');
}
}
};
/*
menu - justify
*/
// 构造函数
function Justify(editor) {
var _this = this;
this.editor = editor;
this.$elem = $('
');
this.type = 'droplist';
// 当前是否 active 状态
this._active = false;
// 初始化 droplist
this.droplist = new DropList(this, {
width: 100,
$title: $('对齐方式
'),
type: 'list', // droplist 以列表形式展示
list: [{ $elem: $(' 靠左'), value: 'justifyLeft' }, { $elem: $(' 居中'), value: 'justifyCenter' }, { $elem: $(' 靠右'), value: 'justifyRight' }],
onClick: function onClick(value) {
// 注意 this 是指向当前的 List 对象
_this._command(value);
}
});
}
// 原型
Justify.prototype = {
constructor: Justify,
// 执行命令
_command: function _command(value) {
var editor = this.editor;
editor.cmd.do(value);
}
};
/*
menu - Forecolor
*/
// 构造函数
function ForeColor(editor) {
var _this = this;
this.editor = editor;
this.$elem = $(' ');
this.type = 'droplist';
// 获取配置的颜色
var config = editor.config;
var colors = config.colors || [];
// 当前是否 active 状态
this._active = false;
// 初始化 droplist
this.droplist = new DropList(this, {
width: 120,
$title: $('文字颜色
'),
type: 'inline-block', // droplist 内容以 block 形式展示
list: colors.map(function (color) {
return { $elem: $(''), value: color };
}),
onClick: function onClick(value) {
// 注意 this 是指向当前的 ForeColor 对象
_this._command(value);
}
});
}
// 原型
ForeColor.prototype = {
constructor: ForeColor,
// 执行命令
_command: function _command(value) {
var editor = this.editor;
editor.cmd.do('foreColor', value);
}
};
/*
menu - BackColor
*/
// 构造函数
function BackColor(editor) {
var _this = this;
this.editor = editor;
this.$elem = $(' ');
this.type = 'droplist';
// 获取配置的颜色
var config = editor.config;
var colors = config.colors || [];
// 当前是否 active 状态
this._active = false;
// 初始化 droplist
this.droplist = new DropList(this, {
width: 120,
$title: $('背景色
'),
type: 'inline-block', // droplist 内容以 block 形式展示
list: colors.map(function (color) {
return { $elem: $(''), value: color };
}),
onClick: function onClick(value) {
// 注意 this 是指向当前的 BackColor 对象
_this._command(value);
}
});
}
// 原型
BackColor.prototype = {
constructor: BackColor,
// 执行命令
_command: function _command(value) {
var editor = this.editor;
editor.cmd.do('backColor', value);
}
};
/*
menu - quote
*/
// 构造函数
function Quote(editor) {
this.editor = editor;
this.$elem = $(' ');
this.type = 'click';
// 当前是否 active 状态
this._active = false;
}
// 原型
Quote.prototype = {
constructor: Quote,
onClick: function onClick(e) {
var editor = this.editor;
var $selectionElem = editor.selection.getSelectionContainerElem();
var nodeName = $selectionElem.getNodeName();
if (!UA.isIE()) {
if (nodeName === 'BLOCKQUOTE') {
// 撤销 quote
editor.cmd.do('formatBlock', '');
} else {
// 转换为 quote
editor.cmd.do('formatBlock', '
');
}
return;
}
// IE 中不支持 formatBlock ,要用其他方式兼容
var content = void 0,
$targetELem = void 0;
if (nodeName === 'P') {
// 将 P 转换为 quote
content = $selectionElem.text();
$targetELem = $('' + content + '
');
$targetELem.insertAfter($selectionElem);
$selectionElem.remove();
return;
}
if (nodeName === 'BLOCKQUOTE') {
// 撤销 quote
content = $selectionElem.text();
$targetELem = $('' + content + '
');
$targetELem.insertAfter($selectionElem);
$selectionElem.remove();
}
},
tryChangeActive: function tryChangeActive(e) {
var editor = this.editor;
var $elem = this.$elem;
var reg = /^BLOCKQUOTE$/i;
var cmdValue = editor.cmd.queryCommandValue('formatBlock');
if (reg.test(cmdValue)) {
this._active = true;
$elem.addClass('w-e-active');
} else {
this._active = false;
$elem.removeClass('w-e-active');
}
}
};
/*
menu - code
*/
// 构造函数
function Code(editor) {
this.editor = editor;
this.$elem = $(' ');
this.type = 'panel';
// 当前是否 active 状态
this._active = false;
}
// 原型
Code.prototype = {
constructor: Code,
onClick: function onClick(e) {
var editor = this.editor;
var $startElem = editor.selection.getSelectionStartElem();
var $endElem = editor.selection.getSelectionEndElem();
var isSeleEmpty = editor.selection.isSelectionEmpty();
var selectionText = editor.selection.getSelectionText();
var $code = void 0;
if (!$startElem.equal($endElem)) {
// 跨元素选择,不做处理
editor.selection.restoreSelection();
return;
}
if (!isSeleEmpty) {
// 选取不是空,用 包裹即可
$code = $('' + selectionText + '
');
editor.cmd.do('insertElem', $code);
editor.selection.createRangeByElem($code, false);
editor.selection.restoreSelection();
return;
}
// 选取是空,且没有夸元素选择,则插入
if (this._active) {
// 选中状态,将编辑内容
this._createPanel($startElem.html());
} else {
// 未选中状态,将创建内容
this._createPanel();
}
},
_createPanel: function _createPanel(value) {
var _this = this;
// value - 要编辑的内容
value = value || '';
var type = !value ? 'new' : 'edit';
var textId = getRandom('texxt');
var btnId = getRandom('btn');
var panel = new Panel(this, {
width: 500,
// 一个 Panel 包含多个 tab
tabs: [{
// 标题
title: '插入代码',
// 模板
tpl: '\n \n ',
// 事件绑定
events: [
// 插入代码
{
selector: '#' + btnId,
type: 'click',
fn: function fn() {
var $text = $('#' + textId);
var text = $text.val() || $text.html();
text = replaceHtmlSymbol(text);
if (type === 'new') {
// 新插入
_this._insertCode(text);
} else {
// 编辑更新
_this._updateCode(text);
}
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
}]
} // first tab end
] // tabs end
}); // new Panel end
// 显示 panel
panel.show();
// 记录属性
this.panel = panel;
},
// 插入代码
_insertCode: function _insertCode(value) {
var editor = this.editor;
editor.cmd.do('insertHTML', '' + value + '
');
},
// 更新代码
_updateCode: function _updateCode(value) {
var editor = this.editor;
var $selectionELem = editor.selection.getSelectionContainerElem();
if (!$selectionELem) {
return;
}
$selectionELem.html(value);
editor.selection.restoreSelection();
},
// 试图改变 active 状态
tryChangeActive: function tryChangeActive(e) {
var editor = this.editor;
var $elem = this.$elem;
var $selectionELem = editor.selection.getSelectionContainerElem();
if (!$selectionELem) {
return;
}
var $parentElem = $selectionELem.parent();
if ($selectionELem.getNodeName() === 'CODE' && $parentElem.getNodeName() === 'PRE') {
this._active = true;
$elem.addClass('w-e-active');
} else {
this._active = false;
$elem.removeClass('w-e-active');
}
}
};
/*
menu - emoticon
*/
// 构造函数
function Emoticon(editor) {
this.editor = editor;
this.$elem = $(' ');
this.type = 'panel';
// 当前是否 active 状态
this._active = false;
}
// 原型
Emoticon.prototype = {
constructor: Emoticon,
onClick: function onClick() {
this._createPanel();
},
_createPanel: function _createPanel() {
var _this = this;
var editor = this.editor;
var config = editor.config;
// 获取表情配置
var emotions = config.emotions || [];
// 创建表情 dropPanel 的配置
var tabConfig = [];
emotions.forEach(function (emotData) {
var emotType = emotData.type;
var content = emotData.content || [];
// 这一组表情最终拼接出来的 html
var faceHtml = '';
// emoji 表情
if (emotType === 'emoji') {
content.forEach(function (item) {
if (item) {
faceHtml += '' + item + '';
}
});
}
// 图片表情
if (emotType === 'image') {
content.forEach(function (item) {
var src = item.src;
var alt = item.alt;
if (src) {
// 加一个 data-w-e 属性,点击图片的时候不再提示编辑图片
faceHtml += '';
}
});
}
tabConfig.push({
title: emotData.title,
tpl: '' + faceHtml + '',
events: [{
selector: 'span.w-e-item',
type: 'click',
fn: function fn(e) {
var target = e.target;
var $target = $(target);
var nodeName = $target.getNodeName();
var insertHtml = void 0;
if (nodeName === 'IMG') {
// 插入图片
insertHtml = $target.parent().html();
} else {
// 插入 emoji
insertHtml = '' + $target.html() + '';
}
_this._insert(insertHtml);
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
}]
});
});
var panel = new Panel(this, {
width: 300,
height: 200,
// 一个 Panel 包含多个 tab
tabs: tabConfig
});
// 显示 panel
panel.show();
// 记录属性
this.panel = panel;
},
// 插入表情
_insert: function _insert(emotHtml) {
var editor = this.editor;
editor.cmd.do('insertHTML', emotHtml);
}
};
/*
menu - table
*/
// 构造函数
function Table(editor) {
this.editor = editor;
this.$elem = $(' ');
this.type = 'panel';
// 当前是否 active 状态
this._active = false;
}
// 原型
Table.prototype = {
constructor: Table,
onClick: function onClick() {
if (this._active) {
// 编辑现有表格
this._createEditPanel();
} else {
// 插入新表格
this._createInsertPanel();
}
},
// 创建插入新表格的 panel
_createInsertPanel: function _createInsertPanel() {
var _this = this;
// 用到的 id
var btnInsertId = getRandom('btn');
var textRowNum = getRandom('row');
var textColNum = getRandom('col');
var panel = new Panel(this, {
width: 250,
// panel 包含多个 tab
tabs: [{
// 标题
title: '插入表格',
// 模板
tpl: '\n \n \u521B\u5EFA\n \n \u884C\n \n \u5217\u7684\u8868\u683C\n
\n \n ',
// 事件绑定
events: [{
// 点击按钮,插入表格
selector: '#' + btnInsertId,
type: 'click',
fn: function fn() {
var rowNum = parseInt($('#' + textRowNum).val());
var colNum = parseInt($('#' + textColNum).val());
if (rowNum && colNum && rowNum > 0 && colNum > 0) {
// form 数据有效
_this._insert(rowNum, colNum);
}
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
}]
} // first tab end
] // tabs end
}); // panel end
// 展示 panel
panel.show();
// 记录属性
this.panel = panel;
},
// 插入表格
_insert: function _insert(rowNum, colNum) {
// 拼接 table 模板
var r = void 0,
c = void 0;
var html = '';
for (r = 0; r < rowNum; r++) {
html += '';
if (r === 0) {
for (c = 0; c < colNum; c++) {
html += ' ';
}
} else {
for (c = 0; c < colNum; c++) {
html += ' ';
}
}
html += ' ';
}
html += '
';
// 执行命令
var editor = this.editor;
editor.cmd.do('insertHTML', html);
// 防止 firefox 下出现 resize 的控制点
editor.cmd.do('enableObjectResizing', false);
editor.cmd.do('enableInlineTableEditing', false);
},
// 创建编辑表格的 panel
_createEditPanel: function _createEditPanel() {
var _this2 = this;
// 可用的 id
var addRowBtnId = getRandom('add-row');
var addColBtnId = getRandom('add-col');
var delRowBtnId = getRandom('del-row');
var delColBtnId = getRandom('del-col');
var delTableBtnId = getRandom('del-table');
// 创建 panel 对象
var panel = new Panel(this, {
width: 320,
// panel 包含多个 tab
tabs: [{
// 标题
title: '编辑表格',
// 模板
tpl: '\n ';
}
newTr.innerHTML = tpl;
// 插入
$(newTr).insertAfter($currentTr);
},
// 增加列
_addCol: function _addCol() {
// 获取当前单元格的位置信息
var locationData = this._getLocationData();
if (!locationData) {
return;
}
var trData = locationData.tr;
var tdData = locationData.td;
var tdIndex = tdData.index;
var $currentTr = $(trData.elem);
var $trParent = $currentTr.parent();
var $trs = $trParent.children();
// 遍历所有行
$trs.forEach(function (tr) {
var $tr = $(tr);
var $tds = $tr.children();
var $currentTd = $tds.get(tdIndex);
var name = $currentTd.getNodeName().toLowerCase();
// new 一个 td,并插入
var newTd = document.createElement(name);
$(newTd).insertAfter($currentTd);
});
},
// 删除行
_delRow: function _delRow() {
// 获取当前单元格的位置信息
var locationData = this._getLocationData();
if (!locationData) {
return;
}
var trData = locationData.tr;
var $currentTr = $(trData.elem);
$currentTr.remove();
},
// 删除列
_delCol: function _delCol() {
// 获取当前单元格的位置信息
var locationData = this._getLocationData();
if (!locationData) {
return;
}
var trData = locationData.tr;
var tdData = locationData.td;
var tdIndex = tdData.index;
var $currentTr = $(trData.elem);
var $trParent = $currentTr.parent();
var $trs = $trParent.children();
// 遍历所有行
$trs.forEach(function (tr) {
var $tr = $(tr);
var $tds = $tr.children();
var $currentTd = $tds.get(tdIndex);
// 删除
$currentTd.remove();
});
},
// 删除表格
_delTable: function _delTable() {
var editor = this.editor;
var $selectionELem = editor.selection.getSelectionContainerElem();
if (!$selectionELem) {
return;
}
var $table = $selectionELem.parentUntil('table');
if (!$table) {
return;
}
$table.remove();
},
// 试图改变 active 状态
tryChangeActive: function tryChangeActive(e) {
var editor = this.editor;
var $elem = this.$elem;
var $selectionELem = editor.selection.getSelectionContainerElem();
if (!$selectionELem) {
return;
}
var nodeName = $selectionELem.getNodeName();
if (nodeName === 'TD' || nodeName === 'TH') {
this._active = true;
$elem.addClass('w-e-active');
} else {
this._active = false;
$elem.removeClass('w-e-active');
}
}
};
//
/*
menu - video
*/
// 构造函数
function Video(editor) {
this.editor = editor;
this.$elem = $(' ');
this.type = 'panel';
// 当前是否 active 状态
this._active = false;
}
// 原型
Video.prototype = {
constructor: Video,
onClick: function onClick() {
this._createInsertPanel();
},
_createInsertPanel: function _createInsertPanel() {
var editor = this.editor;
var uploadVideo = editor.uploadVideo;
var config = editor.config;
// id
var upTriggerId = getRandom('up-trigger');
var upFileId = getRandom('up-file');
// tabs 的配置
var tabsConfig = [{
title: '上传 video',
tpl: '\n ' +
'\n ' +
'\n \n ' +
' \n ',
events: [{
// 触发选择视频
selector: '#' + upTriggerId,
type: 'click',
fn: function fn() {
var $file = $('#' + upFileId);
var fileElem = $file[0];
if (fileElem) {
fileElem.click();
} else {
// 返回 true 可关闭 panel
return true;
}
}
}, {
// 选择视频完毕
selector: '#' + upFileId,
type: 'change',
fn: function fn() {
var $file = $('#' + upFileId);
var fileElem = $file[0];
if (!fileElem) {
// 返回 true 可关闭 panel
return true;
}
// 获取选中的 file 对象列表
var fileList = fileElem.files;
if (fileList.length) {
uploadVideo.uploadVideo(fileList);
}
// 返回 true 可关闭 panel
return true;
}
}]
}
]; // tabs end
// 判断 tabs 的显示
var tabsConfigResult = [];
tabsConfigResult.push(tabsConfig[0]);
// 创建 panel 并显示
var panel = new Panel(this, {
width: 300,
tabs: tabsConfigResult
});
panel.show();
// 记录属性
this.panel = panel;
},
// 试图改变 active 状态
tryChangeActive: function tryChangeActive(e) {
var editor = this.editor;
var $elem = this.$elem;
if (editor._selectedImg) {
this._active = true;
$elem.addClass('w-e-active');
} else {
this._active = false;
$elem.removeClass('w-e-active');
}
}
};
// 构造函数
function UploadVideo(editor) {
this.editor = editor;
}
// 原型
UploadVideo.prototype = {
constructor: UploadVideo,
// 根据 debug 弹出不同的信息
_alert: function _alert(alertInfo, debugInfo) {
var editor = this.editor;
var debug = editor.config.debug;
// var debug = true;
var customAlert = editor.config.customAlert;
if (debug) {
throw new Error('wangEditor: ' + (debugInfo || alertInfo));
} else {
if (customAlert && typeof customAlert === 'function') {
customAlert(alertInfo);
} else {
alert(alertInfo);
}
}
},
//插入视频的方法 需要单独定义
insertLinkVideo:function(link){
var _this3 = this;
if (!link) {
return;
}
var editor = this.editor;
var config = editor.config;
// 校验格式
var linkVideoCheck = config.linkVideoCheck;
var checkResult = void 0;
if (linkVideoCheck && linkVideoCheck === 'function') {
checkResult = linkVideoCheck(link);
if (typeof checkResult === 'string') {
// 校验失败,提示信息
alert(checkResult);
return;
}
}
editor.cmd.do('insertHTML', '');
// 验证视频 url 是否有效,无效的话给出提示
var video = document.createElement('video');
video.onload = function () {
var callback = config.linkVideoCallback;
if (callback && typeof callback === 'function') {
callback(link);
}
video = null;
};
video.onerror = function () {
video = null;
// 无法成功下载图片
_this2._alert('插入视频错误', 'wangEditor: \u63D2\u5165\u56FE\u7247\u51FA\u9519\uFF0C\u56FE\u7247\u94FE\u63A5\u662F "' + link + '"\uFF0C\u4E0B\u8F7D\u8BE5\u94FE\u63A5\u5931\u8D25');
return;
};
video.onabort = function () {
video = null;
};
video.src = link;
},
// 上传视频
uploadVideo: function uploadVideo(files) {
console.log(files)
var _this3 = this;
if (!files || !files.length) {
return;
}
// ------------------------------ 获取配置信息 ------------------------------
var editor = this.editor;
var config = editor.config;
var uploadVideoServer = config.uploadVideoServer;//上传地址
var maxSize = config.uploadVideoMaxSize; //100M
var maxSizeM = maxSize / 1000 / 1000;
var maxLength = 1;
var uploadFileName = config.uploadFileName || '';
var uploadVideoParams = config.uploadVideoParams || {};
var uploadVideoHeaders = {};
var hooks =config.uploadImgHooks || {};
var timeout = 5 * 60 * 1000; //5 min
var withCredentials = config.withCredentials;
if (withCredentials == null) {
withCredentials = false;
}
var customUploadVideo = config.customUploadVideo;
// ------------------------------ 验证文件信息 ------------------------------
var resultFiles = [];
var errInfo = [];
arrForEach(files, function (file) {
var name = file.name;
var size = file.size;
// chrome 低版本 name === undefined
if (!name || !size) {
return;
}
if (/\.(mp4)$/i.test(name) === false) {
// 后缀名不合法,不是视频
errInfo.push('\u3010' + name + '\u3011\u4e0d\u662f\u89c6\u9891');
return;
}
if (maxSize < size) {
// 上传视频过大
errInfo.push('\u3010' + name + '\u3011\u5927\u4E8E ' + maxSizeM + 'M');
return;
}
// 验证通过的加入结果列表
resultFiles.push(file);
});
// 抛出验证信息
if (errInfo.length) {
this._alert('视频验证未通过: \n' + errInfo.join('\n'));
return;
}
if (resultFiles.length > maxLength) {
this._alert('一次最多上传' + maxLength + '个视频');
return;
}
// ------------------------------ 自定义上传 ------------------------------
if (customUploadVideo && typeof customUploadVideo === 'function') {
console.log('上传视频了')
customUploadVideo(resultFiles, this.insertLinkVideo.bind(this));
// 阻止以下代码执行
return;
}
// 添加视频数据
var formdata = new FormData();
arrForEach(resultFiles, function (file) {
var name = uploadFileName || file.name;
formdata.append(name, file);
});
// ------------------------------ 上传视频 ------------------------------
if (uploadVideoServer && typeof uploadVideoServer === 'string') {
// 添加参数
var uploadVideoServer = uploadVideoServer.split('#');
uploadVideoServer = uploadVideoServer[0];
var uploadVideoServerHash = uploadVideoServer[1] || '';
objForEach(uploadVideoParams, function (key, val) {
val = encodeURIComponent(val);
// 第一,将参数拼接到 url 中
if (uploadVideoParamsWithUrl) {
if (uploadVideoServer.indexOf('?') > 0) {
uploadVideoServer += '&';
} else {
uploadVideoServer += '?';
}
uploadVideoServer = uploadVideoServer + key + '=' + val;
}
// 第二,将参数添加到 formdata 中
formdata.append(key, val);
});
if (uploadVideoServerHash) {
uploadVideoServer += '#' + uploadVideoServerHash;
}
// 定义 xhr
var xhr = new XMLHttpRequest();
xhr.open('POST', uploadVideoServer);
// 设置超时
xhr.timeout = timeout;
xhr.ontimeout = function () {
// hook - timeout
if (hooks.timeout && typeof hooks.timeout === 'function') {
hooks.timeout(xhr, editor);
}
_this3._alert('上传视频超时');
};
// 监控 progress
if (xhr.upload) {
xhr.upload.onprogress = function (e) {
var percent = void 0;
// 进度条
var progressBar = new Progress(editor);
if (e.lengthComputable) {
percent = e.loaded / e.total;
progressBar.show(percent);
}
};
}
// 返回数据
xhr.onreadystatechange = function () {
var result = void 0;
if (xhr.readyState === 4) {
if (xhr.status < 200 || xhr.status >= 300) {
// hook - error
if (hooks.error && typeof hooks.error === 'function') {
hooks.error(xhr, editor);
}
// xhr 返回状态错误
_this3._alert('上传视频发生错误', '\u4E0A\u4F20\u56FE\u7247\u53D1\u751F\u9519\u8BEF\uFF0C\u670D\u52A1\u5668\u8FD4\u56DE\u72B6\u6001\u662F ' + xhr.status);
return;
}
result = xhr.responseText;
if ((typeof result === 'undefined' ? 'undefined' : _typeof(result)) !== 'object') {
try {
console.log(result);
result = JSON.parse(result);
} catch (ex) {
// hook - fail
if (hooks.fail && typeof hooks.fail === 'function') {
hooks.fail(xhr, editor, result);
}
_this3._alert('上传视频失败', '上传视频返回结果错误,返回结果是: ' + result);
return;
}
}
if (!hooks.customInsert && result.errno == '0') {
// hook - fail
if (hooks.fail && typeof hooks.fail === 'function') {
hooks.fail(xhr, editor, result);
}
// 数据错误
_this3._alert('上传视频失败', '上传视频返回结果错误,返回结果 errno=' + result.errno);
} else {
if (hooks.customInsert && typeof hooks.customInsert === 'function') {
hooks.customInsert(_this3.insertLinkVideo.bind(_this3), result, editor);
} else {
// 将视频插入编辑器
var data = result || [];
// data.forEach(function (link) {
// console.log(link);
//
// });
_this3.insertLinkVideo(data.url);
}
// hook - success
if (hooks.success && typeof hooks.success === 'function') {
hooks.success(xhr, editor, result);
}
}
}
};
// hook - before
if (hooks.before && typeof hooks.before === 'function') {
var beforeResult = hooks.before(xhr, editor, resultFiles);
if (beforeResult && (typeof beforeResult === 'undefined' ? 'undefined' : _typeof(beforeResult)) === 'object') {
if (beforeResult.prevent) {
// 如果返回的结果是 {prevent: true, msg: 'xxxx'} 则表示用户放弃上传
this._alert(beforeResult.msg);
return;
}
}
}
// 自定义 headers
objForEach(uploadVideoHeaders, function (key, val) {
xhr.setRequestHeader(key, val);
});
// 跨域传 cookie
xhr.withCredentials = withCredentials;
// 发送请求
xhr.send(formdata);
// 注意,要 return 。不去操作接下来的 base64 显示方式
return;
}
}
};
/*
menu - img
*/
// 构造函数
function Image(editor) {
this.editor = editor;
var imgMenuId = getRandom('w-e-img');
this.$elem = $(' ');
editor.imgMenuId = imgMenuId;
this.type = 'panel';
// 当前是否 active 状态
this._active = false;
}
// 原型
Image.prototype = {
constructor: Image,
onClick: function onClick() {
var editor = this.editor;
var config = editor.config;
if (config.qiniu) {
return;
}
if (this._active) {
this._createEditPanel();
} else {
this._createInsertPanel();
}
},
_createEditPanel: function _createEditPanel() {
var editor = this.editor;
// id
var width30 = getRandom('width-30');
var width50 = getRandom('width-50');
var width100 = getRandom('width-100');
var delBtn = getRandom('del-btn');
// tab 配置
var tabsConfig = [{
title: '编辑图片',
tpl: '\n \n \n \n \n \n ',
events: [{
// 触发选择图片
selector: '#' + upTriggerId,
type: 'click',
fn: function fn() {
var $file = $('#' + upFileId);
var fileElem = $file[0];
if (fileElem) {
fileElem.click();
} else {
// 返回 true 可关闭 panel
return true;
}
}
}, {
// 选择图片完毕
selector: '#' + upFileId,
type: 'change',
fn: function fn() {
var $file = $('#' + upFileId);
var fileElem = $file[0];
if (!fileElem) {
// 返回 true 可关闭 panel
return true;
}
// 获取选中的 file 对象列表
var fileList = fileElem.files;
if (fileList.length) {
uploadImg.uploadImg(fileList);
}
// 返回 true 可关闭 panel
return true;
}
}]
}, // first tab end
{
title: '网络图片',
tpl: '\n \n ',
events: [{
selector: '#' + linkBtnId,
type: 'click',
fn: function fn() {
var $linkUrl = $('#' + linkUrlId);
var url = $linkUrl.val().trim();
if (url) {
uploadImg.insertLinkImg(url);
}
// 返回 true 表示函数执行结束之后关闭 panel
return true;
}
}]
} // second tab end
]; // tabs end
// 判断 tabs 的显示
var tabsConfigResult = [];
if ((config.uploadImgShowBase64 || config.uploadImgServer || config.customUploadImg) && window.FileReader) {
// 显示“上传图片”
tabsConfigResult.push(tabsConfig[0]);
}
if (config.showLinkImg) {
// 显示“网络图片”
tabsConfigResult.push(tabsConfig[1]);
}
// 创建 panel 并显示
var panel = new Panel(this, {
width: 300,
tabs: tabsConfigResult
});
panel.show();
// 记录属性
this.panel = panel;
},
// 试图改变 active 状态
tryChangeActive: function tryChangeActive(e) {
var editor = this.editor;
var $elem = this.$elem;
if (editor._selectedImg) {
this._active = true;
$elem.addClass('w-e-active');
} else {
this._active = false;
$elem.removeClass('w-e-active');
}
}
};
/*
所有菜单的汇总
*/
// 存储菜单的构造函数
var MenuConstructors = {};
MenuConstructors.bold = Bold;
MenuConstructors.head = Head;
MenuConstructors.fontSize = FontSize;
MenuConstructors.fontName = FontName;
MenuConstructors.link = Link;
MenuConstructors.italic = Italic;
MenuConstructors.redo = Redo;
MenuConstructors.strikeThrough = StrikeThrough;
MenuConstructors.underline = Underline;
MenuConstructors.undo = Undo;
MenuConstructors.list = List;
MenuConstructors.justify = Justify;
MenuConstructors.foreColor = ForeColor;
MenuConstructors.backColor = BackColor;
MenuConstructors.quote = Quote;
MenuConstructors.code = Code;
MenuConstructors.emoticon = Emoticon;
MenuConstructors.table = Table;
MenuConstructors.video = Video;
MenuConstructors.image = Image;
/*
菜单集合
*/
// 构造函数
function Menus(editor) {
this.editor = editor;
this.menus = {};
}
// 修改原型
Menus.prototype = {
constructor: Menus,
// 初始化菜单
init: function init() {
var _this = this;
var editor = this.editor;
var config = editor.config || {};
var configMenus = config.menus || []; // 获取配置中的菜单
// 根据配置信息,创建菜单
configMenus.forEach(function (menuKey) {
var MenuConstructor = MenuConstructors[menuKey];
if (MenuConstructor && typeof MenuConstructor === 'function') {
// 创建单个菜单
_this.menus[menuKey] = new MenuConstructor(editor);
}
});
// 添加到菜单栏
this._addToToolbar();
// 绑定事件
this._bindEvent();
},
// 添加到菜单栏
_addToToolbar: function _addToToolbar() {
var editor = this.editor;
var $toolbarElem = editor.$toolbarElem;
var menus = this.menus;
var config = editor.config;
// config.zIndex 是配置的编辑区域的 z-index,菜单的 z-index 得在其基础上 +1
var zIndex = config.zIndex + 1;
objForEach(menus, function (key, menu) {
var $elem = menu.$elem;
if ($elem) {
// 设置 z-index
$elem.css('z-index', zIndex);
$toolbarElem.append($elem);
}
});
},
// 绑定菜单 click mouseenter 事件
_bindEvent: function _bindEvent() {
var menus = this.menus;
var editor = this.editor;
objForEach(menus, function (key, menu) {
var type = menu.type;
if (!type) {
return;
}
var $elem = menu.$elem;
var droplist = menu.droplist;
var panel = menu.panel;
// 点击类型,例如 bold
if (type === 'click' && menu.onClick) {
$elem.on('click', function (e) {
if (editor.selection.getRange() == null) {
return;
}
menu.onClick(e);
});
}
// 下拉框,例如 head
if (type === 'droplist' && droplist) {
$elem.on('mouseenter', function (e) {
if (editor.selection.getRange() == null) {
return;
}
// 显示
droplist.showTimeoutId = setTimeout(function () {
droplist.show();
}, 200);
}).on('mouseleave', function (e) {
// 隐藏
droplist.hideTimeoutId = setTimeout(function () {
droplist.hide();
}, 0);
});
}
// 弹框类型,例如 link
if (type === 'panel' && menu.onClick) {
$elem.on('click', function (e) {
e.stopPropagation();
if (editor.selection.getRange() == null) {
return;
}
// 在自定义事件中显示 panel
menu.onClick(e);
});
}
});
},
// 尝试修改菜单状态
changeActive: function changeActive() {
var menus = this.menus;
objForEach(menus, function (key, menu) {
if (menu.tryChangeActive) {
setTimeout(function () {
menu.tryChangeActive();
}, 100);
}
});
}
};
/*
粘贴信息的处理
*/
// 获取粘贴的纯文本
function getPasteText(e) {
var clipboardData = e.clipboardData || e.originalEvent && e.originalEvent.clipboardData;
var pasteText = void 0;
if (clipboardData == null) {
pasteText = window.clipboardData && window.clipboardData.getData('text');
} else {
pasteText = clipboardData.getData('text/plain');
}
return replaceHtmlSymbol(pasteText);
}
// 获取粘贴的html
function getPasteHtml(e, filterStyle, ignoreImg) {
var clipboardData = e.clipboardData || e.originalEvent && e.originalEvent.clipboardData;
var pasteText = void 0,
pasteHtml = void 0;
if (clipboardData == null) {
pasteText = window.clipboardData && window.clipboardData.getData('text');
} else {
pasteText = clipboardData.getData('text/plain');
pasteHtml = clipboardData.getData('text/html');
}
if (!pasteHtml && pasteText) {
pasteHtml = ' \n ' + replaceHtmlSymbol(pasteText) + '
';
}
if (!pasteHtml) {
return;
}
// 过滤word中状态过来的无用字符
var docSplitHtml = pasteHtml.split(' \n ',
events: [{
selector: '#' + width30,
type: 'click',
fn: function fn() {
var $img = editor._selectedImg;
if ($img) {
$img.css('max-width', '30%');
}
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
}, {
selector: '#' + width50,
type: 'click',
fn: function fn() {
var $img = editor._selectedImg;
if ($img) {
$img.css('max-width', '50%');
}
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
}, {
selector: '#' + width100,
type: 'click',
fn: function fn() {
var $img = editor._selectedImg;
if ($img) {
$img.css('max-width', '100%');
}
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
}, {
selector: '#' + delBtn,
type: 'click',
fn: function fn() {
var $img = editor._selectedImg;
if ($img) {
$img.remove();
}
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
}]
}];
// 创建 panel 并显示
var panel = new Panel(this, {
width: 300,
tabs: tabsConfig
});
panel.show();
// 记录属性
this.panel = panel;
},
_createInsertPanel: function _createInsertPanel() {
var editor = this.editor;
var uploadImg = editor.uploadImg;
var config = editor.config;
// id
var upTriggerId = getRandom('up-trigger');
var upFileId = getRandom('up-file');
var linkUrlId = getRandom('link-url');
var linkBtnId = getRandom('link-btn');
// tabs 的配置
var tabsConfig = [{
title: '上传图片',
tpl: ' \n ',
// 事件绑定
events: [{
// 增加行
selector: '#' + addRowBtnId,
type: 'click',
fn: function fn() {
_this2._addRow();
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
}, {
// 增加列
selector: '#' + addColBtnId,
type: 'click',
fn: function fn() {
_this2._addCol();
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
}, {
// 删除行
selector: '#' + delRowBtnId,
type: 'click',
fn: function fn() {
_this2._delRow();
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
}, {
// 删除列
selector: '#' + delColBtnId,
type: 'click',
fn: function fn() {
_this2._delCol();
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
}, {
// 删除表格
selector: '#' + delTableBtnId,
type: 'click',
fn: function fn() {
_this2._delTable();
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
}]
}]
});
// 显示 panel
panel.show();
},
// 获取选中的单元格的位置信息
_getLocationData: function _getLocationData() {
var result = {};
var editor = this.editor;
var $selectionELem = editor.selection.getSelectionContainerElem();
if (!$selectionELem) {
return;
}
var nodeName = $selectionELem.getNodeName();
if (nodeName !== 'TD' && nodeName !== 'TH') {
return;
}
// 获取 td index
var $tr = $selectionELem.parent();
var $tds = $tr.children();
var tdLength = $tds.length;
$tds.forEach(function (td, index) {
if (td === $selectionELem[0]) {
// 记录并跳出循环
result.td = {
index: index,
elem: td,
length: tdLength
};
return false;
}
});
// 获取 tr index
var $tbody = $tr.parent();
var $trs = $tbody.children();
var trLength = $trs.length;
$trs.forEach(function (tr, index) {
if (tr === $tr[0]) {
// 记录并跳出循环
result.tr = {
index: index,
elem: tr,
length: trLength
};
return false;
}
});
// 返回结果
return result;
},
// 增加行
_addRow: function _addRow() {
// 获取当前单元格的位置信息
var locationData = this._getLocationData();
if (!locationData) {
return;
}
var trData = locationData.tr;
var $currentTr = $(trData.elem);
var tdData = locationData.td;
var tdLength = tdData.length;
// 拼接即将插入的字符串
var newTr = document.createElement('tr');
var tpl = '',
i = void 0;
for (i = 0; i < tdLength; i++) {
tpl += ' \n