mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-29 07:45:33 +00:00
Added "/ffz log" command to upload logs to pastebin. Added extra error handling in Ember-facing code. Added settings menu categories. Added user name color adjustment. Added support for better moderation cards. Added support for extra moderation commands. Fixed menu size limit. Fixed typo in show_message RPC. Fixed CSS for UI button.
This commit is contained in:
parent
fe55f43b8e
commit
b90a25d794
19 changed files with 1788 additions and 676 deletions
4
script.min.js
vendored
4
script.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -1,11 +1,25 @@
|
||||||
var FFZ = window.FrankerFaceZ;
|
var FFZ = window.FrankerFaceZ;
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------
|
||||||
|
// Log Export
|
||||||
|
// -----------------
|
||||||
|
|
||||||
|
FFZ.ffz_commands.log = function(room, args) {
|
||||||
|
this._pastebin(this._log_data.join("\n"), function(url) {
|
||||||
|
if ( ! url )
|
||||||
|
return this.room_message(room, "There was an error uploading the FrankerFaceZ log.");
|
||||||
|
|
||||||
|
this.room_message(room, "Your FrankerFaceZ log has been pasted to: " + url);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// -----------------
|
// -----------------
|
||||||
// Mass Moderation
|
// Mass Moderation
|
||||||
// -----------------
|
// -----------------
|
||||||
|
|
||||||
FFZ.chat_commands.massunmod = function(room, args) {
|
FFZ.ffz_commands.massunmod = function(room, args) {
|
||||||
args = args.join(" ").trim();
|
args = args.join(" ").trim();
|
||||||
|
|
||||||
if ( ! args.length )
|
if ( ! args.length )
|
||||||
|
@ -29,10 +43,10 @@ FFZ.chat_commands.massunmod = function(room, args) {
|
||||||
return "Sent unmod command for " + count + " users.";
|
return "Sent unmod command for " + count + " users.";
|
||||||
}
|
}
|
||||||
|
|
||||||
FFZ.chat_commands.massunmod.help = "Usage: /ffz massunmod <list, of, users>\nBroadcaster only. Unmod all the users in the provided list.";
|
FFZ.ffz_commands.massunmod.help = "Usage: /ffz massunmod <list, of, users>\nBroadcaster only. Unmod all the users in the provided list.";
|
||||||
|
|
||||||
|
|
||||||
FFZ.chat_commands.massmod = function(room, args) {
|
FFZ.ffz_commands.massmod = function(room, args) {
|
||||||
args = args.join(" ").trim();
|
args = args.join(" ").trim();
|
||||||
|
|
||||||
if ( ! args.length )
|
if ( ! args.length )
|
||||||
|
@ -47,7 +61,6 @@ FFZ.chat_commands.massmod = function(room, args) {
|
||||||
if ( args.length > 50 )
|
if ( args.length > 50 )
|
||||||
return "Each user you mod counts as a single message. To avoid being globally banned, please limit yourself to 50 at a time and wait between uses.";
|
return "Each user you mod counts as a single message. To avoid being globally banned, please limit yourself to 50 at a time and wait between uses.";
|
||||||
|
|
||||||
|
|
||||||
var count = args.length;
|
var count = args.length;
|
||||||
while(args.length) {
|
while(args.length) {
|
||||||
var name = args.shift();
|
var name = args.shift();
|
||||||
|
@ -57,4 +70,4 @@ FFZ.chat_commands.massmod = function(room, args) {
|
||||||
return "Sent mod command for " + count + " users.";
|
return "Sent mod command for " + count + " users.";
|
||||||
}
|
}
|
||||||
|
|
||||||
FFZ.chat_commands.massmod.help = "Usage: /ffz massmod <list, of, users>\nBroadcaster only. Mod all the users in the provided list.";
|
FFZ.ffz_commands.massmod.help = "Usage: /ffz massmod <list, of, users>\nBroadcaster only. Mod all the users in the provided list.";
|
|
@ -5,7 +5,7 @@ var FFZ = window.FrankerFaceZ;
|
||||||
// Developer Mode Command
|
// Developer Mode Command
|
||||||
// -----------------------
|
// -----------------------
|
||||||
|
|
||||||
FFZ.chat_commands.developer_mode = function(room, args) {
|
FFZ.ffz_commands.developer_mode = function(room, args) {
|
||||||
var enabled, args = args && args.length ? args[0].toLowerCase() : null;
|
var enabled, args = args && args.length ? args[0].toLowerCase() : null;
|
||||||
if ( args == "y" || args == "yes" || args == "true" || args == "on" )
|
if ( args == "y" || args == "yes" || args == "true" || args == "on" )
|
||||||
enabled = true;
|
enabled = true;
|
||||||
|
@ -19,4 +19,4 @@ FFZ.chat_commands.developer_mode = function(room, args) {
|
||||||
return "Developer Mode is now " + (enabled ? "enabled" : "disabled") + ". Please refresh your browser.";
|
return "Developer Mode is now " + (enabled ? "enabled" : "disabled") + ". Please refresh your browser.";
|
||||||
}
|
}
|
||||||
|
|
||||||
FFZ.chat_commands.developer_mode.help = "Usage: /ffz developer_mode <on|off>\nEnable or disable Developer Mode. When Developer Mode is enabled, the script will be reloaded from //localhost:8000/script.js instead of from the CDN.";
|
FFZ.ffz_commands.developer_mode.help = "Usage: /ffz developer_mode <on|off>\nEnable or disable Developer Mode. When Developer Mode is enabled, the script will be reloaded from //localhost:8000/script.js instead of from the CDN.";
|
||||||
|
|
|
@ -25,7 +25,11 @@ FFZ.prototype.setup_chatview = function() {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
this.log("Adding UI link manually to Chat view.", view);
|
this.log("Adding UI link manually to Chat view.", view);
|
||||||
view.$('.textarea-contain').append(this.build_ui_link(view));
|
try {
|
||||||
|
view.$('.textarea-contain').append(this.build_ui_link(view));
|
||||||
|
} catch(err) {
|
||||||
|
this.error("setup: build_ui_link: " + err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,16 +44,28 @@ FFZ.prototype._modify_cview = function(view) {
|
||||||
view.reopen({
|
view.reopen({
|
||||||
didInsertElement: function() {
|
didInsertElement: function() {
|
||||||
this._super();
|
this._super();
|
||||||
this.$() && this.$('.textarea-contain').append(f.build_ui_link(this));
|
try {
|
||||||
|
this.$() && this.$('.textarea-contain').append(f.build_ui_link(this));
|
||||||
|
} catch(err) {
|
||||||
|
f.error("didInsertElement: build_ui_link: " + err);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
willClearRender: function() {
|
willClearRender: function() {
|
||||||
this._super();
|
this._super();
|
||||||
this.$(".ffz-ui-toggle").remove();
|
try {
|
||||||
|
this.$(".ffz-ui-toggle").remove();
|
||||||
|
} catch(err) {
|
||||||
|
f.error("willClearRender: remove ui link: " + err);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzUpdateLink: Ember.observer('controller.currentRoom', function() {
|
ffzUpdateLink: Ember.observer('controller.currentRoom', function() {
|
||||||
f.update_ui_link();
|
try {
|
||||||
|
f.update_ui_link();
|
||||||
|
} catch(err) {
|
||||||
|
f.error("ffzUpdateLink: update_ui_link: " + err);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
var FFZ = window.FrankerFaceZ,
|
var FFZ = window.FrankerFaceZ,
|
||||||
|
utils = require("../utils"),
|
||||||
|
|
||||||
reg_escape = function(str) {
|
reg_escape = function(str) {
|
||||||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||||
|
@ -13,6 +14,7 @@ FFZ.settings_info.capitalize = {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: true,
|
value: true,
|
||||||
|
|
||||||
|
category: "Chat",
|
||||||
visible: function() { return ! this.has_bttv },
|
visible: function() { return ! this.has_bttv },
|
||||||
|
|
||||||
name: "Username Capitalization",
|
name: "Username Capitalization",
|
||||||
|
@ -24,6 +26,7 @@ FFZ.settings_info.keywords = {
|
||||||
type: "button",
|
type: "button",
|
||||||
value: [],
|
value: [],
|
||||||
|
|
||||||
|
category: "Chat",
|
||||||
visible: function() { return ! this.has_bttv },
|
visible: function() { return ! this.has_bttv },
|
||||||
|
|
||||||
name: "Highlight Keywords",
|
name: "Highlight Keywords",
|
||||||
|
@ -33,7 +36,7 @@ FFZ.settings_info.keywords = {
|
||||||
var old_val = this.settings.keywords.join(", "),
|
var old_val = this.settings.keywords.join(", "),
|
||||||
new_val = prompt("Highlight Keywords\n\nPlease enter a comma-separated list of words that you would like to be highlighted in chat.", old_val);
|
new_val = prompt("Highlight Keywords\n\nPlease enter a comma-separated list of words that you would like to be highlighted in chat.", old_val);
|
||||||
|
|
||||||
if ( ! new_val )
|
if ( new_val === null || new_val === undefined )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Split them up.
|
// Split them up.
|
||||||
|
@ -47,17 +50,40 @@ FFZ.settings_info.keywords = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.settings_info.fix_color = {
|
||||||
|
type: "boolean",
|
||||||
|
value: false,
|
||||||
|
|
||||||
|
category: "Chat",
|
||||||
|
visible: function() { return ! this.has_bttv },
|
||||||
|
|
||||||
|
name: "Adjust Username Colors",
|
||||||
|
help: "Ensure that username colors contrast with the background enough to be readable.",
|
||||||
|
|
||||||
|
on_update: function(val) {
|
||||||
|
if ( this.has_bttv )
|
||||||
|
return;
|
||||||
|
|
||||||
|
document.body.classList.toggle("ffz-chat-colors", val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
FFZ.settings_info.chat_rows = {
|
FFZ.settings_info.chat_rows = {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: false,
|
value: false,
|
||||||
|
|
||||||
|
category: "Chat",
|
||||||
visible: function() { return ! this.has_bttv },
|
visible: function() { return ! this.has_bttv },
|
||||||
|
|
||||||
name: "Chat Line Backgrounds",
|
name: "Chat Line Backgrounds",
|
||||||
help: "Display alternating background colors for lines in chat.",
|
help: "Display alternating background colors for lines in chat.",
|
||||||
|
|
||||||
on_update: function(val) {
|
on_update: function(val) {
|
||||||
document.querySelector(".app-main").classList.toggle("ffz-chat-background", val);
|
if ( this.has_bttv )
|
||||||
|
return;
|
||||||
|
|
||||||
|
document.body.classList.toggle("ffz-chat-background", val);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,10 +93,19 @@ FFZ.settings_info.chat_rows = {
|
||||||
// ---------------------
|
// ---------------------
|
||||||
|
|
||||||
FFZ.prototype.setup_line = function() {
|
FFZ.prototype.setup_line = function() {
|
||||||
// Alternating Background
|
// Chat Enhancements
|
||||||
document.querySelector('.app-main').classList.toggle('ffz-chat-background', this.settings.chat_rows);
|
document.body.classList.toggle("ffz-chat-colors", !this.has_bttv && this.settings.fix_color);
|
||||||
|
document.body.classList.toggle('ffz-chat-background', !this.has_bttv && this.settings.chat_rows);
|
||||||
|
|
||||||
|
this._colors = {};
|
||||||
this._last_row = {};
|
this._last_row = {};
|
||||||
|
|
||||||
|
var s = this._fix_color_style = document.createElement('style');
|
||||||
|
s.id = "ffz-style-username-colors";
|
||||||
|
s.type = 'text/css';
|
||||||
|
document.head.appendChild(s);
|
||||||
|
|
||||||
|
|
||||||
this.log("Hooking the Ember Line controller.");
|
this.log("Hooking the Ember Line controller.");
|
||||||
|
|
||||||
var Line = App.__container__.resolve('controller:line'),
|
var Line = App.__container__.resolve('controller:line'),
|
||||||
|
@ -79,11 +114,20 @@ FFZ.prototype.setup_line = function() {
|
||||||
Line.reopen({
|
Line.reopen({
|
||||||
tokenizedMessage: function() {
|
tokenizedMessage: function() {
|
||||||
// Add our own step to the tokenization procedure.
|
// Add our own step to the tokenization procedure.
|
||||||
var tokens = f._emoticonize(this, this._super()),
|
var tokens = this._super();
|
||||||
user = f.get_user();
|
|
||||||
|
|
||||||
if ( ! user || this.get("model.from") != user.login )
|
try {
|
||||||
tokens = f._mentionize(this, tokens);
|
tokens = f._emoticonize(this, tokens);
|
||||||
|
var user = f.get_user();
|
||||||
|
|
||||||
|
if ( ! user || this.get("model.from") != user.login )
|
||||||
|
tokens = f._mentionize(this, tokens);
|
||||||
|
|
||||||
|
} catch(err) {
|
||||||
|
try {
|
||||||
|
f.error("LineController tokenizedMessage: " + err);
|
||||||
|
} catch(err) { }
|
||||||
|
}
|
||||||
|
|
||||||
return tokens;
|
return tokens;
|
||||||
|
|
||||||
|
@ -97,60 +141,84 @@ FFZ.prototype.setup_line = function() {
|
||||||
Line.reopen({
|
Line.reopen({
|
||||||
didInsertElement: function() {
|
didInsertElement: function() {
|
||||||
this._super();
|
this._super();
|
||||||
|
try {
|
||||||
|
var el = this.get('element'),
|
||||||
|
user = this.get('context.model.from'),
|
||||||
|
room = this.get('context.parentController.content.id'),
|
||||||
|
color = this.get('context.model.color'),
|
||||||
|
|
||||||
var el = this.get('element'),
|
row_type = this.get('context.model.ffz_alternate');
|
||||||
user = this.get('context.model.from'),
|
|
||||||
room = this.get('context.parentController.content.id'),
|
|
||||||
row_type = this.get('context.model.ffzAlternate');
|
|
||||||
|
|
||||||
if ( row_type === undefined ) {
|
|
||||||
row_type = f._last_row[room] = f._last_row.hasOwnProperty(room) ? !f._last_row[room] : false;
|
|
||||||
this.set("context.model.ffzAlternate", row_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
el.classList.toggle('ffz-alternate', row_type);
|
// Color Processing
|
||||||
el.setAttribute('data-room', room);
|
if ( color )
|
||||||
el.setAttribute('data-sender', user);
|
f._handle_color(color);
|
||||||
|
|
||||||
f.render_badge(this);
|
|
||||||
|
|
||||||
if ( f.settings.capitalize )
|
// Row Alternation
|
||||||
f.capitalize(this, user);
|
if ( row_type === undefined ) {
|
||||||
|
row_type = f._last_row[room] = f._last_row.hasOwnProperty(room) ? !f._last_row[room] : false;
|
||||||
// Check for any mentions.
|
this.set("context.model.ffz_alternate", row_type);
|
||||||
var mentioned = el.querySelector('span.mentioned');
|
|
||||||
if ( mentioned ) {
|
|
||||||
el.classList.add("ffz-mentioned");
|
|
||||||
|
|
||||||
if ( ! document.hasFocus() && ! this.get('context.model.ffzNotified') && f.settings.highlight_notifications ) {
|
|
||||||
var cap_room = FFZ.get_capitalization(room),
|
|
||||||
cap_user = FFZ.get_capitalization(user),
|
|
||||||
room_name = cap_room,
|
|
||||||
msg = this.get("context.model.message");
|
|
||||||
|
|
||||||
if ( this.get("context.parentController.content.isGroupRoom") )
|
|
||||||
room_name = this.get("context.parentController.content.tmiRoom.displayName");
|
|
||||||
|
|
||||||
if ( this.get("context.model.style") == "action" )
|
|
||||||
msg = "* " + cap_user + " " + msg;
|
|
||||||
else
|
|
||||||
msg = cap_user + ": " + msg;
|
|
||||||
|
|
||||||
f.show_notification(
|
|
||||||
msg,
|
|
||||||
"Twitch Chat Mention in " + room_name,
|
|
||||||
cap_room,
|
|
||||||
60000,
|
|
||||||
window.focus.bind(window)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Mark that we've checked this message for mentions.
|
el.classList.toggle('ffz-alternate', row_type);
|
||||||
this.set('context.model.ffzNotified', true);
|
|
||||||
|
|
||||||
|
// Basic Data
|
||||||
|
el.setAttribute('data-room', room);
|
||||||
|
el.setAttribute('data-sender', user);
|
||||||
|
|
||||||
|
|
||||||
|
// Badge
|
||||||
|
f.render_badge(this);
|
||||||
|
|
||||||
|
|
||||||
|
// Capitalization
|
||||||
|
if ( f.settings.capitalize )
|
||||||
|
f.capitalize(this, user);
|
||||||
|
|
||||||
|
|
||||||
|
// Mention Highlighting
|
||||||
|
var mentioned = el.querySelector('span.mentioned');
|
||||||
|
if ( mentioned ) {
|
||||||
|
el.classList.add("ffz-mentioned");
|
||||||
|
|
||||||
|
if ( ! document.hasFocus() && ! this.get('context.model.ffz_notified') && f.settings.highlight_notifications ) {
|
||||||
|
var cap_room = FFZ.get_capitalization(room),
|
||||||
|
cap_user = FFZ.get_capitalization(user),
|
||||||
|
room_name = cap_room,
|
||||||
|
msg = this.get("context.model.message");
|
||||||
|
|
||||||
|
if ( this.get("context.parentController.content.isGroupRoom") )
|
||||||
|
room_name = this.get("context.parentController.content.tmiRoom.displayName");
|
||||||
|
|
||||||
|
if ( this.get("context.model.style") == "action" )
|
||||||
|
msg = "* " + cap_user + " " + msg;
|
||||||
|
else
|
||||||
|
msg = cap_user + ": " + msg;
|
||||||
|
|
||||||
|
f.show_notification(
|
||||||
|
msg,
|
||||||
|
"Twitch Chat Mention in " + room_name,
|
||||||
|
cap_room,
|
||||||
|
60000,
|
||||||
|
window.focus.bind(window)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark that we've checked this message for mentions.
|
||||||
|
this.set('context.model.ffz_notified', true);
|
||||||
|
|
||||||
|
} catch(err) {
|
||||||
|
try {
|
||||||
|
f.error("LineView didInsertElement: " + err);
|
||||||
|
} catch(err) { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Store the capitalization of our own name.
|
// Store the capitalization of our own name.
|
||||||
var user = this.get_user();
|
var user = this.get_user();
|
||||||
if ( user && user.name )
|
if ( user && user.name )
|
||||||
|
@ -158,6 +226,69 @@ FFZ.prototype.setup_line = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------
|
||||||
|
// Fix Name Colors
|
||||||
|
// ---------------------
|
||||||
|
|
||||||
|
FFZ.prototype._handle_color = function(color) {
|
||||||
|
if ( ! color || this._colors[color] )
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._colors[color] = true;
|
||||||
|
|
||||||
|
// Parse the color.
|
||||||
|
var raw = parseInt(color.substr(1), 16),
|
||||||
|
rgb = [
|
||||||
|
(raw >> 16),
|
||||||
|
(raw >> 8 & 0x00FF),
|
||||||
|
(raw & 0x0000FF)
|
||||||
|
],
|
||||||
|
|
||||||
|
lum = utils.get_luminance(rgb),
|
||||||
|
|
||||||
|
output = "",
|
||||||
|
rule = 'span[style="color:' + color + '"]',
|
||||||
|
matched = false;
|
||||||
|
|
||||||
|
if ( lum > 0.3 ) {
|
||||||
|
// Color Too Bright. We need a lum of 0.3 or less.
|
||||||
|
matched = true;
|
||||||
|
|
||||||
|
var s = 255,
|
||||||
|
nc = rgb;
|
||||||
|
while(s--) {
|
||||||
|
nc = utils.darken(nc);
|
||||||
|
if ( utils.get_luminance(nc) <= 0.3 )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
output += '.ffz-chat-colors .ember-chat-container:not(.dark) .chat-line ' + rule + ', .ffz-chat-colors .chat-container:not(.dark) .chat-line ' + rule + ' { color: ' + utils.rgb_to_css(nc) + ' !important; }\n';
|
||||||
|
} else
|
||||||
|
output += '.ffz-chat-colors .ember-chat-container:not(.dark) .chat-line ' + rule + ', .ffz-chat-colors .chat-container:not(.dark) .chat-line ' + rule + ' { color: ' + color + ' !important; }\n';
|
||||||
|
|
||||||
|
if ( lum < 0.1 ) {
|
||||||
|
// Color Too Dark. We need a lum of 0.1 or more.
|
||||||
|
matched = true;
|
||||||
|
|
||||||
|
var s = 255,
|
||||||
|
nc = rgb;
|
||||||
|
while(s--) {
|
||||||
|
nc = utils.brighten(nc);
|
||||||
|
if ( utils.get_luminance(nc) >= 0.1 )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
output += '.ffz-chat-colors .theatre .chat-container .chat-line ' + rule + ', .ffz-chat-colors .chat-container.dark .chat-line ' + rule + ', .ffz-chat-colors .ember-chat-container.dark .chat-line ' + rule + ' { color: ' + utils.rgb_to_css(nc) + ' !important; }\n';
|
||||||
|
} else
|
||||||
|
output += '.ffz-chat-colors .theatre .chat-container .chat-line ' + rule + ', .ffz-chat-colors .chat-container.dark .chat-line ' + rule + ', .ffz-chat-colors .ember-chat-container.dark .chat-line ' + rule + ' { color: ' + color + ' !important; }\n';
|
||||||
|
|
||||||
|
|
||||||
|
if ( matched )
|
||||||
|
this._fix_color_style.innerHTML += output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ---------------------
|
// ---------------------
|
||||||
// Capitalization
|
// Capitalization
|
||||||
// ---------------------
|
// ---------------------
|
||||||
|
@ -205,30 +336,13 @@ FFZ.prototype.capitalize = function(view, user) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.chat_commands.capitalization = function(room, args) {
|
|
||||||
var enabled, args = args && args.length ? args[0].toLowerCase() : null;
|
|
||||||
if ( args == "y" || args == "yes" || args == "true" || args == "on" )
|
|
||||||
enabled = true;
|
|
||||||
else if ( args == "n" || args == "no" || args == "false" || args == "off" )
|
|
||||||
enabled = false;
|
|
||||||
|
|
||||||
if ( enabled === undefined )
|
|
||||||
return "Chat Name Capitalization is currently " + (this.settings.capitalize ? "enabled." : "disabled.");
|
|
||||||
|
|
||||||
this.settings.set("capitalize", enabled);
|
|
||||||
return "Chat Name Capitalization is now " + (enabled ? "enabled." : "disabled.");
|
|
||||||
}
|
|
||||||
|
|
||||||
FFZ.chat_commands.capitalization.help = "Usage: /ffz capitalization <on|off>\nEnable or disable Chat Name Capitalization. This setting does not work with BetterTTV.";
|
|
||||||
|
|
||||||
|
|
||||||
// ---------------------
|
// ---------------------
|
||||||
// Extra Mentions
|
// Extra Mentions
|
||||||
// ---------------------
|
// ---------------------
|
||||||
|
|
||||||
FFZ._regex_cache = {};
|
FFZ._regex_cache = {};
|
||||||
|
|
||||||
FFZ._get_rex = function(word) {
|
FFZ._get_regex = function(word) {
|
||||||
return FFZ._regex_cache[word] = FFZ._regex_cache[word] || RegExp("\\b" + reg_escape(word) + "\\b", "ig");
|
return FFZ._regex_cache[word] = FFZ._regex_cache[word] || RegExp("\\b" + reg_escape(word) + "\\b", "ig");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,25 +380,6 @@ FFZ.prototype._mentionize = function(controller, tokens) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.chat_commands.mentionize = function(room, args) {
|
|
||||||
if ( args && args.length ) {
|
|
||||||
var mention_words = args.join(" ").trim().split(/\W*,\W*/);
|
|
||||||
if ( mention_words.length == 1 && mention_words[0] == "disable" )
|
|
||||||
mention_words = [];
|
|
||||||
|
|
||||||
this.settings.set("keywords", mention_words);
|
|
||||||
}
|
|
||||||
|
|
||||||
var mention_words = this.settings.keywords;
|
|
||||||
if ( mention_words.length )
|
|
||||||
return "The following words will be highlighted: " + mention_words.join(", ");
|
|
||||||
else
|
|
||||||
return "There are no words set that will be highlighted.";
|
|
||||||
}
|
|
||||||
|
|
||||||
FFZ.chat_commands.mentionize.help = "Usage: /ffz mentionize <comma, separated, word, list|disable>\nSet a list of words that will also be highlighted in chat.";
|
|
||||||
|
|
||||||
|
|
||||||
// ---------------------
|
// ---------------------
|
||||||
// Emoticon Replacement
|
// Emoticon Replacement
|
||||||
// ---------------------
|
// ---------------------
|
||||||
|
|
247
src/ember/moderation-card.js
Normal file
247
src/ember/moderation-card.js
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
var FFZ = window.FrankerFaceZ,
|
||||||
|
utils = require("../utils"),
|
||||||
|
|
||||||
|
keycodes = {
|
||||||
|
ESC: 27,
|
||||||
|
P: 80,
|
||||||
|
B: 66,
|
||||||
|
T: 84
|
||||||
|
},
|
||||||
|
|
||||||
|
btns = [
|
||||||
|
['5m', 300],
|
||||||
|
['10m', 600],
|
||||||
|
['1hr', 3600],
|
||||||
|
['12hr', 43200],
|
||||||
|
['24hr', 86400]],
|
||||||
|
|
||||||
|
MESSAGE = '<svg class="svg-messages" height="16px" version="1.1" viewBox="0 0 18 18" width="16px" x="0px" y="0px"><path clip-rule="evenodd" d="M1,15V3h16v12H1z M15.354,5.354l-0.707-0.707L9,10.293L3.354,4.646L2.646,5.354L6.293,9l-3.646,3.646l0.707,0.707L7,9.707l1.646,1.646h0.707L11,9.707l3.646,3.646l0.707-0.707L11.707,9L15.354,5.354z" fill-rule="evenodd"></path></svg>';
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------
|
||||||
|
// Settings
|
||||||
|
// ----------------
|
||||||
|
|
||||||
|
FFZ.settings_info.enhanced_moderation = {
|
||||||
|
type: "boolean",
|
||||||
|
value: false,
|
||||||
|
|
||||||
|
visible: function() { return ! this.has_bttv },
|
||||||
|
category: "Chat",
|
||||||
|
|
||||||
|
name: "Enhanced Moderation",
|
||||||
|
help: "Use /p, /t, /u and /b in chat to moderator, or use hotkeys with moderation cards."
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------
|
||||||
|
// Initialization
|
||||||
|
// ----------------
|
||||||
|
|
||||||
|
FFZ.prototype.setup_mod_card = function() {
|
||||||
|
this.log("Hooking the Ember Moderation Card view.");
|
||||||
|
var Card = App.__container__.resolve('view:moderation-card'),
|
||||||
|
f = this;
|
||||||
|
|
||||||
|
Card.reopen({
|
||||||
|
didInsertElement: function() {
|
||||||
|
this._super();
|
||||||
|
try {
|
||||||
|
if ( ! f.settings.enhanced_moderation )
|
||||||
|
return;
|
||||||
|
|
||||||
|
var el = this.get('element'),
|
||||||
|
controller = this.get('context');
|
||||||
|
|
||||||
|
// Only do the big stuff if we're mod.
|
||||||
|
if ( controller.get('parentController.model.isModeratorOrHigher') ) {
|
||||||
|
el.classList.add('ffz-moderation-card');
|
||||||
|
el.setAttribute('tabindex', 1);
|
||||||
|
|
||||||
|
// Key Handling
|
||||||
|
el.addEventListener('keyup', function(e) {
|
||||||
|
var key = e.keyCode || e.which,
|
||||||
|
user_id = controller.get('model.user.id'),
|
||||||
|
room = controller.get('parentController.model');
|
||||||
|
|
||||||
|
if ( key == keycodes.P )
|
||||||
|
room.send("/timeout " + user_id + " 1");
|
||||||
|
|
||||||
|
else if ( key == keycodes.B )
|
||||||
|
room.send("/ban " + user_id);
|
||||||
|
|
||||||
|
else if ( key == keycodes.T )
|
||||||
|
room.send("/timeout " + user_id + " 600");
|
||||||
|
|
||||||
|
else if ( key != keycodes.ESC )
|
||||||
|
return;
|
||||||
|
|
||||||
|
controller.send('hideModOverlay');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Extra Moderation
|
||||||
|
var line = document.createElement('div');
|
||||||
|
line.className = 'interface clearfix';
|
||||||
|
|
||||||
|
var btn_click = function(timeout) {
|
||||||
|
var user_id = controller.get('model.user.id'),
|
||||||
|
room = controller.get('parentController.model');
|
||||||
|
|
||||||
|
if ( timeout === -1 )
|
||||||
|
room.send("/unban " + user_id);
|
||||||
|
else
|
||||||
|
room.send("/timeout " + user_id + " " + timeout);
|
||||||
|
},
|
||||||
|
|
||||||
|
btn_make = function(text, timeout) {
|
||||||
|
var btn = document.createElement('button');
|
||||||
|
btn.className = 'button';
|
||||||
|
btn.innerHTML = text;
|
||||||
|
btn.title = "Timeout User for " + utils.number_commas(timeout) + " Second" + (timeout != 1 ? "s" : "");
|
||||||
|
|
||||||
|
if ( timeout === 600 )
|
||||||
|
btn.title = "(T)" + btn.title.substr(1);
|
||||||
|
else if ( timeout === 1 )
|
||||||
|
btn.title = "(P)urge - " + btn.title;
|
||||||
|
|
||||||
|
jQuery(btn).tipsy();
|
||||||
|
|
||||||
|
btn.addEventListener('click', btn_click.bind(this, timeout));
|
||||||
|
return btn;
|
||||||
|
};
|
||||||
|
|
||||||
|
line.appendChild(btn_make('Purge', 1));
|
||||||
|
|
||||||
|
var s = document.createElement('span');
|
||||||
|
s.className = 'right';
|
||||||
|
line.appendChild(s);
|
||||||
|
|
||||||
|
for(var i=0; i < btns.length; i++)
|
||||||
|
s.appendChild(btn_make(btns[i][0], btns[i][1]));
|
||||||
|
|
||||||
|
el.appendChild(line);
|
||||||
|
|
||||||
|
|
||||||
|
// Unban Button
|
||||||
|
|
||||||
|
var unban_btn = document.createElement('button');
|
||||||
|
unban_btn.className = 'unban button glyph-only light';
|
||||||
|
unban_btn.innerHTML = "✓";
|
||||||
|
unban_btn.title = "(U)nban User";
|
||||||
|
|
||||||
|
jQuery(unban_btn).tipsy();
|
||||||
|
unban_btn.addEventListener("click", btn_click.bind(this, -1));
|
||||||
|
|
||||||
|
var ban_btn = el.querySelector('button.ban');
|
||||||
|
ban_btn.setAttribute('title', '(B)an User');
|
||||||
|
|
||||||
|
jQuery(ban_btn).after(unban_btn);
|
||||||
|
|
||||||
|
|
||||||
|
// Fix Other Buttons
|
||||||
|
this.$("button.timeout").remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// More Fixing Other Buttons
|
||||||
|
var op_btn = el.querySelector('button.mod');
|
||||||
|
if ( op_btn ) {
|
||||||
|
var model = controller.get('parentController.model'),
|
||||||
|
can_op = model.get('isBroadcaster') || model.get('isStaff') || model.get('isAdmin');
|
||||||
|
|
||||||
|
if ( ! can_op )
|
||||||
|
op_btn.parentElement.removeChild(op_btn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var msg_btn = el.querySelector(".interface > button");
|
||||||
|
if ( msg_btn && msg_btn.className == "button" ) {
|
||||||
|
msg_btn.innerHTML = MESSAGE;
|
||||||
|
msg_btn.classList.add('glyph-only');
|
||||||
|
msg_btn.classList.add('message');
|
||||||
|
|
||||||
|
msg_btn.title = "Message User";
|
||||||
|
jQuery(msg_btn).tipsy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Focus the Element
|
||||||
|
this.$().draggable({
|
||||||
|
start: function() {
|
||||||
|
el.focus();
|
||||||
|
}});
|
||||||
|
|
||||||
|
el.focus();
|
||||||
|
|
||||||
|
} catch(err) {
|
||||||
|
try {
|
||||||
|
f.error("ModerationCardView didInsertElement: " + err);
|
||||||
|
} catch(err) { }
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------
|
||||||
|
// Chat Commands
|
||||||
|
// ----------------
|
||||||
|
|
||||||
|
FFZ.chat_commands.purge = FFZ.chat_commands.p = function(room, args) {
|
||||||
|
if ( ! args || ! args.length )
|
||||||
|
return "Purge Usage: /p username [more usernames separated by spaces]";
|
||||||
|
|
||||||
|
if ( args.length > 10 )
|
||||||
|
return "Please only purge up to 10 users at once.";
|
||||||
|
|
||||||
|
for(var i=0; i < args.length; i++) {
|
||||||
|
var name = args[i];
|
||||||
|
if ( name )
|
||||||
|
room.room.send("/timeout " + name + " 1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FFZ.chat_commands.p.enabled = function() { return this.settings.enhanced_moderation; }
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.chat_commands.t = function(room, args) {
|
||||||
|
if ( ! args || ! args.length )
|
||||||
|
return "Timeout Usage: /t username [duration]";
|
||||||
|
room.room.send("/timeout " + args.join(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
FFZ.chat_commands.t.enabled = function() { return this.settings.enhanced_moderation; }
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.chat_commands.b = function(room, args) {
|
||||||
|
if ( ! args || ! args.length )
|
||||||
|
return "Ban Usage: /b username [more usernames separated by spaces]";
|
||||||
|
|
||||||
|
if ( args.length > 10 )
|
||||||
|
return "Please only ban up to 10 users at once.";
|
||||||
|
|
||||||
|
for(var i=0; i < args.length; i++) {
|
||||||
|
var name = args[i];
|
||||||
|
if ( name )
|
||||||
|
room.room.send("/ban " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FFZ.chat_commands.b.enabled = function() { return this.settings.enhanced_moderation; }
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.chat_commands.u = function(room, args) {
|
||||||
|
if ( ! args || ! args.length )
|
||||||
|
return "Unban Usage: /b username [more usernames separated by spaces]";
|
||||||
|
|
||||||
|
if ( args.length > 10 )
|
||||||
|
return "Please only unban up to 10 users at once.";
|
||||||
|
|
||||||
|
for(var i=0; i < args.length; i++) {
|
||||||
|
var name = args[i];
|
||||||
|
if ( name )
|
||||||
|
room.room.send("/unban " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FFZ.chat_commands.u.enabled = function() { return this.settings.enhanced_moderation; }
|
|
@ -50,6 +50,7 @@ FFZ.prototype.setup_room = function() {
|
||||||
// --------------------
|
// --------------------
|
||||||
|
|
||||||
FFZ.chat_commands = {};
|
FFZ.chat_commands = {};
|
||||||
|
FFZ.ffz_commands = {};
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype.room_message = function(room, text) {
|
FFZ.prototype.room_message = function(room, text) {
|
||||||
|
@ -66,6 +67,54 @@ FFZ.prototype.room_message = function(room, text) {
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype.run_command = function(text, room_id) {
|
FFZ.prototype.run_command = function(text, room_id) {
|
||||||
|
var room = this.rooms[room_id];
|
||||||
|
if ( ! room || ! room.room )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ! text )
|
||||||
|
return;
|
||||||
|
|
||||||
|
var args = text.split(" "),
|
||||||
|
cmd = args.shift().substr(1).toLowerCase(),
|
||||||
|
|
||||||
|
command = FFZ.chat_commands[cmd],
|
||||||
|
output;
|
||||||
|
|
||||||
|
if ( ! command )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( command.hasOwnProperty('enabled') ) {
|
||||||
|
var val = command.enabled;
|
||||||
|
if ( typeof val == "function" ) {
|
||||||
|
try {
|
||||||
|
val = command.enabled.bind(this)(room, args);
|
||||||
|
} catch(err) {
|
||||||
|
this.error('command "' + cmd + '" enabled: ' + err);
|
||||||
|
val = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! val )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.log("Received Command: " + cmd, args, true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
output = command.bind(this)(room, args);
|
||||||
|
} catch(err) {
|
||||||
|
this.error('command "' + cmd + '" runner: ' + err);
|
||||||
|
output = "There was an error running the command.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( output )
|
||||||
|
this.room_message(room, output);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.prototype.run_ffz_command = function(text, room_id) {
|
||||||
var room = this.rooms[room_id];
|
var room = this.rooms[room_id];
|
||||||
if ( ! room || !room.room )
|
if ( ! room || !room.room )
|
||||||
return;
|
return;
|
||||||
|
@ -84,7 +133,7 @@ FFZ.prototype.run_command = function(text, room_id) {
|
||||||
|
|
||||||
this.log("Received Command: " + cmd, args, true);
|
this.log("Received Command: " + cmd, args, true);
|
||||||
|
|
||||||
var command = FFZ.chat_commands[cmd], output;
|
var command = FFZ.ffz_commands[cmd], output;
|
||||||
if ( command ) {
|
if ( command ) {
|
||||||
try {
|
try {
|
||||||
output = command.bind(this)(room, args);
|
output = command.bind(this)(room, args);
|
||||||
|
@ -100,9 +149,9 @@ FFZ.prototype.run_command = function(text, room_id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.chat_commands.help = function(room, args) {
|
FFZ.ffz_commands.help = function(room, args) {
|
||||||
if ( args && args.length ) {
|
if ( args && args.length ) {
|
||||||
var command = FFZ.chat_commands[args[0].toLowerCase()];
|
var command = FFZ.ffz_commands[args[0].toLowerCase()];
|
||||||
if ( ! command )
|
if ( ! command )
|
||||||
return 'There is no "' + args[0] + '" command.';
|
return 'There is no "' + args[0] + '" command.';
|
||||||
|
|
||||||
|
@ -114,13 +163,13 @@ FFZ.chat_commands.help = function(room, args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmds = [];
|
var cmds = [];
|
||||||
for(var c in FFZ.chat_commands)
|
for(var c in FFZ.ffz_commands)
|
||||||
FFZ.chat_commands.hasOwnProperty(c) && cmds.push(c);
|
FFZ.ffz_commands.hasOwnProperty(c) && cmds.push(c);
|
||||||
|
|
||||||
return "The available commands are: " + cmds.join(", ");
|
return "The available commands are: " + cmds.join(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
FFZ.chat_commands.help.help = "Usage: /ffz help [command]\nList available commands, or show help for a specific command.";
|
FFZ.ffz_commands.help.help = "Usage: /ffz help [command]\nList available commands, or show help for a specific command.";
|
||||||
|
|
||||||
|
|
||||||
// --------------------
|
// --------------------
|
||||||
|
@ -214,12 +263,20 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
// Track which rooms the user is currently in.
|
// Track which rooms the user is currently in.
|
||||||
init: function() {
|
init: function() {
|
||||||
this._super();
|
this._super();
|
||||||
f.add_room(this.id, this);
|
try {
|
||||||
|
f.add_room(this.id, this);
|
||||||
|
} catch(err) {
|
||||||
|
f.error("add_room: " + err);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
willDestroy: function() {
|
willDestroy: function() {
|
||||||
this._super();
|
this._super();
|
||||||
f.remove_room(this.id);
|
try {
|
||||||
|
f.remove_room(this.id);
|
||||||
|
} catch(err) {
|
||||||
|
f.error("remove_room: " + err);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getSuggestions: function() {
|
getSuggestions: function() {
|
||||||
|
@ -228,19 +285,35 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
// filteredSuggestions property of the chat-input component would
|
// filteredSuggestions property of the chat-input component would
|
||||||
// be even better, but I was already hooking the room model.
|
// be even better, but I was already hooking the room model.
|
||||||
var suggestions = this._super();
|
var suggestions = this._super();
|
||||||
if ( this.settings.capitalize )
|
|
||||||
suggestions = _.map(suggestions, FFZ.get_capitalization);
|
try {
|
||||||
|
if ( f.settings.capitalize )
|
||||||
|
suggestions = _.map(suggestions, FFZ.get_capitalization);
|
||||||
|
} catch(err) {
|
||||||
|
f.error("get_suggestions: " + err);
|
||||||
|
}
|
||||||
|
|
||||||
return suggestions;
|
return suggestions;
|
||||||
},
|
},
|
||||||
|
|
||||||
send: function(text) {
|
send: function(text) {
|
||||||
var cmd = text.split(' ', 1)[0].toLowerCase();
|
try {
|
||||||
if ( cmd === "/ffz" ) {
|
var cmd = text.split(' ', 1)[0].toLowerCase();
|
||||||
this.set("messageToSend", "");
|
if ( cmd === "/ffz" ) {
|
||||||
f.run_command(text.substr(5), this.get('id'));
|
this.set("messageToSend", "");
|
||||||
} else
|
f.run_ffz_command(text.substr(5), this.get('id'));
|
||||||
return this._super(text);
|
return;
|
||||||
|
|
||||||
|
} else if ( cmd.charAt(0) === "/" && f.run_command(text, this.get('id')) ) {
|
||||||
|
this.set("messageToSend", "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch(err) {
|
||||||
|
f.error("send: " + err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._super(text);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,11 @@ FFZ.prototype.setup_router = function() {
|
||||||
var f = this;
|
var f = this;
|
||||||
App.__container__.lookup('router:main').reopen({
|
App.__container__.lookup('router:main').reopen({
|
||||||
ffzTransition: function() {
|
ffzTransition: function() {
|
||||||
f.track_page();
|
try {
|
||||||
|
f.track_page();
|
||||||
|
} catch(err) {
|
||||||
|
f.error("ffzTransition: " + err);
|
||||||
|
}
|
||||||
}.on('didTransition')
|
}.on('didTransition')
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -18,72 +18,77 @@ FFZ.prototype._modify_viewers = function(controller) {
|
||||||
|
|
||||||
controller.reopen({
|
controller.reopen({
|
||||||
lines: function() {
|
lines: function() {
|
||||||
var viewers = this._super(),
|
var viewers = this._super();
|
||||||
categories = [],
|
try {
|
||||||
data = {},
|
var categories = [],
|
||||||
last_category = null;
|
data = {},
|
||||||
|
last_category = null;
|
||||||
|
|
||||||
// Get the broadcaster name.
|
// Get the broadcaster name.
|
||||||
var Channel = App.__container__.lookup('controller:channel'),
|
var Channel = App.__container__.lookup('controller:channel'),
|
||||||
room_id = this.get('parentController.model.id'),
|
room_id = this.get('parentController.model.id'),
|
||||||
broadcaster = Channel && Channel.get('id');
|
broadcaster = Channel && Channel.get('id');
|
||||||
|
|
||||||
// We can get capitalization for the broadcaster from the channel.
|
// We can get capitalization for the broadcaster from the channel.
|
||||||
if ( broadcaster ) {
|
if ( broadcaster ) {
|
||||||
var display_name = Channel.get('display_name');
|
var display_name = Channel.get('display_name');
|
||||||
if ( display_name )
|
if ( display_name )
|
||||||
FFZ.capitalization[broadcaster] = [display_name, Date.now()];
|
FFZ.capitalization[broadcaster] = [display_name, Date.now()];
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the current room isn't the channel's chat, then we shouldn't
|
// If the current room isn't the channel's chat, then we shouldn't
|
||||||
// display them as the broadcaster.
|
// display them as the broadcaster.
|
||||||
if ( room_id != broadcaster )
|
if ( room_id != broadcaster )
|
||||||
broadcaster = null;
|
broadcaster = null;
|
||||||
|
|
||||||
// Now, break the viewer array down into something we can use.
|
// Now, break the viewer array down into something we can use.
|
||||||
for(var i=0; i < viewers.length; i++) {
|
for(var i=0; i < viewers.length; i++) {
|
||||||
var entry = viewers[i];
|
var entry = viewers[i];
|
||||||
if ( entry.category ) {
|
if ( entry.category ) {
|
||||||
last_category = entry.category;
|
last_category = entry.category;
|
||||||
categories.push(last_category);
|
categories.push(last_category);
|
||||||
data[last_category] = [];
|
data[last_category] = [];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
var viewer = entry.chatter.toLowerCase();
|
var viewer = entry.chatter.toLowerCase();
|
||||||
if ( ! viewer )
|
if ( ! viewer )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If the viewer is the broadcaster, give them their own
|
||||||
|
// group. Don't put them with normal mods!
|
||||||
|
if ( viewer == broadcaster ) {
|
||||||
|
categories.unshift("Broadcaster");
|
||||||
|
data["Broadcaster"] = [viewer];
|
||||||
|
|
||||||
|
} else if ( data.hasOwnProperty(last_category) )
|
||||||
|
data[last_category].push(viewer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, rebuild the viewer list. However, we're going to actually
|
||||||
|
// sort it this time.
|
||||||
|
viewers = [];
|
||||||
|
for(var i=0; i < categories.length; i++) {
|
||||||
|
var category = categories[i],
|
||||||
|
chatters = data[category];
|
||||||
|
|
||||||
|
if ( ! chatters || ! chatters.length )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// If the viewer is the broadcaster, give them their own
|
viewers.push({category: category});
|
||||||
// group. Don't put them with normal mods!
|
viewers.push({chatter: ""});
|
||||||
if ( viewer == broadcaster ) {
|
|
||||||
categories.unshift("Broadcaster");
|
|
||||||
data["Broadcaster"] = [viewer];
|
|
||||||
|
|
||||||
} else if ( data.hasOwnProperty(last_category) )
|
// Push the chatters, capitalizing them as we go.
|
||||||
data[last_category].push(viewer);
|
chatters.sort();
|
||||||
|
while(chatters.length) {
|
||||||
|
var viewer = chatters.shift();
|
||||||
|
viewer = FFZ.get_capitalization(viewer);
|
||||||
|
viewers.push({chatter: viewer});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Now, rebuild the viewer list. However, we're going to actually
|
} catch(err) {
|
||||||
// sort it this time.
|
f.error("ViewersController lines: " + err);
|
||||||
viewers = [];
|
|
||||||
for(var i=0; i < categories.length; i++) {
|
|
||||||
var category = categories[i],
|
|
||||||
chatters = data[category];
|
|
||||||
|
|
||||||
if ( ! chatters || ! chatters.length )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
viewers.push({category: category});
|
|
||||||
viewers.push({chatter: ""});
|
|
||||||
|
|
||||||
// Push the chatters, capitalizing them as we go.
|
|
||||||
chatters.sort();
|
|
||||||
while(chatters.length) {
|
|
||||||
var viewer = chatters.shift();
|
|
||||||
viewer = FFZ.get_capitalization(viewer);
|
|
||||||
viewers.push({chatter: viewer});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return viewers;
|
return viewers;
|
||||||
|
|
|
@ -23,22 +23,27 @@ FFZ.prototype.setup_bttv = function(delay) {
|
||||||
this.log("BetterTTV was detected after " + delay + "ms. Hooking.");
|
this.log("BetterTTV was detected after " + delay + "ms. Hooking.");
|
||||||
this.has_bttv = true;
|
this.has_bttv = true;
|
||||||
|
|
||||||
this.track('setCustomVariable', '3', 'BetterTTV', BetterTTV.info.versionString());
|
// this.track('setCustomVariable', '3', 'BetterTTV', BetterTTV.info.versionString());
|
||||||
|
|
||||||
// Disable Dark if it's enabled.
|
// Disable Dark if it's enabled.
|
||||||
document.querySelector(".app-main").classList.remove("ffz-dark");
|
document.body.classList.remove("ffz-dark");
|
||||||
if ( this._dark_style ) {
|
if ( this._dark_style ) {
|
||||||
this._dark_style.parentElement.removeChild(this._dark_style);
|
this._dark_style.parentElement.removeChild(this._dark_style);
|
||||||
delete this._dark_style;
|
delete this._dark_style;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disable other features too.
|
||||||
|
document.body.classList.remove("ffz-chat-colors");
|
||||||
|
document.body.classList.remove("ffz-chat-background");
|
||||||
|
|
||||||
|
|
||||||
// Send Message Behavior
|
// Send Message Behavior
|
||||||
var original_send = BetterTTV.chat.helpers.sendMessage, f = this;
|
var original_send = BetterTTV.chat.helpers.sendMessage, f = this;
|
||||||
BetterTTV.chat.helpers.sendMessage = function(message) {
|
BetterTTV.chat.helpers.sendMessage = function(message) {
|
||||||
var cmd = message.split(' ', 1)[0].toLowerCase();
|
var cmd = message.split(' ', 1)[0].toLowerCase();
|
||||||
|
|
||||||
if ( cmd === "/ffz" )
|
if ( cmd === "/ffz" )
|
||||||
f.run_command(message.substr(5), BetterTTV.chat.store.currentRoom);
|
f.run_ffz_command(message.substr(5), BetterTTV.chat.store.currentRoom);
|
||||||
else
|
else
|
||||||
return original_send(message);
|
return original_send(message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ FFZ.prototype._feature_friday_ui = function(room_id, parent, view) {
|
||||||
btn.innerHTML = "<span>" + message + "</span>";
|
btn.innerHTML = "<span>" + message + "</span>";
|
||||||
|
|
||||||
// Track the number of users to click this button.
|
// Track the number of users to click this button.
|
||||||
btn.addEventListener('click', function() { f.track('trackLink', this.href, 'link'); });
|
// btn.addEventListener('click', function() { f.track('trackLink', this.href, 'link'); });
|
||||||
|
|
||||||
btnc.appendChild(btn);
|
btnc.appendChild(btn);
|
||||||
parent.appendChild(btnc);
|
parent.appendChild(btnc);
|
||||||
|
|
54
src/main.js
54
src/main.js
|
@ -9,6 +9,9 @@ require('./shims');
|
||||||
var FFZ = window.FrankerFaceZ = function() {
|
var FFZ = window.FrankerFaceZ = function() {
|
||||||
FFZ.instance = this;
|
FFZ.instance = this;
|
||||||
|
|
||||||
|
// Logging
|
||||||
|
this._log_data = [];
|
||||||
|
|
||||||
// Get things started.
|
// Get things started.
|
||||||
this.initialize();
|
this.initialize();
|
||||||
}
|
}
|
||||||
|
@ -19,7 +22,7 @@ FFZ.get = function() { return FFZ.instance; }
|
||||||
|
|
||||||
// Version
|
// Version
|
||||||
var VER = FFZ.version_info = {
|
var VER = FFZ.version_info = {
|
||||||
major: 3, minor: 0, revision: 0,
|
major: 3, minor: 1, revision: 0,
|
||||||
toString: function() {
|
toString: function() {
|
||||||
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
|
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
|
||||||
}
|
}
|
||||||
|
@ -30,6 +33,8 @@ var VER = FFZ.version_info = {
|
||||||
|
|
||||||
FFZ.prototype.log = function(msg, data, to_json) {
|
FFZ.prototype.log = function(msg, data, to_json) {
|
||||||
msg = "FFZ: " + msg + (to_json ? " -- " + JSON.stringify(data) : "");
|
msg = "FFZ: " + msg + (to_json ? " -- " + JSON.stringify(data) : "");
|
||||||
|
this._log_data.push(msg);
|
||||||
|
|
||||||
if ( data !== undefined && console.groupCollapsed && console.dir ) {
|
if ( data !== undefined && console.groupCollapsed && console.dir ) {
|
||||||
console.groupCollapsed(msg);
|
console.groupCollapsed(msg);
|
||||||
if ( navigator.userAgent.indexOf("Firefox/") !== -1 )
|
if ( navigator.userAgent.indexOf("Firefox/") !== -1 )
|
||||||
|
@ -43,6 +48,43 @@ FFZ.prototype.log = function(msg, data, to_json) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.prototype.error = function(msg, data, to_json) {
|
||||||
|
msg = "FFZ Error: " + msg + (to_json ? " -- " + JSON.stringify(data) : "");
|
||||||
|
this._log_data.push(msg);
|
||||||
|
|
||||||
|
if ( data !== undefined && console.groupCollapsed && console.dir ) {
|
||||||
|
console.groupCollapsed(msg);
|
||||||
|
if ( navigator.userAgent.indexOf("Firefox/") !== -1 )
|
||||||
|
console.log(data);
|
||||||
|
else
|
||||||
|
console.dir(data);
|
||||||
|
|
||||||
|
console.groupEnd(msg);
|
||||||
|
} else
|
||||||
|
console.assert(false, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.prototype.paste_logs = function() {
|
||||||
|
this._pastebin(this._log_data.join("\n"), function(url) {
|
||||||
|
if ( ! url )
|
||||||
|
return console.log("FFZ Error: Unable to upload log to pastebin.");
|
||||||
|
|
||||||
|
console.log("FFZ: Your FrankerFaceZ log has been pasted to: " + url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.prototype._pastebin = function(data, callback) {
|
||||||
|
jQuery.ajax({url: "http://putco.de/", type: "PUT", data: data, context: this})
|
||||||
|
.success(function(e) {
|
||||||
|
callback.bind(this)(e.trim() + ".log");
|
||||||
|
}).fail(function(e) {
|
||||||
|
callback.bind(this)(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// -------------------
|
// -------------------
|
||||||
// User Data
|
// User Data
|
||||||
// -------------------
|
// -------------------
|
||||||
|
@ -69,14 +111,15 @@ require('./socket');
|
||||||
require('./emoticons');
|
require('./emoticons');
|
||||||
require('./badges');
|
require('./badges');
|
||||||
|
|
||||||
require('./ember/router');
|
// Analytics: require('./ember/router');
|
||||||
require('./ember/room');
|
require('./ember/room');
|
||||||
require('./ember/line');
|
require('./ember/line');
|
||||||
require('./ember/chatview');
|
require('./ember/chatview');
|
||||||
require('./ember/viewers');
|
require('./ember/viewers');
|
||||||
|
require('./ember/moderation-card');
|
||||||
//require('./ember/teams');
|
//require('./ember/teams');
|
||||||
|
|
||||||
require('./tracking');
|
// Analytics: require('./tracking');
|
||||||
|
|
||||||
require('./debug');
|
require('./debug');
|
||||||
|
|
||||||
|
@ -141,13 +184,14 @@ FFZ.prototype.setup_ember = function(delay) {
|
||||||
this.setup_emoticons();
|
this.setup_emoticons();
|
||||||
this.setup_badges();
|
this.setup_badges();
|
||||||
|
|
||||||
this.setup_piwik();
|
//this.setup_piwik();
|
||||||
|
|
||||||
this.setup_router();
|
//this.setup_router();
|
||||||
this.setup_room();
|
this.setup_room();
|
||||||
this.setup_line();
|
this.setup_line();
|
||||||
this.setup_chatview();
|
this.setup_chatview();
|
||||||
this.setup_viewers();
|
this.setup_viewers();
|
||||||
|
this.setup_mod_card();
|
||||||
|
|
||||||
//this.setup_teams();
|
//this.setup_teams();
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ FFZ.settings_info.dark_twitch = {
|
||||||
if ( this.has_bttv )
|
if ( this.has_bttv )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
document.querySelector(".app-main").classList.toggle("ffz-dark", val);
|
document.body.classList.toggle("ffz-dark", val);
|
||||||
if ( val )
|
if ( val )
|
||||||
this._load_dark_css();
|
this._load_dark_css();
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ FFZ.prototype.setup_dark = function() {
|
||||||
if ( this.has_bttv )
|
if ( this.has_bttv )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
document.querySelector(".app-main").classList.toggle("ffz-dark", this.settings.dark_twitch);
|
document.body.classList.toggle("ffz-dark", this.settings.dark_twitch);
|
||||||
if ( this.settings.dark_twitch )
|
if ( this.settings.dark_twitch )
|
||||||
this._load_dark_css();
|
this._load_dark_css();
|
||||||
}
|
}
|
||||||
|
|
155
src/ui/menu.js
155
src/ui/menu.js
|
@ -95,7 +95,7 @@ FFZ.prototype.build_ui_popup = function(view) {
|
||||||
|
|
||||||
// Add the menu to the DOM.
|
// Add the menu to the DOM.
|
||||||
this._popup = container;
|
this._popup = container;
|
||||||
sub_container.style.maxHeight = Math.max(300, view.$().height() - 212) + "px";
|
sub_container.style.maxHeight = Math.max(100, view.$().height() - 162) + "px";
|
||||||
view.$('.chat-interface').append(container);
|
view.$('.chat-interface').append(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,31 +124,12 @@ FFZ.prototype._ui_change_page = function(view, menu, container, page) {
|
||||||
|
|
||||||
FFZ.menu_pages.settings = {
|
FFZ.menu_pages.settings = {
|
||||||
render: function(view, container) {
|
render: function(view, container) {
|
||||||
var menu = document.createElement('div');
|
var settings = {},
|
||||||
menu.className = 'chat-menu-content';
|
categories = [];
|
||||||
|
for(var key in FFZ.settings_info) {
|
||||||
var settings = [];
|
var info = FFZ.settings_info[key],
|
||||||
for(var key in FFZ.settings_info)
|
cat = info.category || "Miscellaneous",
|
||||||
settings.push([key, FFZ.settings_info[key]]);
|
cs = settings[cat];
|
||||||
|
|
||||||
settings.sort(function(a,b) {
|
|
||||||
var ai = a[1],
|
|
||||||
bi = b[1],
|
|
||||||
|
|
||||||
an = ai.name.toLowerCase(),
|
|
||||||
bn = bi.name.toLowerCase();
|
|
||||||
|
|
||||||
if ( an < bn ) return -1;
|
|
||||||
else if ( an > bn ) return 1;
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
for(var i=0; i < settings.length; i++) {
|
|
||||||
var key = settings[i][0],
|
|
||||||
info = settings[i][1],
|
|
||||||
el = document.createElement('p'),
|
|
||||||
val = this.settings.get(key);
|
|
||||||
|
|
||||||
if ( info.visible !== undefined && info.visible !== null ) {
|
if ( info.visible !== undefined && info.visible !== null ) {
|
||||||
var visible = info.visible;
|
var visible = info.visible;
|
||||||
|
@ -159,45 +140,94 @@ FFZ.menu_pages.settings = {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
el.className = 'clearfix';
|
if ( ! cs ) {
|
||||||
|
categories.push(cat);
|
||||||
if ( info.type == "boolean" ) {
|
cs = settings[cat] = [];
|
||||||
var swit = document.createElement('a'),
|
|
||||||
label = document.createElement('span');
|
|
||||||
|
|
||||||
swit.className = 'switch';
|
|
||||||
swit.classList.toggle('active', val);
|
|
||||||
swit.innerHTML = "<span></span>";
|
|
||||||
|
|
||||||
label.className = 'switch-label';
|
|
||||||
label.innerHTML = info.name;
|
|
||||||
|
|
||||||
el.appendChild(swit);
|
|
||||||
el.appendChild(label);
|
|
||||||
|
|
||||||
swit.addEventListener("click", this._ui_toggle_setting.bind(this, swit, key));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
el.classList.add("option");
|
|
||||||
var link = document.createElement('a');
|
|
||||||
link.innerHTML = info.name;
|
|
||||||
link.href = "#";
|
|
||||||
el.appendChild(link);
|
|
||||||
|
|
||||||
link.addEventListener("click", info.method.bind(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( info.help ) {
|
cs.push([key, info]);
|
||||||
var help = document.createElement('span');
|
|
||||||
help.className = 'help';
|
|
||||||
help.innerHTML = info.help;
|
|
||||||
el.appendChild(help);
|
|
||||||
}
|
|
||||||
|
|
||||||
menu.appendChild(el);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
container.appendChild(menu);
|
categories.sort(function(a,b) {
|
||||||
|
var a = a.toLowerCase(),
|
||||||
|
b = b.toLowerCase();
|
||||||
|
|
||||||
|
if ( a < b ) return -1;
|
||||||
|
else if ( a > b ) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
for(var ci=0; ci < categories.length; ci++) {
|
||||||
|
var category = categories[ci],
|
||||||
|
cset = settings[category],
|
||||||
|
|
||||||
|
menu = document.createElement('div'),
|
||||||
|
heading = document.createElement('div');
|
||||||
|
|
||||||
|
heading.className = 'heading';
|
||||||
|
menu.className = 'chat-menu-content';
|
||||||
|
heading.innerHTML = category;
|
||||||
|
menu.appendChild(heading);
|
||||||
|
|
||||||
|
cset.sort(function(a,b) {
|
||||||
|
var ai = a[1],
|
||||||
|
bi = b[1],
|
||||||
|
|
||||||
|
an = ai.name.toLowerCase(),
|
||||||
|
bn = bi.name.toLowerCase();
|
||||||
|
|
||||||
|
if ( an < bn ) return -1;
|
||||||
|
else if ( an > bn ) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
for(var i=0; i < cset.length; i++) {
|
||||||
|
var key = cset[i][0],
|
||||||
|
info = cset[i][1],
|
||||||
|
el = document.createElement('p'),
|
||||||
|
val = this.settings.get(key);
|
||||||
|
|
||||||
|
el.className = 'clearfix';
|
||||||
|
|
||||||
|
if ( info.type == "boolean" ) {
|
||||||
|
var swit = document.createElement('a'),
|
||||||
|
label = document.createElement('span');
|
||||||
|
|
||||||
|
swit.className = 'switch';
|
||||||
|
swit.classList.toggle('active', val);
|
||||||
|
swit.innerHTML = "<span></span>";
|
||||||
|
|
||||||
|
label.className = 'switch-label';
|
||||||
|
label.innerHTML = info.name;
|
||||||
|
|
||||||
|
el.appendChild(swit);
|
||||||
|
el.appendChild(label);
|
||||||
|
|
||||||
|
swit.addEventListener("click", this._ui_toggle_setting.bind(this, swit, key));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
el.classList.add("option");
|
||||||
|
var link = document.createElement('a');
|
||||||
|
link.innerHTML = info.name;
|
||||||
|
link.href = "#";
|
||||||
|
el.appendChild(link);
|
||||||
|
|
||||||
|
link.addEventListener("click", info.method.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( info.help ) {
|
||||||
|
var help = document.createElement('span');
|
||||||
|
help.className = 'help';
|
||||||
|
help.innerHTML = info.help;
|
||||||
|
el.appendChild(help);
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.appendChild(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
container.appendChild(menu);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
name: "Settings",
|
name: "Settings",
|
||||||
|
@ -236,8 +266,7 @@ FFZ.menu_pages.channel = {
|
||||||
var room_id = view.get('controller.currentRoom.id'),
|
var room_id = view.get('controller.currentRoom.id'),
|
||||||
room = this.rooms[room_id];
|
room = this.rooms[room_id];
|
||||||
|
|
||||||
this.log("Menu for Room: " + room_id, room);
|
//this.track('trackEvent', 'Menu', 'Open', room_id);
|
||||||
this.track('trackEvent', 'Menu', 'Open', room_id);
|
|
||||||
|
|
||||||
// Add the header and ad button.
|
// Add the header and ad button.
|
||||||
/*var btn = document.createElement('a');
|
/*var btn = document.createElement('a');
|
||||||
|
|
|
@ -19,6 +19,7 @@ FFZ.settings_info.highlight_notifications = {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: false,
|
value: false,
|
||||||
|
|
||||||
|
category: "Chat",
|
||||||
visible: function() { return ! this.has_bttv },
|
visible: function() { return ! this.has_bttv },
|
||||||
|
|
||||||
name: "Highlight Notifications",
|
name: "Highlight Notifications",
|
||||||
|
@ -54,7 +55,7 @@ FFZ.settings_info.highlight_notifications = {
|
||||||
// ---------------------
|
// ---------------------
|
||||||
|
|
||||||
FFZ.ws_commands.message = function(message) {
|
FFZ.ws_commands.message = function(message) {
|
||||||
this.show_mesage(message);
|
this.show_message(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ FFZ.prototype.setup_races = function() {
|
||||||
FFZ.settings_info.srl_races = {
|
FFZ.settings_info.srl_races = {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: true,
|
value: true,
|
||||||
|
|
||||||
|
category: "Channel Metadata",
|
||||||
name: "SRL Race Information",
|
name: "SRL Race Information",
|
||||||
help: 'Display information about <a href="http://www.speedrunslive.com/" target="_new">SpeedRunsLive</a> races under channels.',
|
help: 'Display information about <a href="http://www.speedrunslive.com/" target="_new">SpeedRunsLive</a> races under channels.',
|
||||||
on_update: function(val) {
|
on_update: function(val) {
|
||||||
|
|
41
src/utils.js
41
src/utils.js
|
@ -11,8 +11,42 @@ var sanitize_cache = {},
|
||||||
else if ( num == 3 ) return '3rd';
|
else if ( num == 3 ) return '3rd';
|
||||||
else if ( num == null ) return '---';
|
else if ( num == null ) return '---';
|
||||||
return num + "th";
|
return num + "th";
|
||||||
|
},
|
||||||
|
|
||||||
|
brighten = function(rgb, amount) {
|
||||||
|
amount = (amount === 0) ? 0 : (amount || 1);
|
||||||
|
amount = Math.round(255 * -(amount / 100));
|
||||||
|
|
||||||
|
var r = Math.max(0, Math.min(255, rgb[0] - amount)),
|
||||||
|
g = Math.max(0, Math.min(255, rgb[1] - amount)),
|
||||||
|
b = Math.max(0, Math.min(255, rgb[2] - amount));
|
||||||
|
|
||||||
|
return [r,g,b];
|
||||||
|
},
|
||||||
|
|
||||||
|
rgb_to_css = function(rgb) {
|
||||||
|
return "rgb(" + rgb[0] + ", " + rgb[1] + ", " + rgb[2] + ")";
|
||||||
|
},
|
||||||
|
|
||||||
|
darken = function(rgb, amount) {
|
||||||
|
amount = (amount === 0) ? 0 : (amount || 1);
|
||||||
|
return brighten(rgb, -amount);
|
||||||
|
},
|
||||||
|
|
||||||
|
get_luminance = function(rgb) {
|
||||||
|
rgb = [rgb[0]/255, rgb[1]/255, rgb[2]/255];
|
||||||
|
for (var i =0; i<rgb.length; i++) {
|
||||||
|
if (rgb[i] <= 0.03928) {
|
||||||
|
rgb[i] = rgb[i] / 12.92;
|
||||||
|
} else {
|
||||||
|
rgb[i] = Math.pow( ((rgb[i]+0.055)/1.055), 2.4 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var l = (0.2126 * rgb[0]) + (0.7152 * rgb[1]) + (0.0722 * rgb[2]);
|
||||||
|
return l;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
update_css: function(element, id, css) {
|
update_css: function(element, id, css) {
|
||||||
var all = element.innerHTML,
|
var all = element.innerHTML,
|
||||||
|
@ -34,6 +68,11 @@ module.exports = {
|
||||||
element.innerHTML = all;
|
element.innerHTML = all;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get_luminance: get_luminance,
|
||||||
|
brighten: brighten,
|
||||||
|
darken: darken,
|
||||||
|
rgb_to_css: rgb_to_css,
|
||||||
|
|
||||||
number_commas: function(x) {
|
number_commas: function(x) {
|
||||||
var parts = x.toString().split(".");
|
var parts = x.toString().split(".");
|
||||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||||
|
@ -41,7 +80,7 @@ module.exports = {
|
||||||
},
|
},
|
||||||
|
|
||||||
place_string: place_string,
|
place_string: place_string,
|
||||||
|
|
||||||
placement: function(entrant) {
|
placement: function(entrant) {
|
||||||
if ( entrant.state == "forfeit" ) return "Forfeit";
|
if ( entrant.state == "forfeit" ) return "Forfeit";
|
||||||
else if ( entrant.state == "dq" ) return "DQed";
|
else if ( entrant.state == "dq" ) return "DQed";
|
||||||
|
|
155
style.css
155
style.css
|
@ -16,8 +16,17 @@
|
||||||
.ffz-ui-toggle svg.svg-emoticons path { fill: rgba(0,0,0,0.2); }
|
.ffz-ui-toggle svg.svg-emoticons path { fill: rgba(0,0,0,0.2); }
|
||||||
.ffz-ui-toggle:hover svg.svg-emoticons path { fill: rgba(0,0,0,0.5); }
|
.ffz-ui-toggle:hover svg.svg-emoticons path { fill: rgba(0,0,0,0.5); }
|
||||||
|
|
||||||
.chat-container.dark .ffz-ui-toggle svg.svg-emoticons path,.app-main.theatre .ffz-ui-toggle svg.svg-emoticons path,.ffz-ui-toggle.dark svg.svg-emoticons path { fill: #888; }
|
|
||||||
.chat-container.dark .ffz-ui-toggle:hover svg.svg-emoticons path,.app-main.theatre .ffz-ui-toggle:hover svg.svg-emoticons path,.ffz-ui-toggle.dark:hover svg.svg-emoticons path { fill: #777; }
|
.ember-chat-container.dark .ffz-ui-toggle svg.svg-emoticons path,
|
||||||
|
.chat-container.dark .ffz-ui-toggle svg.svg-emoticons path,
|
||||||
|
.app-main.theatre .ffz-ui-toggle svg.svg-emoticons path,
|
||||||
|
.ffz-ui-toggle.dark svg.svg-emoticons path { fill: #888; }
|
||||||
|
|
||||||
|
.ember-chat-container.dark .ffz-ui-toggle:hover svg.svg-emoticons path,
|
||||||
|
.chat-container.dark .ffz-ui-toggle:hover svg.svg-emoticons path,
|
||||||
|
.app-main.theatre .ffz-ui-toggle:hover svg.svg-emoticons path,
|
||||||
|
.ffz-ui-toggle.dark:hover svg.svg-emoticons path { fill: #777; }
|
||||||
|
|
||||||
|
|
||||||
.ffz-ui-toggle.no-emotes svg.svg-emoticons path { fill: rgba(80,0,0,0.2); }
|
.ffz-ui-toggle.no-emotes svg.svg-emoticons path { fill: rgba(80,0,0,0.2); }
|
||||||
.ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path { fill: rgba(80,0,0,0.5); }
|
.ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path { fill: rgba(80,0,0,0.5); }
|
||||||
|
@ -28,14 +37,37 @@
|
||||||
.ffz-ui-toggle.blue.live svg.svg-emoticons path { fill: rgba(47,88,185,0.5); }
|
.ffz-ui-toggle.blue.live svg.svg-emoticons path { fill: rgba(47,88,185,0.5); }
|
||||||
.ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill: rgba(47,88,185,1); }
|
.ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill: rgba(47,88,185,1); }
|
||||||
|
|
||||||
.app-main.theatre .ffz-ui-toggle.no-emotes svg.svg-emoticons path,.chat-container.dark .ffz-ui-toggle.no-emotes svg.svg-emoticons path,.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.no-emotes svg.svg-emoticons path { fill: #543f3f; }
|
|
||||||
.app-main.theatre .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path,.chat-container.dark .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path,.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.no-emotes:hover svg.svg-emoticons path { fill: #453434; }
|
|
||||||
|
|
||||||
.app-main.theatre .ffz-ui-toggle.live svg.svg-emoticons path,.chat-container.dark .ffz-ui-toggle.live svg.svg-emoticons path,.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.live svg.svg-emoticons path { fill: #5b4487; }
|
.ember-chat-container.dark .ffz-ui-toggle.no-emotes svg.svg-emoticons path,
|
||||||
.app-main.theatre .ffz-ui-toggle.live:hover svg.svg-emoticons path,.chat-container.dark .ffz-ui-toggle.live:hover svg.svg-emoticons path,.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.live:hover svg.svg-emoticons path { fill: #513c78; }
|
.app-main.theatre .ffz-ui-toggle.no-emotes svg.svg-emoticons path,
|
||||||
|
.chat-container.dark .ffz-ui-toggle.no-emotes svg.svg-emoticons path,
|
||||||
|
.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.no-emotes svg.svg-emoticons path { fill: #453434; }
|
||||||
|
|
||||||
|
.ember-chat-container.dark .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path,
|
||||||
|
.app-main.theatre .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path,
|
||||||
|
.chat-container.dark .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path,
|
||||||
|
.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.no-emotes:hover svg.svg-emoticons path { fill: #543f3f; }
|
||||||
|
|
||||||
|
.ember-chat-container.dark .ffz-ui-toggle.live svg.svg-emoticons path,
|
||||||
|
.app-main.theatre .ffz-ui-toggle.live svg.svg-emoticons path,
|
||||||
|
.chat-container.dark .ffz-ui-toggle.live svg.svg-emoticons path,
|
||||||
|
.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.live svg.svg-emoticons path { fill: #513c78; }
|
||||||
|
|
||||||
|
.ember-chat-container.dark .ffz-ui-toggle.live:hover svg.svg-emoticons path,
|
||||||
|
.app-main.theatre .ffz-ui-toggle.live:hover svg.svg-emoticons path,
|
||||||
|
.chat-container.dark .ffz-ui-toggle.live:hover svg.svg-emoticons path,
|
||||||
|
.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.live:hover svg.svg-emoticons path { fill: #5b4487; }
|
||||||
|
|
||||||
|
.ember-chat-container.dark .ffz-ui-toggle.blue.live svg.svg-emoticons path,
|
||||||
|
.app-main.theatre .ffz-ui-toggle.blue.live svg.svg-emoticons path,
|
||||||
|
.chat-container.dark .ffz-ui-toggle.blue.live svg.svg-emoticons path,
|
||||||
|
.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.blue.live svg.svg-emoticons path { fill: #3c4e78; }
|
||||||
|
|
||||||
|
.ember-chat-container.dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path,
|
||||||
|
.app-main.theatre .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path,
|
||||||
|
.chat-container.dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path,
|
||||||
|
.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.blue.live:hover svg.svg-emoticons path { fill: #445887; }
|
||||||
|
|
||||||
.app-main.theatre .ffz-ui-toggle.blue.live svg.svg-emoticons path,.chat-container.dark .ffz-ui-toggle.blue.live svg.svg-emoticons path,.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.blue.live svg.svg-emoticons path { fill: #445887; }
|
|
||||||
.app-main.theatre .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path,.chat-container.dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path,.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.blue.live:hover svg.svg-emoticons path { fill: #3c4e78; }
|
|
||||||
|
|
||||||
.ffz-ui-toggle.live {
|
.ffz-ui-toggle.live {
|
||||||
animation: ffzfade 8s linear infinite;
|
animation: ffzfade 8s linear infinite;
|
||||||
|
@ -158,7 +190,9 @@
|
||||||
fill: rgba(255,255,255,0.35) !important;
|
fill: rgba(255,255,255,0.35) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-main.theatre .follow-button .notify:before, .app-main.theatre .button.drop:after, .app-main.theatre .follow-button .drop.follow:after {
|
.app-main.theatre .follow-button .notify:before,
|
||||||
|
.app-main.theatre .button.drop:after,
|
||||||
|
.app-main.theatre .follow-button .drop.follow:after {
|
||||||
border: 5px solid rgba(255,255,255,0.35);
|
border: 5px solid rgba(255,255,255,0.35);
|
||||||
border-left-color: transparent;
|
border-left-color: transparent;
|
||||||
border-right-color: transparent;
|
border-right-color: transparent;
|
||||||
|
@ -258,7 +292,8 @@
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ffz-race-popup a.twitch, #ffz-race-popup a.hitbox {
|
#ffz-race-popup a.twitch,
|
||||||
|
#ffz-race-popup a.hitbox {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
|
@ -287,12 +322,24 @@
|
||||||
|
|
||||||
/* Menu Options */
|
/* Menu Options */
|
||||||
|
|
||||||
|
@media screen and (max-width: 369px) {
|
||||||
|
.ember-chat-container .ember-chat .chat-interface .emoticon-selector {
|
||||||
|
right: -10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.ffz-ui-menu-page {
|
.ffz-ui-menu-page {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
margin: 0 -20px;
|
margin: 0 -20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
border-bottom: 1px solid rgba(0,0,0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content {
|
.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content {
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
@ -341,7 +388,7 @@
|
||||||
margin-bottom: -1px;
|
margin-bottom: -1px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-left: 1px solid rgba(0,0,0,0.2);
|
border-left: 1px solid rgba(0,0,0,0.2);
|
||||||
border-bottom: 1px solid rgba(0,0,0,0.2);
|
border-bottom: 1px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ffz-ui-popup ul.menu li.active {
|
.ffz-ui-popup ul.menu li.active {
|
||||||
|
@ -375,13 +422,79 @@
|
||||||
background-color: rgba(255,255,255, 0.75);
|
background-color: rgba(255,255,255, 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ffz-chat-background.theatre .chat-container .chat-line .mentioned, .ffz-chat-background .chat-container.dark .chat-line .mentioned {
|
.ffz-chat-background .app-main.theatre .chat-container .chat-line .mentioned,
|
||||||
|
.ffz-chat-background .ember-chat-container.dark .chat-line .mentioned,
|
||||||
|
.ffz-chat-background .chat-container.dark .chat-line .mentioned {
|
||||||
color: #8c8c9c;
|
color: #8c8c9c;
|
||||||
background-color: rgba(16,16,20, 0.75);
|
background-color: rgba(16,16,20, 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Fix Moderation Cards */
|
||||||
|
|
||||||
|
.ember-chat .moderation-card {
|
||||||
|
box-shadow: #808080 0 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ember-chat .moderation-card button {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ember-chat .moderation-card button:not(.glyph-only):hover,
|
||||||
|
.ember-chat .moderation-card button:not(.glyph-only):focus {
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgba(117,80,186, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ember-chat .moderation-card button.message {
|
||||||
|
height: 30px; width: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ember-chat .ffz-moderation-card .interface .mod-controls:last-of-type,
|
||||||
|
.ember-chat .moderation-card .interface span.right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ember-chat .moderation-card:focus {
|
||||||
|
outline: none;
|
||||||
|
box-shadow: #000 0 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ember-chat-container.dark .ember-chat .moderation-card:focus,
|
||||||
|
.chat-container.dark .ember-chat .moderation-card:focus,
|
||||||
|
.app-main.theatre .ember-chat .moderation-card:focus {
|
||||||
|
box-shadow: #fff 0 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ember-chat-container.dark .ember-chat .moderation-card .interface,
|
||||||
|
.chat-container.dark .ember-chat .moderation-card .interface,
|
||||||
|
.app-main.theatre .ember-chat .moderation-card .interface {
|
||||||
|
background-color: #232329;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ember-chat .ffz-moderation-card .interface:not(:last-of-type) {
|
||||||
|
border-bottom: none;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ember-chat .moderation-card .interface {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ember-chat .moderation-card h3.name {
|
||||||
|
display: inline-block;
|
||||||
|
text-shadow: black 0 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ember-chat .moderation-card .channel_background {
|
||||||
|
width: 100%;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Chat Rows */
|
/* Chat Rows */
|
||||||
|
|
||||||
.ffz-chat-background .more-messages-indicator {
|
.ffz-chat-background .more-messages-indicator {
|
||||||
/* This looks better when it's full width. */
|
/* This looks better when it's full width. */
|
||||||
margin: 0 -20px;
|
margin: 0 -20px;
|
||||||
|
@ -404,10 +517,6 @@
|
||||||
background-color: rgba(0,0,0, 0.1);
|
background-color: rgba(0,0,0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.theatre.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-alternate, .ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-alternate {
|
|
||||||
background-color: rgba(255,255,255, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-mentioned {
|
.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-mentioned {
|
||||||
background-color: rgba(255,127,127, 0.2);
|
background-color: rgba(255,127,127, 0.2);
|
||||||
}
|
}
|
||||||
|
@ -416,10 +525,20 @@
|
||||||
background-color: rgba(255,127,127, 0.4);
|
background-color: rgba(255,127,127, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.theatre.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-mentioned, .ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned {
|
.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .chat-line.ffz-alternate,
|
||||||
|
.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-alternate,
|
||||||
|
.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .chat-line.ffz-alternate {
|
||||||
|
background-color: rgba(255,255,255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .chat-line.ffz-mentioned,
|
||||||
|
.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned,
|
||||||
|
.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned {
|
||||||
background-color: rgba(255,0,0, 0.2);
|
background-color: rgba(255,0,0, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.theatre.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate, .ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate {
|
.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate,
|
||||||
|
.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate,
|
||||||
|
.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate {
|
||||||
background-color: rgba(255,0,0, 0.3);
|
background-color: rgba(255,0,0, 0.3);
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue