'use strict'; /** +------------------------------------------------------------------------------------+ + iceEditor(富文本编辑器) +------------------------------------------------------------------------------------+ + iceEditor v1.1.9 * MIT License By iceui.cn + 作者:ice + 官方:iceui.cn + 时间:2021-06-23 +------------------------------------------------------------------------------------+ + 版权声明:该版权完全归iceUI官方所有,可转载使用和学习,但请务必保留版权信息 +------------------------------------------------------------------------------------+ + iceEditor是一款简约风格的富文本编辑器,体型十分娇小,无任何依赖,整个编辑器只有一个 + 文件,功能却很不平凡!简约的唯美设计,简洁、极速、使用它的时候不需要引用jQuery、font + css……等文件,因为整个编辑器只是一个Js,支持上传图片、附件!支持添加音乐、视频! +------------------------------------------------------------------------------------+ */ var ice = ice || {}; ice.editor = function (id, callback) { class iceEditor { constructor(id) { //------------------------参数配置 开始------------------------ // 工具栏菜单 this.menu = [ 'backColor', 'fontSize', 'foreColor', 'bold', 'italic', 'underline', 'strikeThrough', 'line', 'justifyLeft', 'justifyCenter', 'justifyRight', 'indent', 'outdent', 'line', 'insertOrderedList', 'insertUnorderedList', 'line', 'superscript', 'subscript', 'createLink', 'unlink', 'line', 'hr', 'face', 'table', 'files', 'music', 'video', 'insertImage', 'removeFormat', 'paste', 'line', 'code' ]; // 不需要的工具栏菜单 this.notMenu = []; // 文字背景颜色 this.backColor = [ '#ffffff', '#000000', '#eeece1', '#1f497d', '#4f81bd', '#c0504d', '#9bbb59', '#8064a2', '#4bacc6', '#f79646', '#f2f2f2', '#979797', '#ddd9c3', '#c6d9f0', '#dbe5f1', '#f2dcdb', '#ebf1dd', '#e5e0ec', '#dbeef3', '#fdeada', '#d8d8d8', '#595959', '#c4bd97', '#8db3e2', '#b8cce4', '#e5b9b7', '#d7e3bc', '#ccc1d9', '#b7dde8', '#fbd5b5', '#bfbfbf', '#3f3f3f', '#938953', '#548dd4', '#95b3d7', '#d99694', '#c3d69b', '#b2a2c7', '#92cddc', '#fac08f', '#a5a5a5', '#262626', '#494429', '#17365d', '#366092', '#953734', '#76923c', '#5f497a', '#31859b', '#e36c09', '#7f7f7f', '#0c0c0c', '#1d1b10', '#0f243e', '#244061', '#632423', '#4f6128', '#3f3151', '#205867', '#974806', '#c00000', '#ff0000', '#ffc000', '#ffff00', '#92d050', '#00b050', '#00b0f0', '#0070c0', '#002060', '#7030a0' ]; //文字颜色 this.foreColor = this.backColor; //编辑器的尺寸 this.width = '100%'; this.height = '400px'; //查看源码 this.code = 0; //窗口最大化和最小化 this.maxWindow = 1; //编辑器禁用 this.disabled = 0; //编辑器局部样式 this.css = ''; //编辑器全局样式 this.globalCss = false; //编辑器全局图标 this.globalIcon = false; //图片和附件提交地址 this.uploadUrl = 0; //纯文本粘贴 this.pasteText = 1; //截图粘贴启用 this.screenshot = 1; //截图粘贴直接上传到服务器 this.screenshotUpload = 1; //网络图片上传到服务器 this.imgAutoUpload = 1; //图片下载到本地的域名,默认为本地域名(false),其它域名为数组类型 this.imgDomain = 0; //上传监听 this.ajax.uploadTimeout = 15000; //ajax超时时间 this.ajax.xhr = function () { }; //ajax的xhr设置 this.ajax.formData = function (e) { return e }; //ajax的formData设置 this.ajax.timeout = function () { }; //ajax超时回调 this.ajax.progress = function () { }; //ajax进度回调 this.ajax.success = function (e) { return e }; //ajax成功回调 this.ajax.error = function () { }; //ajax失败回调 this.ajax.complete = function () { }; //ajax成功或失败都回调 //上传附件 this.filesUpload = {}; this.filesUpload.name = 'file[]'; this.filesUpload.formData = function (e) { return e }; this.filesUpload.success = function (e) { return e }; this.filesUpload.error = function () { }; this.filesUpload.complete = function () { }; //上传图片 this.imgUpload = {}; this.imgUpload.name = 'file[]'; this.imgUpload.formData = function (e) { return e }; this.imgUpload.success = function (e) { return e }; this.imgUpload.error = function () { }; this.imgUpload.complete = function () { }; //表情 this.face = [{ title: '文字', type: 'text', list: [{ title: '开心', content: '(^_^)' }, { title: '受不了', content: '(>_<)' }, { title: '鄙视', content: '(¬、¬)' }, { title: '难过', content: '(*>﹏<*)' }, { title: '可爱', content: '(。◕‿◕。)' }, { title: '无奈', content: '╮(╯_╰)╭' }, { title: '惊喜', content: '╰(*°▽°*)╯' }, { title: '听音乐', content: '♪(^∇^*)' }, { title: '害羞', content: '(✿◡‿◡)' }, { title: '睡啦', content: '(∪。∪)..zzZ' }, { title: '臭美', content: '(o≖◡≖)' }, { title: '流汗', content: '(ーー゛)' } ] }]; //HTML标签过滤黑名单-忽略粘贴过来的HTML标签 this.filterTag = ['meta', 'script', 'object', 'form', 'iframe']; //style过滤黑名单-忽略粘贴过来的style样式 this.filterStyle = ['background-image']; //块级元素 this.blockTag = ['address', 'caption', 'dd', 'div', 'dl', 'dt', 'fieldset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'legend', 'fieldset', 'li', 'noframes', 'noscript', 'ol', 'ul', 'p', 'pre', 'table', 'tbody', 'tfoot', 'th', 'thead', 'tr', 'video']; //------------------------参数配置 结束------------------------ //构建功能模块唯一id this.getTime = '1' + String(new Date().getTime()).substr(4, 8); this.iframeId = '_iframe' + this.getTime; this.toolId = '_tool' + this.getTime; this.linkId = '_link' + this.getTime; this.linkInputId = '_LinkInput' + this.getTime; this.musicId = '_music' + this.getTime; this.musicInputId = '_musicInput' + this.getTime; this.videoId = '_video' + this.getTime; this.imageId = '_image' + this.getTime; this.imgUploadId = '_imgUpload' + this.getTime; this.filesId = '_files' + this.getTime; this.filesUploadId = '_filesUpload' + this.getTime; this.tableId = '_table' + this.getTime; this.dragId = '_drag' + this.getTime; //菜单列表对象 this.menuList = {}; //获取编辑器对象 var _z = this; this.editor = this.id(id); if (!this.editor) return alert('请提供一个有效的id'); this.textarea = 0; // 只能是 textarea 和 div ,其他类型的元素不行 if (this.editor.nodeName !== 'TEXTAREA' && this.editor.nodeName !== 'DIV') { return console.log('iceEditor:暂不支持该标签「' + this.editor.nodeName + '」,推荐使用div或textarea'); } if (this.editor.nodeName == 'TEXTAREA') { this.editor.style.display = 'none'; this.divId = '_div' + this.getTime; var div = this.c('div'); div.className = 'iceEditor'; div.id = this.divId; this.insertAfter(div, this.editor); //加载编辑器的内容 this.textarea = this.editor; this.editor = this.id(this.divId); this.value = this.textarea.value; } else { this.editor.className = 'iceEditor'; this.value = this.editor.innerHTML; this.editor.innerHTML = ''; } //创建编辑器配置样式 this.cssConfig = this.c('style'); this.cssConfig.type = 'text/css'; this.editor.appendChild(this.cssConfig); //创建编辑器菜单栏 this.tool = this.c('div'); this.tool.id = this.toolId; this.tool.className = 'iceEditor-tool iceEditor-noselect'; this.editor.appendChild(this.tool); //创建iframe this.iframe = this.c('iframe'); this.iframe.id = this.iframeId; this.iframe.className = 'iceEditor-noselect'; this.iframe.frameBorder = 0; this.editor.appendChild(this.iframe); //创建可拖拽层 this.dragBg = this.c('div'); this.dragBg.className = 'iceEditor-dragBg'; this.editor.appendChild(this.dragBg); //创建编辑器的高度可拖拽容器 this.drag = this.c('div'); this.drag.id = this.dragId; this.drag.className = 'iceEditor-drag iceEditor-noselect'; this.drag.innerHTML = ''; this.editor.appendChild(this.drag); //编辑器拖拽增高 this.drag.onmousedown = function (e) { _z.dragBg.style.display = 'block'; var y = e.clientY; var ch = _z.iframe.clientHeight; window.onmousemove = function (e) { var h = e.clientY - y; if (ch >= 100) { _z.iframe.height = ch + h + 'px'; _z.height = ch + h + 'px'; } else { _z.iframe.height = '100px'; _z.height = ch + h + 'px'; } } window.onmouseup = function () { window.onmousemove = null; window.onmouseup = null; _z.dragBg.style.display = 'none'; } } //创建禁用编辑器的遮罩 this.disableds = this.c('div'); this.disableds.className = 'iceEditor-disabled'; this.editor.appendChild(this.disableds); //获取iframe对象 this.w = this.iframe.contentWindow; //获取iframe Window 对象 this.d = this.iframe.contentDocument; //获取iframe documen 对象 //为了兼容万恶的IE 创建iframe中的body this.d.open(); var value = this.value.trim(); if (!value.length || value.substr(0, 3) != '

') value = '

' + this.value + '

'; this.d.write('' + value + ''); this.d.close(); // 设置元素为可编辑 this.d.body.designMode = 'on'; //打开设计模式 this.d.body.contentEditable = true; // 设置元素为可编辑 this.d.body.addEventListener('click', function () { _z.parentTagName = _z.range.anchorNode.parentNode.tagName; for (var i = 0; i < _z.menu.length; i++) { if (_z.menu[i] == 'line') continue; var a = _z.menuList[_z.menu[i]]; if (_z.d.queryCommandState(_z.menu[i])) { a.className = 'iceEditor-actives'; } else { if (a.className != 'iceEditor-line' && a.className != 'iceEditor-active-s') a.className = ''; } } }) //内容区 this.content = this.d.body; //改变textarea内容 if (this.textarea) { setInterval(function () { _z.setTextarea(); }, 1000); } this.init(); //初始化参数 this.create(); //创建编辑器 this.paste(); //监听粘贴 callback && callback.call(this, this); } id(a) { return document.getElementById(a) } c(a) { return document.createElement(a) } //初始化参数 init() { this.files = null; this.insertImage = null; this.element = this.d.body; //this.element.focus(); //默认获取焦点 this.range = this.d.createRange ? this.w.getSelection() : this.d.selection.createRange(); } //设置textarea setTextarea(n, obj) { if (!this.textarea) return; var html = this.code ? this.html(this.getHTML()) : this.getHTML(); html = html.replace(/(.*?)<\/pre>/gi, function (all, a = '', b = '') { return '' + b.split('
').join("\n") + ''; }); this.textarea.value = html; } //dom后面插入节点 insertAfter(n, obj) { var parent = obj.parentNode; if (parent.lastChild == obj) { parent.appendChild(n, obj); } else { parent.insertBefore(n, obj.nextSibling); } } //插入HTML setHTML(html, a) { this.element.focus(); var range = this.range.getRangeAt(0); //将选中的文档放在html中的DOM内 if (!a) html.appendChild(range.extractContents()); //删除选中的内容 range.deleteContents(); //创建文档碎片并放入新节点 range.insertNode(this.w.document.createDocumentFragment().appendChild(html)); //合并范围至末尾 //合并范围至末尾 range.collapse(false); } //插入文字内容 setText(text, a) { this.element.focus(); var range = this.range.getRangeAt(0); range.deleteContents(); var el = document.createElement('div'); if (a) { //是否为html el.innerHTML = text; } else { el.appendChild(document.createTextNode(text)); } var frag = document.createDocumentFragment(), node, lastNode; while ((node = el.firstChild)) { lastNode = frag.appendChild(node); } range.insertNode(frag); if (lastNode) { range = range.cloneRange(); range.setStartAfter(lastNode); range.collapse(true); this.range.removeAllRanges(); this.range.addRange(range); } range.collapse(true); } //获取选中的HTML getSelectHTML() { var p = this.c('p'); p.appendChild(this.range.getRangeAt(0).cloneContents()); return p.innerHTML; } //获取选中的内容 getSelectText() { if (this.range.toString() == 'false' || this.range.toString() == '') { return ''; } else { return this.range.toString(); } } unhtml(str) { var s = ''; if (str.length == 0) return ''; s = str.replace(/&/g, "&"); s = s.replace(//g, ">"); s = s.replace(/\'/g, "'"); s = s.replace(/\"/g, '"'); return s; } html(str) { var s = ''; if (str.length == 0) return ''; s = str.replace(/</g, "<"); s = s.replace(/>/g, ">"); s = s.replace(/'/g, "\'"); s = s.replace(/"/g, "\""); s = s.replace(/&/g, "&"); return s; } //转义:HTML转成字符串 toText(html) { var temp = this.c('div'); (temp.textContent != null) ? (temp.textContent = html) : (temp.innerText = html); var output = temp.innerHTML; temp = null; return output; } //转义:字符串转成HTML toHTML(text) { var temp = this.c('div'); temp.innerHTML = text; var output = temp.innerText || temp.textContent; temp = null; return output; } //判断祖先节点是否存在 inNodeParent(el, parent) { if (!el) return false; if (el.parentNode) { if (typeof parent == 'string') { parent = parent.toUpperCase(); if (el.tagName == parent) return true; return el.parentNode.tagName == parent ? true : this.inNodeParent(el.parentNode, parent); } else { return el.parentNode == parent ? true : this.inNodeParent(el.parentNode, parent); } } return false; } //数组查询 inArray(needle, array) { if (typeof needle == 'string' || typeof needle == 'number') { for (var i in array) if (needle === array[i]) return true; return false; } } // 获取 range 对象 getRangegetRange() { return this.range.getRangeAt(0); } //弹窗 popup(options) { options = options || {}; var width = options.width || '400'; //默认宽度 var height = options.height || '200'; //默认高度 var title = options.title || ''; //默认不显示标题 var content = options.content || ''; //默认内容 return '
' + title + '
' + content + '
'; } //获取对象距离窗口页面的顶部和左部的距离 getCoords(el) { var box = el.getBoundingClientRect(), doc = el.ownerDocument, body = doc.body, html = doc.documentElement, clientTop = html.clientTop || body.clientTop || 0, clientLeft = html.clientLeft || body.clientLeft || 0, top = box.top - clientTop, left = box.left - clientLeft; return { 'top': top, 'left': left }; } //阻止冒泡 pd(event) { window.event ? window.event.cancelBubble = true : e.stopPropagation(); } //是否为ie isIE() { return !!window.ActiveXObject || "ActiveXObject" in window } //异步请求 ajax(json) { var _z = this; json = json || {}; if (!json.url) return; json.timeout = json.timeout || _z.ajax.uploadTimeout; json.data = json.data || {}; var json2url = function (json) { var arr = []; for (var name in json) { arr.push(name + '=' + encodeURIComponent(json[name])); } return arr.join('&'); } //创建 var xhr = new XMLHttpRequest(); //xhr.withCredentials = false; //连接 和 发送 - 第二步 //监听进度事件 xhr.addEventListener('progress', progress, false); xhr.open('POST', json.url, true); //设置表单提交时的内容类型 xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); if (json.data instanceof FormData == false) { xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); } else { json.data = _z.ajax.formData(json.data); } _z.ajax.xhr(xhr); xhr.send(json.data instanceof FormData ? json.data : json2url(json.data)); //接收 - 第三步 json.loading && json.loading(); json.timer = setTimeout(function () { xhr.onreadystatechange = null; _z.ajax.timeout(xhr); json.error && json.error('网络超时。'); }, json.timeout); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { clearTimeout(json.timer); if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) { var res = ''; if (xhr.responseText.length > 0) res = JSON.parse(xhr.responseText); let newRes = _z.ajax.success(res, xhr); res = newRes ? newRes : res; _z.ajax.complete(res, xhr); json.success && json.success(res); } else { _z.ajax.error(xhr); _z.ajax.complete(xhr); json.error && json.error(xhr); } } else { _z.ajax.error(xhr); _z.ajax.complete(xhr); } }; //上传进度 function progress(evt) { var percent = 0; //百分比 percent = evt.lengthComputable ? Math.round(evt.loaded / evt.total * 100) : 0; _z.ajax.progress(percent, evt, xhr); } } //创建菜单 createMenu(json) { var _z = this; var li = this.c('li'); if (json.id) li.id = json.id; if (json.css) li.className = json.css; if (json.style) this.css += json.style; //将菜单设置成文字或者图标 if (json.menu || json.icon) { var div = this.c('div'); if (json.title) div.title = json.title; div.className = 'iceEditor-exec'; if (json.menu) { div.innerHTML = json.menu; } else { if (json.icon) div.innerHTML = ''; } if (json.data) div.setAttribute('data', json.data); li.appendChild(div); } //使用下拉菜单 if (json.dropdown) { var div = this.c('div'); div.className = 'iceEditor-menuDropdown'; div.innerHTML = json.dropdown; li.appendChild(div); li.openMenu = 1; li.onmouseover = function () { if (li.openMenu) div.className = 'iceEditor-menuDropdown iceEditor-menuActive'; } li.onmouseout = function () { div.className = 'iceEditor-menuDropdown'; } var exec = div.getElementsByClassName('iceEditor-exec'); for (var i = 0; i < exec.length; i++) { exec[i].addEventListener('click', function () { div.className = 'iceEditor-menuDropdown'; li.openMenu = 0; setTimeout(function () { li.openMenu = 1 }, 500); }) } } //使用弹窗 if (json.popup) { li.innerHTML += this.popup(json.popup); li.popup = li.getElementsByClassName('iceEditor-popup')[0]; li.onclick = function () { li.popup.style.display = 'block'; li.popup.getElementsByClassName('iceEditor-popupClose')[0].onclick = function () { li.popup.style.display = 'none'; _z.pd(); } } li.close = function () { li.popup.style.display = 'none'; _z.pd(); } } li.success = json.success ? json.success : false; //菜单的点击事件 if (json.click) li.onclick = function () { json.click(this, _z) }; this.menuList[json.name] = li; } //插件开发 plugin(json) { if (json.name == undefined) return console.log('plugin:menu参数不能为空'); if (this.inArray(json.name, this.menu)) return console.log('plugin:menu已经存在,请重新命名'); this.menu.push(json.name); this.createMenu(json); } //工具栏菜单HTML menuHTML() { //文字大小 this.createMenu({ title: '文字大小', name: 'fontSize', icon: 'fontSize', dropdown: '' }); //文字背景颜色 var html = ''; this.createMenu({ title: '文字背景颜色', name: 'backColor', icon: 'backColor', dropdown: html }); //文字颜色 var html = ''; this.createMenu({ title: '文字颜色', name: 'foreColor', icon: 'foreColor', dropdown: html }); //加粗 this.createMenu({ title: '加粗', name: 'bold', data: 'bold', icon: 'bold' }); //倾斜 this.createMenu({ title: '倾斜', name: 'italic', data: 'italic', icon: 'italic' }); //下划线 this.createMenu({ title: '下划线', name: 'underline', data: 'underline', icon: 'underline' }); //删除线 this.createMenu({ title: '删除线', name: 'strikeThrough', data: 'strikeThrough', icon: 'strike' }); //左对齐 this.createMenu({ title: '左对齐', name: 'justifyLeft', data: 'justifyLeft', icon: 'alignleft' }); //居中对齐 this.createMenu({ title: '居中对齐', name: 'justifyCenter', data: 'justifyCenter', icon: 'aligncenter' }); //右对齐 this.createMenu({ title: '右对齐', name: 'justifyRight', data: 'justifyRight', icon: 'alignright' }); //缩进 this.createMenu({ title: '缩进', name: 'indent', data: 'indent', icon: 'indent' }); //取消缩进 this.createMenu({ title: '取消缩进', name: 'outdent', data: 'outdent', icon: 'outdent' }); //有序列表 this.createMenu({ title: '有序列表', name: 'insertOrderedList', data: 'insertOrderedList', icon: 'orderedlist' }); //无序列表 this.createMenu({ title: '无序列表', name: 'insertUnorderedList', data: 'insertUnorderedList', icon: 'unorderedlist' }); //下标 this.createMenu({ title: '下标', name: 'subscript', data: 'subscript', icon: 'subscript' }); //上标 this.createMenu({ title: '上标', name: 'superscript', data: 'superscript', icon: 'superscript' }); //取消连接 this.createMenu({ title: '取消连接', name: 'unlink', data: 'unlink', icon: 'unlink' }); //添加水平线 this.createMenu({ title: '添加水平线', name: 'hr', data: 'insertHorizontalRule', icon: 'min' }); //清除格式 this.createMenu({ title: '清除格式', name: 'removeFormat', data: 'removeFormat', icon: 'remove' }); //富文本粘贴 this.createMenu({ title: '富文本粘贴', name: 'paste', icon: 'word', success: function (e, z) { if (!z.pasteText) e.className = 'iceEditor-active-s'; e.onclick = function () { z.pasteText = z.pasteText ? false : true; e.className = z.pasteText ? '' : 'iceEditor-active-s'; } } }); //pasteText //全选 this.createMenu({ title: '全选', name: 'selectAll', data: 'selectAll', icon: 'empty' }); //查看源码 this.createMenu({ title: '查看源码', name: 'code', icon: 'code', data: 'code' }); //插入表情 var html = '
'; for (var i = 0; i < this.face.length; i++) { html += '' + this.face[i].title + ''; } html += '
'; for (var i = 0; i < this.face.length; i++) { html += '
'; for (var s = 0; s < this.face[i].list.length; s++) { if (this.face[i].type == 'img') { html += ''; } else { html += '' + this.face[i].list[s].content + ''; } } html += '
'; } html += '
'; this.createMenu({ title: '插入表情', name: 'face', icon: 'face', dropdown: html, success: function (e, z) { var titleBox = e.getElementsByClassName('iceEditor-faceTitle')[0]; var title = titleBox.getElementsByTagName('span'); var main = e.getElementsByClassName('iceEditor-faceMain')[0]; var list = e.getElementsByClassName('iceEditor-faceList'); var pace = main.getElementsByTagName('span'); for (var i = 0; i < pace.length; i++) { pace[i].onclick = function () { z.setText(' ' + this.innerHTML + ' ', true); } } for (var i = 0; i < title.length; i++) { title[i].i = i; title[i].onclick = function () { for (var s = 0; s < title.length; s++) { list[s].className = 'iceEditor-faceList'; title[s].className = ''; } list[this.i].className = 'iceEditor-faceList iceEditor-faceActive'; title[this.i].className = 'iceEditor-faceActive'; } } title[0].className = 'iceEditor-faceActive'; list[0].className = 'iceEditor-faceList iceEditor-faceActive'; }, style: ` .iceEditor-face{width:310px;} .iceEditor-face span{cursor:pointer;} .iceEditor-faceTitle{border:2px solid #f7f7f7;} .iceEditor-faceTitle span{display:inline-block;padding:5px 10px;margin-bottom:-2px;} .iceEditor-faceTitle .iceEditor-faceActive{border-bottom:2px solid #333;} .iceEditor-faceMain{padding:15px 10px;} .iceEditor-faceList{display:none;width:100%;} .iceEditor-faceList.iceEditor-faceActive{display:block;} .iceEditor-faceList span{margin:3px 7px;display:inline-block;} .iceEditor-faceList .iceEditor-faceText{min-width:80px;text-align:center;} ` }); //表格 this.createMenu({ title: '表格', name: 'table', icon: 'table', dropdown: '', success: function (e, z) { //表格 z.table = z.id(z.tableId); var tableBox = z.table.getElementsByClassName('iceEditor-tableBox')[0]; var tableBgOn = z.table.getElementsByClassName('iceEditor-tableBgOn')[0]; var tableNum = z.table.getElementsByClassName('iceEditor-tableNum')[0]; tableBox.onmouseover = function (ev) { var o = z.getCoords(this), r = 1, c = 1; this.onmousemove = function (ev) { var Event = ev || event; var x = Event.clientX - o.left - 5; var y = Event.clientY - o.top - 5; if (x <= 180 && y <= 180) { r = Math.ceil(x / 18); c = Math.ceil(y / 18); tableBgOn.style.width = r * 18 + 'px'; tableBgOn.style.height = c * 18 + 'px'; tableNum.innerHTML = '表格:' + r + "×" + c } } this.onmousedown = function () { var tableNode = z.c('table'); tableNode.width = '100%'; tableNode.border = 1; tableNode.style.border = '1px solid #bdbdbd'; tableNode.style.borderSpacing = 0; tableNode.style.borderCollapse = 'collapse'; tableNode.className = 'table table-border'; for (var x = 0; x < c; x++) { var trNode = tableNode.insertRow(); for (var y = 0; y < r; y++) { var tdNode = trNode.insertCell(); tdNode.innerHTML = '
'; } } z.setHTML(tableNode, true); } this.onmouseout = function () { this.onmousemove = null; this.onmouseout = null; } } } }); //添加链接 this.createMenu({ title: '添加链接', name: 'createLink', icon: 'link', id: this.linkId, popup: { width: 320, height: 110, title: '添加链接', content: '' }, success: function (e, z) { z.link = z.id(z.linkId); z.linkInput = z.id(z.linkInputId); z.link.getElementsByClassName('iceEditor-btn')[0].onclick = function () { //如果选中的内容存在a标签的话,删除 var str = z.getSelectHTML().replace(/]+>/ig, '').replace(/<\s*\/a\s*>/ig, ''); var a = z.c('a'); if (z.link.getElementsByTagName('input')[1].checked) a.target = '_blank'; a.href = z.linkInput.value; a.innerHTML = str; z.setHTML(a, true); z.link.getElementsByClassName('iceEditor-popup')[0].style.display = 'none'; z.pd(); } } }); //添加音乐 this.createMenu({ title: '添加音乐', name: 'music', icon: 'music', id: this.musicId, popup: { width: 320, height: 80, title: '添加音乐', content: '
确定
' }, success: function (e, z) { z.music = z.id(z.musicId); z.musicInput = z.id(z.musicInputId); z.music.getElementsByClassName('iceEditor-btn')[0].onclick = function () { var a = z.c('audio'); a.src = z.musicInput.value; a.controls = 'controls'; z.setHTML(a, true); z.music.getElementsByClassName('iceEditor-popup')[0].style.display = 'none'; z.pd(); } } }); //附件上传 this.createMenu({ title: '附件上传', name: 'files', icon: 'files', id: this.filesId, popup: { width: 320, height: 200, title: '附件上传', content: '
' }, success: function (e, z) { z.files = z.id(z.filesId); var close = z.files.getElementsByClassName('iceEditor-popup')[0]; z.id(z.filesUploadId).onchange = function () { if (!z.uploadUrl) return alert('请配置uploadUrl项'); var formData = new FormData(); for (var i = 0; i < this.files.length; i++) { formData.append(z.filesUpload.name, this.files[i]); } formData = z.filesUpload.formData(formData); z.ajax({ url: z.uploadUrl, data: formData, success: function (res) { if (res) { for (var f = 0; f < res.length; f++) { var obj = res[f]; if (obj.error) { z.filesUpload.error(obj, res); z.filesUpload.complete(obj, res); alert(obj.error); } else { obj = z.filesUpload.success(obj, res); var a = z.c('a'); a.href = obj.url; a.className = 'download'; a.download = obj.name; a.innerText = obj.name; a.target = '_blank'; z.setHTML(a, true); z.setHTML(z.c('br'), true); z.filesUpload.complete(obj, res); } } close.style.display = 'none'; } else { z.filesUpload.error(res); z.filesUpload.complete(res); } }, error: function (xhr) { z.filesUpload.error(xhr); z.filesUpload.complete(xhr); } }) } } }); //添加图片 this.createMenu({ title: '添加图片', name: 'insertImage', icon: 'pic', id: this.imageId, popup: { width: 320, height: 250, title: '图片上传', content: '
确定
' }, success: function (e, z) { z.insertImage = z.id(z.imageId); var close = z.insertImage.getElementsByClassName('iceEditor-popup')[0]; //输入连接插入图片 var url = z.insertImage.getElementsByClassName('iceEditor-insertImageUrl')[0]; var width = z.insertImage.getElementsByClassName('iceEditor-inputWidth')[0]; var height = z.insertImage.getElementsByClassName('iceEditor-inputHeight')[0]; var btn = z.insertImage.getElementsByClassName('iceEditor-btn')[0]; //绑定输入连接 btn.onclick = function () { var img = z.c('img'); img.src = url.value; if (width.value.trim()) img.width = width.value.trim(); if (height.value.trim()) img.height = height.value.trim(); z.setHTML(img); close.style.display = 'none'; z.pd(); } //上传图片 z.id(z.imgUploadId).onchange = function () { if (!z.uploadUrl) return alert('请配置uploadUrl项'); var formData = new FormData(); for (var i = 0; i < this.files.length; i++) { formData.append(z.imgUpload.name, this.files[i]); } formData = z.imgUpload.formData(formData); z.ajax({ url: z.uploadUrl, data: formData, success: function (res) { if (res) { for (var f = 0; f < res.length; f++) { var obj = res[f]; if (obj.error) { z.imgUpload.error(obj, res); z.imgUpload.complete(obj, res); alert(obj.error); } else { obj = z.imgUpload.success(obj, res); var a = z.c('img'); a.src = obj.url; if (width.value.trim()) a.width = width.value.trim(); if (height.value.trim()) a.height = height.value.trim(); z.setHTML(a, true); z.imgUpload.success(obj, res); z.imgUpload.complete(obj, res); } } close.style.display = 'none'; } else { z.imgUpload.error(res); z.imgUpload.complete(res); } } }) } } }); //添加视频 this.createMenu({ title: '添加视频', name: 'video', icon: 'video', id: this.videoId, popup: { width: 320, height: 170, title: '添加视频', content: '
URL:
确定
' }, success: function (e, z) { z.video = z.id(z.videoId); var type; var close = z.video.getElementsByClassName('iceEditor-popup')[0]; var url = z.video.getElementsByClassName('iceEditor-videoUrl')[0]; var width = z.video.getElementsByClassName('iceEditor-inputWidth')[0]; var height = z.video.getElementsByClassName('iceEditor-inputHeight')[0]; var btn = z.video.getElementsByClassName('iceEditor-btn')[0]; btn.onclick = function () { if (!url.value.length) return alert('视频地址不能为空'); var v = z.c('iframe'); v.width = width.value.length ? width.value : 510; v.height = height.value.length ? height.value : 498; v.setAttribute('frameborder', 0); v.setAttribute('allowfullscreen', true); var error = '抱歉,无法处理该链接!'; var domain = /^http(s)?:\/\/(.*?)\//.exec(url.value) // 正则出域名 if (domain.length == 3) { if (domain[2] == 'www.bilibili.com' || domain[2] == 'bilibili.com') { // bilibili //源地址:https://www.bilibili.com/video/BV1UZ4y1g7De?spm_id_from=333.851.b_7265706f7274466972737431.11 //处理地址:https://player.bilibili.com/player.html?bvid=BV1UZ4y1g7De id = /video\/(.*?)\?/g.exec(url.value) if (!id) { id = /video\/(.*)/g.exec(url.value) } v.src = 'https://player.bilibili.com/player.html?bvid=' + id[1]; } else if (domain[2] == 'v.youku.com') { // youku //源地址:https://v.youku.com/v_show/id_XNTAwOTI4MzUxNg==.html //处理地址:https://player.youku.com/embed/XMjM0ODA3NjIw var id = url.value.split('.html'); if (id.length > 1) { id = id[0].split('id_'); if (id.length > 1 && id[1].length) { v.src = 'https://player.youku.com/embed/' + id[1]; } else { return alert('优酷:' + error); } } else { return alert('优酷:' + error); } } else if (domain[2] == 'www.ixigua.com') { //西瓜视频 id = /[0-9]{6,}/g.exec(url.value) v.src = 'https://www.ixigua.com/iframe/' + id[0]; } else { v = z.c('video'); v.src = url.value; v.width = width.value.length ? width.value : 510; v.height = height.value.length ? height.value : 498; v.controls = 'controls'; } } else { return alert('URL地址不合法!'); } z.setHTML(v, true); close.style.display = 'none'; z.pd(); } } }); //窗口最大化 this.createMenu({ title: '最大化', name: 'max', icon: 'max', data: 'max', css: 'iceEditor-maxWindow' }); //窗口最小化 this.createMenu({ title: '最小化', name: 'min', icon: 'min', data: 'min', css: 'iceEditor-minWindow' }); //菜单栏禁止 this.createMenu({ name: 'disabled', css: 'iceEditor-disabledMask' }); } //格式化菜单栏 menuFormat() { var _z = this; this.menuHTML(); var ul = this.c('ul'); ul.className = 'iceEditor-menu'; this.tool.innerHTML = ''; //防止重复创建 this.tool.appendChild(ul); //添加菜单 for (var i = 0; i < this.menu.length; i++) { if (this.menu[i] == 'line') { //分割线 var line = _z.c('li'); line.className = 'iceEditor-line'; ul.appendChild(line); continue; } if (this.notMenu.indexOf(this.menu[i]) == -1) { ul.appendChild(this.menuList[this.menu[i]]); if (this.menuList[this.menu[i]].success) { this.menuList[this.menu[i]].success(this.menuList[this.menu[i]], _z); } } } if (this.maxWindow) { ul.appendChild(this.menuList.max); ul.appendChild(this.menuList.min); } ul.appendChild(this.menuList.disabled); //根据菜单配置来初始化菜单功能 ---结束--- //初始化编辑器尺寸 this.editor.style.width = this.width; this.iframe.width = this.width; this.iframe.height = this.height; } //设置菜单的功能 menuAction() { var menu = this.tool.getElementsByClassName('iceEditor-exec'); var _z = this; for (var i = 0; i < menu.length; i++) { menu[i].e = this; menu[i].attr = menu[i].getAttribute('data'); if (menu[i].attr) { menu[i].onclick = function () { //anchorNode 返回选中内容前节点内的内容 switch (this.attr) { //删除线 case 'strikeThrough': var parent = _z.range.anchorNode.parentNode; if (parent.style.textDecoration == 'line-through') { var content = _z.range.anchorNode.parentNode.innerHTML; parent.parentNode.removeChild(parent); _z.setText(content, true); } else { var a = _z.c('span'); a.style.textDecoration = 'line-through'; _z.setHTML(a); } break; //查看源代码 case 'code': var d = _z.tool.getElementsByClassName('iceEditor-disabledMask')[0]; _z.code = _z.code ? 0 : 1; if (_z.code) { _z.tool.className = 'iceEditor-tool iceEditor-noselect'; d.style.display = 'block'; this.className = 'iceEditor-exec iceEditor-active'; _z.d.body.className = 'iceEditor-code'; var pre = _z.d.body.getElementsByTagName('pre'); //处理pre标签 for (var s = 0; s < pre.length; s++) pre[s].innerHTML = pre[s].innerHTML.replace(/<\/*br>/g, "\n"); var text = _z.getHTML(); //格式化段落 text = text.replace(/<\/p>

/gim, "<\/p>\n

").replace(/>

\n\n<");
									_z.d.body.innerHTML = _z.unhtml(text);

								} else {
									_z.tool.className = 'iceEditor-tool iceEditor-noselect';
									d.style.display = 'none';
									this.className = 'iceEditor-exec';
									_z.d.body.className = '';
									var text = _z.getHTML();
									_z.d.body.innerHTML = _z.html(text);
									var pre = _z.d.body.getElementsByTagName('pre');
									for (var s = 0; s < pre.length; s++) pre[s].innerHTML = pre[s].innerHTML.replace(/\n/g, "
"); } break; //最大化 case 'max': var webHeight = window.innerHeight; //页面视口高度 if (typeof webHeight != 'number') { if (document.compatMode == 'CSS1Compat') { webHeight = document.documentElement.clientHeight; } else { webWidth = document.body.clientWidth; } } _z.editor.style.position = 'fixed'; _z.editor.style.zIndex = _z.getTime; _z.editor.style.width = '100%'; _z.editor.style.height = '100%'; _z.editor.style.top = 0; _z.editor.style.left = 0; _z.iframe.height = webHeight - 35 - 20 + 'px'; this.parentNode.style.display = 'none'; _z.tool.getElementsByClassName('iceEditor-minWindow')[0].style.display = 'block'; break; //最小化 case 'min': _z.editor.removeAttribute('style'); _z.iframe.height = _z.height; this.parentNode.style.display = 'none'; _z.tool.getElementsByClassName('iceEditor-maxWindow')[0].style.display = 'block'; break; //默认执行execCommand default: var b = this.attr.split('|'); if (!_z.w.document._useStyleWithCSS) { _z.w.document.execCommand('styleWithCSS', null, true); _z.w.document._useStyleWithCSS = true; } if (b.length > 1) { _z.w.document.execCommand(b[0], false, b[1]); } else { _z.w.document.execCommand(b[0], false, null); } //_z.range.getRangeAt(0).collapse(); //取消选中状态 } return false; } } } } //粘贴world pasteWord(html) { //是否是word过来的内容 function isWordContent(str) { return /(class="?Mso|style="[^"]*\bmso\-|w:WordDocument|<(v|o):|lang=)/gi.test(str); } //转换cm/pt单位到px function unitToPx(v) { if (!/(pt|cm)/.test(v)) return v; var unit; v.replace(/([\d.]+)(\w+)/, function (str, s, u) { v = s, unit = u; }); v = unit == 'cm' ? parseFloat(v) * 25 : Math.round(parseFloat(v) * 96 / 72); return v + (v ? 'px' : ''); } //去掉小数 function transUnit(v) { return v.replace(/[\d.]+\w+/g, function (m) { return unitToPx(m) }); } //处理word格式 function filterPasteWord(str) { return str .replace(//gi, "") .replace(//gi, "") .replace(//gi, '') .replace(/.*?<\/head>/gi, '') .replace(/<\/body>/gi, '') .replace(/<\/html>/gi, '') .replace(/[\t\s]+/gi, ' ') .replace(/.*?<\/xml>/gi, '') .replace(/.*?<\/o:p>/gi, '') .replace(/]*>\s*<\/span>/gi, '') .replace(/<(span|font|p|b|i|u|s)[^>]*>\s*<\/\1>/gi, '') .replace(/v:\w+=(["']?)[^'"]+\1/g, '') .replace(/]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi, "

