Files
jiapu/public/js/generation-pages.js
T
2026-08-29 19:06:07 +08:00

786 lines
28 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(function (root, factory) {
// 字辈管理模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.GenerationPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.GenerationPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
function confirmAction(message) {
if (root.ProfileUI && typeof root.ProfileUI.confirmAction === 'function') {
return root.ProfileUI.confirmAction(message);
}
return Promise.resolve(!root['confirm'] || root['confirm'](message));
}
var documentRef = root.document;
var poemsById = Object.create(null);
var lastPreviewSignature = '';
var managementAccess = false;
var writePending = false;
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function shouldRedirectToLogin(api, error) {
var status = error && (error.status || error.code);
return !api || !api.getToken || !api.getToken() || Number(status) === 401;
}
function isForbidden(error) {
return Number(error && (error.status || error.code)) === 403;
}
function redirectUnauthorized(api, error) {
if (!shouldRedirectToLogin(api, error)) return false;
if (api && api.clearToken) api.clearToken();
if (!root.location) return true;
if (typeof root.location.replace === 'function') {
root.location.replace('login.html');
return true;
}
root.location.href = 'login.html';
return true;
}
function query(selector, rootNode) {
return documentRef ? (rootNode || documentRef).querySelector(selector) : null;
}
function queryAll(selector, rootNode) {
return documentRef ? Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector)) : [];
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
if (root.alert) root.alert(message);
}
function setGenerationState(selector, type, message) {
var target = query(selector);
if (!target) return;
if (root.ProfileUI && root.ProfileUI.setApiState) {
root.ProfileUI.setApiState(target, type, message);
return;
}
target.innerHTML = '<div class="api-state api-state--' + escapeHtml(type) + '" data-api-state="' + escapeHtml(type) + '">' +
escapeHtml(message) + '</div>';
}
function setGenerationFormStatus(message, type) {
var target = query('[data-generation-form-status]');
if (!target) return;
if (!message) {
target.innerHTML = '';
return;
}
if (root.ProfileUI && root.ProfileUI.setApiState) {
root.ProfileUI.setApiState(target, type || 'error', message);
return;
}
target.textContent = message;
}
function getQueryParam(search, name) {
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
return params.get(name) || '';
}
function getCurrentGenealogyId(search) {
var page = query('[data-generation-page]');
var source = search === undefined && root.location ? root.location.search : search;
var profileGenealogyId;
if (search === undefined && root.ProfileUI && root.ProfileUI.getGenealogyId) {
profileGenealogyId = root.ProfileUI.getGenealogyId();
if (profileGenealogyId) return profileGenealogyId;
}
return getQueryParam(source, 'genealogyId') || (page && page.getAttribute('data-genealogy-id')) || '';
}
function trimOrUndefined(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
return text || undefined;
}
function toIntegerOrUndefined(value) {
var text = trimOrUndefined(value);
var number;
if (!text) return undefined;
number = Number(text);
return Number.isInteger(number) && Number.isSafeInteger(number) ? number : undefined;
}
function buildGenerationPoemBody(values) {
var source = values || {};
var body = {
generationNo: toIntegerOrUndefined(source.generationNo),
generationText: trimOrUndefined(source.generationText)
};
var description = trimOrUndefined(source.description);
var sortOrder = trimOrUndefined(source.sortOrder);
var status = trimOrUndefined(source.status);
if (description !== undefined) body.description = description;
if (sortOrder !== undefined) body.sortOrder = Number(sortOrder);
if (status !== undefined) body.status = status;
return body;
}
function buildBatchBody(values) {
var source = values || {};
return {
poemText: String(source.poemText || '').trim(),
disableMissing: Boolean(source.disableMissing)
};
}
function validateGenerationPoemBody(body) {
if (!body || !Number.isInteger(body.generationNo) || body.generationNo < 1 || body.generationNo > 2147483647) {
return '世代序号必须是 1 到 2147483647 之间的整数';
}
if (!body.generationText) return '请填写字辈文字';
if (body.generationText.length > 50) return '字辈文字不能超过 50 个字符';
if (body.description && body.description.length > 500) return '说明不能超过 500 个字符';
if (body.sortOrder !== undefined && (!Number.isInteger(body.sortOrder) || !Number.isSafeInteger(body.sortOrder))) {
return '排序值必须是整数';
}
if (body.sortOrder !== undefined && (body.sortOrder < -2147483648 || body.sortOrder > 2147483647)) {
return '排序值必须在 -2147483648 到 2147483647 之间';
}
if (body.status !== undefined && body.status !== '0' && body.status !== '1') return '字辈状态只能是 0 或 1';
return '';
}
function validateBatchBody(body) {
var words;
if (!body || !body.poemText) return '请填写批量字辈内容';
if (body.poemText.length > 26000) return '批量字辈内容不能超过 26000 个字符';
words = splitPoemText(body.poemText);
if (words.length > 500) return '一次最多导入 500 个世代';
if (words.some(function (word) { return word.length > 50; })) return '单个字辈不能超过 50 个字符';
return '';
}
function splitPoemText(value) {
var text = String(value || '').trim();
if (!text) return [];
if (/[\s,;;、/|]/.test(text)) {
return text.split(/[\s,;;、/|]+/).filter(Boolean);
}
return Array.from(text);
}
function normalizeId(value) {
var text;
if (value === undefined || value === null || value === '') return '';
if (typeof value === 'number' && !Number.isSafeInteger(value)) return '';
text = String(value);
return /^\d+$/.test(text) ? text : '';
}
function getPoemId(item) {
return normalizeId(item && item.poemId);
}
function normalizeGenerationPoem(item) {
var poemId = getPoemId(item);
var genealogyId = normalizeId(item && item.genealogyId);
var generationNo = toIntegerOrUndefined(item && item.generationNo);
var generationText = trimOrUndefined(item && item.generationText);
var status = trimOrUndefined(item && item.status);
var poem;
if (!poemId || generationNo === undefined || !generationText || (status !== '0' && status !== '1')) return null;
poem = {
poemId: poemId,
generationNo: generationNo,
generationText: generationText,
status: status
};
if (genealogyId) poem.genealogyId = genealogyId;
if (item.genealogyNo !== undefined && item.genealogyNo !== null) poem.genealogyNo = String(item.genealogyNo);
if (item.genealogyName !== undefined && item.genealogyName !== null) poem.genealogyName = String(item.genealogyName);
if (item.description !== undefined && item.description !== null) poem.description = String(item.description);
if (toIntegerOrUndefined(item.sortOrder) !== undefined) poem.sortOrder = toIntegerOrUndefined(item.sortOrder);
if (item.remark !== undefined && item.remark !== null) poem.remark = String(item.remark);
return poem;
}
function canEditGenerations(genealogy) {
return Boolean(genealogy && (genealogy.canEditContent === true || genealogy.canManage === true));
}
function normalizeGenerationAccess(genealogy) {
var canEditContent = canEditGenerations(genealogy);
return {
canEditContent: canEditContent,
listMethod: canEditContent ? 'generationPoemsManagement' : 'generationPoems'
};
}
function normalizeList(data) {
if (Array.isArray(data)) return data;
if (data && Array.isArray(data.rows)) return data.rows;
return [];
}
function escapeHtml(value) {
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function renderGenerationPoem(poem) {
var details = [];
var stateText = poem.status === '1' ? '已停用' : '正常';
var actions = '';
if (poem.description) details.push('说明:' + poem.description);
if (poem.sortOrder !== undefined) details.push('排序:' + poem.sortOrder);
details.push('状态:' + stateText);
if (managementAccess) {
actions = '<div class="row-actions">' +
'<button class="pill" type="button" data-generation-edit="' + escapeHtml(poem.poemId) + '">编辑</button>' +
'<button class="pill" type="button" data-generation-status="' + escapeHtml(poem.poemId) + '">' + (poem.status === '1' ? '恢复' : '停用') + '</button>' +
'</div>';
}
return '<div class="module-row" data-generation-poem-id="' + escapeHtml(poem.poemId) + '">' +
'<div><h3>第 ' + escapeHtml(poem.generationNo) + ' 代:' + escapeHtml(poem.generationText) + '</h3><p>' + escapeHtml(details.join(' · ')) + '</p></div>' +
actions + '</div>';
}
function renderGenerationPoems(data) {
var container = query('[data-generation-list]');
var normalized = normalizeList(data).map(normalizeGenerationPoem);
var invalidCount = normalized.filter(function (item) { return !item; }).length;
var poems = normalized.filter(Boolean);
poemsById = Object.create(null);
poems.forEach(function (poem) {
poemsById[poem.poemId] = poem;
});
if (!container) return;
if (invalidCount) {
setGenerationState('[data-generation-list]', 'error', '字辈响应缺少 poemId、generationNo、generationText 或 status,请联系后端补充 DTO。');
return;
}
if (!poems.length) {
setGenerationState('[data-generation-list]', 'empty', '暂无字辈记录');
return;
}
container.innerHTML = poems.map(renderGenerationPoem).join('');
}
function normalizeCount(value) {
var count = toIntegerOrUndefined(value);
return count !== undefined && count >= 0 ? count : undefined;
}
function normalizePreviewItem(item) {
var action = item && item.action;
var generationNo = toIntegerOrUndefined(item && item.generationNo);
var poemId = getPoemId(item);
var oldText = trimOrUndefined(item && item.oldGenerationText);
var newText = trimOrUndefined(item && item.newGenerationText);
var oldStatus = trimOrUndefined(item && item.oldStatus);
var newStatus = trimOrUndefined(item && item.newStatus);
var normalized;
if (!generationNo || ['create', 'update', 'keep', 'disable'].indexOf(action) === -1) return null;
if (newStatus !== '0' && newStatus !== '1') return null;
if (action === 'create' && !newText) return null;
if (action !== 'create' && (!poemId || !oldText || (oldStatus !== '0' && oldStatus !== '1'))) return null;
if ((action === 'update' || action === 'keep') && !newText) return null;
normalized = {
generationNo: generationNo
};
if (poemId) normalized.poemId = poemId;
if (oldText) normalized.oldGenerationText = oldText;
if (newText) normalized.newGenerationText = newText;
if (oldStatus !== undefined) normalized.oldStatus = oldStatus;
normalized.newStatus = newStatus;
normalized.action = action;
if (item.warning !== undefined && item.warning !== null) normalized.warning = String(item.warning);
return normalized;
}
function normalizePreview(data) {
var counts;
var items;
var actualCounts = { create: 0, update: 0, keep: 0, disable: 0 };
if (!data || !Array.isArray(data.items) || !data.items.length) return null;
counts = {
createCount: normalizeCount(data.createCount),
updateCount: normalizeCount(data.updateCount),
keepCount: normalizeCount(data.keepCount),
disableCount: normalizeCount(data.disableCount)
};
if (Object.keys(counts).some(function (key) { return counts[key] === undefined; })) return null;
items = data.items.map(normalizePreviewItem);
if (items.some(function (item) { return !item; })) return null;
items.forEach(function (item) { actualCounts[item.action] += 1; });
if (counts.createCount !== actualCounts.create ||
counts.updateCount !== actualCounts.update ||
counts.keepCount !== actualCounts.keep ||
counts.disableCount !== actualCounts.disable) return null;
counts.items = items;
return counts;
}
function buildBatchConfirmMessage(disableMissing) {
if (disableMissing) {
return '确认按当前预览保存字辈,并停用未出现在文本中的后续世代吗?历史记录不会删除。';
}
return '确认按当前预览保存字辈吗?';
}
function renderBatchPreview(data) {
var container = query('[data-generation-batch-preview]');
var preview = normalizePreview(data);
var summary;
if (!container) return false;
if (!preview) {
setGenerationState('[data-generation-batch-preview]', 'error', '批量预览响应缺少 items,请联系后端补充 DTO。');
return false;
}
summary = '新增 ' + (preview.createCount === undefined ? '-' : preview.createCount) +
' 条 · 更新 ' + (preview.updateCount === undefined ? '-' : preview.updateCount) +
' 条 · 保留 ' + (preview.keepCount === undefined ? '-' : preview.keepCount) +
' 条 · 停用 ' + (preview.disableCount === undefined ? '-' : preview.disableCount) + ' 条';
container.innerHTML = '<div class="module-row"><div><h3>变更预览</h3><p>' + escapeHtml(summary) + '</p></div></div>' +
preview.items.map(function (item) {
var generationNo = item && item.generationNo;
var action = item && item.action;
var oldText = item && item.oldGenerationText;
var newText = item && item.newGenerationText;
var warning = item && item.warning;
var oldStatus = item && item.oldStatus;
var newStatus = item && item.newStatus;
var text = '第 ' + (generationNo === undefined || generationNo === null ? '-' : generationNo) + ' 代:' +
(oldText === undefined || oldText === null ? '(新增)' : oldText) + ' → ' +
(newText === undefined || newText === null ? '(无)' : newText);
if (action) text += ' · ' + action;
if (oldStatus !== undefined || newStatus !== undefined) {
text += ' · 状态:' + formatStatus(oldStatus) + ' → ' + formatStatus(newStatus);
}
if (warning) text += ' · 警告:' + warning;
return '<div class="module-row"><p>' + escapeHtml(text) + '</p></div>';
}).join('');
return true;
}
function formatStatus(value) {
if (String(value) === '0') return '正常';
if (String(value) === '1') return '停用';
return value === undefined || value === null ? '未提供' : String(value);
}
function getFormValues(form) {
var values = {};
queryAll('[name]', form).forEach(function (field) {
values[field.name] = field.type === 'checkbox' ? field.checked : field.value;
});
return values;
}
function setBatchStatus(message) {
var target = query('[data-generation-batch-status]');
if (target) target.textContent = message || '';
}
function setGenerationEditorVisible(visible) {
var editor = query('[data-generation-editor]');
if (editor) editor.hidden = !visible;
}
function setGenerationSubmitPending(pending) {
queryAll('[data-generation-editor-submit]').forEach(function (button) {
if (!button.dataset.defaultLabel) button.dataset.defaultLabel = button.textContent;
button.disabled = Boolean(pending) || !managementAccess;
button.textContent = pending ? '正在保存…' : button.dataset.defaultLabel;
button.setAttribute('aria-busy', pending ? 'true' : 'false');
});
}
function refreshManagementControls() {
var disabled = !managementAccess || writePending;
queryAll('[data-generation-management]').forEach(function (element) {
element.hidden = !managementAccess;
});
if (!managementAccess) setGenerationEditorVisible(false);
queryAll('[data-generation-add], [data-generation-batch-action], [data-generation-edit], [data-generation-status]').forEach(function (control) {
control.disabled = disabled;
});
queryAll('[data-generation-management] textarea, [data-generation-management] input, [data-generation-editor] textarea, [data-generation-editor] input, [data-generation-editor] select, [data-generation-editor] button').forEach(function (control) {
control.disabled = disabled;
});
setGenerationSubmitPending(writePending);
}
function setManagementEnabled(enabled) {
managementAccess = Boolean(enabled);
refreshManagementControls();
}
function setWritePending(pending) {
writePending = Boolean(pending);
refreshManagementControls();
}
function renderForbiddenState() {
setGenerationState('[data-generation-list]', 'forbidden', '当前账号没有字辈维护权限');
lastPreviewSignature = '';
setManagementEnabled(false);
setBatchStatus('当前账号没有字辈维护权限');
setGenerationFormStatus('当前账号没有字辈维护权限', 'forbidden');
}
function syncGenealogyLinks(genealogyId) {
if (root.ProfileUI && root.ProfileUI.syncGenealogyContextLinks) {
root.ProfileUI.syncGenealogyContextLinks();
return;
}
queryAll('[data-genealogy-context-link]').forEach(function (link) {
var href = link.getAttribute('href');
var base;
if (!href || href === '#') return;
base = href.split('?')[0];
link.href = base + '?genealogyId=' + encodeURIComponent(genealogyId);
});
}
function requireGenealogyId() {
var genealogyId = getCurrentGenealogyId();
var container;
if (!genealogyId) {
container = query('[data-generation-list]');
if (container) setGenerationState('[data-generation-list]', 'error', '请从具体家谱进入字辈管理');
setGenerationEditorVisible(false);
setGenerationFormStatus('请从具体家谱进入字辈管理', 'error');
showMessage('请从具体家谱进入字辈管理');
}
return genealogyId;
}
function openPoemEditor(poemId) {
var form = query('[data-generation-form]');
var existing = poemId ? poemsById[poemId] : null;
var title = query('[data-generation-editor-title]');
if (!managementAccess || writePending || !form || (poemId && !existing)) return;
form.reset();
queryAll('[name]', form).forEach(function (field) {
var value;
if (field.name === 'poemId') value = poemId || '';
if (field.name === 'generationNo') value = existing ? existing.generationNo : '';
if (field.name === 'generationText') value = existing ? existing.generationText : '';
if (field.name === 'description') value = existing && existing.description ? existing.description : '';
if (field.name === 'sortOrder') value = existing && existing.sortOrder !== undefined ? existing.sortOrder : '';
if (field.name === 'status') value = existing ? existing.status : '';
if (value !== undefined) field.value = value;
});
if (title) title.textContent = existing ? '编辑字辈' : '新增字辈';
setGenerationFormStatus('');
setGenerationEditorVisible(true);
if (root.location && root.location.hash !== '#generation-editor') root.location.hash = 'generation-editor';
if (query('[name="generationNo"]', form) && query('[name="generationNo"]', form).focus) {
query('[name="generationNo"]', form).focus();
}
}
function closePoemEditor() {
var form = query('[data-generation-form]');
if (form) form.reset();
setGenerationFormStatus('');
setGenerationEditorVisible(false);
}
async function loadGenerationPoems() {
var api = getApi();
var genealogyId;
var access;
if (redirectUnauthorized(api)) return;
genealogyId = requireGenealogyId();
if (!genealogyId) return;
syncGenealogyLinks(genealogyId);
setGenerationState('[data-generation-list]', 'loading', '正在加载字辈记录…');
try {
access = normalizeGenerationAccess(await api.genealogyDetail(genealogyId));
setManagementEnabled(access.canEditContent);
renderGenerationPoems(await api[access.listMethod](genealogyId));
} catch (error) {
if (redirectUnauthorized(api, error)) return;
if (isForbidden(error)) {
renderForbiddenState();
return;
}
setGenerationState('[data-generation-list]', 'error', '字辈列表加载失败,请稍后重试。');
showMessage(error.message || '字辈列表加载失败');
}
}
async function submitPoem(form) {
var api = getApi();
var genealogyId;
var poemId;
var body;
var validation;
if (writePending || !managementAccess || redirectUnauthorized(api) || !form) return;
genealogyId = requireGenealogyId();
if (!genealogyId) return;
poemId = normalizeId(getFormValues(form).poemId);
if (getFormValues(form).poemId && !poemId) {
setGenerationFormStatus('字辈编号无效,请返回列表重新编辑。', 'error');
return;
}
if (poemId && !poemsById[poemId]) {
setGenerationFormStatus('当前字辈不存在或已更新,请返回列表刷新后重试。', 'error');
return;
}
body = buildGenerationPoemBody(getFormValues(form));
validation = validateGenerationPoemBody(body);
if (validation) {
setGenerationFormStatus(validation, 'error');
return;
}
setGenerationFormStatus('正在保存字辈…', 'loading');
setWritePending(true);
try {
if (poemId) {
await api.updateGenerationPoem(genealogyId, poemId, body);
} else {
await api.createGenerationPoem(genealogyId, body);
}
showMessage('字辈已保存');
closePoemEditor();
await loadGenerationPoems();
} catch (error) {
if (redirectUnauthorized(api, error)) return;
if (isForbidden(error)) {
renderForbiddenState();
return;
}
setGenerationFormStatus(error.message || '字辈保存失败', 'error');
} finally {
setWritePending(false);
}
}
async function togglePoemStatus(poemId) {
var api = getApi();
var genealogyId;
var existing = poemsById[poemId];
var body;
if (writePending || !managementAccess || redirectUnauthorized(api)) return;
genealogyId = requireGenealogyId();
if (!genealogyId || !existing) return;
body = buildGenerationPoemBody({
generationNo: existing.generationNo,
generationText: existing.generationText,
description: existing.description,
sortOrder: existing.sortOrder,
status: existing.status === '1' ? '0' : '1'
});
setWritePending(true);
try {
await api.updateGenerationPoem(genealogyId, poemId, body);
showMessage(existing.status === '1' ? '字辈已恢复' : '字辈已停用');
await loadGenerationPoems();
} catch (error) {
if (redirectUnauthorized(api, error)) return;
if (isForbidden(error)) {
renderForbiddenState();
return;
}
showMessage(error.message || '字辈状态更新失败');
} finally {
setWritePending(false);
}
}
async function previewBatch() {
var api = getApi();
var genealogyId;
var form = query('[data-generation-batch-form]');
var body;
var validation;
if (writePending || !managementAccess || redirectUnauthorized(api) || !form) return;
genealogyId = requireGenealogyId();
if (!genealogyId) return;
body = buildBatchBody(getFormValues(form));
validation = validateBatchBody(body);
if (validation) {
setBatchStatus(validation);
return;
}
setBatchStatus('正在预览…');
setWritePending(true);
try {
if (renderBatchPreview(await api.previewGenerationPoems(genealogyId, body))) {
lastPreviewSignature = JSON.stringify(body);
setBatchStatus('预览完成,请确认后保存');
} else {
lastPreviewSignature = '';
setBatchStatus('预览响应不完整');
}
} catch (error) {
if (redirectUnauthorized(api, error)) return;
if (isForbidden(error)) {
renderForbiddenState();
return;
}
lastPreviewSignature = '';
setBatchStatus(error.message || '批量预览失败');
} finally {
setWritePending(false);
}
}
async function saveBatch() {
var api = getApi();
var genealogyId;
var form = query('[data-generation-batch-form]');
var body;
var validation;
if (writePending || !managementAccess || redirectUnauthorized(api) || !form) return;
genealogyId = requireGenealogyId();
if (!genealogyId) return;
body = buildBatchBody(getFormValues(form));
validation = validateBatchBody(body);
if (validation) {
setBatchStatus(validation);
return;
}
if (lastPreviewSignature !== JSON.stringify(body)) {
setBatchStatus('请先预览当前内容,再保存');
return;
}
if (!await confirmAction(buildBatchConfirmMessage(body.disableMissing))) return;
setBatchStatus('正在保存…');
setWritePending(true);
try {
await api.saveGenerationPoems(genealogyId, body);
lastPreviewSignature = '';
setBatchStatus('批量字辈已保存');
await loadGenerationPoems();
} catch (error) {
if (redirectUnauthorized(api, error)) return;
if (isForbidden(error)) {
renderForbiddenState();
return;
}
setBatchStatus(error.message || '批量保存失败');
} finally {
setWritePending(false);
}
}
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('submit', function (event) {
var form = event.target.closest('[data-generation-form]');
if (!form) return;
event.preventDefault();
submitPoem(form);
});
documentRef.addEventListener('click', function (event) {
var target = event.target;
var action = target.closest('[data-generation-batch-action]');
var poemButton = target.closest('[data-generation-edit], [data-generation-status]');
if (action) {
event.preventDefault();
if (action.getAttribute('data-generation-batch-action') === 'preview') previewBatch();
if (action.getAttribute('data-generation-batch-action') === 'save') saveBatch();
return;
}
if (target.closest('[data-generation-add]')) {
event.preventDefault();
openPoemEditor('');
return;
}
if (target.closest('[data-generation-editor-cancel]')) {
event.preventDefault();
closePoemEditor();
return;
}
if (!poemButton) return;
event.preventDefault();
if (poemButton.hasAttribute('data-generation-edit')) openPoemEditor(poemButton.getAttribute('data-generation-edit'));
if (poemButton.hasAttribute('data-generation-status')) togglePoemStatus(poemButton.getAttribute('data-generation-status'));
});
}
function init() {
if (!documentRef) return;
bindActions();
if (query('[data-generation-page]')) loadGenerationPoems();
}
return {
getCurrentGenealogyId: getCurrentGenealogyId,
buildGenerationPoemBody: buildGenerationPoemBody,
buildBatchBody: buildBatchBody,
validateGenerationPoemBody: validateGenerationPoemBody,
validateBatchBody: validateBatchBody,
canEditGenerations: canEditGenerations,
splitPoemText: splitPoemText,
normalizeGenerationPoem: normalizeGenerationPoem,
normalizeGenerationAccess: normalizeGenerationAccess,
normalizePreview: normalizePreview,
buildBatchConfirmMessage: buildBatchConfirmMessage,
normalizeList: normalizeList,
shouldRedirectToLogin: shouldRedirectToLogin,
isForbidden: isForbidden,
init: init
};
});