MarkdownTableInterceptor.js 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import { BasicInterceptor } from '@growi/core/dist/utils';
  2. import MarkdownTable from '~/client/models/MarkdownTable';
  3. import {
  4. getStrFromBot, addRowToMarkdownTable, getStrToEot, isEndOfLine, mergeMarkdownTable,
  5. } from './MarkdownTableUtil';
  6. /**
  7. * Interceptor for markdown table
  8. */
  9. export default class MarkdownTableInterceptor extends BasicInterceptor {
  10. /**
  11. * @inheritdoc
  12. */
  13. isInterceptWhen(contextName) {
  14. return (
  15. contextName === 'preHandleEnter'
  16. );
  17. }
  18. /**
  19. * return boolean value whether processable parallel
  20. */
  21. isProcessableParallel() {
  22. return false;
  23. }
  24. addRow(cm) {
  25. // get lines all of table from current position to beginning of table
  26. const strFromBot = getStrFromBot(cm);
  27. let table = MarkdownTable.fromMarkdownString(strFromBot);
  28. addRowToMarkdownTable(table);
  29. const strToEot = getStrToEot(cm);
  30. const tableBottom = MarkdownTable.fromMarkdownString(strToEot);
  31. if (tableBottom.table.length > 0) {
  32. table = mergeMarkdownTable([table, tableBottom]);
  33. }
  34. replaceMarkdownTableWithReformed(cm, table);
  35. }
  36. reformTable(cm) {
  37. const tableStr = getStrFromBot(cm) + getStrToEot(cm);
  38. const table = MarkdownTable.fromMarkdownString(tableStr);
  39. replaceMarkdownTableWithReformed(cm, table);
  40. }
  41. removeRow(editor) {
  42. editor.replaceLine('\n');
  43. }
  44. /**
  45. * @inheritdoc
  46. */
  47. async process(contextName, ...args) {
  48. const context = Object.assign(args[0]); // clone
  49. const editor = context.editor; // AbstractEditor instance
  50. // "autoFormatMarkdownTable" may be undefined, so it is compared to true and converted to bool.
  51. const noIntercept = (context.autoFormatMarkdownTable === false);
  52. // https://regex101.com/r/1UuWBJ/3
  53. const emptyLineOfTableRE = /^([^\r\n|]*)\|((\s*\|)+)$/;
  54. // do nothing if editor is not a CodeMirrorEditor or no intercept
  55. if (editor == null || editor.getCodeMirror() == null || noIntercept) {
  56. return context;
  57. }
  58. const cm = editor.getCodeMirror();
  59. const isInTable = isInTable(cm);
  60. const isLastRow = getStrToEot(cm) === editor.getStrToEol();
  61. if (isInTable) {
  62. // at EOL in the table
  63. if (isEndOfLine(cm)) {
  64. this.addRow(cm);
  65. }
  66. // last empty row
  67. else if (isLastRow && emptyLineOfTableRE.test(editor.getStrFromBol() + editor.getStrToEol())) {
  68. this.removeRow(editor);
  69. }
  70. else {
  71. this.reformTable(cm);
  72. }
  73. // report to manager that handling was done
  74. context.handlers.push(this.className);
  75. return context;
  76. }
  77. }
  78. }