mirror of
				https://github.com/KoboldAI/KoboldAI-Client.git
				synced 2025-06-05 21:59:24 +02:00 
			
		
		
		
	Fix problems with stories that end in newlines
Today I learned that the editor only works properly when the last <chunk> tag has a <br> inside it at the end. This last <br> is invisible and is automatically created by all major browsers when you use the enter key to type a newline at the end of a story to "prevent the element from collapsing". When there's more than one <br> at the end of the last <chunk>, only the last of those <br>s is invisible, so if you have three <br>s, they are rendered as two newlines. This only applies to the last <chunk>, so if the second last <chunk> has three <br>s at the end, they are still rendered as three newlines. Since the browser is really insistent on doing this, this commit mostly deals with dynamically creating and deleting <br> tags at the ends of <chunk> tags as needed to provide a consistent experience, and making sure that all <br> tags actually go inside of <chunk> tags to prevent breaking the editor. The latter behaviour was exhibited by Chrome and caused a bug when you added a newline at the end of your story using the editor.
This commit is contained in:
		| @@ -496,6 +496,14 @@ function returnWiList(ar) { | ||||
| 	socket.send({'cmd': 'sendwilist', 'data': list}); | ||||
| } | ||||
|  | ||||
| function formatChunkInnerText(chunk) { | ||||
| 	var text = chunk.innerText.replace(/\u00a0/g, " "); | ||||
| 	if((chunk.nextSibling === null || chunk.nextSibling.nodeType !== 1 || chunk.nextSibling.tagName !== "CHUNK") && text.slice(-1) === '\n') { | ||||
| 		return text.slice(0, -1); | ||||
| 	} | ||||
| 	return text; | ||||
| } | ||||
|  | ||||
| function dosubmit() { | ||||
| 	var txt = input_text.val().replace(/\u00a0/g, " "); | ||||
| 	if(!memorymode && !gamestarted && ((!adventure || !action_mode) && txt.trim().length == 0)) { | ||||
| @@ -750,11 +758,13 @@ function chunkOnTextInput(event) { | ||||
| 		// mobile devices, but the other method is also here as | ||||
| 		// a fallback | ||||
| 		if(document.queryCommandSupported && document.execCommand && document.queryCommandSupported('insertHTML')) { | ||||
| 			document.execCommand('insertHTML', false, event.originalEvent.data.slice(0, -1) + '<br/><span id="_EDITOR_SENTINEL_">|</span>'); | ||||
| 			document.execCommand('insertHTML', false, event.originalEvent.data.slice(0, -1) + '<br id="_EDITOR_LINEBREAK_"/><span id="_EDITOR_SENTINEL_">|</span>'); | ||||
| 			var t = $('#_EDITOR_SENTINEL_').contents().filter(function() { return this.nodeType === 3; })[0]; | ||||
| 		} else { | ||||
| 			var t = document.createTextNode('|'); | ||||
| 			r.insertNode(document.createElement('br')); | ||||
| 			var b = document.createElement('br'); | ||||
| 			b.id = "_EDITOR_LINEBREAK_"; | ||||
| 			r.insertNode(b); | ||||
| 			r.collapse(false); | ||||
| 			r.insertNode(t); | ||||
| 		} | ||||
| @@ -771,6 +781,25 @@ function chunkOnTextInput(event) { | ||||
| 			// document.execCommand method | ||||
| 			r.deleteContents(); | ||||
| 		} | ||||
|  | ||||
| 		// In Chrome the added <br/> 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 <br/> back in the right place | ||||
| 		var br = $("#_EDITOR_LINEBREAK_")[0]; | ||||
| 		if(br.parentNode === game_text[0]) { | ||||
| 			if(br.previousSibling.nodeType !== 1) { | ||||
| 				br.previousSibling.previousSibling.appendChild(br.previousSibling); | ||||
| 			} | ||||
| 			br.previousSibling.appendChild(br); | ||||
| 			r.selectNodeContents(br.parentNode); | ||||
| 			s.removeAllRanges(); | ||||
| 			s.addRange(r); | ||||
| 			r.collapse(false); | ||||
| 		} | ||||
| 		br.id = ""; | ||||
| 		if(game_text[0].lastChild.tagName === "BR") { | ||||
| 			br.parentNode.appendChild(game_text[0].lastChild); | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
| } | ||||
| @@ -816,6 +845,10 @@ function downloadStory(format) { | ||||
| 	for(var i = 0; i < actionlist.length; i++) { | ||||
| 		actionlist_compiled.push(actionlist[i].innerText.replace(/\u00a0/g, " ")); | ||||
| 	} | ||||
| 	var last = actionlist_compiled[actionlist_compiled.length-1]; | ||||
| 	if(last.slice(-1) === '\n') { | ||||
| 		actionlist_compiled[actionlist_compiled.length-1] = last.slice(0, -1); | ||||
| 	} | ||||
|  | ||||
| 	if(format == "plaintext") { | ||||
| 		var objectURL = URL.createObjectURL(new Blob(actionlist_compiled)); | ||||
| @@ -890,10 +923,10 @@ function applyChunkDeltas(nodes) { | ||||
| 		var selected_chunks = buildChunkSetFromNodeArray(getSelectedNodes()); | ||||
| 		for(var i = 0; i < chunks.length; i++) { | ||||
| 			var chunk = document.getElementById("n" + chunks[i]); | ||||
| 			if(chunk && chunk.innerText.length != 0 && chunks[i] != '0') { | ||||
| 			if(chunk && formatChunkInnerText(chunk).length != 0 && chunks[i] != '0') { | ||||
| 				if(!selected_chunks.has(chunks[i])) { | ||||
| 					modified_chunks.delete(chunks[i]); | ||||
| 					socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': chunk.innerText.replace(/\u00a0/g, " ")}); | ||||
| 					socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': formatChunkInnerText(chunk)}); | ||||
| 				} | ||||
| 				empty_chunks.delete(chunks[i]); | ||||
| 			} else { | ||||
| @@ -914,7 +947,7 @@ function syncAllModifiedChunks(including_selected_chunks=false) { | ||||
| 		if(including_selected_chunks || !selected_chunks.has(chunks[i])) { | ||||
| 			modified_chunks.delete(chunks[i]); | ||||
| 			var chunk = document.getElementById("n" + chunks[i]); | ||||
| 			var data = chunk ? document.getElementById("n" + chunks[i]).innerText.replace(/\u00a0/g, " ") : ""; | ||||
| 			var data = chunk ? formatChunkInnerText(document.getElementById("n" + chunks[i])) : ""; | ||||
| 			if(data.length == 0) { | ||||
| 				empty_chunks.add(chunks[i]); | ||||
| 			} else { | ||||
| @@ -927,7 +960,7 @@ function syncAllModifiedChunks(including_selected_chunks=false) { | ||||
|  | ||||
| function restorePrompt() { | ||||
| 	if(game_text[0].firstChild && game_text[0].firstChild.nodeType === 3) { | ||||
| 		saved_prompt = game_text[0].firstChild.textContent.replace(/\u00a0/g, " "); | ||||
| 		saved_prompt = formatChunkInnerText(game_text[0].firstChild); | ||||
| 		unbindGametext(); | ||||
| 		game_text[0].innerText = ""; | ||||
| 		bindGametext(); | ||||
| @@ -961,9 +994,9 @@ function deleteEmptyChunks() { | ||||
| 	} | ||||
| 	if(modified_chunks.has('0')) { | ||||
| 		modified_chunks.delete(chunks[i]); | ||||
| 		socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data':  document.getElementById("n0").innerText.replace(/\u00a0/g, " ")}); | ||||
| 		socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': formatChunkInnerText(document.getElementById("n0"))}); | ||||
| 	} | ||||
| 	saved_prompt = $("#n0")[0].innerText.replace(/\u00a0/g, " "); | ||||
| 	saved_prompt = formatChunkInnerText($("#n0")[0]); | ||||
| } | ||||
|  | ||||
| function highlightEditingChunks() { | ||||
| @@ -1203,9 +1236,12 @@ $(document).ready(function(){ | ||||
| 			modified_chunks = new Set(); | ||||
| 			empty_chunks = new Set(); | ||||
| 			game_text.html(msg.data); | ||||
| 			if(game_text[0].lastChild !== null && game_text[0].lastChild.tagName === "CHUNK") { | ||||
| 				game_text[0].lastChild.appendChild(document.createElement("br")); | ||||
| 			} | ||||
| 			bindGametext(); | ||||
| 			if(gamestarted) { | ||||
| 				saved_prompt = $("#n0")[0].innerText.replace(/\u00a0/g, " "); | ||||
| 				saved_prompt = formatChunkInnerText($("#n0")[0]); | ||||
| 			} | ||||
| 			// Scroll to bottom of text | ||||
| 			if(newly_loaded) { | ||||
| @@ -1217,26 +1253,43 @@ $(document).ready(function(){ | ||||
| 			scrollToBottom(); | ||||
| 		} else if(msg.cmd == "updatechunk") { | ||||
| 			hideMessage(); | ||||
| 			const {index, html} = msg.data; | ||||
| 			const existingChunk = game_text.children(`#n${index}`) | ||||
| 			const newChunk = $(html); | ||||
| 			var index = msg.data.index; | ||||
| 			var html = msg.data.html; | ||||
| 			var existingChunk = game_text.children('#n' + index); | ||||
| 			var newChunk = $(html); | ||||
| 			unbindGametext(); | ||||
| 			if (existingChunk.length > 0) { | ||||
| 				// Update existing chunk | ||||
| 				if(existingChunk[0].nextSibling === null || existingChunk[0].nextSibling.nodeType !== 1 || existingChunk[0].nextSibling.tagName !== "CHUNK") { | ||||
| 					newChunk[0].appendChild(document.createElement("br")); | ||||
| 				} | ||||
| 				existingChunk.before(newChunk); | ||||
| 				existingChunk.remove(); | ||||
| 			} else if (!empty_chunks.has(index.toString())) { | ||||
| 				// Append at the end | ||||
| 				unbindGametext(); | ||||
| 				var lc = game_text[0].lastChild; | ||||
| 				if(lc.tagName === "CHUNK" && lc.lastChild !== null && lc.lastChild.tagName === "BR") { | ||||
| 					lc.removeChild(lc.lastChild); | ||||
| 				} | ||||
| 				newChunk[0].appendChild(document.createElement("br")); | ||||
| 				game_text.append(newChunk); | ||||
| 				bindGametext(); | ||||
| 			} | ||||
| 			bindGametext(); | ||||
| 			hide([$('#curtain')]); | ||||
| 		} else if(msg.cmd == "removechunk") { | ||||
| 			hideMessage(); | ||||
| 			let index = msg.data; | ||||
| 			var index = msg.data; | ||||
| 			var element = game_text.children('#n' + index); | ||||
| 			if(element.length) { | ||||
| 				unbindGametext(); | ||||
| 			game_text.children(`#n${index}`).remove()  // Remove the chunk | ||||
| 				if((element[0].nextSibling === null || element[0].nextSibling.nodeType !== 1 || element[0].nextSibling.tagName !== "CHUNK") && element[0].previousSibling !== null && element[0].previousSibling.tagName === "CHUNK") { | ||||
| 					element[0].previousSibling.appendChild(document.createElement("br")); | ||||
| 				} | ||||
| 				element.remove();  // Remove the chunk | ||||
| 				bindGametext(); | ||||
| 			} | ||||
| 			hide([$('#curtain')]); | ||||
| 		} else if(msg.cmd == "setgamestate") { | ||||
| 			// Enable or Disable buttons | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Gnome Ann
					Gnome Ann