Skip to content

Instantly share code, notes, and snippets.

@sanity
Created March 3, 2020 07:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sanity/5a378159796c4dabf40dfcda35c2e468 to your computer and use it in GitHub Desktop.
Save sanity/5a378159796c4dabf40dfcda35c2e468 to your computer and use it in GitHub Desktop.
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="kweb_native_assets/jquery/jquery-3.1.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.8.2/dist/semantic.min.css">
<script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.8.2/dist/semantic.min.js"></script>
<script language="JavaScript">
function toWSUrl(s) {
let l = window.location;
return (l.protocol === "https:" ? "wss://" : "ws://") + l.host + "/" + s;
}
let kwebClientId = "G31dWi";
let websocketEstablished = false;
let preWSMsgQueue = [];
let socket;
function handleInboundMessage(msg) {
const yourId = msg["yourId"];
const debugToken = msg["debugToken"];
if (kwebClientId != yourId) {
console.error(
"Received message from incorrect clientId, was " +
yourId +
", should be " +
kwebClientId
);
}
const execute = msg["execute"];
if (execute !== undefined) {
try {
eval(execute["js"]);
console.debug("Executed `" + execute["js"] + "`");
} catch (err) {
if (debugToken != undefined) {
console.error("Error evaluating [" + execute["js"] + "] : " + err);
var error = {
debugToken: debugToken,
error: { name: err.name, message: err.message }
};
var message = { id: kwebClientId, error: error };
sendMessage(JSON.stringify(message));
} else {
throw err;
}
}
}
let evaluate = msg["evaluate"];
if (evaluate !== undefined) {
try {
const data = eval(evaluate["js"]);
console.debug("Evaluated [" + evaluate["js"] + "]", data);
const callback = { callbackId: evaluate["callbackId"], data: data };
const message = { id: kwebClientId, callback: callback };
sendMessage(JSON.stringify(message));
} catch (err) {
if (debugToken != undefined) {
console.error("Error evaluating `" + evaluate["js"] + "`: " + err);
const error = {
debugToken: debugToken,
error: { name: err.name, message: err.message }
};
const message = { id: kwebClientId, error: error };
sendMessage(JSON.stringify(message));
} else {
throw err;
}
}
}
const instructions = msg["instructions"];
if (instructions !== undefined) {
for (let i = 0; i < instructions.length; i++) {
const instruction = instructions[i];
if (instruction.type === "SetAttribute") {
document
.getElementById(instruction.parameters[0])
.setAttribute(instruction.parameters[1], instruction.parameters[2]);
} else if (instruction.type === "RemoveAttribute") {
const id = instruction.parameters[0];
const attribute = instruction.parameters[1];
document.getElementById(id).removeAttribute(attribute);
} else if (instruction.type === "CreateElement") {
const tag = instruction.parameters[0];
const attributes = instruction.parameters[1];
const myId = instruction.parameters[2];
const parentId = instruction.parameters[3];
const position = instruction.parameters[4];
const newEl = document.createElement(tag);
newEl.setAttribute("id", myId);
for (const key in attributes) {
if (key !== "id") {
newEl.setAttribute(key, attributes[key]);
}
}
let parentElement = document.getElementById(parentId);
if (position > -1) {
parentElement.insertBefore(newEl, parentElement.childNodes[position]);
} else {
parentElement.appendChild(newEl);
}
} else if (instruction.type === "AddText") {
const id = instruction.parameters[0];
const text = instruction.parameters[1];
const textNode = document.createTextNode(text);
document.getElementById(id).appendChild(textNode);
} else if (instruction.type === "SetText") {
const id = instruction.parameters[0];
const text = instruction.parameters[1];
document.getElementById(id).textContent = text
}
}
}
}
function connectWs() {
var wsURL = toWSUrl("ws");
console.debug("Establishing websocket connection", wsURL);
socket = new WebSocket(wsURL);
if (window.WebSocket === undefined) {
document.body.innerHTML =
"<h1>Unfortunately this website requires a browser that supports websockets (all modern browsers do)</h1>";
console.error("Browser doesn't support window.WebSocket");
} else {
socket.onopen = function() {
console.debug("socket.onopen event received");
websocketEstablished = true;
console.debug("Websocket established", wsURL);
sendMessage(JSON.stringify({ id: kwebClientId, hello: true }));
while (preWSMsgQueue.length > 0) {
sendMessage(preWSMsgQueue.shift());
}
};
socket.onmessage = function(event) {
var msg = JSON.parse(event.data);
console.debug("Message received from socket: ", event.data);
handleInboundMessage(msg);
};
socket.onclose = function(evt) {
console.debug("Socket closed");
var explanation = "";
if (evt.reason && evt.reason.length > 0) {
explanation = "reason: " + evt.reason;
} else {
explanation = "without a reason specified";
}
console.error("WebSocket was closed", explanation, evt);
websocketEstablished = false;
if (evt.wasClean){
console.warn("Attempting reconnect...")
connectWs()
} else {
console.warn("Forcing page reload");
location.reload(true);
}
// setTimeout(function() { location.reload(true); }, 5000);
};
socket.onerror = function(evt) {
console.error("WebSocket error", evt);
websocketEstablished = false;
console.warn("Forcing page reload");
location.reload(true);
// setTimeout(function() { location.reload(true); }, 5000);
};
}
}
function sendMessage(msg) {
if (websocketEstablished) {
console.debug("Sending WebSocket message", msg);
socket.send(msg);
} else {
console.debug(
"Queueing WebSocket message as connection isn't established",
msg
);
preWSMsgQueue.push(msg);
}
}
function callbackWs(callbackId, data) {
var msg = JSON.stringify({
id: kwebClientId,
callback: { callbackId: callbackId, data: JSON.stringify(data) }
});
sendMessage(msg);
}
/*
* Utility functions
*/
function hasClass(el, className) {
if (el.classList) return el.classList.contains(className);
else
return !!el.className.render(new RegExp("(\\s|^)" + className + "(\\s|$)"));
}
function addClass(el, className) {
if (el.classList) el.classList.add(className);
else if (!hasClass(el, className)) el.className += " " + className;
}
function removeClass(el, className) {
if (el.classList) el.classList.remove(className);
else if (hasClass(el, className)) {
var reg = new RegExp("(\\s|^)" + className + "(\\s|$)");
el.className = el.className.replace(reg, " ");
}
}
function removeElementByIdIfExists(id) {
var e = document.getElementById(id);
if (e) {
e.parentNode.removeChild(e);
}
}
var docCookies = {
getItem: function(sKey) {
if (!sKey || !this.hasItem(sKey)) {
return "__COOKIE_NOT_FOUND_TOKEN__";
}
return unescape(
document.cookie.replace(
new RegExp(
"(?:^|.*;\\s*)" +
escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") +
"\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*"
),
"$1"
)
);
},
/**
* docCookies.setString(sKey, sValue, vEnd, sPath, sDomain, bSecure)
*
* @argument sKey (String): the firstName of the cookie;
* @argument sValue (String): the value of the cookie;
* @optional argument vEnd (Number, String, Date Object or null): the max-age in seconds (e.g., 31536e3 for a year) or the
* expires date in GMTString format or in Date Object format; if not specified it will expire at the end of session;
* @optional argument sPath (String or null): e.g., "/", "/mydir"; if not specified, defaults to the current pathSegments of the current document location;
* @optional argument sDomain (String or null): e.g., "example.com", ".example.com" (includes all subdomains) or "subdomain.example.com"; if not
* specified, defaults to the host portion of the current document location;
* @optional argument bSecure (Boolean or null): cookie will be transmitted only over secure protocol as https;
* @return undefined;
**/
setItem: function(sKey, sValue, vEnd, sPath, sDomain, bSecure) {
if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/.test(sKey)) {
return;
}
var sExpires = "";
if (vEnd) {
switch (typeof vEnd) {
case "number":
sExpires = "; max-age=" + vEnd;
break;
case "string":
sExpires = "; expires=" + vEnd;
break;
case "object":
if (vEnd.hasOwnProperty("toGMTString")) {
sExpires = "; expires=" + vEnd.toGMTString();
}
break;
}
}
document.cookie =
escape(sKey) +
"=" +
escape(sValue) +
sExpires +
(sDomain ? "; domain=" + sDomain : "") +
(sPath ? "; path=" + sPath : "") +
(bSecure ? "; secure" : "");
},
removeItem: function(sKey) {
if (!sKey || !this.hasItem(sKey)) {
return;
}
var oExpDate = new Date();
oExpDate.setDate(oExpDate.getDate() - 1);
document.cookie =
encodeURIComponent(sKey) + "=; expires=" + oExpDate.toGMTString() + "; path=/";
},
hasItem: function(sKey) {
return new RegExp(
"(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\="
).test(document.cookie);
}
};
window.addEventListener("pageshow", function(event) {
if (window.performance.navigation.type === 2) {
location.reload(true);
}
});
function buildPage() {
handleInboundMessage({"yourId":"G31dWi","debugToken":"726edec539beb06a","evaluate":{"js":"document.origin","callbackId":1369705618}});
handleInboundMessage({"yourId":"G31dWi","debugToken":"29165255f353e7d1","execute":{"js":"document.getElementById(\"K4\").innerHTML\u003d\"A simple demo of \u003ca href\u003d\\\"https:\\/\\/docs.kweb.io\\/\\\"\u003eKweb\u003c\\/a\u003e, add and delete items from a\\nto do list.\\n\u003cp\\/\u003e\\nTry visiting this URL in another browser window and make some changes.\\n\u003cp\\/\u003e\\nYou may find the source code for this app\\n\u003ca href\u003d\\\"https:\\/\\/github.com\\/kwebio\\/core\\/tree\\/master\\/src\\/main\\/kotlin\\/io\\/kweb\\/demos\\/todo\\\"\u003ehere\u003c\\/a\u003e.\";"}});
handleInboundMessage({"yourId":"G31dWi","debugToken":"5966a2df23364205","execute":{"js":"document.getElementById(\"Kf\")\n .addEventListener(\"click\", function(event) {\n callbackWs(657780482, {\"altKey\" : event.altKey, \"button\" : event.button, \"buttons\" : event.buttons, \"clientX\" : event.clientX, \"clientY\" : event.clientY, \"ctrlKey\" : event.ctrlKey, \"detail\" : event.detail, \"metaKey\" : event.metaKey, \"movementX\" : event.movementX, \"movementY\" : event.movementY, \"region\" : event.region, \"retrieved\" : event.retrieved, \"screenX\" : event.screenX, \"screenY\" : event.screenY, \"shiftKey\" : event.shiftKey, \"type\" : event.type, \"x\" : event.x, \"y\" : event.y});\n });\n "}});
handleInboundMessage({"yourId":"G31dWi","debugToken":"32d198f3beac8e2e","execute":{"js":"document.getElementById(\"Kk\")\n .addEventListener(\"click\", function(event) {\n callbackWs(622908227, {\"altKey\" : event.altKey, \"button\" : event.button, \"buttons\" : event.buttons, \"clientX\" : event.clientX, \"clientY\" : event.clientY, \"ctrlKey\" : event.ctrlKey, \"detail\" : event.detail, \"metaKey\" : event.metaKey, \"movementX\" : event.movementX, \"movementY\" : event.movementY, \"region\" : event.region, \"retrieved\" : event.retrieved, \"screenX\" : event.screenX, \"screenY\" : event.screenY, \"shiftKey\" : event.shiftKey, \"type\" : event.type, \"x\" : event.x, \"y\" : event.y});\n });\n "}});
handleInboundMessage({"yourId":"G31dWi","debugToken":"15bec4aa8042e7","execute":{"js":"document.getElementById(\"Ko\")\n .addEventListener(\"keypress\", function(event) {\n callbackWs(340913554, {\"altKey\" : event.altKey, \"code\" : event.code, \"ctrlKey\" : event.ctrlKey, \"detail\" : event.detail, \"isComposing\" : event.isComposing, \"key\" : event.key, \"locale\" : event.locale, \"location\" : event.location, \"metaKey\" : event.metaKey, \"retrieved\" : event.retrieved, \"shiftKey\" : event.shiftKey, \"type\" : event.type});\n });\n "}});
handleInboundMessage({"yourId":"G31dWi","debugToken":"f17f2fc96b55fb6","execute":{"js":"document.getElementById(\"Kp\")\n .addEventListener(\"click\", function(event) {\n callbackWs(889151310, {\"altKey\" : event.altKey, \"button\" : event.button, \"buttons\" : event.buttons, \"clientX\" : event.clientX, \"clientY\" : event.clientY, \"ctrlKey\" : event.ctrlKey, \"detail\" : event.detail, \"metaKey\" : event.metaKey, \"movementX\" : event.movementX, \"movementY\" : event.movementY, \"region\" : event.region, \"retrieved\" : event.retrieved, \"screenX\" : event.screenX, \"screenY\" : event.screenY, \"shiftKey\" : event.shiftKey, \"type\" : event.type, \"x\" : event.x, \"y\" : event.y});\n });\n "}});
handleInboundMessage({"yourId":"G31dWi","debugToken":"2b2c426bfe645973","execute":{"js":""}});
connectWs();
}
</script>
<title id="K9">To Do List #KVar(18e827c)</title>
</head>
<body onload="buildPage()">
<noscript>
This page is built with <a href="https://kweb.io/">Kweb</a>, which requires JavaScript to be enabled.
</noscript>
<div id="K0" class="ui main container">
<div id="K1" class="column">
<div id="K2" class="ui vertical segment">
<div id="K3" class="ui message">
<p id="K4"></p>
</div>
</div>
<div id="K5" class="ui vertical segment">
<h1 id="K6" class="ui dividing header">To do List</h1>
<div id="K7" class="content">
<span id="K8"><span id="Ka"><h3 id="Kb"></h3>
<div id="Kc" class="ui middle aligned divided list">
<div id="Kd" class="item">
<div id="Ke" class="right floated content">
<button type="button" class="mini ui icon button" id="Kf"><i id="Kg" class="trash icon"></i></button>
</div>
<div id="Kh" class="content">
One
</div>
</div>
<div id="Ki" class="item">
<div id="Kj" class="right floated content">
<button type="button" class="mini ui icon button" id="Kk"><i id="Kl" class="trash icon"></i></button>
</div>
<div id="Km" class="content">
Two
</div>
</div>
</div>
<div id="Kn" class="ui action input">
<input type="text" id="Ko" placeholder="Add Item"><button type="button" class="ui button" id="Kp">Add</button>
</div></span></span>
</div>
</div>
</div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment