hackmd-agent.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /**
  2. * GROWI agent for HackMD
  3. *
  4. * This file will be transpiled as a single JS
  5. * and should be load from HackMD head via 'lib/routes/hackmd.js' route
  6. *
  7. * USAGE:
  8. * <script src="${hostname of GROWI}/_hackmd/load-agent"></script>
  9. *
  10. * @author Yuki Takei <yuki@weseek.co.jp>
  11. */
  12. import Penpal from 'penpal';
  13. // Penpal.debug = true;
  14. import { debounce } from 'throttle-debounce';
  15. /* eslint-disable no-console */
  16. const allowedOrigin = '{{origin}}'; // will be replaced by swig
  17. /**
  18. * return the value of CodeMirror
  19. */
  20. function getValueOfCodemirror() {
  21. // get CodeMirror instance
  22. const editor = window.editor;
  23. return editor.doc.getValue();
  24. }
  25. /**
  26. * set the specified document to CodeMirror
  27. * @param {string} value
  28. */
  29. function setValueToCodemirror(value) {
  30. // get CodeMirror instance
  31. const editor = window.editor;
  32. editor.doc.setValue(value);
  33. }
  34. /**
  35. * set the specified document to CodeMirror on window loaded
  36. * @param {string} value
  37. */
  38. function setValueToCodemirrorOnInit(newValue) {
  39. if (window.cmClient != null) {
  40. setValueToCodemirror(newValue);
  41. return;
  42. }
  43. else {
  44. const intervalId = setInterval(() => {
  45. if (window.cmClient != null) {
  46. clearInterval(intervalId);
  47. setValueToCodemirror(newValue);
  48. }
  49. }, 250);
  50. }
  51. }
  52. /**
  53. * postMessage to GROWI to notify body changes
  54. * @param {string} body
  55. */
  56. function postParentToNotifyBodyChanges(body) {
  57. window.growi.notifyBodyChanges(body);
  58. }
  59. // generate debounced function
  60. const debouncedPostParentToNotifyBodyChanges = debounce(1500, postParentToNotifyBodyChanges);
  61. /**
  62. * postMessage to GROWI to save with shortcut
  63. * @param {string} document
  64. */
  65. function postParentToSaveWithShortcut(document) {
  66. window.growi.saveWithShortcut(document);
  67. }
  68. function addEventListenersToCodemirror() {
  69. // get CodeMirror instance
  70. const codemirror = window.CodeMirror;
  71. // get CodeMirror editor instance
  72. const editor = window.editor;
  73. // e.g. 404 not found
  74. if (codemirror == null || editor == null) {
  75. return;
  76. }
  77. //// change event
  78. editor.on('change', (cm, change) => {
  79. debouncedPostParentToNotifyBodyChanges(cm.doc.getValue());
  80. });
  81. //// save event
  82. // Reset save commands and Cmd-S/Ctrl-S shortcuts that initialized by HackMD
  83. codemirror.commands.save = function(cm) {
  84. postParentToSaveWithShortcut(cm.doc.getValue());
  85. };
  86. delete editor.options.extraKeys['Cmd-S'];
  87. delete editor.options.extraKeys['Ctrl-S'];
  88. }
  89. function connectToParentWithPenpal() {
  90. const connection = Penpal.connectToParent({
  91. parentOrigin: allowedOrigin,
  92. // Methods child is exposing to parent
  93. methods: {
  94. getValue() {
  95. return getValueOfCodemirror();
  96. },
  97. setValue(newValue) {
  98. setValueToCodemirror(newValue);
  99. },
  100. setValueOnInit(newValue) {
  101. setValueToCodemirrorOnInit(newValue);
  102. }
  103. }
  104. });
  105. connection.promise.then(parent => {
  106. window.growi = parent;
  107. });
  108. }
  109. /**
  110. * main
  111. */
  112. (function() {
  113. // check HackMD is in iframe
  114. if (window === window.parent) {
  115. console.log('[GROWI] Loading agent for HackMD is not processed because currently not in iframe');
  116. return;
  117. }
  118. console.log('[HackMD] Loading GROWI agent for HackMD...');
  119. window.addEventListener('load', (event) => {
  120. console.log('loaded');
  121. addEventListenersToCodemirror();
  122. });
  123. connectToParentWithPenpal();
  124. console.log('[HackMD] GROWI agent for HackMD has successfully loaded.');
  125. }());