Editor.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. //编辑器
  2. Namespace.register("U.MD.UI.editor");
  3. /* 默认编辑器,嵌入到指定元素内
  4. * @param parent {element} 创建在指定的父亲元素
  5. * @param callback {function} 非必传 操作处理函数
  6. * 操作处理函数 该函数默认第一个参数为操作记录。
  7. * 格式形如 : { updateLine : [修改行ID, 修改行ID,], addLine : [添加行ID], deleteLine : [删除行ID] }
  8. * */
  9. U.MD.UI.Editor = U.MD.UI.editor = function (parent, callback) {
  10. U.UF.DL.asynLoadCss({ "rel": "stylesheet", "type": "text/css", "href": "/css/Controls/Complex/Editor.css" });
  11. // parent.innerHTML = ''; //清空区域内容
  12. //!$(parent).find($('.editorBar'))[0] ? "" : U.selectEl('.editorBar').remove();
  13. //_div = $$("div", { "className": "editorBar" }, parent);
  14. //创建div
  15. U.MD.UI.editor.createEditor(parent);
  16. //创建编辑区域
  17. U.UF.E.initEditor($('.editor', parent)[0], callback);
  18. //初始化编辑区域
  19. U.MD.UI.editor.EditorEventBind(parent);
  20. //绑定事件
  21. U.MD.UI.editor.operateJson.editor = U.selectEl('.editor', parent)[0];
  22. //把编辑区域赋值给editor
  23. return U.MD.UI.editor.operateJson;
  24. //返回可操作集合
  25. }
  26. U.MD.UI.editor.operateJson = {
  27. /*
  28. * U.MD.UI.editor.loadContent 加载编辑器内容
  29. * param1 text(str) 需要加载的文本内容
  30. * */
  31. loadContent: function (text) {
  32. this.editor.focus();
  33. U.UF.E.onpaste(null, this.editor, text);
  34. // var _div = $$("div", { innerHTML: text, style: { display: "none"} }, document.body);
  35. // var _pdiv = U.UF.E.unifiedFormat(_div);
  36. // var _range = U.UF.E.getRangeAt();
  37. // var _block = U.UF.E.getLineElement(_range.startContainer);
  38. // for (var i = 0; i < _pdiv.children.length; i++) {
  39. // _block.parentElement.appendChild(_pdiv.children[i]);
  40. // }
  41. // U.selectEl(_block).remove();
  42. // U.selectEl(_div).remove();
  43. },
  44. /*
  45. * U.MD.UI.editor.getContent 得到编辑器内容
  46. * */
  47. getContent: function () {
  48. return this.editor.innerHTML;
  49. //直接返回编辑区域的内容
  50. }
  51. };
  52. /*
  53. U.MD.UI.editor.CreateEditor 创建HTML内容
  54. param1 parent(elemt)父元素
  55. */
  56. U.MD.UI.editor.createEditor = function (parent) {
  57. parent.innerHTML =
  58. "<div class='toolbar' style=\"width: 788px;background-color: #f5f5f5;border: 1px solid #c7d3e1;line-height: 0;padding: 6px;height: 25px;\">\n" +
  59. " <button class=\"last\" style=\"float: left;margin: 0 3px;position: relative;outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/left.png') no-repeat center;\">\n" +
  60. " </button>\n" +
  61. " <button class=\"future\" style=\"float: left;margin: 0 3px;position: relative;outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/right.png') no-repeat center;\">\n" +
  62. " </button>\n" +
  63. " <i style=\"display: inline-block;width: 1px;height: 22px;background-color: #bcbcbc;float: left;margin: 0 3px;position: relative;\">\n" +
  64. "\n" +
  65. " </i>\n" +
  66. "<div class='setFont' style='float: left;margin: 0 3px;position: relative;padding:0px'></div>" +
  67. " <i style=\"display: inline-block;width: 1px;height: 22px;background-color: #bcbcbc;float: left;margin: 0 3px;position: relative;\">\n" +
  68. "\n" +
  69. " </i>\n" +
  70. "<div class='setSize' style='float: left;margin: 0 3px;position: relative;padding:0px'></div>" +
  71. " <i style=\"display: inline-block;width: 1px;height: 22px;background-color: #bcbcbc;float: left;margin: 0 3px;position: relative;\">\n" +
  72. "\n" +
  73. " </i>\n" +
  74. " <label style=\"float: left;margin: 0 3px;position: relative;\">\n" +
  75. " <button class=\"pic\" style=\"outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/pic.png') no-repeat center;\">\n" +
  76. " </button>\n" +
  77. " <input multiple accept='image/*' type='file' class='picUpload' style='display: none;' onchange='U.UF.E.picture(this,this.parentNode.parentNode.nextSibling)' />\n" + //onchange='U.UF.E.picture(this)'
  78. " </label>\n" +
  79. " <label style=\"float: left;margin: 0 3px;position: relative;\">\n" +
  80. " <button class=\"attachment\" style=\"outline: none;cursor: pointer;border: 1px solid transparent;width: 25px;height: 25px;background: url(/img/YS2017.png) no-repeat;background-position: -1054px -593.5px;\"></button>\n" +
  81. " <input multiple=\"\" type=\"file\" class=\"attachmentUpload\" style=\"display: none;\" onchange='U.UF.E.attachment(this,this.parentNode.parentNode.nextSibling)' >\n" + //accept=\"image/*\"
  82. " </label>\n" +
  83. " <i style=\"display: inline-block;width: 1px;height: 22px;background-color: #bcbcbc;float: left;margin: 0 3px;position: relative;\">\n" +
  84. "\n" +
  85. " </i>\n" +
  86. " <div style=\"float: left;margin: 0 3px;position: relative;padding:0px\">\n" +
  87. " <button class=\"fontColor\" style=\"outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/fontColor.png') no-repeat center;\">\n" +
  88. " </button>\n" +
  89. " <div class='fontColorBar colorBar' style='display:none;position: absolute;'>\n" +
  90. " </div>\n" +
  91. " </div>\n" +
  92. " <i style=\"display: inline-block;width: 1px;height: 22px;background-color: #bcbcbc;float: left;margin: 0 3px;position: relative;\">\n" +
  93. "\n" +
  94. " </i>\n" +
  95. " <div style=\"float: left;margin: 0 3px;position: relative;padding:0px\">\n" +
  96. " <button class=\"backgroundColor\" style=\"outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/blockColor.png') no-repeat center;\">\n" +
  97. " </button>\n" +
  98. " <div class='backgroundColorBar colorBar' style='display:none;position: absolute;'>\n" +
  99. " </div>\n" +
  100. " </div>\n" +
  101. " <i style=\"display: inline-block;width: 1px;height: 22px;background-color: #bcbcbc;float: left;margin: 0 3px;position: relative;\">\n" +
  102. "\n" +
  103. " </i>\n" +
  104. " <button class=\"bIcon\" style=\"float: left;margin: 0 3px;position: relative;outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/strong.png') no-repeat center;\">\n" +
  105. " </button>\n" +
  106. " <button class=\"iIcon\" style=\"float: left;margin: 0 3px;position: relative;outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/i.png') no-repeat center;\">\n" +
  107. " </button>\n" +
  108. " <button class=\"UIcon\" style=\"float: left;margin: 0 3px;position: relative;outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/x.png') no-repeat center;\">\n" +
  109. " </button>\n" +
  110. " <button class=\"SIcon\" style=\"float: left;margin: 0 3px;position: relative;outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/-S-.png') no-repeat center;\">\n" +
  111. " </button>\n" +
  112. " <i style=\"display: inline-block;width: 1px;height: 22px;background-color: #bcbcbc;float: left;margin: 0 3px;position: relative;\">\n" +
  113. "\n" +
  114. " </i>\n" +
  115. " <button class=\"textLeft\" style=\"float: left;margin: 0 3px;position: relative;outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/textLeft.png') no-repeat center;\">\n" +
  116. " </button>\n" +
  117. " <button class=\"textCenter\" style=\"float: left;margin: 0 3px;position: relative;outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/textCenter.png') no-repeat center;\">\n" +
  118. " </button>\n" +
  119. " <button class=\"textRight\" style=\"float: left;margin: 0 3px;position: relative;outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/textRight.png') no-repeat center;\">\n" +
  120. " </button>\n" +
  121. " <i style=\"display: inline-block;width: 1px;height: 22px;background-color: #bcbcbc;float: left;margin: 0 3px;position: relative;\" >\n" +
  122. "\n" +
  123. " </i>\n" +
  124. " <button class=\"a\" style=\"float: left;margin: 0 3px;position: relative;outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/a.png') no-repeat center;\">\n" +
  125. " </button>\n" +
  126. " <button class=\"b\" style=\"float: left;margin: 0 3px;position: relative;outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/b.png') no-repeat center;\">\n" +
  127. " </button>\n" +
  128. " <button class=\"c\" style=\"float: left;margin: 0 3px;position: relative;outline: none;cursor: pointer;border: 1px solid transparent;height: 25px;width: 25px;background: url('/EditorImage/c.png') no-repeat center;\">\n" +
  129. " </button>\n" +
  130. " </div>\n" +
  131. " <div class=\"editor\" contenteditable=\"true\" style=\"width: 800px;min-height: 300px;border: 1px solid #E6E5E5;overflow: auto;\">\n" +
  132. " </div>";
  133. //以下代码只能跑一次,导致只能上传一张图片,因此必须把onchange固化到html代码中。
  134. //解决方法一,<input multiple accept='image/*' type='file' class='picUpload' style='display: none;' onchange='U.UF.E.picture(this,this.parentNode.parentNode.nextSibling)' />\n" + //onchange='U.UF.E.picture(this)'
  135. //解决方法二:用纯碎的js重写上面的html编码。暂时未实现。
  136. /*$('input.picUpload[type="file"]', parent)[0].onchange = function () {
  137. U.UF.E.picture(this, U.selectEl('.editor', parent)[0])
  138. }
  139. U.selectEl('input.attachmentUpload[type="file"]', parent)[0].onchange = function () {
  140. U.UF.E.attachment(this, U.selectEl('.editor', parent)[0])
  141. }*/
  142. //注释:在js中写如下语句,只能触发一次,因此把语句固化到html中。
  143. //找到上传图片的input控件
  144. /* var _upImgInput = U.selectEl('input.picUpload[type="file"]', parent)[0];
  145. _upImgInput.onchange = function () {
  146. //找到编辑区域,此处分开写,不然调试太费力。
  147. var _editor = U.selectEl('.editor', parent)[0];
  148. U.UF.E.picture(this, _editor);
  149. _upImgInput.value = "";
  150. }
  151. //找到上传文件的input控件
  152. var _upFileInput = U.selectEl('input.attachmentUpload[type="file"]', parent)[0];
  153. _upFileInput.onchange = function () {
  154. //找到编辑区域,此处分开写,不然调试太费力。
  155. var _editor = U.selectEl('.editor', parent)[0];
  156. U.UF.E.attachment(this, _editor);
  157. _upFileInput.value = "";
  158. }*/
  159. };
  160. /*
  161. U.MD.UI.editor.EditorEventBind 创建绑定事件
  162. param1 parent(elemt) 范围
  163. */
  164. U.MD.UI.editor.EditorEventBind = function (parent) {
  165. //绑定图片拉伸
  166. // U.UF.E.key($('.editor', parent));
  167. //绑定键盘事件
  168. var _font = U.MD.UI.Font();
  169. //生成字体下拉框
  170. _font.style.cssText += "vertical-align: super;";
  171. var _size = U.MD.UI.WordSize();
  172. //生成字体大小下拉框
  173. _size.style.cssText += "vertical-align: super;";
  174. U.selectEl('.setFont', parent).append(_font);
  175. _font.onchange = function () {
  176. U.UF.E.setRangeStyle({ 'font-family': _font.value });
  177. };
  178. //设置字体样式
  179. U.selectEl('.setSize', parent).append(_size);
  180. _size.onchange = function () {
  181. U.UF.E.setRangeStyle({ 'font-size': _size.value });
  182. };
  183. //设置图片上传点击
  184. U.selectEl('.pic', parent)[0].onclick = function () {
  185. U.selectEl('.picUpload', parent)[0].click();
  186. };
  187. //设置附件上传点击
  188. U.selectEl('.attachment', parent)[0].onclick = function () {
  189. U.selectEl('.attachmentUpload', parent)[0].click();
  190. };
  191. //图片点击
  192. U.selectEl('.bIcon', parent)[0].onclick = function () {
  193. U.UF.E.setRangeStyle({ 'font-weight': 'bold' });
  194. };
  195. //加粗
  196. U.selectEl('.iIcon', parent)[0].onclick = function () {
  197. U.UF.E.setRangeStyle({ 'font-style': 'italic' });
  198. };
  199. //斜体
  200. U.selectEl('.UIcon', parent)[0].onclick = function () {
  201. U.UF.E.setRangeStyle({ 'text-decoration': 'underline' });
  202. };
  203. //下划线
  204. U.selectEl('.SIcon', parent)[0].onclick = function () {
  205. U.UF.E.setRangeStyle({ 'text-decoration': 'line-through' });
  206. };
  207. //删除线
  208. U.selectEl('.fontColor', parent).bind('click', function () {
  209. //修改字体颜色
  210. if ($('.fontColorBar', parent).css('display') == "none") {
  211. U.MD.UI.colorPicker($('.fontColorBar', parent)[0], function (r) {
  212. U.selectEl('.MD_ColorPicker', U.selectEl('.fontColorBar', parent)[0]).remove();
  213. U.selectEl('.fontColorBar', parent).hide();
  214. U.UF.E.setRangeStyle({ 'color': r });
  215. });
  216. U.selectEl('.fontColorBar', parent).show();
  217. }
  218. });
  219. U.selectEl('.backgroundColor', parent).bind('click', function () {
  220. //修改背景颜色
  221. if ($('.backgroundColorBar', parent).css('display') == "none") {
  222. U.MD.UI.colorPicker($('.backgroundColorBar', parent)[0], function (r) {
  223. U.selectEl('.MD_ColorPicker', U.selectEl('.backgroundColorBar', parent)[0]).remove();
  224. U.selectEl('.backgroundColorBar', parent).hide();
  225. U.UF.E.setRangeStyle({ 'backgroundColor': r });
  226. });
  227. U.selectEl('.backgroundColorBar', parent).show();
  228. }
  229. });
  230. // U.selectEl('.upload', parent)[0].onchange = function () {
  231. // U.UF.E.picture(this);
  232. //// 上传图片
  233. // var _this = this;
  234. // U.UF.UP.inputUpload([_this], 'http://disk.1473.cn/USUpfile.ashx?typename=UseStudioEditor&UserId=FA92AAC5-4134-449F-9659-0DC12F4F68E9', function (r) {
  235. // var img = '<img style="max-width: 80%;" src="http://fs.1473.cn/' + r.value[0] + '">';
  236. // U.UF.E.addRange(img);
  237. // _this.value = '';
  238. // });
  239. // }
  240. /*$('.editor', parent)[0].onpaste = function (e) {
  241. //绑定粘贴
  242. var _text = e.clipboardData.getData('text/html') || event.clipboardData.getData("text/plain");
  243. var _div = $$("div", { innerHTML: _text, style: { display: "none"} }, document.body);
  244. U.UF.E.unifiedFormat(_div);
  245. document.body.removeChild(_div);
  246. };*/
  247. U.selectEl('.a', parent).bind('click', function () {
  248. U.UF.E.addHref();
  249. });
  250. //添加a标签
  251. U.selectEl('.c', parent).bind('click', function () {
  252. U.UF.E.clearStyle(U.UF.E.getRangeAt());
  253. });
  254. //清除格式
  255. U.selectEl('.textLeft', parent).bind('click', function () {
  256. U.UF.E.setLineStyle({ 'text-align': 'left' });
  257. });
  258. //居左
  259. U.selectEl('.textCenter', parent).bind('click', function () {
  260. U.UF.E.setLineStyle({ 'text-align': 'center' });
  261. });
  262. //居中
  263. U.selectEl('.textRight', parent).bind('click', function () {
  264. U.UF.E.setLineStyle({ 'text-align': 'right' });
  265. });
  266. //居右
  267. };
  268. /**
  269. * 下拉框
  270. * @param choosecon 【object】必选 若需要value值使用集合({'11111111':'aaaaaaaa','2222222':'bbbbbbbb','33333333':'cccccccc'})键名为value值
  271. * @param selattr 【object】必选 设置最外层div的属性值
  272. * @param optionevent 【function】必选 给每个选择区域的点击后回调函数,参数一:value值或者文本值
  273. * @param parentnode 【element】可选 添加到里面的元素
  274. * @returns {*} 【element】 返回出创建好的下拉控件
  275. * @constructor
  276. */
  277. U.MD.UI.editor.Select = function (choosecon, selattr, optionevent, parentnode) {
  278. var _id = "";
  279. selattr.id && (_id = selattr.id) && (delete selattr.id);
  280. var _selectEl = $$('div', { id: _id }, parentnode || null), //创建最外层
  281. _value = $$('div', selattr, _selectEl),
  282. _textarea = $$('div', {}, _value); //创建最第二层
  283. $$('div', { style: { cssText: 'border-width: 6px 4px; border-style: solid; border-color: rgb(166, 178, 192) transparent transparent; width: 0; position: absolute; right: 4px; top: 50%; margin-top: -3px'} }, _value); //小三角
  284. //_text = $$('div', { style: { cssText: "padding-left: 6px; overflow: hidden; height:100%;cursor: pointer;"} }, _textarea), //创建显示文本内容div
  285. var _con = $$('div', {
  286. datacontent: '',
  287. style: { cssText: 'display: none;position: absolute; margin-top:-1px; min-width: 100%; max-width: 280px; max-height: 200px ;border: 1px solid silver; overflow-x: hidden; cursor: pointer;' }
  288. }, _selectEl), //创建选择区域
  289. _range;
  290. /*默认属性*/
  291. // !selattr.style.border ? _selectEl.style.border = '1px solid #000' : '';
  292. // !selattr.style.background ? _selectEl.style.background = '#fff' : '';
  293. // !selattr.style.width ? _selectEl.style.width = "122px" : '';
  294. // !selattr.style.height ? _selectEl.style.height = '24px' : '';
  295. (selattr.style && !selattr.style.position) ? _selectEl.style.position = 'relative' : '';
  296. (selattr.style && !selattr.style.textIndent) ? _textarea.style.textIndent = '6px' : '';
  297. // !selattr.style.overflow ? _selectEl.style.overflow = 'hidden' : '';
  298. _textarea.style.whiteSpace = 'pre';
  299. _textarea.style.overflow = 'hidden'
  300. _textarea.style.width = _selectEl.offsetWidth - 15 + "px";
  301. for (var i in choosecon) { //循环集合
  302. $$('div', {
  303. value: i, innerText: choosecon[i], //创建选择内容
  304. style: { cssText: 'padding: 4px 6px; background: #fff' },
  305. onmouseover: function () { /*绑定光标移入事件*/
  306. this.style.background = '#ccc'
  307. },
  308. onmouseout: function () { /*绑定光标移除事件*/
  309. this.style.background = '#fff'
  310. }, onclick: function () { /*绑定点击事件*/
  311. _textarea.innerText = this.innerText; /*改变问题*/
  312. U.UF.E.reSelectRange(_range) /*重新聚焦光标*/
  313. optionevent(this.value || this.innerText); /*回调*/
  314. }
  315. }, _con);
  316. }
  317. for (var i in choosecon) {// 第一个及默认值
  318. _textarea.innerText = choosecon[i];
  319. break;
  320. }
  321. _textarea.style.lineHeight = parseInt(_textarea.style.height) + 'px'; //使显示文本居中
  322. _selectEl.onclick = function () { //绑定点击事件
  323. var _el = this.querySelector('div[datacontent]');
  324. U.UF.E.reSelectRange(_range) /*重新聚焦光标*/
  325. _el.style.display === 'block' ? _el.style.display = 'none' : _el.style.display = 'block'; /*显示隐藏*/
  326. };
  327. U.selectEl(document).bind('click', function () { /*绑定事件*/
  328. if (_con.style.display != 'none')
  329. _con.style.display = 'none'
  330. if ($(".BD_BorderPicker")[0]) {
  331. if ($(".BD_BorderPicker")[0].style.display != 'none')
  332. U.selectEl(".BD_BorderPicker")[0].style.display = 'none'
  333. }
  334. }, false);
  335. U.selectEl(_selectEl).bind('click', function (e) { /*绑定事件*/
  336. U.UF.EV.stopBubble(e);
  337. //阻止事件冒泡
  338. });
  339. _selectEl.onmousedown = function () { /*绑定事件*/
  340. _range = U.UF.E.getRangeAt() /*获取光标位置*/
  341. }
  342. return _selectEl; //返回创建元素
  343. };