2026-04-13 18:55:00 +00:00
|
|
|
jQuery(document).ready(function($){
|
2026-04-16 16:59:23 +00:00
|
|
|
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();
|
2026-04-13 18:55:00 +00:00
|
|
|
});
|
2026-04-16 16:59:23 +00:00
|
|
|
frame.open();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$('#ansico-upload-button').on('click', openAvatarFrame);
|
|
|
|
|
|
|
|
|
|
$('#ansico-remove-button').on('click', function(e){
|
2026-04-13 18:55:00 +00:00
|
|
|
e.preventDefault();
|
|
|
|
|
$('#ansico-avatar-url').val('');
|
|
|
|
|
$('#ansico-avatar-preview').hide().attr('src', '');
|
2026-04-16 16:59:23 +00:00
|
|
|
$('.ansico-avatar-trigger').removeClass('has-image');
|
|
|
|
|
if (!$('.ansico-avatar-trigger .ansico-avatar-placeholder').length) {
|
|
|
|
|
$('.ansico-avatar-trigger').append('<span class="ansico-avatar-placeholder">Upload</span>');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
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 = $('<button type="button" class="ansico-avatar-trigger" aria-label="Upload profile picture"></button>');
|
|
|
|
|
$preview.before($trigger);
|
|
|
|
|
$trigger.append($preview);
|
|
|
|
|
if (!$preview.attr('src')) {
|
|
|
|
|
$preview.hide();
|
|
|
|
|
$trigger.append('<span class="ansico-avatar-placeholder">Upload</span>');
|
|
|
|
|
} 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 = $('<div class="ansico-profile-section ansico-profile-bio-section"></div>');
|
|
|
|
|
$bioSection.append($('<h2></h2>').text(bioTitle));
|
|
|
|
|
var $bioTable = $('<table class="form-table" role="presentation"></table>');
|
|
|
|
|
$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 = $('<div class="ansico-profile-tabs-nav" role="tablist" aria-label="Profile settings tabs"></div>');
|
|
|
|
|
var $panelsWrap = $('<div class="ansico-profile-tabs-wrap"></div>');
|
|
|
|
|
var panels = {
|
|
|
|
|
profile: $('<div class="ansico-profile-tab-panel" id="ansico-profile-tab-profile" role="tabpanel"></div>'),
|
|
|
|
|
federation: $('<div class="ansico-profile-tab-panel" id="ansico-profile-tab-federation" role="tabpanel"></div>'),
|
|
|
|
|
other: $('<div class="ansico-profile-tab-panel" id="ansico-profile-tab-other" role="tabpanel"></div>')
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
$.each(panelLabels, function(key, label){
|
|
|
|
|
var target = 'ansico-profile-tab-' + (key === 'other' ? 'other' : key);
|
|
|
|
|
var $button = $('<button type="button" class="ansico-profile-tab-button" role="tab" aria-selected="false"></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 = $('<div class="ansico-profile-section"></div>');
|
|
|
|
|
$wrap.append($('<h2></h2>').text(title));
|
|
|
|
|
var $table = $('<table class="form-table" role="presentation"></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));
|
2026-04-13 18:55:00 +00:00
|
|
|
});
|
2026-04-16 16:59:23 +00:00
|
|
|
|
|
|
|
|
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 = $('<table class="form-table" role="presentation"></table>');
|
|
|
|
|
contactSections[0].nodes = contactSections[0].nodes.add($contactTable);
|
|
|
|
|
}
|
|
|
|
|
if ( socialRows.length ) {
|
|
|
|
|
$contactTable.append('<tr class="ansico-profile-subheading-row"><th colspan="2">Social profiles</th></tr>');
|
|
|
|
|
$contactTable.append(socialRows);
|
|
|
|
|
}
|
|
|
|
|
if ( websiteRows.length ) {
|
|
|
|
|
$contactTable.append('<tr class="ansico-profile-subheading-row"><th colspan="2">Website</th></tr>');
|
|
|
|
|
$contactTable.append(websiteRows);
|
|
|
|
|
}
|
|
|
|
|
} else if ( socialRows.length || websiteRows.length ) {
|
|
|
|
|
var $contactWrap = $('<div class="ansico-profile-section"></div>');
|
|
|
|
|
$contactWrap.append($('<h2></h2>').text('Kontaktinformationer'));
|
|
|
|
|
var $contactTableOnly = $('<table class="form-table" role="presentation"></table>');
|
|
|
|
|
if ( socialRows.length ) {
|
|
|
|
|
$contactTableOnly.append('<tr class="ansico-profile-subheading-row"><th colspan="2">Social profiles</th></tr>');
|
|
|
|
|
$contactTableOnly.append(socialRows);
|
|
|
|
|
}
|
|
|
|
|
if ( websiteRows.length ) {
|
|
|
|
|
$contactTableOnly.append('<tr class="ansico-profile-subheading-row"><th colspan="2">Website</th></tr>');
|
|
|
|
|
$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 = $('<div class="ansico-profile-card"></div>');
|
|
|
|
|
var $nodes = getSectionNodes($heading);
|
|
|
|
|
$nodes.wrapAll($section);
|
|
|
|
|
});
|
|
|
|
|
panels.federation.children('h2, h3').each(function(){
|
|
|
|
|
var $heading = $(this);
|
|
|
|
|
var $section = $('<div class="ansico-profile-card"></div>');
|
|
|
|
|
var $nodes = getSectionNodes($heading);
|
|
|
|
|
$nodes.wrapAll($section);
|
|
|
|
|
});
|
|
|
|
|
panels.other.children('h2, h3').each(function(){
|
|
|
|
|
var $heading = $(this);
|
|
|
|
|
var $section = $('<div class="ansico-profile-card"></div>');
|
|
|
|
|
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 = $('<div class="ansico-profile-inline-grid"></div>');
|
|
|
|
|
$.each([$firstRow, $lastRow], function(_, $row){
|
|
|
|
|
var $field = $('<div class="ansico-profile-inline-field"></div>');
|
|
|
|
|
$field.append($('<label class="ansico-profile-inline-label"></label>').html($row.find('th').first().html()));
|
|
|
|
|
var $control = $('<div class="ansico-profile-inline-control"></div>');
|
|
|
|
|
$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 = $('<table class="form-table" role="presentation"></table>');
|
|
|
|
|
$heroCard.append($heroTable);
|
|
|
|
|
}
|
|
|
|
|
if ( headerRows.length ) {
|
|
|
|
|
var $coverTable = $('<table class="form-table ansico-profile-cover-table" role="presentation"></table>');
|
|
|
|
|
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 = $('<button type="button" class="ansico-header-trigger" aria-label="Choose header image"></button>');
|
|
|
|
|
if ( $img.length ) {
|
|
|
|
|
$trigger.append($img);
|
|
|
|
|
$trigger.addClass('has-image');
|
|
|
|
|
} else {
|
|
|
|
|
$trigger.append('<span class="ansico-header-placeholder">Choose a header image</span>');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$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 = $('<div class="ansico-header-actions"></div>');
|
|
|
|
|
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('<span class="ansico-header-placeholder">Choose a header image</span>');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
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('<span class="ansico-header-placeholder">Choose a header image</span>');
|
|
|
|
|
}
|
|
|
|
|
}, 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 = $('<div class="ansico-profile-submit-wrap"></div>');
|
|
|
|
|
$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();
|
|
|
|
|
});
|