JSからtextareaの文字列を変更した時、Undoに対応できるようにする #dev #javascript version 3
:追加された部分
:削除された部分
(差分が大きい場合、文字単位では表示しません)
JSからtextareaの文字列を変更した時、Ctrl+Zの取り消しUndoに対応できるようにする #dev #javascript
mimemoのmarkdownエディタを作っていく上で、リストの補完など一部のアイデアはesareaから拝借しています(ありがたや)。
ただ、esarea(及びesaのmarkdownエディタ)は、ブラウザによって補完したあとにCtrl+Zなどでの「取り消し」ができないので、これはエディタとして致命的、ということでmimemoでは頑張って対応させたので、その辺フィードバックも兼ねたハウツーメモです。
[mimemo](https://mimemo.io/)のmarkdownエディタを作っていく上で、リストの補完などのアイデアとコードは一部[esarea](https://github.com/fukayatsu/esarea)のものを下敷きにして書かせていただきました(多謝)。
# textarea書き換え時にできるだけUndo対応させる
ただ、esarea(及び[esa](https://esa.io/)のmarkdownエディタ)は、一部のブラウザで補完したあとにCtrl+Zなどでの「取り消し」ができなくなるようでしたので、これはエディタとして致命的、ということでmimemoでは頑張って(?)Undo対応させたので、その辺フィードバックも兼ねたハウツーメモです。
* Firefoxは元々Undo対応している
* ChromeなどはexecCommandで'insertText'を呼んで書き換える形にするとUndoできる形で書き換えられる
* IEではexecCommandで'ms-beginUndoUnit','ms-endUndoUnit'で挟んで書き換えするとUndo対応できる
# JSからtextarea書き換えた時にUndo対応させる
簡単なデモ
### 方法
* Chrome、SafariはexecCommand('insertText')で書き換える形にするとUndoできる形で書き換えられる
* Firefoxは何もしないでも元々Undo対応していて、逆にexecCommand使うとうまく動かなかったりする
* MS Edgeは何もしないでも元々Undo対応している模様
* IEではexecCommandで'ms-beginUndoUnit','ms-endUndoUnit'で挟んで書き換えるとUndo対応できる
### 簡単なデモ
https://embed.plnkr.co/KSfSIgA1WZplUVKCAKKC/
実際に使ってるコード(抜粋)
### 実際に使ってるコード(抜粋)
```js
class EditorInput{
// ...
// ※this.inputElmが対象になるtextarea
replace(str, fromIdx, toIdx) {
let inserted = false;
if (str) {
let expectedLen = this.inputElm.value.length - Math.abs(toIdx - fromIdx) + str.length;
this.inputElm.contentEditable = true;
this.inputElm.focus();
this.inputElm.selectionStart = fromIdx;
this.inputElm.selectionEnd = toIdx;
try {
inserted = document.execCommand('insertText', false, str);
} catch (e) {
inserted = false
}
if (inserted && (this.inputElm.value.length !== expectedLen || this.inputElm.value.substr(fromIdx, str.length) !== str)) {
//firefoxでなぜかうまくいってないくせにinsertedにfalseが返ってこなくなっているので失敗を検知してfalseにする
//firefoxでなぜかうまくいってないくせにinsertedがtrueになるので失敗を検知してfalseに…
inserted = false;
}
}
if (!inserted) {
try {
document.execCommand('ms-beginUndoUnit');
} catch (e) {}
let value = this.inputElm.value;
this.inputElm.value = '' + value.substring(0, fromIdx) + str + value.substring(toIdx);
try {
document.execCommand('ms-endUndoUnit');
} catch (e) {}
}
this._updated();
}
// ...
}
```
mimemoのmarkdownエディタを作っていく上で、リストの補完などのアイデアとコードは一部esareaのものを下敷きにして書かせていただきました(多謝)。
ただ、esarea(及びesaのmarkdownエディタ)は、一部のブラウザで補完したあとにCtrl+Zなどでの「取り消し」ができなくなるようでしたので、これはエディタとして致命的、ということでmimemoでは頑張って(?)Undo対応させたので、その辺フィードバックも兼ねたハウツーメモです。
JSからtextarea書き換えた時にUndo対応させる
方法
- Chrome、SafariはexecCommand('insertText')で書き換える形にするとUndoできる形で書き換えられる
- Firefoxは何もしないでも元々Undo対応していて、逆にexecCommand使うとうまく動かなかったりする
- MS Edgeは何もしないでも元々Undo対応している模様
- IEではexecCommandで'ms-beginUndoUnit','ms-endUndoUnit'で挟んで書き換えるとUndo対応できる
簡単なデモ
実際に使ってるコード(抜粋)
class EditorInput{
// ...
// ※this.inputElmが対象になるtextarea
replace(str, fromIdx, toIdx) {
let inserted = false;
if (str) {
let expectedLen = this.inputElm.value.length - Math.abs(toIdx - fromIdx) + str.length;
this.inputElm.focus();
this.inputElm.selectionStart = fromIdx;
this.inputElm.selectionEnd = toIdx;
try {
inserted = document.execCommand('insertText', false, str);
} catch (e) {
inserted = false
}
if (inserted && (this.inputElm.value.length !== expectedLen || this.inputElm.value.substr(fromIdx, str.length) !== str)) {
//firefoxでなぜかうまくいってないくせにinsertedがtrueになるので失敗を検知してfalseに…
inserted = false;
}
}
if (!inserted) {
try {
document.execCommand('ms-beginUndoUnit');
} catch (e) {}
let value = this.inputElm.value;
this.inputElm.value = '' + value.substring(0, fromIdx) + str + value.substring(toIdx);
try {
document.execCommand('ms-endUndoUnit');
} catch (e) {}
}
}
// ...
}