1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-18 12:00:53 +00:00

Clean up file formatting. Mixed line endings and white spacing are the worst.

This commit is contained in:
SirStendec 2016-07-13 02:31:26 -04:00
parent 3fb0c5a358
commit 4b11c2f591
41 changed files with 4053 additions and 4053 deletions

View file

@ -275,6 +275,6 @@ if (typeof module !== "undefined" && module.exports) {
module.exports.saveAs = saveAs; module.exports.saveAs = saveAs;
} else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) { } else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) {
define([], function() { define([], function() {
return saveAs; return saveAs;
}); });
} }

View file

@ -132,9 +132,9 @@ FFZ.settings_info.sub_notice_badges = {
name: "Old-Style Subscriber Notice Badges", name: "Old-Style Subscriber Notice Badges",
no_bttv: true, no_bttv: true,
help: "Display a subscriber badge on old-style chat messages about new subscribers.", help: "Display a subscriber badge on old-style chat messages about new subscribers.",
on_update: function(val) { on_update: function(val) {
this.toggle_style('badges-sub-notice', ! this.has_bttv && ! val); this.toggle_style('badges-sub-notice', ! this.has_bttv && ! val);
this.toggle_style('badges-sub-notice-on', ! this.has_bttv && val); this.toggle_style('badges-sub-notice-on', ! this.has_bttv && val);
} }
@ -231,8 +231,8 @@ FFZ.prototype.setup_badges = function() {
this.toggle_style('badges-transparent', val === 5); this.toggle_style('badges-transparent', val === 5);
document.body.classList.toggle('ffz-transparent-badges', val === 5); document.body.classList.toggle('ffz-transparent-badges', val === 5);
this.toggle_style('badges-sub-notice', ! this.settings.sub_notice_badges); this.toggle_style('badges-sub-notice', ! this.settings.sub_notice_badges);
this.toggle_style('badges-sub-notice-on', this.settings.sub_notice_badges); this.toggle_style('badges-sub-notice-on', this.settings.sub_notice_badges);
} }
this.toggle_style('badges-legacy', this.settings.legacy_badges === 3); this.toggle_style('badges-legacy', this.settings.legacy_badges === 3);
@ -345,9 +345,9 @@ FFZ.prototype.get_line_badges = function(msg) {
last_id = -1, last_id = -1,
had_last = false, had_last = false,
room = msg.get && msg.get('room') || msg.room, room = msg.get && msg.get('room') || msg.room,
from = msg.get && msg.get('from') || msg.from, from = msg.get && msg.get('from') || msg.from,
tags = msg.get && msg.get('tags') || msg.tags || {}, tags = msg.get && msg.get('tags') || msg.tags || {},
badge_tag = tags.badges || {}, badge_tag = tags.badges || {},
service = utils.ember_lookup('service:badges'), service = utils.ember_lookup('service:badges'),

View file

@ -1,5 +1,5 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
utils = require('./utils'), utils = require('./utils'),
hue2rgb = function(p, q, t) { hue2rgb = function(p, q, t) {
if ( t < 0 ) t += 1; if ( t < 0 ) t += 1;
@ -66,30 +66,30 @@ FFZ.settings_info.luv_contrast = {
method: function() { method: function() {
var f = this, var f = this,
old_val = this.settings.luv_contrast; old_val = this.settings.luv_contrast;
utils.prompt( utils.prompt(
"Luv Adjustment Minimum Contrast Ratio", "Luv Adjustment Minimum Contrast Ratio",
"Please enter a new value for the minimum contrast ratio required between username colors and the background.</p><p><b>Default:</b> 4.5", "Please enter a new value for the minimum contrast ratio required between username colors and the background.</p><p><b>Default:</b> 4.5",
old_val, old_val,
function(new_val) { function(new_val) {
if ( new_val === null || new_val === undefined ) if ( new_val === null || new_val === undefined )
return; return;
var parsed = parseFloat(new_val); var parsed = parseFloat(new_val);
if ( Number.isNaN(parsed) || ! Number.isFinite(parsed) ) if ( Number.isNaN(parsed) || ! Number.isFinite(parsed) )
parsed = 4.5; parsed = 4.5;
f.settings.set("luv_contrast", parsed); f.settings.set("luv_contrast", parsed);
}); });
}, },
on_update: function(val) { on_update: function(val) {
this._rebuild_contrast(); this._rebuild_contrast();
this._rebuild_filter_styles(); this._rebuild_filter_styles();
if ( ! this.has_bttv && this.settings.fix_color == '1' ) if ( ! this.has_bttv && this.settings.fix_color == '1' )
this._rebuild_colors(); this._rebuild_colors();
} }
}; };
@ -199,26 +199,26 @@ RGBAColor.prototype.eq = function(rgb) {
} }
RGBAColor.fromName = function(name) { RGBAColor.fromName = function(name) {
var context = FFZ.Color._context; var context = FFZ.Color._context;
if ( ! context ) { if ( ! context ) {
var canvas = FFZ.Color._canvas = document.createElement('canvas'); var canvas = FFZ.Color._canvas = document.createElement('canvas');
context = FFZ.Color._context = canvas.getContext("2d"); context = FFZ.Color._context = canvas.getContext("2d");
} }
context.clearRect(0,0,1,1); context.clearRect(0,0,1,1);
context.fillStyle = name; context.fillStyle = name;
context.fillRect(0,0,1,1); context.fillRect(0,0,1,1);
var data = context.getImageData(0,0,1,1); var data = context.getImageData(0,0,1,1);
if ( ! data || ! data.data || data.data.length !== 4 ) if ( ! data || ! data.data || data.data.length !== 4 )
return null; return null;
return new RGBAColor(data.data[0], data.data[1], data.data[2], data.data[3] / 255); return new RGBAColor(data.data[0], data.data[1], data.data[2], data.data[3] / 255);
} }
RGBAColor.fromCSS = function(rgb) { RGBAColor.fromCSS = function(rgb) {
if ( ! rgb ) if ( ! rgb )
return null; return null;
rgb = rgb.trim(); rgb = rgb.trim();
@ -230,7 +230,7 @@ RGBAColor.fromCSS = function(rgb) {
var r = match[1], var r = match[1],
g = match[2], g = match[2],
b = match[3], b = match[3],
a = match[4]; a = match[4];
if ( r.charAt(r.length-1) === '%' ) if ( r.charAt(r.length-1) === '%' )
r = 255 * (parseInt(r) / 100); r = 255 * (parseInt(r) / 100);
@ -247,19 +247,19 @@ RGBAColor.fromCSS = function(rgb) {
else else
b = parseInt(b); b = parseInt(b);
if ( a ) if ( a )
if ( a.charAt(a.length-1) === '%' ) if ( a.charAt(a.length-1) === '%' )
a = parseInt(a) / 100; a = parseInt(a) / 100;
else else
a = parseFloat(a); a = parseFloat(a);
else else
a = 1; a = 1;
return new RGBAColor( return new RGBAColor(
Math.min(Math.max(0, r), 255), Math.min(Math.max(0, r), 255),
Math.min(Math.max(0, g), 255), Math.min(Math.max(0, g), 255),
Math.min(Math.max(0, b), 255), Math.min(Math.max(0, b), 255),
Math.min(Math.max(0, a), 1) Math.min(Math.max(0, a), 1)
); );
} }
@ -272,7 +272,7 @@ RGBAColor.fromHex = function(code) {
(raw >> 16), // Red (raw >> 16), // Red
(raw >> 8 & 0x00FF), // Green (raw >> 8 & 0x00FF), // Green
(raw & 0x0000FF), // Blue, (raw & 0x0000FF), // Blue,
1 // Alpha 1 // Alpha
) )
} }
@ -298,7 +298,7 @@ RGBAColor.fromHSVA = function(h, s, v, a) {
Math.round(Math.min(Math.max(0, r*255), 255)), Math.round(Math.min(Math.max(0, r*255), 255)),
Math.round(Math.min(Math.max(0, g*255), 255)), Math.round(Math.min(Math.max(0, g*255), 255)),
Math.round(Math.min(Math.max(0, b*255), 255)), Math.round(Math.min(Math.max(0, b*255), 255)),
a === undefined ? 1 : a a === undefined ? 1 : a
); );
} }
@ -312,7 +312,7 @@ RGBAColor.fromXYZA = function(x, y, z, a) {
Math.max(0, Math.min(255, 255 * XYZAColor.channelConverter(R))), Math.max(0, Math.min(255, 255 * XYZAColor.channelConverter(R))),
Math.max(0, Math.min(255, 255 * XYZAColor.channelConverter(G))), Math.max(0, Math.min(255, 255 * XYZAColor.channelConverter(G))),
Math.max(0, Math.min(255, 255 * XYZAColor.channelConverter(B))), Math.max(0, Math.min(255, 255 * XYZAColor.channelConverter(B))),
a === undefined ? 1 : a a === undefined ? 1 : a
); );
} }
@ -329,7 +329,7 @@ RGBAColor.fromHSLA = function(h, s, l, a) {
Math.round(Math.min(Math.max(0, 255 * hue2rgb(p, q, h + 1/3)), 255)), Math.round(Math.min(Math.max(0, 255 * hue2rgb(p, q, h + 1/3)), 255)),
Math.round(Math.min(Math.max(0, 255 * hue2rgb(p, q, h)), 255)), Math.round(Math.min(Math.max(0, 255 * hue2rgb(p, q, h)), 255)),
Math.round(Math.min(Math.max(0, 255 * hue2rgb(p, q, h - 1/3)), 255)), Math.round(Math.min(Math.max(0, 255 * hue2rgb(p, q, h - 1/3)), 255)),
a === undefined ? 1 : a a === undefined ? 1 : a
); );
} }
@ -366,7 +366,7 @@ RGBAColor.prototype.brighten = function(amount) {
Math.max(0, Math.min(255, this.r + amount)), Math.max(0, Math.min(255, this.r + amount)),
Math.max(0, Math.min(255, this.g + amount)), Math.max(0, Math.min(255, this.g + amount)),
Math.max(0, Math.min(255, this.b + amount)), Math.max(0, Math.min(255, this.b + amount)),
this.a this.a
); );
} }
@ -548,7 +548,7 @@ XYZAColor.fromRGBA = function(r, g, b, a) {
0.412453 * R + 0.357580 * G + 0.180423 * B, 0.412453 * R + 0.357580 * G + 0.180423 * B,
0.212671 * R + 0.715160 * G + 0.072169 * B, 0.212671 * R + 0.715160 * G + 0.072169 * B,
0.019334 * R + 0.119193 * G + 0.950227 * B, 0.019334 * R + 0.119193 * G + 0.950227 * B,
a === undefined ? 1 : a a === undefined ? 1 : a
); );
} }
@ -638,8 +638,8 @@ FFZ.prototype._rebuild_contrast = function() {
this._luv_required_bright = new XYZAColor(0, (this.settings.luv_contrast * (new RGBAColor(35,35,35,1).toXYZA().y + 0.05) - 0.05), 0, 1).toLUVA().l; this._luv_required_bright = new XYZAColor(0, (this.settings.luv_contrast * (new RGBAColor(35,35,35,1).toXYZA().y + 0.05) - 0.05), 0, 1).toLUVA().l;
this._luv_required_dark = new XYZAColor(0, ((new RGBAColor(217,217,217,1).toXYZA().y + 0.05) / this.settings.luv_contrast - 0.05), 0, 1).toLUVA().l; this._luv_required_dark = new XYZAColor(0, ((new RGBAColor(217,217,217,1).toXYZA().y + 0.05) / this.settings.luv_contrast - 0.05), 0, 1).toLUVA().l;
this._luv_background_bright = new XYZAColor(0, (this.settings.luv_contrast * (RGBAColor.fromCSS("#3c3a41").toXYZA().y + 0.05) - 0.05), 0, 1).toLUVA().l; this._luv_background_bright = new XYZAColor(0, (this.settings.luv_contrast * (RGBAColor.fromCSS("#3c3a41").toXYZA().y + 0.05) - 0.05), 0, 1).toLUVA().l;
this._luv_background_dark = new XYZAColor(0, ((RGBAColor.fromCSS("#acacbf").toXYZA().y + 0.05) / this.settings.luv_contrast - 0.05), 0, 1).toLUVA().l; this._luv_background_dark = new XYZAColor(0, ((RGBAColor.fromCSS("#acacbf").toXYZA().y + 0.05) / this.settings.luv_contrast - 0.05), 0, 1).toLUVA().l;
} }
FFZ.prototype._rebuild_colors = function() { FFZ.prototype._rebuild_colors = function() {
@ -658,7 +658,7 @@ FFZ.prototype._update_colors = function(darkness_only) {
Settings = utils.ember_lookup('controller:settings'), Settings = utils.ember_lookup('controller:settings'),
is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('settings.darkMode')), is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('settings.darkMode')),
cr_dark = this.settings.dark_twitch || (Layout && Layout.get('isTheatreMode')); cr_dark = this.settings.dark_twitch || (Layout && Layout.get('isTheatreMode'));
if ( darkness_only && this._color_old_darkness === is_dark ) if ( darkness_only && this._color_old_darkness === is_dark )
return; return;
@ -680,20 +680,20 @@ FFZ.prototype._update_colors = function(darkness_only) {
FFZ.prototype._handle_filter_color = function(color) { FFZ.prototype._handle_filter_color = function(color) {
if (!( color instanceof RGBAColor )) if (!( color instanceof RGBAColor ))
color = RGBAColor.fromCSS(color); color = RGBAColor.fromCSS(color);
var light_color = color, var light_color = color,
dark_color = color, dark_color = color,
luv = color.toLUVA(); luv = color.toLUVA();
if ( luv.l < this._luv_background_bright ) if ( luv.l < this._luv_background_bright )
light_color = luv._l(this._luv_background_bright).toRGBA(); light_color = luv._l(this._luv_background_bright).toRGBA();
if ( luv.l > this._luv_background_dark ) if ( luv.l > this._luv_background_dark )
dark_color = luv._l(this._luv_background_dark).toRGBA(); dark_color = luv._l(this._luv_background_dark).toRGBA();
return [light_color, dark_color]; return [light_color, dark_color];
} }
@ -701,90 +701,90 @@ FFZ.prototype._handle_color = function(color) {
if ( color instanceof RGBAColor ) if ( color instanceof RGBAColor )
color = color.toCSS(); color = color.toCSS();
if ( ! color ) if ( ! color )
return null; return null;
if ( this._hex_colors.hasOwnProperty(color) ) if ( this._hex_colors.hasOwnProperty(color) )
return this._hex_colors[color]; return this._hex_colors[color];
var rgb = RGBAColor.fromCSS(color), var rgb = RGBAColor.fromCSS(color),
light_color = rgb, light_color = rgb,
dark_color = rgb; dark_color = rgb;
// Color Blindness Handling // Color Blindness Handling
if ( this.settings.color_blind !== '0' ) { if ( this.settings.color_blind !== '0' ) {
var new_color = rgb.daltonize(this.settings.color_blind); var new_color = rgb.daltonize(this.settings.color_blind);
if ( ! rgb.eq(new_color) ) { if ( ! rgb.eq(new_color) ) {
rgb = new_color; rgb = new_color;
light_color = dark_color = rgb; light_color = dark_color = rgb;
} }
} }
// Color Processing - RGB // Color Processing - RGB
if ( this.settings.fix_color === '4' ) { if ( this.settings.fix_color === '4' ) {
var lum = rgb.luminance(); var lum = rgb.luminance();
if ( lum > 0.3 ) { if ( lum > 0.3 ) {
var s = 127, nc = rgb; var s = 127, nc = rgb;
while(s--) { while(s--) {
nc = nc.brighten(-1); nc = nc.brighten(-1);
if ( nc.luminance() <= 0.3 ) if ( nc.luminance() <= 0.3 )
break; break;
} }
light_color = nc; light_color = nc;
} }
if ( lum < 0.15 ) { if ( lum < 0.15 ) {
var s = 127, nc = rgb; var s = 127, nc = rgb;
while(s--) { while(s--) {
nc = nc.brighten(); nc = nc.brighten();
if ( nc.luminance() >= 0.15 ) if ( nc.luminance() >= 0.15 )
break; break;
} }
dark_color = nc; dark_color = nc;
} }
} }
// Color Processing - HSL // Color Processing - HSL
if ( this.settings.fix_color === '2' ) { if ( this.settings.fix_color === '2' ) {
var hsl = rgb.toHSLA(); var hsl = rgb.toHSLA();
light_color = hsl._l(Math.min(Math.max(0, 0.7 * hsl.l), 1)).toRGBA(); light_color = hsl._l(Math.min(Math.max(0, 0.7 * hsl.l), 1)).toRGBA();
dark_color = hsl._l(Math.min(Math.max(0, 0.3 + (0.7 * hsl.l)), 1)).toRGBA(); dark_color = hsl._l(Math.min(Math.max(0, 0.3 + (0.7 * hsl.l)), 1)).toRGBA();
} }
// Color Processing - HSV // Color Processing - HSV
if ( this.settings.fix_color === '3' ) { if ( this.settings.fix_color === '3' ) {
var hsv = rgb.toHSVA(); var hsv = rgb.toHSVA();
if ( hsv.s === 0 ) { if ( hsv.s === 0 ) {
// Black and White // Black and White
light_color = hsv._v(Math.min(Math.max(0.5, 0.5 * hsv.v), 1)).toRGBA(); light_color = hsv._v(Math.min(Math.max(0.5, 0.5 * hsv.v), 1)).toRGBA();
dark_color = hsv._v(Math.min(Math.max(0.5, 0.5 + (0.5 * hsv.v)), 1)).toRGBA(); dark_color = hsv._v(Math.min(Math.max(0.5, 0.5 + (0.5 * hsv.v)), 1)).toRGBA();
} else { } else {
light_color = RGBAColor.fromHSVA(hsv.h, Math.min(Math.max(0.7, 0.7 + (0.3 * hsv.s)), 1), Math.min(0.7, hsv.v), hsv.a); light_color = RGBAColor.fromHSVA(hsv.h, Math.min(Math.max(0.7, 0.7 + (0.3 * hsv.s)), 1), Math.min(0.7, hsv.v), hsv.a);
dark_color = RGBAColor.fromHSVA(hsv.h, Math.min(0.7, hsv.s), Math.min(Math.max(0.7, 0.7 + (0.3 * hsv.v)), 1), hsv.a); dark_color = RGBAColor.fromHSVA(hsv.h, Math.min(0.7, hsv.s), Math.min(Math.max(0.7, 0.7 + (0.3 * hsv.v)), 1), hsv.a);
} }
} }
// Color Processing - LUV // Color Processing - LUV
if ( this.settings.fix_color === '1' ) { if ( this.settings.fix_color === '1' ) {
var luv = rgb.toLUVA(); var luv = rgb.toLUVA();
if ( luv.l > this._luv_required_dark ) if ( luv.l > this._luv_required_dark )
light_color = luv._l(this._luv_required_dark).toRGBA(); light_color = luv._l(this._luv_required_dark).toRGBA();
if ( luv.l < this._luv_required_bright ) if ( luv.l < this._luv_required_bright )
dark_color = luv._l(this._luv_required_bright).toRGBA(); dark_color = luv._l(this._luv_required_bright).toRGBA();
} }
var out = this._hex_colors[color] = [light_color.toHex(), dark_color.toHex()]; var out = this._hex_colors[color] = [light_color.toHex(), dark_color.toHex()];
return out; return out;
} }

View file

@ -6,12 +6,12 @@ var SVGPATH = 'm120.95 1.74c4.08-0.09 8.33-0.84 12.21 0.82 3.61 1.8 7 4.16 11.01
IS_OSX = navigator.platform ? navigator.platform.indexOf('Mac') !== -1 : /OS X/.test(navigator.userAgent), IS_OSX = navigator.platform ? navigator.platform.indexOf('Mac') !== -1 : /OS X/.test(navigator.userAgent),
IS_WIN = navigator.platform ? navigator.platform.indexOf('Win') !== -1 : /Windows/.test(navigator.userAgent), IS_WIN = navigator.platform ? navigator.platform.indexOf('Win') !== -1 : /Windows/.test(navigator.userAgent),
SEPARATORS = "[\\s`~<>!-#%-\\x2A,-/:;\\x3F@\\x5B-\\x5D_\\x7B}\\u00A1\\u00A7\\u00AB\\u00B6\\u00B7\\u00BB\\u00BF\\u037E\\u0387\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061E\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u0AF0\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166D\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u2329\\u232A\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E3B\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uAAF0\\uAAF1\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65]", SEPARATORS = "[\\s`~<>!-#%-\\x2A,-/:;\\x3F@\\x5B-\\x5D_\\x7B}\\u00A1\\u00A7\\u00AB\\u00B6\\u00B7\\u00BB\\u00BF\\u037E\\u0387\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061E\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u0AF0\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166D\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u2329\\u232A\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E3B\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uAAF0\\uAAF1\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65]",
SPLITTER = new RegExp(SEPARATORS + "*," + SEPARATORS + "*"), SPLITTER = new RegExp(SEPARATORS + "*," + SEPARATORS + "*"),
svg = function(cls, width, height, path, viewbox) { svg = function(cls, width, height, path, viewbox) {
return '<svg version="1.1" class="ffz-svg svg-' + cls + '" height="' + height + 'px" width="' + width + 'px" x="0px" y="0px" viewbox="' + (viewbox||'0 0 16 16') + '"><path clip-rule="evenodd" fill-rule="evenodd" d="' + path + '"></path></svg>'; return '<svg version="1.1" class="ffz-svg svg-' + cls + '" height="' + height + 'px" width="' + width + 'px" x="0px" y="0px" viewbox="' + (viewbox||'0 0 16 16') + '"><path clip-rule="evenodd" fill-rule="evenodd" d="' + path + '"></path></svg>';
}; };
module.exports = FrankerFaceZ.constants = { module.exports = FrankerFaceZ.constants = {
@ -22,8 +22,8 @@ module.exports = FrankerFaceZ.constants = {
IS_WIN: IS_WIN, IS_WIN: IS_WIN,
META_NAME: IS_OSX ? "⌘" : (IS_WIN ? "Win" : "Meta"), META_NAME: IS_OSX ? "⌘" : (IS_WIN ? "Win" : "Meta"),
// Twitch Client ID for API Stuff // Twitch Client ID for API Stuff
CLIENT_ID: "a3bc9znoz6vi8ozsoca0inlcr4fcvkl", CLIENT_ID: "a3bc9znoz6vi8ozsoca0inlcr4fcvkl",
API_SERVER: "https://api.frankerfacez.com/", API_SERVER: "https://api.frankerfacez.com/",
@ -36,12 +36,12 @@ module.exports = FrankerFaceZ.constants = {
["wss://localhost:8001/", 1]] ["wss://localhost:8001/", 1]]
}, },
CHAT_COLORS: ["#FF0000", "#0000FF", "#008000", "#B22222", "#FF7F50", "#9ACD32", "#FF4500", "#2E8B57", "#DAA520", "#D2691E", "#5F9EA0", "#1E90FF", "#FF69B4", "#8A2BE2", "#00FF7F"], CHAT_COLORS: ["#FF0000", "#0000FF", "#008000", "#B22222", "#FF7F50", "#9ACD32", "#FF4500", "#2E8B57", "#DAA520", "#D2691E", "#5F9EA0", "#1E90FF", "#FF69B4", "#8A2BE2", "#00FF7F"],
TOOLTIP_DISTANCE: 50, TOOLTIP_DISTANCE: 50,
SEPARATORS: SEPARATORS, SEPARATORS: SEPARATORS,
SPLITTER: SPLITTER, SPLITTER: SPLITTER,
UUID_TEST: /(?:^| +)([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}) *$/i, UUID_TEST: /(?:^| +)([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}) *$/i,
@ -92,44 +92,44 @@ module.exports = FrankerFaceZ.constants = {
EMOJI_REGEX: /(\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d[\udc68\udc69]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d[\udc68\udc69]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc41\u200d\ud83d\udde8|(?:[\u0023\u002a\u0030-\u0039])\ufe0f?\u20e3|(?:(?:[\u261d\u270c])(?:\ufe0f|(?!\ufe0e))|\ud83c[\udf85\udfc2-\udfc4\udfc7\udfca\udfcb]|\ud83d[\udc42\udc43\udc46-\udc50\udc66-\udc69\udc6e\udc70-\udc78\udc7c\udc81-\udc83\udc85-\udc87\udcaa\udd75\udd90\udd95\udd96\ude45-\ude47\ude4b-\ude4f\udea3\udeb4-\udeb6\udec0]|\ud83e\udd18|[\u26f9\u270a\u270b\u270d])(?:\ud83c[\udffb-\udfff]|)|\ud83c\udde6\ud83c[\udde8-\uddec\uddee\uddf1\uddf2\uddf4\uddf6-\uddfa\uddfc\uddfd\uddff]|\ud83c\udde7\ud83c[\udde6\udde7\udde9-\uddef\uddf1-\uddf4\uddf6-\uddf9\uddfb\uddfc\uddfe\uddff]|\ud83c\udde8\ud83c[\udde6\udde8\udde9\uddeb-\uddee\uddf0-\uddf5\uddf7\uddfa-\uddff]|\ud83c\udde9\ud83c[\uddea\uddec\uddef\uddf0\uddf2\uddf4\uddff]|\ud83c\uddea\ud83c[\udde6\udde8\uddea\uddec\udded\uddf7-\uddfa]|\ud83c\uddeb\ud83c[\uddee-\uddf0\uddf2\uddf4\uddf7]|\ud83c\uddec\ud83c[\udde6\udde7\udde9-\uddee\uddf1-\uddf3\uddf5-\uddfa\uddfc\uddfe]|\ud83c\udded\ud83c[\uddf0\uddf2\uddf3\uddf7\uddf9\uddfa]|\ud83c\uddee\ud83c[\udde8-\uddea\uddf1-\uddf4\uddf6-\uddf9]|\ud83c\uddef\ud83c[\uddea\uddf2\uddf4\uddf5]|\ud83c\uddf0\ud83c[\uddea\uddec-\uddee\uddf2\uddf3\uddf5\uddf7\uddfc\uddfe\uddff]|\ud83c\uddf1\ud83c[\udde6-\udde8\uddee\uddf0\uddf7-\uddfb\uddfe]|\ud83c\uddf2\ud83c[\udde6\udde8-\udded\uddf0-\uddff]|\ud83c\uddf3\ud83c[\udde6\udde8\uddea-\uddec\uddee\uddf1\uddf4\uddf5\uddf7\uddfa\uddff]|\ud83c\uddf4\ud83c\uddf2|\ud83c\uddf5\ud83c[\udde6\uddea-\udded\uddf0-\uddf3\uddf7-\uddf9\uddfc\uddfe]|\ud83c\uddf6\ud83c\udde6|\ud83c\uddf7\ud83c[\uddea\uddf4\uddf8\uddfa\uddfc]|\ud83c\uddf8\ud83c[\udde6-\uddea\uddec-\uddf4\uddf7-\uddf9\uddfb\uddfd-\uddff]|\ud83c\uddf9\ud83c[\udde6\udde8\udde9\uddeb-\udded\uddef-\uddf4\uddf7\uddf9\uddfb\uddfc\uddff]|\ud83c\uddfa\ud83c[\udde6\uddec\uddf2\uddf8\uddfe\uddff]|\ud83c\uddfb\ud83c[\udde6\udde8\uddea\uddec\uddee\uddf3\uddfa]|\ud83c\uddfc\ud83c[\uddeb\uddf8]|\ud83c\uddfd\ud83c\uddf0|\ud83c\uddfe\ud83c[\uddea\uddf9]|\ud83c\uddff\ud83c[\udde6\uddf2\uddfc]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf21\udf24-\udf84\udf86-\udf93\udf96\udf97\udf99-\udf9b\udf9e-\udfc1\udfc5\udfc6\udfc8\udfc9\udfcc-\udff0\udff3-\udff5\udff7-\udfff]|\ud83d[\udc00-\udc41\udc44\udc45\udc51-\udc65\udc6a-\udc6d\udc6f\udc79-\udc7b\udc7d-\udc80\udc84\udc88-\udca9\udcab-\udcfd\udcff-\udd3d\udd49-\udd4e\udd50-\udd67\udd6f\udd70\udd73\udd74\udd76-\udd79\udd87\udd8a-\udd8d\udda5\udda8\uddb1\uddb2\uddbc\uddc2-\uddc4\uddd1-\uddd3\udddc-\uddde\udde1\udde3\udde8\uddef\uddf3\uddfa-\ude44\ude48-\ude4a\ude80-\udea2\udea4-\udeb3\udeb7-\udebf\udec1-\udec5\udecb-\uded0\udee0-\udee5\udee9\udeeb\udeec\udef0\udef3]|\ud83e[\udd10-\udd17\udd80-\udd84\uddc0]|[\u2328\u23cf\u23e9-\u23f3\u23f8-\u23fa\u2602-\u2604\u2618\u2620\u2622\u2623\u2626\u262a\u262e\u262f\u2638\u2692\u2694\u2696\u2697\u2699\u269b\u269c\u26b0\u26b1\u26c8\u26ce\u26cf\u26d1\u26d3\u26e9\u26f0\u26f1\u26f4\u26f7\u26f8\u2705\u271d\u2721\u2728\u274c\u274e\u2753-\u2755\u2763\u2795-\u2797\u27b0\u27bf\ue50a]|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37]|[\u00a9\u00ae\u203c\u2049\u2122\u2139\u2194-\u2199\u21a9\u21aa\u231a\u231b\u24c2\u25aa\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600\u2601\u260e\u2611\u2614\u2615\u2639\u263a\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267b\u267f\u2693\u26a0\u26a1\u26aa\u26ab\u26bd\u26be\u26c4\u26c5\u26d4\u26ea\u26f2\u26f3\u26f5\u26fa\u26fd\u2702\u2708\u2709\u270f\u2712\u2714\u2716\u2733\u2734\u2744\u2747\u2757\u2764\u27a1\u2934\u2935\u2b05-\u2b07\u2b1b\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299])(?:\ufe0f|(?!\ufe0e)))/g, EMOJI_REGEX: /(\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d[\udc68\udc69]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d[\udc68\udc69]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc41\u200d\ud83d\udde8|(?:[\u0023\u002a\u0030-\u0039])\ufe0f?\u20e3|(?:(?:[\u261d\u270c])(?:\ufe0f|(?!\ufe0e))|\ud83c[\udf85\udfc2-\udfc4\udfc7\udfca\udfcb]|\ud83d[\udc42\udc43\udc46-\udc50\udc66-\udc69\udc6e\udc70-\udc78\udc7c\udc81-\udc83\udc85-\udc87\udcaa\udd75\udd90\udd95\udd96\ude45-\ude47\ude4b-\ude4f\udea3\udeb4-\udeb6\udec0]|\ud83e\udd18|[\u26f9\u270a\u270b\u270d])(?:\ud83c[\udffb-\udfff]|)|\ud83c\udde6\ud83c[\udde8-\uddec\uddee\uddf1\uddf2\uddf4\uddf6-\uddfa\uddfc\uddfd\uddff]|\ud83c\udde7\ud83c[\udde6\udde7\udde9-\uddef\uddf1-\uddf4\uddf6-\uddf9\uddfb\uddfc\uddfe\uddff]|\ud83c\udde8\ud83c[\udde6\udde8\udde9\uddeb-\uddee\uddf0-\uddf5\uddf7\uddfa-\uddff]|\ud83c\udde9\ud83c[\uddea\uddec\uddef\uddf0\uddf2\uddf4\uddff]|\ud83c\uddea\ud83c[\udde6\udde8\uddea\uddec\udded\uddf7-\uddfa]|\ud83c\uddeb\ud83c[\uddee-\uddf0\uddf2\uddf4\uddf7]|\ud83c\uddec\ud83c[\udde6\udde7\udde9-\uddee\uddf1-\uddf3\uddf5-\uddfa\uddfc\uddfe]|\ud83c\udded\ud83c[\uddf0\uddf2\uddf3\uddf7\uddf9\uddfa]|\ud83c\uddee\ud83c[\udde8-\uddea\uddf1-\uddf4\uddf6-\uddf9]|\ud83c\uddef\ud83c[\uddea\uddf2\uddf4\uddf5]|\ud83c\uddf0\ud83c[\uddea\uddec-\uddee\uddf2\uddf3\uddf5\uddf7\uddfc\uddfe\uddff]|\ud83c\uddf1\ud83c[\udde6-\udde8\uddee\uddf0\uddf7-\uddfb\uddfe]|\ud83c\uddf2\ud83c[\udde6\udde8-\udded\uddf0-\uddff]|\ud83c\uddf3\ud83c[\udde6\udde8\uddea-\uddec\uddee\uddf1\uddf4\uddf5\uddf7\uddfa\uddff]|\ud83c\uddf4\ud83c\uddf2|\ud83c\uddf5\ud83c[\udde6\uddea-\udded\uddf0-\uddf3\uddf7-\uddf9\uddfc\uddfe]|\ud83c\uddf6\ud83c\udde6|\ud83c\uddf7\ud83c[\uddea\uddf4\uddf8\uddfa\uddfc]|\ud83c\uddf8\ud83c[\udde6-\uddea\uddec-\uddf4\uddf7-\uddf9\uddfb\uddfd-\uddff]|\ud83c\uddf9\ud83c[\udde6\udde8\udde9\uddeb-\udded\uddef-\uddf4\uddf7\uddf9\uddfb\uddfc\uddff]|\ud83c\uddfa\ud83c[\udde6\uddec\uddf2\uddf8\uddfe\uddff]|\ud83c\uddfb\ud83c[\udde6\udde8\uddea\uddec\uddee\uddf3\uddfa]|\ud83c\uddfc\ud83c[\uddeb\uddf8]|\ud83c\uddfd\ud83c\uddf0|\ud83c\uddfe\ud83c[\uddea\uddf9]|\ud83c\uddff\ud83c[\udde6\uddf2\uddfc]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf21\udf24-\udf84\udf86-\udf93\udf96\udf97\udf99-\udf9b\udf9e-\udfc1\udfc5\udfc6\udfc8\udfc9\udfcc-\udff0\udff3-\udff5\udff7-\udfff]|\ud83d[\udc00-\udc41\udc44\udc45\udc51-\udc65\udc6a-\udc6d\udc6f\udc79-\udc7b\udc7d-\udc80\udc84\udc88-\udca9\udcab-\udcfd\udcff-\udd3d\udd49-\udd4e\udd50-\udd67\udd6f\udd70\udd73\udd74\udd76-\udd79\udd87\udd8a-\udd8d\udda5\udda8\uddb1\uddb2\uddbc\uddc2-\uddc4\uddd1-\uddd3\udddc-\uddde\udde1\udde3\udde8\uddef\uddf3\uddfa-\ude44\ude48-\ude4a\ude80-\udea2\udea4-\udeb3\udeb7-\udebf\udec1-\udec5\udecb-\uded0\udee0-\udee5\udee9\udeeb\udeec\udef0\udef3]|\ud83e[\udd10-\udd17\udd80-\udd84\uddc0]|[\u2328\u23cf\u23e9-\u23f3\u23f8-\u23fa\u2602-\u2604\u2618\u2620\u2622\u2623\u2626\u262a\u262e\u262f\u2638\u2692\u2694\u2696\u2697\u2699\u269b\u269c\u26b0\u26b1\u26c8\u26ce\u26cf\u26d1\u26d3\u26e9\u26f0\u26f1\u26f4\u26f7\u26f8\u2705\u271d\u2721\u2728\u274c\u274e\u2753-\u2755\u2763\u2795-\u2797\u27b0\u27bf\ue50a]|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37]|[\u00a9\u00ae\u203c\u2049\u2122\u2139\u2194-\u2199\u21a9\u21aa\u231a\u231b\u24c2\u25aa\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600\u2601\u260e\u2611\u2614\u2615\u2639\u263a\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267b\u267f\u2693\u26a0\u26a1\u26aa\u26ab\u26bd\u26be\u26c4\u26c5\u26d4\u26ea\u26f2\u26f3\u26f5\u26fa\u26fd\u2702\u2708\u2709\u270f\u2712\u2714\u2716\u2733\u2734\u2744\u2747\u2757\u2764\u27a1\u2934\u2935\u2b05-\u2b07\u2b1b\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299])(?:\ufe0f|(?!\ufe0e)))/g,
EMOJI_CATEGORIES: { EMOJI_CATEGORIES: {
people: "People & Smileys", people: "People & Smileys",
nature: "Animals & Nature", nature: "Animals & Nature",
food: "Food & Drink", food: "Food & Drink",
activity: "Activity", activity: "Activity",
travel: "Travel & Places", travel: "Travel & Places",
objects: "Objects", objects: "Objects",
symbols: "Symbols", symbols: "Symbols",
flags: "Flags" flags: "Flags"
//modifier: "Modifiers" //modifier: "Modifiers"
}, },
EMOJI_LOGOS: { EMOJI_LOGOS: {
activity: '26bd', activity: '26bd',
food: '1f34e', food: '1f34e',
flags: '1f1fa-1f1f8', flags: '1f1fa-1f1f8',
nature: '1f436', nature: '1f436',
objects: '1f4a1', objects: '1f4a1',
people: '1f632', people: '1f632',
symbols: '2049', symbols: '2049',
travel: '1f697' travel: '1f697'
//modifier: '262f' //modifier: '262f'
}, },
ZREKNARF: svg('glyph_views svg-zreknarf', 16, 12.5, SVGPATH, '0 0 249 195'), ZREKNARF: svg('glyph_views svg-zreknarf', 16, 12.5, SVGPATH, '0 0 249 195'),
CHAT_BUTTON: svg('emoticons', 24, 18, SVGPATH, '0 0 249 195'), CHAT_BUTTON: svg('emoticons', 24, 18, SVGPATH, '0 0 249 195'),
ROOMS: svg('glyph_views svg-roomlist', 16, 16, 'M1,13v-2h14v2H1z M1,5h13v2H1V5z M1,2h10v2H1V2z M12,10H1V8h11V10z'), ROOMS: svg('glyph_views svg-roomlist', 16, 16, 'M1,13v-2h14v2H1z M1,5h13v2H1V5z M1,2h10v2H1V2z M12,10H1V8h11V10z'),
CAMERA: svg('camera', 16, 16, 'M24,20v6H4V10h20v6l8-6v16L24,20z', '0 0 36 36'), CAMERA: svg('camera', 16, 16, 'M24,20v6H4V10h20v6l8-6v16L24,20z', '0 0 36 36'),
INVITE: svg('plus', 16, 16, 'M15,9h-3v3h-2V9H7V7h3V4h2v3h3V9z M9,6H6v4h2h1v3h4l0,0l0,0v1h-3H4H1v-1l3-3h2L4,8V2h6v1H9V6z'), INVITE: svg('plus', 16, 16, 'M15,9h-3v3h-2V9H7V7h3V4h2v3h3V9z M9,6H6v4h2h1v3h4l0,0l0,0v1h-3H4H1v-1l3-3h2L4,8V2h6v1H9V6z'),
LIVE: svg('glyph_live_small', 13, 16,'M11,14H5H2v-1l3-3h2L5,8V2h6v6l-2,2h2l3,3v1H11z'), LIVE: svg('glyph_live_small', 13, 16,'M11,14H5H2v-1l3-3h2L5,8V2h6v6l-2,2h2l3,3v1H11z'),
EYE: svg('glyph_views svg-eye', 16, 16, 'M11,13H5L1,9V8V7l4-4h6l4,4v1v1L11,13z M8,5C6.344,5,5,6.343,5,8c0,1.656,1.344,3,3,3c1.657,0,3-1.344,3-3C11,6.343,9.657,5,8,5z M8,9C7.447,9,7,8.552,7,8s0.447-1,1-1s1,0.448,1,1S8.553,9,8,9z'), EYE: svg('glyph_views svg-eye', 16, 16, 'M11,13H5L1,9V8V7l4-4h6l4,4v1v1L11,13z M8,5C6.344,5,5,6.343,5,8c0,1.656,1.344,3,3,3c1.657,0,3-1.344,3-3C11,6.343,9.657,5,8,5z M8,9C7.447,9,7,8.552,7,8s0.447-1,1-1s1,0.448,1,1S8.553,9,8,9z'),
CLOCK: svg('glyph_views svg-clock', 16, 16, 'M8,15c-3.866,0-7-3.134-7-7s3.134-7,7-7s7,3.134,7,7 S11.866,15,8,15z M8,3C5.238,3,3,5.238,3,8s2.238,5,5,5s5-2.238,5-5S10.762,3,8,3z M7.293,8.707L7,8l1-4l0.902,3.607L11,11 L7.293,8.707z'), CLOCK: svg('glyph_views svg-clock', 16, 16, 'M8,15c-3.866,0-7-3.134-7-7s3.134-7,7-7s7,3.134,7,7 S11.866,15,8,15z M8,3C5.238,3,3,5.238,3,8s2.238,5,5,5s5-2.238,5-5S10.762,3,8,3z M7.293,8.707L7,8l1-4l0.902,3.607L11,11 L7.293,8.707z'),
GEAR: svg('gear', 16, 16, 'M15,7v2h-2.115c-0.125,0.615-0.354,1.215-0.713,1.758l1.484,1.484l-1.414,1.414l-1.484-1.484C10.215,12.531,9.615,12.76,9,12.885V15H7v-2.12c-0.614-0.126-1.21-0.356-1.751-0.714l-1.491,1.49l-1.414-1.414l1.491-1.49C3.477,10.211,3.247,9.613,3.12,9H1V7h2.116C3.24,6.384,3.469,5.785,3.829,5.242L2.343,3.757l1.414-1.414l1.485,1.485C5.785,3.469,6.384,3.24,7,3.115V1h2v2.12c0.613,0.126,1.211,0.356,1.752,0.714l1.49-1.491l1.414,1.414l-1.49,1.492C12.523,5.79,12.754,6.387,12.88,7H15z M8,6C6.896,6,6,6.896,6,8s0.896,2,2,2s2-0.896,2-2S9.104,6,8,6z'), GEAR: svg('gear', 16, 16, 'M15,7v2h-2.115c-0.125,0.615-0.354,1.215-0.713,1.758l1.484,1.484l-1.414,1.414l-1.484-1.484C10.215,12.531,9.615,12.76,9,12.885V15H7v-2.12c-0.614-0.126-1.21-0.356-1.751-0.714l-1.491,1.49l-1.414-1.414l1.491-1.49C3.477,10.211,3.247,9.613,3.12,9H1V7h2.116C3.24,6.384,3.469,5.785,3.829,5.242L2.343,3.757l1.414-1.414l1.485,1.485C5.785,3.469,6.384,3.24,7,3.115V1h2v2.12c0.613,0.126,1.211,0.356,1.752,0.714l1.49-1.491l1.414,1.414l-1.49,1.492C12.523,5.79,12.754,6.387,12.88,7H15z M8,6C6.896,6,6,6.896,6,8s0.896,2,2,2s2-0.896,2-2S9.104,6,8,6z'),
HEART: svg('heart', 16, 16, 'M8,13.5L1.5,7V4l2-2h3L8,3.5L9.5,2h3l2,2v3L8,13.5z'), HEART: svg('heart', 16, 16, 'M8,13.5L1.5,7V4l2-2h3L8,3.5L9.5,2h3l2,2v3L8,13.5z'),
UNHEART: svg('unheart', 16, 16, 'M1,9V7h14v2H1z M1,4l2-2h3l2,2l2-2h3l2,2v2H1V4z M8,14l-4.667-4h9.333L8,14z'), UNHEART: svg('unheart', 16, 16, 'M1,9V7h14v2H1z M1,4l2-2h3l2,2l2-2h3l2,2v2H1V4z M8,14l-4.667-4h9.333L8,14z'),
EMOTE: svg('emote', 16, 16, 'M9,18c-4.971,0-9-4.029-9-9s4.029-9,9-9s9,4.029,9,9S13.971,18,9,18z M14,4.111V4h-0.111C12.627,2.766,10.904,2,9,2C7.095,2,5.373,2.766,4.111,4H4v0.111C2.766,5.373,2,7.096,2,9s0.766,3.627,2,4.889V14l0.05-0.051C5.317,15.217,7.067,16,9,16c1.934,0,3.684-0.783,4.949-2.051L14,14v-0.111c1.234-1.262,2-2.984,2-4.889S15.234,5.373,14,4.111zM11,6h2v4h-2V6z M12.535,12.535C11.631,13.44,10.381,14,9,14s-2.631-0.56-3.536-1.465l0.707-0.707C6.896,12.553,7.896,13,9,13s2.104-0.447,2.828-1.172L12.535,12.535z M5,6h2v4H5V6z', '0 0 18 18'), EMOTE: svg('emote', 16, 16, 'M9,18c-4.971,0-9-4.029-9-9s4.029-9,9-9s9,4.029,9,9S13.971,18,9,18z M14,4.111V4h-0.111C12.627,2.766,10.904,2,9,2C7.095,2,5.373,2.766,4.111,4H4v0.111C2.766,5.373,2,7.096,2,9s0.766,3.627,2,4.889V14l0.05-0.051C5.317,15.217,7.067,16,9,16c1.934,0,3.684-0.783,4.949-2.051L14,14v-0.111c1.234-1.262,2-2.984,2-4.889S15.234,5.373,14,4.111zM11,6h2v4h-2V6z M12.535,12.535C11.631,13.44,10.381,14,9,14s-2.631-0.56-3.536-1.465l0.707-0.707C6.896,12.553,7.896,13,9,13s2.104-0.447,2.828-1.172L12.535,12.535z M5,6h2v4H5V6z', '0 0 18 18'),
STAR: svg('star', 16, 16, 'M15,6l-4.041,2.694L13,14l-5-3.333L3,14l2.041-5.306L1,6h5.077L8,1l1.924,5H15z'), STAR: svg('star', 16, 16, 'M15,6l-4.041,2.694L13,14l-5-3.333L3,14l2.041-5.306L1,6h5.077L8,1l1.924,5H15z'),
CLOSE: svg('close_small', 16, 16, 'M12.657,4.757L9.414,8l3.243,3.242l-1.415,1.415L8,9.414l-3.243,3.243l-1.414-1.415L6.586,8L3.343,4.757l1.414-1.414L8,6.586l3.242-3.243L12.657,4.757z'), CLOSE: svg('close_small', 16, 16, 'M12.657,4.757L9.414,8l3.243,3.242l-1.415,1.415L8,9.414l-3.243,3.243l-1.414-1.415L6.586,8L3.343,4.757l1.414-1.414L8,6.586l3.242-3.243L12.657,4.757z'),
EDIT: svg('edit', 16, 16, 'M6.414,12.414L3.586,9.586l8-8l2.828,2.828L6.414,12.414z M4.829,14H2l0,0v-2.828l0.586-0.586l2.828,2.828L4.829,14z'), EDIT: svg('edit', 16, 16, 'M6.414,12.414L3.586,9.586l8-8l2.828,2.828L6.414,12.414z M4.829,14H2l0,0v-2.828l0.586-0.586l2.828,2.828L4.829,14z'),
GRAPH: svg('glyph_views graph', 16, 16, 'M1,16V2h16v14H1z M5,4H3v1h2V4z M5,7H3v1h2V7z M5,10H3v1h2V10zM5,13H3v1h2V13z M9,7H7v7h2V7z M12,10h-2v4h2V10z M15,4h-2v10h2V4z', '0 0 18 18') GRAPH: svg('glyph_views graph', 16, 16, 'M1,16V2h16v14H1z M5,4H3v1h2V4z M5,7H3v1h2V7z M5,10H3v1h2V10zM5,13H3v1h2V13z M9,7H7v7h2V7z M12,10h-2v4h2V10z M15,4h-2v10h2V4z', '0 0 18 18')
} }

