Revert "Replace quadratic emote list impl with Map"
This reverts commit 0f9bc44925
.
The original commit was not backwards compatible with use cases that
users were relying on, such as emotes being sorted in insertion order by
default.
I will develop a new patch which fixes the performance issue in a
backwards compatible way.
This commit is contained in:
parent
aeab31825e
commit
966da1ac58
|
@ -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.53.1",
|
"version": "3.52.4",
|
||||||
"repository": {
|
"repository": {
|
||||||
"url": "http://github.com/calzoneman/sync"
|
"url": "http://github.com/calzoneman/sync"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,42 +1,96 @@
|
||||||
var ChannelModule = require("./module");
|
var ChannelModule = require("./module");
|
||||||
var XSS = require("../xss");
|
var XSS = require("../xss");
|
||||||
|
|
||||||
class EmoteList {
|
function EmoteList(defaults) {
|
||||||
constructor(list) {
|
if (!defaults) {
|
||||||
if (!list) {
|
defaults = [];
|
||||||
list = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emotes = new Map(list.map(e => [e.name, e]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON() {
|
this.emotes = defaults.map(validateEmote).filter(function (f) {
|
||||||
let list = [];
|
return f !== false;
|
||||||
|
});
|
||||||
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;
|
||||||
|
@ -72,19 +126,21 @@ EmoteModule.prototype = Object.create(ChannelModule.prototype);
|
||||||
|
|
||||||
EmoteModule.prototype.load = function (data) {
|
EmoteModule.prototype.load = function (data) {
|
||||||
if ("emotes" in data) {
|
if ("emotes" in data) {
|
||||||
this.emotes = new EmoteList(data.emotes);
|
for (var i = 0; i < data.emotes.length; i++) {
|
||||||
|
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.toJSON();
|
data.emotes = this.emotes.pack();
|
||||||
};
|
};
|
||||||
|
|
||||||
EmoteModule.prototype.packInfo = function (data, isAdmin) {
|
EmoteModule.prototype.packInfo = function (data, isAdmin) {
|
||||||
if (isAdmin) {
|
if (isAdmin) {
|
||||||
data.emoteCount = this.emotes.size();
|
data.emoteCount = this.emotes.emotes.length;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -92,12 +148,13 @@ 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.toJSON();
|
var f = this.emotes.pack();
|
||||||
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);
|
||||||
|
@ -121,7 +178,7 @@ EmoteModule.prototype.handleRenameEmote = function (user, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var e = this.emotes.hasEmote(data.name);
|
var e = this.emotes.emoteExists(data);
|
||||||
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) + "'. " +
|
||||||
|
@ -140,17 +197,9 @@ EmoteModule.prototype.handleRenameEmote = function (user, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var hadOld = this.emotes.deleteEmote(f.old);
|
// See comment above
|
||||||
|
var success = this.emotes.renameEmote(Object.assign({}, f));
|
||||||
if (!hadOld) {
|
if(!success){ return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emotes.setEmote(f.name, {
|
|
||||||
name: f.name,
|
|
||||||
source: f.source,
|
|
||||||
image: f.image
|
|
||||||
});
|
|
||||||
|
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
|
||||||
|
@ -183,11 +232,7 @@ EmoteModule.prototype.handleUpdateEmote = function (user, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emotes.setEmote(f.name, {
|
this.emotes.updateEmote(f);
|
||||||
name: f.name,
|
|
||||||
source: f.source,
|
|
||||||
image: f.image
|
|
||||||
});
|
|
||||||
|
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
|
||||||
|
@ -209,7 +254,9 @@ EmoteModule.prototype.handleImportEmotes = function (user, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emotes = new EmoteList(data.map(validateEmote).filter(f => f));
|
this.emotes.importList(data.map(validateEmote).filter(function (f) {
|
||||||
|
return f !== false;
|
||||||
|
}));
|
||||||
|
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
|
||||||
|
@ -229,7 +276,7 @@ EmoteModule.prototype.handleRemoveEmote = function (user, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emotes.deleteEmote(data.name);
|
this.emotes.removeEmote(data);
|
||||||
|
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
|
||||||
|
@ -237,4 +284,22 @@ 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,6 +189,11 @@ 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,6 +197,11 @@ 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,6 +127,7 @@ 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,6 +846,12 @@ $("#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,6 +2944,18 @@ 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) {
|
||||||
|
@ -3027,6 +3039,7 @@ 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);
|
||||||
|
@ -3179,6 +3192,7 @@ 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