Insert channel/user into channel list at alphabetically sorted point, not just the end

Don't sort queries/users after special chans


Set all users in tests to be of type query


Add test for not inserting infront of lobby


Break after finding the index, otherwise it always adds it to the end


Add checking for lobby in first test


Fix off-by-one error on the frontend


Fix utterly idiotic issue adding a duplicate of the channel we are on rather than the new user when we query


Check that we always insert before first special chan
This commit is contained in:
Al McKinlay 2018-03-12 12:42:59 +00:00
parent 191f8429c3
commit 5ce67ba093
9 changed files with 232 additions and 12 deletions

View File

@ -10,11 +10,12 @@ const sidebar = $("#sidebar");
socket.on("join", function(data) { socket.on("join", function(data) {
const id = data.network; const id = data.network;
const network = sidebar.find(`#network-${id}`); const network = sidebar.find(`#network-${id}`);
network.append( const channels = network.children();
templates.chan({ const position = $(channels[data.index || channels.length - 1]); // Put channel in correct position, or the end if we don't have one
const sidebarEntry = templates.chan({
channels: [data.chan], channels: [data.chan],
}) });
); $(sidebarEntry).insertAfter(position);
chat.append( chat.append(
templates.chat({ templates.chat({
channels: [data.chan], channels: [data.chan],

View File

@ -128,6 +128,28 @@ Network.prototype.getNetworkStatus = function() {
return status; return status;
}; };
Network.prototype.addChannel = function(newChan) {
let index = this.channels.length; // Default to putting as the last item in the array
// Don't sort special channels in amongst channels/users.
if (newChan.type === Chan.Type.CHANNEL || newChan.type === Chan.Type.QUERY) {
// We start at 1 so we don't test against the lobby
for (let i = 1; i < this.channels.length; i++) {
const compareChan = this.channels[i];
// Negative if the new chan is alphabetically before the next chan in the list, positive if after
if (newChan.name.localeCompare(compareChan.name, {sensitivity: "base"}) <= 0
|| (compareChan.type !== Chan.Type.CHANNEL && compareChan.type !== Chan.Type.QUERY)) {
index = i;
break;
}
}
}
this.channels.splice(index, 0, newChan);
return index;
};
Network.prototype.export = function() { Network.prototype.export = function() {
const network = _.pick(this, [ const network = _.pick(this, [
"uuid", "uuid",

View File

@ -47,11 +47,12 @@ exports.input = function(network, chan, cmd, args) {
type: Chan.Type.QUERY, type: Chan.Type.QUERY,
name: target, name: target,
}); });
network.channels.push(newChan);
this.emit("join", { this.emit("join", {
network: network.id, network: network.id,
chan: newChan.getFilteredClone(true), chan: newChan.getFilteredClone(true),
shouldOpen: true, shouldOpen: true,
index: network.addChannel(newChan),
}); });
this.save(); this.save();
newChan.loadMessages(this, network); newChan.loadMessages(this, network);

View File

@ -37,10 +37,10 @@ module.exports = function(irc, network) {
type: Chan.Type.SPECIAL, type: Chan.Type.SPECIAL,
name: chanName, name: chanName,
}); });
network.channels.push(chan);
client.emit("join", { client.emit("join", {
network: network.id, network: network.id,
chan: chan.getFilteredClone(true), chan: chan.getFilteredClone(true),
index: network.addChannel(chan),
}); });
} }

View File

@ -15,12 +15,13 @@ module.exports = function(irc, network) {
name: data.channel, name: data.channel,
state: Chan.State.JOINED, state: Chan.State.JOINED,
}); });
network.channels.push(chan);
client.save();
client.emit("join", { client.emit("join", {
network: network.id, network: network.id,
chan: chan.getFilteredClone(true), chan: chan.getFilteredClone(true),
index: network.addChannel(chan),
}); });
client.save();
chan.loadMessages(client, network); chan.loadMessages(client, network);

View File

@ -46,10 +46,11 @@ module.exports = function(irc, network) {
type: Chan.Type.SPECIAL, type: Chan.Type.SPECIAL,
name: "Channel List", name: "Channel List",
}); });
network.channels.push(chan);
client.emit("join", { client.emit("join", {
network: network.id, network: network.id,
chan: chan.getFilteredClone(true), chan: chan.getFilteredClone(true),
index: network.addChannel(chan),
}); });
} }

View File

@ -67,11 +67,13 @@ module.exports = function(irc, network) {
type: Chan.Type.QUERY, type: Chan.Type.QUERY,
name: target, name: target,
}); });
network.channels.push(chan);
client.emit("join", { client.emit("join", {
network: network.id, network: network.id,
chan: chan.getFilteredClone(true), chan: chan.getFilteredClone(true),
index: network.addChannel(chan),
}); });
client.save();
chan.loadMessages(client, network); chan.loadMessages(client, network);
} }
} }

View File

@ -13,13 +13,15 @@ module.exports = function(irc, network) {
type: Chan.Type.QUERY, type: Chan.Type.QUERY,
name: data.nick, name: data.nick,
}); });
network.channels.push(chan);
client.emit("join", { client.emit("join", {
shouldOpen: true, shouldOpen: true,
network: network.id, network: network.id,
chan: chan.getFilteredClone(true), chan: chan.getFilteredClone(true),
index: network.addChannel(chan),
}); });
chan.loadMessages(client, network); chan.loadMessages(client, network);
client.save();
} }
let msg; let msg;

