jQuery(document).ready(function($){ var frame; function openAvatarFrame(e){ if (e) { e.preventDefault(); } if(frame){ frame.open(); return; } frame = wp.media({ title: 'Profilbillede', button: { text: 'Brug' }, multiple: false }); frame.on('select', function(){ var att = frame.state().get('selection').first().toJSON(); $('#ansico-avatar-url').val(att.url); $('#ansico-avatar-preview').attr('src', att.url).show(); $('.ansico-avatar-trigger').addClass('has-image'); $('.ansico-avatar-trigger .ansico-avatar-placeholder').remove(); }); frame.open(); } $('#ansico-upload-button').on('click', openAvatarFrame); $('#ansico-remove-button').on('click', function(e){ e.preventDefault(); $('#ansico-avatar-url').val(''); $('#ansico-avatar-preview').hide().attr('src', ''); $('.ansico-avatar-trigger').removeClass('has-image'); if (!$('.ansico-avatar-trigger .ansico-avatar-placeholder').length) { $('.ansico-avatar-trigger').append('Upload'); } }); function normalizeText(text) { return $.trim(String(text || '').replace(/\s+/g, ' ')).toLowerCase(); } function textMatches(text, patterns) { var normalized = normalizeText(text); for (var i = 0; i < patterns.length; i++) { if (normalized.indexOf(patterns[i]) !== -1) { return true; } } return false; } function enhanceAvatarUi() { var $preview = $('#ansico-avatar-preview'); var $upload = $('#ansico-upload-button'); var $remove = $('#ansico-remove-button'); if (!$preview.length || !$upload.length) { return; } var $cell = $preview.closest('td'); $cell.addClass('ansico-avatar-cell'); $upload.addClass('ansico-avatar-hidden-button'); if (!$cell.find('.ansico-avatar-trigger').length) { var $trigger = $(''); $preview.before($trigger); $trigger.append($preview); if (!$preview.attr('src')) { $preview.hide(); $trigger.append('Upload'); } else { $trigger.addClass('has-image'); } } $cell.on('click', '.ansico-avatar-trigger', openAvatarFrame); $remove.addClass('ansico-avatar-remove-button'); } enhanceAvatarUi(); if ( ! window.ansicoAdminSettings || ! window.ansicoAdminSettings.cleanUpProfileSettings ) { return; } var $form = $('#your-profile'); if ( ! $form.length ) { return; } var labels = window.ansicoAdminSettings.labels || {}; var initialSerializedState = ''; var panelLabels = { profile: labels.profile || 'Profile', federation: labels.federation || 'Federation', other: labels.otherSettings || 'Other settings' }; var profileHeadingPatterns = ['name', 'navn', 'contact info', 'kontaktinformation', 'account management', 'kontohåndtering', 'social profiles', 'profilbillede', 'ansico avatar']; var federationHeadingPatterns = ['activitypub', 'moderation', 'moderering', 'federation', 'føderation']; var otherHeadingPatterns = ['application passwords', 'applikationsadgangskoder']; function bucketForHeading(text) { if ( textMatches(text, otherHeadingPatterns) ) { return 'other'; } if ( textMatches(text, profileHeadingPatterns) ) { return 'profile'; } if ( textMatches(text, federationHeadingPatterns) ) { return 'federation'; } return 'other'; } function getSectionNodes($heading) { var $nodes = $heading; var $next = $heading.next(); while ( $next.length && ! $next.is('h2, h3') ) { $nodes = $nodes.add($next); $next = $next.next(); } return $nodes; } function createSectionBucket($nodes) { return { headingText: $nodes.first().text() || '', nodes: $nodes }; } function collectSections($container) { var results = []; $container.children('h2, h3').each(function(){ results.push(createSectionBucket(getSectionNodes($(this)))); }); return results; } function extractSectionByMatcher(sections, matcherFn) { var extracted = []; for (var i = sections.length - 1; i >= 0; i--) { if (matcherFn(sections[i])) { extracted.unshift(sections.splice(i, 1)[0]); } } return extracted; } function appendSections($panel, sections) { $.each(sections, function(_, section){ $panel.append(section.nodes); }); } // Rename heading in-place for the Ansico avatar section. $form.find('h2, h3').each(function(){ var $heading = $(this); if ( normalizeText($heading.text()) === 'ansico avatar' ) { $heading.text('Profilbillede'); } }); // Separate biography into its own section. var $bioRow = $(); $form.find('tr').each(function(){ var headingText = normalizeText($(this).find('th').first().text()); if ( headingText.indexOf('biographical info') !== -1 || headingText.indexOf('biografisk info') !== -1 ) { $bioRow = $(this); return false; } }); var $bioSection = $(); if ( $bioRow.length ) { var bioTitle = $.trim($bioRow.find('th').first().text()) || 'Biografisk info'; $bioSection = $('
'); $bioSection.append($('

').text(bioTitle)); var $bioTable = $(''); $bioTable.append($bioRow); $bioSection.append($bioTable); var $sourceTable = $bioRow.closest('table'); if ( $sourceTable.find('tr').length === 0 ) { var $prevHeading = $sourceTable.prevAll('h2, h3').first(); $sourceTable.remove(); if ( $prevHeading.length ) { $prevHeading.remove(); } } } var $submits = $form.find('p.submit, .submit').filter(function(){ return $(this).find(':submit').length || $(this).is('p.submit'); }).detach(); var sections = collectSections($form); if ( ! sections.length && ! $bioSection.length ) { if ( $submits.length ) { $form.append($submits); } return; } var $tabsNav = $('
'); var $panelsWrap = $('
'); var panels = { profile: $('
'), federation: $('
'), other: $('
') }; $.each(panelLabels, function(key, label){ var target = 'ansico-profile-tab-' + (key === 'other' ? 'other' : key); var $button = $(''); $button.text(label).attr('data-panel', target); $tabsNav.append($button); }); var profileSections = extractSectionByMatcher(sections, function(section){ return bucketForHeading(section.headingText) === 'profile'; }); var federationSections = extractSectionByMatcher(sections, function(section){ return bucketForHeading(section.headingText) === 'federation'; }); var otherSections = sections; // Pull sections with ActivityPub-ish field names into Federation even if heading text is unexpected. var fallbackFromProfile = extractSectionByMatcher(profileSections, function(section){ return section.nodes.find('[name*="activitypub"], [id*="activitypub"], [class*="activitypub"], [name*="moderation"], [id*="moderation"], [class*="moderation"]').length > 0 || textMatches(section.headingText, federationHeadingPatterns); }); federationSections = federationSections.concat(fallbackFromProfile); var socialFromOther = extractSectionByMatcher(otherSections, function(section){ return textMatches(section.headingText, ['social profiles']) || section.nodes.find('[name^="ansico_social_"], [id^="ansico_social_"]').length > 0; }); profileSections = profileSections.concat(socialFromOther); var applicationPasswordSections = extractSectionByMatcher(profileSections, function(section){ return textMatches(section.headingText, otherHeadingPatterns) || section.nodes.find('[name*="application_password"], [id*="application-password"], .application-passwords').length > 0; }); otherSections = applicationPasswordSections.concat(otherSections); function findAndExtractRows($sectionNodes, patterns) { var rows = $(); $sectionNodes.filter('table').add($sectionNodes.find('table')).each(function(){ $(this).find('tr').each(function(){ var rowLabel = normalizeText($(this).find('th').first().text()); if ( textMatches(rowLabel, patterns) ) { rows = rows.add($(this)); } }); }); return rows; } function buildSingleTableSection(title, $rows) { if ( !$rows.length ) { return null; } var $wrap = $('
'); $wrap.append($('

').text(title)); var $table = $(''); $table.append($rows); $wrap.append($table); return createSectionBucket($wrap); } function findAllRows($sectionNodes) { var rows = $(); $sectionNodes.filter('table').add($sectionNodes.find('table')).each(function(){ rows = rows.add($(this).find('tr')); }); return rows; } function pruneEmptySectionList(sectionList) { return $.grep(sectionList, function(section){ var $tables = section.nodes.filter('table').add(section.nodes.find('table')); if ( ! $tables.length ) { return true; } return $tables.find('tr').length > 0; }); } // Reorder profile sections into a more social-profile-like flow. var orderedProfile = []; var avatarSections = extractSectionByMatcher(profileSections, function(section){ return textMatches(section.headingText, ['profilbillede', 'ansico avatar']); }); var nameSections = extractSectionByMatcher(profileSections, function(section){ return textMatches(section.headingText, ['name', 'navn']); }); var contactSections = extractSectionByMatcher(profileSections, function(section){ return textMatches(section.headingText, ['contact info', 'kontaktinformation']); }); var socialSections = extractSectionByMatcher(profileSections, function(section){ return textMatches(section.headingText, ['social profiles']); }); var accountSections = extractSectionByMatcher(profileSections, function(section){ return textMatches(section.headingText, ['account management', 'kontohåndtering']); }); var socialRows = $(); $.each(socialSections, function(_, section){ socialRows = socialRows.add(findAllRows(section.nodes)); }); var websiteRows = $(); $.each(contactSections, function(_, section){ var $rows = findAndExtractRows(section.nodes, ['website', 'websted', 'site url']); if ( $rows.length ) { websiteRows = websiteRows.add($rows); } }); if ( contactSections.length ) { var $contactTable = contactSections[0].nodes.filter('table').add(contactSections[0].nodes.find('table')).first(); if ( !$contactTable.length ) { $contactTable = $(''); contactSections[0].nodes = contactSections[0].nodes.add($contactTable); } if ( socialRows.length ) { $contactTable.append('Social profiles'); $contactTable.append(socialRows); } if ( websiteRows.length ) { $contactTable.append('Website'); $contactTable.append(websiteRows); } } else if ( socialRows.length || websiteRows.length ) { var $contactWrap = $('
'); $contactWrap.append($('

').text('Kontaktinformationer')); var $contactTableOnly = $(''); if ( socialRows.length ) { $contactTableOnly.append('Social profiles'); $contactTableOnly.append(socialRows); } if ( websiteRows.length ) { $contactTableOnly.append('Website'); $contactTableOnly.append(websiteRows); } $contactWrap.append($contactTableOnly); contactSections.push(createSectionBucket($contactWrap)); } // Move ActivityPub header image into the profile hero card instead of Federation. var headerRows = $(); $.each(federationSections, function(_, section){ section.nodes.filter('table').add(section.nodes.find('table')).each(function(){ $(this).find('tr').each(function(){ var $row = $(this); var rowLabel = normalizeText($row.find('th').first().text()); var hasHeaderFields = $row.find('[name*="header"], [id*="header"], [class*="header"], [name*="banner"], [id*="banner"], [class*="banner"]').length > 0; if ( textMatches(rowLabel, ['header image', 'headerbillede', 'cover image', 'banner image']) || hasHeaderFields ) { headerRows = headerRows.add($row); } }); }); }); profileSections = pruneEmptySectionList(profileSections); federationSections = pruneEmptySectionList(federationSections); orderedProfile = orderedProfile.concat(avatarSections, nameSections, contactSections); if ( $bioSection.length ) { orderedProfile.push(createSectionBucket($bioSection)); $bioSection = $(); } orderedProfile = orderedProfile.concat(accountSections, profileSections); appendSections(panels.profile, orderedProfile); appendSections(panels.federation, federationSections); appendSections(panels.other, otherSections); // If any ActivityPub/Moderation heading still ended up elsewhere, move it explicitly. function moveMatchingHeadings($panel, patterns, $targetPanel) { $panel.children('h2, h3').each(function(){ var $heading = $(this); if ( textMatches($heading.text(), patterns) ) { $targetPanel.append(getSectionNodes($heading)); } }); } moveMatchingHeadings(panels.profile, federationHeadingPatterns, panels.federation); moveMatchingHeadings(panels.other, federationHeadingPatterns, panels.federation); moveMatchingHeadings(panels.profile, otherHeadingPatterns, panels.other); moveMatchingHeadings(panels.federation, otherHeadingPatterns, panels.other); moveMatchingHeadings(panels.other, ['social profiles'], panels.profile); // Decorate section cards. panels.profile.children('h2, h3').each(function(){ var $heading = $(this); var $section = $('
'); var $nodes = getSectionNodes($heading); $nodes.wrapAll($section); }); panels.federation.children('h2, h3').each(function(){ var $heading = $(this); var $section = $('
'); var $nodes = getSectionNodes($heading); $nodes.wrapAll($section); }); panels.other.children('h2, h3').each(function(){ var $heading = $(this); var $section = $('
'); var $nodes = getSectionNodes($heading); $nodes.wrapAll($section); }); panels.profile.find('.ansico-profile-card').first().addClass('ansico-profile-card-avatar'); function compactNameFields() { panels.profile.find('.ansico-profile-card').each(function(){ var $card = $(this); var headingText = $card.children('h2, h3').first().text(); if ( ! textMatches(headingText, ['name', 'navn']) ) { return; } var $table = $card.find('table.form-table').first(); if ( ! $table.length ) { return; } var $firstRow = $(); var $lastRow = $(); $table.find('tr').each(function(){ var rowLabel = normalizeText($(this).find('th').first().text()); if ( !$firstRow.length && textMatches(rowLabel, ['first name', 'fornavn']) ) { $firstRow = $(this); } else if ( !$lastRow.length && textMatches(rowLabel, ['last name', 'efternavn']) ) { $lastRow = $(this); } }); if ( $firstRow.length && $lastRow.length && ! $card.find('.ansico-profile-inline-grid').length ) { var $grid = $('
'); $.each([$firstRow, $lastRow], function(_, $row){ var $field = $('
'); $field.append($('').html($row.find('th').first().html())); var $control = $('
'); $control.append($row.find('td').contents()); $field.append($control); $grid.append($field); $row.remove(); }); $table.before($grid); if ( !$table.find('tr').length ) { $table.remove(); } } }); } function integrateHeroHeaderRow() { var $heroCard = panels.profile.find('.ansico-profile-card').filter(function(){ return textMatches($(this).children('h2, h3').first().text(), ['profilbillede', 'profile picture', 'ansico avatar']); }).first(); if ( !$heroCard.length ) { return; } $heroCard.addClass('ansico-profile-hero-card'); var $heroTable = $heroCard.find('table.form-table').first(); if ( !$heroTable.length ) { $heroTable = $(''); $heroCard.append($heroTable); } if ( headerRows.length ) { var $coverTable = $(''); headerRows.each(function(){ $(this).addClass('ansico-profile-cover-row'); }); $coverTable.append(headerRows); $heroCard.find('h2, h3').first().after($coverTable); $heroCard.addClass('has-cover'); } $heroTable.find('tr').each(function(){ var rowLabel = normalizeText($(this).find('th').first().text()); if ( textMatches(rowLabel, ['profilbillede', 'profile picture', 'avatar']) ) { $(this).addClass('ansico-profile-avatar-row'); } }); panels.federation.find('.ansico-profile-card').each(function(){ if ( ! $(this).find('tr').length ) { $(this).remove(); } }); } function enhanceHeaderImageUi() { var $coverRow = panels.profile.find('.ansico-profile-cover-row').first(); if ( !$coverRow.length || $coverRow.hasClass('ansico-cover-ui-ready') ) { return; } $coverRow.addClass('ansico-cover-ui-ready'); var $cell = $coverRow.find('td').first(); if ( !$cell.length ) { return; } var $buttons = $cell.find('button, .button, input[type="button"], input[type="submit"]'); var $selectButton = $buttons.filter(function(){ return !/remove|delete|fjerne|slet/.test(normalizeText($(this).text() || $(this).val())); }).first(); var $removeButton = $buttons.filter(function(){ return /remove|delete|fjerne|slet/.test(normalizeText($(this).text() || $(this).val())); }).first(); var $img = $cell.find('img').first(); var $trigger = $(''); if ( $img.length ) { $trigger.append($img); $trigger.addClass('has-image'); } else { $trigger.append('Choose a header image'); } $cell.prepend($trigger); if ( $selectButton.length ) { $selectButton.addClass('ansico-header-hidden-button'); $trigger.on('click', function(e){ e.preventDefault(); $selectButton.trigger('click'); }); } if ( $removeButton.length ) { $removeButton.addClass('ansico-header-remove-button'); } var $actions = $('
'); if ( $selectButton.length ) { $actions.append($selectButton); } if ( $removeButton.length ) { $actions.append($removeButton); } if ( $actions.children().length ) { $cell.append($actions); } var observer = new MutationObserver(function(){ var $latestImg = $cell.find('img').not($trigger.find('img')).first(); if ( $latestImg.length ) { $trigger.empty().append($latestImg).addClass('has-image'); } else if ( !$trigger.find('img').length ) { $trigger.removeClass('has-image').html('Choose a header image'); } }); observer.observe($cell.get(0), { childList: true, subtree: true }); if ( $removeButton.length ) { $removeButton.on('click', function(){ setTimeout(function(){ if ( !$trigger.find('img').length ) { $trigger.removeClass('has-image').html('Choose a header image'); } }, 50); }); } } $panelsWrap.append(panels.profile, panels.federation, panels.other); var $firstHeading = $form.children('h2, h3').first(); if ( $firstHeading.length ) { $firstHeading.before($tabsNav, $panelsWrap); } else { $form.prepend($tabsNav, $panelsWrap); } if ( $submits.length ) { var $submitWrap = $('
'); $submitWrap.append($submits); $form.append($submitWrap); } function activateTab(panelId) { $tabsNav.find('.ansico-profile-tab-button').each(function(){ var active = $(this).attr('data-panel') === panelId; $(this).toggleClass('is-active', active).attr('aria-selected', active ? 'true' : 'false'); }); $panelsWrap.find('.ansico-profile-tab-panel').each(function(){ $(this).toggleClass('is-active', this.id === panelId); }); } $tabsNav.on('click', '.ansico-profile-tab-button', function(){ activateTab($(this).attr('data-panel')); }); function refreshInitialState() { initialSerializedState = $form.serialize(); } function setupUnsavedChangesGuard() { $(window).off('beforeunload.edit-profile'); $(window).off('beforeunload.ansicoProfileCleanup'); refreshInitialState(); $(window).on('beforeunload.ansicoProfileCleanup', function(){ if ( $form.serialize() !== initialSerializedState ) { return labels.leaveWarning || 'Vil du forlade webstedet? Ændringer, du har foretaget, gemmes muligvis ikke.'; } }); $form.on('submit', function(){ refreshInitialState(); $(window).off('beforeunload.ansicoProfileCleanup'); }); } compactNameFields(); integrateHeroHeaderRow(); enhanceHeaderImageUi(); activateTab('ansico-profile-tab-profile'); enhanceAvatarUi(); setupUnsavedChangesGuard(); });