<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  <title>Reactive Programming</title>
</head>

<body>
  
  
  <div>
    <h1>Exercise: Typing of the Dead</h1>
    <div>
      Type the given word correctly and watch the console. Most of the time 1 of the 2 subscriptions on the typoStream will fire (when there should fire none).
    </div>
    <br />
    <div id="TotDWord"></div>
    <input type="text" name="" id="TotDInput" value="" /><span>Highscore: </span><span id="TotDHighscore"></span>
    <div id="TotDScore"></div>
  </div>

  <script>
    console.clear();
  </script>

  <script data-require="jquery" data-semver="3.1.1" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.6/rx.all.js"></script>

  <script src="util/renderer.js"></script>

  <script src="exercise/TypingOfTheDead.js"></script>

</body>
function render(data, containerId) {
  if (!containerId) containerId = 'content';
  const content = document.createElement('div');
  innerHtml = data;
  if (typeof data === 'object') innerHtml = JSON.stringify(data);
  content.innerHTML = innerHtml;
  document.getElementById(containerId).appendChild(content);
}

function renderHtml(html, containerId) {
  if (!containerId) containerId = 'content';
  document.getElementById(containerId).appendChild(html);
}

function createElement(containerId) {
  const ele = document.createElement('div');
  renderHtml(ele, containerId);
  return $(ele);
}
(() => {

  // --- UI Stuff, NO NEED TO TOUCH THESE --- //
  const wordField = $('#TotDWord');
  const inputField = $('#TotDInput');
  // ----------------------------------------- //

  // A stream of the users string inputs
  const inputFieldStream = Rx.Observable.fromEvent(inputField, 'keyup')
    .map(x => x.target.value).distinctUntilChanged();

  // This stream is used to represent the users unput - we don't use the 
  // inputFieldStream directly because we want to manually send values aswell
  const inputStream = new Rx.Subject();


  // Feed the stream from the field into our inputStream
  inputFieldStream.subscribe(inputStream);

  // A stream that allows us to manually trigger that we need a new word
  const nextStream = new Rx.Subject();

  // When we want the next word we need to reset the users input
  nextStream.subscribe(() => {
    inputField.val('');
    inputStream.onNext('');
  });

  // This stream calls a server for a new random word every time the nextStream emits an event. We startWith a value to trigger the first word
  const wordStream = nextStream.startWith('')
    .flatMapLatest(getRandomWord)
    // publish & refCount cache the result - otherwise every .map on wordStream would cause a new HTTP request
    .publish().refCount();

  // When there is a new word, we display it
  wordStream.subscribe(word => {
    wordField.empty();
    wordField.append(word);
  });

  // Checkstream combines the latest word with the latest userinput. It emits an array, like this ['the word', 'the user input'];
  const checkStream = wordStream.combineLatest(inputStream);

  // Emits an event if the user input is not correct
  const typoStream = checkStream.filter(tuple => {
      const word = tuple[0];
      const input = tuple[1];
      return !word.startsWith(input);
    });

  // When there is a typo we need a new word
  typoStream.subscribe(nextStream);

  // Emits an event when the user has entered the entire word correctly
  const wordCompletedStream = checkStream.filter(tuple => {
    const word = tuple[0];
    const input = tuple[1];
    return word == input;
  });

  /**
   * THIS WILL (MOST OF THE TIME) NOT FIRE WHEN YOU COMPLETE A WORD
   */
  typoStream.subscribe(x => console.log('wont get executed'));

  // Whenever the word is completed, request a new word
  wordCompletedStream.subscribe(nextStream);

  /**
   * THIS WILL FIRE WHEN YOU COMPLETE A WORD
   */
  typoStream.subscribe(x => console.log('will get executed'));

  // Calls a server for a random word
  // returns a promise
  function getRandomWord() {
    return $.ajax({
      // Change the URL to cause a 404 error
      url: 'http://setgetgo.com/randomword/get.php'
    }).promise();
  }

})();