function elToObject(el){
obj = {}
if(el.targetElement)
el = el.targetElement
el.getAttributeNames().forEach(name => {
obj[name] = el.getAttribute(name)
if(el[name])
obj[name] = el[name]
})
return obj
}
function wrapElement(app, el){
const allEvents = [
'click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseenter',
'mouseleave', 'mouseover', 'mouseout', 'keydown', 'keyup', 'keypress',
'focus', 'blur', 'change', 'input', 'submit', 'reset', 'resize',
'contextmenu', 'drag', 'drop', 'dragstart', 'dragend', 'dragover',
'dragenter', 'dragleave', 'touchstart', 'touchmove', 'touchend',
'touchcancel', 'pointerdown', 'pointerup', 'pointermove', 'pointerover',
'pointerout', 'pointerenter', 'pointerleave', 'wheel'/*'scroll',*/
];
const props = [
'data',
'id',
'isTrusted',
'altKey',
'ctrlKey',
'layerX',
'layerY',
'movementX',
'movementY',
'offsetX',
'offsetY',
'pageX',
'pageY',
'screenX',
'screenY',
'shiftKey',
'metaKey',
'value',
'code',
'keyCode',
'key'
]
el.app = app
allEvents.forEach(event => {
el.addEventListener(event, async(e) => {
if(el.app.suppress)
return
obj = {}
obj["id"] = el.id ? el.id : el._uuid
obj["uuid"] = el._uuid
obj["event"] = event
obj['attrs'] = elToObject(el)
obj['data'] = {}
props.forEach(prop => {
if(e[prop] != undefined){
obj['data'][prop] = e[prop]
}
if(e["targetElement"] && e["targetElement"][prop] != undefined){
obj['data'][prop] = e["targetElement"][prop]
}
})
//obj["data"] = JSON.stringify(e)
obj["nr"] = el.app.inc()
response = await el.app.emit(event, obj);
},false)
})
}
HTMLElement.prototype.rWebGui = function(){
const rWebGui = this
const config = { attributes: true, childList: true, subtree: true };
const callback = (mutationList, observer) => {
for (const mutation of mutationList) {
if (mutation.type === "childList") {
mutation.addedNodes.forEach(child => {
wrapElement(rWebGui, child)
if(!child._uuid){
child._uuid = rWebGui.createUUID()
}
})
} else if (mutation.type === "attributes") {
obj = {}
obj["uuid"] = mutation.target._uuid
obj[mutation.attributeName] = mutation.target.getAttribute(mutation.attributeName)
rWebGui.emit("attributeChanged", obj)
}
}
};
const observer = new MutationObserver(callback);
observer.observe(rWebGui, config);
}
class RWebGuiApp extends HTMLElement {
_ready = false
_uuid = null
ws = null
_inc = 0;
connected = false
callbacks = {}
suppress = false
inc() {
this._inc++;
return this._inc
}
get isReady() {
return this.app._ready && this.app.connected
}
get url() {
const protocol = window.location.protocol === "https:" ? "wss" : "ws";
return `${protocol}://${window.location.host}/ws/${this.uuid}`
}
constructor() {
// Always call super first in constructor
super();
if(!this.parent || !this.parent.app){
this.ws = new WebSocket(this.url)
const me = this
this.ws.onopen = ()=>{
me.connected = true;
}
this.ws.onmessage = (e)=>{
const data = JSON.parse(e.data)
if(data.event_id){
if(me.callbacks[data.event_id])
{
me.callbacks[data.event_id](data)
}else if(data.event == "call"){
const method = me[data.method]
if(!method){
data['success'] = false;
data['result'] = null;
}else{
let response = method(...data.args)
data['result'] = response
data['success'] = true
}
if(data['callback'])
me.ws.send(JSON.stringify(
data
))
}else {
if(data.event == "set_attr"){
const el = document.getElementById(data['id'])
if(el){
data['data'].forEach(attr=>{
el.setAttribute(attr['name'], attr['value'])
el[attr['name']] = attr['value']
})}
}
}
}
}
}
}
getAttr(id,key){
const el = document.getElementById(id)
if (el[key] != undefined)
return el[key]
return el.getAttribute(key)
}
getData(id,key){
const el = document.getElementById(id)
return el.dataset[key]
}
setData(id,key,value){
const el = document.getElementById(id)
el.dataset[key] = value
return true
}
setStyle(id, key, value){
const el = document.getElementById(id)
el.style[key] = value
}
getStyle(id, key){
return document.getElementById(id).style[key]
}
setAttr(id, key, value) {
try{
document.getElementById(id).setAttribute(key, value)
document.getElementById(id)[key] = value
}catch(e){
console.error("Element not found:", key)
console.error("Failed to set value:", value)
}
return true
}
get isApp(){
return !this.parent || !this.parent.app
}
emit(event, data) {
if(!this.app.isReady)
return false;
const me = this
return new Promise(resolve => {
data["event_id"] = me.inc()
me.callbacks[data["event_id"]] = resolve
me.app.ws.send(JSON.stringify({"uuid":obj.uuid,"event_id":data["event_id"], "event": event, "data": data}))
}).then(res => {
return res
})
}
get uuid() {
if(!this._uuid){
this._uuid = this.createUUID()
}
return this._uuid
}
createUUID(){
const uuid = crypto.randomUUID();
return uuid
}
get app() {
if(!this.parent)
return this
if(!this.parent.app)
return this
return this.parent.app
}
connectedCallback() {
this.rWebGui()
if(!this.isApp){
this._uuid = this.generateUUID()
this._ready = true;
return;
}
// this.querySelectorAll("*").forEach(child => {
// child.rWebGui()
// })
/// this.dataset.uuid = this.generateUUID();
this._ready = true
}
attributeChangedCallback(name, oldValue, newValue) {
this.emit("attributeChanged", {aa:123})
}
}
customElements.define("rwebgui-app",RWebGuiApp);
/*
document.addEventListener("DOMContentLoaded", () => {
document.querySelectorAll("*").forEach(child => {
child.rWebGui()
})
})*/;