Merge pull request #82 from VE-FORBRYDERNE/editor

Fix some editor issues in Firefox and possibly mobile browsers
This commit is contained in:
henk717 2021-11-19 00:04:31 +01:00 committed by GitHub
commit 4e791b2f2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 23 deletions

View File

@ -71,7 +71,6 @@ var connected = false;
var newly_loaded = true; var newly_loaded = true;
var modified_chunks = new Set(); var modified_chunks = new Set();
var empty_chunks = new Set(); var empty_chunks = new Set();
var mutation_observer = null;
var gametext_bound = false; var gametext_bound = false;
var saved_prompt = "..."; var saved_prompt = "...";
var override_focusout = false; var override_focusout = false;
@ -805,6 +804,48 @@ function chunkOnTextInput(event) {
} }
} }
// This gets run when one or more chunks are edited. The event occurs before
// the actual edits are made by the browser, so we are free to check which
// nodes are selected or stop the event from occurring.
function chunkOnBeforeInput(event) {
// Register all selected chunks as having been modified
applyChunkDeltas(getSelectedNodes());
// Fix editing across chunks and paragraphs in Firefox 93.0 and higher
if(event.originalEvent.inputType === "deleteContentBackward" && document.queryCommandSupported && document.execCommand && document.queryCommandSupported('delete')) {
event.preventDefault();
document.execCommand('delete');
}
var s = rangy.getSelection();
if(!s.isCollapsed) {
s.deleteFromDocument();
}
if(buildChunkSetFromNodeArray(getSelectedNodes()).size === 0) {
var s = rangy.getSelection();
var r = s.getRangeAt(0);
if(document.queryCommandSupported && document.execCommand && document.queryCommandSupported('insertHTML')) {
document.execCommand('insertHTML', false, '<span id="_EDITOR_SENTINEL_">|</span>');
} else {
var t = document.createTextNode('|');
var b = document.createElement('span');
b.id = "_EDITOR_SENTINEL_";
b.insertNode(t);
r.insertNode(b);
}
var sentinel = document.getElementById("_EDITOR_SENTINEL_");
if(sentinel.nextSibling && sentinel.nextSibling.tagName === "CHUNK") {
r.selectNodeContents(sentinel.nextSibling);
r.collapse(true);
} else if(sentinel.previousSibling && sentinel.previousSibling.tagName === "CHUNK") {
r.selectNodeContents(sentinel.previousSibling);
r.collapse(false);
}
s.removeAllRanges();
s.addRange(r);
sentinel.parentNode.removeChild(sentinel);
}
}
function chunkOnKeyDown(event) { function chunkOnKeyDown(event) {
// Make escape commit the changes (Originally we had Enter here to but its not required and nicer for users if we let them type freely // Make escape commit the changes (Originally we had Enter here to but its not required and nicer for users if we let them type freely
// You can add the following after 27 if you want it back to committing on enter : || (!event.shiftKey && event.keyCode == 13) // You can add the following after 27 if you want it back to committing on enter : || (!event.shiftKey && event.keyCode == 13)
@ -1020,26 +1061,11 @@ function highlightEditingChunks() {
} }
} }
// This gets run every time the text in a chunk is edited
// or a chunk is deleted
function chunkOnDOMMutate(mutations, observer) {
if(!gametext_bound || !allowedit) {
return;
}
var nodes = [];
for(var i = 0; i < mutations.length; i++) {
var mutation = mutations[i];
nodes = nodes.concat(Array.from(mutation.addedNodes), Array.from(mutation.removedNodes));
nodes.push(mutation.target);
}
applyChunkDeltas(nodes);
}
// This gets run every time you try to paste text into the editor // This gets run every time you try to paste text into the editor
function chunkOnPaste(event) { function chunkOnPaste(event) {
if(!gametext_bound) { // Register the chunk we're pasting in as having been modified
return; applyChunkDeltas(getSelectedNodes());
}
// If possible, intercept paste events into the editor in order to always // If possible, intercept paste events into the editor in order to always
// paste as plaintext // paste as plaintext
if(event.originalEvent.clipboardData && document.queryCommandSupported && document.execCommand && document.queryCommandSupported('insertHTML')) { if(event.originalEvent.clipboardData && document.queryCommandSupported && document.execCommand && document.queryCommandSupported('insertHTML')) {
@ -1112,12 +1138,10 @@ function chunkOnFocusOut(event) {
} }
function bindGametext() { function bindGametext() {
mutation_observer.observe(game_text[0], {characterData: true, childList: true, subtree: true});
gametext_bound = true; gametext_bound = true;
} }
function unbindGametext() { function unbindGametext() {
mutation_observer.disconnect();
gametext_bound = false; gametext_bound = false;
} }
@ -1532,6 +1556,8 @@ $(document).ready(function(){
// Register editing events // Register editing events
game_text.on('textInput', game_text.on('textInput',
chunkOnTextInput chunkOnTextInput
).on('beforeinput',
chunkOnBeforeInput
).on('keydown', ).on('keydown',
chunkOnKeyDown chunkOnKeyDown
).on('paste', ).on('paste',
@ -1543,7 +1569,6 @@ $(document).ready(function(){
).on('focusout', ).on('focusout',
chunkOnFocusOut chunkOnFocusOut
); );
mutation_observer = new MutationObserver(chunkOnDOMMutate);
// This is required for the editor to work correctly in Firefox on desktop // This is required for the editor to work correctly in Firefox on desktop
// because the gods of HTML and JavaScript say so // because the gods of HTML and JavaScript say so

View File

@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<script src="static/jquery-3.6.0.min.js"></script> <script src="static/jquery-3.6.0.min.js"></script>
<script src="static/socket.io.min.js"></script> <script src="static/socket.io.min.js"></script>
<script src="static/application.js?ver=1.16.4a"></script> <script src="static/application.js?ver=1.16.4b"></script>
<script src="static/bootstrap.min.js"></script> <script src="static/bootstrap.min.js"></script>
<script src="static/bootstrap-toggle.min.js"></script> <script src="static/bootstrap-toggle.min.js"></script>
<script src="static/rangy-core.min.js"></script> <script src="static/rangy-core.min.js"></script>