$1

") //去掉多余的属性 .replace(/\s+(class|lang|align)\s*=\s*(['"]?)([\w-]+)\2/gi, function (str, name, marks, val) { //保留list的标示 return name == "class" && val == "MsoListParagraph" ? str : ''; }) //清除多余的font/span不能匹配 有可能是空格 .replace(/<(font|span)[^>]*>(\s*)<\/\1>/gi, function (a, b, c) { return c.replace(/[\t\r\n ]+/g, ' '); }) //处理style的问题 .replace(/(<[a-z][^>]*)\sstyle=(["'])([^\2]*?)\2/gi, function (str, tag, tmp, style) { var n = [], s = style.replace(/^\s+|\s+$/, "").replace(/'/g, "'").replace(/"/gi, "'").replace(/[\d.]+(cm|pt)/g, function (str) { return unitToPx(str); }).split(/;\s*/g); for (var i = 0, v; v = s[i]; i++) { var name, value, parts = v.split(":"); if (parts.length == 2) { name = parts[0].toLowerCase().trim(), value = parts[1].toLowerCase().trim(); if ((/^(background)\w*/.test(name) && value.replace(/(initial|\s)/g, "").length == 0) || (/^(margin)\w*/.test(name) && /^0\w+$/.test(value))) continue; switch (name) { case "mso-vertical-align-alt": if (!//g, "") .replace(//g, "") .replace(//g, '') .replace(/.*?<\/head>/g, '') .replace(/<\/body>/g, '') .replace(/<\/html>/g, '') .replace(/\s+(id|class|lang|align|data|data-\w*)\s*=\s*(['"]?).*?\2/gi, ''); //过滤被禁止的html标签 for (var i = 0; i < this.filterTag.length; i++) { html = html.replace(new RegExp("<" + this.filterTag[i] + "[^>]*>.*?<\/" + this.filterTag[i] + ">", "gim"), ''); } //过滤style属性 var _z = this; html = html.replace(/\s+style\s*=\s*(['"]?)(.*?)\1/g, function (a, q, b) { if (b) { b = b.replace(/('|")/gi, "'"); //防止属性中的单双引号被转义,注意转义以后的分号,因为需要通过分号来分割样式 var info = b.split(';'); if (info.length) { var h = []; for (var i = 0; i < info.length; i++) { var styleName = info[i].trim(); if (styleName) { var name = styleName.split(':')[0]; if (!_z.filterStyle.includes(name)) { //用来将rgb颜色转为十六进制,rgba不变 var color = styleName.split(':'); if (color.length > 1 && /rgb\s*\(/gi.test(color[1])) { color[1] = color[1].replace(/rgb\s*\(.*?\)/gi, function (a) { a = a.split(/\D+/); return "#" + ((1 << 24) + (parseInt(a[1]) << 16) + (parseInt(a[2]) << 8) + parseInt(a[3])).toString(16).slice(1); }); h.push(name + ':' + color[1]); } else { h.push(styleName); } } } } return ' style="' + h.join(';') + '"'; } } return ''; }); //div转p return html.replace(/]*)>/g, "").replace(/<\/div>/g, "

"); } //美化HTML格式 formatHTML(html) { html = html.replace(/[\t\s]+/g, ' ') //清除空标签 .replace(/<(span|font|p|b|i|u|s)[^>]*>(<(?!img)[^>]*>)*<\/\1>/gi, '') //清除标签内末尾的空格,起到美化作用 .replace(/<(.+)\s+>/g, '<$1>') //格式美化 //.replace(/>\s*

\n){1,}/gi, '
'); //格式化块级元素段落 for (var i = 0; i < this.blockTag.length; i++) { html = html.replace(new RegExp("<\/" + this.blockTag[i] + ">", "gim"), "<\/" + this.blockTag[i] + ">\r\n"); } return html.replace(/\r\n{1,}/gim, "\r\n").trim(); } //纯文本粘贴 paste() { // 干掉IE http之类地址自动加链接 try { this.w.document.execCommand("AutoUrlDetect", false, false); } catch (e) { } var _z = this; var _w = this.w; //上传 var upload = function (imgBase64) { //如果禁用上传到服务器,则直接以base64格式显示图像 if (!_z.screenshotUpload) { var p = _z.c('p'); var a = _z.c('img'); a.src = imgBase64; p.appendChild(a); _z.setHTML(p, true); return; } function dataURItoBlob(base64Data) { var byteString; if (base64Data.split(',')[0].indexOf('base64') >= 0) { byteString = atob(base64Data.split(',')[1]); } else { byteString = unescape(base64Data.split(',')[1]); } var mimeString = base64Data.split(',')[0].split(':')[1].split(';')[0]; var a = new Uint8Array(byteString.length); for (var i = 0; i < byteString.length; i++) { a[i] = byteString.charCodeAt(i); } return new Blob([a], { type: mimeString }); } var blob = dataURItoBlob(imgBase64); var formData = new FormData(); formData.append(_z.imgUpload.name, blob); formData = _z.imgUpload.formData(formData); _z.ajax({ url: _z.uploadUrl, data: formData, success: function (res) { if (res) { for (var f = 0; f < res.length; f++) { var obj = res[f]; if (obj.error) { _z.imgUpload.error(obj, res); _z.imgUpload.complete(obj, res); alert(obj.error); } else { obj = _z.imgUpload.success(obj, res); var p = _z.c('p'); var a = _z.c('img'); a.src = obj.url; p.appendChild(a); _z.setHTML(p, true); _z.imgUpload.success(obj, res); _z.imgUpload.complete(obj, res); } } } else { _z.imgUpload.error(res); _z.imgUpload.complete(res); } }, error: function (xhr) { _z.imgUpload.error(xhr); _z.imgUpload.complete(xhr); } }) }; var getBase64 = function () { setTimeout(function () { //保证图片先插入到div里,然后去获取值 var imgList = _z.d.body.getElementsByTagName('img'); for (var i = 0; i < imgList.length; i++) { if (imgList[i].src.substr(0, 5) == 'data:') { upload(imgList[i].src); imgList[i].parentNode.removeChild(imgList[i]); break; } } }, 10); }; this.d.body.addEventListener('paste', function (e) { // console.log(_z.range.getRangeAt(0).endContainer); // console.log(_z.range.getRangeAt(0).startOffset); if (!_z.isIE()) e.preventDefault(); var clip = (window.clipboardData || e.clipboardData || e.originalEvent.clipboardData); //获取粘贴板数据 var text = clip.getData('Text'); var str = _z.pasteText && text.length ? text : (clip.getData('text/html').length ? clip.getData('text/html') : text); var htmlContent = clip.getData('text/html') ? true : false; //富文本粘贴模式开启状态下 if (htmlContent && !_z.pasteText) { //复制过来的数据有些情况会被转义,需要再次转义回来,单双引号全部转为单引号比较可靠 str = str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/ /g, " ").replace(/'/g, "'").replace(/"/g, "'"); } //截图粘贴功能 判断是否开启,判断是否在pre标签中 if (_z.screenshot && !_z.inNodeParent(_z.range.getRangeAt(0).endContainer, 'pre')) { if (clip) { //ie11没有items var blob = clip.items ? (clip.items[0] && clip.items[0].type.indexOf("image") !== -1 ? clip.items[0].getAsFile() : 0) : 0; if (blob) { var reader = new FileReader(); reader.onload = function (e) { //图片的Base64编码字符串 var base64_str = e.target.result; upload(base64_str); } reader.readAsDataURL(blob); } } getBase64(); } if (!str.length) return; //源码模式下直接纯文本粘贴 if (_z.code) { _z.setText(text); return; } var t = str.replace(/[\r|\n]+/g, "\n").split("\n"); //判断光标是否在pre标签中 if (_z.inNodeParent(_z.range.getRangeAt(0).endContainer, 'pre')) { var t = text.replace(/[\r|\n]+/g, "\n").split("\n"); for (var i = 0; i < t.length; i++) { t[i] = _z.toText(t[i]); } _z.setText(t.join('
'), true); return; } if (_z.pasteText && t.length == 1) { _z.setText(str); return; } //纯文本粘贴 if (_z.pasteText || !htmlContent) { for (var i = 0; i < t.length; i++) { if (t[i]) { //有效去除空标签 _z.setText('

' + t[i].trim() + '

', true); } } } else { //过滤word str = _z.pasteWord(str); str = _z.formatHTML(str); //过滤HTML str = _z.pasteHTML(str); //格式化HTML str = _z.formatHTML(str); _z.setText(str, true); } //处理冗余标签 str = _z.getHTML(); _z.d.body.innerHTML = str; str = _z.getHTML(); str = str.replace(/

<\/p>/gi, '') .replace(/<\/p>
/gi, '') .replace(/<(span|font|p|b|i|u|s)[^>]*>(<(?!img)[^>]*>)*<\/\1>/gi, ''); _z.d.body.innerHTML = str; //下载网络图片到本地 if (_z.imgAutoUpload) { var str = _z.getHTML(); str.replace(//gi, function (all, b = '') { //这里必须使用闭包,因为使用了异步 (function (a) { //判断是否为本地图片 if (b.substr(0, 1) == '/' && b.substr(0, 2) != '//') return; //如果为网络图片,过滤白名单域名 _z.imgDomain = _z.imgDomain && Array.isArray(_z.imgDomain) ? _z.imgDomain : [document.domain]; //将当前域名加入白名单 !_z.imgDomain.includes(document.domain) && _z.imgDomain.push(document.domain); for (var i = 0; i < _z.imgDomain.length; i++) { if (new RegExp("^((http|https):)*(\/)*" + _z.imgDomain[i], "i").test(a)) { return; } } _z.ajax({ url: _z.uploadUrl, data: { 'iceEditor-img': a }, success: function (res) { if (res && !res.error) { res = _z.imgUpload.success(res); _z.imgUpload.complete(res); str = str.replace(new RegExp(a, 'gi'), res.url); _z.setValue(str); } else { _z.imgUpload.error(res, res); _z.imgUpload.complete(res, res); } }, error: function (xhr) { _z.imgUpload.error(xhr); _z.imgUpload.complete(xhr); } }) })(b); }); } }); function nodePrev(el) { if (!el) return false; var node = el.nextSibling; if (node && node.nodeType != 1) node = nodePrev(node); return node; } this.d.body.addEventListener('keydown', function (e) { var range = _z.range.getRangeAt(0); if (e.keyCode == 13) { //回车处理pre中的代码 if (_z.inNodeParent(range.endContainer, 'pre')) { //这一步是真特么费劲 if (_z.range.anchorNode.parentNode.tagName == 'PRE') { _z.element.focus(); //判断一下光标是否处于当前节点文字的末尾 var isCursorEnd = range.endContainer.length == range.startOffset; //Chrome浏览器有个非常操蛋的毛病,就是如果当前节点是最后一个,输入文字后回车 //第一次换行不起作用,需要两次回车才能换行 //所以需要判断当前节点是否为最后一个节点,完全是给Chrome用的 var isNodeEnd = nodePrev(range.endContainer) ? false : true; var br = isNodeEnd ? '

