diff options
Diffstat (limited to 'public/js/mv/connect.js')
-rw-r--r-- | public/js/mv/connect.js | 193 |
1 files changed, 157 insertions, 36 deletions
diff --git a/public/js/mv/connect.js b/public/js/mv/connect.js index 0fee5e7..564690d 100644 --- a/public/js/mv/connect.js +++ b/public/js/mv/connect.js @@ -1,7 +1,9 @@ "use strict"; var mv = function(mv) { - mv.socket = { - connect: connect + mv.connect = { + connect: connect, + join: join, + part: part }; /* If we're updating due to something we received, then don't broadcast back. */ var netrendering = false; @@ -19,12 +21,17 @@ var mv = function(mv) { socket.on("disconnect", function() { console.log("DISCONNECT", arguments); }); d3.select("#connect-status").style("display", "block"); socket.emit('login'); + /* Tell the server our starting filters */ + socket.emit("filter", { filters: mv.charter.filters() }); /* * Protocol: * selflogin -> id (I) * login -> id (I), nick (S) * nickset -> id (I), nick (S) - * users -> { id -> {nick (S), filters ({dim (S) -> filter (*)}) } } + * join -> id (I), channel (I) + * part -> id (I) + * filterset -> id (I), filters ({dim (S) -> filter (*)}) + * users -> { id -> { nick (S), channel (I), filters ({dim (S) -> filter (*)}) } } * logout -> id (I) */ socket.on('selflogin', function(d) { @@ -48,9 +55,20 @@ var mv = function(mv) { users[d.id].nick = d.nick; updateUsersStatus(); }); + socket.on('join', function(d) { + users[d.id].channel = d.channel; + updateUsersStatus(); + }); + socket.on('part', function(d) { + delete users[d.id].channel; + updateUsersStatus(); + }); socket.on('filterset', function(d) { /* Someone changed their filter */ - users[d.id].filters = d.filters; + /* Ignore server sourced (ID: 0) changes */ + if (d.id) { + users[d.id].filters = d.filters; + } /* Use the variable netrendering to denote that we're rendering due to a change received from the network. */ netrendering = true; setOwnFilters(d.filters); @@ -83,6 +101,13 @@ var mv = function(mv) { var key; /* Check for keys in the filters to apply which are not in our charts. */ for (key in filters) { + if (key == "date") { + /* + * Special case! FIXME: Find a more elegant way to handle this + */ + filters[key][0] = new Date(filters[key][0]); + filters[key][1] = new Date(filters[key][1]); + } if (!(key in mv.charts)) continue; var filter = mv.charts[key].filter(); @@ -115,49 +140,145 @@ var mv = function(mv) { dc.redrawAll(); } } + function join(channel) { + if (channel != null) { + socket.emit("join", channel); + } else { + socket.emit("join"); + } + } + function part() { + socket.emit("part"); + } function updateUsersStatus() { /* Convert the user list to a form suitable for a d3 selection */ - var data = []; - for (var uid in users) { users[uid].id = uid; data.push(users[uid]); } - /* Data join */ - var userlist = usersStatus.selectAll(".user") - .data(data, function(d) { return d.id; }); - /* Enter */ - userlist - .enter().append("li").attr("class", "user") + var groups = []; + /* Track the groupless people separately. They should come at the end. */ + var unchannelled = []; + var channelById = {}; + var channelNames = []; + for (var uid in users) { + users[uid].id = uid; + if ("channel" in users[uid]) { + if (!(users[uid].channel in channelById)) { + groups.push(channelById[users[uid].channel] = []); + channelNames.push(users[uid].channel); + } + channelById[users[uid].channel].push(users[uid]); + } else { + unchannelled.push(users[uid]); + } + } + console.log("Channels:", groups, "Users without channels:", unchannelled); + groups.push(unchannelled); + var createpart = usersStatus.select(".createpart"); + /* Link to part a channel we're in, or create a channel if we're not in one */ + if (createpart.empty()) { + createpart = usersStatus.append("a") + .attr("class", "createpart") + ; + } + if ("channel" in users[id]) { + createpart + .attr("href", "javascript:mv.connect.part();") + .text("Part channel") + ; + } else { + createpart + .attr("href", "javascript:mv.connect.join();") + .text("Create channel") + ; + } + /* List of groups, with unchanneled users at the end */ + var grouplist = usersStatus.selectAll(".group") + .data(groups, function(d, i) { return channelNames[i]; }) + ; + grouplist + .enter().append("div").attr("class", "group") ; /* Update */ - userlist - .each(function(d,i) { - var elm = d3.select(this); - console.log("Userlist para appending", d,i); - var name = elm.select(".name"); - var nick = d.nick == null ? "Anonymous User " + d.id : d.nick; - if (d.id == id) { - /* This is us! We can edit our name. */ - if (name.empty()) { - console.log("Found our entry. id:", id, "datum", d); - name = elm.append("input").attr("class", "name") - .attr("type", "text") - .attr("placeholder", "Enter name here") - .on("change", function () { - /* A d3 select must be dereferenced twice to access the DOM entity */ - socket.emit("nick", { nick: name[0][0].value }); - }) + grouplist + .each(function(d, i) { + var group = d3.select(this); + var ul = group.select("ul"); + if (ul.empty()) { + ul = group.append("ul"); + } + /* + * Hacky way to check if these are the users without a channel. + * Feel free to FIXME! + */ + if (i != groups.length - 1) { + console.log("Group is a channel", i, groups.length); + group + .attr("class", "group channel") + ; + var join = group.select(".join"); + if (join.empty()) { + join = group.append("a") + .attr("class", "join") + .attr("href", "javascript:mv.connect.join(" + channelNames[i] + ");") + .text("Join channel") ; } - name.attr("value", nick); + if (users[id].channel == channelNames[i]) { + /* We're in this channel */ + join.style("display", "none"); + } else { + join.style("display", "inline"); + } } else { - /* This is someone else. We can't edit their name. */ - if (name.empty()) { - name = elm.append("p").attr("class", "name"); + console.log("Group is not a channel", i, groups.length); + var join = group.select(".join"); + group + .attr("class", "group") + ; + if (join.empty()) { + join.remove(); } - name.text(nick); } + /* Update the list of users in this group */ + var userlist = ul.selectAll(".user") + .data(d, function(d) { return d.id; }) + ; + userlist + .enter().append("li").attr("class", "user") + ; + userlist + .each(function(d,i) { + var elm = d3.select(this); + console.log("Userlist para appending", d,i); + var name = elm.select(".name"); + var nick = d.nick == null ? "Anonymous User " + d.id : d.nick; + if (d.id == id) { + /* This is us! We can edit our name. */ + if (name.empty()) { + console.log("Found our entry. id:", id, "datum", d); + name = elm.append("input").attr("class", "name") + .attr("type", "text") + .attr("placeholder", "Enter name here") + .on("change", function () { + /* A d3 select must be dereferenced twice to access the DOM entity */ + socket.emit("nick", { nick: name[0][0].value }); + }) + ; + } + name.attr("value", nick); + } else { + /* This is someone else. We can't edit their name. */ + if (name.empty()) { + name = elm.append("p").attr("class", "name"); + } + name.text(nick); + } + }) + ; + userlist + .exit().remove() + ; }) ; - /* Remove */ - userlist + grouplist .exit().remove() ; } |