2015-01-20 20:25:26 -05:00
|
|
|
var FFZ = window.FrankerFaceZ,
|
2015-02-10 01:34:23 -05:00
|
|
|
utils = require("../utils"),
|
2015-01-20 20:25:26 -05:00
|
|
|
|
|
|
|
reg_escape = function(str) {
|
|
|
|
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
2015-02-24 00:33:29 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
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/",
|
|
|
|
build_srcset = function(id) {
|
|
|
|
return TWITCH_BASE + id + "/1.0 1x, " + TWITCH_BASE + id + "/2.0 2x, " + TWITCH_BASE + id + "/3.0 4x";
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
data_to_tooltip = function(data) {
|
2015-02-26 00:42:11 -05:00
|
|
|
var set = data.set,
|
2015-02-24 00:33:29 -05:00
|
|
|
set_type = data.set_type;
|
|
|
|
|
|
|
|
if ( set_type === undefined )
|
|
|
|
set_type = "Channel";
|
|
|
|
|
|
|
|
if ( ! set )
|
|
|
|
return data.code;
|
|
|
|
|
|
|
|
else if ( set == "00000turbo" || set == "turbo" ) {
|
|
|
|
set = "Twitch Turbo";
|
|
|
|
set_type = null;
|
|
|
|
}
|
|
|
|
|
2015-02-26 00:42:11 -05:00
|
|
|
return "Emoticon: " + data.code + "\n" + (set_type ? set_type + ": " : "") + set;
|
2015-02-24 00:33:29 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
build_tooltip = function(id) {
|
|
|
|
var emote_data = this._twitch_emotes[id],
|
|
|
|
set = emote_data ? emote_data.set : null;
|
|
|
|
|
|
|
|
if ( ! emote_data )
|
|
|
|
return "???";
|
|
|
|
|
|
|
|
if ( typeof emote_data == "string" )
|
|
|
|
return emote_data;
|
|
|
|
|
|
|
|
if ( emote_data.tooltip )
|
|
|
|
return emote_data.tooltip;
|
|
|
|
|
|
|
|
return emote_data.tooltip = data_to_tooltip(emote_data);
|
|
|
|
},
|
|
|
|
|
|
|
|
load_emote_data = function(id, code, success, data) {
|
|
|
|
if ( ! success )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( code )
|
|
|
|
data.code = code;
|
|
|
|
|
|
|
|
this._twitch_emotes[id] = data;
|
|
|
|
var tooltip = build_tooltip.bind(this)(id);
|
|
|
|
|
|
|
|
var images = document.querySelectorAll('img[emote-id="' + id + '"]');
|
|
|
|
for(var x=0; x < images.length; x++)
|
|
|
|
images[x].title = tooltip;
|
2015-01-20 20:25:26 -05:00
|
|
|
};
|
2015-01-20 01:53:18 -05:00
|
|
|
|
|
|
|
|
2015-02-08 02:01:09 -05:00
|
|
|
// ---------------------
|
|
|
|
// Settings
|
|
|
|
// ---------------------
|
|
|
|
|
|
|
|
FFZ.settings_info.capitalize = {
|
|
|
|
type: "boolean",
|
|
|
|
value: true,
|
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
category: "Chat",
|
2015-02-08 02:01:09 -05:00
|
|
|
visible: function() { return ! this.has_bttv },
|
|
|
|
|
|
|
|
name: "Username Capitalization",
|
|
|
|
help: "Display names in chat with proper capitalization."
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-02-24 00:33:29 -05:00
|
|
|
FFZ.settings_info.banned_words = {
|
|
|
|
type: "button",
|
|
|
|
value: [],
|
|
|
|
|
|
|
|
category: "Chat",
|
|
|
|
visible: function() { return ! this.has_bttv },
|
|
|
|
|
|
|
|
name: "Banned Words",
|
|
|
|
help: "Set a list of words that will be locally removed from chat messages.",
|
|
|
|
|
|
|
|
method: function() {
|
|
|
|
var old_val = this.settings.banned_words.join(", "),
|
|
|
|
new_val = prompt("Banned Words\n\nPlease enter a comma-separated list of words that you would like to be removed from chat messages.", old_val);
|
|
|
|
|
|
|
|
if ( new_val === null || new_val === undefined )
|
|
|
|
return;
|
|
|
|
|
|
|
|
new_val = new_val.trim().split(SPLITTER);
|
|
|
|
var vals = [];
|
|
|
|
|
|
|
|
for(var i=0; i < new_val.length; i++)
|
|
|
|
new_val[i] && vals.push(new_val[i]);
|
|
|
|
|
|
|
|
if ( vals.length == 1 && vals[0] == "disable" )
|
|
|
|
vals = [];
|
|
|
|
|
|
|
|
this.settings.set("banned_words", vals);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-02-08 02:01:09 -05:00
|
|
|
FFZ.settings_info.keywords = {
|
|
|
|
type: "button",
|
|
|
|
value: [],
|
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
category: "Chat",
|
2015-02-08 02:01:09 -05:00
|
|
|
visible: function() { return ! this.has_bttv },
|
|
|
|
|
|
|
|
name: "Highlight Keywords",
|
|
|
|
help: "Set additional keywords that will be highlighted in chat.",
|
|
|
|
|
|
|
|
method: function() {
|
|
|
|
var old_val = this.settings.keywords.join(", "),
|
|
|
|
new_val = prompt("Highlight Keywords\n\nPlease enter a comma-separated list of words that you would like to be highlighted in chat.", old_val);
|
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
if ( new_val === null || new_val === undefined )
|
2015-02-08 02:01:09 -05:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Split them up.
|
2015-02-24 00:33:29 -05:00
|
|
|
new_val = new_val.trim().split(SPLITTER);
|
|
|
|
var vals = [];
|
|
|
|
|
|
|
|
for(var i=0; i < new_val.length; i++)
|
|
|
|
new_val[i] && vals.push(new_val[i]);
|
2015-02-08 02:01:09 -05:00
|
|
|
|
2015-02-24 00:33:29 -05:00
|
|
|
if ( vals.length == 1 && vals[0] == "disable" )
|
|
|
|
vals = [];
|
2015-02-08 02:01:09 -05:00
|
|
|
|
2015-02-24 00:33:29 -05:00
|
|
|
this.settings.set("keywords", vals);
|
2015-02-08 02:01:09 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
FFZ.settings_info.fix_color = {
|
|
|
|
type: "boolean",
|
2015-02-26 00:42:11 -05:00
|
|
|
value: true,
|
2015-02-10 01:34:23 -05:00
|
|
|
|
|
|
|
category: "Chat",
|
|
|
|
visible: function() { return ! this.has_bttv },
|
|
|
|
|
|
|
|
name: "Adjust Username Colors",
|
|
|
|
help: "Ensure that username colors contrast with the background enough to be readable.",
|
|
|
|
|
|
|
|
on_update: function(val) {
|
|
|
|
if ( this.has_bttv )
|
|
|
|
return;
|
|
|
|
|
|
|
|
document.body.classList.toggle("ffz-chat-colors", val);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-02-08 02:01:09 -05:00
|
|
|
FFZ.settings_info.chat_rows = {
|
|
|
|
type: "boolean",
|
|
|
|
value: false,
|
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
category: "Chat",
|
2015-02-08 02:01:09 -05:00
|
|
|
visible: function() { return ! this.has_bttv },
|
|
|
|
|
|
|
|
name: "Chat Line Backgrounds",
|
|
|
|
help: "Display alternating background colors for lines in chat.",
|
|
|
|
|
|
|
|
on_update: function(val) {
|
2015-02-10 01:34:23 -05:00
|
|
|
if ( this.has_bttv )
|
|
|
|
return;
|
|
|
|
|
|
|
|
document.body.classList.toggle("ffz-chat-background", val);
|
2015-02-08 02:01:09 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-01-20 01:53:18 -05:00
|
|
|
// ---------------------
|
|
|
|
// Initialization
|
|
|
|
// ---------------------
|
|
|
|
|
|
|
|
FFZ.prototype.setup_line = function() {
|
2015-02-10 01:34:23 -05:00
|
|
|
// Chat Enhancements
|
|
|
|
document.body.classList.toggle("ffz-chat-colors", !this.has_bttv && this.settings.fix_color);
|
|
|
|
document.body.classList.toggle('ffz-chat-background', !this.has_bttv && this.settings.chat_rows);
|
|
|
|
|
|
|
|
this._colors = {};
|
2015-02-08 02:01:09 -05:00
|
|
|
this._last_row = {};
|
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
var s = this._fix_color_style = document.createElement('style');
|
|
|
|
s.id = "ffz-style-username-colors";
|
|
|
|
s.type = 'text/css';
|
|
|
|
document.head.appendChild(s);
|
|
|
|
|
|
|
|
|
2015-02-24 00:33:29 -05:00
|
|
|
// Emoticon Data
|
|
|
|
this._twitch_emotes = {};
|
|
|
|
|
|
|
|
|
2015-01-20 01:53:18 -05:00
|
|
|
this.log("Hooking the Ember Line controller.");
|
|
|
|
|
|
|
|
var Line = App.__container__.resolve('controller:line'),
|
|
|
|
f = this;
|
|
|
|
|
|
|
|
Line.reopen({
|
|
|
|
tokenizedMessage: function() {
|
|
|
|
// Add our own step to the tokenization procedure.
|
2015-02-10 01:34:23 -05:00
|
|
|
var tokens = this._super();
|
2015-01-20 20:25:26 -05:00
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
try {
|
2015-02-26 00:42:11 -05:00
|
|
|
var start = performance.now();
|
2015-02-24 00:33:29 -05:00
|
|
|
tokens = f._remove_banned(tokens);
|
2015-02-10 01:34:23 -05:00
|
|
|
tokens = f._emoticonize(this, tokens);
|
|
|
|
var user = f.get_user();
|
|
|
|
|
|
|
|
if ( ! user || this.get("model.from") != user.login )
|
|
|
|
tokens = f._mentionize(this, tokens);
|
|
|
|
|
2015-02-26 00:42:11 -05:00
|
|
|
var end = performance.now();
|
|
|
|
if ( end - start > 5 )
|
2015-03-30 00:52:18 -04:00
|
|
|
f.log("Tokenizing Message Took Too Long - " + (end-start) + "ms", tokens, false, true);
|
2015-02-26 00:42:11 -05:00
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
} catch(err) {
|
|
|
|
try {
|
|
|
|
f.error("LineController tokenizedMessage: " + err);
|
|
|
|
} catch(err) { }
|
|
|
|
}
|
2015-01-20 20:25:26 -05:00
|
|
|
|
|
|
|
return tokens;
|
2015-01-20 01:53:18 -05:00
|
|
|
|
2015-02-08 02:01:09 -05:00
|
|
|
}.property("model.message", "isModeratorOrHigher")
|
2015-01-20 01:53:18 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
this.log("Hooking the Ember Line view.");
|
|
|
|
var Line = App.__container__.resolve('view:line');
|
|
|
|
|
|
|
|
Line.reopen({
|
|
|
|
didInsertElement: function() {
|
|
|
|
this._super();
|
2015-02-10 01:34:23 -05:00
|
|
|
try {
|
2015-02-26 00:42:11 -05:00
|
|
|
var start = performance.now();
|
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
var el = this.get('element'),
|
2015-02-24 00:33:29 -05:00
|
|
|
controller = this.get('context'),
|
|
|
|
user = controller.get('model.from'),
|
|
|
|
room = controller.get('parentController.content.id'),
|
|
|
|
color = controller.get('model.color'),
|
2015-01-20 01:53:18 -05:00
|
|
|
|
2015-02-24 00:33:29 -05:00
|
|
|
row_type = controller.get('model.ffz_alternate');
|
2015-01-20 01:53:18 -05:00
|
|
|
|
2015-02-08 02:01:09 -05:00
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
// 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;
|
|
|
|
this.set("context.model.ffz_alternate", row_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
el.classList.toggle('ffz-alternate', row_type);
|
|
|
|
|
|
|
|
|
|
|
|
// Basic Data
|
|
|
|
el.setAttribute('data-room', room);
|
|
|
|
el.setAttribute('data-sender', user);
|
2015-03-15 21:24:22 -04:00
|
|
|
el.setAttribute('data-deleted', controller.get('model.deleted'));
|
2015-02-10 01:34:23 -05:00
|
|
|
|
|
|
|
|
|
|
|
// Badge
|
|
|
|
f.render_badge(this);
|
|
|
|
|
|
|
|
|
|
|
|
// Capitalization
|
|
|
|
if ( f.settings.capitalize )
|
|
|
|
f.capitalize(this, user);
|
|
|
|
|
|
|
|
|
|
|
|
// Mention Highlighting
|
|
|
|
var mentioned = el.querySelector('span.mentioned');
|
|
|
|
if ( mentioned ) {
|
|
|
|
el.classList.add("ffz-mentioned");
|
|
|
|
|
2015-02-26 00:42:11 -05:00
|
|
|
if ( f.settings.highlight_notifications && !document.hasFocus() && !this.get('context.model.ffz_notified') ) {
|
2015-02-10 01:34:23 -05:00
|
|
|
var cap_room = FFZ.get_capitalization(room),
|
|
|
|
cap_user = FFZ.get_capitalization(user),
|
|
|
|
room_name = cap_room,
|
|
|
|
msg = this.get("context.model.message");
|
|
|
|
|
|
|
|
if ( this.get("context.parentController.content.isGroupRoom") )
|
|
|
|
room_name = this.get("context.parentController.content.tmiRoom.displayName");
|
|
|
|
|
|
|
|
if ( this.get("context.model.style") == "action" )
|
|
|
|
msg = "* " + cap_user + " " + msg;
|
|
|
|
else
|
|
|
|
msg = cap_user + ": " + msg;
|
|
|
|
|
|
|
|
f.show_notification(
|
|
|
|
msg,
|
|
|
|
"Twitch Chat Mention in " + room_name,
|
|
|
|
cap_room,
|
|
|
|
60000,
|
|
|
|
window.focus.bind(window)
|
|
|
|
);
|
|
|
|
}
|
2015-02-08 02:01:09 -05:00
|
|
|
}
|
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
// Mark that we've checked this message for mentions.
|
|
|
|
this.set('context.model.ffz_notified', true);
|
|
|
|
|
2015-02-24 00:33:29 -05:00
|
|
|
|
|
|
|
// Banned Links
|
|
|
|
var bad_links = el.querySelectorAll('a.deleted-link');
|
|
|
|
for(var i=0; i < bad_links.length; i++) {
|
2015-02-26 00:42:11 -05:00
|
|
|
var link = bad_links[i];
|
2015-02-24 00:33:29 -05:00
|
|
|
|
|
|
|
link.addEventListener("click", function(e) {
|
|
|
|
if ( ! this.classList.contains("deleted-link") )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Get the URL
|
|
|
|
var href = this.getAttribute('data-url'),
|
|
|
|
link = href;
|
|
|
|
|
|
|
|
// Delete Old Stuff
|
|
|
|
this.classList.remove('deleted-link');
|
|
|
|
this.removeAttribute("data-url");
|
|
|
|
this.removeAttribute("title");
|
|
|
|
this.removeAttribute("original-title");
|
|
|
|
|
|
|
|
// Process URL
|
|
|
|
if ( href.indexOf("@") > -1 && (-1 === href.indexOf("/") || href.indexOf("@") < href.indexOf("/")) )
|
|
|
|
href = "mailto:" + href;
|
|
|
|
else if ( ! href.match(/^https?:\/\//) )
|
|
|
|
href = "http://" + href;
|
|
|
|
|
|
|
|
// Set up the Link
|
|
|
|
this.href = href;
|
|
|
|
this.target = "_new";
|
|
|
|
this.textContent = link;
|
|
|
|
|
|
|
|
// Stop from Navigating
|
|
|
|
e.preventDefault();
|
|
|
|
});
|
|
|
|
|
|
|
|
// Also add a nice tooltip.
|
|
|
|
jQuery(link).tipsy();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Enhanced Emotes
|
2015-02-26 00:42:11 -05:00
|
|
|
var images = el.querySelectorAll('img.emoticon');
|
2015-02-24 00:33:29 -05:00
|
|
|
for(var i=0; i < images.length; i++) {
|
|
|
|
var img = images[i],
|
|
|
|
name = img.alt,
|
|
|
|
match = /\/emoticons\/v1\/(\d+)\/1\.0/.exec(img.src),
|
|
|
|
id = match ? parseInt(match[1]) : null;
|
|
|
|
|
|
|
|
if ( id !== null ) {
|
|
|
|
// High-DPI Images
|
|
|
|
img.setAttribute('srcset', build_srcset(id));
|
|
|
|
img.setAttribute('emote-id', id);
|
|
|
|
|
|
|
|
// Source Lookup
|
|
|
|
var emote_data = f._twitch_emotes[id];
|
|
|
|
if ( emote_data ) {
|
|
|
|
if ( typeof emote_data != "string" )
|
|
|
|
img.title = emote_data.tooltip;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
f._twitch_emotes[id] = img.alt;
|
|
|
|
f.ws_send("twitch_emote", id, load_emote_data.bind(f, id, img.alt));
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if ( img.getAttribute('data-ffz-emote') ) {
|
|
|
|
var data = JSON.parse(decodeURIComponent(img.getAttribute('data-ffz-emote'))),
|
|
|
|
id = data && data[0] || null,
|
|
|
|
set_id = data && data[1] || null,
|
|
|
|
|
|
|
|
set = f.emote_sets[set_id],
|
|
|
|
emote = set ? set.emotes[id] : null,
|
|
|
|
|
2015-03-30 00:52:18 -04:00
|
|
|
set_name = set ? (set.title || set.id) : "Unknown FFZ Set",
|
|
|
|
set_type = (set && set.title) ? "FrankerFaceZ" : "FFZ Channel";
|
2015-02-24 00:33:29 -05:00
|
|
|
|
2015-03-30 00:52:18 -04:00
|
|
|
if ( set && f.feature_friday && set.id == f.feature_friday.set )
|
2015-02-24 00:33:29 -05:00
|
|
|
set_name = "Feature Friday - " + f.feature_friday.channel;
|
|
|
|
|
|
|
|
img.title = data_to_tooltip({
|
2015-03-30 00:52:18 -04:00
|
|
|
code: emote ? (emote.hidden ? "???" : emote.name) : name,
|
2015-02-24 00:33:29 -05:00
|
|
|
set: set_name,
|
|
|
|
set_type: set_type
|
|
|
|
});
|
2015-02-26 00:42:11 -05:00
|
|
|
}
|
|
|
|
}
|
2015-02-24 00:33:29 -05:00
|
|
|
|
2015-02-26 00:42:11 -05:00
|
|
|
jQuery(images).tipsy();
|
2015-02-24 00:33:29 -05:00
|
|
|
|
|
|
|
|
2015-02-26 00:42:11 -05:00
|
|
|
var duration = performance.now() - start;
|
|
|
|
if ( duration > 5 )
|
2015-03-30 00:52:18 -04:00
|
|
|
f.log("Line Took Too Long - " + duration + "ms", el.innerHTML, false, true);
|
2015-02-24 00:33:29 -05:00
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
} catch(err) {
|
|
|
|
try {
|
|
|
|
f.error("LineView didInsertElement: " + err);
|
|
|
|
} catch(err) { }
|
|
|
|
}
|
2015-01-20 01:53:18 -05:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
|
2015-01-20 01:53:18 -05:00
|
|
|
// Store the capitalization of our own name.
|
|
|
|
var user = this.get_user();
|
|
|
|
if ( user && user.name )
|
|
|
|
FFZ.capitalization[user.login] = [user.name, Date.now()];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
// ---------------------
|
|
|
|
// 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;
|
|
|
|
|
2015-02-26 00:42:11 -05:00
|
|
|
var s = 127,
|
2015-02-10 01:34:23 -05:00
|
|
|
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';
|
|
|
|
|
2015-02-26 00:42:11 -05:00
|
|
|
if ( lum < 0.15 ) {
|
2015-02-10 01:34:23 -05:00
|
|
|
// Color Too Dark. We need a lum of 0.1 or more.
|
|
|
|
matched = true;
|
|
|
|
|
2015-02-26 00:42:11 -05:00
|
|
|
var s = 127,
|
2015-02-10 01:34:23 -05:00
|
|
|
nc = rgb;
|
|
|
|
while(s--) {
|
|
|
|
nc = utils.brighten(nc);
|
2015-02-26 00:42:11 -05:00
|
|
|
if ( utils.get_luminance(nc) >= 0.15 )
|
2015-02-10 01:34:23 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-20 01:53:18 -05:00
|
|
|
// ---------------------
|
|
|
|
// Capitalization
|
|
|
|
// ---------------------
|
|
|
|
|
|
|
|
FFZ.capitalization = {};
|
|
|
|
FFZ._cap_fetching = 0;
|
|
|
|
|
|
|
|
FFZ.get_capitalization = function(name, callback) {
|
2015-02-08 02:01:09 -05:00
|
|
|
// Use the BTTV code if it's present.
|
2015-02-24 00:33:29 -05:00
|
|
|
if ( window.BetterTTV && BetterTTV.chat && BetterTTV.chat.helpers.lookupDisplayName )
|
2015-02-08 02:01:09 -05:00
|
|
|
return BetterTTV.chat.helpers.lookupDisplayName(name);
|
|
|
|
|
2015-02-08 02:59:20 -05:00
|
|
|
if ( ! name )
|
|
|
|
return name;
|
|
|
|
|
2015-01-20 01:53:18 -05:00
|
|
|
name = name.toLowerCase();
|
|
|
|
if ( name == "jtv" || name == "twitchnotify" )
|
|
|
|
return name;
|
|
|
|
|
|
|
|
var old_data = FFZ.capitalization[name];
|
|
|
|
if ( old_data ) {
|
|
|
|
if ( Date.now() - old_data[1] < 3600000 )
|
|
|
|
return old_data[0];
|
|
|
|
}
|
|
|
|
|
2015-02-24 00:33:29 -05:00
|
|
|
if ( FFZ._cap_fetching < 25 ) {
|
2015-01-20 01:53:18 -05:00
|
|
|
FFZ._cap_fetching++;
|
2015-02-24 00:33:29 -05:00
|
|
|
FFZ.get().ws_send("get_display_name", name, function(success, data) {
|
|
|
|
var cap_name = success ? data : name;
|
|
|
|
FFZ.capitalization[name] = [cap_name, Date.now()];
|
|
|
|
FFZ._cap_fetching--;
|
|
|
|
typeof callback === "function" && callback(cap_name);
|
|
|
|
});
|
2015-01-20 01:53:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return old_data ? old_data[0] : name;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FFZ.prototype.capitalize = function(view, user) {
|
|
|
|
var name = FFZ.get_capitalization(user, this.capitalize.bind(this, view));
|
2015-02-26 00:42:11 -05:00
|
|
|
if ( !name || !view )
|
|
|
|
return;
|
|
|
|
|
|
|
|
var from = view.$('.from');
|
|
|
|
from && from.text(name);
|
2015-01-20 01:53:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-20 20:25:26 -05:00
|
|
|
// ---------------------
|
|
|
|
// Extra Mentions
|
|
|
|
// ---------------------
|
|
|
|
|
|
|
|
FFZ._regex_cache = {};
|
|
|
|
|
2015-02-10 01:34:23 -05:00
|
|
|
FFZ._get_regex = function(word) {
|
2015-02-08 02:01:09 -05:00
|
|
|
return FFZ._regex_cache[word] = FFZ._regex_cache[word] || RegExp("\\b" + reg_escape(word) + "\\b", "ig");
|
|
|
|
}
|
|
|
|
|
2015-02-24 00:33:29 -05:00
|
|
|
FFZ._words_to_regex = function(list) {
|
|
|
|
var regex = FFZ._regex_cache[list];
|
|
|
|
if ( ! regex ) {
|
|
|
|
var reg = "";
|
|
|
|
for(var i=0; i < list.length; i++) {
|
|
|
|
if ( ! list[i] )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
reg += (reg ? "|" : "") + reg_escape(list[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
regex = FFZ._regex_cache[list] = new RegExp("(^|.*?" + SEPARATORS + ")(" + reg + ")(?=$|" + SEPARATORS + ")", "ig");
|
|
|
|
}
|
|
|
|
|
|
|
|
return regex;
|
2015-01-20 20:25:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FFZ.prototype._mentionize = function(controller, tokens) {
|
2015-02-08 02:01:09 -05:00
|
|
|
var mention_words = this.settings.keywords;
|
2015-02-08 02:59:20 -05:00
|
|
|
if ( ! mention_words || ! mention_words.length )
|
2015-01-20 20:25:26 -05:00
|
|
|
return tokens;
|
|
|
|
|
|
|
|
if ( typeof tokens == "string" )
|
|
|
|
tokens = [tokens];
|
|
|
|
|
2015-02-24 00:33:29 -05:00
|
|
|
var regex = FFZ._words_to_regex(mention_words),
|
|
|
|
new_tokens = [];
|
|
|
|
|
|
|
|
for(var i=0; i < tokens.length; i++) {
|
|
|
|
var token = tokens[i];
|
|
|
|
if ( ! _.isString(token) ) {
|
|
|
|
new_tokens.push(token);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! token.match(regex) ) {
|
|
|
|
new_tokens.push(token);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
token = token.replace(regex, function(all, prefix, match) {
|
|
|
|
new_tokens.push(prefix);
|
|
|
|
new_tokens.push({
|
|
|
|
mentionedUser: match,
|
|
|
|
own: false
|
|
|
|
});
|
|
|
|
|
|
|
|
return "";
|
|
|
|
});
|
|
|
|
|
|
|
|
if ( token )
|
|
|
|
new_tokens.push(token);
|
|
|
|
}
|
|
|
|
|
|
|
|
return new_tokens;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ---------------------
|
|
|
|
// Banned Words
|
|
|
|
// ---------------------
|
|
|
|
|
|
|
|
FFZ.prototype._remove_banned = function(tokens) {
|
|
|
|
var banned_words = this.settings.banned_words;
|
|
|
|
if ( ! banned_words || ! banned_words.length )
|
|
|
|
return tokens;
|
|
|
|
|
|
|
|
if ( typeof tokens == "string" )
|
|
|
|
tokens = [tokens];
|
|
|
|
|
|
|
|
var regex = FFZ._words_to_regex(banned_words),
|
|
|
|
new_tokens = [];
|
|
|
|
|
|
|
|
for(var i=0; i < tokens.length; i++) {
|
|
|
|
var token = tokens[i];
|
|
|
|
if ( ! _.isString(token ) ) {
|
|
|
|
if ( token.emoticonSrc && regex.test(token.altText) )
|
|
|
|
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">',
|
|
|
|
own: true
|
|
|
|
});
|
|
|
|
else
|
|
|
|
new_tokens.push(token);
|
|
|
|
|
|
|
|
} else
|
|
|
|
new_tokens.push(token.replace(regex, "$1***"));
|
|
|
|
}
|
|
|
|
|
|
|
|
return new_tokens;
|
2015-01-20 20:25:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-20 01:53:18 -05:00
|
|
|
// ---------------------
|
|
|
|
// Emoticon Replacement
|
|
|
|
// ---------------------
|
|
|
|
|
|
|
|
FFZ.prototype._emoticonize = function(controller, tokens) {
|
|
|
|
var room_id = controller.get("parentController.model.id"),
|
|
|
|
user_id = controller.get("model.from"),
|
|
|
|
f = this;
|
|
|
|
|
|
|
|
// Get our sets.
|
|
|
|
var sets = this.getEmotes(user_id, room_id),
|
|
|
|
emotes = [];
|
|
|
|
|
|
|
|
// Build a list of emotes that match.
|
|
|
|
_.each(sets, function(set_id) {
|
|
|
|
var set = f.emote_sets[set_id];
|
|
|
|
if ( ! set )
|
|
|
|
return;
|
|
|
|
|
|
|
|
_.each(set.emotes, function(emote) {
|
|
|
|
_.any(tokens, function(token) {
|
|
|
|
return _.isString(token) && token.match(emote.regex);
|
|
|
|
}) && emotes.push(emote);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// Don't bother proceeding if we have no emotes.
|
|
|
|
if ( ! emotes.length )
|
|
|
|
return tokens;
|
|
|
|
|
|
|
|
// Now that we have all the matching tokens, do crazy stuff.
|
|
|
|
if ( typeof tokens == "string" )
|
|
|
|
tokens = [tokens];
|
|
|
|
|
|
|
|
// This is weird stuff I basically copied from the old Twitch code.
|
|
|
|
// Here, for each emote, we split apart every text token and we
|
|
|
|
// put it back together with the matching bits of text replaced
|
|
|
|
// with an object telling Twitch's line template how to render the
|
|
|
|
// emoticon.
|
|
|
|
_.each(emotes, function(emote) {
|
|
|
|
//var eo = {isEmoticon:true, cls: emote.klass};
|
2015-02-24 00:33:29 -05:00
|
|
|
var eo = {isEmoticon:true, cls: emote.klass, emoticonSrc: emote.url + '" data-ffz-emote="' + encodeURIComponent(JSON.stringify([emote.id, emote.set_id])), altText: (emote.hidden ? "???" : emote.name)};
|
2015-01-20 01:53:18 -05:00
|
|
|
|
|
|
|
tokens = _.compact(_.flatten(_.map(tokens, function(token) {
|
|
|
|
if ( _.isObject(token) )
|
|
|
|
return token;
|
|
|
|
|
|
|
|
var tbits = token.split(emote.regex), bits = [];
|
|
|
|
tbits.forEach(function(val, ind) {
|
|
|
|
bits.push(val);
|
|
|
|
if ( ind !== tbits.length - 1 )
|
|
|
|
bits.push(eo);
|
|
|
|
});
|
|
|
|
return bits;
|
|
|
|
})));
|
|
|
|
});
|
|
|
|
|
|
|
|
return tokens;
|
2015-01-12 17:58:07 -05:00
|
|
|
}
|