1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-10 08:10:52 +00:00

Added nice following tooltips to the sidebar. Shift-clicking emotes in the menu works now. Fixed color code bugs on non-ember. Fixed DDoS prevention nonsense.

This commit is contained in:
SirStendec 2015-08-02 02:41:03 -04:00
parent 08ad23ec02
commit 9ece18ec0f
12 changed files with 737 additions and 421 deletions

519
script.js

File diff suppressed because it is too large Load diff

16
script.min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -46,7 +46,7 @@ FFZ.settings_info.fix_color = {
on_update: function(val) { on_update: function(val) {
document.body.classList.toggle("ffz-chat-colors-gray", !this.has_bttv && (val === '-1')); document.body.classList.toggle("ffz-chat-colors-gray", !this.has_bttv && (val === '-1'));
if ( ! this.has_bttv && val !== '-1' ) if ( ! this.has_bttv && val !== '-1' )
this._rebuild_colors(); this._rebuild_colors();
} }
@ -62,7 +62,7 @@ FFZ.settings_info.luv_contrast = {
name: "Username Colors - Luv Minimum Contrast", name: "Username Colors - Luv Minimum Contrast",
help: "Set the minimum contrast ratio used by Luv Adjustment to ensure colors are readable.", help: "Set the minimum contrast ratio used by Luv Adjustment to ensure colors are readable.",
method: function() { method: function() {
var old_val = this.settings.luv_contrast, var old_val = this.settings.luv_contrast,
new_val = prompt("Luv Adjustment Minimum Contrast Ratio\n\nPlease enter a new value for the minimum contrast ratio required between username colors and the background. The default is: 4.5", old_val); new_val = prompt("Luv Adjustment Minimum Contrast Ratio\n\nPlease enter a new value for the minimum contrast ratio required between username colors and the background. The default is: 4.5", old_val);
@ -73,10 +73,10 @@ FFZ.settings_info.luv_contrast = {
var parsed = parseFloat(new_val); var parsed = parseFloat(new_val);
if ( parsed === NaN || parsed < 1 ) if ( parsed === NaN || parsed < 1 )
parsed = 4.5; parsed = 4.5;
this.settings.set("luv_contrast", parsed); this.settings.set("luv_contrast", parsed);
}, },
on_update: function(val) { on_update: function(val) {
this._rebuild_contrast(); this._rebuild_contrast();
@ -116,19 +116,19 @@ FFZ.settings_info.color_blind = {
FFZ.prototype.setup_colors = function() { FFZ.prototype.setup_colors = function() {
this._colors = {}; this._colors = {};
this._rebuild_contrast(); this._rebuild_contrast();
this._update_colors(); this._update_colors();
// Events for rebuilding colors. // Events for rebuilding colors.
var Layout = App.__container__.lookup('controller:layout'), var Layout = window.App && App.__container__.lookup('controller:layout'),
Settings = App.__container__.lookup('controller:settings'); Settings = window.App && App.__container__.lookup('controller:settings');
if ( Layout ) if ( Layout )
Layout.addObserver("isTheatreMode", this._update_colors.bind(this, true)); Layout.addObserver("isTheatreMode", this._update_colors.bind(this, true));
if ( Settings ) if ( Settings )
Settings.addObserver("model.darkMode", this._update_colors.bind(this, true)) Settings.addObserver("model.darkMode", this._update_colors.bind(this, true))
this._color_old_darkness = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('model.darkMode')); this._color_old_darkness = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('model.darkMode'));
} }
@ -196,13 +196,13 @@ RGBColor.fromHex = function(code) {
RGBColor.fromHSV = function(h, s, v) { RGBColor.fromHSV = function(h, s, v) {
var r, g, b, var r, g, b,
i = Math.floor(h * 6), i = Math.floor(h * 6),
f = h * 6 - i, f = h * 6 - i,
p = v * (1 - s), p = v * (1 - s),
q = v * (1 - f * s), q = v * (1 - f * s),
t = v * (1 - (1 - f) * s); t = v * (1 - (1 - f) * s);
switch(i % 6) { switch(i % 6) {
case 0: r = v, g = t, b = p; break; case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break; case 1: r = q, g = v, b = p; break;
@ -211,7 +211,7 @@ RGBColor.fromHSV = function(h, s, v) {
case 4: r = t, g = p, b = v; break; case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; case 5: r = v, g = p, b = q;
} }
return new RGBColor( return new RGBColor(
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)),
@ -240,12 +240,12 @@ RGBColor.fromHSL = function(h, s, l) {
var q = l < 0.5 ? l * (1 + s) : l + s - l * s, var q = l < 0.5 ? l * (1 + s) : l + s - l * s,
p = 2 * l - q; p = 2 * l - q;
return new RGBColor( return new RGBColor(
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))
); );
} }
RGBColor.prototype.toHSV = function() { return HSVColor.fromRGB(this.r, this.g, this.b); } RGBColor.prototype.toHSV = function() { return HSVColor.fromRGB(this.r, this.g, this.b); }
@ -254,7 +254,7 @@ RGBColor.prototype.toCSS = function() { return "rgb(" + Math.round(this.r) + ","
RGBColor.prototype.toXYZ = function() { return XYZColor.fromRGB(this.r, this.g, this.b); } RGBColor.prototype.toXYZ = function() { return XYZColor.fromRGB(this.r, this.g, this.b); }
RGBColor.prototype.toLUV = function() { return this.toXYZ().toLUV(); } RGBColor.prototype.toLUV = function() { return this.toXYZ().toLUV(); }
RGBColor.prototype.toHex = function() { RGBColor.prototype.toHex = function() {
var rgb = this.b | (this.g << 8) | (this.r << 16); var rgb = this.b | (this.g << 8) | (this.r << 16);
return '#' + (0x1000000 + rgb).toString(16).slice(1); return '#' + (0x1000000 + rgb).toString(16).slice(1);
} }
@ -276,7 +276,7 @@ RGBColor.prototype.luminance = function() {
RGBColor.prototype.brighten = function(amount) { RGBColor.prototype.brighten = function(amount) {
amount = typeof amount === "number" ? amount : 1; amount = typeof amount === "number" ? amount : 1;
amount = Math.round(255 * (amount / 100)); amount = Math.round(255 * (amount / 100));
return new RGBColor( return new RGBColor(
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)),
@ -292,10 +292,10 @@ RGBColor.prototype.daltonize = function(type, amount) {
if ( FFZ.Color.CVDMatrix.hasOwnProperty(type) ) if ( FFZ.Color.CVDMatrix.hasOwnProperty(type) )
cvd = FFZ.Color.CVDMatrix[type]; cvd = FFZ.Color.CVDMatrix[type];
else else
throw "Invalid CVD matrix."; throw "Invalid CVD matrix.";
} else } else
cvd = type; cvd = type;
var cvd_a = cvd[0], cvd_b = cvd[1], cvd_c = cvd[2], var cvd_a = cvd[0], cvd_b = cvd[1], cvd_c = cvd[2],
cvd_d = cvd[3], cvd_e = cvd[4], cvd_f = cvd[5], cvd_d = cvd[3], cvd_e = cvd[4], cvd_f = cvd[5],
cvd_g = cvd[6], cvd_h = cvd[7], cvd_i = cvd[8], cvd_g = cvd[6], cvd_h = cvd[7], cvd_i = cvd[8],
@ -343,7 +343,7 @@ HSLColor.prototype.eq = function(hsl) {
HSLColor.fromRGB = function(r, g, b) { HSLColor.fromRGB = function(r, g, b) {
r /= 255; g /= 255; b /= 255; r /= 255; g /= 255; b /= 255;
var max = Math.max(r,g,b), var max = Math.max(r,g,b),
min = Math.min(r,g,b), min = Math.min(r,g,b),
@ -389,15 +389,15 @@ HSVColor.prototype.eq = function(hsv) { return hsv.h === this.h && hsv.s === thi
HSVColor.fromRGB = function(r, g, b) { HSVColor.fromRGB = function(r, g, b) {
r /= 255; g /= 255; b /= 255; r /= 255; g /= 255; b /= 255;
var max = Math.max(r, g, b), var max = Math.max(r, g, b),
min = Math.min(r, g, b), min = Math.min(r, g, b),
d = Math.min(Math.max(0, max - min), 1), d = Math.min(Math.max(0, max - min), 1),
h, h,
s = max === 0 ? 0 : d / max, s = max === 0 ? 0 : d / max,
v = max; v = max;
if ( d === 0 ) if ( d === 0 )
h = 0; h = 0;
else { else {
@ -413,7 +413,7 @@ HSVColor.fromRGB = function(r, g, b) {
} }
h /= 6; h /= 6;
} }
return new HSVColor(h, s, v); return new HSVColor(h, s, v);
} }
@ -560,25 +560,25 @@ FFZ.prototype._rebuild_colors = function() {
FFZ.prototype._update_colors = function(darkness_only) { FFZ.prototype._update_colors = function(darkness_only) {
// Update the lines. ALL of them. // Update the lines. ALL of them.
var Layout = App.__container__.lookup('controller:layout'), var Layout = window.App && App.__container__.lookup('controller:layout'),
Settings = App.__container__.lookup('controller:settings'), Settings = window.App && App.__container__.lookup('controller:settings'),
is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('model.darkMode')); is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('model.darkMode'));
if ( darkness_only && this._color_old_darkness === is_dark ) if ( darkness_only && this._color_old_darkness === is_dark )
return; return;
this._color_old_darkness = is_dark; this._color_old_darkness = is_dark;
var colored_bits = document.querySelectorAll('.chat-line .has-color'); var colored_bits = document.querySelectorAll('.chat-line .has-color');
for(var i=0, l=colored_bits.length; i < l; i++) { for(var i=0, l=colored_bits.length; i < l; i++) {
var bit = colored_bits[i], var bit = colored_bits[i],
color = bit.getAttribute('data-color'), color = bit.getAttribute('data-color'),
colors = color && this._handle_color(color); colors = color && this._handle_color(color);
if ( ! colors ) if ( ! colors )
continue; continue;
bit.style.color = is_dark ? colors[1] : colors[0]; bit.style.color = is_dark ? colors[1] : colors[0];
} }
} }
@ -589,7 +589,7 @@ FFZ.prototype._handle_color = function(color) {
return this._colors[color]; return this._colors[color];
var rgb = RGBColor.fromHex(color), var rgb = RGBColor.fromHex(color),
light_color = color, light_color = color,
dark_color = color; dark_color = color;
@ -601,20 +601,20 @@ FFZ.prototype._handle_color = function(color) {
light_color = dark_color = rgb.toHex(); light_color = dark_color = rgb.toHex();
} }
} }
// 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.toHex(); light_color = nc.toHex();
} }
@ -625,25 +625,25 @@ FFZ.prototype._handle_color = function(color) {
if ( nc.luminance() >= 0.15 ) if ( nc.luminance() >= 0.15 )
break; break;
} }
dark_color = nc.toHex(); dark_color = nc.toHex();
} }
} }
// Color Processing - HSL // Color Processing - HSL
if ( this.settings.fix_color === '2' ) { if ( this.settings.fix_color === '2' ) {
var hsl = rgb.toHSL(); var hsl = rgb.toHSL();
light_color = hsl._l(Math.min(Math.max(0, 0.7 * hsl.l), 1)).toHex(); light_color = hsl._l(Math.min(Math.max(0, 0.7 * hsl.l), 1)).toHex();
dark_color = hsl._l(Math.min(Math.max(0, 0.3 + (0.7 * hsl.l)), 1)).toHex(); dark_color = hsl._l(Math.min(Math.max(0, 0.3 + (0.7 * hsl.l)), 1)).toHex();
} }
// Color Processing - HSV // Color Processing - HSV
if ( this.settings.fix_color === '3' ) { if ( this.settings.fix_color === '3' ) {
var hsv = rgb.toHSV(); var hsv = rgb.toHSV();
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)).toRGB().toHex(); light_color = hsv._v(Math.min(Math.max(0.5, 0.5 * hsv.v), 1)).toRGB().toHex();
@ -651,21 +651,21 @@ FFZ.prototype._handle_color = function(color) {
} else { } else {
light_color = RGBColor.fromHSV(hsv.h, Math.min(Math.max(0.7, 0.7 + (0.3 * hsv.s)), 1), Math.min(0.7, hsv.v)).toHex(); light_color = RGBColor.fromHSV(hsv.h, Math.min(Math.max(0.7, 0.7 + (0.3 * hsv.s)), 1), Math.min(0.7, hsv.v)).toHex();
dark_color = RGBColor.fromHSV(hsv.h, Math.min(0.7, hsv.s), Math.min(Math.max(0.7, 0.7 + (0.3 * hsv.v)), 1)).toHex(); dark_color = RGBColor.fromHSV(hsv.h, Math.min(0.7, hsv.s), Math.min(Math.max(0.7, 0.7 + (0.3 * hsv.v)), 1)).toHex();
} }
} }
// Color Processing - LUV // Color Processing - LUV
if ( this.settings.fix_color === '1' ) { if ( this.settings.fix_color === '1' ) {
var luv = rgb.toLUV(); var luv = rgb.toLUV();
if ( luv.l > this._luv_required_dark ) if ( luv.l > this._luv_required_dark )
light_color = luv._l(this._luv_required_dark).toRGB().toHex(); light_color = luv._l(this._luv_required_dark).toRGB().toHex();
if ( luv.l < this._luv_required_bright ) if ( luv.l < this._luv_required_bright )
dark_color = luv._l(this._luv_required_bright).toRGB().toHex(); dark_color = luv._l(this._luv_required_bright).toRGB().toHex();
} }
var out = this._colors[color] = [light_color, dark_color]; var out = this._colors[color] = [light_color, dark_color];
return out; return out;
} }

