TeaWeb/shared/js/ui/modal/ModalSettings.ts

1386 lines
63 KiB
TypeScript
Raw Normal View History

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 {
let modal: Modal;
modal = createModal({
2019-08-21 10:00:01 +02:00
header: tr("Settings"),
body: () => {
2019-08-21 10:00:01 +02:00
const tag = $("#tmpl_settings").renderTag().dividerfy();
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-08-21 10:00:01 +02:00
const target = entry.attr("container");
if(!target) return;
2019-08-21 10:00:01 +02:00
right.find("> .container." + target).removeClass("hidden");
entry.addClass("selected");
})
}
2019-08-21 10:00:01 +02:00
/* initialize all tabs */
2019-08-21 10:00:01 +02:00
/* enable one tab */
{
left.find(".entry[container" + (default_page ? ("='" + default_page + "'") : "") + "]").first().trigger('click');
}
2019-08-21 10:00:01 +02:00
return tag;
},
2019-08-21 10:00:01 +02:00
footer: null
});
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);
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-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-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-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-08-21 10:00:01 +02:00
$(document.body).css("font-size", value + "px");
});
}
/* 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-08-21 10:00:01 +02:00
function settings_general_language(container: JQuery, modal: Modal) {
2019-08-21 10:00:01 +02:00
const container_entries = container.find(".container-list .entries");
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-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-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-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-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-08-21 10:00:01 +02:00
});
info_modal.open()
};
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-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-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"
});
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");
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);
}
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();
} 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-08-21 10:00:01 +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-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);
} else {
2019-08-21 10:00:01 +02:00
option_colloquial.prop("checked", settings.static_global(Settings.KEY_CHAT_COLLOQUIAL_TIMESTAMPS));
}
2019-08-21 10:00:01 +02:00
}).prop("checked", settings.static_global(Settings.KEY_CHAT_FIXED_TIMESTAMPS)).trigger('change');
}
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 update_format_helper = () => server_connections.server_connection_handlers().map(e => e.side_bar).forEach(e => {
e.private_conversations().update_input_format_helper();
e.channel_conversations().update_input_format_helper();
});
2019-08-21 10:00:01 +02:00
{
const option = container.find(".option-support-markdown") as JQuery<HTMLInputElement>;
option.on('change', event => {
settings.changeGlobal(Settings.KEY_CHAT_ENABLE_MARKDOWN, option[0].checked);
update_format_helper();
2019-08-21 10:00:01 +02:00
}).prop("checked", settings.static_global(Settings.KEY_CHAT_ENABLE_MARKDOWN));
}
{
const option = container.find(".option-support-bbcode") as JQuery<HTMLInputElement>;
option.on('change', event => {
settings.changeGlobal(Settings.KEY_CHAT_ENABLE_BBCODE, option[0].checked);
update_format_helper();
}).prop("checked", settings.static_global(Settings.KEY_CHAT_ENABLE_BBCODE));
}
2019-08-21 10:00:01 +02:00
{
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-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-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-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");
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();
});
});
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
}
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-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-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-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
});
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');
}
2019-08-21 10:00:01 +02:00
/* Sensitivity */
{
const container_sensitivity = container.find(".container-sensitivity");
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");
2019-08-21 10:00:01 +02:00
if(_last_filter) {
_last_filter.callback_level = undefined;
_last_filter = undefined;
}
2019-08-21 10:00:01 +02:00
if(default_recorder.get_vad_type() !== "threshold") {
container_sensitivity.addClass("disabled");
return;
}
container_sensitivity.removeClass("disabled");
Implemented the Material Design and fixed some bugs (#33) * cleaned up some files * Fundamental style update * Redesigned some style * fixed hostbanner popup * Removed old identity stuff * fixed close listener * Fixed changelog date * fixed release chat icons * fixed url * Fixed hostbanner * Uploaded missing images * Improved update handling * Improved script files * Fixed loading error and icon error * fixed Yes/No modal * Fixed loader issues with MS Edge * fixed modal style bug * Fixed control bar overflow for small devices * Improved error handling on identity creation * Logging generate error to terminal * fixed possible php error * fixed some possible loading errors when other files have'nt been already loaded. * removed debug message * Changed emsrcypten flags * Improved codec error handling * removed webassembly as required dependency * Improved and fixed channel tree issues * Improved the sliders * Removed unneeded files * fixed loader versions cache * second slight performance improved (dont animate elements anymore if they are not shown) * Fixed query visibility setting * not showing useless client infos for query clients * Added an auto reconnect system * Added a canceled message and increased reconnect interval * removed implemented todo * fixed repetitive channel names * Reworked the channel tree selected lines * Fixed channel tree names * Fixed name alignment * fixed the native client * added min width to the server select groups to avoid a disappearing effect on shrink * fixed bugged downloaded icons
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;
Implemented the Material Design and fixed some bugs (#33) * cleaned up some files * Fundamental style update * Redesigned some style * fixed hostbanner popup * Removed old identity stuff * fixed close listener * Fixed changelog date * fixed release chat icons * fixed url * Fixed hostbanner * Uploaded missing images * Improved update handling * Improved script files * Fixed loading error and icon error * fixed Yes/No modal * Fixed loader issues with MS Edge * fixed modal style bug * Fixed control bar overflow for small devices * Improved error handling on identity creation * Logging generate error to terminal * fixed possible php error * fixed some possible loading errors when other files have'nt been already loaded. * removed debug message * Changed emsrcypten flags * Improved codec error handling * removed webassembly as required dependency * Improved and fixed channel tree issues * Improved the sliders * Removed unneeded files * fixed loader versions cache * second slight performance improved (dont animate elements anymore if they are not shown) * Fixed query visibility setting * not showing useless client infos for query clients * Added an auto reconnect system * Added a canceled message and increased reconnect interval * removed implemented todo * fixed repetitive channel names * Reworked the channel tree selected lines * Fixed channel tree names * Fixed name alignment * fixed the native client * added min width to the server select groups to avoid a disappearing effect on shrink * fixed bugged downloaded icons
2019-02-17 16:08:10 +01:00
2019-08-21 10:00:01 +02:00
_last_filter = filter;
filter.callback_level = _set_level;
});
}
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
});
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()));
}
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
});
}
2019-08-21 10:00:01 +02:00
//delay-time
}
}
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");
Implemented the Material Design and fixed some bugs (#33) * cleaned up some files * Fundamental style update * Redesigned some style * fixed hostbanner popup * Removed old identity stuff * fixed close listener * Fixed changelog date * fixed release chat icons * fixed url * Fixed hostbanner * Uploaded missing images * Improved update handling * Improved script files * Fixed loading error and icon error * fixed Yes/No modal * Fixed loader issues with MS Edge * fixed modal style bug * Fixed control bar overflow for small devices * Improved error handling on identity creation * Logging generate error to terminal * fixed possible php error * fixed some possible loading errors when other files have'nt been already loaded. * removed debug message * Changed emsrcypten flags * Improved codec error handling * removed webassembly as required dependency * Improved and fixed channel tree issues * Improved the sliders * Removed unneeded files * fixed loader versions cache * second slight performance improved (dont animate elements anymore if they are not shown) * Fixed query visibility setting * not showing useless client infos for query clients * Added an auto reconnect system * Added a canceled message and increased reconnect interval * removed implemented todo * fixed repetitive channel names * Reworked the channel tree selected lines * Fixed channel tree names * Fixed name alignment * fixed the native client * added min width to the server select groups to avoid a disappearing effect on shrink * fixed bugged downloaded icons
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;
Implemented the Material Design and fixed some bugs (#33) * cleaned up some files * Fundamental style update * Redesigned some style * fixed hostbanner popup * Removed old identity stuff * fixed close listener * Fixed changelog date * fixed release chat icons * fixed url * Fixed hostbanner * Uploaded missing images * Improved update handling * Improved script files * Fixed loading error and icon error * fixed Yes/No modal * Fixed loader issues with MS Edge * fixed modal style bug * Fixed control bar overflow for small devices * Improved error handling on identity creation * Logging generate error to terminal * fixed possible php error * fixed some possible loading errors when other files have'nt been already loaded. * removed debug message * Changed emsrcypten flags * Improved codec error handling * removed webassembly as required dependency * Improved and fixed channel tree issues * Improved the sliders * Removed unneeded files * fixed loader versions cache * second slight performance improved (dont animate elements anymore if they are not shown) * Fixed query visibility setting * not showing useless client infos for query clients * Added an auto reconnect system * Added a canceled message and increased reconnect interval * removed implemented todo * fixed repetitive channel names * Reworked the channel tree selected lines * Fixed channel tree names * Fixed name alignment * fixed the native client * added min width to the server select groups to avoid a disappearing effect on shrink * fixed bugged downloaded icons
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");
Implemented the Material Design and fixed some bugs (#33) * cleaned up some files * Fundamental style update * Redesigned some style * fixed hostbanner popup * Removed old identity stuff * fixed close listener * Fixed changelog date * fixed release chat icons * fixed url * Fixed hostbanner * Uploaded missing images * Improved update handling * Improved script files * Fixed loading error and icon error * fixed Yes/No modal * Fixed loader issues with MS Edge * fixed modal style bug * Fixed control bar overflow for small devices * Improved error handling on identity creation * Logging generate error to terminal * fixed possible php error * fixed some possible loading errors when other files have'nt been already loaded. * removed debug message * Changed emsrcypten flags * Improved codec error handling * removed webassembly as required dependency * Improved and fixed channel tree issues * Improved the sliders * Removed unneeded files * fixed loader versions cache * second slight performance improved (dont animate elements anymore if they are not shown) * Fixed query visibility setting * not showing useless client infos for query clients * Added an auto reconnect system * Added a canceled message and increased reconnect interval * removed implemented todo * fixed repetitive channel names * Reworked the channel tree selected lines * Fixed channel tree names * Fixed name alignment * fixed the native client * added min width to the server select groups to avoid a disappearing effect on shrink * fixed bugged downloaded icons
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");
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();
});
});
Implemented the Material Design and fixed some bugs (#33) * cleaned up some files * Fundamental style update * Redesigned some style * fixed hostbanner popup * Removed old identity stuff * fixed close listener * Fixed changelog date * fixed release chat icons * fixed url * Fixed hostbanner * Uploaded missing images * Improved update handling * Improved script files * Fixed loading error and icon error * fixed Yes/No modal * Fixed loader issues with MS Edge * fixed modal style bug * Fixed control bar overflow for small devices * Improved error handling on identity creation * Logging generate error to terminal * fixed possible php error * fixed some possible loading errors when other files have'nt been already loaded. * removed debug message * Changed emsrcypten flags * Improved codec error handling * removed webassembly as required dependency * Improved and fixed channel tree issues * Improved the sliders * Removed unneeded files * fixed loader versions cache * second slight performance improved (dont animate elements anymore if they are not shown) * Fixed query visibility setting * not showing useless client infos for query clients * Added an auto reconnect system * Added a canceled message and increased reconnect interval * removed implemented todo * fixed repetitive channel names * Reworked the channel tree selected lines * Fixed channel tree names * Fixed name alignment * fixed the native client * added min width to the server select groups to avoid a disappearing effect on shrink * fixed bugged downloaded icons
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());
2019-08-21 10:00:01 +02:00
modal.close_listener.push(sound.save);
}
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!
}
2019-08-21 10:00:01 +02: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
}
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);
}
2019-08-21 10:00:01 +02:00
for(const listener of profile_identity_changed)
listener();
});
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();
});
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();
});
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();
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();
});
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-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");
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");
2019-08-21 10:00:01 +02:00
const button_new = container_settings.find(".button-new");
const button_improve = container_settings.find(".button-improve");
2019-08-21 10:00:01 +02:00
const button_import = container_settings.find(".button-import");
const button_export = container_settings.find(".button-export");
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;
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();
});
});
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();
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-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();
});
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;
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);
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();
};
2019-03-07 15:30:53 +01:00
if (profile && profile.valid()) {
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)
spawnTeamSpeakIdentityImport(set_identity);
});
2019-08-21 10:00:01 +02:00
} else {
spawnTeamSpeakIdentityImport(set_identity);
2019-08-21 10:00:01 +02:00
}
});
2019-08-21 10:00:01 +02: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;
createInputModal(tr("File name"), tr("Please enter the file name"), text => !!text, name => {
2019-03-07 15:30:53 +01:00
if (name) {
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();
}).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;
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-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-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");
} 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-08-21 10:00:01 +02:00
selected_profile.update_valid_flag();
});
}
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-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-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-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)
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-08-21 10:00:01 +02:00
/* change avatar button */
{
2019-08-21 10:00:01 +02:00
container.find(".button-change-avatar").hide();
}
2019-08-21 10:00:01 +02:00
/* create new button */
{
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);
profiles.mark_need_save();
}
}).open();
});
2019-08-21 10:00:01 +02: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);
/* set the connect profile to the just set once */
settings.changeGlobal(Settings.KEY_CONNECT_PROFILE, "default");
});
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);
}
});
}
});
2019-08-21 10:00:01 +02:00
selected_profile_changed.push(() => {
button.prop("disabled", !selected_profile || selected_profile.identity.id === "default");
});
}
2019-08-21 10:00:01 +02:00
update_profiles(undefined);
modal.close_listener.push(() => {
2019-08-21 10:00:01 +02:00
if(profiles.requires_save())
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-03-07 19:06:52 +01:00
}