/**
@Name:layui.layedit 富文本编辑器
@Author:贤心
@License:MIT
@Edit by KnfieZ
*/
layui.define(['layer', 'form'], function (exports) {
"use strict";
var $ = layui.$
, layer = layui.layer
, form = layui.form
, hint = layui.hint()
, device = layui.device()
, MOD_NAME = 'layedit', THIS = 'layui-this', SHOW = 'layui-show', ABLED = 'layui-disabled'
, Edit = function () {
var that = this;
that.index = 0;
//全局配置
that.config = {
//默认工具bar
tool: [
'strong', 'italic', 'underline', 'del'
, '|'
, 'left', 'center', 'right'
, '|'
, 'link', 'unlink', 'face', 'image'
]
, hideTool: []
, height: 280 //默认高
};
};
//全局设置
Edit.prototype.set = function (options) {
var that = this;
$.extend(true, that.config, options);
return that;
};
//事件监听
Edit.prototype.on = function (events, callback) {
return layui.onevent(MOD_NAME, events, callback);
};
//建立编辑器
Edit.prototype.build = function (id, settings) {
settings = settings || {};
var that = this
, config = that.config
, ELEM = 'layui-layedit', textArea = $(typeof (id) == 'string' ? '#' + id : id)
, name = 'LAY_layedit_' + (++that.index)
, haveBuild = textArea.next('.' + ELEM)
, set = $.extend({}, config, settings)
, tool = function () {
var node = [], hideTools = {};
layui.each(set.hideTool, function (_, item) {
hideTools[item] = true;
});
layui.each(set.tool, function (_, item) {
if (tools[item] && !hideTools[item]) {
node.push(tools[item]);
}
});
return node.join('');
}()
, editor = $(['
'
, '
' + tool + '
'
, '
'
, ''
, '
'
, '
'].join(''))
//编辑器不兼容ie8以下
if (device.ie && device.ie < 8) {
return textArea.removeClass('layui-hide').addClass(SHOW);
}
haveBuild[0] && (haveBuild.remove());
setIframe.call(that, editor, textArea[0], set)
textArea.addClass('layui-hide').after(editor);
return that.index;
};
//获得编辑器中内容
Edit.prototype.getContent = function (index) {
var iframeWin = getWin(index);
if (!iframeWin[0]) return;
return toLower(iframeWin[0].document.body.innerHTML);
};
//获得编辑器中纯文本内容
Edit.prototype.getText = function (index) {
var iframeWin = getWin(index);
if (!iframeWin[0]) return;
return $(iframeWin[0].document.body).text();
};
/**
* 设置编辑器内容
* @param {[type]} index 编辑器索引
* @param {[type]} content 要设置的内容
* @param {[type]} flag 是否追加模式
*/
Edit.prototype.setContent = function (index, content, flag) {
var iframeWin = getWin(index);
if (!iframeWin[0]) return;
if (flag) {
$(iframeWin[0].document.body).append(content)
} else {
$(iframeWin[0].document.body).html(content)
};
layedit.sync(index)
};
//将编辑器内容同步到textarea(一般用于异步提交时)
Edit.prototype.sync = function (index) {
var iframeWin = getWin(index);
if (!iframeWin[0]) return;
var textarea = $('#' + iframeWin[1].attr('textarea'));
textarea.val(toLower(iframeWin[0].document.body.innerHTML));
};
//获取编辑器选中内容
Edit.prototype.getSelection = function (index) {
var iframeWin = getWin(index);
if (!iframeWin[0]) return;
var range = Range(iframeWin[0].document);
return document.selection ? range.text : range.toString();
};
//iframe初始化
var setIframe = function (editor, textArea, set) {
var that = this, iframe = editor.find('iframe');
iframe.css({
height: set.height
}).on('load', function () {
var conts = iframe.contents()
, iframeWin = iframe.prop('contentWindow')
, head = conts.find('head')
, style = $([''].join(''))
, body = conts.find('body');
head.append(style);
body.attr('contenteditable', 'true').css({
'min-height': set.height
}).html(textArea.value || '');
hotkey.apply(that, [iframeWin, iframe, textArea, set]); //快捷键处理
toolActive.call(that, iframeWin, editor, set); //触发工具
});
}
//获得iframe窗口对象
, getWin = function (index) {
var iframe = $('#LAY_layedit_' + index)
, iframeWin = iframe.prop('contentWindow');
return [iframeWin, iframe];
}
//IE8下将标签处理成小写
, toLower = function (html) {
if (device.ie == 8) {
html = html.replace(/<.+>/g, function (str) {
return str.toLowerCase();
});
}
return html;
}
//快捷键处理
, hotkey = function (iframeWin, iframe, textArea, set) {
var iframeDOM = iframeWin.document, body = $(iframeDOM.body);
body.on('keydown', function (e) {
var keycode = e.keyCode;
//处理回车
if (keycode === 13) {
var range = Range(iframeDOM);
var container = getContainer(range)
, parentNode = container.parentNode;
if (parentNode.tagName.toLowerCase() === 'pre') {
if (e.shiftKey) return
layer.msg('请暂时用shift+enter');
return false;
}
iframeDOM.execCommand('formatBlock', false, '');
}
});
//给textarea同步内容
$(textArea).parents('form').on('submit', function () {
var html = body.html();
//IE8下将标签处理成小写
if (device.ie == 8) {
html = html.replace(/<.+>/g, function (str) {
return str.toLowerCase();
});
}
textArea.value = html;
});
//处理粘贴
body.on('paste', function (e) {
iframeDOM.execCommand('formatBlock', false, '
');
setTimeout(function () {
filter.call(iframeWin, body);
textArea.value = body.html();
}, 100);
});
}
//标签过滤
, filter = function (body) {
var iframeWin = this
, iframeDOM = iframeWin.document;
//清除影响版面的css属性
body.find('*[style]').each(function () {
var textAlign = this.style.textAlign;
this.removeAttribute('style');
$(this).css({
'text-align': textAlign || ''
})
});
//修饰表格
body.find('table').addClass('layui-table');
//移除不安全的标签
body.find('script,link').remove();
}
//Range对象兼容性处理
, Range = function (iframeDOM) {
return iframeDOM.selection
? iframeDOM.selection.createRange()
: iframeDOM.getSelection().getRangeAt(0);
}
//当前Range对象的endContainer兼容性处理
, getContainer = function (range) {
return range.endContainer || range.parentElement().childNodes[0]
}
//在选区插入内联元素
, insertInline = function (tagName, attr, range) {
var iframeDOM = this.document
, elem = document.createElement(tagName)
for (var key in attr) {
elem.setAttribute(key, attr[key]);
}
elem.removeAttribute('text');
if (iframeDOM.selection) { //IE
var text = range.text || attr.text;
if (tagName === 'a' && !text) return;
if (text) {
elem.innerHTML = text;
}
range.pasteHTML($(elem).prop('outerHTML'));
range.select();
} else { //非IE
var text = range.toString() || attr.text;
if (tagName === 'a' && !text) return;
if (text) {
elem.innerHTML = text;
}
range.deleteContents();
range.insertNode(elem);
}
}
//工具选中
, toolCheck = function (tools, othis) {
var iframeDOM = this.document
, CHECK = 'layedit-tool-active'
, container = getContainer(Range(iframeDOM))
, item = function (type) {
return tools.find('.layedit-tool-' + type)
}
if (othis) {
othis[othis.hasClass(CHECK) ? 'removeClass' : 'addClass'](CHECK);
}
tools.find('>i').removeClass(CHECK);
item('unlink').addClass(ABLED);
$(container).parents().each(function () {
var tagName = this.tagName.toLowerCase()
, textAlign = this.style.textAlign;
//文字
if (tagName === 'b' || tagName === 'strong') {
item('b').addClass(CHECK)
}
if (tagName === 'i' || tagName === 'em') {
item('i').addClass(CHECK)
}
if (tagName === 'u') {
item('u').addClass(CHECK)
}
if (tagName === 'strike') {
item('d').addClass(CHECK)
}
//对齐
if (tagName === 'p') {
if (textAlign === 'center') {
item('center').addClass(CHECK);
} else if (textAlign === 'right') {
item('right').addClass(CHECK);
} else {
item('left').addClass(CHECK);
}
}
//超链接
if (tagName === 'a') {
item('link').addClass(CHECK);
item('unlink').removeClass(ABLED);
}
});
}
//触发工具
, toolActive = function (iframeWin, editor, set) {
var iframeDOM = iframeWin.document
, body = $(iframeDOM.body)
, toolEvent = {
//超链接
link: function (range) {
debugger;
var container = getContainer(range)
, parentNode = $(container).parent();
link.call(body, {
href: parentNode.attr('href')
, target: parentNode.attr('target')
}, function (field) {
var parent = parentNode[0];
if (parent.tagName === 'A') {
parent.href = field.url;
} else {
insertInline.call(iframeWin, 'a', {
target: field.target
, href: field.url
, text: field.url
}, range);
}
});
}
//清除超链接
, unlink: function (range) {
iframeDOM.execCommand('unlink');
}
//表情
, face: function (range) {
face.call(this, function (img) {
insertInline.call(iframeWin, 'img', {
src: img.src
, alt: img.alt
}, range);
});
}
//图片1
, image: function (range) {
var that = this;
layui.use('upload', function (upload) {
var uploadImage = set.uploadImage || {};
upload.render({
url: uploadImage.url
, method: uploadImage.type
, elem: $(that).find('input')[0]
, done: function (res) {
if (res.code == 0) {
res.data = res.data[0] || {};
insertInline.call(iframeWin, 'img', {
//src: res.data.src
src:window.hywa.config.href+window.hywa.config.port['show_img']+encodeURIComponent(res.data.src)
, alt: res.data.title
}, range);
} else {
layer.msg(res.msg || '上传失败');
}
}
});
});
}
//图片2
, image_alt: function (range) {
debugger;
var that = this;
layer.open({
type: 1
, id: 'fly-jie-image-upload'
, title: '插入图片'
, shade: false
, area: '465px'
, skin: 'layui-layer-border'
, content: ['
'].join('')
, success: function (layero, index) {
var upload = layui.upload;
var loding, altStr = layero.find('input[name="altStr"]'), Imgsrc = layero.find('input[name="Imgsrc"]');
var uploadImage = set.uploadImage || {};
//执行实例
upload.render({
elem: '#LayEdit_InsertImage'
, url: uploadImage.url
, method: uploadImage.type
, before: function (obj) { loding = layer.msg('文件上传中,请稍等哦', { icon: 16, shade: 0.3, time: 0 }); }
, done: function (res, input, upload) {
layer.close(loding);
if (res.code == 0) {
res.data = res.data[0] || {};
Imgsrc.val(window.hywa.config.href+window.hywa.config.port['show_img']+encodeURIComponent(res.data.src));
altStr.val(res.data.title);
} else {
layer.msg(res.msg, { icon: 5 });
}
}
});
$(".ImgSubmit").click(function () {
insertInline.call(iframeWin, 'img', {
src: Imgsrc.val()
, alt: altStr.val()
}, range);
layer.close(index);
})
}
});
}
//插入视频
, video: function (range) {
var that = this;
layer.open({
type: 1
, id: 'fly-jie-video-upload'
, title: '插入视频'
, shade: false
, area: '465px'
, skin: 'layui-layer-border'
, content: [''].join('')
, success: function (layero, index) {
var loding, video = layero.find('input[name="video"]'), cover = layero.find('input[name="cover"]');
var upload = layui.upload;
var uploadFile = set.uploadFile || {};
//执行实例
var uploadInst = upload.render({
elem: '#fly-jie-video-upload .layui-upload-file'
, url: uploadFile.url
, method: uploadFile.type
, before: function (input) { loding = layer.msg('文件上传中,请稍等哦', { icon: 16, shade: 0.3, time: 0 }); }
, done: function (res, input) {
layer.close(loding);
//if (res.code == 0) {
// res.data = res.data || {};
// insertInline.call(iframeWin, 'video', {
// src: res.data.src
// , alt: res.data.title
// }, range);
//} else {
// layer.msg(res.msg || '上传失败');
//}
if (res.status == 0) {
if ($(input).attr('lay-type') == 'image') {
cover.val(res.data);
} else {
video.val(res.data);
}
} else {
layer.msg(res.msg, { icon: 5 });
}
}
, error: function () {
//请求异常回调
}
});
}
});
}
//插入代码
, code: function (range) {
code.call(body, function (pre) {
insertInline.call(iframeWin, 'pre', {
text: pre.code
, 'lay-lang': pre.lang
}, range);
});
}
//帮助
, help: function () {
layer.open({
type: 2
, title: '帮助'
, area: ['600px', '380px']
, shadeClose: true
, shade: 0.1
, skin: 'layui-layer-msg'
, content: ['http://www.layui.com/about/layedit/help.html', 'no']
});
}
}
, tools = editor.find('.layui-layedit-tool')
, click = function () {
var othis = $(this)
, events = othis.attr('layedit-event')
, command = othis.attr('lay-command');
if (othis.hasClass(ABLED)) return;
body.focus();
var range = Range(iframeDOM)
, container = range.commonAncestorContainer
if (command) {
iframeDOM.execCommand(command);
if (/justifyLeft|justifyCenter|justifyRight/.test(command)) {
iframeDOM.execCommand('formatBlock', false, '');
}
setTimeout(function () {
body.focus();
}, 10);
} else {
toolEvent[events] && toolEvent[events].call(this, range);
}
toolCheck.call(iframeWin, tools, othis);
}
, isClick = /image/
tools.find('>i').on('mousedown', function () {
var othis = $(this)
, events = othis.attr('layedit-event');
if (isClick.test(events)) return;
click.call(this)
}).on('click', function () {
var othis = $(this)
, events = othis.attr('layedit-event');
if (!isClick.test(events)) return;
click.call(this)
});
//触发内容区域
body.on('click', function () {
toolCheck.call(iframeWin, tools);
layer.close(face.index);
});
}
//超链接面板
, link = function (options, callback) {
var body = this, index = layer.open({
type: 1
, id: 'LAY_layedit_link'
, area: '350px'
, shade: 0.05
, shadeClose: true
, moveType: 1
, title: '超链接'
, skin: 'layui-layer-msg'
, content: ['
'].join('')
, success: function (layero, index) {
var eventFilter = 'submit(layedit-link-yes)';
form.render('radio');
layero.find('.layui-btn-primary').on('click', function () {
layer.close(index);
body.focus();
});
form.on(eventFilter, function (data) {
layer.close(link.index);
callback && callback(data.field);
});
}
});
link.index = index;
}
//表情面板
, face = function (callback) {
//表情库
var faces = function () {
var alt = ["[微笑]", "[嘻嘻]", "[哈哈]", "[可爱]", "[可怜]", "[挖鼻]", "[吃惊]", "[害羞]", "[挤眼]", "[闭嘴]", "[鄙视]", "[爱你]", "[泪]", "[偷笑]", "[亲亲]", "[生病]", "[太开心]", "[白眼]", "[右哼哼]", "[左哼哼]", "[嘘]", "[衰]", "[委屈]", "[吐]", "[哈欠]", "[抱抱]", "[怒]", "[疑问]", "[馋嘴]", "[拜拜]", "[思考]", "[汗]", "[困]", "[睡]", "[钱]", "[失望]", "[酷]", "[色]", "[哼]", "[鼓掌]", "[晕]", "[悲伤]", "[抓狂]", "[黑线]", "[阴险]", "[怒骂]", "[互粉]", "[心]", "[伤心]", "[猪头]", "[熊猫]", "[兔子]", "[ok]", "[耶]", "[good]", "[NO]", "[赞]", "[来]", "[弱]", "[草泥马]", "[神马]", "[囧]", "[浮云]", "[给力]", "[围观]", "[威武]", "[奥特曼]", "[礼物]", "[钟]", "[话筒]", "[蜡烛]", "[蛋糕]"], arr = {};
layui.each(alt, function (index, item) {
arr[item] = layui.cache.dir + 'images/face/' + index + '.gif';
});
return arr;
}();
face.hide = face.hide || function (e) {
if ($(e.target).attr('layedit-event') !== 'face') {
layer.close(face.index);
}
}
return face.index = layer.tips(function () {
var content = [];
layui.each(faces, function (key, item) {
content.push('
');
});
return '';
}(), this, {
tips: 1
, time: 0
, skin: 'layui-box layui-util-face'
, maxWidth: 500
, success: function (layero, index) {
layero.css({
marginTop: -4
, marginLeft: -10
}).find('.layui-clear>li').on('click', function () {
callback && callback({
src: faces[this.title]
, alt: this.title
});
layer.close(index);
});
$(document).off('click', face.hide).on('click', face.hide);
}
});
}
//插入代码面板
, code = function (callback) {
var body = this, index = layer.open({
type: 1
, id: 'LAY_layedit_code'
, area: '550px'
, shade: 0.05
, shadeClose: true
, moveType: 1
, title: '插入代码'
, skin: 'layui-layer-msg'
, content: [''].join('')
, success: function (layero, index) {
var eventFilter = 'submit(layedit-code-yes)';
form.render('select');
layero.find('.layui-btn-primary').on('click', function () {
layer.close(index);
body.focus();
});
form.on(eventFilter, function (data) {
layer.close(code.index);
callback && callback(data.field);
});
}
});
code.index = index;
}
//全部工具
, tools = {
html: ''
, strong: ''
, italic: ''
, underline: ''
, del: ''
, '|': ''
, left: ''
, center: ''
, right: ''
, link: ''
, unlink: ''
, face: ''
, image: ''
, image_alt: ''
, code: ''
, video: ''
, help: ''
}
, edit = new Edit();
exports(MOD_NAME, edit);
});
function stringToEntity(str, radix) {
let arr = str.split('')
radix = radix || 0
let tmp = arr.map(item =>
`${(radix ? 'x' + item.charCodeAt(0).toString(16) : item.charCodeAt(0))};`).join('')
console.log(`'${str}' 转实体为 '${tmp}'`)
return tmp
}
function entityToString(entity) {
let entities = entity.split(';')
entities.pop()
let tmp = entities.map(item => String.fromCharCode(
item[2] === 'x' ? parseInt(item.slice(3), 16) : parseInt(item.slice(2)))).join('')
console.log(`'${entity}' 转字符串为 '${tmp}'`)
return tmp
}