mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-29 15:55:33 +00:00
Refactored colors. Fixed scrolling on mobile. Added image preview on hover.
This commit is contained in:
parent
2bc2b7003b
commit
02b0a95bd0
22 changed files with 2121 additions and 425 deletions
6
dark.css
6
dark.css
|
@ -206,12 +206,18 @@
|
|||
.ffz-dark input.text,
|
||||
.ffz-dark input.string,
|
||||
.ffz-dark textarea,
|
||||
.ffz-dark select,
|
||||
.ffz-dark option,
|
||||
.ffz-dark .directory_header #custom_filter input {
|
||||
background-color: rgba(255,255,255,0.05);
|
||||
border-color: rgba(255,255,255,0.1);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ffz-dark option {
|
||||
background-color: #191919;
|
||||
}
|
||||
|
||||
|
||||
/* Other stuff */
|
||||
|
||||
|
|
38
image-proxy.html
Normal file
38
image-proxy.html
Normal file
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
html,body{overflow:hidden; margin:0; padding:0; background:transparent; height: 100%; position: relative }
|
||||
img {
|
||||
max-width: 186px; max-height: 186px;
|
||||
position: absolute;
|
||||
top: 50%; left: 50%;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">window.onload=function(){
|
||||
var IMGUR_REGEX = /(?:https?:\/\/)?(?:i\.)?imgur\.com\/(?:gallery\/)?([A-Za-z0-9]+)(?:\.(.*))?/,
|
||||
GYAZO_REGEX = /(?:https?:\/\/)?(?:i\.)?gyazo\.com\/([a-z0-9]+)/,
|
||||
YOUTUBE_REGEX = /^(?:https?:\/\/)?(?:m\.|www\.)?youtu(?:be\.com|\.be)\/(?:v\/|watch\/|.*?(?:embed|watch).*?v=)?([a-zA-Z0-9\-_]+)$/;
|
||||
|
||||
var url = location.search.substr(1),
|
||||
image_url = url;
|
||||
imgur = url.match(IMGUR_REGEX);
|
||||
|
||||
if ( imgur )
|
||||
image_url = 'http://i.imgur.com/' + imgur[1] + 't.' + (imgur[2] || "png");
|
||||
|
||||
else {
|
||||
var yt = url.match(YOUTUBE_REGEX);
|
||||
if ( yt ) {
|
||||
image_url = 'http://img.youtube.com/vi/' + yt[1] + '/1.jpg'
|
||||
} else {
|
||||
var gyazo = url.match(GYAZO_REGEX);
|
||||
if ( gyazo )
|
||||
image_url = 'http://i.gyazo.com/' + gyazo[1] + '.png';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var el = document.createElement('img');
|
||||
el.src = image_url;
|
||||
document.body.appendChild(el);
|
||||
}</script>
|
14
script.min.js
vendored
14
script.min.js
vendored
File diff suppressed because one or more lines are too long
634
src/colors.js
Normal file
634
src/colors.js
Normal file
|
@ -0,0 +1,634 @@
|
|||
var FFZ = window.FrankerFaceZ,
|
||||
|
||||
hue2rgb = function(p, q, t) {
|
||||
if ( t < 0 ) t += 1;
|
||||
if ( t > 1 ) t -= 1;
|
||||
if ( t < 1/6 )
|
||||
return p + (q-p) * 6 * t;
|
||||
if ( t < 1/2 )
|
||||
return q;
|
||||
if ( t < 2/3 )
|
||||
return p + (q-p) * (2/3 - t) * 6;
|
||||
return p;
|
||||
};
|
||||
|
||||
|
||||
// ---------------------
|
||||
// Settings
|
||||
// ---------------------
|
||||
|
||||
FFZ.settings_info.fix_color = {
|
||||
type: "select",
|
||||
options: {
|
||||
'-1': "Disabled",
|
||||
0: "Default Colors",
|
||||
1: "Luv Adjustment",
|
||||
2: "HSL Adjustment (Depreciated)",
|
||||
3: "HSV Adjustment (Depreciated)",
|
||||
4: "RGB Adjustment (Depreciated)"
|
||||
},
|
||||
value: '1',
|
||||
|
||||
category: "Chat Appearance",
|
||||
no_bttv: true,
|
||||
|
||||
name: "Username Colors - Brightness",
|
||||
help: "Ensure that username colors contrast with the background enough to be readable.",
|
||||
|
||||
process_value: function(val) {
|
||||
// Load legacy setting.
|
||||
if ( val === false )
|
||||
return '0';
|
||||
else if ( val === true )
|
||||
return '1';
|
||||
return val;
|
||||
},
|
||||
|
||||
on_update: function(val) {
|
||||
document.body.classList.toggle("ffz-chat-colors", !this.has_bttv && val !== '-1');
|
||||
document.body.classList.toggle("ffz-chat-colors-gray", !this.has_bttv && (val === '-1'));
|
||||
|
||||
if ( ! this.has_bttv && val !== '-1' )
|
||||
this._rebuild_colors();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
FFZ.settings_info.color_blind = {
|
||||
type: "select",
|
||||
options: {
|
||||
0: "Disabled",
|
||||
protanope: "Protanope",
|
||||
deuteranope: "Deuteranope",
|
||||
tritanope: "Tritanope"
|
||||
},
|
||||
value: '0',
|
||||
|
||||
category: "Chat Appearance",
|
||||
no_bttv: true,
|
||||
|
||||
name: "Username Colors - Color Blindness",
|
||||
help: "Adjust username colors in an attempt to make them more distinct for people with color blindness.",
|
||||
|
||||
on_update: function(val) {
|
||||
if ( ! this.has_bttv && this.settings.fix_color !== '-1' )
|
||||
this._rebuild_colors();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// --------------------
|
||||
// Initialization
|
||||
// --------------------
|
||||
|
||||
FFZ.prototype.setup_colors = function() {
|
||||
this.log("Preparing color-alteration style element.");
|
||||
|
||||
this._colors = {};
|
||||
|
||||
var s = this._color_style = document.createElement('style');
|
||||
s.id = 'ffz-style-username-colors';
|
||||
s.type = 'text/css';
|
||||
document.head.appendChild(s);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------
|
||||
// Color Handling Classes
|
||||
// -----------------------
|
||||
|
||||
FFZ.Color = {};
|
||||
|
||||
FFZ.Color.CVDMatrix = {
|
||||
protanope: [ // reds are greatly reduced (1% men)
|
||||
0.0, 2.02344, -2.52581,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 1.0
|
||||
],
|
||||
deuteranope: [ // greens are greatly reduced (1% men)
|
||||
1.0, 0.0, 0.0,
|
||||
0.494207, 0.0, 1.24827,
|
||||
0.0, 0.0, 1.0
|
||||
],
|
||||
tritanope: [ // blues are greatly reduced (0.003% population)
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
-0.395913, 0.801109, 0.0
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
var RGBColor = FFZ.Color.RGB = function(r, g, b) {
|
||||
this.r = r||0; this.g = g||0; this.b = b||0;
|
||||
};
|
||||
|
||||
var HSVColor = FFZ.Color.HSV = function(h, s, v) {
|
||||
this.h = h||0; this.s = s||0; this.v = v||0;
|
||||
};
|
||||
|
||||
var HSLColor = FFZ.Color.HSL = function(h, s, l) {
|
||||
this.h = h||0; this.s = s||0; this.l = l||0;
|
||||
};
|
||||
|
||||
var XYZColor = FFZ.Color.XYZ = function(x, y, z) {
|
||||
this.x = x||0; this.y = y||0; this.z = z||0;
|
||||
};
|
||||
|
||||
var LUVColor = FFZ.Color.LUV = function(l, u, v) {
|
||||
this.l = l||0; this.u = u||0; this.v = v||0;
|
||||
};
|
||||
|
||||
|
||||
// RGB Colors
|
||||
|
||||
RGBColor.prototype.eq = function(rgb) {
|
||||
return rgb.r === this.r && rgb.g === this.g && rgb.b === this.b;
|
||||
}
|
||||
|
||||
RGBColor.fromHex = function(code) {
|
||||
var raw = parseInt(code.charAt(0) === '#' ? code.substr(1) : code, 16);
|
||||
return new RGBColor(
|
||||
(raw >> 16), // Red
|
||||
(raw >> 8 & 0x00FF), // Green
|
||||
(raw & 0x0000FF) // Blue
|
||||
)
|
||||
}
|
||||
|
||||
RGBColor.fromHSV = function(h, s, v) {
|
||||
var r, g, b,
|
||||
|
||||
i = Math.floor(h * 6),
|
||||
f = h * 6 - i,
|
||||
p = v * (1 - s),
|
||||
q = v * (1 - f * s),
|
||||
t = v * (1 - (1 - f) * s);
|
||||
|
||||
switch(i % 6) {
|
||||
case 0: r = v, g = t, b = p; break;
|
||||
case 1: r = q, g = v, b = p; break;
|
||||
case 2: r = p, g = v, b = t; break;
|
||||
case 3: r = p, g = q, b = v; break;
|
||||
case 4: r = t, g = p, b = v; break;
|
||||
case 5: r = v, g = p, b = q;
|
||||
}
|
||||
|
||||
return new RGBColor(
|
||||
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, b*255), 255))
|
||||
);
|
||||
}
|
||||
|
||||
RGBColor.fromXYZ = function(x, y, z) {
|
||||
var R = 3.240479 * x - 1.537150 * y - 0.498535 * z,
|
||||
G = -0.969256 * x + 1.875992 * y + 0.041556 * z,
|
||||
B = 0.055648 * x - 0.204043 * y + 1.057311 * z;
|
||||
|
||||
// Make sure we end up in a real color space
|
||||
return new RGBColor(
|
||||
Math.max(0, Math.min(255, 255 * XYZColor.channelConverter(R))),
|
||||
Math.max(0, Math.min(255, 255 * XYZColor.channelConverter(G))),
|
||||
Math.max(0, Math.min(255, 255 * XYZColor.channelConverter(B)))
|
||||
);
|
||||
}
|
||||
|
||||
RGBColor.fromHSL = function(h, s, l) {
|
||||
if ( s === 0 ) {
|
||||
var v = Math.round(Math.min(Math.max(0, 255*l), 255));
|
||||
return new RGBColor(v, v, v);
|
||||
}
|
||||
|
||||
var q = l < 0.5 ? l * (1 + s) : l + s - l * s,
|
||||
p = 2 * l - q;
|
||||
|
||||
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)), 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.toHSL = function() { return HSLColor.fromRGB(this.r, this.g, this.b); }
|
||||
RGBColor.prototype.toCSS = function() { return "rgb(" + Math.round(this.r) + "," + Math.round(this.g) + "," + Math.round(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.luminance = function() {
|
||||
var rgb = [this.r / 255, this.g / 255, this.b / 255];
|
||||
for (var i =0, l = rgb.length; i < l; i++) {
|
||||
if (rgb[i] <= 0.03928) {
|
||||
rgb[i] = rgb[i] / 12.92;
|
||||
} else {
|
||||
rgb[i] = Math.pow( ((rgb[i]+0.055)/1.055), 2.4 );
|
||||
}
|
||||
}
|
||||
return (0.2126 * rgb[0]) + (0.7152 * rgb[1]) + (0.0722 * rgb[2]);
|
||||
}
|
||||
|
||||
|
||||
RGBColor.prototype.brighten = function(amount) {
|
||||
amount = typeof amount === "number" ? amount : 1;
|
||||
amount = Math.round(255 * (amount / 100));
|
||||
|
||||
return new RGBColor(
|
||||
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.b + amount))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
RGBColor.prototype.daltonize = function(type, amount) {
|
||||
amount = typeof amount === "number" ? amount : 1.0;
|
||||
var cvd;
|
||||
if ( typeof type === "string" ) {
|
||||
if ( FFZ.Color.CVDMatrix.hasOwnProperty(type) )
|
||||
cvd = FFZ.Color.CVDMatrix[type];
|
||||
else
|
||||
throw "Invalid CVD matrix.";
|
||||
} else
|
||||
cvd = type;
|
||||
|
||||
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_g = cvd[6], cvd_h = cvd[7], cvd_i = cvd[8],
|
||||
|
||||
L, M, S, l, m, s, R, G, B, RR, GG, BB;
|
||||
|
||||
// RGB to LMS matrix conversion
|
||||
L = (17.8824 * this.r) + (43.5161 * this.g) + (4.11935 * this.b);
|
||||
M = (3.45565 * this.r) + (27.1554 * this.g) + (3.86714 * this.b);
|
||||
S = (0.0299566 * this.r) + (0.184309 * this.g) + (1.46709 * this.b);
|
||||
// Simulate color blindness
|
||||
l = (cvd_a * L) + (cvd_b * M) + (cvd_c * S);
|
||||
m = (cvd_d * L) + (cvd_e * M) + (cvd_f * S);
|
||||
s = (cvd_g * L) + (cvd_h * M) + (cvd_i * S);
|
||||
// LMS to RGB matrix conversion
|
||||
R = (0.0809444479 * l) + (-0.130504409 * m) + (0.116721066 * s);
|
||||
G = (-0.0102485335 * l) + (0.0540193266 * m) + (-0.113614708 * s);
|
||||
B = (-0.000365296938 * l) + (-0.00412161469 * m) + (0.693511405 * s);
|
||||
// Isolate invisible colors to color vision deficiency (calculate error matrix)
|
||||
R = this.r - R;
|
||||
G = this.g - G;
|
||||
B = this.b - B;
|
||||
// Shift colors towards visible spectrum (apply error modifications)
|
||||
RR = (0.0 * R) + (0.0 * G) + (0.0 * B);
|
||||
GG = (0.7 * R) + (1.0 * G) + (0.0 * B);
|
||||
BB = (0.7 * R) + (0.0 * G) + (1.0 * B);
|
||||
// Add compensation to original values
|
||||
R = Math.min(Math.max(0, RR + this.r), 255);
|
||||
G = Math.min(Math.max(0, GG + this.g), 255);
|
||||
B = Math.min(Math.max(0, BB + this.b), 255);
|
||||
|
||||
return new RGBColor(R, G, B);
|
||||
}
|
||||
|
||||
RGBColor.prototype._r = function(r) { return new RGBColor(r, this.g, this.b); }
|
||||
RGBColor.prototype._g = function(g) { return new RGBColor(this.r, g, this.b); }
|
||||
RGBColor.prototype._b = function(b) { return new RGBColor(this.r, this.g, b); }
|
||||
|
||||
|
||||
// HSL Colors
|
||||
|
||||
HSLColor.prototype.eq = function(hsl) {
|
||||
return hsl.h === this.h && hsl.s === this.s && hsl.l === this.l;
|
||||
}
|
||||
|
||||
HSLColor.fromRGB = function(r, g, b) {
|
||||
r /= 255; g /= 255; b /= 255;
|
||||
|
||||
var max = Math.max(r,g,b),
|
||||
min = Math.min(r,g,b),
|
||||
|
||||
h, s, l = Math.min(Math.max(0, (max+min) / 2), 1),
|
||||
d = Math.min(Math.max(0, max - min), 1);
|
||||
|
||||
if ( d === 0 )
|
||||
h = s = 0;
|
||||
else {
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
switch(max) {
|
||||
case r:
|
||||
h = (g - b) / d + (g < b ? 6 : 0);
|
||||
break;
|
||||
case g:
|
||||
h = (b - r) / d + 2;
|
||||
break;
|
||||
case b:
|
||||
h = (r - g) / d + 4;
|
||||
}
|
||||
h /= 6;
|
||||
}
|
||||
|
||||
return new HSLColor(h, s, l);
|
||||
}
|
||||
|
||||
HSLColor.prototype.toRGB = function() { return RGBColor.fromHSL(this.h, this.s, this.l); }
|
||||
HSLColor.prototype.toCSS = function() { return "hsl(" + Math.round(this.h*360) + "," + Math.round(this.s*100) + "%," + Math.round(this.l*100) + "%)"; }
|
||||
HSLColor.prototype.toHSV = function() { return RGBColor.fromHSL(this.h, this.s, this.l).toHSV(); }
|
||||
HSLColor.prototype.toXYZ = function() { return RGBColor.fromHSL(this.h, this.s, this.l).toXYZ(); }
|
||||
HSLColor.prototype.toLUV = function() { return RGBColor.fromHSL(this.h, this.s, this.l).toLUV(); }
|
||||
|
||||
|
||||
HSLColor.prototype._h = function(h) { return new HSLColor(h, this.s, this.l); }
|
||||
HSLColor.prototype._s = function(s) { return new HSLColor(this.h, s, this.l); }
|
||||
HSLColor.prototype._l = function(l) { return new HSLColor(this.h, this.s, l); }
|
||||
|
||||
|
||||
// HSV Colors
|
||||
|
||||
HSVColor.prototype.eq = function(hsv) { return hsv.h === this.h && hsv.s === this.s && hsv.v === this.v; }
|
||||
|
||||
HSVColor.fromRGB = function(r, g, b) {
|
||||
r /= 255; g /= 255; b /= 255;
|
||||
|
||||
var max = Math.max(r, g, b),
|
||||
min = Math.min(r, g, b),
|
||||
d = Math.min(Math.max(0, max - min), 1),
|
||||
|
||||
h,
|
||||
s = max === 0 ? 0 : d / max,
|
||||
v = max;
|
||||
|
||||
if ( d === 0 )
|
||||
h = 0;
|
||||
else {
|
||||
switch(max) {
|
||||
case r:
|
||||
h = (g - b) / d + (g < b ? 6 : 0);
|
||||
break;
|
||||
case g:
|
||||
h = (b - r) / d + 2;
|
||||
break;
|
||||
case b:
|
||||
h = (r - g) / d + 4;
|
||||
}
|
||||
h /= 6;
|
||||
}
|
||||
|
||||
return new HSVColor(h, s, v);
|
||||
}
|
||||
|
||||
|
||||
HSVColor.prototype.toRGB = function() { return RGBColor.fromHSV(this.h, this.s, this.v); }
|
||||
HSVColor.prototype.toHSL = function() { return RGBColor.fromHSV(this.h, this.s, this.v).toHSL(); }
|
||||
HSVColor.prototype.toXYZ = function() { return RGBColor.fromHSV(this.h, this.s, this.v).toXYZ(); }
|
||||
HSVColor.prototype.toLUV = function() { return RGBColor.fromHSV(this.h, this.s, this.v).toLUV(); }
|
||||
|
||||
|
||||
HSVColor.prototype._h = function(h) { return new HSVColor(h, this.s, this.v); }
|
||||
HSVColor.prototype._s = function(s) { return new HSVColor(this.h, s, this.v); }
|
||||
HSVColor.prototype._v = function(v) { return new HSVColor(this.h, this.s, v); }
|
||||
|
||||
|
||||
// XYZ Colors
|
||||
|
||||
RGBColor.channelConverter = function (channel) {
|
||||
// http://www.brucelindbloom.com/Eqn_RGB_to_XYZ.html
|
||||
// This converts rgb 8bit to rgb linear, lazy because the other algorithm is really really dumb
|
||||
return Math.pow(channel, 2.2);
|
||||
|
||||
// CSS Colors Level 4 says 0.03928, Bruce Lindbloom who cared to write all algos says 0.04045, used bruce because whynawt
|
||||
return (channel <= 0.04045) ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4);
|
||||
};
|
||||
|
||||
XYZColor.channelConverter = function (channel) {
|
||||
// Using lazy conversion in the other direction as well
|
||||
return Math.pow(channel, 1/2.2);
|
||||
|
||||
// I'm honestly not sure about 0.0031308, I've only seen it referenced on Bruce Lindbloom's site
|
||||
return (channel <= 0.0031308) ? channel * 12.92 : Math.pow(1.055 * channel, 1/2.4) - 0.055;
|
||||
};
|
||||
|
||||
|
||||
XYZColor.prototype.eq = function(xyz) { return xyz.x === this.x && xyz.y === this.y && xyz.z === this.z; }
|
||||
|
||||
XYZColor.fromRGB = function(r, g, b) {
|
||||
var R = RGBColor.channelConverter(r / 255),
|
||||
G = RGBColor.channelConverter(g / 255),
|
||||
B = RGBColor.channelConverter(b / 255);
|
||||
|
||||
return new XYZColor(
|
||||
0.412453 * R + 0.357580 * G + 0.180423 * B,
|
||||
0.212671 * R + 0.715160 * G + 0.072169 * B,
|
||||
0.019334 * R + 0.119193 * G + 0.950227 * B
|
||||
);
|
||||
}
|
||||
|
||||
XYZColor.fromLUV = function(l, u, v) {
|
||||
var deltaGammaFactor = 1 / (XYZColor.WHITE.x + 15 * XYZColor.WHITE.y + 3 * XYZColor.WHITE.z);
|
||||
var uDeltaGamma = 4 * XYZColor.WHITE.x * deltaGammaFactor;
|
||||
var vDeltagamma = 9 * XYZColor.WHITE.y * deltaGammaFactor;
|
||||
|
||||
// XYZColor.EPSILON * XYZColor.KAPPA = 8
|
||||
var Y = (l > 8) ? Math.pow((l + 16) / 116, 3) : l / XYZColor.KAPPA;
|
||||
|
||||
var a = 1/3 * (((52 * l) / (u + 13 * l * uDeltaGamma)) - 1);
|
||||
var b = -5 * Y;
|
||||
var c = -1/3;
|
||||
var d = Y * (((39 * l) / (v + 13 * l * vDeltagamma)) - 5);
|
||||
|
||||
var X = (d - b) / (a - c);
|
||||
var Z = X * a + b;
|
||||
|
||||
return new XYZColor(X, Y, Z);
|
||||
}
|
||||
|
||||
|
||||
XYZColor.prototype.toRGB = function() { return RGBColor.fromXYZ(this.x, this.y, this.z); }
|
||||
XYZColor.prototype.toLUV = function() { return LUVColor.fromXYZ(this.x, this.y, this.z); }
|
||||
XYZColor.prototype.toHSL = function() { return RGBColor.fromXYZ(this.x, this.y, this.z).toHSL(); }
|
||||
XYZColor.prototype.toHSV = function() { return RGBColor.fromXYZ(this.x, this.y, this.z).toHSV(); }
|
||||
|
||||
|
||||
XYZColor.prototype._x = function(x) { return new XYZColor(x, this.y, this.z); }
|
||||
XYZColor.prototype._y = function(y) { return new XYZColor(this.x, y, this.z); }
|
||||
XYZColor.prototype._z = function(z) { return new XYZColor(this.x, this.y, z); }
|
||||
|
||||
|
||||
// LUV Colors
|
||||
|
||||
XYZColor.EPSILON = Math.pow(6 / 29, 3);
|
||||
XYZColor.KAPPA = Math.pow(29 / 3, 3);
|
||||
XYZColor.WHITE = (new RGBColor(255, 255, 255)).toXYZ();
|
||||
|
||||
|
||||
LUVColor.prototype.eq = function(luv) { return luv.l === this.l && luv.u === this.u && luv.v === this.v; }
|
||||
|
||||
LUVColor.fromXYZ = function(X, Y, Z) {
|
||||
var deltaGammaFactor = 1 / (XYZColor.WHITE.x + 15 * XYZColor.WHITE.y + 3 * XYZColor.WHITE.z);
|
||||
var uDeltaGamma = 4 * XYZColor.WHITE.x * deltaGammaFactor;
|
||||
var vDeltagamma = 9 * XYZColor.WHITE.y * deltaGammaFactor;
|
||||
|
||||
var yGamma = Y / XYZColor.WHITE.y;
|
||||
var deltaDivider = (X + 15 * Y + 3 * Z);
|
||||
|
||||
if (deltaDivider === 0) {
|
||||
deltaDivider = 1;
|
||||
}
|
||||
|
||||
var deltaFactor = 1 / deltaDivider;
|
||||
|
||||
var uDelta = 4 * X * deltaFactor;
|
||||
var vDelta = 9 * Y * deltaFactor;
|
||||
|
||||
var L = (yGamma > XYZColor.EPSILON) ? 116 * Math.pow(yGamma, 1/3) - 16 : XYZColor.KAPPA * yGamma;
|
||||
var u = 13 * L * (uDelta - uDeltaGamma);
|
||||
var v = 13 * L * (vDelta - vDeltagamma);
|
||||
|
||||
return new LUVColor(L, u, v);
|
||||
}
|
||||
|
||||
|
||||
LUVColor.prototype.toXYZ = function() { return XYZColor.fromLUV(this.l, this.u, this.v); }
|
||||
LUVColor.prototype.toRGB = function() { return XYZColor.fromLUV(this.l, this.u, this.v).toRGB(); }
|
||||
LUVColor.prototype.toHSL = function() { return XYZColor.fromLUV(this.l, this.u, this.v).toHSL(); }
|
||||
LUVColor.prototype.toHSV = function() { return XYZColor.fromLUV(this.l, this.u, this.v).toHSV(); }
|
||||
|
||||
|
||||
LUVColor.prototype._l = function(l) { return new LUVColor(l, this.u, this.v); }
|
||||
LUVColor.prototype._u = function(u) { return new LUVColor(this.l, u, this.v); }
|
||||
LUVColor.prototype._v = function(v) { return new LUVColor(this.l, this.u, v); }
|
||||
|
||||
|
||||
// Required Colors
|
||||
|
||||
var REQUIRED_CONTRAST = 4.5,
|
||||
|
||||
REQUIRED_BRIGHT = new XYZColor(0, (REQUIRED_CONTRAST * (new RGBColor(35,35,35).toXYZ().y + 0.05) - 0.05), 0).toLUV().l,
|
||||
REQUIRED_DARK = new XYZColor(0, ((new RGBColor(217,217,217).toXYZ().y + 0.05) / REQUIRED_CONTRAST - 0.05), 0).toLUV().l;
|
||||
|
||||
|
||||
// --------------------
|
||||
// Rebuild Colors
|
||||
// --------------------
|
||||
|
||||
FFZ.prototype._rebuild_colors = function() {
|
||||
if ( ! this._color_style || this.has_bttv )
|
||||
return;
|
||||
|
||||
this._color_style.innerHTML = '';
|
||||
var colors = Object.keys(this._colors);
|
||||
this._colors = {};
|
||||
for(var i=0, l=colors.length; i<l; i++)
|
||||
this._handle_color(colors[i]);
|
||||
}
|
||||
|
||||
|
||||
FFZ.prototype._handle_color = function(color) {
|
||||
if ( ! color || this._colors.hasOwnProperty(color) )
|
||||
return;
|
||||
|
||||
this._colors[color] = true;
|
||||
var rgb = RGBColor.fromHex(color),
|
||||
|
||||
clr = color,
|
||||
light_color = color,
|
||||
dark_color = color,
|
||||
matched = false,
|
||||
rule = 'span[style="color:' + color + '"]';
|
||||
|
||||
|
||||
// Color Blindness Handling
|
||||
if ( this.settings.color_blind !== '0' ) {
|
||||
var new_color = rgb.daltonize(this.settings.color_blind);
|
||||
if ( ! rgb.eq(new_color) ) {
|
||||
rgb = new_color;
|
||||
clr = light_color = dark_color = rgb.toCSS();
|
||||
matched = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Color Processing - RGB
|
||||
if ( this.settings.fix_color === '4' ) {
|
||||
var lum = rgb.luminance();
|
||||
|
||||
if ( lum > 0.3 ) {
|
||||
var s = 127, nc = rgb;
|
||||
while(s--) {
|
||||
nc = nc.brighten(-1);
|
||||
if ( nc.luminance() <= 0.3 )
|
||||
break;
|
||||
}
|
||||
|
||||
matched = true;
|
||||
light_color = nc.toCSS();
|
||||
}
|
||||
|
||||
if ( lum < 0.15 ) {
|
||||
var s = 127, nc = rgb;
|
||||
while(s--) {
|
||||
nc = nc.brighten();
|
||||
if ( nc.luminance() >= 0.15 )
|
||||
break;
|
||||
}
|
||||
|
||||
matched = true;
|
||||
dark_color = nc.toCSS();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Color Processing - HSL
|
||||
if ( this.settings.fix_color === '2' ) {
|
||||
var hsl = rgb.toHSL();
|
||||
|
||||
matched = true;
|
||||
light_color = hsl._l(Math.min(Math.max(0, 0.7 * hsl.l), 1)).toCSS();
|
||||
dark_color = hsl._l(Math.min(Math.max(0, 0.3 + (0.7 * hsl.l)), 1)).toCSS();
|
||||
}
|
||||
|
||||
|
||||
// Color Processing - HSV
|
||||
if ( this.settings.fix_color === '3' ) {
|
||||
var hsv = rgb.toHSV();
|
||||
matched = true;
|
||||
|
||||
if ( hsv.s === 0 ) {
|
||||
// Black and White
|
||||
light_color = hsv._v(Math.min(Math.max(0.5, 0.5 * hsv.v), 1)).toRGB().toCSS();
|
||||
dark_color = hsv._v(Math.min(Math.max(0.5, 0.5 + (0.5 * hsv.v)), 1)).toRGB().toCSS();
|
||||
|
||||
} 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)).toCSS();
|
||||
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)).toCSS();
|
||||
}
|
||||
}
|
||||
|
||||
// Color Processing - LUV
|
||||
if ( this.settings.fix_color === '1' ) {
|
||||
var luv = rgb.toLUV();
|
||||
|
||||
if ( luv.l > REQUIRED_DARK ) {
|
||||
matched = true;
|
||||
light_color = luv._l(REQUIRED_DARK).toRGB().toCSS();
|
||||
}
|
||||
|
||||
if ( luv.l < REQUIRED_BRIGHT ) {
|
||||
matched = true;
|
||||
dark_color = luv._l(REQUIRED_BRIGHT).toRGB().toCSS();
|
||||
}
|
||||
}
|
||||
|
||||
// Output
|
||||
if ( ! matched )
|
||||
return;
|
||||
|
||||
var output = '';
|
||||
|
||||
if ( light_color !== clr )
|
||||
output += 'body.ffz-chat-colors .chat-line ' + rule + ' { color: ' + light_color + ' !important; }';
|
||||
|
||||
if ( dark_color !== light_color ) {
|
||||
output += 'body.ffz-chat-colors .theatre .chat-container .chat-line ' + rule +
|
||||
', body.ffz-chat-colors .ember-chat-container.dark .chat-line ' + rule +
|
||||
', body.ffz-chat-colors .ember-chat-container.force-dark .chat-line ' + rule +
|
||||
', body.ffz-chat-colors .chat-container.dark .chat-line ' + rule +
|
||||
', body.ffz-chat-colors .chat-container.force-dark .chat-line ' + rule + ' { color: ' + dark_color + ' !important; }';
|
||||
}
|
||||
|
||||
this._color_style.innerHTML += output;
|
||||
}
|
|
@ -464,6 +464,7 @@ FFZ.prototype._modify_cindex = function(view) {
|
|||
FFZ.settings_info.chatter_count = {
|
||||
type: "boolean",
|
||||
value: false,
|
||||
no_mobile: true,
|
||||
|
||||
category: "Channel Metadata",
|
||||
|
||||
|
@ -487,6 +488,7 @@ FFZ.settings_info.chatter_count = {
|
|||
FFZ.settings_info.channel_views = {
|
||||
type: "boolean",
|
||||
value: true,
|
||||
no_mobile: true,
|
||||
|
||||
category: "Channel Metadata",
|
||||
name: "Channel Views",
|
||||
|
@ -500,6 +502,7 @@ FFZ.settings_info.channel_views = {
|
|||
FFZ.settings_info.hosted_channels = {
|
||||
type: "boolean",
|
||||
value: true,
|
||||
no_mobile: true,
|
||||
|
||||
category: "Channel Metadata",
|
||||
name: "Channel Hosting",
|
||||
|
@ -526,6 +529,7 @@ FFZ.settings_info.hosted_channels = {
|
|||
FFZ.settings_info.stream_host_button = {
|
||||
type: "boolean",
|
||||
value: true,
|
||||
no_mobile: true,
|
||||
|
||||
category: "Channel Metadata",
|
||||
name: "Host This Channel Button",
|
||||
|
@ -540,6 +544,7 @@ FFZ.settings_info.stream_host_button = {
|
|||
FFZ.settings_info.stream_uptime = {
|
||||
type: "boolean",
|
||||
value: false,
|
||||
no_mobile: true,
|
||||
|
||||
category: "Channel Metadata",
|
||||
name: "Stream Uptime",
|
||||
|
@ -555,6 +560,7 @@ FFZ.settings_info.stream_title = {
|
|||
type: "boolean",
|
||||
value: true,
|
||||
no_bttv: true,
|
||||
no_mobile: true,
|
||||
|
||||
category: "Channel Metadata",
|
||||
name: "Title Links",
|
||||
|
|
|
@ -13,6 +13,7 @@ FFZ.settings_info.swap_sidebars = {
|
|||
value: false,
|
||||
|
||||
category: "Appearance",
|
||||
no_mobile: true,
|
||||
no_bttv: true,
|
||||
|
||||
name: "Swap Sidebar Positions",
|
||||
|
@ -30,6 +31,7 @@ FFZ.settings_info.minimal_chat = {
|
|||
value: false,
|
||||
|
||||
category: "Chat Appearance",
|
||||
|
||||
name: "Minimalistic Chat",
|
||||
help: "Hide all of the chat user interface, only showing messages and an input box.",
|
||||
|
||||
|
|
|
@ -5,15 +5,6 @@
|
|||
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 + "*"),
|
||||
|
||||
quote_attr = function(attr) {
|
||||
return (attr + '')
|
||||
.replace(/&/g, "&")
|
||||
.replace(/'/g, "'")
|
||||
.replace(/"/g, """)
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">");
|
||||
},
|
||||
|
||||
|
||||
TWITCH_BASE = "http://static-cdn.jtvnw.net/emoticons/v1/",
|
||||
SRCSETS = {};
|
||||
|
@ -25,6 +16,36 @@
|
|||
},
|
||||
|
||||
|
||||
LINK_SPLIT = /^(?:(https?):\/\/)?(?:(.*?)@)?([^\/:]+)(?::(\d+))?(.*?)(?:\?(.*?))?(?:\#(.*?))?$/,
|
||||
YOUTUBE_CHECK = /^(?:https?:\/\/)?(?:m\.|www\.)?youtu(?:be\.com|\.be)\/(?:v\/|watch\/|.*?(?:embed|watch).*?v=)?([a-zA-Z0-9\-_]+)$/,
|
||||
IMGUR_PATH = /^\/(?:gallery\/)?[A-Za-z0-9]+(?:\.(?:png|jpg|jpeg|gif|gifv|bmp))?$/,
|
||||
IMAGE_EXT = /\.(?:png|jpg|jpeg|gif|bmp)$/i,
|
||||
IMAGE_DOMAINS = [],
|
||||
|
||||
is_image = function(href, any_domain) {
|
||||
var match = href.match(LINK_SPLIT);
|
||||
if ( ! match )
|
||||
return;
|
||||
|
||||
var domain = match[3].toLowerCase(), port = match[4],
|
||||
path = match[5];
|
||||
|
||||
// Don't allow non-standard ports.
|
||||
if ( port && port !== '80' && port !== '443' )
|
||||
return false;
|
||||
|
||||
// imgur-specific checks.
|
||||
if ( domain === 'i.imgur.com' || domain === 'imgur.com' || domain === 'www.imgur.com' || domain === 'm.imgur.com' )
|
||||
return IMGUR_PATH.test(path);
|
||||
|
||||
return any_domain ? IMAGE_EXT.test(path) : IMAGE_DOMAINS.indexOf(domain) !== -1;
|
||||
}
|
||||
|
||||
image_iframe = function(href, extra_class) {
|
||||
return '<iframe class="ffz-image-hover' + (extra_class ? ' ' + extra_class : '') + '" allowtransparency="true" src="' + constants.SERVER + 'script/image-proxy.html?' + utils.quote_attr(href) + '"></iframe>';
|
||||
},
|
||||
|
||||
|
||||
data_to_tooltip = function(data) {
|
||||
var set = data.set,
|
||||
set_type = data.set_type,
|
||||
|
@ -86,7 +107,8 @@
|
|||
return link_data.tooltip;
|
||||
|
||||
if ( link_data.type == "youtube" ) {
|
||||
tooltip = "<b>YouTube: " + utils.sanitize(link_data.title) + "</b><hr>";
|
||||
tooltip = this.settings.link_image_hover ? image_iframe(link_data.full || href, 'ffz-yt-thumb') : '';
|
||||
tooltip += "<b>YouTube: " + utils.sanitize(link_data.title) + "</b><hr>";
|
||||
tooltip += "Channel: " + utils.sanitize(link_data.channel) + " | " + utils.time_to_string(link_data.duration) + "<br>";
|
||||
tooltip += utils.number_commas(link_data.views||0) + " Views | 👍 " + utils.number_commas(link_data.likes||0) + " 👎 " + utils.number_commas(link_data.dislikes||0);
|
||||
|
||||
|
@ -126,7 +148,8 @@
|
|||
|
||||
|
||||
} else if ( link_data.type == "reputation" ) {
|
||||
tooltip = '<span style="word-wrap: break-word">' + utils.sanitize(link_data.full.toLowerCase()) + '</span>';
|
||||
tooltip = (this.settings.link_image_hover && is_image(link_data.full || href, this.settings.image_hover_all_domains)) ? image_iframe(link_data.full || href) : '';
|
||||
tooltip += '<span style="word-wrap: break-word">' + utils.sanitize(link_data.full.toLowerCase()) + '</span>';
|
||||
if ( link_data.trust < 50 || link_data.safety < 50 || (link_data.tags && link_data.tags.length > 0) ) {
|
||||
tooltip += "<hr>";
|
||||
var had_extra = false;
|
||||
|
@ -144,8 +167,10 @@
|
|||
}
|
||||
|
||||
|
||||
} else if ( link_data.full )
|
||||
tooltip = '<span style="word-wrap: break-word">' + utils.sanitize(link_data.full.toLowerCase()) + '</span>';
|
||||
} else if ( link_data.full ) {
|
||||
tooltip = (this.settings.link_image_hover && is_image(link_data.full || href, this.settings.image_hover_all_domains)) ? image_iframe(link_data.full || href) : '';
|
||||
tooltip += '<span style="word-wrap: break-word">' + utils.sanitize(link_data.full.toLowerCase()) + '</span>';
|
||||
}
|
||||
|
||||
if ( ! tooltip )
|
||||
tooltip = '<span style="word-wrap: break-word">' + utils.sanitize(href.toLowerCase()) + '</span>';
|
||||
|
@ -361,32 +386,44 @@ FFZ.settings_info.keywords = {
|
|||
};
|
||||
|
||||
|
||||
FFZ.settings_info.fix_color = {
|
||||
type: "boolean",
|
||||
value: true,
|
||||
|
||||
category: "Chat Appearance",
|
||||
no_bttv: true,
|
||||
|
||||
name: "Adjust Username Colors",
|
||||
help: "Ensure that username colors contrast with the background enough to be readable.",
|
||||
|
||||
on_update: function(val) { document.body.classList.toggle("ffz-chat-colors", !this.has_bttv && val); }
|
||||
};
|
||||
|
||||
|
||||
FFZ.settings_info.link_info = {
|
||||
type: "boolean",
|
||||
value: true,
|
||||
|
||||
category: "Chat Appearance",
|
||||
category: "Chat Tooltips",
|
||||
no_bttv: true,
|
||||
|
||||
name: "Link Tooltips <span>Beta</span>",
|
||||
name: "Link Information <span>Beta</span>",
|
||||
help: "Check links against known bad websites, unshorten URLs, and show YouTube info."
|
||||
};
|
||||
|
||||
|
||||
FFZ.settings_info.link_image_hover = {
|
||||
type: "boolean",
|
||||
value: false,
|
||||
|
||||
category: "Chat Tooltips",
|
||||
no_bttv: true,
|
||||
no_mobile: true,
|
||||
|
||||
name: "Image Preview",
|
||||
help: "Display image thumbnails for links to Imgur and YouTube."
|
||||
};
|
||||
|
||||
|
||||
FFZ.settings_info.image_hover_all_domains = {
|
||||
type: "boolean",
|
||||
value: false,
|
||||
|
||||
category: "Chat Tooltips",
|
||||
no_bttv: true,
|
||||
no_mobile: true,
|
||||
|
||||
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>"
|
||||
};
|
||||
|
||||
|
||||
FFZ.settings_info.legacy_badges = {
|
||||
type: "boolean",
|
||||
value: false,
|
||||
|
@ -415,18 +452,35 @@ FFZ.settings_info.chat_rows = {
|
|||
|
||||
|
||||
FFZ.settings_info.chat_separators = {
|
||||
type: "boolean",
|
||||
value: false,
|
||||
type: "select",
|
||||
options: {
|
||||
0: "Disabled",
|
||||
1: "Basic Line (1px solid)",
|
||||
2: "3D Line (2px groove)"
|
||||
},
|
||||
value: '0',
|
||||
|
||||
category: "Chat Appearance",
|
||||
no_bttv: true,
|
||||
|
||||
process_value: function(val) {
|
||||
if ( val === false )
|
||||
return '0';
|
||||
else if ( val === true )
|
||||
return '1';
|
||||
return val;
|
||||
},
|
||||
|
||||
name: "Chat Line Separators",
|
||||
help: "Display thin lines between chat messages for further visual separation.",
|
||||
|
||||
on_update: function(val) { document.body.classList.toggle("ffz-chat-separator", !this.has_bttv && val); }
|
||||
on_update: function(val) {
|
||||
document.body.classList.toggle("ffz-chat-separator", !this.has_bttv && val !== '0');
|
||||
document.body.classList.toggle("ffz-chat-separator-3d", !this.has_bttv && val === '2');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
FFZ.settings_info.chat_padding = {
|
||||
type: "boolean",
|
||||
value: false,
|
||||
|
@ -495,6 +549,52 @@ FFZ.settings_info.chat_font_size = {
|
|||
}
|
||||
|
||||
utils.update_css(this._chat_style, "chat_font_size", css);
|
||||
FFZ.settings_info.chat_ts_size.on_update.bind(this)(this.settings.chat_ts_size);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
FFZ.settings_info.chat_ts_size = {
|
||||
type: "button",
|
||||
value: null,
|
||||
|
||||
category: "Chat Appearance",
|
||||
no_bttv: true,
|
||||
|
||||
name: "Timestamp Font Size",
|
||||
help: "Make the chat timestamp font bigger or smaller.",
|
||||
|
||||
method: function() {
|
||||
var old_val = this.settings.chat_ts_size;
|
||||
|
||||
if ( old_val === null )
|
||||
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);
|
||||
|
||||
if ( new_val === null || new_val === undefined )
|
||||
return;
|
||||
|
||||
var parsed = parseInt(new_val);
|
||||
if ( parsed === NaN || parsed < 1 )
|
||||
parsed = null;
|
||||
|
||||
this.settings.set("chat_ts_size", parsed);
|
||||
},
|
||||
|
||||
on_update: function(val) {
|
||||
if ( this.has_bttv || ! this._chat_style )
|
||||
return;
|
||||
|
||||
var css;
|
||||
if ( val === null )
|
||||
css = "";
|
||||
else {
|
||||
var lh = Math.max(20, Math.round((20/12)*val), Math.round((20/12)*this.settings.chat_font_size));
|
||||
css = ".ember-chat .chat-messages .timestamp { font-size: " + val + "px !important; line-height: " + lh + "px !important; }";
|
||||
}
|
||||
|
||||
utils.update_css(this._chat_style, "chat_ts_font_size", css);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -521,23 +621,19 @@ FFZ.prototype.setup_line = function() {
|
|||
|
||||
|
||||
// Chat Enhancements
|
||||
document.body.classList.toggle("ffz-chat-colors", !this.has_bttv && this.settings.fix_color);
|
||||
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-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-separator", !this.has_bttv && this.settings.chat_separators);
|
||||
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-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-high-contrast-chat", !this.has_bttv && this.settings.high_contrast_chat);
|
||||
|
||||
this._colors = {};
|
||||
this._last_row = {};
|
||||
|
||||
s = this._fix_color_style = document.createElement('style');
|
||||
s.id = "ffz-style-username-colors";
|
||||
s.type = 'text/css';
|
||||
document.head.appendChild(s);
|
||||
|
||||
|
||||
// Emoticon Data
|
||||
this._twitch_emotes = {};
|
||||
this._link_data = {};
|
||||
|
@ -657,13 +753,8 @@ FFZ.prototype._modify_line = function(component) {
|
|||
var el = this.get('element'),
|
||||
user = this.get('msgObject.from'),
|
||||
room = this.get('msgObject.room') || App.__container__.lookup('controller:chat').get('currentRoom.id'),
|
||||
color = this.get('msgObject.color'),
|
||||
row_type = this.get('msgObject.ffz_alternate');
|
||||
|
||||
// Color Processing
|
||||
if ( color )
|
||||
f._handle_color(color);
|
||||
|
||||
// Row Alternation
|
||||
if ( row_type === undefined ) {
|
||||
row_type = f._last_row[room] = f._last_row.hasOwnProperty(room) ? !f._last_row[room] : false;
|
||||
|
@ -733,7 +824,7 @@ FFZ.prototype._modify_line = function(component) {
|
|||
|
||||
|
||||
// Link Tooltips
|
||||
if ( f.settings.link_info ) {
|
||||
if ( f.settings.link_info || f.settings.link_image_hover ) {
|
||||
var links = el.querySelectorAll("span.message a");
|
||||
for(var i=0; i < links.length; i++) {
|
||||
var link = links[i],
|
||||
|
@ -746,6 +837,7 @@ FFZ.prototype._modify_line = function(component) {
|
|||
}
|
||||
|
||||
// Check the cache.
|
||||
if ( f.settings.link_info ) {
|
||||
var link_data = f._link_data[href];
|
||||
if ( link_data ) {
|
||||
if ( !deleted && typeof link_data != "boolean" )
|
||||
|
@ -757,9 +849,16 @@ FFZ.prototype._modify_line = function(component) {
|
|||
} else if ( ! /^mailto:/.test(href) ) {
|
||||
f._link_data[href] = true;
|
||||
f.ws_send("get_link", href, load_link_data.bind(f, href));
|
||||
if ( ! deleted && f.settings.link_image_hover && is_image(href, f.settings.image_hover_all_domains) )
|
||||
link.title = image_iframe(href);
|
||||
}
|
||||
}
|
||||
|
||||
// Now, Images
|
||||
else if ( ! deleted && f.settings.link_image_hover && is_image(href, f.settings.image_hover_all_domains) )
|
||||
link.title = image_iframe(href);
|
||||
}
|
||||
|
||||
jQuery(links).tipsy({html:true});
|
||||
}
|
||||
|
||||
|
@ -834,68 +933,6 @@ FFZ.prototype._modify_line = function(component) {
|
|||
}
|
||||
|
||||
|
||||
// ---------------------
|
||||
// Fix Name Colors
|
||||
// ---------------------
|
||||
|
||||
FFZ.prototype._handle_color = function(color) {
|
||||
if ( ! color || this._colors[color] )
|
||||
return;
|
||||
|
||||
this._colors[color] = true;
|
||||
|
||||
// Parse the color.
|
||||
var raw = parseInt(color.substr(1), 16),
|
||||
rgb = [
|
||||
(raw >> 16),
|
||||
(raw >> 8 & 0x00FF),
|
||||
(raw & 0x0000FF)
|
||||
],
|
||||
|
||||
lum = utils.get_luminance(rgb),
|
||||
|
||||
output = "",
|
||||
rule = 'span[style="color:' + color + '"]',
|
||||
matched = false;
|
||||
|
||||
if ( lum > 0.3 ) {
|
||||
// Color Too Bright. We need a lum of 0.3 or less.
|
||||
matched = true;
|
||||
|
||||
var s = 127,
|
||||
nc = rgb;
|
||||
while(s--) {
|
||||
nc = utils.darken(nc);
|
||||
if ( utils.get_luminance(nc) <= 0.3 )
|
||||
break;
|
||||
}
|
||||
|
||||
output += '.ffz-chat-colors .ember-chat-container:not(.dark) .chat-line ' + rule + ', .ffz-chat-colors .chat-container:not(.dark) .chat-line ' + rule + ' { color: ' + utils.rgb_to_css(nc) + ' !important; }\n';
|
||||
} else
|
||||
output += '.ffz-chat-colors .ember-chat-container:not(.dark) .chat-line ' + rule + ', .ffz-chat-colors .chat-container:not(.dark) .chat-line ' + rule + ' { color: ' + color + ' !important; }\n';
|
||||
|
||||
if ( lum < 0.15 ) {
|
||||
// Color Too Dark. We need a lum of 0.1 or more.
|
||||
matched = true;
|
||||
|
||||
var s = 127,
|
||||
nc = rgb;
|
||||
while(s--) {
|
||||
nc = utils.brighten(nc);
|
||||
if ( utils.get_luminance(nc) >= 0.15 )
|
||||
break;
|
||||
}
|
||||
|
||||
output += '.ffz-chat-colors .theatre .chat-container .chat-line ' + rule + ', .ffz-chat-colors .chat-container.dark .chat-line ' + rule + ', .ffz-chat-colors .ember-chat-container.dark .chat-line ' + rule + ' { color: ' + utils.rgb_to_css(nc) + ' !important; }\n';
|
||||
} else
|
||||
output += '.ffz-chat-colors .theatre .chat-container .chat-line ' + rule + ', .ffz-chat-colors .chat-container.dark .chat-line ' + rule + ', .ffz-chat-colors .ember-chat-container.dark .chat-line ' + rule + ' { color: ' + color + ' !important; }\n';
|
||||
|
||||
|
||||
if ( matched )
|
||||
this._fix_color_style.innerHTML += output;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------
|
||||
// Capitalization
|
||||
// ---------------------
|
||||
|
@ -953,7 +990,7 @@ FFZ.prototype._remove_banned = function(tokens) {
|
|||
new_tokens.push(token.altText.replace(regex, "$1***"));
|
||||
else if ( token.isLink && regex.test(token.href) )
|
||||
new_tokens.push({
|
||||
mentionedUser: '</span><a class="deleted-link" title="' + quote_attr(token.href.replace(regex, "$1***")) + '" data-url="' + quote_attr(token.href) + '" href="#"><banned link></a><span class="mentioning">',
|
||||
mentionedUser: '</span><a class="deleted-link" title="' + utils.quote_attr(token.href.replace(regex, "$1***")) + '" data-url="' + utils.quote_attr(token.href) + '" href="#"><banned link></a><span class="mentioning">',
|
||||
own: true
|
||||
});
|
||||
else
|
||||
|
|
|
@ -98,7 +98,7 @@ FFZ.settings_info.mod_card_hotkeys = {
|
|||
|
||||
FFZ.settings_info.mod_card_info = {
|
||||
type: "boolean",
|
||||
value: false,
|
||||
value: true,
|
||||
|
||||
no_bttv: true,
|
||||
category: "Chat Moderation",
|
||||
|
|
|
@ -5,6 +5,9 @@ var FFZ = window.FrankerFaceZ,
|
|||
constants = require('../constants'),
|
||||
utils = require('../utils'),
|
||||
|
||||
// StrimBagZ Support
|
||||
is_android = navigator.userAgent.indexOf('Android') !== -1,
|
||||
|
||||
|
||||
moderator_css = function(room) {
|
||||
if ( ! room.moderator_badge )
|
||||
|
@ -130,6 +133,15 @@ FFZ.prototype._modify_rview = function(view) {
|
|||
|
||||
this.ffz_frozen = false;
|
||||
|
||||
// Fix scrolling.
|
||||
this._ffz_mouse_down = this.ffzMouseDown.bind(this);
|
||||
if ( is_android )
|
||||
// We don't unbind scroll because that messes with the scrollbar. ;_;
|
||||
this._$chatMessagesScroller.bind('scroll', this._ffz_mouse_down);
|
||||
|
||||
this._$chatMessagesScroller.unbind('mousedown');
|
||||
this._$chatMessagesScroller.bind('mousedown', this._ffz_mouse_down);
|
||||
|
||||
if ( f.settings.chat_hover_pause )
|
||||
this.ffzEnableFreeze();
|
||||
|
||||
|
@ -257,12 +269,9 @@ FFZ.prototype._modify_rview = function(view) {
|
|||
|
||||
this._ffz_mouse_move = this.ffzMouseMove.bind(this);
|
||||
this._ffz_mouse_out = this.ffzMouseOut.bind(this);
|
||||
this._ffz_mouse_down = this.ffzMouseDown.bind(this);
|
||||
|
||||
this._$chatMessagesScroller.unbind('mousedown');
|
||||
this._$chatMessagesScroller.bind('mousedown', this._ffz_mouse_down);
|
||||
|
||||
messages.addEventListener('mousemove', this._ffz_mouse_move);
|
||||
messages.addEventListener('touchmove', this._ffz_mouse_move);
|
||||
messages.addEventListener('mouseout', this._ffz_mouse_out);
|
||||
document.addEventListener('mouseout', this._ffz_mouse_out);
|
||||
},
|
||||
|
@ -311,7 +320,7 @@ FFZ.prototype._modify_rview = function(view) {
|
|||
|
||||
ffzMouseDown: function(event) {
|
||||
var t = this._$chatMessagesScroller;
|
||||
if ( ! this.ffz_frozen && t && t[0] && (event.which > 0 || "mousedown" === event.type || "mousewheel" === event.type) ) {
|
||||
if ( t && t[0] && (event.which > 0 || (!this.ffz_frozne && "mousedown" === event.type) || "mousewheel" === event.type || (is_android && "scroll" === event.type) ) ) {
|
||||
var r = t[0].scrollHeight - t[0].scrollTop - t[0].offsetHeight;
|
||||
this._setStuckToBottom(10 >= r);
|
||||
}
|
||||
|
@ -939,6 +948,7 @@ FFZ.prototype._modify_room = function(room) {
|
|||
if ( ! is_whisper )
|
||||
msg.room = this.get('id');
|
||||
|
||||
// Tokenization
|
||||
f.tokenize_chat_line(msg);
|
||||
|
||||
// Keep the history.
|
||||
|
@ -974,11 +984,17 @@ FFZ.prototype._modify_room = function(room) {
|
|||
}
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
f.error("Room addMessage: " + err);
|
||||
}
|
||||
} catch(err) { f.error("Room addMessage: " + err); }
|
||||
|
||||
return this._super(msg);
|
||||
var out = this._super(msg);
|
||||
|
||||
try {
|
||||
// Color processing.
|
||||
var color = msg.color;
|
||||
if ( color )
|
||||
f._handle_color(color);
|
||||
} catch(err) { f.error("Room addMessage2: " + err); }
|
||||
return out;
|
||||
},
|
||||
|
||||
setHostMode: function(e) {
|
||||
|
|
|
@ -56,9 +56,11 @@ FFZ.prototype.setup_bttv = function(delay) {
|
|||
|
||||
// Disable other features too.
|
||||
document.body.classList.remove("ffz-chat-colors");
|
||||
document.body.classList.remove("ffz-chat-colors-gray");
|
||||
document.body.classList.remove("ffz-chat-background");
|
||||
document.body.classList.remove("ffz-chat-padding");
|
||||
document.body.classList.remove("ffz-chat-separator");
|
||||
document.body.classList.remove("ffz-chat-separator-3d");
|
||||
document.body.classList.remove("ffz-sidebar-swap");
|
||||
document.body.classList.remove("ffz-transparent-badges");
|
||||
document.body.classList.remove("ffz-high-contrast-chat");
|
||||
|
|
|
@ -21,7 +21,7 @@ FFZ.get = function() { return FFZ.instance; }
|
|||
|
||||
// Version
|
||||
var VER = FFZ.version_info = {
|
||||
major: 3, minor: 4, revision: 19,
|
||||
major: 3, minor: 4, revision: 25,
|
||||
toString: function() {
|
||||
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ require('./ui/menu');
|
|||
require('./settings');
|
||||
require('./socket');
|
||||
|
||||
|
||||
require('./colors');
|
||||
require('./emoticons');
|
||||
require('./badges');
|
||||
require('./tokenize');
|
||||
|
@ -211,6 +211,7 @@ FFZ.prototype.setup_normal = function(delay, no_socket) {
|
|||
if ( ! no_socket )
|
||||
this.ws_create();
|
||||
|
||||
this.setup_colors();
|
||||
this.setup_emoticons();
|
||||
this.setup_badges();
|
||||
|
||||
|
@ -245,9 +246,11 @@ FFZ.prototype.setup_dashboard = function(delay) {
|
|||
this.setup_dark();
|
||||
|
||||
this.ws_create();
|
||||
this.setup_colors();
|
||||
this.setup_emoticons();
|
||||
this.setup_badges();
|
||||
|
||||
this.setup_tokenization();
|
||||
this.setup_notifications();
|
||||
this.setup_css();
|
||||
|
||||
|
@ -288,6 +291,8 @@ FFZ.prototype.setup_ember = function(delay) {
|
|||
//this.setup_piwik();
|
||||
|
||||
//this.setup_router();
|
||||
this.setup_colors();
|
||||
this.setup_tokenization();
|
||||
this.setup_channel();
|
||||
this.setup_room();
|
||||
this.setup_line();
|
||||
|
|
|
@ -10,6 +10,10 @@ var FFZ = window.FrankerFaceZ,
|
|||
var val = ! this.settings.get(key);
|
||||
this.settings.set(key, val);
|
||||
swit.classList.toggle('active', val);
|
||||
},
|
||||
|
||||
option_setting = function(select, key) {
|
||||
this.settings.set(key, JSON.parse(select.options[select.selectedIndex].value));
|
||||
};
|
||||
|
||||
|
||||
|
@ -41,6 +45,9 @@ FFZ.prototype.load_settings = function() {
|
|||
}
|
||||
}
|
||||
|
||||
if ( info.process_value )
|
||||
val = info.process_value.bind(this)(val);
|
||||
|
||||
this.settings[key] = val;
|
||||
}
|
||||
|
||||
|
@ -61,7 +68,9 @@ FFZ.prototype.load_settings = function() {
|
|||
FFZ.menu_pages.settings = {
|
||||
render: function(view, container) {
|
||||
var settings = {},
|
||||
categories = [];
|
||||
categories = [],
|
||||
is_android = navigator.userAgent.indexOf('Android') !== -1;
|
||||
|
||||
for(var key in FFZ.settings_info) {
|
||||
if ( ! FFZ.settings_info.hasOwnProperty(key) )
|
||||
continue;
|
||||
|
@ -79,6 +88,9 @@ FFZ.menu_pages.settings = {
|
|||
continue;
|
||||
}
|
||||
|
||||
if ( is_android && info.no_mobile )
|
||||
continue;
|
||||
|
||||
if ( ! cs ) {
|
||||
categories.push(cat);
|
||||
cs = settings[cat] = [];
|
||||
|
@ -139,8 +151,8 @@ FFZ.menu_pages.settings = {
|
|||
var a = a[1],
|
||||
b = b[1],
|
||||
|
||||
at = a.type,
|
||||
bt = b.type,
|
||||
at = a.type === "button" ? 2 : 1,
|
||||
bt = b.type === "button" ? 2 : 1,
|
||||
|
||||
an = a.name.toLowerCase(),
|
||||
bn = b.name.toLowerCase();
|
||||
|
@ -193,6 +205,27 @@ FFZ.menu_pages.settings = {
|
|||
|
||||
swit.addEventListener("click", toggle_setting.bind(this, swit, key));
|
||||
|
||||
} else if ( info.type === "select" ) {
|
||||
var select = document.createElement('select'),
|
||||
label = document.createElement('span');
|
||||
|
||||
label.className = 'option-label';
|
||||
label.innerHTML = info.name;
|
||||
|
||||
for(var ok in info.options) {
|
||||
var op = document.createElement('option');
|
||||
op.value = JSON.stringify(ok);
|
||||
if ( val === ok )
|
||||
op.setAttribute('selected', true);
|
||||
op.innerHTML = info.options[ok];
|
||||
select.appendChild(op);
|
||||
}
|
||||
|
||||
select.addEventListener('change', option_setting.bind(this, select, key));
|
||||
|
||||
el.appendChild(label);
|
||||
el.appendChild(select);
|
||||
|
||||
} else {
|
||||
el.classList.add("option");
|
||||
var link = document.createElement('a');
|
||||
|
|
|
@ -8,15 +8,12 @@ var FFZ = window.FrankerFaceZ,
|
|||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||
},
|
||||
|
||||
LINK = /(?:https?:\/\/)?(?:[-a-zA-Z0-9@:%_\+~#=]+\.)+[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#!?&//=]*)/g,
|
||||
|
||||
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 + "*");
|
||||
|
||||
|
||||
try {
|
||||
helpers = window.require && window.require("ember-twitch-chat/helpers/chat-line-helpers");
|
||||
} catch(err) { }
|
||||
|
||||
|
||||
FFZ.SRC_IDS = {},
|
||||
FFZ.src_to_id = function(src) {
|
||||
if ( FFZ.SRC_IDS.hasOwnProperty(src) )
|
||||
|
@ -34,7 +31,7 @@ FFZ.src_to_id = function(src) {
|
|||
|
||||
|
||||
// ---------------------
|
||||
// Time Format
|
||||
// Settings
|
||||
// ---------------------
|
||||
|
||||
var ts = new Date(0).toLocaleTimeString().toUpperCase();
|
||||
|
@ -51,20 +48,73 @@ FFZ.settings_info.twenty_four_timestamps = {
|
|||
};
|
||||
|
||||
|
||||
if ( helpers )
|
||||
FFZ.settings_info.show_deleted_links = {
|
||||
type: "boolean",
|
||||
value: false,
|
||||
|
||||
category: "Chat Moderation",
|
||||
no_bttv: true,
|
||||
|
||||
name: "Show Deleted Links",
|
||||
help: "Do not delete links based on room settings or link length."
|
||||
};
|
||||
|
||||
|
||||
// ---------------------
|
||||
// Setup
|
||||
// ---------------------
|
||||
|
||||
FFZ.prototype.setup_tokenization = function() {
|
||||
helpers = window.require && window.require("ember-twitch-chat/helpers/chat-line-helpers");
|
||||
if ( ! helpers )
|
||||
return this.log("Unable to get chat helper functions.");
|
||||
|
||||
this.log("Hooking Ember chat line helpers.");
|
||||
|
||||
var f = this;
|
||||
|
||||
// Timestamp Display
|
||||
helpers.getTime = function(e) {
|
||||
if ( e === undefined || e === null )
|
||||
return '?:??';
|
||||
|
||||
var hours = e.getHours(),
|
||||
minutes = e.getMinutes();
|
||||
|
||||
if ( hours > 12 && ! FFZ.get().settings.twenty_four_timestamps )
|
||||
if ( hours > 12 && ! f.settings.twenty_four_timestamps )
|
||||
hours -= 12;
|
||||
else if ( hours === 0 && ! FFZ.get().settings.twenty_four_timestamps )
|
||||
else if ( hours === 0 && ! f.settings.twenty_four_timestamps )
|
||||
hours = 12;
|
||||
|
||||
return hours + ':' + (minutes < 10 ? '0' : '') + minutes;
|
||||
};
|
||||
|
||||
|
||||
// Linkify Messages
|
||||
helpers.linkifyMessage = function(tokens, delete_links) {
|
||||
var show_deleted = f.settings.show_deleted_links;
|
||||
|
||||
return _.chain(tokens).map(function(token) {
|
||||
if ( ! _.isString(token) )
|
||||
return token;
|
||||
|
||||
var matches = token.match(LINK);
|
||||
if ( ! matches || ! matches.length )
|
||||
return [token];
|
||||
|
||||
return _.zip(
|
||||
token.split(LINK),
|
||||
_.map(matches, function(e) {
|
||||
if ( ! show_deleted && (delete_links || e.length > 255) )
|
||||
return {mentionedUser: '</span><a class="deleted-link" title="' + utils.quote_attr(e) + '" data-url="' + utils.quote_attr(e) + '" href="#"><' + (e.length > 255 ? 'long link' : 'deleted link') + '></a><span class="mentioning">', own: true}
|
||||
return {isLink: true, href: e};
|
||||
})
|
||||
);
|
||||
}).flatten().compact().value();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// ---------------------
|
||||
// Tokenization
|
||||
// ---------------------
|
||||
|
@ -73,6 +123,8 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification) {
|
|||
if ( msgObject.cachedTokens )
|
||||
return msgObject.cachedTokens;
|
||||
|
||||
try {
|
||||
|
||||
var msg = msgObject.message,
|
||||
user = this.get_user(),
|
||||
room_id = msgObject.room,
|
||||
|
@ -82,11 +134,15 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification) {
|
|||
tokens = [msg];
|
||||
|
||||
// Standard tokenization
|
||||
if ( helpers && helpers.linkifyMessage )
|
||||
tokens = helpers.linkifyMessage(tokens);
|
||||
if ( user && user.login )
|
||||
|
||||
if ( user && user.login && helpers && helpers.mentionizeMessage )
|
||||
tokens = helpers.mentionizeMessage(tokens, user.login, from_me);
|
||||
|
||||
if ( helpers && helpers.emoticonizeMessage )
|
||||
tokens = helpers.emoticonizeMessage(tokens, emotes);
|
||||
|
||||
if ( this.settings.replace_bad_emotes )
|
||||
tokens = this.tokenize_replace_emotes(tokens);
|
||||
|
||||
|
@ -149,7 +205,7 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification) {
|
|||
msg,
|
||||
"Twitch Chat Whisper",
|
||||
"ffz_whisper_notice",
|
||||
60000,
|
||||
(this.settings.notification_timeout*1000),
|
||||
function() {
|
||||
window.focus();
|
||||
}
|
||||
|
@ -159,7 +215,7 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification) {
|
|||
msg,
|
||||
"Twitch Chat Mention in " + room_name,
|
||||
room_id,
|
||||
60000,
|
||||
(this.settings.notification_timeout*1000),
|
||||
function() {
|
||||
window.focus();
|
||||
var cont = App.__container__.lookup('controller:chat');
|
||||
|
@ -174,6 +230,10 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification) {
|
|||
}
|
||||
|
||||
msgObject.cachedTokens = tokens;
|
||||
} catch(err) {
|
||||
this.error("Tokenization Error: " + err);
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ FFZ.settings_info.hide_recent_past_broadcast = {
|
|||
value: false,
|
||||
|
||||
//no_bttv: true,
|
||||
no_mobile: true,
|
||||
|
||||
category: "Channel Metadata",
|
||||
name: "Hide \"Watch Last Broadcast\"",
|
||||
|
|
|
@ -8,6 +8,7 @@ FFZ.settings_info.following_count = {
|
|||
value: true,
|
||||
|
||||
no_bttv: true,
|
||||
no_mobile: true,
|
||||
|
||||
category: "Appearance",
|
||||
name: "Sidebar Following Count",
|
||||
|
|
|
@ -20,6 +20,7 @@ FFZ.prototype.setup_following = function() {
|
|||
FFZ.settings_info.follow_buttons = {
|
||||
type: "boolean",
|
||||
value: true,
|
||||
no_mobile: true,
|
||||
|
||||
category: "Channel Metadata",
|
||||
name: "Relevant Follow Buttons",
|
||||
|
|
|
@ -255,7 +255,7 @@ FFZ.prototype.build_ui_popup = function(view) {
|
|||
|
||||
// Add the menu to the DOM.
|
||||
this._popup = container;
|
||||
sub_container.style.maxHeight = Math.max(200, view.$().height() - 172) + "px";
|
||||
sub_container.style.maxHeight = Math.max(200, view.$().height() - 472) + "px";
|
||||
view.$('.chat-interface').append(container);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ FFZ.settings_info.highlight_notifications = {
|
|||
|
||||
category: "Chat Filtering",
|
||||
no_bttv: true,
|
||||
no_mobile: true,
|
||||
//visible: function() { return ! this.has_bttv },
|
||||
|
||||
name: "Highlight Notifications",
|
||||
|
@ -51,6 +52,33 @@ FFZ.settings_info.highlight_notifications = {
|
|||
};
|
||||
|
||||
|
||||
FFZ.settings_info.notification_timeout = {
|
||||
type: "button",
|
||||
value: 60,
|
||||
|
||||
category: "Chat Filtering",
|
||||
no_bttv: true,
|
||||
no_mobile: true,
|
||||
|
||||
name: "Notification Timeout",
|
||||
help: "Specify how long notifications should be displayed before automatically closing.",
|
||||
|
||||
method: function() {
|
||||
var old_val = this.settings.notification_timeout,
|
||||
new_val = prompt("Notification Timeout\n\nPlease enter the time you'd like notifications to be displayed before automatically closing, in seconds.\n\nDefault is: 60", old_val);
|
||||
|
||||
if ( new_val === null || new_val === undefined )
|
||||
return;
|
||||
|
||||
var parsed = parseInt(new_val);
|
||||
if ( parsed === NaN || parsed < 1 )
|
||||
parsed = 60;
|
||||
|
||||
this.settings.set("notification_timeout", parsed);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ---------------------
|
||||
// Socket Commands
|
||||
// ---------------------
|
||||
|
@ -88,7 +116,7 @@ FFZ.prototype.show_notification = function(message, title, tag, timeout, on_clic
|
|||
|
||||
if ( perm === "granted" ) {
|
||||
title = title || "FrankerFaceZ";
|
||||
timeout = timeout || 10000;
|
||||
timeout = timeout || (this.settings.notification_timeout*1000);
|
||||
|
||||
var options = {
|
||||
lang: "en-US",
|
||||
|
|
|
@ -19,6 +19,7 @@ FFZ.prototype.setup_races = function() {
|
|||
FFZ.settings_info.srl_races = {
|
||||
type: "boolean",
|
||||
value: true,
|
||||
no_mobile: true,
|
||||
|
||||
category: "Channel Metadata",
|
||||
name: "SRL Race Information",
|
||||
|
|
46
src/utils.js
46
src/utils.js
|
@ -19,38 +19,6 @@ var sanitize_cache = {},
|
|||
return num + "th";
|
||||
},
|
||||
|
||||
brighten = function(rgb, amount) {
|
||||
amount = (amount === 0) ? 0 : (amount || 1);
|
||||
amount = Math.round(255 * -(amount / 100));
|
||||
|
||||
var r = Math.max(0, Math.min(255, rgb[0] - amount)),
|
||||
g = Math.max(0, Math.min(255, rgb[1] - amount)),
|
||||
b = Math.max(0, Math.min(255, rgb[2] - amount));
|
||||
|
||||
return [r,g,b];
|
||||
},
|
||||
|
||||
rgb_to_css = function(rgb) {
|
||||
return "rgb(" + rgb[0] + ", " + rgb[1] + ", " + rgb[2] + ")";
|
||||
},
|
||||
|
||||
darken = function(rgb, amount) {
|
||||
amount = (amount === 0) ? 0 : (amount || 1);
|
||||
return brighten(rgb, -amount);
|
||||
},
|
||||
|
||||
get_luminance = function(rgb) {
|
||||
rgb = [rgb[0]/255, rgb[1]/255, rgb[2]/255];
|
||||
for (var i =0; i<rgb.length; i++) {
|
||||
if (rgb[i] <= 0.03928) {
|
||||
rgb[i] = rgb[i] / 12.92;
|
||||
} else {
|
||||
rgb[i] = Math.pow( ((rgb[i]+0.055)/1.055), 2.4 );
|
||||
}
|
||||
}
|
||||
return (0.2126 * rgb[0]) + (0.7152 * rgb[1]) + (0.0722 * rgb[2]);
|
||||
},
|
||||
|
||||
date_regex = /^(\d{4}|\+\d{6})(?:-?(\d{2})(?:-?(\d{2})(?:T(\d{2})(?::?(\d{2})(?::?(\d{2})(?:(?:\.|,)(\d{1,}))?)?)?(Z|([\-+])(\d{2})(?::?(\d{2}))?)?)?)?)?$/,
|
||||
|
||||
parse_date = function(str) {
|
||||
|
@ -221,11 +189,6 @@ module.exports = {
|
|||
|
||||
emoji_to_codepoint: emoji_to_codepoint,
|
||||
|
||||
get_luminance: get_luminance,
|
||||
brighten: brighten,
|
||||
darken: darken,
|
||||
rgb_to_css: rgb_to_css,
|
||||
|
||||
parse_date: parse_date,
|
||||
|
||||
number_commas: function(x) {
|
||||
|
@ -253,6 +216,15 @@ module.exports = {
|
|||
return m;
|
||||
},
|
||||
|
||||
quote_attr: function(attr) {
|
||||
return (attr + '')
|
||||
.replace(/&/g, "&")
|
||||
.replace(/'/g, "'")
|
||||
.replace(/"/g, """)
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">");
|
||||
},
|
||||
|
||||
date_string: function(date) {
|
||||
return date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate();
|
||||
},
|
||||
|
|
57
style.css
57
style.css
|
@ -504,10 +504,19 @@ body:not(.ffz-minimal-chat):not(.ffz-menu-replace) .emoticon-selector-toggle + s
|
|||
|
||||
.ffz-ui-menu-page p.disabled span.switch-label,
|
||||
.ffz-ui-menu-page span.help,
|
||||
.ffz-ui-menu-page span.option-label,
|
||||
.ffz-ui-menu-page p.option a {
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.ffz-ui-menu-page span.option-label {
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
.ffz-ui-menu-page select {
|
||||
margin: 0 10px 5px;
|
||||
}
|
||||
|
||||
.ffz-ui-popup ul.menu {
|
||||
list-style-type: none;
|
||||
border-top: 1px solid rgba(0,0,0,0.2);
|
||||
|
@ -600,6 +609,7 @@ body:not(.ffz-minimal-chat):not(.ffz-menu-replace) .emoticon-selector-toggle + s
|
|||
.ffz-ui-popup ul.menu svg path { fill: #333; }
|
||||
|
||||
|
||||
.ffz-ui-popup .option-label span,
|
||||
.ffz-ui-popup .switch-label span {
|
||||
opacity: 0.8;
|
||||
font-size: 10px;
|
||||
|
@ -653,6 +663,11 @@ body:not(.ffz-minimal-chat):not(.ffz-menu-replace) .emoticon-selector-toggle + s
|
|||
display: none;
|
||||
}
|
||||
|
||||
.ffz-chat-colors-gray .chat-line:not(.admin):not(.notification) span.from,
|
||||
.ffz-chat-colors-gray .chat-line:not(.admin):not(.notification) span.message {
|
||||
color: inherit !important
|
||||
}
|
||||
|
||||
.ffz-chat-background .ember-chat .mentioning,
|
||||
.ffz-chat-background .ember-chat .mentioned {
|
||||
border-radius: 10px;
|
||||
|
@ -836,6 +851,15 @@ body:not(.ffz-chat-purge-icon) .ember-chat .mod-icons .purge { display: none; }
|
|||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
||||
.ffz-chat-separator-3d .chat-line:before {
|
||||
border-top: 1px solid rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
.ffz-chat-separator-3d ul.chat-lines div:first-of-type .chat-line:before {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.ffz-chat-separator:not(.ffz-chat-background) ul.chat-lines div:last-of-type .chat-line:before,
|
||||
.ffz-chat-separator ul.chat-lines div:last-of-type .chat-line:not(.ffz-alternate):before {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
@ -848,6 +872,13 @@ body:not(.ffz-chat-purge-icon) .ember-chat .mod-icons .purge { display: none; }
|
|||
border-bottom-color: #000;
|
||||
}
|
||||
|
||||
.ffz-chat-separator-3d .app-main.theatre .chat-line:before,
|
||||
.ffz-chat-separator-3d .chat-container.dark .chat-line:before,
|
||||
.ffz-chat-separator-3d .chat-container.force-dark .chat-line:before,
|
||||
.ffz-chat-separator-3d .ember-chat-container.dark .chat-line:before,
|
||||
.ffz-chat-separator-3d .ember-chat-container.force-dark .chat-line:before {
|
||||
border-top-color: rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
.ffz-chat-background .chat-history .chat-line.ffz-alternate:before,
|
||||
.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-alternate:before {
|
||||
|
@ -1655,6 +1686,28 @@ li[data-name="following"] a {
|
|||
}
|
||||
|
||||
.ffz-high-contrast-chat .chat-line .mentioned {
|
||||
color: inherit !important;
|
||||
background-color: transparent !important;
|
||||
color: #fff !important;
|
||||
background-color: #000 !important;
|
||||
}
|
||||
|
||||
.ffz-high-contrast-chat .chat-container.dark .chat-line .mentioned,
|
||||
.ffz-high-contrast-chat .chat-container.force-dark .chat-line .mentioned,
|
||||
.ffz-high-contrast-chat .ember-chat-container.dark .chat-line .mentioned,
|
||||
.ffz-high-contrast-chat .ember-chat-container.force-dark .chat-line .mentioned,
|
||||
.ffz-high-contrast-chat .app-main.theatre .chat-container .chat-line .mentioned,
|
||||
.ffz-high-contrast-chat.ffz-dark .ember-chat-container.dark .chat-line .chat-line .mentioned,
|
||||
.ffz-high-contrast-chat.ffz-dark .chat-container.dark .chat-line .chat-line .mentioned {
|
||||
color: #000 !important;
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
.ffz-image-hover {
|
||||
border:none;
|
||||
max-width: 186px;
|
||||
max-height: 186px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ffz-yt-thumb {
|
||||
max-height: 90px;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue