Ver Fonte

[Refs #20] automaticaly scroll to last message when receiving data
[Refs #9] Make ui more confortable

B Thibault há 8 anos atrás
pai
commit
87aa735527
4 ficheiros alterados com 100 adições e 22 exclusões
  1. 8 0
      cli/resources.js
  2. 62 8
      cli/ui.js
  3. 13 11
      srv/public/slack.min.js
  4. 17 3
      srv/public/style.css

+ 8 - 0
cli/resources.js

@@ -16,6 +16,9 @@ var R = {
         ,noRoomSelected: "no-room-selected"
         ,chatList: {
             entry: "slack-context-room"
+            ,typeChannel: "slack-channel"
+            ,typeGroup: "slack-group"
+            ,typeDirect: "slack-ims"
         }
         ,msg: {
             item: "slackmsg-item"
@@ -24,6 +27,11 @@ var R = {
             ,authorname: "slackmsg-author-name"
             ,authorAvatar: "slackmsg-author-img"
             ,msg: "slackmsg-msg"
+
+            ,hover: {
+                container: "slackmsg-hover"
+                ,reply: "slackmsg-hover-reply"
+            }
         }
     }
 };

+ 62 - 8
cli/ui.js

@@ -6,7 +6,12 @@
 function createChanListItem(chan) {
     var dom = document.createElement("li");
     dom.id = chan.id;
-    dom.className = R.klass.chatList.entry;
+    if (chan.id[0] === 'D')
+        dom.className = R.klass.chatList.entry + " " +R.klass.chatList.typeDirect;
+    else if (chan.id[0] === 'G')
+        dom.className = R.klass.chatList.entry + " " +R.klass.chatList.typeGroup;
+    else if (chan.id[0] === 'C')
+        dom.className = R.klass.chatList.entry + " " +R.klass.chatList.typeChannel;
     dom.textContent = chan.name;
     return dom;
 }
@@ -69,44 +74,55 @@ function onRoomSelected() {
     onRoomUpdated();
 }
 
-function createMessageDom(msg) {
+function createMessageDom(channelId, msg) {
     var dom = document.createElement("div")
         ,ts = document.createElement("div")
         ,text = document.createElement("div")
         ,author = document.createElement("div")
         ,authorImg = document.createElement("img")
-        ,authorName = document.createElement("span");
+        ,authorName = document.createElement("span")
+        ,hover = document.createElement("ul")
+        ,hoverReply = document.createElement("li")
         ,sender = msg.raw["user"] ?
             SLACK.context.users[msg.raw["user"]] :
             SLACK.context.bots[msg.raw["bot_id"]];
 
+    dom.id = channelId +"_" +msg.ts;
     dom.className = R.klass.msg.item;
     ts.className = R.klass.msg.ts;
     text.className = R.klass.msg.msg;
     author.className = R.klass.msg.author;
     authorImg.className = R.klass.msg.authorAvatar;
     authorName.className = R.klass.msg.authorname;
+    hover.className = R.klass.msg.hover.container;
+    hoverReply.className = R.klass.msg.hover.reply;
     ts.textContent = (new Date(msg.ts * 1000)).toLocaleTimeString();
     text.textContent = msg.raw["text"];
     authorName.textContent = sender ? sender.name : (msg.raw["username"] || "?");
     authorImg.src = sender ? sender.icons.image_48 : "";
     author.appendChild(authorImg);
     author.appendChild(authorName);
+    hover.appendChild(hoverReply);
     dom.appendChild(author);
     dom.appendChild(text);
     dom.appendChild(ts);
+    dom.appendChild(hover);
     return dom;
 }
 
 function onRoomUpdated() {
-    var chatFrag = document.createDocumentFragment();
+    var chatFrag = document.createDocumentFragment()
+        ,currentRoomId = SELECTED_ROOM.id;
 
     document.getElementById(R.id.currentRoom.content).textContent = "";
-    if (SLACK.history[SELECTED_ROOM.id])
-        SLACK.history[SELECTED_ROOM.id].messages.forEach(function(msg) {
-            chatFrag.appendChild(createMessageDom(msg));
+    if (SLACK.history[currentRoomId])
+        SLACK.history[currentRoomId].messages.forEach(function(msg) {
+            chatFrag.appendChild(createMessageDom(currentRoomId, msg));
         });
-    document.getElementById(R.id.currentRoom.content).appendChild(chatFrag);
+    var content = document.getElementById(R.id.currentRoom.content);
+    content.appendChild(chatFrag);
+    //TODO scroll lock
+    console.log(content.scrollTop = content.scrollHeight -content.clientHeight);
 }
 
 function onChanClick(e) {
@@ -125,8 +141,46 @@ function onChanClick(e) {
     }
 }
 
+function replyTo(msg) {
+    console.log("Replying to ", msg);
+}
+
+function chatClickDelegate(e) {
+    var target = e.target
+        ,getMessageId = function(e, target) {
+            target = target || e.target;
+            while (target !== e.currentTarget && target) {
+                if (target.classList.contains(R.klass.msg.item)) {
+                    return target.id;
+                }
+                target = target.parentElement;
+            }
+        };
+    while (target !== e.currentTarget && target) {
+        if (target.classList.contains(R.klass.msg.hover.container)) {
+            return;
+        } else if (target.classList.contains(R.klass.msg.hover.reply)) {
+            var messageId = getMessageId(e, target);
+            if (messageId) {
+                messageId = parseFloat(messageId.split("_")[1]);
+                var history = SLACK.history[SELECTED_ROOM.id].messages;
+
+                for (var i =0, histLen =history.length; i < histLen && history[i].ts <= messageId; i++) {
+                    if (history[i].ts === messageId) {
+                        replyTo(history[i]);
+                        return;
+                    }
+                }
+            }
+            return;
+        }
+        target = target.parentElement;
+    }
+}
+
 document.addEventListener('DOMContentLoaded', function() {
     document.getElementById(R.id.chatList).addEventListener("click", onChanClick);
+    document.getElementById(R.id.currentRoom.content).addEventListener("click", chatClickDelegate);
     document.getElementById(R.id.message.form).addEventListener("submit", function(e) {
         e.preventDefault();
         var input =document.getElementById(R.id.message.input);

+ 13 - 11
srv/public/slack.min.js

@@ -1,11 +1,13 @@
-function g(a,b){this.id=a.id;this.name=a.name;this.b=parseFloat(a.last_read);this.a={};if(a.members)for(var e=0,c=a.members.length;e<c;e++){var f=h(b,a.members[e]);this.a[f.id]=f;f.f[this.id]=this}}function m(a,b){var e=[];this.id=b.id;this.a={};for(var c=0,f=b.members.length;c<f;c++){var d=h(a,b.members[c]);this.a[b.members[c]]=d;d.f[this.id]=this;e.push(d.name)}this.name=e.join(", ");this.b=parseFloat(b.last_read)}function p(a,b){this.id=b.id;this.c=a;this.b=parseFloat(b.last_read)}
-function q(a){this.id=a.id;this.name=a.name;this.status=a.status;this.b={w:a.profile.image_24,A:a.profile.image_32,i:a.profile.image_48,m:a.profile.image_72,u:a.profile.image_192,C:a.profile.image_512};this.f={};this.a=null}function r(a){this.id=a.id;this.name=a.name;this.b={B:a.icons.image_36,i:a.icons.image_48,m:a.icons.image_72};this.f={};this.a=null}function t(){this.f={};this.b={};this.h={};this.a={};this.c=null;this.g={}}function h(a,b){return a.a[b]||a.g[b]||null}
-"undefined"!==typeof module&&(module.l.o=t);function u(a){this.j=parseFloat(a.ts);this.raw=a}function v(a,b,e){this.id="string"===typeof a?a:a.id;this.a=[];this.b=b;e&&w(this,e)}function w(a,b){b.forEach(function(a){this.push(a)}.bind(a))}v.prototype.push=function(a){for(var b=parseFloat(a.ts),e=0,c=this.a.length;e<c;e++)if(this.a[e].j===b)return!1;for(this.a.push(new u(a));this.a.length>this.b;)this.a.shift()};"undefined"!==typeof module&&(module.l.s=v);function x(){var a=document.createDocumentFragment(),b=y.a.c?Object.keys(y.a.c.f):[];b.sort(function(a,b){return a[0]!==b[0]?a[0]-b[0]:(y.a.f[a]||y.a.b[a]).name.localeCompare((y.a.f[b]||y.a.b[b]).name)});b.forEach(function(b){b=y.a.f[b]||y.a.b[b];var c=document.createElement("li");c.id=b.id;c.className="slack-context-room";c.textContent=b.name;c&&a.appendChild(c)});b=y.a.a?Object.keys(y.a.a):[];b.sort(function(a,b){return y.a.a[a].name.localeCompare(y.a.a[b].name)});b.forEach(function(b){b=y.a.a[b].a;
-var c=document.createElement("li");c.id=b.id;c.className="slack-context-room";c.textContent=b.c.name;c&&a.appendChild(c)});document.getElementById("chanList").textContent="";document.getElementById("chanList").appendChild(a)}
-function z(a){var b=document.createElement("div"),e=document.createElement("div"),c=document.createElement("div"),f=document.createElement("div"),d=document.createElement("img"),k=document.createElement("span");b.className="slackmsg-item";e.className="slackmsg-ts";c.className="slackmsg-msg";f.className="slackmsg-author";d.className="slackmsg-author-img";k.className="slackmsg-author-name";e.textContent=(new Date(1E3*a.j)).toLocaleTimeString();c.textContent=a.raw.text;var l=a.raw.user?y.a.a[a.raw.user]:
-y.a.g[a.raw.bot_id];k.textContent=l?l.name:a.raw.username||"?";d.src=l?l.b.i:"";f.appendChild(d);f.appendChild(k);b.appendChild(f);b.appendChild(c);b.appendChild(e);return b}function A(){var a=document.createDocumentFragment();document.getElementById("chatWindow").textContent="";y.b[B.id]&&y.b[B.id].a.forEach(function(b){a.appendChild(z(b))});document.getElementById("chatWindow").appendChild(a)}
-function C(a){for(;a.target!==a.currentTarget&&a.target;){if(a.target.classList.contains("slack-context-room")){if((a=y.a.f[a.target.id]||y.a.h[a.target.id]||y.a.b[a.target.id])&&a!==B){B&&document.getElementById(B.id).classList.remove("selected");document.getElementById(a.id).classList.add("selected");document.body.classList.remove("no-room-selected");B=a;a=void 0;var b=B.name||(B.c?B.c.name:void 0);if(!b){b=[];for(a in B.a)b.push(B.a[a].name);b=b.join(", ")}document.getElementById("currentRoomTitle").textContent=
-b;A();B.b&&!y.b[B.id]&&(a=new XMLHttpRequest,a.open("GET","api/hist?room="+B.id,!0),a.send(null))}break}a.target=a.target.parentElement}}
-document.addEventListener("DOMContentLoaded",function(){document.getElementById("chatList").addEventListener("click",C);document.getElementById("msgForm").addEventListener("submit",function(a){a.preventDefault();a=document.getElementById("msgInput");if(B&&a.value){var b=new XMLHttpRequest;b.open("POST","api/msg?room="+B.id+"&text="+encodeURIComponent(a.value),!0);b.send(null);a.value=""}return!1});D()});var y;y=new function(){this.c=0;this.a=new t;this.b={}};var E=5,B=null;function F(a){var b=new XMLHttpRequest;b.timeout=6E4;b.onreadystatechange=function(){if(4===b.readyState)if(b.status){var e=null,c=2===Math.floor(b.status/100);if(c){E=5;e=b.response;try{e=JSON.parse(e)}catch(f){e=null}}else E+=Math.floor(E/2),E=Math.min(60,E);a(c,e)}else F(a),E=5};b.open("GET","api?v="+y.c,!0);b.send(null)}
-function G(a,b){if(a){if(b){var e=y;b.v&&(e.c=b.v);if(b["static"]){for(var c=e.a,f=b["static"],d=0,k=f.bots.length;d<k;d++)c.g[f.bots[d].id]=new r(f.bots[d]);d=0;for(k=f.users.length;d<k;d++)c.a[f.users[d].id]=new q(f.users[d]);d=0;for(k=f.ims.length;d<k;d++){var l=h(c,f.ims[d].user);l&&(l.a=new p(l,f.ims[d]),c.h[l.a.id]=l.a)}d=0;for(k=f.channels.length;d<k;d++)c.f[f.channels[d].id]=new g(f.channels[d],c);d=0;for(k=f.groups.length;d<k;d++)c.b[f.groups[d].id]=new m(c,f.groups[d]);c.c=h(c,f.self.id);
-x()}if(b.live){for(var n in b.live)(c=e.b[n])?w(c,b.live[n]):e.b[n]=new v(n,500,b.live[n]);B&&b.live[B.id]&&A()}}D()}else setTimeout(D,1E3*E)}function D(){F(G)};
+function g(b,a){this.id=b.id;this.name=b.name;this.b=parseFloat(b.last_read);this.a={};if(b.members)for(var c=0,e=b.members.length;c<e;c++){var f=h(a,b.members[c]);this.a[f.id]=f;f.f[this.id]=this}}function n(b,a){var c=[];this.id=a.id;this.a={};for(var e=0,f=a.members.length;e<f;e++){var d=h(b,a.members[e]);this.a[a.members[e]]=d;d.f[this.id]=this;c.push(d.name)}this.name=c.join(", ");this.b=parseFloat(a.last_read)}function p(b,a){this.id=a.id;this.c=b;this.b=parseFloat(a.last_read)}
+function r(b){this.id=b.id;this.name=b.name;this.status=b.status;this.b={w:b.profile.image_24,A:b.profile.image_32,j:b.profile.image_48,m:b.profile.image_72,u:b.profile.image_192,C:b.profile.image_512};this.f={};this.a=null}function t(b){this.id=b.id;this.name=b.name;this.b={B:b.icons.image_36,j:b.icons.image_48,m:b.icons.image_72};this.f={};this.a=null}function u(){this.f={};this.b={};this.i={};this.a={};this.c=null;this.h={}}function h(b,a){return b.a[a]||b.h[a]||null}
+"undefined"!==typeof module&&(module.l.o=u);function v(b){this.g=parseFloat(b.ts);this.raw=b}function x(b,a,c){this.id="string"===typeof b?b:b.id;this.a=[];this.b=a;c&&y(this,c)}function y(b,a){a.forEach(function(b){this.push(b)}.bind(b))}x.prototype.push=function(b){for(var a=parseFloat(b.ts),c=0,e=this.a.length;c<e;c++)if(this.a[c].g===a)return!1;for(this.a.push(new v(b));this.a.length>this.b;)this.a.shift()};"undefined"!==typeof module&&(module.l.s=x);function z(){var b=document.createDocumentFragment(),a=A.a.c?Object.keys(A.a.c.f):[];a.sort(function(b,a){return b[0]!==a[0]?b[0]-a[0]:(A.a.f[b]||A.a.b[b]).name.localeCompare((A.a.f[a]||A.a.b[a]).name)});a.forEach(function(a){a=A.a.f[a]||A.a.b[a];var c=document.createElement("li");c.id=a.id;"D"===a.id[0]?c.className="slack-context-room slack-ims":"G"===a.id[0]?c.className="slack-context-room slack-group":"C"===a.id[0]&&(c.className="slack-context-room slack-channel");c.textContent=a.name;c&&b.appendChild(c)});
+a=A.a.a?Object.keys(A.a.a):[];a.sort(function(a,b){return A.a.a[a].name.localeCompare(A.a.a[b].name)});a.forEach(function(a){a=A.a.a[a].a;var c=document.createElement("li");c.id=a.id;c.className="slack-context-room";c.textContent=a.c.name;c&&b.appendChild(c)});document.getElementById("chanList").textContent="";document.getElementById("chanList").appendChild(b)}
+function B(b,a){var c=document.createElement("div"),e=document.createElement("div"),f=document.createElement("div"),d=document.createElement("div"),k=document.createElement("img"),l=document.createElement("span"),m=document.createElement("ul"),w=document.createElement("li"),q=a.raw.user?A.a.a[a.raw.user]:A.a.h[a.raw.bot_id];c.id=b+"_"+a.g;c.className="slackmsg-item";e.className="slackmsg-ts";f.className="slackmsg-msg";d.className="slackmsg-author";k.className="slackmsg-author-img";l.className="slackmsg-author-name";
+m.className="slackmsg-hover";w.className="slackmsg-hover-reply";e.textContent=(new Date(1E3*a.g)).toLocaleTimeString();f.textContent=a.raw.text;l.textContent=q?q.name:a.raw.username||"?";k.src=q?q.b.j:"";d.appendChild(k);d.appendChild(l);m.appendChild(w);c.appendChild(d);c.appendChild(f);c.appendChild(e);c.appendChild(m);return c}
+function C(){var b=document.createDocumentFragment(),a=D.id;document.getElementById("chatWindow").textContent="";A.b[a]&&A.b[a].a.forEach(function(c){b.appendChild(B(a,c))});var c=document.getElementById("chatWindow");c.appendChild(b);console.log(c.scrollTop=c.scrollHeight-c.clientHeight)}
+function E(b){for(;b.target!==b.currentTarget&&b.target;){if(b.target.classList.contains("slack-context-room")){if((b=A.a.f[b.target.id]||A.a.i[b.target.id]||A.a.b[b.target.id])&&b!==D){D&&document.getElementById(D.id).classList.remove("selected");document.getElementById(b.id).classList.add("selected");document.body.classList.remove("no-room-selected");D=b;b=void 0;var a=D.name||(D.c?D.c.name:void 0);if(!a){a=[];for(b in D.a)a.push(D.a[b].name);a=a.join(", ")}document.getElementById("currentRoomTitle").textContent=
+a;C();D.b&&!A.b[D.id]&&(b=new XMLHttpRequest,b.open("GET","api/hist?room="+D.id,!0),b.send(null))}break}b.target=b.target.parentElement}}
+function F(b){for(var a=b.target;a!==b.currentTarget&&a&&!a.classList.contains("slackmsg-hover");){if(a.classList.contains("slackmsg-hover-reply")){a:{for(a=a||b.target;a!==b.currentTarget&&a;){if(a.classList.contains("slackmsg-item")){b=a.id;break a}a=a.parentElement}b=void 0}if(b){b=parseFloat(b.split("_")[1]);for(var a=A.b[D.id].a,c=0,e=a.length;c<e&&a[c].g<=b;c++)if(a[c].g===b){console.log("Replying to ",a[c]);break}}break}a=a.parentElement}}
+document.addEventListener("DOMContentLoaded",function(){document.getElementById("chatList").addEventListener("click",E);document.getElementById("chatWindow").addEventListener("click",F);document.getElementById("msgForm").addEventListener("submit",function(b){b.preventDefault();b=document.getElementById("msgInput");if(D&&b.value){var a=new XMLHttpRequest;a.open("POST","api/msg?room="+D.id+"&text="+encodeURIComponent(b.value),!0);a.send(null);b.value=""}return!1});G()});var A;A=new function(){this.c=0;this.a=new u;this.b={}};var H=5,D=null;function I(b){var a=new XMLHttpRequest;a.timeout=6E4;a.onreadystatechange=function(){if(4===a.readyState)if(a.status){var c=null,e=2===Math.floor(a.status/100);if(e){H=5;c=a.response;try{c=JSON.parse(c)}catch(f){c=null}}else H+=Math.floor(H/2),H=Math.min(60,H);b(e,c)}else I(b),H=5};a.open("GET","api?v="+A.c,!0);a.send(null)}
+function J(b,a){if(b){if(a){var c=A;a.v&&(c.c=a.v);if(a["static"]){for(var e=c.a,f=a["static"],d=0,k=f.bots.length;d<k;d++)e.h[f.bots[d].id]=new t(f.bots[d]);d=0;for(k=f.users.length;d<k;d++)e.a[f.users[d].id]=new r(f.users[d]);d=0;for(k=f.ims.length;d<k;d++){var l=h(e,f.ims[d].user);l&&(l.a=new p(l,f.ims[d]),e.i[l.a.id]=l.a)}d=0;for(k=f.channels.length;d<k;d++)e.f[f.channels[d].id]=new g(f.channels[d],e);d=0;for(k=f.groups.length;d<k;d++)e.b[f.groups[d].id]=new n(e,f.groups[d]);e.c=h(e,f.self.id);
+z()}if(a.live){for(var m in a.live)(e=c.b[m])?y(e,a.live[m]):c.b[m]=new x(m,500,a.live[m]);D&&a.live[D.id]&&C()}}G()}else setTimeout(G,1E3*H)}function G(){I(J)};

+ 17 - 3
srv/public/style.css

@@ -22,18 +22,32 @@ body {
     bottom: 0;
     left: 250px;
     right: 0;
+    overflow: hidden;
 }
 
 .slack-context-room.selected {
     background-color: lightgrey;
 }
 
-.slack-chat-content { height: 85vh; overflow: auto; }
-.slack-chat-title { font-size: 1.75em; font-style: italic; }
-.slackmsg-item { position: relative; background: #eee; margin-top: 15px; }
+.slack-chat-content { height: calc(100vh - 8em); overflow: auto; }
+.slack-chat-title { display: inline-block; height: 1.75em; font-size: 1.75em; font-style: italic; }
+.slack-chat-control { display: inline-block; width: 100%; height: 2em; padding: 1.5em 0; }
+.slack-chat-control * { display: inline-block; height: 100%; }
+.slack-context-room.slack-channel + .slack-context-room:not(.slack-channel), .slack-context-room.slack-group + .slack-context-room:not(.slack-group) { margin-top: 1em; border-bottom: 1px solid grey; }
+.slackmsg-item { position: relative; background: #eee; }
+.slackmsg-item:not(:first-child) { margin-top: 15px; }
 .slackmsg-author { display: inline-block; }
 .slackmsg-author-img { margin-right: 15px; }
 .slackmsg-author-name { position: absolute; max-height: 1em; overflow: hidden; font-style: italic; }
 .slackmsg-msg { display: inline-block; vertical-align: top; margin-top: 1em; }
 .slackmsg-ts {}
 
+.slackmsg-hover { display: none; position: absolute; top: 0; right: 0; margin: 0; list-style: none; padding: 0; }
+.slackmsg-hover > li { display: inline-block; width: 1.5em; height: 1.5em; background: white; border: 1px solid black; cursor: pointer; }
+.slackmsg-hover > li:first-child { border-bottom-left-radius: 5px; }
+.slackmsg-hover > li:last-child { border-top-right-radius: 5px; }
+/*
+ * DEBUG
+.slackmsg-item:hover .slackmsg-hover { display: block; }
+*/
+