Redraw Event Introspection

by JAForbes

Level: expert • Mithril.js Version: latest

Live Example

Dependencies

,
Type Name URL
scriptmithril@latesthttps://unpkg.com/mithril@latest
scriptbss.jshttps://unpkg.com/bss@1.6.4/bss.js

JavaScript

let oldM = window.m
let m = (...args) => {
  let x = oldM(...args)
  let stack = (new Error().stack+'').split(/\bat\b/gm)[2].trim()
  let selector = args[0]
  let [column, ln, file, protocol] = stack.split(':').reverse()
  column = column.match(/\d+/)[0]

  if( x.attrs ) {
    for(let k of Object.keys(x.attrs)){
      if ( k.slice(0,2) == 'on' ) {
        let old = x.attrs[k]
        x.attrs[k] = (...args) => {
          m.redraw.cause.unshift({
            type: 'event',
            selector,
            vnode: x,
            where: {
              column, ln, file, protocol
            }
          })
          return old(...args)
        }
      }
    }
  }

  return x
}

m.oldRequest = oldM.request
const newRequest = (...args) => {

  let [url, options] =
    typeof args[0] != 'string'
    ? [args[0].url, args[0]||{}]
    : args.concat({})

  let out = m.oldRequest(...args)

  let stack = (new Error().stack+'').split(/\bat\b/gm)[2].trim()
  let selector = args[0]
  let [column, ln, file, protocol] = stack.split(':').reverse()
  column = column.match(/\d+/)[0]

  out.finally( () => {
    m.redraw.cause.unshift({
      type: 'request',
      url,
      options,
      where: {
        column, ln, file, protocol
      }
    })
  })
  return out
}

Object.assign(m, oldM, { request: newRequest })
m.redraw.cause = []

let renders = 0
m.mount(document.body, () => ({
  view: () => [
    m('button.a', { onclick(){} }, 'Button A'),
    m('button.b', { onclick(){
      m.request('https://jsonplaceholder.typicode.com/todos/1')
    } }, 'Button B'),
    m('input[type=date]', { oninput(){} }),
    m('input[type=text]', { oninput(){} }),
    m('p','Renders: ', ++renders),
    m.redraw.cause.flatMap(({ vnode, type, url, options, selector, where }) =>
      type == 'event'
      ? [
        m('pre', m('code', `m("${selector}", ${JSON.stringify(vnode.attrs)}, ${vnode.text ? `"${vnode.text}"` : ''})`)),
        ,m('.table'
          ,Object.entries({ selector, ...where }).map(
            ([k,v]) =>
              m('.row'
                  ,m('.key', k), m('.value', v)
              )
          )
        )
      ]
      : type == 'request'
      ? [
        ,m('pre', m('code', `m.request("${url}", ${JSON.stringify(options)})`))
        ,m('.table'
          ,Object.entries({ ...where }).map(
            ([k,v]) =>
              m('.row'
                  ,m('.key', k), m('.value', v)
              )
          )
        )
      ]
      : null
    )
  ]
}))

CSS

.row {
  display: grid;
  grid-template-columns: 4em 1fr;
  gap: 1em;
}

.row .key {
  font-weight: bold;
}

The snippet requires the latest version of Mithril.js framework. As an expert user, who is familiar with all the aspects of Mithril.js and JavaScript itself, you are able the follow the example easily.

In this example we can see some Mithril.js API methods like m.mount, m.redraw or m.request, besides Mithril.js' basic m() hyperscript function.

The code sample was authored by JAForbes. It was last modified on 16 February 2022.

Contribute

Do you see some improvements, that could be addressed here? Then let me know by opening an issue. As an alternative, you can fork the repository on GitHub, push your commits and send a pull request. To start your work, click on the edit link below. Thank you for contributing to this repo.

See more code examples  •  Edit this example on GitHub