## とあるノートアプリから始まった色々調査 --- ### Agenda - key event - componsition event - content editable ---- ![](https://i.imgur.com/CEL18cQ.gif) Note: 之所以會想要做這個主題,是因為我很喜歡看到有新的筆記軟體就會跑去玩。而之前玩到一款網頁版的 note app, 發生了這樣的 bug 只要是CJK的文字就會壞掉。因為想知道為什麼開始調查,所以有了這個分享。 ---- Chrome ![](https://i.imgur.com/CEL18cQ.gif) ---- Firefox ![](https://i.imgur.com/xAKcedd.gif) --- ### key event Note: 簡單的入門開始。 因為我在開發和前端相關領域的資歷都很淺,今天講的內容可能過分簡單。如果有任何可以補充的歡迎隨時幫我補充。 ---- #### 大家都知道的 key event 在 browser 中,當按下鍵盤時會觸發三個事件 - keydown - keyup - keypress ---- keydown & keyup ```text The keydown event is fired when a key is pressed. The keydown and keyup events provide a code indicating which key is pressed. ``` Note: - 首先,「keydown」「keyup」比較好理解,keydown可以連續觸發,而 keyup 只會在放開的那一個瞬間觸發。 - 就像是玩遊戲的時候,可以長按集氣,但只會有一個放開的瞬間釋放 ---- Keydown v.s keypress ? ---- MDN: ```text keypress イベントとは異なり、 keydown イベントはすべてのキーにおいて、 文字が入力されるかどうかにかかわらず発生します。 ``` Note: keypress是一種 press ,雖然看起來很像 keydown,但 keypress 只會被「文字按鍵」觸發。 ---- では、問題です。 「はい」を入力するとき、「h」を押すと、 keypressは発火する?しない? <span>[実験しよう](https://www.w3.org/2002/09/tests/keys.html)<!-- .element: class="fragment" data-fragment-index="1" --></span> ---- A: 発火しない ---- bugについての推論 おそらくこちらのイベント処理がちゃんと処理されてないから、 keydownなどで混乱しちゃって、 バグになった Note: ではFirefoxはなんで(ちょっと)うまくいったの? ---- MDN: ```text Firefox 65 から、 keydown および keyup イベントは IME 入力中でも発生するようになり、 CJKT のユーザーのブラウザー間の互換性が向上しました (バグ 354358)。 ``` Note: この内容はおそらく先ほどのfirefoxがそうなにバグらない理由ではないかと。 --- Wait, What? IME? <span><h4>Input Method Editor<!-- .element: class="fragment" data-fragment-index="1" --></h4></span> ---- [Input method editor (インプットメソッドエディター)](https://developer.mozilla.org/ja/docs/Glossary/Input_method_editor) ```text インプットメソッドエディター (IME) は、 テキスト入力のための特殊なユーザーインターフェイスを提供するプログラムです。 インプットメソッドエディターは多くの場面で使用されています。 ``` Note: 也就是說, Firefox 65 から、 keydown および keyup イベントは IME 入力中で発生する。 ---- Reactのソースコードを見ましょう Note: 在寫 React 的時候,我們調用得Event基本上都不是原生的 Event。 React 基本上把 Event 都包起來做了各種處理才交到我們手上。 ---- #### [react/packages/react-dom/src/events/plugins/BeforeInputEventPlugin.js](https://github.com/facebook/react/blob/main/packages/react-dom/src/events/plugins/BeforeInputEventPlugin.js) Composition start ```js /** * Does our fallback best-guess model think this event signifies that * composition has begun? */ function isFallbackCompositionStart( domEventName: DOMEventName, nativeEvent: any, ): boolean { return domEventName === 'keydown' && nativeEvent.keyCode === START_KEYCODE; } ``` ---- ``` START_KEYCODE = 229 ``` ```text If an Input Method Editor is processing key input and the event is keydown, return 229. ``` [keyCode in key events](https://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html) ---- #### [react/packages/react-dom/src/events/plugins/BeforeInputEventPlugin.js](https://github.com/facebook/react/blob/main/packages/react-dom/src/events/plugins/BeforeInputEventPlugin.js) Composition end ```js /** * Does our fallback mode think that this event is the end of composition? */ function isFallbackCompositionEnd( domEventName: DOMEventName, nativeEvent: any, ): boolean { switch (domEventName) { case 'keyup': // Command keys insert or clear IME input. return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1; // const END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space case 'keydown': // Expect IME keyCode on each keydown. If we get any other // code we must have exited earlier. return nativeEvent.keyCode !== START_KEYCODE; case 'keypress': case 'mousedown': case 'focusout': // Events are not possible without cancelling IME. return true; default: return false; } } ``` ---- Composition Events: https://codepen.io/keronscribe/pen/PoErpwm Note: こちらのテスト用のcodepenを見当たって、 でも、よく見ると一番右がdivでできでいるのインプットエリア。 との初心者の発見がありました。 そこで話戻るですが、 先のめっちゃバグるノードで、もうしかしてこれを使って実装されたのと。 --- あたりです ```html [8] <div data-gramm="false" role="textbox" dir="ltr" class="EditorContainer" data-slate-editor="true" data-slate-node="value" contenteditable="true" style="outline: none; white-space: pre-wrap; overflow-wrap: break-word;" </div> ``` --- ### content editable ```text HTMLElement インターフェイスの contentEditable プロパティは、 要素が編集可能かどうかを指定します。 この**列挙属性**には、次の値を設定できます。 ``` ---- ```text この**列挙属性**には、次の値を設定できます。 'true' は、要素の内容が編集可能 (contenteditable) であることを示します。 'false' は、要素が編集できないことを示します。 'inherit' は、要素がその親の編集可能状態を継承することを示します。 ``` ---- content editable を使っている editor - GitHub も使っている [CodeMirror](https://github.com/codemirror/CodeMirror/blob/22e9d4f6ce451196803898be1bad859567df6107/src/input/ContentEditableInput.js#L19) - このスライドを作成する環境の[HackMD](https://hackmd.io/) - 最近ちょっと話題になってる[lexical](https://github.com/facebook/lexical/blob/4e57eb8d7e0ca00fe998f02b9dd3efaaef858a2e/packages/lexical-react/src/LexicalContentEditable.jsx#L94) ---- [lexical Rich text editor ](https://playground.lexical.dev/)は本当に綺麗と思います。 Note: Reactも使えるので興味がある方ぜひ ---
{"metaMigratedAt":"2023-06-16T23:29:37.982Z","metaMigratedFrom":"YAML","title":"範例簡報","breaks":true,"slideOptions":"{\"theme\":\"moon\",\"transition\":\"fade\"}","contributors":"[{\"id\":\"55656006-7069-4b3c-b452-8f557a1d2ca8\",\"add\":10347,\"del\":5058}]"}
    375 views