aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomsmeding <tom.smeding@gmail.com>2017-03-25 23:02:21 +0100
committertomsmeding <tom.smeding@gmail.com>2017-03-25 23:02:21 +0100
commit11f606c269e3b7cca1848bc227e8e38321fb6e3e (patch)
treec1dded2e8a1f244f8b9a17b0aa7778b2e0afe353
parent7157893eb0d7cce75a423b42e183ef88bc2130eb (diff)
Start work on web client
-rw-r--r--webclient/client.html326
1 files changed, 326 insertions, 0 deletions
diff --git a/webclient/client.html b/webclient/client.html
new file mode 100644
index 0000000..3472cb8
--- /dev/null
+++ b/webclient/client.html
@@ -0,0 +1,326 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>tomsg webclient</title>
+<script>
+var sock=null,username=null;
+var roomlist=[":console"];
+var currentroom=":console";
+var roomlogs={":console":[]};
+
+(function(){
+ var id=1;
+ function uniqid(){
+ return id++;
+ }
+})();
+
+var net_callbacks={};
+
+function net_send(msg,cb){
+ var id=uniqid()+"";
+ sock.send(id+" "+msg);
+ net_callbacks[id]=cb;
+}
+
+function reconnect(){
+ if(sock)sock.close();
+
+ net_callbacks={};
+
+ var host=location.hostname||"localhost";
+ sock=new WebSocket("ws://"+host+":29546");
+ updateStatus();
+ updateRoomList();
+ sock.addEventListener("message",function(msg){
+ var spl=msg.split(" ",2);
+ var id=spl[0],type=spl[1];
+ var rest=msg.slice(id.length+type.length+2);
+ if(id=="_push"){
+ if(type=="message"){
+ spl=rest.split(" ",2);
+ var r=spl[0],u=spl[1];
+ addRoomEntry(r,"message",[u,rest.slice(r.length+u.length+2)]);
+ } else {
+ alert("Unknown push message type '"+type+"'!");
+ }
+ } else if(net_callbacks[id]){
+ var fn=net_callbacks[id];
+ var obj;
+ if(type=="ok")fn(true);
+ else if(type=="error")fn(null,rest);
+ else if(type=="name")fn(rest);
+ else if(type=="list")fn(rest.split(" ").slice(1));
+ else alert("Unknown server response message type '"+type+"'!");
+ } else {
+ alert("No callback for server message id '"+id+"'!");
+ }
+ });
+ sock.addEventListener("open",function(){
+ updateStatus();
+ });
+ sock.addEventListener("close",function(ev){
+ updateStatus();
+ if(ev.code!=1000){
+ setTimeout(function(){
+ reconnect();
+ },1000+Math.random()*1000);
+ }
+ });
+}
+
+function updateStatus(){
+ var str=null;
+ if(!sock||sock.readyState>=2){
+ str="not connected";
+ } else if(sock.readyState==0){
+ str="connecting...";
+ } else if(username){
+ str="u: "+username;
+ } else {
+ str="connected";
+ }
+ var div=document.getElementById("status");
+ if(!div.firstChild)div.appendChild(document.createTextNode(""));
+ div.firstChild.nodeValue=str;
+}
+
+function updateRoomList(){
+ var rldiv=document.getElementById("roomlist");
+ var ch=rldiv.children,len=ch.length;
+ var i;
+ for(i=len-1;i>=0;i--)rldiv.removeChild(ch[i]);
+
+ var div;
+ for(i=0;i<roomlist.length;i++){
+ div=document.createElement("div");
+ div.classList.add("roomlistitem");
+ if(roomlist[i]==currentroom)div.classList.add("selected");
+ div.addEventListener("click",function(roomid){
+ currentroom=roomid;
+ drawRoom(currentroom);
+ }.bind(this,roomlist[i]));
+ div.appendChild(document.createTextNode(roomlist[i]));
+ rldiv.appendChild(div);
+ }
+}
+
+function drawRoom(roomid){
+ var tbody=document.getElementById("roomlog");
+ var ch=tbody.children,len=ch.length;
+ var i;
+ for(i=len-1;i>=0;i--)tbody.removeChild(ch[i]);
+
+ var roomtitle=document.getElementById("roomtitle");
+ if(!roomtitle.firstChild)roomtitle.appendChild(document.createTextNode(roomid));
+ else roomtitle.firstChild.nodeValue=roomid;
+
+ var tr,td;
+ var items=roomlogs[roomid];
+ if(!items){
+ alert("drawRoom on nonexistent roomid '"+roomid+"'!");
+ return;
+ }
+ for(i=Math.max(0,items.length-20);i<items.length;i++){
+ drawRoomEntry(items[i][0],items[i][1]);
+ }
+}
+
+function drawRoomEntry(type,args){
+ var tbody=document.getElementById("roomlog");
+ var tr=document.createElement("tr");
+ var td;
+ switch(type){
+ case "message":
+ td=document.createElement("td");
+ td.appendChild(document.createTextNode(args[0]));
+ tr.appendChild(td);
+ td=document.createElement("td");
+ td.classList.add("message");
+ td.appendChild(document.createTextNode(args[1]));
+ tr.appendChild(td);
+ tbody.appendChild(tr);
+ break;
+
+ default:
+ alert("drawRoomEntry on unknown type '"+type+"'!");
+ break;
+ }
+}
+
+function addRoomEntry(roomid,type,args){
+ if(!roomlogs[roomid]){
+ alert("addRoomEntry on nonexistent roomid '"+roomid+"'!");
+ return;
+ }
+ roomlogs[roomid].push([type,args]);
+ if(roomid==currentroom){
+ drawRoomEntry(type,args);
+ }
+}
+
+function doSend(){
+ var inputelem=document.getElementById("roominput");
+ var text=inputelem.value;
+ inputelem.value="";
+ addRoomEntry(currentroom,"message",["-",text]);
+}
+
+function doKeypress(ev){
+ if(ev.keyCode==10||ev.keyCode==13)doSend();
+}
+
+window.addEventListener("load",function(){
+ reconnect();
+ drawRoom(currentroom);
+});
+</script>
+<style>
+html, body{
+ margin:0;
+ width:100%;
+ height:100%;
+}
+body{
+ background-color:#04040c;
+ color:#eee;
+ font-family:mononoki,meslo,monaco,monospace;
+ font-size:11pt;
+}
+table{
+ border-collapse:collapse;
+}
+#window{
+ width:100%;
+ height:100%;
+}
+
+/* SIDEBAR */
+#sidebar{
+ width:150px;
+ border-right:1px #668 solid;
+ vertical-align:top;
+}
+
+#branding{
+ background-color:#223;
+ padding:4px;
+ height:22px;
+ text-align:center;
+ font-size:13pt;
+}
+#status{
+ padding:2px;
+ margin:8px 0px 10px 0px;
+}
+.roomlistitem{
+ margin:1px 0px;
+ padding:3px 2px;
+ background-color:#223;
+ cursor:pointer;
+}
+.roomlistitem:hover{
+ background-color:#282833;
+}
+.roomlistitem.selected{
+ background-color:#335;
+ font-weight:bold;
+}
+.roomlistitem:hover{
+ background-color:#445;
+}
+
+/* ROOM VIEW */
+#room{
+ width:100%;
+ height:100%;
+}
+#room_td{
+ padding:0;
+}
+#roomtitle{
+ height:22px;
+ padding:4px;
+ background-color:#335;
+ font-weight:bold;
+}
+
+#roomlog_td{
+ vertical-align:top;
+}
+#roomlog_table{
+ width:100%;
+ /*height:100%;*/
+}
+#roomlog > tr > td:first-child{
+ width:150px;
+}
+
+#roombar_tr{
+ height:30px;
+ border-top:1px #668 solid;
+}
+#roominput_td{
+ position:relative;
+ vertical-align:top;
+ padding:0px 1px 0px 10px;
+}
+#roominput{
+ position:absolute;
+ background-color:rgba(0,0,0,0);
+ padding:0;
+ border-width:0;
+ width:calc(100% - 11px);
+ height:100%;
+ color:white;
+ font-family:inherit;
+ font-size:inherit;
+}
+#roomsend_td{
+ position:relative;
+ width:40px;
+ vertical-align:top;
+ padding:0;
+}
+#roomsend{
+ position:absolute;
+ width:100%;
+ height:100%;
+ background-color:#335;
+ border-width:0px;
+ color:#ccc;
+ font-family:inherit;
+ font-size:inherit;
+ cursor:pointer;
+}
+#roomsend:hover{
+ background-color:#445;
+}
+</style>
+<script src="https://use.fontawesome.com/ccf28a5626.js"></script>
+</head>
+<body>
+<table id="window"><tbody><tr>
+ <td id="sidebar">
+ <div id="branding">TOMSG</div>
+ <div id="status">&nbsp;</div>
+ <div id="roomlist"></div>
+ </td>
+ <td id="room_td">
+ <table id="room"><tbody>
+ <tr id="roomtitle_tr"><td id="roomtitle" colspan="2"></td></tr>
+ <tr id="roomlog_tr"><td id="roomlog_td" colspan="2">
+ <table id="roomlog_table"><tbody id="roomlog"></tbody></table>
+ </td></tr>
+ <tr id="roombar_tr">
+ <td id="roominput_td"><input type="text" id="roominput" onkeypress="doKeypress(event)"></td>
+ <td id="roomsend_td">
+ <button id="roomsend" onclick="doSend()"><i class="fa fa-send"></i></button>
+ </td>
+ </tr>
+ </tbody></table>
+ </td>
+</tr></tbody></table>
+</body>
+</html>