2015-05-17 19:02:57 -04:00
var FFZ = window . FrankerFaceZ ,
2015-02-10 01:34:23 -05:00
utils = require ( "../utils" ) ,
2015-01-20 20:25:26 -05:00
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/" ,
2015-07-04 17:06:36 -04:00
SRCSETS = { } ;
2015-02-24 00:33:29 -05:00
build _srcset = function ( id ) {
2015-07-04 17:06:36 -04:00
if ( SRCSETS [ id ] )
return SRCSETS [ id ] ;
var out = SRCSETS [ id ] = TWITCH _BASE + id + "/1.0 1x, " + TWITCH _BASE + id + "/2.0 2x, " + TWITCH _BASE + id + "/3.0 4x" ;
return out ;
2015-02-24 00:33:29 -05:00
} ,
data _to _tooltip = function ( data ) {
2015-02-26 00:42:11 -05:00
var set = data . set ,
2015-06-05 03:59:28 -04:00
set _type = data . set _type ,
owner = data . owner ;
2015-02-24 00:33:29 -05:00
if ( set _type === undefined )
set _type = "Channel" ;
if ( ! set )
return data . code ;
2015-07-04 17:06:36 -04:00
else if ( set == "--twitch-turbo--" || set == "turbo" ) {
2015-02-24 00:33:29 -05:00
set = "Twitch Turbo" ;
set _type = null ;
}
2015-06-05 03:59:28 -04:00
return "Emoticon: " + data . code + "\n" + ( set _type ? set _type + ": " : "" ) + set + ( owner ? "\nBy: " + owner . display _name : "" ) ;
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-05-17 19:02:57 -04:00
} ,
2015-01-20 01:53:18 -05:00
2015-05-17 19:02:57 -04:00
build _link _tooltip = function ( href ) {
var link _data = this . _link _data [ href ] ,
tooltip ;
2015-01-20 01:53:18 -05:00
2015-05-17 19:02:57 -04:00
if ( ! link _data )
return "" ;
2015-02-08 02:01:09 -05:00
2015-05-17 19:02:57 -04:00
if ( link _data . tooltip )
return link _data . tooltip ;
2015-02-08 02:01:09 -05:00
2015-05-17 19:02:57 -04:00
if ( link _data . type == "youtube" ) {
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 ) ;
} else if ( link _data . type == "strawpoll" ) {
tooltip = "<b>Strawpoll: " + utils . sanitize ( link _data . title ) + "</b><hr><table><tbody>" ;
for ( var key in link _data . items ) {
var votes = link _data . items [ key ] ,
percentage = Math . floor ( ( votes / link _data . total ) * 100 ) ;
tooltip += '<tr><td style="text-align:left">' + utils . sanitize ( key ) + '</td><td style="text-align:right">' + utils . number _commas ( votes ) + "</td></tr>" ;
}
tooltip += "</tbody></table><hr>Total: " + utils . number _commas ( link _data . total ) ;
var fetched = utils . parse _date ( link _data . fetched ) ;
if ( fetched ) {
var age = Math . floor ( ( fetched . getTime ( ) - Date . now ( ) ) / 1000 ) ;
if ( age > 60 )
tooltip += "<br><small>Data was cached " + utils . time _to _string ( age ) + " ago.</small>" ;
}
} else if ( link _data . type == "twitch" ) {
tooltip = "<b>Twitch: " + utils . sanitize ( link _data . display _name ) + "</b><hr>" ;
var since = utils . parse _date ( link _data . since ) ;
if ( since )
tooltip += "Member Since: " + utils . date _string ( since ) + "<br>" ;
tooltip += "<nobr>Views: " + utils . number _commas ( link _data . views ) + "</nobr> | <nobr>Followers: " + utils . number _commas ( link _data . followers ) + "</nobr>" ;
2015-06-05 03:59:28 -04:00
} else if ( link _data . type == "twitch_vod" ) {
tooltip = "<b>Twitch " + ( link _data . broadcast _type == "highlight" ? "Highlight" : "Broadcast" ) + ": " + utils . sanitize ( link _data . title ) + "</b><hr>" ;
tooltip += "By: " + utils . sanitize ( link _data . display _name ) + ( link _data . game ? " | Playing: " + utils . sanitize ( link _data . game ) : " | Not Playing" ) + "<br>" ;
tooltip += "Views: " + utils . number _commas ( link _data . views ) + " | " + utils . time _to _string ( link _data . length ) ;
2015-05-17 19:02:57 -04:00
} else if ( link _data . type == "twitter" ) {
tooltip = "<b>Tweet By: " + utils . sanitize ( link _data . user ) + "</b><hr>" ;
tooltip += utils . sanitize ( link _data . tweet ) ;
} else if ( link _data . type == "reputation" ) {
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 ;
if ( link _data . trust < 50 || link _data . safety < 50 ) {
link _data . unsafe = true ;
tooltip += "<b>Potentially Unsafe Link</b><br>" ;
tooltip += "Trust: " + link _data . trust + "% | Child Safety: " + link _data . safety + "%" ;
had _extra = true ;
}
if ( link _data . tags && link _data . tags . length > 0 )
tooltip += ( had _extra ? "<br>" : "" ) + "Tags: " + link _data . tags . join ( ", " ) ;
tooltip += "<br>Data Source: WOT" ;
}
} else if ( link _data . full )
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>' ;
link _data . tooltip = tooltip ;
return tooltip ;
} ,
load _link _data = function ( href , success , data ) {
if ( ! success )
return ;
this . _link _data [ href ] = data ;
data . unsafe = false ;
var tooltip = build _link _tooltip . bind ( this ) ( href ) , links ,
no _trail = href . charAt ( href . length - 1 ) == "/" ? href . substr ( 0 , href . length - 1 ) : null ;
if ( no _trail )
links = document . querySelectorAll ( 'span.message a[href="' + href + '"], span.message a[href="' + no _trail + '"], span.message a[data-url="' + href + '"], span.message a[data-url="' + no _trail + '"]' ) ;
else
links = document . querySelectorAll ( 'span.message a[href="' + href + '"], span.message a[data-url="' + href + '"]' ) ;
if ( ! this . settings . link _info )
return ;
for ( var x = 0 ; x < links . length ; x ++ ) {
if ( data . unsafe )
links [ x ] . classList . add ( 'unsafe-link' ) ;
2015-02-08 02:01:09 -05:00
2015-05-17 19:02:57 -04:00
if ( ! links [ x ] . classList . contains ( 'deleted-link' ) )
links [ x ] . title = tooltip ;
}
2015-02-08 02:01:09 -05:00
} ;
2015-05-17 19:02:57 -04:00
// ---------------------
// Settings
// ---------------------
2015-07-06 00:09:21 -04:00
FFZ . settings _info . room _status = {
type : "boolean" ,
value : true ,
category : "Chat" ,
no _bttv : true ,
name : "Room Status Indicators" ,
help : "Display the current room state (slow mode, sub mode, and r9k mode) next to the Chat button." ,
on _update : function ( ) {
if ( this . _roomv )
this . _roomv . ffzUpdateStatus ( ) ;
}
} ;
FFZ . settings _info . replace _bad _emotes = {
type : "boolean" ,
value : true ,
category : "Chat" ,
name : "Fix Low Quality Twitch Global Emoticons" ,
help : "Replace emoticons such as DansGame and RedCoat with cleaned up versions that don't have pixels around the edges or white backgrounds for nicer display on dark chat."
}
2015-07-04 17:06:36 -04:00
FFZ . settings _info . parse _emoji = {
type : "boolean" ,
value : true ,
category : "Chat" ,
name : "Replace Emoji with Images" ,
help : "Replace emoji in chat messages with nicer looking images from the open-source Twitter Emoji project."
} ;
FFZ . settings _info . room _status = {
type : "boolean" ,
value : true ,
category : "Chat" ,
no _bttv : true ,
name : "Room Status Indicators" ,
help : "Display the current room state (slow mode, sub mode, and r9k mode) next to the Chat button." ,
on _update : function ( ) {
if ( this . _roomv )
this . _roomv . ffzUpdateStatus ( ) ;
}
} ;
FFZ . settings _info . scrollback _length = {
type : "button" ,
value : 150 ,
category : "Chat" ,
no _bttv : true ,
name : "Scrollback Length" ,
help : "Set the maximum number of lines to keep in chat." ,
method : function ( ) {
var new _val = prompt ( "Scrollback Length\n\nPlease enter a new maximum length for the chat scrollback. Default: 150\n\nNote: Making this too large will cause your browser to lag." , this . settings . scrollback _length ) ;
if ( new _val === null || new _val === undefined )
return ;
new _val = parseInt ( new _val ) ;
if ( new _val === NaN )
return ;
if ( new _val < 10 )
new _val = 10 ;
this . settings . set ( "scrollback_length" , new _val ) ;
// Update our everything.
var Chat = App . _ _container _ _ . lookup ( 'controller:chat' ) ,
current _id = Chat && Chat . get ( 'currentRoom.id' ) ;
for ( var room _id in this . rooms ) {
var room = this . rooms [ room _id ] ;
room . room . set ( 'messageBufferSize' , new _val + ( ( this . _roomv && ! this . _roomv . get ( 'stuckToBottom' ) && current _id === room _id ) ? 150 : 0 ) ) ;
}
}
} ;
2015-02-24 00:33:29 -05:00
FFZ . settings _info . banned _words = {
type : "button" ,
value : [ ] ,
category : "Chat" ,
2015-05-17 19:02:57 -04:00
no _bttv : true ,
//visible: function() { return ! this.has_bttv },
2015-02-24 00:33:29 -05:00
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-05-17 19:02:57 -04:00
no _bttv : true ,
//visible: function() { return ! this.has_bttv },
2015-02-08 02:01:09 -05:00
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" ,
2015-05-17 19:02:57 -04:00
no _bttv : true ,
//visible: function() { return ! this.has_bttv },
2015-02-10 01:34:23 -05:00
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-05-17 19:02:57 -04:00
FFZ . settings _info . link _info = {
type : "boolean" ,
value : true ,
category : "Chat" ,
no _bttv : true ,
//visible: function() { return ! this.has_bttv },
name : "Link Tooltips <span>Beta</span>" ,
help : "Check links against known bad websites, unshorten URLs, and show YouTube info."
} ;
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-05-17 19:02:57 -04:00
no _bttv : true ,
//visible: function() { return ! this.has_bttv },
2015-02-08 02:01:09 -05:00
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-05-17 19:02:57 -04:00
this . _link _data = { } ;
2015-02-24 00:33:29 -05:00
2015-06-10 18:46:04 -04:00
this . log ( "Hooking the Ember Whisper controller." ) ;
var Whisper = App . _ _container _ _ . resolve ( 'component:whisper-line' ) ;
if ( Whisper )
this . _modify _line ( Whisper ) ;
2015-02-24 00:33:29 -05:00
2015-01-20 01:53:18 -05:00
this . log ( "Hooking the Ember Line controller." ) ;
2015-06-10 18:46:04 -04:00
var Line = App . _ _container _ _ . resolve ( 'component:message-line' ) ;
if ( Line )
this . _modify _line ( Line ) ;
2015-01-20 01:53:18 -05:00
2015-06-10 18:46:04 -04: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 ( ) ] ;
}
FFZ . prototype . _modify _line = function ( component ) {
var f = this ;
component . reopen ( {
2015-01-20 01:53:18 -05:00
tokenizedMessage : function ( ) {
// Add our own step to the tokenization procedure.
2015-06-05 03:59:28 -04:00
var tokens = this . get ( "msgObject.cachedTokens" ) ;
if ( tokens )
return tokens ;
tokens = this . _super ( ) ;
2015-01-20 20:25:26 -05:00
2015-02-10 01:34:23 -05:00
try {
2015-06-05 03:59:28 -04:00
var start = performance . now ( ) ,
user = f . get _user ( ) ,
from _me = user && this . get ( "msgObject.from" ) === user . login ;
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 ) ;
2015-07-04 17:06:36 -04:00
if ( f . settings . parse _emoji )
tokens = f . tokenize _emoji ( tokens ) ;
2015-05-17 19:02:57 -04:00
// Store the capitalization.
2015-06-05 03:59:28 -04:00
var display = this . get ( "msgObject.tags.display-name" ) ;
2015-05-17 19:02:57 -04:00
if ( display && display . length )
2015-06-05 03:59:28 -04:00
FFZ . capitalization [ this . get ( "msgObject.from" ) ] = [ display . trim ( ) , Date . now ( ) ] ;
if ( ! from _me )
tokens = f . tokenize _mentions ( tokens ) ;
for ( var i = 0 ; i < tokens . length ; i ++ ) {
var token = tokens [ i ] ;
if ( ! _ . isString ( token ) && token . mentionedUser && ! token . own ) {
this . set ( 'msgObject.ffz_has_mention' , true ) ;
break ;
}
}
2015-05-17 19:02:57 -04:00
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
2015-06-05 03:59:28 -04:00
this . set ( "msgObject.cachedTokens" , tokens ) ;
2015-01-20 20:25:26 -05:00
return tokens ;
2015-01-20 01:53:18 -05:00
2015-06-05 03:59:28 -04:00
} . property ( "msgObject.message" , "isChannelLinksDisabled" , "currentUserNick" , "msgObject.from" , "msgObject.tags.emotes" ) ,
2015-01-20 01:53:18 -05:00
2015-06-10 18:46:04 -04:00
ffzUpdated : Ember . observer ( "msgObject.ffz_deleted" , "msgObject.ffz_old_messages" , function ( ) {
this . rerender ( ) ;
} ) ,
2015-07-04 17:06:36 -04:00
willClearRender : function ( ) {
// This is here to prevent tipsy tooltips from hanging around.
try {
this . $ ( 'a.mod-icon' ) . tipsy ( 'disable' ) ;
jQuery ( 'body > .tipsy:last' ) . remove ( ) ;
} catch ( err ) {
f . error ( "LineView willClearRender: " + err ) ;
}
this . _super ( ) ;
} ,
2015-01-20 01:53:18 -05:00
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-06-05 03:59:28 -04:00
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' ) ;
2015-01-20 01:53:18 -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 ;
2015-06-05 03:59:28 -04:00
this . set ( "msgObject.ffz_alternate" , row _type ) ;
2015-02-10 01:34:23 -05:00
}
2015-07-04 17:06:36 -04:00
el . classList . toggle ( 'ffz-alternate' , row _type || false ) ;
el . classList . toggle ( 'ffz-deleted' , f . settings . prevent _clear && this . get ( 'msgObject.ffz_deleted' ) || false ) ;
2015-02-10 01:34:23 -05:00
// Basic Data
el . setAttribute ( 'data-room' , room ) ;
el . setAttribute ( 'data-sender' , user ) ;
2015-06-10 18:46:04 -04:00
el . setAttribute ( 'data-deleted' , this . get ( 'msgObject.deleted' ) || false ) ;
// Old Messages (for Chat Clear)
var old _messages = this . get ( "msgObject.ffz_old_messages" ) ;
if ( old _messages && old _messages . length ) {
var btn = document . createElement ( 'div' ) ;
btn . className = 'button primary float-right' ;
btn . innerHTML = 'Show ' + utils . number _commas ( old _messages . length ) + ' Old' ;
btn . addEventListener ( "click" , f . _show _deleted . bind ( f , room ) ) ;
el . classList . add ( 'clearfix' ) ;
el . classList . add ( 'ffz-has-deleted' ) ;
this . $ ( '.message' ) . append ( btn ) ;
}
2015-02-10 01:34:23 -05:00
// Badge
f . render _badge ( this ) ;
// Mention Highlighting
2015-06-05 03:59:28 -04:00
if ( this . get ( "msgObject.ffz_has_mention" ) )
2015-02-10 01:34:23 -05:00
el . classList . add ( "ffz-mentioned" ) ;
2015-02-24 00:33:29 -05:00
// Banned Links
2015-07-04 17:06:36 -04:00
var bad _links = el . querySelectorAll ( 'span.message a.deleted-link' ) ;
for ( var i = 0 ; i < bad _links . length ; i ++ )
bad _links [ i ] . addEventListener ( "click" , f . _deleted _link _click ) ;
2015-05-17 19:02:57 -04:00
// Link Tooltips
if ( f . settings . link _info ) {
var links = el . querySelectorAll ( "span.message a" ) ;
for ( var i = 0 ; i < links . length ; i ++ ) {
var link = links [ i ] ,
href = link . href ,
deleted = false ;
if ( link . classList . contains ( "deleted-link" ) ) {
href = link . getAttribute ( "data-url" ) ;
deleted = true ;
}
// Check the cache.
var link _data = f . _link _data [ href ] ;
if ( link _data ) {
if ( ! deleted && typeof link _data != "boolean" )
link . title = link _data . tooltip ;
if ( link _data . unsafe )
link . classList . add ( 'unsafe-link' ) ;
} else if ( ! /^mailto:/ . test ( href ) ) {
f . _link _data [ href ] = true ;
f . ws _send ( "get_link" , href , load _link _data . bind ( f , href ) ) ;
}
}
jQuery ( links ) . tipsy ( { html : true } ) ;
2015-02-24 00:33:29 -05:00
}
// Enhanced Emotes
2015-07-04 17:06:36 -04:00
var images = el . querySelectorAll ( 'span.message 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 ,
2015-07-04 17:06:36 -04:00
id = FFZ . src _to _id ( img . src ) ;
2015-02-24 00:33:29 -05:00
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 ) ) ;
}
2015-07-04 17:06:36 -04:00
} else if ( img . getAttribute ( 'data-ffz-emoji' ) ) {
var eid = img . getAttribute ( 'data-ffz-emoji' ) ,
data = f . emoji _data && f . emoji _data [ eid ] ;
if ( data ) {
img . setAttribute ( 'srcset' , data . srcSet ) ;
2015-07-06 00:09:21 -04:00
img . title = "Emoji: " + img . alt + "\nName: :" + data . short _name + ":" ;
2015-07-04 17:06:36 -04:00
}
2015-02-24 00:33:29 -05:00
} 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 ] ,
2015-06-05 03:59:28 -04:00
emote = set ? set . emoticons [ id ] : null ;
2015-02-24 00:33:29 -05:00
2015-06-05 03:59:28 -04:00
// High-DPI!
if ( emote && emote . srcSet )
img . setAttribute ( 'srcset' , emote . srcSet ) ;
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-04-15 21:00:52 -04:00
set _name = f . feature _friday . title + " - " + f . feature _friday . display _name ;
2015-02-24 00:33:29 -05:00
2015-06-05 03:59:28 -04:00
img . title = f . _emote _tooltip ( emote ) ;
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
// ---------------------
// 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: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 ;
}
2015-02-24 00:33:29 -05:00
// ---------------------
// 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
// ---------------------
2015-06-05 03:59:28 -04:00
FFZ . prototype . _emoticonize = function ( component , tokens ) {
2015-06-10 18:46:04 -04:00
var room _id = component . get ( "msgObject.room" ) ,
2015-06-05 03:59:28 -04:00
user _id = component . get ( "msgObject.from" ) ;
2015-01-20 01:53:18 -05:00
2015-06-05 03:59:28 -04:00
return this . tokenize _emotes ( user _id , room _id , tokens ) ;
2015-01-12 17:58:07 -05:00
}