JSFiddle - React, Tailwind, and code Playground

by lid0

HTML

<progress id="prog1" value="10" max="100"></progress>

<p>
output(events):
</p>
<pre id="output"></pre>

CSS

#output {
  font-size:12px;
  background:#cfcfcf;
  padding:1px;
}

JavaScript

/**
lidlanca -  2021 Mar
add ability to listen to value change of <progress> element
 - hook to .value setter, to detect value set
 - hook to getter of .setAttribute, and wrap call to spy on call
 will dispatch customEvent 'change' preValue and newValue will be attached to the event detail property.
**/

function findDescriptor(obj, prop) {
  return Object.hasOwnProperty.call(obj, prop) ?
    Object.getOwnPropertyDescriptor(obj, prop) :
    findDescriptor(Object.getPrototypeOf(obj), prop);
}


// log output 
var output = document.getElementById("output")

// progress element
var el = document.getElementById("prog1")
// add value change event ( .value or via setAttribute )
supportValueChangeEvent(el)

// listen for change event, will fire even if value is the same, can be improved 
el.addEventListener("change", function(ee) {
  output.innerHTML += "&lt;progress&gt; event 'change' : " + JSON.stringify(ee.detail) + "\n"
})



function supportValueChangeEvent(el) {
  var {
    get: Vget,
    set: Vset
  } = findDescriptor(el, "value")

  var {
    value: SetAttributeGet,
  } = findDescriptor(el, "setAttribute")

  Object.defineProperty(el, "setAttribute", {
    get() {
      var origSetAttributeMethod = SetAttributeGet.bind(this); //bind original method
      // proxy/wrap method
      var _setAttribute = function(key, value) {

        prevValue = el.getAttribute("value")

        var ev = new CustomEvent('change', {
          detail: {
            prevValue: prevValue,
            newValue: `${value}`
          }
        });
        // call original set method 
        origSetAttributeMethod(key, value)
        // dispatch change event, if changed 
        if (prevValue != value) el.dispatchEvent(ev);

        return true
      }

      return _setAttribute;
    }
  })

  Object.defineProperty(el, "value", {
    configurable: true,
    enumerable: true,
    set(value) {
      var prevValue = Vget.call(this)
      var ev = new CustomEvent('change', {
        detail:...