–>
/**
* 信纸模态窗口管理
* 实现点击信纸打开模态窗口,并提供导航功能
*/
document.addEventListener(“DOMContentLoaded”, function() {
const pageLoader = document.getElementById(‘page-loader’);
if (pageLoader) pageLoader.style.display = ‘block’;
try {
// 初始化信纸元素 (MODIFIED)
initLetterPapers();
// 创建和初始化模态窗口
createModalIfNotExists(); // Renamed for clarity
// 模态窗口功能初始化
initModalFunctionality();
// 添加无障碍支持
addAccessibilitySupport();
} catch (error) {
console.error(‘初始化失败:’, error);
} finally {
// 隐藏加载指示器
if (pageLoader) pageLoader.style.display = ‘none’;
}
});
/**
* Helper function to build and append a single letter paper.
* @param {Array} elements – Array of HTML elements for this entry.
* @param {HTMLElement} container – The parent container to append the letter paper to.
*/
function buildAndAppendLetterPaper(elements, container) {
if (!elements || elements.length === 0) return;
const letterPaperDiv = document.createElement(‘div’);
// This class is crucial for styling and for the modal script to find these elements
letterPaperDiv.classList.add(‘letter-paper’);
// The original script targeted .wp-block-group.letter-paper.
// We can add .wp-block-group if needed for stricter CSS, but .letter-paper should be enough.
// letterPaperDiv.classList.add(‘wp-block-group’);
const innerContainer = document.createElement(‘div’);
// Mimic the original structure that showModalContent expects for content extraction
innerContainer.classList.add(‘wp-block-group__inner-container’, ‘is-layout-constrained’, ‘wp-block-group-is-layout-constrained’);
elements.forEach(el => {
innerContainer.appendChild(el); // el is already a clone from the calling function
});
letterPaperDiv.appendChild(innerContainer);
// Add accessibility attributes
letterPaperDiv.setAttribute(‘tabindex’, ‘0’);
letterPaperDiv.setAttribute(‘role’, ‘button’);
const h4Title = innerContainer.querySelector(‘h4.wp-block-heading’); // Ensure we get the correct H4
if (h4Title) {
letterPaperDiv.setAttribute(‘aria-label’, `打开日记: ${h4Title.textContent.trim()}`);
} else {
letterPaperDiv.setAttribute(‘aria-label’, ‘打开日记条目’);
}
container.appendChild(letterPaperDiv);
}
/**
* 初始化信纸元素 (MODIFIED for new log format)
* Parses flat WordPress block structure into letter paper cards.
*/
function initLetterPapers() {
const logContainerSelector = ‘.entry-content’; // Common WordPress content area
const mainLogContainer = document.querySelector(logContainerSelector);
if (!mainLogContainer) {
console.warn(`Log container “${logContainerSelector}” not found. Script will not process logs.`);
// Try to find if the elements are direct children of body for testing purposes
// This part is for robustness if .entry-content is missing in a test setup.
// In a real WP environment, .entry-content or a theme equivalent should exist.
const testNodes = Array.from(document.body.childNodes).filter(n => n.nodeType === 1 && n.classList.contains(‘wp-block-heading’));
if (testNodes.length > 0 && !document.querySelector(‘.entry-content’)) {
console.warn(“No ‘.entry-content’ found, but found WP blocks in body. Attempting to process body children. This is not recommended for production.”);
// In this specific test case, let’s wrap body contents for processing
const tempWrapper = document.createElement(‘div’);
tempWrapper.classList.add(‘entry-content’); // Give it the class we expect
while(document.body.firstChild && document.body.firstChild.id !== ‘page-loader’ && !document.body.firstChild.classList.contains(‘modal-overlay’)) {
tempWrapper.appendChild(document.body.firstChild);
}
document.body.insertBefore(tempWrapper, document.getElementById(‘page-loader’));
// Re-assign mainLogContainer
// mainLogContainer = tempWrapper; // This line caused an issue, it should be used if we process from body.
// For the provided HTML, .entry-content exists.
} else if (!mainLogContainer) {
return;
}
}
// If mainLogContainer is still null after the warning and potential body processing attempt.
if (!mainLogContainer) {
console.error(`Log container “${logContainerSelector}” definitively not found. Aborting initLetterPapers.`);
return;
}
const originalNodes = Array.from(mainLogContainer.childNodes);
const processedContentContainer = document.createElement(‘div’);
processedContentContainer.className = ‘clearfix’; // To contain floated letter-papers
let currentEntryElements = [];
let collectingEntry = false;
originalNodes.forEach(node => {
// We are interested in element nodes (type 1) and relevant WP comment nodes (type 8)
if (node.nodeType !== 1 && node.nodeType !== 8) {
// If it’s a text node with only whitespace, ignore. Otherwise, preserve non-block text.
if (node.nodeType === 3 && node.textContent.trim() === ”) return;
if (!collectingEntry) { // Preserve elements before the first H4 entry starts
processedContentContainer.appendChild(node.cloneNode(true));
} else { // If inside an entry, and it’s not a block comment
if(node.nodeType !== 8) currentEntryElements.push(node.cloneNode(true));
}
return;
}
// Handle WordPress comment nodes – the actual element is usually the next ELEMENT sibling
let elementNode = node;
if (node.nodeType === 8) {
let nextSibling = node.nextSibling;
while(nextSibling && nextSibling.nodeType !== 1) {
nextSibling = nextSibling.nextSibling;
}
if (nextSibling) {
elementNode = nextSibling;
} else {
// This comment node doesn’t have an associated element, or it’s a closing block comment.
// If it’s a closing block like /wp:shortcode and we are not collecting, add the comment itself.
if (!collectingEntry && node.nodeValue.trim().startsWith(‘/wp:’)) {
processedContentContainer.appendChild(node.cloneNode(true));
}
return;
}
}
// Now elementNode is an actual HTML element
if (elementNode.tagName === ‘H4’ && elementNode.classList.contains(‘wp-block-heading’)) {
if (collectingEntry && currentEntryElements.length > 0) {
buildAndAppendLetterPaper(currentEntryElements, processedContentContainer);
}
currentEntryElements = [elementNode.cloneNode(true)];
collectingEntry = true;
} else if (collectingEntry) {
// Skip top-level separators that are truly between entries.
// A separator is inter-entry if the *next actual block* is an H4.
if (elementNode.tagName === ‘HR’ && elementNode.classList.contains(‘wp-block-separator’)) {
let nextActualBlock = elementNode.nextElementSibling;
while(nextActualBlock && nextActualBlock.nodeType === 8) { // Skip over comment nodes
let temp = nextActualBlock.nextElementSibling;
if (temp && temp.nodeType === 1) nextActualBlock = temp;
else break;
}
if (nextActualBlock && nextActualBlock.tagName === ‘H4’ && nextActualBlock.classList.contains(‘wp-block-heading’)) {
// This separator is between entries, so skip it.
} else {
currentEntryElements.push(elementNode.cloneNode(true));
}
} else {
currentEntryElements.push(elementNode.cloneNode(true));
}
} else {
// Element before the first H4 (e.g., music player)
// The WP comment for the shortcode is preserved, then the shortcode div itself.
if(node.nodeType === 8) processedContentContainer.appendChild(node.cloneNode(true)); // Add the wp:shortcode comment
processedContentContainer.appendChild(elementNode.cloneNode(true)); // Add the actual div.wp-block-shortcode
if(node.nodeType === 8) { // Add the /wp:shortcode comment if it’s paired
let closingComment = elementNode.nextSibling;
while(closingComment && closingComment.nodeType !== 8) closingComment = closingComment.nextSibling;
if (closingComment && closingComment.nodeValue.trim().startsWith(‘/wp:’)) {
processedContentContainer.appendChild(closingComment.cloneNode(true));
}
}
}
});
// Append the last collected entry
if (collectingEntry && currentEntryElements.length > 0) {
buildAndAppendLetterPaper(currentEntryElements, processedContentContainer);
}
// Replace the original content of mainLogContainer with the new structured content
mainLogContainer.innerHTML = ”;
mainLogContainer.appendChild(processedContentContainer);
}
/**
* Creates modal elements if they don’t already exist in the DOM.
*/
function createModalIfNotExists() {
if (document.querySelector(‘.modal-overlay’)) {
return; // Modal already exists
}
const modalOverlay = document.createElement(‘div’);
modalOverlay.classList.add(‘modal-overlay’);
modalOverlay.setAttribute(‘role’, ‘dialog’);
modalOverlay.setAttribute(‘aria-modal’, ‘true’);
modalOverlay.setAttribute(‘aria-labelledby’, ‘modal-title’); // Title will be set dynamically
const modalContentWrapper = document.createElement(‘div’);
modalContentWrapper.classList.add(‘modal-content’); // This is the styled “paper” for the modal
const modalInnerContent = document.createElement(‘div’);
modalInnerContent.setAttribute(‘id’, ‘modal-content-inner’); // Where actual content goes
modalContentWrapper.appendChild(modalInnerContent);
const loader = document.createElement(‘div’);
loader.classList.add(‘loader’);
loader.setAttribute(‘id’, ‘modal-loader’);
modalContentWrapper.appendChild(loader); // Loader inside content wrapper for centering
const closeButton = document.createElement(‘button’);
closeButton.innerHTML = ‘×’;
closeButton.classList.add(‘close-button’);
closeButton.setAttribute(‘aria-label’, ‘关闭’);
closeButton.setAttribute(‘title’, ‘关闭’);
modalContentWrapper.appendChild(closeButton); // Close button also part of the paper
// Nav buttons are part of the overlay, not the content paper
const prevButton = document.createElement(‘button’);
prevButton.classList.add(‘nav-button’, ‘prev-button’);
prevButton.setAttribute(‘aria-label’, ‘上一个’);
prevButton.setAttribute(‘title’, ‘上一个’);
modalOverlay.appendChild(prevButton);
const nextButton = document.createElement(‘button’);
nextButton.classList.add(‘nav-button’, ‘next-button’);
nextButton.setAttribute(‘aria-label’, ‘下一个’);
nextButton.setAttribute(‘title’, ‘下一个’);
modalOverlay.appendChild(nextButton);
modalOverlay.appendChild(modalContentWrapper);
document.body.appendChild(modalOverlay);
}
/**
* (Original createModal function renamed and adapted slightly)
* Create modal elements if they don’t already exist.
*/
function createModal() { // This is the original function, now createModalIfNotExists is preferred
createModalIfNotExists();
}
/**
* 初始化模态窗口功能
*/
function initModalFunctionality() {
// IMPORTANT: Query for .letter-paper AFTER initLetterPapers has run and created them.
const letterPapers = document.querySelectorAll(‘.letter-paper’);
const body = document.body;
const modalOverlay = document.querySelector(‘.modal-overlay’);
const modalContent = document.querySelector(‘#modal-content-inner’);
const closeButton = document.querySelector(‘.close-button’);
const prevButton = document.querySelector(‘.prev-button’);
const nextButton = document.querySelector(‘.next-button’);
const modalLoader = document.querySelector(‘#modal-loader’);
if (!modalOverlay || !modalContent || !closeButton || !prevButton || !nextButton || !modalLoader) {
console.error(“Modal elements not found. Cannot initialize modal functionality.”);
return;
}
let currentIndex = -1;
function closeModal() {
modalOverlay.classList.remove(‘active’);
setTimeout(() => {
modalOverlay.style.display = ‘none’;
modalContent.innerHTML = ”;
body.classList.remove(‘no-scroll’);
}, 300); // Match transition duration
}
function showModalContent(letterPaper) {
modalLoader.style.display = ‘block’;
modalContent.innerHTML = ”; // Clear previous content
setTimeout(() => {
try {
// The content for the modal is directly within the .wp-block-group__inner-container
const contentContainer = letterPaper.querySelector(‘.wp-block-group__inner-container’);
if (contentContainer) {
const safeContent = contentContainer.cloneNode(true);
const links = safeContent.querySelectorAll(‘a’);
links.forEach(link => {
link.setAttribute(‘target’, ‘_blank’);
link.setAttribute(‘rel’, ‘noopener noreferrer’);
});
modalContent.appendChild(safeContent);
const titleElement = safeContent.querySelector(‘h4.wp-block-heading’);
if (titleElement) {
modalOverlay.setAttribute(‘aria-labelledby’, ‘modal-title-dynamic’); // Give an ID to the h4
titleElement.id = ‘modal-title-dynamic’;
} else {
modalOverlay.removeAttribute(‘aria-labelledby’); // No specific title
}
modalOverlay.style.display = ‘flex’;
setTimeout(() => modalOverlay.classList.add(‘active’), 10); // For transition
body.classList.add(‘no-scroll’);
updateNavigationButtons();
} else {
throw new Error(“Content container not found in letter paper.”);
}
} catch (error) {
console.error(‘加载内容失败:’, error);
showError(‘内容加载失败,请稍后重试.’);
} finally {
modalLoader.style.display = ‘none’;
}
}, 200);
}
function showError(message) {
modalContent.innerHTML = `
出错了
${message}
`;
modalOverlay.setAttribute(‘aria-labelledby’, ‘modal-title-dynamic’);
}
function updateNavigationButtons() {
prevButton.style.visibility = (currentIndex > 0) ? ‘visible’ : ‘hidden’;
nextButton.style.visibility = (currentIndex 0) {
currentIndex–;
showModalContent(letterPapers[currentIndex]);
// Ensure the new active element is focused for screen readers
letterPapers[currentIndex].focus();
}
}
function navigateToNext() {
if (currentIndex { event.stopPropagation(); navigateToPrevious(); });
nextButton.addEventListener(‘click’, (event) => { event.stopPropagation(); navigateToNext(); });
letterPapers.forEach((letterPaper, index) => {
letterPaper.addEventListener(‘click’, (event) => {
currentIndex = index;
showModalContent(letterPaper);
event.stopPropagation();
});
letterPaper.addEventListener(‘keydown’, (event) => {
if (event.key === ‘Enter’ || event.key === ‘ ‘) {
currentIndex = index;
showModalContent(letterPaper);
event.preventDefault();
}
});
});
modalOverlay.addEventListener(‘click’, (event) => {
if (event.target === modalOverlay) {
closeModal();
}
});
modalOverlay.style.display = ‘none’; // Ensure it’s hidden on load
}
/**
* 添加键盘导航和无障碍支持
*/
function addAccessibilitySupport() {
document.addEventListener(‘keydown’, (event) => {
const modalOverlay = document.querySelector(‘.modal-overlay’);
if (modalOverlay && modalOverlay.style.display === ‘flex’ && modalOverlay.classList.contains(‘active’)) {
switch(event.key) {
case ‘Escape’:
document.querySelector(‘.close-button’).click();
break;
case ‘ArrowLeft’:
const prevButton = document.querySelector(‘.prev-button’);
if (prevButton.style.visibility !== ‘hidden’) prevButton.click();
break;
case ‘ArrowRight’:
const nextButton = document.querySelector(‘.next-button’);
if (nextButton.style.visibility !== ‘hidden’) nextButton.click();
break;
}
}
});
const modalOverlayForFocusTrap = document.querySelector(‘.modal-overlay’);
if (modalOverlayForFocusTrap) {
modalOverlayForFocusTrap.addEventListener(‘keydown’, function(event) {
if (event.key === ‘Tab’) {
const focusableElements = this.querySelectorAll(‘button, [href], input, select, textarea, [tabindex]:not([tabindex=”-1″])’);
const visibleFocusableElements = Array.from(focusableElements).filter(el => {
return el.offsetParent !== null && window.getComputedStyle(el).visibility !== ‘hidden’;
});
if (visibleFocusableElements.length === 0) {
event.preventDefault();
return;
}
const firstElement = visibleFocusableElements[0];
const lastElement = visibleFocusableElements[visibleFocusableElements.length – 1];
if (event.shiftKey) {
if (document.activeElement === firstElement) {
lastElement.focus();
event.preventDefault();
}
} else {
if (document.activeElement === lastElement) {
firstElement.focus();
event.preventDefault();
}
}
}
});
}
}
/**
* 添加懒加载支持 (Optional, original function)
* 当信纸元素进入视口时才加载内容 (currently placeholder images)
*/
function initLazyLoading() {
if (‘IntersectionObserver’ in window) {
const letterPapers = document.querySelectorAll(‘.letter-paper’); // Target dynamically created papers
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const letterPaper = entry.target;
// Example: Load images within the letter paper if they use data-src
const imagesToLoad = letterPaper.querySelectorAll(‘img[data-src]’);
imagesToLoad.forEach(img => {
img.src = img.getAttribute(‘data-src’);
img.removeAttribute(‘data-src’);
});
letterPaper.style.animationDelay = (Math.random() * 0.5) + ‘s’; // If you have entry animations
observer.unobserve(letterPaper);
}
});
}, {
root: null,
rootMargin: ’50px’, /* Preload a bit before visible */
threshold: 0.1 /* 10% visible */
});
letterPapers.forEach(paper => observer.observe(paper));
}
}
// Initialize lazy loading after other DOM manipulations are complete
window.addEventListener(‘load’, initLazyLoading);
#page {grid-template-columns:100% !important;}
TCR (T-cell receptor) and BCR (B-cell receptor) are critical in the adaptive immune response. These receptors are located on the surface of T cells and B cells, respectively, and are responsible for recognizing specific antigens.
TCR: Recognizes antigenic peptides presented by MHC molecules on antigen-presenting cells.
BCR: Recognizes free antigens and can directly bind to pathogens.
2. Co-stimulatory and Inhibitory Receptors
T cells and B cells require co-stimulatory signals in addition to antigen recognition to become fully activated.
Inhibitory receptors (e.g., CTLA-4, PD-1) downregulate immune responses to maintain self-tolerance and prevent autoimmunity.
3. Cytokine Receptor Signaling
Cytokines are signaling proteins that modulate immune responses by binding to cytokine receptors on immune cells.
Cytokine receptor engagement leads to signal transduction pathways that influence cell survival, proliferation, differentiation, and effector functions.
4. Signal Transduction in T Cells
Signal transduction is the process by which a signal on the cell surface is converted into a specific cellular response.
TCR engagement triggers intracellular signaling cascades that lead to T cell activation, proliferation, and differentiation.
Key molecules involved in TCR signaling include:
Src family kinases (e.g., Lck)
ZAP-70
LAT (Linker for Activation of T cells)
Ca2+ signaling
NFACT (Nuclear Factor of Activated T cells)
OralI
Diacylglycerol (DAG)
5. TCR Structure and Function
The TCR is composed of two main chains, TCRα and TCRβ, which together form a heterodimer and recognize antigenic peptides presented by MHC molecules. 5.1 TCRα
Formed by recombination of V (variable) and J (joining) gene segments.
The diversity of the TCRα chain is enhanced by N-region diversity (random nucleotide insertions or deletions during gene recombination).
5.2 TCRβ
Formed by recombination of V, D (diversity), and J gene segments.
Plays a critical role in TCR diversity and antigen recognition.
Together, these chains provide the specificity required for the TCR to recognize a vast array of antigen–MHC complexes, which is crucial for immune surveillance.
γδ T Cells: A subset of T cells that express γ and δ chains instead of the traditional αβ chains, recognizing non-peptide antigens.
6. Discovery and Characterization of TCR
Hedrick et al., Nature (1984): Pioneering study on the isolation of cDNA clones encoding T cell-specific membrane proteins.
Method: Extracted RNA from T cells and B cells, hybridized T-cell cDNA with B-cell RNA. Non-hybridizing sequences were identified as T-cell specific.
This discovery was a major breakthrough in understanding TCR specificity.
7. CD3 and Co-receptor Complex
TCR/CD3 Complex: After the discovery of the TCR, CD3 proteins were identified via IP-Edman degradation.
CD4 and CD8 are critical co-receptors in T cell activation:
They are coupled to the Src family kinase Lck, which phosphorylates the CD3 complex and initiates downstream signaling.
Lck is essential for the phosphorylation of ITAMs (Immunoreceptor Tyrosine-based Activation Motifs) in the TCR complex.
8. ZAP-70 and Signal Transduction
ZAP-70 (Zeta-chain-associated protein kinase 70):
Identified through a study on a mutant T-cell line with defective calcium flux, which lacked ZAP-70 as shown by Western blot analysis.
ZAP-70 is a protein tyrosine kinase that plays a crucial role in TCR signal transduction. It is recruited to phosphorylated ITAMs by its tandem SH2 domains and is activated by Lck.
ZAP-70 Function:
ZAP-70 is essential for the propagation of the TCR signal by phosphorylating downstream adaptor proteins such as LAT.
9. Key Molecules in TCR Signaling
Lck (Src Family Kinase):
A critical regulator of TCR signaling.
Upon TCR engagement, Lck phosphorylates the ITAMs in the CD3 complex, which recruits ZAP-70 and initiates downstream signaling pathways.
LAT (Linker for Activation of T cells):
A key adaptor protein in the TCR signaling pathway. LAT is phosphorylated by ZAP-70 and serves as a scaffold for the recruitment of other signaling molecules.
Calcium (Ca2+) Signaling:
Ca2+ influx is a crucial second messenger in TCR signaling, leading to the activation of transcription factors like NFAT (Nuclear Factor of Activated T cells).
Diacylglycerol (DAG):
A lipid-derived second messenger that activates downstream pathways such as the Protein Kinase C (PKC) pathway, which is involved in T cell activation.
10. Signal Molecules as Drugs
Small molecules targeting these signaling pathways offer potential therapeutic strategies for modulating immune responses. For example:
Kinase inhibitors targeting Lck or ZAP-70 can modulate T cell activation in autoimmune diseases or transplant rejection.
Cytokine inhibitors can be used to dampen excessive immune responses in conditions like cytokine storm or chronic inflammation.
This note provides a structured overview of TCR signaling, its components, and the key discoveries that shaped our understanding of T-cell functionality.