html-editor.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. $(function () {
  2. window.addDocumentModalFormHtml = $(this).find("form").html();
  3. window.editor = new wangEditor('#htmlEditor');
  4. editor.config.mapAk = window.baiduMapKey;
  5. editor.config.printLog = false;
  6. editor.config.showMenuTooltips = true
  7. editor.config.menuTooltipPosition = 'down'
  8. editor.config.uploadImgUrl = window.imageUploadURL;
  9. editor.config.uploadImgFileName = "editormd-image-file";
  10. editor.config.uploadParams = {
  11. "editor" : "wangEditor"
  12. };
  13. editor.config.uploadImgServer = window.imageUploadURL;
  14. editor.config.customUploadImg = function (resultFiles, insertImgFn) {
  15. // resultFiles 是 input 中选中的文件列表
  16. // insertImgFn 是获取图片 url 后,插入到编辑器的方法
  17. var file = resultFiles[0];
  18. // file type is only image.
  19. if (/^image\//.test(file.type)) {
  20. var form = new FormData();
  21. form.append('editormd-image-file', file, file.name);
  22. var layerIndex = 0;
  23. $.ajax({
  24. url: window.imageUploadURL,
  25. type: "POST",
  26. dataType: "json",
  27. data: form,
  28. processData: false,
  29. contentType: false,
  30. error: function() {
  31. layer.close(layerIndex);
  32. layer.msg("图片上传失败");
  33. },
  34. success: function(data) {
  35. layer.close(layerIndex);
  36. if(data.errcode !== 0){
  37. layer.msg(data.message);
  38. }else{
  39. insertImgFn(data.url);
  40. }
  41. }
  42. });
  43. } else {
  44. console.warn('You could only upload images.');
  45. }
  46. };
  47. editor.config.lang = window.lang;
  48. editor.i18next = window.i18next;
  49. editor.config.languages['en']['wangEditor']['menus']['title']['保存'] = 'save';
  50. editor.config.languages['en']['wangEditor']['menus']['title']['发布'] = 'publish';
  51. editor.config.languages['en']['wangEditor']['menus']['title']['附件'] = 'attachment';
  52. editor.config.languages['en']['wangEditor']['menus']['title']['history'] = 'history';
  53. /*
  54. editor.config.menus.splice(0,0,"|");
  55. editor.config.menus.splice(0,0,"history");
  56. editor.config.menus.splice(0,0,"save");
  57. editor.config.menus.splice(0,0,"release");
  58. editor.config.menus.splice(29,0,"attach")
  59. //移除地图、背景色
  60. editor.config.menus = $.map(editor.config.menus, function(item, key) {
  61. if (item === 'fullscreen') {
  62. return null;
  63. }
  64. return item;
  65. });
  66. */
  67. /*
  68. window.editor.config.uploadImgFns.onload = function (resultText, xhr) {
  69. // resultText 服务器端返回的text
  70. // xhr 是 xmlHttpRequest 对象,IE8、9中不支持
  71. // 上传图片时,已经将图片的名字存在 editor.uploadImgOriginalName
  72. var originalName = editor.uploadImgOriginalName || '';
  73. var res = jQuery.parseJSON(resultText);
  74. if (res.errcode === 0){
  75. editor.command(null, 'insertHtml', '<img src="' + res.url + '" alt="' + res.alt + '" style="max-width:100%;"/>');
  76. }else{
  77. layer.msg(res.message);
  78. }
  79. };
  80. */
  81. window.editormdLocales = {
  82. 'zh-CN': {
  83. placeholder: '本编辑器支持 Markdown 编辑,左边编写,右边预览。',
  84. contentUnsaved: '编辑内容未保存,需要保存吗?',
  85. noDocNeedPublish: '没有需要发布的文档',
  86. loadDocFailed: '文档加载失败',
  87. fetchDocFailed: '获取当前文档信息失败',
  88. cannotAddToEmptyNode: '空节点不能添加内容',
  89. overrideModified: '文档已被其他人修改确定覆盖已存在的文档吗?',
  90. confirm: '确定',
  91. cancel: '取消',
  92. contentsNameEmpty: '目录名称不能为空',
  93. addDoc: '添加文档',
  94. edit: '编辑',
  95. delete: '删除',
  96. loadFailed: '加载失败请重试',
  97. tplNameEmpty: '模板名称不能为空',
  98. tplContentEmpty: '模板内容不能为空',
  99. saveSucc: '保存成功',
  100. serverExcept: '服务器异常',
  101. paramName: '参数名称',
  102. paramType: '参数类型',
  103. example: '示例值',
  104. remark: '备注',
  105. },
  106. 'en': {
  107. placeholder: 'This editor supports Markdown editing, writing on the left and previewing on the right.',
  108. contentUnsaved: 'The edited content is not saved, need to save it?',
  109. noDocNeedPublish: 'No Document need to be publish',
  110. loadDocFailed: 'Load Document failed',
  111. fetchDocFailed: 'Fetch Document info failed',
  112. cannotAddToEmptyNode: 'Cannot add content to empty node',
  113. overrideModified: 'The document has been modified by someone else, are you sure to overwrite the document?',
  114. confirm: 'Confirm',
  115. cancel: 'Cancel',
  116. contentsNameEmpty: 'Document Name cannot be empty',
  117. addDoc: 'Add Document',
  118. edit: 'Edit',
  119. delete: 'Delete',
  120. loadFailed: 'Failed to load, please try again',
  121. tplNameEmpty: 'Template name cannot be empty',
  122. tplContentEmpty: 'Template content cannot be empty',
  123. saveSucc: 'Save success',
  124. serverExcept: 'Server Exception',
  125. paramName: 'Parameter',
  126. paramType: 'Type',
  127. example: 'Example',
  128. remark: 'Remark',
  129. }
  130. };
  131. window.editor.config.onchange = function (newHtml) {
  132. var saveMenu = window.editor.menus.menuList.find((item) => item.key == 'save');
  133. // 判断内容是否改变
  134. if (window.source !== window.editor.txt.html()) {
  135. saveMenu.$elem.addClass('selected');
  136. } else {
  137. saveMenu.$elem.removeClass('selected');
  138. }
  139. };
  140. window.editor.create();
  141. $("#htmlEditor").css("height","100%");
  142. if(window.documentCategory.length > 0){
  143. var item = window.documentCategory[0];
  144. var $select_node = { node : {id : item.id}};
  145. loadDocument($select_node);
  146. }
  147. /***
  148. * 加载指定的文档到编辑器中
  149. * @param $node
  150. */
  151. function loadDocument($node) {
  152. var index = layer.load(1, {
  153. shade: [0.1,'#fff'] //0.1透明度的白色背景
  154. });
  155. $.get(window.editURL + $node.node.id ).done(function (res) {
  156. layer.close(index);
  157. if(res.errcode === 0){
  158. window.isLoad = true;
  159. window.editor.txt.clear();
  160. window.editor.txt.html(res.data.content);
  161. // 将原始内容备份
  162. window.source = res.data.content;
  163. var node = { "id" : res.data.doc_id,'parent' : res.data.parent_id === 0 ? '#' : res.data.parent_id ,"text" : res.data.doc_name,"identify" : res.data.identify,"version" : res.data.version};
  164. pushDocumentCategory(node);
  165. window.selectNode = node;
  166. pushVueLists(res.data.attach);
  167. }else{
  168. layer.msg("文档加载失败");
  169. }
  170. }).fail(function () {
  171. layer.close(index);
  172. layer.msg("文档加载失败");
  173. });
  174. }
  175. /**
  176. * 保存文档到服务器
  177. * @param $is_cover 是否强制覆盖
  178. */
  179. function saveDocument($is_cover,callback) {
  180. var index = null;
  181. var node = window.selectNode;
  182. var html = window.editor.txt.html() ;
  183. var content = "";
  184. if($.trim(html) !== ""){
  185. content = toMarkdown(html, { gfm: true });
  186. }
  187. var version = "";
  188. if (!node) {
  189. layer.msg(editormdLocales[lang].fetchDocFailed);
  190. return;
  191. }
  192. var doc_id = parseInt(node.id);
  193. for(var i in window.documentCategory){
  194. var item = window.documentCategory[i];
  195. if(item.id === doc_id){
  196. version = item.version;
  197. break;
  198. }
  199. }
  200. $.ajax({
  201. beforeSend : function () {
  202. index = layer.load(1, {shade: [0.1,'#fff'] });
  203. },
  204. url : window.editURL,
  205. data : {"identify" : window.book.identify,"doc_id" : doc_id,"markdown" : content,"html" : html,"cover" : $is_cover ? "yes":"no","version": version},
  206. type :"post",
  207. dataType :"json",
  208. success : function (res) {
  209. layer.close(index);
  210. if(res.errcode === 0){
  211. for(var i in window.documentCategory){
  212. var item = window.documentCategory[i];
  213. if(item.id === doc_id){
  214. window.documentCategory[i].version = res.data.version;
  215. break;
  216. }
  217. }
  218. // 更新内容备份
  219. window.source = res.data.content;
  220. // 触发编辑器 onchange 回调函数
  221. window.editor.config.onchange();
  222. if(typeof callback === "function"){
  223. callback();
  224. }
  225. }else if(res.errcode === 6005){
  226. var confirmIndex = layer.confirm(editormdLocales[lang].overrideModified, {
  227. btn: [editormdLocales[lang].confirm, editormdLocales[lang].cancel] // 按钮
  228. }, function () {
  229. layer.close(confirmIndex);
  230. saveDocument(true,callback);
  231. });
  232. }else{
  233. layer.msg(res.message);
  234. }
  235. }
  236. });
  237. }
  238. /**
  239. * 添加顶级文档
  240. */
  241. $("#addDocumentForm").ajaxForm({
  242. beforeSubmit : function () {
  243. var doc_name = $.trim($("#documentName").val());
  244. if (doc_name === ""){
  245. return showError("目录名称不能为空","#add-error-message")
  246. }
  247. window.addDocumentFormIndex = layer.load(1, { shade: [0.1,'#fff'] });
  248. return true;
  249. },
  250. success : function (res) {
  251. if(res.errcode === 0){
  252. var data = { "id" : res.data.doc_id,'parent' : res.data.parent_id === 0 ? '#' : res.data.parent_id ,"text" : res.data.doc_name,"identify" : res.data.identify,"version" : res.data.version};
  253. var node = window.treeCatalog.get_node(data.id);
  254. if(node){
  255. window.treeCatalog.rename_node({"id":data.id},data.text);
  256. }else {
  257. window.treeCatalog.create_node(data.parent, data);
  258. window.treeCatalog.deselect_all();
  259. window.treeCatalog.select_node(data);
  260. }
  261. pushDocumentCategory(data);
  262. $("#markdown-save").removeClass('change').addClass('disabled');
  263. $("#addDocumentModal").modal('hide');
  264. }else{
  265. showError(res.message,"#add-error-message")
  266. }
  267. layer.close(window.addDocumentFormIndex);
  268. }
  269. });
  270. /**
  271. * 文档目录树
  272. */
  273. $("#sidebar").jstree({
  274. 'plugins': ["wholerow", "types", 'dnd', 'contextmenu'],
  275. "types": {
  276. "default": {
  277. "icon": false // 删除默认图标
  278. }
  279. },
  280. 'core': {
  281. 'check_callback': true,
  282. "multiple": false,
  283. 'animation': 0,
  284. "data": window.documentCategory
  285. },
  286. "contextmenu": {
  287. show_at_node: false,
  288. select_node: false,
  289. "items": {
  290. "添加文档": {
  291. "separator_before": false,
  292. "separator_after": true,
  293. "_disabled": false,
  294. "label": window.editormdLocales[window.lang].addDoc,//"添加文档",
  295. "icon": "fa fa-plus",
  296. "action": function (data) {
  297. var inst = $.jstree.reference(data.reference),
  298. node = inst.get_node(data.reference);
  299. openCreateCatalogDialog(node);
  300. }
  301. },
  302. "编辑": {
  303. "separator_before": false,
  304. "separator_after": true,
  305. "_disabled": false,
  306. "label": window.editormdLocales[window.lang].edit,
  307. "icon": "fa fa-edit",
  308. "action": function (data) {
  309. var inst = $.jstree.reference(data.reference);
  310. var node = inst.get_node(data.reference);
  311. openEditCatalogDialog(node);
  312. }
  313. },
  314. "删除": {
  315. "separator_before": false,
  316. "separator_after": true,
  317. "_disabled": false,
  318. "label": window.editormdLocales[window.lang].delete,
  319. "icon": "fa fa-trash-o",
  320. "action": function (data) {
  321. var inst = $.jstree.reference(data.reference);
  322. var node = inst.get_node(data.reference);
  323. openDeleteDocumentDialog(node);
  324. }
  325. }
  326. }
  327. }
  328. }).on('loaded.jstree', function () {
  329. window.treeCatalog = $(this).jstree();
  330. }).on('select_node.jstree', function (node, selected, event) {
  331. if(window.editor.menus.menuList.find((item) => item.key == 'save').$elem.hasClass('selected')) {
  332. if (confirm(window.editormdLocales[window.lang].contentUnsaved)) {
  333. saveDocument(false,function () {
  334. loadDocument(selected);
  335. });
  336. return true;
  337. }
  338. }
  339. loadDocument(selected);
  340. }).on("move_node.jstree", jstree_save);
  341. window.saveDocument = saveDocument;
  342. window.releaseBook = function () {
  343. if(Object.prototype.toString.call(window.documentCategory) === '[object Array]' && window.documentCategory.length > 0){
  344. if(window.editor.menus.menuList.find((item) => item.key == 'save').$elem.hasClass('selected')) {
  345. if(confirm(editormdLocales[lang].contentUnsaved)) {
  346. saveDocument();
  347. }
  348. }
  349. locales = {
  350. 'zh-CN': {
  351. publishToQueue: '发布任务已推送到任务队列,稍后将在后台执行。',
  352. },
  353. 'en': {
  354. publishToQueue: 'The publish task has been pushed to the queue</br> and will be executed soon.',
  355. }
  356. }
  357. $.ajax({
  358. url: window.releaseURL,
  359. data: {"identify": window.book.identify},
  360. type: "post",
  361. dataType: "json",
  362. success: function (res) {
  363. if (res.errcode === 0) {
  364. layer.msg(locales[lang].publishToQueue);
  365. } else {
  366. layer.msg(res.message);
  367. }
  368. }
  369. });
  370. }else{
  371. layer.msg(editormdLocales[lang].noDocNeedPublish)
  372. }
  373. };
  374. $(window).resize(function(e) {
  375. var $container = $(editor.$textContainerElem.elems[0]);
  376. var $manual = $container.closest('.manual-wangEditor');
  377. var maxHeight = $manual.closest('.manual-editor-container').innerHeight();
  378. var statusHeight = $manual.siblings('.manual-editor-status').outerHeight(true);
  379. var manualHeihgt = maxHeight - statusHeight;
  380. $manual.height(manualHeihgt);
  381. var toolbarHeight = $container.siblings('.w-e-toolbar').outerHeight(true);
  382. $container.height($container.parent().innerHeight() - toolbarHeight);
  383. });
  384. $(window).trigger('resize');
  385. });