View file

@ -59,6 +59,8 @@ module.exports = {
CAMERA: '<svg class="svg-camera" height="16px" version="1.1" viewBox="0 0 36 36" width="16px" x="0px" y="0px"><path fill-rule="evenodd" clip-rule="evenodd" d="M24,20v6H4V10h20v6l8-6v16L24,20z"/></svg>', CAMERA: '<svg class="svg-camera" height="16px" version="1.1" viewBox="0 0 36 36" width="16px" x="0px" y="0px"><path fill-rule="evenodd" clip-rule="evenodd" d="M24,20v6H4V10h20v6l8-6v16L24,20z"/></svg>',
INVITE: '<svg class="svg-plus" height="16px" version="1.1" viewBox="0 0 16 16" width="16px" x="0px" y="0px"><path clip-rule="evenodd" d="M15,9h-3v3h-2V9H7V7h3V4h2v3h3V9z M9,6H6v4h2h1v3h4l0,0l0,0v1h-3H4H1v-1l3-3h2L4,8V2h6v1H9V6z" fill-rule="evenodd"></path></svg>', INVITE: '<svg class="svg-plus" height="16px" version="1.1" viewBox="0 0 16 16" width="16px" x="0px" y="0px"><path clip-rule="evenodd" d="M15,9h-3v3h-2V9H7V7h3V4h2v3h3V9z M9,6H6v4h2h1v3h4l0,0l0,0v1h-3H4H1v-1l3-3h2L4,8V2h6v1H9V6z" fill-rule="evenodd"></path></svg>',
LIVE: '<svg class="svg-glyph_live_small" height="16px" version="1.1" viewbox="0 0 16 16" width="13px" x="0px" y="0px"><path clip-rule="evenodd" d="M11,14H5H2v-1l3-3h2L5,8V2h6v6l-2,2h2l3,3v1H11z" fill-rule="evenodd"></path></svg>',
EYE: '<svg class="svg-glyph_views ffz-svg svg-eye" height="16px" version="1.1" viewBox="0 0 16 16" width="16px" x="0px" y="0px"><path clip-rule="evenodd" d="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" fill-rule="evenodd"></path></svg>', EYE: '<svg class="svg-glyph_views ffz-svg svg-eye" height="16px" version="1.1" viewBox="0 0 16 16" width="16px" x="0px" y="0px"><path clip-rule="evenodd" d="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" fill-rule="evenodd"></path></svg>',
CLOCK: '<svg class="svg-glyph_views ffz-svg svg-clock" height="16px" version="1.1" viewBox="0 0 16 16" width="16px" x="0px" y="0px"><path fill-rule="evenodd" clip-rule="evenodd" fill="#888888" d="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"/></svg>', CLOCK: '<svg class="svg-glyph_views ffz-svg svg-clock" height="16px" version="1.1" viewBox="0 0 16 16" width="16px" x="0px" y="0px"><path fill-rule="evenodd" clip-rule="evenodd" fill="#888888" d="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"/></svg>',
GEAR: '<svg class="svg-gear" height="16px" version="1.1" viewBox="0 0 16 16" width="16px" x="0px" y="0px"><path clip-rule="evenodd" d="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" fill-rule="evenodd"></path></svg>', GEAR: '<svg class="svg-gear" height="16px" version="1.1" viewBox="0 0 16 16" width="16px" x="0px" y="0px"><path clip-rule="evenodd" d="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" fill-rule="evenodd"></path></svg>',

View file

@ -36,7 +36,7 @@ FFZ.settings_info.line_purge_icon = {
name: "Purge Icon in Mod Icons", name: "Purge Icon in Mod Icons",
help: "Display a Purge Icon in chat line Mod Icons for quickly purging users.", help: "Display a Purge Icon in chat line Mod Icons for quickly purging users.",
on_update: function(val) { on_update: function(val) {
if ( this.has_bttv ) if ( this.has_bttv )
return; return;
@ -49,10 +49,10 @@ FFZ.settings_info.line_purge_icon = {
FFZ.settings_info.replace_bad_emotes = { FFZ.settings_info.replace_bad_emotes = {
type: "boolean", type: "boolean",
value: true, value: true,
category: "Chat Appearance", category: "Chat Appearance",
no_bttv: true, no_bttv: true,
name: "Fix Low Quality Twitch Global Emoticons", name: "Fix Low Quality Twitch Global Emoticons",
help: "Replace emoticons such as DansGame and RedCoat with cleaned up versions that don't have pixels around the edges or white backgrounds for nicer display on dark chat." help: "Replace emoticons such as DansGame and RedCoat with cleaned up versions that don't have pixels around the edges or white backgrounds for nicer display on dark chat."
} }
@ -240,11 +240,11 @@ FFZ.settings_info.link_image_hover = {
FFZ.settings_info.image_hover_all_domains = { FFZ.settings_info.image_hover_all_domains = {
type: "boolean", type: "boolean",
value: false, value: false,
category: "Chat Tooltips", category: "Chat Tooltips",
no_bttv: true, no_bttv: true,
no_mobile: true, no_mobile: true,
name: "Image Preview - All Domains", name: "Image Preview - All Domains",
help: "<i>Requires Image Preview.</i> Attempt to show an image preview for any URL ending in the appropriate extension. <b>Warning: This may be used to leak your IP address to malicious users.</b>" help: "<i>Requires Image Preview.</i> Attempt to show an image preview for any URL ending in the appropriate extension. <b>Warning: This may be used to leak your IP address to malicious users.</b>"
}; };
@ -288,7 +288,7 @@ FFZ.settings_info.chat_separators = {
category: "Chat Appearance", category: "Chat Appearance",
no_bttv: true, no_bttv: true,
process_value: function(val) { process_value: function(val) {
if ( val === false ) if ( val === false )
return '0'; return '0';
@ -305,8 +305,8 @@ FFZ.settings_info.chat_separators = {
document.body.classList.toggle("ffz-chat-separator-3d", !this.has_bttv && val === '2'); document.body.classList.toggle("ffz-chat-separator-3d", !this.has_bttv && val === '2');
} }
}; };
FFZ.settings_info.chat_padding = { FFZ.settings_info.chat_padding = {
type: "boolean", type: "boolean",
value: false, value: false,
@ -377,7 +377,7 @@ FFZ.settings_info.chat_font_size = {
var parsed = parseInt(new_val); var parsed = parseInt(new_val);
if ( ! parsed || parsed === NaN || parsed < 1 ) if ( ! parsed || parsed === NaN || parsed < 1 )
parsed = 12; parsed = 12;
this.settings.set("chat_font_size", parsed); this.settings.set("chat_font_size", parsed);
}, },
@ -414,10 +414,10 @@ FFZ.settings_info.chat_ts_size = {
method: function() { method: function() {
var old_val = this.settings.chat_ts_size; var old_val = this.settings.chat_ts_size;
if ( ! old_val ) if ( ! old_val )
old_val = this.settings.chat_font_size; old_val = this.settings.chat_font_size;
var new_val = prompt("Chat Timestamp Font Size\n\nPlease enter a new size for the chat timestamp font. The default is to match the regular chat font size.", old_val); var new_val = prompt("Chat Timestamp Font Size\n\nPlease enter a new size for the chat timestamp font. The default is to match the regular chat font size.", old_val);
if ( new_val === null || new_val === undefined ) if ( new_val === null || new_val === undefined )
@ -426,7 +426,7 @@ FFZ.settings_info.chat_ts_size = {
var parsed = parseInt(new_val); var parsed = parseInt(new_val);
if ( ! parsed || parsed === NaN || parsed < 1 ) if ( ! parsed || parsed === NaN || parsed < 1 )
parsed = null; parsed = null;
this.settings.set("chat_ts_size", parsed); this.settings.set("chat_ts_size", parsed);
}, },
@ -456,7 +456,7 @@ FFZ.prototype.setup_line = function() {
jQuery(document.body).on("mouseleave", ".tipsy", function() { jQuery(document.body).on("mouseleave", ".tipsy", function() {
this.parentElement.removeChild(this); this.parentElement.removeChild(this);
}); });
// Aliases // Aliases
try { try {
this.aliases = JSON.parse(localStorage.ffz_aliases || '{}'); this.aliases = JSON.parse(localStorage.ffz_aliases || '{}');
@ -464,29 +464,29 @@ FFZ.prototype.setup_line = function() {
this.log("Error Loading Aliases: " + err); this.log("Error Loading Aliases: " + err);
this.aliases = {}; this.aliases = {};
} }
// Chat Style // Chat Style
var s = this._chat_style = document.createElement('style'); var s = this._chat_style = document.createElement('style');
s.id = "ffz-style-chat"; s.id = "ffz-style-chat";
s.type = 'text/css'; s.type = 'text/css';
document.head.appendChild(s); document.head.appendChild(s);
// Initial calculation. // Initial calculation.
FFZ.settings_info.chat_font_size.on_update.bind(this)(this.settings.chat_font_size); FFZ.settings_info.chat_font_size.on_update.bind(this)(this.settings.chat_font_size);
// Chat Enhancements // Chat Enhancements
document.body.classList.toggle("ffz-chat-colors", !this.has_bttv && this.settings.fix_color !== '-1'); document.body.classList.toggle("ffz-chat-colors", !this.has_bttv && this.settings.fix_color !== '-1');
document.body.classList.toggle("ffz-chat-colors-gray", !this.has_bttv && this.settings.fix_color === '-1'); document.body.classList.toggle("ffz-chat-colors-gray", !this.has_bttv && this.settings.fix_color === '-1');
document.body.classList.toggle("ffz-legacy-badges", this.settings.legacy_badges); document.body.classList.toggle("ffz-legacy-badges", this.settings.legacy_badges);
document.body.classList.toggle('ffz-chat-background', !this.has_bttv && this.settings.chat_rows); document.body.classList.toggle('ffz-chat-background', !this.has_bttv && this.settings.chat_rows);
document.body.classList.toggle("ffz-chat-separator", !this.has_bttv && this.settings.chat_separators !== '0'); document.body.classList.toggle("ffz-chat-separator", !this.has_bttv && this.settings.chat_separators !== '0');
document.body.classList.toggle("ffz-chat-separator-3d", !this.has_bttv && this.settings.chat_separators === '2'); document.body.classList.toggle("ffz-chat-separator-3d", !this.has_bttv && this.settings.chat_separators === '2');
document.body.classList.toggle("ffz-chat-padding", !this.has_bttv && this.settings.chat_padding); document.body.classList.toggle("ffz-chat-padding", !this.has_bttv && this.settings.chat_padding);
document.body.classList.toggle("ffz-chat-purge-icon", !this.has_bttv && this.settings.line_purge_icon); document.body.classList.toggle("ffz-chat-purge-icon", !this.has_bttv && this.settings.line_purge_icon);
document.body.classList.toggle("ffz-high-contrast-chat-text", !this.has_bttv && this.settings.high_contrast_chat[2] === '1'); document.body.classList.toggle("ffz-high-contrast-chat-text", !this.has_bttv && this.settings.high_contrast_chat[2] === '1');
document.body.classList.toggle("ffz-high-contrast-chat-bold", !this.has_bttv && this.settings.high_contrast_chat[1] === '1'); document.body.classList.toggle("ffz-high-contrast-chat-bold", !this.has_bttv && this.settings.high_contrast_chat[1] === '1');
document.body.classList.toggle("ffz-high-contrast-chat-bg", !this.has_bttv && this.settings.high_contrast_chat[0] === '1'); document.body.classList.toggle("ffz-high-contrast-chat-bg", !this.has_bttv && this.settings.high_contrast_chat[0] === '1');
@ -521,7 +521,7 @@ FFZ.prototype.save_aliases = function() {
FFZ.prototype._modify_line = function(component) { FFZ.prototype._modify_line = function(component) {
var f = this, var f = this,
Layout = App.__container__.lookup('controller:layout'), Layout = App.__container__.lookup('controller:layout'),
Settings = App.__container__.lookup('controller:settings'); Settings = App.__container__.lookup('controller:settings');
@ -573,22 +573,22 @@ FFZ.prototype._modify_line = function(component) {
ffzUpdated: Ember.observer("msgObject.ffz_deleted", "msgObject.ffz_old_messages", function() { ffzUpdated: Ember.observer("msgObject.ffz_deleted", "msgObject.ffz_old_messages", function() {
this.rerender(); this.rerender();
}), }),
click: function(e) { click: function(e) {
if ( e.target && e.target.classList.contains('ffz-old-messages') ) if ( e.target && e.target.classList.contains('ffz-old-messages') )
return f._show_deleted(this.get('msgObject.room')); return f._show_deleted(this.get('msgObject.room'));
if ( e.target && e.target.classList.contains('deleted-link') ) if ( e.target && e.target.classList.contains('deleted-link') )
return f._deleted_link_click.bind(e.target)(e); return f._deleted_link_click.bind(e.target)(e);
if ( e.target && e.target.classList.contains('mod-icon') ) { if ( e.target && e.target.classList.contains('mod-icon') ) {
jQuery(e.target).trigger('mouseout'); jQuery(e.target).trigger('mouseout');
if ( e.target.classList.contains('purge') ) { if ( e.target.classList.contains('purge') ) {
var i = this.get('msgObject.from'), var i = this.get('msgObject.from'),
room_id = this.get('msgObject.room'), room_id = this.get('msgObject.room'),
room = room_id && f.rooms[room_id] && f.rooms[room_id].room; room = room_id && f.rooms[room_id] && f.rooms[room_id].room;
if ( room ) { if ( room ) {
room.send("/timeout " + i + " 1"); room.send("/timeout " + i + " 1");
room.clearMessages(i); room.clearMessages(i);
@ -596,7 +596,7 @@ FFZ.prototype._modify_line = function(component) {
return; return;
} }
} }
if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons && e.target && e.target.classList.contains('emoticon') ) { if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons && e.target && e.target.classList.contains('emoticon') ) {
var eid = e.target.getAttribute('data-emote'); var eid = e.target.getAttribute('data-emote');
if ( eid ) if ( eid )
@ -606,10 +606,10 @@ FFZ.prototype._modify_line = function(component) {
window.open("https://www.frankerfacez.com/emoticons/" + eid); window.open("https://www.frankerfacez.com/emoticons/" + eid);
} }
} }
return this._super(e); return this._super(e);
}, },
ffzUserLevel: function() { ffzUserLevel: function() {
if ( this.get('isStaff') ) if ( this.get('isStaff') )
return 5; return 5;
@ -623,27 +623,27 @@ FFZ.prototype._modify_line = function(component) {
return 1; return 1;
return 0; return 0;
}.property('msgObject.labels.[]'), }.property('msgObject.labels.[]'),
render: function(e) { render: function(e) {
var deleted = this.get('msgObject.deleted'), var deleted = this.get('msgObject.deleted'),
r = this, r = this,
badges = {}, badges = {},
user = this.get('msgObject.from'), user = this.get('msgObject.from'),
room_id = this.get('msgObject.room'), room_id = this.get('msgObject.room'),
room = f.rooms && f.rooms[room_id], room = f.rooms && f.rooms[room_id],
recipient = this.get('msgObject.to'), recipient = this.get('msgObject.to'),
is_whisper = recipient && recipient.length, is_whisper = recipient && recipient.length,
this_ul = this.get('ffzUserLevel'), this_ul = this.get('ffzUserLevel'),
other_ul = room && room.room && room.room.get('ffzUserLevel') || 0, other_ul = room && room.room && room.room.get('ffzUserLevel') || 0,
row_type = this.get('msgObject.ffz_alternate'), row_type = this.get('msgObject.ffz_alternate'),
raw_color = this.get('msgObject.color'), raw_color = this.get('msgObject.color'),
colors = raw_color && f._handle_color(raw_color), colors = raw_color && f._handle_color(raw_color),
is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('model.darkMode')); is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('model.darkMode'));
if ( row_type === undefined ) { if ( row_type === undefined ) {
@ -653,19 +653,19 @@ FFZ.prototype._modify_line = function(component) {
e.push('<div class="indicator"></div>'); e.push('<div class="indicator"></div>');
e.push('<span class="timestamp float-left">' + this.get("timestamp") + '</span> '); e.push('<span class="timestamp float-left">' + this.get("timestamp") + '</span> ');
if ( ! is_whisper && this_ul < other_ul ) { if ( ! is_whisper && this_ul < other_ul ) {
e.push('<span class="mod-icons float-left">'); e.push('<span class="mod-icons float-left">');
if ( deleted ) if ( deleted )
e.push('<a class="mod-icon float-left tooltip unban" title="Unban User" href="#">Unban</a>'); e.push('<a class="mod-icon float-left tooltip unban" title="Unban User" href="#">Unban</a>');
else else
e.push('<a class="mod-icon float-left tooltip ban" title="Ban User" href="#">Ban</a>'); e.push('<a class="mod-icon float-left tooltip ban" title="Ban User" href="#">Ban</a>');
e.push('<a class="mod-icon float-left tooltip timeout" title="Timeout User (10m)" href="#">Timeout</a>'); e.push('<a class="mod-icon float-left tooltip timeout" title="Timeout User (10m)" href="#">Timeout</a>');
e.push('<a class="mod-icon float-left tooltip purge" title="Purge User (Timeout 1s)" href="#">Purge</a>'); e.push('<a class="mod-icon float-left tooltip purge" title="Purge User (Timeout 1s)" href="#">Purge</a>');
e.push('</span>'); e.push('</span>');
} }
// Stock Badges // Stock Badges
if ( ! is_whisper && this.get('isBroadcaster') ) if ( ! is_whisper && this.get('isBroadcaster') )
badges[0] = {klass: 'broadcaster', title: 'Broadcaster'}; badges[0] = {klass: 'broadcaster', title: 'Broadcaster'};
@ -677,7 +677,7 @@ FFZ.prototype._modify_line = function(component) {
badges[0] = {klass: 'global-moderator', title: 'Global Moderator'}; badges[0] = {klass: 'global-moderator', title: 'Global Moderator'};
else if ( ! is_whisper && this.get('isModerator') ) else if ( ! is_whisper && this.get('isModerator') )
badges[0] = {klass: 'moderator', title: 'Moderator'}; badges[0] = {klass: 'moderator', title: 'Moderator'};
if ( ! is_whisper && this.get('isSubscriber') ) if ( ! is_whisper && this.get('isSubscriber') )
badges[10] = {klass: 'subscriber', title: 'Subscriber'}; badges[10] = {klass: 'subscriber', title: 'Subscriber'};
if ( this.get('hasTurbo') ) if ( this.get('hasTurbo') )
@ -692,10 +692,10 @@ FFZ.prototype._modify_line = function(component) {
for(var key in badges) { for(var key in badges) {
var badge = badges[key], var badge = badges[key],
css = badge.image ? 'background-image:url(&quot;' + badge.image + '&quot;);' : ''; css = badge.image ? 'background-image:url(&quot;' + badge.image + '&quot;);' : '';
if ( badge.color ) if ( badge.color )
css += 'background-color:' + badge.color + ';'; css += 'background-color:' + badge.color + ';';
if ( badge.extra_css ) if ( badge.extra_css )
css += badge.extra_css; css += badge.extra_css;
@ -703,11 +703,11 @@ FFZ.prototype._modify_line = function(component) {
} }
e.push('</span>'); e.push('</span>');
var alias = f.aliases[user], var alias = f.aliases[user],
name = this.get('msgObject.tags.display-name') || (user && user.capitalize()) || "unknown user", name = this.get('msgObject.tags.display-name') || (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' : '';
if ( alias ) if ( alias )
e.push('<span class="from ffz-alias tooltip' + colored + '" style="' + style + (colors ? '" data-color="' + raw_color : '') + '" title="' + utils.sanitize(name) + '">' + utils.sanitize(alias) + '</span>'); e.push('<span class="from ffz-alias tooltip' + colored + '" style="' + style + (colors ? '" data-color="' + raw_color : '') + '" title="' + utils.sanitize(name) + '">' + utils.sanitize(alias) + '</span>');
@ -717,14 +717,14 @@ FFZ.prototype._modify_line = function(component) {
if ( is_whisper ) { if ( is_whisper ) {
var to_alias = f.aliases[recipient], var to_alias = f.aliases[recipient],
to_name = this.get('msgObject.tags.recipient-display-name') || (recipient && recipient.capitalize()) || "unknown user", to_name = this.get('msgObject.tags.recipient-display-name') || (recipient && recipient.capitalize()) || "unknown user",
to_color = this.get('msgObject.toColor'), to_color = this.get('msgObject.toColor'),
to_colors = to_color && f._handle_color(to_color), to_colors = to_color && f._handle_color(to_color),
to_style = to_color && 'color:' + (is_dark ? to_colors[1] : to_colors[0]), to_style = to_color && 'color:' + (is_dark ? to_colors[1] : to_colors[0]),
to_colored = to_style ? ' has-color' : ''; to_colored = to_style ? ' has-color' : '';
this._renderWhisperArrow(e); this._renderWhisperArrow(e);
if ( to_alias ) if ( to_alias )
e.push('<span class="to ffz-alias tooltip' + to_colored + '" style="' + to_style + (to_color ? '" data-color="' + to_color : '') + '" title="' + utils.sanitize(to_name) + '">' + utils.sanitize(to_alias) + '</span>'); e.push('<span class="to ffz-alias tooltip' + to_colored + '" style="' + to_style + (to_color ? '" data-color="' + to_color : '') + '" title="' + utils.sanitize(to_name) + '">' + utils.sanitize(to_alias) + '</span>');
else else
@ -732,26 +732,26 @@ FFZ.prototype._modify_line = function(component) {
} }
e.push('<span class="colon">:</span> '); e.push('<span class="colon">:</span> ');
if ( this.get('msgObject.style') !== 'action' ) { if ( this.get('msgObject.style') !== 'action' ) {
style = ''; style = '';
colored = ''; colored = '';
} }
if ( deleted ) if ( deleted )
e.push('<span class="deleted"><a class="undelete" href="#">&lt;message deleted&gt;</a></span>'); e.push('<span class="deleted"><a class="undelete" href="#">&lt;message deleted&gt;</a></span>');
else { else {
e.push('<span class="message' + colored + '" style="' + style + '">'); e.push('<span class="message' + colored + '" style="' + style + '">');
e.push(f.render_tokens(this.get('tokenizedMessage'), true)); e.push(f.render_tokens(this.get('tokenizedMessage'), true));
var old_messages = this.get('msgObject.ffz_old_messages'); var old_messages = this.get('msgObject.ffz_old_messages');
if ( old_messages && old_messages.length ) if ( old_messages && old_messages.length )
e.push('<div class="button primary float-right ffz-old-messages">Show ' + utils.number_commas(old_messages.length) + ' Old</div>'); e.push('<div class="button primary float-right ffz-old-messages">Show ' + utils.number_commas(old_messages.length) + ' Old</div>');
e.push('</span>'); e.push('</span>');
} }
}, },
classNameBindings: [ classNameBindings: [
'msgObject.ffz_alternate:ffz-alternate', 'msgObject.ffz_alternate:ffz-alternate',
'msgObject.ffz_has_mention:ffz-mentioned', 'msgObject.ffz_has_mention:ffz-mentioned',
@ -759,12 +759,12 @@ FFZ.prototype._modify_line = function(component) {
'ffzHasOldMessages:clearfix', 'ffzHasOldMessages:clearfix',
'ffzHasOldMessages:ffz-has-deleted' 'ffzHasOldMessages:ffz-has-deleted'
], ],
ffzWasDeleted: function() { ffzWasDeleted: function() {
return f.settings.prevent_clear && this.get('msgObject.ffz_deleted'); return f.settings.prevent_clear && this.get('msgObject.ffz_deleted');
}.property('msgObject.ffz_deleted'), }.property('msgObject.ffz_deleted'),
ffzHasOldMessages: function() { ffzHasOldMessages: function() {
var old_messages = this.get('msgObject.ffz_old_messages'); var old_messages = this.get('msgObject.ffz_old_messages');
return old_messages && old_messages.length; return old_messages && old_messages.length;
@ -773,7 +773,7 @@ FFZ.prototype._modify_line = function(component) {
didInsertElement: function() { didInsertElement: function() {
this._super(); this._super();
var el = this.get('element'); var el = this.get('element');
el.setAttribute('data-room', this.get('msgObject.room')); el.setAttribute('data-room', this.get('msgObject.room'));

View file

@ -49,22 +49,8 @@ FFZ.prototype._emote_menu_enumerator = function() {
if ( emote.hidden ) if ( emote.hidden )
continue; continue;
// TODO: Stop having to calculate this here. var title = "FrankerFaceZ " + set.title,
var title = set.title, badge = set.icon || null; badge = set.icon || '//cdn.frankerfacez.com/script/devicon.png';
if ( ! title ) {
if ( set.id === "global" )
title = "FrankerFaceZ Global Emotes";
else if ( set.id == "globalevent" )
title = "FrankerFaceZ Event Emotes";
else if ( this.feature_friday && set.id == this.feature_friday.set )
title = "FrankerFaceZ " + this.feature_friday.title + ": " + this.feature_friday.display_name;
else
title = "FrankerFaceZ Set: " + FFZ.get_capitalization(set.id);
} else
title = "FrankerFaceZ: " + title;
emotes.push({text: emote.name, url: emote.urls[1], emotes.push({text: emote.name, url: emote.urls[1],
hidden: false, channel: title, badge: badge}); hidden: false, channel: title, badge: badge});

View file

@ -21,7 +21,7 @@ FFZ.get = function() { return FFZ.instance; }
// Version // Version
var VER = FFZ.version_info = { var VER = FFZ.version_info = {
major: 3, minor: 5, revision: 8, major: 3, minor: 5, revision: 10,
toString: function() { toString: function() {
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
} }
@ -169,7 +169,7 @@ FFZ.prototype.initialize = function(increment, delay) {
this.init_normal(delay); this.init_normal(delay);
return; return;
} }
if ( location.hostname === 'passport' && /^\/(?:authorize)/.test(location.pathname) ) { if ( location.hostname === 'passport' && /^\/(?:authorize)/.test(location.pathname) ) {
this.log("Running on passport!"); this.log("Running on passport!");
this.init_normal(delay, true); this.init_normal(delay, true);

View file

@ -2,6 +2,7 @@ var FFZ = window.FrankerFaceZ;
FFZ.prototype._ws_open = false; FFZ.prototype._ws_open = false;
FFZ.prototype._ws_delay = 0; FFZ.prototype._ws_delay = 0;
FFZ.prototype._ws_last_iframe = 0;
FFZ.ws_commands = {}; FFZ.ws_commands = {};
FFZ.ws_on_close = []; FFZ.ws_on_close = [];
@ -11,6 +12,22 @@ FFZ.ws_on_close = [];
// Socket Creation // Socket Creation
// ---------------- // ----------------
FFZ.prototype.ws_iframe = function() {
this._ws_last_iframe = Date.now();
var ifr = document.createElement('iframe'),
f = this;
ifr.src = 'http://catbag.frankerfacez.com';
ifr.style.visibility = 'hidden';
document.body.appendChild(ifr);
setTimeout(function() {
document.body.removeChild(ifr);
if ( ! f._ws_open )
f.ws_create();
}, 2000);
}
FFZ.prototype.ws_create = function() { FFZ.prototype.ws_create = function() {
var f = this, ws; var f = this, ws;
@ -30,6 +47,7 @@ FFZ.prototype.ws_create = function() {
ws.onopen = function(e) { ws.onopen = function(e) {
f._ws_open = true; f._ws_open = true;
f._ws_delay = 0; f._ws_delay = 0;
f._ws_last_iframe = Date.now();
f.log("Socket connected."); f.log("Socket connected.");
// Check for incognito. We don't want to do a hello in incognito mode. // Check for incognito. We don't want to do a hello in incognito mode.
@ -106,6 +124,12 @@ FFZ.prototype.ws_create = function() {
} }
} }
if ( f._ws_delay > 10000 ) {
var ua = navigator.userAgent.toLowerCase();
if ( Date.now() - f._ws_last_iframe > 1800000 && !(ua.indexOf('chrome') === -1 && ua.indexOf('safari') !== -1) )
return f.ws_iframe();
}
// We never ever want to not have a socket. // We never ever want to not have a socket.
if ( f._ws_delay < 60000 ) if ( f._ws_delay < 60000 )
f._ws_delay += (Math.floor(Math.random()*10) + 5) * 1000; f._ws_delay += (Math.floor(Math.random()*10) + 5) * 1000;

View file

@ -1,5 +1,6 @@
var FFZ = window.FrankerFaceZ, var FFZ = window.FrankerFaceZ,
utils = require('../utils'); utils = require('../utils'),
constants = require('../constants');
@ -16,7 +17,7 @@ FFZ.settings_info.following_count = {
on_update: function(val) { on_update: function(val) {
this._schedule_following_count(); this._schedule_following_count();
var Stream = window.App && App.__container__.resolve('model:stream'), var Stream = window.App && App.__container__.resolve('model:stream'),
Live = Stream && Stream.find("live"); Live = Stream && Stream.find("live");
@ -35,7 +36,7 @@ FFZ.prototype.setup_following_count = function(has_ember) {
// Start it updating. // Start it updating.
if ( this.settings.following_count ) if ( this.settings.following_count )
this._schedule_following_count(); this._schedule_following_count();
// If we don't have Ember, no point in trying this stuff. // If we don't have Ember, no point in trying this stuff.
if ( ! has_ember ) if ( ! has_ember )
return this._update_following_count(); return this._update_following_count();
@ -52,11 +53,17 @@ FFZ.prototype.setup_following_count = function(has_ember) {
return this.log("Unable to find Live Streams collection."); return this.log("Unable to find Live Streams collection.");
Live.addObserver('total', function() { f._draw_following_count(this.get('total')); }); Live.addObserver('total', function() { f._draw_following_count(this.get('total')); });
Live.addObserver('content.length', function() { f._draw_following_channels(this.get('content'), this.get('total')); })
Live.load(); Live.load();
var total = Live.get('total'); var total = Live.get('total'),
if ( typeof total === "number" ) streams = Live.get('content');
if ( typeof total === "number" ) {
this._draw_following_count(total); this._draw_following_count(total);
if ( streams && streams.length )
this._draw_following_channels(streams, total);
}
} }
@ -84,7 +91,7 @@ FFZ.prototype._update_following_count = function() {
} }
this._following_count_timer = setTimeout(this._update_following_count.bind(this), 55000 + (10000*Math.random())); this._following_count_timer = setTimeout(this._update_following_count.bind(this), 55000 + (10000*Math.random()));
var Stream = window.App && App.__container__.resolve('model:stream'), var Stream = window.App && App.__container__.resolve('model:stream'),
Live = Stream && Stream.find("live"), Live = Stream && Stream.find("live"),
f = this; f = this;
@ -92,15 +99,84 @@ FFZ.prototype._update_following_count = function() {
if ( Live ) if ( Live )
Live.load(); Live.load();
else else
Twitch.api && Twitch.api.get("streams/followed", {limit:1, offset:0}, {version:3}) Twitch.api && Twitch.api.get("streams/followed", {limit:5, offset:0}, {version:3})
.done(function(data) { .done(function(data) {
f._draw_following_count(data._total); f._draw_following_count(data._total);
f._draw_following_channels(data.streams, data._total);
}).fail(function() { }).fail(function() {
f._draw_following_count(); f._draw_following_count();
f._draw_following_channels();
}) })
} }
FFZ.prototype._draw_following_channels = function(streams, total) {
// First, build the data.
var tooltip = 'Following';
if ( streams && streams.length ) {
var c = 0;
for(var i=0, l = streams.length; i < l; i++) {
var stream = streams[i];
if ( ! stream || ! stream.channel )
continue;
c += 1;
if ( c > 5 ) {
var ttl = total || streams.length;
tooltip += '<hr><span>And ' + utils.number_commas(ttl - 5) + ' more...</span>';
break;
}
tooltip += (i > 0 ? '<br>' : '<hr>') + '<span class="viewers">' + constants.LIVE + ' ' + utils.number_commas(stream.viewers) + '</span><b>' + utils.sanitize(stream.channel.display_name || stream.channel.name) + '</b><br><span class="playing">' + (stream.channel.game ? 'Playing ' + utils.sanitize(stream.channel.game) : 'Not Playing') + '</span>';
}
}
// Small
var small_following = jQuery('#small_nav ul.game_filters li[data-name="following"] a');
if ( small_following && small_following.length ) {
var data = small_following.data('tipsy');
if ( data && data.options ) {
data.options.gravity = function() { return this.parentElement.getAttribute('data-name') === 'following' ? 'nw': 'w'; };
data.options.html = true;
data.options.className = 'ffz-wide-tip';
} else
small_following.tipsy({html: true, className: 'ffz-wide-tip', gravity: 'nw'});
small_following.attr('title', tooltip);
}
// Large
var large_following = jQuery('#large_nav #nav_personal li[data-name="following"] a');
if ( large_following && large_following.length ) {
var data = large_following.data('tipsy');
if ( data && data.options ) {
data.options.html = true;
data.options.className = 'ffz-wide-tip';
} else
large_following.tipsy({html:true, className: 'ffz-wide-tip'});
large_following.attr('title', tooltip);
}
// Heading
var head_following = jQuery('#header_actions #header_following');
if ( head_following && head_following.length ) {
var data = head_following.data('tipsy');
if ( data && data.options ) {
data.options.html = true;
data.options.className = 'ffz-wide-tip';
} else
head_following.tipsy({html: true, className: 'ffz-wide-tip'});
head_following.attr('title', tooltip);
}
}
FFZ.prototype._draw_following_count = function(count) { FFZ.prototype._draw_following_count = function(count) {
// Small // Small
var small_following = document.querySelector('#small_nav ul.game_filters li[data-name="following"] a'); var small_following = document.querySelector('#small_nav ul.game_filters li[data-name="following"] a');
@ -118,8 +194,8 @@ FFZ.prototype._draw_following_count = function(count) {
badge.innerHTML = count ? utils.format_unread(count) : ''; badge.innerHTML = count ? utils.format_unread(count) : '';
} }
} }
// Large // Large
var large_following = document.querySelector('#large_nav #nav_personal li[data-name="following"] a'); var large_following = document.querySelector('#large_nav #nav_personal li[data-name="following"] a');
if ( large_following ) { if ( large_following ) {
@ -136,7 +212,7 @@ FFZ.prototype._draw_following_count = function(count) {
badge.innerHTML = count ? utils.format_unread(count) : ''; badge.innerHTML = count ? utils.format_unread(count) : '';
} }
} }
// Heading // Heading
var head_following = document.querySelector('#header_actions #header_following'); var head_following = document.querySelector('#header_actions #header_following');
if ( head_following ) { if ( head_following ) {

View file

@ -3,16 +3,32 @@ var FFZ = window.FrankerFaceZ,
utils = require('../utils'), utils = require('../utils'),
TWITCH_BASE = "http://static-cdn.jtvnw.net/emoticons/v1/", TWITCH_BASE = "http://static-cdn.jtvnw.net/emoticons/v1/",
fix_menu_position = function(container) { fix_menu_position = function(container) {
var swapped = document.body.classList.contains('ffz-sidebar-swap');
var bounds = container.getBoundingClientRect(), var bounds = container.getBoundingClientRect(),
left = parseInt(container.style.left || '0'), left = parseInt(container.style.left || '0'),
right = bounds.left + container.scrollWidth; right = bounds.left + container.scrollWidth,
moved = !!container.style.left;
if ( bounds.left < 0 )
container.style.left = (left - bounds.left) + 'px'; if ( swapped ) {
else if ( right > document.body.clientWidth ) if ( bounds.left < 20 ) {
container.style.left = (left - (right - document.body.clientWidth)) + 'px'; container.style.left = '';
moved = false;
} else if ( right > document.body.clientWidth )
container.style.left = (left - (right - document.body.clientWidth)) + 'px';
} else {
if ( bounds.left < 0 )
container.style.left = (left - bounds.left) + 'px';
else if ( right > (document.body.clientWidth - 20) ) {
container.style.left = '';
moved = false;
}
}
container.classList.toggle('ui-moved', moved);
}; };
@ -29,7 +45,7 @@ FFZ.prototype.setup_menu = function() {
if ( ! popup ) return; if ( ! popup ) return;
if ( popup.id === 'ffz-chat-menu' && popup.style && popup.style.left ) if ( popup.id === 'ffz-chat-menu' && popup.style && popup.style.left )
return; return;
popup = jQuery(popup); popup = jQuery(popup);
parent = popup.parent(); parent = popup.parent();
@ -221,7 +237,31 @@ FFZ.prototype.build_ui_popup = function(view) {
var heading = document.createElement('li'); var heading = document.createElement('li');
heading.className = 'title'; heading.className = 'title';
heading.innerHTML = "<span>" + (constants.DEBUG ? "[DEV] " : "") + "FrankerFaceZ</span>"; heading.innerHTML = '<span class="title">Franker' + (constants.DEBUG ? 'Dev' : 'Face') + 'Z</span>';
// Close Button
var close_btn = document.createElement('span'),
f = this;
close_btn.className = 'ffz-handle ffz-close-button';
heading.insertBefore(close_btn, heading.firstChild);
var can_close = false;
close_btn.addEventListener('mousedown', function() {
var popup = f._popup;
can_close = popup && popup.id === "ffz-chat-menu" && popup.style.left;
});
close_btn.addEventListener('click', function() {
var popup = f._popup;
if ( can_close && popup ) {
popup.parentElement.removeChild(popup);
delete f._popup;
f._popup_kill && f._popup_kill();
delete f._popup_kill;
}
});
menu.appendChild(heading); menu.appendChild(heading);
// Draggable // Draggable
@ -312,7 +352,7 @@ FFZ.prototype._ui_change_page = function(view, inner, menu, container, page) {
this.log("No matching page: " + page); this.log("No matching page: " + page);
FFZ.menu_pages[page].render.bind(this)(view, container, inner, menu); FFZ.menu_pages[page].render.bind(this)(view, container, inner, menu);
// Re-position if necessary. // Re-position if necessary.
var f = this; var f = this;
setTimeout(function(){f._fix_menu_position();}); setTimeout(function(){f._fix_menu_position();});
@ -328,7 +368,8 @@ FFZ.menu_pages.channel = {
// Get the current room. // Get the current room.
var room_id = view.get('controller.currentRoom.id'), var room_id = view.get('controller.currentRoom.id'),
room = this.rooms[room_id], room = this.rooms[room_id],
has_product = false; has_product = false,
f = this;
// Check for a product. // Check for a product.
if ( this.settings.replace_twitch_menu ) { if ( this.settings.replace_twitch_menu ) {
@ -351,7 +392,6 @@ FFZ.menu_pages.channel = {
// See if we've loaded. If we haven't loaded the ticket yet // See if we've loaded. If we haven't loaded the ticket yet
// then try loading it, and then re-render the menu. // then try loading it, and then re-render the menu.
if ( tickets && ! is_subscribed && ! is_loaded ) { if ( tickets && ! is_subscribed && ! is_loaded ) {
var f = this;
tickets.addObserver('isLoaded', function() { tickets.addObserver('isLoaded', function() {
setTimeout(function(){ setTimeout(function(){
if ( inner.getAttribute('data-page') !== 'channel' ) if ( inner.getAttribute('data-page') !== 'channel' )
@ -360,7 +400,7 @@ FFZ.menu_pages.channel = {
inner.innerHTML = ''; inner.innerHTML = '';
FFZ.menu_pages.channel.render.bind(f)(view, inner); FFZ.menu_pages.channel.render.bind(f)(view, inner);
},0); },0);
}); });
tickets.load(); tickets.load();
@ -395,8 +435,17 @@ FFZ.menu_pages.channel = {
s.style.width = emote.width + "px"; s.style.width = emote.width + "px";
s.style.height = emote.height + "px"; s.style.height = emote.height + "px";
s.title = emote.regex; s.title = emote.regex;
if ( can_use )
s.addEventListener('click', this._add_emote.bind(this, view, emote.regex)); s.addEventListener('click', function(can_use, id, code, e) {
if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons )
window.open("https://twitchemotes.com/emote/" + id);
else if ( can_use )
this._add_emote(view, code);
else
return;
e.preventDefault();
}.bind(this, can_use, emote.id, emote.regex));
grid.appendChild(s); grid.appendChild(s);
c++; c++;
} }
@ -475,7 +524,7 @@ FFZ.menu_pages.channel = {
// -------------------- // --------------------
FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, image, sub_text) { FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, image, sub_text) {
var grid = document.createElement('div'), c = 0; var grid = document.createElement('div'), c = 0, f = this;
grid.className = 'emoticon-grid'; grid.className = 'emoticon-grid';
if ( header != null ) { if ( header != null ) {
@ -549,7 +598,14 @@ FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, image, sub
s.style.height = emote.height + "px"; s.style.height = emote.height + "px";
s.title = this._emote_tooltip(emote); s.title = this._emote_tooltip(emote);
s.addEventListener('click', this._add_emote.bind(this, view, emote.name)); s.addEventListener('click', function(id, code, e) {
e.preventDefault();
if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons )
window.open("https://www.frankerfacez.com/emoticons/" + id);
else
this._add_emote(view, code);
}.bind(this, emote.id, emote.name));
grid.appendChild(s); grid.appendChild(s);
} }

View file

@ -79,53 +79,10 @@ FFZ.menu_pages.myemotes = {
render: function(view, container) { render: function(view, container) {
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'];
needed_sets = [];
for(var set_id in twitch_sets) // We don't have to do async stuff anymore cause we pre-load data~!
if ( twitch_sets.hasOwnProperty(set_id) && ! this._twitch_set_to_channel.hasOwnProperty(set_id) ) return FFZ.menu_pages.myemotes.draw_menu.bind(this)(view, container, twitch_sets);
needed_sets.push(set_id);
if ( ! needed_sets.length )
return FFZ.menu_pages.myemotes.draw_menu.bind(this)(view, container, twitch_sets);
var f = this,
fail = function() {
if ( ! needed_sets.length )
return;
needed_sets = [];
var ts = {};
for(var set_id in twitch_sets)
if ( f._twitch_set_to_channel[set_id] )
ts[set_id] = twitch_sets[set_id];
else
ts[set_id] = []; //"twitch_unknown";
return FFZ.menu_pages.myemotes.draw_menu.bind(f)(view, container, ts);
};
if ( ! this.ws_send("twitch_sets", needed_sets, function(success, data) {
if ( ! needed_sets.length )
return;
needed_sets = [];
if ( success ) {
for(var set_id in data) {
if ( ! data.hasOwnProperty(set_id) )
continue;
f._twitch_set_to_channel[set_id] = data[set_id];
}
localStorage.ffzTwitchSets = JSON.stringify(f._twitch_set_to_channel);
return FFZ.menu_pages.my_emotes.draw_menu.bind(f)(view, container, twitch_sets);
} else
fail();
}) )
fail()
else
setTimeout(fail, 2000);
}, },
toggle_section: function(heading) { toggle_section: function(heading) {
@ -154,15 +111,15 @@ FFZ.menu_pages.myemotes = {
menu.className = 'emoticon-grid collapsable'; menu.className = 'emoticon-grid collapsable';
menu.appendChild(heading); menu.appendChild(heading);
menu.setAttribute('data-set', 'emoji'); menu.setAttribute('data-set', 'emoji');
menu.classList.toggle('collapsed', this.settings.emote_menu_collapsed.indexOf('emoji') !== -1); menu.classList.toggle('collapsed', this.settings.emote_menu_collapsed.indexOf('emoji') !== -1);
heading.addEventListener('click', function() { FFZ.menu_pages.myemotes.toggle_section.bind(f)(this); }); heading.addEventListener('click', function() { FFZ.menu_pages.myemotes.toggle_section.bind(f)(this); });
var set = []; var set = [];
for(var eid in this.emoji_data) for(var eid in this.emoji_data)
set.push(this.emoji_data[eid]); set.push(this.emoji_data[eid]);
set.sort(function(a,b) { set.sort(function(a,b) {
var an = a.short_name.toLowerCase(), var an = a.short_name.toLowerCase(),
bn = b.short_name.toLowerCase(); bn = b.short_name.toLowerCase();
@ -173,7 +130,7 @@ FFZ.menu_pages.myemotes = {
if ( a.raw > b.raw ) return 1; if ( a.raw > b.raw ) return 1;
return 0; return 0;
}); });
for(var i=0; i < set.length; i++) { for(var i=0; i < set.length; i++) {
var emoji = set[i], var emoji = set[i],
em = document.createElement('span'), em = document.createElement('span'),
@ -182,13 +139,13 @@ FFZ.menu_pages.myemotes = {
em.className = 'emoticon tooltip'; em.className = 'emoticon tooltip';
em.title = 'Emoji: ' + emoji.raw + '\nName: :' + emoji.short_name + ':'; em.title = 'Emoji: ' + emoji.raw + '\nName: :' + emoji.short_name + ':';
em.addEventListener('click', this._add_emote.bind(this, view, emoji.raw)); em.addEventListener('click', this._add_emote.bind(this, view, emoji.raw));
em.style.backgroundImage = 'url("' + emoji.src + '")'; em.style.backgroundImage = 'url("' + emoji.src + '")';
em.style.backgroundImage = '-webkit-' + img_set; em.style.backgroundImage = '-webkit-' + img_set;
em.style.backgroundImage = '-moz-' + img_set; em.style.backgroundImage = '-moz-' + img_set;
em.style.backgroundImage = '-ms-' + img_set; em.style.backgroundImage = '-ms-' + img_set;
em.style.backgroudnImage = img_set; em.style.backgroudnImage = img_set;
menu.appendChild(em); menu.appendChild(em);
} }
@ -268,7 +225,13 @@ FFZ.menu_pages.myemotes = {
} }
em.title = code; em.title = code;
em.addEventListener("click", this._add_emote.bind(this, view, code)); em.addEventListener("click", function(id, code, e) {
e.preventDefault();
if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons )
window.open("https://twitchemotes.com/emote/" + id);
else
this._add_emote(view, code);
}.bind(this, emote.id, emote.code));
menu.appendChild(em); menu.appendChild(em);
} }
@ -287,7 +250,7 @@ FFZ.menu_pages.myemotes = {
menu.className = 'emoticon-grid collapsable'; menu.className = 'emoticon-grid collapsable';
menu.appendChild(heading); menu.appendChild(heading);
menu.setAttribute('data-set', 'ffz-' + set.id); menu.setAttribute('data-set', 'ffz-' + set.id);
menu.classList.toggle('collapsed', this.settings.emote_menu_collapsed.indexOf('ffz-' + set.id) !== -1); menu.classList.toggle('collapsed', this.settings.emote_menu_collapsed.indexOf('ffz-' + set.id) !== -1);
heading.addEventListener('click', function() { FFZ.menu_pages.myemotes.toggle_section.bind(f)(this); }); heading.addEventListener('click', function() { FFZ.menu_pages.myemotes.toggle_section.bind(f)(this); });
@ -333,7 +296,13 @@ FFZ.menu_pages.myemotes = {
em.style.width = emote.width + "px"; em.style.width = emote.width + "px";
em.title = this._emote_tooltip(emote); em.title = this._emote_tooltip(emote);
em.addEventListener("click", this._add_emote.bind(this, view, emote.name)); em.addEventListener("click", function(id, code, e) {
e.preventDefault();
if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons )
window.open("https://www.frankerfacez.com/emoticons/" + id);
else
this._add_emote(view, code);
}.bind(this, emote.id, emote.name));
menu.appendChild(em); menu.appendChild(em);
} }

106
style.css
View file

@ -579,12 +579,85 @@ body:not(.ffz-minimal-chat):not(.ffz-menu-replace) .emoticon-selector-toggle + s
float: left; float: left;
} }
.ffz-ui-popup ul.menu li.title > span { span.ffz-handle {
display: block; display: inline-block;
padding: 10px 20px; position: relative;
line-height: 16px; height: 26px;
width: 14px;
transition: width 500ms;
} }
span.ffz-handle:before,
span.ffz-handle:after {
position: absolute;
left: 4px;
top: 5px;
content: "";
height: 14px;
border: 1px solid #bbb;
border-radius: 4px;
transition: transform 500ms, left 500ms, border-color 500ms, border-width 500ms, height 500ms;
}
span.ffz-handle:after { left: 8px }
.ffz-ui-popup.ui-moved span.ffz-handle { width: 24px; cursor: pointer; }
.ffz-ui-popup.ui-moved span.ffz-handle:before,
.ffz-ui-popup.ui-moved span.ffz-handle:after {
left: 11px;
border-color: #333;
}
.ffz-ui-popup.ui-moved span.ffz-handle:before { transform: rotate(45deg); }
.ffz-ui-popup.ui-moved span.ffz-handle:after { transform: rotate(-45deg); }
.app-main.theatre span.ffz-handle:before,
.chat-container.dark span.ffz-handle:before,
.chat-container.force-dark span.ffz-handle:before,
.ember-chat-container.dark span.ffz-handle:before,
.ember-chat-container.force-dark span.ffz-handle:before,
.ffz-ui-popup.dark span.ffz-handle:before,
.app-main.theatre span.ffz-handle:after,
.chat-container.dark span.ffz-handle:after,
.chat-container.force-dark span.ffz-handle:after,
.ember-chat-container.dark span.ffz-handle:after,
.ember-chat-container.force-dark span.ffz-handle:after,
.ffz-ui-popup.dark span.ffz-handle:after {
border-color: #666;
}
.app-main.theatre .ffz-ui-popup.ui-moved span.ffz-handle:before,
.chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:before,
.chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:before,
.ember-chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:before,
.ember-chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:before,
.ffz-ui-popup.ui-moved.dark span.ffz-handle:before,
.app-main.theatre .ffz-ui-popup.ui-moved span.ffz-handle:after,
.chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:after,
.chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:after,
.ember-chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:after,
.ember-chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:after,
.ffz-ui-popup.ui-moved.dark span.ffz-handle:after {
border-color: #d3d3d3;
}
.ffz-ui-popup ul.menu li.title > span.ffz-handle {
float: left;
margin: 5px;
}
.ffz-ui-popup ul.menu li.title > span.title {
display: block;
margin-left: 24px;
padding: 10px 20px 10px 0;
line-height: 16px;
transition: margin-left 500ms;
}
.ffz-ui-popup.ui-moved ul.menu li.title > span.title { margin-left: 34px; }
.ffz-ui-popup ul.menu a { .ffz-ui-popup ul.menu a {
display: block; display: block;
padding: 10px; padding: 10px;
@ -1006,6 +1079,23 @@ body:not(.ffz-chat-purge-icon) .ember-chat .mod-icons .purge { display: none; }
/* Emoticon Tooltips */ /* Emoticon Tooltips */
.ffz-wide-tip .tipsy-inner {
max-width: 600px;
text-align: left;
}
.ffz-wide-tip span.viewers {
float: right;
}
.ffz-wide-tip span.viewers svg {
float: left;
margin: 1px;
}
.ffz-wide-tip svg path { fill: #fff; }
.ffz-wide-tip span.playing { opacity: 0.7; }
.tipsy .tipsy-inner { .tipsy .tipsy-inner {
white-space: pre-wrap; white-space: pre-wrap;
} }
@ -1165,7 +1255,7 @@ a.unsafe-link {
.ffz-room-row:hover svg path, .ffz-room-row:hover svg path,
.ffz-room-row:focus svg path, .ffz-room-row:focus svg path,
.ffz-room-row.active svg path { fill: #fff; } .ffz-room-row.active svg path { fill: #fff; }
.ffz-room-row:hover td, .ffz-room-row:hover td,
.ffz-room-row:focus td, .ffz-room-row:focus td,
@ -1643,7 +1733,7 @@ li[data-name="following"] a {
position: absolute; position: absolute;
right: 10px; right: 10px;
top: 8px; top: 8px;
line-height: 14px; line-height: 14px;
padding: 2px 5px; padding: 2px 5px;
} }
@ -1696,12 +1786,12 @@ li[data-name="following"] a {
/* High Contrast Chat */ /* High Contrast Chat */
.ffz-high-contrast-chat-text .chat-container, .ffz-high-contrast-chat-text .chat-container,
.ffz-high-contrast-chat-text .ember-chat-container { .ffz-high-contrast-chat-text .ember-chat-container {
color: "#000"; color: "#000";
} }
.ffz-high-contrast-chat-bg .chat-container, .ffz-high-contrast-chat-bg .chat-container,
.ffz-high-contrast-chat-bg .ember-chat-container { .ffz-high-contrast-chat-bg .ember-chat-container {
background-color: #fff; background-color: #fff;
} }