From accbaea99157944e689b8a77bf84c8eb9ddfb4a0 Mon Sep 17 00:00:00 2001 From: vfbd Date: Thu, 30 Jun 2022 11:08:22 -0400 Subject: [PATCH 1/6] Fix a problem where a story with only the prompt cannot be edited --- static/application.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/static/application.js b/static/application.js index e8f3d4e9..5667d80a 100644 --- a/static/application.js +++ b/static/application.js @@ -1728,7 +1728,9 @@ function deleteEmptyChunks() { modified_chunks.delete(chunks[i]); socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': formatChunkInnerText(document.getElementById("n0"))}); } - saved_prompt = formatChunkInnerText($("#n0")[0]); + if(gamestarted) { + saved_prompt = formatChunkInnerText($("#n0")[0]); + } } function highlightEditingChunks() { @@ -1752,10 +1754,15 @@ function highlightEditingChunks() { } function cleanupChunkWhitespace() { + unbindGametext(); + // Merge empty chunks with the next chunk var chunks = Array.from(empty_chunks); chunks.sort(function(e) {parseInt(e)}); for(var i = 0; i < chunks.length; i++) { + if(chunks[i] == "0") { + continue; + } var original_chunk = document.getElementById("n" + chunks[i]); var chunk = original_chunk.nextSibling; while(chunk) { @@ -1766,6 +1773,9 @@ function cleanupChunkWhitespace() { } if(chunk) { chunk.innerText = original_chunk.innerText + chunk.innerText; + if(original_chunk.innerText.length != 0 && !modified_chunks.has(chunk.getAttribute("n"))) { + modified_chunks.add(chunk.getAttribute("n")); + } } original_chunk.innerText = ""; } @@ -1784,9 +1794,14 @@ function cleanupChunkWhitespace() { var ln = original_chunk.innerText.trimEnd().length; if (chunk) { chunk.innerText = original_chunk.innerText.substring(ln) + chunk.innerText; + if(ln != original_chunk.innerText.length && !modified_chunks.has(chunk.getAttribute("n"))) { + modified_chunks.add(chunk.getAttribute("n")); + } } original_chunk.innerText = original_chunk.innerText.substring(0, ln); } + + bindGametext(); } // This gets run every time the text in a chunk is edited From ce5f4d3dda775d24c3ebe23894fb3d3460cd1976 Mon Sep 17 00:00:00 2001 From: vfbd Date: Thu, 30 Jun 2022 11:31:54 -0400 Subject: [PATCH 2/6] Click on blank part of editor to defocus in Chromium based browsers In Chromium based browsers you can now click the blank part of the editor to submit changes. This is to maintain consistency with the editor behaviour in Firefox which already did this when you clicked on the blank part of the editor. --- static/application.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/static/application.js b/static/application.js index 5667d80a..235434d7 100644 --- a/static/application.js +++ b/static/application.js @@ -2510,6 +2510,12 @@ $(document).ready(function(){ chunkOnFocusOut ); mutation_observer = new MutationObserver(chunkOnDOMMutate); + $("#gamescreen").on('click', function(e) { + if(this !== e.target) { + return; + } + document.activeElement.blur(); + }); // This is required for the editor to work correctly in Firefox on desktop // because the gods of HTML and JavaScript say so From cccf8296fcce3486f3a9a0a2bc0e7858f331da43 Mon Sep 17 00:00:00 2001 From: vfbd Date: Thu, 30 Jun 2022 12:03:39 -0400 Subject: [PATCH 3/6] Fix enter key sometimes putting two newlines in editor This happens when, in a Chromium-based browser, you try to insert a newline at the end of the last action of your story. --- static/application.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/static/application.js b/static/application.js index 235434d7..1572e3bb 100644 --- a/static/application.js +++ b/static/application.js @@ -1420,9 +1420,14 @@ function chunkOnTextInput(event) { // to put the
back in the right place var br = $("#_EDITOR_LINEBREAK_")[0]; if(br.parentNode === game_text[0]) { + var parent = br.previousSibling; if(br.previousSibling.nodeType !== 1) { + parent = br.previousSibling.previousSibling; br.previousSibling.previousSibling.appendChild(br.previousSibling); } + if(parent.lastChild.tagName === "BR") { + parent.lastChild.remove(); // Chrome also inserts an extra
in this case for some reason so we need to remove it + } br.previousSibling.appendChild(br); r.selectNodeContents(br.parentNode); s.removeAllRanges(); From 1ff0a4b9a96f64807b042e5ddd8c50f30c837f2e Mon Sep 17 00:00:00 2001 From: vfbd Date: Thu, 30 Jun 2022 12:23:06 -0400 Subject: [PATCH 4/6] Submit button now waits for inlineedit/inlinedelete commands --- static/application.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/static/application.js b/static/application.js index 1572e3bb..ab534a02 100644 --- a/static/application.js +++ b/static/application.js @@ -126,6 +126,7 @@ var adventure = false; var chatmode = false; var sliders_throttle = getThrottle(200); +var submit_throttle = null; //=================================================================// // METHODS @@ -882,6 +883,17 @@ function dosubmit(disallow_abort) { return; } chunkOnFocusOut("override"); + // Wait for editor changes to be applied before submitting + submit_throttle = getThrottle(70); + submit_throttle.txt = txt; + submit_throttle.disallow_abort = disallow_abort; + submit_throttle(0, _dosubmit); +} + +function _dosubmit() { + var txt = submit_throttle.txt; + var disallow_abort = submit_throttle.disallow_abort; + submit_throttle = null; input_text.val(""); hideMessage(); hidegenseqs(); @@ -1619,12 +1631,18 @@ function applyChunkDeltas(nodes) { if(!selected_chunks.has(chunks[i])) { modified_chunks.delete(chunks[i]); socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': formatChunkInnerText(chunk)}); + if(submit_throttle !== null) { + submit_throttle(0, _dosubmit); + } } empty_chunks.delete(chunks[i]); } else { if(!selected_chunks.has(chunks[i])) { modified_chunks.delete(chunks[i]); socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': formatChunkInnerText(chunk)}); + if(submit_throttle !== null) { + submit_throttle(0, _dosubmit); + } } empty_chunks.add(chunks[i]); } @@ -1646,6 +1664,9 @@ function syncAllModifiedChunks(including_selected_chunks=false) { empty_chunks.delete(chunks[i]); } socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': data}); + if(submit_throttle !== null) { + submit_throttle(0, _dosubmit); + } } } } @@ -1698,10 +1719,16 @@ function restorePrompt() { if(this.innerText.trim().length) { saved_prompt = this.innerText.trim(); socket.send({'cmd': 'inlinedelete', 'data': this.getAttribute("n")}); + if(submit_throttle !== null) { + submit_throttle(0, _dosubmit); + } this.parentNode.removeChild(this); return false; } socket.send({'cmd': 'inlinedelete', 'data': this.getAttribute("n")}); + if(submit_throttle !== null) { + submit_throttle(0, _dosubmit); + } this.parentNode.removeChild(this); }); } @@ -1716,6 +1743,9 @@ function restorePrompt() { modified_chunks.delete('0'); empty_chunks.delete('0'); socket.send({'cmd': 'inlineedit', 'chunk': '0', 'data': saved_prompt}); + if(submit_throttle !== null) { + submit_throttle(0, _dosubmit); + } } function deleteEmptyChunks() { @@ -1727,11 +1757,17 @@ function deleteEmptyChunks() { restorePrompt(); } else { socket.send({'cmd': 'inlinedelete', 'data': chunks[i]}); + if(submit_throttle !== null) { + submit_throttle(0, _dosubmit); + } } } if(modified_chunks.has('0')) { modified_chunks.delete(chunks[i]); socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': formatChunkInnerText(document.getElementById("n0"))}); + if(submit_throttle !== null) { + submit_throttle(0, _dosubmit); + } } if(gamestarted) { saved_prompt = formatChunkInnerText($("#n0")[0]); From c3eade8046a29399d023ca21ad27222697a0b455 Mon Sep 17 00:00:00 2001 From: vfbd Date: Fri, 1 Jul 2022 13:12:57 -0400 Subject: [PATCH 5/6] Fix editor bug in iOS when adding newline at end of the last action Not only does iOS also have that issue that Chromium-based browsers have, but it also has a different issue where it selects all text in the last chunk of your story, so I added some code to deselect the text in that case. --- static/application.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/static/application.js b/static/application.js index ab534a02..52c84357 100644 --- a/static/application.js +++ b/static/application.js @@ -1427,7 +1427,7 @@ function chunkOnTextInput(event) { r.deleteContents(); } - // In Chrome the added
will go outside of the chunks if we press + // In Chrome and Safari the added
will go outside of the chunks if we press // enter at the end of the story in the editor, so this is here // to put the
back in the right place var br = $("#_EDITOR_LINEBREAK_")[0]; @@ -1438,7 +1438,18 @@ function chunkOnTextInput(event) { br.previousSibling.previousSibling.appendChild(br.previousSibling); } if(parent.lastChild.tagName === "BR") { - parent.lastChild.remove(); // Chrome also inserts an extra
in this case for some reason so we need to remove it + parent.lastChild.remove(); // Chrome and Safari also insert an extra
in this case for some reason so we need to remove it + if(using_webkit_patch) { + // Safari on iOS has a bug where it selects all text in the last chunk of the story when this happens so we collapse the selection to the end of the chunk in that case + setTimeout(function() { + var s = getSelection(); + var r = s.getRangeAt(0); + r.selectNodeContents(parent); + r.collapse(false); + s.removeAllRanges(); + s.addRange(r); + }, 2); + } } br.previousSibling.appendChild(br); r.selectNodeContents(br.parentNode); From c336a43544b49513fb5de531d03f3d3d095e9b44 Mon Sep 17 00:00:00 2001 From: vfbd Date: Fri, 1 Jul 2022 13:45:57 -0400 Subject: [PATCH 6/6] Fix some remaining editor whitespace-fixing issues --- static/application.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/static/application.js b/static/application.js index 52c84357..85ab88a8 100644 --- a/static/application.js +++ b/static/application.js @@ -85,6 +85,7 @@ var wiscroll = 0; var editmode = false; var connected = false; var newly_loaded = true; +var all_modified_chunks = new Set(); var modified_chunks = new Set(); var empty_chunks = new Set(); var gametext_bound = false; @@ -1632,6 +1633,7 @@ function applyChunkDeltas(nodes) { var chunks = Array.from(buildChunkSetFromNodeArray(nodes)); for(var i = 0; i < chunks.length; i++) { modified_chunks.add(chunks[i]); + all_modified_chunks.add(chunks[i]); } setTimeout(function() { var chunks = Array.from(modified_chunks); @@ -1808,6 +1810,16 @@ function highlightEditingChunks() { function cleanupChunkWhitespace() { unbindGametext(); + var chunks = Array.from(all_modified_chunks); + for(var i = 0; i < chunks.length; i++) { + var original_chunk = document.getElementById("n" + chunks[i]); + if(original_chunk === null || original_chunk.innerText.trim().length === 0) { + all_modified_chunks.delete(chunks[i]); + modified_chunks.delete(chunks[i]); + empty_chunks.add(chunks[i]); + } + } + // Merge empty chunks with the next chunk var chunks = Array.from(empty_chunks); chunks.sort(function(e) {parseInt(e)}); @@ -1816,6 +1828,9 @@ function cleanupChunkWhitespace() { continue; } var original_chunk = document.getElementById("n" + chunks[i]); + if(original_chunk === null) { + continue; + } var chunk = original_chunk.nextSibling; while(chunk) { if(chunk.tagName === "CHUNK") { @@ -1832,7 +1847,7 @@ function cleanupChunkWhitespace() { original_chunk.innerText = ""; } // Move whitespace at the end of non-empty chunks into the beginning of the next non-empty chunk - var chunks = Array.from(modified_chunks); + var chunks = Array.from(all_modified_chunks); chunks.sort(function(e) {parseInt(e)}); for(var i = 0; i < chunks.length; i++) { var original_chunk = document.getElementById("n" + chunks[i]); @@ -1935,6 +1950,7 @@ function chunkOnFocusOut(event) { return; } cleanupChunkWhitespace(); + all_modified_chunks = new Set(); syncAllModifiedChunks(true); setTimeout(function() { var blurred = game_text[0] !== document.activeElement; @@ -2106,6 +2122,7 @@ $(document).ready(function(){ unbindGametext(); allowedit = gamestarted && $("#allowediting").prop('checked'); game_text.attr('contenteditable', allowedit); + all_modified_chunks = new Set(); modified_chunks = new Set(); empty_chunks = new Set(); game_text.html(msg.data);