Commit ·
bf8500f
1
Parent(s): ece7379
fix: unified undo/redo - toolbar+keyboard use same stack, works with typing+formatting+Quran apply
Browse files- src/index.html +1 -0
- src/js/editor.js +5 -0
- src/js/format.js +4 -3
src/index.html
CHANGED
|
@@ -1347,6 +1347,7 @@
|
|
| 1347 |
function _replaceInEditor(newText, ref) {
|
| 1348 |
var editor = document.getElementById('editor-container');
|
| 1349 |
if (!editor || !_quranCurrentQuery) return false;
|
|
|
|
| 1350 |
closeQuranModal();
|
| 1351 |
// Replace in editor: wrap in quran-applied span to protect from analysis
|
| 1352 |
var plain = editor.textContent || '';
|
|
|
|
| 1347 |
function _replaceInEditor(newText, ref) {
|
| 1348 |
var editor = document.getElementById('editor-container');
|
| 1349 |
if (!editor || !_quranCurrentQuery) return false;
|
| 1350 |
+
pushUndoState(); // Save state before Quran replace
|
| 1351 |
closeQuranModal();
|
| 1352 |
// Replace in editor: wrap in quran-applied span to protect from analysis
|
| 1353 |
var plain = editor.textContent || '';
|
src/js/editor.js
CHANGED
|
@@ -79,6 +79,8 @@ function initEditor() {
|
|
| 79 |
}
|
| 80 |
} catch (e) {}
|
| 81 |
|
|
|
|
|
|
|
| 82 |
editor.addEventListener('input', () => {
|
| 83 |
// Pipeline Hardening v3.3: Skip re-analysis when programmatically applying suggestions
|
| 84 |
if (_isApplyingSuggestion) return;
|
|
@@ -86,6 +88,9 @@ function initEditor() {
|
|
| 86 |
updateEditorStats();
|
| 87 |
updatePlaceholder();
|
| 88 |
analyzeTextDelayed();
|
|
|
|
|
|
|
|
|
|
| 89 |
try {
|
| 90 |
localStorage.setItem('bayan_editor_draft', editor.innerHTML);
|
| 91 |
} catch (e) {}
|
|
|
|
| 79 |
}
|
| 80 |
} catch (e) {}
|
| 81 |
|
| 82 |
+
// Debounced undo push — saves state after 500ms of no typing
|
| 83 |
+
let _undoInputTimer = null;
|
| 84 |
editor.addEventListener('input', () => {
|
| 85 |
// Pipeline Hardening v3.3: Skip re-analysis when programmatically applying suggestions
|
| 86 |
if (_isApplyingSuggestion) return;
|
|
|
|
| 88 |
updateEditorStats();
|
| 89 |
updatePlaceholder();
|
| 90 |
analyzeTextDelayed();
|
| 91 |
+
// Push undo state after typing pauses
|
| 92 |
+
clearTimeout(_undoInputTimer);
|
| 93 |
+
_undoInputTimer = setTimeout(pushUndoState, 500);
|
| 94 |
try {
|
| 95 |
localStorage.setItem('bayan_editor_draft', editor.innerHTML);
|
| 96 |
} catch (e) {}
|
src/js/format.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
| 8 |
* @param {boolean} [keepSelection] - if true, don't collapse selection
|
| 9 |
*/
|
| 10 |
function execFormat(command, value, keepSelection) {
|
|
|
|
| 11 |
document.execCommand(command, false, value !== undefined ? value : null);
|
| 12 |
const editor = getEditorElement();
|
| 13 |
if (editor) editor.focus();
|
|
@@ -29,9 +30,9 @@ function formatItalic() { execFormat('italic'); }
|
|
| 29 |
function formatUnderline() { execFormat('underline'); }
|
| 30 |
function formatStrikethrough() { execFormat('strikethrough'); }
|
| 31 |
|
| 32 |
-
/* ── Undo / Redo (
|
| 33 |
-
function formatUndo() {
|
| 34 |
-
function formatRedo() {
|
| 35 |
|
| 36 |
/* ── Alignment (applies to paragraph containing selection/cursor) ── */
|
| 37 |
function formatAlignRight() { execFormat('justifyRight'); }
|
|
|
|
| 8 |
* @param {boolean} [keepSelection] - if true, don't collapse selection
|
| 9 |
*/
|
| 10 |
function execFormat(command, value, keepSelection) {
|
| 11 |
+
pushUndoState(); // Save state before formatting
|
| 12 |
document.execCommand(command, false, value !== undefined ? value : null);
|
| 13 |
const editor = getEditorElement();
|
| 14 |
if (editor) editor.focus();
|
|
|
|
| 30 |
function formatUnderline() { execFormat('underline'); }
|
| 31 |
function formatStrikethrough() { execFormat('strikethrough'); }
|
| 32 |
|
| 33 |
+
/* ── Undo / Redo (uses custom stack — same as Ctrl+Z/Y) ── */
|
| 34 |
+
function formatUndo() { editorUndo(); }
|
| 35 |
+
function formatRedo() { editorRedo(); }
|
| 36 |
|
| 37 |
/* ── Alignment (applies to paragraph containing selection/cursor) ── */
|
| 38 |
function formatAlignRight() { execFormat('justifyRight'); }
|