diff --git a/static/application.js b/static/application.js
index e8f3d4e9..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;
@@ -126,6 +127,7 @@ var adventure = false;
var chatmode = false;
var sliders_throttle = getThrottle(200);
+var submit_throttle = null;
//=================================================================//
// METHODS
@@ -882,6 +884,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();
@@ -1415,14 +1428,30 @@ 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];
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 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);
s.removeAllRanges();
@@ -1604,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);
@@ -1614,12 +1644,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]);
}
@@ -1641,6 +1677,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);
+ }
}
}
}
@@ -1693,10 +1732,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);
});
}
@@ -1711,6 +1756,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() {
@@ -1722,13 +1770,21 @@ 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]);
}
- saved_prompt = formatChunkInnerText($("#n0")[0]);
}
function highlightEditingChunks() {
@@ -1752,11 +1808,29 @@ 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)});
for(var i = 0; i < chunks.length; i++) {
+ if(chunks[i] == "0") {
+ 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") {
@@ -1766,11 +1840,14 @@ 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 = "";
}
// 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]);
@@ -1784,9 +1861,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
@@ -1868,6 +1950,7 @@ function chunkOnFocusOut(event) {
return;
}
cleanupChunkWhitespace();
+ all_modified_chunks = new Set();
syncAllModifiedChunks(true);
setTimeout(function() {
var blurred = game_text[0] !== document.activeElement;
@@ -2039,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);
@@ -2495,6 +2579,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