summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am11
-rw-r--r--src/http.h2
-rw-r--r--src/ws/favicon.icobin0 -> 16958 bytes
-rw-r--r--src/ws/handler.js101
-rw-r--r--src/ws/munia.css58
-rw-r--r--src/ws/munia.html31
-rw-r--r--src/ws/node.js137
-rw-r--r--src/ws/proto.js211
-rw-r--r--src/ws/view.js151
9 files changed, 696 insertions, 6 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index d820912..42df50c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,11 +1,11 @@
-SUBDIRS =
+SUBDIRS = ws
bin_PROGRAMS = muniad muniacli
muniad_LDADD = $(LIBWEBSOCKETS_LIBS) $(EXPAT_LIBS)
muniad_CXXFLAGS = -std=c++17 $(LIBWEBSOCKETS_CFLAGS) $(EXPAT_CFLAGS) \
- -I../hugin
+ -I$(top_srcdir)/hugin -DWSDATADIR=\"$(datadir)/ws\"
muniad_SOURCES = \
muniad.cc \
@@ -20,11 +20,11 @@ muniad_SOURCES = \
nodetree.cc \
xml_encode_decode.cc \
xmlparser.cc \
- ../hugin/hugin.c
+ $(top_srcdir)/hugin/hugin.c
muniacli_LDADD = $(LIBWEBSOCKETS_LIBS)
-muniacli_CXXFLAGS = $(LIBWEBSOCKETS_CFLAGS) -I../hugin
+muniacli_CXXFLAGS = $(LIBWEBSOCKETS_CFLAGS) -I$(top_srcdir)/hugin
muniacli_SOURCES = \
muniacli.cc
@@ -42,4 +42,5 @@ EXTRA_DIST = \
nodetree.h \
xml_encode_decode.h \
xmlparser.h \
- ../hugin/hugin.h
+ $(top_srcdir)/hugin/hugin.h \
+ $(top_srcdir)/hugin/hugin.hpp
diff --git a/src/http.h b/src/http.h
index f3ca3a3..ffd8a67 100644
--- a/src/http.h
+++ b/src/http.h
@@ -31,7 +31,7 @@
#include <libwebsockets.h>
-#define LOCAL_RESOURCE_PATH "."
+#define LOCAL_RESOURCE_PATH WSDATADIR
// this protocol server (always the first one) just knows how to do HTTP
int callback_http(struct lws *wsi,
diff --git a/src/ws/favicon.ico b/src/ws/favicon.ico
new file mode 100644
index 0000000..7a00f82
--- /dev/null
+++ b/src/ws/favicon.ico
Binary files differ
diff --git a/src/ws/handler.js b/src/ws/handler.js
new file mode 100644
index 0000000..906a03b
--- /dev/null
+++ b/src/ws/handler.js
@@ -0,0 +1,101 @@
+/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+
+
+document.addEventListener("connectEvent", connectEventHandler, false);
+function connectEventHandler(e)
+{
+ document.getElementById("wsnode_status").style.backgroundColor = "#40ff40";
+ document.getElementById("wsnode_status").textContent = "NodeProto websocket connection opened ";
+
+ //login("foobar", "hundemad");
+ //subscribe(0);
+}
+
+document.addEventListener("disconnectEvent", disconnectEventHandler, false);
+function disconnectEventHandler(e)
+{
+ document.getElementById("wsnode_status").style.backgroundColor = "#ff4040";
+ document.getElementById("wsnode_status").textContent = "NodeProto websocket connection CLOSED ";
+}
+
+document.addEventListener("removeEvent", removeEventHandler, false);
+function removeEventHandler(e)
+{
+ var subscribeid = e.detail.subscribeid;
+ var id = e.detail.id;
+
+ var node = findNode(id, subscribeid);
+ if(node.parent) node.parent.removeChild(node);
+}
+
+document.addEventListener("moveEvent", moveEventHandler, false);
+function moveEventHandler(e)
+{
+ var subscribeid = e.detail.subscribeid;
+ var id = e.detail.id;
+ var parentid = e.detail.parentid;
+
+ var node = findNode(id, subscribeid);
+ var new_parent = findNode(parentid, subscribeid);
+ if(node != null && new_parent != null) new_parent.addChild(node);
+}
+
+document.addEventListener("createEvent", createEventHandler, false);
+function createEventHandler(e)
+{
+ var subscribeid = e.detail.subscribeid;
+ var id = e.detail.id;
+ var parentid = e.detail.parentid;
+
+ var node = new Node(id, subscribeid);
+ node.create();
+
+ if(parentid == -1) {
+ nodes.push(node);
+ var board = getBoard(subscribeid);
+ board.appendChild(node.element);
+ return;
+ }
+
+ var parent = findNode(parentid, subscribeid);
+ if(parent != null) {
+ parent.addChild(node);
+ }
+
+}
+
+document.addEventListener("updateEvent", updateEventHandler, false);
+function updateEventHandler(e)
+{
+ var subscribeid = e.detail.subscribeid;
+ var id = e.detail.id;
+ var name = e.detail.name;
+ var value = e.detail.value;
+
+ var node = findNode(id, subscribeid);
+ if(node == null) return;
+
+ node.setAttribute(name, value);
+}
+
+///////
+//////
+/////
+////
+///
+//
+
+document.addEventListener("messageEvent", messageEventHandler, false);
+function messageEventHandler(e) {
+ LogEvent(e.detail.time.toString()+": "+e.detail.message
+ );
+}
+
+// log event in console
+function LogEvent(msg) {
+ var log = document.getElementById("log");
+ log.textContent += msg + "\n";
+ var ot = log.scrollHeight - log.clientHeight;
+ if (ot > 0) log.scrollTop = ot;
+}
diff --git a/src/ws/munia.css b/src/ws/munia.css
new file mode 100644
index 0000000..f94f4b7
--- /dev/null
+++ b/src/ws/munia.css
@@ -0,0 +1,58 @@
+/* Prevent the text contents of draggable elements from being selectable. */
+[draggable] {
+ -moz-user-select: none;
+ -khtml-user-select: none;
+ -webkit-user-select: none;
+ user-select: none;
+}
+
+body {
+ cursor: default;
+}
+
+.node {
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -o-user-select: none;
+ user-select: none;
+ cursor: move;
+ background-color: #888;
+ border-style: solid;
+ border-width: medium;
+/* border-radius: 15px;*/
+ padding: 4px;
+ margin: 6px;
+ max-width: 300px;
+}
+
+.board {
+ width: *;
+ min-height: 100px;
+ padding: 2px;
+ margin: 2px;
+
+ background: -moz-linear-gradient(left center, rgb(0,0,0), rgb(79,79,79), rgb(21,21,21));
+ background: -webkit-gradient(linear, left top, right top,
+ color-stop(0, rgb(0,0,0)),
+ color-stop(0.50, rgb(79,79,79)),
+ color-stop(1, rgb(21,21,21)));
+ background: -webkit-linear-gradient(left center, rgb(0,0,0), rgb(79,79,79), rgb(21,21,21));
+ background: -ms-linear-gradient(left center, rgb(0,0,0), rgb(79,79,79), rgb(21,21,21));
+}
+
+
+.log
+{
+ height: 20em;
+ font-family: monospace;
+ font-size: 1em;
+ padding: 2px 5px;
+ color: #0f0;
+ background-color: #111;
+ border: 1px solid #030;
+ border-radius: 4px;
+ overflow: auto;
+}
diff --git a/src/ws/munia.html b/src/ws/munia.html
new file mode 100644
index 0000000..669cda7
--- /dev/null
+++ b/src/ws/munia.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html lang="en">
+<head>
+ <meta http-equiv="Pragma" content="no-cache"/>
+ <meta http-equiv="Expires" content="-1"/>
+ <title>Munia</title>
+ <link rel="stylesheet" type="text/css" href="munia.css" media="screen"/>
+</head>
+<body id="body">
+<div id="wsnode_status">NodeProto not initialized</div>
+<div id="input_div">
+ NodeProto: <input type="text" id="input_node_data"
+ onkeyup="node_submit_KeyUpHandler(this, event)"
+ value=""/>
+ <input type="button" value="submit" onclick="node_submit()"/><br/>
+</div>
+
+<div id="boards" class="boards"></div>
+
+<pre class="log" id="log">Event information log
+=====================
+</pre>
+
+<script type="text/javascript" charset="utf-8" src="proto.js"></script>
+<script type="text/javascript" charset="utf-8" src="node.js"></script>
+<script type="text/javascript" charset="utf-8" src="view.js"></script>
+<script type="text/javascript" charset="utf-8" src="handler.js"></script>
+
+</body>
+</html>
diff --git a/src/ws/node.js b/src/ws/node.js
new file mode 100644
index 0000000..3cb325c
--- /dev/null
+++ b/src/ws/node.js
@@ -0,0 +1,137 @@
+/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+
+function createId(boardid, nodeid)
+{
+ return "b" + boardid + "_t" + nodeid;
+}
+
+function idFromStr(str)
+{
+ return str.substring(str.search('t') + 1, str.length);
+}
+
+var nodes = new Array();
+
+function findNode(id, subscribeid)
+{
+ for(var i = 0; i < nodes.length; i++) {
+ var node = nodes[i];
+ var child = node.findNode(id, subscribeid);
+ if(child != null) return child;
+ }
+
+ return null;
+}
+
+function Node(id, subscribeid)
+{
+ this.id = id;
+ this.subscribeid = subscribeid;
+ this.children = new Array();
+ this.attributes = {};
+ this.parent = null;
+
+ // Elements:
+ this.element = document.createElement("div");
+ this.div_id = document.createElement("span");
+ this.div_title = document.createElement("span");
+}
+
+Node.prototype.dump = function()
+{
+ alert(this.id);
+}
+
+Node.prototype.findNode = function(id, subscribeid)
+{
+ if(this.subscribeid != subscribeid) return null;
+
+ if(this.id == id) return this;
+
+ for(var i = 0; i < this.children.length; i++) {
+ var node = this.children[i];
+ var child = node.findNode(id, subscribeid);
+ if(child != null) return child;
+ }
+
+ return null;
+}
+
+Node.prototype.addChild = function(node)
+{
+ if(node.parent != null) node.parent.removeChild(node);
+ this.children.push(node);
+ node.parent = this;
+ this.element.appendChild(node.element);
+}
+
+Node.prototype.removeChild = function(node)
+{
+ this.children = this.children.filter(
+ function(e) {
+ return e.id != node.id;
+ });
+ node.parent = null;
+ this.element.removeChild(node.element);
+}
+
+Node.prototype.create = function()
+{
+ var node = this.element;
+
+ node.name = "node";
+ node.setAttribute("class", "node");
+ node.setAttribute("ondblclick", "editTitle(this, event)");
+ //node.setAttribute("onclick", "showHideChildren(this, event)");
+ node.setAttribute("ondrop", "drop(this, event)");
+ node.setAttribute("ondragover", "return false");
+ node.setAttribute("draggable", true);
+ node.setAttribute("ondragstart", "drag(this, event)");
+ node.setAttribute("title", this.id);
+
+ // This is a hack to make it possible to identify the nodeid and
+ // oberveid from the node id alone.
+ node.id = createId(this.subscribeid, this.id);
+
+/*
+ var subscribe_button = document.createElement("div");
+ subscribe_button.name = "subscribe_button";
+ subscribe_button.setAttribute("onclick", "subscribeMe(this, event)");
+ subscribe_button.setAttribute("title", this.id);
+ subscribe_button.setAttribute("style", "float: left; display: inline-box; width:14px; height: 14px; border: solid green 2px; cursor: pointer;");
+ var txt_plus = document.createTextNode("+");
+ subscribe_button.appendChild(txt_plus);
+ node.appendChild(subscribe_button);
+
+ var unsubscribe_button = document.createElement("div");
+ unsubscribe_button.name = "unsubscribe_button";
+ unsubscribe_button.setAttribute("onclick", "unsubscribeMe(this, event)");
+ unsubscribe_button.setAttribute("title", this.id);
+ unsubscribe_button.setAttribute("style", "float: left; display: inline-box; width:14px; height: 14px; border: solid red 2px; cursor: pointer;");
+ var txt_minus = document.createTextNode("-");
+ unsubscribe_button.appendChild(txt_minus);
+ node.appendChild(unsubscribe_button);
+*/
+
+ this.element.appendChild(this.div_id);
+ var id_txt = document.createTextNode(this.id);
+ this.div_id.appendChild(id_txt);
+
+ this.element.appendChild(this.div_title);
+
+ this.setAttribute("title", "(missing title)");
+}
+
+Node.prototype.setAttribute = function(name, value)
+{
+ this.attributes[name] = value;
+
+ if(name == "title") {
+ if(this.div_title.firstChild != null) {
+ this.div_title.removeChild(this.div_title.firstChild);
+ }
+ var title_txt = document.createTextNode(value);
+ this.div_title.appendChild(title_txt);
+ }
+}
diff --git a/src/ws/proto.js b/src/ws/proto.js
new file mode 100644
index 0000000..5a71157
--- /dev/null
+++ b/src/ws/proto.js
@@ -0,0 +1,211 @@
+/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+
+function get_appropriate_ws_url()
+{
+ // From: https://gist.github.com/2428561
+ var parser = document.createElement('a');
+ parser.href = document.URL;
+
+ // We open the websocket encrypted if this page came on an
+ // https:// url itself, otherwise unencrypted
+ if(parser.protocol == "http:") parser.protocol = "ws:";
+ if(parser.protocol == "https:") parser.protocol = "wss:";
+
+ return parser.href;
+}
+
+var socket_node = new WebSocket(get_appropriate_ws_url(), "lws-node-protocol");
+
+try {
+ socket_node.onopen = function() {
+ var connectEvent = new CustomEvent("connectEvent", {
+ detail: {
+ time: new Date(),
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ document.dispatchEvent(connectEvent);
+ }
+
+ socket_node.onmessage = function got_packet(msg) {
+ var messageEvent = new CustomEvent("messageEvent", {
+ detail: {
+ message: "recv [" + msg.data + "]",
+ time: new Date(),
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ document.dispatchEvent(messageEvent);
+
+ var msgs = new Array();
+ var idx = 0;
+ msgs[idx] = '';
+ var c = 0;
+ var instring = false;
+ for(c = 0; c < msg.data.length; c++) {
+ if(msg.data[c] == '"' && c > 0 && msg.data[c - 1] != '\\') instring = !instring;
+ if(msg.data[c] == ';' && instring == false) {
+ idx++;
+ msgs[idx] = '';
+ }
+ if(msg.data[c] != ';' || instring == true) msgs[idx] += msg.data[c];
+ }
+
+ f = 0;
+ while (f < msgs.length - 1) {
+ var msg = new Array();
+ instring = false;
+ idx = 0;
+
+ // Strip padding and trailing whitespace.
+ var msgstr = msgs[f].replace(/^\s+||\s+$/g,'');
+
+ if(msgstr == ';') {
+ f++;
+ continue;
+ }
+
+ msg[idx] = '';
+ for(c = 0; c < msgstr.length; c++) {
+ if(msgstr[c] == '"' && c > 0 && msgstr[c - 1] != '\\') {
+ instring = !instring;
+ continue;
+ }
+ if(msgstr[c] == ' ' && instring == false) {
+ msg[idx] = msg[idx].replace("\\\\","\\").replace("\\\"","\"");
+ idx++;
+ msg[idx] = '';
+ }
+ if(msgstr[c] != ' ' || instring == true) msg[idx] += msgstr[c];
+ }
+
+ var subscribeid = msg[0];
+ var cmd = msg[1];
+ var id = msg[2];
+
+ if(cmd == "remove") {
+ var removeEvent = new CustomEvent("removeEvent", {
+ detail: {
+ subscribeid: subscribeid,
+ id: id,
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ document.dispatchEvent(removeEvent);
+ }
+ else if(cmd == "move") {
+ var moveEvent = new CustomEvent("moveEvent", {
+ detail: {
+ subscribeid: subscribeid,
+ id: id,
+ parentid: msg[3],
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ document.dispatchEvent(moveEvent);
+ }
+ else if(cmd == "create") {
+ var createEvent = new CustomEvent("createEvent", {
+ detail: {
+ subscribeid: subscribeid,
+ id: id,
+ parentid: msg[3],
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ document.dispatchEvent(createEvent);
+ }
+ else if(cmd == "update") {
+ var updateEvent = new CustomEvent("updateEvent", {
+ detail: {
+ subscribeid: subscribeid,
+ id: id,
+ name: msg[3],
+ value: msg[4],
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ document.dispatchEvent(updateEvent);
+ }
+ f++;
+ }
+ }
+
+ socket_node.onclose = function(){
+ var disconnectEvent = new CustomEvent("disconnectEvent", {
+ detail: {
+ time: new Date(),
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ document.dispatchEvent(disconnectEvent);
+ }
+} catch(exception) {
+ alert('<p>Error' + exception + '</p>');
+}
+
+function transmit(msg)
+{
+ //LogEvent(msg);
+ var messageEvent = new CustomEvent("messageEvent", {
+ detail: {
+ message: "send [" + msg + "]",
+ time: new Date(),
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ document.dispatchEvent(messageEvent);
+
+ socket_node.send(msg);
+}
+
+function login(user, password)
+{
+ transmit("login "+user+" "+password);
+}
+
+function logout()
+{
+ transmit("logout");
+}
+
+function subscribe(id)
+{
+ transmit("subscribe "+id);
+}
+
+function unsubscribe(id)
+{
+ transmit("unsubscribe "+id);
+}
+
+function create(id, parent)
+{
+ transmit("create "+id+" "+parent);
+}
+
+function remove(id)
+{
+ transmit("remove "+id);
+}
+
+function update(id, name, value)
+{
+ transmit("update "+id+" "+name+" "+value);
+}
+
+function move(id, parent)
+{
+ transmit("move "+id+" "+parent);
+}
+
+
diff --git a/src/ws/view.js b/src/ws/view.js
new file mode 100644
index 0000000..5f98587
--- /dev/null
+++ b/src/ws/view.js
@@ -0,0 +1,151 @@
+/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+
+/*
+function createNode()
+{
+ var node = new Node();
+ node.id = 42;
+ node.dump = function() {
+ alert(this.id);
+ }
+}
+*/
+
+function getNode(subscribeid, id)
+{
+
+}
+
+function updateNode(subscribeid, id, name, value)
+{
+}
+
+function getBoard(subscribeid)
+{
+ var board = document.getElementById("board_" + subscribeid);
+ if(!board) {
+ board = document.createElement("div");
+ board.name = "board";
+ board.setAttribute("class", "board");
+ board.id = "board_" + subscribeid;
+ boards.appendChild(board);
+ }
+
+ return board;
+}
+
+//////////////////////////////////////////////////////
+//////////////////////////////////////////////////////
+
+function clear() {
+ document.getElementById("input_data").value = "";
+}
+
+function deleteNode(id) {
+ remove(id);
+}
+
+function drag(target, e) {
+ e.dataTransfer.setData('Text', target.id);
+ e.stopPropagation(); // <--- this fixes the drag target problem
+}
+
+function drop(target, e) {
+ e.preventDefault();
+ e.stopPropagation();
+
+ var id = e.dataTransfer.getData('Text');
+ var node = document.getElementById(id);
+ move(idFromStr(id), idFromStr(target.id));
+}
+
+function subscribeMe(target, e)
+{
+ e.stopPropagation();
+ subscribe(target.title);
+}
+
+function unsubscribeMe(target, e)
+{
+ e.stopPropagation();
+ unsubscribe(target.title);
+}
+
+function showHideChildren(target, e)
+{
+ e.stopPropagation();
+ updateid = idFromStr(target.id);
+ if(target.style.backgroundColor != "red") {
+ target.style.backgroundColor = "red";
+ for(var i = 1; i < target.childNodes.length; i++) {
+ target.childNodes[i].style.display = "none";
+ }
+ } else {
+ target.style.backgroundColor = "grey";
+ for(var i = 1; i < target.childNodes.length; i++) {
+ target.childNodes[i].style.display = "block";
+ }
+ }
+}
+
+function node_submit() {
+ var data = document.getElementById("input_node_data");
+ transmit(data.value);
+ data.value = "";
+}
+
+function node_submit_KeyUpHandler(target, e)
+{
+ if(e.which == 13) { // enter
+ node_submit();
+ }
+}
+
+//
+// Butt ugly.. but hey! it works...
+//
+var updateid;
+var divtxt;
+var oldtxt;
+var oldtitle;
+function onKeyUpHandler(target, e)
+{
+ if(e.which == 13) { // enter
+ divtxt.removeChild(target);
+ oldtxt.nodeValue = 'updating...';
+ update(updateid, "title", target.value);
+ }
+ if(e.which == 27) { // escape
+ divtxt.removeChild(target);
+ oldtxt.nodeValue = oldtitle;
+ }
+}
+
+function onLostFocusHandler(target, e)
+{
+ if(target.value == oldtitle) {
+ divtxt.removeChild(target);
+ oldtxt.nodeValue = oldtitle;
+ }
+}
+
+function editTitle(target, e)
+{
+ e.stopPropagation();
+ updateid = idFromStr(target.id);
+ if(updateid < 10) return;
+ var inp = document.createElement("input");
+ var txtdiv = document.getElementById(target.id + "_txt");
+ divtxt = txtdiv;
+ oldtxt = txtdiv.firstChild;
+ oldtitle = oldtxt.nodeValue;
+ oldtxt.nodeValue = "";
+ inp.setAttribute("onkeyup", "onKeyUpHandler(this, event)");
+ inp.setAttribute("onblur", "onLostFocusHandler(this, event)");
+ inp.setAttribute("style", "border: inherit; padding: inherit; margin: inherit; background: inherit;");
+ inp.value = oldtitle;
+ lineedit = inp;
+ txtdiv.appendChild(inp);
+ inp.focus();
+}