View File

@ -147,4 +147,194 @@ describe("Network", function() {
); );
}); });
}); });
describe("#addChannel(newChan)", function() {
it("should add channel", function() {
const chan = new Chan({name: "#thelounge"});
const network = new Network({
channels: [
chan,
],
});
// Lobby and initial channel
expect(network.channels.length).to.equal(2);
const newChan = new Chan({name: "#freenode"});
network.addChannel(newChan);
expect(network.channels.length).to.equal(3);
});
it("should add channel alphabetically", function() {
const chan1 = new Chan({name: "#abc"});
const chan2 = new Chan({name: "#thelounge"});
const chan3 = new Chan({name: "#zero"});
const network = new Network({
channels: [
chan1,
chan2,
chan3,
],
name: "freenode",
});
const newChan = new Chan({name: "#freenode"});
network.addChannel(newChan);
expect(network.channels[0].name).to.equal("freenode");
expect(network.channels[1]).to.equal(chan1);
expect(network.channels[2]).to.equal(newChan);
expect(network.channels[3]).to.equal(chan2);
expect(network.channels[4]).to.equal(chan3);
});
it("should sort case-insensitively", function() {
const chan1 = new Chan({name: "#abc"});
const chan2 = new Chan({name: "#THELOUNGE"});
const network = new Network({
channels: [
chan1,
chan2,
],
});
const newChan = new Chan({name: "#freenode"});
network.addChannel(newChan);
expect(network.channels[1]).to.equal(chan1);
expect(network.channels[2]).to.equal(newChan);
expect(network.channels[3]).to.equal(chan2);
});
it("should sort users separately from channels", function() {
const chan1 = new Chan({name: "#abc"});
const chan2 = new Chan({name: "#THELOUNGE"});
const network = new Network({
channels: [
chan1,
chan2,
],
});
const newUser = new Chan({name: "mcinkay", type: Chan.Type.QUERY});
network.addChannel(newUser);
expect(network.channels[1]).to.equal(chan1);
expect(network.channels[2]).to.equal(chan2);
expect(network.channels[3]).to.equal(newUser);
});
it("should sort users alphabetically", function() {
const chan1 = new Chan({name: "#abc"});
const chan2 = new Chan({name: "#THELOUNGE"});
const user1 = new Chan({name: "astorije", type: Chan.Type.QUERY});
const user2 = new Chan({name: "xpaw", type: Chan.Type.QUERY});
const network = new Network({
channels: [
chan1,
chan2,
user1,
user2,
],
});
const newUser = new Chan({name: "mcinkay", type: Chan.Type.QUERY});
network.addChannel(newUser);
expect(network.channels[1]).to.equal(chan1);
expect(network.channels[2]).to.equal(chan2);
expect(network.channels[3]).to.equal(user1);
expect(network.channels[4]).to.equal(newUser);
expect(network.channels[5]).to.equal(user2);
});
it("should not sort special channels", function() {
const chan1 = new Chan({name: "#abc"});
const chan2 = new Chan({name: "#THELOUNGE"});
const user1 = new Chan({name: "astorije", type: Chan.Type.QUERY});
const user2 = new Chan({name: "xpaw", type: Chan.Type.QUERY});
const network = new Network({
channels: [
chan1,
chan2,
user1,
user2,
],
});
const newBanlist = new Chan({name: "Banlist for #THELOUNGE", type: Chan.Type.SPECIAL});
network.addChannel(newBanlist);
expect(network.channels[1]).to.equal(chan1);
expect(network.channels[2]).to.equal(chan2);
expect(network.channels[3]).to.equal(user1);
expect(network.channels[4]).to.equal(user2);
expect(network.channels[5]).to.equal(newBanlist);
});
it("should not compare against special channels", function() {
const chan1 = new Chan({name: "#abc"});
const chan2 = new Chan({name: "#THELOUNGE"});
const user1 = new Chan({name: "astorije", type: Chan.Type.QUERY});
const network = new Network({
channels: [
chan1,
chan2,
user1,
],
});
const newBanlist = new Chan({name: "Banlist for #THELOUNGE", type: Chan.Type.SPECIAL});
network.addChannel(newBanlist);
const newUser = new Chan({name: "mcinkay", type: Chan.Type.QUERY});
network.addChannel(newUser);
expect(network.channels[1]).to.equal(chan1);
expect(network.channels[2]).to.equal(chan2);
expect(network.channels[3]).to.equal(user1);
expect(network.channels[4]).to.equal(newUser);
expect(network.channels[5]).to.equal(newBanlist);
});
it("should insert before first special channel", function() {
const banlist = new Chan({name: "Banlist for #THELOUNGE", type: Chan.Type.SPECIAL});
const chan1 = new Chan({name: "#thelounge"});
const user1 = new Chan({name: "astorije", type: Chan.Type.QUERY});
const network = new Network({
channels: [
banlist,
chan1,
user1,
],
});
const newChan = new Chan({name: "#freenode"});
network.addChannel(newChan);
expect(network.channels[1]).to.equal(newChan);
expect(network.channels[2]).to.equal(banlist);
expect(network.channels[3]).to.equal(chan1);
expect(network.channels[4]).to.equal(user1);
});
it("should never add something in front of the lobby", function() {
const network = new Network({
name: "freenode",
channels: [],
});
const newUser = new Chan({name: "astorije"});
network.addChannel(newUser);
expect(network.channels[1]).to.equal(newUser);
});
});
}); });