Replace quadratic emote list impl with Map
This commit is contained in:
parent
8399eab33f
commit
0f9bc44925
|
@ -2,7 +2,7 @@
|
||||||
"author": "Calvin Montgomery",
|
"author": "Calvin Montgomery",
|
||||||
"name": "CyTube",
|
"name": "CyTube",
|
||||||
"description": "Online media synchronizer and chat",
|
"description": "Online media synchronizer and chat",
|
||||||
"version": "3.52.3",
|
"version": "3.53.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"url": "http://github.com/calzoneman/sync"
|
"url": "http://github.com/calzoneman/sync"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,96 +1,42 @@
|
||||||
var ChannelModule = require("./module");
|
var ChannelModule = require("./module");
|
||||||
var XSS = require("../xss");
|
var XSS = require("../xss");
|
||||||
|
|
||||||
function EmoteList(defaults) {
|
class EmoteList {
|
||||||
if (!defaults) {
|
constructor(list) {
|
||||||
defaults = [];
|
if (!list) {
|
||||||
|
list = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emotes = new Map(list.map(e => [e.name, e]));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emotes = defaults.map(validateEmote).filter(function (f) {
|
toJSON() {
|
||||||
return f !== false;
|
let list = [];
|
||||||
});
|
|
||||||
|
for (let [key, value] of this.emotes.entries()) {
|
||||||
|
list.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasEmote(name) {
|
||||||
|
return this.emotes.has(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
setEmote(name, emote) {
|
||||||
|
this.emotes.set(name, emote);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteEmote(name) {
|
||||||
|
return this.emotes.delete(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
size() {
|
||||||
|
return this.emotes.size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EmoteList.prototype = {
|
|
||||||
pack: function () {
|
|
||||||
return Array.prototype.slice.call(this.emotes);
|
|
||||||
},
|
|
||||||
|
|
||||||
importList: function (emotes) {
|
|
||||||
this.emotes = Array.prototype.slice.call(emotes);
|
|
||||||
},
|
|
||||||
|
|
||||||
emoteExists: function (emote){
|
|
||||||
if(this.emotes.filter((item)=>{ return item.name === emote.name }).length){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
renameEmote: function (emote) {
|
|
||||||
var found = false;
|
|
||||||
for (var i = 0; i < this.emotes.length; i++) {
|
|
||||||
if (this.emotes[i].name === emote.old) {
|
|
||||||
found = true;
|
|
||||||
this.emotes[i] = emote;
|
|
||||||
delete this.emotes[i].old;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(found){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
updateEmote: function (emote) {
|
|
||||||
var found = false;
|
|
||||||
for (var i = 0; i < this.emotes.length; i++) {
|
|
||||||
if (this.emotes[i].name === emote.name) {
|
|
||||||
found = true;
|
|
||||||
this.emotes[i] = emote;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If no emote was updated, add a new one */
|
|
||||||
if (!found) {
|
|
||||||
this.emotes.push(emote);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
removeEmote: function (emote) {
|
|
||||||
var found = false;
|
|
||||||
for (var i = 0; i < this.emotes.length; i++) {
|
|
||||||
if (this.emotes[i].name === emote.name) {
|
|
||||||
this.emotes.splice(i, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
moveEmote: function (from, to) {
|
|
||||||
if (from < 0 || to < 0 ||
|
|
||||||
from >= this.emotes.length || to >= this.emotes.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var f = this.emotes[from];
|
|
||||||
/* Offset from/to indexes to account for the fact that removing
|
|
||||||
an element changes the position of one of them.
|
|
||||||
|
|
||||||
I could have just done a swap, but it's already implemented this way
|
|
||||||
and it works. */
|
|
||||||
to = to > from ? to + 1 : to;
|
|
||||||
from = to > from ? from : from + 1;
|
|
||||||
|
|
||||||
this.emotes.splice(to, 0, f);
|
|
||||||
this.emotes.splice(from, 1);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function validateEmote(f) {
|
function validateEmote(f) {
|
||||||
if (typeof f.name !== "string" || typeof f.image !== "string") {
|
if (typeof f.name !== "string" || typeof f.image !== "string") {
|
||||||
return false;
|
return false;
|
||||||
|
@ -126,21 +72,19 @@ EmoteModule.prototype = Object.create(ChannelModule.prototype);
|
||||||
|
|
||||||
EmoteModule.prototype.load = function (data) {
|
EmoteModule.prototype.load = function (data) {
|
||||||
if ("emotes" in data) {
|
if ("emotes" in data) {
|
||||||
for (var i = 0; i < data.emotes.length; i++) {
|
this.emotes = new EmoteList(data.emotes);
|
||||||
this.emotes.updateEmote(data.emotes[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
EmoteModule.prototype.save = function (data) {
|
EmoteModule.prototype.save = function (data) {
|
||||||
data.emotes = this.emotes.pack();
|
data.emotes = this.emotes.toJSON();
|
||||||
};
|
};
|
||||||
|
|
||||||
EmoteModule.prototype.packInfo = function (data, isAdmin) {
|
EmoteModule.prototype.packInfo = function (data, isAdmin) {
|
||||||
if (isAdmin) {
|
if (isAdmin) {
|
||||||
data.emoteCount = this.emotes.emotes.length;
|
data.emoteCount = this.emotes.size();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -148,13 +92,12 @@ EmoteModule.prototype.onUserPostJoin = function (user) {
|
||||||
user.socket.on("renameEmote", this.handleRenameEmote.bind(this, user));
|
user.socket.on("renameEmote", this.handleRenameEmote.bind(this, user));
|
||||||
user.socket.on("updateEmote", this.handleUpdateEmote.bind(this, user));
|
user.socket.on("updateEmote", this.handleUpdateEmote.bind(this, user));
|
||||||
user.socket.on("importEmotes", this.handleImportEmotes.bind(this, user));
|
user.socket.on("importEmotes", this.handleImportEmotes.bind(this, user));
|
||||||
user.socket.on("moveEmote", this.handleMoveEmote.bind(this, user));
|
|
||||||
user.socket.on("removeEmote", this.handleRemoveEmote.bind(this, user));
|
user.socket.on("removeEmote", this.handleRemoveEmote.bind(this, user));
|
||||||
this.sendEmotes([user]);
|
this.sendEmotes([user]);
|
||||||
};
|
};
|
||||||
|
|
||||||
EmoteModule.prototype.sendEmotes = function (users) {
|
EmoteModule.prototype.sendEmotes = function (users) {
|
||||||
var f = this.emotes.pack();
|
var f = this.emotes.toJSON();
|
||||||
var chan = this.channel;
|
var chan = this.channel;
|
||||||
users.forEach(function (u) {
|
users.forEach(function (u) {
|
||||||
u.socket.emit("emoteList", f);
|
u.socket.emit("emoteList", f);
|
||||||
|
@ -178,7 +121,7 @@ EmoteModule.prototype.handleRenameEmote = function (user, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var e = this.emotes.emoteExists(data);
|
var e = this.emotes.hasEmote(data.name);
|
||||||
var f = validateEmote(data);
|
var f = validateEmote(data);
|
||||||
if (!f || e) {
|
if (!f || e) {
|
||||||
var message = "Unable to rename emote '" + JSON.stringify(data) + "'. " +
|
var message = "Unable to rename emote '" + JSON.stringify(data) + "'. " +
|
||||||
|
@ -197,9 +140,17 @@ EmoteModule.prototype.handleRenameEmote = function (user, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// See comment above
|
var hadOld = this.emotes.deleteEmote(f.old);
|
||||||
var success = this.emotes.renameEmote(Object.assign({}, f));
|
|
||||||
if(!success){ return; }
|
if (!hadOld) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emotes.setEmote(f.name, {
|
||||||
|
name: f.name,
|
||||||
|
source: f.source,
|
||||||
|
image: f.image
|
||||||
|
});
|
||||||
|
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
|
||||||
|
@ -232,7 +183,11 @@ EmoteModule.prototype.handleUpdateEmote = function (user, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emotes.updateEmote(f);
|
this.emotes.setEmote(f.name, {
|
||||||
|
name: f.name,
|
||||||
|
source: f.source,
|
||||||
|
image: f.image
|
||||||
|
});
|
||||||
|
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
|
||||||
|
@ -254,9 +209,7 @@ EmoteModule.prototype.handleImportEmotes = function (user, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emotes.importList(data.map(validateEmote).filter(function (f) {
|
this.emotes = new EmoteList(data.map(validateEmote).filter(f => f));
|
||||||
return f !== false;
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
|
||||||
|
@ -276,7 +229,7 @@ EmoteModule.prototype.handleRemoveEmote = function (user, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emotes.removeEmote(data);
|
this.emotes.deleteEmote(data.name);
|
||||||
|
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
|
||||||
|
@ -284,22 +237,4 @@ EmoteModule.prototype.handleRemoveEmote = function (user, data) {
|
||||||
this.channel.broadcastAll("removeEmote", data);
|
this.channel.broadcastAll("removeEmote", data);
|
||||||
};
|
};
|
||||||
|
|
||||||
EmoteModule.prototype.handleMoveEmote = function (user, data) {
|
|
||||||
if (typeof data !== "object") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.channel.modules.permissions.canEditEmotes(user)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof data.to !== "number" || typeof data.from !== "number") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emotes.moveEmote(data.from, data.to);
|
|
||||||
|
|
||||||
this.dirty = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = EmoteModule;
|
module.exports = EmoteModule;
|
||||||
|
|
|
@ -189,11 +189,6 @@ html(lang="en")
|
||||||
.modal-body
|
.modal-body
|
||||||
.pull-left
|
.pull-left
|
||||||
input.emotelist-search.form-control(type="text", placeholder="Search")
|
input.emotelist-search.form-control(type="text", placeholder="Search")
|
||||||
.pull-right
|
|
||||||
.checkbox
|
|
||||||
label
|
|
||||||
input.emotelist-alphabetical(type="checkbox")
|
|
||||||
| Sort alphabetically
|
|
||||||
.emotelist-paginator-container
|
.emotelist-paginator-container
|
||||||
table.emotelist-table
|
table.emotelist-table
|
||||||
tbody
|
tbody
|
||||||
|
|
|
@ -197,11 +197,6 @@ mixin emotes
|
||||||
form.form-inline
|
form.form-inline
|
||||||
.form-group
|
.form-group
|
||||||
input.emotelist-search.form-control(type="text", placeholder="Search")
|
input.emotelist-search.form-control(type="text", placeholder="Search")
|
||||||
.form-group
|
|
||||||
.checkbox
|
|
||||||
label
|
|
||||||
input.emotelist-alphabetical(type="checkbox")
|
|
||||||
| Sort alphabetically
|
|
||||||
.emotelist-paginator-container
|
.emotelist-paginator-container
|
||||||
table.emotelist-table.table.table-striped.table-condensed
|
table.emotelist-table.table.table-striped.table-condensed
|
||||||
thead
|
thead
|
||||||
|
|
|
@ -127,7 +127,6 @@ var USEROPTS = {
|
||||||
default_quality : getOrDefault("default_quality", "auto"),
|
default_quality : getOrDefault("default_quality", "auto"),
|
||||||
boop : getOrDefault("boop", "never"),
|
boop : getOrDefault("boop", "never"),
|
||||||
show_shadowchat : getOrDefault("show_shadowchat", false),
|
show_shadowchat : getOrDefault("show_shadowchat", false),
|
||||||
emotelist_sort : getOrDefault("emotelist_sort", true),
|
|
||||||
no_emotes : getOrDefault("no_emotes", false),
|
no_emotes : getOrDefault("no_emotes", false),
|
||||||
strip_image : getOrDefault("strip_image", false),
|
strip_image : getOrDefault("strip_image", false),
|
||||||
chat_tab_method : getOrDefault("chat_tab_method", "Cycle options")
|
chat_tab_method : getOrDefault("chat_tab_method", "Cycle options")
|
||||||
|
|
|
@ -846,12 +846,6 @@ $("#emotelistbtn").click(function () {
|
||||||
EMOTELISTMODAL.modal();
|
EMOTELISTMODAL.modal();
|
||||||
});
|
});
|
||||||
|
|
||||||
EMOTELISTMODAL.find(".emotelist-alphabetical").change(function () {
|
|
||||||
USEROPTS.emotelist_sort = this.checked;
|
|
||||||
setOpt("emotelist_sort", USEROPTS.emotelist_sort);
|
|
||||||
});
|
|
||||||
EMOTELISTMODAL.find(".emotelist-alphabetical").prop("checked", USEROPTS.emotelist_sort);
|
|
||||||
|
|
||||||
$("#fullscreenbtn").click(function () {
|
$("#fullscreenbtn").click(function () {
|
||||||
var elem = document.querySelector("#videowrap .embed-responsive");
|
var elem = document.querySelector("#videowrap .embed-responsive");
|
||||||
// this shit is why frontend web development sucks
|
// this shit is why frontend web development sucks
|
||||||
|
|
|
@ -2915,8 +2915,8 @@ function formatScriptAccessPrefs() {
|
||||||
|
|
||||||
function EmoteList(selector, emoteClickCallback) {
|
function EmoteList(selector, emoteClickCallback) {
|
||||||
this.elem = $(selector);
|
this.elem = $(selector);
|
||||||
|
this.sortAlphabetical = true;
|
||||||
this.initSearch();
|
this.initSearch();
|
||||||
this.initSortOption();
|
|
||||||
this.table = this.elem.find(".emotelist-table")[0];
|
this.table = this.elem.find(".emotelist-table")[0];
|
||||||
this.paginatorContainer = this.elem.find(".emotelist-paginator-container");
|
this.paginatorContainer = this.elem.find(".emotelist-paginator-container");
|
||||||
this.cols = 5;
|
this.cols = 5;
|
||||||
|
@ -2944,18 +2944,6 @@ EmoteList.prototype.initSearch = function () {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
EmoteList.prototype.initSortOption = function () {
|
|
||||||
this.sortOption = this.elem.find(".emotelist-alphabetical");
|
|
||||||
this.sortAlphabetical = false;
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.sortOption.change(function () {
|
|
||||||
self.sortAlphabetical = this.checked;
|
|
||||||
self.handleChange();
|
|
||||||
self.loadPage(0);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
EmoteList.prototype.handleChange = function () {
|
EmoteList.prototype.handleChange = function () {
|
||||||
this.emotes = CHANNEL.emotes.slice();
|
this.emotes = CHANNEL.emotes.slice();
|
||||||
if (this.sortAlphabetical) {
|
if (this.sortAlphabetical) {
|
||||||
|
@ -3039,7 +3027,6 @@ function onEmoteClicked(emote) {
|
||||||
}
|
}
|
||||||
|
|
||||||
window.EMOTELIST = new EmoteList("#emotelist", onEmoteClicked);
|
window.EMOTELIST = new EmoteList("#emotelist", onEmoteClicked);
|
||||||
window.EMOTELIST.sortAlphabetical = USEROPTS.emotelist_sort;
|
|
||||||
|
|
||||||
function CSEmoteList(selector) {
|
function CSEmoteList(selector) {
|
||||||
EmoteList.call(this, selector);
|
EmoteList.call(this, selector);
|
||||||
|
@ -3192,7 +3179,6 @@ CSEmoteList.prototype.loadPage = function (page) {
|
||||||
};
|
};
|
||||||
|
|
||||||
window.CSEMOTELIST = new CSEmoteList("#cs-emotes");
|
window.CSEMOTELIST = new CSEmoteList("#cs-emotes");
|
||||||
window.CSEMOTELIST.sortAlphabetical = USEROPTS.emotelist_sort;
|
|
||||||
|
|
||||||
function showChannelSettings() {
|
function showChannelSettings() {
|
||||||
$("#channeloptions").modal();
|
$("#channeloptions").modal();
|
||||||
|
|
Loading…
Reference in a new issue