diff --git a/admin/themes/default/js/user_list.js b/admin/themes/default/js/user_list.js index 0983181b02..fd71097c11 100644 --- a/admin/themes/default/js/user_list.js +++ b/admin/themes/default/js/user_list.js @@ -16,6 +16,10 @@ let selection = []; let first_update = true; let total_users = 0 let filter_by = 'id DESC'; +let plugins_set_functions = {}; +let plugins_get_functions = {}; +let plugins_load = []; +let plugins_users_infos_table = []; /*---------------- Escape of pop-in ----------------*/ @@ -92,25 +96,23 @@ $( document ).ready(function() { fadeOut: 200 }); $(".advanced-filter-level select option").eq(1).remove(); - $('.edit-password').click(function () { - $('.user-property-password').hide(); - $('.user-property-password-change').show().css('display', 'flex'); + $('.button-edit-password-icon').click(function () { + $('.user-property-password-change-inputs, .edit-password-success').hide() + $('.user-property-password-choice').show(); + $('.user-property-password-change').fadeIn(); }) $('.edit-password-cancel').click(function () { - //possibly reset input value - $('.user-property-password').show(); - $('.user-property-password-change').hide(); + $('.user-property-password-change').fadeOut(); + reset_input_password(); }) $('.edit-username').click(function () { - $('.user-property-username').hide(); - $('.user-property-username-change').show().css('display', 'flex'); + $('.user-property-username-change').show(); }) $('.edit-username-cancel').click(function () { //possibly reset input value - $('.user-property-username').show(); $('.user-property-username-change').hide(); }) @@ -156,7 +158,16 @@ $( document ).ready(function() { $(this).siblings().attr("data-selected", "0"); } }) - $(".AddUserGenPassword").click(gen_password); + $(".AddUserGenPassword").on('click', function() { + const password = gen_password(); + $("#AddUserPassword").val(password); + }); + $('.EditUserGenPassword').on('click', function() { + const password = gen_password(); + $('#edit_user_password').val(password); + $('#edit_user_conf_password').val(password); + hide_error_edit_user(); + }); $('.AddUserSubmit').click(add_user); $('.AddUserCancel').click(add_user_close); $(".CloseAddUser").click(add_user_close); @@ -349,6 +360,68 @@ $( document ).ready(function() { } update_user_list(); }); + + /* tabsheet pop in user */ + editTabsBind(); + + $('.edit-user-slides').on('scroll', function() { + const slides = $('.edit-user-slides').children(); + const rectView = this.getBoundingClientRect(); + $('.edit-user-tabsheet').removeClass('selected'); + // for debug + // console.log('RECT REFERENCES left / right', rectView.left.toFixed(0), ' / ', rectView.right.toFixed(0)); + + slides.each(function() { + const rect = this.getBoundingClientRect(); + // for debug + // console.log('rect',$(this).attr('id'), ' left / right : ', rect.left, ' / ', rect.right); + if (+rect.left.toFixed(0) >= +rectView.left.toFixed(0) - 1 && +rect.right.toFixed(0) <= +rectView.right.toFixed(0) + 1) { + const tabId = $(this).attr('id'); + $('#name_' + tabId).addClass('selected'); + } + }); + }); + + // Show / Hide password input + $('.icon-show-password').on('click', function() { + const icon = $(this); + const closestInput = icon.siblings(); + if (closestInput.attr('type') === 'password') { + closestInput.attr('type', 'text'); + icon.removeClass('icon-eye').addClass('icon-eye-off'); + } else { + closestInput.attr('type', 'password'); + icon.removeClass('icon-eye-off').addClass('icon-eye'); + } + }); + + // Password input onchange clear error + $('#edit_user_password, #edit_user_conf_password').on('keyup', function() { + hide_error_edit_user(); + }); + + + /* tabsheet pop in guest */ + $('.guest-edit-user-tabsheet').off('click').on('click', function() { + const tabName = $(this).attr('id').split('_'); + const tabId = tabName[1] + '_' + tabName[2] + '_' + tabName[3]; + $('#' + tabId)[0].scrollIntoView({ + behavior: 'smooth' + }); + }); + $('.guest-edit-user-slides').on('scroll', function() { + const slides = $('.guest-edit-user-slides').children(); + const rectView = this.getBoundingClientRect(); + $('.guest-edit-user-tabsheet').removeClass('selected'); + slides.each(function() { + const rect = this.getBoundingClientRect(); + if (+rect.left.toFixed(0) >= +rectView.left.toFixed(0) - 1 && +rect.right.toFixed(0) <= +rectView.right.toFixed(0) + 1) { + const tabId = $(this).attr('id'); + $('#name_' + tabId).addClass('selected'); + } + }); + + }); }); function set_view_selector(view_type) { @@ -722,9 +795,7 @@ function setupRegisterDates(register_dates) { Add User ------------------*/ -function gen_password(e) { - e.preventDefault(); - +function gen_password() { var characterSet = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789'; var i; @@ -736,7 +807,7 @@ function gen_password(e) { password += characterSet.charAt(Math.floor(Math.random() * characterSet.length)); } - jQuery("#AddUserPassword").val(password); + return password; } function add_user_close() { @@ -931,6 +1002,157 @@ function get_container_index_from_uid(uid) { return -1; } +function hide_error_edit_user() { + $('#UserList .EditUserErrors').animate({opacity: 0}, 100); +} + +function show_error_edit_user() { + $('#UserList .EditUserErrors').animate({opacity: 1}, 300); +} + +function reset_input_password() { + $('#edit_user_password, #edit_user_conf_password').val(''); +} + +function editTabsBind () { + $('.edit-user-tabsheet').off('click').on('click', function() { + const tabName = $(this).attr('id').split('_'); + const tabId = tabName[1] + '_' + tabName[2]; + + $('#' + tabId)[0].scrollIntoView({ + behavior: 'smooth' + }); + }); +} + +function check_tabs (title_tab_name_id) { + + if (plugins_load.length > 1) { + const countMoresPlugins = plugins_load.length - 1; + if (!document.getElementById('mores_plugins_expand')) { + $('.edit-user-tab-title').append( + '' + + '' + ); + } + $('#mores_plugins_expand').html('+' + countMoresPlugins); + + const dropdown = $('#dropdown_mores_plugins'); + const tabsheetTitle = $('#' + title_tab_name_id); + $('.edit-user-tab-title').css('margin-top', '3px'); + $('.edit-user-tab-title p:lt(4)').css('padding-top', '5px'); + tabsheetTitle.css({'max-width': '100%'}); + tabsheetTitle.appendTo(dropdown); + + if (1 == countMoresPlugins) { + tabsheetTitle.css('border-radius', '10px'); + } else { + dropdown.children().css('border-radius', '0'); + dropdown.children().first().css('border-radius', '10px 10px 0 0'); + dropdown.children().last().css('border-radius', '0 0 10px 10px'); + } + + $('#mores_plugins_expand').off('click').on('click', function () { + const icon = $(this); + if(icon.hasClass('open')) { + icon.removeClass('open').addClass('close'); + dropdown.fadeOut(); + } else { + icon.removeClass('close').addClass('open'); + dropdown.fadeIn(); + $(window).off('click.hideUsersModal').on('click.hideUsersModal', function(e) { + if (!$(e.target).closest('#dropdown_mores_plugins').length && !$(e.target).is('#mores_plugins_expand')) { + $('#dropdown_mores_plugins').fadeOut(); + icon.removeClass('open').addClass('close'); + } + }); + } + }); + } +} + +/** + * Adds a new tab to the user's modal + * @param {string} tab_name - The tab name (will also be used for the new tab id) + * @param {string} content_id - The id of the HTML element + * @param {string | null} users_table - The name of the column created in the users table (must be null if the set_data_function and get_data_function functions are used) + * @param {() => {} | null} set_data_function - API call set function with ajax (must be null if users_table is used) + * @param {() => {} | null} get_data_function - API call get function with ajax (must be null if users_table is used) + * @returns {void} Displays the new tab in the user's modal + */ +function plugin_add_tab_in_user_modal(tab_name, content_id, users_table=null, set_data_function=null, get_data_function=null) { + // verification + if (typeof tab_name !== 'string') { + throw new TypeError('tab_name must be a string.'); + } + const name = tab_name.replace(/ /g, '').toLowerCase(); + if (document.getElementById('name_tab_' + name)) { + throw new TypeError('An element with this tab_name already exists.'); + } + + if (typeof content_id !== 'string') { + throw new TypeError('content_id must be a string.'); + } else if (!document.getElementById(content_id)) { + throw new TypeError('HTML element "' + content_id + '" not found.'); + } else if (document.querySelector('.edit-user-slides #' + content_id)) { + throw new TypeError('An element with this content_id already exists.'); + } + + if (users_table && typeof users_table !== 'string') { + throw new TypeError('users_table must be a string.'); + } + if (users_table && (set_data_function || get_data_function)) { + throw new TypeError('users_table must be null if set_data_function or get_data_function is used.'); + } + + if (set_data_function && typeof set_data_function !== 'function') { + throw new TypeError('set_data_function must be a function.'); + } else if (set_data_function && typeof set_data_function === 'function') { + plugins_set_functions[name + '_set_function'] = set_data_function; + } + + if (get_data_function && typeof get_data_function !== 'function') { + throw new TypeError('get_data_function must be a function.'); + } else if (get_data_function && typeof get_data_function === 'function') { + plugins_get_functions[name + '_get_function'] = get_data_function; + } + + if (users_table) { + plugins_users_infos_table.push({content_id, users_table}); + } + + // DOM modification + const content = $('#' + content_id); + + // TODO Add a super div with the real width and height (for better css custom) + $('.edit-user-tab-title').append( + '

'+ tab_name +'

' + ); + + $('.edit-user-slides').append( + '
' + ); + + content.appendTo('#tab_' + name); + content.show(); + + editTabsBind(); + + $('.edit-user-tabsheet').addClass('tab-with-plugin'); + + plugins_load.push('name_tab_' + name); + check_tabs('name_tab_' + name); + + if (plugins_load.length <= 1) { + $('#name_tab_' + name).tipTip({ + delay: 0, + fadeIn: 200, + fadeOut: 200, + edgeOffset: 3 + }); + } +} + /*----------------------- Generate User Containers -----------------------*/ @@ -1083,11 +1305,17 @@ function fill_user_edit_summary(user_to_edit, pop_in, isGuest) { pop_in.find('.user-property-username-change input').val(user_to_edit.username); pop_in.find('.user-property-password-change input').val(''); pop_in.find('.user-property-permissions a').attr('href', `admin.php?page=user_perm&user_id=${user_to_edit.id}`); - pop_in.find('.user-property-register').html(get_formatted_date(user_to_edit.registration_date)); + pop_in.find('.user-property-register').html(user_to_edit.registration_date_string); pop_in.find('.user-property-register').tipTip({content:`${registered_str}
${user_to_edit.registration_date_since}`}); - pop_in.find('.user-property-last-visit').html(get_formatted_date(user_to_edit.last_visit)); + pop_in.find('.user-property-last-visit').html(user_to_edit.last_visit_string); pop_in.find('.user-property-last-visit').tipTip({content: `${last_visit_str}
${user_to_edit.last_visit_since}`}); pop_in.find('.user-property-history a').attr('href', history_base_url + user_to_edit.id); + + // Hide the copy password button if you are not using https + if(!window.isSecureContext) { + $('#copy_password').hide(); + $('.update-password-success').css('margin', '40px 0'); + } } function fill_user_edit_properties(user_to_edit, pop_in) { @@ -1137,7 +1365,25 @@ function fill_user_edit_update(user_to_edit, pop_in) { pop_in.find('.update-user-button').unbind("click").click( user_to_edit.id === guest_id ? update_guest_info : update_user_info); pop_in.find('.edit-username-validate').unbind("click").click(update_user_username); - pop_in.find('.edit-password-validate').unbind("click").click(update_user_password); + pop_in.find('#edit_modal_password').off('click').on('click', function() { + $('.user-property-password-choice').hide(); + $('.user-property-password-change-inputs').fadeIn(); + }); + pop_in.find('.edit-password-validate').unbind("click").click(function() { + const errDiv = $('#UserList .EditUserErrors'); + const inputPassword = $('#edit_user_password').val(); + const inputConfirmPassword = $('#edit_user_conf_password').val(); + + if (inputPassword == '' || inputConfirmPassword == '') { + errDiv.html(missingField); + show_error_edit_user(); + } else if (inputPassword !== inputConfirmPassword) { + errDiv.html(noMatchPassword); + show_error_edit_user(); + } else { + update_user_password(); + } + }); pop_in.find('.delete-user-button').unbind("click").click(function () { $.confirm({ title: title_msg.replace('%s', user_to_edit.username), @@ -1231,12 +1477,28 @@ function is_owner(user_id) { } function fill_user_edit(user_to_edit) { - let pop_in = $('.UserListPopInContainer'); + let pop_in = $('#UserList'); fill_user_edit_summary(user_to_edit, pop_in, false); fill_user_edit_properties(user_to_edit, pop_in); fill_user_edit_preferences(user_to_edit, pop_in); fill_user_edit_update(user_to_edit, pop_in); fill_user_edit_permissions(user_to_edit, pop_in); + + // plugins get function + if (Object.keys(plugins_get_functions).length > 0) { + Object.entries(plugins_get_functions).forEach((f) => { + f[1](); + }); + } + const keyUserToEdit = Object.keys(user_to_edit); + plugins_users_infos_table.forEach((i) => { + $('#' + i.content_id).val(''); + if (keyUserToEdit.includes(i.users_table)) { + $('#' + i.content_id).val(user_to_edit[i.users_table]); + } else { + console.error(i.users_table, ' doesn\'t exist in USER_INFOS_TABLE'); + } + }); } function fill_guest_edit() { @@ -1351,7 +1613,7 @@ function select_whole_set() { } function update_user_username() { - let pop_in_container = $('.UserListPopInContainer'); + let pop_in_container = $('#UserList'); let ajax_data = { pwg_token: pwg_token, user_id: last_user_id @@ -1374,16 +1636,20 @@ function update_user_username() { $('#UserList .user-property-initials span').html(get_initials(current_users[last_user_index].username)); fill_container_user_info($('#user-table-content .user-container').eq(last_user_index), last_user_index); } - $("#UserList .update-user-success").fadeIn().delay(1500).fadeOut(2500); - $('.user-property-username').show(); - $('.user-property-username-change').hide(); + $('.user-property-username-change-input').hide(); + $('.edit-username-success').fadeIn(); + $('#close_username_success').on('click', function () { + $('.edit-username-success').hide(); + $('.user-property-username-change-input').show(); + $('.user-property-username-change').hide(); + }); } } }) } function update_user_password() { - let pop_in_container = $('.UserListPopInContainer'); + let pop_in_container = $('#UserList'); let ajax_data = { pwg_token: pwg_token, user_id: last_user_id @@ -1396,9 +1662,22 @@ function update_user_password() { success: (raw_data) => { data = jQuery.parseJSON(raw_data); if (data.stat == 'ok') { - $("#UserList .update-user-success").fadeIn().delay(1500).fadeOut(2500); - $('.user-property-password').show(); - $('.user-property-password-change').hide(); + $('.user-property-password-change-inputs').hide(); + $('.edit-password-success').fadeIn(); + + if (window.isSecureContext && navigator.clipboard) { + $('#copy_password').on('click', async function() { + navigator.clipboard.writeText(ajax_data['password']); + $('#password_msg_success').html(passwordCopied); + }); + }; + + $('#close_password_success').on('click', function() { + $('.user-property-password-change').hide(); + $('.edit-password-success').hide(); + $('.user-property-password-change-inputs').show(); + reset_input_password(); + }); } } }) @@ -1414,6 +1693,16 @@ function update_user_info() { pwg_token: pwg_token, user_id: last_user_id }; + if (plugins_users_infos_table.length > 0) { + const keyCurrentUsers = Object.keys(current_users[last_user_index]); + plugins_users_infos_table.forEach((i) => { + if (keyCurrentUsers.includes(i.users_table)) { + ajax_data[i.users_table] = $('#' + i.content_id).val(); + } else { + console.error(i.users_table, ' doesn\'t exist in USER_INFOS_TABLE'); + } + }); + } ajax_data = fill_ajax_data_from_container(ajax_data, pop_in_container); jQuery.ajax({ @@ -1449,6 +1738,13 @@ function update_user_info() { $(".update-user-button i").removeClass("icon-spin6 animate-spin").addClass("icon-floppy"); $(".update-user-button").removeClass("unclickable"); + // update plugins + if (Object.keys(plugins_get_functions).length > 0) { + Object.entries(plugins_set_functions).forEach((f) => { + f[1](); + }); + } + } else if (data.stat === 'fail') { $("#UserList .update-user-fail").html(data.message); $("#UserList .update-user-fail").fadeIn(); @@ -1575,6 +1871,9 @@ function update_user_list() { last_user_index = uid_index; fill_user_edit(current_users[uid_index]); $("#UserList").fadeIn(); + $('#tab_properties')[0].scrollIntoView({ + behavior: 'instant' + }); }); set_selected_to_selection();