diff --git a/CHANGELOG.md b/CHANGELOG.md index eed3a920..dc8b453f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,8 +14,19 @@
"/, '
').replace(/"<\\/p>$/, '
'); // strip quotation marks; } + if (lastSelectedHtml) { + // console.log(">>>>>>>>>>>>> getSelectedHtml using cached selection lastSelectedHtml: "+ lastSelectedHtml); + return lastSelectedHtml; + } return ""; } @@ -708,6 +725,14 @@ document.addEventListener("selectionchange", function() { let btn_ok = document.getElementById('mzta-btn_ok'); let btn_diff = document.getElementById('mzta-btn_diff'); if (isSomethingSelected()) { + // Cache the selection + var selection = window.getSelection(); + if (selection.rangeCount > 0) { + var range = selection.getRangeAt(0); + var tempDiv = document.createElement("div"); + tempDiv.appendChild(range.cloneContents()); + lastSelectedHtml = tempDiv.innerHTML.replace(/^"/, '
').replace(/"<\\/p>$/, '
'); + } enableButton(btn_ok); if(current_action == '1'){ let btn_reply_type = document.getElementById('mzta-btn_change_reply_type'); @@ -756,7 +781,8 @@ function selectContentOnMouseUp(event) { // If the click was inside the excluded area, do nothing return; } - + // console.log(">>>>>>>>>>>>> selectContentOnMouseUp isDragging: " + isDragging); + // Reset the dragging flag when the mouse is released") if ((!isDragging)&&(!isSomethingSelected())) { // If no dragging has occurred, execute the selection code selectContentOnClick(event); @@ -781,6 +807,8 @@ function selectContentOnClick(event) { // Traverse the DOM upwards to find the nearest parent div var parentDiv = clickedElement.closest('div'); + // console.log(">>>>>>>>>>>>> parentDiv: " + parentDiv.classList); + if (parentDiv) { // Create a range object var range = document.createRange(); @@ -796,6 +824,7 @@ function selectContentOnClick(event) { // Add the new range to the selection selection.addRange(range); + // console.log(">>>>>>>>>>>>> selectContentOnClick selection.rangeCount: " + selection.rangeCount); } } diff --git a/js/mzta-compose-script.js b/js/mzta-compose-script.js index 972a32de..09e64272 100644 --- a/js/mzta-compose-script.js +++ b/js/mzta-compose-script.js @@ -617,9 +617,58 @@ switch (message.command) { break; + case "showSpamReport": + const data = message.data; + if(document.getElementById('mzta-spam-report-banner')) return Promise.resolve(true); + + const container = document.createElement('div'); + container.id = 'mzta-spam-report-banner'; + + const isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; + + let bgColor = '#f8f9fa'; + let textColor = '#333'; + let borderColor = '#ccc'; + + if (data.spamValue >= (data.SpamThreshold || 50)) { + bgColor = isDark ? '#5a1a1a' : '#ffe6e6'; + textColor = isDark ? '#ffcccc' : '#cc0000'; + borderColor = '#cc0000'; + } else { + bgColor = isDark ? '#1a401a' : '#e6ffe6'; + textColor = isDark ? '#ccffcc' : '#006600'; + borderColor = '#006600'; + } + + container.style.cssText = `background-color: ${bgColor}; color: ${textColor}; border-bottom: 1px solid ${borderColor}; padding: 8px 12px; font-family: system-ui, -apple-system, sans-serif; font-size: 13px; display: flex; align-items: center; gap: 15px; width: 100%; box-sizing: border-box;`; + + const scoreText = document.createElement('strong'); + scoreText.textContent = ((data.spamValue >= (data.SpamThreshold || 50)) ? browser.i18n.getMessage("Spam") : browser.i18n.getMessage("Valid")) + " [" + data.spamValue + "/100]"; + + const reasonText = document.createElement('span'); + reasonText.textContent = browser.i18n.getMessage("Explanation") + ": " + data.explanation; + + const closeBtn = document.createElement('span'); + closeBtn.textContent = '×'; + closeBtn.style.cssText = 'margin-left: auto; cursor: pointer; font-weight: bold; font-size: 16px; padding: 0 5px;'; + closeBtn.title = browser.i18n.getMessage("chatgpt_win_close"); + closeBtn.onclick = function() { + container.remove(); + browser.runtime.sendMessage({ command: "removeSpamReport", headerMessageId: data.headerMessageId }); + }; + + container.appendChild(scoreText); + container.appendChild(reasonText); + container.appendChild(closeBtn); + + document.body.insertBefore(container, document.body.firstChild); + return Promise.resolve(true); + default: // do nothing return Promise.resolve(false); break; } -}); \ No newline at end of file +}); + +browser.runtime.sendMessage({ command: "checkSpamReport" }); \ No newline at end of file diff --git a/js/mzta-menus.js b/js/mzta-menus.js index b164bae1..4d04dcaf 100644 --- a/js/mzta-menus.js +++ b/js/mzta-menus.js @@ -110,6 +110,25 @@ export class mzta_Menus { taWorkingStatus.startWorking(); const tabs = await browser.tabs.query({ active: true, currentWindow: true }); const msg_text = await getMailBody(tabs, placeholdersUtils.hasPlaceholder(curr_prompt.text,'mail_typed_text')); + + if (curr_prompt.id === 'prompt_get_calendar_event_from_clipboard') { + try { + const clipboardText = await navigator.clipboard.readText(); + if (!clipboardText) { + browser.tabs.sendMessage(tabs[0].id, { command: "sendAlert", curr_tab_type: tabs[0].type, message: browser.i18n.getMessage('clipboard_empty_error') }); + taWorkingStatus.stopWorking(); + return {ok:'0'}; + } + msg_text.selection = clipboardText; + msg_text.text = clipboardText; + } catch (e) { + console.error("Clipboard read error:", e); + browser.tabs.sendMessage(tabs[0].id, { command: "sendAlert", curr_tab_type: tabs[0].type, message: browser.i18n.getMessage('clipboard_read_error') }); + taWorkingStatus.stopWorking(); + return {ok:'0'}; + } + } + // console.log(">>>>>>>>>>>>> msg_text: " + JSON.stringify(msg_text)); //check if a selection is needed if(String(curr_prompt.need_selected) == "1" && (msg_text.selection==='')){ @@ -256,7 +275,8 @@ export class mzta_Menus { return {ok:'1'}; break; // Add tags to the email - END } - case 'prompt_get_calendar_event': { // Get a calendar event info + case 'prompt_get_calendar_event': // Get a calendar event info + case 'prompt_get_calendar_event_from_clipboard': { // here from clipboard let calendar_event_data = ''; let prefs_at = await browser.storage.sync.get({ connection_type: prefs_default.connection_type, diff --git a/js/mzta-placeholders.js b/js/mzta-placeholders.js index bfb841c7..d8b63008 100644 --- a/js/mzta-placeholders.js +++ b/js/mzta-placeholders.js @@ -267,6 +267,24 @@ const defaultPlaceholders = [ is_default: "1", is_dynamic: "0", enabled: 1, + }, + { + id: 'mail_text_body_or_selected', + name: "__MSG_placeholder_mail_text_body_or_selected__", + default_value: "", + type: 0, + is_default: "1", + is_dynamic: "0", + enabled: 1, + }, + { + id: 'mail_html_body_or_selected', + name: "__MSG_placeholder_mail_html_body_or_selected__", + default_value: "", + type: 0, + is_default: "1", + is_dynamic: "0", + enabled: 1, } ]; @@ -517,6 +535,12 @@ export const placeholdersUtils = { case 'selected_html': finalSubs['selected_html'] = placeholdersUtils.failSafePlaceholders(selection_html); break; + case 'mail_text_body_or_selected': + finalSubs['mail_text_body_or_selected'] = placeholdersUtils.failSafePlaceholders(selection_text || body_text); + break; + case 'mail_html_body_or_selected': + finalSubs['mail_html_body_or_selected'] = placeholdersUtils.failSafePlaceholders(selection_html || msg_text?.html); + break; case 'author': finalSubs['author'] = placeholdersUtils.failSafePlaceholders(curr_message.author); break; diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js index a3fac86e..4a73f20a 100644 --- a/js/mzta-prompts.js +++ b/js/mzta-prompts.js @@ -294,6 +294,21 @@ const specialPrompts = [ is_default: "1", is_special: "1", }, + { + id: 'prompt_get_calendar_event_from_clipboard', + name: "__MSG_prompt_get_calendar_event_from_clipboard__", + text: "prompt_get_calendar_event_full_text", + type: "1", + action: "0", + need_selected: "0", + need_signature: "0", + need_custom_text: "0", + define_response_lang: "0", + use_diff_viewer: "0", + api_type: '', + is_default: "1", + is_special: "1", + }, { id: 'prompt_get_task', name: "__MSG_prompt_get_task__", diff --git a/js/mzta-spamreport.js b/js/mzta-spamreport.js index 99b4efc5..3674cdc0 100644 --- a/js/mzta-spamreport.js +++ b/js/mzta-spamreport.js @@ -32,6 +32,11 @@ export const taSpamReport = { return output[key] || null; }, + async removeReportData(data_id) { + const key = this._data_prefix + data_id; + await browser.storage.session.remove(key); + }, + async getAllReportData() { let allData = await browser.storage.session.get(null); let reportData = {}; diff --git a/js/mzta-utils.js b/js/mzta-utils.js index 90feb52b..a8aabdb2 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -577,6 +577,7 @@ export function getActiveSpecialPromptsIDs(args = {}) { addtags = false, addtags_api = false, get_calendar_event = false, + get_calendar_event_from_clipboard = false, get_task = false, is_chatgpt_web = false } = args; @@ -596,6 +597,9 @@ export function getActiveSpecialPromptsIDs(args = {}) { if (get_calendar_event) { output.push('prompt_get_calendar_event'); } + if (get_calendar_event_from_clipboard) { + output.push('prompt_get_calendar_event_from_clipboard'); + } if (get_task) { output.push('prompt_get_task'); } diff --git a/manifest.json b/manifest.json index bb91cd1f..9260970b 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "ThunderAI", "description": "__MSG_extensionDescription__", - "version": "4.0.0", + "version": "4.0.0pre1", "author": "Mic (m@micz.it)", "homepage_url": "https://micz.it/thunderbird-addon-thunderai/", "browser_specific_settings": { @@ -34,6 +34,7 @@ "messagesTagsList" ], "optional_permissions": [ + "clipboardRead", "messagesTags", "messagesUpdate", "messagesMove", diff --git a/mzta-background.js b/mzta-background.js index e6aeb0f1..f9386f61 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -99,6 +99,7 @@ let special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_init.add_tags, addtags_api: hasSpecificIntegration(prefs_init.add_tags_use_specific_integration, prefs_init.add_tags_connection_type), get_calendar_event: doGetSparkFeature(prefs_init.get_calendar_event), + get_calendar_event_from_clipboard: doGetSparkFeature(prefs_init.get_calendar_event_from_clipboard), get_task: doGetSparkFeature(prefs_init.get_task), is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web") }); @@ -197,13 +198,15 @@ function preparePopupMenu(tab) { } async function _reload_menus() { - let prefs_reload = await browser.storage.sync.get({add_tags: prefs_default.add_tags, get_calendar_event: prefs_default.get_calendar_event, get_task: prefs_default.get_task, connection_type: prefs_default.connection_type}); + let prefs_reload = await browser.storage.sync.get({add_tags: prefs_default.add_tags, get_calendar_event: prefs_default.get_calendar_event, get_calendar_event_from_clipboard: prefs_default.get_calendar_event_from_clipboard, get_task: prefs_default.get_task, connection_type: prefs_default.connection_type}); let getCalendarEvent = doGetSparkFeature(prefs_reload.get_calendar_event); + let getCalendarEventFromClipboard = doGetSparkFeature(prefs_reload.get_calendar_event_from_clipboard); let getTask = doGetSparkFeature(prefs_reload.get_task); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_reload.add_tags, addtags_api: hasSpecificIntegration(prefs_init.add_tags_use_specific_integration, prefs_init.add_tags_connection_type), get_calendar_event: getCalendarEvent, + get_calendar_event_from_clipboard: getCalendarEventFromClipboard, get_task: getTask, is_chatgpt_web: (prefs_reload.connection_type === "chatgpt_web") }); @@ -401,6 +404,29 @@ messenger.runtime.onMessage.addListener((message, sender, sendResponse) => { case 'api_send_custom_text': browser.tabs.sendMessage(message.tabId, { command: "api_send_custom_text", custom_text: message.custom_text }); break; + case 'checkSpamReport': + if(!prefs_init.spamfilter_show_msg_panel){ + return; + } + + async function _checkSpamReport(tabId) { + try { + if (sender.tab.type !== 'messageDisplay' && sender.tab.type !== 'mail') return; + let message = await browser.messageDisplay.getDisplayedMessage(tabId); + if (!message) return; + let report = await taSpamReport.loadReportData(message.headerMessageId); + if (report) { + browser.tabs.sendMessage(tabId, { command: "showSpamReport", data: report }); + } + } catch (e) { + taLog.error("Error in checkSpamReport: " + e); + } + } + _checkSpamReport(sender.tab.id); + break; + case 'removeSpamReport': + taSpamReport.removeReportData(message.headerMessageId); + break; default: break; } @@ -849,6 +875,7 @@ async function reload_pref_init(){ do_debug: prefs_default.do_debug, add_tags: prefs_default.add_tags, get_calendar_event: prefs_default.get_calendar_event, + get_calendar_event_from_clipboard: prefs_default.get_calendar_event_from_clipboard, get_task: prefs_default.get_task, connection_type: prefs_default.connection_type, add_tags_auto: prefs_default.add_tags_auto, @@ -857,6 +884,7 @@ async function reload_pref_init(){ spamfilter: prefs_default.spamfilter, summarize: prefs_default.summarize, spamfilter_threshold: prefs_default.spamfilter_threshold, + spamfilter_show_msg_panel: prefs_default.spamfilter_show_msg_panel, dynamic_menu_force_enter: prefs_default.dynamic_menu_force_enter, ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type']) }); @@ -874,11 +902,13 @@ function setupStorageChangeListener() { if (changes.add_tags) { const newTags = changes.add_tags.newValue; let getCalendarEvent = doGetSparkFeature(prefs_init.get_calendar_event); + let getCalendarEventFromClipboard = doGetSparkFeature(prefs_init.get_calendar_event_from_clipboard); let getTask = doGetSparkFeature(prefs_init.get_task); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: newTags, addtags_api: hasSpecificIntegration(prefs_init.add_tags_use_specific_integration, prefs_init.add_tags_connection_type), get_calendar_event: getCalendarEvent, + get_calendar_event_from_clipboard: getCalendarEventFromClipboard, get_task: getTask, is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web") }); @@ -889,11 +919,30 @@ function setupStorageChangeListener() { if (changes.get_calendar_event) { const newCalendarEvent = changes.get_calendar_event.newValue; let getCalendarEvent = doGetSparkFeature(newCalendarEvent); + let getCalendarEventFromClipboard = doGetSparkFeature(prefs_init.get_calendar_event_from_clipboard); let getTask = doGetSparkFeature(prefs_init.get_task); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_init.add_tags, addtags_api: hasSpecificIntegration(prefs_init.add_tags_use_specific_integration, prefs_init.add_tags_connection_type), get_calendar_event: getCalendarEvent, + get_calendar_event_from_clipboard: getCalendarEventFromClipboard, + get_task: getTask, + is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web") + }); + menus.reload(special_prompts_ids); + } + + // Process 'get_calendar_event_from_clipboard' changes + if (changes.get_calendar_event_from_clipboard) { + const newCalendarEventFromClipboard = changes.get_calendar_event_from_clipboard.newValue; + let getCalendarEvent = doGetSparkFeature(prefs_init.get_calendar_event); + let getCalendarEventFromClipboard = doGetSparkFeature(newCalendarEventFromClipboard); + let getTask = doGetSparkFeature(prefs_init.get_task); + const special_prompts_ids = getActiveSpecialPromptsIDs({ + addtags: prefs_init.add_tags, + addtags_api: hasSpecificIntegration(prefs_init.add_tags_use_specific_integration, prefs_init.add_tags_connection_type), + get_calendar_event: getCalendarEvent, + get_calendar_event_from_clipboard: getCalendarEventFromClipboard, get_task: getTask, is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web") }); @@ -904,11 +953,13 @@ function setupStorageChangeListener() { if (changes.get_task) { const newTask = changes.get_task.newValue; let getCalendarEvent = doGetSparkFeature(prefs_init.get_calendar_event); + let getCalendarEventFromClipboard = doGetSparkFeature(prefs_init.get_calendar_event_from_clipboard); let getTask = doGetSparkFeature(newTask); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_init.add_tags, addtags_api: hasSpecificIntegration(prefs_init.add_tags_use_specific_integration, prefs_init.add_tags_connection_type), get_calendar_event: getCalendarEvent, + get_calendar_event_from_clipboard: getCalendarEventFromClipboard, get_task: getTask, is_chatgpt_web: (prefs_init.connection_type === "chatgpt_web") }); @@ -919,11 +970,13 @@ function setupStorageChangeListener() { if (changes.connection_type) { const newConnectionType = changes.connection_type.newValue; let getCalendarEvent = doGetSparkFeature(prefs_init.get_calendar_event); + let getCalendarEventFromClipboard = doGetSparkFeature(prefs_init.get_calendar_event_from_clipboard); let getTask = doGetSparkFeature(prefs_init.get_task); const special_prompts_ids = getActiveSpecialPromptsIDs({ addtags: prefs_init.add_tags, addtags_api: hasSpecificIntegration(prefs_init.add_tags_use_specific_integration, prefs_init.add_tags_connection_type), get_calendar_event: getCalendarEvent, + get_calendar_event_from_clipboard: getCalendarEventFromClipboard, get_task: getTask, is_chatgpt_web: (newConnectionType === "chatgpt_web") }); @@ -1284,6 +1337,18 @@ async function processEmails(messages, addTagsAuto, spamFilter) { } taSpamReport.saveReportData(report_data, message.headerMessageId); + + // Check if the message is currently displayed and update the banner + if (prefs_init.spamfilter_show_msg_panel) { + let tabs = await browser.tabs.query({ active: true, currentWindow: true }); + if (tabs.length > 0) { + let activeTab = tabs[0]; + let displayedMessage = await browser.messageDisplay.getDisplayedMessage(activeTab.id); + if (displayedMessage && displayedMessage.id === message.id) { + browser.tabs.sendMessage(activeTab.id, { command: "showSpamReport", data: report_data }); + } + } + } } } taWorkingStatus.stopWorking(); diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index 89d65cab..e56b208f 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -125,13 +125,16 @@ export const prefs_default = { add_tags_auto_uselist_list: '', add_tags_enabled_accounts: [], get_calendar_event: true, + get_calendar_event_from_clipboard: false, // Enable calendar event from clipboard menu item get_task: true, calendar_enforce_timezone: false, calendar_timezone: '', + calendar_no_selection: false, // If true do not ask for selection, but use the full prompt spamfilter: false, spamfilter_threshold: 70, spamfilter_enabled_accounts: [], auto_summary_enabled: false, // Enable automatic AI summarization for message previews + spamfilter_show_msg_panel: true, summarize: false, ...generated_prefs } diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index 32b66f1f..6a2bb65c 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -17,8 +17,19 @@