diff --git a/channel.js b/channel.js index 72444dce..7d794f72 100644 --- a/channel.js +++ b/channel.js @@ -1491,17 +1491,32 @@ Channel.prototype.tryToggleLock = function(user) { this.setLock(this.openqueue); } +Channel.prototype.tryRemoveFilter = function(user, f) { + if(!this.hasPermission(user, "filteredit")) + return false; + + this.removeFilter(f); +} + +Channel.prototype.removeFilter = function(filter) { + for(var i = 0; i < this.filters.length; i++) { + if(this.filters[i].name == filter.name) { + this.filters.splice(i, 1); + break; + } + } + this.broadcastChatFilters(); +} + Channel.prototype.updateFilter = function(filter) { + if(filter.name == "") + filter.name = filter.source; var found = false; for(var i = 0; i < this.filters.length; i++) { - if(this.filters[i].name == "" && filter.name == "" - && this.filters[i].source == filter.source) { - found = true; - this.filters[i] = filter; - } - else if(filter.name != "" && this.filters[i].name == filter.name) { + if(this.filters[i].name == filter.name) { found = true; this.filters[i] = filter; + break; } } if(!found) { @@ -1510,45 +1525,45 @@ Channel.prototype.updateFilter = function(filter) { this.broadcastChatFilters(); } -Channel.prototype.removeFilter = function(name, source) { - for(var i = 0; i < this.filters.length; i++) { - if(this.filters[i].name == name - && this.filters[i].source == source) { - this.filters.splice(i, 1); - break; - } - } - this.broadcastChatFilters(); -} - -Channel.prototype.tryChangeFilter = function(user, data) { +Channel.prototype.tryUpdateFilter = function(user, f) { if(!this.hasPermission(user, "filteredit")) { return; } - if(data.cmd == undefined || data.filter == undefined) { + var re = f.source; + var flags = f.flags; + try { + new RegExp(re, flags); + } + catch(e) { return; } + var filter = new Filter(f.name, f.source, f.flags, f.replace); + filter.active = f.active; + filter.filterlinks = f.filterlinks; + this.updateFilter(filter); +} - if(data.cmd == "update") { - var re = data.filter.source; - var flags = data.filter.flags; - try { - new RegExp(re, flags); - } - catch(e) { - return; - } - var f = new Filter(data.filter.name, - data.filter.source, - data.filter.flags, - data.filter.replace); - f.active = data.filter.active; - this.updateFilter(f); - } - else if(data.cmd == "remove") { - this.removeFilter(data.filter.name, data.filter.source); +Channel.prototype.moveFilter = function(data) { + if(data.from < 0 || data.to < 0 || data.from >= this.filters.length || + data.to > this.filters.length) { + return; } + var f = this.filters[data.from]; + var to = data.to > data.from ? data.to + 1 : data.to; + var from = data.to > data.from ? data.from : data.from + 1; + this.filters.splice(to, 0, f); + this.filters.splice(from, 1); + this.broadcastChatFilters(); +} + +Channel.prototype.tryMoveFilter = function(user, data) { + if(!this.hasPermission(user, "filteredit")) + return; + + if(typeof data.to !== "number" || typeof data.from !== "number") + return; + this.moveFilter(data); } Channel.prototype.tryUpdatePermissions = function(user, perms) { @@ -1676,6 +1691,11 @@ Channel.prototype.filterMessage = function(msg) { for(var j = 0; j < subs.length; j++) { if(this.opts.enable_link_regex && subs[j].match(link)) { subs[j] = subs[j].replace(link, "$1"); + for(var i = 0; i < this.filters.length; i++) { + if(!this.filters[i].filterlinks || !this.filters[i].active) + continue; + subs[j] = this.filters[i].filter(subs[j]); + } continue; } for(var i = 0; i < this.filters.length; i++) { diff --git a/filter.js b/filter.js index c2586abf..f7213fe1 100644 --- a/filter.js +++ b/filter.js @@ -16,6 +16,7 @@ var Filter = function(name, regex, flags, replace) { this.regex = new RegExp(this.source, this.flags); this.replace = replace; this.active = true; + this.filterlinks = false; } Filter.prototype.pack = function() { @@ -24,7 +25,8 @@ Filter.prototype.pack = function() { source: this.source, flags: this.flags, replace: this.replace, - active: this.active + active: this.active, + filterlinks: this.filterlinks } } diff --git a/user.js b/user.js index 2dbcc6ab..97f75dc3 100644 --- a/user.js +++ b/user.js @@ -367,9 +367,21 @@ User.prototype.initCallbacks = function() { } }.bind(this)); - this.socket.on("chatFilter", function(data) { + this.socket.on("updateFilter", function(data) { if(this.channel != null) { - this.channel.tryChangeFilter(this, data); + this.channel.tryUpdateFilter(this, data); + } + }.bind(this)); + + this.socket.on("removeFilter", function(data) { + if(this.channel != null) { + this.channel.tryRemoveFilter(this, data); + } + }.bind(this)); + + this.socket.on("moveFilter", function(data) { + if(this.channel != null) { + this.channel.tryMoveFilter(this, data); } }.bind(this)); diff --git a/www/assets/css/ytsync.css b/www/assets/css/ytsync.css index beb002b6..f2b1682c 100644 --- a/www/assets/css/ytsync.css +++ b/www/assets/css/ytsync.css @@ -154,7 +154,7 @@ html, body { border-left: 0; } -#messagebuffer div, #messagebuffer code { +#messagebuffer div, #messagebuffer code, #filteredit code { white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ @@ -162,6 +162,10 @@ html, body { word-wrap: break-word; /* Internet Explorer 5.5+ */ } +#filteredit td { + max-width: 200px; +} + .userlist_siteadmin { color: #cc0000; font-weight: bold; diff --git a/www/assets/js/callbacks.js b/www/assets/js/callbacks.js index 264784a0..f624966a 100644 --- a/www/assets/js/callbacks.js +++ b/www/assets/js/callbacks.js @@ -133,34 +133,133 @@ Callbacks = { .appendTo($("").appendTo(tr)); var linktd = $("").appendTo(tr); var link = $("").attr("type", "checkbox") - .prop("checked", false).appendTo(linktd); + .prop("checked", f.filterlinks).appendTo(linktd); var activetd = $("").appendTo(tr); var active = $("").attr("type", "checkbox") .prop("checked", f.active).appendTo(activetd); + (function(f) { + regex.click(function() { + if(this.find(".filter-regex-edit").length > 0) + return; + var r = this.text(); + this.text(""); + var edit = $("").attr("type", "text") + .css("font-family", "Monospace") + .attr("placeholder", r) + .val(r) + .addClass("filter-regex-edit") + .appendTo(this) + .focus(); - var remcallback = (function(filter) { return function() { - socket.emit("chatFilter", { - cmd: "remove", - filter: filter - }); - } })(f); - remove.click(remcallback); + function save() { + var r = this.val(); + var r2 = r; + if(r.trim() == "") + r = this.attr("placeholder"); + this.parent().text(r); + f.source = r; + socket.emit("updateFilter", f); + } + edit.blur(save.bind(edit)); + edit.keydown(function(ev) { + if(ev.keyCode == 13) + save.bind(edit)(); + }); + }.bind(regex)); + flags.click(function() { + if(this.find(".filter-flags-edit").length > 0) + return; + var r = this.text(); + this.text(""); + var edit = $("").attr("type", "text") + .css("font-family", "Monospace") + .attr("placeholder", r) + .val(r) + .addClass("filter-flags-edit") + .appendTo(this) + .focus(); - var actcallback = (function(filter) { return function() { - // Apparently when you check a checkbox, its value is changed - // before this callback. When you uncheck it, its value is not - // changed before this callback - // [](/amgic) - var enabled = active.prop("checked"); - filter.active = (filter.active == enabled) ? !enabled : enabled; - socket.emit("chatFilter", { - cmd: "update", - filter: filter + function save() { + var r = this.val(); + var r2 = r; + if(r.trim() == "") + r = this.attr("placeholder"); + this.parent().text(r); + f.flags = r; + socket.emit("updateFilter", f); + } + edit.blur(save.bind(edit)); + edit.keydown(function(ev) { + if(ev.keyCode == 13) + save.bind(edit)(); + }); + }.bind(flags)); + replace.click(function() { + if(this.find(".filter-replace-edit").length > 0) + return; + var r = this.text(); + this.text(""); + var edit = $("").attr("type", "text") + .css("font-family", "Monospace") + .attr("placeholder", r) + .val(r) + .addClass("filter-replace-edit") + .appendTo(this) + .focus(); + + function save() { + var r = this.val(); + var r2 = r; + if(r.trim() == "") + r = this.attr("placeholder"); + this.parent().text(r); + f.replace = r; + socket.emit("updateFilter", f); + } + edit.blur(save.bind(edit)); + edit.keydown(function(ev) { + if(ev.keyCode == 13) + save.bind(edit)(); + }); + }.bind(replace)); + + remove.click(function() { + socket.emit("removeFilter", f); }); - } })(f); - active.click(actcallback); + + active.click(function() { + // Apparently when you check a checkbox, its value is changed + // before this callback. When you uncheck it, its value is not + // changed before this callback + // [](/amgic) + var enabled = active.prop("checked"); + f.active = (f.active == enabled) ? !enabled : enabled; + socket.emit("updateFilter", f); + }); + link.click(function() { + var enabled = link.prop("checked"); + f.filterlinks = (f.filterlinks == enabled) ? !enabled : enabled; + socket.emit("updateFilter", f); + }); + })(f); } + $(tbl.children()[1]).sortable({ + start: function(ev, ui) { + FILTER_FROM = ui.item.prevAll().length; + }, + update: function(ev, ui) { + FILTER_TO = ui.item.prevAll().length; + if(FILTER_TO != FILTER_FROM) { + socket.emit("moveFilter", { + from: FILTER_FROM, + to: FILTER_TO + }); + console.log("moveFilter", FILTER_FROM, FILTER_TO); + } + } + }); + var newfilt = $("");//.appendTo(tbl); $("").appendTo(newfilt); var name = $("").attr("type", "text") diff --git a/www/assets/js/data.js b/www/assets/js/data.js index 7a4c32b0..fe50c3b3 100644 --- a/www/assets/js/data.js +++ b/www/assets/js/data.js @@ -42,6 +42,8 @@ var SESSION = readCookie("cytube_session"); var LEADTMR = false; var PL_FROM = 0; var PL_TO = 0; +var FILTER_FROM = 0; +var FILTER_TO = 0; function getOrDefault(k, def) { var v = localStorage.getItem(k); diff --git a/www/channeloptions.html b/www/channeloptions.html index fc77ad43..148d1dd7 100644 --- a/www/channeloptions.html +++ b/www/channeloptions.html @@ -91,6 +91,7 @@
+

Filters will be processed in the order that they are listed here. Click and drag a row to rearrange the order. Click a regex, flags, or replacement field to edit a filter. Changes are automatically saved when you finish editing.