wangEditor 修改 “視訊”選單 的實現方式,達到上傳視訊的功能---完整版
阿新 • • 發佈:2018-12-19
(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) {
// 如 <div>
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', 'italic', 'underline', 'strikeThrough', 'foreColor', 'backColor', 'link', 'list', 'justify', 'quote', 'emoticon', 'image', 'table', 'video', 'code', 'undo', 'redo'],
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'
}, {
alt: '[允悲]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/2c/moren_yunbei_org.png'
}, {
alt: '[笑而不語]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/3a/moren_xiaoerbuyu_org.png'
}, {
alt: '[費解]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/3c/moren_feijie_org.png'
}, {
alt: '[憧憬]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/37/moren_chongjing_org.png'
}, {
alt: '[並不簡單]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/fc/moren_bbjdnew_org.png'
}, {
alt: '[微笑]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/5c/huanglianwx_org.gif'
}, {
alt: '[酷]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/8a/pcmoren_cool2017_org.png'
}, {
alt: '[嘻嘻]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/0b/tootha_org.gif'
}, {
alt: '[哈哈]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/6a/laugh.gif'
}, {
alt: '[可愛]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/14/tza_org.gif'
}, {
alt: '[可憐]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/af/kl_org.gif'
}, {
alt: '[挖鼻]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/0b/wabi_org.gif'
}, {
alt: '[吃驚]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/f4/cj_org.gif'
}, {
alt: '[害羞]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/6e/shamea_org.gif'
}, {
alt: '[擠眼]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/c3/zy_org.gif'
}, {
alt: '[閉嘴]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/29/bz_org.gif'
}, {
alt: '[鄙視]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/71/bs2_org.gif'
}, {
alt: '[愛你]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/6d/lovea_org.gif'
}, {
alt: '[淚]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/9d/sada_org.gif'
}, {
alt: '[偷笑]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/19/heia_org.gif'
}, {
alt: '[親親]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/8f/qq_org.gif'
}, {
alt: '[生病]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/b6/sb_org.gif'
}, {
alt: '[太開心]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/58/mb_org.gif'
}, {
alt: '[白眼]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/d9/landeln_org.gif'
}, {
alt: '[右哼哼]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/98/yhh_org.gif'
}, {
alt: '[左哼哼]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/6d/zhh_org.gif'
}, {
alt: '[噓]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/a6/x_org.gif'
}, {
alt: '[衰]',
src: 'http://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/af/cry.gif'
}]
}
// , {
// // 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: '[浮雲]'
// }, {
// src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/c9/geili_thumb.gif',
// alt: '[給力]'
// }, {
// src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/f2/wg_thumb.gif',
// alt: '[圍觀]'
// }, {
// src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/70/vw_thumb.gif',
// alt: '[威武]'
// }, {
// src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/6e/panda_thumb.gif',
// alt: '[熊貓]'
// }, {
// src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/81/rabbit_thumb.gif',
// alt: '[兔子]'
// }, {
// src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/bc/otm_thumb.gif',
// alt: '[奧特曼]'
// }, {
// src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/15/j_thumb.gif',
// alt: '[囧]'
// }, {
// src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/89/hufen_thumb.gif',
// alt: '[互粉]'
// }, {
// src: 'http://img.t.sinajs.cn/t35/style/images/common/face/ext/normal/c4/liwu_thumb.gif',
// alt: '[禮物]'
// }]
// }, {
// // tab 的標題
// title: 'emoji',
// // type -> 'emoji' / 'image'
// type: 'emoji',
// // content -> 陣列
// content: '\ud83d\ude05 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?'.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,
// 對貼上的文字進行自定義處理,返回處理後的結果。編輯器會將處理後的結果貼上到編輯區域中。
// 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: 100 * 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: 5*60*1000,
// 上傳圖片 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(/"/gm, '"');
}
// 返回百分比的格式
/*
bold-menu
*/
// 建構函式
function Bold(editor) {
this.editor = editor;
this.$elem = $('<div class="w-e-menu">\n <i class="w-e-icon-bold"><i/>\n </div>');
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 = $('<div class="w-e-droplist"></div>');
// 標題
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 = $('<ul class="' + (type === 'list' ? 'w-e-list' : 'w-e-block') + '"></ul>');
$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 = $('<li class="w-e-item"></li>');
if ($elem) {
$li.append($elem);
$list.append($li);
$elem.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 = $('<div class="w-e-menu"><i class="w-e-icon-header"><i/></div>');
this.type = 'droplist';
// 當前是否 active 狀態
this._active = false;
// 初始化 droplist
this.droplist = new DropList(this, {
width: 100,
$title: $('<p>設定標題</p>'),
type: 'list', // droplist 以列表形式展示
list: [{ $elem: $('<h1>H1</h1>'), value: '<h1>' }, { $elem: $('<h2>H2</h2>'), value: '<h2>' }, { $elem: $('<h3>H3</h3>'), value: '<h3>' }, { $elem: $('<h4>H4</h4>'), value: '<h4>' }, { $elem: $('<h5>H5</h5>'), value: '<h5>' }, { $elem: $('<p>正文</p>'), value: '<p>' }],
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)) {
// 不能選中多行來設定標題,否則會出現問題
// 例如選中的是 <p>xxx</p><p>yyy</p> 來設定標題,設定之後會成為 <h1>xxx<br>yyy</h1> 不符合預期
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');
}
}
};
/*
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 = $('<div class="w-e-panel-container"></div>');
var width = opt.width || 300; // 預設 300px
$container.css('width', width + 'px').css('margin-left', (0 - width) / 2 + 'px');
// 新增關閉按鈕
var $closeBtn = $('<i class="w-e-icon-close w-e-panel-close"></i>');
$container.append($closeBtn);
$closeBtn.on('click', function () {
_this.hide();
});
// 準備 tabs 容器
var $tabTitleContainer = $('<ul class="w-e-panel-tab-title"></ul>');
var $tabContentContainer = $('<div class="w-e-panel-tab-content"></div>');
$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 = $('<li class="w-e-item">' + title + '</li>');
$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 = $('<div class="w-e-menu"><i class="w-e-icon-link"><i/></div>');
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: '<div>\n <input id="' + inputTextId + '" type="text" class="block" value="' + text + '" placeholder="\u94FE\u63A5\u6587\u5B57"/></td>\n <input id="' + inputLinkId + '" type="text" class="block" value="' + link + '" placeholder="http://..."/></td>\n <div class="w-e-button-container">\n <button id="' + btnOkId + '" class="right">\u63D2\u5165</button>\n <button id="' + btnDelId + '" class="gray right" style="display:' + delBtnDisplay + '">\u5220\u9664\u94FE\u63A5</button>\n </div>\n </div>',
// 事件繫結
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', '<span>' + selectionText + '</span>');
},
// 插入連結
_insertLink: function _insertLink(text, link) {
if (!text || !link) {
return;
}
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', '<a href="' + link + '" target="_blank">' + text + '</a>');
} 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 = $('<div class="w-e-menu">\n <i class="w-e-icon-italic"><i/>\n </div>');
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 = $('<div class="w-e-menu">\n <i class="w-e-icon-redo"><i/>\n </div>');
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 = $('<div class="w-e-menu">\n <i class="w-e-icon-strikethrough"><i/>\n </div>');
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 = $('<div class="w-e-menu">\n <i class="w-e-icon-underline"><i/>\n </div>');
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 = $('<div class="w-e-menu">\n <i class="w-e-icon-undo"><i/>\n </div>');
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 = $('<div class="w-e-menu"><i class="w-e-icon-list2"><i/></div>');
this.type = 'droplist';
// 當前是否 active 狀態
this._active = false;
// 初始化 droplist
this.droplist = new DropList(this, {
width: 120,
$title: $('<p>設定列表</p>'),
type: 'list', // droplist 以列表形式展示
list: [{ $elem: $('<span><i class="w-e-icon-list-numbered"></i> 有序列表</span>'), value: 'insertOrderedList' }, { $elem: $('<span><i class="w-e-icon-list2"></i> 無序列表</span>'), 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);
// 驗證列表是否被包裹在 <p> 之內
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)) {
// 證明是頂級標籤,沒有被 <p> 包裹
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 = $('<div class="w-e-menu"><i class="w-e-icon-paragraph-left"><i/></div>');
this.type = 'droplist';
// 當前是否 active 狀態
this._active = false;
// 初始化 droplist
this.droplist = new DropList(this, {
width: 100,
$title: $('<p>對齊方式</p>'),
type: 'list', // droplist 以列表形式展示
list: [{ $elem: $('<span><i class="w-e-icon-paragraph-left"></i> 靠左</span>'), value: 'justifyLeft' }, { $elem: $('<span><i class="w-e-icon-paragraph-center"></i> 居中</span>'), value: 'justifyCenter' }, { $elem: $('<span><i class="w-e-icon-paragraph-right"></i> 靠右</span>'), 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 = $('<div class="w-e-menu"><i class="w-e-icon-pencil2"><i/></div>');
this.type = 'droplist';
// 獲取配置的顏色
var config = editor.config;
var colors = config.colors || [];
// 當前是否 active 狀態
this._active = false;
// 初始化 droplist
this.droplist = new DropList(this, {
width: 120,
$title: $('<p>文字顏色</p>'),
type: 'inline-block', // droplist 內容以 block 形式展示
list: colors.map(function (color) {
return { $elem: $('<i style="color:' + color + ';" class="w-e-icon-pencil2"></i>'), 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 = $('<div class="w-e-menu"><i class="w-e-icon-paint-brush"><i/></div>');
this.type = 'droplist';
// 獲取配置的顏色
var config = editor.config;
var colors = config.colors || [];
// 當前是否 active 狀態
this._active = false;
// 初始化 droplist
this.droplist = new DropList(this, {
width: 120,
$title: $('<p>背景色</p>'),
type: 'inline-block', // droplist 內容以 block 形式展示
list: colors.map(function (color) {
return { $elem: $('<i style="color:' + color + ';" class="w-e-icon-paint-brush"></i>'), 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 = $('<div class="w-e-menu">\n <i class="w-e-icon-quotes-left"><i/>\n </div>');
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', '<P>');
} else {
// 轉換為 quote
editor.cmd.do('formatBlock', '<BLOCKQUOTE>');
}
return;
}
// IE 中不支援 formatBlock <BLOCKQUOTE> ,要用其他方式相容
var content = void 0,
$targetELem = void 0;
if (nodeName === 'P') {
// 將 P 轉換為 quote
content = $selectionElem.text();
$targetELem = $('<blockquote>' + content + '</blockquote>');
$targetELem.insertAfter($selectionElem);
$selectionElem.remove();
return;
}
if (nodeName === 'BLOCKQUOTE') {
// 撤銷 quote
content = $selectionElem.text();
$targetELem = $('<p>' + content + '</p>');
$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 = $('<div class="w-e-menu">\n <i class="w-e-icon-terminal"><i/>\n </div>');
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> 包裹即可
$code = $('<code>' + selectionText + '</code>');
editor.cmd.do('insertElem', $code);
editor.selection.createRangeByElem($code, false);
editor.selection.restoreSelection();
return;
}
// 選取是空,且沒有誇元素選擇,則插入 <pre><code></code></prev>
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: '<div>\n <textarea id="' + textId + '" style="height:145px;;">' + value + '</textarea>\n <div class="w-e-button-container">\n <button id="' + btnId + '" class="right">\u63D2\u5165</button>\n </div>\n <div>',
// 事件繫結
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', '<pre><code>' + value + '</code></pre><p><br></p>');
},
// 更新程式碼
_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 = $('<div class="w-e-menu">\n <i class="w-e-icon-happy"><i/>\n </div>');
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 (i