I made this for fun
. Maybe somebody is still interested in this thread, so i posted it.
Kotlin code:
import org.w3c.dom.HTMLElement
import org.w3c.dom.OPEN
import org.w3c.dom.ShadowRootInit
import org.w3c.dom.ShadowRootMode
import kotlin.browser.window
fun main(args: Array<String>) {
val xTestSpec = customElementSpec().apply {
observedAttributes = arrayOf("prop")
init = XTest::init.unsafeCast<(HTMLElement) -> Unit>()
attributeChangedCallback = XTest::attributeChangedCallback.unsafeCast<(HTMLElement, String, String, String) -> Unit>()
}
val xTestConstructor = getCustomElementConstructor(xTestSpec)
window.customElements.define("x-test", xTestConstructor)
}
abstract external class XTest : HTMLElement
fun XTest.init() {
val shadow = attachShadow(ShadowRootInit(ShadowRootMode.OPEN)).unsafeCast<HTMLElement>()
shadow.innerHTML = "<p>Works !!!</p>"
}
fun XTest.attributeChangedCallback(attrName: String, oldVal: String, newVal: String) {
println("$attrName: $oldVal -> $newVal")
}
private fun customElementSpec(): CustomElementSpec = js("{}").unsafeCast<CustomElementSpec>()
private external interface CustomElementSpec {
var observedAttributes: Array<String>?
var init: ((receiver: HTMLElement) -> Unit)?
var connectedCallback: ((receiver: HTMLElement) -> Unit)?
var disconnectedCallback: ((receiver: HTMLElement) -> Unit)?
var attributeChangedCallback: ((receiver: HTMLElement, attrName: String, oldVal: String, newVal: String) -> Unit)?
var adoptedCallback: ((receiver: HTMLElement) -> Unit)?
}
private val getCustomElementConstructor: (spec: CustomElementSpec) -> () -> dynamic by lazy {
function<(spec: CustomElementSpec) -> () -> dynamic>("spec", block = BLOCK)
}
@JsName("Function")
private external fun <T> function(vararg params: String, block: String): T
private const val BLOCK = """const myObservedAttributes = spec.observedAttributes;
const myInit = spec.init;
const myConnectedCallback = spec.connectedCallback;
const myDisconnectedCallback = spec.disconnectedCallback;
const myAttributeChangedCallback = spec.attributeChangedCallback;
const myAdoptedCallback = spec.adoptedCallback;
return class extends HTMLElement {
static get observedAttributes() {
if (myObservedAttributes) {
return myObservedAttributes;
}
}
constructor() {
super();
if (myInit) {
myInit(this);
}
}
connectedCallback() {
if (myConnectedCallback) {
myConnectedCallback(this);
}
}
disconnectedCallback() {
if (myDisconnectedCallback) {
myDisconnectedCallback(this);
}
}
attributeChangedCallback(attrName, oldVal, newVal) {
if (myAttributeChangedCallback) {
myAttributeChangedCallback(this, attrName, oldVal, newVal);
}
}
adoptedCallback() {
if (myAdoptedCallback) {
myAdoptedCallback(this);
}
}
};"""
HTML code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test - Web Components</title>
<script src="out/production/kotlin-webcomponents/lib/kotlin.js"></script>
<script src="out/production/kotlin-webcomponents/kotlin-webcomponents.js"></script>
</head>
<body>
<x-test prop="test"></x-test>
</body>
</html>
Google Chrome 68.0.3440.106 (Build oficial) (64 bits) screenshot:
Firefox Developer Edition 63.0b1 (64-bits) screenshot:

