2015-01-20 20:25:26 -05:00
var FFZ = window . FrankerFaceZ ,
reg _escape = function ( str ) {
return str . replace ( /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g , "\\$&" ) ;
} ;
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 ,
visible : function ( ) { return ! this . has _bttv } ,
name : "Username Capitalization" ,
help : "Display names in chat with proper capitalization."
} ;
FFZ . settings _info . keywords = {
type : "button" ,
value : [ ] ,
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 ) ;
if ( ! new _val )
return ;
// Split them up.
new _val = new _val . trim ( ) . split ( /\W*,\W*/ ) ;
if ( new _val . length == 1 && ( new _val [ 0 ] == "" || new _val [ 0 ] == "disable" ) )
new _val = [ ] ;
this . settings . set ( "keywords" , new _val ) ;
}
} ;
FFZ . settings _info . chat _rows = {
type : "boolean" ,
value : false ,
visible : function ( ) { return ! this . has _bttv } ,
name : "Chat Line Backgrounds" ,
help : "Display alternating background colors for lines in chat." ,
on _update : function ( val ) {
document . querySelector ( ".app-main" ) . classList . toggle ( "ffz-chat-background" , val ) ;
}
} ;
2015-01-20 01:53:18 -05:00
// ---------------------
// Initialization
// ---------------------
FFZ . prototype . setup _line = function ( ) {
2015-02-08 02:01:09 -05:00
// Alternating Background
document . querySelector ( '.app-main' ) . classList . toggle ( 'ffz-chat-background' , this . settings . chat _rows ) ;
this . _last _row = { } ;
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-01-20 20:25:26 -05:00
var tokens = f . _emoticonize ( this , this . _super ( ) ) ,
user = f . get _user ( ) ;
if ( ! user || this . get ( "model.from" ) != user . login )
tokens = f . _mentionize ( this , tokens ) ;
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 ( ) ;
var el = this . get ( 'element' ) ,
2015-02-08 02:01:09 -05:00
user = this . get ( 'context.model.from' ) ,
room = this . get ( 'context.parentController.content.id' ) ,
row _type = this . get ( 'context.model.ffzAlternate' ) ;
2015-01-20 01:53:18 -05:00
2015-02-08 02:01:09 -05:00
if ( row _type === undefined ) {
row _type = f . _last _row [ room ] = f . _last _row . hasOwnProperty ( room ) ? ! f . _last _row [ room ] : false ;
this . set ( "context.model.ffzAlternate" , row _type ) ;
}
el . classList . toggle ( 'ffz-alternate' , row _type ) ;
el . setAttribute ( 'data-room' , room ) ;
2015-01-20 01:53:18 -05:00
el . setAttribute ( 'data-sender' , user ) ;
f . render _badge ( this ) ;
2015-02-08 02:01:09 -05:00
if ( f . settings . capitalize )
2015-01-20 01:53:18 -05:00
f . capitalize ( this , user ) ;
2015-02-08 02:01:09 -05:00
// Check for any mentions.
var mentioned = el . querySelector ( 'span.mentioned' ) ;
if ( mentioned ) {
el . classList . add ( "ffz-mentioned" ) ;
if ( ! document . hasFocus ( ) && ! this . get ( 'context.model.ffzNotified' ) && f . settings . highlight _notifications ) {
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 )
) ;
}
}
// Mark that we've checked this message for mentions.
this . set ( 'context.model.ffzNotified' , true ) ;
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 ( ) ] ;
}
// ---------------------
// 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.
if ( window . BetterTTV )
return BetterTTV . chat . helpers . lookupDisplayName ( 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 ] ;
}
if ( FFZ . _cap _fetching < 5 ) {
FFZ . _cap _fetching ++ ;
Twitch . api . get ( "users/" + name )
. always ( function ( data ) {
var cap _name = data . display _name || name ;
FFZ . capitalization [ name ] = [ cap _name , Date . now ( ) ] ;
FFZ . _cap _fetching -- ;
2015-01-20 20:25:26 -05:00
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 ) ) ;
if ( name )
view . $ ( '.from' ) . text ( name ) ;
}
FFZ . chat _commands . capitalization = function ( room , args ) {
var enabled , args = args && args . length ? args [ 0 ] . toLowerCase ( ) : null ;
if ( args == "y" || args == "yes" || args == "true" || args == "on" )
enabled = true ;
else if ( args == "n" || args == "no" || args == "false" || args == "off" )
enabled = false ;
if ( enabled === undefined )
2015-02-08 02:01:09 -05:00
return "Chat Name Capitalization is currently " + ( this . settings . capitalize ? "enabled." : "disabled." ) ;
2015-01-20 01:53:18 -05:00
2015-02-08 02:01:09 -05:00
this . settings . set ( "capitalize" , enabled ) ;
2015-01-20 01:53:18 -05:00
return "Chat Name Capitalization is now " + ( enabled ? "enabled." : "disabled." ) ;
}
FFZ . chat _commands . capitalization . help = "Usage: /ffz capitalization <on|off>\nEnable or disable Chat Name Capitalization. This setting does not work with BetterTTV." ;
2015-01-20 20:25:26 -05:00
// ---------------------
// Extra Mentions
// ---------------------
FFZ . _regex _cache = { } ;
2015-02-08 02:01:09 -05:00
FFZ . _get _rex = function ( word ) {
return FFZ . _regex _cache [ word ] = FFZ . _regex _cache [ word ] || RegExp ( "\\b" + reg _escape ( word ) + "\\b" , "ig" ) ;
}
FFZ . _mentions _to _regex = function ( list ) {
return FFZ . _regex _cache [ list ] = FFZ . _regex _cache [ list ] || RegExp ( "\\b(?:" + _ . chain ( list ) . map ( reg _escape ) . value ( ) . join ( "|" ) + ")\\b" , "ig" ) ;
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 ;
if ( ! mention _words )
2015-01-20 20:25:26 -05:00
return tokens ;
if ( typeof tokens == "string" )
tokens = [ tokens ] ;
2015-02-08 02:01:09 -05:00
var regex = FFZ . _mentions _to _regex ( mention _words ) ;
return _ . chain ( tokens ) . map ( function ( token ) {
if ( ! _ . isString ( token ) )
return token ;
else if ( ! token . match ( regex ) )
return [ token ] ;
return _ . zip (
_ . map ( token . split ( regex ) , _ . identity ) ,
_ . map ( token . match ( regex ) , function ( e ) {
return {
mentionedUser : e ,
own : false
} ;
} )
) ;
} ) . flatten ( ) . compact ( ) . value ( ) ;
2015-01-20 20:25:26 -05:00
}
FFZ . chat _commands . mentionize = function ( room , args ) {
if ( args && args . length ) {
2015-02-08 02:01:09 -05:00
var mention _words = args . join ( " " ) . trim ( ) . split ( /\W*,\W*/ ) ;
if ( mention _words . length == 1 && mention _words [ 0 ] == "disable" )
mention _words = [ ] ;
2015-01-20 20:25:26 -05:00
2015-02-08 02:01:09 -05:00
this . settings . set ( "keywords" , mention _words ) ;
2015-01-20 20:25:26 -05:00
}
2015-02-08 02:01:09 -05:00
var mention _words = this . settings . keywords ;
if ( mention _words . length )
return "The following words will be highlighted: " + mention _words . join ( ", " ) ;
2015-01-20 20:25:26 -05:00
else
2015-02-08 02:01:09 -05:00
return "There are no words set that will be highlighted." ;
2015-01-20 20:25:26 -05:00
}
2015-02-08 02:01:09 -05:00
FFZ . chat _commands . mentionize . help = "Usage: /ffz mentionize <comma, separated, word, list|disable>\nSet a list of words that will also be highlighted in chat." ;
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};
var eo = { isEmoticon : true , cls : emote . klass , emoticonSrc : emote . url , altText : ( emote . hidden ? "???" : emote . name ) } ;
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
}