2017-11-13 01:23:39 -05:00
'use strict' ;
// ============================================================================
// Menu Module
// ============================================================================
import Module from 'utilities/module' ;
2018-04-01 18:24:08 -04:00
import { createElement } from 'utilities/dom' ;
2019-06-03 19:47:41 -04:00
import { get , has , deep _copy } from 'utilities/object' ;
2017-11-13 01:23:39 -05:00
2018-07-24 16:11:02 -04:00
import Dialog from 'utilities/dialog' ;
2018-03-24 04:19:41 -04:00
2018-10-22 18:56:24 -04:00
import Mixin from './setting-mixin' ;
2018-07-24 16:11:02 -04:00
import { parse _path } from 'src/settings' ;
2018-03-24 04:19:41 -04:00
2017-11-13 01:23:39 -05:00
function format _term ( term ) {
return term . replace ( /<[^>]*>/g , '' ) . toLocaleLowerCase ( ) ;
}
2018-07-18 18:58:05 -04:00
// TODO: Rewrite literally everything about the menu to use a router and further
2017-11-13 01:23:39 -05:00
// separate the concept of navigation from visible pages.
export default class MainMenu extends Module {
constructor ( ... args ) {
super ( ... args ) ;
this . inject ( 'settings' ) ;
this . inject ( 'i18n' ) ;
this . inject ( 'site' ) ;
this . inject ( 'vue' ) ;
2018-04-05 15:44:47 -04:00
this . load _requires = [ 'vue' ] ;
2018-10-22 18:56:24 -04:00
this . Mixin = Mixin ;
2017-11-13 01:23:39 -05:00
//this.should_enable = true;
2019-05-03 22:52:26 -04:00
this . new _seen = false ;
2017-11-13 01:23:39 -05:00
this . _settings _tree = null ;
this . _settings _count = 0 ;
2018-07-24 16:11:02 -04:00
this . dialog = new Dialog ( ( ) => this . buildDialog ( ) ) ;
2018-07-18 18:58:05 -04:00
this . has _update = false ;
2019-05-03 22:36:26 -04:00
this . opened = false ;
2019-06-03 19:47:41 -04:00
this . showing = false ;
2017-11-13 01:23:39 -05:00
this . settings . addUI ( 'profiles' , {
path : 'Data Management @{"sort": 1000, "profile_warning": false} > Profiles @{"profile_warning": false}' ,
component : 'profile-manager'
} ) ;
2019-03-14 21:43:44 -04:00
this . settings . addUI ( 'backup' , {
path : 'Data Management > Backup and Restore @{"profile_warning": false}' ,
component : 'backup-restore' ,
getFFZ : ( ) => this . resolve ( 'core' )
} ) ;
2017-11-13 01:23:39 -05:00
this . settings . addUI ( 'home' , {
path : 'Home @{"sort": -1000, "profile_warning": false}' ,
component : 'home-page'
} ) ;
2019-05-03 19:30:46 -04:00
this . settings . addUI ( 'faq' , {
path : 'Home > FAQ' ,
component : 'faq-page'
} ) ;
2017-11-13 01:23:39 -05:00
this . settings . addUI ( 'feedback' , {
path : 'Home > Feedback' ,
component : 'feedback-page'
} ) ;
2018-12-03 18:08:32 -05:00
this . settings . addUI ( 'feedback.log' , {
path : 'Home > Feedback >> Log @{"sort": 1000}' ,
component : 'async-text' ,
watch : [
'reports.error.include-user' ,
'reports.error.include-settings'
] ,
data : ( ) => this . resolve ( 'core' ) . generateLog ( )
} )
2017-11-13 01:23:39 -05:00
this . settings . addUI ( 'changelog' , {
path : 'Home > Changelog' ,
component : 'changelog'
} ) ;
2018-09-24 14:33:06 -04:00
this . on ( 'settings:added-definition' , ( key , definition ) => {
this . _addDefinitionToTree ( key , definition ) ;
this . scheduleUpdate ( ) ;
} )
2018-07-18 18:58:05 -04:00
this . on ( 'socket:command:new_version' , version => {
if ( version === window . FrankerFaceZ . version _info . commit )
return ;
2018-08-02 14:29:18 -04:00
this . log . info ( 'New Version:' , version ) ;
2018-07-18 18:58:05 -04:00
this . has _update = true ;
const mb = this . resolve ( 'site.menu_button' ) ;
if ( mb )
mb . has _update = true ;
if ( this . _vue )
this . _vue . $children [ 0 ] . context . has _update = true ;
} ) ;
2019-05-03 22:36:26 -04:00
this . scheduleUpdate ( ) ;
2017-11-13 01:23:39 -05:00
}
2018-07-05 20:27:17 -04:00
openPopout ( ) {
const win = window . open (
'https://twitch.tv/popout/frankerfacez/chat?ffz-settings' ,
'_blank' ,
'resizable=yes,scrollbars=yes,width=850,height=600'
) ;
if ( win ) {
win . focus ( ) ;
return true ;
} else {
this . log . warn ( 'Unable to open popout settings window.' ) ;
return false ;
}
}
2017-11-13 01:23:39 -05:00
async onLoad ( ) {
this . vue . component (
( await import ( /* webpackChunkName: "main-menu" */ './components.js' ) ) . default
) ;
}
2018-07-24 16:11:02 -04:00
async onEnable ( ) {
await this . site . awaitElement ( Dialog . EXCLUSIVE ) ;
2017-11-13 01:23:39 -05:00
2019-06-01 02:11:22 -04:00
this . on ( 'addons:added' , this . scheduleUpdate , this ) ;
this . on ( 'i18n:update' , this . scheduleUpdate , this ) ;
2019-05-03 22:36:26 -04:00
this . dialog . on ( 'show' , ( ) => {
2019-06-03 19:47:41 -04:00
this . showing = true ;
2019-05-03 22:36:26 -04:00
this . opened = true ;
this . updateButtonUnseen ( ) ;
this . emit ( 'show' )
} ) ;
this . dialog . on ( 'hide' , ( ) => {
2019-06-03 19:47:41 -04:00
this . showing = false ;
2019-05-03 22:36:26 -04:00
this . emit ( 'hide' ) ;
this . destroyDialog ( ) ;
} ) ;
2018-07-24 16:11:02 -04:00
this . dialog . on ( 'resize' , ( ) => {
if ( this . _vue )
this . _vue . $children [ 0 ] . maximized = this . dialog . maximized
} ) ;
2017-11-13 01:23:39 -05:00
2018-07-24 16:11:02 -04:00
this . on ( 'site.menu_button:clicked' , this . dialog . toggleVisible , this . dialog ) ;
this . dialog . show ( ) ;
2017-11-13 01:23:39 -05:00
}
onDisable ( ) {
2018-07-24 16:11:02 -04:00
this . dialog . hide ( ) ;
this . off ( 'site.menu_button:clicked' , this . dialog . toggleVisible , this . dialog ) ;
2017-11-13 01:23:39 -05:00
}
2019-06-03 19:47:41 -04:00
requestPage ( page ) {
const vue = get ( '_vue.$children.0' , this ) ;
if ( vue && vue . navigate )
vue . navigate ( page ) ;
else
this . _wanted _page = page ;
}
2019-05-03 22:36:26 -04:00
getUnseen ( ) {
const pages = this . getSettingsTree ( ) ;
if ( ! Array . isArray ( pages ) )
return 0 ;
let i = 0 ;
for ( const page of pages )
if ( page )
i += ( page . unseen || 0 ) ;
return i ;
}
2018-07-24 16:11:02 -04:00
buildDialog ( ) {
if ( this . _menu )
return this . _menu ;
2017-11-13 01:23:39 -05:00
2018-07-24 16:11:02 -04:00
this . _vue = new this . vue . Vue ( {
el : createElement ( 'div' ) ,
render : h => h ( 'main-menu' , this . getData ( ) )
} ) ;
2017-11-13 01:23:39 -05:00
2018-07-24 16:11:02 -04:00
return this . _menu = this . _vue . $el ;
2017-11-13 01:23:39 -05:00
}
2018-07-24 16:11:02 -04:00
destroyDialog ( ) {
if ( this . _vue )
this . _vue . $destroy ( ) ;
2017-11-13 01:23:39 -05:00
2018-07-24 16:11:02 -04:00
this . _menu = this . _vue = null ;
2017-11-13 01:23:39 -05:00
}
2018-09-24 14:33:06 -04:00
scheduleUpdate ( ) {
if ( this . _update _timer )
return ;
this . _update _timer = setTimeout ( ( ) => this . updateLiveMenu ( ) , 250 ) ;
}
2019-05-03 22:36:26 -04:00
updateButtonUnseen ( ) {
const mb = this . resolve ( 'site.menu_button' ) ;
if ( mb )
mb . new _settings = this . opened ? 0 : this . getUnseen ( ) ;
}
2018-09-24 14:33:06 -04:00
updateLiveMenu ( ) {
clearTimeout ( this . _update _timer ) ;
this . _update _timer = null ;
2019-05-03 22:36:26 -04:00
this . updateButtonUnseen ( ) ;
2018-09-24 14:33:06 -04:00
if ( ! this . _vue || ! this . _vue . $children || ! this . _vue . $children [ 0 ] )
return ;
const root = this . _vue . $children [ 0 ] ,
item = root . currentItem ,
key = item && item . full _key ,
tree = this . getSettingsTree ( ) ;
root . nav = tree ;
root . nav _keys = tree . keys ;
2019-06-03 19:47:41 -04:00
root . currentItem = tree . keys [ key ] || ( this . _wanted _page && tree . keys [ this . _wanted _page ] ) || ( this . has _update ?
2018-09-24 14:33:06 -04:00
tree . keys [ 'home.changelog' ] :
tree . keys [ 'home' ] ) ;
2019-06-03 19:47:41 -04:00
this . _wanted _page = null ;
2018-09-24 14:33:06 -04:00
}
2017-11-13 01:23:39 -05:00
rebuildSettingsTree ( ) {
this . _settings _tree = { } ;
this . _settings _count = 0 ;
for ( const [ key , def ] of this . settings . definitions )
this . _addDefinitionToTree ( key , def ) ;
for ( const [ key , def ] of this . settings . ui _structures )
this . _addDefinitionToTree ( key , def ) ;
}
_addDefinitionToTree ( key , def ) {
if ( ! def . ui || ! this . _settings _tree )
return ;
if ( ! def . ui . path _tokens ) {
if ( def . ui . path )
def . ui . path _tokens = parse _path ( def . ui . path ) ;
else
return ;
}
if ( ! def . ui || ! def . ui . path _tokens || ! this . _settings _tree )
return ;
const tree = this . _settings _tree ,
tokens = def . ui . path _tokens ,
len = tokens . length ;
let prefix = null ,
token ;
// Create and/or update all the necessary structure elements for
// this node in the settings tree.
for ( let i = 0 ; i < len ; i ++ ) {
const raw _token = tokens [ i ] ,
key = prefix ? ` ${ prefix } . ${ raw _token . key } ` : raw _token . key ;
token = tree [ key ] ;
if ( ! token )
token = tree [ key ] = {
full _key : key ,
sort : 0 ,
parent : prefix ,
2019-05-03 22:36:26 -04:00
expanded : prefix == null ,
2017-11-13 01:23:39 -05:00
i18n _key : ` setting. ${ key } ` ,
desc _i18n _key : ` setting. ${ key } .description `
} ;
Object . assign ( token , raw _token ) ;
2018-07-13 14:32:12 -04:00
2017-11-13 01:23:39 -05:00
prefix = key ;
}
// Add this setting to the tree.
token . settings = token . settings || [ ] ;
token . settings . push ( [ key , def ] ) ;
this . _settings _count ++ ;
}
getSettingsTree ( ) {
const started = performance . now ( ) ;
if ( ! this . _settings _tree )
this . rebuildSettingsTree ( ) ;
const tree = this . _settings _tree ,
2019-05-03 22:52:26 -04:00
settings _seen = this . new _seen ? null : this . settings . provider . get ( 'cfg-seen' ) ,
new _seen = settings _seen ? null : [ ] ,
2019-05-03 22:36:26 -04:00
collapsed = this . settings . provider . get ( 'cfg-collapsed' ) ,
2017-11-13 01:23:39 -05:00
root = { } ,
copies = { } ,
needs _sort = new Set ,
needs _component = new Set ,
have _locale = this . i18n . locale !== 'en' ;
2019-05-03 22:52:26 -04:00
if ( new _seen )
this . new _seen = true ;
2017-11-13 01:23:39 -05:00
for ( const key in tree ) {
if ( ! has ( tree , key ) )
continue ;
const token = copies [ key ] = copies [ key ] || Object . assign ( { } , tree [ key ] ) ,
p _key = token . parent ,
parent = p _key ?
( copies [ p _key ] = copies [ p _key ] || Object . assign ( { } , tree [ p _key ] ) ) :
root ;
token . parent = p _key ? parent : null ;
token . page = token . page || parent . page ;
2019-05-03 22:36:26 -04:00
if ( collapsed )
token . expanded = ! collapsed . includes ( token . full _key ) ;
2017-11-13 01:23:39 -05:00
if ( token . page && ! token . component )
needs _component . add ( token ) ;
if ( token . settings ) {
const list = token . contents = token . contents || [ ] ;
for ( const [ setting _key , def ] of token . settings )
if ( def . ui ) { //} && def.ui.title ) {
const i18n _key = ` ${ token . i18n _key } . ${ def . ui . key } `
const tok = Object . assign ( {
i18n _key ,
desc _i18n _key : ` ${ i18n _key } .description ` ,
sort : 0 ,
title : setting _key
} , def . ui , {
full _key : ` setting: ${ setting _key } ` ,
setting : setting _key ,
path _tokens : undefined ,
parent : token
} ) ;
2017-11-15 21:59:47 -05:00
if ( has ( def , 'default' ) && ! has ( tok , 'default' ) ) {
2017-11-13 01:23:39 -05:00
const def _type = typeof def . default ;
2018-04-02 03:30:22 -04:00
if ( def _type === 'object' )
tok . default = deep _copy ( def . default ) ;
else
2017-11-13 01:23:39 -05:00
tok . default = def . default ;
}
2019-06-01 02:11:22 -04:00
let terms = [
2017-11-13 01:23:39 -05:00
setting _key ,
this . i18n . t ( tok . i18n _key , tok . title , tok , true )
] ;
if ( have _locale && this . i18n . has ( tok . i18n _key ) )
terms . push ( this . i18n . t ( tok . i18n _key , tok . title , tok ) ) ;
if ( tok . description ) {
terms . push ( this . i18n . t ( tok . desc _i18n _key , tok . description , tok , true ) ) ;
if ( have _locale && this . i18n . has ( tok . desc _i18n _key ) )
terms . push ( this . i18n . t ( tok . desc _i18n _key , tok . description , tok ) ) ;
}
2019-06-01 02:11:22 -04:00
if ( tok . getExtraTerms )
terms = terms . concat ( tok . getExtraTerms ( ) ) ;
2017-11-13 01:23:39 -05:00
tok . search _terms = terms . map ( format _term ) . join ( '\n' ) ;
2019-05-03 22:52:26 -04:00
if ( settings _seen ) {
if ( ! settings _seen . includes ( setting _key ) ) {
let i = tok ;
while ( i ) {
i . unseen = ( i . unseen || 0 ) + 1 ;
i = i . parent ;
}
}
} else if ( new _seen )
new _seen . push ( setting _key ) ;
2019-05-03 22:36:26 -04:00
2017-11-13 01:23:39 -05:00
list . push ( tok ) ;
}
token . settings = undefined ;
if ( list . length > 1 )
needs _sort . add ( list ) ;
}
if ( ! token . search _terms ) {
const formatted = this . i18n . t ( token . i18n _key , token . title , token , true ) ;
let terms = [ token . key ] ;
if ( formatted && formatted . localeCompare ( token . key , undefined , { sensitivity : 'base' } ) )
terms . push ( formatted ) ;
if ( have _locale && this . i18n . has ( token . i18n _key ) )
terms . push ( this . i18n . t ( token . i18n _key , token . title , token ) ) ;
if ( token . description ) {
terms . push ( this . i18n . t ( token . desc _i18n _key , token . description , token , true ) ) ;
if ( have _locale && this . i18n . has ( token . desc _i18n _key ) )
terms . push ( this . i18n . t ( token . desc _i18n _key , token . description , token ) ) ;
}
terms = terms . map ( format _term ) ;
for ( const lk of [ 'tabs' , 'contents' , 'items' ] )
if ( token [ lk ] )
for ( const tok of token [ lk ] )
if ( tok . search _terms )
terms . push ( tok . search _terms ) ;
terms = token . search _terms = terms . join ( '\n' ) ;
let p = parent ;
while ( p && p . search _terms ) {
2018-04-02 03:30:22 -04:00
p . search _terms += ` \n ${ terms } ` ;
2017-11-13 01:23:39 -05:00
p = p . parent ;
}
}
const lk = token . tab ? 'tabs' : token . page ? 'contents' : 'items' ,
list = parent [ lk ] = parent [ lk ] || [ ] ;
list . push ( token ) ;
if ( list . length > 1 )
needs _sort . add ( list ) ;
}
for ( const token of needs _component ) {
token . component = token . tabs ? 'tab-container' :
token . contents ? 'menu-container' :
2018-03-24 04:19:41 -04:00
'setting-check-box' ;
2017-11-13 01:23:39 -05:00
}
for ( const list of needs _sort )
list . sort ( ( a , b ) => {
if ( a . sort < b . sort ) return - 1 ;
if ( a . sort > b . sort ) return 1 ;
2018-04-12 02:29:43 -04:00
return a . key && a . key . localeCompare ( b . key ) ;
2017-11-13 01:23:39 -05:00
} ) ;
const items = root . items || [ ] ;
items . keys = copies ;
2019-05-03 22:36:26 -04:00
// Save for now, since we just want to mark everything as seen.
2019-05-03 22:52:26 -04:00
if ( new _seen )
this . settings . provider . set ( 'cfg-seen' , new _seen ) ;
2019-05-03 22:36:26 -04:00
if ( ! collapsed ) {
const new _collapsed = [ ] ;
for ( const key of Object . keys ( copies ) ) {
const item = copies [ key ] ;
if ( item && item . items && item . parent )
new _collapsed . push ( key ) ;
}
this . settings . provider . set ( 'cfg-collapsed' , new _collapsed ) ;
}
this . log . info ( ` Built Tree in ${ ( performance . now ( ) - started ) . toFixed ( 5 ) } ms with ${ Object . keys ( tree ) . length } structure nodes and ${ this . _settings _count } settings nodes. ` ) ;
2017-11-13 01:23:39 -05:00
return items ;
}
getProfiles ( context ) {
const profiles = [ ] ,
keys = { } ;
context = context || this . settings . main _context ;
for ( const profile of this . settings . _ _profiles )
profiles . push ( keys [ profile . id ] = this . getProfileProxy ( profile , context ) ) ;
return [ profiles , keys ] ;
}
2018-03-24 04:19:41 -04:00
getProfileProxy ( profile , context ) { // eslint-disable-line class-methods-use-this
2017-11-13 01:23:39 -05:00
return {
id : profile . id ,
order : context . manager . _ _profiles . indexOf ( profile ) ,
live : context . _ _profiles . includes ( profile ) ,
title : profile . name ,
i18n _key : profile . i18n _key ,
description : profile . description ,
desc _i18n _key : profile . desc _i18n _key || profile . i18n _key && ` ${ profile . i18n _key } .description ` ,
2019-06-13 22:56:50 -04:00
url : profile . url ,
2017-11-13 01:23:39 -05:00
move : idx => context . manager . moveProfile ( profile . id , idx ) ,
save : ( ) => profile . save ( ) ,
update : data => {
profile . data = data
profile . save ( )
} ,
2019-06-13 22:56:50 -04:00
getBackup : ( ) => deep _copy ( profile . getBackup ( ) ) ,
2017-11-13 01:23:39 -05:00
context : deep _copy ( profile . context ) ,
get : key => profile . get ( key ) ,
set : ( key , val ) => profile . set ( key , val ) ,
delete : key => profile . delete ( key ) ,
has : key => profile . has ( key ) ,
on : ( ... args ) => profile . on ( ... args ) ,
off : ( ... args ) => profile . off ( ... args )
}
}
getContext ( ) {
const t = this ,
Vue = this . vue . Vue ,
settings = this . settings ,
context = settings . main _context ,
[ profiles , profile _keys ] = this . getProfiles ( ) ,
2018-03-24 04:19:41 -04:00
_c = {
profiles ,
profile _keys ,
currentProfile : profile _keys [ 0 ] ,
2017-11-13 01:23:39 -05:00
2018-07-18 18:58:05 -04:00
has _update : this . has _update ,
2018-03-24 04:19:41 -04:00
createProfile : data => {
const profile = settings . createProfile ( data ) ;
return t . getProfileProxy ( profile , context ) ;
} ,
2017-11-13 01:23:39 -05:00
2018-03-24 04:19:41 -04:00
deleteProfile : profile => settings . deleteProfile ( profile ) ,
2017-11-13 01:23:39 -05:00
2018-03-24 04:19:41 -04:00
context : {
_users : 0 ,
2017-11-13 01:23:39 -05:00
2018-03-24 04:19:41 -04:00
profiles : context . _ _profiles . map ( profile => profile . id ) ,
get : key => context . get ( key ) ,
uses : key => context . uses ( key ) ,
2017-11-13 01:23:39 -05:00
2018-03-24 04:19:41 -04:00
on : ( ... args ) => context . on ( ... args ) ,
off : ( ... args ) => context . off ( ... args ) ,
2017-11-13 01:23:39 -05:00
2018-03-24 04:19:41 -04:00
order : id => context . order . indexOf ( id ) ,
2019-06-13 22:56:50 -04:00
context : deep _copy ( context . _context ) ,
2017-11-13 01:23:39 -05:00
2018-03-24 04:19:41 -04:00
_update _profiles ( changed ) {
const new _list = [ ] ,
profiles = context . manager . _ _profiles ;
2019-06-13 22:56:50 -04:00
2018-03-24 04:19:41 -04:00
for ( let i = 0 ; i < profiles . length ; i ++ ) {
const profile = profile _keys [ profiles [ i ] . id ] ;
profile . order = i ;
2019-06-13 22:56:50 -04:00
2018-03-24 04:19:41 -04:00
new _list . push ( profile ) ;
}
2017-11-13 01:23:39 -05:00
2018-03-24 04:19:41 -04:00
Vue . set ( _c , 'profiles' , new _list ) ;
2017-11-13 01:23:39 -05:00
2018-03-24 04:19:41 -04:00
if ( changed && changed . id === _c . currentProfile . id )
_c . currentProfile = profile _keys [ changed . id ] ;
} ,
2017-11-13 01:23:39 -05:00
2018-03-24 04:19:41 -04:00
_profile _created ( profile ) {
Vue . set ( profile _keys , profile . id , t . getProfileProxy ( profile , context ) ) ;
this . _update _profiles ( )
} ,
2017-11-13 01:23:39 -05:00
2018-03-24 04:19:41 -04:00
_profile _changed ( profile ) {
Vue . set ( profile _keys , profile . id , t . getProfileProxy ( profile , context ) ) ;
this . _update _profiles ( profile ) ;
} ,
2017-11-13 01:23:39 -05:00
2018-03-24 04:19:41 -04:00
_profile _deleted ( profile ) {
Vue . delete ( profile _keys , profile . id ) ;
this . _update _profiles ( ) ;
2017-11-13 01:23:39 -05:00
2018-03-24 04:19:41 -04:00
if ( _c . currentProfile . id === profile . id )
_c . currentProfile = profile _keys [ 0 ]
} ,
2017-11-13 01:23:39 -05:00
2018-03-24 04:19:41 -04:00
_context _changed ( ) {
2019-06-13 22:56:50 -04:00
this . context = deep _copy ( context . _context ) ;
const profiles = context . manager . _ _profiles ,
ids = this . profiles = context . _ _profiles . map ( profile => profile . id ) ;
for ( let i = 0 ; i < profiles . length ; i ++ ) {
const id = profiles [ i ] . id ,
profile = profile _keys [ id ] ;
profile . live = ids . includes ( id ) ;
2018-03-24 04:19:41 -04:00
}
} ,
_add _user ( ) {
this . _users ++ ;
if ( this . _users === 1 ) {
settings . on ( ':profile-created' , this . _profile _created , this ) ;
settings . on ( ':profile-changed' , this . _profile _changed , this ) ;
settings . on ( ':profile-deleted' , this . _profile _deleted , this ) ;
settings . on ( ':profiles-reordered' , this . _update _profiles , this ) ;
context . on ( 'context_changed' , this . _context _changed , this ) ;
context . on ( 'profiles_changed' , this . _context _changed , this ) ;
this . profiles = context . _ _profiles . map ( profile => profile . id ) ;
}
} ,
_remove _user ( ) {
this . _users -- ;
if ( this . _users === 0 ) {
settings . off ( ':profile-created' , this . _profile _created , this ) ;
settings . off ( ':profile-changed' , this . _profile _changed , this ) ;
settings . off ( ':profile-deleted' , this . _profile _deleted , this ) ;
settings . off ( ':profiles-reordered' , this . _update _profiles , this ) ;
context . off ( 'context_changed' , this . _context _changed , this ) ;
context . off ( 'profiles_changed' , this . _context _changed , this ) ;
}
2017-11-13 01:23:39 -05:00
}
}
2018-03-24 04:19:41 -04:00
} ;
2017-11-13 01:23:39 -05:00
return _c ;
}
2019-05-03 22:36:26 -04:00
markSeen ( item , seen ) {
let had _seen = true ;
if ( ! seen ) {
had _seen = false ;
seen = this . settings . provider . get ( 'cfg-seen' , [ ] ) ;
}
if ( Array . isArray ( item . contents ) ) {
for ( const child of item . contents )
child && this . markSeen ( child , seen ) ;
2019-05-24 22:46:34 -04:00
}
2019-05-29 16:35:09 -04:00
if ( item . setting ) {
if ( ! seen . includes ( item . setting ) ) {
seen . push ( item . setting ) ;
let i = item . parent ;
while ( i ) {
i . unseen = ( i . unseen || 1 ) - 1 ;
i = i . parent ;
}
2019-05-03 22:36:26 -04:00
}
}
if ( ! had _seen )
this . settings . provider . set ( 'cfg-seen' , seen ) ;
}
2019-05-24 22:46:34 -04:00
markAllSeen ( thing , seen ) {
let had _seen = true ;
if ( ! seen ) {
had _seen = false ;
seen = this . settings . provider . get ( 'cfg-seen' , [ ] ) ;
}
if ( Array . isArray ( thing ) )
for ( const page of thing )
if ( page )
this . markAllSeen ( page , seen ) ;
if ( Array . isArray ( thing . items ) )
for ( const item of thing . items )
this . markAllSeen ( item , seen ) ;
if ( Array . isArray ( thing . contents ) )
for ( const content of thing . contents )
this . markAllSeen ( content , seen ) ;
if ( Array . isArray ( thing . tabs ) )
for ( const tab of thing . tabs )
this . markAllSeen ( tab , seen ) ;
if ( Array . isArray ( thing . settings ) )
for ( const setting of thing . settings )
if ( setting )
this . markAllSeen ( setting [ 1 ] , seen ) ;
if ( thing . setting && ! seen . includes ( thing . setting ) )
seen . push ( thing . setting ) ;
if ( thing . unseen )
thing . unseen = 0 ;
if ( ! had _seen )
this . settings . provider . set ( 'cfg-seen' , seen ) ;
}
2017-11-13 01:23:39 -05:00
getData ( ) {
const settings = this . getSettingsTree ( ) ,
2019-05-03 22:36:26 -04:00
context = this . getContext ( ) ,
2019-06-03 19:47:41 -04:00
current = ( this . _wanted _page && settings . keys [ this . _wanted _page ] ) || ( this . has _update ? settings . keys [ 'home.changelog' ] : settings . keys [ 'home' ] ) ;
2019-05-03 22:36:26 -04:00
2019-06-03 19:47:41 -04:00
this . _wanted _page = null ;
2019-05-03 22:36:26 -04:00
this . markSeen ( current ) ;
2017-11-13 01:23:39 -05:00
2019-05-24 22:46:34 -04:00
let has _unseen = false ;
for ( const page of settings )
if ( page && page . unseen ) {
has _unseen = true ;
break ;
}
2019-06-01 02:11:22 -04:00
const out = {
2017-11-13 01:23:39 -05:00
context ,
2018-07-05 20:27:17 -04:00
query : '' ,
faded : false ,
2017-11-13 01:23:39 -05:00
nav : settings ,
2019-05-03 22:36:26 -04:00
currentItem : current ,
2017-11-13 01:23:39 -05:00
nav _keys : settings . keys ,
2019-05-24 22:46:34 -04:00
has _unseen ,
2018-07-24 16:11:02 -04:00
maximized : this . dialog . maximized ,
exclusive : this . dialog . exclusive ,
2019-05-24 22:46:34 -04:00
markAllSeen : thing => this . markAllSeen ( thing ) ,
2019-05-03 22:36:26 -04:00
markSeen : item => this . markSeen ( item ) ,
markExpanded : item => {
const collapsed = this . settings . provider . get ( 'cfg-collapsed' , [ ] ) ,
included = collapsed . indexOf ( item . full _key ) ;
if ( item . expanded && included !== - 1 )
collapsed . splice ( included , 1 ) ;
else if ( ! item . expanded && included === - 1 )
collapsed . push ( item . full _key ) ;
else
return ;
this . settings . provider . set ( 'cfg-collapsed' , collapsed ) ;
} ,
2018-07-24 16:11:02 -04:00
resize : e => ! this . dialog . exclusive && this . dialog . toggleSize ( e ) ,
close : e => ! this . dialog . exclusive && this . dialog . toggleVisible ( e ) ,
2018-07-05 20:27:17 -04:00
popout : e => {
2018-07-24 16:11:02 -04:00
if ( this . dialog . exclusive )
2018-07-05 20:27:17 -04:00
return ;
2018-07-24 16:11:02 -04:00
this . dialog . toggleVisible ( e ) ;
2018-07-05 20:27:17 -04:00
if ( ! this . openPopout ( ) )
2018-07-24 16:11:02 -04:00
alert ( this . i18n . t ( 'popup.error' , 'We tried opening a pop-up window and could not. Make sure to allow pop-ups from Twitch.' ) ) ; // eslint-disable-line no-alert
2018-07-05 20:27:17 -04:00
} ,
2018-03-22 19:09:28 +01:00
2018-07-24 16:11:02 -04:00
version : window . FrankerFaceZ . version _info ,
2019-06-01 02:11:22 -04:00
} ;
return out ;
2017-11-13 01:23:39 -05:00
}
2018-03-24 04:19:41 -04:00
}