layedit-╘н░ц.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. /**
  2. @Name:layui.layedit 富文本编辑器
  3. @Author:贤心
  4. @License:MIT
  5. @Edit by KnfieZ
  6. */
  7. layui.define(['layer', 'form'], function (exports) {
  8. "use strict";
  9. var $ = layui.$
  10. , layer = layui.layer
  11. , form = layui.form
  12. , hint = layui.hint()
  13. , device = layui.device()
  14. , MOD_NAME = 'layedit', THIS = 'layui-this', SHOW = 'layui-show', ABLED = 'layui-disabled'
  15. , Edit = function () {
  16. var that = this;
  17. that.index = 0;
  18. //全局配置
  19. that.config = {
  20. //默认工具bar
  21. tool: [
  22. 'strong', 'italic', 'underline', 'del'
  23. , '|'
  24. , 'left', 'center', 'right'
  25. , '|'
  26. , 'link', 'unlink', 'face', 'image'
  27. ]
  28. , hideTool: []
  29. , height: 280 //默认高
  30. };
  31. };
  32. //全局设置
  33. Edit.prototype.set = function (options) {
  34. var that = this;
  35. $.extend(true, that.config, options);
  36. return that;
  37. };
  38. //事件监听
  39. Edit.prototype.on = function (events, callback) {
  40. return layui.onevent(MOD_NAME, events, callback);
  41. };
  42. //建立编辑器
  43. Edit.prototype.build = function (id, settings) {
  44. settings = settings || {};
  45. var that = this
  46. , config = that.config
  47. , ELEM = 'layui-layedit', textArea = $(typeof (id) == 'string' ? '#' + id : id)
  48. , name = 'LAY_layedit_' + (++that.index)
  49. , haveBuild = textArea.next('.' + ELEM)
  50. , set = $.extend({}, config, settings)
  51. , tool = function () {
  52. var node = [], hideTools = {};
  53. layui.each(set.hideTool, function (_, item) {
  54. hideTools[item] = true;
  55. });
  56. layui.each(set.tool, function (_, item) {
  57. if (tools[item] && !hideTools[item]) {
  58. node.push(tools[item]);
  59. }
  60. });
  61. return node.join('');
  62. }()
  63. , editor = $(['<div class="' + ELEM + '">'
  64. , '<div class="layui-unselect layui-layedit-tool">' + tool + '</div>'
  65. , '<div class="layui-layedit-iframe">'
  66. , '<iframe id="' + name + '" name="' + name + '" textarea="' + id + '" frameborder="0"></iframe>'
  67. , '</div>'
  68. , '</div>'].join(''))
  69. //编辑器不兼容ie8以下
  70. if (device.ie && device.ie < 8) {
  71. return textArea.removeClass('layui-hide').addClass(SHOW);
  72. }
  73. haveBuild[0] && (haveBuild.remove());
  74. setIframe.call(that, editor, textArea[0], set)
  75. textArea.addClass('layui-hide').after(editor);
  76. return that.index;
  77. };
  78. //获得编辑器中内容
  79. Edit.prototype.getContent = function (index) {
  80. var iframeWin = getWin(index);
  81. if (!iframeWin[0]) return;
  82. return toLower(iframeWin[0].document.body.innerHTML);
  83. };
  84. //获得编辑器中纯文本内容
  85. Edit.prototype.getText = function (index) {
  86. var iframeWin = getWin(index);
  87. if (!iframeWin[0]) return;
  88. return $(iframeWin[0].document.body).text();
  89. };
  90. /**
  91. * 设置编辑器内容
  92. * @param {[type]} index 编辑器索引
  93. * @param {[type]} content 要设置的内容
  94. * @param {[type]} flag 是否追加模式
  95. */
  96. Edit.prototype.setContent = function (index, content, flag) {
  97. var iframeWin = getWin(index);
  98. if (!iframeWin[0]) return;
  99. if (flag) {
  100. $(iframeWin[0].document.body).append(content)
  101. } else {
  102. $(iframeWin[0].document.body).html(content)
  103. };
  104. layedit.sync(index)
  105. };
  106. //将编辑器内容同步到textarea(一般用于异步提交时)
  107. Edit.prototype.sync = function (index) {
  108. var iframeWin = getWin(index);
  109. if (!iframeWin[0]) return;
  110. var textarea = $('#' + iframeWin[1].attr('textarea'));
  111. textarea.val(toLower(iframeWin[0].document.body.innerHTML));
  112. };
  113. //获取编辑器选中内容
  114. Edit.prototype.getSelection = function (index) {
  115. var iframeWin = getWin(index);
  116. if (!iframeWin[0]) return;
  117. var range = Range(iframeWin[0].document);
  118. return document.selection ? range.text : range.toString();
  119. };
  120. //iframe初始化
  121. var setIframe = function (editor, textArea, set) {
  122. var that = this, iframe = editor.find('iframe');
  123. iframe.css({
  124. height: set.height
  125. }).on('load', function () {
  126. var conts = iframe.contents()
  127. , iframeWin = iframe.prop('contentWindow')
  128. , head = conts.find('head')
  129. , style = $(['<style>'
  130. , '*{margin: 0; padding: 0;}'
  131. , 'body{padding: 10px; line-height: 20px; overflow-x: hidden; word-wrap: break-word; font: 14px Helvetica Neue,Helvetica,PingFang SC,Microsoft YaHei,Tahoma,Arial,sans-serif; -webkit-box-sizing: border-box !important; -moz-box-sizing: border-box !important; box-sizing: border-box !important;}'
  132. , 'a{color:#01AAED; text-decoration:none;}a:hover{color:#c00}'
  133. , 'p{margin-bottom: 10px;}'
  134. , 'img{display: inline-block; border: none; vertical-align: middle;}'
  135. , 'pre{margin: 10px 0; padding: 10px; line-height: 20px; border: 1px solid #ddd; border-left-width: 6px; background-color: #F2F2F2; color: #333; font-family: Courier New; font-size: 12px;}'
  136. , '</style>'].join(''))
  137. , body = conts.find('body');
  138. head.append(style);
  139. body.attr('contenteditable', 'true').css({
  140. 'min-height': set.height
  141. }).html(textArea.value || '');
  142. hotkey.apply(that, [iframeWin, iframe, textArea, set]); //快捷键处理
  143. toolActive.call(that, iframeWin, editor, set); //触发工具
  144. });
  145. }
  146. //获得iframe窗口对象
  147. , getWin = function (index) {
  148. var iframe = $('#LAY_layedit_' + index)
  149. , iframeWin = iframe.prop('contentWindow');
  150. return [iframeWin, iframe];
  151. }
  152. //IE8下将标签处理成小写
  153. , toLower = function (html) {
  154. if (device.ie == 8) {
  155. html = html.replace(/<.+>/g, function (str) {
  156. return str.toLowerCase();
  157. });
  158. }
  159. return html;
  160. }
  161. //快捷键处理
  162. , hotkey = function (iframeWin, iframe, textArea, set) {
  163. var iframeDOM = iframeWin.document, body = $(iframeDOM.body);
  164. body.on('keydown', function (e) {
  165. var keycode = e.keyCode;
  166. //处理回车
  167. if (keycode === 13) {
  168. var range = Range(iframeDOM);
  169. var container = getContainer(range)
  170. , parentNode = container.parentNode;
  171. if (parentNode.tagName.toLowerCase() === 'pre') {
  172. if (e.shiftKey) return
  173. layer.msg('请暂时用shift+enter');
  174. return false;
  175. }
  176. iframeDOM.execCommand('formatBlock', false, '<p>');
  177. }
  178. });
  179. //给textarea同步内容
  180. $(textArea).parents('form').on('submit', function () {
  181. var html = body.html();
  182. //IE8下将标签处理成小写
  183. if (device.ie == 8) {
  184. html = html.replace(/<.+>/g, function (str) {
  185. return str.toLowerCase();
  186. });
  187. }
  188. textArea.value = html;
  189. });
  190. //处理粘贴
  191. body.on('paste', function (e) {
  192. iframeDOM.execCommand('formatBlock', false, '<p>');
  193. setTimeout(function () {
  194. filter.call(iframeWin, body);
  195. textArea.value = body.html();
  196. }, 100);
  197. });
  198. }
  199. //标签过滤
  200. , filter = function (body) {
  201. var iframeWin = this
  202. , iframeDOM = iframeWin.document;
  203. //清除影响版面的css属性
  204. body.find('*[style]').each(function () {
  205. var textAlign = this.style.textAlign;
  206. this.removeAttribute('style');
  207. $(this).css({
  208. 'text-align': textAlign || ''
  209. })
  210. });
  211. //修饰表格
  212. body.find('table').addClass('layui-table');
  213. //移除不安全的标签
  214. body.find('script,link').remove();
  215. }
  216. //Range对象兼容性处理
  217. , Range = function (iframeDOM) {
  218. return iframeDOM.selection
  219. ? iframeDOM.selection.createRange()
  220. : iframeDOM.getSelection().getRangeAt(0);
  221. }
  222. //当前Range对象的endContainer兼容性处理
  223. , getContainer = function (range) {
  224. return range.endContainer || range.parentElement().childNodes[0]
  225. }
  226. //在选区插入内联元素
  227. , insertInline = function (tagName, attr, range) {
  228. var iframeDOM = this.document
  229. , elem = document.createElement(tagName)
  230. for (var key in attr) {
  231. elem.setAttribute(key, attr[key]);
  232. }
  233. elem.removeAttribute('text');
  234. if (iframeDOM.selection) { //IE
  235. var text = range.text || attr.text;
  236. if (tagName === 'a' && !text) return;
  237. if (text) {
  238. elem.innerHTML = text;
  239. }
  240. range.pasteHTML($(elem).prop('outerHTML'));
  241. range.select();
  242. } else { //非IE
  243. var text = range.toString() || attr.text;
  244. if (tagName === 'a' && !text) return;
  245. if (text) {
  246. elem.innerHTML = text;
  247. }
  248. range.deleteContents();
  249. range.insertNode(elem);
  250. }
  251. }
  252. //工具选中
  253. , toolCheck = function (tools, othis) {
  254. var iframeDOM = this.document
  255. , CHECK = 'layedit-tool-active'
  256. , container = getContainer(Range(iframeDOM))
  257. , item = function (type) {
  258. return tools.find('.layedit-tool-' + type)
  259. }
  260. if (othis) {
  261. othis[othis.hasClass(CHECK) ? 'removeClass' : 'addClass'](CHECK);
  262. }
  263. tools.find('>i').removeClass(CHECK);
  264. item('unlink').addClass(ABLED);
  265. $(container).parents().each(function () {
  266. var tagName = this.tagName.toLowerCase()
  267. , textAlign = this.style.textAlign;
  268. //文字
  269. if (tagName === 'b' || tagName === 'strong') {
  270. item('b').addClass(CHECK)
  271. }
  272. if (tagName === 'i' || tagName === 'em') {
  273. item('i').addClass(CHECK)
  274. }
  275. if (tagName === 'u') {
  276. item('u').addClass(CHECK)
  277. }
  278. if (tagName === 'strike') {
  279. item('d').addClass(CHECK)
  280. }
  281. //对齐
  282. if (tagName === 'p') {
  283. if (textAlign === 'center') {
  284. item('center').addClass(CHECK);
  285. } else if (textAlign === 'right') {
  286. item('right').addClass(CHECK);
  287. } else {
  288. item('left').addClass(CHECK);
  289. }
  290. }
  291. //超链接
  292. if (tagName === 'a') {
  293. item('link').addClass(CHECK);
  294. item('unlink').removeClass(ABLED);
  295. }
  296. });
  297. }
  298. //触发工具
  299. , toolActive = function (iframeWin, editor, set) {
  300. var iframeDOM = iframeWin.document
  301. , body = $(iframeDOM.body)
  302. , toolEvent = {
  303. //超链接
  304. link: function (range) {
  305. debugger;
  306. var container = getContainer(range)
  307. , parentNode = $(container).parent();
  308. link.call(body, {
  309. href: parentNode.attr('href')
  310. , target: parentNode.attr('target')
  311. }, function (field) {
  312. var parent = parentNode[0];
  313. if (parent.tagName === 'A') {
  314. parent.href = field.url;
  315. } else {
  316. insertInline.call(iframeWin, 'a', {
  317. target: field.target
  318. , href: field.url
  319. , text: field.url
  320. }, range);
  321. }
  322. });
  323. }
  324. //清除超链接
  325. , unlink: function (range) {
  326. iframeDOM.execCommand('unlink');
  327. }
  328. //表情
  329. , face: function (range) {
  330. face.call(this, function (img) {
  331. insertInline.call(iframeWin, 'img', {
  332. src: img.src
  333. , alt: img.alt
  334. }, range);
  335. });
  336. }
  337. //图片1
  338. , image: function (range) {
  339. var that = this;
  340. layui.use('upload', function (upload) {
  341. var uploadImage = set.uploadImage || {};
  342. upload.render({
  343. url: uploadImage.url
  344. , method: uploadImage.type
  345. , elem: $(that).find('input')[0]
  346. , done: function (res) {
  347. if (res.code == 0) {
  348. res.data = res.data[0] || {};
  349. insertInline.call(iframeWin, 'img', {
  350. //src: res.data.src
  351. src:window.hywa.config.href+window.hywa.config.port['show_img']+encodeURIComponent(res.data.src)
  352. , alt: res.data.title
  353. }, range);
  354. } else {
  355. layer.msg(res.msg || '上传失败');
  356. }
  357. }
  358. });
  359. });
  360. }
  361. //图片2
  362. , image_alt: function (range) {
  363. debugger;
  364. var that = this;
  365. layer.open({
  366. type: 1
  367. , id: 'fly-jie-image-upload'
  368. , title: '插入图片'
  369. , shade: false
  370. , area: '465px'
  371. , skin: 'layui-layer-border'
  372. , content: ['<ul class="layui-form layui-form-pane" style="margin: 20px;">'
  373. , '<li class="layui-form-item">'
  374. , '<label class="layui-form-label">图片</label>'
  375. , '<div class="layui-input-inline">'
  376. , '<button type="button" class="layui-btn" id="LayEdit_InsertImage"> <i class="layui-icon"></i>上传图片</button>'
  377. , '<input type="text" name="Imgsrc" placeholder="请选择文件" style="width: 60%;position: relative;float: right;" class="layui-input">'
  378. , '</div>'
  379. , '</li>'
  380. , '<li class="layui-form-item">'
  381. , '<label class="layui-form-label">描述</label>'
  382. , '<div class="layui-input-inline">'
  383. , '<input type="text" required name="altStr" placeholder="alt属性" value="" class="layui-input">'
  384. , '</div>'
  385. , '</li>'
  386. , '<li class="layui-form-item" style="text-align: center;">'
  387. , '<button type="button" lay-submit lay-filter="uploadImages" class="layui-btn ImgSubmit">确认</button>'
  388. , '</li>'
  389. , '</ul>'].join('')
  390. , success: function (layero, index) {
  391. var upload = layui.upload;
  392. var loding, altStr = layero.find('input[name="altStr"]'), Imgsrc = layero.find('input[name="Imgsrc"]');
  393. var uploadImage = set.uploadImage || {};
  394. //执行实例
  395. upload.render({
  396. elem: '#LayEdit_InsertImage'
  397. , url: uploadImage.url
  398. , method: uploadImage.type
  399. , before: function (obj) { loding = layer.msg('文件上传中,请稍等哦', { icon: 16, shade: 0.3, time: 0 }); }
  400. , done: function (res, input, upload) {
  401. layer.close(loding);
  402. if (res.code == 0) {
  403. res.data = res.data[0] || {};
  404. Imgsrc.val(window.hywa.config.href+window.hywa.config.port['show_img']+encodeURIComponent(res.data.src));
  405. altStr.val(res.data.title);
  406. } else {
  407. layer.msg(res.msg, { icon: 5 });
  408. }
  409. }
  410. });
  411. $(".ImgSubmit").click(function () {
  412. insertInline.call(iframeWin, 'img', {
  413. src: Imgsrc.val()
  414. , alt: altStr.val()
  415. }, range);
  416. layer.close(index);
  417. })
  418. }
  419. });
  420. }
  421. //插入视频
  422. , video: function (range) {
  423. var that = this;
  424. layer.open({
  425. type: 1
  426. , id: 'fly-jie-video-upload'
  427. , title: '插入视频'
  428. , shade: false
  429. , area: '465px'
  430. , skin: 'layui-layer-border'
  431. , content: ['<ul class="layui-form layui-form-pane" style="margin: 20px;">'
  432. , '<li class="layui-form-item">'
  433. , '<label class="layui-form-label">封面</label>'
  434. , '<div class="layui-input-inline">'
  435. , '<input type="text" required name="cover" placeholder="支持直接粘贴远程图片地址" value="" class="layui-input">'
  436. , '</div>'
  437. , '<input required type="file" name="file" lay-type="image" class="layui-upload-file" value="">'
  438. , '</li>'
  439. , '<li class="layui-form-item">'
  440. , '<label class="layui-form-label">URL</label>'
  441. , '<div class="layui-input-inline">'
  442. , '<input type="text" required name="video" placeholder="支持直接粘贴远程视频地址" value="" class="layui-input">'
  443. , '</div>'
  444. , '<input required type="file" name="file" lay-type="video" class="layui-upload-file" value="">'
  445. , '</li>'
  446. , '<li class="layui-form-item" style="text-align: center;">'
  447. , '<button type="button" lay-submit lay-filter="uploadImages" class="layui-btn">确认</button>'
  448. , '</li>'
  449. , '</ul>'].join('')
  450. , success: function (layero, index) {
  451. var loding, video = layero.find('input[name="video"]'), cover = layero.find('input[name="cover"]');
  452. var upload = layui.upload;
  453. var uploadFile = set.uploadFile || {};
  454. //执行实例
  455. var uploadInst = upload.render({
  456. elem: '#fly-jie-video-upload .layui-upload-file'
  457. , url: uploadFile.url
  458. , method: uploadFile.type
  459. , before: function (input) { loding = layer.msg('文件上传中,请稍等哦', { icon: 16, shade: 0.3, time: 0 }); }
  460. , done: function (res, input) {
  461. layer.close(loding);
  462. //if (res.code == 0) {
  463. // res.data = res.data || {};
  464. // insertInline.call(iframeWin, 'video', {
  465. // src: res.data.src
  466. // , alt: res.data.title
  467. // }, range);
  468. //} else {
  469. // layer.msg(res.msg || '上传失败');
  470. //}
  471. if (res.status == 0) {
  472. if ($(input).attr('lay-type') == 'image') {
  473. cover.val(res.data);
  474. } else {
  475. video.val(res.data);
  476. }
  477. } else {
  478. layer.msg(res.msg, { icon: 5 });
  479. }
  480. }
  481. , error: function () {
  482. //请求异常回调
  483. }
  484. });
  485. }
  486. });
  487. }
  488. //插入代码
  489. , code: function (range) {
  490. code.call(body, function (pre) {
  491. insertInline.call(iframeWin, 'pre', {
  492. text: pre.code
  493. , 'lay-lang': pre.lang
  494. }, range);
  495. });
  496. }
  497. //帮助
  498. , help: function () {
  499. layer.open({
  500. type: 2
  501. , title: '帮助'
  502. , area: ['600px', '380px']
  503. , shadeClose: true
  504. , shade: 0.1
  505. , skin: 'layui-layer-msg'
  506. , content: ['http://www.layui.com/about/layedit/help.html', 'no']
  507. });
  508. }
  509. }
  510. , tools = editor.find('.layui-layedit-tool')
  511. , click = function () {
  512. var othis = $(this)
  513. , events = othis.attr('layedit-event')
  514. , command = othis.attr('lay-command');
  515. if (othis.hasClass(ABLED)) return;
  516. body.focus();
  517. var range = Range(iframeDOM)
  518. , container = range.commonAncestorContainer
  519. if (command) {
  520. iframeDOM.execCommand(command);
  521. if (/justifyLeft|justifyCenter|justifyRight/.test(command)) {
  522. iframeDOM.execCommand('formatBlock', false, '<p>');
  523. }
  524. setTimeout(function () {
  525. body.focus();
  526. }, 10);
  527. } else {
  528. toolEvent[events] && toolEvent[events].call(this, range);
  529. }
  530. toolCheck.call(iframeWin, tools, othis);
  531. }
  532. , isClick = /image/
  533. tools.find('>i').on('mousedown', function () {
  534. var othis = $(this)
  535. , events = othis.attr('layedit-event');
  536. if (isClick.test(events)) return;
  537. click.call(this)
  538. }).on('click', function () {
  539. var othis = $(this)
  540. , events = othis.attr('layedit-event');
  541. if (!isClick.test(events)) return;
  542. click.call(this)
  543. });
  544. //触发内容区域
  545. body.on('click', function () {
  546. toolCheck.call(iframeWin, tools);
  547. layer.close(face.index);
  548. });
  549. }
  550. //超链接面板
  551. , link = function (options, callback) {
  552. var body = this, index = layer.open({
  553. type: 1
  554. , id: 'LAY_layedit_link'
  555. , area: '350px'
  556. , shade: 0.05
  557. , shadeClose: true
  558. , moveType: 1
  559. , title: '超链接'
  560. , skin: 'layui-layer-msg'
  561. , content: ['<ul class="layui-form" style="margin: 15px;">'
  562. , '<li class="layui-form-item">'
  563. , '<label class="layui-form-label" style="width: 60px;">URL</label>'
  564. , '<div class="layui-input-block" style="margin-left: 90px">'
  565. , '<input name="url" lay-verify="url" value="' + (options.href || '') + '" autofocus="true" autocomplete="off" class="layui-input">'
  566. , '</div>'
  567. , '</li>'
  568. , '<li class="layui-form-item">'
  569. , '<label class="layui-form-label" style="width: 60px;">打开方式</label>'
  570. , '<div class="layui-input-block" style="margin-left: 90px">'
  571. , '<input type="radio" name="target" value="_self" class="layui-input" title="当前窗口"'
  572. + ((options.target === '_self' || !options.target) ? 'checked' : '') + '>'
  573. , '<input type="radio" name="target" value="_blank" class="layui-input" title="新窗口" '
  574. + (options.target === '_blank' ? 'checked' : '') + '>'
  575. , '</div>'
  576. , '</li>'
  577. , '<li class="layui-form-item" style="text-align: center;">'
  578. , '<button type="button" lay-submit lay-filter="layedit-link-yes" class="layui-btn"> 确定 </button>'
  579. , '<button style="margin-left: 20px;" type="button" class="layui-btn layui-btn-primary"> 取消 </button>'
  580. , '</li>'
  581. , '</ul>'].join('')
  582. , success: function (layero, index) {
  583. var eventFilter = 'submit(layedit-link-yes)';
  584. form.render('radio');
  585. layero.find('.layui-btn-primary').on('click', function () {
  586. layer.close(index);
  587. body.focus();
  588. });
  589. form.on(eventFilter, function (data) {
  590. layer.close(link.index);
  591. callback && callback(data.field);
  592. });
  593. }
  594. });
  595. link.index = index;
  596. }
  597. //表情面板
  598. , face = function (callback) {
  599. //表情库
  600. var faces = function () {
  601. var alt = ["[微笑]", "[嘻嘻]", "[哈哈]", "[可爱]", "[可怜]", "[挖鼻]", "[吃惊]", "[害羞]", "[挤眼]", "[闭嘴]", "[鄙视]", "[爱你]", "[泪]", "[偷笑]", "[亲亲]", "[生病]", "[太开心]", "[白眼]", "[右哼哼]", "[左哼哼]", "[嘘]", "[衰]", "[委屈]", "[吐]", "[哈欠]", "[抱抱]", "[怒]", "[疑问]", "[馋嘴]", "[拜拜]", "[思考]", "[汗]", "[困]", "[睡]", "[钱]", "[失望]", "[酷]", "[色]", "[哼]", "[鼓掌]", "[晕]", "[悲伤]", "[抓狂]", "[黑线]", "[阴险]", "[怒骂]", "[互粉]", "[心]", "[伤心]", "[猪头]", "[熊猫]", "[兔子]", "[ok]", "[耶]", "[good]", "[NO]", "[赞]", "[来]", "[弱]", "[草泥马]", "[神马]", "[囧]", "[浮云]", "[给力]", "[围观]", "[威武]", "[奥特曼]", "[礼物]", "[钟]", "[话筒]", "[蜡烛]", "[蛋糕]"], arr = {};
  602. layui.each(alt, function (index, item) {
  603. arr[item] = layui.cache.dir + 'images/face/' + index + '.gif';
  604. });
  605. return arr;
  606. }();
  607. face.hide = face.hide || function (e) {
  608. if ($(e.target).attr('layedit-event') !== 'face') {
  609. layer.close(face.index);
  610. }
  611. }
  612. return face.index = layer.tips(function () {
  613. var content = [];
  614. layui.each(faces, function (key, item) {
  615. content.push('<li title="' + key + '"><img src="' + item + '" alt="' + key + '"></li>');
  616. });
  617. return '<ul class="layui-clear">' + content.join('') + '</ul>';
  618. }(), this, {
  619. tips: 1
  620. , time: 0
  621. , skin: 'layui-box layui-util-face'
  622. , maxWidth: 500
  623. , success: function (layero, index) {
  624. layero.css({
  625. marginTop: -4
  626. , marginLeft: -10
  627. }).find('.layui-clear>li').on('click', function () {
  628. callback && callback({
  629. src: faces[this.title]
  630. , alt: this.title
  631. });
  632. layer.close(index);
  633. });
  634. $(document).off('click', face.hide).on('click', face.hide);
  635. }
  636. });
  637. }
  638. //插入代码面板
  639. , code = function (callback) {
  640. var body = this, index = layer.open({
  641. type: 1
  642. , id: 'LAY_layedit_code'
  643. , area: '550px'
  644. , shade: 0.05
  645. , shadeClose: true
  646. , moveType: 1
  647. , title: '插入代码'
  648. , skin: 'layui-layer-msg'
  649. , content: ['<ul class="layui-form layui-form-pane" style="margin: 15px;">'
  650. , '<li class="layui-form-item">'
  651. , '<label class="layui-form-label">请选择语言</label>'
  652. , '<div class="layui-input-block">'
  653. , '<select name="lang">'
  654. , '<option value="JavaScript">JavaScript</option>'
  655. , '<option value="HTML">HTML</option>'
  656. , '<option value="CSS">CSS</option>'
  657. , '<option value="Java">Java</option>'
  658. , '<option value="PHP">PHP</option>'
  659. , '<option value="C#">C#</option>'
  660. , '<option value="Python">Python</option>'
  661. , '<option value="Ruby">Ruby</option>'
  662. , '<option value="Go">Go</option>'
  663. , '</select>'
  664. , '</div>'
  665. , '</li>'
  666. , '<li class="layui-form-item layui-form-text">'
  667. , '<label class="layui-form-label">代码</label>'
  668. , '<div class="layui-input-block">'
  669. , '<textarea name="code" lay-verify="required" autofocus="true" class="layui-textarea" style="height: 200px;"></textarea>'
  670. , '</div>'
  671. , '</li>'
  672. , '<li class="layui-form-item" style="text-align: center;">'
  673. , '<button type="button" lay-submit lay-filter="layedit-code-yes" class="layui-btn"> 确定 </button>'
  674. , '<button style="margin-left: 20px;" type="button" class="layui-btn layui-btn-primary"> 取消 </button>'
  675. , '</li>'
  676. , '</ul>'].join('')
  677. , success: function (layero, index) {
  678. var eventFilter = 'submit(layedit-code-yes)';
  679. form.render('select');
  680. layero.find('.layui-btn-primary').on('click', function () {
  681. layer.close(index);
  682. body.focus();
  683. });
  684. form.on(eventFilter, function (data) {
  685. layer.close(code.index);
  686. callback && callback(data.field);
  687. });
  688. }
  689. });
  690. code.index = index;
  691. }
  692. //全部工具
  693. , tools = {
  694. html: '<i class="layui-icon layedit-tool-html" title="HTML源代码" lay-command="html" layedit-event="html"">&#xe64b;</i><span class="layedit-tool-mid"></span>'
  695. , strong: '<i class="layui-icon layedit-tool-b" title="加粗" lay-command="Bold" layedit-event="b"">&#xe62b;</i>'
  696. , italic: '<i class="layui-icon layedit-tool-i" title="斜体" lay-command="italic" layedit-event="i"">&#xe644;</i>'
  697. , underline: '<i class="layui-icon layedit-tool-u" title="下划线" lay-command="underline" layedit-event="u"">&#xe646;</i>'
  698. , del: '<i class="layui-icon layedit-tool-d" title="删除线" lay-command="strikeThrough" layedit-event="d"">&#xe64f;</i>'
  699. , '|': '<span class="layedit-tool-mid"></span>'
  700. , left: '<i class="layui-icon layedit-tool-left" title="左对齐" lay-command="justifyLeft" layedit-event="left"">&#xe649;</i>'
  701. , center: '<i class="layui-icon layedit-tool-center" title="居中对齐" lay-command="justifyCenter" layedit-event="center"">&#xe647;</i>'
  702. , right: '<i class="layui-icon layedit-tool-right" title="右对齐" lay-command="justifyRight" layedit-event="right"">&#xe648;</i>'
  703. , link: '<i class="layui-icon layedit-tool-link" title="插入链接" layedit-event="link"">&#xe64c;</i>'
  704. , unlink: '<i class="layui-icon layedit-tool-unlink layui-disabled" title="清除链接" lay-command="unlink" layedit-event="unlink"">&#xe64d;</i>'
  705. , face: '<i class="layui-icon layedit-tool-face" title="表情" layedit-event="face"">&#xe650;</i>'
  706. , image: '<i class="layui-icon layedit-tool-image" title="图片" layedit-event="image">&#xe64a;<input type="file" name="file"></i>'
  707. , image_alt: '<i class="layui-icon layedit-tool-image_alt" title="图片" layedit-event="image_alt">&#xe64a;</i>'
  708. , code: '<i class="layui-icon layedit-tool-code" title="插入代码" layedit-event="code">&#xe64e;</i>'
  709. , video: '<i class="layui-icon layedit-tool-video" title="插入视频" layedit-event="video">&#xe61f;</i>'
  710. , help: '<i class="layui-icon layedit-tool-help" title="帮助" layedit-event="help">&#xe607;</i>'
  711. }
  712. , edit = new Edit();
  713. exports(MOD_NAME, edit);
  714. });
  715. function stringToEntity(str, radix) {
  716. let arr = str.split('')
  717. radix = radix || 0
  718. let tmp = arr.map(item =>
  719. `&#${(radix ? 'x' + item.charCodeAt(0).toString(16) : item.charCodeAt(0))};`).join('')
  720. console.log(`'${str}' 转实体为 '${tmp}'`)
  721. return tmp
  722. }
  723. function entityToString(entity) {
  724. let entities = entity.split(';')
  725. entities.pop()
  726. let tmp = entities.map(item => String.fromCharCode(
  727. item[2] === 'x' ? parseInt(item.slice(3), 16) : parseInt(item.slice(2)))).join('')
  728. console.log(`'${entity}' 转字符串为 '${tmp}'`)
  729. return tmp
  730. }