MarkdownDrawioUtil.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /**
  2. * Utility for markdown drawio
  3. */
  4. class MarkdownDrawioUtil {
  5. constructor() {
  6. this.lineBeginPartOfDrawioRE = /^```(\s.*)drawio$/;
  7. this.lineEndPartOfDrawioRE = /^```$/;
  8. this.curPos = this.curPos.bind(this);
  9. this.doc = this.doc.bind(this);
  10. }
  11. // get cursor position from editor
  12. curPos(editor) {
  13. return editor.state.selection.main.head;
  14. }
  15. // get doc from editor
  16. doc(editor) {
  17. return editor.state.doc;
  18. }
  19. // get first line number
  20. firstLineNum() {
  21. return 1;
  22. }
  23. // get last line number
  24. lastLineNum(editor) {
  25. return this.doc(editor).lines;
  26. }
  27. // get cursor line
  28. cursorLine(editor) {
  29. return this.doc(editor).lineAt(this.curPos(editor));
  30. }
  31. // get line
  32. getLine(editor, lineNum) {
  33. return this.doc(editor).line(lineNum);
  34. }
  35. /**
  36. * return the postion of the BOD(beginning of drawio)
  37. * (If the BOD is not found after the cursor or the EOD is found before the BOD, return null)
  38. */
  39. getBod(editor) {
  40. if (this.lineBeginPartOfDrawioRE.test(this.cursorLine(editor)).text) {
  41. // get the beginning of the line where the cursor is located
  42. return this.cursorLine(editor).from;
  43. }
  44. let line = this.cursorLine(editor).number - 1;
  45. let isFound = false;
  46. for (; line >= this.firstLineNum(); line--) {
  47. const strLine = this.getLine(editor, line).text;
  48. if (this.lineBeginPartOfDrawioRE.test(strLine)) {
  49. isFound = true;
  50. break;
  51. }
  52. if (this.lineEndPartOfDrawioRE.test(strLine)) {
  53. isFound = false;
  54. break;
  55. }
  56. }
  57. if (!isFound) {
  58. return null;
  59. }
  60. const botLine = Math.max(this.firstLineNum(), line);
  61. return this.getLine(editor, botLine).from;
  62. }
  63. /**
  64. * return the postion of the EOD(end of drawio)
  65. * (If the EOD is not found after the cursor or the BOD is found before the EOD, return null)
  66. */
  67. getEod(editor) {
  68. if (this.lineEndPartOfDrawioRE.test(this.cursorLine(editor)).text) {
  69. // get the end of the line where the cursor is located
  70. return this.cursorLine(editor).to;
  71. }
  72. let line = this.cursorLine(editor).number + 1;
  73. let isFound = false;
  74. for (; line <= this.lastLineNum(editor); line++) {
  75. const strLine = this.getLine(editor, line).text;
  76. if (this.lineEndPartOfDrawioRE.test(strLine)) {
  77. isFound = true;
  78. break;
  79. }
  80. if (this.lineBeginPartOfDrawioRE.test(strLine)) {
  81. isFound = false;
  82. break;
  83. }
  84. }
  85. if (!isFound) {
  86. return null;
  87. }
  88. const eodLine = Math.min(line, this.lastLineNum(editor));
  89. return this.getLine(editor, eodLine).to;
  90. }
  91. /**
  92. * return boolean value whether the cursor position is in a drawio
  93. */
  94. isInDrawioBlock(editor) {
  95. const bod = this.getBod(editor);
  96. const eod = this.getEod(editor);
  97. if (bod === null || eod === null) {
  98. return false;
  99. }
  100. return JSON.stringify(bod) !== JSON.stringify(eod);
  101. }
  102. /**
  103. * return drawioData instance where the cursor is
  104. * (If the cursor is not in a drawio block, return null)
  105. */
  106. getMarkdownDrawioMxfile(editor) {
  107. if (this.isInDrawioBlock(editor)) {
  108. const bod = this.getBod(editor);
  109. const eod = this.getEod(editor);
  110. // skip block begin sesion("``` drawio")
  111. const bodLineNum = this.doc(editor).lineAt(bod).number + 1;
  112. const bodLine = this.getLine(editor, bodLineNum).from;
  113. // skip block end sesion("```")
  114. const eodLineNum = this.doc(editor).lineAt(eod).number - 1;
  115. const eodLine = this.getLine(editor, eodLineNum).to;
  116. return editor.state.sliceDoc(bodLine, eodLine);
  117. }
  118. return null;
  119. }
  120. replaceFocusedDrawioWithEditor(editor, drawioData) {
  121. const drawioBlock = ['``` drawio', drawioData.toString(), '```'].join('\n');
  122. let beginPos;
  123. let endPos;
  124. if (this.isInDrawioBlock(editor)) {
  125. beginPos = this.getBod(editor);
  126. endPos = this.getEod(editor);
  127. }
  128. else {
  129. beginPos = this.cursorLine(editor).from;
  130. endPos = this.cursorLine(editor).to;
  131. }
  132. editor.dispatch({
  133. changes: {
  134. from: beginPos,
  135. to: endPos,
  136. insert: drawioBlock,
  137. },
  138. });
  139. }
  140. /**
  141. * return markdown where the drawioData specified by line number params is replaced to the drawioData specified by drawioData param
  142. * @param {string} drawioData
  143. * @param {string} markdown
  144. * @param beginLineNumber
  145. * @param endLineNumber
  146. */
  147. replaceDrawioInMarkdown(drawioData, markdown, beginLineNumber, endLineNumber) {
  148. const splitMarkdown = markdown.split(/\r\n|\r|\n/);
  149. const markdownBeforeDrawio = splitMarkdown.slice(0, beginLineNumber - 1);
  150. const markdownAfterDrawio = splitMarkdown.slice(endLineNumber);
  151. let newMarkdown = '';
  152. if (markdownBeforeDrawio.length > 0) {
  153. newMarkdown += `${markdownBeforeDrawio.join('\n')}\n`;
  154. }
  155. newMarkdown += '``` drawio\n';
  156. newMarkdown += drawioData;
  157. newMarkdown += '\n```';
  158. if (markdownAfterDrawio.length > 0) {
  159. newMarkdown += `\n${markdownAfterDrawio.join('\n')}`;
  160. }
  161. return newMarkdown;
  162. }
  163. /**
  164. * return an array of the starting line numbers of the drawio sections found in markdown
  165. */
  166. findAllDrawioSection(editor) {
  167. const lineNumbers = [];
  168. // refs: https://github.com/codemirror/CodeMirror/blob/5.64.0/addon/fold/foldcode.js#L106-L111
  169. for (let i = this.firstLineNum(), e = this.lastLineNum(editor); i <= e; i++) {
  170. const lineText = this.getLine(editor, i + 1).text;
  171. const match = this.lineBeginPartOfDrawioRE.exec(lineText);
  172. if (match) {
  173. lineNumbers.push(i);
  174. }
  175. }
  176. return lineNumbers;
  177. }
  178. }
  179. // singleton pattern
  180. const instance = new MarkdownDrawioUtil();
  181. Object.freeze(instance);
  182. export default instance;