keeping formatted summary #580
This commit is contained in:
parent
3cb1fb0972
commit
7e9b507f0f
5 changed files with 103 additions and 45 deletions
|
|
@ -924,8 +924,22 @@ switch (message.command) {
|
||||||
|
|
||||||
const summaryText = document.createElement('div');
|
const summaryText = document.createElement('div');
|
||||||
summaryText.className = 'thunderai-summary-content';
|
summaryText.className = 'thunderai-summary-content';
|
||||||
|
const hasHtml = !!summaryData.summary_html;
|
||||||
|
|
||||||
|
// Helper to set summary content using DOMParser (innerHTML is blocked in Thunderbird content scripts)
|
||||||
|
function setSummaryHtml(element, html) {
|
||||||
|
element.textContent = '';
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const doc = parser.parseFromString(html, 'text/html');
|
||||||
|
while (doc.body.firstChild) {
|
||||||
|
element.appendChild(doc.body.firstChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (summaryData.error) {
|
if (summaryData.error) {
|
||||||
summaryText.textContent = summaryData.message || browser.i18n.getMessage("summarize_error");
|
summaryText.textContent = summaryData.message || browser.i18n.getMessage("summarize_error");
|
||||||
|
} else if (hasHtml) {
|
||||||
|
setSummaryHtml(summaryText, summaryData.summary_html);
|
||||||
} else {
|
} else {
|
||||||
summaryText.textContent = summaryData.summary;
|
summaryText.textContent = summaryData.summary;
|
||||||
}
|
}
|
||||||
|
|
@ -936,58 +950,94 @@ switch (message.command) {
|
||||||
const maxLen = summaryData.maxDisplayLength || 0;
|
const maxLen = summaryData.maxDisplayLength || 0;
|
||||||
const fullText = summaryData.summary;
|
const fullText = summaryData.summary;
|
||||||
if (!summaryData.error && maxLen > 0 && fullText && fullText.length > maxLen) {
|
if (!summaryData.error && maxLen > 0 && fullText && fullText.length > maxLen) {
|
||||||
let cutPos = fullText.lastIndexOf(' ', maxLen);
|
|
||||||
if (cutPos <= 0) cutPos = maxLen;
|
|
||||||
const truncated = fullText.substring(0, cutPos) + '\u2026';
|
|
||||||
summaryText.textContent = truncated;
|
|
||||||
|
|
||||||
// Set up animated expand/collapse via max-height transition
|
// Set up animated expand/collapse via max-height transition
|
||||||
summaryText.style.overflow = 'hidden';
|
summaryText.style.overflow = 'hidden';
|
||||||
summaryText.style.transition = 'max-height 0.2s ease';
|
summaryText.style.transition = 'max-height 0.2s ease';
|
||||||
|
|
||||||
// Measure truncated height after layout
|
if (!hasHtml) {
|
||||||
requestAnimationFrame(() => {
|
// Plain text: truncate by character position
|
||||||
const collapsedHeight = summaryText.scrollHeight;
|
let cutPos = fullText.lastIndexOf(' ', maxLen);
|
||||||
summaryText.style.maxHeight = collapsedHeight + 'px';
|
if (cutPos <= 0) cutPos = maxLen;
|
||||||
});
|
const truncated = fullText.substring(0, cutPos) + '\u2026';
|
||||||
|
summaryText.textContent = truncated;
|
||||||
|
|
||||||
const toggleLink = document.createElement('a');
|
// Measure truncated height after layout
|
||||||
toggleLink.textContent = browser.i18n.getMessage("summarize_see_more") || "See more";
|
requestAnimationFrame(() => {
|
||||||
toggleLink.href = '#';
|
|
||||||
toggleLink.style.cssText = 'display: inline-block; margin-top: 4px; font-size: 13px; color: ' +
|
|
||||||
(isDarkSummary ? '#6db3f2' : '#1a5fa8') + '; cursor: pointer; text-decoration: underline;';
|
|
||||||
|
|
||||||
let expanded = false;
|
|
||||||
toggleLink.addEventListener('click', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
if (!expanded) {
|
|
||||||
// Expand: set full text, measure, animate to full height
|
|
||||||
summaryText.textContent = fullText;
|
|
||||||
const fullHeight = summaryText.scrollHeight;
|
|
||||||
summaryText.style.maxHeight = fullHeight + 'px';
|
|
||||||
toggleLink.textContent = browser.i18n.getMessage("summarize_see_less") || "See less";
|
|
||||||
} else {
|
|
||||||
// Collapse: measure current truncated height, then animate down
|
|
||||||
summaryText.textContent = truncated;
|
|
||||||
// Force layout to get the target height before animating
|
|
||||||
const collapsedHeight = summaryText.scrollHeight;
|
const collapsedHeight = summaryText.scrollHeight;
|
||||||
summaryText.textContent = fullText;
|
summaryText.style.maxHeight = collapsedHeight + 'px';
|
||||||
// Set explicit current height so transition has a starting point
|
});
|
||||||
summaryText.style.maxHeight = summaryText.scrollHeight + 'px';
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
summaryText.style.maxHeight = collapsedHeight + 'px';
|
|
||||||
});
|
|
||||||
// Swap text after transition ends
|
|
||||||
summaryText.addEventListener('transitionend', function handler() {
|
|
||||||
summaryText.removeEventListener('transitionend', handler);
|
|
||||||
summaryText.textContent = truncated;
|
|
||||||
});
|
|
||||||
toggleLink.textContent = browser.i18n.getMessage("summarize_see_more") || "See more";
|
|
||||||
}
|
|
||||||
expanded = !expanded;
|
|
||||||
});
|
|
||||||
|
|
||||||
summaryTextWrapper.appendChild(toggleLink);
|
const toggleLink = document.createElement('a');
|
||||||
|
toggleLink.textContent = browser.i18n.getMessage("summarize_see_more") || "See more";
|
||||||
|
toggleLink.href = '#';
|
||||||
|
toggleLink.style.cssText = 'display: inline-block; margin-top: 4px; font-size: 13px; color: ' +
|
||||||
|
(isDarkSummary ? '#6db3f2' : '#1a5fa8') + '; cursor: pointer; text-decoration: underline;';
|
||||||
|
|
||||||
|
let expanded = false;
|
||||||
|
toggleLink.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!expanded) {
|
||||||
|
// Expand: set full text, measure, animate to full height
|
||||||
|
summaryText.textContent = fullText;
|
||||||
|
const fullHeight = summaryText.scrollHeight;
|
||||||
|
summaryText.style.maxHeight = fullHeight + 'px';
|
||||||
|
toggleLink.textContent = browser.i18n.getMessage("summarize_see_less") || "See less";
|
||||||
|
} else {
|
||||||
|
// Collapse: measure current truncated height, then animate down
|
||||||
|
summaryText.textContent = truncated;
|
||||||
|
// Force layout to get the target height before animating
|
||||||
|
const collapsedHeight = summaryText.scrollHeight;
|
||||||
|
summaryText.textContent = fullText;
|
||||||
|
// Set explicit current height so transition has a starting point
|
||||||
|
summaryText.style.maxHeight = summaryText.scrollHeight + 'px';
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
summaryText.style.maxHeight = collapsedHeight + 'px';
|
||||||
|
});
|
||||||
|
// Swap text after transition ends
|
||||||
|
summaryText.addEventListener('transitionend', function handler() {
|
||||||
|
summaryText.removeEventListener('transitionend', handler);
|
||||||
|
summaryText.textContent = truncated;
|
||||||
|
});
|
||||||
|
toggleLink.textContent = browser.i18n.getMessage("summarize_see_more") || "See more";
|
||||||
|
}
|
||||||
|
expanded = !expanded;
|
||||||
|
});
|
||||||
|
|
||||||
|
summaryTextWrapper.appendChild(toggleLink);
|
||||||
|
} else {
|
||||||
|
// HTML content: use max-height to collapse, preserve full HTML
|
||||||
|
const collapsedMaxHeight = '4.2em'; // ~3 lines collapsed
|
||||||
|
summaryText.style.maxHeight = collapsedMaxHeight;
|
||||||
|
|
||||||
|
const toggleLink = document.createElement('a');
|
||||||
|
toggleLink.textContent = browser.i18n.getMessage("summarize_see_more") || "See more";
|
||||||
|
toggleLink.href = '#';
|
||||||
|
toggleLink.style.cssText = 'display: inline-block; margin-top: 4px; font-size: 13px; color: ' +
|
||||||
|
(isDarkSummary ? '#6db3f2' : '#1a5fa8') + '; cursor: pointer; text-decoration: underline;';
|
||||||
|
|
||||||
|
let expanded = false;
|
||||||
|
toggleLink.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!expanded) {
|
||||||
|
summaryText.style.maxHeight = summaryText.scrollHeight + 'px';
|
||||||
|
toggleLink.textContent = browser.i18n.getMessage("summarize_see_less") || "See less";
|
||||||
|
} else {
|
||||||
|
summaryText.style.maxHeight = collapsedMaxHeight;
|
||||||
|
toggleLink.textContent = browser.i18n.getMessage("summarize_see_more") || "See more";
|
||||||
|
}
|
||||||
|
expanded = !expanded;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Only show toggle if content is actually taller than collapsed height
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if (summaryText.scrollHeight > summaryText.clientHeight) {
|
||||||
|
summaryTextWrapper.appendChild(toggleLink);
|
||||||
|
} else {
|
||||||
|
summaryText.style.maxHeight = '';
|
||||||
|
summaryText.style.overflow = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const summaryBody = document.createElement('div');
|
const summaryBody = document.createElement('div');
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,7 @@ export class taStorage {
|
||||||
let now = Date.now();
|
let now = Date.now();
|
||||||
record[taStorage.FIELD_SUMMARY] = {
|
record[taStorage.FIELD_SUMMARY] = {
|
||||||
summary: summary_data.summary,
|
summary: summary_data.summary,
|
||||||
|
summary_html: summary_data.summary_html || '',
|
||||||
error: summary_data.error || false,
|
error: summary_data.error || false,
|
||||||
message: summary_data.message || '',
|
message: summary_data.message || '',
|
||||||
summary_date: summary_data.summary_date instanceof Date
|
summary_date: summary_data.summary_date instanceof Date
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@ export class taSummaryStore {
|
||||||
return {
|
return {
|
||||||
headerMessageId: data_id,
|
headerMessageId: data_id,
|
||||||
summary: summary.summary,
|
summary: summary.summary,
|
||||||
|
summary_html: summary.summary_html || '',
|
||||||
error: summary.error || false,
|
error: summary.error || false,
|
||||||
message: summary.message || '',
|
message: summary.message || '',
|
||||||
summary_date: new Date(summary.summary_date || summary.ts),
|
summary_date: new Date(summary.summary_date || summary.ts),
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
|
<script src="api_webchat/markdown-it.min.js"></script>
|
||||||
<script src="mzta-background.js" type="module"></script>
|
<script src="mzta-background.js" type="module"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -297,9 +297,11 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||||
case 'chatgpt_saveSummary':
|
case 'chatgpt_saveSummary':
|
||||||
async function _saveSummaryFromWebchat(msg) {
|
async function _saveSummaryFromWebchat(msg) {
|
||||||
try {
|
try {
|
||||||
|
let summaryHtml = msg.text.trim();
|
||||||
let cleanedSummary = cleanSummaryText(msg.text);
|
let cleanedSummary = cleanSummaryText(msg.text);
|
||||||
const summaryData = {
|
const summaryData = {
|
||||||
summary: cleanedSummary,
|
summary: cleanedSummary,
|
||||||
|
summary_html: summaryHtml,
|
||||||
summary_date: new Date(),
|
summary_date: new Date(),
|
||||||
headerMessageId: msg.headerMessageId
|
headerMessageId: msg.headerMessageId
|
||||||
};
|
};
|
||||||
|
|
@ -558,9 +560,12 @@ async function _generateSummaryForMessage(headerMessageId, tabId) {
|
||||||
await cmd.initWorker();
|
await cmd.initWorker();
|
||||||
const aiResponse = await cmd.sendPrompt();
|
const aiResponse = await cmd.sendPrompt();
|
||||||
let cleanedSummary = cleanSummaryText(aiResponse);
|
let cleanedSummary = cleanSummaryText(aiResponse);
|
||||||
|
const md = window.markdownit();
|
||||||
|
let summaryHtml = md.render(aiResponse);
|
||||||
|
|
||||||
const summaryData = {
|
const summaryData = {
|
||||||
summary: cleanedSummary,
|
summary: cleanedSummary,
|
||||||
|
summary_html: summaryHtml,
|
||||||
summary_date: new Date(),
|
summary_date: new Date(),
|
||||||
headerMessageId: headerMessageId
|
headerMessageId: headerMessageId
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue