agent-for-hackmd.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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. const styleFilePath = '{{styleFilePath}}'; // will be replaced by swig
  18. /**
  19. * Insert link tag to load style file
  20. */
  21. function insertStyle() {
  22. const element = document.createElement('link');
  23. element.href = styleFilePath;
  24. element.rel = 'stylesheet';
  25. document.getElementsByTagName('head')[0].appendChild(element);
  26. }
  27. /**
  28. * return the value of CodeMirror
  29. */
  30. function getValueOfCodemirror() {
  31. // get CodeMirror instance
  32. const editor = window.editor;
  33. return editor.doc.getValue();
  34. }
  35. /**
  36. * set the specified document to CodeMirror
  37. * @param {string} document
  38. */
  39. function setValueToCodemirror(document) {
  40. // get CodeMirror instance
  41. const editor = window.editor;
  42. editor.doc.setValue(document);
  43. }
  44. /**
  45. * postMessage to GROWI to notify body changes
  46. * @param {string} body
  47. */
  48. function postParentToNotifyBodyChanges(body) {
  49. window.growi.notifyBodyChanges(body);
  50. }
  51. // generate debounced function
  52. const debouncedPostParentToNotifyBodyChanges = debounce(1500, postParentToNotifyBodyChanges);
  53. /**
  54. * postMessage to GROWI to save with shortcut
  55. * @param {string} document
  56. */
  57. function postParentToSaveWithShortcut(document) {
  58. window.growi.saveWithShortcut(document);
  59. }
  60. function addEventListenersToCodemirror() {
  61. // get CodeMirror instance
  62. const codemirror = window.CodeMirror;
  63. // get CodeMirror editor instance
  64. const editor = window.editor;
  65. //// change event
  66. editor.on('change', (cm, change) => {
  67. debouncedPostParentToNotifyBodyChanges(cm.doc.getValue());
  68. });
  69. //// save event
  70. // Reset save commands and Cmd-S/Ctrl-S shortcuts that initialized by HackMD
  71. codemirror.commands.save = function(cm) {
  72. postParentToSaveWithShortcut(cm.doc.getValue());
  73. };
  74. delete editor.options.extraKeys['Cmd-S'];
  75. delete editor.options.extraKeys['Ctrl-S'];
  76. }
  77. /**
  78. * main
  79. */
  80. (function() {
  81. // check HackMD is in iframe
  82. if (window === window.parent) {
  83. console.log('[GROWI] Loading agent for HackMD is not processed because currently not in iframe');
  84. return;
  85. }
  86. console.log('[HackMD] Loading GROWI agent for HackMD...');
  87. insertStyle();
  88. window.addEventListener('load', (event) => {
  89. console.log('loaded');
  90. addEventListenersToCodemirror();
  91. });
  92. const connection = Penpal.connectToParent({
  93. parentOrigin: allowedOrigin,
  94. // Methods child is exposing to parent
  95. methods: {
  96. getValue() {
  97. return getValueOfCodemirror();
  98. },
  99. setValue(newValue) {
  100. setValueToCodemirror(newValue);
  101. },
  102. }
  103. });
  104. connection.promise.then(parent => {
  105. window.growi = parent;
  106. });
  107. console.log('[HackMD] GROWI agent for HackMD has successfully loaded.');
  108. }());