WYSIWYGなMarkdownエディターを目指してContentEditableおよびexecCommandと真っ向勝負してみる(part 2)
この記事はpart2です。
part1をまだご覧になっていない方はそちらを先にお読みいただくと話の流れがわかりやすいかと思います。
前回残された修正点
前回の実装で残された修正点は以下のようになっています。
- 挿入された要素にキャレットを合わせることができない
-
blockquote
はEnter
を押しても抜け出すことができない
今回はこれらを修正していきます。
① 挿入した要素にキャレットを合わせられない問題について
前回の実装ではexecCommand
でHTML要素を変更した後に、innerText
を空にしていました。
この際、キャレットが置き換えた要素の直前の要素に(なぜか)移動してしまうのが原因でこのような不具合が起こっています。
そして、置き換えた要素にはキャレットを合わせることはできません。
この問題を解決するために、要素を置き換えた後にinnerText
を空にするのではなく、スペースを入れることで対処してみました。
すなわち、
// 前回のコード
window.getSelection().getRangeAt(0).endContainer.parentNode.innerText = ''
// 修正
window.getSelection().getRangeAt(0).endContainer.parentNode.innerText = '\xA0'
どうにかキャレットを合わせることができました。
ですが、これによって新たな問題が出てきました。
上のGif画像の最後にちょっと映ってますが、改行した後に再びH1
が挿入されています。
この問題は前回の二番目の問題である、無限blockquote
と同じようなものと捉え次の章で対処します。
また、ブラウザの標準機能として、リストを抜け出す際には空の行でEnter
を押す必要があります。
1. aaa
2. | ←キャレット位置
↓ Enter押下
1. aaa
|
ですが、先ほどの実装では行の末尾にスペースが入るため、行が空とはみなされず改行しても延々とリストのままです。
つまり、リストや順序付きリストを挿入する際にはスペースを挿入する必要はなさそうです。
前回の実装でマークダウン記法の場合分けをしましたが、リストや順序付きリストの時には前回同様innerText
を空にするようにします。
② 無限blockquote
について
例によって詳しい原因は不明ですが、前回の実装ではblockquote
の中でEnter
を押しても抜け出すことができませんでした。
原因がわからないため、改行で新たに挿入されたblockquote
をexecCommand
で無理やりdiv
に変換する実装をしました。
マークダウン記法を置き換えたのと逆のやり方です。
document.execCommand('formatblock', false, 'div')
なお、Shift+Enter
は同じ要素内での改行なので、Shift
なしのEnter
のみを捕捉して上記のコマンドを実行する必要があります。
また、リストや順序付きリストはブラウザの標準機能で望ましい動きをするので、div
に置き換える処理を適応しない必要があります。
Shift
の捕捉はキーイベントの.shiftKey
プロパティで入手できます。
リストの判定は、キャレットのある要素名を取得することでやりました。
上記をまとめると以下の処理になります。
if (!event.shiftKey && event.keyCode === 13) {
if (!focusingOnOrderElement()) {
document.execCommand('formatblock', false, 'div')
}
}
const focusingOnOrderElement = () => {
const element_name = window.getSelection().getRangeAt(0).endContainer.parentNode.nodeName
return (element_name === 'LI' || element_name === 'UL' || element_name === 'OL')
}
完成形
今回の改良点をまとめると以下のようになります。
const element = document.getElementById('markdown')
element.focus()
element.addEventListener('keyup', (event) => {
const currentLine = window.getSelection().getRangeAt(0).endContainer.data || ''
if (!event.shiftKey && event.keyCode === 13) {
if (!focusingOnOrderElement()) {
document.execCommand('formatblock', false, 'div')
}
}else{
if (currentLine.match(/^#{1}\xA0$/)) { // 見出し
document.execCommand('formatblock', false, 'h1')
clearCurrentLine()
} else if (currentLine.match(/^#{2}\xA0$/)){
document.execCommand('formatblock', false, 'h2')
clearCurrentLine()
} else if (currentLine.match(/^#{3}\xA0$/)) {
document.execCommand('formatblock', false, 'h3')
clearCurrentLine()
} else if (currentLine.match(/^#{4}\xA0$/)) {
document.execCommand('formatblock', false, 'h4')
clearCurrentLine()
} else if (currentLine.match(/^#{5}\xA0$/)) {
document.execCommand('formatblock', false, 'h5')
clearCurrentLine()
} else if (currentLine.match(/^#{6}\xA0$/)) {
document.execCommand('formatblock', false, 'h6')
clearCurrentLine()
} else if (currentLine.match(/^>\xA0$/)) { // 引用
document.execCommand('formatblock', false, 'blockquote')
clearCurrentLine()
} else if (currentLine.match(/^\d+\.\xA0$/)) { // 順序付きリスト
document.execCommand('insertOrderedList')
clearCurrentLine('')
} else if (currentLine.match(/^[\-+*]\xA0+$/)) { // リスト
document.execCommand('insertUnorderedList')
clearCurrentLine('')
}
}
})
const clearCurrentLine = (clearCharacter = '\xA0') => {
window.getSelection().getRangeAt(0).endContainer.parentNode.innerText = clearCharacter
}
const focusingOnOrderElement = () => {
const element_name = window.getSelection().getRangeAt(0).endContainer.parentNode.nodeName
return (element_name === 'LI' || element_name === 'UL' || element_name === 'OL')
}
デモはこちらです。
次回に向けて
今回の実装でChrome上でもなんとか動くようになりました(SafariとChromeのみで試しています)
次回以降は強調やイタリックなどの文頭ではないマークダウン記法の判定をできればと思います。
乱文でしたが、最後までお読みいただきありがとうございましたm(_ _)m
改善点などございましたら、ご教授願います。
Author And Source
この問題について(WYSIWYGなMarkdownエディターを目指してContentEditableおよびexecCommandと真っ向勝負してみる(part 2)), 我々は、より多くの情報をここで見つけました https://qiita.com/TomOse/items/cc79eff90485a907ee15著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .