JSFiddle - React, Tailwind, and code Playground

by nikgrozev

HTML

<html>
  <body>
    <p>Clicking the buttons will change their style and open a "spinner"</p>
    <div>
      <button onclick="samleXMLHttpRequest()">
        XMLHttpRequest button
      </button>
    </div>
    <div>
      <button onclick="fetch('https://jsonplaceholder.typicode.com/posts')">
        Fetch button
      </button>
    </div>
    <div>
      <button onclick="console.log('I was clicked')">
        Console Log button
      </button>
    </div>
    <div>
      <a href="https://example.com">Navigate away (shows "spinner")</a>
    </div>

    <p>Dynamic buttons will be added below with the same behaviour:</p>
    <div id="spinner-id" class="hidden">
      Loading...
    </div>
  </body>
</html>

CSS

.button-clicked {
  opacity: 0.6;
  background: black;
  color: white;
}
.hidden {
  display: none;
}
.running-spinner {
  position: fixed;
  width: 100%;
  height: 100vh;
  background: gray;
  top: 0;
  left: 0;
  opacity: 0.7;
  color: black;
  text-align: center;
  padding-top: 50vh;
  z-index: 100;
}

JavaScript 1.7

/* ======================================================================================= */
/* ===================== Test Code - adds a button every N seconds ======================= */
function samleXMLHttpRequest(){
  const req = new XMLHttpRequest();
  req.open("GET", "https://jsonplaceholder.typicode.com/posts");
  req.send();
}
let dynamicButtonCount = 1;
setInterval(() => {
	var button = document.createElement("button");
	button.innerHTML = "Dynamic button " + dynamicButtonCount++;
  button.onclick=samleXMLHttpRequest;
  var div = document.createElement("div");
  div.appendChild(button);
  document.getElementsByTagName("body")[0].appendChild(div)
}, 10 * 1000)
/* ========================================================================================= */

/* ========================================================================================= */
/* ============ Change the style of every button (dynamic or static) on click ============== */
const timeout = 500;
const processButton = (btn) => {
  // If we processed it - skip
  if (!btn || btn.getAttribute("data-single-click-listener-added" === "true")) {
    return
  }

  // Callback to enable, disable after timeout
  const clickCallback = () => {
    btn.classList.add("button-clicked");
    setTimeout(() => {
      btn.classList.remove("button-clicked");
    }, timeout);
  }
  
  // Add the listener
  btn.addEventListener("click", () => setTimeout(clickCallback, 0), {capture: true}) ;

  // mark it as processed
  btn.setAttribute("data-single-click-listener-added", "true");
}

// Get all buttons on the page after load:
window.addEventListener("DOMContentLoaded", () => {
  const buttons = document.getElementsByTagName('button');
  for (let i = 0; i < buttons.length; i++) {
    processButton(buttons[i])
  }
})

// Traverse a node recursively to get all the buttons 
const getButtonChildren = (node) => {
  if (!node || !node.tagName) {
    return [];
  }
  if (node.tagName.toLowerCase() === "button") {
   ...