martor.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. /**
  2. * Name : Martor v1.3.3
  3. * Created by : Agus Makmun (Summon Agus)
  4. * Release date : 18-Sep-2018
  5. * License : GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
  6. * Repository : https://github.com/agusmakmun/django-markdown-editor
  7. **/
  8. (function ($) {
  9. if (!$) {
  10. $ = django.jQuery;
  11. }
  12. $.fn.martor = function() {
  13. var martor = $(this);
  14. var mainMartor = $('.main-martor');
  15. martor.trigger('martor.init');
  16. // CSRF code
  17. var getCookie = function(name) {
  18. var cookieValue = null;
  19. var i = 0;
  20. if (document.cookie && document.cookie !== '') {
  21. var cookies = document.cookie.split(';');
  22. for (i; i < cookies.length; i++) {
  23. var cookie = jQuery.trim(cookies[i]);
  24. // Does this cookie string begin with the name we want?
  25. if (cookie.substring(0, name.length + 1) === (name + '=')) {
  26. cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
  27. break;
  28. }
  29. }
  30. }
  31. return cookieValue;
  32. }
  33. // Each multiple editor fields
  34. mainMartor.each(function(i, obj) {
  35. var field_name = $(obj).data('field-name');
  36. var textareaId = $('#id_'+field_name);
  37. var editorId = 'martor-'+field_name;
  38. var editor = ace.edit(editorId);
  39. var editorConfig = JSON.parse(textareaId.data('enable-configs').replace(/'/g, '"'));
  40. editor.setTheme('ace/theme/github');
  41. editor.getSession().setMode('ace/mode/markdown');
  42. editor.getSession().setUseWrapMode(true);
  43. editor.$blockScrolling = Infinity; // prevents ace from logging annoying warnings
  44. editor.renderer.setScrollMargin(10, 10); // set padding
  45. editor.setAutoScrollEditorIntoView(true);
  46. editor.setOptions({
  47. enableBasicAutocompletion: true,
  48. enableSnippets: true,
  49. enableLiveAutocompletion: true,
  50. enableMultiselect: false
  51. });
  52. if (editorConfig.living == 'true') {
  53. $(obj).addClass('enable-living');
  54. }
  55. var emojiWordCompleter = {
  56. getCompletions: function(editor, session, pos, prefix, callback) {
  57. var wordList = emojis; // from `atwho/emojis.min.js`
  58. var obj = editor.getSession().getTokenAt(pos.row, pos.column.count);
  59. var curTokens = obj.value.split(/\s+/);
  60. var lastToken = curTokens[curTokens.length-1];
  61. if (lastToken[0] == ':') {
  62. callback(null, wordList.map(function(word) {
  63. return {
  64. caption: word,
  65. value: word.replace(':', '') + ' ',
  66. meta: 'emoji' // this should return as text only.
  67. };
  68. }));
  69. }
  70. }
  71. }
  72. var mentionWordCompleter = {
  73. getCompletions: function(editor, session, pos, prefix, callback) {
  74. var obj = editor.getSession().getTokenAt(pos.row, pos.column.count);
  75. var curTokens = obj.value.split(/\s+/);
  76. var lastToken = curTokens[curTokens.length-1];
  77. if (lastToken[0] == '@' && lastToken[1] == '[') {
  78. username = lastToken.replace(/([\@\[/\]/])/g, '');
  79. $.ajax({
  80. url: textareaId.data('search-users-url'),
  81. data: {
  82. 'username': username,
  83. 'csrfmiddlewaretoken': getCookie('csrftoken')
  84. },
  85. success: function(data) {
  86. if (data['status'] == 200) {
  87. var wordList = [];
  88. for (var i = 0; i < data['data'].length; i++) {
  89. wordList.push(data['data'][i].username)
  90. }
  91. callback(null, wordList.map(function(word) {
  92. return {
  93. caption: word,
  94. value: word,
  95. meta: 'username' // this should return as text only.
  96. };
  97. }));
  98. }
  99. }// end success
  100. });
  101. }
  102. }
  103. }
  104. // Set autocomplete for ace editor
  105. if (editorConfig.mention === 'true') {
  106. editor.completers = [emojiWordCompleter, mentionWordCompleter]
  107. }else {
  108. editor.completers = [emojiWordCompleter]
  109. }
  110. // set css `display:none` fot this textarea.
  111. textareaId.attr({'style': 'display:none'});
  112. // assign all `field_name`, uses for a per-single editor.
  113. $(obj).find('.martor-toolbar').find('.markdown-selector').attr({'data-field-name': field_name});
  114. $(obj).find('.upload-progress').attr({'data-field-name': field_name});
  115. $(obj).find('.modal-help-guide').attr({'data-field-name': field_name});
  116. $(obj).find('.modal-emoji').attr({'data-field-name': field_name});
  117. // Set if editor has changed.
  118. editor.on('change', function(evt){
  119. var value = editor.getValue();
  120. textareaId.val(value);
  121. });
  122. // resize the editor using `resizable.min.js`
  123. $('#'+editorId).resizable({
  124. direction: 'bottom',
  125. stop: function() {
  126. editor.resize();
  127. }
  128. });
  129. // update the preview if this menu is clicked
  130. var currentTab = $('.tab.segment[data-tab=preview-tab-'+field_name+']');
  131. var previewTabButton = $('.item[data-tab=preview-tab-'+field_name+']');
  132. var refreshPreview = function() {
  133. var value = editor.getValue();
  134. var form = new FormData();
  135. form.append('content', value);
  136. form.append('csrfmiddlewaretoken', getCookie('csrftoken'));
  137. $.ajax({
  138. url: textareaId.data('markdownfy-url'),
  139. type: 'POST',
  140. data: form,
  141. processData: false,
  142. contentType: false,
  143. success: function(response) {
  144. if(response){
  145. currentTab.html(response);
  146. $('pre').each(function(i, block){
  147. hljs.highlightBlock(block);
  148. });
  149. }else {currentTab.html('<p>Nothing to preview</p>');}
  150. },
  151. error: function(response) {
  152. console.log("error", response);
  153. }
  154. });
  155. };
  156. if (editorConfig.living === 'true') {
  157. editor.on('change', refreshPreview);
  158. }else {
  159. previewTabButton.click(function(){
  160. // hide the `.martor-toolbar` for this current editor if under preview.
  161. $(this).closest('.tab-martor-menu').find('.martor-toolbar').hide();
  162. refreshPreview();
  163. });
  164. }
  165. var editorTabButton = $('.item[data-tab=editor-tab-'+field_name+']');
  166. editorTabButton.click(function(){
  167. // show the `.martor-toolbar` for this current editor if under preview.
  168. $(this).closest('.tab-martor-menu').find('.martor-toolbar').show();
  169. });
  170. // win/linux: Ctrl+B, mac: Command+B
  171. var markdownToBold = function(editor) {
  172. var originalRange = editor.getSelectionRange();
  173. if (editor.selection.isEmpty()) {
  174. var curpos = editor.getCursorPosition();
  175. editor.session.insert(curpos, ' **** ');
  176. editor.focus();
  177. editor.selection.moveTo(curpos.row, curpos.column+3);
  178. }else {
  179. var range = editor.getSelectionRange();
  180. var text = editor.session.getTextRange(range);
  181. editor.session.replace(range, '**'+text+'**');
  182. originalRange.end.column += 4; // this because injected from 4 `*` characters.
  183. editor.focus();
  184. editor.selection.setSelectionRange(originalRange);
  185. }
  186. };
  187. // win/linux: Ctrl+I, mac: Command+I
  188. var markdownToItalic = function(editor) {
  189. var originalRange = editor.getSelectionRange();
  190. if (editor.selection.isEmpty()) {
  191. var curpos = editor.getCursorPosition();
  192. editor.session.insert(curpos, ' __ ');
  193. editor.focus();
  194. editor.selection.moveTo(curpos.row, curpos.column+2);
  195. }else {
  196. var range = editor.getSelectionRange();
  197. var text = editor.session.getTextRange(range);
  198. editor.session.replace(range, '_'+text+'_');
  199. originalRange.end.column += 2; // this because injected from 2 `_` characters.
  200. editor.focus();
  201. editor.selection.setSelectionRange(originalRange);
  202. }
  203. };
  204. // win/linux: Ctrl+Shift+U
  205. var markdownToUnderscores = function(editor) {
  206. var originalRange = editor.getSelectionRange();
  207. if (editor.selection.isEmpty()) {
  208. var curpos = editor.getCursorPosition();
  209. editor.session.insert(curpos, ' ++++ ');
  210. editor.focus();
  211. editor.selection.moveTo(curpos.row, curpos.column+3);
  212. }else {
  213. var range = editor.getSelectionRange();
  214. var text = editor.session.getTextRange(range);
  215. editor.session.replace(range, '++'+text+'++');
  216. originalRange.end.column += 4; // this because injected from 4 `*` characters.
  217. editor.focus();
  218. editor.selection.setSelectionRange(originalRange);
  219. }
  220. };
  221. // win/linux: Ctrl+Shift+S
  222. var markdownToStrikethrough = function(editor) {
  223. var originalRange = editor.getSelectionRange();
  224. if (editor.selection.isEmpty()) {
  225. var curpos = editor.getCursorPosition();
  226. editor.session.insert(curpos, ' ~~~~ ');
  227. editor.focus();
  228. editor.selection.moveTo(curpos.row, curpos.column+3);
  229. }else {
  230. var range = editor.getSelectionRange();
  231. var text = editor.session.getTextRange(range);
  232. editor.session.replace(range, '~~'+text+'~~');
  233. originalRange.end.column += 4; // this because injected from 4 `*` characters.
  234. editor.focus();
  235. editor.selection.setSelectionRange(originalRange);
  236. }
  237. };
  238. // win/linux: Ctrl+H, mac: Command+H
  239. var markdownToHorizontal = function(editor) {
  240. var originalRange = editor.getSelectionRange();
  241. if (editor.selection.isEmpty()) {
  242. var curpos = editor.getCursorPosition();
  243. editor.session.insert(curpos, '\n\n----------\n\n');
  244. editor.focus();
  245. editor.selection.moveTo(curpos.row+4, curpos.column+10);
  246. }
  247. else {
  248. var range = editor.getSelectionRange();
  249. var text = editor.session.getTextRange(range);
  250. editor.session.replace(range, '\n\n----------\n\n'+text);
  251. editor.focus();
  252. editor.selection.moveTo(
  253. originalRange.end.row+4,
  254. originalRange.end.column+10
  255. );
  256. }
  257. };
  258. // win/linux: Ctrl+Alt+1, mac: Command+Option+1
  259. var markdownToH1 = function(editor) {
  260. var originalRange = editor.getSelectionRange();
  261. if (editor.selection.isEmpty()) {
  262. var curpos = editor.getCursorPosition();
  263. editor.session.insert(curpos, '\n\n# ');
  264. editor.focus();
  265. editor.selection.moveTo(curpos.row+2, curpos.column+2);
  266. }
  267. else {
  268. var range = editor.getSelectionRange();
  269. var text = editor.session.getTextRange(range);
  270. editor.session.replace(range, '\n\n# '+text+'\n');
  271. editor.focus();
  272. editor.selection.moveTo(
  273. originalRange.end.row+2,
  274. originalRange.end.column+2
  275. );
  276. }
  277. };
  278. // win/linux: Ctrl+Alt+2, mac: Command+Option+2
  279. var markdownToH2 = function(editor) {
  280. var originalRange = editor.getSelectionRange();
  281. if (editor.selection.isEmpty()) {
  282. var curpos = editor.getCursorPosition();
  283. editor.session.insert(curpos, '\n\n## ');
  284. editor.focus();
  285. editor.selection.moveTo(curpos.row+2, curpos.column+3);
  286. }
  287. else {
  288. var range = editor.getSelectionRange();
  289. var text = editor.session.getTextRange(range);
  290. editor.session.replace(range, '\n\n## '+text+'\n');
  291. editor.focus();
  292. editor.selection.moveTo(
  293. originalRange.end.row+2,
  294. originalRange.end.column+3
  295. );
  296. }
  297. };
  298. // win/linux: Ctrl+Alt+3, mac: Command+Option+3
  299. var markdownToH3 = function(editor) {
  300. var originalRange = editor.getSelectionRange();
  301. if (editor.selection.isEmpty()) {
  302. var curpos = editor.getCursorPosition();
  303. editor.session.insert(curpos, '\n\n### ');
  304. editor.focus();
  305. editor.selection.moveTo(curpos.row+2, curpos.column+4);
  306. }
  307. else {
  308. var range = editor.getSelectionRange();
  309. var text = editor.session.getTextRange(range);
  310. editor.session.replace(range, '\n\n### '+text+'\n');
  311. editor.focus();
  312. editor.selection.moveTo(
  313. originalRange.end.row+2,
  314. originalRange.end.column+4
  315. );
  316. }
  317. };
  318. // win/linux: Ctrl+Alt+P, mac: Command+Option+P
  319. var markdownToPre = function(editor) {
  320. var originalRange = editor.getSelectionRange();
  321. if (editor.selection.isEmpty()) {
  322. var curpos = editor.getCursorPosition();
  323. editor.session.insert(curpos, '\n\n```\n\n```\n');
  324. editor.focus();
  325. editor.selection.moveTo(curpos.row+3, curpos.column);
  326. }
  327. else {
  328. var range = editor.getSelectionRange();
  329. var text = editor.session.getTextRange(range);
  330. editor.session.replace(range, '\n\n```\n'+text+'\n```\n');
  331. editor.focus();
  332. editor.selection.moveTo(
  333. originalRange.end.row+3,
  334. originalRange.end.column+3
  335. );
  336. }
  337. };
  338. // win/linux: Ctrl+Alt+C, mac: Command+Option+C
  339. var markdownToCode = function(editor) {
  340. var originalRange = editor.getSelectionRange();
  341. if (editor.selection.isEmpty()) {
  342. var curpos = editor.getCursorPosition();
  343. editor.session.insert(curpos, ' `` ');
  344. editor.focus();
  345. editor.selection.moveTo(curpos.row, curpos.column+2);
  346. }else {
  347. var range = editor.getSelectionRange();
  348. var text = editor.session.getTextRange(range);
  349. editor.session.replace(range, '`'+text+'`');
  350. originalRange.end.column += 2; // this because injected from 2 `_` characters.
  351. editor.focus();
  352. editor.selection.setSelectionRange(originalRange);
  353. }
  354. };
  355. // win/linux: Ctrl+Q, mac: Command+Q
  356. var markdownToBlockQuote = function(editor) {
  357. var originalRange = editor.getSelectionRange();
  358. if (editor.selection.isEmpty()) {
  359. var curpos = editor.getCursorPosition();
  360. editor.session.insert(curpos, '\n\n> \n');
  361. editor.focus();
  362. editor.selection.moveTo(curpos.row+2, curpos.column+2);
  363. }
  364. else {
  365. var range = editor.getSelectionRange();
  366. var text = editor.session.getTextRange(range);
  367. editor.session.replace(range, '\n\n> '+text+'\n');
  368. editor.focus();
  369. editor.selection.moveTo(
  370. originalRange.end.row+2,
  371. originalRange.end.column+2
  372. );
  373. }
  374. };
  375. // win/linux: Ctrl+U, mac: Command+U
  376. var markdownToUnorderedList = function(editor) {
  377. var originalRange = editor.getSelectionRange();
  378. if (editor.selection.isEmpty()) {
  379. var curpos = editor.getCursorPosition();
  380. editor.session.insert(curpos, '\n\n* ');
  381. editor.focus();
  382. editor.selection.moveTo(curpos.row+2, curpos.column+2);
  383. }
  384. else {
  385. var range = editor.getSelectionRange();
  386. var text = editor.session.getTextRange(range);
  387. editor.session.replace(range, '\n\n* '+text);
  388. editor.focus();
  389. editor.selection.moveTo(
  390. originalRange.end.row+2,
  391. originalRange.end.column+2
  392. );
  393. }
  394. };
  395. // win/linux: Ctrl+Shift+O, mac: Command+Option+O
  396. var markdownToOrderedList = function(editor) {
  397. var originalRange = editor.getSelectionRange();
  398. if (editor.selection.isEmpty()) {
  399. var curpos = editor.getCursorPosition();
  400. editor.session.insert(curpos, '\n\n1. ');
  401. editor.focus();
  402. editor.selection.moveTo(curpos.row+2, curpos.column+3);
  403. }
  404. else {
  405. var range = editor.getSelectionRange();
  406. var text = editor.session.getTextRange(range);
  407. editor.session.replace(range, '\n\n1. '+text);
  408. editor.focus();
  409. editor.selection.moveTo(
  410. originalRange.end.row+2,
  411. originalRange.end.column+3
  412. );
  413. }
  414. };
  415. // win/linux: Ctrl+L, mac: Command+L
  416. var markdownToLink = function(editor) {
  417. var originalRange = editor.getSelectionRange();
  418. if (editor.selection.isEmpty()) {
  419. var curpos = editor.getCursorPosition();
  420. editor.session.insert(curpos, ' [](http://) ');
  421. editor.focus();
  422. editor.selection.moveTo(curpos.row, curpos.column+2);
  423. }else {
  424. var range = editor.getSelectionRange();
  425. var text = editor.session.getTextRange(range);
  426. editor.session.replace(range, '['+text+'](http://) ');
  427. editor.focus();
  428. editor.selection.moveTo(
  429. originalRange.end.row,
  430. originalRange.end.column+10
  431. );
  432. }
  433. };
  434. // win/linux: Ctrl+Shift+I, mac: Command+Option+I
  435. // or via upload: imageData={name:null, link:null}
  436. var markdownToImageLink = function(editor, imageData) {
  437. var originalRange = editor.getSelectionRange();
  438. if (typeof(imageData) === 'undefined') {
  439. if (editor.selection.isEmpty()) {
  440. var curpos = editor.getCursorPosition();
  441. editor.session.insert(curpos, ' ![](http://) ');
  442. editor.focus();
  443. editor.selection.moveTo(curpos.row, curpos.column+3);
  444. }else {
  445. var range = editor.getSelectionRange();
  446. var text = editor.session.getTextRange(range);
  447. editor.session.replace(range, '!['+text+'](http://) ');
  448. editor.focus();
  449. editor.selection.moveTo(
  450. originalRange.end.row,
  451. originalRange.end.column+11
  452. );
  453. }
  454. }else { // this if use image upload to imgur.
  455. var curpos = editor.getCursorPosition();
  456. editor.session.insert(curpos, '!['+imageData.name+']('+imageData.link+') ');
  457. editor.focus();
  458. editor.selection.moveTo(
  459. curpos.row,
  460. curpos.column+imageData.name.length+2
  461. );
  462. }
  463. };
  464. // win/linux: Ctrl+M, mac: Command+M
  465. var markdownToMention = function(editor) {
  466. var originalRange = editor.getSelectionRange();
  467. if (editor.selection.isEmpty()) {
  468. var curpos = editor.getCursorPosition();
  469. editor.session.insert(curpos, ' @[]');
  470. editor.focus();
  471. editor.selection.moveTo(curpos.row, curpos.column+3);
  472. }else {
  473. var range = editor.getSelectionRange();
  474. var text = editor.session.getTextRange(range);
  475. editor.session.replace(range, '@['+text+']');
  476. editor.focus();
  477. editor.selection.moveTo(
  478. originalRange.end.row,
  479. originalRange.end.column+3
  480. )
  481. }
  482. };
  483. // Insert Emoji to text editor: $('.insert-emoji').data('emoji-target')
  484. var markdownToEmoji = function(editor, data_target) {
  485. var curpos = editor.getCursorPosition();
  486. editor.session.insert(curpos, ' '+data_target+' ');
  487. editor.focus();
  488. editor.selection.moveTo(curpos.row, curpos.column+data_target.length+2);
  489. };
  490. // Markdown Image Uploader auto insert to editor.
  491. // with special insert, eg: ![avatar.png](i.imgur.com/DytfpTz.png)
  492. var markdownToUploadImage = function(editor) {
  493. var firstForm = $('#'+editorId).closest('form').get(0);
  494. var field_name = editor.container.id.replace('martor-', '');
  495. var form = new FormData(firstForm);
  496. form.append('csrfmiddlewaretoken', getCookie('csrftoken'));
  497. $.ajax({
  498. url: textareaId.data('upload-url'),
  499. type: 'POST',
  500. data: form,
  501. async: true,
  502. cache: false,
  503. contentType: false,
  504. enctype: 'multipart/form-data',
  505. processData: false,
  506. beforeSend: function() {
  507. console.log('Uploading...');
  508. $('.upload-progress[data-field-name='+field_name+']').show();
  509. },
  510. success: function (response) {
  511. $('.upload-progress[data-field-name='+field_name+']').hide();
  512. if (response.status == 200) {
  513. console.log(response);
  514. markdownToImageLink(
  515. editor=editor,
  516. imageData={name: response.name, link: response.link}
  517. );
  518. }else if (response.status == 403) {
  519. alert(response.data.error); // invalid client id
  520. }
  521. else {
  522. console.log(response)
  523. }
  524. },
  525. error: function(response) {
  526. console.log("error", response);
  527. $('.upload-progress[data-field-name='+field_name+']').hide();
  528. }
  529. });
  530. return false;
  531. };
  532. // Trigger Keyboards
  533. editor.commands.addCommand({
  534. name: 'markdownToBold',
  535. bindKey: {win: 'Ctrl-B', mac: 'Command-B'},
  536. exec: function(editor) {
  537. markdownToBold(editor);
  538. },
  539. readOnly: true
  540. });
  541. editor.commands.addCommand({
  542. name: 'markdownToItalic',
  543. bindKey: {win: 'Ctrl-I', mac: 'Command-I'},
  544. exec: function(editor) {
  545. markdownToItalic(editor);
  546. },
  547. readOnly: true
  548. });
  549. editor.commands.addCommand({
  550. name: 'markdownToUnderscores',
  551. bindKey: {win: 'Ctrl-Shift-U', mac: 'Command-Option-U'},
  552. exec: function(editor) {
  553. markdownToUnderscores(editor);
  554. },
  555. readOnly: true
  556. });
  557. editor.commands.addCommand({
  558. name: 'markdownToStrikethrough',
  559. bindKey: {win: 'Ctrl-Shift-S', mac: 'Command-Option-S'},
  560. exec: function(editor) {
  561. markdownToStrikethrough(editor);
  562. },
  563. readOnly: true
  564. });
  565. editor.commands.addCommand({
  566. name: 'markdownToHorizontal',
  567. bindKey: {win: 'Ctrl-H', mac: 'Command-H'},
  568. exec: function(editor) {
  569. markdownToHorizontal(editor);
  570. },
  571. readOnly: true
  572. });
  573. editor.commands.addCommand({
  574. name: 'markdownToH1',
  575. bindKey: {win: 'Ctrl-Alt-1', mac: 'Command-Option-1'},
  576. exec: function(editor) {
  577. markdownToH1(editor);
  578. },
  579. readOnly: true
  580. });
  581. editor.commands.addCommand({
  582. name: 'markdownToH2',
  583. bindKey: {win: 'Ctrl-Alt-2', mac: 'Command-Option-3'},
  584. exec: function(editor) {
  585. markdownToH2(editor);
  586. },
  587. readOnly: true
  588. });
  589. editor.commands.addCommand({
  590. name: 'markdownToH3',
  591. bindKey: {win: 'Ctrl-Alt-3', mac: 'Command-Option-3'},
  592. exec: function(editor) {
  593. markdownToH3(editor);
  594. },
  595. readOnly: true
  596. });
  597. editor.commands.addCommand({
  598. name: 'markdownToPre',
  599. bindKey: {win: 'Ctrl-Alt-P', mac: 'Command-Option-P'},
  600. exec: function(editor) {
  601. markdownToPre(editor);
  602. },
  603. readOnly: true
  604. });
  605. editor.commands.addCommand({
  606. name: 'markdownToCode',
  607. bindKey: {win: 'Ctrl-Alt-C', mac: 'Command-Option-C'},
  608. exec: function(editor) {
  609. markdownToCode(editor);
  610. },
  611. readOnly: true
  612. });
  613. editor.commands.addCommand({
  614. name: 'markdownToBlockQuote',
  615. bindKey: {win: 'Ctrl-Q', mac: 'Command-Q'},
  616. exec: function(editor) {
  617. markdownToBlockQuote(editor);
  618. },
  619. readOnly: true
  620. });
  621. editor.commands.addCommand({
  622. name: 'markdownToUnorderedList',
  623. bindKey: {win: 'Ctrl-U', mac: 'Command-U'},
  624. exec: function(editor) {
  625. markdownToUnorderedList(editor);
  626. },
  627. readOnly: true
  628. });
  629. editor.commands.addCommand({
  630. name: 'markdownToOrderedList',
  631. bindKey: {win: 'Ctrl-Shift+O', mac: 'Command-Option-O'},
  632. exec: function(editor) {
  633. markdownToOrderedList(editor);
  634. },
  635. readOnly: true
  636. });
  637. editor.commands.addCommand({
  638. name: 'markdownToLink',
  639. bindKey: {win: 'Ctrl-L', mac: 'Command-L'},
  640. exec: function(editor) {
  641. markdownToLink(editor);
  642. },
  643. readOnly: true
  644. });
  645. editor.commands.addCommand({
  646. name: 'markdownToImageLink',
  647. bindKey: {win: 'Ctrl-Shift-I', mac: 'Command-Option-I'},
  648. exec: function(editor) {
  649. markdownToImageLink(editor);
  650. },
  651. readOnly: true
  652. });
  653. if (editorConfig.mention === 'true') {
  654. editor.commands.addCommand({
  655. name: 'markdownToMention',
  656. bindKey: {win: 'Ctrl-M', mac: 'Command-M'},
  657. exec: function(editor) {
  658. markdownToMention(editor);
  659. },
  660. readOnly: true
  661. });
  662. }
  663. // Trigger Click
  664. $('.markdown-bold[data-field-name='+field_name+']').click(function(){
  665. markdownToBold(editor);
  666. });
  667. $('.markdown-italic[data-field-name='+field_name+']').click(function(){
  668. markdownToItalic(editor);
  669. });
  670. $('.markdown-horizontal[data-field-name='+field_name+']').click(function(){
  671. markdownToHorizontal(editor);
  672. });
  673. $('.markdown-h1[data-field-name='+field_name+']').click(function(){
  674. markdownToH1(editor);
  675. });
  676. $('.markdown-h2[data-field-name='+field_name+']').click(function(){
  677. markdownToH2(editor);
  678. });
  679. $('.markdown-h3[data-field-name='+field_name+']').click(function(){
  680. markdownToH3(editor);
  681. });
  682. $('.markdown-pre[data-field-name='+field_name+']').click(function(){
  683. markdownToPre(editor);
  684. });
  685. $('.markdown-code[data-field-name='+field_name+']').click(function(){
  686. markdownToCode(editor);
  687. });
  688. $('.markdown-blockquote[data-field-name='+field_name+']').click(function(){
  689. markdownToBlockQuote(editor);
  690. });
  691. $('.markdown-unordered-list[data-field-name='+field_name+']').click(function(){
  692. markdownToUnorderedList(editor);
  693. });
  694. $('.markdown-ordered-list[data-field-name='+field_name+']').click(function(){
  695. markdownToOrderedList(editor);
  696. });
  697. $('.markdown-link[data-field-name='+field_name+']').click(function(){
  698. markdownToLink(editor);
  699. });
  700. $('.markdown-image-link[data-field-name='+field_name+']').click(function(){
  701. markdownToImageLink(editor);
  702. });
  703. // Custom decission for toolbar buttons.
  704. var btnMention = $('.markdown-direct-mention[data-field-name='+field_name+']'); // To Direct Mention
  705. var btnUpload = $('.markdown-image-upload[data-field-name='+field_name+']'); // To Upload Image
  706. if (editorConfig.mention === 'true' && editorConfig.imgur === 'true') {
  707. btnMention.click(function(){
  708. markdownToMention(editor);
  709. });
  710. btnUpload.on('change', function(evt){
  711. evt.preventDefault();
  712. markdownToUploadImage(editor);
  713. });
  714. }else if (editorConfig.mention === 'true' && editorConfig.imgur === 'false') {
  715. btnMention.click(function(){
  716. markdownToMention(editor);
  717. });
  718. btnUpload.remove();
  719. }else if (editorConfig.mention === 'false' && editorConfig.imgur === 'true') {
  720. btnMention.remove();
  721. btnUpload.on('change', function(evt){
  722. evt.preventDefault();
  723. markdownToUploadImage(editor);
  724. });
  725. }
  726. else {
  727. btnMention.remove();
  728. btnUpload.remove();
  729. // Disable help of `mention`
  730. $('.markdown-reference tbody tr')[1].remove();
  731. }
  732. // Modal Popup for Help Guide & Emoji Cheat Sheet
  733. $('.markdown-help[data-field-name='+field_name+']').click(function(){
  734. $('.modal-help-guide[data-field-name='+field_name+']').modal('show');
  735. });
  736. // Toggle editor, preview, maximize
  737. var mainMartor = $(obj);
  738. var martorField = $('.martor-field-'+field_name);
  739. var btnToggleMaximize = $('.markdown-toggle-maximize[data-field-name='+field_name+']');
  740. // Toggle maximize and minimize
  741. var handleToggleMinimize = function() {
  742. $(document.body).removeClass('overflow');
  743. $(this).attr({'title': 'Full Screen'});
  744. $(this).find('.minimize.icon').removeClass('minimize').addClass('maximize');
  745. $('.main-martor-fullscreen').find('.martor-preview').removeAttr('style');
  746. mainMartor.removeClass('main-martor-fullscreen');
  747. martorField.removeAttr('style');
  748. editor.resize();
  749. }
  750. var handleToggleMaximize = function(selector) {
  751. selector.attr({'title': 'Minimize'});
  752. selector.find('.maximize.icon').removeClass('maximize').addClass('minimize');
  753. mainMartor.addClass('main-martor-fullscreen');
  754. var clientHeight = document.body.clientHeight-90;
  755. martorField.attr({'style':'height:'+clientHeight+'px'});
  756. var preview = $('.main-martor-fullscreen').find('.martor-preview');
  757. preview.attr({'style': 'overflow-y: auto;height:'+clientHeight+'px'});
  758. editor.resize();
  759. selector.one('click', handleToggleMinimize);
  760. $(document.body).addClass('overflow');
  761. }
  762. btnToggleMaximize.on('click', function(){
  763. handleToggleMaximize($(this));
  764. });
  765. // Exit full screen when `ESC` is pressed.
  766. $(document).keyup(function(e) {
  767. if (e.keyCode == 27 && mainMartor.hasClass('main-martor-fullscreen')) {
  768. $('.minimize.icon').trigger('click');
  769. }
  770. });
  771. // markdown insert emoji from the modal
  772. $('.markdown-emoji[data-field-name='+field_name+']').click(function(){
  773. var modalEmoji = $('.modal-emoji[data-field-name='+field_name+']');
  774. var emojiList = emojis; // from `plugins/js/emojis.min.js`
  775. var segmentEmoji = modalEmoji.find('.emoji-content-body');
  776. var loaderInit = modalEmoji.find('.emoji-loader-init');
  777. // setup initial loader
  778. segmentEmoji.html('');
  779. loaderInit.show();
  780. modalEmoji.modal({
  781. onVisible: function () {
  782. for (var i = 0; i < emojiList.length; i++) {
  783. var linkEmoji = textareaId.data('base-emoji-url') + emojiList[i].replace(/:/g, '') + '.png';
  784. segmentEmoji.append(''
  785. +'<div class="four wide column">'
  786. + '<p><a data-emoji-target="'+emojiList[i]+'" class="insert-emoji">'
  787. + '<img class="marked-emoji" src="'+linkEmoji+'"> '+emojiList[i]
  788. + '</a></p>'
  789. +'</div>');
  790. $('a[data-emoji-target="'+emojiList[i]+'"]').click(function(){
  791. markdownToEmoji(editor, $(this).data('emoji-target'));
  792. modalEmoji.modal('hide', 100);
  793. });
  794. }
  795. loaderInit.hide();
  796. modalEmoji.modal('refresh');
  797. }
  798. }).modal('show');
  799. });
  800. // Set initial value if has the content before.
  801. if (textareaId.val() != '') {
  802. editor.setValue(textareaId.val());
  803. }
  804. });// end each `mainMartor`
  805. };
  806. $(function() {
  807. $('.martor').martor();
  808. });
  809. })(jQuery);
  810. $( document ).ready(function(){
  811. // Semantic UI
  812. $('.ui.martor-toolbar .ui.dropdown').dropdown();
  813. $('.ui.tab-martor-menu .item').tab();
  814. });