Просмотр исходного кода

Resolved conflict cherry picking https://github.com/weseek/growi/pull/6562/commits/3f368383528636380f7463af911869aabe46c5a0

Taichi Masuyama 3 лет назад
Родитель
Сommit
8d50d69ce8

+ 66 - 39
packages/app/src/components/PageEditor/CodeMirrorEditor.jsx

@@ -8,7 +8,6 @@ import PropTypes from 'prop-types';
 import { Button } from 'reactstrap';
 import * as loadScript from 'simple-load-script';
 import urljoin from 'url-join';
-import { debounce } from 'throttle-debounce';
 
 import InterceptorManager from '~/services/interceptor-manager';
 import loggerFactory from '~/utils/logger';
@@ -116,7 +115,8 @@ class CodeMirrorEditor extends AbstractEditor {
       isCheatsheetModalShown: false,
       additionalClassSet: new Set(),
       isEmojiPickerShown: false,
-      emojiSearchText: null,
+      emojiSearchText: '',
+      isEmojiPickerMode: false,
     };
 
     this.gridEditModal = React.createRef();
@@ -141,7 +141,15 @@ class CodeMirrorEditor extends AbstractEditor {
     this.pasteHandler = this.pasteHandler.bind(this);
     this.cursorHandler = this.cursorHandler.bind(this);
     this.changeHandler = this.changeHandler.bind(this);
-    this.keyUpHandler = this.keyUpHandler.bind(this);
+    this.onEmojiPickerMode = this.onEmojiPickerMode.bind(this);
+    this.offEmojiPickerMode = this.offEmojiPickerMode.bind(this);
+    this.resetEmojiSearchText = this.resetEmojiSearchText.bind(this);
+    this.resetEmojiPickerInfo = this.resetEmojiPickerInfo.bind(this);
+    this.shouldLoadEmojiPicker = this.shouldLoadEmojiPicker.bind(this);
+    this.loadEmojiSearchText = this.loadEmojiSearchText.bind(this);
+    this.showEmojiPicker = this.showEmojiPicker.bind(this);
+    this.loadEmojiPicker = this.loadEmojiPicker.bind(this);
+    this.keyPressHandler = this.keyPressHandler.bind(this);
 
     this.updateCheatsheetStates = this.updateCheatsheetStates.bind(this);
 
@@ -156,7 +164,6 @@ class CodeMirrorEditor extends AbstractEditor {
 
     this.foldDrawioSection = this.foldDrawioSection.bind(this);
     this.onSaveForDrawio = this.onSaveForDrawio.bind(this);
-    this.checkWhetherEmojiPickerShouldBeShown = this.checkWhetherEmojiPickerShouldBeShown.bind(this);
 
   }
 
@@ -587,26 +594,66 @@ class CodeMirrorEditor extends AbstractEditor {
 
   }
 
-  shouldCallCheckWhetherEmojiPickerShouldBeShown(event) { // 引数は要検討
-    const state = {
-      isEmojiPickerMode: true,
-      currentLetter: 'a', // :, Space, Backspace, Enter
-    };
+  onEmojiPickerMode() {
+    this.setState({ isEmojiPickerMode: true });
+  }
 
-    if (state.currentLetter === 'Space') {
-      state.isEmojiPickerMode = false;
-    }
-    if (state.currentLetter === ':') {
-      state.isEmojiPickerMode = true;
+  offEmojiPickerMode() {
+    this.setState({ isEmojiPickerMode: false });
+  }
+
+  resetEmojiSearchText() {
+    this.setState({ emojiSearchText: '' });
+  }
+
+  resetEmojiPickerInfo() {
+    this.offEmojiPickerMode();
+    this.resetEmojiSearchText();
+  }
+
+  shouldLoadEmojiPicker(ch) {
+    const lowerCh = ch.toLowerCase();
+
+    const isEmojiPickerMode = this.state.isEmojiPickerMode;
+    const isChValid = 'abcdefghijklmnopqrstuvwxyz0123456789-+_'.indexOf(lowerCh) !== -1;
+    return isEmojiPickerMode && isChValid;
+  }
+
+  loadEmojiSearchText(newchar) {
+    if (!this.state.isEmojiPickerMode) {
+      return;
     }
 
-    return event.key !== 'Backspace';
+    this.setState(prev => ({ emojiSearchText: prev.emojiSearchText.concat(newchar) }));
+  }
+
+  showEmojiPicker() {
+    // show emoji picker with a stored word
+    this.setState({ isEmojiPickerShown: true });
+    this.offEmojiPickerMode();
   }
 
-  keyUpHandler(editor, event) {
-    if (this.shouldCallCheckWhetherEmojiPickerShouldBeShown(event)) {
-      debounce(100, () => this.checkWhetherEmojiPickerShouldBeShown());
+  loadEmojiPicker(ch) {
+    this.loadEmojiSearchText(ch);
+
+    this.showEmojiPicker();
+  }
+
+  keyPressHandler(editor, event) {
+    const char = event.key;
+
+    if (char === ':') {
+      this.onEmojiPickerMode();
+      this.resetEmojiSearchText();
+      return;
     }
+
+    if (!this.shouldLoadEmojiPicker(char)) {
+      this.resetEmojiPickerInfo();
+      return;
+    }
+
+    this.loadEmojiPicker(char);
   }
 
   /**
@@ -630,26 +677,6 @@ class CodeMirrorEditor extends AbstractEditor {
 
   }
 
-  /**
-   * Show emoji picker component when emoji pattern (`:` + searchWord ) found
-   * eg `:a`, `:ap`
-   */
-  checkWhetherEmojiPickerShouldBeShown() {
-    const searchWord = this.emojiPickerHelper.getEmoji();
-
-    if (searchWord == null) {
-      this.setState({ isEmojiPickerShown: false });
-      this.setState({ emojiSearchText: null });
-    }
-    else {
-      this.setState({ emojiSearchText: searchWord });
-      // Show emoji picker after user stop typing
-      setTimeout(() => {
-        this.setState({ isEmojiPickerShown: true });
-      }, 700);
-    }
-  }
-
   /**
    * update states which related to cheatsheet
    * @param {boolean} isGfmModeTmp (use state.isGfmMode if null is set)
@@ -1062,7 +1089,7 @@ class CodeMirrorEditor extends AbstractEditor {
               this.props.onDragEnter(event);
             }
           }}
-          onKeyUp={this.keyUpHandler}
+          onKeyPress={this.keyPressHandler}
         />
 
         { this.renderLoadingKeymapOverlay() }

+ 43 - 65
packages/app/src/components/PageEditor/EmojiPickerHelper.ts

@@ -7,83 +7,61 @@ const EMOJI_PATTERN = new RegExp(/\B:[^:\s]+/);
 
 export default class EmojiPickerHelper {
 
-editor;
+  editor;
 
-pattern: RegExp;
+  pattern: RegExp;
 
-constructor(editor) {
-  this.editor = editor;
-  this.pattern = EMOJI_PATTERN;
-}
+  constructor(editor) {
+    this.editor = editor;
+    this.pattern = EMOJI_PATTERN;
+  }
 
-setStyle = ():CSSProperties => {
-  const offset = 20;
-  const emojiPickerHeight = 420;
-  const cursorPos = this.editor.cursorCoords(true);
-  const editorPos = this.editor.getWrapperElement().getBoundingClientRect();
-  // Emoji Picker bottom position exceed editor's bottom position
-  if (cursorPos.bottom + emojiPickerHeight > editorPos.bottom) {
+  setStyle = ():CSSProperties => {
+    const offset = 20;
+    const emojiPickerHeight = 420;
+    const cursorPos = this.editor.cursorCoords(true);
+    const editorPos = this.editor.getWrapperElement().getBoundingClientRect();
+    // Emoji Picker bottom position exceed editor's bottom position
+    if (cursorPos.bottom + emojiPickerHeight > editorPos.bottom) {
+      return {
+        top: editorPos.bottom - emojiPickerHeight,
+        left: cursorPos.left + offset,
+        position: 'fixed',
+      };
+    }
     return {
-      top: editorPos.bottom - emojiPickerHeight,
+      top: cursorPos.top + offset,
       left: cursorPos.left + offset,
       position: 'fixed',
     };
-  }
-  return {
-    top: cursorPos.top + offset,
-    left: cursorPos.left + offset,
-    position: 'fixed',
   };
-}
-
-getSearchCursor =() => {
-  const currentPos = this.editor.getCursor();
-  const sc = this.editor.getSearchCursor(this.pattern, currentPos, { multiline: false });
-  return sc;
-}
-
-// Add emoji when triggered by search
-addEmojiOnSearch = (emoji) => {
-  const currentPos = this.editor.getCursor();
-  const sc = this.getSearchCursor();
-  if (sc.findPrevious()) {
-    sc.replace(`${emoji.colons} `, this.editor.getTokenAt(currentPos).string);
-    this.editor.focus();
-    this.editor.refresh();
-  }
-}
 
+  getSearchCursor = () => {
+    const currentPos = this.editor.getCursor();
+    const sc = this.editor.getSearchCursor(this.pattern, currentPos, { multiline: false });
+    return sc;
+  };
 
-// Add emoji when triggered by click emoji icon on top of editor
-addEmoji = (emoji) => {
-  const currentPos = this.editor.getCursor();
-  const doc = this.editor.getDoc();
-  doc.replaceRange(`${emoji.colons} `, currentPos);
-  this.editor.focus();
-  this.editor.refresh();
-}
-
-getEmoji = () => {
-  const sc = this.getSearchCursor();
-  const currentPos = this.editor.getCursor();
-
-  if (sc.findPrevious()) {
-    const isInputtingEmoji = (currentPos.line === sc.to().line && currentPos.ch === sc.to().ch);
-    // current search cursor position
-    if (!isInputtingEmoji) {
-      return;
+  // Add emoji when triggered by search
+  addEmojiOnSearch = (emoji) => {
+    const currentPos = this.editor.getCursor();
+    const sc = this.getSearchCursor();
+    if (sc.findPrevious()) {
+      sc.replace(`${emoji.colons} `, this.editor.getTokenAt(currentPos).string);
+      this.editor.focus();
+      this.editor.refresh();
     }
-    const pos = {
-      line: sc.to().line,
-      ch: sc.to().ch,
-    };
-    const currentSearchText = sc.matches(true, pos).match[0];
-    const searchWord = currentSearchText.replace(':', '');
-    return searchWord;
-  }
+  };
 
-  return;
-}
+
+  // Add emoji when triggered by click emoji icon on top of editor
+  addEmoji = (emoji) => {
+    const currentPos = this.editor.getCursor();
+    const doc = this.editor.getDoc();
+    doc.replaceRange(`${emoji.colons} `, currentPos);
+    this.editor.focus();
+    this.editor.refresh();
+  };
 
 }