agent-for-hackmd.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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 { debounce } from 'throttle-debounce';
  13. const JSON = window.JSON;
  14. /* eslint-disable no-console */
  15. const allowedOrigin = '{{origin}}'; // will be replaced by swig
  16. const styleFilePath = '{{styleFilePath}}'; // will be replaced by swig
  17. /**
  18. * Validate origin
  19. * @param {object} event
  20. */
  21. function validateOrigin(event) {
  22. if (event.origin !== allowedOrigin) {
  23. console.error('[HackMD] Message is rejected.', 'Cause: "event.origin" and "allowedOrigin" does not match');
  24. return;
  25. }
  26. }
  27. /**
  28. * Insert link tag to load style file
  29. */
  30. function insertStyle() {
  31. const element = document.createElement('link');
  32. element.href = styleFilePath;
  33. element.rel = 'stylesheet';
  34. document.getElementsByTagName('head')[0].appendChild(element);
  35. }
  36. function postMessageOnChange(body) {
  37. const data = {
  38. operation: 'notifyBodyChanges',
  39. body
  40. };
  41. window.parent.postMessage(JSON.stringify(data), allowedOrigin);
  42. }
  43. function postMessageOnSave(body) {
  44. const data = {
  45. operation: 'save',
  46. body
  47. };
  48. window.parent.postMessage(JSON.stringify(data), allowedOrigin);
  49. }
  50. function addEventListenersToCodemirror() {
  51. // get CodeMirror instance
  52. const codemirror = window.CodeMirror;
  53. // get CodeMirror editor instance
  54. const editor = window.editor;
  55. //// change event
  56. // generate debounced function
  57. const debouncedPostMessageOnChange = debounce(1500, postMessageOnChange);
  58. editor.on('change', (cm, change) => {
  59. debouncedPostMessageOnChange(cm.doc.getValue());
  60. });
  61. //// save event
  62. // Reset save commands and Cmd-S/Ctrl-S shortcuts that initialized by HackMD
  63. codemirror.commands.save = function(cm) {
  64. postMessageOnSave(cm.doc.getValue());
  65. };
  66. delete editor.options.extraKeys['Cmd-S'];
  67. delete editor.options.extraKeys['Ctrl-S'];
  68. }
  69. function setValue(document) {
  70. // get CodeMirror instance
  71. const editor = window.editor;
  72. editor.doc.setValue(document);
  73. }
  74. /**
  75. * main
  76. */
  77. (function() {
  78. // check HackMD is in iframe
  79. if (window === window.parent) {
  80. console.log('[GROWI] Loading agent for HackMD is not processed because currently not in iframe');
  81. return;
  82. }
  83. console.log('[HackMD] Loading GROWI agent for HackMD...');
  84. insertStyle();
  85. // Add event listeners
  86. window.addEventListener('message', (event) => {
  87. validateOrigin(event);
  88. const data = JSON.parse(event.data);
  89. switch (data.operation) {
  90. case 'getValue':
  91. console.log('getValue called');
  92. break;
  93. case 'setValue':
  94. setValue(data.document);
  95. break;
  96. }
  97. });
  98. window.addEventListener('load', (event) => {
  99. console.log('loaded');
  100. addEventListenersToCodemirror();
  101. });
  102. console.log('[HackMD] GROWI agent for HackMD has successfully loaded.');
  103. }());