editorCommonEvent.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import {processHeading} from "../ir/process";
  2. import {processKeydown as irProcessKeydown} from "../ir/processKeydown";
  3. import {getMarkdown} from "../markdown/getMarkdown";
  4. import {processHeading as processHeadingSV} from "../sv/process";
  5. import {processKeydown as mdProcessKeydown} from "../sv/processKeydown";
  6. import {setEditMode} from "../toolbar/EditMode";
  7. import {hidePanel} from "../toolbar/setToolbar";
  8. import {uploadFiles} from "../upload";
  9. import {getCursorPosition} from "../util/selection";
  10. import {afterRenderEvent} from "../wysiwyg/afterRenderEvent";
  11. import {processKeydown} from "../wysiwyg/processKeydown";
  12. import {removeHeading, setHeading} from "../wysiwyg/setHeading";
  13. import {getEventName, isCtrl} from "./compatibility";
  14. import {getSelectText} from "./getSelectText";
  15. import {hasClosestByMatchTag} from "./hasClosest";
  16. import {matchHotKey} from "./hotKey";
  17. export const focusEvent = (vditor: IVditor, editorElement: HTMLElement) => {
  18. editorElement.addEventListener("focus", () => {
  19. if (vditor.options.focus) {
  20. vditor.options.focus(getMarkdown(vditor));
  21. }
  22. hidePanel(vditor, ["subToolbar"]);
  23. });
  24. };
  25. export const blurEvent = (vditor: IVditor, editorElement: HTMLElement) => {
  26. editorElement.addEventListener("blur", () => {
  27. if (vditor.options.blur) {
  28. vditor.options.blur(getMarkdown(vditor));
  29. }
  30. });
  31. };
  32. export const dropEvent = (vditor: IVditor, editorElement: HTMLElement) => {
  33. if (vditor.options.upload.url || vditor.options.upload.handler) {
  34. editorElement.addEventListener("drop",
  35. (event: CustomEvent & { dataTransfer?: DataTransfer, target: HTMLElement }) => {
  36. if (event.dataTransfer.types[0] !== "Files") {
  37. return;
  38. }
  39. const files = event.dataTransfer.items;
  40. if (files.length > 0) {
  41. uploadFiles(vditor, files);
  42. }
  43. event.preventDefault();
  44. });
  45. }
  46. };
  47. export const scrollCenter = (vditor: IVditor) => {
  48. if (!vditor.options.typewriterMode) {
  49. return;
  50. }
  51. const editorElement = vditor[vditor.currentMode].element;
  52. const cursorTop = getCursorPosition(editorElement).top;
  53. if (typeof vditor.options.height === "string" && !vditor.element.classList.contains("vditor--fullscreen")) {
  54. window.scrollTo(window.scrollX,
  55. cursorTop + vditor.element.offsetTop + vditor.toolbar.element.offsetHeight - window.innerHeight / 2 + 10);
  56. }
  57. if (typeof vditor.options.height === "number" || vditor.element.classList.contains("vditor--fullscreen")) {
  58. editorElement.scrollTop = cursorTop + editorElement.scrollTop - editorElement.clientHeight / 2 + 10;
  59. }
  60. };
  61. export const hotkeyEvent = (vditor: IVditor, editorElement: HTMLElement) => {
  62. editorElement.addEventListener("keydown", (event: KeyboardEvent & { target: HTMLElement }) => {
  63. // hint: 上下选择
  64. if ((vditor.options.hint.at || vditor.toolbar.elements.emoji) && vditor.hint.select(event, vditor)) {
  65. return;
  66. }
  67. if (vditor.currentMode === "sv") {
  68. if (mdProcessKeydown(vditor, event)) {
  69. return;
  70. }
  71. } else if (vditor.currentMode === "wysiwyg") {
  72. if (processKeydown(vditor, event)) {
  73. return;
  74. }
  75. } else if (vditor.currentMode === "ir") {
  76. if (irProcessKeydown(vditor, event)) {
  77. return;
  78. }
  79. }
  80. if (vditor.options.ctrlEnter && matchHotKey("⌘-Enter", event)) {
  81. vditor.options.ctrlEnter(getMarkdown(vditor));
  82. event.preventDefault();
  83. return;
  84. }
  85. // undo
  86. if (matchHotKey("⌘-Z", event) && !vditor.toolbar.elements.undo) {
  87. vditor.undo.undo(vditor);
  88. event.preventDefault();
  89. return;
  90. }
  91. // redo
  92. if (matchHotKey("⌘-Y", event) && !vditor.toolbar.elements.redo) {
  93. vditor.undo.redo(vditor);
  94. event.preventDefault();
  95. return;
  96. }
  97. // esc
  98. if (event.key === "Escape") {
  99. if (vditor.hint.element.style.display === "block") {
  100. vditor.hint.element.style.display = "none";
  101. } else if (vditor.options.esc) {
  102. vditor.options.esc(getMarkdown(vditor));
  103. }
  104. event.preventDefault();
  105. return;
  106. }
  107. // h1 - h6 hotkey
  108. if (isCtrl(event) && event.altKey && !event.shiftKey && /^Digit[1-6]$/.test(event.code)) {
  109. if (vditor.currentMode === "wysiwyg") {
  110. const tagName = event.code.replace("Digit", "H");
  111. if (hasClosestByMatchTag(getSelection().getRangeAt(0).startContainer, tagName)) {
  112. removeHeading(vditor);
  113. } else {
  114. setHeading(vditor, tagName);
  115. }
  116. afterRenderEvent(vditor);
  117. } else if (vditor.currentMode === "sv") {
  118. processHeadingSV(vditor, "#".repeat(parseInt(event.code.replace("Digit", ""), 10)) + " ");
  119. } else if (vditor.currentMode === "ir") {
  120. processHeading(vditor, "#".repeat(parseInt(event.code.replace("Digit", ""), 10)) + " ");
  121. }
  122. event.preventDefault();
  123. return true;
  124. }
  125. // toggle edit mode
  126. if (isCtrl(event) && event.altKey && !event.shiftKey && /^Digit[7-9]$/.test(event.code)) {
  127. if (event.code === "Digit7") {
  128. setEditMode(vditor, "wysiwyg", event);
  129. } else if (event.code === "Digit8") {
  130. setEditMode(vditor, "ir", event);
  131. } else if (event.code === "Digit9") {
  132. setEditMode(vditor, "sv", event);
  133. }
  134. return true;
  135. }
  136. // toolbar action
  137. vditor.options.toolbar.find((menuItem: IMenuItem) => {
  138. if (!menuItem.hotkey || menuItem.toolbar) {
  139. if (menuItem.toolbar) {
  140. const sub = menuItem.toolbar.find((subMenuItem: IMenuItem) => {
  141. if (!subMenuItem.hotkey) {
  142. return false;
  143. }
  144. if (matchHotKey(subMenuItem.hotkey, event)) {
  145. vditor.toolbar.elements[subMenuItem.name].children[0]
  146. .dispatchEvent(new CustomEvent(getEventName()));
  147. event.preventDefault();
  148. return true;
  149. }
  150. });
  151. return sub ? true : false;
  152. }
  153. return false;
  154. }
  155. if (matchHotKey(menuItem.hotkey, event)) {
  156. vditor.toolbar.elements[menuItem.name].children[0].dispatchEvent(new CustomEvent(getEventName()));
  157. event.preventDefault();
  158. return true;
  159. }
  160. });
  161. });
  162. };
  163. export const selectEvent = (vditor: IVditor, editorElement: HTMLElement) => {
  164. if (!vditor.options.select) {
  165. return;
  166. }
  167. editorElement.addEventListener("selectstart", (event: Event) => {
  168. editorElement.onmouseup = () => {
  169. const selectText = getSelectText(vditor[vditor.currentMode].element);
  170. if (selectText) {
  171. vditor.options.select(selectText);
  172. }
  173. };
  174. });
  175. };