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,41 +1,95 @@
|
||||||
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]));
|
this.emotes = defaults.map(validateEmote).filter(function (f) {
|
||||||
|
return f !== false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON() {
|
EmoteList.prototype = {
|
||||||
let list = [];
|
pack: function () {
|
||||||
|
return Array.prototype.slice.call(this.emotes);
|
||||||
|
},
|
||||||
|
|
||||||
for (let [key, value] of this.emotes.entries()) {
|
importList: function (emotes) {
|
||||||
list.push(value);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasEmote(name) {
|
/* If no emote was updated, add a new one */
|
||||||
return this.emotes.has(name);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
setEmote(name, emote) {
|
var f = this.emotes[from];
|
||||||
this.emotes.set(name, emote);
|
/* Offset from/to indexes to account for the fact that removing
|
||||||
}
|
an element changes the position of one of them.
|
||||||
|
|
||||||
deleteEmote(name) {
|
I could have just done a swap, but it's already implemented this way
|
||||||
return this.emotes.delete(name);
|
and it works. */
|
||||||
}
|
to = to > from ? to + 1 : to;
|
||||||
|
from = to > from ? from : from + 1;
|
||||||
|
|
||||||
size() {
|
this.emotes.splice(to, 0, f);
|
||||||
return this.emotes.size;
|
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") {
|
||||||
|
|
@ -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