View file

@ -241,8 +241,8 @@ FFZ.prototype.modify_channel_index = function(view) {
var top = event && event.target && event.target.scrollTop, var top = event && event.target && event.target.scrollTop,
height = this.get('layout.playerSize.1'); height = this.get('layout.playerSize.1');
if ( ! top ) if ( ! top )
top = jQuery(this.get('element')).parents('.tse-scroll-content').scrollTop(); top = jQuery(this.get('element')).parents('.tse-scroll-content').scrollTop();
document.body.classList.toggle('ffz-small-player', f.settings.small_player && top >= height); document.body.classList.toggle('ffz-small-player', f.settings.small_player && top >= height);
}, },

File diff suppressed because it is too large Load diff

View file

@ -14,11 +14,11 @@ FFZ.basic_settings.delayed_chat = {
300: "Minor (Bot Moderation; 0.3s)", 300: "Minor (Bot Moderation; 0.3s)",
1200: "Normal (Human Moderation; 1.2s)", 1200: "Normal (Human Moderation; 1.2s)",
5000: "Large (Spoiler Removal / Really Slow Mods; 5s)", 5000: "Large (Spoiler Removal / Really Slow Mods; 5s)",
10000: "Extra Large (10s)", 10000: "Extra Large (10s)",
15000: "Extremely Large (15s)", 15000: "Extremely Large (15s)",
20000: "Mods Asleep; Delay Chat (20s)", 20000: "Mods Asleep; Delay Chat (20s)",
30000: "Half a Minute (30s)", 30000: "Half a Minute (30s)",
60000: "Why??? (1m)" 60000: "Why??? (1m)"
}, },
category: "Chat", category: "Chat",
@ -141,11 +141,11 @@ FFZ.settings_info.chat_delay = {
300: "Minor (Bot Moderation; 0.3s)", 300: "Minor (Bot Moderation; 0.3s)",
1200: "Normal (Human Moderation; 1.2s)", 1200: "Normal (Human Moderation; 1.2s)",
5000: "Large (Spoiler Removal / Really Slow Mods; 5s)", 5000: "Large (Spoiler Removal / Really Slow Mods; 5s)",
10000: "Extra Large (10s)", 10000: "Extra Large (10s)",
15000: "Extremely Large (15s)", 15000: "Extremely Large (15s)",
20000: "Mods Asleep; Delay Chat (20s)", 20000: "Mods Asleep; Delay Chat (20s)",
30000: "Half a Minute (30s)", 30000: "Half a Minute (30s)",
60000: "Why??? (1m)" 60000: "Why??? (1m)"
}, },
value: 0, value: 0,
@ -328,22 +328,22 @@ FFZ.settings_info.visible_rooms = {
// -------------------- // --------------------
FFZ.prototype.refresh_chat = function() { FFZ.prototype.refresh_chat = function() {
var parents, lines = jQuery('ul.chat-lines'); var parents, lines = jQuery('ul.chat-lines');
if ( this.has_bttv || ! lines || ! lines.length ) if ( this.has_bttv || ! lines || ! lines.length )
return; return;
parents = lines.parents('.chatReplay'); parents = lines.parents('.chatReplay');
if ( parents && parents.length ) if ( parents && parents.length )
return; return;
// There are chat-lines in the DOM and they aren't chat replay. // There are chat-lines in the DOM and they aren't chat replay.
var controller = utils.ember_lookup('controller:chat'); var controller = utils.ember_lookup('controller:chat');
if ( ! controller ) if ( ! controller )
return; return;
var current_room = controller.get("currentRoom"); var current_room = controller.get("currentRoom");
controller.blurRoom(); controller.blurRoom();
controller.focusRoom(current_room); controller.focusRoom(current_room);
} }
FFZ.prototype.setup_chatview = function() { FFZ.prototype.setup_chatview = function() {
@ -402,10 +402,10 @@ FFZ.prototype.setup_chatview = function() {
f._chatv.ffzUpdateMenuUnread(); f._chatv.ffzUpdateMenuUnread();
}.observes("invitedPrivateGroupRooms"), }.observes("invitedPrivateGroupRooms"),
ffzChangedRoom: function() { ffzChangedRoom: function() {
if ( f._inputv ) if ( f._inputv )
Ember.propertyDidChange(f._inputv, 'ffz_emoticons'); Ember.propertyDidChange(f._inputv, 'ffz_emoticons');
}.observes('currentRoom'), }.observes('currentRoom'),
notificationsCount: function() { notificationsCount: function() {
if ( ! f._chatv || f.has_bttv ) if ( ! f._chatv || f.has_bttv )
@ -487,7 +487,7 @@ FFZ.prototype.modify_chat_view = function(view) {
var f = this; var f = this;
utils.ember_reopen_view(view, { utils.ember_reopen_view(view, {
ffz_init: function() { ffz_init: function() {
f._chatv = this; f._chatv = this;
var room_id = this.get('controller.currentRoom.id'), var room_id = this.get('controller.currentRoom.id'),
el = this.get('element'); el = this.get('element');
@ -559,7 +559,7 @@ FFZ.prototype.modify_chat_view = function(view) {
ffzChangeRoom: Ember.observer('controller.currentRoom', function() { ffzChangeRoom: Ember.observer('controller.currentRoom', function() {
f.update_ui_link(); f.update_ui_link();
this.ffz_unread = this.ffz_unread || {}; this.ffz_unread = this.ffz_unread || {};
// Close mod cards when changing to a new room. // Close mod cards when changing to a new room.
if ( f._mod_card ) if ( f._mod_card )
@ -699,7 +699,7 @@ FFZ.prototype.modify_chat_view = function(view) {
ffzUpdateUnread: function(target_id) { ffzUpdateUnread: function(target_id) {
var current_id = this.get('controller.currentRoom.id'); var current_id = this.get('controller.currentRoom.id');
this.ffz_unread = this.ffz_unread || {}; this.ffz_unread = this.ffz_unread || {};
if ( target_id === current_id ) if ( target_id === current_id )
// We don't care about updates to the current room. // We don't care about updates to the current room.
@ -1036,7 +1036,7 @@ FFZ.prototype.modify_chat_view = function(view) {
link.title = "Chat Room Management"; link.title = "Chat Room Management";
link.innerHTML = '<figure class="icon">' + constants.ROOMS + '</figure><span class="notifications"></span>'; link.innerHTML = '<figure class="icon">' + constants.ROOMS + '</figure><span class="notifications"></span>';
jQuery(link).tipsy({gravity: "n", offset: 5}); jQuery(link).tipsy({gravity: "n", offset: 5});
link.addEventListener('click', function() { link.addEventListener('click', function() {
var controller = view.get('controller'); var controller = view.get('controller');

View file

@ -177,22 +177,22 @@ FFZ.prototype.modify_conversation_line = function(component) {
return this._super(e); return this._super(e);
}, },
didUpdate: function() { this.ffzRender() }, didUpdate: function() { this.ffzRender() },
ffz_init: function() { this.ffzRender() }, ffz_init: function() { this.ffzRender() },
ffzRender: function() { ffzRender: function() {
var el = this.get('element'), var el = this.get('element'),
e = [], e = [],
user = this.get('message.from.username'), user = this.get('message.from.username'),
raw_color = this.get('message.from.color'), raw_color = this.get('message.from.color'),
colors = raw_color && f._handle_color(raw_color), colors = raw_color && f._handle_color(raw_color),
is_dark = (Layout && Layout.get('isTheatreMode')) || f.settings.dark_twitch, is_dark = (Layout && Layout.get('isTheatreMode')) || f.settings.dark_twitch,
myself = f.get_user(), myself = f.get_user(),
from_me = myself && myself.login === user, from_me = myself && myself.login === user,
alias = f.aliases[user], alias = f.aliases[user],
name = this.get('message.from.displayName') || (user && user.capitalize()) || "unknown user", name = this.get('message.from.displayName') || (user && user.capitalize()) || "unknown user",
style = colors && 'color:' + (is_dark ? colors[1] : colors[0]), style = colors && 'color:' + (is_dark ? colors[1] : colors[0]),
colored = style ? ' has-color' : ''; colored = style ? ' has-color' : '';
@ -212,7 +212,7 @@ FFZ.prototype.modify_conversation_line = function(component) {
e.push('<span class="message' + colored + '" style="' + style + (colors ? '" data-color="' + raw_color : '') + '">'); e.push('<span class="message' + colored + '" style="' + style + (colors ? '" data-color="' + raw_color : '') + '">');
e.push(f.render_tokens(this.get('tokenizedMessage'), true, f.settings.filter_whispered_links && !from_me)); e.push(f.render_tokens(this.get('tokenizedMessage'), true, f.settings.filter_whispered_links && !from_me));
e.push('</span>'); e.push('</span>');
el.innerHTML = e.join(''); el.innerHTML = e.join('');
} }
}); });
} }

View file

@ -246,13 +246,13 @@ FFZ.prototype._modify_following = function() {
this.log("Found Following model."); this.log("Found Following model.");
Following.reopen({ Following.reopen({
ffz_streams: {}, ffz_streams: {},
ffz_hosts_for: {}, ffz_hosts_for: {},
ffz_skipped: 0, ffz_skipped: 0,
empty: function() { empty: function() {
this._super(); this._super();
this.set("ffz_streams", {}); this.set("ffz_streams", {});
this.set("ffz_hosts_for", {}); this.set("ffz_hosts_for", {});
this.set("ffz_skipped", 0); this.set("ffz_skipped", 0);
}, },
@ -260,7 +260,7 @@ FFZ.prototype._modify_following = function() {
// We have to override request with nearly the same logic // We have to override request with nearly the same logic
// to prevent infinitely trying to load more streams. // to prevent infinitely trying to load more streams.
if (!Twitch.user.isLoggedIn() || window.App.get("disableFollowingDirectory")) return RSVP.resolve({ if (!Twitch.user.isLoggedIn() || window.App.get("disableFollowingDirectory")) return RSVP.resolve({
hosts: [], _total: 0 hosts: [], _total: 0
}); });
var t = { var t = {
@ -268,16 +268,16 @@ FFZ.prototype._modify_following = function() {
offset: this.get('content.length') + this.get('ffz_skipped') offset: this.get('content.length') + this.get('ffz_skipped')
}; };
// Don't use FFZ's Client ID because loading hosts is a normal part // Don't use FFZ's Client ID because loading hosts is a normal part
// of the dashboard. We're just manipulating the logic a bit. // of the dashboard. We're just manipulating the logic a bit.
return Twitch.api.get("/api/users/:login/followed/hosting", t); return Twitch.api.get("/api/users/:login/followed/hosting", t);
}, },
afterSuccess: function(e) { afterSuccess: function(e) {
var valid_hosts = [], var valid_hosts = [],
streams = this.get('ffz_streams'), streams = this.get('ffz_streams'),
skipped = this.get('ffz_skipped'), skipped = this.get('ffz_skipped'),
hosts_for = this.get('ffz_hosts_for'), hosts_for = this.get('ffz_hosts_for'),
t = this; t = this;
@ -285,27 +285,27 @@ FFZ.prototype._modify_following = function() {
var host = e.hosts[i], var host = e.hosts[i],
target = host && host.target && host.target.id; target = host && host.target && host.target.id;
if ( host.rollbackData ) if ( host.rollbackData )
host.rollbackData = undefined; host.rollbackData = undefined;
if ( f.settings.directory_group_hosts && streams[target] ) { if ( f.settings.directory_group_hosts && streams[target] ) {
skipped++; skipped++;
//hosts_for[target] && hosts_for[target] //hosts_for[target] && hosts_for[target]
streams[target].ffz_hosts && streams[target].ffz_hosts.push({logo: host.logo, name: host.name, display_name: host.display_name}); streams[target].ffz_hosts && streams[target].ffz_hosts.push({logo: host.logo, name: host.name, display_name: host.display_name});
continue; continue;
} }
streams[target] = host; streams[target] = host;
//hosts_for[target] = [{logo: host.logo, name: host.name, display_name: host.display_name}]; //hosts_for[target] = [{logo: host.logo, name: host.name, display_name: host.display_name}];
host.ffz_hosts = [{logo: host.logo, name: host.name, display_name: host.display_name}]; host.ffz_hosts = [{logo: host.logo, name: host.name, display_name: host.display_name}];
valid_hosts.push(host); valid_hosts.push(host);
} }
//f.log("Stuff!", [this, e, valid_hosts, skipped]); //f.log("Stuff!", [this, e, valid_hosts, skipped]);
this.set('ffz_skipped', skipped); this.set('ffz_skipped', skipped);
this.setContent(valid_hosts); this.setContent(valid_hosts);
// We could get non-empty results even with no new hosts. // We could get non-empty results even with no new hosts.
this.set('gotNonEmptyResults', e.hosts && e.hosts.length); this.set('gotNonEmptyResults', e.hosts && e.hosts.length);
@ -321,31 +321,31 @@ FFZ.prototype._modify_following = function() {
// TODO: Something less stupid. // TODO: Something less stupid.
for(var i=0; i < content.length; i++) { for(var i=0; i < content.length; i++) {
var host = content[i]; var host = content[i];
host_copy.push({ host_copy.push({
display_name: host.display_name, display_name: host.display_name,
game: host.game, game: host.game,
id: host.id, id: host.id,
logo: host.logo, logo: host.logo,
name: host.name, name: host.name,
target: { target: {
_id: host.target._id, _id: host.target._id,
channel: { channel: {
display_name: host.target.channel.display_name, display_name: host.target.channel.display_name,
id: host.target.channel.id, id: host.target.channel.id,
logo: host.target.channel.logo, logo: host.target.channel.logo,
name: host.target.channel.name, name: host.target.channel.name,
url: host.target.channel.url url: host.target.channel.url
}, },
id: host.target.id, id: host.target.id,
meta_game: host.target.meta_game, meta_game: host.target.meta_game,
preview: host.target.preview, preview: host.target.preview,
title: host.target.title, title: host.target.title,
url: host.target.url, url: host.target.url,
viewers: host.target.viewers viewers: host.target.viewers
} }
}); });
} }
Following.clear(); Following.clear();
Following.afterSuccess({hosts: host_copy, _total: total}); Following.afterSuccess({hosts: host_copy, _total: total});
@ -421,7 +421,7 @@ FFZ.prototype.modify_game_follow_button = function(component) {
FFZ.prototype.modify_directory_live = function(component, is_csgo) { FFZ.prototype.modify_directory_live = function(component, is_csgo) {
var f = this, var f = this,
pref = is_csgo ? 'channel.' : 'stream.'; pref = is_csgo ? 'channel.' : 'stream.';
utils.ember_reopen_view(component, { utils.ember_reopen_view(component, {
ffz_init: function() { ffz_init: function() {
@ -429,11 +429,11 @@ FFZ.prototype.modify_directory_live = function(component, is_csgo) {
meta = el && el.querySelector('.meta'), meta = el && el.querySelector('.meta'),
thumb = el && el.querySelector('.thumb'), thumb = el && el.querySelector('.thumb'),
cap = thumb && thumb.querySelector('.cap'), cap = thumb && thumb.querySelector('.cap'),
channel_id = this.get(pref + 'channel.name'), channel_id = this.get(pref + 'channel.name'),
game = this.get(pref + 'game'); game = this.get(pref + 'game');
el.classList.add('ffz-directory-preview'); el.classList.add('ffz-directory-preview');
el.setAttribute('data-channel', channel_id); el.setAttribute('data-channel', channel_id);
el.setAttribute('data-game', game); el.setAttribute('data-game', game);
el.classList.toggle('ffz-game-banned', f.settings.banned_games.indexOf(game && game.toLowerCase()) !== -1); el.classList.toggle('ffz-game-banned', f.settings.banned_games.indexOf(game && game.toLowerCase()) !== -1);
@ -450,8 +450,8 @@ FFZ.prototype.modify_directory_live = function(component, is_csgo) {
this.ffzUpdateUptime(); this.ffzUpdateUptime();
} }
this._ffz_image_timer = setInterval(this.ffzRotateImage.bind(this), 30000); this._ffz_image_timer = setInterval(this.ffzRotateImage.bind(this), 30000);
this.ffzRotateImage(); this.ffzRotateImage();
if ( f.settings.directory_logos ) { if ( f.settings.directory_logos ) {
el.classList.add('ffz-directory-logo'); el.classList.add('ffz-directory-logo');
@ -468,8 +468,8 @@ FFZ.prototype.modify_directory_live = function(component, is_csgo) {
link.href = '/' + channel_id; link.href = '/' + channel_id;
link.addEventListener('click', function(e) { link.addEventListener('click', function(e) {
if ( e.button !== 0 || e.altKey || e.ctrlKey || e.shiftKey || e.metaKey ) if ( e.button !== 0 || e.altKey || e.ctrlKey || e.shiftKey || e.metaKey )
return; return;
var Channel = utils.ember_resolve('model:deprecated-channel'); var Channel = utils.ember_resolve('model:deprecated-channel');
if ( ! Channel ) if ( ! Channel )
@ -494,21 +494,21 @@ FFZ.prototype.modify_directory_live = function(component, is_csgo) {
if ( this._ffz_uptime_timer ) if ( this._ffz_uptime_timer )
clearInterval(this._ffz_uptime_timer); clearInterval(this._ffz_uptime_timer);
if ( this._ffz_image_timer ) if ( this._ffz_image_timer )
clearInterval(this._ffz_image_timer); clearInterval(this._ffz_image_timer);
}, },
ffzRotateImage: function() { ffzRotateImage: function() {
var url = this.get(pref + 'preview.medium'), var url = this.get(pref + 'preview.medium'),
now = Math.round((new Date).getTime() / 150000); now = Math.round((new Date).getTime() / 150000);
if ( FFZ._image_cache[url] && FFZ._image_cache[url] !== now ) if ( FFZ._image_cache[url] && FFZ._image_cache[url] !== now )
url += '?_=' + now; url += '?_=' + now;
else else
FFZ._image_cache[url] = now; FFZ._image_cache[url] = now;
this.$('.thumb .cap img').attr('src', url); this.$('.thumb .cap img').attr('src', url);
}, },
ffzUpdateUptime: function() { ffzUpdateUptime: function() {
var raw_created = this.get(pref + 'created_at'), var raw_created = this.get(pref + 'created_at'),
@ -554,7 +554,7 @@ FFZ.prototype.modify_video_preview = function(component) {
boxart.setAttribute('original-title', game); boxart.setAttribute('original-title', game);
boxart.addEventListener('click', function(e) { boxart.addEventListener('click', function(e) {
if ( e.button !== 0 || e.altKey || e.ctrlKey || e.shiftKey || e.metaKey ) if ( e.button !== 0 || e.altKey || e.ctrlKey || e.shiftKey || e.metaKey )
return; return;
e.preventDefault(); e.preventDefault();
jQuery('.tipsy').remove(); jQuery('.tipsy').remove();
@ -661,25 +661,25 @@ FFZ.prototype.modify_directory_host = function(component) {
f.show_popup(menu, [x, y], document.querySelector('#main_col > .tse-scroll-content > .tse-content')); f.show_popup(menu, [x, y], document.querySelector('#main_col > .tse-scroll-content > .tse-content'));
}, },
ffzRotateImage: function() { ffzRotateImage: function() {
var url = this.get('stream.target.preview'), var url = this.get('stream.target.preview'),
now = Math.round((new Date).getTime() / 150000); now = Math.round((new Date).getTime() / 150000);
if ( FFZ._image_cache[url] && FFZ._image_cache[url] !== now ) if ( FFZ._image_cache[url] && FFZ._image_cache[url] !== now )
url += '?_=' + now; url += '?_=' + now;
else else
FFZ._image_cache[url] = now; FFZ._image_cache[url] = now;
this.$('.thumb .cap img').attr('src', url); this.$('.thumb .cap img').attr('src', url);
}, },
ffz_destroy: function() { ffz_destroy: function() {
var target = this.get('stream.target.channel'); var target = this.get('stream.target.channel');
if ( f._popup && f._popup.classList.contains('ffz-channel-selector') && f._popup.getAttribute('data-channel') === target ) if ( f._popup && f._popup.classList.contains('ffz-channel-selector') && f._popup.getAttribute('data-channel') === target )
f.close_popup(); f.close_popup();
if ( this._ffz_image_timer ) if ( this._ffz_image_timer )
clearInterval(this._ffz_image_timer); clearInterval(this._ffz_image_timer);
}, },
ffz_init: function() { ffz_init: function() {
@ -700,8 +700,8 @@ FFZ.prototype.modify_directory_host = function(component) {
el.classList.toggle('ffz-game-banned', f.settings.banned_games.indexOf(game && game.toLowerCase()) !== -1); el.classList.toggle('ffz-game-banned', f.settings.banned_games.indexOf(game && game.toLowerCase()) !== -1);
el.classList.toggle('ffz-game-spoilered', f.settings.spoiler_games.indexOf(game && game.toLowerCase()) !== -1); el.classList.toggle('ffz-game-spoilered', f.settings.spoiler_games.indexOf(game && game.toLowerCase()) !== -1);
this._ffz_image_timer = setInterval(this.ffzRotateImage.bind(this), 30000); this._ffz_image_timer = setInterval(this.ffzRotateImage.bind(this), 30000);
this.ffzRotateImage(); this.ffzRotateImage();
if ( f.settings.directory_logos ) { if ( f.settings.directory_logos ) {
el.classList.add('ffz-directory-logo'); el.classList.add('ffz-directory-logo');

View file

@ -140,7 +140,7 @@ FFZ.prototype.setup_profile_following = function() {
} }
}); });
// TODO: Add nice Manage Following button to the directory. // TODO: Add nice Manage Following button to the directory.
// Now, rebuild any views. // Now, rebuild any views.
try { FollowedItem.create().destroy(); try { FollowedItem.create().destroy();
@ -148,9 +148,9 @@ FFZ.prototype.setup_profile_following = function() {
var views = utils.ember_views(); var views = utils.ember_views();
if ( views ) { if ( views ) {
for(var key in views) { for(var key in views) {
var view = views[key]; var view = views[key];
if ( view instanceof FollowedItem ) { if ( view instanceof FollowedItem ) {
this.log("Manually updating existing component:display-followed-item.", view); this.log("Manually updating existing component:display-followed-item.", view);
try { try {
@ -161,7 +161,7 @@ FFZ.prototype.setup_profile_following = function() {
this.error("setup: component:display-followed-item ffzInit: " + err); this.error("setup: component:display-followed-item ffzInit: " + err);
} }
} }
} }
} }
@ -358,11 +358,11 @@ FFZ.prototype._modify_display_followed_item = function(component) {
FFZ.prototype._hook_following = function(Following) { FFZ.prototype._hook_following = function(Following) {
var f = this; var f = this;
if ( ! Following || Following.ffz_hooked ) if ( ! Following || Following.ffz_hooked )
return; return;
Following.reopen({ Following.reopen({
ffz_hooked: true, ffz_hooked: true,
apiLoad: function(e) { apiLoad: function(e) {
var channel_id = this.get('id'), var channel_id = this.get('id'),
t = this; t = this;
@ -398,11 +398,11 @@ FFZ.prototype._hook_following = function(Following) {
FFZ.prototype._hook_followers = function(Followers) { FFZ.prototype._hook_followers = function(Followers) {
var f = this; var f = this;
if ( ! Followers || Followers.ffz_hooked ) if ( ! Followers || Followers.ffz_hooked )
return; return;
Followers.reopen({ Followers.reopen({
ffz_hooked: true, ffz_hooked: true,
apiLoad: function(e) { apiLoad: function(e) {
var channel_id = this.get('id'), var channel_id = this.get('id'),
t = this; t = this;

View file

@ -1,5 +1,5 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
utils = require('../utils'); utils = require('../utils');
// -------------------- // --------------------
@ -108,18 +108,18 @@ FFZ.settings_info.right_column_width = {
method: function() { method: function() {
var f = this, var f = this,
old_val = this.settings.right_column_width || 340; old_val = this.settings.right_column_width || 340;
utils.prompt("Right Sidebar Width", "Please enter a new width for the right sidebar, in pixels.</p><p><b>Minimum:</b> 250<br><b>Default:</b> 340", old_val, function(new_val) { utils.prompt("Right Sidebar Width", "Please enter a new width for the right sidebar, in pixels.</p><p><b>Minimum:</b> 250<br><b>Default:</b> 340", old_val, function(new_val) {
if ( new_val === null || new_val === undefined ) if ( new_val === null || new_val === undefined )
return; return;
var width = parseInt(new_val); var width = parseInt(new_val);
if ( ! width || Number.isNaN(width) || ! Number.isFinite(width) ) if ( ! width || Number.isNaN(width) || ! Number.isFinite(width) )
width = 340; width = 340;
f.settings.set('right_column_width', Math.max(250, width)); f.settings.set('right_column_width', Math.max(250, width));
}); });
}, },
on_update: function(val) { on_update: function(val) {
@ -223,19 +223,19 @@ FFZ.prototype.setup_layout = function() {
height = size[1], height = size[1],
host_height = size[2]; host_height = size[2];
return "<style>.dynamic-player, .dynamic-player object, .dynamic-player video{width:" + width + "px !important;height:" + height + "px !important} .dynamic-target-player,.dynamic-target-player object, .dynamic-target-player video{width:" + width + "px !important;height:" + host_height + "px !important}</style><style>.dynamic-player .player object, .dynamic-player .player video{width:100% !important; height:100% !important}</style>"; return "<style>.dynamic-player, .dynamic-player object, .dynamic-player video{width:" + width + "px !important;height:" + height + "px !important} .dynamic-target-player,.dynamic-target-player object, .dynamic-target-player video{width:" + width + "px !important;height:" + host_height + "px !important}</style><style>.dynamic-player .player object, .dynamic-player .player video{width:100% !important; height:100% !important}</style>";
}.property("playerSize"), }.property("playerSize"),
ffzPortraitWarning: function() { ffzPortraitWarning: function() {
var t = this; var t = this;
// Delay this, in case we're just resizing the window. // Delay this, in case we're just resizing the window.
setTimeout(function() { setTimeout(function() {
if ( ! f.settings.portrait_mode || f._portrait_warning || f.settings.portrait_warning || document.body.getAttribute('data-current-path').indexOf('user.') !== 0 || ! t.get('isTooSmallForRightColumn') ) if ( ! f.settings.portrait_mode || f._portrait_warning || f.settings.portrait_warning || document.body.getAttribute('data-current-path').indexOf('user.') !== 0 || ! t.get('isTooSmallForRightColumn') )
return; return;
f._portrait_warning = true; f._portrait_warning = true;
f.show_message('Twitch\'s Chat Sidebar has been hidden as a result of FrankerFaceZ\'s Portrait Mode because the window is too wide.<br><br>Please <a href="#" onclick="ffz.settings.set(\'portrait_mode\',0);jQuery(this).parents(\'.ffz-noty\').remove();ffz._portrait_warning = false;return false">disable Portrait Mode</a> or make your window narrower.<br><br><a href="#" onclick="ffz.settings.set(\'portrait_warning\',true);jQuery(this).parents(\'.ffz-noty\').remove();return false">Do not show this message again</a>'); f.show_message('Twitch\'s Chat Sidebar has been hidden as a result of FrankerFaceZ\'s Portrait Mode because the window is too wide.<br><br>Please <a href="#" onclick="ffz.settings.set(\'portrait_mode\',0);jQuery(this).parents(\'.ffz-noty\').remove();ffz._portrait_warning = false;return false">disable Portrait Mode</a> or make your window narrower.<br><br><a href="#" onclick="ffz.settings.set(\'portrait_warning\',true);jQuery(this).parents(\'.ffz-noty\').remove();return false">Do not show this message again</a>');
}, 50); }, 50);
}.observes("isTooSmallForRightColumn"), }.observes("isTooSmallForRightColumn"),
@ -253,73 +253,73 @@ FFZ.prototype.setup_layout = function() {
out += 'width: 50vh !important; height: 28.125vh !important;'; out += 'width: 50vh !important; height: 28.125vh !important;';
if ( ! f.has_bttv ) { if ( ! f.has_bttv ) {
if ( this.get('isRightColumnClosed') ) if ( this.get('isRightColumnClosed') )
out += 'top: 0; right: 0}'; out += 'top: 0; right: 0}';
else { else {
if ( this.get('portraitMode') ) { if ( this.get('portraitMode') ) {
var size = this.get('playerSize'), var size = this.get('playerSize'),
video_below = this.get('portraitVideoBelow'), video_below = this.get('portraitVideoBelow'),
video_height = size[1] + 120 + 60, video_height = size[1] + 120 + 60,
chat_height = window_height - video_height, chat_height = window_height - video_height,
video_top = video_below ? chat_height : 0, video_top = video_below ? chat_height : 0,
chat_top = video_below ? 0 : video_height, chat_top = video_below ? 0 : video_height,
theatre_video_height = Math.floor(Math.max(window_height * 0.1, Math.min(window_height - 300, 9 * window_width / 16))), theatre_video_height = Math.floor(Math.max(window_height * 0.1, Math.min(window_height - 300, 9 * window_width / 16))),
theatre_chat_height = window_height - theatre_video_height, theatre_chat_height = window_height - theatre_video_height,
theatre_video_top = video_below ? theatre_chat_height : 0, theatre_video_top = video_below ? theatre_chat_height : 0,
theatre_chat_top = video_below ? 0 : theatre_video_height; theatre_chat_top = video_below ? 0 : theatre_video_height;
out += 'top: ' + video_top + 'px;right: 0}' + out += 'top: ' + video_top + 'px;right: 0}' +
'body[data-current-path^="user."] #left_col .warp { min-height: inherit }' + 'body[data-current-path^="user."] #left_col .warp { min-height: inherit }' +
'body[data-current-path^="user."] #left_col { overflow: hidden }' + 'body[data-current-path^="user."] #left_col { overflow: hidden }' +
'body[data-current-path^="user."] #left_col .warp,' + 'body[data-current-path^="user."] #left_col .warp,' +
'body[data-current-path^="user."] #left_col,' + 'body[data-current-path^="user."] #left_col,' +
'body[data-current-path^="user."]:not(.ffz-sidebar-swap) #main_col{' + 'body[data-current-path^="user."]:not(.ffz-sidebar-swap) #main_col{' +
'margin-right:0 !important;' + 'margin-right:0 !important;' +
'top:' + video_top + 'px;' + 'top:' + video_top + 'px;' +
'height:' + video_height + 'px}' + 'height:' + video_height + 'px}' +
'body[data-current-path^="user."].ffz-sidebar-swap #main_col{' + 'body[data-current-path^="user."].ffz-sidebar-swap #main_col{' +
'margin-left:0 !important;' + 'margin-left:0 !important;' +
'top:' + video_top + 'px;' + 'top:' + video_top + 'px;' +
'height:' + video_height + 'px}' + 'height:' + video_height + 'px}' +
'body[data-current-path^="user."] #right_col{' + 'body[data-current-path^="user."] #right_col{' +
'width:100%;' + 'width:100%;' +
'top:' + chat_top + 'px;' + 'top:' + chat_top + 'px;' +
'height:' + chat_height + 'px}' + 'height:' + chat_height + 'px}' +
'body[data-current-path^="user."] .app-main.theatre #left_col .warp,' + 'body[data-current-path^="user."] .app-main.theatre #left_col .warp,' +
'body[data-current-path^="user."] .app-main.theatre #left_col,' + 'body[data-current-path^="user."] .app-main.theatre #left_col,' +
'body[data-current-path^="user."] .app-main.theatre #main_col{' + 'body[data-current-path^="user."] .app-main.theatre #main_col{' +
'top:' + theatre_video_top + 'px;' + 'top:' + theatre_video_top + 'px;' +
'height:' + theatre_video_height + 'px}' + 'height:' + theatre_video_height + 'px}' +
'body[data-current-path^="user."] .app-main.theatre #right_col{' + 'body[data-current-path^="user."] .app-main.theatre #right_col{' +
'top:' + theatre_chat_top + 'px;' + 'top:' + theatre_chat_top + 'px;' +
'height:' + theatre_chat_height + 'px}'; 'height:' + theatre_chat_height + 'px}';
} else { } else {
var width = this.get('rightColumnWidth'); var width = this.get('rightColumnWidth');
out += 'top: 0; right: ' + width + 'px}' + out += 'top: 0; right: ' + width + 'px}' +
'#main_col.expandRight #right_close{left: none !important}' + '#main_col.expandRight #right_close{left: none !important}' +
'#right_col{width:' + width + 'px}' + '#right_col{width:' + width + 'px}' +
'body:not(.ffz-sidebar-swap) #main_col:not(.expandRight){' + 'body:not(.ffz-sidebar-swap) #main_col:not(.expandRight){' +
'margin-right:' + width + 'px}' + 'margin-right:' + width + 'px}' +
'body.ffz-sidebar-swap #main_col:not(.expandRight){' + 'body.ffz-sidebar-swap #main_col:not(.expandRight){' +
'margin-left:' + width + 'px}'; 'margin-left:' + width + 'px}';
} }
} }
f._layout_style.innerHTML = out; f._layout_style.innerHTML = out;
} }
}.observes("isRightColumnClosed", "playerSize", "rightColumnWidth", "portraitMode", "windowHeight", "windowWidth"), }.observes("isRightColumnClosed", "playerSize", "rightColumnWidth", "portraitMode", "windowHeight", "windowWidth"),
ffzUpdatePlayerStyle: function() { ffzUpdatePlayerStyle: function() {
Ember.propertyDidChange(Layout, 'playerStyle'); Ember.propertyDidChange(Layout, 'playerStyle');
}.observes('windowHeight', 'windowWidth'), }.observes('windowHeight', 'windowWidth'),
ffzUpdatePortraitCSS: function() { ffzUpdatePortraitCSS: function() {
var portrait = this.get("portraitMode"); var portrait = this.get("portraitMode");

File diff suppressed because it is too large Load diff

View file

@ -323,7 +323,7 @@ FFZ.settings_info.mod_buttons = {
method: function() { method: function() {
var f = this, var f = this,
old_val = ""; old_val = "";
for(var i=0; i < this.settings.mod_buttons.length; i++) { for(var i=0; i < this.settings.mod_buttons.length; i++) {
var pair = this.settings.mod_buttons[i], var pair = this.settings.mod_buttons[i],
@ -349,113 +349,113 @@ FFZ.settings_info.mod_buttons = {
} }
utils.prompt( utils.prompt(
"Custom In-Line Moderation Icons", "Custom In-Line Moderation Icons",
"Please enter a list of commands to be made available as mod icons within chat lines. Commands are separated by spaces. " + "Please enter a list of commands to be made available as mod icons within chat lines. Commands are separated by spaces. " +
"To include spaces in a command, surround the command with double quotes (\"). Use <code>{user}</code> to insert the user's name " + "To include spaces in a command, surround the command with double quotes (\"). Use <code>{user}</code> to insert the user's name " +
"into the command, otherwise it will be appended to the end. Use <code>{id}</code> to insert the unique message ID into the command.</p>" + "into the command, otherwise it will be appended to the end. Use <code>{id}</code> to insert the unique message ID into the command.</p>" +
"<p><b>Example:</b> <code>!permit \"!reg add {user}\" \"/timeout {user} 1 {id}\"</code></p><p>To " + "<p><b>Example:</b> <code>!permit \"!reg add {user}\" \"/timeout {user} 1 {id}\"</code></p><p>To " +
"send multiple commands, separate them with <code>&lt;LINE&gt;</code>.</p><p>Numeric values will become timeout buttons for " + "send multiple commands, separate them with <code>&lt;LINE&gt;</code>.</p><p>Numeric values will become timeout buttons for " +
"that number of seconds. The text <code>&lt;BAN&gt;</code> is a special value that will act like the normal Ban button in chat.</p><p>" + "that number of seconds. The text <code>&lt;BAN&gt;</code> is a special value that will act like the normal Ban button in chat.</p><p>" +
"To assign a specific letter for use as the icon, specify it at the start of the command followed by an equals sign.</p><p>" + "To assign a specific letter for use as the icon, specify it at the start of the command followed by an equals sign.</p><p>" +
"<b>Example:</b> <code>A=\"!reg add\"</code></p><p><b>Default:</b> <code>&lt;BAN&gt; 600</code>", "<b>Example:</b> <code>A=\"!reg add\"</code></p><p><b>Default:</b> <code>&lt;BAN&gt; 600</code>",
old_val.substr(1), old_val.substr(1),
function(new_val) { function(new_val) {
if ( new_val === null || new_val === undefined ) if ( new_val === null || new_val === undefined )
return; return;
var vals = [], prefix = ''; var vals = [], prefix = '';
new_val = new_val.trim(); new_val = new_val.trim();
while(new_val) { while(new_val) {
if ( new_val.charAt(1) === '=' ) { if ( new_val.charAt(1) === '=' ) {
prefix = new_val.charAt(0); prefix = new_val.charAt(0);
new_val = new_val.substr(2); new_val = new_val.substr(2);
continue; continue;
} }
if ( new_val.charAt(0) === '"' ) { if ( new_val.charAt(0) === '"' ) {
var end = new_val.indexOf('"', 1); var end = new_val.indexOf('"', 1);
if ( end === -1 ) if ( end === -1 )
end = new_val.length; end = new_val.length;
var segment = new_val.substr(1, end - 1); var segment = new_val.substr(1, end - 1);
if ( segment ) { if ( segment ) {
vals.push([prefix, segment]); vals.push([prefix, segment]);
prefix = ''; prefix = '';
} }
new_val = new_val.substr(end + 1); new_val = new_val.substr(end + 1);
} else { } else {
var ind = new_val.indexOf(' '); var ind = new_val.indexOf(' ');
if ( ind === -1 ) { if ( ind === -1 ) {
if ( new_val ) { if ( new_val ) {
vals.push([prefix, new_val]); vals.push([prefix, new_val]);
prefix = ''; prefix = '';
} }
new_val = ''; new_val = '';
} else { } else {
var segment = new_val.substr(0, ind); var segment = new_val.substr(0, ind);
if ( segment ) { if ( segment ) {
vals.push([prefix, segment]); vals.push([prefix, segment]);
prefix = ''; prefix = '';
} }
new_val = new_val.substr(ind + 1); new_val = new_val.substr(ind + 1);
} }
} }
} }
var final = []; var final = [];
for(var i=0; i < vals.length; i++) { for(var i=0; i < vals.length; i++) {
var had_prefix = false, prefix = vals[i][0], val = vals[i][1]; var had_prefix = false, prefix = vals[i][0], val = vals[i][1];
if ( val === "<BAN>" ) if ( val === "<BAN>" )
val = false; val = false;
var num = parseInt(val); var num = parseInt(val);
if ( num > 0 && ! Number.isNaN(num) ) if ( num > 0 && ! Number.isNaN(num) )
val = num; val = num;
if ( ! prefix ) { if ( ! prefix ) {
var tmp; var tmp;
if ( typeof val === "string" ) if ( typeof val === "string" )
tmp = /\w/.exec(val); tmp = /\w/.exec(val);
else else
tmp = utils.duration_string(val); tmp = utils.duration_string(val);
prefix = tmp && tmp.length ? tmp[0].toUpperCase() : "C"; prefix = tmp && tmp.length ? tmp[0].toUpperCase() : "C";
} else } else
had_prefix = true; had_prefix = true;
if ( typeof val === "string" ) { if ( typeof val === "string" ) {
// Split it up for this step. // Split it up for this step.
var lines = val.split(/ *<LINE> */); var lines = val.split(/ *<LINE> */);
for(var x=0; x < lines.length; x++) { for(var x=0; x < lines.length; x++) {
if ( lines[x].indexOf('{user}') === -1 ) if ( lines[x].indexOf('{user}') === -1 )
lines[x] += ' {user}'; lines[x] += ' {user}';
} }
val = lines.join("<LINE>"); val = lines.join("<LINE>");
} }
final.push([prefix, val, had_prefix]); final.push([prefix, val, had_prefix]);
} }
f.settings.set('mod_buttons', final); f.settings.set('mod_buttons', final);
// Update existing chat lines. // Update existing chat lines.
var CL = utils.ember_resolve('component:chat/chat-line'), var CL = utils.ember_resolve('component:chat/chat-line'),
views = CL ? utils.ember_views() : []; views = CL ? utils.ember_views() : [];
for(var vid in views) { for(var vid in views) {
var view = views[vid]; var view = views[vid];
if ( view instanceof CL && view.buildModIconsHTML ) if ( view instanceof CL && view.buildModIconsHTML )
view.$('.mod-icons').replaceWith(view.buildModIconsHTML()); view.$('.mod-icons').replaceWith(view.buildModIconsHTML());
} }
}, 600); }, 600);
} }
}; };
@ -472,7 +472,7 @@ FFZ.settings_info.mod_card_buttons = {
method: function() { method: function() {
var f = this, var f = this,
old_val = ""; old_val = "";
for(var i=0; i < this.settings.mod_card_buttons.length; i++) { for(var i=0; i < this.settings.mod_card_buttons.length; i++) {
var cmd = this.settings.mod_card_buttons[i]; var cmd = this.settings.mod_card_buttons[i];
if ( cmd.indexOf(' ') !== -1 ) if ( cmd.indexOf(' ') !== -1 )
@ -481,51 +481,51 @@ FFZ.settings_info.mod_card_buttons = {
old_val += ' ' + cmd; old_val += ' ' + cmd;
} }
utils.prompt( utils.prompt(
"Moderation Card Additional Buttons", "Moderation Card Additional Buttons",
"Please enter a list of additional commands to display buttons for on moderation cards. Commands are separated by spaces. " + "Please enter a list of additional commands to display buttons for on moderation cards. Commands are separated by spaces. " +
"To include spaces in a command, surround the command with double quotes (\"). Use <code>{user}</code> to insert the " + "To include spaces in a command, surround the command with double quotes (\"). Use <code>{user}</code> to insert the " +
"user's name into the command, otherwise it will be appended to the end.</p><p><b>Example:</b> !permit \"!reg add {user}\"", "user's name into the command, otherwise it will be appended to the end.</p><p><b>Example:</b> !permit \"!reg add {user}\"",
old_val.substr(1), old_val.substr(1),
function(new_val) { function(new_val) {
if ( new_val === null || new_val === undefined ) if ( new_val === null || new_val === undefined )
return; return;
var vals = []; var vals = [];
new_val = new_val.trim(); new_val = new_val.trim();
while(new_val) { while(new_val) {
if ( new_val.charAt(0) === '"' ) { if ( new_val.charAt(0) === '"' ) {
var end = new_val.indexOf('"', 1); var end = new_val.indexOf('"', 1);
if ( end === -1 ) if ( end === -1 )
end = new_val.length; end = new_val.length;
var segment = new_val.substr(1, end - 1); var segment = new_val.substr(1, end - 1);
if ( segment ) if ( segment )
vals.push(segment); vals.push(segment);
new_val = new_val.substr(end + 1); new_val = new_val.substr(end + 1);
} else { } else {
var ind = new_val.indexOf(' '); var ind = new_val.indexOf(' ');
if ( ind === -1 ) { if ( ind === -1 ) {
if ( new_val ) if ( new_val )
vals.push(new_val); vals.push(new_val);
new_val = ''; new_val = '';
} else { } else {
var segment = new_val.substr(0, ind); var segment = new_val.substr(0, ind);
if ( segment ) if ( segment )
vals.push(segment); vals.push(segment);
new_val = new_val.substr(ind + 1); new_val = new_val.substr(ind + 1);
} }
} }
} }
f.settings.set("mod_card_buttons", vals); f.settings.set("mod_card_buttons", vals);
}, 600); }, 600);
} }
}; };
@ -541,36 +541,36 @@ FFZ.settings_info.mod_card_durations = {
help: "Add additional timeout buttons to moderation cards with specific durations.", help: "Add additional timeout buttons to moderation cards with specific durations.",
method: function() { method: function() {
var f = this, var f = this,
old_val = this.settings.mod_card_durations.join(", "); old_val = this.settings.mod_card_durations.join(", ");
utils.prompt( utils.prompt(
"Moderation Card Timeout Buttons", "Moderation Card Timeout Buttons",
"Please enter a comma-separated list of durations that you would like to have timeout buttons for. " + "Please enter a comma-separated list of durations that you would like to have timeout buttons for. " +
"Durations must be expressed in seconds.</p><p><b>Default:</b> 300, 600, 3600, 43200, 86400, 604800", "Durations must be expressed in seconds.</p><p><b>Default:</b> 300, 600, 3600, 43200, 86400, 604800",
old_val, old_val,
function(new_val) { function(new_val) {
if ( new_val === null || new_val === undefined ) if ( new_val === null || new_val === undefined )
return; return;
if ( new_val === "reset" ) if ( new_val === "reset" )
new_val = FFZ.settings_info.mod_card_durations.value.join(", "); new_val = FFZ.settings_info.mod_card_durations.value.join(", ");
// Split them up. // Split them up.
new_val = new_val.trim().split(/[ ,]+/); new_val = new_val.trim().split(/[ ,]+/);
var vals = []; var vals = [];
for(var i=0; i < new_val.length; i++) { for(var i=0; i < new_val.length; i++) {
var val = parseInt(new_val[i]); var val = parseInt(new_val[i]);
if ( val === 0 ) if ( val === 0 )
val = 1; val = 1;
if ( ! Number.isNaN(val) && val > 0 ) if ( ! Number.isNaN(val) && val > 0 )
vals.push(val); vals.push(val);
} }
f.settings.set("mod_card_durations", vals); f.settings.set("mod_card_durations", vals);
}, 600); }, 600);
} }
}; };
@ -1335,11 +1335,11 @@ FFZ.prototype._build_mod_card_history = function(msg, modcard, show_from) {
// Interactivity // Interactivity
jQuery('a.undelete', l_el).click(function(e) { this.parentElement.outerHTML = this.getAttribute('data-message'); }); jQuery('a.undelete', l_el).click(function(e) { this.parentElement.outerHTML = this.getAttribute('data-message'); });
jQuery('.deleted-word', l_el).click(function(e) { jQuery(this).trigger('mouseout'); this.outerHTML = this.getAttribute('data-text'); }); jQuery('.deleted-word', l_el).click(function(e) { jQuery(this).trigger('mouseout'); this.outerHTML = this.getAttribute('data-text'); });
jQuery('a.deleted-link', l_el).click(f._deleted_link_click); jQuery('a.deleted-link', l_el).click(f._deleted_link_click);
jQuery('img.emoticon', l_el).click(function(e) { f._click_emote(this, e) }); jQuery('img.emoticon', l_el).click(function(e) { f._click_emote(this, e) });
//jQuery('.html-tooltip', l_el).tipsy({html:true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')}); //jQuery('.html-tooltip', l_el).tipsy({html:true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')});
//jQuery('.ffz-tooltip', l_el).tipsy({live: true, html: true, title: f.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')}); //jQuery('.ffz-tooltip', l_el).tipsy({live: true, html: true, title: f.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')});
if ( modcard ) { if ( modcard ) {
modcard.get('cardInfo.user.id') !== msg.from && jQuery('span.from', l_el).click(function(e) { modcard.get('cardInfo.user.id') !== msg.from && jQuery('span.from', l_el).click(function(e) {
@ -1379,8 +1379,8 @@ FFZ.prototype._update_alias = function(user) {
var line = lines[i], var line = lines[i],
el_from = line.querySelector('.from'); el_from = line.querySelector('.from');
if ( ! el_from ) if ( ! el_from )
continue; continue;
el_from.classList.toggle('ffz-alias', alias); el_from.classList.toggle('ffz-alias', alias);
el_from.textContent = display_name; el_from.textContent = display_name;
@ -1389,8 +1389,8 @@ FFZ.prototype._update_alias = function(user) {
// Update tab completion. // Update tab completion.
if ( this._inputv ) if ( this._inputv )
Ember.propertyDidChange(this._inputv, 'ffz_name_suggestions'); Ember.propertyDidChange(this._inputv, 'ffz_name_suggestions');
// TODO: Update conversations~ // TODO: Update conversations~
} }

View file

@ -1,6 +1,6 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
utils = require('../utils'), utils = require('../utils'),
constants = require('../constants'); constants = require('../constants');
// --------------- // ---------------
@ -88,9 +88,9 @@ FFZ.prototype.modify_twitch_player = function(player) {
var id = this.get('channel.id'); var id = this.get('channel.id');
f.players[id] = this; f.players[id] = this;
var player = this.get('player'); var player = this.get('player');
if ( player ) if ( player )
this.ffzPostPlayer(); this.ffzPostPlayer();
}, },
ffz_destroy: function() { ffz_destroy: function() {
@ -128,11 +128,11 @@ FFZ.prototype.modify_twitch_player = function(player) {
ffzPostPlayer: function() { ffzPostPlayer: function() {
var player = this.get('player'); var player = this.get('player');
if ( ! player ) if ( ! player )
return; return;
// Make the stats window draggable and fix the button. // Make the stats window draggable and fix the button.
var stats = this.$('.player .js-playback-stats'); var stats = this.$('.player .js-playback-stats');
stats.draggable({cancel: 'li', containment: 'parent'}); stats.draggable({cancel: 'li', containment: 'parent'});
// Add an option to the menu to recreate the player. // Add an option to the menu to recreate the player.
var t = this, var t = this,

View file

@ -332,7 +332,7 @@ FFZ.prototype.modify_room_view = function(view) {
if ( this._ffz_mouse_move ) { if ( this._ffz_mouse_move ) {
messages.removeEventListener('mousemove', this._ffz_mouse_move); messages.removeEventListener('mousemove', this._ffz_mouse_move);
messages.removeEventListener('touchmove', this._ffz_mouse_move); messages.removeEventListener('touchmove', this._ffz_mouse_move);
this._ffz_mouse_move = undefined; this._ffz_mouse_move = undefined;
} }
@ -1502,17 +1502,17 @@ FFZ.prototype._modify_room = function(room) {
// Tokenization // Tokenization
f.tokenize_chat_line(msg, false, this.get('roomProperties.hide_chat_links')); f.tokenize_chat_line(msg, false, this.get('roomProperties.hide_chat_links'));
// If it's from Twitch notify, and it's directly related to // If it's from Twitch notify, and it's directly related to
if ( msg.from === 'twitchnotify' && msg.message.indexOf('subscribed to') === -1 && msg.message.indexOf('subscribed') !== -1 ) { if ( msg.from === 'twitchnotify' && msg.message.indexOf('subscribed to') === -1 && msg.message.indexOf('subscribed') !== -1 ) {
if ( ! msg.tags ) if ( ! msg.tags )
msg.tags = {}; msg.tags = {};
if ( ! msg.tags.badges ) if ( ! msg.tags.badges )
msg.tags.badges = {}; msg.tags.badges = {};
msg.tags.badges.subscriber = '1'; msg.tags.badges.subscriber = '1';
msg.tags.subscriber = true; msg.tags.subscriber = true;
if ( msg.labels && msg.labels.indexOf("subscriber") === -1 ) if ( msg.labels && msg.labels.indexOf("subscriber") === -1 )
msg.labels.push("subscriber"); msg.labels.push("subscriber");
} }
// Keep the history. // Keep the history.
if ( ! is_whisper && msg.from && msg.from !== 'jtv' && msg.from !== 'twitchnotify' && f.settings.mod_card_history ) { if ( ! is_whisper && msg.from && msg.from !== 'jtv' && msg.from !== 'twitchnotify' && f.settings.mod_card_history ) {
@ -1610,9 +1610,9 @@ FFZ.prototype._modify_room = function(room) {
ids[msg_id] = msg; ids[msg_id] = msg;
} }
// Report this message to the dashboard. // Report this message to the dashboard.
if ( window !== window.parent && parent.postMessage && msg.from && msg.from !== "jtv" && msg.from !== "twitchnotify" ) if ( window !== window.parent && parent.postMessage && msg.from && msg.from !== "jtv" && msg.from !== "twitchnotify" )
parent.postMessage({from_ffz: true, command: 'chat_message', data: {from: msg.from, room: msg.room}}, "*"); //location.protocol + "//www.twitch.tv/"); parent.postMessage({from_ffz: true, command: 'chat_message', data: {from: msg.from, room: msg.room}}, "*"); //location.protocol + "//www.twitch.tv/");
// Add the message. // Add the message.
return this._super(msg); return this._super(msg);
@ -1735,8 +1735,8 @@ FFZ.prototype._modify_room = function(room) {
if ( f._cindex ) if ( f._cindex )
f._cindex.ffzUpdateChatters(); f._cindex.ffzUpdateChatters();
if ( window !== window.parent && parent.postMessage ) if ( window !== window.parent && parent.postMessage )
parent.postMessage({from_ffz: true, command: 'chatter_count', data: Object.keys(this.get('ffz_chatters') || {}).length}, "*"); //location.protocol + "//www.twitch.tv/"); parent.postMessage({from_ffz: true, command: 'chatter_count', data: Object.keys(this.get('ffz_chatters') || {}).length}, "*"); //location.protocol + "//www.twitch.tv/");
}, },

View file

@ -1,5 +1,5 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
utils = require("../utils"); utils = require("../utils");
// -------------------- // --------------------

View file

@ -48,7 +48,7 @@ FFZ.settings_info.sidebar_hide_recommended_channels = {
no_mobile: true, no_mobile: true,
name: "Hide Recommended Channels", name: "Hide Recommended Channels",
help: "Hide the Recommended Channels section from the sidebar.", help: "Hide the Recommended Channels section from the sidebar.",
on_update: utils.toggle_cls('ffz-hide-recommended-channels') on_update: utils.toggle_cls('ffz-hide-recommended-channels')
}; };
@ -62,7 +62,7 @@ FFZ.settings_info.sidebar_hide_recommended_friends = {
no_mobile: true, no_mobile: true,
name: "Hide Recommended Friends", name: "Hide Recommended Friends",
help: "Hide the Recommended Friends section from the sidebar.", help: "Hide the Recommended Friends section from the sidebar.",
on_update: utils.toggle_cls('ffz-hide-recommended-friends') on_update: utils.toggle_cls('ffz-hide-recommended-friends')
}; };

View file

@ -1,5 +1,5 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
utils = require('../utils'); utils = require('../utils');
// -------------------- // --------------------

View file

@ -12,206 +12,206 @@ var FFZ = window.FrankerFaceZ,
// --------------------- // ---------------------
FFZ.prototype.setup_vod_chat = function() { FFZ.prototype.setup_vod_chat = function() {
// Get the VOD Chat Service // Get the VOD Chat Service
var f = this, var f = this,
VODService = utils.ember_lookup('service:vod-chat-service'); VODService = utils.ember_lookup('service:vod-chat-service');
if ( VODService ) if ( VODService )
VODService.reopen({ VODService.reopen({
messageBufferSize: f.settings.scrollback_length, messageBufferSize: f.settings.scrollback_length,
pushMessage: function(msg) { pushMessage: function(msg) {
if ( msg.get("color") === null ) { if ( msg.get("color") === null ) {
var colors = this.get("colorSettings"), var colors = this.get("colorSettings"),
from = msg.get("from"); from = msg.get("from");
if ( ! colors.get(from) ) if ( ! colors.get(from) )
colors.set(from, constants.CHAT_COLORS[Math.floor(Math.random() * constants.CHAT_COLORS.length)]); colors.set(from, constants.CHAT_COLORS[Math.floor(Math.random() * constants.CHAT_COLORS.length)]);
msg.set("color", colors.get(from)); msg.set("color", colors.get(from));
} }
this.get("messages").pushObject(msg); this.get("messages").pushObject(msg);
var messages = this.get("messages"), var messages = this.get("messages"),
len = this.get("messages.length"), len = this.get("messages.length"),
limit = this.get("messageBufferSize"); limit = this.get("messageBufferSize");
if ( len > limit ) if ( len > limit )
messages.removeAt(0, len - limit); messages.removeAt(0, len - limit);
} }
}); });
else else
f.error("Unable to locate VOD Chat Service."); f.error("Unable to locate VOD Chat Service.");
this.update_views('component:vod-right-column', this.modify_vod_right_column); this.update_views('component:vod-right-column', this.modify_vod_right_column);
this.update_views('view:vod', this.modify_vod_view); this.update_views('view:vod', this.modify_vod_view);
this.update_views('component:vod-chat-display', this.modify_vod_chat_display); this.update_views('component:vod-chat-display', this.modify_vod_chat_display);
} }
FFZ.prototype.modify_vod_view = function(view) { FFZ.prototype.modify_vod_view = function(view) {
var f = this; var f = this;
utils.ember_reopen_view(view, { utils.ember_reopen_view(view, {
ffz_init: function() { ffz_init: function() {
f._vodv = this; f._vodv = this;
var channel_id = this.get('context.channel.name'); var channel_id = this.get('context.channel.name');
if ( f.settings.auto_theater ) { if ( f.settings.auto_theater ) {
var player = f.players && f.players[channel_id] && f.players[channel_id].get('player'); var player = f.players && f.players[channel_id] && f.players[channel_id].get('player');
if ( player ) if ( player )
player.setTheatre(true); player.setTheatre(true);
} }
// Listen to scrolling. // Listen to scrolling.
this._ffz_scroller = this.ffzOnScroll.bind(this); this._ffz_scroller = this.ffzOnScroll.bind(this);
jQuery(this.get('element')).parents('.tse-scroll-content').on('scroll', this._ffz_scroller); jQuery(this.get('element')).parents('.tse-scroll-content').on('scroll', this._ffz_scroller);
}, },
ffz_destroy: function() { ffz_destroy: function() {
if ( f._vodv === this ) if ( f._vodv === this )
f._vodv = null; f._vodv = null;
if ( this._ffz_scroller ) { if ( this._ffz_scroller ) {
jQuery(this.get('element')).parents('.tse-scroll-content').off('scroll', this._ffz_scroller); jQuery(this.get('element')).parents('.tse-scroll-content').off('scroll', this._ffz_scroller);
this._ffz_scroller = null; this._ffz_scroller = null;
} }
}, },
ffzOnScroll: function(event) { ffzOnScroll: function(event) {
// When we scroll past the bottom of the player, do stuff! // When we scroll past the bottom of the player, do stuff!
var top = event && event.target && event.target.scrollTop, var top = event && event.target && event.target.scrollTop,
height = this.get('layout.playerSize.1'); height = this.get('layout.playerSize.1');
if ( ! top ) if ( ! top )
top = jQuery(this.get('element')).parents('.tse-scroll-content').scrollTop(); top = jQuery(this.get('element')).parents('.tse-scroll-content').scrollTop();
document.body.classList.toggle('ffz-small-player', f.settings.small_player && top >= height); document.body.classList.toggle('ffz-small-player', f.settings.small_player && top >= height);
} }
}); });
} }
FFZ.prototype.modify_vod_right_column = function(component) { FFZ.prototype.modify_vod_right_column = function(component) {
var f = this; var f = this;
utils.ember_reopen_view(component, { utils.ember_reopen_view(component, {
ffz_init: function() { ffz_init: function() {
if ( f.settings.dark_twitch ) { if ( f.settings.dark_twitch ) {
var el = this.get('element'), var el = this.get('element'),
cont = el && el.querySelector('.chat-container'); cont = el && el.querySelector('.chat-container');
if ( cont ) if ( cont )
cont.classList.add('dark'); cont.classList.add('dark');
} }
} }
}); });
} }
FFZ.prototype.modify_vod_chat_display = function(component) { FFZ.prototype.modify_vod_chat_display = function(component) {
var f = this, var f = this,
VODService = utils.ember_lookup('service:vod-chat-service'); VODService = utils.ember_lookup('service:vod-chat-service');
utils.ember_reopen_view(component, { utils.ember_reopen_view(component, {
_prepareToolTips: function() { _prepareToolTips: function() {
this.$(".tooltip").tipsy({ this.$(".tooltip").tipsy({
live: true, live: true,
gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 's') gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 's')
}) })
}, },
ffz_init: function() { ffz_init: function() {
f._vodc = this; f._vodc = this;
// Load the room, if necessary // Load the room, if necessary
var room_id = this.get('video.channel.name'); var room_id = this.get('video.channel.name');
if ( room_id && ! f.rooms[room_id] ) if ( room_id && ! f.rooms[room_id] )
f.load_room(room_id); // TODO: Function to reprocess existing messages. f.load_room(room_id); // TODO: Function to reprocess existing messages.
this.ffz_frozen = false; this.ffz_frozen = false;
if ( f.settings.chat_hover_pause ) if ( f.settings.chat_hover_pause )
this.ffzEnableFreeze(); this.ffzEnableFreeze();
}, },
ffz_destroy: function() { ffz_destroy: function() {
if ( f._vodc === this ) if ( f._vodc === this )
f._vodc = undefined; f._vodc = undefined;
// TODO: Function to unload the old room? // TODO: Function to unload the old room?
this.ffzDisableFreeze(); this.ffzDisableFreeze();
}, },
ffzEnableFreeze: function() { ffzEnableFreeze: function() {
var scroller = this.get('chatMessagesScroller'); var scroller = this.get('chatMessagesScroller');
if ( ! scroller ) if ( ! scroller )
return; return;
this._ffz_interval = setInterval(this.ffzPulse.bind(this), 200); this._ffz_interval = setInterval(this.ffzPulse.bind(this), 200);
this._ffz_mouse_move = this.ffzMouseMove.bind(this); this._ffz_mouse_move = this.ffzMouseMove.bind(this);
this._ffz_mouse_out = this.ffzMouseOut.bind(this); this._ffz_mouse_out = this.ffzMouseOut.bind(this);
scroller.on('mousemove', this._ffz_mouse_move); scroller.on('mousemove', this._ffz_mouse_move);
scroller.on('touchmove', this._ffz_mouse_move); scroller.on('touchmove', this._ffz_mouse_move);
scroller.on('mouseout', this._ffz_mouse_out); scroller.on('mouseout', this._ffz_mouse_out);
}, },
ffzDisableFreeze: function() { ffzDisableFreeze: function() {
if ( this._ffz_interval ) { if ( this._ffz_interval ) {
clearInterval(this._ffz_interval); clearInterval(this._ffz_interval);
this._ffz_interval = undefined; this._ffz_interval = undefined;
} }
this.ffzUnfreeze(); this.ffzUnfreeze();
var scroller = this.get('chatMessagesScroller'); var scroller = this.get('chatMessagesScroller');
if ( ! scroller ) if ( ! scroller )
return; return;
if ( this._ffz_mouse_move ) { if ( this._ffz_mouse_move ) {
scroller.off('mousemove', this._ffz_mouse_move); scroller.off('mousemove', this._ffz_mouse_move);
scroller.off('touchmove', this._ffz_mouse_move); scroller.off('touchmove', this._ffz_mouse_move);
this._ffz_mouse_move = undefined; this._ffz_mouse_move = undefined;
} }
if ( this._ffz_mouse_out ) { if ( this._ffz_mouse_out ) {
scroller.off('mouseout', this._ffz_mouse_out); scroller.off('mouseout', this._ffz_mouse_out);
this._ffz_mouse_out = undefined; this._ffz_mouse_out = undefined;
} }
}, },
ffzUnfreeze: function(from_stuck) { ffzUnfreeze: function(from_stuck) {
this.ffz_frozen = false; this.ffz_frozen = false;
this._ffz_last_move = 0; this._ffz_last_move = 0;
this.ffzUnwarnPaused(); this.ffzUnwarnPaused();
if ( ! from_stuck && this.get('stuckToBottom') ) if ( ! from_stuck && this.get('stuckToBottom') )
this._scrollToBottom(); this._scrollToBottom();
}, },
ffzPulse: function() { ffzPulse: function() {
if ( this.ffz_frozen ) { if ( this.ffz_frozen ) {
var elapsed = Date.now() - this._ffz_last_move; var elapsed = Date.now() - this._ffz_last_move;
if ( elapsed > 750 ) if ( elapsed > 750 )
this.ffzUnfreeze(); this.ffzUnfreeze();
} }
}, },
ffzMouseOut: function(event) { ffzMouseOut: function(event) {
this._ffz_outside = true; this._ffz_outside = true;
var e = this; var e = this;
setTimeout(function() { setTimeout(function() {
if ( e._ffz_outside ) if ( e._ffz_outside )
e.ffzUnfreeze(); e.ffzUnfreeze();
}, 25); }, 25);
}, },
ffzMouseMove: function(event) { ffzMouseMove: function(event) {
this._ffz_last_move = Date.now(); this._ffz_last_move = Date.now();
this._ffz_outside = false; this._ffz_outside = false;
if ( event.screenX === this._ffz_last_screenx && event.screenY === this._ffz_last_screeny ) if ( event.screenX === this._ffz_last_screenx && event.screenY === this._ffz_last_screeny )
return; return;
this._ffz_last_screenx = event.screenX; this._ffz_last_screenx = event.screenX;
@ -222,37 +222,37 @@ FFZ.prototype.modify_vod_chat_display = function(component) {
this.ffz_frozen = true; this.ffz_frozen = true;
if ( this.get('stuckToBottom') ) { if ( this.get('stuckToBottom') ) {
VODService && VODService.set("messageBufferSize", f.settings.scrollback_length + 150); VODService && VODService.set("messageBufferSize", f.settings.scrollback_length + 150);
this.ffzWarnPaused(); this.ffzWarnPaused();
} }
}, },
_scrollToBottom: _.throttle(function() { _scrollToBottom: _.throttle(function() {
var e = this, var e = this,
scroller = e.get('chatMessagesScroller'); scroller = e.get('chatMessagesScroller');
if ( ! scroller || ! scroller.length ) if ( ! scroller || ! scroller.length )
return; return;
Ember.run.next(function() { Ember.run.next(function() {
(window.requestAnimationFrame||setTimeout)(function() { (window.requestAnimationFrame||setTimeout)(function() {
if ( e.ffz_frozen ) if ( e.ffz_frozen )
return; return;
scroller[0].scrollTop = scroller[0].scrollHeight; scroller[0].scrollTop = scroller[0].scrollHeight;
e._setStuckToBottom(true); e._setStuckToBottom(true);
}) })
}) })
}, 300), }, 300),
_setStuckToBottom: function(val) { _setStuckToBottom: function(val) {
this.set("stuckToBottom", val); this.set("stuckToBottom", val);
VODService && VODService.set("messageBufferSize", f.settings.scrollback_length + (val ? 0 : 150)); VODService && VODService.set("messageBufferSize", f.settings.scrollback_length + (val ? 0 : 150));
if ( ! val ) if ( ! val )
this.ffUnfreeze(true); this.ffUnfreeze(true);
}, },
ffzWarnPaused: function() { ffzWarnPaused: function() {
var el = this.get('element'), var el = this.get('element'),
warning = el && el.querySelector('.chat-interface .more-messages-indicator.ffz-freeze-indicator'); warning = el && el.querySelector('.chat-interface .more-messages-indicator.ffz-freeze-indicator');
@ -280,5 +280,5 @@ FFZ.prototype.modify_vod_chat_display = function(component) {
if ( warning ) if ( warning )
warning.classList.add('hidden'); warning.classList.add('hidden');
} }
}); });
} }

View file

@ -1,5 +1,5 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
utils = require("../utils"), utils = require("../utils"),
constants = require("../constants"); constants = require("../constants");
// -------------------- // --------------------
@ -66,23 +66,23 @@ FFZ.prototype._update_views = function(klasses) {
// Iterate over all existing views and update them as necessary. // Iterate over all existing views and update them as necessary.
var views = utils.ember_views(); var views = utils.ember_views();
for(var view_id in views) { for(var view_id in views) {
var view = views[view_id]; var view = views[view_id];
if ( ! view ) if ( ! view )
continue; continue;
for(var i=0; i < klasses.length; i++) for(var i=0; i < klasses.length; i++)
if ( view instanceof klasses[i][1] ) { if ( view instanceof klasses[i][1] ) {
try { try {
if ( ! view.ffz_modified ) if ( ! view.ffz_modified )
klasses[i][2].call(this, view); klasses[i][2].call(this, view);
(view.ffz_update || view.ffz_init).call(view); (view.ffz_update || view.ffz_init).call(view);
} catch(err) { } catch(err) {
this.error("An error occured when updating an existing Ember instance of: " + klasses[i][0], err); this.error("An error occured when updating an existing Ember instance of: " + klasses[i][0], err);
} }
break; break;
} }
} }
} }

View file

@ -221,29 +221,29 @@ FFZ.prototype.load_emoji_data = function(callback, tries) {
emoji.code = eid; emoji.code = eid;
new_data[eid] = emoji; new_data[eid] = emoji;
if ( emoji.short_name ) if ( emoji.short_name )
by_name[emoji.short_name] = eid; by_name[emoji.short_name] = eid;
if ( emoji.names && emoji.names.length ) if ( emoji.names && emoji.names.length )
for(var x=0,y=emoji.names.length; x < y; x++) for(var x=0,y=emoji.names.length; x < y; x++)
by_name[emoji.names[x]] = eid; by_name[emoji.names[x]] = eid;
emoji.raw = _.map(emoji.code.split("-"), utils.codepoint_to_emoji).join(""); emoji.raw = _.map(emoji.code.split("-"), utils.codepoint_to_emoji).join("");
emoji.tw_src = constants.SERVER + 'emoji/tw/' + eid + '.svg'; emoji.tw_src = constants.SERVER + 'emoji/tw/' + eid + '.svg';
emoji.noto_src = constants.SERVER + 'emoji/noto-' + eid + '.svg'; emoji.noto_src = constants.SERVER + 'emoji/noto-' + eid + '.svg';
emoji.one_src = constants.SERVER + 'emoji/one/' + eid + '.svg'; emoji.one_src = constants.SERVER + 'emoji/one/' + eid + '.svg';
emoji.token = { emoji.token = {
type: "emoticon", type: "emoticon",
imgSrc: true, imgSrc: true,
tw_src: emoji.tw_src, tw_src: emoji.tw_src,
noto_src: emoji.noto_src, noto_src: emoji.noto_src,
one_src: emoji.one_src, one_src: emoji.one_src,
tw: emoji.tw, tw: emoji.tw,
noto: emoji.noto, noto: emoji.noto,
one: emoji.one, one: emoji.one,
ffzEmoji: eid, ffzEmoji: eid,
altText: emoji.raw altText: emoji.raw
@ -347,8 +347,8 @@ FFZ.prototype.unload_set = function(set_id) {
api.emote_sets[set_id] = undefined; api.emote_sets[set_id] = undefined;
} }
if ( this._inputv ) if ( this._inputv )
Ember.propertyDidChange(this._inputv, 'ffz_emoticons'); Ember.propertyDidChange(this._inputv, 'ffz_emoticons');
} }
@ -388,14 +388,14 @@ FFZ.prototype._load_set_json = function(set_id, callback, data) {
else else
emote.regex = new RegExp("(^|\\W|\\b)(" + utils.escape_regex(emote.name) + ")\\b", "g"); emote.regex = new RegExp("(^|\\W|\\b)(" + utils.escape_regex(emote.name) + ")\\b", "g");
emote.token = { emote.token = {
type: "emoticon", type: "emoticon",
srcSet: emote.srcSet, srcSet: emote.srcSet,
imgSrc: emote.urls[1], imgSrc: emote.urls[1],
ffzEmote: emote.id, ffzEmote: emote.id,
ffzEmoteSet: set_id, ffzEmoteSet: set_id,
altText: emote.hidden ? '???' : emote.name altText: emote.hidden ? '???' : emote.name
}; };
output_css += build_css(emote); output_css += build_css(emote);
data.count++; data.count++;
@ -410,8 +410,8 @@ FFZ.prototype._load_set_json = function(set_id, callback, data) {
this.update_ui_link(); this.update_ui_link();
if ( this._inputv ) if ( this._inputv )
Ember.propertyDidChange(this._inputv, 'ffz_emoticons'); Ember.propertyDidChange(this._inputv, 'ffz_emoticons');
this.rerender_feed_cards(set_id); this.rerender_feed_cards(set_id);

View file

@ -59,7 +59,7 @@ var API = FFZ.API = function(instance, name, icon, version) {
this.name_key = this.name.replace(/[^A-Z0-9_\-]/g, '').toLowerCase(); this.name_key = this.name.replace(/[^A-Z0-9_\-]/g, '').toLowerCase();
this.icon = icon || null; this.icon = icon || null;
this.version = version || null; this.version = version || null;
this.ffz.log('Registered New Extension #' + this.id + ': ' + this.name); this.ffz.log('Registered New Extension #' + this.id + ': ' + this.name);
}; };
@ -169,14 +169,14 @@ API.prototype._load_set = function(real_id, set_id, data) {
else else
new_emote.regex = new RegExp("(^|\\W|\\b)(" + utils.escape_regex(emote.name) + ")(?=\\W|$)", "g"); new_emote.regex = new RegExp("(^|\\W|\\b)(" + utils.escape_regex(emote.name) + ")(?=\\W|$)", "g");
new_emote.token = { new_emote.token = {
type: "emoticon", type: "emoticon",
srcSet: new_emote.srcSet, srcSet: new_emote.srcSet,
imgSrc: new_emote.urls[1], imgSrc: new_emote.urls[1],
ffzEmote: id, ffzEmote: id,
ffzEmoteSet: real_id, ffzEmoteSet: real_id,
altText: new_emote.hidden ? '???' : new_emote.name altText: new_emote.hidden ? '???' : new_emote.name
}; };
output_css += build_css(new_emote); output_css += build_css(new_emote);
emote_set.count++; emote_set.count++;
@ -294,9 +294,9 @@ API.prototype.register_global_set = function(id, emote_set) {
if ( this.ffz.default_sets && this.ffz.default_sets.indexOf(exact_id) === -1 ) if ( this.ffz.default_sets && this.ffz.default_sets.indexOf(exact_id) === -1 )
this.ffz.default_sets.push(exact_id); this.ffz.default_sets.push(exact_id);
// Update tab completion. // Update tab completion.
if ( this.ffz._inputv ) if ( this.ffz._inputv )
Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons'); Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons');
}; };
@ -324,9 +324,9 @@ API.prototype.unregister_global_set = function(id) {
if ( ind !== -1 ) if ( ind !== -1 )
this.ffz.default_sets.splice(ind,1); this.ffz.default_sets.splice(ind,1);
// Update tab completion. // Update tab completion.
if ( this.ffz._inputv ) if ( this.ffz._inputv )
Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons'); Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons');
}; };
@ -361,9 +361,9 @@ API.prototype.register_room_set = function(room_id, id, emote_set) {
room.ext_sets && room.ext_sets.push(exact_id); room.ext_sets && room.ext_sets.push(exact_id);
emote_set.users.push(room_id); emote_set.users.push(room_id);
// Update tab completion. // Update tab completion.
if ( this.ffz._inputv ) if ( this.ffz._inputv )
Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons'); Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons');
} }
@ -383,9 +383,9 @@ API.prototype.unregister_room_set = function(room_id, id) {
if ( ind !== -1 ) if ( ind !== -1 )
emote_set.users.splice(ind,1); emote_set.users.splice(ind,1);
// Update tab completion. // Update tab completion.
if ( this.ffz._inputv ) if ( this.ffz._inputv )
Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons'); Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons');
} }
@ -473,7 +473,7 @@ API.prototype.user_add_set = function(username, set_id) {
// Update tab completion. // Update tab completion.
var user = this.ffz.get_user(); var user = this.ffz.get_user();
if ( this.ffz._inputv && user && user.login === username ) if ( this.ffz._inputv && user && user.login === username )
Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons'); Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons');
} }
@ -497,7 +497,7 @@ API.prototype.user_remove_set = function(username, set_id) {
// Update tab completion. // Update tab completion.
var user = this.ffz.get_user(); var user = this.ffz.get_user();
if ( this.ffz._inputv && user && user.login === username ) if ( this.ffz._inputv && user && user.login === username )
Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons'); Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons');
} }

View file

@ -42,11 +42,11 @@ FFZ.prototype.setup_bttv = function(delay) {
utils.update_css(this._chat_style, 'chat_ts_font_size', ''); utils.update_css(this._chat_style, 'chat_ts_font_size', '');
} }
// Remove Sub Count and the Chart // Remove Sub Count and the Chart
if ( this.is_dashboard ) { if ( this.is_dashboard ) {
this._update_subscribers(); this._update_subscribers();
this._remove_dash_chart(); this._remove_dash_chart();
} }
document.body.classList.add('ffz-bttv'); document.body.classList.add('ffz-bttv');
@ -101,8 +101,8 @@ FFZ.prototype.setup_bttv = function(delay) {
this.toggle_style('badges-blank'); this.toggle_style('badges-blank');
this.toggle_style('badges-circular-small'); this.toggle_style('badges-circular-small');
this.toggle_style('badges-transparent'); this.toggle_style('badges-transparent');
this.toggle_style('badges-sub-notice'); this.toggle_style('badges-sub-notice');
this.toggle_style('badges-sub-notice-on'); this.toggle_style('badges-sub-notice-on');
// Disable other features too. // Disable other features too.
document.body.classList.remove('ffz-transparent-badges'); document.body.classList.remove('ffz-transparent-badges');
@ -237,39 +237,39 @@ FFZ.prototype.setup_bttv = function(delay) {
} }
}; };
// Emoji! // Emoji!
var parse_emoji = function(token) { var parse_emoji = function(token) {
var setting = f.settings.parse_emoji, var setting = f.settings.parse_emoji,
output = [], output = [],
segments = token.split(constants.EMOJI_REGEX), segments = token.split(constants.EMOJI_REGEX),
text = null; text = null;
if ( setting === 0 ) if ( setting === 0 )
return [token]; return [token];
while(segments.length) { while(segments.length) {
text = (text || '') + segments.shift(); text = (text || '') + segments.shift();
if ( segments.length ) { if ( segments.length ) {
var match = segments.shift(), var match = segments.shift(),
eid = utils.emoji_to_codepoint(match), eid = utils.emoji_to_codepoint(match),
data = f.emoji_data[eid], data = f.emoji_data[eid],
src = data && (setting === 3 ? data.one_src : (setting === 2 ? data.noto_src : data.tw_src)); src = data && (setting === 3 ? data.one_src : (setting === 2 ? data.noto_src : data.tw_src));
if ( src ) { if ( src ) {
if ( text && text.length ) if ( text && text.length )
output.push(text); output.push(text);
var code = utils.quote_attr(data.raw); var code = utils.quote_attr(data.raw);
output.push(['<img class="emoticon emoji ffz-tooltip" height="18px" data-ffz-emoji="' + eid + '" src="' + utils.quote_attr(src) + '" alt="' + code + '">']); output.push(['<img class="emoticon emoji ffz-tooltip" height="18px" data-ffz-emoji="' + eid + '" src="' + utils.quote_attr(src) + '" alt="' + code + '">']);
text = null; text = null;
} else } else
text = (text || '') + match; text = (text || '') + match;
} }
} }
if ( text && text.length ) if ( text && text.length )
output.push(text); output.push(text);
return output; return output;
} }
// Emoticonize // Emoticonize
@ -283,62 +283,62 @@ FFZ.prototype.setup_bttv = function(delay) {
sets = f.getEmotes(l_sender, l_room), sets = f.getEmotes(l_sender, l_room),
emotes = {}, emote, emotes = {}, emote,
user = f.get_user(), user = f.get_user(),
new_tokens = [], new_tokens = [],
mine = user && user.login === l_sender; mine = user && user.login === l_sender;
// Build an object with all of our emotes. // Build an object with all of our emotes.
for(var i=0; i < sets.length; i++) { for(var i=0; i < sets.length; i++) {
var emote_set = f.emote_sets[sets[i]]; var emote_set = f.emote_sets[sets[i]];
if ( emote_set && emote_set.emoticons ) if ( emote_set && emote_set.emoticons )
for(var emote_id in emote_set.emoticons) { for(var emote_id in emote_set.emoticons) {
emote = emote_set.emoticons[emote_id]; emote = emote_set.emoticons[emote_id];
if ( ! emotes.hasOwnProperty(emote.name) ) if ( ! emotes.hasOwnProperty(emote.name) )
emotes[emote.name] = emote; emotes[emote.name] = emote;
} }
} }
for(var i=0, l=tokens.length; i < l; i++) { for(var i=0, l=tokens.length; i < l; i++) {
var token = tokens[i]; var token = tokens[i];
if ( typeof token !== "string" ) { if ( typeof token !== "string" ) {
new_tokens.push(token); new_tokens.push(token);
continue; continue;
} }
// Split the token! // Split the token!
var segments = token.split(' '), var segments = token.split(' '),
text = [], segment; text = [], segment;
for(var x=0,y=segments.length; x < y; x++) { for(var x=0,y=segments.length; x < y; x++) {
segment = segments[x]; segment = segments[x];
if ( emotes.hasOwnProperty(segment) ) { if ( emotes.hasOwnProperty(segment) ) {
emote = emotes[segment]; emote = emotes[segment];
if ( text.length ) { if ( text.length ) {
var toks = parse_emoji(text.join(' ') + ' '); var toks = parse_emoji(text.join(' ') + ' ');
for(var q=0; q < toks.length; q++) for(var q=0; q < toks.length; q++)
new_tokens.push(toks[q]); new_tokens.push(toks[q]);
text = []; text = [];
} }
new_tokens.push(['<img class="emoticon ffz-tooltip" data-ffz-set="' + emote.set_id + '" data-ffz-emote="' + emote.id + '" srcset="' + utils.quote_attr(emote.srcSet || "") + '" src="' + utils.quote_attr(emote.urls[1]) + '" alt="' + utils.quote_attr(emote.name) + '">']); new_tokens.push(['<img class="emoticon ffz-tooltip" data-ffz-set="' + emote.set_id + '" data-ffz-emote="' + emote.id + '" srcset="' + utils.quote_attr(emote.srcSet || "") + '" src="' + utils.quote_attr(emote.urls[1]) + '" alt="' + utils.quote_attr(emote.name) + '">']);
if ( mine && l_room ) if ( mine && l_room )
f.add_usage(l_room, emote); f.add_usage(l_room, emote);
text.push(''); text.push('');
} else } else
text.push(segment); text.push(segment);
} }
if ( text.length > 1 || (text.length === 1 && text[0] !== '') ) { if ( text.length > 1 || (text.length === 1 && text[0] !== '') ) {
var toks = parse_emoji(text.join(' ') + ' '); var toks = parse_emoji(text.join(' ') + ' ');
for(var q=0; q < toks.length; q++) for(var q=0; q < toks.length; q++)
new_tokens.push(toks[q]); new_tokens.push(toks[q]);
} }
} }
return new_tokens; return new_tokens;
} }
this.update_ui_link(); this.update_ui_link();
} }

View file

@ -1,5 +1,5 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
utils = require('../utils'); utils = require('../utils');
// -------------------- // --------------------

View file

@ -1,6 +1,6 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
constants = require('./constants'), constants = require('./constants'),
utils = require('./utils'); utils = require('./utils');
// -------------------- // --------------------

View file

@ -13,16 +13,16 @@ var FFZ = window.FrankerFaceZ = function() {
this._apis = {}; this._apis = {};
this._chat_filters = []; this._chat_filters = [];
// Error Logging // Error Logging
var t = this; var t = this;
window.addEventListener('error', function(event) { window.addEventListener('error', function(event) {
if ( ! event.error ) if ( ! event.error )
return; return;
//var has_stack = event.error && event.error.stack; //var has_stack = event.error && event.error.stack;
t.error("Uncaught JavaScript Error", event.error); t.error("Uncaught JavaScript Error", event.error);
//t.log("JavaScript Error: " + event.message + " [" + event.filename + ":" + event.lineno + ":" + event.colno + "]", has_stack ? event.error.stack : undefined, false, has_stack); //t.log("JavaScript Error: " + event.message + " [" + event.filename + ":" + event.lineno + ":" + event.colno + "]", has_stack ? event.error.stack : undefined, false, has_stack);
}); });
// Get things started. // Get things started.
this.initialize(); this.initialize();
@ -47,8 +47,8 @@ var VER = FFZ.version_info = {
// Logging // Logging
FFZ.prototype.log = function(msg, data, to_json, log_json) { FFZ.prototype.log = function(msg, data, to_json, log_json) {
if ( to_json ) if ( to_json )
msg = msg + ' -- ' + JSON.stringify(data); msg = msg + ' -- ' + JSON.stringify(data);
this._log_data.push(msg + ((!to_json && log_json) ? " -- " + JSON.stringify(data) : "")); this._log_data.push(msg + ((!to_json && log_json) ? " -- " + JSON.stringify(data) : ""));
@ -116,16 +116,16 @@ FFZ.prototype.get_user = function(force_reload) {
if ( ! force_reload && this.__user ) if ( ! force_reload && this.__user )
return this.__user; return this.__user;
var LC = FFZ.utils.ember_lookup('service:login'), var LC = FFZ.utils.ember_lookup('service:login'),
user = LC ? LC.get('userData') : undefined; user = LC ? LC.get('userData') : undefined;
if ( ! user && window.PP && PP.login ) if ( ! user && window.PP && PP.login )
user = PP; user = PP;
if ( user ) if ( user )
this.__user = user; this.__user = user;
return user; return user;
} }
@ -268,7 +268,7 @@ FFZ.prototype.initialize = function(increment, delay) {
FFZ.prototype.init_player = function(delay) { FFZ.prototype.init_player = function(delay) {
var start = (window.performance && performance.now) ? performance.now() : Date.now(); var start = (window.performance && performance.now) ? performance.now() : Date.now();
this.log("Found Twitch Player after " + (delay||0) + " ms at: " + location); this.log("Found Twitch Player after " + (delay||0) + " ms at: " + location);
this.log("Initializing FrankerFaceZ version " + FFZ.version_info); this.log("Initializing FrankerFaceZ version " + FFZ.version_info);
this.users = {}; this.users = {};
this.is_dashboard = false; this.is_dashboard = false;
@ -292,7 +292,7 @@ FFZ.prototype.init_player = function(delay) {
FFZ.prototype.init_normal = function(delay, no_socket) { FFZ.prototype.init_normal = function(delay, no_socket) {
var start = (window.performance && performance.now) ? performance.now() : Date.now(); var start = (window.performance && performance.now) ? performance.now() : Date.now();
this.log("Found non-Ember Twitch after " + (delay||0) + " ms at: " + location); this.log("Found non-Ember Twitch after " + (delay||0) + " ms at: " + location);
this.log("Initializing FrankerFaceZ version " + FFZ.version_info); this.log("Initializing FrankerFaceZ version " + FFZ.version_info);
this.users = {}; this.users = {};
this.is_dashboard = false; this.is_dashboard = false;
@ -322,7 +322,7 @@ FFZ.prototype.init_normal = function(delay, no_socket) {
this.setup_following_count(false); this.setup_following_count(false);
this.setup_menu(); this.setup_menu();
this.setup_message_event(); this.setup_message_event();
this.fix_tooltips(); this.fix_tooltips();
this.find_bttv(10); this.find_bttv(10);
@ -338,10 +338,10 @@ FFZ.prototype.is_dashboard = false;
FFZ.prototype.init_dashboard = function(delay) { FFZ.prototype.init_dashboard = function(delay) {
var start = (window.performance && performance.now) ? performance.now() : Date.now(); var start = (window.performance && performance.now) ? performance.now() : Date.now();
this.log("Found Twitch Dashboard after " + (delay||0) + " ms at: " + location); this.log("Found Twitch Dashboard after " + (delay||0) + " ms at: " + location);
this.log("Initializing FrankerFaceZ version " + FFZ.version_info); this.log("Initializing FrankerFaceZ version " + FFZ.version_info);
var match = location.pathname.match(/\/([^\/]+)/); var match = location.pathname.match(/\/([^\/]+)/);
this.dashboard_channel = match && match[1] || undefined; this.dashboard_channel = match && match[1] || undefined;
this.users = {}; this.users = {};
this.is_dashboard = true; this.is_dashboard = true;
@ -366,7 +366,7 @@ FFZ.prototype.init_dashboard = function(delay) {
this.setup_notifications(); this.setup_notifications();
this.setup_following_count(false); this.setup_following_count(false);
this.setup_menu(); this.setup_menu();
this.setup_dash_stats(); this.setup_dash_stats();
this.setup_dash_feed(); this.setup_dash_feed();
this._update_subscribers(); this._update_subscribers();
@ -387,7 +387,7 @@ FFZ.prototype.init_dashboard = function(delay) {
FFZ.prototype.init_ember = function(delay) { FFZ.prototype.init_ember = function(delay) {
var start = (window.performance && performance.now) ? performance.now() : Date.now(); var start = (window.performance && performance.now) ? performance.now() : Date.now();
this.log("Found Twitch application after " + (delay||0) + " ms at: " + location); this.log("Found Twitch application after " + (delay||0) + " ms at: " + location);
this.log("Initializing FrankerFaceZ version " + FFZ.version_info); this.log("Initializing FrankerFaceZ version " + FFZ.version_info);
this.users = {}; this.users = {};
this.is_dashboard = false; this.is_dashboard = false;
@ -426,7 +426,7 @@ FFZ.prototype.init_ember = function(delay) {
this.setup_player(); this.setup_player();
this.setup_channel(); this.setup_channel();
this.setup_room(); this.setup_room();
this.setup_vod_chat(); this.setup_vod_chat();
this.setup_line(); this.setup_line();
this.setup_bits(); this.setup_bits();
this.setup_layout(); this.setup_layout();
@ -456,13 +456,13 @@ FFZ.prototype.init_ember = function(delay) {
this.fix_tooltips(); this.fix_tooltips();
this.connect_extra_chat(); this.connect_extra_chat();
this.setup_message_event(); this.setup_message_event();
this.find_bttv(10); this.find_bttv(10);
this.find_emote_menu(10); this.find_emote_menu(10);
//this.check_news(); //this.check_news();
this.check_ff(); this.check_ff();
this.refresh_chat(); this.refresh_chat();
var end = (window.performance && performance.now) ? performance.now() : Date.now(), var end = (window.performance && performance.now) ? performance.now() : Date.now(),
duration = end - start; duration = end - start;
@ -482,10 +482,10 @@ FFZ.prototype.setup_message_event = function() {
FFZ.prototype._on_window_message = function(e) { FFZ.prototype._on_window_message = function(e) {
var msg = e.data; var msg = e.data;
if ( typeof msg === "string" ) if ( typeof msg === "string" )
try { try {
msg = JSON.parse(msg); msg = JSON.parse(msg);
} catch(err) { } catch(err) {
// Not JSON? We don't care. // Not JSON? We don't care.
return; return;
@ -495,8 +495,8 @@ FFZ.prototype._on_window_message = function(e) {
return; return;
var handler = FFZ.msg_commands[msg.command]; var handler = FFZ.msg_commands[msg.command];
if ( handler ) if ( handler )
handler.call(this, msg.data); handler.call(this, msg.data);
else else
this.log("Invalid Message: " + msg.command, msg.data, false, true); this.log("Invalid Message: " + msg.command, msg.data, false, true);
} }

File diff suppressed because it is too large Load diff

View file

@ -7,13 +7,13 @@ var FFZ = window.FrankerFaceZ,
bits_helpers, bits_helpers,
bits_service, bits_service,
EXPLANATION_WARN = '<hr>This link has been sent to you via a whisper rather than standard chat, and has not been checked or approved of by any moderators or staff members. Please treat this link with caution and do not visit it if you do not trust the sender.', EXPLANATION_WARN = '<hr>This link has been sent to you via a whisper rather than standard chat, and has not been checked or approved of by any moderators or staff members. Please treat this link with caution and do not visit it if you do not trust the sender.',
reg_escape = function(str) { reg_escape = function(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}, },
LINK = /(?:https?:\/\/)?(?:[-a-zA-Z0-9@:%_\+~#=]+\.)+[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)/g, LINK = /(?:https?:\/\/)?(?:[-a-zA-Z0-9@:%_\+~#=]+\.)+[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)/g,
CLIP_URL = /(?:https?:\/\/)?clips\.twitch\.tv\/(\w+)\/(\w+)/, CLIP_URL = /(?:https?:\/\/)?clips\.twitch\.tv\/(\w+)\/(\w+)/,
@ -53,12 +53,12 @@ var FFZ = window.FrankerFaceZ,
this._link_data[href] = data; this._link_data[href] = data;
//data.unsafe = false; //data.unsafe = false;
if ( ! this.settings.link_info ) if ( ! this.settings.link_info )
return; return;
// If this link is unsafe, add the unsafe-link class to all instances of the link. // If this link is unsafe, add the unsafe-link class to all instances of the link.
if ( data.unsafe ) if ( data.unsafe )
jQuery('a.chat-link[data-url="' + href + '"]').addClass('unsafe-link'); jQuery('a.chat-link[data-url="' + href + '"]').addClass('unsafe-link');
}; };
@ -85,7 +85,7 @@ FFZ._emote_mirror_swap = function(img) {
img.setAttribute('data-alt-attempts', attempts + 1); img.setAttribute('data-alt-attempts', attempts + 1);
var id = img.getAttribute('data-emote'), var id = img.getAttribute('data-emote'),
src = '//' + img.src.split('//')[1]; src = '//' + img.src.split('//')[1];
if ( src.substr(0, constants.TWITCH_BASE.length) === constants.TWITCH_BASE ) { if ( src.substr(0, constants.TWITCH_BASE.length) === constants.TWITCH_BASE ) {
img.src = constants.EMOTE_MIRROR_BASE + id + ".png"; img.src = constants.EMOTE_MIRROR_BASE + id + ".png";
@ -218,8 +218,8 @@ FFZ.prototype.setup_tokenization = function() {
var show_deleted = f.settings.show_deleted_links; var show_deleted = f.settings.show_deleted_links;
return _.chain(tokens).map(function(token) { return _.chain(tokens).map(function(token) {
if ( token.type === "text" ) if ( token.type === "text" )
token = token.text; token = token.text;
if ( ! _.isString(token) ) if ( ! _.isString(token) )
return token; return token;
@ -231,21 +231,21 @@ FFZ.prototype.setup_tokenization = function() {
return _.zip( return _.zip(
token.split(LINK), token.split(LINK),
_.map(matches, function(e) { _.map(matches, function(e) {
var long = e.length > 255, var long = e.length > 255,
out = { out = {
type: "link", type: "link",
length: e.length, length: e.length,
isDeleted: ! show_deleted && (delete_links || long), isDeleted: ! show_deleted && (delete_links || long),
isLong: long, isLong: long,
isMailTo: e.indexOf("@") > -1 && (-1 === e.indexOf("/") || e.indexOf("@") < e.indexOf("/")), isMailTo: e.indexOf("@") > -1 && (-1 === e.indexOf("/") || e.indexOf("@") < e.indexOf("/")),
text: e, text: e,
link: e link: e
}; };
if ( ! out.isMailTo && ! e.match(/^(?:https?:\/\/)/) ) if ( ! out.isMailTo && ! e.match(/^(?:https?:\/\/)/) )
out.link = "http://" + e; out.link = "http://" + e;
return out; return out;
}) })
); );
}).flatten().compact().value(); }).flatten().compact().value();
@ -290,8 +290,8 @@ FFZ.prototype.load_twitch_emote_data = function(tries) {
// --------------------- // ---------------------
FFZ.prototype.render_tooltip = function(el) { FFZ.prototype.render_tooltip = function(el) {
var f = this, var f = this,
func = function() { func = function() {
if ( this.classList.contains('ffz-bit') ) { if ( this.classList.contains('ffz-bit') ) {
var amount = parseInt(this.getAttribute('data-amount').replace(/,/g, '')), var amount = parseInt(this.getAttribute('data-amount').replace(/,/g, '')),
individuals = JSON.parse(this.getAttribute('data-individuals') || "null"), individuals = JSON.parse(this.getAttribute('data-individuals') || "null"),
@ -317,102 +317,102 @@ FFZ.prototype.render_tooltip = function(el) {
return image + out; return image + out;
} else if ( this.classList.contains('emoticon') ) { } else if ( this.classList.contains('emoticon') ) {
var preview_url, width=0, height=0, image, set_id, emote, emote_set, var preview_url, width=0, height=0, image, set_id, emote, emote_set,
emote_id = this.getAttribute('data-ffz-emote'); emote_id = this.getAttribute('data-ffz-emote');
if ( emote_id ) { if ( emote_id ) {
if ( emote_id == "93269" ) if ( emote_id == "93269" )
return ''; return '';
set_id = this.getAttribute('data-ffz-set'); set_id = this.getAttribute('data-ffz-set');
emote_set = f.emote_sets[set_id]; emote_set = f.emote_sets[set_id];
emote = emote_set && emote_set.emoticons[emote_id]; emote = emote_set && emote_set.emoticons[emote_id];
if ( emote ) { if ( emote ) {
var owner = emote.owner, var owner = emote.owner,
title = emote_set.title || "Global", title = emote_set.title || "Global",
source = emote_set.source || "FFZ"; source = emote_set.source || "FFZ";
if ( f.settings.emote_image_hover ) { if ( f.settings.emote_image_hover ) {
if ( emote.urls[4] ) { if ( emote.urls[4] ) {
height = emote.height * 4; height = emote.height * 4;
width = emote.width * 4; width = emote.width * 4;
preview_url = emote.urls[4]; preview_url = emote.urls[4];
} else if ( emote.urls[2] ) { } else if ( emote.urls[2] ) {
height = emote.height * 2; height = emote.height * 2;
width = emote.width * 2; width = emote.width * 2;
} }
if ( width > 186 ) if ( width > 186 )
height *= 186 / width; height *= 186 / width;
height = Math.min(186, height); height = Math.min(186, height);
} else } else
preview_url = null; preview_url = null;
//image = preview_url ? `<img style="height:${height}px" class="emoticon ffz-image-hover" src="${preview_url}?_=preview">` : ''; //image = preview_url ? `<img style="height:${height}px" class="emoticon ffz-image-hover" src="${preview_url}?_=preview">` : '';
image = preview_url ? '<img style="height:' + height + 'px" class="emoticon ffz-image-hover" src="' + preview_url + '"?_=preview">' : ''; image = preview_url ? '<img style="height:' + height + 'px" class="emoticon ffz-image-hover" src="' + preview_url + '"?_=preview">' : '';
return image + 'Emoticon: ' + (emote.hidden ? '???' : emote.name) + '<br>' + source + ' ' + title + (owner ? '<br>By: ' + owner.display_name : ''); return image + 'Emoticon: ' + (emote.hidden ? '???' : emote.name) + '<br>' + source + ' ' + title + (owner ? '<br>By: ' + owner.display_name : '');
//return `${image}Emoticon: ${emote.hidden ? '???' : emote.name}<br>${source} ${title}${owner ? '<br>By: ' + owner.display_name : ""}`; //return `${image}Emoticon: ${emote.hidden ? '???' : emote.name}<br>${source} ${title}${owner ? '<br>By: ' + owner.display_name : ""}`;
} }
} }
emote_id = this.getAttribute('data-emote'); emote_id = this.getAttribute('data-emote');
if ( emote_id ) { if ( emote_id ) {
set_id = f._twitch_emote_to_set[emote_id]; set_id = f._twitch_emote_to_set[emote_id];
emote_set = set_id && f._twitch_set_to_channel[set_id]; emote_set = set_id && f._twitch_set_to_channel[set_id];
var set_type = "Channel"; var set_type = "Channel";
preview_url = f.settings.emote_image_hover && (constants.TWITCH_BASE + emote_id + '/3.0'); preview_url = f.settings.emote_image_hover && (constants.TWITCH_BASE + emote_id + '/3.0');
//image = preview_url ? `<img style="height:112px" class="emoticon ffz-image-hover" src="${preview_url}?_=preview">` : ''; //image = preview_url ? `<img style="height:112px" class="emoticon ffz-image-hover" src="${preview_url}?_=preview">` : '';
image = preview_url ? '<img style="height:112px" class="emoticon ffz-image-hover" src="' + preview_url + '"?_=preview">' : ''; image = preview_url ? '<img style="height:112px" class="emoticon ffz-image-hover" src="' + preview_url + '"?_=preview">' : '';
// Global OR Golden Kappa // Global OR Golden Kappa
if ( emote_set === "--global--" || emote_id === '80393' ) { if ( emote_set === "--global--" || emote_id === '80393' ) {
emote_set = "Twitch Global"; emote_set = "Twitch Global";
set_type = null; set_type = null;
} else if ( emote_set === "--twitch-turbo--" || emote_set === "turbo" || emote_set === "--turbo-faces--" ) { } else if ( emote_set === "--twitch-turbo--" || emote_set === "turbo" || emote_set === "--turbo-faces--" ) {
emote_set = "Twitch Turbo"; emote_set = "Twitch Turbo";
set_type = null; set_type = null;
} }
if ( this.classList.contains('ffz-tooltip-no-credit') ) if ( this.classList.contains('ffz-tooltip-no-credit') )
return image + this.alt; return image + this.alt;
else else
return image + 'Emoticon: ' + this.alt + '<br>' + (set_type ? set_type + ': ' : '') + emote_set; return image + 'Emoticon: ' + this.alt + '<br>' + (set_type ? set_type + ': ' : '') + emote_set;
//return `${image}Emoticon: ${this.alt}<br>${set_type ? set_type + ": " : ""}${emote_set}`; //return `${image}Emoticon: ${this.alt}<br>${set_type ? set_type + ": " : ""}${emote_set}`;
} }
emote_id = this.getAttribute('data-ffz-emoji'); emote_id = this.getAttribute('data-ffz-emoji');
if ( emote_id ) { if ( emote_id ) {
emote = f.emoji_data[emote_id]; emote = f.emoji_data[emote_id];
var src = emote && (f.settings.parse_emoji === 3 ? emote.one_src : (f.settings.parse_emoji === 2 ? emote.noto_src : emote.tw_src)); var src = emote && (f.settings.parse_emoji === 3 ? emote.one_src : (f.settings.parse_emoji === 2 ? emote.noto_src : emote.tw_src));
preview_url = f.settings.emote_image_hover && src; preview_url = f.settings.emote_image_hover && src;
//image = preview_url ? `<img style="height:72px" class="emoticon ffz-image-hover" src="${preview_url}">` : ''; //image = preview_url ? `<img style="height:72px" class="emoticon ffz-image-hover" src="${preview_url}">` : '';
image = preview_url ? '<img style="height:72px" class="emoticon ffz-image-hover" src="' + preview_url + '"?_=preview">' : ''; image = preview_url ? '<img style="height:72px" class="emoticon ffz-image-hover" src="' + preview_url + '"?_=preview">' : '';
return image + "Emoji: " + this.alt + '<br>Name: ' + emote.name + (emote.short_name ? '<br>Short Name :' + emote.short_name + ':' : '') + (emote.cat ? '<br>Category: ' + utils.sanitize(constants.EMOJI_CATEGORIES[emote.cat] || emote.cat) : ''); return image + "Emoji: " + this.alt + '<br>Name: ' + emote.name + (emote.short_name ? '<br>Short Name :' + emote.short_name + ':' : '') + (emote.cat ? '<br>Category: ' + utils.sanitize(constants.EMOJI_CATEGORIES[emote.cat] || emote.cat) : '');
//return `${image}Emoji: ${this.alt}<br>Name: ${emote.name}${emote.short_name ? '<br>Short Name: :' + emote.short_name + ':' : ''}`; //return `${image}Emoji: ${this.alt}<br>Name: ${emote.name}${emote.short_name ? '<br>Short Name: :' + emote.short_name + ':' : ''}`;
} }
} else if ( this.classList.contains('email-link') ) { } else if ( this.classList.contains('email-link') ) {
var url = this.getAttribute("data-url"); var url = this.getAttribute("data-url");
return url ? "E-Mail " + url.substr(7) : ''; return url ? "E-Mail " + url.substr(7) : '';
} else if ( this.classList.contains('chat-link') ) { } else if ( this.classList.contains('chat-link') ) {
// TODO: A lot of shit. Lookup data. // TODO: A lot of shit. Lookup data.
var url = this.getAttribute("data-url"), var url = this.getAttribute("data-url"),
data = url && f._link_data[url], data = url && f._link_data[url],
preview_url = null, preview_url = null,
preview_iframe = true, preview_iframe = true,
image = '', image = '',
text = ''; text = '';
if ( ! url ) if ( ! url )
return; return;
// Do we have data? // Do we have data?
if ( data && data !== true ) { if ( data && data !== true ) {
@ -428,21 +428,21 @@ FFZ.prototype.render_tooltip = function(el) {
else else
image = '<img class="emoticon ffz-image-hover" src="' + utils.quote_attr(preview_url) + '">'; image = '<img class="emoticon ffz-image-hover" src="' + utils.quote_attr(preview_url) + '">';
// If it's not a deleted link, don't waste time showing the URL in the tooltip. // If it's not a deleted link, don't waste time showing the URL in the tooltip.
if ( this.classList.contains('deleted-link') ) if ( this.classList.contains('deleted-link') )
text = url; text = url;
if ( this.classList.contains('warn-link') ) if ( this.classList.contains('warn-link') )
text += EXPLANATION_WARN; text += EXPLANATION_WARN;
return image + text; //`${image}${text}`; return image + text; //`${image}${text}`;
} }
f.log("Unable to Build Tooltip For: " + this.className, this); f.log("Unable to Build Tooltip For: " + this.className, this);
return ""; return "";
}; };
return el ? func(el) : func; return el ? func(el) : func;
}; };
@ -500,53 +500,53 @@ FFZ.prototype.tokenize_conversation_line = function(message, prevent_notificatio
FFZ.prototype.tokenize_vod_line = function(msgObject, delete_links) { FFZ.prototype.tokenize_vod_line = function(msgObject, delete_links) {
var cached = msgObject.get('cachedTokens'); var cached = msgObject.get('cachedTokens');
if ( cached ) if ( cached )
return cached; return cached;
var msg = msgObject.get('message'), var msg = msgObject.get('message'),
room_id = msgObject.get('room'), room_id = msgObject.get('room'),
from_user = msgObject.get('from'), from_user = msgObject.get('from'),
user = this.get_user(), user = this.get_user(),
from_me = user && from_user === user.login, from_me = user && from_user === user.login,
emotes = msgObject.get('tags.emotes'), emotes = msgObject.get('tags.emotes'),
tokens = [msg]; tokens = [msg];
if ( helpers && helpers.linkifyMessage ) if ( helpers && helpers.linkifyMessage )
tokens = helpers.linkifyMessage(tokens, delete_links); tokens = helpers.linkifyMessage(tokens, delete_links);
if ( user && user.login && helpers && helpers.mentionizeMessage ) if ( user && user.login && helpers && helpers.mentionizeMessage )
tokens = helpers.mentionizeMessage(tokens, user.login, from_me); tokens = helpers.mentionizeMessage(tokens, user.login, from_me);
if ( helpers && helpers.emoticonizeMessage && emotes && this.settings.parse_emoticons ) if ( helpers && helpers.emoticonizeMessage && emotes && this.settings.parse_emoticons )
tokens = helpers.emoticonizeMessage(tokens, emotes); tokens = helpers.emoticonizeMessage(tokens, emotes);
// FrankerFaceZ Extras // FrankerFaceZ Extras
tokens = this._remove_banned(tokens); tokens = this._remove_banned(tokens);
if ( this.settings.parse_emoticons && this.settings.parse_emoticons !== 2 ) if ( this.settings.parse_emoticons && this.settings.parse_emoticons !== 2 )
tokens = this.tokenize_emotes(from_user, room_id, tokens, from_me); tokens = this.tokenize_emotes(from_user, room_id, tokens, from_me);
if ( this.settings.parse_emoji ) if ( this.settings.parse_emoji )
tokens = this.tokenize_emoji(tokens); tokens = this.tokenize_emoji(tokens);
var display = msgObject.get('tags.display-name'); var display = msgObject.get('tags.display-name');
if ( display && display.length ) if ( display && display.length )
FFZ.capitalization[from_user] = [display.trim(), Date.now()]; FFZ.capitalization[from_user] = [display.trim(), Date.now()];
if ( ! from_me ) { if ( ! from_me ) {
tokens = this.tokenize_mentions(tokens); tokens = this.tokenize_mentions(tokens);
for(var i=0; i < tokens.length; i++) { for(var i=0; i < tokens.length; i++) {
var token = tokens[i]; var token = tokens[i];
if ( token.type === 'mention' && ! token.isOwnMessage ) { if ( token.type === 'mention' && ! token.isOwnMessage ) {
msgObject.set('ffz_has_mention', true); msgObject.set('ffz_has_mention', true);
break; break;
} }
} }
} }
msgObject.set('cachedTokens', tokens); msgObject.set('cachedTokens', tokens);
return tokens; return tokens;
} }
@ -554,14 +554,14 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, del
if ( msgObject.cachedTokens ) if ( msgObject.cachedTokens )
return msgObject.cachedTokens; return msgObject.cachedTokens;
var msg = msgObject.message, var msg = msgObject.message,
room_id = msgObject.room, room_id = msgObject.room,
from_user = msgObject.from, from_user = msgObject.from,
user = this.get_user(), user = this.get_user(),
from_me = user && from_user === user.login, from_me = user && from_user === user.login,
tags = msgObject.tags || {}, tags = msgObject.tags || {},
emotes = tags.emotes, emotes = tags.emotes,
tokens = [msg]; tokens = [msg];
// Standard Tokenization // Standard Tokenization
if ( tags.bits && bits_helpers && bits_helpers.tokenizeBits ) if ( tags.bits && bits_helpers && bits_helpers.tokenizeBits )
@ -628,13 +628,13 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, del
for(var i=0; i < tokens.length; i++) { for(var i=0; i < tokens.length; i++) {
var token = tokens[i], var token = tokens[i],
is_mention = token.type === "mention"; is_mention = token.type === "mention";
if ( ! is_mention || token.isOwnMessage ) if ( ! is_mention || token.isOwnMessage )
continue; continue;
// We have a mention! // We have a mention!
msgObject.ffz_has_mention = true; msgObject.ffz_has_mention = true;
// If we have chat tabs/rows, update the status. // If we have chat tabs/rows, update the status.
if ( room_id && ! this.has_bttv && this._chatv ) { if ( room_id && ! this.has_bttv && this._chatv ) {
@ -979,79 +979,79 @@ FFZ.prototype.tokenize_ctags = function(tokens, tags_only) {
// --------------------- // ---------------------
FFZ.prototype.tokenize_emotes = function(user, room, tokens, do_report) { FFZ.prototype.tokenize_emotes = function(user, room, tokens, do_report) {
"use strict"; "use strict";
var sets = this.getEmotes(user, room), var sets = this.getEmotes(user, room),
emotes = {}, emotes = {},
emote, emote,
new_tokens = []; new_tokens = [];
if ( ! tokens || ! tokens.length || ! sets || ! sets.length ) if ( ! tokens || ! tokens.length || ! sets || ! sets.length )
return tokens; return tokens;
// Build an object with all of our emotes. // Build an object with all of our emotes.
for(var i=0; i < sets.length; i++) { for(var i=0; i < sets.length; i++) {
var emote_set = this.emote_sets[sets[i]]; var emote_set = this.emote_sets[sets[i]];
if ( emote_set && emote_set.emoticons ) if ( emote_set && emote_set.emoticons )
for(var emote_id in emote_set.emoticons) { for(var emote_id in emote_set.emoticons) {
emote = emote_set.emoticons[emote_id]; emote = emote_set.emoticons[emote_id];
if ( ! emotes.hasOwnProperty(emote.name) ) if ( ! emotes.hasOwnProperty(emote.name) )
emotes[emote.name] = emote; emotes[emote.name] = emote;
} }
} }
if ( typeof tokens === "string" ) if ( typeof tokens === "string" )
tokens = [tokens]; tokens = [tokens];
for(var i=0, l=tokens.length; i < l; i++) { for(var i=0, l=tokens.length; i < l; i++) {
var token = tokens[i]; var token = tokens[i];
if ( ! token ) if ( ! token )
continue; continue;
if ( typeof token !== "string" ) if ( typeof token !== "string" )
if ( token.type === "text" ) if ( token.type === "text" )
token = token.text; token = token.text;
else { else {
new_tokens.push(token); new_tokens.push(token);
continue; continue;
} }
// Split the token! // Split the token!
var segments = token.split(' '), var segments = token.split(' '),
text = [], segment; text = [], segment;
for(var x=0,y=segments.length; x < y; x++) { for(var x=0,y=segments.length; x < y; x++) {
segment = segments[x]; segment = segments[x];
if ( emotes.hasOwnProperty(segment) ) { if ( emotes.hasOwnProperty(segment) ) {
emote = emotes[segment]; emote = emotes[segment];
if ( text.length ) { if ( text.length ) {
// We have pending text. Join it together, with an extra space // We have pending text. Join it together, with an extra space
// on the end for good measure. // on the end for good measure.
new_tokens.push({type: "text", text: text.join(' ') + ' '}); new_tokens.push({type: "text", text: text.join(' ') + ' '});
text = [] text = []
} }
// Push this emote to the tokens. // Push this emote to the tokens.
new_tokens.push(emote.token); new_tokens.push(emote.token);
if ( do_report && room ) if ( do_report && room )
this.add_usage(room, emote); this.add_usage(room, emote);
// Finally, push an empty string to text so that this emote gets spaced. // Finally, push an empty string to text so that this emote gets spaced.
text.push(''); text.push('');
} else } else
text.push(segment); text.push(segment);
} }
// Add any left over text from this segment. // Add any left over text from this segment.
if ( text.length > 1 || (text.length === 1 && text[0] !== '') ) if ( text.length > 1 || (text.length === 1 && text[0] !== '') )
new_tokens.push({type: "text", text: text.join(' ')}); new_tokens.push({type: "text", text: text.join(' ')});
} }
return new_tokens; return new_tokens;
} }
@ -1060,54 +1060,54 @@ FFZ.prototype.tokenize_emotes = function(user, room, tokens, do_report) {
// --------------------- // ---------------------
FFZ.prototype.tokenize_emoji = function(tokens) { FFZ.prototype.tokenize_emoji = function(tokens) {
"use strict"; "use strict";
if ( ! tokens || ! tokens.length || ! this.emoji_data ) if ( ! tokens || ! tokens.length || ! this.emoji_data )
return tokens; return tokens;
if ( typeof tokens === "string" ) if ( typeof tokens === "string" )
tokens = [tokens]; tokens = [tokens];
var new_tokens = []; var new_tokens = [];
for(var i=0, l=tokens.length; i < l; i++) { for(var i=0, l=tokens.length; i < l; i++) {
var token = tokens[i]; var token = tokens[i];
if ( ! token ) if ( ! token )
continue; continue;
if ( typeof token !== "string" ) if ( typeof token !== "string" )
if ( token.type === "text" ) if ( token.type === "text" )
token = token.text; token = token.text;
else { else {
new_tokens.push(token); new_tokens.push(token);
continue; continue;
} }
var segments = token.split(constants.EMOJI_REGEX), var segments = token.split(constants.EMOJI_REGEX),
text = null; text = null;
while(segments.length) { while(segments.length) {
text = (text || '') + segments.shift(); text = (text || '') + segments.shift();
if ( segments.length ) { if ( segments.length ) {
var match = segments.shift(), var match = segments.shift(),
eid = utils.emoji_to_codepoint(match), eid = utils.emoji_to_codepoint(match),
data = this.emoji_data[eid]; data = this.emoji_data[eid];
if ( data ) { if ( data ) {
if ( text && text.length ) if ( text && text.length )
new_tokens.push({type: "text", text: text}); new_tokens.push({type: "text", text: text});
new_tokens.push(data.token); new_tokens.push(data.token);
text = null; text = null;
} else } else
text = (text || '') + match; text = (text || '') + match;
} }
} }
if ( text && text.length ) if ( text && text.length )
new_tokens.push({type: "text", text: text}); new_tokens.push({type: "text", text: text});
} }
return new_tokens; return new_tokens;
} }
@ -1152,8 +1152,8 @@ FFZ.prototype.tokenize_mentions = function(tokens) {
for(var i=0; i < tokens.length; i++) { for(var i=0; i < tokens.length; i++) {
var token = tokens[i]; var token = tokens[i];
if ( token.type === "text" ) if ( token.type === "text" )
token = token.text; token = token.text;
if ( ! _.isString(token) || ! token.match(regex) ) { if ( ! _.isString(token) || ! token.match(regex) ) {
new_tokens.push(token); new_tokens.push(token);
@ -1163,10 +1163,10 @@ FFZ.prototype.tokenize_mentions = function(tokens) {
token = token.replace(regex, function(all, prefix, match) { token = token.replace(regex, function(all, prefix, match) {
new_tokens.push(prefix); new_tokens.push(prefix);
new_tokens.push({ new_tokens.push({
type: "mention", type: "mention",
length: match.length, length: match.length,
user: match, user: match,
isOwnMessage: false, isOwnMessage: false,
}); });
return ""; return "";
@ -1188,7 +1188,7 @@ FFZ.prototype._deleted_link_click = function(e) {
if ( ! this.classList.contains("deleted-link") ) if ( ! this.classList.contains("deleted-link") )
return true; return true;
// Stop from Navigating // Stop from Navigating
e.preventDefault(); e.preventDefault();
// Get the URL // Get the URL
@ -1198,7 +1198,7 @@ FFZ.prototype._deleted_link_click = function(e) {
// Delete Old Stuff // Delete Old Stuff
this.classList.remove('deleted-link'); this.classList.remove('deleted-link');
this.classList.remove('warn-link'); this.classList.remove('warn-link');
// Set up the Link // Set up the Link
this.href = link; this.href = link;
@ -1206,7 +1206,7 @@ FFZ.prototype._deleted_link_click = function(e) {
this.textContent = text; this.textContent = text;
// Refresh tipsy. // Refresh tipsy.
jQuery(this).trigger('mouseout').trigger('mouseover'); jQuery(this).trigger('mouseout').trigger('mouseover');
} }

View file

@ -1,13 +1,13 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
constants = require("../constants"), constants = require("../constants"),
utils = require("../utils"), utils = require("../utils"),
createElement = utils.createElement, createElement = utils.createElement,
NICE_DESCRIPTION = { NICE_DESCRIPTION = {
"cluster": null, "cluster": null,
"manifest_cluster": null, "manifest_cluster": null,
"user_ip": null "user_ip": null
}; };
// ------------------- // -------------------
@ -53,430 +53,430 @@ FFZ.ws_commands.update_news = function(version) {
// ------------------- // -------------------
var include_html = function(heading_text, filename, callback) { var include_html = function(heading_text, filename, callback) {
return function(view, container) { return function(view, container) {
var heading = createElement('div', 'chat-menu-content center'); var heading = createElement('div', 'chat-menu-content center');
heading.innerHTML = '<h1>FrankerFaceZ</h1>' + (heading_text ? '<div class="ffz-about-subheading">' + heading_text + '</div>' : ''); heading.innerHTML = '<h1>FrankerFaceZ</h1>' + (heading_text ? '<div class="ffz-about-subheading">' + heading_text + '</div>' : '');
jQuery.ajax(filename, {cache: false, context: this}) jQuery.ajax(filename, {cache: false, context: this})
.done(function(data) { .done(function(data) {
container.appendChild(heading); container.appendChild(heading);
container.innerHTML += data; container.innerHTML += data;
jQuery('#ffz-old-news-button', container).on('click', function() { jQuery('#ffz-old-news-button', container).on('click', function() {
jQuery(this).remove(); jQuery(this).remove();
jQuery('#ffz-old-news', container).css('display', 'block'); jQuery('#ffz-old-news', container).css('display', 'block');
}); });
typeof callback === "function" && callback(view, container); typeof callback === "function" && callback(view, container);
}).fail(function(data) { }).fail(function(data) {
var content = createElement('div', 'chat-menu-content menu-side-padding'); var content = createElement('div', 'chat-menu-content menu-side-padding');
content.textContent = 'There was an error loading this page from the server.'; content.textContent = 'There was an error loading this page from the server.';
container.appendChild(heading); container.appendChild(heading);
container.appendChild(content); container.appendChild(content);
}); });
} }
}, },
render_news = include_html("news", constants.SERVER + "script/news.html"); render_news = include_html("news", constants.SERVER + "script/news.html");
var make_line = function(key, container) { var make_line = function(key, container) {
var desc = NICE_DESCRIPTION.hasOwnProperty(key) ? NICE_DESCRIPTION[key] : key; var desc = NICE_DESCRIPTION.hasOwnProperty(key) ? NICE_DESCRIPTION[key] : key;
if ( ! desc ) if ( ! desc )
return; return;
line = createElement('li', null, desc + '<span></span>'); line = createElement('li', null, desc + '<span></span>');
line.setAttribute('data-property', key); line.setAttribute('data-property', key);
container.appendChild(line); container.appendChild(line);
return line; return line;
}; };
var update_mem_stats = function(container) { var update_mem_stats = function(container) {
if ( ! document.querySelector('.ffz-ui-sub-menu-page[data-page="debugging"]') ) if ( ! document.querySelector('.ffz-ui-sub-menu-page[data-page="debugging"]') )
return; return;
setTimeout(update_mem_stats.bind(this, container), 1000); setTimeout(update_mem_stats.bind(this, container), 1000);
var mem = window.performance && performance.memory; var mem = window.performance && performance.memory;
if ( ! mem ) if ( ! mem )
return; return;
var sorted_keys = ['jsHeapSizeLimit', 'totalJSHeapSize', 'usedJSHeapSize']; var sorted_keys = ['jsHeapSizeLimit', 'totalJSHeapSize', 'usedJSHeapSize'];
for(var i=0; i < sorted_keys.length; i++) { for(var i=0; i < sorted_keys.length; i++) {
var key = sorted_keys[i], var key = sorted_keys[i],
data = mem[key], data = mem[key],
line = container.querySelector('li[data-property="' + key + '"]'); line = container.querySelector('li[data-property="' + key + '"]');
if ( ! line ) if ( ! line )
line = make_line(key, container); line = make_line(key, container);
if ( line ) if ( line )
line.querySelector('span').textContent = utils.format_size(data) + ' (' + data + ')'; line.querySelector('span').textContent = utils.format_size(data) + ' (' + data + ')';
} }
}; };
var update_player_stats = function(player, container) { var update_player_stats = function(player, container) {
if ( ! document.querySelector('.ffz-ui-sub-menu-page[data-page="debugging"]') || ! player.getVideoInfo ) if ( ! document.querySelector('.ffz-ui-sub-menu-page[data-page="debugging"]') || ! player.getVideoInfo )
return; return;
setTimeout(update_player_stats.bind(this, player, container), 1000); setTimeout(update_player_stats.bind(this, player, container), 1000);
var player_data; var player_data;
try { try {
player_data = player.getVideoInfo(); player_data = player.getVideoInfo();
} catch(err) { } } catch(err) { }
if ( ! player_data ) if ( ! player_data )
return; return;
try { try {
player_data.backend = player.getBackend(); player_data.backend = player.getBackend();
} catch(err) { player_data.backend = undefined } } catch(err) { player_data.backend = undefined }
var sorted_keys = Object.keys(player_data).sort(); var sorted_keys = Object.keys(player_data).sort();
for(var i=0; i < sorted_keys.length; i++) { for(var i=0; i < sorted_keys.length; i++) {
var key = sorted_keys[i], var key = sorted_keys[i],
data = player_data[key], data = player_data[key],
line = container.querySelector('li[data-property="' + key + '"]'); line = container.querySelector('li[data-property="' + key + '"]');
if ( ! line ) if ( ! line )
line = make_line(key, container); line = make_line(key, container);
if ( line ) if ( line )
line.querySelector('span').textContent = data; line.querySelector('span').textContent = data;
} }
}; };
FFZ.menu_pages.about = { FFZ.menu_pages.about = {
name: "About", name: "About",
icon: constants.HEART, icon: constants.HEART,
sort_order: 100000, sort_order: 100000,
pages: { pages: {
about: { about: {
name: "About", name: "About",
render: function(view, container, inner, menu) { render: function(view, container, inner, menu) {
var room = this.rooms[view.get("context.currentRoom.id")], var room = this.rooms[view.get("context.currentRoom.id")],
has_emotes = false, f = this; has_emotes = false, f = this;
if ( room && room.set ) { if ( room && room.set ) {
var set = this.emote_sets[room.set]; var set = this.emote_sets[room.set];
if ( set && set.count > 0 ) if ( set && set.count > 0 )
has_emotes = true; has_emotes = true;
} }
// Heading // Heading
var heading = createElement('div'), var heading = createElement('div'),
content = ''; content = '';
content += "<h1>FrankerFaceZ</h1>"; content += "<h1>FrankerFaceZ</h1>";
content += '<div class="ffz-about-subheading">new ways to woof</div>'; content += '<div class="ffz-about-subheading">new ways to woof</div>';
heading.className = 'chat-menu-content center'; heading.className = 'chat-menu-content center';
heading.innerHTML = content; heading.innerHTML = content;
container.appendChild(heading); container.appendChild(heading);
var clicks = 0, head = heading.querySelector("h1"); var clicks = 0, head = heading.querySelector("h1");
head && head.addEventListener("click", function() { head && head.addEventListener("click", function() {
head.style.cursor = "pointer"; head.style.cursor = "pointer";
clicks++; clicks++;
if ( clicks >= 3 ) { if ( clicks >= 3 ) {
clicks = 0; clicks = 0;
var el = document.querySelector(".app-main") || document.querySelector(".ember-chat-container"); var el = document.querySelector(".app-main") || document.querySelector(".ember-chat-container");
el && el.classList.toggle('ffz-flip'); el && el.classList.toggle('ffz-flip');
} }
setTimeout(function(){clicks=0;head.style.cursor=""},2000); setTimeout(function(){clicks=0;head.style.cursor=""},2000);
}); });
// Button Stuff // Button Stuff
var btn_container = createElement('div'), var btn_container = createElement('div'),
ad_button = createElement('a'), ad_button = createElement('a'),
news_button = createElement('a'), news_button = createElement('a'),
donate_button = createElement('a'), donate_button = createElement('a'),
message = "To use custom emoticons in " + (has_emotes ? "this channel" : "tons of channels") + ", get FrankerFaceZ from https://www.frankerfacez.com"; message = "To use custom emoticons in " + (has_emotes ? "this channel" : "tons of channels") + ", get FrankerFaceZ from https://www.frankerfacez.com";
// Advertising // Advertising
ad_button.className = 'button primary'; ad_button.className = 'button primary';
ad_button.innerHTML = "Advertise in Chat"; ad_button.innerHTML = "Advertise in Chat";
ad_button.addEventListener('click', this._add_emote.bind(this, view, message)); ad_button.addEventListener('click', this._add_emote.bind(this, view, message));
btn_container.appendChild(ad_button); btn_container.appendChild(ad_button);
// Donate // Donate
donate_button.className = 'button ffz-donate'; donate_button.className = 'button ffz-donate';
donate_button.href = "https://www.frankerfacez.com/donate"; donate_button.href = "https://www.frankerfacez.com/donate";
donate_button.target = "_new"; donate_button.target = "_new";
donate_button.innerHTML = "Donate"; donate_button.innerHTML = "Donate";
btn_container.appendChild(donate_button); btn_container.appendChild(donate_button);
btn_container.className = 'chat-menu-content center'; btn_container.className = 'chat-menu-content center';
container.appendChild(btn_container); container.appendChild(btn_container);
// Credits // Credits
var credits = createElement('div'); var credits = createElement('div');
content = '<table class="ffz-about-table">'; content = '<table class="ffz-about-table">';
content += '<tr><th colspan="4">Developers</th></tr>'; content += '<tr><th colspan="4">Developers</th></tr>';
content += '<tr><td>Dan Salvato</td><td><a class="twitch" href="//www.twitch.tv/dansalvato" title="Twitch" target="_new">&nbsp;</a></td><td><a class="twitter" href="https://twitter.com/dansalvato" title="Twitter" target="_new">&nbsp;</a></td><td><a class="youtube" href="https://www.youtube.com/user/dansalvato1" title="YouTube" target="_new">&nbsp;</a></td></tr>'; content += '<tr><td>Dan Salvato</td><td><a class="twitch" href="//www.twitch.tv/dansalvato" title="Twitch" target="_new">&nbsp;</a></td><td><a class="twitter" href="https://twitter.com/dansalvato" title="Twitter" target="_new">&nbsp;</a></td><td><a class="youtube" href="https://www.youtube.com/user/dansalvato1" title="YouTube" target="_new">&nbsp;</a></td></tr>';
content += '<tr><td>Stendec</td><td><a class="twitch" href="//www.twitch.tv/sirstendec" title="Twitch" target="_new">&nbsp;</a></td><td><a class="twitter" href="https://twitter.com/SirStendec" title="Twitter" target="_new">&nbsp;</a></td><td><a class="youtube" href="https://www.youtube.com/channel/UCnxuvmK1DCPCXSJ-mXIh4KQ" title="YouTube" target="_new">&nbsp;</a></td></tr>'; content += '<tr><td>Stendec</td><td><a class="twitch" href="//www.twitch.tv/sirstendec" title="Twitch" target="_new">&nbsp;</a></td><td><a class="twitter" href="https://twitter.com/SirStendec" title="Twitter" target="_new">&nbsp;</a></td><td><a class="youtube" href="https://www.youtube.com/channel/UCnxuvmK1DCPCXSJ-mXIh4KQ" title="YouTube" target="_new">&nbsp;</a></td></tr>';
content += '<tr class="debug"><td><a href="#" id="ffz-changelog">Version ' + FFZ.version_info + '</a></td><td colspan="3"><a href="#" id="ffz-debug-logs">Logs</a></td></tr>'; content += '<tr class="debug"><td><a href="#" id="ffz-changelog">Version ' + FFZ.version_info + '</a></td><td colspan="3"><a href="#" id="ffz-debug-logs">Logs</a></td></tr>';
credits.className = 'chat-menu-content center'; credits.className = 'chat-menu-content center';
credits.innerHTML = content; credits.innerHTML = content;
// Make the Version clickable. // Make the Version clickable.
credits.querySelector('#ffz-changelog').addEventListener('click', credits.querySelector('#ffz-changelog').addEventListener('click',
f._ui_change_subpage.bind(f, view, inner, menu, container, 'changelog')); f._ui_change_subpage.bind(f, view, inner, menu, container, 'changelog'));
// Make the Logs button functional. // Make the Logs button functional.
var getting_logs = false; var getting_logs = false;
credits.querySelector('#ffz-debug-logs').addEventListener('click', function() { credits.querySelector('#ffz-debug-logs').addEventListener('click', function() {
if ( getting_logs ) if ( getting_logs )
return; return;
getting_logs = true; getting_logs = true;
f._pastebin(f._log_data.join("\n"), function(url) { f._pastebin(f._log_data.join("\n"), function(url) {
getting_logs = false; getting_logs = false;
if ( ! url ) if ( ! url )
alert("There was an error uploading the FrankerFaceZ logs."); alert("There was an error uploading the FrankerFaceZ logs.");
else else
prompt("Your FrankerFaceZ logs have been uploaded to the URL:", url); prompt("Your FrankerFaceZ logs have been uploaded to the URL:", url);
}); });
}); });
container.appendChild(credits); container.appendChild(credits);
} }
}, },
changelog: { changelog: {
name: "Changes", name: "Changes",
wide: true, wide: true,
render: include_html("change log", constants.SERVER + "script/changelog.html") render: include_html("change log", constants.SERVER + "script/changelog.html")
}, },
/*news: { /*news: {
name: "News", name: "News",
wide: true, wide: true,
render: function(view, container) { render: function(view, container) {
if ( this._has_news ) { if ( this._has_news ) {
this._has_news = false; this._has_news = false;
localStorage.ffzLastNewsId = this._news_id; localStorage.ffzLastNewsId = this._news_id;
this.update_ui_link(); this.update_ui_link();
} }
return render_news.call(this, view, container); return render_news.call(this, view, container);
} }
},*/ },*/
credits: { credits: {
name: "Credit", name: "Credit",
wide: true, wide: true,
render: include_html("credits", constants.SERVER + "script/credits.html") render: include_html("credits", constants.SERVER + "script/credits.html")
}, },
/*status: { /*status: {
name: "Status", name: "Status",
wide: true, wide: true,
render: include_html("server status", constants.SERVER + "script/status.html", function(view, container) { render: include_html("server status", constants.SERVER + "script/status.html", function(view, container) {
}) })
},*/ },*/
debugging: { debugging: {
name: "Debug", name: "Debug",
wide: true, wide: true,
render: function(view, container) { render: function(view, container) {
// Heading // Heading
var heading = createElement('div'), var heading = createElement('div'),
info_head = createElement('div'), info_head = createElement('div'),
info = createElement('ul'), info = createElement('ul'),
info_list = [ info_list = [
['Client ID', localStorage.ffzClientId || '<i>not set</i>'], ['Client ID', localStorage.ffzClientId || '<i>not set</i>'],
['Socket Server', this._ws_sock && this._ws_sock.url || '<i>disconnected</i>' ], ['Socket Server', this._ws_sock && this._ws_sock.url || '<i>disconnected</i>' ],
['Server Ping', this._ws_last_ping || '<i>unknown</i>'], ['Server Ping', this._ws_last_ping || '<i>unknown</i>'],
['Time Offset', this._ws_sock && this._ws_server_offset && (this._ws_server_offset < 0 ? "-" : "") + utils.time_to_string(Math.abs(this._ws_server_offset) / 1000) || '<i>unknown</i>'] ['Time Offset', this._ws_sock && this._ws_server_offset && (this._ws_server_offset < 0 ? "-" : "") + utils.time_to_string(Math.abs(this._ws_server_offset) / 1000) || '<i>unknown</i>']
], ],
twitch_head = createElement('div'), twitch_head = createElement('div'),
twitch = createElement('ul'), twitch = createElement('ul'),
twitch_list = [ twitch_list = [
['Deploy Flavor', SiteOptions.deploy_flavor] ['Deploy Flavor', SiteOptions.deploy_flavor]
], ],
exp_head = createElement('div'), exp_head = createElement('div'),
experiments = createElement('ul'), experiments = createElement('ul'),
has_memory = window.performance && performance.memory, has_memory = window.performance && performance.memory,
mem_head = createElement('div'), mem_head = createElement('div'),
mem_list = createElement('ul'), mem_list = createElement('ul'),
player_head = createElement('div'), player_head = createElement('div'),
player_list = createElement('ul'), player_list = createElement('ul'),
player, player_data, player, player_data,
ver_head = createElement('div'), ver_head = createElement('div'),
vers = createElement('ul'), vers = createElement('ul'),
version_list = [ version_list = [
['Ember', Ember.VERSION], ['Ember', Ember.VERSION],
['Ember Data', window.DS && DS.VERSION || '<i>unknown</i>'], ['Ember Data', window.DS && DS.VERSION || '<i>unknown</i>'],
['GIT Version', EmberENV.GIT_VERSION], ['GIT Version', EmberENV.GIT_VERSION],
null, null,
['FrankerFaceZ', FFZ.version_info.toString()] ['FrankerFaceZ', FFZ.version_info.toString()]
], ],
log_head = createElement('div'), log_head = createElement('div'),
logs = createElement('pre'); logs = createElement('pre');
for(var pkey in this.players) { for(var pkey in this.players) {
player = this.players[pkey] && this.players[pkey].player; player = this.players[pkey] && this.players[pkey].player;
if ( player ) if ( player )
break; break;
} }
if ( player ) { if ( player ) {
try { try {
player_data = player.getVideoInfo(); player_data = player.getVideoInfo();
} catch(err) { } } catch(err) { }
} }
heading.className = 'chat-menu-content center'; heading.className = 'chat-menu-content center';
heading.innerHTML = '<h1>FrankerFaceZ</h1><div class="ffz-about-subheading">woofs for nerds</div>'; heading.innerHTML = '<h1>FrankerFaceZ</h1><div class="ffz-about-subheading">woofs for nerds</div>';
info_head.className = exp_head.className = mem_head.className = twitch_head.className = player_head.className = ver_head.className = log_head.className = 'list-header'; info_head.className = exp_head.className = mem_head.className = twitch_head.className = player_head.className = ver_head.className = log_head.className = 'list-header';
info.className = mem_list.className = twitch.className = experiments.className = player_list.className = vers.className = 'chat-menu-content menu-side-padding version-list'; info.className = mem_list.className = twitch.className = experiments.className = player_list.className = vers.className = 'chat-menu-content menu-side-padding version-list';
info_head.innerHTML = 'Client Status'; info_head.innerHTML = 'Client Status';
for(var i=0; i < info_list.length; i++) { for(var i=0; i < info_list.length; i++) {
var data = info_list[i], var data = info_list[i],
line = createElement('li'); line = createElement('li');
line.innerHTML = data === null ? '<br>' : data[0] + '<span>' + data[1] + '</span>'; line.innerHTML = data === null ? '<br>' : data[0] + '<span>' + data[1] + '</span>';
info.appendChild(line); info.appendChild(line);
} }
twitch_head.innerHTML = 'Twitch Configuration'; twitch_head.innerHTML = 'Twitch Configuration';
// Check for Twitch geo-location // Check for Twitch geo-location
var user = this.get_user(); var user = this.get_user();
if ( user && user.login ) { if ( user && user.login ) {
twitch_list.push(["Current User", user.login + " [" + user.id + "]"]); twitch_list.push(["Current User", user.login + " [" + user.id + "]"]);
var us = []; var us = [];
user.is_staff && us.push("staff"); user.is_staff && us.push("staff");
user.is_admin && us.push("admin"); user.is_admin && us.push("admin");
user.is_partner && us.push("partner"); user.is_partner && us.push("partner");
user.is_broadcaster && us.push("broadcaster"); user.is_broadcaster && us.push("broadcaster");
user.has_turbo && us.push("turbo"); user.has_turbo && us.push("turbo");
twitch_list.push(["User State", us.join(", ") || "<i>none</i>"]); twitch_list.push(["User State", us.join(", ") || "<i>none</i>"]);
} else } else
twitch_list.push(["Current User", "<i>not logged in</i>"]); twitch_list.push(["Current User", "<i>not logged in</i>"]);
if ( window.Twitch && Twitch.geo && Twitch.geo._result ) { if ( window.Twitch && Twitch.geo && Twitch.geo._result ) {
var data = Twitch.geo._result; var data = Twitch.geo._result;
if ( data.geo ) if ( data.geo )
twitch_list.push(["Region", data.geo + (data.eu ? " [EU]" : "")]); twitch_list.push(["Region", data.geo + (data.eu ? " [EU]" : "")]);
if ( data.received_language ) if ( data.received_language )
twitch_list.push(["Received Language", data.received_language]) twitch_list.push(["Received Language", data.received_language])
} }
for(var i=0; i < twitch_list.length; i++) { for(var i=0; i < twitch_list.length; i++) {
var data = twitch_list[i], var data = twitch_list[i],
line = createElement('li'); line = createElement('li');
line.innerHTML = data === null ? '<br>' : data[0] + '<span>' + data[1] + '</span>'; line.innerHTML = data === null ? '<br>' : data[0] + '<span>' + data[1] + '</span>';
twitch.appendChild(line); twitch.appendChild(line);
} }
var exp_service = utils.ember_lookup('service:experiments'); var exp_service = utils.ember_lookup('service:experiments');
if ( exp_service ) { if ( exp_service ) {
exp_head.innerHTML = 'Twitch Experiments'; exp_head.innerHTML = 'Twitch Experiments';
for(var key in exp_service.values) { for(var key in exp_service.values) {
if ( ! exp_service.values.hasOwnProperty(key) ) if ( ! exp_service.values.hasOwnProperty(key) )
continue; continue;
var val = exp_service.values[key], var val = exp_service.values[key],
line = createElement('li'); line = createElement('li');
line.innerHTML = key + '<span>' + utils.sanitize(val) + '</span>'; line.innerHTML = key + '<span>' + utils.sanitize(val) + '</span>';
experiments.appendChild(line); experiments.appendChild(line);
} }
} }
ver_head.innerHTML = 'Versions'; ver_head.innerHTML = 'Versions';
if ( this.has_bttv ) if ( this.has_bttv )
version_list.push(["BetterTTV", BetterTTV.info.version + 'r' + BetterTTV.info.release]); version_list.push(["BetterTTV", BetterTTV.info.version + 'r' + BetterTTV.info.release]);
if ( Object.keys(this._apis).length ) { if ( Object.keys(this._apis).length ) {
version_list.push(null); version_list.push(null);
for(var key in this._apis) { for(var key in this._apis) {
var api = this._apis[key]; var api = this._apis[key];
version_list.push(['<b>Ext #' + api.id + '.</b> ' + api.name, api.version || '<i>unknown</i>']); version_list.push(['<b>Ext #' + api.id + '.</b> ' + api.name, api.version || '<i>unknown</i>']);
} }
} }
for(var i=0; i < version_list.length; i++) { for(var i=0; i < version_list.length; i++) {
var data = version_list[i], var data = version_list[i],
line = createElement('li'); line = createElement('li');
line.innerHTML = data === null ? '<br>' : data[0] + '<span>' + data[1] + '</span>'; line.innerHTML = data === null ? '<br>' : data[0] + '<span>' + data[1] + '</span>';
vers.appendChild(line); vers.appendChild(line);
} }
log_head.className = 'list-header'; log_head.className = 'list-header';
log_head.innerHTML = 'Logs'; log_head.innerHTML = 'Logs';
logs.className = 'chat-menu-content menu-side-padding'; logs.className = 'chat-menu-content menu-side-padding';
logs.textContent = this._log_data.join("\n"); logs.textContent = this._log_data.join("\n");
container.appendChild(heading); container.appendChild(heading);
container.appendChild(ver_head); container.appendChild(ver_head);
container.appendChild(vers); container.appendChild(vers);
container.appendChild(info_head); container.appendChild(info_head);
container.appendChild(info); container.appendChild(info);
container.appendChild(twitch_head); container.appendChild(twitch_head);
container.appendChild(twitch); container.appendChild(twitch);
if ( exp_service ) { if ( exp_service ) {
container.appendChild(exp_head); container.appendChild(exp_head);
container.appendChild(experiments); container.appendChild(experiments);
} }
if ( has_memory ) { if ( has_memory ) {
mem_head.innerHTML = 'Memory Statistics'; mem_head.innerHTML = 'Memory Statistics';
setTimeout(update_mem_stats.bind(this,mem_list),0); setTimeout(update_mem_stats.bind(this,mem_list),0);
container.appendChild(mem_head); container.appendChild(mem_head);
container.appendChild(mem_list); container.appendChild(mem_list);
} }
if ( player_data ) { if ( player_data ) {
player_head.innerHTML = "Player Statistics"; player_head.innerHTML = "Player Statistics";
setTimeout(update_player_stats.bind(this,player,player_list),0); setTimeout(update_player_stats.bind(this,player,player_list),0);
container.appendChild(player_head); container.appendChild(player_head);
container.appendChild(player_list); container.appendChild(player_list);
} }
container.appendChild(log_head); container.appendChild(log_head);
container.appendChild(logs); container.appendChild(logs);
} }
} }
} }
} }

View file

@ -1,6 +1,6 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
constants = require('../constants'), constants = require('../constants'),
utils = require('../utils'); utils = require('../utils');
// -------------- // --------------

View file

@ -1,6 +1,6 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
constants = require("../constants"), constants = require("../constants"),
utils = require("../utils"); utils = require("../utils");
//styles = require("../styles"); //styles = require("../styles");
@ -148,7 +148,7 @@ FFZ.settings_info.dark_twitch = {
settings && settings.set('darkMode', this.settings.twitch_chat_dark); settings && settings.set('darkMode', this.settings.twitch_chat_dark);
// Try coloring chat replay // Try coloring chat replay
jQuery('.chatReplay').toggleClass('dark', val || false); jQuery('.chatReplay').toggleClass('dark', val || false);
//jQuery('.rechat-chat-line').parents('.chat-container').toggleClass('dark', val || this.settings.twitch_chat_dark); //jQuery('.rechat-chat-line').parents('.chat-container').toggleClass('dark', val || this.settings.twitch_chat_dark);
} }
}; };

View file

@ -1,5 +1,5 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
utils = require('../utils'), utils = require('../utils'),
createElement = utils.createElement; createElement = utils.createElement;

View file

@ -1,5 +1,5 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
utils = require('../utils'), utils = require('../utils'),
update_viewer_count = function(text) { update_viewer_count = function(text) {
var vc = jQuery("#channel_viewer_count"); var vc = jQuery("#channel_viewer_count");
@ -12,15 +12,15 @@ var FFZ = window.FrankerFaceZ,
// ------------------- // -------------------
FFZ.settings_info.dashboard_graph = { FFZ.settings_info.dashboard_graph = {
type: "boolean", type: "boolean",
value: true, value: true,
no_mobile: true, no_mobile: true,
no_bttv: true, no_bttv: true,
category: "Dashboard", category: "Dashboard",
name: "Statistics Graph <small>(Requires Refresh)</small>", name: "Statistics Graph <small>(Requires Refresh)</small>",
help: "Display a graph of your viewers, followers, and chat activity over time." help: "Display a graph of your viewers, followers, and chat activity over time."
} }
@ -29,12 +29,12 @@ FFZ.settings_info.dashboard_graph = {
// ------------------- // -------------------
FFZ.msg_commands.chat_message = function(data) { FFZ.msg_commands.chat_message = function(data) {
if ( ! this.dashboard_channel || data.room !== this.dashboard_channel ) if ( ! this.dashboard_channel || data.room !== this.dashboard_channel )
return; return;
this._stat_chat_lines++; this._stat_chat_lines++;
if ( this._stat_chatters.indexOf(data.from) === -1 ) if ( this._stat_chatters.indexOf(data.from) === -1 )
this._stat_chatters.push(data.from); this._stat_chatters.push(data.from);
} }
@ -43,233 +43,233 @@ FFZ.msg_commands.chat_message = function(data) {
// ------------------- // -------------------
FFZ.prototype.setup_dash_stats = function() { FFZ.prototype.setup_dash_stats = function() {
this._stat_chat_lines = 0; this._stat_chat_lines = 0;
this._stat_chatters = []; this._stat_chatters = [];
this._stat_last_game = null; this._stat_last_game = null;
this._stat_last_status = null; this._stat_last_status = null;
this._update_dash_stats_timer = setTimeout(this.update_dash_stats.bind(this), 0); this._update_dash_stats_timer = setTimeout(this.update_dash_stats.bind(this), 0);
var f = this, var f = this,
stats = document.querySelector('#stats'); stats = document.querySelector('#stats');
if ( this.has_bttv || ! stats || ! window.Highcharts || ! this.settings.dashboard_graph ) if ( this.has_bttv || ! stats || ! window.Highcharts || ! this.settings.dashboard_graph )
return; return;
f.log("Adding dashboard statistics chart."); f.log("Adding dashboard statistics chart.");
// Build a chart, under stats. // Build a chart, under stats.
var container = document.createElement('div'); var container = document.createElement('div');
container.id = "chart_container"; container.id = "chart_container";
container.className = 'ffz-stat-chart'; container.className = 'ffz-stat-chart';
stats.parentElement.insertBefore(container, stats.nextSibling); stats.parentElement.insertBefore(container, stats.nextSibling);
Highcharts.setOptions({global: {useUTC: false}}); Highcharts.setOptions({global: {useUTC: false}});
// Load chart visibility // Load chart visibility
var vis = {}; var vis = {};
if ( localStorage.ffz_dash_chart_visibility ) if ( localStorage.ffz_dash_chart_visibility )
vis = JSON.parse(localStorage.ffz_dash_chart_visibility); vis = JSON.parse(localStorage.ffz_dash_chart_visibility);
var date_format = this.settings.twenty_four_timestamps ? "%H:%M" : "%l:%M", var date_format = this.settings.twenty_four_timestamps ? "%H:%M" : "%l:%M",
chart = this._dash_chart = new Highcharts.Chart({ chart = this._dash_chart = new Highcharts.Chart({
chart: { chart: {
type: 'line', type: 'line',
zoomType: "x", zoomType: "x",
animation: false, animation: false,
renderTo: container, renderTo: container,
height: 200 height: 200
}, },
title: { text: null }, title: { text: null },
credits: { enabled: false }, credits: { enabled: false },
exporting: { enabled: false }, exporting: { enabled: false },
legend: { legend: {
backgroundColor: "#fff" backgroundColor: "#fff"
}, },
xAxis: { xAxis: {
type: 'datetime', type: 'datetime',
tickPixelInterval: 150, tickPixelInterval: 150,
dateTimeLabelFormats: { dateTimeLabelFormats: {
millisecond: date_format, millisecond: date_format,
second: date_format, second: date_format,
minute: date_format minute: date_format
} }
}, },
tooltip: { tooltip: {
formatter: function() { formatter: function() {
if ( this.point ) if ( this.point )
this.points = [this.point]; this.points = [this.point];
var s = [], var s = [],
key = this.points[0].key || this.points[0].x; key = this.points[0].key || this.points[0].x;
if ( key ) { if ( key ) {
if ( typeof key === "number" ) if ( typeof key === "number" )
key = Highcharts.dateFormat((f.settings.twenty_four_timestamps ? "%H:%M" : "%l:%M %P"), key); key = Highcharts.dateFormat((f.settings.twenty_four_timestamps ? "%H:%M" : "%l:%M %P"), key);
s.push('<span style="font-size:10px">' + key + '</span>'); s.push('<span style="font-size:10px">' + key + '</span>');
} }
for(var i=0; i < this.points.length; i++) { for(var i=0; i < this.points.length; i++) {
var point = this.points[i], var point = this.points[i],
series = point.series, series = point.series,
to = series.tooltipOptions, to = series.tooltipOptions,
y = point.text || point.y; y = point.text || point.y;
if ( ! to || ! to.enabled || y === undefined || y === null ) if ( ! to || ! to.enabled || y === undefined || y === null )
continue; continue;
if ( typeof y === "number" ) if ( typeof y === "number" )
y = utils.number_commas(y); y = utils.number_commas(y);
s.push('<span style="color:' + series.color + '">' + series.name + '</span>: <b>' + y + '</b>'); s.push('<span style="color:' + series.color + '">' + series.name + '</span>: <b>' + y + '</b>');
} }
return s.join("<br>"); return s.join("<br>");
}, },
crosshairs: true, crosshairs: true,
shared: true shared: true
}, },
yAxis: [ yAxis: [
{title: { text: null }, min: 0}, {title: { text: null }, min: 0},
{title: { text: null }, min: 0}, {title: { text: null }, min: 0},
{title: { text: null }, min: 0, opposite: true}, {title: { text: null }, min: 0, opposite: true},
{title: { text: null }, min: 0, opposite: true} {title: { text: null }, min: 0, opposite: true}
], ],
series: [ series: [
{ {
type: 'flags', type: 'flags',
name: 'Status', name: 'Status',
showInLegend: false, showInLegend: false,
shape: 'squarepin', shape: 'squarepin',
data: [], data: [],
zIndex: 5 zIndex: 5
}, },
{name: "Viewers", data: [], zIndex: 4, visible: vis.hasOwnProperty('viewers')?vis.viewers:true}, {name: "Viewers", data: [], zIndex: 4, visible: vis.hasOwnProperty('viewers')?vis.viewers:true},
{name: "Followers", data: [], yAxis: 1, zIndex: 3, visible: vis.hasOwnProperty('followers')?vis.followers:true}, {name: "Followers", data: [], yAxis: 1, zIndex: 3, visible: vis.hasOwnProperty('followers')?vis.followers:true},
{name: "Subscribers", data: [], zIndex: 3, showInLegend: false, visible: vis.hasOwnProperty('subscribers')?vis.subscribers:true}, {name: "Subscribers", data: [], zIndex: 3, showInLegend: false, visible: vis.hasOwnProperty('subscribers')?vis.subscribers:true},
{name: "Chat Lines", type: 'area', data: [], yAxis: 2, visible: vis.hasOwnProperty('chat_lines')?vis.chat_lines:false, zIndex: 1}, {name: "Chat Lines", type: 'area', data: [], yAxis: 2, visible: vis.hasOwnProperty('chat_lines')?vis.chat_lines:false, zIndex: 1},
{name: "Chatters", data: [], yAxis: 3, visible: vis.hasOwnProperty('chatters')?vis.chatters:false, zIndex: 2} {name: "Chatters", data: [], yAxis: 3, visible: vis.hasOwnProperty('chatters')?vis.chatters:false, zIndex: 2}
] ]
}); });
} }
FFZ.prototype._dash_chart_chatters = function(force) { FFZ.prototype._dash_chart_chatters = function(force) {
var now = utils.last_minute(), var now = utils.last_minute(),
series = this._dash_chart.series[4], series = this._dash_chart.series[4],
len = series.data.length, len = series.data.length,
last_point = len > 0 && series.data[len-1], last_point = len > 0 && series.data[len-1],
rendered = false; rendered = false;
if ( ! force && ! this._stat_chat_lines && len > 0 && last_point.y === 0 ) { if ( ! force && ! this._stat_chat_lines && len > 0 && last_point.y === 0 ) {
series.addPoint({x: now, y: null}, false); series.addPoint({x: now, y: null}, false);
this._dash_chart.series[5].addPoint({x: now, y: null}, false); this._dash_chart.series[5].addPoint({x: now, y: null}, false);
rendered = true; rendered = true;
} else if ( force || this._stat_chat_lines || len > 0 && last_point && last_point.y !== null ) { } else if ( force || this._stat_chat_lines || len > 0 && last_point && last_point.y !== null ) {
if ( this._stat_chat_lines !== 0 && last_point && last_point.y === null ) { if ( this._stat_chat_lines !== 0 && last_point && last_point.y === null ) {
series.addPoint({x:now-60000, y: 0}, false); series.addPoint({x:now-60000, y: 0}, false);
this._dash_chart.series[5].addPoint({x:now-60000, y: 0}, false); this._dash_chart.series[5].addPoint({x:now-60000, y: 0}, false);
} }
series.addPoint({x: now, y: this._stat_chat_lines || 0}, false); series.addPoint({x: now, y: this._stat_chat_lines || 0}, false);
this._dash_chart.series[5].addPoint({x: now, y: this._stat_chatters.length || 0}, false); this._dash_chart.series[5].addPoint({x: now, y: this._stat_chatters.length || 0}, false);
rendered = true; rendered = true;
} }
this._stat_chat_lines = 0; this._stat_chat_lines = 0;
this._stat_chatters = []; this._stat_chatters = [];
return rendered; return rendered;
} }
FFZ.prototype._remove_dash_chart = function() { FFZ.prototype._remove_dash_chart = function() {
if ( ! this._dash_chart ) if ( ! this._dash_chart )
return; return;
this.log("Removing dashboard statistics chart."); this.log("Removing dashboard statistics chart.");
this._dash_chart.destroy(); this._dash_chart.destroy();
this._dash_chart = null; this._dash_chart = null;
jQuery("#chart_container.ffz-stat-chart").remove(); jQuery("#chart_container.ffz-stat-chart").remove();
} }
FFZ.prototype.update_dash_stats = function() { FFZ.prototype.update_dash_stats = function() {
var f = this, var f = this,
id = this.dashboard_channel; id = this.dashboard_channel;
if ( this.has_bttv || ! id ) if ( this.has_bttv || ! id )
return this._remove_dash_chart(); return this._remove_dash_chart();
this._update_dash_stats_timer = setTimeout(this.update_dash_stats.bind(this), 60000); this._update_dash_stats_timer = setTimeout(this.update_dash_stats.bind(this), 60000);
if ( f._dash_chart ) { if ( f._dash_chart ) {
var series = f._dash_chart.series; var series = f._dash_chart.series;
localStorage.ffz_dash_chart_visibility = JSON.stringify({ localStorage.ffz_dash_chart_visibility = JSON.stringify({
viewers: series[1].visble, viewers: series[1].visble,
followers: series[2].visible, followers: series[2].visible,
subscribers: series[3].visible, subscribers: series[3].visible,
chat_lines: series[4].visible, chat_lines: series[4].visible,
chatters: series[5].visible chatters: series[5].visible
}); });
} }
utils.api.get("streams/" + id , {}, {version: 3}) utils.api.get("streams/" + id , {}, {version: 3})
.done(function(data) { .done(function(data) {
var viewers = null, var viewers = null,
followers = null, followers = null,
game = null, game = null,
status = null; status = null;
if ( ! data || ! data.stream ) if ( ! data || ! data.stream )
!f.has_bttv && update_viewer_count("Offline"); !f.has_bttv && update_viewer_count("Offline");
else { else {
!f.has_bttv && update_viewer_count(utils.number_commas(data.stream.viewers)); !f.has_bttv && update_viewer_count(utils.number_commas(data.stream.viewers));
viewers = data.stream.viewers; viewers = data.stream.viewers;
var chan = data.stream.channel; var chan = data.stream.channel;
if ( chan ) { if ( chan ) {
followers = chan.hasOwnProperty('followers') ? chan.followers || 0 : null; followers = chan.hasOwnProperty('followers') ? chan.followers || 0 : null;
game = chan.game || "Not Playing"; game = chan.game || "Not Playing";
status = chan.status || "Untitled Broadcast"; status = chan.status || "Untitled Broadcast";
if ( chan.views ) if ( chan.views )
jQuery("#views_count span").text(utils.number_commas(chan.views)); jQuery("#views_count span").text(utils.number_commas(chan.views));
if ( followers ) if ( followers )
jQuery("#followers_count span").text(utils.number_commas(followers)); jQuery("#followers_count span").text(utils.number_commas(followers));
} }
} }
if ( f._dash_chart ) { if ( f._dash_chart ) {
var now = utils.last_minute(), var now = utils.last_minute(),
force_draw; force_draw;
// If the game or status changed, we need to insert a pin. // If the game or status changed, we need to insert a pin.
if ( f._stat_last_game !== game || f._stat_last_status !== status ) { if ( f._stat_last_game !== game || f._stat_last_status !== status ) {
f._dash_chart.series[0].addPoint({x: now, title: game, text: status}, false); f._dash_chart.series[0].addPoint({x: now, title: game, text: status}, false);
f._stat_last_game = game; f._stat_last_game = game;
f._stat_last_status = status; f._stat_last_status = status;
} }
force_draw = utils.maybe_chart(f._dash_chart.series[1], {x: now, y: viewers}, false); force_draw = utils.maybe_chart(f._dash_chart.series[1], {x: now, y: viewers}, false);
force_draw = f._dash_chart_chatters(force_draw) || force_draw; force_draw = f._dash_chart_chatters(force_draw) || force_draw;
utils.maybe_chart(f._dash_chart.series[2], {x: now, y: followers}, false, force_draw); utils.maybe_chart(f._dash_chart.series[2], {x: now, y: followers}, false, force_draw);
f._dash_chart.redraw(); f._dash_chart.redraw();
} }
}).fail(function() { }).fail(function() {
if ( f._dash_chart ) { if ( f._dash_chart ) {
f._dash_chart_chatters(); f._dash_chart_chatters();
f._dash_chart.redraw(); f._dash_chart.redraw();
} }
}); });
} }

View file

@ -88,11 +88,11 @@ FFZ.prototype.setup_following_count = function(has_ember) {
Live.load(); Live.load();
/*var Host = utils.ember_resolve('model:hist'), /*var Host = utils.ember_resolve('model:hist'),
HostLive = Host && Host.find("following"); HostLive = Host && Host.find("following");
if ( HostLive ) if ( HostLive )
HostLive.load();*/ HostLive.load();*/
var init = function() { var init = function() {
var total = Live.get('total'), var total = Live.get('total'),
@ -158,13 +158,13 @@ FFZ.prototype._update_following_count = function() {
var Stream = utils.ember_resolve('model:stream'), var Stream = utils.ember_resolve('model:stream'),
Live = Stream && Stream.find("live"), Live = Stream && Stream.find("live"),
Host = utils.ember_resolve('model:host'), Host = utils.ember_resolve('model:host'),
HostLive = Host && Host.find("following"), HostLive = Host && Host.find("following"),
f = this; f = this;
if ( ! this.is_dashboard && HostLive && document.body.getAttribute('data-current-path').indexOf('directory.following') !== -1 ) if ( ! this.is_dashboard && HostLive && document.body.getAttribute('data-current-path').indexOf('directory.following') !== -1 )
HostLive.load(); HostLive.load();
if ( ! this.is_dashboard && Live ) if ( ! this.is_dashboard && Live )
Live.load(); Live.load();
@ -195,12 +195,12 @@ FFZ.prototype._build_following_tooltip = function(el) {
height = document.body.clientHeight - (bb.bottom + 50), height = document.body.clientHeight - (bb.bottom + 50),
max_lines = Math.max(Math.floor(height / 40) - 1, 2), max_lines = Math.max(Math.floor(height / 40) - 1, 2),
/*Host = utils.ember_resolve('model:host'), /*Host = utils.ember_resolve('model:host'),
HostLive = Host && Host.find("following"),*/ HostLive = Host && Host.find("following"),*/
streams = this._tooltip_streams, streams = this._tooltip_streams,
total = this._tooltip_total || (streams && streams.length) || 0, total = this._tooltip_total || (streams && streams.length) || 0,
c = 0; c = 0;
if ( streams && streams.length ) { if ( streams && streams.length ) {
for(var i=0, l = streams.length; i < l; i++) { for(var i=0, l = streams.length; i < l; i++) {
@ -228,46 +228,46 @@ FFZ.prototype._build_following_tooltip = function(el) {
'<span class="playing">' + (stream.channel.game === 'Creative' ? 'Being Creative' : (stream.channel.game ? 'Playing ' + utils.sanitize(stream.channel.game) : 'Not Playing')) + (tags ? ' | ' + _.pluck(tags, "text").join(" ") : '') + '</span>'; '<span class="playing">' + (stream.channel.game === 'Creative' ? 'Being Creative' : (stream.channel.game ? 'Playing ' + utils.sanitize(stream.channel.game) : 'Not Playing')) + (tags ? ' | ' + _.pluck(tags, "text").join(" ") : '') + '</span>';
} }
} else { } else {
c++; // is a terrible programming language c++; // is a terrible programming language
tooltip += "<hr>No one you're following is online."; tooltip += "<hr>No one you're following is online.";
} }
// If we have hosts, and room, try displaying some hosts. // If we have hosts, and room, try displaying some hosts.
/*if ( HostLive && (c + 1) < max_lines && HostLive.get('content.length') > 0 ) { /*if ( HostLive && (c + 1) < max_lines && HostLive.get('content.length') > 0 ) {
var t = HostLive.get('content.length'); var t = HostLive.get('content.length');
c++; c++;
tooltip += '<hr>Live Hosts'; tooltip += '<hr>Live Hosts';
for(var i=0; i < t; i++) { for(var i=0; i < t; i++) {
var host = HostLive.get('content.' + i), var host = HostLive.get('content.' + i),
stream = host && host.target; stream = host && host.target;
if ( ! stream ) if ( ! stream )
continue; continue;
c += 1; c += 1;
if ( c > max_lines ) { if ( c > max_lines ) {
var sc = 1 + (streams && streams.length || 0); var sc = 1 + (streams && streams.length || 0);
tooltip += '<hr><span>And ' + utils.number_commas(t - (max_lines - sc)) + ' more...</span>'; tooltip += '<hr><span>And ' + utils.number_commas(t - (max_lines - sc)) + ' more...</span>';
break; break;
} }
var hosting; var hosting;
if ( ! host.ffz_hosts || host.ffz_hosts.length === 1 ) if ( ! host.ffz_hosts || host.ffz_hosts.length === 1 )
hosting = host.display_name; hosting = host.display_name;
else else
hosting = utils.number_commas(host.ffz_hosts.length); hosting = utils.number_commas(host.ffz_hosts.length);
tooltip += (i === 0 ? '<hr>' : '') + tooltip += (i === 0 ? '<hr>' : '') +
'<span class="stat">' + constants.LIVE + ' ' + utils.number_commas(stream.viewers) + '</span>' + '<span class="stat">' + constants.LIVE + ' ' + utils.number_commas(stream.viewers) + '</span>' +
hosting + ' hosting <b>' + utils.sanitize(stream.channel.display_name || stream.channel.name) + '</b><br>' + hosting + ' hosting <b>' + utils.sanitize(stream.channel.display_name || stream.channel.name) + '</b><br>' +
'<span class="playing">' + (stream.meta_game ? 'Playing ' + utils.sanitize(stream.meta_game) : 'Not Playing') + '</span>'; '<span class="playing">' + (stream.meta_game ? 'Playing ' + utils.sanitize(stream.meta_game) : 'Not Playing') + '</span>';
} }
}*/ }*/
// Reposition the tooltip. // Reposition the tooltip.
setTimeout(function() { setTimeout(function() {
var tip = document.querySelector('.tipsy'); var tip = document.querySelector('.tipsy');
if ( ! tip ) if ( ! tip )
return; return;
var bb = tip.getBoundingClientRect(), var bb = tip.getBoundingClientRect(),

View file

@ -4,7 +4,7 @@ var FFZ = window.FrankerFaceZ,
IS_OSX = constants.IS_OSX, IS_OSX = constants.IS_OSX,
reported_sets = [], reported_sets = [],
fix_menu_position = function(container) { fix_menu_position = function(container) {
var swapped = document.body.classList.contains('ffz-sidebar-swap') && ! document.body.classList.contains('ffz-portrait'); var swapped = document.body.classList.contains('ffz-sidebar-swap') && ! document.body.classList.contains('ffz-portrait');
@ -217,7 +217,7 @@ FFZ.prototype.build_ui_popup = function(view) {
// Stuff // Stuff
//jQuery(inner).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')}); //jQuery(inner).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')});
//jQuery(inner).find('.ffz-tooltip').tipsy({live: true, html: true, title: this.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')}); //jQuery(inner).find('.ffz-tooltip').tipsy({live: true, html: true, title: this.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
// Menu Container // Menu Container
var sub_container = document.createElement('div'); var sub_container = document.createElement('div');
@ -336,33 +336,33 @@ FFZ.prototype.build_ui_popup = function(view) {
FFZ.prototype._ui_change_subpage = function(view, inner, menu, container, subpage) { FFZ.prototype._ui_change_subpage = function(view, inner, menu, container, subpage) {
var page = this._last_page, var page = this._last_page,
last_subpages = this._last_subpage = this._last_subpage || {}; last_subpages = this._last_subpage = this._last_subpage || {};
last_subpages[page] = subpage; last_subpages[page] = subpage;
container.innerHTML = ""; container.innerHTML = "";
container.setAttribute('data-page', subpage); container.setAttribute('data-page', subpage);
// Get the data structure for this page. // Get the data structure for this page.
var page_data = FFZ.menu_pages[page], var page_data = FFZ.menu_pages[page],
data = page_data.pages[subpage]; data = page_data.pages[subpage];
// Render the page first. If there's an error, it won't update the other UI stuff. // Render the page first. If there's an error, it won't update the other UI stuff.
data.render.call(this, view, container, inner, menu); data.render.call(this, view, container, inner, menu);
// Make sure the correct menu tab is selected // Make sure the correct menu tab is selected
jQuery('li.active', menu).removeClass('active'); jQuery('li.active', menu).removeClass('active');
jQuery('#ffz-menu-page-' + page + '-subpage-' + subpage, menu).addClass('active'); jQuery('#ffz-menu-page-' + page + '-subpage-' + subpage, menu).addClass('active');
// Apply wideness - TODO: Revamp wide menus entirely for thin containers // Apply wideness - TODO: Revamp wide menus entirely for thin containers
var is_wide = false, var is_wide = false,
app = document.querySelector(".app-main") || document.querySelector(".ember-chat-container"); app = document.querySelector(".app-main") || document.querySelector(".ember-chat-container");
if ( data.hasOwnProperty('wide') ) if ( data.hasOwnProperty('wide') )
is_wide = data.wide || (typeof data.wide === "function" && data.wide.call(this)); is_wide = data.wide || (typeof data.wide === "function" && data.wide.call(this));
else if ( page_data.hasOwnProperty('wide') ) else if ( page_data.hasOwnProperty('wide') )
is_wide = page_data.wide || (typeof page_data.wide === "function" && page_data.wide.call(this)); is_wide = page_data.wide || (typeof page_data.wide === "function" && page_data.wide.call(this));
inner.style.maxWidth = is_wide ? (app.offsetWidth < 640 ? (app.offsetWidth-40) : 600) + "px" : ""; inner.style.maxWidth = is_wide ? (app.offsetWidth < 640 ? (app.offsetWidth-40) : 600) + "px" : "";
@ -377,33 +377,33 @@ FFZ.prototype._ui_change_page = function(view, inner, menu, container, page) {
container.innerHTML = ""; container.innerHTML = "";
container.setAttribute('data-page', page); container.setAttribute('data-page', page);
// Get the data structure for the new page. // Get the data structure for the new page.
var data = FFZ.menu_pages[page]; var data = FFZ.menu_pages[page];
// See if we're dealing with a sub-menu situation. // See if we're dealing with a sub-menu situation.
if ( data.pages ) { if ( data.pages ) {
// We need to render the sub-menu, and then call the _ui_change_sub_page method // We need to render the sub-menu, and then call the _ui_change_sub_page method
// to render the sub-page. // to render the sub-page.
var submenu = document.createElement('ul'), var submenu = document.createElement('ul'),
subcontainer = document.createElement('div'), subcontainer = document.createElement('div'),
height = parseInt(container.style.maxHeight || '0'); height = parseInt(container.style.maxHeight || '0');
if ( ! height ) if ( ! height )
height = Math.max(200, view.$().height() - 172); height = Math.max(200, view.$().height() - 172);
if ( height && ! Number.isNaN(height) ) { if ( height && ! Number.isNaN(height) ) {
height -= 37; height -= 37;
subcontainer.style.maxHeight = height + 'px'; subcontainer.style.maxHeight = height + 'px';
} }
submenu.className = 'menu sub-menu clearfix'; submenu.className = 'menu sub-menu clearfix';
subcontainer.className = 'ffz-ui-sub-menu-page'; subcontainer.className = 'ffz-ui-sub-menu-page';
// Building Tabs // Building Tabs
var subpages = []; var subpages = [];
for(var key in data.pages) { for(var key in data.pages) {
var subpage = data.pages[key]; var subpage = data.pages[key];
try { try {
if ( ! subpage || (subpage.hasOwnProperty("visible") && (!subpage.visible || (typeof subpage.visible == "function" && !subpage.visible.call(this, view)))) ) if ( ! subpage || (subpage.hasOwnProperty("visible") && (!subpage.visible || (typeof subpage.visible == "function" && !subpage.visible.call(this, view)))) )
continue; continue;
@ -412,65 +412,65 @@ FFZ.prototype._ui_change_page = function(view, inner, menu, container, page) {
continue; continue;
} }
subpages.push([subpage.sort_order || 0, key, subpage]); subpages.push([subpage.sort_order || 0, key, subpage]);
} }
subpages.sort(function(a,b) { subpages.sort(function(a,b) {
if ( a[0] < b[0] ) return -1; if ( a[0] < b[0] ) return -1;
else if ( a[0] > b[0] ) return 1; else if ( a[0] > b[0] ) return 1;
var al = a[1].toLowerCase(), var al = a[1].toLowerCase(),
bl = b[1].toLowerCase(); bl = b[1].toLowerCase();
if ( al < bl ) return -1; if ( al < bl ) return -1;
if ( al > bl ) return 1; if ( al > bl ) return 1;
return 0; return 0;
}); });
for(var i=0; i < subpages.length; i++) { for(var i=0; i < subpages.length; i++) {
var key = subpages[i][1], var key = subpages[i][1],
subpage = subpages[i][2], subpage = subpages[i][2],
tab = document.createElement('li'), tab = document.createElement('li'),
link = document.createElement('a'); link = document.createElement('a');
tab.className = 'item'; tab.className = 'item';
tab.id = 'ffz-menu-page-' + page + '-subpage-' + key; tab.id = 'ffz-menu-page-' + page + '-subpage-' + key;
link.innerHTML = subpage.name; link.innerHTML = subpage.name;
link.addEventListener('click', this._ui_change_subpage.bind(this, view, inner, submenu, subcontainer, key)); link.addEventListener('click', this._ui_change_subpage.bind(this, view, inner, submenu, subcontainer, key));
tab.appendChild(link); tab.appendChild(link);
submenu.appendChild(tab); submenu.appendChild(tab);
} }
// Activate a Tab // Activate a Tab
var last_subpages = this._last_subpage = this._last_subpage || {}, var last_subpages = this._last_subpage = this._last_subpage || {},
last_subpage = last_subpages[page] = last_subpages[page] || data.default_page || subpages[0][1]; last_subpage = last_subpages[page] = last_subpages[page] || data.default_page || subpages[0][1];
if ( typeof last_subpage === "function" ) if ( typeof last_subpage === "function" )
last_subpage = last_subpage.call(this); last_subpage = last_subpage.call(this);
this._ui_change_subpage(view, inner, submenu, subcontainer, last_subpage); this._ui_change_subpage(view, inner, submenu, subcontainer, last_subpage);
// Make sure the correct menu tab is selected // Make sure the correct menu tab is selected
jQuery('li.active', menu).removeClass('active'); jQuery('li.active', menu).removeClass('active');
jQuery('#ffz-menu-page-' + page, menu).addClass('active'); jQuery('#ffz-menu-page-' + page, menu).addClass('active');
// Add this to the container. // Add this to the container.
container.appendChild(subcontainer); container.appendChild(subcontainer);
container.appendChild(submenu); container.appendChild(submenu);
return; return;
} }
// Render the page first. If there's an error, it won't update the other UI stuff. // Render the page first. If there's an error, it won't update the other UI stuff.
data.render.call(this, view, container, inner, menu); data.render.call(this, view, container, inner, menu);
// Make sure the correct menu tab is selected // Make sure the correct menu tab is selected
jQuery('li.active', menu).removeClass('active'); jQuery('li.active', menu).removeClass('active');
jQuery('#ffz-menu-page-' + page, menu).addClass('active'); jQuery('#ffz-menu-page-' + page, menu).addClass('active');
// Apply wideness - TODO: Revamp wide menus entirely for thin containers // Apply wideness - TODO: Revamp wide menus entirely for thin containers
var is_wide = data.wide || (typeof data.wide === "function" && data.wide.call(this)), var is_wide = data.wide || (typeof data.wide === "function" && data.wide.call(this)),
app = document.querySelector(".app-main") || document.querySelector(".ember-chat-container"); app = document.querySelector(".app-main") || document.querySelector(".ember-chat-container");
inner.style.maxWidth = is_wide ? (app.offsetWidth < 640 ? (app.offsetWidth-40) : 600) + "px" : ""; inner.style.maxWidth = is_wide ? (app.offsetWidth < 640 ? (app.offsetWidth-40) : 600) + "px" : "";
@ -498,8 +498,8 @@ FFZ.menu_pages.channel = {
if ( product && !product.get("error") ) { if ( product && !product.get("error") ) {
// We have a product, and no error~! // We have a product, and no error~!
has_product = true; has_product = true;
var Ticket = utils.ember_resolve('model:ticket'), var Ticket = utils.ember_resolve('model:ticket'),
tickets = Ticket && Ticket.find('user', {channel: room_id}), tickets = Ticket && Ticket.find('user', {channel: room_id}),
is_subscribed = tickets ? tickets.get('content') : false, is_subscribed = tickets ? tickets.get('content') : false,
is_loaded = tickets ? tickets.get('isLoaded') : false, is_loaded = tickets ? tickets.get('isLoaded') : false,
icon = room.room.get("badgeSet.subscriber.image"), icon = room.room.get("badgeSet.subscriber.image"),
@ -540,7 +540,7 @@ FFZ.menu_pages.channel = {
header.innerHTML = '<span class="right">Twitch</span>Subscriber Emoticons'; header.innerHTML = '<span class="right">Twitch</span>Subscriber Emoticons';
grid.appendChild(header); grid.appendChild(header);
var known_sets = []; var known_sets = [];
for(var emotes=product.get("emoticons") || [], i=0; i < emotes.length; i++) { for(var emotes=product.get("emoticons") || [], i=0; i < emotes.length; i++) {
var emote = emotes[i]; var emote = emotes[i];
@ -553,17 +553,17 @@ FFZ.menu_pages.channel = {
s.className = 'emoticon ffz-tooltip ffz-tooltip-no-credit' + (!can_use ? " locked" : ""); s.className = 'emoticon ffz-tooltip ffz-tooltip-no-credit' + (!can_use ? " locked" : "");
if ( known_sets.indexOf(emote.emoticon_set) === -1 ) if ( known_sets.indexOf(emote.emoticon_set) === -1 )
known_sets.push(emote.emoticon_set); known_sets.push(emote.emoticon_set);
if ( emote.emoticon_set ) { if ( emote.emoticon_set ) {
var favs = this.settings.favorite_emotes["twitch-" + emote.emoticon_set]; var favs = this.settings.favorite_emotes["twitch-" + emote.emoticon_set];
s.classList.add('ffz-can-favorite'); s.classList.add('ffz-can-favorite');
s.classList.toggle('ffz-favorite', favs && favs.indexOf(emote.id) !== -1 || false); s.classList.toggle('ffz-favorite', favs && favs.indexOf(emote.id) !== -1 || false);
} }
s.setAttribute('data-emote', emote.id); s.setAttribute('data-emote', emote.id);
s.alt = emote.regex; s.alt = emote.regex;
s.style.backgroundImage = 'url("' + constants.TWITCH_BASE + emote.id + '/1.0")'; s.style.backgroundImage = 'url("' + constants.TWITCH_BASE + emote.id + '/1.0")';
s.style.backgroundImage = '-webkit-' + img_set; s.style.backgroundImage = '-webkit-' + img_set;
@ -578,7 +578,7 @@ FFZ.menu_pages.channel = {
if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons ) if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons )
window.open("https://twitchemotes.com/emote/" + id); window.open("https://twitchemotes.com/emote/" + id);
else if ( can_use ) else if ( can_use )
this._add_emote(view, code, "twitch-" + emote_set, id, e); this._add_emote(view, code, "twitch-" + emote_set, id, e);
else else
return; return;
e.preventDefault(); e.preventDefault();
@ -588,11 +588,11 @@ FFZ.menu_pages.channel = {
c++; c++;
} }
if ( reported_sets.indexOf(product.get('id')) === -1 && known_sets.length ) { if ( reported_sets.indexOf(product.get('id')) === -1 && known_sets.length ) {
reported_sets.push(product.get('id')); reported_sets.push(product.get('id'));
this.log("Sets for " + product.get('id') + " [" + product.get('ticketProductId') + "]: " + JSON.stringify(known_sets)); this.log("Sets for " + product.get('id') + " [" + product.get('ticketProductId') + "]: " + JSON.stringify(known_sets));
this.ws_send("report_twitch_set", [product.get('id'), product.get('ticketProductId'), known_sets]); this.ws_send("report_twitch_set", [product.get('id'), product.get('ticketProductId'), known_sets]);
} }
if ( c > 0 ) if ( c > 0 )
@ -646,7 +646,7 @@ FFZ.menu_pages.channel = {
var extra_sets = _.union(room && room.extra_sets || [], room && room.ext_sets || [], []); var extra_sets = _.union(room && room.extra_sets || [], room && room.ext_sets || [], []);
// Basic Emote Sets // Basic Emote Sets
this._emotes_for_sets(inner, view, room && room.set && [room.set] || [], (this.feature_friday || has_product || extra_sets.length ) ? "Channel Emoticons" : null, (room && room.moderator_badge) || "//cdn.frankerfacez.com/script/devicon.png", "FrankerFaceZ"); this._emotes_for_sets(inner, view, room && room.set && [room.set] || [], (this.feature_friday || has_product || extra_sets.length ) ? "Channel Emoticons" : null, (room && room.moderator_badge) || "//cdn.frankerfacez.com/script/devicon.png", "FrankerFaceZ");
for(var i=0; i < extra_sets.length; i++) { for(var i=0; i < extra_sets.length; i++) {
// Look up the set name. // Look up the set name.
@ -734,8 +734,8 @@ FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, image, sub
var s = document.createElement('span'); var s = document.createElement('span');
s.className = 'emoticon ffz-tooltip'; s.className = 'emoticon ffz-tooltip';
s.setAttribute('data-ffz-emote', emote.id); s.setAttribute('data-ffz-emote', emote.id);
s.setAttribute('data-ffz-set', set.id); s.setAttribute('data-ffz-set', set.id);
s.style.backgroundImage = 'url("' + emote.urls[1] + '")'; s.style.backgroundImage = 'url("' + emote.urls[1] + '")';
@ -748,7 +748,7 @@ FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, image, sub
} }
s.style.width = (10+emote.width) + "px"; s.style.width = (10+emote.width) + "px";
s.style.height = (10+emote.height) + "px"; s.style.height = (10+emote.height) + "px";
s.addEventListener('click', function(id, code, e) { s.addEventListener('click', function(id, code, e) {
e.preventDefault(); e.preventDefault();
@ -779,27 +779,27 @@ FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, image, sub
FFZ.prototype._add_emote = function(view, emote, favorites_set, favorites_key, event) { FFZ.prototype._add_emote = function(view, emote, favorites_set, favorites_key, event) {
if ( event && ((!IS_OSX && event.ctrlKey) || (IS_OSX && event.metaKey)) ) { if ( event && ((!IS_OSX && event.ctrlKey) || (IS_OSX && event.metaKey)) ) {
var el = event.target; var el = event.target;
if ( ! el.classList.contains('locked') && el.classList.contains('ffz-can-favorite') && favorites_set && favorites_key ) { if ( ! el.classList.contains('locked') && el.classList.contains('ffz-can-favorite') && favorites_set && favorites_key ) {
var favs = this.settings.favorite_emotes[favorites_set] = this.settings.favorite_emotes[favorites_set] || [], var favs = this.settings.favorite_emotes[favorites_set] = this.settings.favorite_emotes[favorites_set] || [],
is_favorited = favs.indexOf(favorites_key) !== -1; is_favorited = favs.indexOf(favorites_key) !== -1;
if ( is_favorited ) if ( is_favorited )
favs.removeObject(favorites_key); favs.removeObject(favorites_key);
else else
favs.push(favorites_key); favs.push(favorites_key);
this.settings.set("favorite_emotes", this.settings.favorite_emotes, true); this.settings.set("favorite_emotes", this.settings.favorite_emotes, true);
if ( el.classList.contains('ffz-is-favorite') && is_favorited ) { if ( el.classList.contains('ffz-is-favorite') && is_favorited ) {
jQuery(el).trigger('mouseout'); jQuery(el).trigger('mouseout');
el.parentElement.removeChild(el); el.parentElement.removeChild(el);
} else } else
el.classList.toggle('ffz-favorite', ! is_favorited); el.classList.toggle('ffz-favorite', ! is_favorited);
} }
return; return;
} }
var input_el, text, room; var input_el, text, room;

View file

@ -1,6 +1,6 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
constants = require('../constants'), constants = require('../constants'),
utils = require('../utils'); utils = require('../utils');
// -------------------- // --------------------
// Initialization // Initialization

View file

@ -66,15 +66,15 @@ FFZ.settings_info.emoji_in_menu = {
FFZ.settings_info.emote_menu_collapsed = { FFZ.settings_info.emote_menu_collapsed = {
storage_key: "ffz_setting_my_emoticons_collapsed_sections", storage_key: "ffz_setting_my_emoticons_collapsed_sections",
value: [], value: [],
visible: false visible: false
} }
FFZ.settings_info.favorite_emotes = { FFZ.settings_info.favorite_emotes = {
value: {}, value: {},
visible: false visible: false
} }
@ -111,164 +111,164 @@ FFZ.menu_pages.myemotes = {
return this.settings.emoji_in_menu || FFZ.menu_pages.myemotes.has_sets.call(this, view); return this.settings.emoji_in_menu || FFZ.menu_pages.myemotes.has_sets.call(this, view);
}, },
default_page: function() { default_page: function() {
for(var key in this.settings.favorite_emotes) for(var key in this.settings.favorite_emotes)
if ( this.settings.favorite_emotes[key] && this.settings.favorite_emotes[key].length ) if ( this.settings.favorite_emotes[key] && this.settings.favorite_emotes[key].length )
return 'favorites'; return 'favorites';
return 'all'; return 'all';
}, },
pages: { pages: {
favorites: { favorites: {
name: "Favorites", name: "Favorites",
sort_order: 1, sort_order: 1,
render: function(view, container) { render: function(view, container) {
FFZ.menu_pages.myemotes.render_lists.call(this, view, container, true); FFZ.menu_pages.myemotes.render_lists.call(this, view, container, true);
var el = document.createElement("div"); var el = document.createElement("div");
el.className = "emoticon-grid ffz-no-emotes center"; el.className = "emoticon-grid ffz-no-emotes center";
el.innerHTML = "You have no favorite emoticons.<br> <img src=\"//cdn.frankerfacez.com/emoticon/26608/2\"><br>To make an emote a favorite, find it on the <nobr>All Emoticons</nobr> tab and <nobr>" + (constants.IS_OSX ? '⌘' : 'Ctrl') + "-Click</nobr> it."; el.innerHTML = "You have no favorite emoticons.<br> <img src=\"//cdn.frankerfacez.com/emoticon/26608/2\"><br>To make an emote a favorite, find it on the <nobr>All Emoticons</nobr> tab and <nobr>" + (constants.IS_OSX ? '⌘' : 'Ctrl') + "-Click</nobr> it.";
container.appendChild(el); container.appendChild(el);
} }
}, },
all: { all: {
name: "All Emoticons", name: "All Emoticons",
sort_order: 2, sort_order: 2,
visible: function(view) { visible: function(view) {
return FFZ.menu_pages.myemotes.has_sets.call(this, view); return FFZ.menu_pages.myemotes.has_sets.call(this, view);
}, },
render: function(view, container) { render: function(view, container) {
FFZ.menu_pages.myemotes.render_lists.call(this, view, container, false); FFZ.menu_pages.myemotes.render_lists.call(this, view, container, false);
} }
}, },
emoji: { emoji: {
name: "Emoji", name: "Emoji",
sort_order: 3, sort_order: 3,
visible: function() { return this.settings.emoji_in_menu }, visible: function() { return this.settings.emoji_in_menu },
render: function(view, container) { render: function(view, container) {
var sets = []; var sets = [];
for(var cat in constants.EMOJI_CATEGORIES) { for(var cat in constants.EMOJI_CATEGORIES) {
var menu = FFZ.menu_pages.myemotes.draw_emoji.call(this, view, cat, false); var menu = FFZ.menu_pages.myemotes.draw_emoji.call(this, view, cat, false);
if ( menu ) if ( menu )
sets.push([cat, menu]); sets.push([cat, menu]);
} }
sets.sort(function(a,b) { sets.sort(function(a,b) {
var an = a[0], bn = b[0]; var an = a[0], bn = b[0];
if ( an < bn ) return -1; if ( an < bn ) return -1;
if ( an > bn ) return 1; if ( an > bn ) return 1;
return 0; return 0;
}); });
for(var i=0; i < sets.length; i++) for(var i=0; i < sets.length; i++)
container.appendChild(sets[i][1]); container.appendChild(sets[i][1]);
} }
} }
}, },
render_lists: function(view, container, favorites_only) { render_lists: function(view, container, favorites_only) {
var tmi = view.get('controller.currentRoom.tmiSession'), var tmi = view.get('controller.currentRoom.tmiSession'),
twitch_sets = (tmi && tmi.getEmotes() || {'emoticon_sets': {}})['emoticon_sets'], twitch_sets = (tmi && tmi.getEmotes() || {'emoticon_sets': {}})['emoticon_sets'],
user = this.get_user(), user = this.get_user(),
ffz_sets = this.getEmotes(user && user.login, null), ffz_sets = this.getEmotes(user && user.login, null),
sets = []; sets = [];
// Start with Twitch Sets // Start with Twitch Sets
for(var set_id in twitch_sets) { for(var set_id in twitch_sets) {
if ( ! twitch_sets.hasOwnProperty(set_id) || ( ! this.settings.global_emotes_in_menu && set_id === '0' ) ) if ( ! twitch_sets.hasOwnProperty(set_id) || ( ! this.settings.global_emotes_in_menu && set_id === '0' ) )
continue; continue;
var favorites_list = this.settings.favorite_emotes["twitch-" + set_id]; var favorites_list = this.settings.favorite_emotes["twitch-" + set_id];
if ( favorites_only && (! favorites_list || ! favorites_list.length) ) if ( favorites_only && (! favorites_list || ! favorites_list.length) )
continue; continue;
var set = twitch_sets[set_id]; var set = twitch_sets[set_id];
if ( ! set.length ) if ( ! set.length )
continue; continue;
var menu = FFZ.menu_pages.myemotes.draw_twitch_set.call(this, view, set_id, set, favorites_only); var menu = FFZ.menu_pages.myemotes.draw_twitch_set.call(this, view, set_id, set, favorites_only);
if ( menu ) if ( menu )
sets.push([this._twitch_set_to_channel[set_id], menu]); sets.push([this._twitch_set_to_channel[set_id], menu]);
} }
// Emoji~! // Emoji~!
if ( favorites_only && this.settings.emoji_in_menu ) { if ( favorites_only && this.settings.emoji_in_menu ) {
var favorites_list = this.settings.favorite_emotes["emoji"]; var favorites_list = this.settings.favorite_emotes["emoji"];
if ( favorites_list && favorites_list.length ) { if ( favorites_list && favorites_list.length ) {
var menu = FFZ.menu_pages.myemotes.draw_emoji.call(this, view, null, favorites_only); var menu = FFZ.menu_pages.myemotes.draw_emoji.call(this, view, null, favorites_only);
if ( menu ) if ( menu )
sets.push(["emoji", menu]); sets.push(["emoji", menu]);
} }
} }
// Now, FFZ! // Now, FFZ!
for(var i=0; i < ffz_sets.length; i++) { for(var i=0; i < ffz_sets.length; i++) {
var set_id = ffz_sets[i], var set_id = ffz_sets[i],
set = this.emote_sets[set_id], set = this.emote_sets[set_id],
menu_id = set.hasOwnProperty('source_ext') ? 'ffz-ext-' + set.source_ext + '-' + set.source_id : 'ffz-' + set.id, menu_id = set.hasOwnProperty('source_ext') ? 'ffz-ext-' + set.source_ext + '-' + set.source_id : 'ffz-' + set.id,
favorites_list = this.settings.favorite_emotes[menu_id]; favorites_list = this.settings.favorite_emotes[menu_id];
if ( favorites_only && (! favorites_list || ! favorites_list.length) ) if ( favorites_only && (! favorites_list || ! favorites_list.length) )
continue; continue;
if ( ! set || ! set.count || ( ! this.settings.global_emotes_in_menu && this.default_sets.indexOf(set_id) !== -1 ) ) if ( ! set || ! set.count || ( ! this.settings.global_emotes_in_menu && this.default_sets.indexOf(set_id) !== -1 ) )
continue; continue;
var menu = FFZ.menu_pages.myemotes.draw_ffz_set.call(this, view, set, favorites_only); var menu = FFZ.menu_pages.myemotes.draw_ffz_set.call(this, view, set, favorites_only);
if ( menu ) if ( menu )
sets.push([set.title.toLowerCase(), menu]); sets.push([set.title.toLowerCase(), menu]);
} }
if ( ! sets.length ) if ( ! sets.length )
return false; return false;
// Finally, sort and add them all. // Finally, sort and add them all.
sets.sort(function(a,b) { sets.sort(function(a,b) {
var an = a[0], bn = b[0]; var an = a[0], bn = b[0];
if ( an === "turbo" || an === "--turbo-faces--" ) if ( an === "turbo" || an === "--turbo-faces--" )
an = "zza|" + an; an = "zza|" + an;
else if ( an === "global" || (an && an.substr(0,16) === "global emoticons") || an === "--global--" ) else if ( an === "global" || (an && an.substr(0,16) === "global emoticons") || an === "--global--" )
an = "zzy|" + an; an = "zzy|" + an;
else if ( an.substr(0,5) === "emoji" ) else if ( an.substr(0,5) === "emoji" )
an = "zzz|" + an; an = "zzz|" + an;
if ( bn === "turbo" || bn === "--turbo-faces--" ) if ( bn === "turbo" || bn === "--turbo-faces--" )
bn = "zza|" + bn; bn = "zza|" + bn;
else if ( bn === "global" || (bn && bn.substr(0,16) === "global emoticons") || bn === "--global--" ) else if ( bn === "global" || (bn && bn.substr(0,16) === "global emoticons") || bn === "--global--" )
bn = "zzy|" + bn; bn = "zzy|" + bn;
else if ( bn.substr(0,5) === "emoji" ) else if ( bn.substr(0,5) === "emoji" )
bn = "zzz|" + bn; bn = "zzz|" + bn;
if ( an < bn ) return -1; if ( an < bn ) return -1;
if ( an > bn ) return 1; if ( an > bn ) return 1;
return 0; return 0;
}); });
if ( favorites_only ) { if ( favorites_only ) {
var grid = document.createElement('div'); var grid = document.createElement('div');
grid.className = 'emoticon-grid favorites-grid'; grid.className = 'emoticon-grid favorites-grid';
for(var i=0; i < sets.length; i++) for(var i=0; i < sets.length; i++)
grid.appendChild(sets[i][1]); grid.appendChild(sets[i][1]);
container.appendChild(grid); container.appendChild(grid);
} else } else
for(var i=0; i < sets.length; i++) for(var i=0; i < sets.length; i++)
container.appendChild(sets[i][1]); container.appendChild(sets[i][1]);
return true; return true;
}, },
toggle_section: function(heading, container) { toggle_section: function(heading, container) {
@ -285,38 +285,38 @@ FFZ.menu_pages.myemotes = {
this.settings.set('emote_menu_collapsed', collapsed_list, true); this.settings.set('emote_menu_collapsed', collapsed_list, true);
menu.classList.toggle('collapsed', !is_collapsed); menu.classList.toggle('collapsed', !is_collapsed);
if ( is_collapsed ) if ( is_collapsed )
menu.appendChild(container); menu.appendChild(container);
else else
menu.removeChild(container); menu.removeChild(container);
}, },
draw_emoji: function(view, cat, favorites_only) { draw_emoji: function(view, cat, favorites_only) {
var heading = document.createElement('div'), var heading = document.createElement('div'),
menu = document.createElement('div'), menu = document.createElement('div'),
menu_id = 'emoji' + (cat ? '-' + cat : ''), menu_id = 'emoji' + (cat ? '-' + cat : ''),
emotes = favorites_only ? document.createDocumentFragment() : document.createElement('div'), emotes = favorites_only ? document.createDocumentFragment() : document.createElement('div'),
collapsed = ! favorites_only && this.settings.emote_menu_collapsed.indexOf(menu_id) === -1, collapsed = ! favorites_only && this.settings.emote_menu_collapsed.indexOf(menu_id) === -1,
f = this, f = this,
settings = this.settings.parse_emoji || 1, settings = this.settings.parse_emoji || 1,
favorites = this.settings.favorite_emotes["emoji"] || [], favorites = this.settings.favorite_emotes["emoji"] || [],
c = 0; c = 0;
menu.className = 'emoticon-grid'; menu.className = 'emoticon-grid';
menu.setAttribute('data-set', menu_id); menu.setAttribute('data-set', menu_id);
if ( ! favorites_only ) { if ( ! favorites_only ) {
heading.className = 'heading'; heading.className = 'heading';
heading.innerHTML = '<span class="right">Unicode</span>' + (cat ? utils.sanitize(constants.EMOJI_CATEGORIES[cat]) : 'Emoji'); heading.innerHTML = '<span class="right">Unicode</span>' + (cat ? utils.sanitize(constants.EMOJI_CATEGORIES[cat]) : 'Emoji');
heading.style.backgroundImage = 'url("' + constants.SERVER + 'emoji/' + (settings === 3 ? 'one/' : (settings === 2 ? 'noto-' : 'tw/')) + (constants.EMOJI_LOGOS[cat] || '1f4af') + '.svg")'; heading.style.backgroundImage = 'url("' + constants.SERVER + 'emoji/' + (settings === 3 ? 'one/' : (settings === 2 ? 'noto-' : 'tw/')) + (constants.EMOJI_LOGOS[cat] || '1f4af') + '.svg")';
heading.style.backgroundSize = "18px"; heading.style.backgroundSize = "18px";
menu.classList.add('collapsable'); menu.classList.add('collapsable');
menu.appendChild(heading); menu.appendChild(heading);
menu.classList.toggle('collapsed', collapsed); menu.classList.toggle('collapsed', collapsed);
heading.addEventListener('click', function() { FFZ.menu_pages.myemotes.toggle_section.bind(f)(this, emotes); }); heading.addEventListener('click', function() { FFZ.menu_pages.myemotes.toggle_section.bind(f)(this, emotes); });
} }
var set = []; var set = [];
@ -342,36 +342,36 @@ FFZ.menu_pages.myemotes = {
continue; continue;
var is_favorite = favorites.indexOf(emoji.raw) !== -1, var is_favorite = favorites.indexOf(emoji.raw) !== -1,
src = settings === 3 ? emoji.one_src : (settings === 2 ? emoji.noto_src : emoji.tw_src), src = settings === 3 ? emoji.one_src : (settings === 2 ? emoji.noto_src : emoji.tw_src),
image = this.settings.emote_image_hover ? '<img class="emoticon ffz-image-hover" src="' + src + '">' : ''; image = this.settings.emote_image_hover ? '<img class="emoticon ffz-image-hover" src="' + src + '">' : '';
if ( favorites_only && ! is_favorite ) if ( favorites_only && ! is_favorite )
continue; continue;
em.className = 'emoticon emoji ffz-tooltip ffz-can-favorite'; em.className = 'emoticon emoji ffz-tooltip ffz-can-favorite';
em.classList.toggle('ffz-favorite', is_favorite); em.classList.toggle('ffz-favorite', is_favorite);
em.classList.toggle('ffz-is-favorite', favorites_only); em.classList.toggle('ffz-is-favorite', favorites_only);
em.setAttribute('data-ffz-emoji', emoji.code); em.setAttribute('data-ffz-emoji', emoji.code);
em.alt = emoji.raw; em.alt = emoji.raw;
em.addEventListener('click', this._add_emote.bind(this, view, emoji.raw, "emoji", emoji.raw)); em.addEventListener('click', this._add_emote.bind(this, view, emoji.raw, "emoji", emoji.raw));
em.style.backgroundImage = 'url("' + src + '")'; em.style.backgroundImage = 'url("' + src + '")';
em.style.backgroundSize = "18px"; em.style.backgroundSize = "18px";
c++; c++;
emotes.appendChild(em); emotes.appendChild(em);
} }
if ( ! c ) if ( ! c )
return; return;
if ( favorites_only ) if ( favorites_only )
return emotes; return emotes;
if ( ! collapsed ) if ( ! collapsed )
menu.appendChild(emotes); menu.appendChild(emotes);
return menu; return menu;
}, },
@ -379,51 +379,51 @@ FFZ.menu_pages.myemotes = {
draw_twitch_set: function(view, set_id, set, favorites_only) { draw_twitch_set: function(view, set_id, set, favorites_only) {
var heading = document.createElement('div'), var heading = document.createElement('div'),
menu = document.createElement('div'), menu = document.createElement('div'),
emotes = favorites_only ? document.createDocumentFragment() : document.createElement('div'), emotes = favorites_only ? document.createDocumentFragment() : document.createElement('div'),
collapsed = ! favorites_only && this.settings.emote_menu_collapsed.indexOf('twitch-' + set_id) === -1, collapsed = ! favorites_only && this.settings.emote_menu_collapsed.indexOf('twitch-' + set_id) === -1,
f = this, f = this,
channel_id = this._twitch_set_to_channel[set_id], title, channel_id = this._twitch_set_to_channel[set_id], title,
favorites = this.settings.favorite_emotes["twitch-" + set_id] || [], favorites = this.settings.favorite_emotes["twitch-" + set_id] || [],
c = 0; c = 0;
menu.className = 'emoticon-grid'; menu.className = 'emoticon-grid';
menu.setAttribute('data-set', 'twitch-' + set_id); menu.setAttribute('data-set', 'twitch-' + set_id);
if ( ! favorites_only ) { if ( ! favorites_only ) {
if ( channel_id === "twitch_unknown" ) if ( channel_id === "twitch_unknown" )
title = "Unknown Channel"; title = "Unknown Channel";
else if ( channel_id === "--global--" ) else if ( channel_id === "--global--" )
title = "Global Emoticons"; title = "Global Emoticons";
else if ( channel_id === "turbo" || channel_id === "--turbo-faces--" ) else if ( channel_id === "turbo" || channel_id === "--turbo-faces--" )
title = "Twitch Turbo"; title = "Twitch Turbo";
else else
title = FFZ.get_capitalization(channel_id, function(name) { title = FFZ.get_capitalization(channel_id, function(name) {
heading.innerHTML = '<span class="right">Twitch</span>' + utils.sanitize(name); heading.innerHTML = '<span class="right">Twitch</span>' + utils.sanitize(name);
}); });
heading.className = 'heading'; heading.className = 'heading';
heading.innerHTML = '<span class="right">Twitch</span>' + utils.sanitize(title); heading.innerHTML = '<span class="right">Twitch</span>' + utils.sanitize(title);
if ( this._twitch_badges[channel_id] ) if ( this._twitch_badges[channel_id] )
heading.style.backgroundImage = 'url("' + this._twitch_badges[channel_id] + '")'; heading.style.backgroundImage = 'url("' + this._twitch_badges[channel_id] + '")';
else { else {
var f = this; var f = this;
utils.api.get("chat/" + channel_id + "/badges", null, {version: 3}) utils.api.get("chat/" + channel_id + "/badges", null, {version: 3})
.done(function(data) { .done(function(data) {
if ( data.subscriber && data.subscriber.image ) { if ( data.subscriber && data.subscriber.image ) {
f._twitch_badges[channel_id] = data.subscriber.image; f._twitch_badges[channel_id] = data.subscriber.image;
localStorage.ffzTwitchBadges = JSON.stringify(f._twitch_badges); localStorage.ffzTwitchBadges = JSON.stringify(f._twitch_badges);
heading.style.backgroundImage = 'url("' + data.subscriber.image + '")'; heading.style.backgroundImage = 'url("' + data.subscriber.image + '")';
} }
}); });
} }
menu.classList.add('collapsable'); menu.classList.add('collapsable');
menu.appendChild(heading); menu.appendChild(heading);
menu.classList.toggle('collapsed', collapsed); menu.classList.toggle('collapsed', collapsed);
heading.addEventListener('click', function() { FFZ.menu_pages.myemotes.toggle_section.bind(f)(this, emotes); }); heading.addEventListener('click', function() { FFZ.menu_pages.myemotes.toggle_section.bind(f)(this, emotes); });
} }
set.sort(function(a,b) { set.sort(function(a,b) {
var an = a.code.toLowerCase(), var an = a.code.toLowerCase(),
@ -439,21 +439,21 @@ FFZ.menu_pages.myemotes = {
for(var i=0; i < set.length; i++) { for(var i=0; i < set.length; i++) {
var emote = set[i], var emote = set[i],
code = constants.KNOWN_CODES[emote.code] || emote.code, code = constants.KNOWN_CODES[emote.code] || emote.code,
is_favorite = favorites.indexOf(emote.id) !== -1; is_favorite = favorites.indexOf(emote.id) !== -1;
if ( favorites_only && ! is_favorite ) if ( favorites_only && ! is_favorite )
continue; continue;
var em = document.createElement('span'), var em = document.createElement('span'),
img_set = 'image-set(url("' + constants.TWITCH_BASE + emote.id + '/1.0") 1x, url("' + constants.TWITCH_BASE + emote.id + '/2.0") 2x)'; img_set = 'image-set(url("' + constants.TWITCH_BASE + emote.id + '/1.0") 1x, url("' + constants.TWITCH_BASE + emote.id + '/2.0") 2x)';
em.className = 'emoticon ffz-tooltip ffz-can-favorite'; em.className = 'emoticon ffz-tooltip ffz-can-favorite';
em.setAttribute('data-emote', emote.id); em.setAttribute('data-emote', emote.id);
em.alt = code; em.alt = code;
em.classList.toggle('ffz-favorite', is_favorite); em.classList.toggle('ffz-favorite', is_favorite);
em.classList.toggle('ffz-is-favorite', favorites_only); em.classList.toggle('ffz-is-favorite', favorites_only);
em.classList.toggle('ffz-tooltip-no-credit', ! favorites_only); em.classList.toggle('ffz-tooltip-no-credit', ! favorites_only);
if ( this.settings.replace_bad_emotes && constants.EMOTE_REPLACEMENTS[emote.id] ) { if ( this.settings.replace_bad_emotes && constants.EMOTE_REPLACEMENTS[emote.id] ) {
em.style.backgroundImage = 'url("' + constants.EMOTE_REPLACEMENT_BASE + constants.EMOTE_REPLACEMENTS[emote.id] + '")'; em.style.backgroundImage = 'url("' + constants.EMOTE_REPLACEMENT_BASE + constants.EMOTE_REPLACEMENTS[emote.id] + '")';
@ -473,18 +473,18 @@ FFZ.menu_pages.myemotes = {
this._add_emote(view, c, "twitch-" + set_id, id, e); this._add_emote(view, c, "twitch-" + set_id, id, e);
}.bind(this, emote.id, code)); }.bind(this, emote.id, code));
c++; c++;
emotes.appendChild(em); emotes.appendChild(em);
} }
if ( ! c ) if ( ! c )
return; return;
if ( favorites_only ) if ( favorites_only )
return emotes; return emotes;
if ( ! collapsed ) if ( ! collapsed )
menu.appendChild(emotes); menu.appendChild(emotes);
return menu; return menu;
}, },
@ -492,33 +492,33 @@ FFZ.menu_pages.myemotes = {
draw_ffz_set: function(view, set, favorites_only) { draw_ffz_set: function(view, set, favorites_only) {
var heading = document.createElement('div'), var heading = document.createElement('div'),
menu = document.createElement('div'), menu = document.createElement('div'),
emote_container = favorites_only ? document.createDocumentFragment() : document.createElement('div'), emote_container = favorites_only ? document.createDocumentFragment() : document.createElement('div'),
f = this, f = this,
emotes = [], emotes = [],
menu_id = set.hasOwnProperty('source_ext') ? 'ffz-ext-' + set.source_ext + '-' + set.source_id : 'ffz-' + set.id, menu_id = set.hasOwnProperty('source_ext') ? 'ffz-ext-' + set.source_ext + '-' + set.source_id : 'ffz-' + set.id,
favorites = this.settings.favorite_emotes[menu_id] || [], favorites = this.settings.favorite_emotes[menu_id] || [],
c = 0, c = 0,
icon = set.icon || (set.hasOwnProperty('source_ext') && '//cdn.frankerfacez.com/emoji/tw-1f4ac.svg') || '//cdn.frankerfacez.com/script/devicon.png', icon = set.icon || (set.hasOwnProperty('source_ext') && '//cdn.frankerfacez.com/emoji/tw-1f4ac.svg') || '//cdn.frankerfacez.com/script/devicon.png',
collapsed = ! favorites_only && this.settings.emote_menu_collapsed.indexOf(menu_id) === -1; collapsed = ! favorites_only && this.settings.emote_menu_collapsed.indexOf(menu_id) === -1;
menu.className = 'emoticon-grid'; menu.className = 'emoticon-grid';
menu.setAttribute('data-set', menu_id); menu.setAttribute('data-set', menu_id);
if ( ! favorites_only ) { if ( ! favorites_only ) {
menu.classList.add('collapsable'); menu.classList.add('collapsable');
heading.className = 'heading'; heading.className = 'heading';
heading.innerHTML = '<span class="right">' + (utils.sanitize(set.source) || 'FrankerFaceZ') + '</span>' + set.title; heading.innerHTML = '<span class="right">' + (utils.sanitize(set.source) || 'FrankerFaceZ') + '</span>' + set.title;
heading.style.backgroundImage = 'url("' + icon + '")'; heading.style.backgroundImage = 'url("' + icon + '")';
if ( icon.indexOf('.svg') !== -1 ) if ( icon.indexOf('.svg') !== -1 )
heading.style.backgroundSize = "18px"; heading.style.backgroundSize = "18px";
menu.appendChild(heading); menu.appendChild(heading);
menu.classList.toggle('collapsed', collapsed); menu.classList.toggle('collapsed', collapsed);
heading.addEventListener('click', function() { FFZ.menu_pages.myemotes.toggle_section.bind(f)(this, emote_container); }); heading.addEventListener('click', function() { FFZ.menu_pages.myemotes.toggle_section.bind(f)(this, emote_container); });
} }
for(var emote_id in set.emoticons) for(var emote_id in set.emoticons)
set.emoticons.hasOwnProperty(emote_id) && ! set.emoticons[emote_id].hidden && emotes.push(set.emoticons[emote_id]); set.emoticons.hasOwnProperty(emote_id) && ! set.emoticons[emote_id].hidden && emotes.push(set.emoticons[emote_id]);
@ -536,12 +536,12 @@ FFZ.menu_pages.myemotes = {
for(var i=0; i < emotes.length; i++) { for(var i=0; i < emotes.length; i++) {
var emote = emotes[i], var emote = emotes[i],
is_favorite = favorites.indexOf(emote.id) !== -1; is_favorite = favorites.indexOf(emote.id) !== -1;
if ( favorites_only && ! is_favorite ) if ( favorites_only && ! is_favorite )
continue; continue;
var em = document.createElement('span'), var em = document.createElement('span'),
img_set = 'image-set(url("' + emote.urls[1] + '") 1x'; img_set = 'image-set(url("' + emote.urls[1] + '") 1x';
if ( emote.urls[2] ) if ( emote.urls[2] )
@ -553,11 +553,11 @@ FFZ.menu_pages.myemotes = {
img_set += ')'; img_set += ')';
em.className = 'emoticon ffz-tooltip ffz-can-favorite'; em.className = 'emoticon ffz-tooltip ffz-can-favorite';
em.classList.toggle('ffz-favorite', is_favorite); em.classList.toggle('ffz-favorite', is_favorite);
em.classList.toggle('ffz-is-favorite', favorites_only); em.classList.toggle('ffz-is-favorite', favorites_only);
em.setAttribute('data-ffz-emote', emote.id); em.setAttribute('data-ffz-emote', emote.id);
em.setAttribute('data-ffz-set', set.id); em.setAttribute('data-ffz-set', set.id);
em.style.backgroundImage = 'url("' + emote.urls[1] + '")'; em.style.backgroundImage = 'url("' + emote.urls[1] + '")';
em.style.backgroundImage = '-webkit-' + img_set; em.style.backgroundImage = '-webkit-' + img_set;
@ -587,18 +587,18 @@ FFZ.menu_pages.myemotes = {
this._add_emote(view, code, menu_id, id, e); this._add_emote(view, code, menu_id, id, e);
}.bind(this, emote.id, emote.name)); }.bind(this, emote.id, emote.name));
c++; c++;
emote_container.appendChild(em); emote_container.appendChild(em);
} }
if ( ! c ) if ( ! c )
return; return;
if ( favorites_only ) if ( favorites_only )
return emote_container; return emote_container;
if ( ! collapsed ) if ( ! collapsed )
menu.appendChild(emote_container); menu.appendChild(emote_container);
return menu; return menu;
} }

View file

@ -1,5 +1,5 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
utils = require("../utils"), utils = require("../utils"),
constants = require("../constants"); constants = require("../constants");
@ -76,21 +76,21 @@ FFZ.settings_info.notification_timeout = {
help: "Specify how long notifications should be displayed before automatically closing.", help: "Specify how long notifications should be displayed before automatically closing.",
method: function() { method: function() {
var f = this; var f = this;
utils.prompt( utils.prompt(
"Notification Timeout", "Notification Timeout",
"Please enter the time you'd like notifications to be displayed before automatically closing, in seconds.</p><p><b>Default:</b> 60", "Please enter the time you'd like notifications to be displayed before automatically closing, in seconds.</p><p><b>Default:</b> 60",
this.settings.notification_timeout, this.settings.notification_timeout,
function(new_val) { function(new_val) {
if ( new_val === null || new_val === undefined ) if ( new_val === null || new_val === undefined )
return; return;
new_val = parseInt(new_val); new_val = parseInt(new_val);
if ( Number.isNaN(new_val) || ! Number.isFinite(new_val) || new_val < 1 ) if ( Number.isNaN(new_val) || ! Number.isFinite(new_val) || new_val < 1 )
new_val = 60; new_val = 60;
f.settings.set("notification_timeout", new_val); f.settings.set("notification_timeout", new_val);
}); });
} }
}; };

View file

@ -1,5 +1,5 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
constants = require('../constants'); constants = require('../constants');
// --------------- // ---------------
@ -14,10 +14,10 @@ FFZ.prototype.setup_popups = function() {
if ( e.button && e.button !== 0 ) if ( e.button && e.button !== 0 )
return; return;
// Check for modal clicks // Check for modal clicks
var modal = document.getElementById('ffz-modal-container'); var modal = document.getElementById('ffz-modal-container');
if ( modal && (modal === e.target || modal.contains(e.target)) ) if ( modal && (modal === e.target || modal.contains(e.target)) )
return; return;
var popup = f._popup, var popup = f._popup,
parent = f._popup_parent; parent = f._popup_parent;

View file

@ -31,70 +31,70 @@ FFZ.prototype._update_subscribers = function() {
// context of the web user. // context of the web user.
// Get the count! // Get the count!
jQuery.getJSON("/" + id + "/dashboard/revenue/summary_data").done(function(data) { jQuery.getJSON("/" + id + "/dashboard/revenue/summary_data").done(function(data) {
var el, sub_count = data && data.data && data.data.total_subscriptions; var el, sub_count = data && data.data && data.data.total_subscriptions;
if ( typeof sub_count === "string" ) if ( typeof sub_count === "string" )
sub_count = parseInt(sub_count.replace(/[,\.]/g, "")); sub_count = parseInt(sub_count.replace(/[,\.]/g, ""));
if ( typeof sub_count !== "number" || sub_count === 0 || sub_count === NaN || sub_count === Infinity ) { if ( typeof sub_count !== "number" || sub_count === 0 || sub_count === NaN || sub_count === Infinity ) {
el = document.querySelector("#ffz-sub-display"); el = document.querySelector("#ffz-sub-display");
if ( el ) if ( el )
el.parentElement.removeChild(el); el.parentElement.removeChild(el);
var failed = f._failed_sub_checks = (f._failed_sub_checks || 0) + 1; var failed = f._failed_sub_checks = (f._failed_sub_checks || 0) + 1;
if ( f._update_subscribers_timer && failed >= 5 ) { if ( f._update_subscribers_timer && failed >= 5 ) {
f.log("Subscriber count failed 5 times. Giving up."); f.log("Subscriber count failed 5 times. Giving up.");
clearTimeout(f._update_subscribers_timer); clearTimeout(f._update_subscribers_timer);
delete f._update_subscribers_timer; delete f._update_subscribers_timer;
} }
return; return;
} }
// Graph this glorious data point // Graph this glorious data point
if ( f._dash_chart ) { if ( f._dash_chart ) {
if ( ! f._dash_chart.series[3].options.showInLegend ) { if ( ! f._dash_chart.series[3].options.showInLegend ) {
f._dash_chart.series[3].options.showInLegend = true; f._dash_chart.series[3].options.showInLegend = true;
f._dash_chart.legend.renderLegend(); f._dash_chart.legend.renderLegend();
} }
f._dash_chart.series[3].addPoint({x: utils.last_minute(), y: sub_count}); f._dash_chart.series[3].addPoint({x: utils.last_minute(), y: sub_count});
} }
el = document.querySelector('#ffz-sub-display span'); el = document.querySelector('#ffz-sub-display span');
if ( ! el ) { if ( ! el ) {
var cont = f.is_dashboard ? document.querySelector("#stats") : document.querySelector("#channel .stats-and-actions .channel-stats"); var cont = f.is_dashboard ? document.querySelector("#stats") : document.querySelector("#channel .stats-and-actions .channel-stats");
if ( ! cont ) if ( ! cont )
return; return;
var stat = document.createElement('span'); var stat = document.createElement('span');
stat.className = 'ffz stat'; stat.className = 'ffz stat';
stat.id = 'ffz-sub-display'; stat.id = 'ffz-sub-display';
stat.title = 'Subscribers'; stat.title = 'Subscribers';
stat.innerHTML = constants.STAR + ' '; stat.innerHTML = constants.STAR + ' ';
el = document.createElement('span'); el = document.createElement('span');
stat.appendChild(el); stat.appendChild(el);
utils.api.get("chat/" + id + "/badges", null, {version: 3}) utils.api.get("chat/" + id + "/badges", null, {version: 3})
.done(function(data) { .done(function(data) {
if ( data.subscriber && data.subscriber.image ) { if ( data.subscriber && data.subscriber.image ) {
stat.innerHTML = ''; stat.innerHTML = '';
stat.appendChild(el); stat.appendChild(el);
stat.style.backgroundImage = 'url("' + data.subscriber.image + '")'; stat.style.backgroundImage = 'url("' + data.subscriber.image + '")';
stat.style.backgroundRepeat = 'no-repeat'; stat.style.backgroundRepeat = 'no-repeat';
stat.style.paddingLeft = '23px'; stat.style.paddingLeft = '23px';
stat.style.backgroundPosition = '0 50%'; stat.style.backgroundPosition = '0 50%';
} }
}); });
cont.appendChild(stat); cont.appendChild(stat);
jQuery(stat).tipsy({gravity: f.is_dashboard ? "s" : utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); jQuery(stat).tipsy({gravity: f.is_dashboard ? "s" : utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
} }
el.innerHTML = utils.number_commas(sub_count); el.innerHTML = utils.number_commas(sub_count);
}).fail(function(){ }).fail(function(){
var el = document.querySelector("#ffz-sub-display"); var el = document.querySelector("#ffz-sub-display");

View file

@ -154,44 +154,44 @@ var createElement = function(tag, className, content) {
}, },
// This code borrowed from the twemoji project, with tweaks. // This code borrowed from the twemoji project, with tweaks.
UFE0Fg = /\uFE0F/g, UFE0Fg = /\uFE0F/g,
U200D = String.fromCharCode(0x200D), U200D = String.fromCharCode(0x200D),
EMOJI_CODEPOINTS = {}, EMOJI_CODEPOINTS = {},
emoji_to_codepoint = function(surrogates, sep) { emoji_to_codepoint = function(surrogates, sep) {
if ( EMOJI_CODEPOINTS[surrogates] && EMOJI_CODEPOINTS[surrogates][sep] ) if ( EMOJI_CODEPOINTS[surrogates] && EMOJI_CODEPOINTS[surrogates][sep] )
return EMOJI_CODEPOINTS[surrogates][sep]; return EMOJI_CODEPOINTS[surrogates][sep];
var input = surrogates.indexOf(U200D) === -1 ? surrogates.replace(UFE0Fg, '') : surrogates, var input = surrogates.indexOf(U200D) === -1 ? surrogates.replace(UFE0Fg, '') : surrogates,
out = [], out = [],
c = 0, p = 0, i = 0; c = 0, p = 0, i = 0;
while (i < input.length) { while (i < input.length) {
c = input.charCodeAt(i++); c = input.charCodeAt(i++);
if ( p ) { if ( p ) {
out.push((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toString(16)); out.push((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toString(16));
p = 0; p = 0;
} else if ( 0xD800 <= c && c <= 0xDBFF ) } else if ( 0xD800 <= c && c <= 0xDBFF )
p = c; p = c;
else else
out.push(c.toString(16)); out.push(c.toString(16));
} }
var retval = EMOJI_CODEPOINTS[surrogates] = out.join('-'); var retval = EMOJI_CODEPOINTS[surrogates] = out.join('-');
return retval; return retval;
}, },
codepoint_to_emoji = function(codepoint) { codepoint_to_emoji = function(codepoint) {
var code = typeof codepoint === 'string' ? parseInt(codepoint, 16) : codepoint; var code = typeof codepoint === 'string' ? parseInt(codepoint, 16) : codepoint;
if ( code < 0x10000 ) if ( code < 0x10000 )
return String.fromCharCode(code); return String.fromCharCode(code);
code -= 0x10000; code -= 0x10000;
return String.fromCharCode( return String.fromCharCode(
0xD800 + (code >> 10), 0xD800 + (code >> 10),
0xDC00 + (code & 0x3FF) 0xDC00 + (code & 0x3FF)
) )
}, },
// Twitch Emote Helpers // Twitch Emote Helpers
@ -205,118 +205,118 @@ var createElement = function(tag, className, content) {
}, },
// Twitch API // Twitch API
api_call = function(method, url, data, options, token) { api_call = function(method, url, data, options, token) {
options = options || {}; options = options || {};
var headers = options.headers = options.headers || {}; var headers = options.headers = options.headers || {};
headers['Client-ID'] = constants.CLIENT_ID; headers['Client-ID'] = constants.CLIENT_ID;
if ( token ) if ( token )
headers.Authorization = 'OAuth ' + token; headers.Authorization = 'OAuth ' + token;
return Twitch.api[method].call(this, url, data, options); return Twitch.api[method].call(this, url, data, options);
}, },
// Dialogs // Dialogs
show_modal = function(contents, on_close, width) { show_modal = function(contents, on_close, width) {
var container = createElement('div', 'twitch_subwindow_container'), var container = createElement('div', 'twitch_subwindow_container'),
subwindow = createElement('div', 'twitch_subwindow ffz-subwindow'), subwindow = createElement('div', 'twitch_subwindow ffz-subwindow'),
card = createElement('div', 'card'), card = createElement('div', 'card'),
close_button = createElement('div', 'modal-close-button', constants.CLOSE), close_button = createElement('div', 'modal-close-button', constants.CLOSE),
closer = function() { container.parentElement.removeChild(container) }; closer = function() { container.parentElement.removeChild(container) };
container.id = 'ffz-modal-container'; container.id = 'ffz-modal-container';
subwindow.style.width = '100%'; subwindow.style.width = '100%';
subwindow.style.maxWidth = (width||420) + 'px'; subwindow.style.maxWidth = (width||420) + 'px';
close_button.addEventListener('click', function() { close_button.addEventListener('click', function() {
closer(); closer();
if ( on_close ) if ( on_close )
on_close(false); on_close(false);
}); });
container.appendChild(subwindow); container.appendChild(subwindow);
subwindow.appendChild(card); subwindow.appendChild(card);
subwindow.appendChild(close_button); subwindow.appendChild(close_button);
card.appendChild(contents); card.appendChild(contents);
var el = document.querySelector('app-main'); var el = document.querySelector('app-main');
if ( el ) if ( el )
el.parentElement.insertBefore(container, el.nextSibling); el.parentElement.insertBefore(container, el.nextSibling);
else else
document.body.appendChild(container); document.body.appendChild(container);
return closer; return closer;
}, },
ember_lookup = function(thing) { ember_lookup = function(thing) {
if ( ! window.App ) if ( ! window.App )
return; return;
try { try {
if ( App.__deprecatedInstance__ && App.__deprecatedInstance__.registry && App.__deprecatedInstance__.registry.lookup ) if ( App.__deprecatedInstance__ && App.__deprecatedInstance__.registry && App.__deprecatedInstance__.registry.lookup )
return App.__deprecatedInstance__.registry.lookup(thing); return App.__deprecatedInstance__.registry.lookup(thing);
if ( App.__container__ && App.__container__.lookup ) if ( App.__container__ && App.__container__.lookup )
return App.__container__.lookup(thing); return App.__container__.lookup(thing);
} catch(err) { } catch(err) {
FrankerFaceZ.get().error("There was an error looking up an Ember instance: " + thing, err); FrankerFaceZ.get().error("There was an error looking up an Ember instance: " + thing, err);
return null; return null;
} }
}; };
module.exports = FFZ.utils = { module.exports = FFZ.utils = {
// Ember Manipulation // Ember Manipulation
ember_views: function() { ember_views: function() {
return ember_lookup('-view-registry:main') || {}; return ember_lookup('-view-registry:main') || {};
}, },
ember_lookup: ember_lookup, ember_lookup: ember_lookup,
ember_resolve: function(thing) { ember_resolve: function(thing) {
if ( ! window.App ) if ( ! window.App )
return; return;
if ( App.__deprecatedInstance__ && App.__deprecatedInstance__.registry && App.__deprecatedInstance__.registry.resolve ) if ( App.__deprecatedInstance__ && App.__deprecatedInstance__.registry && App.__deprecatedInstance__.registry.resolve )
return App.__deprecatedInstance__.registry.resolve(thing); return App.__deprecatedInstance__.registry.resolve(thing);
if ( App.__container__ && App.__container__.resolve ) if ( App.__container__ && App.__container__.resolve )
return App.__container__.resolve(thing); return App.__container__.resolve(thing);
}, },
ember_reopen_view: function(component, data) { ember_reopen_view: function(component, data) {
if ( typeof component === 'string' ) if ( typeof component === 'string' )
component = ember_resolve(component); component = ember_resolve(component);
data.ffz_modified = true; data.ffz_modified = true;
if ( data.ffz_init && ! data.didInsertElement ) if ( data.ffz_init && ! data.didInsertElement )
data.didInsertElement = function() { data.didInsertElement = function() {
this._super(); this._super();
try { try {
this.ffz_init(); this.ffz_init();
} catch(err) { } catch(err) {
FFZ.get().error("An error occured running ffz_init on " + this.toString(), err); FFZ.get().error("An error occured running ffz_init on " + this.toString(), err);
} }
}; };
if ( data.ffz_destroy && ! data.willClearRender ) if ( data.ffz_destroy && ! data.willClearRender )
data.willClearRender = function() { data.willClearRender = function() {
try { try {
this.ffz_destroy(); this.ffz_destroy();
} catch(err) { } catch(err) {
FFZ.get().error("An error occured running ffz_destroy on " + this.toString(), err); FFZ.get().error("An error occured running ffz_destroy on " + this.toString(), err);
} }
this._super(); this._super();
}; };
return component.reopen(data); return component.reopen(data);
}, },
// Other Stuff // Other Stuff
@ -324,15 +324,15 @@ module.exports = FFZ.utils = {
/*build_tooltip: build_tooltip, /*build_tooltip: build_tooltip,
load_emote_data: load_emote_data,*/ load_emote_data: load_emote_data,*/
api: { api: {
del: function(u,d,o,t) { return api_call('del', u,d,o,t); }, del: function(u,d,o,t) { return api_call('del', u,d,o,t); },
get: function(u,d,o,t) { return api_call('get', u,d,o,t); }, get: function(u,d,o,t) { return api_call('get', u,d,o,t); },
post: function(u,d,o,t) { return api_call('post', u,d,o,t); }, post: function(u,d,o,t) { return api_call('post', u,d,o,t); },
put: function(u,d,o,t) { return api_call('put', u,d,o,t); } put: function(u,d,o,t) { return api_call('put', u,d,o,t); }
}, },
show_modal: show_modal, show_modal: show_modal,
confirm: function(title, description, callback) { confirm: function(title, description, callback) {
var contents = createElement('div', 'text-content'), var contents = createElement('div', 'text-content'),
heading = title ? createElement('div', 'content-header', '<h4>' + title + '</h4>') : null, heading = title ? createElement('div', 'content-header', '<h4>' + title + '</h4>') : null,
@ -340,7 +340,7 @@ module.exports = FFZ.utils = {
buttons = createElement('div', 'buttons', '<a class="js-subwindow-close button"><span>Cancel</span></a><button class="button primary" type="submit"><span>OK</span></button>'), buttons = createElement('div', 'buttons', '<a class="js-subwindow-close button"><span>Cancel</span></a><button class="button primary" type="submit"><span>OK</span></button>'),
close_btn = buttons.querySelector('.js-subwindow-close'), close_btn = buttons.querySelector('.js-subwindow-close'),
okay_btn = buttons.querySelector('.button.primary'); okay_btn = buttons.querySelector('.button.primary');
if ( heading ) if ( heading )
contents.appendChild(heading); contents.appendChild(heading);
@ -368,21 +368,21 @@ module.exports = FFZ.utils = {
closer = show_modal(contents, cb); closer = show_modal(contents, cb);
okay_btn.addEventListener('click', function(e) { e.preventDefault(); cb(true); return false }); okay_btn.addEventListener('click', function(e) { e.preventDefault(); cb(true); return false });
close_btn.addEventListener('click', function(e) { e.preventDefault(); cb(false); return false }); close_btn.addEventListener('click', function(e) { e.preventDefault(); cb(false); return false });
}, },
prompt: function(title, description, old_value, callback, width, input) { prompt: function(title, description, old_value, callback, width, input) {
var contents = createElement('div', 'text-content'), var contents = createElement('div', 'text-content'),
heading = createElement('div', 'content-header', '<h4>' + title + '</h4>'), heading = createElement('div', 'content-header', '<h4>' + title + '</h4>'),
form = createElement('form'), form = createElement('form'),
close_btn, okay_btn; close_btn, okay_btn;
if ( ! input ) { if ( ! input ) {
input = createElement('input'); input = createElement('input');
input.type = 'text'; input.type = 'text';
} }
form.innerHTML = '<div class="item">' + (description ? '<p>' + description + '</p>' : '') + '<div class="input-placeholder"></div><div class="buttons"><a class="js-subwindow-close button"><span>Cancel</span></a><button class="button primary" type="submit"><span>OK</span></button></div>'; form.innerHTML = '<div class="item">' + (description ? '<p>' + description + '</p>' : '') + '<div class="input-placeholder"></div><div class="buttons"><a class="js-subwindow-close button"><span>Cancel</span></a><button class="button primary" type="submit"><span>OK</span></button></div>';
var ph = form.querySelector('.input-placeholder'), var ph = form.querySelector('.input-placeholder'),
par = ph.parentElement; par = ph.parentElement;
@ -390,54 +390,54 @@ module.exports = FFZ.utils = {
par.insertBefore(input, ph); par.insertBefore(input, ph);
par.removeChild(ph); par.removeChild(ph);
contents.appendChild(heading); contents.appendChild(heading);
contents.appendChild(form); contents.appendChild(form);
close_btn = form.querySelector('.js-subwindow-close'); close_btn = form.querySelector('.js-subwindow-close');
okay_btn = form.querySelector('.button.primary'); okay_btn = form.querySelector('.button.primary');
if ( old_value !== undefined ) if ( old_value !== undefined )
input.value = old_value; input.value = old_value;
var closer, var closer,
cb = function(success) { cb = function(success) {
closer(); closer();
if ( ! callback ) if ( ! callback )
return; return;
callback(success ? input.value : null); callback(success ? input.value : null);
}; };
closer = show_modal(contents, cb, width); closer = show_modal(contents, cb, width);
try { try {
input.focus(); input.focus();
} catch(err) { } } catch(err) { }
form.addEventListener('submit', function(e) { e.preventDefault(); cb(true); return false }); form.addEventListener('submit', function(e) { e.preventDefault(); cb(true); return false });
okay_btn.addEventListener('click', function(e) { e.preventDefault(); cb(true); return false }); okay_btn.addEventListener('click', function(e) { e.preventDefault(); cb(true); return false });
close_btn.addEventListener('click', function(e) { e.preventDefault(); cb(false); return false }); close_btn.addEventListener('click', function(e) { e.preventDefault(); cb(false); return false });
}, },
last_minute: function() { last_minute: function() {
var now = new Date(); var now = new Date();
if ( now.getSeconds() >= 30 ) if ( now.getSeconds() >= 30 )
now.setMinutes(now.getMinutes()+1); now.setMinutes(now.getMinutes()+1);
now.setSeconds(0); now.setSeconds(0);
now.setMilliseconds(0); now.setMilliseconds(0);
return now.getTime(); return now.getTime();
}, },
maybe_chart: function(series, point, render, force) { maybe_chart: function(series, point, render, force) {
var len = series.data.length; var len = series.data.length;
if ( force || point.y !== null || (len > 0 && series.data[len-1].y !== null) ) { if ( force || point.y !== null || (len > 0 && series.data[len-1].y !== null) ) {
series.addPoint(point, render); series.addPoint(point, render);
return true; return true;
} }
return false; return false;
}, },
update_css: function(element, id, css) { update_css: function(element, id, css) {
var all = element.innerHTML, var all = element.innerHTML,
@ -462,16 +462,16 @@ module.exports = FFZ.utils = {
tooltip_placement: function(margin, prefer) { tooltip_placement: function(margin, prefer) {
return function() { return function() {
var pref = prefer; var pref = prefer;
if ( typeof pref === "function" ) if ( typeof pref === "function" )
pref = pref.call(this); pref = pref.call(this);
var dir = {ns: pref[0], ew: (pref.length > 1 ? pref[1] : false)}, var dir = {ns: pref[0], ew: (pref.length > 1 ? pref[1] : false)},
$this = $(this), $this = $(this),
half_width = $this.width() / 2, half_width = $this.width() / 2,
half_height = $this.height() / 2, half_height = $this.height() / 2,
boundTop = $(document).scrollTop() + half_height + (margin*2), boundTop = $(document).scrollTop() + half_height + (margin*2),
boundLeft = $(document).scrollLeft() + half_width + margin; boundLeft = $(document).scrollLeft() + half_width + margin;
if ($this.offset().top < boundTop) dir.ns = 'n'; if ($this.offset().top < boundTop) dir.ns = 'n';
if ($this.offset().left < boundLeft) dir.ew = 'w'; if ($this.offset().left < boundLeft) dir.ew = 'w';
@ -486,7 +486,7 @@ module.exports = FFZ.utils = {
uncompressEmotes: uncompressEmotes, uncompressEmotes: uncompressEmotes,
emoji_to_codepoint: emoji_to_codepoint, emoji_to_codepoint: emoji_to_codepoint,
codepoint_to_emoji: codepoint_to_emoji, codepoint_to_emoji: codepoint_to_emoji,
parse_date: parse_date, parse_date: parse_date,