From 8e3ce4e1c31be48739ebed96b8847e1b6e1eacc3 Mon Sep 17 00:00:00 2001 From: Xaekai Date: Tue, 16 May 2017 09:56:37 -0700 Subject: [PATCH 1/3] Emote renaming This allow emotes to be renamed in the same fashion the image URLs can be changed. --- src/channel/emotes.js | 43 +++++++++++++++++++++++++++++++ www/js/callbacks.js | 48 ++++++++++++++++++++++++++++++++++ www/js/util.js | 60 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 148 insertions(+), 3 deletions(-) diff --git a/src/channel/emotes.js b/src/channel/emotes.js index bb073046..31ae3d97 100644 --- a/src/channel/emotes.js +++ b/src/channel/emotes.js @@ -20,6 +20,16 @@ EmoteList.prototype = { this.emotes = Array.prototype.slice.call(emotes); }, + renameEmote: function (emote) { + for (var i = 0; i < this.emotes.length; i++) { + if (this.emotes[i].name === emote.old) { + this.emotes[i] = emote; + delete this.emotes[i].old; + break; + } + } + }, + updateEmote: function (emote) { var found = false; for (var i = 0; i < this.emotes.length; i++) { @@ -118,6 +128,7 @@ EmoteModule.prototype.packInfo = function (data, isAdmin) { }; 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)); @@ -133,6 +144,38 @@ EmoteModule.prototype.sendEmotes = function (users) { }); }; +EmoteModule.prototype.handleRenameEmote = function (user, data) { + if (typeof data !== "object") { + return; + } + + if (!this.channel.modules.permissions.canEditEmotes(user)) { + return; + } + + var f = validateEmote(data); + if (!f) { + var message = "Unable to rename emote '" + JSON.stringify(data) + "'. " + + "Please contact an administrator for assistance."; + if (!data.image || !data.name) { + message = "Emote names and images must not be blank."; + } + + user.socket.emit("errorMsg", { + msg: message, + alert: true + }); + return; + } + + var chan = this.channel; + chan.broadcastAll("renameEmote", f); + chan.logger.log(`[mod] ${user.getName()} renamed emote: ${f.old} -> ${f.name}`); + + // Doing this after the broadcast because this function deletes the "old" prop + this.emotes.renameEmote(f); +}; + EmoteModule.prototype.handleUpdateEmote = function (user, data) { if (typeof data !== "object") { return; diff --git a/www/js/callbacks.js b/www/js/callbacks.js index fbe8f646..550d0ea9 100644 --- a/www/js/callbacks.js +++ b/www/js/callbacks.js @@ -1019,6 +1019,54 @@ Callbacks = { CSEMOTELIST.handleChange(); }, + renameEmote: function (data) { + var badBefore = /\s/g.test(data.old); + var badAfter = /\s/g.test(data.name); + var oldName = data.old; + delete data.old; + + data.regex = new RegExp(data.source, "gi"); + + for (var i = 0; i < CHANNEL.emotes.length; i++) { + if (CHANNEL.emotes[i].name === oldName) { + CHANNEL.emotes[i] = data; + break; + } + } + + // Now bad + if(badAfter){ + // But wasn't bad before: Add it to bad list + if(!badBefore){ + CHANNEL.badEmotes.push(data); + } + // Was bad before too: Update + else { + for (var i = 0; i < CHANNEL.badEmotes.length; i++) { + if (CHANNEL.badEmotes[i].name === oldName) { + CHANNEL.badEmotes[i] = data; + break; + } + } + } + } + // Not bad now + else { + // But was bad before: Drop from list + if(badBefore){ + for (var i = 0; i < CHANNEL.badEmotes.length; i++) { + if (CHANNEL.badEmotes[i].name === oldName) { + CHANNEL.badEmotes.splice(i, 1); + break; + } + } + } + } + + EMOTELIST.handleChange(); + CSEMOTELIST.handleChange(); + }, + removeEmote: function (data) { var found = -1; for (var i = 0; i < CHANNEL.emotes.length; i++) { diff --git a/www/js/util.js b/www/js/util.js index ad1c40b9..370ef3ca 100644 --- a/www/js/util.js +++ b/www/js/util.js @@ -3102,7 +3102,7 @@ CSEmoteList.prototype.loadPage = function (page) { var row = document.createElement("tr"); tbody.appendChild(row); - (function (emote) { + (function (emote, row) { // Add delete button var tdDelete = document.createElement("td"); var btnDelete = document.createElement("button"); @@ -3120,13 +3120,67 @@ CSEmoteList.prototype.loadPage = function (page) { }; // Add emote name - // TODO: editable var tdName = document.createElement("td"); var nameDisplay = document.createElement("code"); nameDisplay.textContent = emote.name; tdName.appendChild(nameDisplay); row.appendChild(tdName); + var $nameDisplay = $(nameDisplay); + $nameDisplay.click(function (clickEvent) { + $nameDisplay.detach(); + + var editInput = document.createElement("input"); + editInput.className = "form-control"; + editInput.type = "text"; + editInput.value = emote.name; + tdName.appendChild(editInput); + editInput.focus(); + + function save() { + var val = editInput.value; + tdName.removeChild(editInput); + tdName.appendChild(nameDisplay); + + // Nothing was changed + if(val === emote.name){ return } + + // Emote name already exists + if( CHANNEL.emotes.filter((emote)=>{ return emote.name === val }).length ){ + /* + * Since we are already in a modal + * and Bootstrap doesn't have supermodals + * we will make a self destructing warning + * as a row in the table + */ + var wrow = document.createElement("tr"); + var tdBlankDel = document.createElement("td"); wrow.appendChild(tdBlankDel); + var tdWarnMess = document.createElement("td"); wrow.appendChild(tdWarnMess); + var warnSpan = document.createElement("p"); tdWarnMess.appendChild(warnSpan); + warnSpan.className = "text-warning"; + warnSpan.textContent = "An emote of that name already exists."; + tdWarnMess.colSpan = "2"; + + row.insertAdjacentElement("beforebegin", wrow) + $(wrow).delay(2500).fadeOut('slow', function(){ $(this).remove() }); + + return; + } + socket.emit("renameEmote", { + old: emote.name, + image: emote.image, + name: val + }); + } + + editInput.onblur = save; + editInput.onkeyup = function (event) { + if (event.keyCode === 13) { + save(); + } + }; + }); + // Add emote image var tdImage = document.createElement("td"); var urlDisplay = document.createElement("code"); @@ -3172,7 +3226,7 @@ CSEmoteList.prototype.loadPage = function (page) { } }; }); - })(this.emotes[i]); + })(this.emotes[i], row); } }; From 8434d20826f6de64c763b17c4633e51e5d107c64 Mon Sep 17 00:00:00 2001 From: Xaekai Date: Tue, 16 May 2017 19:15:12 -0700 Subject: [PATCH 2/3] Fix minor issues with emote rename --- src/channel/emotes.js | 5 ++--- www/js/callbacks.js | 4 ++++ www/js/util.js | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/channel/emotes.js b/src/channel/emotes.js index 31ae3d97..3ebf1411 100644 --- a/src/channel/emotes.js +++ b/src/channel/emotes.js @@ -168,12 +168,11 @@ EmoteModule.prototype.handleRenameEmote = function (user, data) { return; } + this.emotes.renameEmote(Object.assign({}, f)); + var chan = this.channel; chan.broadcastAll("renameEmote", f); chan.logger.log(`[mod] ${user.getName()} renamed emote: ${f.old} -> ${f.name}`); - - // Doing this after the broadcast because this function deletes the "old" prop - this.emotes.renameEmote(f); }; EmoteModule.prototype.handleUpdateEmote = function (user, data) { diff --git a/www/js/callbacks.js b/www/js/callbacks.js index 550d0ea9..d2d1438e 100644 --- a/www/js/callbacks.js +++ b/www/js/callbacks.js @@ -1039,6 +1039,7 @@ Callbacks = { // But wasn't bad before: Add it to bad list if(!badBefore){ CHANNEL.badEmotes.push(data); + delete CHANNEL.emoteMap[oldName]; } // Was bad before too: Update else { @@ -1060,7 +1061,10 @@ Callbacks = { break; } } + } else { + delete CHANNEL.emoteMap[oldName]; } + CHANNEL.emoteMap[data.name] = data; } EMOTELIST.handleChange(); diff --git a/www/js/util.js b/www/js/util.js index 370ef3ca..342ebdfa 100644 --- a/www/js/util.js +++ b/www/js/util.js @@ -3146,7 +3146,7 @@ CSEmoteList.prototype.loadPage = function (page) { if(val === emote.name){ return } // Emote name already exists - if( CHANNEL.emotes.filter((emote)=>{ return emote.name === val }).length ){ + if( CHANNEL.emotes.filter(function(emote){ return emote.name === val }).length ){ /* * Since we are already in a modal * and Bootstrap doesn't have supermodals From 9cfd97088e843adcdbdd162ac178804ed7b5757a Mon Sep 17 00:00:00 2001 From: Xaekai Date: Thu, 18 May 2017 02:55:57 -0700 Subject: [PATCH 3/3] Some validation --- src/channel/emotes.js | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/channel/emotes.js b/src/channel/emotes.js index 3ebf1411..e748286d 100644 --- a/src/channel/emotes.js +++ b/src/channel/emotes.js @@ -20,14 +20,28 @@ EmoteList.prototype = { 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) { @@ -149,17 +163,29 @@ EmoteModule.prototype.handleRenameEmote = function (user, data) { return; } + /* + ** This shouldn't be able to happen, + ** but we have idiots that like to send handcrafted frames to fuck with shit + */ + if (typeof data.old !== "string"){ + return; + } + if (!this.channel.modules.permissions.canEditEmotes(user)) { return; } + var e = this.emotes.emoteExists(data); var f = validateEmote(data); - if (!f) { + if (!f || e) { var message = "Unable to rename emote '" + JSON.stringify(data) + "'. " + "Please contact an administrator for assistance."; if (!data.image || !data.name) { message = "Emote names and images must not be blank."; } + if (e) { + message = "Emote already exists."; + } user.socket.emit("errorMsg", { msg: message, @@ -168,7 +194,9 @@ EmoteModule.prototype.handleRenameEmote = function (user, data) { return; } - this.emotes.renameEmote(Object.assign({}, f)); + // See comment above + var success = this.emotes.renameEmote(Object.assign({}, f)); + if(!success){ return; } var chan = this.channel; chan.broadcastAll("renameEmote", f);