Song Sad Happy Rage
</script>

<script>

  // prepare HTML defined "result" container for new output
  const resultContainer = document.getElementById("result");

  // keys for joke reactions
  const SAD = "sad";
  const HAPPY = "happy";
  const RAGE = "rage";

  // prepare fetch urls
  const url = "http://ssjn.nighthawkcodescrums.gq/api/song";
  const sad_url = url + "/sad/";  // haha reaction
  const happy_url = url + "/happy/";  // boohoo reaction
  const rage_url = url + "/rage/";  // boohoo reaction

  // prepare fetch GET options
  const options = {
    method: 'GET', // *GET, POST, PUT, DELETE, etc.
    mode: 'cors', // no-cors, *cors, same-origin
    cache: 'default', // *default, no-cache, reload, force-cache, only-if-cached
    credentials: 'omit', // include, *same-origin, omit
    headers: {
      'Content-Type': 'application/json'
      // 'Content-Type': 'application/x-www-form-urlencoded',
    },
  };
  // prepare fetch PUT options, clones with JS Spread Operator (...)
  const put_options = {...options, method: 'PUT'}; // clones and replaces method

  // fetch the API
  fetch(url, options)
    // response is a RESTful "promise" on any successful fetch
    .then(response => {
      // check for response errors
      if (response.status !== 200) {
          error('GET API response failure: ' + response.status);
          return;
      }
      // valid response will have JSON data
      response.json().then(data => {
          console.log(data);
          for (const row of data) {
            // make "tr element" for each "row of data"
            const tr = document.createElement("tr");
            
            // td for joke cell
            const song = document.createElement("td");
              song.innerHTML = row.id + ". " + row.song;  // add fetched data to innerHTML

            // td for haha cell with onclick actions (making the buttons)
            const sad = document.createElement("td");
              const sad_but = document.createElement('button');
              sad_but.id = SAD+row.id   // establishes a HAHA JS id for cell
              sad_but.innerHTML = row.sad;  // add fetched "haha count" to innerHTML
              sad_but.onclick = function () {
                // onclick function call with "like parameters"
                reaction(SAD, sad_url+row.id, sad_but.id);  
              };
              sad.appendChild(sad_but);  // add "haha button" to haha cell

            // td for boohoo cell with onclick actions
            const happy = document.createElement("td");
              const happy_but = document.createElement('button');
              happy_but.id = HAPPY+row.id  // establishes a BOOHOO JS id for cell
              happy_but.innerHTML = row.happy;  // add fetched "boohoo count" to innerHTML
              happy_but.onclick = function () {
                // onclick function call with "jeer parameters"
                reaction(HAPPY, happy_url+row.id, happy_but.id);  
              };
              happy.appendChild(happy_but);  // add "boohoo button" to boohoo cell

              // td for haha cell with onclick actions (making the buttons)
            const rage = document.createElement("td");
              const rage_but = document.createElement('button');
              rage_but.id = RAGE+row.id   // establishes a HAHA JS id for cell
              rage_but.innerHTML = row.rage;  // add fetched "haha count" to innerHTML
              rage_but.onclick = function () {
                // onclick function call with "like parameters"
                reaction(RAGE, rage_url+row.id, rage_but.id);  
              };
              rage.appendChild(rage_but);  // add "haha button" to haha cell
             
            // this builds ALL td's (cells) into tr (row) element
            tr.appendChild(song);
            tr.appendChild(sad);
            tr.appendChild(happy);
            tr.appendChild(rage);

            // this adds all the tr (row) work above to the HTML "result" container
            resultContainer.appendChild(tr);
          }
      })
  })
  // catch fetch errors (ie Nginx ACCESS to server blocked)
  .catch(err => {
    error(err + " " + url);
  });

  // Reaction function to likes or jeers user actions
  function reaction(type, put_url, elemID) {

    // fetch the API
    fetch(put_url, put_options)
    // response is a RESTful "promise" on any successful fetch
    .then(response => {
      // check for response errors
      if (response.status !== 200) {
          error("PUT API response failure: " + response.status)
          return;  // api failure
      }
      // valid response will have JSON data
      response.json().then(data => {
          console.log(data);
          // Likes or Jeers updated/incremented
          if (type === SAD) // like data element
            document.getElementById(elemID).innerHTML = data.sad;  // fetched haha data assigned to haha Document Object Model (DOM)
          else if (type === HAPPY) // jeer data element
            document.getElementById(elemID).innerHTML = data.happy;  // fetched boohoo data assigned to boohoo Document Object Model (DOM)
          else if (type === RAGE)
            document.getElementById(elemID).innerHTML = data.rage;
          else
            error("unknown type: " + type);  // should never occur
      })
    })
    // catch fetch errors (ie Nginx ACCESS to server blocked)
    .catch(err => {
      error(err + " " + put_url);
    });
    
  }

  // Something went wrong with actions or responses
  function error(err) {
    // log as Error in console
    console.error(err);
    // append error to resultContainer
    const tr = document.createElement("tr");
    const td = document.createElement("td");
    td.innerHTML = err;
    tr.appendChild(td);
    resultContainer.appendChild(tr);
  }

</script>
evalmachine.<anonymous>:1
<script>
^

SyntaxError: Unexpected token <
    at createScript (vm.js:56:10)
    at Object.runInThisContext (vm.js:97:10)
    at run ([eval]:1020:15)
    at onRunRequest ([eval]:864:18)
    at onMessage ([eval]:828:13)
    at emitTwo (events.js:106:13)
    at process.emit (events.js:191:7)
    at process.nextTick (internal/child_process.js:758:12)
    at _combinedTickCallback (internal/process/next_tick.js:73:7)
    at process._tickCallback (internal/process/next_tick.js:104:9)