(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, '''); } 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 '
' + escapeHtml(message) + '
'; } 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(); if (window.PublicNavigation) window.PublicNavigation.clearUser(); window.NavigationUtil.open(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.NavigationUtil.open(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 = $('' + '当前家谱正在识别家谱'); $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 '' + escapeHtml(item.label) + ''; } 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 '
' + '' + escapeHtml(item.label) + '' + '
' + item.items.map(function (child) { return renderWorkspaceLink(child, currentPage); }).join('') + '
'; }).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 '' + escapeHtml(item.label) + ''; } 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: 'index.html' }, { 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', 'index.html').html( '' + '个人中心' ); $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(''); currentPage = getCurrentPageName(); isFamilyWorkspace = familyWorkspacePages.indexOf(currentPage) >= 0; navigation = isFamilyWorkspace ? familyWorkspaceNavigation : accountWorkspaceNavigation; workspaceLabel = isFamilyWorkspace ? '当前家谱功能导航' : '个人中心功能导航'; $header.append(''); $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 = '
'; event.preventDefault(); if (!values.length) return; $.each(values, function (_, value) { html += ''; }); html += '
'; 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.$));