diff --git a/lib/channel-new.js b/lib/channel-new.js
index c6977846..22bf7f67 100644
--- a/lib/channel-new.js
+++ b/lib/channel-new.js
@@ -954,7 +954,7 @@ Channel.prototype.sendChatFilters = function (users) {
return;
}
- u.socket.emit("chatFilters", f);
+ u.socket.emit("chatFilters", pkt);
});
};
@@ -2751,7 +2751,9 @@ Channel.prototype.search = function (query, callback) {
/**
* Sends the result of readLog() to a user if the user has sufficient permission
*/
-Channel.prototype.tryReadLog = function (user) {
+Channel.prototype.handleReadLog = function (user) {
+ var self = this;
+
if (user.rank < 3) {
user.kick("Attempted readChanLog with insufficient permission");
return;
@@ -2766,7 +2768,7 @@ Channel.prototype.tryReadLog = function (user) {
}
var filterIp = user.global_rank < 255;
- this.readLog(filterIp, function (err, data) {
+ self.readLog(filterIp, function (err, data) {
if (err) {
user.socket.emit("readChanLog", {
success: false,
diff --git a/lib/user.js b/lib/user.js
index d09fa97a..beedf05a 100644
--- a/lib/user.js
+++ b/lib/user.js
@@ -360,7 +360,7 @@ User.prototype.initChannelCallbacks = function () {
});
wrapTypecheck("setMotd", function (data) {
- self.channel.handleUpdateMotd(self, data);
+ self.channel.handleSetMotd(self, data);
});
wrapTypecheck("updateFilter", function (data) {
@@ -385,7 +385,7 @@ User.prototype.initChannelCallbacks = function () {
self.channel.sendChannelRanks([self]);
});
- wrap("requestChatFilter", function () {
+ wrap("requestChatFilters", function () {
self.channel.sendChatFilters([self]);
});
diff --git a/templates/channel.jade b/templates/channel.jade
index b8dfaeb3..9a4a3a85 100644
--- a/templates/channel.jade
+++ b/templates/channel.jade
@@ -166,8 +166,10 @@ html(lang="en")
button.close(data-dismiss="modal", aria-hidden="true") ×
h4 Channel Settings
ul.nav.nav-tabs
- li: a(href="#cs-miscoptions" data-toggle="tab") General Settings
- li: a(href="#cs-adminoptions" data-toggle="tab") Admin Settings
+ li: a(href="#cs-miscoptions", data-toggle="tab") General Settings
+ li: a(href="#cs-adminoptions", data-toggle="tab") Admin Settings
+ li: a(href="#cs-chanlog", data-toggle="tab", onclick="javascript:socket.emit('readChanLog')") Channel Log
+ li: a(href="#cs-chatfilters", data-toggle="tab", onclick="javascript:socket.emit('requestChatFilters')") Chat Filters
li.dropdown
a#cs-edit-dd-toggle(href="#", data-toggle="dropdown") Edit
span.caret
@@ -188,6 +190,8 @@ html(lang="en")
mixin banlist()
mixin recentjoins()
mixin chanranks()
+ mixin chatfilters()
+ mixin chanlog()
.modal-footer
button.btn.btn-default(type="button", data-dismiss="modal") Close
include footer
diff --git a/templates/channeloptions.jade b/templates/channeloptions.jade
index 149e6d95..4ffd77a9 100644
--- a/templates/channeloptions.jade
+++ b/templates/channeloptions.jade
@@ -30,9 +30,12 @@ mixin miscoptions
mixin textbox("cs-voteskip_ratio", "Voteskip ratio", "0.5")
mixin textbox("cs-maxlength", "Max video length", "HH:MM:SS")
mixin textbox("cs-afk_timeout", "Auto-AFK Delay", "0 (disabled)")
+ mixin rcheckbox("cs-chat_antiflood", "Throttle chat")
+ mixin textbox("cs-chat_antiflood_burst", "# of messages allowed before throttling")
+ mixin textbox("cs-chat_antiflood_sustained", "# of messages (after burst) allowed per second")
.form-group
.col-sm-8.col-sm-offset-4
- button.btn.btn-default#cs-miscoptionssubmit Save
+ span.text-info Changes are automatically saved.
mixin adminoptions
#cs-adminoptions.tab-pane
@@ -46,28 +49,28 @@ mixin adminoptions
mixin rcheckbox("cs-show_public", "List channel publicly")
.form-group
.col-sm-8.col-sm-offset-4
- button.btn.btn-default#cs-adminoptionssubmit Save
+ span.text-info Changes are automatically saved.
mixin motdeditor
#cs-motdeditor.tab-pane
h4 MOTD editor
p The MOTD can be formatted using a subset of HTML. Tags which attempt to execute Javascript will be removed.
textarea.form-control#cs-motdtext(rows="10")
- button.btn.btn-primary.pull-right#cs-motdsubmit Save MOTD
+ button.btn.btn-primary#cs-motdsubmit Save MOTD
mixin csseditor
#cs-csseditor.tab-pane
h4 CSS editor
p Maximum size 20KB. If more space is required, use the External CSS option under General Settings to link to an externally hosted stylesheet.
textarea.form-control#cs-csstext(rows="10")
- button.btn.btn-primary.pull-right#cs-csssubmit Save CSS
+ button.btn.btn-primary#cs-csssubmit Save CSS
mixin jseditor
#cs-jseditor.tab-pane
h4 JS editor
p Maximum size 20KB. If more space is required, use the External JS option under General Settings to link to an externally hosted stylesheet.
textarea.form-control#cs-jstext(rows="10")
- button.btn.btn-primary.pull-right#cs-jssubmit Save JS
+ button.btn.btn-primary#cs-jssubmit Save JS
mixin banlist
#cs-banlist.tab-pane
@@ -105,3 +108,42 @@ mixin chanranks
tr
th Name
th Rank
+
+mixin chatfilters
+ #cs-chatfilters.tab-pane
+ h4 Chat Filters
+ table.table.table-striped.table-condensed
+ thead
+ tr
+ th Control
+ th Name
+ th Active
+
+mixin chanlog
+ #cs-chanlog.tab-pane
+ h4 Channel Log
+ strong Filter Log:
+ form(role="form", action="javscript:void(0)")
+ .checkbox
+ label Everything
+ input#filter_all(type="checkbox", checked="checked")
+ .checkbox
+ label Chat
+ input#filter_chat(type="checkbox")
+ .checkbox
+ label Polls
+ input#filter_polls(type="checkbox")
+ .checkbox
+ label Playlist actions
+ input#filter_queue(type="checkbox")
+ .checkbox
+ label Bans
+ input#filter_bans(type="checkbox")
+ .checkbox
+ label Channel settings
+ input#filter_channelsettings(type="checkbox")
+ .checkbox
+ label Join/Quit messages
+ input#filter_joinquit(type="checkbox")
+ pre#chanlog_contents(style="max-height: 400px; overflow-y: scroll")
+ button.btn.btn-default#chanlog_refresh Refresh
diff --git a/www/assets/js/callbacks.js b/www/assets/js/callbacks.js
index ad5005cc..8f99d2f3 100644
--- a/www/assets/js/callbacks.js
+++ b/www/assets/js/callbacks.js
@@ -235,155 +235,9 @@ Callbacks = {
},
chatFilters: function(entries) {
- var tbl = $("#filteredit table");
- if(!tbl.hasClass("table")) {
- setTimeout(function() {
- Callbacks.chatFilters(entries);
- }, 100);
- return;
- }
- tbl.find(".filter-row").remove();
- for(var i = 0; i < entries.length; i++) {
- var f = entries[i];
- var tr = $("
").appendTo(tbl).addClass("filter-row");
- var remove = $("").addClass("btn btn-xs btn-danger")
- .appendTo($(" | ").appendTo(tr));
- $("").addClass("glyphicon glyphicon-trash").appendTo(remove);
- var name = $("").text(f.name)
- .appendTo($(" | ").appendTo(tr));
- var regex = $("").text(f.source)
- .appendTo($(" | ").appendTo(tr));
- var flags = $("").text(f.flags)
- .appendTo($(" | ").appendTo(tr));
- var replace = $("").text(f.replace)
- .appendTo($(" | ").appendTo(tr));
- var linktd = $(" | ").appendTo(tr);
- var link = $("").attr("type", "checkbox")
- .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 = $("").addClass("form-control filter-regex-edit")
- .attr("type", "text")
- .css("font-family", "Monospace")
- .attr("placeholder", r)
- .val(r)
- .appendTo(this)
- .focus();
-
- 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("form-control filter-flags-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.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("form-control 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);
- });
-
- 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
- });
- }
- }
- });
+ var tbl = $("#cs-chatfilters table");
+ tbl.data("entries", entries);
+ formatCSChatFilterList();
},
channelOpts: function(opts) {
diff --git a/www/assets/js/ui.js b/www/assets/js/ui.js
index 35f228ee..aa0776c7 100644
--- a/www/assets/js/ui.js
+++ b/www/assets/js/ui.js
@@ -466,6 +466,8 @@ $("#cs-chanranks-owner").click(chanrankSubmit.bind(this, 4));
["#showmediaurl", "#showsearch", "#showcustomembed"].forEach(function (id) {
$(id).click(function () {
$(".plcontrol-collapse").collapse("hide");
+ $("#plcontrol button").button("hide");
+ $(id).button("toggle");
});
});
$(".plcontrol-collapse").collapse();
@@ -493,7 +495,47 @@ $(".cs-textbox").keyup(function () {
}
var data = {};
- data[key] = value;
+ if (key.match(/chat_antiflood_(burst|sustained)/)) {
+ data = {
+ chat_antiflood_params: {
+ burst: $("#cs-chat_antiflood_burst").val(),
+ sustained: $("#cs-chat_antiflood_sustained").val()
+ }
+ };
+ } else {
+ data[key] = value;
+ }
socket.emit("setOptions", data);
}, 1000);
});
+
+$("#chanlog_refresh").click(function () {
+ socket.emit("readChanLog");
+});
+
+$("#cs-chanlog input[type='checkbox']").change(function () {
+ var id = $(this).attr("id");
+ if (id !== "filter_all" && $(this).prop("checked")) {
+ $("#filter_all").prop("checked", false);
+ }
+
+ filterChannelLog();
+});
+
+$("#cs-motdsubmit").click(function () {
+ socket.emit("setMotd", {
+ motd: $("#cs-motdtext").val()
+ });
+});
+
+$("#cs-csssubmit").click(function () {
+ socket.emit("setChannelCSS", {
+ css: $("#cs-csstext").val()
+ });
+});
+
+$("#cs-jssubmit").click(function () {
+ socket.emit("setChannelJS", {
+ js: $("#cs-jstext").val()
+ });
+});
diff --git a/www/assets/js/util.js b/www/assets/js/util.js
index 9abefa27..aa5e6555 100644
--- a/www/assets/js/util.js
+++ b/www/assets/js/util.js
@@ -739,11 +739,10 @@ function handleModPermissions() {
$("#cs-externalcss").attr("disabled", CLIENT.rank < 3);
$("#cs-externaljs").val(CHANNEL.opts.externaljs);
$("#cs-externaljs").attr("disabled", CLIENT.rank < 3);
- /* TODO FIX */
- $("#opt_chat_antiflood").prop("checked", CHANNEL.opts.chat_antiflood);
+ $("#cs-chat_antiflood").prop("checked", CHANNEL.opts.chat_antiflood);
if ("chat_antiflood_params" in CHANNEL.opts) {
- $("#opt_chat_antiflood_burst").val(CHANNEL.opts.chat_antiflood_params.burst);
- $("#opt_chat_antiflood_sustained").val(CHANNEL.opts.chat_antiflood_params.sustained);
+ $("#cs-chat_antiflood_burst").val(CHANNEL.opts.chat_antiflood_params.burst);
+ $("#cs-chat_antiflood_sustained").val(CHANNEL.opts.chat_antiflood_params.sustained);
}
$("#cs-show_public").prop("checked", CHANNEL.opts.show_public);
$("#cs-show_public").attr("disabled", CLIENT.rank < 3);
@@ -1814,3 +1813,71 @@ function formatCSBanlist() {
}
});
}
+
+function formatCSChatFilterList() {
+ var tbl = $("#cs-chatfilters table");
+ tbl.find("tbody").remove();
+ tbl.find(".ui-sortable").remove();
+ var entries = tbl.data("entries") || [];
+ entries.forEach(function (f) {
+ var tr = $("
").appendTo(tbl);
+ var control = $("").addClass("btn btn-xs btn-default")
+ .attr("title", "Edit this filter")
+ .appendTo($(" | ").appendTo(tr));
+ $("").addClass("glyphicon glyphicon-list").appendTo(control);
+ var name = $("").text(f.name).appendTo($(" | ").appendTo(tr));
+ var activetd = $(" | ").appendTo(tr);
+ var active = $("").attr("type", "checkbox")
+ .prop("checked", f.active)
+ .appendTo(activetd)
+ .change(function () {
+ f.active = $(this).prop("checked");
+ socket.emit("updateFilter", f);
+ });
+
+ control.click(function () {
+ var tr2 = $("
").insertAfter(tr);
+ var wrap = $(" | ").attr("colspan", "3").appendTo(tr2);
+ var form = $("").addClass("form-inline").attr("role", "form")
+ .attr("action", "javascript:void(0)")
+ .appendTo(wrap);
+ var addTextbox = function (placeholder) {
+ var div = $("").addClass("form-group").appendTo(form)
+ .css("margin-right", "10px")
+ .css("max-width", "25%");
+ var input = $("").addClass("form-control")
+ .attr("type", "text")
+ .attr("placeholder", placeholder)
+ .attr("title", placeholder)
+ .appendTo(div);
+ return input;
+ };
+
+ var regex = addTextbox("Filter regex").val(f.source);
+ var flags = addTextbox("Regex flags").val(f.flags);
+ var replace = addTextbox("Replacement text").val(f.replace);
+
+ var checkwrap = $("").addClass("checkbox").appendTo(form);
+ var checklbl = $("").text("Filter Links").appendTo(checkwrap);
+ $("").attr("type", "checkbox").prependTo(checklbl);
+
+ var save = $("").addClass("btn btn-xs btn-success")
+ .insertAfter(control);
+ $("").addClass("glyphicon glyphicon-save").appendTo(save);
+ });
+ });
+ $(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
+ });
+ }
+ }
+ });
+}
diff --git a/www/css/cytube.css b/www/css/cytube.css
index e0901490..f59bcc9c 100644
--- a/www/css/cytube.css
+++ b/www/css/cytube.css
@@ -484,6 +484,14 @@
font-family: Monospace;
}
-#cs-csssubmit, #cs-motdsubmit, #cs-jssubmit {
- margin: 10px 0;
+#cs-csstext, #cs-jstext, #cs-motdtext {
+ font-family: Monospace;
+}
+
+#cs-csssubmit, #cs-motdsubmit, #cs-jssubmit {
+ margin-top: 10px;
+}
+
+#cs-chatfilters input[type='text'] {
+ font-family: Monospace;
}