Eleditor.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935
  1. /**
  2. * Version: 1.8.9
  3. * Title: Eleditor 移动端富文本编辑器
  4. * Site: https://eleditor.fixel.cn
  5. * Doc: http://doc.eleditor.fixel.cn
  6. * Author: Try
  7. */
  8. (function(w){
  9. /*polyfill*/
  10. if (typeof Object.assign != 'function') {
  11. // Must be writable: true, enumerable: false, configurable: true
  12. Object.defineProperty(Object, "assign", {
  13. value: function assign(target, varArgs) { // .length of function is 2
  14. 'use strict';
  15. if (target == null) { // TypeError if undefined or null
  16. throw new TypeError('Cannot convert undefined or null to object');
  17. }
  18. var to = Object(target);
  19. for (var index = 1; index < arguments.length; index++) {
  20. var nextSource = arguments[index];
  21. if (nextSource != null) { // Skip over if undefined or null
  22. for (var nextKey in nextSource) {
  23. // Avoid bugs when hasOwnProperty is shadowed
  24. if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
  25. to[nextKey] = nextSource[nextKey];
  26. }
  27. }
  28. }
  29. }
  30. return to;
  31. },
  32. writable: true,
  33. configurable: true
  34. });
  35. }
  36. var _debug = false;
  37. var _version = '1.8.9'
  38. var _namespace = 'Eleditor';
  39. var _notctname = ['INPUT', 'IMG', 'TEXTAREA'];
  40. var _toolnames = {
  41. insertText: '插文字',
  42. insertImage: '插图片',
  43. insertLink: '插链接',
  44. insertHr: '水平线',
  45. editText: '改文字',
  46. "delete": '删除',
  47. undo: '撤销',
  48. cancel: '取消',
  49. };
  50. var _editorTpl = '';
  51. w[_namespace] = function(){};
  52. if( typeof jQuery === 'undefined' && typeof Zepto === 'undefined' ){
  53. return console.warn('|--Eleditor 请引入jQuery或者Zepto!模块化环境请把依赖全局安装');
  54. }else if( typeof $ === 'undefined' ){
  55. var $ = typeof jQuery != 'undefined' ? jQuery : Zepto;
  56. }
  57. var _scriptPath = function(func){
  58. var _js = document.scripts;
  59. _js = _js[ _js.length - 1 ].src.substring(0, _js[ _js.length-1 ].src.lastIndexOf("/") + 1 );
  60. func(_js);
  61. return _js;
  62. }(function(s){
  63. var _buildLib = '<link rel="stylesheet" href="https://www.shangxueshe.cn/static/js/layout/base.css?v='+(_debug ? (+new Date()) : _version)+'">';
  64. $('head').append(_buildLib);
  65. });
  66. var _inArray = function(s,a){
  67. for(var i in a){
  68. if(a[i]==s){
  69. return true;
  70. }
  71. }
  72. return false;
  73. };
  74. var _formatInnerText = function (t) {
  75. var s = t.replace(/\ +/g, "");
  76. s = s.replace(/[ ]/g, "");
  77. s = s.replace(/[\r\n]/g, "");
  78. return s.replace(/(^\s*)|(\s*$)/g, "");
  79. };
  80. var _getLayerMaxZIndex = function(){
  81. var _max = Math.max.apply(null,
  82.   $.map($('body *'), function(e) {
  83. var _$e = $(e);
  84. if (_$e.css('position') != 'static')
  85. return parseInt(_$e.css('z-index')) || 1;
  86. }));
  87. return (_max + '').indexOf('Infinity') >= 0 ? 1 : _max + 1;
  88. };
  89. var _genEditorUid = function(){
  90. return _namespace + '' + +new Date;
  91. };
  92. var _correctHtmlStructure = function(){
  93. var _$wrap = arguments[0],
  94. _empty = arguments[1];
  95. $.each(_$wrap.find('iframe,audio,video'), function() {
  96. var _$this = $(this),
  97. _tagName = this.tagName.toLocaleLowerCase();
  98. if( !_$this.parent().hasClass('Eleditor-'+_tagName+'-area') ){
  99. $(this).wrap('<div class="Eleditor-'+_tagName+'-area"></div>');
  100. }
  101. });
  102. if( _formatInnerText(_$wrap.text()) == '' && _$wrap.find('img,iframe,video').length === 0 ){
  103. _$wrap.append(_empty);
  104. }
  105. if( _$wrap.find('*').length === 0 ){
  106. _$wrap.html('<p class="Eleditor-placeholder">'+_$wrap.html()+'</p>');
  107. }
  108. };
  109. var _buildEditorModule = function(_toolbars, _uid){
  110. var _layerZIndex = _getLayerMaxZIndex();
  111. var _html = '<div class="Eleditor-wrap" style="z-index:'+_layerZIndex+'" id="'+_uid+'">\
  112. <div class="Eleditor-controller">\
  113. <ul>';
  114. for (var i = 0; i < _toolbars.length; i++) {
  115. var _it = _toolbars[i],
  116. _id = typeof _it === 'object' ? _it.id : _it,
  117. _tag = (typeof _it === 'object' && _it.tag) ? _it.tag.toLocaleLowerCase() : null,
  118. _name = typeof _it === 'object' ? _it.name : _toolnames[_it];
  119. _html += '<li event="'+_id+'" '+(_tag ? 'bind-tags="'+_tag+'"' : '')+' class="Eleditor-'+_id+'">'+_name+'</li>';
  120. }
  121. _html += ' </ul>\
  122. </div>\
  123. <div class="Eleditor-loading"><p></p></div>\
  124. <div class="Eleditor-textEditor">\
  125. <div class="Eleditor-textStyle">\
  126. <div class="Eleditor-textStyle-item"><div class="Eleditor-textStyle-bold"></div></div>\
  127. <div class="Eleditor-textStyle-item"><div class="Eleditor-textStyle-color"><span></span></div></div>\
  128. <div class="Eleditor-textStyle-item"><div class="Eleditor-textStyle-linedecoration"></div></div>\
  129. <div class="Eleditor-textStyle-item"><div class="Eleditor-textStyle-bgColor"></div></div>\
  130. <div class="Eleditor-textStyle-item"><div class="Eleditor-textStyle-fontSize"></div></div>\
  131. <div class="Eleditor-textStyle-item"><div class="Eleditor-textStyle-lineHeight"></div></div>\
  132. <div class="Eleditor-textStyle-item">\
  133. <div class="Eleditor-textStyle-align Eleditor-textStyle-alignLeft" align="left"></div>\
  134. </div>\
  135. <div class="Eleditor-textStyle-item">\
  136. <div class="Eleditor-textStyle-align Eleditor-textStyle-alignCenter" align="center">\
  137. </div>\
  138. </div>\
  139. <div class="Eleditor-textStyle-item">\
  140. <div class="Eleditor-textStyle-align Eleditor-textStyle-alignRight" align="right">\
  141. </div>\
  142. </div>\
  143. <div class="Eleditor-textStyle-item Eleditor-textStyle-item-upImg">\
  144. <div class="Eleditor-textStyle-upImg"></div>\
  145. </div>\
  146. </div>\
  147. <div class="Eleditor-textEditor-colors">\
  148. <div class="Eleditor-textEditor-modulePane"><span></span></div>\
  149. <ul>\
  150. <li><span style="background-color:#232323;"></span></li>\
  151. <li><span style="background-color:#2196F3;"></span></li>\
  152. <li><span style="background-color:#795548;"></span></li>\
  153. <li><span style="background-color:#00BCD4;"></span></li>\
  154. <li><span style="background-color:#4CAF50;"></span></li>\
  155. <li><span style="background-color:#E666E5;"></span></li>\
  156. <li><span style="background-color:#FF9800;"></span></li>\
  157. <li><span style="background-color:#FF5722;"></span></li>\
  158. <li><span style="background-color:#ff2a1a;"></span></li>\
  159. <li><span style="background-color:#FFEB3B;"></span></li>\
  160. <li><span style="background-color:#ffffff;border: 1px solid #ccc;"></span></li>\
  161. <li>\
  162. <span class="Eleditor-inheritValue" style="background-color:transparent; border: 1px solid #dedede;">\
  163. </span>\
  164. </li>\
  165. </ul>\
  166. </div>\
  167. <div class="Eleditor-textEditor-fontsizes">\
  168. <div class="Eleditor-textEditor-modulePane"><span>字体大小</span></div>\
  169. <ul>\
  170. <li class="Eleditor-inheritValue">默认</li>\
  171. <li>14px</li>\
  172. <li>16px</li>\
  173. <li>20px</li>\
  174. <li>28px</li>\
  175. <li>35px</li>\
  176. </ul>\
  177. </div>\
  178. <div class="Eleditor-textEditor-lineheight">\
  179. <div class="Eleditor-textEditor-modulePane"><span>行高</span></div>\
  180. <ul>\
  181. <li class="Eleditor-inheritValue">默认</li>\
  182. <li>20px</li>\
  183. <li>25px</li>\
  184. <li>30px</li>\
  185. <li>35px</li>\
  186. <li>40px</li>\
  187. </ul>\
  188. </div>\
  189. <div class="Eleditor-textEditor-linedecorations">\
  190. <div class="Eleditor-textEditor-modulePane"><span>文本修饰</span></div>\
  191. <ul>\
  192. <li class="Eleditor-inheritValue">无</li>\
  193. <li style="text-decoration: overline">上划线修饰</li>\
  194. <li style="text-decoration: line-through">删除线修饰</li>\
  195. <li style="text-decoration: underline">下划线修饰</li>\
  196. </ul>\
  197. </div>\
  198. <div class="Eleditor-textEditor-formats">\
  199. <div class="Eleditor-textEditor-format"></div>\
  200. <div class="Eleditor-textEditor-clean"></div>\
  201. </div>\
  202. <div class="Eleditor-inputarea">\
  203. <input placeholder="请输入超链接" type="text" />\
  204. <div placeholder="点击输入内容" class="textarea" contenteditable="true"></div>\
  205. </div>\
  206. <div class="Eleditor-method">\
  207. <button class="Eleditor-commit">提交</button>\
  208. <button class="Eleditor-cancel">取消</button>\
  209. </div>\
  210. </div>\
  211. <div class="Eleditor-delete-layer" style="z-index:'+_layerZIndex+'">\
  212. <div class="Eleditor-delete-tip">进入批量删除模式,点击段落进行删除</div>\
  213. <div class="Eleditor-delete-revoke"></div>\
  214. <div class="Eleditor-delete-clear"></div>\
  215. <div class="Eleditor-delete-back">返回继续编辑</div>\
  216. </div>\
  217. </div>';
  218. return _html;
  219. };
  220. w[_namespace] = function(){
  221. console.log('|--Eleditor Initing');
  222. var _args = arguments[0];
  223. _args.upload = _args.upload || {};
  224. _args.mounted = _args.mounted || function(){};
  225. _args.changer = _args.changer || function(){};
  226. _args.toolbars = _args.toolbars || [],
  227. // _undolen = isNaN(_args._undolen) ? 10 : _args._undolen;
  228. _editorUid = _genEditorUid(),
  229. _historys = [],
  230. _placeHolder = _args.placeHolder || '<p class="Eleditor-placeholder">点击此处编辑内容</p>',
  231. _uploadRole = null;
  232. if( _args.toolbars.length === 0 ){
  233. _args.toolbars = [
  234. 'insertText',
  235. 'editText',
  236. 'insertImage',
  237. 'insertLink',
  238. 'insertHr',
  239. 'delete',
  240. 'undo',
  241. 'cancel',
  242. ];
  243. }
  244. if( _args.el instanceof jQuery ){
  245. var _$wrap = _args.el;
  246. }else{
  247. var _$wrap = $(_args.el);
  248. if( _$wrap.length === 0 ){
  249. return console.warn('|--Eleditor '+_args.el+'元素不存在,请在DOMContentLoaded后初始化Eleditor');
  250. }else if( _$wrap.length != 1 ){
  251. var _$wrap = $(_$wrap[0]);
  252. }
  253. }
  254. if( _$wrap.attr('Eleditor-Inited') === 'true' ){
  255. return console.warn('|--Eleditor '+_args.el+'已经绑定了Eleditor');
  256. }
  257. _$wrap.attr({'Eleditor-Inited': 'true', 'Eleditor-Uid': _editorUid});
  258. _correctHtmlStructure(_$wrap, _placeHolder);
  259. /*insert editor*/
  260. var _lastScrollH = null;
  261. var _$window = $(w);
  262. var _$scrollWrap = $('html,body');
  263. var _$editorWrap = $(_buildEditorModule(_args.toolbars, _editorUid));
  264. var _$editorController = _$editorWrap.find('.Eleditor-controller');
  265. var _$editorLoadingMask = _$editorWrap.find('.Eleditor-loading');
  266. var _$editorTextModule = _$editorWrap.find('.Eleditor-textEditor');
  267. var _$editorTextArea = _$editorTextModule.find(".Eleditor-inputarea .textarea");
  268. var _$editorUploadImageBtn = _$editorController.find(".Eleditor-insertImage");
  269. var _$editorBarUploadImageBtn = _$editorTextModule.find('.Eleditor-textStyle-item-upImg');
  270. var _$editorTextLinkArea = _$editorTextModule.find(".Eleditor-inputarea input");
  271. var _$editorColorModule = _$editorTextModule.find(".Eleditor-textEditor-colors");
  272. var _$editorFontsizeModule = _$editorTextModule.find(".Eleditor-textEditor-fontsizes");
  273. var _$editorUndoBtn = _$editorWrap.find(".Eleditor-undo");
  274. var _$editorLineheightModule = _$editorTextModule.find(".Eleditor-textEditor-lineheight");
  275. var _$editorLinedecorationsModule = _$editorTextModule.find(".Eleditor-textEditor-linedecorations");
  276. var _$editorDeleteLayer = _$editorWrap.find(".Eleditor-delete-layer");
  277. _$wrap.addClass('Eleditor-area');
  278. _$wrap.after(_$editorWrap);
  279. console.log('|--Eleditor Mounted To', _$wrap);
  280. /*bindEvent*/
  281. var _$selected = null,
  282. _imageUploader = null;
  283. var _showEditorControllerLayer = function(_$e){
  284. _$selected = _$e;
  285. _$e.addClass('Eleditor-active');
  286. var _calTop = _$e.offset().top + _$e.outerHeight();
  287. $.each(_$editorController.find('li'), function(i, e){
  288. var _$e = $(e),
  289. _tgs = _$e.attr('bind-tags');
  290. if( _tgs ){
  291. _tgs = _tgs.toLocaleLowerCase().split(',');
  292. if( _inArray(_$selected[0].tagName.toLocaleLowerCase(), _tgs) ){
  293. _$e.show();
  294. }else{
  295. _$e.hide();
  296. }
  297. }
  298. });
  299. _$editorController.show();
  300. _flushEditorControllerLayerPosi();
  301. if( typeof _$scrollWrap.animate === 'function' ){
  302. _$scrollWrap.stop().animate({scrollTop: (_calTop - 150) + 'px'}, 500);
  303. }else{
  304. _$scrollWrap.scrollTop((_calTop - 150) + 'px');
  305. }
  306. _imageUploader && _imageUploader.refresh();
  307. };
  308. var _flushEditorControllerLayerPosi = function(){
  309. if( _$selected ){
  310. _$editorController.css({
  311. top: _$selected.offset().top + _$selected.outerHeight(),
  312. width: _$wrap.width() - 5
  313. });
  314. }
  315. },
  316. _hideEditorControllerLayer = function(){
  317. _$wrap.find('.Eleditor-active').removeClass('Eleditor-active');
  318. _$editorController.hide();
  319. _$selected = null;
  320. };
  321. var _showEditorDeleteLayer = function(){
  322. _flushEditorDeleteLayerHistoryBtn();
  323. _$wrap.addClass('Eleditor-deleteMode');
  324. _$editorDeleteLayer.show();
  325. },
  326. _flushEditorDeleteLayerHistoryBtn = function(){
  327. if( _historys.length > 0 ){
  328. _$editorWrap.find('.Eleditor-delete-revoke').removeClass('Eleditor-delete-revoke-disabled')
  329. }else{
  330. _$editorWrap.find('.Eleditor-delete-revoke').addClass('Eleditor-delete-revoke-disabled')
  331. }
  332. },
  333. _hideEditorDeleteLayer = function(){
  334. _$wrap.removeClass('Eleditor-deleteMode');
  335. _$editorDeleteLayer.hide();
  336. };
  337. var _showEditorWrapMask = function(){
  338. _$editorController.hide();
  339. _$editorWrap.addClass('Eleditor-mask');
  340. _lastScrollH = _$window.scrollTop();
  341. _$scrollWrap.addClass('Eleditor-scrollLocked');
  342. },
  343. _hideEditorWrapMask = function(){
  344. _$editorWrap.removeClass('Eleditor-mask');
  345. _$scrollWrap.removeClass('Eleditor-scrollLocked');
  346. _$window.scrollTop(_lastScrollH);
  347. };
  348. var _showLoadingMask = function(){
  349. _showEditorWrapMask();
  350. _$editorLoadingMask.show();
  351. _$editorLoadingMask.html('<p>'+arguments[0]+'</p>')
  352. },
  353. _hideLoadingMask = function(){
  354. _hideEditorWrapMask();
  355. _$editorLoadingMask.hide();
  356. };
  357. var _appendHistory = function(){
  358. _historys.push( _$wrap.html() );
  359. // if( _historys.length > _undolen ){
  360. // _historys.splice(0, 1)
  361. // }
  362. _flushHistoryBtn();
  363. _flushEditorDeleteLayerHistoryBtn();
  364. return true;
  365. },
  366. _revokeEdit = function(){
  367. if( _historys.length === 0 ){
  368. return;
  369. }
  370. _$wrap.html(_historys.pop());
  371. _args.changer();
  372. _flushHistoryBtn();
  373. _flushEditorDeleteLayerHistoryBtn();
  374. _hideEditorControllerLayer();
  375. },
  376. _flushHistoryBtn = function(){
  377. if( _historys.length == 0 ){
  378. _$editorUndoBtn.hide();
  379. }else{
  380. _$editorUndoBtn.show();
  381. }
  382. };
  383. var _syncRenderTextEditorView = function(){
  384. _$editorTextModule.attr('role', 'edit').show();
  385. _$editorTextArea.html( _$selected.hasClass('Eleditor-placeholder') ? '' : _$selected.html() );
  386. _$editorTextArea.attr('style', _$selected.attr('style'));
  387. if( _$selected.css('font-weight') == 'bold' ){
  388. _$editorTextModule.find('.Eleditor-textStyle-bold').addClass('Eleditor-active');
  389. }
  390. if( _inArray(_$selected.css('text-decoration'), ['overline', 'line-through', 'underline']) ){
  391. _$editorTextModule.find('.Eleditor-textStyle-linedecoration').addClass('Eleditor-active');
  392. }
  393. if( _$selected[0].tagName == 'A' ){
  394. _$editorTextModule.attr('type', 'link');
  395. _$editorTextLinkArea.val(_$selected.attr('href'));
  396. }else{
  397. _$editorTextModule.attr('type', 'word');
  398. }
  399. var _selectAlign = _$selected.css('text-align');
  400. if( _inArray(_selectAlign, ['left', 'center', 'right']) ){
  401. _$editorTextModule.find('.Eleditor-textStyle-align[align='+_selectAlign+']').addClass('Eleditor-active');
  402. }else{
  403. _$editorTextModule.find('.Eleditor-textStyle-align').removeClass('Eleditor-active');
  404. }
  405. _$editorTextModule.find('.Eleditor-textStyle-color span').css('background-color', _$selected.css('color'));
  406. };
  407. if( typeof WebUploader != 'undefined' && typeof _args.uploader != 'function' ){
  408. //controller
  409. _imageUploader = WebUploader.create({
  410. auto: true,
  411. server: _args.upload.server || '/upload',
  412. pick: _$editorUploadImageBtn,
  413. resize: false,
  414. headers: _args.upload.headers || {},
  415. formData: _args.upload.formData || {},
  416. duplicate: true,
  417. fileSingleSizeLimit: _args.upload.fileSizeLimit ? _args.upload.fileSizeLimit*1024*1024 : undefined,
  418. accept: Object.assign({
  419. title: 'Images',
  420. extensions: 'gif,jpg,jpeg,bmp,png,webp',
  421. mimeTypes: 'image/gif,image/jpg,image/jpeg,image/bmp,image/png,image/webp'
  422. }, _args.upload.accept || {}),
  423. fileVal: _args.upload.formName,
  424. });
  425. _imageUploader.on( 'uploadStart', function( _file, _percentage ) {
  426. _showLoadingMask('上传图片中<span id="uploadProgress">1</span>%');
  427. });
  428. _imageUploader.on( 'uploadProgress', function( _file, _percentage ) {
  429. $('#uploadProgress').html( parseFloat((_percentage * 100).toFixed(2)) );
  430. });
  431. // _uploadRole
  432. _imageUploader.on( 'error', function() {
  433. if( arguments[0]=="Q_TYPE_DENIED" ) w.alert("请上传图片格式文件");
  434. if( arguments[0]=="F_EXCEED_SIZE" ) w.alert("文件大小不能超过"+(arguments[1] / 1048576)+"M");
  435. });
  436. _imageUploader.on( 'uploadComplete', function() { _hideLoadingMask(); });
  437. _imageUploader.on( 'uploadSuccess', function( _file, _call ) {
  438. var _hasStyleBarBtn = $('#rt_'+_file.source.ruid).parents('.Eleditor-textStyle-item-upImg').length > 0;
  439. if( _call.status == 1 ){
  440. if( _hasStyleBarBtn ){
  441. _$editorTextArea.append('<img src="'+_call.url+'">');
  442. }else{
  443. _appendHistory();
  444. _$selected.after( $('<img src="'+_call.url+'">') );
  445. if( _$selected.hasClass('Eleditor-placeholder') ){
  446. _$selected.remove();
  447. }
  448. }
  449. _args.changer();
  450. }else{
  451. w.alert('上传失败:['+_call.msg+']');
  452. }
  453. if( !_hasStyleBarBtn ){
  454. _hideEditorControllerLayer();
  455. }
  456. });
  457. _imageUploader.addButton({ id: _$editorBarUploadImageBtn });
  458. _$editorBarUploadImageBtn.addClass('Eleditor-webUploader-btn');
  459. }else if( typeof _args.uploader == 'function' ){
  460. var _uploaderHanlder = function(){
  461. var _hasStyleBarBtn = $(this).hasClass('Eleditor-textStyle-item-upImg');
  462. try{
  463. _args.uploader.call(this).then(function(_url){
  464. var _urls = typeof _url === 'object' && _url.length ? _url : [_url]
  465. if( _hasStyleBarBtn ){
  466. for (var _uindex = 0; _uindex < _urls.length; _uindex++) {
  467. _$editorTextArea.append('<img src="'+_urls[_uindex]+'">');
  468. }
  469. }else{
  470. _appendHistory();
  471. for (var _uindex = 0; _uindex < _urls.length; _uindex++) {
  472. _$selected.after( $('<img src="'+_urls[_uindex]+'">') );
  473. }
  474. if( _$selected.hasClass('Eleditor-placeholder') ){
  475. _$selected.remove();
  476. }
  477. _hideEditorControllerLayer();
  478. }
  479. _args.changer();
  480. }, function(_err){
  481. w.alert('上传失败:['+_err+']');
  482. });
  483. }catch(_e){
  484. console.warn(_e);
  485. console.warn('|--Eleditor 请检查uploader函数返回是否是标准Promise对象!');
  486. }
  487. }
  488. _$editorUploadImageBtn.click(_uploaderHanlder);
  489. _$editorBarUploadImageBtn.click(_uploaderHanlder);
  490. }else{
  491. _$editorBarUploadImageBtn.addClass('Eleditor-textStyle-item-upImg-disabled')
  492. }
  493. var _editorModuleEvents = {
  494. insertText: function(){
  495. _showEditorWrapMask();
  496. _$editorTextModule.attr({'role': 'insert', 'type': 'word'}).show();
  497. },
  498. insertLink: function(){
  499. _showEditorWrapMask();
  500. _$editorTextModule.attr({'role': 'insert', 'type': 'link'}).show();
  501. },
  502. insertImage: function(){
  503. if( typeof WebUploader === 'undefined' && typeof _args.uploader != 'function' ){
  504. window.alert('上传参数未定义.');
  505. }
  506. },
  507. insertHr: function(){
  508. _appendHistory();
  509. var _$hr = $('<div class="horizontal-line" style="padding: 10px 0;border-bottom: 1px solid #aaa;margin-bottom: 20px;"></div>');
  510. _$selected.after(_$hr);
  511. _args.changer();
  512. _hideEditorControllerLayer();
  513. },
  514. editText: function(){
  515. if( _inArray(_$selected[0].tagName, _notctname) ){
  516. return this.insertText();
  517. }
  518. _showEditorWrapMask();
  519. _syncRenderTextEditorView();
  520. },
  521. "delete": function(){
  522. if( _$wrap.find('*').length == 1 ){
  523. _appendHistory();
  524. _args.changer();
  525. _$selected.remove();
  526. }else{
  527. _showEditorDeleteLayer();
  528. }
  529. _hideEditorControllerLayer();
  530. _correctHtmlStructure(_$wrap, _placeHolder);
  531. },
  532. undo: function(){
  533. _revokeEdit();
  534. },
  535. cancel: function(){
  536. _hideEditorControllerLayer();
  537. }
  538. };
  539. for (var i = 0; i < _args.toolbars.length; i++) {
  540. if( typeof _args.toolbars[i] === 'object' ){
  541. _editorModuleEvents[_args.toolbars[i].id] = _args.toolbars[i].handle;
  542. }
  543. };
  544. /*text area click*/
  545. _$window.on('resize', function(){
  546. _flushEditorControllerLayerPosi();
  547. });
  548. _$editorController.on('click', 'ul li', function() {
  549. var _$this = $(this),
  550. _event = _$this.attr('event');
  551. if( typeof _editorModuleEvents[_event] === 'function' ){
  552. if( typeof _toolnames[_event] != 'undefined' ){
  553. _editorModuleEvents[_event]();
  554. }else{
  555. _editorModuleEvents[_event](_$selected, _$this) !== false && _editorModuleEvents.cancel();
  556. }
  557. }
  558. });
  559. _$editorWrap.on('click', '.Eleditor-delete-revoke', function() {
  560. _revokeEdit();
  561. });
  562. _$editorDeleteLayer.on('click', '.Eleditor-delete-clear', function() {
  563. if( !confirm('确定清空内容吗?') ){
  564. return;
  565. }
  566. var _$cloneNode = _$wrap.clone();
  567. _$cloneNode.find('.Eleditor-placeholder').remove();
  568. if( _formatInnerText(_$cloneNode.text()) != '' ){
  569. _appendHistory();
  570. _$wrap.html('');
  571. _args.changer();
  572. _correctHtmlStructure(_$wrap, _placeHolder);
  573. }
  574. });
  575. _$editorDeleteLayer.on('click', '.Eleditor-delete-back', function() {
  576. _hideEditorDeleteLayer();
  577. });
  578. /*textEditor*/
  579. _$editorTextModule.on('click', '.Eleditor-textStyle-bold', function() {
  580. _$editorTextArea.css("font-weight", $(this).hasClass("Eleditor-active") ? "normal" : "bold");
  581. $(this).toggleClass("Eleditor-active");
  582. });
  583. _$editorTextModule.on('click', '.Eleditor-textStyle-linedecoration', function() {
  584. _$editorLinedecorationsModule.show();
  585. $(this).addClass('Eleditor-active');
  586. });
  587. _$editorTextModule.on('click', '.Eleditor-textStyle-color,.Eleditor-textStyle-bgColor', function() {
  588. var _$this = $(this);
  589. var _role = _$this.hasClass('Eleditor-textStyle-bgColor') ? 'bgcolor' : 'color';
  590. _$editorColorModule.find('.Eleditor-textEditor-modulePane span').html(_role == 'bgcolor' ? '文字背景颜色' : '文字颜色');
  591. _$editorColorModule.attr('role', _role).show();
  592. $(this).addClass('Eleditor-active');
  593. });
  594. _$editorTextModule.on('click', '.Eleditor-textStyle-fontSize', function() {
  595. _$editorFontsizeModule.show();
  596. $(this).addClass('Eleditor-active');
  597. });
  598. _$editorTextModule.on('click', '.Eleditor-textStyle-lineHeight', function() {
  599. _$editorLineheightModule.show();
  600. $(this).addClass('Eleditor-active');
  601. });
  602. _$editorLinedecorationsModule.on('click', 'ul li', function() {
  603. if( !$(this).hasClass('Eleditor-inheritValue') ){
  604. _$editorTextArea.css("text-decoration", $(this).css('text-decoration'));
  605. }else{
  606. _$editorTextArea.css("text-decoration", 'inherit');
  607. _$editorTextModule.find('.Eleditor-textStyle-linedecoration').removeClass('Eleditor-active');
  608. }
  609. _$editorLinedecorationsModule.hide();
  610. });
  611. _$editorLineheightModule.on('click', 'ul li', function() {
  612. if( !$(this).hasClass('Eleditor-inheritValue') ){
  613. _$editorTextArea.css("line-height", $(this).html());
  614. }else{
  615. _$editorTextArea.css("line-height", 'inherit');
  616. _$editorTextModule.find('.Eleditor-textStyle-lineHeight').removeClass('Eleditor-active');
  617. }
  618. _$editorLineheightModule.hide();
  619. });
  620. _$editorFontsizeModule.on('click', 'ul li', function() {
  621. if( !$(this).hasClass('Eleditor-inheritValue') ){
  622. _$editorTextArea.css("font-size", $(this).html());
  623. }else{
  624. _$editorTextArea.css("font-size", 'inherit');
  625. _$editorTextModule.find('.Eleditor-textStyle-fontSize').removeClass('Eleditor-active');
  626. }
  627. _$editorFontsizeModule.hide();
  628. });
  629. _$editorTextModule.on('click', ".Eleditor-textStyle-align", function() {
  630. var _align = $(this).attr('align');
  631. _$editorTextArea.css({"text-align": _align, "display": 'block'});
  632. _$editorTextModule.find(".Eleditor-textStyle-align.Eleditor-active").removeClass('Eleditor-active');
  633. $(this).addClass('Eleditor-active');
  634. });
  635. _$editorTextModule.on('click', ".Eleditor-textEditor-format", function() {
  636. var _$cloneTextArea = _$editorTextArea,
  637. _removeAttrs = 'style width height border bgcolor align color';
  638. _$cloneTextArea.removeAttr(_removeAttrs);
  639. $.each(_$cloneTextArea.find('*'), function(_i, _e) {
  640. var _$eachElm = _$cloneTextArea.find(_e);
  641. if( _inArray(_e.tagName.toLocaleLowerCase(), ['script', 'style']) ){
  642. _$eachElm.remove();
  643. }else{
  644. _$eachElm.removeAttr(_removeAttrs);
  645. }
  646. });
  647. _$editorTextArea.html(_$cloneTextArea.html());
  648. _$editorTextModule.find('.Eleditor-active').removeClass('Eleditor-active');
  649. });
  650. _$editorTextModule.on('click', ".Eleditor-textEditor-clean", function() {
  651. confirm('确定清空内容(不可恢复)?') && _$editorTextArea.html("");
  652. });
  653. _$editorTextModule.on('click', ".Eleditor-cancel,.Eleditor-commit", function() {
  654. arguments[0].preventDefault();
  655. if( $(this).hasClass('Eleditor-commit') ){
  656. var _style = _$editorTextArea.attr('style') || '';
  657. var _content = _$editorTextArea.html();
  658. var _editAct = _$editorTextModule.attr('role') == 'edit';
  659. var _hasPlaceHolder = _$selected.hasClass('Eleditor-placeholder');
  660. if( !_content ){
  661. return alert('请输入内容文字');
  662. }
  663. _appendHistory();
  664. if( _editAct || (_hasPlaceHolder && _$editorTextModule.attr('type') != 'link') ){
  665. if( _$editorTextModule.attr('type') == 'link' ){
  666. _$selected.attr('href', _$editorTextLinkArea.val());
  667. }
  668. _$selected.attr('style', _style).removeClass('Eleditor-placeholder').html( _content );
  669. }else{
  670. var _buildWordHtml = '';
  671. if( _$editorTextModule.attr('type') == 'link' ){
  672. var _link = _$editorTextLinkArea.val();
  673. _buildWordHtml = '<a style="'+_style+'" href="'+_link+'">'+_content+'</a>';
  674. }else{
  675. _buildWordHtml = '<p style="'+_style+'">'+_content+"</p>";
  676. }
  677. _$selected.after( $(_buildWordHtml) );
  678. if( _hasPlaceHolder ){
  679. _$selected.remove();
  680. }
  681. }
  682. _args.changer();
  683. _flushEditorControllerLayerPosi();
  684. }
  685. _$editorTextModule.find('.Eleditor-active').removeClass('Eleditor-active');
  686. _$editorTextModule.find('.Eleditor-textStyle-color span').removeAttr('style');
  687. _$editorTextArea.removeAttr('style').html('');
  688. _$editorTextLinkArea.val('');
  689. _hideEditorWrapMask();
  690. _$editorTextModule.hide();
  691. _hideEditorControllerLayer();
  692. });
  693. _$editorColorModule.on('click', 'ul li span', function() {
  694. var _color = $(this).css('background-color');
  695. if( _$editorColorModule.attr('role') == 'color' ){
  696. if( !$(this).hasClass('Eleditor-inheritValue') ){
  697. _$editorTextArea.css("color", _color);
  698. _$editorTextModule.find('.Eleditor-textStyle-color span').css("background-color", _color);
  699. }else{
  700. _$editorTextArea.css("color", 'inherit');
  701. _$editorTextModule.find('.Eleditor-textStyle-color').removeClass('Eleditor-active').find('span').removeAttr('style');
  702. }
  703. }else{
  704. if( !$(this).hasClass('Eleditor-inheritValue') ){
  705. _$editorTextArea.css("background-color", _color);
  706. }else{
  707. _$editorTextArea.css("background-color", 'inherit');
  708. _$editorTextModule.find('.Eleditor-textStyle-bgColor').removeClass('Eleditor-active');
  709. }
  710. }
  711. _$editorColorModule.hide();
  712. });
  713. /*controller*/
  714. _$wrap.on('click', '*', function(_e) {
  715. var _$this = $(this);
  716. if( _$wrap.hasClass('Eleditor-deleteMode') ){
  717. if( !_$this.hasClass('Eleditor-placeholder') ){
  718. _appendHistory();
  719. if( typeof _$this.fadeOut === 'function' ){
  720. _$this.fadeOut('fast', function(){
  721. _$this.remove();
  722. _correctHtmlStructure(_$wrap, _placeHolder);
  723. });
  724. }else{
  725. _$this.remove();
  726. _correctHtmlStructure(_$wrap, _placeHolder);
  727. }
  728. _args.changer();
  729. }
  730. }else if( !_$this.hasClass('Eleditor-active') ){
  731. _hideEditorControllerLayer();
  732. _hideEditorDeleteLayer();
  733. _showEditorControllerLayer(_$this);
  734. }
  735. return _e.preventDefault() == 0;
  736. });
  737. /*call*/
  738. _args.mounted();
  739. return {
  740. clear: function(){
  741. _args.changer();
  742. _$wrap.html('');
  743. _correctHtmlStructure(_$wrap, _placeHolder);
  744. },
  745. revoke: function(){
  746. _revokeEdit();
  747. },
  748. append: function(){
  749. _hideEditorControllerLayer();
  750. var _object = arguments[0];
  751. if( !_object ){
  752. return;
  753. }
  754. var _$content = $(_object);
  755. if( typeof _object == 'string' && _$content.length == 0 ){
  756. _$content = $('<p>'+_object+'</p>');
  757. }
  758. _$wrap.find('.Eleditor-placeholder').remove();
  759. _appendHistory();
  760. return _$wrap.append(_$content);
  761. },
  762. trigger: function(){
  763. var _event = arguments[0];
  764. if( _event == 'insertText' ){
  765. _$selected = _$wrap.find('>:last');
  766. _editorModuleEvents.insertText();
  767. }else if( _event == 'insertLink' ){
  768. _$selected = _$wrap.find('>:last');
  769. _editorModuleEvents.insertLink();
  770. }
  771. },
  772. saveState: function(){
  773. return _appendHistory();
  774. },
  775. getEditNode: function(){
  776. return _$selected;
  777. },
  778. getContent: function(){
  779. var _$cloneNode = _$wrap.clone();
  780. _$cloneNode.find('.Eleditor-placeholder').remove();
  781. _$cloneNode.find('.Eleditor-active').removeClass('Eleditor-active');
  782. return _$cloneNode.html();
  783. },
  784. getContentText: function(){
  785. var _$cloneNode = _$wrap.clone();
  786. _$cloneNode.find('.Eleditor-placeholder').remove();
  787. return _formatInnerText(_$cloneNode.text());
  788. },
  789. hideEditorControllerLayer: _hideEditorControllerLayer,
  790. destory: function(){
  791. _$wrap.removeAttr('Eleditor-Inited Eleditor-Uid');
  792. _$wrap.removeClass('Eleditor-area');
  793. _$wrap.find('.Eleditor-placeholder').remove()
  794. _$wrap.off().find('.Eleditor-active').removeClass('Eleditor-active');
  795. _$editorWrap.find('*').off();
  796. _$editorWrap.remove();
  797. console.log('|--Eleditor '+_editorUid+' destoryed');
  798. }
  799. }
  800. }
  801. })(window);