JSFiddle - React, Tailwind, and code Playground

by kentaromiura

HTML

<custom-element name="kenta-b" noscript extends="b">
      <template>this should be bold</template>
    </custom-element>

    <custom-element name="kenta-simple" noscript>
      <template>
        <b> Simple element </b>
      </template>
    </custom-element>

    <custom-element name="kenta-foo" constructor="foo">
      <template>foo
      <span><div data-id="test1">this is for testing deep clonenode</div></span>
      <span data-id="test2"></span>
      </template>
      <script>
        document.register.tag('kenta-foo', {
          options: true,
          ready: function(){
            console.log('ready', this, foo)
            //testing the $ shortcuts
            console.log(this.$.test1.innerHTML)
            this.$.test2.innerHTML = "test"
          },
          created: function(){
            console.log('created', this)
          },
          test: function(){
            console.log('test!')
          }
        })
      </script>
      <style>
      kenta-foo {
        display: block;
        color:red;
      }
      </style>
    </custom-element>

    <kenta-foo id=test></kenta-foo>
    <kenta-simple></kenta-simple>
    <kenta-b></kenta-b>
<script>
onload = function(){
  document.getElementById('test').test()
  console.log(typeof(foo) !== 'undefined')
}
</script>

JavaScript

(function(global){
  if (!document.register) document.register = document.registerElement

  var customElements = {},
      create = Object.create || function(proto){
        var f = function(){}
        f.prototype = proto
        return new f()
      },
      has = (has = Object.prototype.hasOwnProperty, has.call.bind(has)),
      nop = function(){},
      collect = function(from, collected){
        if (document.querySelectorAll) return document.querySelectorAll('[data-id]', from)
        collected = collected || []
        if ('getAttribute' in from && from.getAttribute('data-id')){
          collected.push(from)
        }
        for (var i = 0, max = from.children.length; i<max; i++){
          collect(from.children[i], collected)
        }
        return collected
      }

  document.register.tag = function(name, options){

    options = options || {}
    if (!customElements[name]){
      customElements[name] = {
        options: options
      }
      return;
    }

    var xtends = customElements[name].xtends,
        ctor = customElements[name].ctor,
        proto = xtends? create(document.createElement(xtends).constructor.prototype) : create(HTMLElement.prototype),
        created = options.created || nop,
        ready = options.ready || nop,
        onAttributeChange = options.attributeChangedCallback || nop,
        attributes = customElements[name].attributes.split(' '),
        template = customElements[name].content,
        descriptor = function(attribute){
          return {
              enumerable: true,
              get: function(){
                return this.getAttribute(attribute)
              },
              set: function(value){
                this.setAttribute(attribute, value)
              }
            }
        }

    delete options.created
    delete options.ready
    delete options.attributeChangedCallback

    for (var any in options){
      if (has(options, any)){
        proto[any] = options[any]
      }
    }

   ...