' : '
'; var range = _z.range.getRangeAt(0); range.insertNode(range.createContextualFragment(br)); //接下来这一步是为了修正光标位置 var node = _z.range.anchorNode.nextSibling.nextSibling; range.setStart(node, 0); range.setEnd(node, 0); range.collapse(); } else if (_z.parentTagName == 'PRE' || _z.range.anchorNode.tagName == 'PRE') { _z.setText('
', true); } e.preventDefault(); return; } } // 去除Crtl+b/Ctrl+i/Ctrl+u等快捷键 // e.metaKey for mac if (e.ctrlKey || e.metaKey) { switch (e.keyCode) { case 13: { e.preventDefault(); break; } case 66: //ctrl+B or ctrl+b case 98: case 73: //ctrl+I or ctrl+i case 105: case 85: //ctrl+U or ctrl+u case 117: { e.preventDefault(); break; } } } }); } //配置格式化 create() { //添加样式 if (this.cssConfig.styleSheet) { this.cssConfig.styleSheet.cssText = this.css; } else { this.cssConfig.innerHTML = this.css; } this.menuFormat(); this.menuAction(); this.disableds.style.display = this.disabled ? 'block' : 'none'; this.styleInit(); //渲染样式 } //获取编辑器的HTML内容 getHTML() { return this.content.innerHTML; } //获取编辑器的Text内容 getText() { return this.content.innerText; } //获取编辑器的HTML内容,等同getHTML getValue() { return this.content.innerHTML; } //设置编辑器的内容 setValue(v) { this.content.innerHTML = v; this.setTextarea(); } //追加编辑器的内容 addValue(v) { this.content.innerHTML += v; this.setTextarea(); } //禁止输入 inputDisabled() { this.d.body.designMode = 'off'; this.d.body.contentEditable = false; } //启动输入 inputEnable() { this.d.body.designMode = 'on'; this.d.body.contentEditable = true; } //监听输入 inputCallback(fn) { var _z = this; _z.d.body.oninput = function () { fn && fn.call(_z, _z.getHTML(), _z.getText()); } _z.d.body.addEventListener('paste', function (e) { fn && fn.call(_z, _z.getHTML(), _z.getText()); }) } //加载样式 styleInit() { //编辑器图标 ice.editor.css = this.globalCss ? this.globalCss : '.iceEditor{color:#353535!important;font-family:"Microsoft YaHei";font-size:14px!important;background:#fff;position:relative;border:solid 1px #ccc}.iceEditor *{margin:0;padding:0;box-sizing:border-box;font-size:14px;}.iceEditor a{color:#606060;text-decoration:none;-webkit-tap-highlight-color:transparent}.iceEditor a:hover{color:#000}.iceEditor ul{margin:initial;padding:initial}.iceEditor-line{height:20px;width:1px;background:#cecece;margin:8px 8px 0 8px !important}.iceEditor-row{margin-bottom:10px;}.iceEditor-group{text-align:left;margin-bottom:10px;}.iceEditor-group label {min-width:50px!important;display:inline-block!important;text-align:right!important;font-weight:normal!important;}.iceEditor input{height:27px!important;line-height:27px!important;padding:3px!important;border:1px solid #B7B7B7!important;font-family:inherit;font-size:inherit;vertical-align:middle;outline:none;display:inline-block!important;}.iceEditor-exec{cursor:pointer}.iceEditor-icon{width:22px;height:16px;fill:currentColor;overflow:hidden;vertical-align:middle;font-size:16px}.iceEditor-noselect{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.iceEditor-menuDropdown{min-width:35px;min-height:35px;transition:all .4s ease;margin-top:60px;opacity:0;visibility:hidden;position:absolute;background:#fff;z-index:999;box-shadow:0 2px 9px 0 rgba(0,0,0,.2);border-bottom:2px solid #676767;border-top:1px solid #676767}.iceEditor-menuDropdown::before{content:"";display:block;width:0;height:0;border-left:8px solid transparent;border-right:8px solid transparent;border-bottom:8px solid #676767;position:absolute;top:-8px;left:9px}.iceEditor-menuTitle{width:100%!important;text-align:center;height:30px;line-height:30px;border-top:1px solid #efefef}.iceEditor-tool{width:100%;background:#eee;border-bottom:solid 1px #ccc;position:relative}.iceEditor-tool:after,.iceEditor-tool:before{display:table;content:" "}.iceEditor-tool:after{clear:both}.iceEditor-menu{margin:0!important;width:100%;padding:0 10px;display:inline-block;float:left}.iceEditor-menu a{list-style:none;float:left;min-width:35px;height:35px;padding:0 5px;text-align:center;line-height:35px;cursor:pointer}.iceEditor-menu a:hover{background:#cdcdcd}.iceEditor-menu>li>div.iceEditor-exec{list-style:none;float:left;min-width:35px;height:35px;padding:0 5px;text-align:center;line-height:35px;cursor:pointer}.iceEditor-menu>li>div.iceEditor-exec:hover{background:#cdcdcd}.iceEditor-menu svg{fill:currentColor;overflow:hidden;vertical-align:middle;font-size:16px}.iceEditor-menu .iceEditor-active{background:#e0e0e0;position:relative;z-index:999}.iceEditor-menu .iceEditor-actives,.iceEditor-menu .iceEditor-active-s{background:#d8d8d8;}.iceEditor-menu .iceEditor-disabledMask{background:rgba(238,238,238,0.7);width:100%;height:100%;position:absolute;left:0;top:0;display:none}.iceEditor-menu li{margin:0;display:inline-block;float:left;line-height:initial;}.iceEditor-menu li .iceEditor-menuDropdown.iceEditor-menuActive{margin-top:44px;opacity:1;visibility:visible}.iceEditor-menu li.iceEditor-minWindow{display:none}.iceEditor-menu li.iceEditor-maxWindow,.iceEditor-menu li.iceEditor-minWindow{float:right}.iceEditor-menu li.iceEditor-maxWindow>div,.iceEditor-menu li.iceEditor-minWindow>div{position:relative;z-index:9}.iceEditor-menu li.iceEditor-maxWindow .iceEditor-icon,.iceEditor-menu li.iceEditor-minWindow .iceEditor-icon{color:#606060}.iceEditor-codeLanguages select{padding:5px 5px;width:120px;outline:none;font-size:15px;margin-top:10px;}.iceEditor input.iceEditor-uploadInput{display:none!important}.iceEditor-uploadBtn{float:none;width:auto;font-size:15px;background:#00b7ee;height:40px;line-height:40px;padding:0 30px;color:#fff;display:inline-block;margin:0 auto 15px auto;cursor:pointer;box-shadow:0 1px 1px rgba(0,0,0,.1)}.iceEditor-uploadBtn:hover{background:#009ccb}.iceEditor-uploadIcon{width:45px;height:45px;color:#bababa;margin:20px 20px 10px}.iceEditor-backColor{width:230px;padding:5px!important}.iceEditor-backColor span{width:20px;height:20px;padding:0;margin:1px;display:inline-block}.iceEditor-fontSize{width:280px}.iceEditor-fontSize li{width:40px;text-align:center}.iceEditor-fontSize span{width:40px;display:inline-block;padding:10px 0}.iceEditor-fontSize span:hover{background:#eee;color:#4CAF50}.iceEditor-createLink label{display:inline-block;}.iceEditor .iceEditor-link{width:175px!important;}.iceEditor-popup .iceEditor-insertImage{text-align:center}.iceEditor-popup .iceEditor-insertImageUrl{width:220px!important;height:27px;outline:0;margin-right:15px}.iceEditor-popup .iceEditor-inputWidth{width:50px!important;height:27px;outline:0;margin-right:15px}.iceEditor-popup .iceEditor-inputHeight{width:50px!important;height:27px;outline:0}.iceEditor-popup .iceEditor-btn{width:auto;display:inline-block;float:none;color:#fff!important;height:27px;line-height:25px;padding:0 10px;background:#939393;vertical-align:middle;margin-left:5px;border:1px solid #7b7b7b}.iceEditor-popup .iceEditor-btn:hover{background:#7b7b7b!important;color:#fff}.iceEditor-tableBox{position:relative;width:190px;height:214px;padding:5px;overflow:hidden}.iceEditor-tableBgOn{position:absolute!important;top:5px;left:5px;z-index:4;width:18px;height:18px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIjd6vvD2f9LKLW+AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKwNDEVT0AAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC) repeat}.iceEditor-tableBgOff{width:180px;height:180px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIj4+Pjp6ekKlAqjAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKhmnaJzPAAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC) repeat}.iceEditor-tableNum{height:30px;line-height:30px;text-align:center;color:#757575}.iceEditor-video{text-align:left}.iceEditor-video label{margin-right:20px;display:inline-block}.iceEditor-video input{margin-right:5px}.iceEditor-video div{height:27px;margin-bottom:10px}.iceEditor-popup .iceEditor-videoUrl{width:255px!important;height:27px;outline:0;margin-right:0}.iceEditor-content{width:100%;height:100%;padding:20px;position:relative}.iceEditor-content:focus{outline:0}.iceEditor-dragBg{position:absolute;width:100%;height:100%;top:0;left:0;z-index:1;display:none;}.iceEditor-drag{color:#757575;background:#eee;text-align:center;height:12px;line-height:0;cursor:n-resize}.iceEditor-disabled{position:absolute;width:100%;height:100%;top:0;left:0;background:rgba(191,191,191,.79);z-index:99999;display:none}.iceEditor-popup{display:none}.iceEditor-popupMain{width:400px;height:200px;position:fixed;margin:auto;top:0;bottom:0;left:0;right:0;background:#fff;box-shadow:0 1px 1px rgba(0,0,0,.12);z-index:9999;animation-name:iceEditorPopup;animation-duration:.5s}.iceEditor-popupBox{width:100%;height:100%;position:fixed;top:0;left:0;background:rgba(0,0,0,.33);opacity:.5;filter:alpha(opacity=50);z-index:1}.iceEditor-popupTitle{width:100%;height:30px;line-height:30px;background:#2f2f2f;padding:0 10px;color:#fff}.iceEditor-popupTitle span{display:inline-block;vertical-align:middle}.iceEditor-popupTitle::before{content:"";display:inline-block;width:10px;height:10px;border-radius:10px;background:#c7f98c;vertical-align:middle;margin-right:8px}.iceEditor-popupClose{float:right;padding:0 10px;color:#fff;font-size:18px;cursor:pointer}.iceEditor-popupClose:hover{color:#8fe5ff}.iceEditor-popupContent{width:100%;padding:10px;color:#000;overflow:auto;float:left}.iceEditor-popupBtn{width:100%;border:0;color:#fff;background:#03A9F4;border-top:1px solid #efefef;padding:0 20px;margin:0;height:35px;text-align:center;line-height:35px;cursor:pointer;margin-top:20px;outline:0}.iceEditor-popupBtn:hover{color:#151515;background:#efefef}@keyframes iceEditorPopup{0%{top:-100px;opacity:0}to{top:0;opacity:1}}'; //编辑器图标 ice.editor.svg = this.globalIcon ? this.globalIcon : ''; (function svg() { var a = document.getElementById('iceEditor-css'); if (a) a.parentNode.removeChild(a); a = document.getElementById('iceEditor-icon'); if (a) a.parentNode.removeChild(a); var c = document.createElement('style'), d, s, b = document.body; if (c.styleSheet) { c.styleSheet.cssText = ice.editor.css; } else { c.innerHTML = ice.editor.css; } c.id = 'iceEditor-css'; document.getElementsByTagName('head')[0].appendChild(c); d = document.createElement("div"); d.innerHTML = ice.editor.css + ice.editor.svg; ice.editor.svg = null; s = d.getElementsByTagName("svg")[0]; if (s) { s.id = 'iceEditor-icon'; s.setAttribute("aria-hidden", "true"); s.style.position = "absolute"; s.style.width = 0; s.style.height = 0; s.style.overflow = "hidden"; if (b.firstChild) { b.firstChild.parentNode.insertBefore(s, b.firstChild) } else { b.appendChild(s) } } })(); } } return new iceEditor(id, callback); }