summarize_display_mode added. see #580
This commit is contained in:
parent
7bac86cc82
commit
58437ad168
8 changed files with 218 additions and 85 deletions
|
|
@ -1951,6 +1951,22 @@
|
||||||
"message": "Choose whether to automatically generate summaries when viewing messages. Requires an API-based connection (not ChatGPT Web).",
|
"message": "Choose whether to automatically generate summaries when viewing messages. Requires an API-based connection (not ChatGPT Web).",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
"prefs_OptionText_summarize_display_mode": {
|
||||||
|
"message": "Display summary in",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"prefs_OptionText_summarize_display_mode_inline": {
|
||||||
|
"message": "Message pane (inline)",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"prefs_OptionText_summarize_display_mode_webchat": {
|
||||||
|
"message": "Chat window",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"prefs_OptionText_summarize_display_mode_Info": {
|
||||||
|
"message": "Choose where the summary result is displayed. Inline mode shows a summary banner directly in the message pane. Chat window mode opens the AI chat window.",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
"summarize_title": {
|
"summarize_title": {
|
||||||
"message": "Summary",
|
"message": "Summary",
|
||||||
"description": ""
|
"description": ""
|
||||||
|
|
|
||||||
|
|
@ -43,19 +43,32 @@ js/mzta-compose-script.js (inserts text into Thunderbird compose window)
|
||||||
|
|
||||||
### Data Flow: Inline Summary on Message Display
|
### Data Flow: Inline Summary on Message Display
|
||||||
|
|
||||||
|
The `summarize_display_mode` preference (`'inline'` or `'webchat'`) controls where
|
||||||
|
the summary is displayed. The `summarize_auto` preference controls when it is triggered.
|
||||||
|
|
||||||
|
- `summarize_auto = 2` (automatic) always generates inline, regardless of `summarize_display_mode`.
|
||||||
|
- `summarize_auto = 1` (manual button) respects `summarize_display_mode`:
|
||||||
|
- `'inline'` → button click triggers inline generation
|
||||||
|
- `'webchat'` → button click opens the AI chat window via `_openSummaryWebchat()`
|
||||||
|
- Context menu summarize also respects `summarize_display_mode`:
|
||||||
|
- `'inline'` with a single message → generates inline via `_generateSummaryForMessage()`
|
||||||
|
- `'webchat'` or multiple messages → opens the AI chat window via `openChatGPT()`
|
||||||
|
|
||||||
```
|
```
|
||||||
User opens/selects a message in Thunderbird
|
User opens/selects a message in Thunderbird
|
||||||
↓
|
↓
|
||||||
mzta-compose-script.js (sends "initSummary" to background)
|
mzta-compose-script.js (sends "initSummary" to background)
|
||||||
↓
|
↓
|
||||||
mzta-background.js (checks summarize_auto pref)
|
mzta-background.js (checks summarize_auto + summarize_display_mode prefs)
|
||||||
↓
|
↓
|
||||||
┌────────────────────────────────────────────────┐
|
┌──────────────────────────────────────────────────────────┐
|
||||||
│ summarize_auto = 0 → do nothing │
|
│ summarize_auto = 0 → do nothing │
|
||||||
│ summarize_auto = 1 → show "click to generate" │
|
│ summarize_auto = 1 → show "click to generate" button │
|
||||||
│ summarize_auto = 2 → generate immediately │
|
│ display_mode = inline → click triggers inline gen │
|
||||||
└────────────────────────────────────────────────┘
|
│ display_mode = webchat → click opens chat window │
|
||||||
↓ (if generating)
|
│ summarize_auto = 2 → generate immediately (always inline)│
|
||||||
|
└──────────────────────────────────────────────────────────┘
|
||||||
|
↓ (if generating inline)
|
||||||
taSummaryStore (check cache / set processing)
|
taSummaryStore (check cache / set processing)
|
||||||
↓ (cache miss)
|
↓ (cache miss)
|
||||||
mzta-special-commands (via Web Worker, NOT chatgpt_web)
|
mzta-special-commands (via Web Worker, NOT chatgpt_web)
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ These are generated programmatically at the bottom of `mzta-options-default.js`
|
||||||
| `spamfilter_show_msg_panel` | `true` | Show info panel on spam detection |
|
| `spamfilter_show_msg_panel` | `true` | Show info panel on spam detection |
|
||||||
| `summarize` | `false` | Enable email summarization |
|
| `summarize` | `false` | Enable email summarization |
|
||||||
| `summarize_auto` | `0` | Auto-summarize mode: `0` = disabled, `1` = manual (show "click to generate" button), `2` = automatic (generate on message open) |
|
| `summarize_auto` | `0` | Auto-summarize mode: `0` = disabled, `1` = manual (show "click to generate" button), `2` = automatic (generate on message open) |
|
||||||
|
| `summarize_display_mode` | `'inline'` | Where to display summaries: `'inline'` = message pane banner, `'webchat'` = AI chat window. Note: `summarize_auto = 2` always uses inline regardless of this setting. |
|
||||||
|
|
||||||
### Summarize Settings Page (`pages/summarize/`)
|
### Summarize Settings Page (`pages/summarize/`)
|
||||||
|
|
||||||
|
|
@ -106,7 +107,11 @@ The summarize settings page provides:
|
||||||
- `0` (Disabled) — no inline summaries
|
- `0` (Disabled) — no inline summaries
|
||||||
- `1` (Manual) — shows a "Click to generate summary" button in message display
|
- `1` (Manual) — shows a "Click to generate summary" button in message display
|
||||||
- `2` (Automatic) — generates summary immediately when message is opened
|
- `2` (Automatic) — generates summary immediately when message is opened
|
||||||
3. **Three editable prompts** (used by context menu summarize, not inline):
|
3. **Display mode dropdown** (`summarize_display_mode`) — controls where summaries are shown:
|
||||||
|
- `'inline'` — summary banner in the message pane (default)
|
||||||
|
- `'webchat'` — opens the AI chat window
|
||||||
|
- Note: `summarize_auto = 2` always generates inline regardless of this setting. Context menu summarize with multiple messages always falls back to webchat.
|
||||||
|
4. **Three editable prompts** (used by context menu summarize and webchat mode):
|
||||||
- Summarize instruction prompt (`prompt_summarize`)
|
- Summarize instruction prompt (`prompt_summarize`)
|
||||||
- Email template prompt (`prompt_summarize_email_template`)
|
- Email template prompt (`prompt_summarize_email_template`)
|
||||||
- Email separator prompt (`prompt_summarize_email_separator`)
|
- Email separator prompt (`prompt_summarize_email_separator`)
|
||||||
|
|
|
||||||
|
|
@ -850,9 +850,9 @@ switch (message.command) {
|
||||||
triggerContainer.id = 'mzta-summary-generating';
|
triggerContainer.id = 'mzta-summary-generating';
|
||||||
triggerContainer.style.cursor = 'default';
|
triggerContainer.style.cursor = 'default';
|
||||||
triggerText.textContent = browser.i18n.getMessage("summarize_generating");
|
triggerText.textContent = browser.i18n.getMessage("summarize_generating");
|
||||||
browser.runtime.sendMessage({
|
browser.runtime.sendMessage({
|
||||||
command: "triggerSummaryGeneration",
|
command: message.webchat ? "triggerSummaryWebchat" : "triggerSummaryGeneration",
|
||||||
headerMessageId: message.headerMessageId
|
headerMessageId: message.headerMessageId
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -222,27 +222,41 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||||
async function _initSummary() {
|
async function _initSummary() {
|
||||||
try {
|
try {
|
||||||
let tabId = sender.tab.id;
|
let tabId = sender.tab.id;
|
||||||
let prefs = await browser.storage.sync.get({ summarize_auto: 0 });
|
let prefs = await browser.storage.sync.get({ summarize_auto: 0, summarize_display_mode: prefs_default.summarize_display_mode });
|
||||||
if (prefs.summarize_auto === 0) return;
|
if (prefs.summarize_auto === 0) return;
|
||||||
|
|
||||||
let message = await browser.messageDisplay.getDisplayedMessage(tabId);
|
let message = await browser.messageDisplay.getDisplayedMessage(tabId);
|
||||||
if (!message) return;
|
if (!message) return;
|
||||||
|
|
||||||
let cachedSummary = await summaryStore.loadSummary(message.headerMessageId);
|
// Auto mode (summarize_auto === 2) always generates inline
|
||||||
if (cachedSummary && !cachedSummary.error) {
|
if (prefs.summarize_auto === 2) {
|
||||||
browser.tabs.sendMessage(tabId, { command: "showSummary", data: cachedSummary });
|
let cachedSummary = await summaryStore.loadSummary(message.headerMessageId);
|
||||||
return;
|
if (cachedSummary && !cachedSummary.error) {
|
||||||
}
|
browser.tabs.sendMessage(tabId, { command: "showSummary", data: cachedSummary });
|
||||||
|
return;
|
||||||
if (await summaryStore.isProcessing(message.headerMessageId)) {
|
}
|
||||||
browser.tabs.sendMessage(tabId, { command: "showSummaryGenerating" });
|
if (await summaryStore.isProcessing(message.headerMessageId)) {
|
||||||
return;
|
browser.tabs.sendMessage(tabId, { command: "showSummaryGenerating" });
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
if (prefs.summarize_auto === 1) {
|
|
||||||
browser.tabs.sendMessage(tabId, { command: "showSummaryButton", headerMessageId: message.headerMessageId });
|
|
||||||
} else if (prefs.summarize_auto === 2) {
|
|
||||||
_generateSummaryForMessage(message.headerMessageId, tabId);
|
_generateSummaryForMessage(message.headerMessageId, tabId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manual button mode (summarize_auto === 1)
|
||||||
|
if (prefs.summarize_display_mode === 'inline') {
|
||||||
|
let cachedSummary = await summaryStore.loadSummary(message.headerMessageId);
|
||||||
|
if (cachedSummary && !cachedSummary.error) {
|
||||||
|
browser.tabs.sendMessage(tabId, { command: "showSummary", data: cachedSummary });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (await summaryStore.isProcessing(message.headerMessageId)) {
|
||||||
|
browser.tabs.sendMessage(tabId, { command: "showSummaryGenerating" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
browser.tabs.sendMessage(tabId, { command: "showSummaryButton", headerMessageId: message.headerMessageId });
|
||||||
|
} else {
|
||||||
|
browser.tabs.sendMessage(tabId, { command: "showSummaryButton", headerMessageId: message.headerMessageId, webchat: true });
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
taLog.error("Error in initSummary: " + e);
|
taLog.error("Error in initSummary: " + e);
|
||||||
|
|
@ -257,6 +271,13 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||||
}
|
}
|
||||||
_triggerSummaryGeneration(message);
|
_triggerSummaryGeneration(message);
|
||||||
break;
|
break;
|
||||||
|
case 'triggerSummaryWebchat':
|
||||||
|
async function _triggerSummaryWebchat(message) {
|
||||||
|
let tabId = sender.tab.id;
|
||||||
|
await _openSummaryWebchat(message.headerMessageId, tabId);
|
||||||
|
}
|
||||||
|
_triggerSummaryWebchat(message);
|
||||||
|
break;
|
||||||
case 'generate_summary':
|
case 'generate_summary':
|
||||||
async function _generate_summary(message) {
|
async function _generate_summary(message) {
|
||||||
await _generateSummaryForMessage(message.headerMessageId, message.tabId);
|
await _generateSummaryForMessage(message.headerMessageId, message.tabId);
|
||||||
|
|
@ -514,6 +535,55 @@ async function _generateSummaryForMessage(headerMessageId, tabId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function _openSummaryWebchat(headerMessageId, tabId) {
|
||||||
|
try {
|
||||||
|
const specialPrompts = await getSpecialPrompts();
|
||||||
|
const prompt = specialPrompts.find(p => p.id === 'prompt_summarize');
|
||||||
|
const prompt_email = specialPrompts.find(p => p.id === 'prompt_summarize_email_template');
|
||||||
|
const prompt_email_separator = specialPrompts.find(p => p.id === 'prompt_summarize_email_separator');
|
||||||
|
|
||||||
|
const chatgpt_lang = await taPromptUtils.getDefaultLang(prompt);
|
||||||
|
|
||||||
|
const prompt_string = await taPromptUtils.preparePrompt({
|
||||||
|
curr_prompt: prompt,
|
||||||
|
chatgpt_lang: chatgpt_lang,
|
||||||
|
});
|
||||||
|
const prompt_email_separator_string = await taPromptUtils.preparePrompt({
|
||||||
|
curr_prompt: prompt_email_separator,
|
||||||
|
chatgpt_lang: chatgpt_lang,
|
||||||
|
});
|
||||||
|
|
||||||
|
const messageResult = await browser.messages.query({ headerMessageId: headerMessageId });
|
||||||
|
if (!messageResult || messageResult.messages.length === 0) {
|
||||||
|
console.error("[ThunderAI] _openSummaryWebchat: Message not found for headerMessageId:", headerMessageId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const curr_message = messageResult.messages[0];
|
||||||
|
const curr_message_full = await browser.messages.getFull(curr_message.id);
|
||||||
|
const curr_body_full_html = getMailBody(curr_message_full);
|
||||||
|
let curr_body_full_text = htmlBodyToPlainText(curr_body_full_html.html);
|
||||||
|
if (curr_body_full_text.length === 0) {
|
||||||
|
curr_body_full_text = curr_body_full_html.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
const email_text = await taPromptUtils.preparePrompt({
|
||||||
|
curr_prompt: prompt_email,
|
||||||
|
curr_message: curr_message,
|
||||||
|
chatgpt_lang: chatgpt_lang,
|
||||||
|
body_text: curr_body_full_text,
|
||||||
|
subject_text: curr_message_full.headers.subject,
|
||||||
|
msg_text: curr_body_full_html,
|
||||||
|
});
|
||||||
|
|
||||||
|
const full_prompt = prompt_string + prompt_email_separator_string + email_text;
|
||||||
|
|
||||||
|
openChatGPT(full_prompt, prompt.action, tabId, prompt.name, prompt.need_custom_text, prompt);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("[ThunderAI] Error opening summary webchat:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Listen for messages from ThunderAI-Sparks
|
// Listen for messages from ThunderAI-Sparks
|
||||||
browser.runtime.onMessageExternal.addListener((message, sender, sendResponse) => {
|
browser.runtime.onMessageExternal.addListener((message, sender, sendResponse) => {
|
||||||
switch (message.action) {
|
switch (message.action) {
|
||||||
|
|
@ -1384,66 +1454,79 @@ async function processEmails(args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (summarize) {
|
if (summarize) {
|
||||||
// we have three prompts, the actual assignment for the LLM, the email
|
|
||||||
// template prompt, and the email separator prompt
|
|
||||||
const specialPrompts = await getSpecialPrompts();
|
|
||||||
const prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize');
|
|
||||||
const prompt_email = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_template');
|
|
||||||
const prompt_email_separator = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_separator');
|
|
||||||
|
|
||||||
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
|
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
|
||||||
const chatgpt_lang = await taPromptUtils.getDefaultLang(prompt);
|
const tabId = tabs[0].id;
|
||||||
|
let summarize_prefs = await browser.storage.sync.get({ summarize_display_mode: prefs_default.summarize_display_mode });
|
||||||
// replace placeholders in the prompts the assignment prompt and email
|
|
||||||
// separator prompt do not have a message as context, so there is only
|
// Collect messages into array to check count
|
||||||
// limited things to replace
|
const messageArray = [];
|
||||||
const prompt_string = await taPromptUtils.preparePrompt({
|
for await (let msg of messages) {
|
||||||
curr_prompt: prompt,
|
messageArray.push(msg);
|
||||||
chatgpt_lang: chatgpt_lang,
|
}
|
||||||
});
|
|
||||||
const prompt_email_separator_string = await taPromptUtils.preparePrompt({
|
// Inline mode for single message: generate inline summary in the message pane
|
||||||
curr_prompt: prompt_email_separator,
|
if (summarize_prefs.summarize_display_mode === 'inline' && messageArray.length === 1) {
|
||||||
chatgpt_lang: chatgpt_lang,
|
await _generateSummaryForMessage(messageArray[0].headerMessageId, tabId);
|
||||||
});
|
} else {
|
||||||
|
// Webchat mode, or inline with multiple messages (fallback to webchat)
|
||||||
|
// we have three prompts, the actual assignment for the LLM, the email
|
||||||
// assemble all email messages into one string and add the assignment prompt
|
// template prompt, and the email separator prompt
|
||||||
const messages_list = [];
|
const specialPrompts = await getSpecialPrompts();
|
||||||
for await (let curr_message of messages) {
|
const prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize');
|
||||||
|
const prompt_email = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_template');
|
||||||
// extract body of current message as text
|
const prompt_email_separator = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_separator');
|
||||||
const curr_message_full = await browser.messages.getFull(curr_message.id);
|
|
||||||
const curr_body_full_html = getMailBody(curr_message_full);
|
const chatgpt_lang = await taPromptUtils.getDefaultLang(prompt);
|
||||||
let curr_body_full_text = htmlBodyToPlainText(curr_body_full_html.html);
|
|
||||||
if( curr_body_full_text.length === 0) {
|
// replace placeholders in the prompts the assignment prompt and email
|
||||||
taLog.log("No HTML found in the message body, using plain text...");
|
// separator prompt do not have a message as context, so there is only
|
||||||
curr_body_full_text = curr_message_full.text;
|
// limited things to replace
|
||||||
}
|
const prompt_string = await taPromptUtils.preparePrompt({
|
||||||
|
curr_prompt: prompt,
|
||||||
messages_list.push(await taPromptUtils.preparePrompt({
|
chatgpt_lang: chatgpt_lang,
|
||||||
curr_prompt: prompt_email,
|
});
|
||||||
curr_message: curr_message,
|
const prompt_email_separator_string = await taPromptUtils.preparePrompt({
|
||||||
chatgpt_lang: chatgpt_lang,
|
curr_prompt: prompt_email_separator,
|
||||||
body_text: curr_body_full_text,
|
chatgpt_lang: chatgpt_lang,
|
||||||
subject_text: curr_message_full.headers.subject,
|
});
|
||||||
msg_text: curr_body_full_html,
|
|
||||||
}));
|
|
||||||
};
|
// assemble all email messages into one string and add the assignment prompt
|
||||||
const messages_string = messages_list.join(prompt_email_separator_string);
|
const messages_list = [];
|
||||||
|
for (let curr_message of messageArray) {
|
||||||
const full_prompt = prompt_string + prompt_email_separator_string + messages_string;
|
|
||||||
|
// extract body of current message as text
|
||||||
// console.log(full_prompt);
|
const curr_message_full = await browser.messages.getFull(curr_message.id);
|
||||||
|
const curr_body_full_html = getMailBody(curr_message_full);
|
||||||
// send the prompt to the chat interface
|
let curr_body_full_text = htmlBodyToPlainText(curr_body_full_html.html);
|
||||||
openChatGPT(
|
if( curr_body_full_text.length === 0) {
|
||||||
full_prompt,
|
taLog.log("No HTML found in the message body, using plain text...");
|
||||||
prompt.action,
|
curr_body_full_text = curr_message_full.text;
|
||||||
tabs[0].id,
|
}
|
||||||
prompt.name,
|
|
||||||
prompt.need_custom_text,
|
messages_list.push(await taPromptUtils.preparePrompt({
|
||||||
prompt
|
curr_prompt: prompt_email,
|
||||||
);
|
curr_message: curr_message,
|
||||||
|
chatgpt_lang: chatgpt_lang,
|
||||||
|
body_text: curr_body_full_text,
|
||||||
|
subject_text: curr_message_full.headers.subject,
|
||||||
|
msg_text: curr_body_full_html,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
const messages_string = messages_list.join(prompt_email_separator_string);
|
||||||
|
|
||||||
|
const full_prompt = prompt_string + prompt_email_separator_string + messages_string;
|
||||||
|
|
||||||
|
// send the prompt to the chat interface
|
||||||
|
openChatGPT(
|
||||||
|
full_prompt,
|
||||||
|
prompt.action,
|
||||||
|
tabId,
|
||||||
|
prompt.name,
|
||||||
|
prompt.need_custom_text,
|
||||||
|
prompt
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
taWorkingStatus.stopWorking();
|
taWorkingStatus.stopWorking();
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,7 @@ export const prefs_default = {
|
||||||
spamfilter_threshold: 70,
|
spamfilter_threshold: 70,
|
||||||
spamfilter_enabled_accounts: [],
|
spamfilter_enabled_accounts: [],
|
||||||
summarize_auto: 0, // 0: disabled, 1: manual button, 2: automatic
|
summarize_auto: 0, // 0: disabled, 1: manual button, 2: automatic
|
||||||
|
summarize_display_mode: 'inline', // 'inline' or 'webchat'
|
||||||
spamfilter_show_msg_panel: true,
|
spamfilter_show_msg_panel: true,
|
||||||
summarize: false,
|
summarize: false,
|
||||||
...generated_prefs
|
...generated_prefs
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,18 @@
|
||||||
</label>
|
</label>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="summarize_tr">
|
||||||
|
<td><span class="opt_title">__MSG_prefs_OptionText_summarize_display_mode__</span></td>
|
||||||
|
<td>
|
||||||
|
<label>
|
||||||
|
<select id="summarize_display_mode" name="summarize_display_mode" class="option-input">
|
||||||
|
<option value="inline">__MSG_prefs_OptionText_summarize_display_mode_inline__</option>
|
||||||
|
<option value="webchat">__MSG_prefs_OptionText_summarize_display_mode_webchat__</option>
|
||||||
|
</select>
|
||||||
|
<br>__MSG_prefs_OptionText_summarize_display_mode_Info__
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<!-- PROMPTS -->
|
<!-- PROMPTS -->
|
||||||
|
|
|
||||||
|
|
@ -240,6 +240,9 @@ async function restoreOptions() {
|
||||||
if (element.id === 'summarize_auto') {
|
if (element.id === 'summarize_auto') {
|
||||||
default_select_value = prefs_default.summarize_auto;
|
default_select_value = prefs_default.summarize_auto;
|
||||||
}
|
}
|
||||||
|
if (element.id === 'summarize_display_mode') {
|
||||||
|
default_select_value = prefs_default.summarize_display_mode;
|
||||||
|
}
|
||||||
const restoreValue = result[element.id] ?? default_select_value;
|
const restoreValue = result[element.id] ?? default_select_value;
|
||||||
// Check if option exists
|
// Check if option exists
|
||||||
let optionExists = Array.from(element.options).some(opt => opt.value === String(restoreValue));
|
let optionExists = Array.from(element.options).some(opt => opt.value === String(restoreValue));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue