JSFiddle - React, Tailwind, and code Playground

HTML

<h1>(copy for stackoverflow question)</h1>

		<label>
			Ciphertext:
			<br />
			<textarea id="ciphertext"></textarea>
		</label>
		<br />
		<button id="decipher">Go</button>

		<p>Output:</p>

		<pre id="log"></pre>

		<p>Plaintext:</p>

		<textarea id="plaintext"></textarea>
		

	</body>
</html>

CSS

body {
				width: 900px;
				margin: 0 auto;
			}

			pre {
				background: #eee;
				border: 1px dashed #aaa;
				max-height: 150px;
				overflow: auto;
				word-wrap: break-word;
			}

			textarea {
				width: 100%;
				height: 100px;
			}

JavaScript

$(document).ready(function(){
	$('#decipher').click(Decipher);
});

function Decipher() 
{
	var $mCipher;
	var $mTempCipher;
	var $mKeyLength;

	var init = function() 
	{
		$('#log').html();
		startDeciphering();
	}

	var startDeciphering = function()
	{
		log('Starting to decipher'); 

		// normalize the ciphertext to alphanumeric only
		$mCipher = normalize( $('#ciphertext').val() );

		output($mCipher); // temp

		// @todo: try to guess the key length using the Friedman method?

		// try to define key length using the Kasiski method
		$mKeyLength = defineKeyLength();

		// @todo: generic exit function
		if(!$mKeyLength) return false;

		// 
	}


	var defineKeyLength = function()
	{
		log('Step 1: Define key length', true);
		var $lRecurringStrings = [];

		// find recurring strings of decreasing length
		for(var $i = 12; $i > 3; $i--) {
			console.log("String length:", $i);
			$lRecurringStrings = $lRecurringStrings.concat(findRecurringString($i));
		}

		// show recurring strings or exit 
		if($lRecurringStrings.length > 0)
			log("Recurring strings:" + $lRecurringStrings , true);
		else {
			log('No recurring strings found :(. Either the key is too long or the ciphertext is too short to break the code.', true);
			return false;
		}

			getDistances();

	}



	var findRecurringString = function($aLength, $aCallback)
	{
		log('Finding recurring strings of length ' + $aLength, true)

		// use a temp cipher so we can safely replace matched strings without messing up the original
		$mTempCipher = $mCipher;
		var $lRecurring = [];

		// loop through the ciphertext, taking a string of $aLength length and advancing one next letter each step
		for(var $i = 0; $i <= $mTempCipher.length - $aLength; $i++) {

			log('.');
			var $lString = $mTempCipher.substr($i, $aLength);

			console.log($i, $mTempCipher.length, $aLength);
			
            listRecurrence({ string: $lString }, function($aData){
				// return 
				$lRecurring.push($aData.string);
			});
		}

		return...