2017-11-13 01:23:39 -05:00
'use strict' ;
// ============================================================================
// Badge Handling
// ============================================================================
2019-12-10 20:46:33 -05:00
import { NEW _API , SERVER , API _SERVER , IS _WEBKIT , IS _FIREFOX , WEBKIT _CSS as WEBKIT } from 'utilities/constants' ;
2017-11-28 02:03:59 -05:00
2018-04-01 18:24:08 -04:00
import { createElement , ManagedStyle } from 'utilities/dom' ;
2021-03-22 18:19:09 -04:00
import { has , maybe _call , SourcedSet } from 'utilities/object' ;
2017-11-13 01:23:39 -05:00
import Module from 'utilities/module' ;
2019-12-05 23:13:27 -05:00
import { ColorAdjuster } from 'src/utilities/color' ;
const CSS _BADGES = {
1 : {
staff : { 1 : { color : '#200f33' , svg : true , trans : { color : '#6441a5' } } } ,
admin : { 1 : { color : '#faaf19' , svg : true } } ,
global _mod : { 1 : { color : '#0c6f20' , svg : true } } ,
broadcaster : { 1 : { color : '#e71818' , svg : true } } ,
moderator : { 1 : { color : '#34ae0a' , svg : true } } ,
twitchbot : { 1 : { color : '#34ae0a' } } ,
partner : { 1 : { color : 'transparent' , trans : { image : true , color : '#6441a5' } } } ,
'clip-champ' : { 1 : { color : '#6441a5' } } ,
vip : { 1 : { color : '#b33ff0' , trans : { color : 'transparent' , invert : false } } } ,
turbo : { 1 : { color : '#6441a5' , svg : true } } ,
premium : { 1 : { color : '#009cdc' } } ,
subscriber : { 0 : { color : '#6441a5' } , 1 : { color : '#6441a5' } } ,
} ,
2 : {
staff : { 1 : { color : '#000' } } ,
2019-12-06 15:56:58 -05:00
admin : { 1 : { color : '#DB7600' } } ,
2019-12-05 23:13:27 -05:00
broadcaster : { 1 : { color : '#E91916' } } ,
2019-12-06 15:56:58 -05:00
moderator : { 1 : { color : '#00AD03' } } ,
2019-12-05 23:13:27 -05:00
global _mod : { 1 : { color : '#006441' } } ,
2019-12-06 15:56:58 -05:00
twitchbot : { 1 : { color : '#00AD03' } } ,
2019-12-05 23:13:27 -05:00
partner : { 1 : { color : '#9146FF' } } ,
subscriber : { 0 : { color : '#8205B4' } , 1 : { color : '#8205B4' } } ,
2019-12-06 15:56:58 -05:00
vip : { 1 : { color : '#E005B9' } } ,
2019-12-05 23:13:27 -05:00
turbo : { 1 : { color : '#59399A' } } ,
2019-12-06 15:56:58 -05:00
premium : { 1 : { color : '#00A0D6' } } ,
2019-12-05 23:13:27 -05:00
'anonymous-cheerer' : { 1 : { color : '#4B367C' } } ,
'clip-champ' : { 1 : { color : '#9146FF' } }
}
2017-11-13 01:23:39 -05:00
}
2018-01-16 17:36:56 -05:00
export const BADGE _POSITIONS = {
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
staff : - 2 ,
admin : - 1 ,
global _mod : - 1 ,
2018-01-16 17:36:56 -05:00
broadcaster : 0 ,
mod : 1 ,
moderator : 1 ,
twitchbot : 1 ,
2018-11-14 18:33:57 -05:00
vip : 2 ,
2018-01-16 17:36:56 -05:00
subscriber : 25
} ;
2017-11-13 01:23:39 -05:00
2017-11-28 02:03:59 -05:00
const NO _REPEAT = 'background-repeat:no-repeat;background-position:center;' ,
2019-12-05 23:13:27 -05:00
BASE _IMAGE = ` ${ SERVER } /static/badges/twitch/ ` ,
2018-02-02 16:00:01 -05:00
CSS _MASK _IMAGE = IS _WEBKIT ? 'webkitMaskImage' : 'maskImage' ,
2017-11-28 02:03:59 -05:00
CSS _TEMPLATES = {
2021-02-17 02:08:21 -05:00
0 : data => ` ${ data . fore ? ` color: ${ data . fore } ; ` : '' } background: ${ data . image || '' } ${ data . color } ;background-size: ${ data . scale * 1.8 } rem; ${ data . svg ? '' : ` background-image: ${ data . image _set } ; ` } ${ NO _REPEAT } ` ,
2018-01-16 17:36:56 -05:00
1 : data => ` ${ CSS _TEMPLATES [ 0 ] ( data ) } border-radius: ${ data . scale * .2 } rem; ` ,
2 : data => ` ${ CSS _TEMPLATES [ 0 ] ( data ) } border-radius: ${ data . scale * .9 } rem;background-size: ${ data . scale * 1.6 } rem; ` ,
2021-02-17 02:08:21 -05:00
3 : data => ` ${ data . fore ? ` color: ${ data . fore } ; ` : '' } background: ${ data . color } ;border-radius: ${ data . scale * .9 } rem; ` ,
2018-01-16 17:36:56 -05:00
4 : data => ` ${ CSS _TEMPLATES [ 3 ] ( data ) } height: ${ data . scale } rem;min-width: ${ data . scale } rem; ` ,
5 : data => ` background: ${ data . image } ;background-size: ${ data . scale * 1.8 } rem; ${ data . svg ? ` ` : ` background-image: ${ data . image _set } ; ` } ${ NO _REPEAT } ` ,
6 : data => ` background:linear-gradient( ${ data . color } , ${ data . color } ); ${ WEBKIT } mask-image: ${ data . image } ; ${ WEBKIT } mask-size: ${ data . scale * 1.8 } rem ${ data . scale * 1.8 } rem; ${ data . svg ? ` ` : ` ${ WEBKIT } mask-image: ${ data . image _set } ; ` } `
2017-11-28 02:03:59 -05:00
} ;
2018-02-02 16:18:03 -05:00
export function generateOverrideCSS ( data , style ) {
2018-04-02 03:30:22 -04:00
const urls = data . urls || { 1 : data . image } ,
image = ` url(" ${ urls [ 1 ] } ") ` ,
2018-02-02 16:18:03 -05:00
image _set = ` ${ WEBKIT } image-set( ${ image } 1x ${ urls [ 2 ] ? ` , url(" ${ urls [ 2 ] } ") 2x ` : '' } ${ urls [ 4 ] ? ` , url(" ${ urls [ 4 ] } ") 4x ` : '' } ) ` ;
2018-01-16 17:36:56 -05:00
if ( style === 3 || style === 4 )
return '' ;
if ( style === 6 )
return ` ${ WEBKIT } mask-image: ${ image } !important; ${ WEBKIT } mask-image: ${ image _set } !important; ` ;
else
return ` background-image: ${ image } !important;background-image: ${ image _set } !important; ` ;
}
2021-02-17 02:08:21 -05:00
export function generateBadgeCSS ( badge , version , data , style , is _dark , badge _version = 2 , color _fixer , fg _fixer , scale = 1 , clickable = false ) {
2017-11-28 02:03:59 -05:00
let color = data . color || 'transparent' ,
2021-03-02 16:55:25 -05:00
fore = data . fore || is _dark ? '#fff' : '#000' ,
2021-02-17 02:08:21 -05:00
base _image = data . image || ( data . addon ? null : ` ${ BASE _IMAGE } ${ badge _version } / ${ badge } ${ data . svg ? '.svg' : ` / ${ version } / ` } ` ) ,
2017-11-28 02:03:59 -05:00
trans = false ,
invert = false ,
svg , image , image _set ;
2021-02-17 02:08:21 -05:00
if ( base _image && style > 4 ) {
2017-11-28 02:03:59 -05:00
const td = data . trans || { } ;
color = td . color || color ;
if ( td . image ) {
trans = true ;
if ( td . image !== true )
base _image = td . image ;
}
if ( has ( td , 'invert' ) )
invert = td . invert && ! is _dark ;
else
invert = style === 5 && ! is _dark ;
}
if ( style === 3 || style === 4 ) {
if ( color === 'transparent' && data . trans )
color = data . trans . color || color ;
2018-02-02 16:29:41 -05:00
}
2017-11-28 02:03:59 -05:00
2018-02-02 16:29:41 -05:00
if ( color === 'transparent' )
style = 0 ;
2017-11-28 02:03:59 -05:00
2021-02-17 02:08:21 -05:00
if ( base _image && style !== 3 && style !== 4 ) {
2017-11-28 02:03:59 -05:00
svg = base _image . endsWith ( '.svg' ) ;
2018-01-16 17:36:56 -05:00
if ( data . urls )
2019-12-10 20:46:33 -05:00
image = ` url(" ${ data . urls [ scale ] } ") ` ;
2018-01-16 17:36:56 -05:00
else
image = ` url(" ${ svg ? base _image : ` ${ base _image } ${ scale } ${ trans ? '_trans' : '' } .png ` } ") ` ;
2019-12-10 20:46:33 -05:00
if ( data . urls && scale === 1 ) {
2018-02-02 16:00:01 -05:00
image _set = ` ${ WEBKIT } image-set( ${ image } 1x ${ data . urls [ 2 ] ? ` , url(" ${ data . urls [ 2 ] } ") 2x ` : '' } ${ data . urls [ 4 ] ? ` , url(" ${ data . urls [ 4 ] } ") 4x ` : '' } ) `
2017-11-28 02:03:59 -05:00
2021-04-25 13:11:28 -04:00
} else if ( data . urls && scale === 2 ) {
image _set = ` ${ WEBKIT } image-set( ${ image } 1x ${ data . urls [ 4 ] ? ` , url(" ${ data . urls [ 4 ] } ") 2x ` : '' } ) ` ;
2018-01-16 17:36:56 -05:00
} else if ( ! svg && scale < 4 ) {
2017-11-28 02:03:59 -05:00
if ( scale === 1 )
image _set = ` ${ WEBKIT } image-set( ${ image } 1x, url(" ${ base _image } 2 ${ trans ? '_trans' : '' } .png") 2x, url(" ${ base _image } 4 ${ trans ? '_trans' : '' } .png") 4x) ` ;
else if ( scale === 2 )
image _set = ` ${ WEBKIT } image-set( ${ image } 1x, url(" ${ base _image } 4 ${ trans ? '_trans' : '' } .png") 2x) ` ;
} else
2019-12-10 20:46:33 -05:00
image _set = image ;
2017-11-28 02:03:59 -05:00
}
2019-12-05 23:13:27 -05:00
if ( color _fixer && color && color !== 'transparent' )
color = color _fixer . process ( color ) || color ;
2021-02-17 02:08:21 -05:00
if ( fg _fixer && fore && fore !== 'transparent' && color !== 'transparent' ) {
fg _fixer . base = color ;
fore = fg _fixer . process ( fore ) || fore ;
}
2021-02-19 18:42:16 -05:00
if ( ! base _image ) {
if ( style > 4 )
style = 1 ;
else if ( style > 3 )
style = 2 ;
}
2021-02-17 02:08:21 -05:00
2021-02-19 18:42:16 -05:00
return ` ${ clickable && ( data . click _handler || data . click _url || data . click _action ) ? 'cursor:pointer;' : '' } ${ invert ? 'filter:invert(100%);' : '' } ${ CSS _TEMPLATES [ style ] ( {
2019-12-10 20:46:33 -05:00
scale : 1 ,
2017-11-28 02:03:59 -05:00
color ,
2021-02-17 02:08:21 -05:00
fore ,
2017-11-28 02:03:59 -05:00
image ,
image _set ,
svg
2021-02-17 15:24:07 -05:00
} ) } $ { data . css || '' } ` ;
2017-11-28 02:03:59 -05:00
}
2017-11-13 01:23:39 -05:00
export default class Badges extends Module {
2017-11-28 02:03:59 -05:00
constructor ( ... args ) {
super ( ... args ) ;
this . inject ( 'i18n' ) ;
this . inject ( 'settings' ) ;
this . inject ( 'tooltips' ) ;
2018-04-12 02:29:43 -04:00
this . inject ( 'experiments' ) ;
2017-11-28 02:03:59 -05:00
this . style = new ManagedStyle ( 'badges' ) ;
2020-07-14 21:24:07 -04:00
2021-03-22 18:19:09 -04:00
// Bulk data structure for badges applied to a lot of users.
// This lets us avoid allocating lots of individual user
// objects when we don't need to do so.
this . bulk = new Map ;
2020-07-14 21:24:07 -04:00
// Special data structure for supporters to greatly reduce
// memory usage and speed things up for people who only have
// a supporter badge.
2021-03-22 18:19:09 -04:00
//this.supporter_id = null;
//this.supporters = new Set;
2020-07-14 21:24:07 -04:00
2017-11-28 02:03:59 -05:00
this . badges = { } ;
2018-02-22 18:23:44 -05:00
this . twitch _badges = { } ;
2019-12-10 20:46:33 -05:00
if ( IS _FIREFOX )
this . settings . add ( 'chat.badges.media-queries' , {
default : true ,
ui : {
path : 'Chat > Badges >> tabs ~> Appearance' ,
title : 'Use @media queries to support High-DPI Badge images in Mozilla Firefox.' ,
description : 'This is required to see high-DPI badges on Firefox because Firefox still has yet to support `image-set()` after more than five years. It may be less reliable.' ,
component : 'setting-check-box'
}
} ) ;
2019-12-05 23:13:27 -05:00
this . settings . add ( 'chat.badges.version' , {
default : 2 ,
ui : {
path : 'Chat > Badges >> tabs ~> Appearance' ,
title : 'Version' ,
component : 'setting-select-box' ,
data : [
{ value : 1 , title : '1 (Pre December 2019)' } ,
{ value : 2 , title : '2 (Current)' }
]
}
} ) ;
2020-08-17 13:33:30 -04:00
this . settings . add ( 'chat.badges.clickable' , {
default : true ,
ui : {
path : 'Chat > Badges >> Behavior' ,
title : 'Allow clicking badges.' ,
description : 'Certain badges, such as Prime Gaming, act as links when this is enabled.' ,
component : 'setting-check-box'
}
} ) ;
2019-12-05 23:13:27 -05:00
this . settings . add ( 'chat.badges.fix-colors' , {
default : true ,
ui : {
path : 'Chat > Badges >> tabs ~> Appearance' ,
title : 'Adjust badge colors for visibility.' ,
description : 'Ensures that badges are visible against the current background.\n\n**Note:** Only affects badges with custom rendering. Subscriber badges, bit badges, etc. are not affected.' ,
component : 'setting-check-box'
}
} ) ;
2018-02-22 18:23:44 -05:00
this . settings . add ( 'chat.badges.hidden' , {
2018-03-22 22:39:27 -04:00
default : { } ,
type : 'object_merge' ,
ui : {
2018-02-22 18:23:44 -05:00
path : 'Chat > Badges >> tabs ~> Visibility' ,
2018-07-05 20:27:17 -04:00
title : 'Visibility' ,
2018-02-22 18:23:44 -05:00
component : 'badge-visibility' ,
2021-02-22 20:11:35 -05:00
getBadges : cb => this . getSettingsBadges ( true , cb )
2018-02-22 18:23:44 -05:00
}
} ) ;
2017-11-28 02:03:59 -05:00
2018-03-15 03:31:30 -04:00
this . settings . add ( 'chat.badges.custom-mod' , {
default : true ,
ui : {
path : 'Chat > Badges >> tabs ~> Appearance' ,
title : 'Use custom moderator badges where available.' ,
component : 'setting-check-box'
}
2021-04-14 16:53:15 -04:00
} ) ;
this . settings . add ( 'chat.badges.custom-vip' , {
default : true ,
ui : {
path : 'Chat > Badges >> tabs ~> Appearance' ,
title : 'Use custom VIP badges where available.' ,
component : 'setting-check-box'
}
} ) ;
2018-03-15 03:31:30 -04:00
2017-11-28 02:03:59 -05:00
this . settings . add ( 'chat.badges.style' , {
2019-12-05 23:13:27 -05:00
default : 1 ,
2017-11-28 02:03:59 -05:00
ui : {
2018-02-22 18:23:44 -05:00
path : 'Chat > Badges >> tabs ~> Appearance' ,
2017-11-28 02:03:59 -05:00
title : 'Style' ,
component : 'setting-select-box' ,
data : [
2019-12-05 23:13:27 -05:00
{ value : 0 , title : 'Square' } ,
2017-11-28 02:03:59 -05:00
{ value : 1 , title : 'Rounded' } ,
{ value : 2 , title : 'Circular' } ,
{ value : 3 , title : 'Circular (Color Only)' } ,
{ value : 4 , title : 'Circular (Color Only, Small)' } ,
{ value : 5 , title : 'Transparent' } ,
{ value : 6 , title : 'Transparent (Colored)' }
]
}
} ) ;
2020-08-17 13:33:30 -04:00
this . handleClick = this . handleClick . bind ( this ) ;
2017-11-28 02:03:59 -05:00
}
2021-02-22 20:11:35 -05:00
getSettingsBadges ( include _addons , callback ) {
2019-04-28 17:28:16 -04:00
const twitch = [ ] ,
2021-06-10 18:53:16 -04:00
other = [ ] ,
2020-01-24 19:02:06 -05:00
owl = [ ] ,
tcon = [ ] ,
2019-04-28 17:28:16 -04:00
game = [ ] ,
ffz = [ ] ,
addon = [ ] ;
2021-02-22 20:11:35 -05:00
const twitch _keys = Object . keys ( this . twitch _badges ) ;
if ( ! twitch _keys . length && callback ) {
const td = this . resolve ( 'site.twitch_data' ) ;
if ( td )
td . getBadges ( ) . then ( data => {
this . updateTwitchBadges ( data ) ;
callback ( ) ;
} ) ;
}
2019-04-28 17:28:16 -04:00
for ( const key in this . twitch _badges )
if ( has ( this . twitch _badges , key ) ) {
const badge = this . twitch _badges [ key ] ,
vs = [ ] ;
let v = badge && ( badge [ 1 ] || badge [ 0 ] ) ;
for ( const key in badge )
2020-01-24 19:02:06 -05:00
if ( key !== '__cat' && has ( badge , key ) ) {
2019-04-28 17:28:16 -04:00
const version = badge [ key ] ;
if ( ! v )
v = version ;
if ( version && version . image1x )
vs . push ( {
version : key ,
name : version . title ,
image : version . image1x ,
styleImage : ` url(" ${ version . image1x } ") `
} ) ;
}
2020-01-24 19:02:06 -05:00
if ( v ) {
let cat ;
2021-06-10 18:53:16 -04:00
if ( badge . _ _cat === 'm-other' )
cat = other ;
else if ( badge . _ _cat === 'm-owl' )
2020-01-24 19:02:06 -05:00
cat = owl ;
else if ( badge . _ _cat === 'm-tcon' )
cat = tcon ;
else if ( badge . _ _cat === 'm-game' )
cat = game ;
else
cat = twitch ;
cat . push ( {
2019-04-28 17:28:16 -04:00
id : key ,
provider : 'twitch' ,
name : v . title ,
color : 'transparent' ,
image : v . image2x ,
versions : vs ,
styleImage : ` url(" ${ v . image2x } ") `
} ) ;
2020-01-24 19:02:06 -05:00
}
2019-04-28 17:28:16 -04:00
}
if ( include _addons )
for ( const key in this . badges )
if ( has ( this . badges , key ) ) {
2021-03-22 18:19:09 -04:00
const badge = this . badges [ key ] ;
2021-02-22 20:11:35 -05:00
if ( badge . no _visibility )
continue ;
2021-03-22 18:19:09 -04:00
let image = badge . urls ? ( badge . urls [ 2 ] || badge . urls [ 1 ] ) : badge . image ,
color = badge . color || 'transparent' ;
if ( ! badge . addon ) {
image = ` //cdn.frankerfacez.com/badge/ ${ badge . id } /2/rounded ` ;
color = 'transparent' ;
}
2019-12-18 13:25:14 -05:00
( badge . addon ? addon : ffz ) . push ( {
2019-04-28 17:28:16 -04:00
id : key ,
provider : 'ffz' ,
name : badge . title ,
2021-03-22 18:19:09 -04:00
color ,
2019-04-28 17:28:16 -04:00
image ,
styleImage : ` url(" ${ image } ") `
} ) ;
}
return [
2019-12-18 13:25:14 -05:00
{ title : 'Twitch' , id : 'm-twitch' , badges : twitch } ,
2020-01-24 19:02:06 -05:00
{ title : 'Twitch: TwitchCon' , id : 'm-tcon' , badges : tcon } ,
2021-06-10 18:53:16 -04:00
{ title : 'Twitch: Other' , id : 'm-other' , badges : other } ,
2020-01-24 19:02:06 -05:00
{ title : 'Twitch: Overwatch League' , id : 'm-owl' , badges : owl } ,
2019-12-18 13:25:14 -05:00
{ title : 'Twitch: Game' , id : 'm-game' , key : 'game' , badges : game } ,
{ title : 'FrankerFaceZ' , id : 'm-ffz' , badges : ffz } ,
{ title : 'Add-on' , id : 'm-addon' , badges : addon }
2019-04-28 17:28:16 -04:00
] ;
}
2017-11-28 02:03:59 -05:00
onEnable ( ) {
2018-03-15 03:31:30 -04:00
this . parent . context . on ( 'changed:chat.badges.custom-mod' , this . rebuildAllCSS , this ) ;
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
this . parent . context . on ( 'changed:chat.badges.custom-vip' , this . rebuildAllCSS , this ) ;
2017-11-28 02:03:59 -05:00
this . parent . context . on ( 'changed:chat.badges.style' , this . rebuildAllCSS , this ) ;
this . parent . context . on ( 'changed:theme.is-dark' , this . rebuildAllCSS , this ) ;
this . parent . context . on ( 'changed:theme.tooltips-dark' , this . rebuildAllCSS , this ) ;
2019-12-05 23:13:27 -05:00
this . parent . context . on ( 'changed:chat.badges.version' , this . rebuildAllCSS , this ) ;
2019-12-10 20:46:33 -05:00
this . parent . context . on ( 'changed:chat.badges.media-queries' , this . rebuildAllCSS , this ) ;
2019-12-05 23:13:27 -05:00
this . parent . context . on ( 'changed:chat.badges.fix-colors' , this . rebuildColoredBadges , this ) ;
2020-08-17 13:33:30 -04:00
this . parent . context . on ( 'changed:chat.badges.clickable' , this . rebuildAllCSS , this ) ;
2017-11-28 02:03:59 -05:00
this . rebuildAllCSS ( ) ;
this . loadGlobalBadges ( ) ;
this . tooltips . types . badge = ( target , tip ) => {
2018-02-02 18:51:38 -05:00
tip . add _class = 'ffz__tooltip--badges' ;
2020-08-14 17:17:24 -04:00
const show _previews = this . parent . context . get ( 'tooltip.badge-images' ) ;
2021-11-15 17:12:01 -05:00
const ds = this . getBadgeData ( target ) ;
2020-08-14 17:17:24 -04:00
2021-11-15 17:12:01 -05:00
const out = [ ] ;
2018-02-02 16:00:01 -05:00
2021-11-15 17:12:01 -05:00
if ( ds . data == null )
2018-12-03 18:08:32 -05:00
return out ;
2021-11-15 17:12:01 -05:00
for ( const d of ds . data ) {
2018-02-02 16:00:01 -05:00
const p = d . provider ;
if ( p === 'twitch' ) {
2021-11-15 17:12:01 -05:00
const bd = this . getTwitchBadge ( d . badge , d . version , ds . room _id , ds . room _login ) ,
2019-05-08 22:47:38 -04:00
global _badge = this . getTwitchBadge ( d . badge , d . version , null , null , true ) || { } ;
2018-02-02 16:00:01 -05:00
if ( ! bd )
continue ;
2019-04-28 17:28:16 -04:00
let title = bd . title || global _badge . title ;
2020-06-30 19:48:46 -04:00
const tier = bd . tier || global _badge . tier ;
2019-04-28 17:28:16 -04:00
if ( d . data ) {
if ( d . badge === 'subscriber' ) {
2020-06-30 19:48:46 -04:00
if ( tier > 0 )
2021-11-12 16:58:35 -05:00
title = this . i18n . t ( 'badges.subscriber.tier-months' , '{title}\n(Tier {tier}, {months, plural, one {# Month} other {# Months}})' , {
2020-06-30 19:48:46 -04:00
title ,
tier ,
months : d . data
} ) ;
else
2021-11-12 16:58:35 -05:00
title = this . i18n . t ( 'badges.subscriber.months' , '{title}\n({count, plural, one {# Month} other {# Months}})' , {
2020-06-30 19:48:46 -04:00
title ,
count : d . data
} ) ;
2019-10-28 01:06:02 -04:00
} else if ( d . badge === 'founder' ) {
2021-11-12 16:58:35 -05:00
title = this . i18n . t ( 'badges.founder.months' , '{title}\n(Subscribed for {count, plural, one {# Month} other {# Months}})' , {
2019-10-28 01:06:02 -04:00
title ,
count : d . data
} ) ;
2019-04-28 17:28:16 -04:00
}
}
2018-04-01 18:24:08 -04:00
out . push ( < div class = "ffz-badge-tip" >
{ show _previews && < img class = "preview-image ffz-badge" src = { bd . image4x } / > }
2019-04-28 17:28:16 -04:00
{ title }
2018-04-01 18:24:08 -04:00
< / div > ) ;
2018-02-02 16:00:01 -05:00
} else if ( p === 'ffz' ) {
2018-04-01 18:24:08 -04:00
out . push ( < div class = "ffz-badge-tip" >
2021-02-17 02:08:21 -05:00
{ show _previews && d . image && < div
2018-04-01 18:24:08 -04:00
class = "preview-image ffz-badge"
style = { {
backgroundColor : d . color ,
backgroundImage : ` url(" ${ d . image } ") `
} }
/ > }
{ d . title }
< / div > ) ;
2018-02-02 16:00:01 -05:00
}
}
2017-11-28 02:03:59 -05:00
2018-02-02 16:00:01 -05:00
return out ;
}
2017-11-28 02:03:59 -05:00
}
2021-11-15 17:12:01 -05:00
getBadgeData ( target ) {
let container = target . parentElement ? . parentElement ;
if ( ! container ? . dataset ? . roomId )
container = target . closest ( '[data-room-id]' ) ;
const room _id = container ? . dataset ? . roomId ,
room _login = container ? . dataset ? . room ,
user _id = container ? . dataset ? . userId ,
user _login = container ? . dataset ? . user ;
let data ;
if ( target . dataset . badgeData )
data = JSON . parse ( target . dataset . badgeData ) ;
else {
const badge _idx = target . dataset . badgeIdx ;
let message ;
if ( container . message )
message = container . message ;
else {
const fine = this . resolve ( 'site.fine' ) ;
if ( fine ) {
message = container [ fine . accessor ] ? . return ? . stateNode ? . props ? . message ;
if ( ! message )
message = fine . searchParent ( container , n => n . props ? . message ) ? . props ? . message ;
if ( ! message )
message = fine . searchParent ( container , n => n . props ? . node ) ? . props ? . node ? . _ffz _message ;
if ( ! message )
message = fine . searchParent ( container , n => n . props ? . messageContext ) ? . props ? . messageContext ? . comment ? . _ffz _message ;
if ( ! message )
message = fine . searchParent ( container , n => n . _ffzIdentityMsg , 50 ) ? . _ffzIdentityMsg ;
}
}
if ( message ? . _ffz _message )
message = message . _ffz _message ;
if ( message )
data = message . ffz _badge _cache ? . [ badge _idx ] ? . [ 1 ] ? . badges ;
}
return {
room _id : room _id ,
room _login : room _login ,
user _id : user _id ,
user _login : user _login ,
data
} ;
}
2020-08-17 13:33:30 -04:00
handleClick ( event ) {
if ( ! this . parent . context . get ( 'chat.badges.clickable' ) )
return ;
const target = event . target ;
2021-11-15 17:12:01 -05:00
const ds = this . getBadgeData ( target ) ;
2020-08-17 13:33:30 -04:00
2021-11-15 17:12:01 -05:00
if ( ds . data == null )
2020-08-17 13:33:30 -04:00
return ;
let url = null ;
2021-11-15 17:12:01 -05:00
for ( const d of ds . data ) {
2020-08-17 13:33:30 -04:00
const p = d . provider ;
if ( p === 'twitch' ) {
2021-11-15 17:12:01 -05:00
const bd = this . getTwitchBadge ( d . badge , d . version , ds . room _id , ds . room _login ) ,
2020-08-17 13:33:30 -04:00
global _badge = this . getTwitchBadge ( d . badge , d . version , null , null , true ) || { } ;
if ( ! bd )
continue ;
if ( bd . click _url )
url = bd . click _url ;
else if ( global _badge . click _url )
url = global _badge . click _url ;
2021-11-15 17:12:01 -05:00
else if ( ( bd . click _action === 'sub' || global _badge . click _action === 'sub' ) && ds . room _login )
url = ` https://www.twitch.tv/subs/ ${ ds . room _login } ` ;
2020-08-17 13:33:30 -04:00
else
continue ;
break ;
} else if ( p === 'ffz' ) {
const badge = this . badges [ target . dataset . badge ] ;
2021-02-17 15:24:07 -05:00
if ( badge ? . click _handler ) {
2021-11-15 17:12:01 -05:00
url = badge . click _handler ( ds . user _id , ds . user _login , ds . room _id , ds . room _login , ds . data , event ) ;
2021-02-17 15:24:07 -05:00
break ;
}
2020-08-17 13:33:30 -04:00
if ( badge ? . click _url ) {
url = badge . click _url ;
break ;
}
}
}
if ( url ) {
const link = createElement ( 'a' , {
target : '_blank' ,
rel : 'noopener noreferrer' ,
href : url
} ) ;
link . click ( ) ;
}
event . preventDefault ( ) ;
}
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
cacheBadges ( msg , skip _hide = false ) {
if ( msg . ffz _badge _cache )
return msg . ffz _badge _cache ;
2021-03-22 18:19:09 -04:00
2020-11-23 18:12:07 -05:00
const hidden _badges = skip _hide ? { } : ( this . parent . context . get ( 'chat.badges.hidden' ) || { } ) ,
2018-02-02 16:00:01 -05:00
badge _style = this . parent . context . get ( 'chat.badges.style' ) ,
2018-03-15 03:31:30 -04:00
custom _mod = this . parent . context . get ( 'chat.badges.custom-mod' ) ,
2021-04-14 16:53:15 -04:00
custom _vip = this . parent . context . get ( 'chat.badges.custom-vip' ) ,
2018-03-15 03:31:30 -04:00
is _mask = badge _style > 5 ,
2018-02-02 16:00:01 -05:00
is _colored = badge _style !== 5 ,
has _image = badge _style !== 3 && badge _style !== 4 ,
2019-12-18 13:25:14 -05:00
ffz _hidden = hidden _badges [ 'm-ffz' ] ,
addon _hidden = hidden _badges [ 'm-addon' ] ,
2020-01-24 19:02:06 -05:00
tb = this . twitch _badges ,
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
slotted = new Map ,
2018-01-16 17:36:56 -05:00
twitch _badges = msg . badges || { } ,
2019-04-28 17:28:16 -04:00
dynamic _data = msg . badgeDynamicData || { } ,
2017-11-28 02:03:59 -05:00
2021-03-22 18:19:09 -04:00
//user = msg.user || {},
//user_id = user.id,
//user_login = user.login,
2017-11-28 02:03:59 -05:00
room _id = msg . roomID ,
room _login = msg . roomLogin ,
2018-03-15 03:31:30 -04:00
room = this . parent . getRoom ( room _id , room _login , true ) ,
2021-03-22 18:19:09 -04:00
badges = msg . ffz _badges ; // this.getBadges(user_id, user_login, room_id, room_login);
2018-01-16 17:36:56 -05:00
let last _slot = 50 , slot ;
2017-11-28 02:03:59 -05:00
for ( const badge _id in twitch _badges )
if ( has ( twitch _badges , badge _id ) ) {
2018-01-16 17:36:56 -05:00
const version = twitch _badges [ badge _id ] ,
2019-12-18 13:25:14 -05:00
is _hidden = hidden _badges [ badge _id ] ,
2020-01-24 19:02:06 -05:00
bdata = tb && tb [ badge _id ] ,
cat = bdata && bdata . _ _cat || 'm-twitch' ;
2018-01-16 17:36:56 -05:00
2020-01-24 19:02:06 -05:00
if ( is _hidden || ( is _hidden == null && hidden _badges [ cat ] ) )
2018-01-16 17:36:56 -05:00
continue ;
if ( has ( BADGE _POSITIONS , badge _id ) )
slot = BADGE _POSITIONS [ badge _id ] ;
else
slot = last _slot ++ ;
2019-10-28 01:06:02 -04:00
const data = dynamic _data [ badge _id ] || ( badge _id === 'founder' && dynamic _data [ 'subscriber' ] ) ,
2021-04-14 16:53:15 -04:00
mod _urls = badge _id === 'moderator' && custom _mod && room && room . data && room . data . mod _urls ,
vip _urls = badge _id === 'vip' && custom _vip && room && room . data && room . data . vip _badge ,
2018-03-15 03:31:30 -04:00
badges = [ ] ;
2021-04-14 16:53:15 -04:00
if ( mod _urls ) {
2018-03-15 03:31:30 -04:00
const bd = this . getTwitchBadge ( badge _id , version , room _id , room _login ) ;
badges . push ( {
provider : 'ffz' ,
2021-04-14 16:53:15 -04:00
image : mod _urls [ 4 ] || mod _urls [ 2 ] || mod _urls [ 1 ] ,
2018-03-15 03:31:30 -04:00
color : '#34ae0a' ,
2019-04-28 17:28:16 -04:00
title : bd ? bd . title : 'Moderator' ,
data
2018-03-15 03:31:30 -04:00
} ) ;
2021-04-14 16:53:15 -04:00
} else if ( vip _urls ) {
const bd = this . getTwitchBadge ( badge _id , version , room _id , room _login ) ;
badges . push ( {
provider : 'ffz' ,
image : vip _urls [ 4 ] || vip _urls [ 2 ] || vip _urls [ 1 ] ,
color : 'transparent' ,
title : bd ? bd . title : 'VIP' ,
data
} ) ;
2018-03-15 03:31:30 -04:00
} else
badges . push ( {
provider : 'twitch' ,
badge : badge _id ,
2019-04-28 17:28:16 -04:00
version ,
data
2018-03-15 03:31:30 -04:00
} ) ;
2018-02-02 16:00:01 -05:00
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
slotted . set ( slot , {
2018-01-16 17:36:56 -05:00
id : badge _id ,
props : {
'data-provider' : 'twitch' ,
'data-badge' : badge _id ,
2018-02-08 18:28:30 -05:00
'data-version' : version ,
style : { }
2018-02-02 16:00:01 -05:00
} ,
badges
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
} ) ;
2017-11-28 02:03:59 -05:00
}
2021-03-22 18:19:09 -04:00
if ( Array . isArray ( badges ) ) {
const handled _ids = new Set ;
2020-12-01 18:19:17 -05:00
2021-03-22 18:19:09 -04:00
for ( const badge of badges )
if ( badge && badge . id != null ) {
if ( handled _ids . has ( badge . id ) )
continue ;
2020-12-01 18:19:17 -05:00
2021-03-22 18:19:09 -04:00
handled _ids . add ( badge . id ) ;
2019-12-18 13:25:14 -05:00
2021-03-22 18:19:09 -04:00
const full _badge = this . badges [ badge . id ] || { } ,
is _hidden = hidden _badges [ badge . id ] ;
2018-01-16 17:36:56 -05:00
2021-03-22 18:19:09 -04:00
if ( is _hidden || ( is _hidden == null && ( full _badge . addon ? addon _hidden : ffz _hidden ) ) )
continue ;
2018-02-02 16:00:01 -05:00
2021-03-22 18:19:09 -04:00
const slot = has ( badge , 'slot' ) ? badge . slot : full _badge . slot ,
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
old _badge = slotted . get ( slot ) ,
2021-03-22 18:19:09 -04:00
urls = badge . urls || ( badge . image ? { 1 : badge . image } : null ) ,
color = badge . color || full _badge . color || 'transparent' ,
no _invert = badge . no _invert ,
masked = color !== 'transparent' && is _mask ,
bu = ( urls || full _badge . urls || { 1 : full _badge . image } ) ,
bd = {
provider : 'ffz' ,
image : bu [ 4 ] || bu [ 2 ] || bu [ 1 ] ,
color : badge . color || full _badge . color ,
title : badge . title || full _badge . title ,
} ;
// Hacky nonsense.
if ( ! full _badge . addon ) {
bd . image = ` //cdn.frankerfacez.com/badge/ ${ badge . id } /4/rounded ` ;
bd . color = null ;
}
2020-12-01 18:19:17 -05:00
2021-03-22 18:19:09 -04:00
let style ;
2018-02-02 18:51:38 -05:00
2021-03-22 18:19:09 -04:00
if ( old _badge ) {
old _badge . badges . push ( bd ) ;
2018-02-02 18:51:38 -05:00
2021-03-22 18:19:09 -04:00
const replaces = has ( badge , 'replaces' ) ? badge . replaces : full _badge . replaces ,
replaces _type = badge . replaces _type || full _badge . replaces _type ;
if ( replaces && ( ! replaces _type || replaces _type === old _badge . id ) ) {
old _badge . replaced = badge . id ;
old _badge . content = badge . content || full _badge . content || old _badge . content ;
} else
continue ;
2018-01-16 17:36:56 -05:00
2021-03-22 18:19:09 -04:00
style = old _badge . props . style ;
2018-01-16 17:36:56 -05:00
2021-03-22 18:19:09 -04:00
} else if ( slot == null )
continue ;
2018-01-16 17:36:56 -05:00
2021-03-22 18:19:09 -04:00
else {
style = { } ;
const props = {
className : 'ffz-tooltip ffz-badge' ,
'data-tooltip-type' : 'badge' ,
'data-provider' : 'ffz' ,
'data-badge' : badge . id ,
style
} ;
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
slotted . set ( slot , {
2021-03-22 18:19:09 -04:00
id : badge . id ,
props ,
badges : [ bd ] ,
content : badge . content || full _badge . content
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
} )
2021-02-17 02:08:21 -05:00
}
2018-02-02 18:51:38 -05:00
2021-03-22 18:19:09 -04:00
if ( no _invert ) {
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
const old = slotted . get ( slot ) ;
old . full _size = true ;
old . no _invert = true ;
2018-11-12 13:34:53 -05:00
2021-03-22 18:19:09 -04:00
style . background = 'unset' ;
style . backgroundSize = 'unset' ;
style [ CSS _MASK _IMAGE ] = 'unset' ;
}
2018-09-24 18:49:03 +02:00
2021-03-22 18:19:09 -04:00
if ( ( has _image || color === 'transparent' ) && urls ) {
const image = ` url(" ${ urls [ 1 ] } ") ` ;
let image _set ;
if ( urls [ 2 ] || urls [ 4 ] )
image _set = ` ${ WEBKIT } image-set( ${ image } 1x ${ urls [ 2 ] ? ` , url(" ${ urls [ 2 ] } ") 2x ` : '' } ${ urls [ 4 ] ? ` , url(" ${ urls [ 4 ] } ") 4x ` : '' } ) ` ;
2018-02-02 16:00:01 -05:00
2021-03-22 18:19:09 -04:00
style [ masked && ! no _invert ? CSS _MASK _IMAGE : 'backgroundImage' ] = image ;
if ( image _set )
style [ masked && ! no _invert ? CSS _MASK _IMAGE : 'backgroundImage' ] = image _set ;
}
2018-02-02 16:00:01 -05:00
2021-03-22 18:19:09 -04:00
if ( is _colored && badge . color ) {
if ( masked && ! no _invert )
style . backgroundImage = ` linear-gradient( ${ badge . color } , ${ badge . color } ) ` ;
else
style . backgroundColor = badge . color ;
}
2018-02-02 16:00:01 -05:00
}
2021-03-22 18:19:09 -04:00
}
2018-01-16 17:36:56 -05:00
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
return msg . ffz _badge _cache = Array . from ( slotted ) . sort ( ( a , b ) => a [ 0 ] - b [ 0 ] ) ;
}
2018-01-16 17:36:56 -05:00
2021-02-17 02:08:21 -05:00
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
render ( msg , createElement , skip _hide = false , skip _click = false ) {
if ( ! msg . badges && ! msg . ffz _badges )
return null ;
2017-11-28 02:03:59 -05:00
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
if ( ! msg . ffz _badge _cache )
this . cacheBadges ( msg , skip _hide ) ;
2020-08-17 13:33:30 -04:00
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
if ( ! msg . ffz _badge _cache . length )
return null ;
2017-11-28 02:03:59 -05:00
4.25.0
* Fixed: Smooth Scrolling no longer causing chat to scroll. (Closes #1068)
* Fixed: Issue with users using certain external stylesheets causing chat messages to become impossible to read on mouse hover. (Closes #1066)
* Fixed: Issues with badge sorting causing some badges to be overridden when they shouldn't be.
* Changed: Improve caching of badge data, such that re-rendering chat lines requires less computation.
* Changed: Refactor how chat lines listen for settings changes to reduce code duplication.
* Changed: Refactor how chat lines are invalidated to minimize work when changing settings.
* API Added: `chat:rerender-lines` event that, when emitted, causes all chat lines to be re-rendered.
* API Added: `chat:update-line-tokens` event that, when emitted, causes all chat lines to have their tokens invalidated and recalculated.
* API Added: `chat:update-line-badges` event that, when emitted, causes all chat lines to have their cached badges invalidated and recalculated.
* API Changed: `chat:update-lines-by-user` now has extra properties for separately invalidating tokens or badges. The full signature is `chat:update-lines-by-user(id, login, invalidate_tokens = true, invalidate_badges = true)`
2021-06-23 16:08:57 -04:00
const out = [ ] ;
for ( let i = 0 , l = msg . ffz _badge _cache . length ; i < l ; i ++ ) {
const data = msg . ffz _badge _cache [ i ] [ 1 ] ,
props = data . props ;
let content = maybe _call ( data . content , this , data , msg , createElement ) ;
if ( content && ! Array . isArray ( content ) )
content = [ content ] ;
props . className = ` ffz-tooltip ffz-badge ${ content ? ' tw-pd-x-05' : '' } ${ data . full _size ? ' ffz-full-size' : '' } ${ data . no _invert ? ' ffz-no-invert' : '' } ` ;
props . key = ` ${ props [ 'data-provider' ] } - ${ props [ 'data-badge' ] } ` ;
props [ 'data-tooltip-type' ] = 'badge' ;
props [ 'data-badge-idx' ] = i ;
//props['data-badge-data'] = JSON.stringify(data.badges);
if ( ! skip _click )
props . onClick = this . handleClick ;
if ( data . replaced )
props [ 'data-replaced' ] = data . replaced ;
out . push ( createElement ( 'span' , props , content || undefined ) ) ;
}
2017-11-28 02:03:59 -05:00
return out ;
}
2019-12-05 23:13:27 -05:00
rebuildColor ( ) {
if ( this . parent . context . get ( 'chat.badges.fix-colors' ) ) {
2021-02-17 02:08:21 -05:00
this . fg _fixer = new ColorAdjuster ( '#fff' , 1 , 4.5 ) ;
2019-12-05 23:13:27 -05:00
this . color _fixer = new ColorAdjuster (
this . parent . context . get ( 'theme.is-dark' ) ? '#181818' : '#FFFFFF' ,
1 ,
2.5
) ;
2021-02-17 02:08:21 -05:00
} else {
this . fg _fixer = null ;
2019-12-05 23:13:27 -05:00
this . color _fixer = null ;
2021-02-17 02:08:21 -05:00
}
2019-12-05 23:13:27 -05:00
}
rebuildColoredBadges ( ) {
this . rebuildColor ( ) ;
this . buildBadgeCSS ( ) ;
this . buildTwitchCSSBadgeCSS ( ) ;
}
2017-11-28 02:03:59 -05:00
rebuildAllCSS ( ) {
2019-12-05 23:13:27 -05:00
this . rebuildColor ( ) ;
2018-03-15 03:31:30 -04:00
for ( const room of this . parent . iterateRooms ( ) ) {
2017-11-28 02:03:59 -05:00
room . buildBadgeCSS ( ) ;
2018-03-15 03:31:30 -04:00
room . buildModBadgeCSS ( ) ;
}
2017-11-28 02:03:59 -05:00
2018-01-16 17:36:56 -05:00
this . buildBadgeCSS ( ) ;
2017-11-28 02:03:59 -05:00
this . buildTwitchBadgeCSS ( ) ;
this . buildTwitchCSSBadgeCSS ( ) ;
}
// ========================================================================
// Extension Badges
// ========================================================================
getBadges ( user _id , user _login , room _id , room _login ) {
const room = this . parent . getRoom ( room _id , room _login , true ) ,
2021-03-22 18:19:09 -04:00
global _user = this . parent . getUser ( user _id , user _login , true ) ;
if ( global _user ) {
user _id = user _id ? ? global _user . id ;
user _login = user _login ? ? global _user . login ;
}
2017-11-28 02:03:59 -05:00
2021-03-22 18:19:09 -04:00
const room _user = room && room . getUser ( user _id , user _login , true ) ;
2020-07-14 21:24:07 -04:00
2021-03-22 18:19:09 -04:00
const out = ( global _user ? . badges ? global _user . badges . _cache : [ ] ) . concat (
room _user ? . badges ? room _user . badges . _cache : [ ] ) ;
if ( this . bulk . size ) {
const str _user = String ( user _id ) ;
for ( const [ badge _id , users ] of this . bulk ) {
if ( users ? . _cache . has ( str _user ) )
out . push ( { id : badge _id } ) ;
}
}
2020-07-14 21:24:07 -04:00
return out ;
2017-11-28 02:03:59 -05:00
}
2021-03-22 18:19:09 -04:00
setBulk ( source , badge _id , entries ) {
let set = this . bulk . get ( badge _id ) ;
if ( ! set )
this . bulk . set ( badge _id , set = new SourcedSet ( true ) ) ;
set . set ( source , entries ) ;
}
deleteBulk ( source , badge _id ) {
const set = this . bulk . get ( badge _id ) ;
if ( set )
set . delete ( source ) ;
}
extendBulk ( source , badge _id , entries ) {
let set = this . bulk . get ( badge _id ) ;
if ( ! set )
this . bulk . set ( badge _id , set = new SourcedSet ( true ) ) ;
if ( ! Array . isArray ( entries ) )
entries = [ entries ] ;
set . extend ( source , ... entries ) ;
}
2017-11-28 02:03:59 -05:00
async loadGlobalBadges ( tries = 0 ) {
let response , data ;
2018-04-12 02:29:43 -04:00
2020-03-05 18:21:11 -05:00
if ( this . experiments . getAssignment ( 'api_load' ) && tries < 1 )
2018-04-12 02:29:43 -04:00
try {
2020-11-12 17:02:04 -05:00
fetch ( ` ${ NEW _API } /v1/badges/ids ` ) . catch ( ( ) => { } ) ;
2018-04-12 02:29:43 -04:00
} catch ( err ) { /* do nothing */ }
2017-11-28 02:03:59 -05:00
try {
2020-07-14 21:24:07 -04:00
response = await fetch ( ` ${ API _SERVER } /v1/badges/ids ` ) ;
2017-11-28 02:03:59 -05:00
} catch ( err ) {
tries ++ ;
if ( tries < 10 )
return setTimeout ( ( ) => this . loadGlobalBadges ( tries ) , 500 * tries ) ;
this . log . error ( 'Error loading global badge data.' , err ) ;
return false ;
}
if ( ! response . ok )
return false ;
try {
data = await response . json ( ) ;
} catch ( err ) {
this . log . error ( 'Error parsing global badge data.' , err ) ;
return false ;
}
let badges = 0 , users = 0 ;
if ( data . badges )
for ( const badge of data . badges )
if ( badge && badge . id ) {
2018-02-02 16:00:01 -05:00
this . loadBadgeData ( badge . id , badge , false ) ;
2017-11-28 02:03:59 -05:00
badges ++ ;
}
if ( data . users )
for ( const badge _id in data . users )
if ( has ( data . users , badge _id ) ) {
2021-03-22 18:19:09 -04:00
const badge = this . badges [ badge _id ] ,
name = badge ? . name ;
2017-11-28 02:03:59 -05:00
let c = 0 ;
2020-07-14 21:24:07 -04:00
2021-03-22 18:19:09 -04:00
if ( name === 'supporter' || name === 'bot' ) {
this . setBulk ( 'ffz-global' , badge _id , data . users [ badge _id ] . map ( x => String ( x ) ) ) ;
/ * t h i s . s u p p o r t e r _ i d = b a d g e _ i d ;
2020-07-14 21:24:07 -04:00
for ( const user _id of data . users [ badge _id ] )
2021-03-22 18:19:09 -04:00
this . supporters . add ( ` ${ user _id } ` ) ; * /
2020-07-14 21:24:07 -04:00
2021-03-22 18:19:09 -04:00
c = data . users [ badge _id ] . length ; // this.supporters.size;
2020-07-14 21:24:07 -04:00
} else
for ( const user _id of data . users [ badge _id ] ) {
const user = this . parent . getUser ( user _id , undefined ) ;
if ( user . addBadge ( 'ffz-global' , badge _id ) ) {
c ++ ;
users ++ ;
}
2017-11-28 02:03:59 -05:00
}
if ( c > 0 )
this . log . info ( ` Added " ${ badge ? badge . name : ` # ${ badge _id } ` } " to ${ c } users. ` ) ;
}
this . log . info ( ` Loaded ${ badges } badges and assigned them to ${ users } users. ` ) ;
2018-01-16 17:36:56 -05:00
this . buildBadgeCSS ( ) ;
2017-11-28 02:03:59 -05:00
}
2018-02-02 16:00:01 -05:00
loadBadgeData ( badge _id , data , generate _css = true ) {
2017-11-28 02:03:59 -05:00
this . badges [ badge _id ] = data ;
2021-02-17 02:08:21 -05:00
if ( data ) {
if ( data . addon === undefined )
data . addon = /^addon/ . test ( badge _id ) ;
2019-12-18 13:25:14 -05:00
2021-02-17 02:08:21 -05:00
if ( data . replaces && ! data . replaces _type ) {
data . replaces _type = data . replaces ;
data . replaces = true ;
}
2017-11-28 02:03:59 -05:00
2021-02-17 02:08:21 -05:00
if ( ! data . addon && ( data . name === 'developer' || data . name === 'supporter' ) )
data . click _url = 'https://www.frankerfacez.com/donate' ;
}
2018-02-02 16:00:01 -05:00
if ( generate _css )
this . buildBadgeCSS ( ) ;
2017-11-28 02:03:59 -05:00
}
2018-01-16 17:36:56 -05:00
buildBadgeCSS ( ) {
const style = this . parent . context . get ( 'chat.badges.style' ) ,
2019-12-10 20:46:33 -05:00
is _dark = this . parent . context . get ( 'theme.is-dark' ) ,
2020-08-17 13:33:30 -04:00
can _click = this . parent . context . get ( 'chat.badges.clickable' ) ,
2019-12-10 20:46:33 -05:00
use _media = IS _FIREFOX && this . parent . context . get ( 'chat.badges.media-queries' ) ;
2018-01-16 17:36:56 -05:00
const out = [ ] ;
for ( const key in this . badges )
if ( has ( this . badges , key ) ) {
const data = this . badges [ key ] ,
selector = ` .ffz-badge[data-badge=" ${ key } "] ` ;
out . push ( ` .ffz-badge[data-replaced=" ${ key } "]{ ${ generateOverrideCSS ( data , style , is _dark ) } } ` ) ;
2019-12-10 20:46:33 -05:00
if ( use _media ) {
2021-02-17 02:08:21 -05:00
out . push ( ` @media (max-resolution: 99dpi) { ${ selector } { ${ generateBadgeCSS ( key , 0 , data , style , is _dark , 0 , this . color _fixer , this . fg _fixer , 1 , can _click ) } }} ` ) ;
out . push ( ` @media (min-resolution: 100dpi) and (max-resolution:199dpi) { ${ selector } { ${ generateBadgeCSS ( key , 0 , data , style , is _dark , 0 , this . color _fixer , this . fg _fixer , 2 , can _click ) } }} ` ) ;
out . push ( ` @media (min-resolution: 200dpi) { ${ selector } { ${ generateBadgeCSS ( key , 0 , data , style , is _dark , 0 , this . color _fixer , this . fg _fixer , 4 , can _click ) } }} ` ) ;
2019-12-10 20:46:33 -05:00
} else
2021-02-17 02:08:21 -05:00
out . push ( ` ${ selector } { ${ generateBadgeCSS ( key , 0 , data , style , is _dark , 0 , this . color _fixer , this . fg _fixer , undefined , can _click ) } } ` ) ;
2018-01-16 17:36:56 -05:00
}
this . style . set ( 'ext-badges' , out . join ( '\n' ) ) ;
}
2017-11-28 02:03:59 -05:00
// ========================================================================
// Twitch Badges
// ========================================================================
2019-05-08 22:47:38 -04:00
getTwitchBadge ( badge , version , room _id , room _login , retried = false ) {
2017-11-28 02:03:59 -05:00
const room = this . parent . getRoom ( room _id , room _login , true ) ;
let b ;
if ( room ) {
2018-01-19 17:17:16 -05:00
const versions = room . badges && room . badges [ badge ] ;
b = versions && versions [ version ] ;
2017-11-28 02:03:59 -05:00
}
if ( ! b ) {
2018-01-19 17:17:16 -05:00
const versions = this . twitch _badges && this . twitch _badges [ badge ] ;
b = versions && versions [ version ] ;
2017-11-28 02:03:59 -05:00
}
2019-05-08 22:47:38 -04:00
if ( ! b && ! retried ) {
const chat = this . resolve ( 'site.chat' ) ;
if ( chat && chat . tryUpdateBadges )
chat . tryUpdateBadges ( ) ;
}
2017-11-28 02:03:59 -05:00
return b ;
}
2019-05-08 22:47:38 -04:00
getTwitchBadgeCount ( ) {
return this . twitch _badge _count || 0 ;
2019-05-03 19:30:46 -04:00
}
2017-11-28 02:03:59 -05:00
updateTwitchBadges ( badges ) {
2019-05-08 22:47:38 -04:00
this . twitch _badge _count = 0 ;
2019-05-03 19:30:46 -04:00
if ( ! Array . isArray ( badges ) )
2018-01-19 17:17:16 -05:00
this . twitch _badges = badges ;
else {
2019-05-03 19:30:46 -04:00
let b = null ;
if ( badges . length ) {
b = { } ;
for ( const data of badges ) {
const sid = data . setID ,
2020-01-24 19:02:06 -05:00
bs = b [ sid ] = b [ sid ] || {
_ _cat : getBadgeCategory ( sid )
} ;
2019-05-03 19:30:46 -04:00
2019-05-08 22:47:38 -04:00
this . twitch _badge _count ++ ;
2021-07-27 22:51:04 -04:00
bs [ data . version ] = fixBadgeData ( data ) ;
2019-05-03 19:30:46 -04:00
}
2018-01-19 17:17:16 -05:00
}
this . twitch _badges = b ;
}
2017-11-28 02:03:59 -05:00
this . buildTwitchBadgeCSS ( ) ;
2020-08-17 13:33:30 -04:00
this . buildTwitchCSSBadgeCSS ( ) ;
2017-11-28 02:03:59 -05:00
}
buildTwitchCSSBadgeCSS ( ) {
const style = this . parent . context . get ( 'chat.badges.style' ) ,
2019-12-05 23:13:27 -05:00
is _dark = this . parent . context . get ( 'theme.is-dark' ) ,
2020-08-17 13:33:30 -04:00
can _click = this . parent . context . get ( 'chat.badges.clickable' ) ,
2019-12-10 20:46:33 -05:00
use _media = IS _FIREFOX && this . parent . context . get ( 'chat.badges.media-queries' ) ,
2019-12-05 23:13:27 -05:00
badge _version = this . parent . context . get ( 'chat.badges.version' ) ,
2020-08-17 13:33:30 -04:00
versioned = CSS _BADGES [ badge _version ] || { } ,
twitch _data = this . twitch _badges || { } ;
2017-11-28 02:03:59 -05:00
const out = [ ] ;
2019-12-05 23:13:27 -05:00
for ( const key in versioned )
if ( has ( versioned , key ) ) {
2020-08-17 13:33:30 -04:00
const data = versioned [ key ] ,
twitch = twitch _data [ key ] ;
2017-11-28 02:03:59 -05:00
for ( const version in data )
if ( has ( data , version ) ) {
const d = data [ version ] ,
2020-08-17 13:33:30 -04:00
td = twitch ? . [ version ] ,
2017-11-28 02:03:59 -05:00
selector = ` .ffz-badge[data-badge=" ${ key } "][data-version=" ${ version } "] ` ;
2020-08-17 13:33:30 -04:00
if ( td && td . click _url )
d . click _url = td . click _url ;
if ( td && td . click _action )
d . click _action = td . click _action ;
2019-12-10 20:46:33 -05:00
if ( use _media ) {
2021-02-17 02:08:21 -05:00
out . push ( ` @media (max-resolution: 99dpi) { ${ selector } { ${ generateBadgeCSS ( key , version , d , style , is _dark , badge _version , this . color _fixer , this . fg _fixer , 1 , can _click ) } }} ` ) ;
out . push ( ` @media (min-resolution: 100dpi) and (max-resolution:199dpi) { ${ selector } { ${ generateBadgeCSS ( key , version , d , style , is _dark , badge _version , this . color _fixer , this . fg _fixer , 2 , can _click ) } }} ` ) ;
out . push ( ` @media (min-resolution: 200dpi) { ${ selector } { ${ generateBadgeCSS ( key , version , d , style , is _dark , badge _version , this . color _fixer , this . fg _fixer , 4 , can _click ) } }} ` ) ;
2019-12-10 20:46:33 -05:00
} else
2021-02-17 02:08:21 -05:00
out . push ( ` ${ selector } { ${ generateBadgeCSS ( key , version , d , style , is _dark , badge _version , this . color _fixer , this . fg _fixer , undefined , can _click ) } } ` ) ;
2017-11-28 02:03:59 -05:00
}
}
this . style . set ( 'css-badges' , out . join ( '\n' ) ) ;
}
buildTwitchBadgeCSS ( ) {
if ( ! this . twitch _badges )
this . style . delete ( 'twitch-badges' ) ;
2019-12-05 23:13:27 -05:00
const badge _version = this . parent . context . get ( 'chat.badges.version' ) ,
2019-12-10 20:46:33 -05:00
use _media = IS _FIREFOX && this . parent . context . get ( 'chat.badges.media-queries' ) ,
2020-08-17 13:33:30 -04:00
can _click = this . parent . context . get ( 'chat.badges.clickable' ) ,
2019-12-05 23:13:27 -05:00
versioned = CSS _BADGES [ badge _version ] || { } ;
2017-11-28 02:03:59 -05:00
const out = [ ] ;
2018-01-19 17:17:16 -05:00
for ( const key in this . twitch _badges )
if ( has ( this . twitch _badges , key ) ) {
2019-12-05 23:13:27 -05:00
if ( has ( versioned , key ) )
2018-01-19 17:17:16 -05:00
continue ;
const versions = this . twitch _badges [ key ] ;
for ( const version in versions )
if ( has ( versions , version ) ) {
2019-12-10 20:46:33 -05:00
const data = versions [ version ] ,
selector = ` .ffz-badge[data-badge=" ${ key } "][data-version=" ${ version } "] ` ;
2018-01-19 17:17:16 -05:00
2019-12-10 20:46:33 -05:00
out . push ( ` ${ selector } {
2020-08-17 13:33:30 -04:00
$ { can _click && ( data . click _action || data . click _url ) ? 'cursor:pointer;' : '' }
2018-01-19 17:17:16 -05:00
background - color : transparent ;
filter : none ;
$ { WEBKIT } mask - image : none ;
background - size : 1.8 rem ;
background - image : url ( "${data.image1x}" ) ;
background - image : $ { WEBKIT } image - set (
url ( "${data.image1x}" ) 1 x ,
url ( "${data.image2x}" ) 2 x ,
url ( "${data.image4x}" ) 4 x
) ;
2019-12-10 20:46:33 -05:00
} ` );
if ( use _media ) {
out . push ( ` @media (min-resolution: 100dpi) and (max-resolution:199dpi) { ${ selector } {
2019-12-10 22:07:48 -05:00
background - image : url ( "${data.image2x}" ) ;
2019-12-10 20:46:33 -05:00
} } ` );
out . push ( ` @media (min-resolution: 200dpi) { ${ selector } {
2019-12-10 22:07:48 -05:00
background - image : url ( "${data.image4x}" ) ;
2019-12-10 20:46:33 -05:00
} } ` );
}
2018-01-19 17:17:16 -05:00
}
2017-11-28 02:03:59 -05:00
}
2017-11-13 01:23:39 -05:00
2017-11-28 02:03:59 -05:00
if ( out . length )
this . style . set ( 'twitch-badges' , out . join ( '\n' ) ) ;
else
this . style . delete ( 'twitch-badges' ) ;
}
2020-01-24 19:02:06 -05:00
}
2021-06-10 18:53:16 -04:00
const OTHER _BADGES = [
'vga-champ-2017' ,
'warcraft' ,
'samusoffer_beta' ,
'power-rangers' ,
'bits-charity' ,
'glhf-pledge'
] ;
2020-08-17 13:33:30 -04:00
export function getBadgeCategory ( key ) {
2021-06-10 18:53:16 -04:00
if ( OTHER _BADGES . includes ( key ) )
return 'm-other' ;
else if ( key . startsWith ( 'overwatch-league' ) )
2020-01-24 19:02:06 -05:00
return 'm-owl' ;
2021-06-10 18:53:16 -04:00
else if ( key . startsWith ( 'twitchcon' ) || key . startsWith ( 'glitchcon' ) )
2020-01-24 19:02:06 -05:00
return 'm-tcon' ;
else if ( /_\d+$/ . test ( key ) )
return 'm-game' ;
return 'm-twitch' ;
2020-08-17 13:33:30 -04:00
}
export function fixBadgeData ( badge ) {
if ( ! badge )
return badge ;
2021-07-27 22:51:04 -04:00
// Duplicate the badge object, because
// Apollo results are frozen.
badge = { ... badge } ;
2020-08-17 13:33:30 -04:00
// Click Behavior
2021-02-22 20:11:35 -05:00
if ( ! badge . clickAction && badge . onClickAction )
badge . clickAction = badge . onClickAction ;
2020-08-17 13:33:30 -04:00
if ( badge . clickAction === 'VISIT_URL' && badge . clickURL )
badge . click _url = badge . clickURL ;
if ( badge . clickAction === 'TURBO' )
badge . click _url = 'https://www.twitch.tv/products/turbo?ref=chat_badge' ;
if ( badge . clickAction === 'SUBSCRIBE' && badge . channelName )
badge . click _url = ` https://www.twitch.tv/subs/ ${ badge . channelName } ` ;
else if ( badge . clickAction )
badge . click _action = 'sub' ;
// Subscriber Tier
if ( badge . setID === 'subscriber' ) {
const id = parseInt ( badge . version , 10 ) ;
if ( ! isNaN ( id ) && isFinite ( id ) ) {
badge . tier = ( id - ( id % 1000 ) ) / 1000 ;
if ( badge . tier < 0 )
badge . tier = 0 ;
} else
badge . tier = 0 ;
}
return badge ;
2017-11-13 01:23:39 -05:00
}