2018-03-07 19:06:52 +01:00
namespace Modals {
2019-08-21 10:00:01 +02:00
export function spawnSettingsModal ( default_page? : string ) : Modal {
2019-01-28 20:36:11 +01:00
let modal : Modal ;
modal = createModal ( {
2019-08-21 10:00:01 +02:00
header : tr ( "Settings" ) ,
2019-01-28 20:36:11 +01:00
body : ( ) = > {
2019-08-21 10:00:01 +02:00
const tag = $ ( "#tmpl_settings" ) . renderTag ( ) . dividerfy ( ) ;
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
/* general "tab" mechanic */
const left = tag . find ( "> .left" ) ;
const right = tag . find ( "> .right" ) ;
{
left . find ( ".entry:not(.group)" ) . on ( 'click' , event = > {
const entry = $ ( event . target ) ;
right . find ( "> .container" ) . addClass ( "hidden" ) ;
left . find ( ".selected" ) . removeClass ( "selected" ) ;
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
const target = entry . attr ( "container" ) ;
if ( ! target ) return ;
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
right . find ( "> .container." + target ) . removeClass ( "hidden" ) ;
entry . addClass ( "selected" ) ;
} )
}
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
/* initialize all tabs */
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
/* enable one tab */
{
left . find ( ".entry[container" + ( default_page ? ( "='" + default_page + "'" ) : "" ) + "]" ) . first ( ) . trigger ( 'click' ) ;
}
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
return tag ;
2019-01-28 20:36:11 +01:00
} ,
2019-08-21 10:00:01 +02:00
footer : null
2019-01-28 20:36:11 +01:00
} ) ;
2019-08-21 10:00:01 +02:00
modal . htmlTag . find ( ".modal-body" ) . addClass ( "modal-settings" ) ;
settings_general_application ( modal . htmlTag . find ( ".right .container.general-application" ) , modal ) ;
settings_general_language ( modal . htmlTag . find ( ".right .container.general-language" ) , modal ) ;
settings_general_chat ( modal . htmlTag . find ( ".right .container.general-chat" ) , modal ) ;
settings_audio_microphone ( modal . htmlTag . find ( ".right .container.audio-microphone" ) , modal ) ;
settings_audio_speaker ( modal . htmlTag . find ( ".right .container.audio-speaker" ) , modal ) ;
settings_audio_sounds ( modal . htmlTag . find ( ".right .container.audio-sounds" ) , modal ) ;
const update_profiles = settings_identity_profiles ( modal . htmlTag . find ( ".right .container.identity-profiles" ) , modal ) ;
settings_identity_forum ( modal . htmlTag . find ( ".right .container.identity-forum" ) , modal , update_profiles as any ) ;
2019-01-28 20:36:11 +01:00
modal . open ( ) ;
return modal ;
}
2019-08-21 10:00:01 +02:00
function settings_general_application ( container : JQuery , modal : Modal ) {
/* hostbanner */
{
const option = container . find ( ".option-hostbanner-background" ) as JQuery < HTMLInputElement > ;
option . on ( 'change' , event = > {
settings . changeGlobal ( Settings . KEY_HOSTBANNER_BACKGROUND , option [ 0 ] . checked ) ;
for ( const sc of server_connections . server_connection_handlers ( ) )
sc . hostbanner . update ( ) ;
} ) . prop ( "checked" , settings . static_global ( Settings . KEY_HOSTBANNER_BACKGROUND ) ) ;
}
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
/* font size */
{
const current_size = parseInt ( getComputedStyle ( document . body ) . fontSize ) ; //settings.static_global(Settings.KEY_FONT_SIZE, 12);
const select = container . find ( ".option-font-size" ) ;
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
if ( select . find ( "option[value='" + current_size + "']" ) . length )
select . find ( "option[value='" + current_size + "']" ) . prop ( "selected" , true ) ;
else
select . find ( "option[value='-1']" ) . prop ( "selected" , true ) ;
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
select . on ( 'change' , event = > {
const value = parseInt ( select . val ( ) as string ) ;
2019-09-19 01:25:57 +02:00
settings . changeGlobal ( Settings . KEY_FONT_SIZE , value ) ;
2019-10-19 17:13:40 +02:00
console . log ( "Changed font size to %dpx" , value ) ;
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
$ ( document . body ) . css ( "font-size" , value + "px" ) ;
} ) ;
}
2019-11-24 13:41:42 +01:00
/* all permissions */
{
const option = container . find ( ".option-all-permissions" ) as JQuery < HTMLInputElement > ;
option . on ( 'change' , event = > {
settings . changeGlobal ( Settings . KEY_HOSTBANNER_BACKGROUND , option [ 0 ] . checked ) ;
} ) . prop ( "checked" , settings . global ( Settings . KEY_PERMISSIONS_SHOW_ALL ) ) ;
}
2019-08-21 10:00:01 +02:00
}
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
function settings_general_language ( container : JQuery , modal : Modal ) {
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
const container_entries = container . find ( ".container-list .entries" ) ;
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
const tag_loading = container . find ( ".cover-loading" ) ;
const template = $ ( "#settings-translations-list-entry" ) ;
const restart_hint = container . find ( ".restart-note" ) . hide ( ) ;
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
const display_repository_info = ( repository : i18n.TranslationRepository ) = > {
const info_modal = createModal ( {
header : tr ( "Repository info" ) ,
body : ( ) = > {
return $ ( "#settings-translations-list-entry-info" ) . renderTag ( {
type : "repository" ,
name : repository.name ,
url : repository.url ,
contact : repository.contact ,
translations : repository.translations || [ ]
2019-01-28 20:36:11 +01:00
} ) ;
2019-08-21 10:00:01 +02:00
} ,
footer : ( ) = > {
let footer = $ . spawn ( "div" ) ;
footer . addClass ( "modal-button-group" ) ;
footer . css ( "margin-top" , "5px" ) ;
footer . css ( "margin-bottom" , "5px" ) ;
footer . css ( "text-align" , "right" ) ;
let buttonOk = $ . spawn ( "button" ) ;
buttonOk . text ( tr ( "Close" ) ) ;
buttonOk . click ( ( ) = > info_modal . close ( ) ) ;
footer . append ( buttonOk ) ;
return footer ;
2019-01-28 20:36:11 +01:00
}
2019-08-21 10:00:01 +02:00
} ) ;
info_modal . open ( )
} ;
const display_translation_info = ( translation : i18n.RepositoryTranslation , repository : i18n.TranslationRepository ) = > {
const info_modal = createModal ( {
header : tr ( "Translation info" ) ,
body : ( ) = > {
const tag = $ ( "#settings-translations-list-entry-info" ) . renderTag ( {
type : "translation" ,
name : translation.name ,
url : translation.path ,
repository_name : repository.name ,
contributors : translation.contributors || [ ]
2019-01-28 20:36:11 +01:00
} ) ;
2019-08-21 10:00:01 +02:00
tag . find ( ".button-info" ) . on ( 'click' , ( ) = > display_repository_info ( repository ) ) ;
return tag ;
} ,
footer : ( ) = > {
let footer = $ . spawn ( "div" ) ;
footer . addClass ( "modal-button-group" ) ;
footer . css ( "margin-top" , "5px" ) ;
footer . css ( "margin-bottom" , "5px" ) ;
footer . css ( "text-align" , "right" ) ;
let buttonOk = $ . spawn ( "button" ) ;
buttonOk . text ( tr ( "Close" ) ) ;
buttonOk . click ( ( ) = > info_modal . close ( ) ) ;
footer . append ( buttonOk ) ;
return footer ;
2019-01-28 20:36:11 +01:00
}
2019-08-21 10:00:01 +02:00
} ) ;
info_modal . open ( )
} ;
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
const update_current_selected = ( ) = > {
const container_current = container . find ( ".selected-language" ) ;
container_current . empty ( ) . text ( tr ( "Loading" ) ) ;
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
let current_translation : i18n.RepositoryTranslation ;
i18n . iterate_repositories ( repository = > {
if ( current_translation ) return ;
for ( const entry of repository . translations )
if ( i18n . config . translation_config ( ) . current_translation_path == entry . path ) {
current_translation = entry ;
return ;
}
} ) . then ( ( ) = > {
container_current . empty ( ) ;
const language = current_translation ? current_translation . country_code : "gb" ;
$ . spawn ( "div" ) . addClass ( "country flag-" + language . toLowerCase ( ) ) . attr ( 'title' , i18n . country_name ( language , tr ( "Unknown language" ) ) ) . appendTo ( container_current ) ;
$ . spawn ( "a" ) . text ( current_translation ? current_translation.name : tr ( "English (Default)" ) ) . appendTo ( container_current ) ;
} ) . catch ( error = > {
/* This shall never happen */
} ) ;
} ;
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
const initially_selected = i18n . config . translation_config ( ) . current_translation_url ;
const update_list = ( ) = > {
container_entries . empty ( ) ;
const currently_selected = i18n . config . translation_config ( ) . current_translation_url ;
//Default translation
{
const tag = template . renderTag ( {
type : "default" ,
selected : ! currently_selected || currently_selected == "default"
2018-12-28 15:39:23 +01:00
} ) ;
2019-08-21 10:00:01 +02:00
tag . on ( 'click' , ( ) = > {
i18n . select_translation ( undefined , undefined ) ;
container_entries . find ( ".selected" ) . removeClass ( "selected" ) ;
tag . addClass ( "selected" ) ;
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
update_current_selected ( ) ;
restart_hint . toggle ( initially_selected !== i18n . config . translation_config ( ) . current_translation_url ) ;
} ) ;
tag . appendTo ( container_entries ) ;
}
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
{
tag_loading . show ( ) ;
i18n . iterate_repositories ( repo = > {
let repo_tag = container_entries . find ( "[repository=\"" + repo . unique_id + "\"]" ) ;
if ( repo_tag . length == 0 ) {
repo_tag = template . renderTag ( {
type : "repository" ,
name : repo.name || repo . url ,
id : repo.unique_id
} ) ;
repo_tag . find ( ".button-delete" ) . on ( 'click' , e = > {
e . preventDefault ( ) ;
Modals . spawnYesNo ( tr ( "Are you sure?" ) , tr ( "Do you really want to delete this repository?" ) , answer = > {
if ( answer ) {
i18n . delete_repository ( repo ) ;
update_list ( ) ;
}
} ) ;
} ) ;
repo_tag . find ( ".button-info" ) . on ( 'click' , e = > {
e . preventDefault ( ) ;
display_repository_info ( repo ) ;
} ) ;
container_entries . append ( repo_tag ) ;
}
for ( const translation of repo . translations ) {
const tag = template . renderTag ( {
type : "translation" ,
name : translation.name || translation . path ,
id : repo.unique_id ,
country_code : translation.country_code ,
selected : i18n.config.translation_config ( ) . current_translation_path == translation . path
} ) ;
tag . find ( ".button-info" ) . on ( 'click' , e = > {
e . preventDefault ( ) ;
display_translation_info ( translation , repo ) ;
} ) ;
tag . on ( 'click' , e = > {
if ( e . isDefaultPrevented ( ) ) return ;
i18n . select_translation ( repo , translation ) ;
container_entries . find ( ".selected" ) . removeClass ( "selected" ) ;
tag . addClass ( "selected" ) ;
update_current_selected ( ) ;
restart_hint . toggle ( initially_selected !== i18n . config . translation_config ( ) . current_translation_url ) ;
} ) ;
tag . insertAfter ( repo_tag ) ;
}
} ) . then ( ( ) = > tag_loading . hide ( ) ) . catch ( error = > {
console . error ( error ) ;
/* this should NEVER happen */
} )
}
2018-03-07 19:06:52 +01:00
2019-08-21 10:00:01 +02:00
} ;
/* button add repository */
{
container . find ( ".button-add-repository" ) . on ( 'click' , ( ) = > {
createInputModal ( tr ( "Enter repository URL" ) , tr ( "Enter repository URL:" ) , text = > {
try {
new URL ( text ) ;
return true ;
} catch ( error ) {
return false ;
}
} , url = > {
if ( ! url ) return ;
tag_loading . show ( ) ;
i18n . load_repository ( url as string ) . then ( repository = > {
i18n . register_repository ( repository ) ;
update_list ( ) ;
} ) . catch ( error = > {
tag_loading . hide ( ) ;
createErrorModal ( "Failed to load repository" , tr ( "Failed to query repository.<br>Ensure that this repository is valid and reachable.<br>Error: " ) + error ) . open ( ) ;
} )
} ) . open ( ) ;
} ) ;
}
container . find ( ".button-restart" ) . on ( 'click' , ( ) = > {
if ( app . is_web ( ) ) {
location . reload ( ) ;
2019-01-28 20:36:11 +01:00
} else {
2019-08-21 10:00:01 +02:00
createErrorModal ( tr ( "Not implemented" ) , tr ( "Client restart isn't implemented.<br>Please do it manually!" ) ) . open ( ) ;
2019-01-28 20:36:11 +01:00
}
2019-08-21 10:00:01 +02:00
} ) ;
2019-04-15 16:58:42 +02:00
2019-08-21 10:00:01 +02:00
update_list ( ) ;
update_current_selected ( ) ;
}
function settings_general_chat ( container : JQuery , modal : Modal ) {
/* timestamp format */
{
const option_fixed = container . find ( ".option-fixed-timestamps" ) as JQuery < HTMLInputElement > ;
const option_colloquial = container . find ( ".option-colloquial-timestamps" ) as JQuery < HTMLInputElement > ;
option_colloquial . on ( 'change' , event = > {
settings . changeGlobal ( Settings . KEY_CHAT_COLLOQUIAL_TIMESTAMPS , option_colloquial [ 0 ] . checked ) ;
2019-01-28 20:36:11 +01:00
} ) ;
2019-08-21 10:00:01 +02:00
option_fixed . on ( 'change' , event = > {
settings . changeGlobal ( Settings . KEY_CHAT_FIXED_TIMESTAMPS , option_fixed [ 0 ] . checked ) ;
option_colloquial
. prop ( "disabled" , option_fixed [ 0 ] . checked )
. parents ( "label" ) . toggleClass ( "disabled" , option_fixed [ 0 ] . checked ) ;
if ( option_fixed [ 0 ] . checked ) {
option_colloquial . prop ( "checked" , false ) ;
2019-04-15 16:58:42 +02:00
} else {
2019-08-21 10:00:01 +02:00
option_colloquial . prop ( "checked" , settings . static_global ( Settings . KEY_CHAT_COLLOQUIAL_TIMESTAMPS ) ) ;
2019-04-15 16:58:42 +02:00
}
2019-08-21 10:00:01 +02:00
} ) . prop ( "checked" , settings . static_global ( Settings . KEY_CHAT_FIXED_TIMESTAMPS ) ) . trigger ( 'change' ) ;
}
2019-04-15 16:58:42 +02:00
2019-08-21 10:00:01 +02:00
{
const option = container . find ( ".option-instant-channel-switch" ) as JQuery < HTMLInputElement > ;
option . on ( 'change' , event = > {
settings . changeGlobal ( Settings . KEY_SWITCH_INSTANT_CHAT , option [ 0 ] . checked ) ;
} ) . prop ( "checked" , settings . static_global ( Settings . KEY_SWITCH_INSTANT_CHAT ) ) ;
}
{
const option = container . find ( ".option-instant-client-switch" ) as JQuery < HTMLInputElement > ;
option . on ( 'change' , event = > {
settings . changeGlobal ( Settings . KEY_SWITCH_INSTANT_CLIENT , option [ 0 ] . checked ) ;
} ) . prop ( "checked" , settings . static_global ( Settings . KEY_SWITCH_INSTANT_CLIENT ) ) ;
}
{
const option = container . find ( ".option-colored-emojies" ) as JQuery < HTMLInputElement > ;
option . on ( 'change' , event = > {
settings . changeGlobal ( Settings . KEY_CHAT_COLORED_EMOJIES , option [ 0 ] . checked ) ;
} ) . prop ( "checked" , settings . static_global ( Settings . KEY_CHAT_COLORED_EMOJIES ) ) ;
}
{
const option = container . find ( ".option-support-markdown" ) as JQuery < HTMLInputElement > ;
option . on ( 'change' , event = > {
settings . changeGlobal ( Settings . KEY_CHAT_ENABLE_MARKDOWN , option [ 0 ] . checked ) ;
} ) . prop ( "checked" , settings . static_global ( Settings . KEY_CHAT_ENABLE_MARKDOWN ) ) ;
}
{
const option = container . find ( ".option-url-tagging" ) as JQuery < HTMLInputElement > ;
option . on ( 'change' , event = > {
settings . changeGlobal ( Settings . KEY_CHAT_TAG_URLS , option [ 0 ] . checked ) ;
} ) . prop ( "checked" , settings . static_global ( Settings . KEY_CHAT_TAG_URLS ) ) ;
2019-01-28 20:36:11 +01:00
}
2019-10-19 17:13:40 +02:00
/* Icon size */
{
const container_slider = container . find ( ".container-icon-size .container-slider" ) ;
const container_value = container . find ( ".container-icon-size .value" ) ;
sliderfy ( container_slider , {
unit : '%' ,
min_value : 25 ,
max_value : 300 ,
step : 5 ,
initial_value : settings.static_global ( Settings . KEY_ICON_SIZE ) ,
value_field : container_value
} ) ;
container_slider . on ( 'change' , event = > {
const value = parseInt ( container_slider . attr ( "value" ) as string ) ;
settings . changeGlobal ( Settings . KEY_ICON_SIZE , value ) ;
console . log ( "Changed icon size to %sem" , ( value / 100 ) . toFixed ( 2 ) ) ;
MessageHelper . set_icon_size ( ( value / 100 ) . toFixed ( 2 ) + "em" ) ;
} ) ;
}
2018-03-07 19:06:52 +01:00
}
2019-08-21 10:00:01 +02:00
function settings_audio_microphone ( container : JQuery , modal : Modal ) {
let _callbacks_filter_change : ( ( ) = > any ) [ ] = [ ] ;
/* devices */
{
const container_devices = container . find ( ".container-devices" ) ;
2019-05-20 18:57:14 +02:00
2019-08-21 10:00:01 +02:00
let level_meters : audio.recorder.LevelMeter [ ] = [ ] ;
modal . close_listener . push ( ( ) = > {
for ( const meter of level_meters )
meter . destory ( ) ;
level_meters = [ ] ;
} ) ;
const update_devices = ( ) = > {
container_devices . children ( ) . remove ( ) ;
for ( const meter of level_meters )
meter . destory ( ) ;
level_meters = [ ] ;
const current_selected = default_recorder . current_device ( ) ;
const generate_device = ( device : audio.recorder.InputDevice | undefined ) = > {
const selected = device === current_selected || ( typeof ( current_selected ) !== "undefined" && typeof ( device ) !== "undefined" && current_selected . unique_id == device . unique_id ) ;
let tag_volume : JQuery , tag_volume_error : JQuery ;
const tag = $ . spawn ( "div" ) . addClass ( "device" ) . toggleClass ( "selected" , selected ) . append (
$ . spawn ( "div" ) . addClass ( "container-selected" ) . append (
$ . spawn ( "div" ) . addClass ( "icon_em client-apply" )
) ,
$ . spawn ( "div" ) . addClass ( "container-name" ) . append (
$ . spawn ( "div" ) . addClass ( "device-driver" ) . text (
device ? ( device . driver || "Unknown driver" ) : "No device"
) ,
$ . spawn ( "div" ) . addClass ( "device-name" ) . text (
device ? ( device . name || "Unknown name" ) : "No device"
) ,
) ,
$ . spawn ( "div" ) . addClass ( "container-activity" ) . append (
$ . spawn ( "div" ) . addClass ( "container-activity-bar" ) . append (
tag_volume = $ . spawn ( "div" ) . addClass ( "bar-hider" ) ,
tag_volume_error = $ . spawn ( "div" ) . addClass ( "bar-error" )
)
)
) ;
tag . on ( 'click' , event = > {
if ( tag . hasClass ( "selected" ) )
return ;
2019-05-20 18:57:14 +02:00
2019-08-21 10:00:01 +02:00
const _old = container_devices . find ( ".selected" ) ;
_old . removeClass ( "selected" ) ;
tag . addClass ( "selected" ) ;
2018-03-07 19:06:52 +01:00
2019-08-21 10:00:01 +02:00
default_recorder . set_device ( device ) . then ( ( ) = > {
console . debug ( tr ( "Changed default microphone device" ) ) ;
for ( const cb of _callbacks_filter_change )
cb ( ) ;
} ) . catch ( ( error ) = > {
_old . addClass ( "selected" ) ;
tag . removeClass ( "selected" ) ;
2018-10-28 18:25:43 +01:00
2019-08-21 10:00:01 +02:00
console . error ( tr ( "Failed to change microphone to device %o: %o" ) , device , error ) ;
createErrorModal ( tr ( "Failed to change microphone" ) , MessageHelper . formatMessage ( tr ( "Failed to change the microphone to the target microphone{:br:}{}" ) , error ) ) . open ( ) ;
} ) ;
} ) ;
2018-10-28 18:25:43 +01:00
2019-08-21 10:00:01 +02:00
tag_volume . css ( 'width' , '100%' ) ;
if ( device ) {
audio . recorder . create_levelmeter ( device ) . then ( meter = > {
level_meters . push ( meter ) ;
meter . set_observer ( value = > {
tag_volume . css ( 'width' , ( 100 - value ) + '%' ) ;
} ) ;
} ) . catch ( error = > {
console . warn ( tr ( "Failed to generate levelmeter for device %o: %o" ) , device , error ) ;
tag_volume_error . attr ( 'title' , error ) . text ( error ) ;
} ) ;
2019-03-07 15:30:53 +01:00
}
2018-11-17 16:25:44 +01:00
2019-08-21 10:00:01 +02:00
return tag ;
} ;
2018-03-08 15:40:31 +01:00
2019-08-21 10:00:01 +02:00
generate_device ( undefined ) . appendTo ( container_devices ) ;
audio . recorder . devices ( ) . forEach ( e = > generate_device ( e ) . appendTo ( container_devices ) ) ;
} ;
update_devices ( ) ;
2019-03-07 15:30:53 +01:00
2019-08-21 10:00:01 +02:00
const button_update = container . find ( ".button-update" ) ;
button_update . on ( 'click' , async event = > {
button_update . prop ( "disabled" , true ) ;
if ( audio . recorder . device_refresh_available ( ) ) {
try {
await audio . recorder . refresh_devices ( ) ;
} catch ( error ) {
console . warn ( tr ( "Failed to refresh input devices: %o" ) , error ) ;
}
}
try {
update_devices ( ) ;
} catch ( error ) {
console . error ( tr ( "Failed to build new device list: %o" ) , error ) ;
}
button_update . prop ( "disabled" , false ) ;
} ) ;
}
2019-05-20 18:57:14 +02:00
2019-08-21 10:00:01 +02:00
/* settings */
{
/* volume */
{
const container_volume = container . find ( ".container-volume" ) ;
const slider = container_volume . find ( ".container-slider" ) ;
sliderfy ( slider , {
min_value : 0 ,
max_value : 100 ,
step : 1 ,
initial_value : default_recorder.get_volume ( )
} ) ;
slider . on ( 'change' , event = > {
const value = parseInt ( slider . attr ( "value" ) ) ;
default_recorder . set_volume ( value ) ;
} ) ;
}
2019-05-20 18:57:14 +02:00
2019-08-21 10:00:01 +02:00
/* vad select */
{
const container_select = container . find ( ".container-select-vad" ) ;
container_select . find ( "input" ) . on ( 'change' , event = > {
if ( ! ( < HTMLInputElement > event . target ) . checked )
return ;
2019-05-20 18:57:14 +02:00
2019-08-21 10:00:01 +02:00
const mode = ( < HTMLInputElement > event . target ) . value ;
if ( mode == "active" )
default_recorder . set_vad_type ( "active" ) ;
else if ( mode == "threshold" )
default_recorder . set_vad_type ( "threshold" ) ;
else
default_recorder . set_vad_type ( "push_to_talk" ) ;
for ( const cb of _callbacks_filter_change )
cb ( ) ;
2019-03-07 15:30:53 +01:00
} ) ;
2018-11-17 16:25:44 +01:00
2019-08-21 10:00:01 +02:00
let elements = container_select . find ( 'input[value="' + default_recorder . get_vad_type ( ) + '"]' ) ;
if ( elements . length < 1 )
elements = container_select . find ( 'input[value]' ) ;
elements . first ( ) . trigger ( 'click' ) ;
}
2018-11-17 16:25:44 +01:00
2019-08-21 10:00:01 +02:00
/* Sensitivity */
{
const container_sensitivity = container . find ( ".container-sensitivity" ) ;
2018-11-17 16:25:44 +01:00
2019-08-21 10:00:01 +02:00
const container_bar = container_sensitivity . find ( ".container-activity-bar" ) ;
const bar_hider = container_bar . find ( ".bar-hider" ) ;
2019-03-07 15:30:53 +01:00
2019-08-21 10:00:01 +02:00
sliderfy ( container_bar , {
min_value : 0 ,
max_value : 100 ,
step : 1 ,
initial_value : default_recorder.get_vad_threshold ( )
} ) ;
container_bar . on ( 'change' , event = > {
const threshold = parseInt ( container_bar . attr ( "value" ) ) ;
default_recorder . set_vad_threshold ( threshold ) ;
} ) ;
2019-01-27 13:11:40 +01:00
2019-08-21 10:00:01 +02:00
const _set_level = level = > {
bar_hider . css ( "width" , ( 100 - level ) + "%" ) ;
} ;
2018-03-08 15:40:31 +01:00
2019-08-21 10:00:01 +02:00
let _last_filter : audio.recorder.filter.ThresholdFilter ;
modal . close_listener . push ( ( ) = > {
if ( _last_filter ) {
_last_filter . callback_level = undefined ;
_last_filter = undefined ;
}
} ) ;
_callbacks_filter_change . push ( ( ) = > {
container_sensitivity . toggleClass ( "disabled" , default_recorder . get_vad_type ( ) !== "threshold" ) ;
2018-10-28 18:25:43 +01:00
2019-08-21 10:00:01 +02:00
if ( _last_filter ) {
_last_filter . callback_level = undefined ;
_last_filter = undefined ;
}
2018-10-28 18:25:43 +01:00
2019-08-21 10:00:01 +02:00
if ( default_recorder . get_vad_type ( ) !== "threshold" ) {
container_sensitivity . addClass ( "disabled" ) ;
return ;
}
container_sensitivity . removeClass ( "disabled" ) ;
2019-02-17 16:08:10 +01:00
2019-08-21 10:00:01 +02:00
_set_level ( 0 ) ;
if ( ! default_recorder . input )
return ;
2018-03-08 15:40:31 +01:00
2019-08-21 10:00:01 +02:00
if ( default_recorder . input . current_state ( ) === audio . recorder . InputState . PAUSED )
default_recorder . input . start ( ) . then ( result = > {
if ( result === audio . recorder . InputStartResult . EOK ) {
for ( const cb of _callbacks_filter_change )
cb ( ) ;
}
} ) ; /* for us to show the VAD */
2018-03-08 15:40:31 +01:00
2019-08-21 10:00:01 +02:00
const filter = default_recorder . input . get_filter ( audio . recorder . filter . Type . THRESHOLD ) as audio . recorder . filter . ThresholdFilter ;
if ( ! filter )
return ;
2019-02-17 16:08:10 +01:00
2019-08-21 10:00:01 +02:00
_last_filter = filter ;
filter . callback_level = _set_level ;
} ) ;
}
2018-10-28 18:25:43 +01:00
2019-08-21 10:00:01 +02:00
/* push to talk */
{
/* PPT Key */
{
const button_key = container . find ( ".container-ppt button" ) ;
_callbacks_filter_change . push ( ( ) = > {
button_key . prop ( 'disabled' , default_recorder . get_vad_type ( ) !== "push_to_talk" ) ;
2019-03-07 15:30:53 +01:00
} ) ;
2018-10-28 18:25:43 +01:00
2019-08-21 10:00:01 +02:00
button_key . on ( 'click' , event = > {
Modals . spawnKeySelect ( key = > {
if ( ! key )
return ;
default_recorder . set_vad_ppt_key ( key ) ;
button_key . text ( ppt . key_description ( key ) ) ;
} ) ;
} ) ;
button_key . text ( ppt . key_description ( default_recorder . get_vad_ppt_key ( ) ) ) ;
}
2018-10-28 18:25:43 +01:00
2019-08-21 10:00:01 +02:00
/* Delay */
2019-03-07 15:30:53 +01:00
{
2019-08-21 10:00:01 +02:00
const container_delay = container . find ( ".container-ppt-delay" ) ;
const input_time = container_delay . find ( "input.delay-time" ) ;
const input_enabled = container_delay . find ( "input.delay-enabled" ) ;
input_enabled . on ( 'change' , event = > {
const enabled = input_enabled . prop ( "checked" ) ;
if ( enabled ) {
if ( default_recorder . get_vad_type ( ) === "push_to_talk" )
input_time . prop ( "disabled" , false ) . parent ( ) . removeClass ( "disabled" ) ;
default_recorder . set_vad_ppt_delay ( Math . abs ( default_recorder . get_vad_ppt_delay ( ) ) ) ;
} else {
input_time . prop ( "disabled" , true ) . parent ( ) . addClass ( "disabled" ) ;
default_recorder . set_vad_ppt_delay ( - Math . abs ( default_recorder . get_vad_ppt_delay ( ) ) ) ;
}
} ) ;
input_time . on ( 'change' , event = > {
const value = parseFloat ( input_time . val ( ) as any ) ;
default_recorder . set_vad_ppt_delay ( value * 1000 ) ;
} ) . val ( Math . abs ( default_recorder . get_vad_ppt_delay ( ) / 1000 ) . toFixed ( 2 ) ) ;
input_enabled . prop ( "checked" , default_recorder . get_vad_ppt_delay ( ) >= 0 ) ;
_callbacks_filter_change . push ( ( ) = > {
let enabled = default_recorder . get_vad_type ( ) === "push_to_talk" ;
input_enabled . prop ( "disabled" , ! enabled ) . parent ( ) . toggleClass ( "disabled" , ! enabled ) ;
enabled = enabled && input_enabled . prop ( "checked" ) ;
input_time . prop ( "disabled" , ! enabled ) . parent ( ) . toggleClass ( "disabled" , ! enabled ) ;
2019-03-07 15:30:53 +01:00
} ) ;
}
2018-10-28 18:25:43 +01:00
2019-08-21 10:00:01 +02:00
//delay-time
2018-10-28 18:25:43 +01:00
}
}
2019-08-21 10:00:01 +02:00
for ( const cb of _callbacks_filter_change )
cb ( ) ;
}
function settings_audio_speaker ( container : JQuery , modal : Modal ) {
/* devices */
{
const container_devices = container . find ( ".left .container-devices" ) ;
const contianer_error = container . find ( ".left .container-error" ) ;
2018-10-28 18:25:43 +01:00
2019-02-17 16:08:10 +01:00
const update_devices = ( ) = > {
2019-08-21 10:00:01 +02:00
container_devices . children ( ) . remove ( ) ;
const current_selected = audio . player . current_device ( ) ;
const generate_device = ( device : audio.player.Device | undefined ) = > {
const selected = device === current_selected || ( typeof ( current_selected ) !== "undefined" && typeof ( device ) !== "undefined" && current_selected . device_id == device . device_id ) ;
const tag = $ . spawn ( "div" ) . addClass ( "device" ) . toggleClass ( "selected" , selected ) . append (
$ . spawn ( "div" ) . addClass ( "container-selected" ) . append (
$ . spawn ( "div" ) . addClass ( "icon_em client-apply" )
) ,
$ . spawn ( "div" ) . addClass ( "container-name" ) . append (
$ . spawn ( "div" ) . addClass ( "device-driver" ) . text (
device ? ( device . driver || "Unknown driver" ) : "No device"
) ,
$ . spawn ( "div" ) . addClass ( "device-name" ) . text (
device ? ( device . name || "Unknown name" ) : "No device"
)
)
) ;
tag . on ( 'click' , event = > {
if ( tag . hasClass ( "selected" ) )
return ;
2019-02-17 16:08:10 +01:00
2019-08-21 10:00:01 +02:00
const _old = container_devices . find ( ".selected" ) ;
_old . removeClass ( "selected" ) ;
tag . addClass ( "selected" ) ;
2019-02-17 16:08:10 +01:00
2019-08-21 10:00:01 +02:00
audio . player . set_device ( device ? device.device_id : null ) . then ( ( ) = > {
console . debug ( tr ( "Changed default speaker device" ) ) ;
} ) . catch ( ( error ) = > {
_old . addClass ( "selected" ) ;
tag . removeClass ( "selected" ) ;
2018-10-28 18:25:43 +01:00
2019-08-21 10:00:01 +02:00
console . error ( tr ( "Failed to change speaker to device %o: %o" ) , device , error ) ;
createErrorModal ( tr ( "Failed to change speaker" ) , MessageHelper . formatMessage ( tr ( "Failed to change the speaker device to the target speaker{:br:}{}" ) , error ) ) . open ( ) ;
} ) ;
2018-10-28 18:25:43 +01:00
} ) ;
2019-02-17 16:08:10 +01:00
2019-08-21 10:00:01 +02:00
return tag ;
} ;
2019-04-29 18:49:01 +02:00
2019-08-21 10:00:01 +02:00
generate_device ( undefined ) . appendTo ( container_devices ) ;
audio . player . available_devices ( ) . then ( result = > {
contianer_error . text ( "" ) . hide ( ) ;
result . forEach ( e = > generate_device ( e ) . appendTo ( container_devices ) ) ;
} ) . catch ( error = > {
if ( typeof ( error ) === "string" )
contianer_error . text ( error ) . show ( ) ;
2018-03-17 08:05:37 +01:00
2019-08-21 10:00:01 +02:00
console . log ( tr ( "Failed to query available speaker devices: %o" ) , error ) ;
contianer_error . text ( tr ( "Errors occurred (View console)" ) ) . show ( ) ;
} ) ;
} ;
update_devices ( ) ;
2019-01-27 13:11:40 +01:00
2019-08-21 10:00:01 +02:00
const button_update = container . find ( ".button-update" ) ;
button_update . on ( 'click' , async event = > {
button_update . prop ( "disabled" , true ) ;
try {
update_devices ( ) ;
} catch ( error ) {
console . error ( tr ( "Failed to build new speaker device list: %o" ) , error ) ;
}
button_update . prop ( "disabled" , false ) ;
} ) ;
}
2019-01-27 13:11:40 +01:00
2019-08-21 10:00:01 +02:00
/* slider */
{
2019-01-27 13:11:40 +01:00
{
2019-08-21 10:00:01 +02:00
const container_master = container . find ( ".container-volume-master" ) ;
const slider = container_master . find ( ".container-slider" ) ;
sliderfy ( slider , {
min_value : 0 ,
max_value : 100 ,
step : 1 ,
initial_value : settings.static_global ( Settings . KEY_SOUND_MASTER , 100 ) ,
value_field : [ container_master . find ( ".container-value" ) ]
} ) ;
slider . on ( 'change' , event = > {
const volume = parseInt ( slider . attr ( 'value' ) ) ;
if ( audio . player . set_master_volume )
audio . player . set_master_volume ( volume / 100 ) ;
settings . changeGlobal ( Settings . KEY_SOUND_MASTER , volume ) ;
} ) ;
2019-01-27 13:11:40 +01:00
}
{
2019-08-21 10:00:01 +02:00
const container_soundpack = container . find ( ".container-volume-soundpack" ) ;
const slider = container_soundpack . find ( ".container-slider" ) ;
sliderfy ( slider , {
min_value : 0 ,
max_value : 100 ,
step : 1 ,
initial_value : settings.static_global ( Settings . KEY_SOUND_MASTER_SOUNDS , 100 ) ,
value_field : [ container_soundpack . find ( ".container-value" ) ]
} ) ;
slider . on ( 'change' , event = > {
const volume = parseInt ( slider . attr ( 'value' ) ) ;
sound . set_master_volume ( volume / 100 ) ;
settings . changeGlobal ( Settings . KEY_SOUND_MASTER_SOUNDS , volume ) ;
} ) ;
2019-01-27 13:11:40 +01:00
}
2019-08-21 10:00:01 +02:00
}
2019-01-27 13:11:40 +01:00
2019-08-21 10:00:01 +02:00
/* button test sound */
{
container . find ( ".button-test-sound" ) . on ( 'click' , event = > {
sound . manager . play ( Sound . SOUND_TEST , {
default_volume : 1 ,
ignore_muted : true ,
ignore_overlap : true
} )
} ) ;
}
}
2019-01-27 13:11:40 +01:00
2019-08-21 10:00:01 +02:00
function settings_audio_sounds ( contianer : JQuery , modal : Modal ) {
/* initialize sound list */
{
const container_sounds = contianer . find ( ".container-sounds" ) ;
const generate_sound = ( _sound : Sound ) = > {
let tag_play_pause : JQuery , tag_play : JQuery , tag_pause : JQuery , tag_input_muted : JQuery ;
let tag = $ . spawn ( "div" ) . addClass ( "sound" ) . append (
tag_play_pause = $ . spawn ( "div" ) . addClass ( "container-button-play_pause" ) . append (
tag_play = $ . spawn ( "img" ) . attr ( "src" , "img/icon_sound_play.svg" ) ,
tag_pause = $ . spawn ( "img" ) . attr ( "src" , "img/icon_sound_pause.svg" )
) ,
$ . spawn ( "div" ) . addClass ( "container-name" ) . text ( _sound ) ,
$ . spawn ( "label" ) . addClass ( "container-button-toggle" ) . append (
$ . spawn ( "div" ) . addClass ( "switch" ) . append (
tag_input_muted = $ . spawn ( "input" ) . attr ( "type" , "checkbox" ) ,
$ . spawn ( "span" ) . addClass ( "slider" ) . append (
$ . spawn ( "div" ) . addClass ( "dot" )
)
)
)
) ;
tag_play_pause . on ( 'click' , event = > {
if ( tag_pause . is ( ":visible" ) )
return ;
tag_play . hide ( ) ;
tag_pause . show ( ) ;
2019-01-27 13:11:40 +01:00
2019-08-21 10:00:01 +02:00
const _done = flag = > {
tag_pause . hide ( ) ;
tag_play . show ( ) ;
2019-01-27 13:11:40 +01:00
} ;
2019-08-21 10:00:01 +02:00
const _timeout = setTimeout ( ( ) = > _done ( false ) , 10 * 1000 ) ; /* the sounds are not longer than 10 seconds */
2019-01-27 13:11:40 +01:00
2019-08-21 10:00:01 +02:00
sound . manager . play ( _sound , {
ignore_overlap : true ,
ignore_muted : true ,
default_volume : 1 ,
2019-01-27 13:11:40 +01:00
2019-08-21 10:00:01 +02:00
callback : flag = > {
clearTimeout ( _timeout ) ;
_done ( flag ) ;
}
2019-01-27 13:11:40 +01:00
} ) ;
2019-08-21 10:00:01 +02:00
} ) ;
tag_pause . hide ( ) ;
2019-01-27 13:11:40 +01:00
2019-08-21 10:00:01 +02:00
tag_input_muted . prop ( "checked" , sound . get_sound_volume ( _sound , 1 ) > 0 ) ;
tag_input_muted . on ( 'change' , event = > {
const volume = tag_input_muted . prop ( "checked" ) ? 1 : 0 ;
sound . set_sound_volume ( _sound , volume ) ;
console . log ( tr ( "Changed sound volume to %o for sound %o" ) , volume , _sound ) ;
2019-01-27 13:11:40 +01:00
} ) ;
2019-08-21 10:00:01 +02:00
return tag ;
} ;
//container-sounds
for ( const sound_key in Sound )
generate_sound ( Sound [ sound_key as any ] as any ) . appendTo ( container_sounds ) ;
/* the filter */
const input_filter = contianer . find ( ".input-sounds-filter" ) ;
input_filter . on ( 'change keyup' , event = > {
const filter = input_filter . val ( ) as string ;
container_sounds . find ( ".sound" ) . each ( ( _ , _element ) = > {
const element = $ ( _element ) ;
element . toggle ( filter . length == 0 || element . text ( ) . toLowerCase ( ) . indexOf ( filter ) !== - 1 ) ;
} )
} ) ;
2019-01-27 13:11:40 +01:00
}
2019-08-21 10:00:01 +02:00
const overlap_tag = contianer . find ( ".option-overlap-same" ) ;
overlap_tag . on ( 'change' , event = > {
const activated = ( < HTMLInputElement > event . target ) . checked ;
sound . set_overlap_activated ( activated ) ;
} ) . prop ( "checked" , sound . overlap_activated ( ) ) ;
2018-03-17 08:05:37 +01:00
2019-08-21 10:00:01 +02:00
const mute_tag = contianer . find ( ".option-mute-output" ) ;
mute_tag . on ( 'change' , event = > {
const activated = ( < HTMLInputElement > event . target ) . checked ;
sound . set_ignore_output_muted ( ! activated ) ;
} ) . prop ( "checked" , ! sound . ignore_output_muted ( ) ) ;
2018-05-05 14:58:30 +02:00
2019-08-21 10:00:01 +02:00
modal . close_listener . push ( sound . save ) ;
}
2018-12-15 14:04:29 +01:00
2019-08-21 10:00:01 +02:00
type SelectedIdentity = {
identity : profiles.ConnectionProfile ;
2019-03-07 15:30:53 +01:00
2019-08-21 10:00:01 +02:00
update_name ( text? : string ) ;
update_valid_flag ( ) ;
update_type ( ) ;
2019-03-07 15:30:53 +01:00
2019-08-21 10:00:01 +02:00
update_avatar ( ) ;
}
function settings_identity_profiles ( container : JQuery , modal : Modal ) {
let selected_profile : SelectedIdentity ;
let selected_profile_changed : ( ( ) = > void ) [ ] = [ ] ;
let profile_identity_changed : ( ( ) = > void ) [ ] = [ ] ;
2019-03-07 15:30:53 +01:00
2019-08-21 10:00:01 +02:00
let update_profiles : ( selected_id : string ) = > void ;
2019-03-07 15:30:53 +01:00
2019-08-21 10:00:01 +02:00
/* profile list */
{
const container_profiles = container . find ( ".container-profiles" ) ;
const build_profile = ( profile : profiles.ConnectionProfile , selected : boolean ) = > {
let tag_name : JQuery , tag_default : JQuery , tag_valid : JQuery , tag_type : JQuery , tag_avatar : JQuery ;
let tag = $ . spawn ( "div" ) . addClass ( "profile" ) . append (
tag_avatar = $ . spawn ( "div" ) . addClass ( "container-avatar" ) ,
$ . spawn ( "div" ) . addClass ( "container-info" ) . append (
$ . spawn ( "div" ) . addClass ( "container-type" ) . append (
tag_type = $ . spawn ( "div" ) . text ( profile . selected_identity_type || tr ( "Type unset" ) ) ,
tag_default = $ . spawn ( "div" ) . addClass ( "tag-default" ) . text ( tr ( "(Default)" ) ) ,
tag_valid = $ . spawn ( "div" ) . addClass ( "icon_em icon-status" )
. toggleClass ( "client-apply" , profile . valid ( ) )
. toggleClass ( "client-delete" , ! profile . valid ( ) )
) ,
tag_name = $ . spawn ( "div" ) . addClass ( "profile-name" ) . text ( profile . profile_name || tr ( "Unnamed" ) )
)
) ;
tag_avatar . hide ( ) ; /* no avatars yet */
tag_default . toggle ( profile . id === "default" ) ;
tag . on ( 'click' , event = > {
if ( tag . hasClass ( 'selected' ) )
return ;
container_profiles . find ( ".selected" ) . removeClass ( "selected" ) ;
tag . addClass ( "selected" ) ;
/* reset profile name if may in change */
if ( selected_profile )
selected_profile . update_name ( ) ;
selected_profile = {
identity : profile ,
update_name ( text ) {
tag_name . text ( typeof ( text ) === "string" ? text : ( profile . profile_name || tr ( "Unnamed" ) ) )
} ,
update_type() {
tag_type . text ( profile . selected_identity_type || tr ( "Type unset" ) ) ;
} ,
update_valid_flag() {
tag_valid
. toggleClass ( "client-apply" , profile . valid ( ) )
. toggleClass ( "client-delete" , ! profile . valid ( ) )
} ,
update_avatar() {
//TODO HERE!
2018-12-28 15:39:23 +01:00
}
2019-08-21 10:00:01 +02:00
} ;
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
for ( const listener of selected_profile_changed )
listener ( ) ;
} ) ;
2019-03-28 17:29:42 +01:00
2019-08-21 10:00:01 +02:00
if ( selected )
tag . trigger ( 'click' ) ;
2019-03-07 15:30:53 +01:00
2019-08-21 10:00:01 +02:00
return tag ;
2019-03-07 15:30:53 +01:00
} ;
2019-08-21 10:00:01 +02:00
update_profiles = ( selected_id ) = > {
selected_id = selected_id || "default" ;
container_profiles . children ( ) . remove ( ) ;
profiles . profiles ( ) . forEach ( e = > build_profile ( e , e . id == selected_id ) . appendTo ( container_profiles ) ) ;
2019-03-07 15:30:53 +01:00
2019-08-21 10:00:01 +02:00
} ;
2019-03-07 15:30:53 +01:00
}
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
/* profile general info */
{
const input_name = container . find ( ".right input.profile-name" ) ;
const input_default_name = container . find ( ".right input.profile-default-name" ) ;
const select_type = container . find ( ".right select.profile-identity-type" ) ;
selected_profile_changed . push ( ( ) = > {
//profile-identity-type
if ( ! selected_profile . identity ) {
input_name . val ( tr ( "No profile selected" ) ) . prop ( "disabled" , true ) ;
input_default_name . val ( "" ) . prop ( "disabled" , true ) ;
select_type . val ( "unset" ) . prop ( "disabled" , true ) ;
select_type . parent ( ) . toggleClass ( "is-invalid" , true ) ;
} else {
input_name . val ( selected_profile . identity . profile_name ) . prop ( "disabled" , false ) ;
2019-10-19 17:13:40 +02:00
input_default_name
. val ( selected_profile . identity . default_username )
. attr ( "placeholder" , selected_profile . identity . connect_username ( ) || "Another TeaSpeak user" )
. prop ( "disabled" , false ) ;
2019-08-21 10:00:01 +02:00
select_type . val ( selected_profile . identity . selected_identity_type || "unset" ) . prop ( "disabled" , false ) ;
}
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
for ( const listener of profile_identity_changed )
listener ( ) ;
} ) ;
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
input_name . on ( 'keyup' , event = > {
const text = input_name . val ( ) as string ;
const profile = profiles . find_profile_by_name ( text ) ;
input_name . parent ( ) . toggleClass ( "is-invalid" , text . length < 3 || ( profile && profile != selected_profile . identity ) ) ;
selected_profile . update_name ( text ) ;
} ) . on ( 'change' , event = > {
const text = input_name . val ( ) as string ;
const profile = profiles . find_profile_by_name ( text ) ;
if ( text . length < 3 || ( profile && profile != selected_profile . identity ) ) return ;
selected_profile . identity . profile_name = text ;
profiles . mark_need_save ( ) ;
} ) ;
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
input_default_name . on ( 'change' , event = > {
selected_profile . identity . default_username = input_default_name . val ( ) as string ;
profiles . mark_need_save ( ) ;
} ) ;
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
select_type . on ( 'change' , event = > {
selected_profile . identity . selected_identity_type = ( select_type . val ( ) as string ) . toLowerCase ( ) ;
profiles . mark_need_save ( ) ;
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
selected_profile . update_type ( ) ;
for ( const listener of profile_identity_changed )
listener ( ) ;
selected_profile . update_valid_flag ( ) ;
} ) ;
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
profile_identity_changed . push ( ( ) = > {
select_type . parent ( )
. toggleClass ( "is-invalid" , typeof ( profiles . identities . IdentitifyType [ selected_profile . identity . selected_identity_type . toUpperCase ( ) ] ) === "undefined" ) ;
} ) ;
}
2019-01-19 13:42:18 +01:00
2019-08-21 10:00:01 +02:00
/* profile special info */
{
/* teamspeak */
{
const container_settings = container . find ( ".container-teamspeak" ) ;
const container_valid = container_settings . find ( ".container-valid" ) ;
const container_invalid = container_settings . find ( ".container-invalid" ) ;
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
const input_current_level = container_settings . find ( ".current-level" ) ;
const input_unique_id = container_settings . find ( ".unique-id" ) ;
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
const button_new = container_settings . find ( ".button-new" ) ;
const button_improve = container_settings . find ( ".button-improve" ) ;
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
const button_import = container_settings . find ( ".button-import" ) ;
const button_export = container_settings . find ( ".button-export" ) ;
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
button_improve . on ( 'click' , event = > {
const profile = selected_profile . identity . selected_identity ( profiles . identities . IdentitifyType . TEAMSPEAK ) as profiles . identities . TeaSpeakIdentity ;
if ( ! profile ) return ;
2018-12-28 15:39:23 +01:00
2019-08-30 23:06:39 +02:00
Modals . spawnTeamSpeakIdentityImprove ( profile , selected_profile . identity . profile_name ) . close_listener . push ( ( ) = > {
2019-08-21 10:00:01 +02:00
profiles . mark_need_save ( ) ;
for ( const listener of profile_identity_changed )
listener ( ) ;
} ) ;
2018-12-28 15:39:23 +01:00
} ) ;
2019-08-21 10:00:01 +02:00
button_new . on ( 'click' , event = > {
const profile = selected_profile . identity . selected_identity ( profiles . identities . IdentitifyType . TEAMSPEAK ) as profiles . identities . TeaSpeakIdentity ;
const generate_identity = ( ) = > {
profiles . identities . TeaSpeakIdentity . generate_new ( ) . then ( identity = > {
selected_profile . identity . set_identity ( profiles . identities . IdentitifyType . TEAMSPEAK , identity ) ;
createInfoModal ( tr ( "Identity generated" ) , tr ( "A new identity had been successfully generated" ) ) . open ( ) ;
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
profiles . mark_need_save ( ) ;
for ( const listener of profile_identity_changed )
listener ( ) ;
} ) . catch ( error = > {
console . error ( tr ( "Failed to generate a new identity. Error object: %o" ) , error ) ;
createErrorModal ( tr ( "Failed to generate identity" ) , tr ( "Failed to generate a new identity.<br>Error:" ) + error ) . open ( ) ;
} ) ;
} ;
2019-01-19 13:42:18 +01:00
2019-08-21 10:00:01 +02:00
if ( profile && profile . valid ( ) ) {
spawnYesNo ( tr ( "Are you sure" ) , tr ( "Do you really want to generate a new identity and override the old identity?" ) , result = > {
if ( result )
generate_identity ( ) ;
} ) ;
} else
generate_identity ( ) ;
} ) ;
2019-01-28 20:36:11 +01:00
button_import . on ( 'click' , event = > {
2019-08-21 10:00:01 +02:00
const profile = selected_profile . identity . selected_identity ( profiles . identities . IdentitifyType . TEAMSPEAK ) as profiles . identities . TeaSpeakIdentity ;
2019-01-28 20:36:11 +01:00
const set_identity = ( identity : profiles.identities.TeaSpeakIdentity ) = > {
2019-08-21 10:00:01 +02:00
selected_profile . identity . set_identity ( profiles . identities . IdentitifyType . TEAMSPEAK , identity ) ;
2019-01-28 20:36:11 +01:00
createInfoModal ( tr ( "Identity imported" ) , tr ( "Your identity has been successfully imported!" ) ) . open ( ) ;
2019-08-21 10:00:01 +02:00
profiles . mark_need_save ( ) ;
for ( const listener of profile_identity_changed )
listener ( ) ;
2018-12-28 15:39:23 +01:00
} ;
2019-03-07 15:30:53 +01:00
if ( profile && profile . valid ( ) ) {
2019-01-28 20:36:11 +01:00
spawnYesNo ( tr ( "Are you sure" ) , tr ( "Do you really want to import a new identity and override the old identity?" ) , result = > {
2019-03-07 15:30:53 +01:00
if ( result )
2019-01-28 20:36:11 +01:00
spawnTeamSpeakIdentityImport ( set_identity ) ;
} ) ;
2019-08-21 10:00:01 +02:00
} else {
2019-01-28 20:36:11 +01:00
spawnTeamSpeakIdentityImport ( set_identity ) ;
2019-08-21 10:00:01 +02:00
}
2019-01-28 20:36:11 +01:00
} ) ;
2019-08-21 10:00:01 +02:00
2019-01-28 20:36:11 +01:00
button_export . on ( 'click' , event = > {
2019-08-21 10:00:01 +02:00
const profile = selected_profile . identity . selected_identity ( profiles . identities . IdentitifyType . TEAMSPEAK ) as profiles . identities . TeaSpeakIdentity ;
if ( ! profile ) return ;
2019-01-28 20:36:11 +01:00
createInputModal ( tr ( "File name" ) , tr ( "Please enter the file name" ) , text = > ! ! text , name = > {
2019-03-07 15:30:53 +01:00
if ( name ) {
2019-01-28 20:36:11 +01:00
profile . export_ts ( true ) . then ( data = > {
const element = $ . spawn ( "a" )
. text ( "donwload" )
. attr ( "href" , "data:test/plain;charset=utf-8," + encodeURIComponent ( data ) )
. attr ( "download" , name + ".ini" )
. css ( "display" , "none" )
. appendTo ( $ ( "body" ) ) ;
element [ 0 ] . click ( ) ;
2019-08-21 10:00:01 +02:00
element . remove ( ) ;
2019-01-28 20:36:11 +01:00
} ) . catch ( error = > {
console . error ( error ) ;
createErrorModal ( tr ( "Failed to export identity" ) , tr ( "Failed to export and save identity.<br>Error: " ) + error ) . open ( ) ;
} ) ;
}
} ) . open ( ) ;
} ) ;
2019-08-21 10:00:01 +02:00
profile_identity_changed . push ( ( ) = > {
const enabled = selected_profile && selected_profile . identity . selected_identity_type === "teamspeak" ;
container_settings . toggle ( enabled ) ;
if ( ! enabled ) return ;
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
const profile = selected_profile . identity . selected_identity ( profiles . identities . IdentitifyType . TEAMSPEAK ) as profiles . identities . TeaSpeakIdentity ;
button_improve . prop ( "disabled" , ! profile ) ;
button_export . toggle ( ! ! profile ) ;
2019-01-19 13:42:18 +01:00
2019-08-21 10:00:01 +02:00
button_import . toggleClass ( "btn-danger" , ! ! profile ) . toggleClass ( "btn-success" , ! profile ) ;
button_new . toggleClass ( "btn-danger" , ! ! profile ) . toggleClass ( "btn-success" , ! profile ) ;
2019-01-28 20:36:11 +01:00
2019-08-21 10:00:01 +02:00
container_invalid . toggle ( ! profile ) ;
container_valid . toggle ( ! ! profile ) ;
if ( ! profile ) {
input_current_level . val ( "no profile" ) ;
input_unique_id . val ( "no profile" ) ;
2019-01-28 20:36:11 +01:00
} else {
2019-08-21 10:00:01 +02:00
input_current_level . val ( "loading...." ) ;
profile . level ( ) . then ( level = > input_current_level . val ( level + "" ) ) ;
input_unique_id . val ( profile . uid ( ) ) ;
2019-01-28 20:36:11 +01:00
}
2019-08-21 10:00:01 +02:00
selected_profile . update_valid_flag ( ) ;
2019-01-19 13:42:18 +01:00
} ) ;
2018-12-28 15:39:23 +01:00
}
2019-08-21 10:00:01 +02:00
/* teaspeak forum */
{
const container_settings = container . find ( ".container-teaforo" ) ;
const continer_valid = container_settings . find ( ".container-valid" ) ;
const continer_invalid = container_settings . find ( ".container-invalid" ) ;
const button_setup = container_settings . find ( ".button-setup" ) ;
2019-01-19 13:42:18 +01:00
2019-08-21 10:00:01 +02:00
profile_identity_changed . push ( ( ) = > {
container_settings . toggle ( selected_profile && selected_profile . identity . selected_identity_type === "teaforo" ) ;
const profile = selected_profile . identity . selected_identity ( profiles . identities . IdentitifyType . TEAFORO ) as profiles . identities . TeaForumIdentity ;
const valid = profile && profile . valid ( ) ;
continer_valid . toggle ( valid ) ;
continer_invalid . toggle ( ! valid ) ;
} ) ;
button_setup . on ( 'click' , event = > {
2019-08-21 12:45:17 +02:00
modal . htmlTag . find ( '.entry[container="identity-forum"]' ) . trigger ( 'click' ) ;
2019-01-19 13:42:18 +01:00
} ) ;
}
2019-08-21 10:00:01 +02:00
/* nickname */
{
const container_settings = container . find ( ".container-nickname" ) ;
const input_nickname = container_settings . find ( ".nickname" ) ;
profile_identity_changed . push ( ( ) = > {
const active = selected_profile && selected_profile . identity . selected_identity_type === "nickname" ;
container_settings . toggle ( active ) ;
if ( ! active ) return ;
let profile = selected_profile . identity . selected_identity ( profiles . identities . IdentitifyType . NICKNAME ) as profiles . identities . NameIdentity ;
if ( ! profile )
selected_profile . identity . set_identity ( profiles . identities . IdentitifyType . NICKNAME , profile = new profiles . identities . NameIdentity ( ) ) ;
input_nickname . val ( profile . name ( ) ) . trigger ( 'change' ) ;
} ) ;
2019-01-19 13:42:18 +01:00
2019-08-21 10:00:01 +02:00
input_nickname . on ( 'keydown' , event = > {
const profile = selected_profile . identity . selected_identity ( profiles . identities . IdentitifyType . NICKNAME ) as profiles . identities . NameIdentity ;
if ( ! profile )
2019-01-19 13:42:18 +01:00
return ;
2019-08-21 10:00:01 +02:00
profile . set_name ( input_nickname . val ( ) as string ) ;
profiles . mark_need_save ( ) ;
selected_profile . update_valid_flag ( ) ;
input_nickname . parent ( ) . toggleClass ( 'is-invalid' , ! profile . valid ( ) ) ;
2019-01-19 13:42:18 +01:00
} ) ;
2018-12-28 15:39:23 +01:00
}
}
2019-08-21 10:00:01 +02:00
/* change avatar button */
2018-12-28 15:39:23 +01:00
{
2019-08-21 10:00:01 +02:00
container . find ( ".button-change-avatar" ) . hide ( ) ;
2018-12-28 15:39:23 +01:00
}
2019-08-21 10:00:01 +02:00
/* create new button */
2018-12-28 15:39:23 +01:00
{
2019-08-21 10:00:01 +02:00
container . find ( ".button-create" ) . on ( 'click' , event = > {
createInputModal ( tr ( "Please enter a name" ) , tr ( "Please enter a name for the new profile:" ) , text = > text . length >= 3 && ! profiles . find_profile_by_name ( text ) , value = > {
2019-03-07 15:30:53 +01:00
if ( value ) {
2019-08-21 10:00:01 +02:00
const profile = profiles . create_new_profile ( value as string ) ;
update_profiles ( profile . id ) ;
2018-12-28 15:39:23 +01:00
profiles . mark_need_save ( ) ;
}
} ) . open ( ) ;
} ) ;
2019-08-21 10:00:01 +02:00
}
2018-12-28 15:39:23 +01:00
2019-08-21 10:00:01 +02:00
/* set as default button */
{
const button = container . find ( ".button-set-default" ) ;
button . on ( 'click' , event = > {
profiles . set_default_profile ( selected_profile . identity ) ;
profiles . mark_need_save ( ) ;
update_profiles ( selected_profile . identity . id ) ;
2018-12-28 15:39:23 +01:00
} ) ;
2019-08-21 10:00:01 +02:00
selected_profile_changed . push ( ( ) = > {
button . prop ( "disabled" , ! selected_profile || selected_profile . identity . id === "default" ) ;
} ) ;
}
/* delete button */
{
const button = container . find ( ".button-delete" ) ;
button . on ( 'click' , event = > {
if ( selected_profile && selected_profile . identity . id != 'default' ) {
2019-03-07 15:30:53 +01:00
spawnYesNo ( tr ( "Are you sure?" ) , tr ( "Do you really want to delete this profile?" ) , result = > {
if ( result ) {
2019-08-21 10:00:01 +02:00
profiles . delete_profile ( selected_profile . identity ) ;
profiles . mark_need_save ( ) ;
update_profiles ( undefined ) ;
2018-12-28 15:39:23 +01:00
}
} ) ;
}
} ) ;
2019-08-21 10:00:01 +02:00
selected_profile_changed . push ( ( ) = > {
button . prop ( "disabled" , ! selected_profile || selected_profile . identity . id === "default" ) ;
} ) ;
2018-12-28 15:39:23 +01:00
}
2019-08-21 10:00:01 +02:00
update_profiles ( undefined ) ;
2018-12-28 15:39:23 +01:00
modal . close_listener . push ( ( ) = > {
2019-08-21 10:00:01 +02:00
if ( profiles . requires_save ( ) )
2018-12-28 15:39:23 +01:00
profiles . save ( ) ;
} ) ;
2019-08-21 10:00:01 +02:00
return update_profiles ;
}
function settings_identity_forum ( container : JQuery , modal : Modal , update_profiles : ( ) = > any ) {
const containers_connected = container . find ( ".show-connected" ) ;
const containers_disconnected = container . find ( ".show-disconnected" ) ;
const update_state = ( ) = > {
const logged_in = forum . logged_in ( ) ;
containers_connected . toggle ( logged_in ) ;
containers_disconnected . toggle ( ! logged_in ) ;
if ( logged_in ) {
container . find ( ".forum-username" ) . text ( forum . data ( ) . name ( ) ) ;
container . find ( ".forum-premium" ) . text ( forum . data ( ) . is_premium ( ) ? tr ( "Yes" ) : tr ( "No" ) ) ;
}
} ;
/* login */
{
const button_login = container . find ( ".button-login" ) ;
const input_username = container . find ( ".input-username" ) ;
const input_password = container . find ( ".input-password" ) ;
const container_error = container . find ( ".container-login .container-error" ) ;
const container_captcha_g = container . find ( ".g-recaptcha" ) ;
let captcha : boolean | string = false ;
const update_button_state = ( ) = > {
let enabled = true ;
enabled = enabled && ! ! input_password . val ( ) ;
enabled = enabled && ! ! input_username . val ( ) ;
enabled = enabled && ( typeof ( captcha ) === "boolean" ? ! captcha : ! ! captcha ) ;
button_login . prop ( "disabled" , ! enabled ) ;
} ;
/* username */
input_username . on ( 'change keyup' , update_button_state ) ;
/* password */
input_password . on ( 'change keyup' , update_button_state ) ;
button_login . on ( 'click' , event = > {
input_username . prop ( "disabled" , true ) ;
input_password . prop ( "disabled" , true ) ;
button_login . prop ( "disabled" , true ) ;
container_error . removeClass ( "shown" ) ;
forum . login ( input_username . val ( ) as string , input_password . val ( ) as string , typeof ( captcha ) === "string" ? captcha : undefined ) . then ( state = > {
captcha = false ;
console . debug ( tr ( "Forum login result: %o" ) , state ) ;
if ( state . status === "success" ) {
update_state ( ) ;
update_profiles ( ) ;
return ;
}
setTimeout ( ( ) = > {
if ( ! ! state . error_message ) /* clear password if we have an error */
input_password . val ( "" ) ;
input_password . focus ( ) ;
update_button_state ( ) ;
} , 0 ) ;
if ( state . status === "captcha" ) {
//TODO Works currently only with localhost!
button_login . hide ( ) ;
container_error . text ( state . error_message || tr ( "Captcha required" ) ) . addClass ( "shown" ) ;
captcha = "" ;
console . log ( tr ( "Showing captcha for site-key: %o" ) , state . captcha . data ) ;
forum . gcaptcha . spawn ( container_captcha_g , state . captcha . data , token = > {
captcha = token ;
console . debug ( tr ( "Got captcha token: %o" ) , token ) ;
container_captcha_g . hide ( ) ;
button_login . show ( ) ;
update_button_state ( ) ;
} ) . catch ( error = > {
console . error ( tr ( "Failed to initialize forum captcha: %o" ) , error ) ;
container_error . text ( "Failed to initialize GReCaptcha! No authentication possible." ) . addClass ( "shown" ) ;
container_captcha_g . hide ( ) ;
button_login . hide ( ) ;
} ) ;
container_captcha_g . show ( ) ;
} else {
container_error . text ( state . error_message || tr ( "Unknown error" ) ) . addClass ( "shown" ) ;
}
} ) . catch ( error = > {
console . error ( tr ( "Failed to login within the forum. Error: %o" ) , error ) ;
createErrorModal ( tr ( "Forum login failed." ) , tr ( "Forum login failed. Lookup the console for more information" ) ) . open ( ) ;
} ) . then ( ( ) = > {
input_username . prop ( "disabled" , false ) ;
input_password . prop ( "disabled" , false ) ;
update_button_state ( ) ;
} ) ;
} ) ;
update_button_state ( ) ;
}
/* logout */
{
container . find ( ".button-logout" ) . on ( 'click' , event = > {
forum . logout ( ) . catch ( error = > {
console . error ( tr ( "Failed to logout from forum: %o" ) , error ) ;
createErrorModal ( tr ( "Forum logout failed" ) , MessageHelper . formatMessage ( tr ( "Failed to logout from forum account.{:br:}Error: {}" ) , error ) ) . open ( ) ;
} ) . then ( ( ) = > {
if ( modal . shown )
update_state ( ) ;
update_profiles ( ) ;
} ) ;
} ) ;
}
update_state ( ) ;
2018-12-28 15:39:23 +01:00
}
2018-03-07 19:06:52 +01:00
}