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",
|
||||
"name": "CyTube",
|
||||
"description": "Online media synchronizer and chat",
|
||||
"version": "3.53.1",
|
||||
"version": "3.52.4",
|
||||
"repository": {
|
||||
"url": "http://github.com/calzoneman/sync"
|
||||
},
|
||||
|
|
|
@ -1,42 +1,96 @@
|
|||
var ChannelModule = require("./module");
|
||||
var XSS = require("../xss");
|
||||
|
||||
class EmoteList {
|
||||
constructor(list) {
|
||||
if (!list) {
|
||||
list = [];
|
||||
}
|
||||
|
||||
this.emotes = new Map(list.map(e => [e.name, e]));
|
||||
function EmoteList(defaults) {
|
||||
if (!defaults) {
|
||||
defaults = [];
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
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;
|
||||
}
|
||||
this.emotes = defaults.map(validateEmote).filter(function (f) {
|
||||
return f !== false;
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
if (typeof f.name !== "string" || typeof f.image !== "string") {
|
||||
return false;
|
||||
|
@ -72,19 +126,21 @@ EmoteModule.prototype = Object.create(ChannelModule.prototype);
|
|||
|
||||
EmoteModule.prototype.load = function (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;
|
||||
};
|
||||
|
||||
EmoteModule.prototype.save = function (data) {
|
||||
data.emotes = this.emotes.toJSON();
|
||||
data.emotes = this.emotes.pack();
|
||||
};
|
||||
|
||||
EmoteModule.prototype.packInfo = function (data, 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("updateEmote", this.handleUpdateEmote.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));
|
||||
this.sendEmotes([user]);
|
||||
};
|
||||
|
||||
EmoteModule.prototype.sendEmotes = function (users) {
|
||||
var f = this.emotes.toJSON();
|
||||
var f = this.emotes.pack();
|
||||
var chan = this.channel;
|
||||
users.forEach(function (u) {
|
||||
u.socket.emit("emoteList", f);
|
||||
|
@ -121,7 +178,7 @@ EmoteModule.prototype.handleRenameEmote = function (user, data) {
|
|||
return;
|
||||
}
|
||||
|
||||
var e = this.emotes.hasEmote(data.name);
|
||||
var e = this.emotes.emoteExists(data);
|
||||
var f = validateEmote(data);
|
||||
if (!f || e) {
|
||||
var message = "Unable to rename emote '" + JSON.stringify(data) + "'. " +
|
||||
|
@ -140,17 +197,9 @@ EmoteModule.prototype.handleRenameEmote = function (user, data) {
|
|||
return;
|
||||
}
|
||||
|
||||
var hadOld = this.emotes.deleteEmote(f.old);
|
||||
|
||||
if (!hadOld) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.emotes.setEmote(f.name, {
|
||||
name: f.name,
|
||||
source: f.source,
|
||||
image: f.image
|
||||
});
|
||||
// See comment above
|
||||
var success = this.emotes.renameEmote(Object.assign({}, f));
|
||||
if(!success){ return; }
|
||||
|
||||
this.dirty = true;
|
||||
|
||||
|
@ -183,11 +232,7 @@ EmoteModule.prototype.handleUpdateEmote = function (user, data) {
|
|||
return;
|
||||
}
|
||||
|
||||
this.emotes.setEmote(f.name, {
|
||||
name: f.name,
|
||||
source: f.source,
|
||||
image: f.image
|
||||
});
|
||||
this.emotes.updateEmote(f);
|
||||
|
||||
this.dirty = true;
|
||||
|
||||
|
@ -209,7 +254,9 @@ EmoteModule.prototype.handleImportEmotes = function (user, data) {
|
|||
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;
|
||||
|
||||
|
@ -229,7 +276,7 @@ EmoteModule.prototype.handleRemoveEmote = function (user, data) {
|
|||
return;
|
||||
}
|
||||
|
||||
this.emotes.deleteEmote(data.name);
|
||||
this.emotes.removeEmote(data);
|
||||
|
||||
this.dirty = true;
|
||||
|
||||
|
@ -237,4 +284,22 @@ EmoteModule.prototype.handleRemoveEmote = function (user, 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;
|
||||
|
|
|
@ -189,6 +189,11 @@ html(lang="en")
|
|||
.modal-body
|
||||
.pull-left
|
||||
input.emotelist-search.form-control(type="text", placeholder="Search")
|
||||
.pull-right
|
||||
.checkbox
|
||||
label
|
||||
input.emotelist-alphabetical(type="checkbox")
|
||||
| Sort alphabetically
|
||||
.emotelist-paginator-container
|
||||
table.emotelist-table
|
||||
tbody
|
||||
|
|
|
@ -197,6 +197,11 @@ mixin emotes
|
|||
form.form-inline
|
||||
.form-group
|
||||
input.emotelist-search.form-control(type="text", placeholder="Search")
|
||||
.form-group
|
||||
.checkbox
|
||||
label
|
||||
input.emotelist-alphabetical(type="checkbox")
|
||||
| Sort alphabetically
|
||||
.emotelist-paginator-container
|
||||
table.emotelist-table.table.table-striped.table-condensed
|
||||
thead
|
||||
|
|
|
@ -127,6 +127,7 @@ var USEROPTS = {
|
|||
default_quality : getOrDefault("default_quality", "auto"),
|
||||
boop : getOrDefault("boop", "never"),
|
||||
show_shadowchat : getOrDefault("show_shadowchat", false),
|
||||
emotelist_sort : getOrDefault("emotelist_sort", true),
|
||||
no_emotes : getOrDefault("no_emotes", false),
|
||||
strip_image : getOrDefault("strip_image", false),
|
||||
chat_tab_method : getOrDefault("chat_tab_method", "Cycle options")
|
||||
|
|
|
@ -846,6 +846,12 @@ $("#emotelistbtn").click(function () {
|
|||
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 () {
|
||||
var elem = document.querySelector("#videowrap .embed-responsive");
|
||||
// this shit is why frontend web development sucks
|
||||
|
|
|
@ -2915,8 +2915,8 @@ function formatScriptAccessPrefs() {
|
|||
|
||||
function EmoteList(selector, emoteClickCallback) {
|
||||
this.elem = $(selector);
|
||||
this.sortAlphabetical = true;
|
||||
this.initSearch();
|
||||
this.initSortOption();
|
||||
this.table = this.elem.find(".emotelist-table")[0];
|
||||
this.paginatorContainer = this.elem.find(".emotelist-paginator-container");
|
||||
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 () {
|
||||
this.emotes = CHANNEL.emotes.slice();
|
||||
if (this.sortAlphabetical) {
|
||||
|
@ -3027,6 +3039,7 @@ function onEmoteClicked(emote) {
|
|||
}
|
||||
|
||||
window.EMOTELIST = new EmoteList("#emotelist", onEmoteClicked);
|
||||
window.EMOTELIST.sortAlphabetical = USEROPTS.emotelist_sort;
|
||||
|
||||
function CSEmoteList(selector) {
|
||||
EmoteList.call(this, selector);
|
||||
|
@ -3179,6 +3192,7 @@ CSEmoteList.prototype.loadPage = function (page) {
|
|||
};
|
||||
|
||||
window.CSEMOTELIST = new CSEmoteList("#cs-emotes");
|
||||
window.CSEMOTELIST.sortAlphabetical = USEROPTS.emotelist_sort;
|
||||
|
||||
function showChannelSettings() {
|
||||
$("#channeloptions").modal();
|
||||
|
|
Loading…
Reference in a new issue