748 lines
28 KiB
JavaScript
748 lines
28 KiB
JavaScript
(function (window, $) {
|
||
'use strict';
|
||
|
||
var profileUI = window.ProfileUI || {};
|
||
var layuiReady = false;
|
||
var layerApi = null;
|
||
var genealogyContextStorageKey = 'genealogy_current_context_v1';
|
||
var mobileMenuId = 'profile-mobile-menu';
|
||
var apiStateTypes = ['loading', 'empty', 'error', 'forbidden'];
|
||
var familyWorkspacePages = [
|
||
'profile-family-home.html', 'profile-tree.html', 'profile-generation.html',
|
||
'profile-family-admin.html', 'profile-admin-permissions.html', 'profile-join-review.html',
|
||
'profile-content.html', 'profile-article.html', 'profile-article-edit.html',
|
||
'profile-album.html', 'profile-album-detail.html', 'profile-album-edit.html',
|
||
'profile-video.html', 'profile-video-edit.html', 'profile-feed.html',
|
||
'profile-feed-detail.html', 'profile-feed-edit.html', 'profile-ceremony.html',
|
||
'profile-ceremony-detail.html', 'profile-gift-edit.html', 'profile-gift.html',
|
||
'profile-growth.html', 'profile-growth-edit.html', 'profile-merit.html',
|
||
'profile-merit-edit.html', 'profile-memo.html', 'profile-memo-edit.html',
|
||
'profile-relative.html', 'profile-relative-edit.html', 'profile-invite.html',
|
||
'profile-data-reminders.html', 'profile-documents.html', 'profile-family-settings.html'
|
||
];
|
||
var familyWorkspaceNavigation = [
|
||
{ label: '家谱主页', href: 'profile-family-home.html', context: true },
|
||
{ label: '世系管理', items: [
|
||
{ label: '世系图', href: 'profile-tree.html', context: true },
|
||
{ label: '字辈谱', href: 'profile-generation.html', context: true },
|
||
{ label: '资料提醒', href: 'profile-data-reminders.html', context: true }
|
||
] },
|
||
{ label: '内容发布', items: [
|
||
{ label: '内容工作台', href: 'profile-content.html', context: true },
|
||
{ label: '谱文', href: 'profile-article.html', pages: ['profile-article-edit.html'], context: true },
|
||
{ label: '家族圈', href: 'profile-feed.html', pages: ['profile-feed-detail.html', 'profile-feed-edit.html'], context: true },
|
||
{ label: '相册', href: 'profile-album.html', pages: ['profile-album-detail.html', 'profile-album-edit.html'], context: true },
|
||
{ label: '视频', href: 'profile-video.html', pages: ['profile-video-edit.html'], context: true },
|
||
{ label: '祭祀活动', href: 'profile-ceremony.html', pages: ['profile-ceremony-detail.html', 'profile-gift-edit.html'], context: true },
|
||
{ label: '贺礼邀请', href: 'profile-gift.html', context: true },
|
||
{ label: '成长记录', href: 'profile-growth.html', pages: ['profile-growth-edit.html'], context: true },
|
||
{ label: '功德录', href: 'profile-merit.html', pages: ['profile-merit-edit.html'], context: true },
|
||
{ label: '备忘录', href: 'profile-memo.html', pages: ['profile-memo-edit.html'], context: true },
|
||
{ label: '亲友记录', href: 'profile-relative.html', pages: ['profile-relative-edit.html'], context: true },
|
||
{ label: '重要证件', href: 'profile-documents.html', context: true }
|
||
] },
|
||
{ label: '家族管理', items: [
|
||
{ label: '成员管理', href: 'profile-family-admin.html', context: true },
|
||
{ label: '入谱审核', href: 'profile-join-review.html', context: true },
|
||
{ label: '邀请家人', href: 'profile-invite.html', context: true },
|
||
{ label: '家谱维护', href: 'profile-family-settings.html', context: true },
|
||
{ label: '权限说明', href: 'profile-admin-permissions.html', context: true }
|
||
] },
|
||
{ label: '消息中心', href: 'profile-messages.html' }
|
||
];
|
||
var accountWorkspaceNavigation = [
|
||
{ label: '个人中心', href: 'profile.html' },
|
||
{ label: '我的家谱', items: [
|
||
{ label: '家谱列表', href: 'profile-families.html' },
|
||
{ label: '创建家谱', href: 'profile-create-family.html' },
|
||
{ label: '加入家谱', href: 'join-genealogy.html' },
|
||
{ label: '我的申请', href: 'profile-join-family.html' }
|
||
] },
|
||
{ label: '账号资料', items: [
|
||
{ label: '个人资料', href: 'profile-data.html' },
|
||
{ label: '账号安全', href: 'profile-security.html' }
|
||
] },
|
||
{ label: '服务与帮助', items: [
|
||
{ label: '帮助与服务', href: 'profile-services.html' },
|
||
{ label: '意见反馈', href: 'profile-feedback.html', pages: ['my-tickets.html', 'submit-ticket.html', 'ticket-detail.html'] },
|
||
{ label: '推广收益', href: 'profile-earnings.html' },
|
||
{ label: '分享与邀请', href: 'profile-share.html' }
|
||
] },
|
||
{ label: '消息中心', href: 'profile-messages.html' }
|
||
];
|
||
|
||
function escapeHtml(value) {
|
||
return String(value === undefined || value === null ? '' : value)
|
||
.replace(/&/g, '&')
|
||
.replace(/</g, '<')
|
||
.replace(/>/g, '>')
|
||
.replace(/"/g, '"')
|
||
.replace(/'/g, ''');
|
||
}
|
||
|
||
function renderApiState(type, message) {
|
||
var role;
|
||
var busy;
|
||
|
||
if (apiStateTypes.indexOf(type) < 0) throw new TypeError('不支持的业务状态:' + type);
|
||
role = type === 'error' || type === 'forbidden' ? 'alert' : 'status';
|
||
busy = type === 'loading' ? ' aria-busy="true"' : '';
|
||
return '<div class="api-state api-state--' + type + '" data-api-state="' + type +
|
||
'" role="' + role + '" aria-live="polite"' + busy + '>' + escapeHtml(message) + '</div>';
|
||
}
|
||
|
||
function setApiState(element, type, message) {
|
||
if (!element) return;
|
||
element.innerHTML = renderApiState(type, message);
|
||
}
|
||
|
||
function revealDetail(element) {
|
||
var reduceMotion;
|
||
|
||
if (!element) return;
|
||
reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||
if (typeof element.scrollIntoView === 'function') {
|
||
element.scrollIntoView({ behavior: reduceMotion ? 'auto' : 'smooth', block: 'start' });
|
||
}
|
||
if (typeof element.focus === 'function') element.focus({ preventScroll: true });
|
||
}
|
||
|
||
profileUI.renderApiState = renderApiState;
|
||
profileUI.setApiState = setApiState;
|
||
profileUI.revealDetail = revealDetail;
|
||
window.ProfileUI = profileUI;
|
||
|
||
if (!$) return;
|
||
|
||
function getSessionStorage() {
|
||
try {
|
||
return window.sessionStorage;
|
||
} catch (error) {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
function normalizeGenealogyName(value) {
|
||
var name = String(value === undefined || value === null ? '' : value).trim();
|
||
|
||
return name && name.length <= 80 ? name : '';
|
||
}
|
||
|
||
function getStoredGenealogyContext() {
|
||
var storage = getSessionStorage();
|
||
var stored;
|
||
var context;
|
||
var genealogyId;
|
||
var genealogyName;
|
||
|
||
if (!storage) return null;
|
||
try {
|
||
stored = storage.getItem(genealogyContextStorageKey);
|
||
context = stored ? JSON.parse(stored) : null;
|
||
} catch (error) {
|
||
return null;
|
||
}
|
||
genealogyId = normalizeGenealogyId(context && context.genealogyId);
|
||
genealogyName = normalizeGenealogyName(context && context.genealogyName);
|
||
return genealogyId && genealogyName ? {
|
||
genealogyId: genealogyId,
|
||
genealogyName: genealogyName
|
||
} : null;
|
||
}
|
||
|
||
function setCurrentGenealogyContext(genealogyId, genealogyName) {
|
||
var storage = getSessionStorage();
|
||
var context = {
|
||
genealogyId: normalizeGenealogyId(genealogyId),
|
||
genealogyName: normalizeGenealogyName(genealogyName)
|
||
};
|
||
|
||
if (!context.genealogyId || !context.genealogyName) return null;
|
||
if (storage) {
|
||
try {
|
||
storage.setItem(genealogyContextStorageKey, JSON.stringify(context));
|
||
} catch (error) {}
|
||
}
|
||
renderCurrentGenealogyContext();
|
||
return context;
|
||
}
|
||
|
||
function clearCurrentGenealogyContext() {
|
||
var storage = getSessionStorage();
|
||
|
||
if (!storage) return;
|
||
try {
|
||
storage.removeItem(genealogyContextStorageKey);
|
||
} catch (error) {}
|
||
}
|
||
|
||
function getCurrentGenealogyContext() {
|
||
var genealogyId = getGenealogyId();
|
||
var context = getStoredGenealogyContext();
|
||
|
||
if (!context) return null;
|
||
return !genealogyId || context.genealogyId === genealogyId ? context : null;
|
||
}
|
||
|
||
function openLegacyLogout() {
|
||
var $modal = $('#logoutModal');
|
||
|
||
if (!$modal.length) return;
|
||
$modal.prop('hidden', false).addClass('show').attr('aria-hidden', 'false');
|
||
$('body').addClass('logout-modal-open');
|
||
}
|
||
|
||
function closeLegacyLogout() {
|
||
var $modal = $('#logoutModal');
|
||
|
||
$modal.removeClass('show').attr('aria-hidden', 'true').prop('hidden', true);
|
||
$('body').removeClass('logout-modal-open');
|
||
}
|
||
|
||
function openConfirm(options) {
|
||
var settings = $.extend({
|
||
title: '确认操作',
|
||
content: '确定继续吗?',
|
||
confirmText: '确定',
|
||
cancelText: '取消',
|
||
onConfirm: $.noop,
|
||
onCancel: $.noop
|
||
}, options || {});
|
||
|
||
if (layerApi) {
|
||
layerApi.confirm(settings.content, {
|
||
title: settings.title,
|
||
btn: [settings.confirmText, settings.cancelText],
|
||
skin: 'profile-layer-confirm'
|
||
}, function (index) {
|
||
settings.onConfirm();
|
||
layerApi.close(index);
|
||
}, function () {
|
||
settings.onCancel();
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (window.confirm(settings.content)) settings.onConfirm();
|
||
else settings.onCancel();
|
||
}
|
||
|
||
function confirmAction(content, options) {
|
||
var settings = typeof content === 'string'
|
||
? $.extend({}, options || {}, { content: content })
|
||
: $.extend({}, content || {});
|
||
|
||
return new Promise(function (resolve) {
|
||
settings.onConfirm = function () { resolve(true); };
|
||
settings.onCancel = function () { resolve(false); };
|
||
openConfirm(settings);
|
||
});
|
||
}
|
||
|
||
function initLayui() {
|
||
if (!window.layui || layuiReady) return;
|
||
|
||
layuiReady = true;
|
||
window.layui.use(['layer', 'form'], function () {
|
||
layerApi = window.layui.layer;
|
||
if (window.layui.form) window.layui.form.render();
|
||
});
|
||
}
|
||
|
||
function performLogout(targetUrl) {
|
||
var api = window.GenealogyApi && window.GenealogyApi.defaultClient;
|
||
var redirect = function () {
|
||
clearCurrentGenealogyContext();
|
||
window.location.href = targetUrl || 'index.html';
|
||
};
|
||
|
||
if (!api || !api.logout) {
|
||
redirect();
|
||
return;
|
||
}
|
||
|
||
api.logout().catch(function () {}).then(redirect);
|
||
}
|
||
|
||
function bindLogout() {
|
||
$(document).on('click', '[data-logout-open]', function (event) {
|
||
var targetUrl = $(this).attr('data-logout-url') || 'index.html';
|
||
|
||
event.preventDefault();
|
||
if (!layerApi) {
|
||
openLegacyLogout();
|
||
return;
|
||
}
|
||
|
||
openConfirm({
|
||
title: '退出登录',
|
||
content: '确认退出当前账号吗?退出后需要重新登录才能继续管理家谱。',
|
||
confirmText: '确认退出',
|
||
onConfirm: function () {
|
||
performLogout(targetUrl);
|
||
}
|
||
});
|
||
});
|
||
|
||
$(document).on('click', '[data-logout-confirm]', function (event) {
|
||
event.preventDefault();
|
||
closeLegacyLogout();
|
||
performLogout($(this).attr('href') || 'index.html');
|
||
});
|
||
|
||
$(document).on('click', '[data-logout-close]', function () {
|
||
closeLegacyLogout();
|
||
});
|
||
|
||
$(document).on('keydown', function (event) {
|
||
if (event.key === 'Escape') closeLegacyLogout();
|
||
});
|
||
}
|
||
|
||
function bindConfirmActions() {
|
||
$(document).on('click', '[data-layer-confirm]', function (event) {
|
||
var $item = $(this);
|
||
var href = $item.attr('href');
|
||
|
||
event.preventDefault();
|
||
openConfirm({
|
||
title: $item.attr('data-confirm-title') || '确认操作',
|
||
content: $item.attr('data-layer-confirm') || '确定继续吗?',
|
||
confirmText: $item.attr('data-confirm-text') || '确定',
|
||
onConfirm: function () {
|
||
if (href && href !== '#') window.location.href = href;
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
function normalizeGenealogyId(value) {
|
||
var text = String(value === undefined || value === null ? '' : value).trim();
|
||
|
||
return /^[1-9][0-9]*$/.test(text) ? text : '';
|
||
}
|
||
|
||
function getGenealogyId(search) {
|
||
var source = search === undefined ? (window.location && window.location.search) : search;
|
||
var params = new URLSearchParams(String(source || '').replace(/^\?/, ''));
|
||
|
||
return normalizeGenealogyId(params.get('genealogyId'));
|
||
}
|
||
|
||
function withGenealogyId(href, genealogyId) {
|
||
var value = String(href || '');
|
||
var hashIndex;
|
||
var hash = '';
|
||
var parts;
|
||
var params;
|
||
|
||
genealogyId = normalizeGenealogyId(genealogyId);
|
||
if (!genealogyId || !value || value.charAt(0) === '#' || /^(?:https?:|mailto:|tel:)/i.test(value)) return value;
|
||
hashIndex = value.indexOf('#');
|
||
if (hashIndex >= 0) {
|
||
hash = value.slice(hashIndex);
|
||
value = value.slice(0, hashIndex);
|
||
}
|
||
parts = value.split('?');
|
||
params = new URLSearchParams(parts[1] || '');
|
||
params.set('genealogyId', genealogyId);
|
||
return parts[0] + '?' + params.toString() + hash;
|
||
}
|
||
|
||
function getGenealogyEntryUrl(href) {
|
||
var value = String(href || '');
|
||
|
||
if (!value || value.charAt(0) === '#' || /^(?:https?:|mailto:|tel:)/i.test(value)) return value;
|
||
if (value.indexOf('profile-families.html') === 0) return value;
|
||
return 'profile-families.html?next=' + encodeURIComponent(value);
|
||
}
|
||
|
||
var genealogyContextPagePattern = /(?:^|\/)profile-(?:admin-permissions|album(?:-detail|-edit)?|article(?:-edit)?|ceremony(?:-detail)?|content|family-admin|family-home|feed(?:-detail|-edit)?|generation|gift(?:-edit)?|growth(?:-edit)?|join-review|memo(?:-edit)?|merit(?:-edit)?|relative(?:-edit)?|tree|video(?:-edit)?)\.html(?:[?#]|$)/;
|
||
|
||
function isGenealogyContextHref(href) {
|
||
var value = String(href || '');
|
||
|
||
return !/^(?:https?:|mailto:|tel:)/i.test(value) && genealogyContextPagePattern.test(value);
|
||
}
|
||
|
||
function syncGenealogyContextLinks() {
|
||
var context = getCurrentGenealogyContext();
|
||
var genealogyId = getGenealogyId() || (context && context.genealogyId);
|
||
|
||
$('[data-genealogy-context-link], a[href]').filter(function () {
|
||
var $link = $(this);
|
||
|
||
return $link.is('[data-genealogy-context-link]') || isGenealogyContextHref($link.attr('href'));
|
||
}).each(function () {
|
||
var $link = $(this);
|
||
|
||
$link.attr('href', genealogyId ? withGenealogyId($link.attr('href'), genealogyId) : getGenealogyEntryUrl($link.attr('href')));
|
||
});
|
||
}
|
||
|
||
function renderCurrentGenealogyContext() {
|
||
var context = getCurrentGenealogyContext();
|
||
var name = context ? context.genealogyName : '正在识别家谱';
|
||
|
||
$('[data-current-genealogy-name]').text(name);
|
||
$('[data-current-genealogy-link]').attr('aria-label', context ?
|
||
'当前家谱:' + context.genealogyName + ',点击切换家谱' :
|
||
'当前家谱,点击切换家谱');
|
||
}
|
||
|
||
function refreshCurrentGenealogyContext() {
|
||
var genealogyId = getGenealogyId();
|
||
var api = window.GenealogyApi && window.GenealogyApi.defaultClient;
|
||
|
||
if (!genealogyId || getCurrentGenealogyContext() || !api || !api.genealogyDetail) return;
|
||
api.genealogyDetail(genealogyId).then(function (detail) {
|
||
var detailId = normalizeGenealogyId(detail && detail.genealogyId);
|
||
var detailName = normalizeGenealogyName(detail && detail.genealogyName);
|
||
|
||
if (detailId === genealogyId && detailName) {
|
||
setCurrentGenealogyContext(detailId, detailName);
|
||
}
|
||
}).catch(function () {
|
||
$('[data-current-genealogy-name]').text('当前家谱');
|
||
});
|
||
}
|
||
|
||
function initCurrentGenealogyContext() {
|
||
var context = getCurrentGenealogyContext();
|
||
var genealogyId = getGenealogyId() || (context && context.genealogyId);
|
||
var $nav;
|
||
var $actions;
|
||
var $context;
|
||
|
||
if (!genealogyId) return;
|
||
$nav = $('.site-header .nav').first();
|
||
if (!$nav.length || $nav.find('[data-current-genealogy-link]').length) return;
|
||
$context = $('<a class="profile-current-genealogy" data-current-genealogy-link href="profile-families.html">' +
|
||
'<span>当前家谱</span><strong data-current-genealogy-name>正在识别家谱</strong></a>');
|
||
$actions = $nav.find('.nav-actions').first();
|
||
if ($actions.length) $context.insertBefore($actions);
|
||
else $nav.append($context);
|
||
renderCurrentGenealogyContext();
|
||
refreshCurrentGenealogyContext();
|
||
}
|
||
|
||
function getCurrentPageName() {
|
||
return (window.location.pathname.split('/').pop() || 'profile.html').split('?')[0];
|
||
}
|
||
|
||
function isWorkspaceItemCurrent(item, currentPage) {
|
||
return item.href === currentPage || (Array.isArray(item.pages) && item.pages.indexOf(currentPage) >= 0);
|
||
}
|
||
|
||
function renderWorkspaceLink(item, currentPage) {
|
||
var isCurrent = isWorkspaceItemCurrent(item, currentPage);
|
||
|
||
return '<a' + (isCurrent ? ' class="active" aria-current="page"' : '') +
|
||
' href="' + escapeHtml(item.href) + '"' + (item.context ? ' data-genealogy-context-link' : '') + '>' +
|
||
escapeHtml(item.label) + '</a>';
|
||
}
|
||
|
||
function renderWorkspaceNavigation(items, currentPage) {
|
||
return items.map(function (item) {
|
||
var isOpen;
|
||
|
||
if (!item.items) return renderWorkspaceLink(item, currentPage);
|
||
isOpen = item.items.some(function (child) { return isWorkspaceItemCurrent(child, currentPage); });
|
||
return '<details class="workspace-nav-group' + (isOpen ? ' is-open' : '') +
|
||
'" data-workspace-nav-group' + (isOpen ? ' open' : '') + '>' +
|
||
'<summary>' + escapeHtml(item.label) + '</summary>' +
|
||
'<div class="workspace-nav-items">' + item.items.map(function (child) {
|
||
return renderWorkspaceLink(child, currentPage);
|
||
}).join('') + '</div></details>';
|
||
}).join('');
|
||
}
|
||
|
||
function getHeaderSection(currentPage) {
|
||
if (['profile-families.html', 'profile-create-family.html', 'join-genealogy.html', 'profile-join-family.html', 'profile-family-home.html'].indexOf(currentPage) >= 0) {
|
||
return 'profile-families.html';
|
||
}
|
||
if ([
|
||
'profile-tree.html', 'profile-generation.html', 'profile-family-admin.html',
|
||
'profile-admin-permissions.html', 'profile-join-review.html', 'profile-invite.html',
|
||
'profile-data-reminders.html', 'profile-documents.html', 'profile-family-settings.html'
|
||
].indexOf(currentPage) >= 0) return 'profile-family-admin.html';
|
||
if (familyWorkspacePages.indexOf(currentPage) >= 0) return 'profile-content.html';
|
||
if (['profile-data.html', 'profile-security.html'].indexOf(currentPage) >= 0) return 'profile-data.html';
|
||
if (['profile-services.html', 'profile-feedback.html', 'my-tickets.html', 'submit-ticket.html', 'ticket-detail.html', 'profile-earnings.html', 'profile-share.html'].indexOf(currentPage) >= 0) {
|
||
return 'profile-services.html';
|
||
}
|
||
return '';
|
||
}
|
||
|
||
function renderHeaderLink(item, currentSection) {
|
||
var isCurrent = item.href === currentSection;
|
||
|
||
return '<a' + (isCurrent ? ' class="active" aria-current="page"' : '') +
|
||
' href="' + escapeHtml(item.href) + '"' + (item.context ? ' data-genealogy-context-link' : '') + '>' +
|
||
escapeHtml(item.label) + '</a>';
|
||
}
|
||
|
||
function initWorkspaceNavigation() {
|
||
var currentPage = getCurrentPageName();
|
||
var isFamilyWorkspace = familyWorkspacePages.indexOf(currentPage) >= 0;
|
||
var navigation = isFamilyWorkspace ? familyWorkspaceNavigation : accountWorkspaceNavigation;
|
||
var $sidebar = $('.module-nav').first();
|
||
var $header = $('.site-header').first();
|
||
var headerItems = [
|
||
{ label: '我的家谱', href: 'profile-families.html' },
|
||
{ label: '家族管理', href: 'profile-family-admin.html', context: true },
|
||
{ label: '内容发布', href: 'profile-content.html', context: true },
|
||
{ label: '个人资料', href: 'profile-data.html' },
|
||
{ label: '帮助与服务', href: 'profile-services.html' }
|
||
];
|
||
var currentSection = getHeaderSection(currentPage);
|
||
|
||
if ($header.length) {
|
||
$header.find('.brand').first().attr('href', 'profile.html').html(
|
||
'<img class="brand-logo brand-logo-mark" src="public/images/logo-mark.png" alt="" />' +
|
||
'<span class="brand-text">个人中心</span>'
|
||
);
|
||
$header.find('.nav-links').first().attr('aria-label', '个人中心主导航').html(headerItems.map(function (item) {
|
||
return renderHeaderLink(item, currentSection);
|
||
}).join(''));
|
||
}
|
||
if (!$sidebar.length) return;
|
||
$sidebar
|
||
.attr('aria-label', isFamilyWorkspace ? '当前家谱功能导航' : '个人中心功能导航')
|
||
.attr('data-workspace-navigation', isFamilyWorkspace ? 'family' : 'account')
|
||
.html(renderWorkspaceNavigation(navigation, currentPage));
|
||
$('body').addClass('has-workspace-navigation');
|
||
}
|
||
|
||
function setMobileMenuOpen(isOpen) {
|
||
var $menu = $('[data-profile-mobile-menu]').first();
|
||
var $toggle = $('[data-profile-mobile-menu-toggle]').first();
|
||
|
||
if (!$menu.length || !$toggle.length) return;
|
||
$menu.prop('hidden', !isOpen).toggleClass('is-open', !!isOpen).attr('aria-hidden', isOpen ? 'false' : 'true');
|
||
$toggle.attr('aria-expanded', isOpen ? 'true' : 'false');
|
||
}
|
||
|
||
function initMobileMenu() {
|
||
var $header = $('.site-header').first();
|
||
var $nav;
|
||
var currentPage;
|
||
var isFamilyWorkspace;
|
||
var navigation;
|
||
var workspaceLabel;
|
||
|
||
if (!$('body').is('.page-profile, .page-profile-module')) return;
|
||
if (!$header.length || $header.find('[data-profile-mobile-menu]').length) return;
|
||
$nav = $header.find('.nav').first();
|
||
if (!$nav.length) return;
|
||
$nav.append('<button class="profile-mobile-menu-toggle" type="button" data-profile-mobile-menu-toggle ' +
|
||
'aria-expanded="false" aria-controls="' + mobileMenuId + '">菜单</button>');
|
||
currentPage = getCurrentPageName();
|
||
isFamilyWorkspace = familyWorkspacePages.indexOf(currentPage) >= 0;
|
||
navigation = isFamilyWorkspace ? familyWorkspaceNavigation : accountWorkspaceNavigation;
|
||
workspaceLabel = isFamilyWorkspace ? '当前家谱功能导航' : '个人中心功能导航';
|
||
$header.append('<div class="profile-mobile-menu" id="' + mobileMenuId + '" data-profile-mobile-menu hidden aria-hidden="true">' +
|
||
'<div class="container profile-mobile-menu-inner">' +
|
||
'<nav class="profile-mobile-workspace" aria-label="' + workspaceLabel + '">' +
|
||
renderWorkspaceNavigation(navigation, currentPage) + '</nav>' +
|
||
'<div class="profile-mobile-account-actions">' +
|
||
(isFamilyWorkspace ? '<a href="profile-families.html">切换家谱</a>' : '') +
|
||
'<button type="button" data-logout-open data-logout-url="index.html">退出登录</button></div>' +
|
||
'</div></div>');
|
||
$header.find('[data-profile-mobile-menu] a').each(function () {
|
||
var $link = $(this);
|
||
var target = ($link.attr('href') || '').split('?')[0];
|
||
|
||
if (target === currentPage) $link.addClass('is-current').attr('aria-current', 'page');
|
||
});
|
||
}
|
||
|
||
function bindGenealogySelection() {
|
||
$(document).on('click', '[data-genealogy-id][data-genealogy-name]', function () {
|
||
setCurrentGenealogyContext($(this).attr('data-genealogy-id'), $(this).attr('data-genealogy-name'));
|
||
});
|
||
}
|
||
|
||
function bindMobileMenu() {
|
||
$(document).on('click', '[data-profile-mobile-menu-toggle]', function () {
|
||
setMobileMenuOpen($(this).attr('aria-expanded') !== 'true');
|
||
});
|
||
$(document).on('click', '[data-profile-mobile-menu] a, [data-profile-mobile-menu] button', function () {
|
||
setMobileMenuOpen(false);
|
||
});
|
||
$(document).on('click', function (event) {
|
||
if (!$(event.target).closest('.site-header').length) setMobileMenuOpen(false);
|
||
});
|
||
$(document).on('keydown', function (event) {
|
||
var $menu;
|
||
|
||
if (event.key !== 'Escape') return;
|
||
$menu = $('[data-profile-mobile-menu]').first();
|
||
if (!$menu.length || $menu.prop('hidden')) return;
|
||
setMobileMenuOpen(false);
|
||
$('[data-profile-mobile-menu-toggle]').first().trigger('focus');
|
||
});
|
||
}
|
||
|
||
function updateDisplay($trigger, value) {
|
||
var target = $trigger.attr('data-update-target');
|
||
var $target = target ? $(target) : $trigger.closest('p').find('b').first();
|
||
var $title;
|
||
|
||
if (!value) return;
|
||
if ($target.length) {
|
||
$target.text(value);
|
||
return;
|
||
}
|
||
|
||
$title = $trigger.closest('.module-row').find('h3').first();
|
||
if ($title.length) {
|
||
$title.text($title.text().replace(/([::]).*$/, '$1' + value));
|
||
}
|
||
}
|
||
|
||
function promptAction(options) {
|
||
var settings = $.extend({
|
||
title: '填写内容',
|
||
value: '',
|
||
formType: 1,
|
||
maxlength: 200
|
||
}, options || {});
|
||
|
||
return new Promise(function (resolve) {
|
||
if (!layerApi) {
|
||
resolve(window.prompt(settings.title, settings.value) || null);
|
||
return;
|
||
}
|
||
|
||
layerApi.prompt({
|
||
title: settings.title,
|
||
value: settings.value,
|
||
formType: settings.formType,
|
||
maxlength: settings.maxlength,
|
||
cancel: function () { resolve(null); }
|
||
}, function (value, index) {
|
||
resolve(value);
|
||
layerApi.close(index);
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindPromptActions() {
|
||
$(document).on('click', '[data-layer-prompt]', function (event) {
|
||
var $item = $(this);
|
||
var title = $item.attr('data-prompt-title') || $item.text() || '填写内容';
|
||
var placeholder = $item.attr('data-layer-prompt') || '';
|
||
var formType = $item.attr('data-prompt-type') === 'textarea' ? 2 : 0;
|
||
|
||
event.preventDefault();
|
||
if (!layerApi) {
|
||
var fallbackValue = window.prompt(placeholder || title, '');
|
||
if (fallbackValue) updateDisplay($item, fallbackValue);
|
||
return;
|
||
}
|
||
|
||
layerApi.prompt({
|
||
title: title,
|
||
value: $item.attr('data-prompt-value') || '',
|
||
formType: formType,
|
||
maxlength: Number($item.attr('data-prompt-maxlength')) || 200
|
||
}, function (value, index) {
|
||
updateDisplay($item, value);
|
||
layerApi.close(index);
|
||
layerApi.msg('已更新');
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindSelectActions() {
|
||
$(document).on('click', '[data-layer-select]', function (event) {
|
||
var $item = $(this);
|
||
var values = ($item.attr('data-layer-select') || '').split('|').filter(Boolean);
|
||
var title = $item.attr('data-select-title') || '请选择';
|
||
var html = '<div class="profile-popup-select">';
|
||
|
||
event.preventDefault();
|
||
if (!values.length) return;
|
||
|
||
$.each(values, function (_, value) {
|
||
html += '<button type="button" data-popup-value="' + value + '">' + value + '</button>';
|
||
});
|
||
html += '</div>';
|
||
|
||
if (!layerApi) {
|
||
updateDisplay($item, values[0]);
|
||
return;
|
||
}
|
||
|
||
layerApi.open({
|
||
title: title,
|
||
content: html,
|
||
area: ['360px', 'auto'],
|
||
skin: 'profile-layer-confirm',
|
||
success: function (layero, index) {
|
||
layero.find('[data-popup-value]').on('click', function () {
|
||
updateDisplay($item, $(this).attr('data-popup-value'));
|
||
layerApi.close(index);
|
||
layerApi.msg('已选择');
|
||
});
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindMessageActions() {
|
||
$(document).on('click', '[data-layer-msg]', function (event) {
|
||
event.preventDefault();
|
||
if (layerApi) layerApi.msg($(this).attr('data-layer-msg'));
|
||
});
|
||
}
|
||
|
||
function bindSelectableCards() {
|
||
$(document).on('click', '[data-select-card]', function () {
|
||
var $card = $(this);
|
||
var group = $card.attr('data-select-card');
|
||
|
||
if (group) $('[data-select-card="' + group + '"]').removeClass('is-selected');
|
||
$card.addClass('is-selected');
|
||
});
|
||
}
|
||
|
||
$(function () {
|
||
initLayui();
|
||
initWorkspaceNavigation();
|
||
bindLogout();
|
||
bindConfirmActions();
|
||
bindPromptActions();
|
||
bindSelectActions();
|
||
bindMessageActions();
|
||
bindSelectableCards();
|
||
bindGenealogySelection();
|
||
bindMobileMenu();
|
||
initCurrentGenealogyContext();
|
||
initMobileMenu();
|
||
syncGenealogyContextLinks();
|
||
});
|
||
|
||
Object.assign(profileUI, {
|
||
confirm: openConfirm,
|
||
confirmAction: confirmAction,
|
||
promptAction: promptAction,
|
||
closeLogout: closeLegacyLogout,
|
||
initLayui: initLayui,
|
||
getGenealogyId: getGenealogyId,
|
||
normalizeGenealogyId: normalizeGenealogyId,
|
||
withGenealogyId: withGenealogyId,
|
||
getGenealogyEntryUrl: getGenealogyEntryUrl,
|
||
isGenealogyContextHref: isGenealogyContextHref,
|
||
getCurrentGenealogyContext: getCurrentGenealogyContext,
|
||
setCurrentGenealogyContext: setCurrentGenealogyContext,
|
||
clearCurrentGenealogyContext: clearCurrentGenealogyContext,
|
||
refreshCurrentGenealogyContext: refreshCurrentGenealogyContext,
|
||
syncGenealogyContextLinks: syncGenealogyContextLinks,
|
||
renderApiState: renderApiState,
|
||
setApiState: setApiState,
|
||
revealDetail: revealDetail
|
||
});
|
||
})(window, window.jQuery || (window.layui && window.layui.$));
|