diff --git a/_locales/en/messages.json b/_locales/en/messages.json index e05c3f41..af6e4e97 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1012,13 +1012,25 @@ "description": "" }, "prefs_OptionText_get_calendar_event_Info": { - "message": "If checked, an item will be included in the menu to get a calendar event information from selected text.", + "message": "If checked, an item will be included in the menu to get calendar event information from selected text.", "description": "" }, "get_calendar_event_prompt_prefs_title": { "message": "Calendar Events Options", "description": "" }, + "prefs_OptionText_get_task": { + "message": "Add a new task from selected text", + "description": "" + }, + "prefs_OptionText_get_task_Info": { + "message": "If checked, an item will be included in the menu to get task information from selected text.", + "description": "" + }, + "get_task_prompt_prefs_title": { + "message": "Tasks Options", + "description": "" + }, "Select_your_timezone": { "message": "Select your timezone", "description": "" @@ -1028,7 +1040,7 @@ "description": "" }, "prefs_OptionText_calendar_enforce_timezone_Info": { - "message": "If checked, the specified timezone will be enforced for the calendar events.", + "message": "If checked, the specified timezone will be enforced for the calendar events and the tasks.", "description": "" }, "prefs_OptionText_btnManageCalendarEventInfo": { @@ -1052,11 +1064,23 @@ "description": "" }, "prefs_OptionText_get_calendar_event_Sparks_not_present": { - "message": "To use the calendar event feature, please install the ThunderAI Sparks addon.", + "message": "To use the calendar event and task features, please install the ThunderAI Sparks addon.", "description": "" }, "prefs_OptionText_get_calendar_event_Sparks_wrong_version": { - "message": "To use the calendar event feature, please install an updated version of ThunderAI Sparks addon.", + "message": "To use the calendar event and task features, please install an updated version of ThunderAI Sparks addon.", + "description": "" + }, + "GetTask_PageTitle": { + "message": "Manage Tasks Settings", + "description": "" + }, + "GetTask_info_default": { + "message": "In this page you can modify the default prompt used to get a task from selected text.", + "description": "" + }, + "prefs_OptionText_btnManageTaskInfo": { + "message": "Manage tasks settings", "description": "" }, "prefs_OptionText_download_now": { diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index 573d2085..c4674218 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -52,6 +52,7 @@ export const prefs_default = { add_tags_auto_only_inbox: true, add_tags_context_menu: true, get_calendar_event: true, + get_task: true, calendar_enforce_timezone: false, calendar_timezone: '', spamfilter: false, diff --git a/options/mzta-options.html b/options/mzta-options.html index 30b8a790..08d987b1 100644 --- a/options/mzta-options.html +++ b/options/mzta-options.html @@ -374,6 +374,16 @@ + + __MSG_prefs_OptionText_get_task__ +
+ + + + __MSG_prefs_OptionText_get_calendar_event_Sparks_not_present__ diff --git a/options/mzta-options.js b/options/mzta-options.js index ee575645..07376d81 100644 --- a/options/mzta-options.js +++ b/options/mzta-options.js @@ -386,6 +386,13 @@ document.addEventListener('DOMContentLoaded', async () => { get_calendar_event_info_btn.disabled = event.target.checked ? '' : 'disabled'; }); get_calendar_event_info_btn.disabled = get_calendar_event_el.checked ? '' : 'disabled'; + + let get_task_el = document.getElementById('get_task'); + let get_task_info_btn = document.getElementById('btnManageTaskInfo'); + get_task_el.addEventListener('click', (event) => { + get_task_info_btn.disabled = event.target.checked ? '' : 'disabled'; + }); + get_task_info_btn.disabled = get_task_el.checked ? '' : 'disabled'; document.getElementById('btnManagePrompts').addEventListener('click', () => { // check if the tab is already there @@ -439,6 +446,19 @@ document.addEventListener('DOMContentLoaded', async () => { }) }); + document.getElementById('btnManageTaskInfo').addEventListener('click', () => { + // check if the tab is already there + browser.tabs.query({url: browser.runtime.getURL('../pages/get-task/mzta-get-task.html')}).then((tabs) => { + if (tabs.length > 0) { + // if the tab is already there, focus it + browser.tabs.update(tabs[0].id, {active: true}); + } else { + // if the tab is not there, create it + browser.tabs.create({url: browser.runtime.getURL('../pages/get-task/mzta-get-task.html')}); + } + }) + }); + document.getElementById('btnOpenAICompForceModel').addEventListener('click', () => { let modelName = prompt(browser.i18n.getMessage('OpenAIComp_force_model_ask')).trim(); if ((modelName !== null) && (modelName !== undefined) && (modelName !== '')) { diff --git a/pages/get-task/mzta-get-task.css b/pages/get-task/mzta-get-task.css new file mode 100644 index 00000000..0ce83ec5 --- /dev/null +++ b/pages/get-task/mzta-get-task.css @@ -0,0 +1,119 @@ +#get_task_prompt_container{ + width: 90%; + margin: 20px auto; +} + +#get_task_prompt_text{ + width: 100%; +} + +.infoline{ + font-size: 0.8em; + font-style: italic; +} + +.btn_div{ + width: 100%; + display: flex; + justify-content: space-between; +} + +table#miczPrefs { + padding: 10px; + border-spacing: 0px; + width: 90%; + margin: 0px auto 40px auto; + border: 1px solid #ccc; +} + +.get_task_table_title{ + width: 90%; + margin: auto; +} + +.section_title{ + font-weight: bold; +} + +table#miczPrefs td{ + border-top: 1px solid #ccc; + border-bottom: 1px solid #ccc; + vertical-align: top; + padding: 2px; +} + +table#miczPrefs tr:first-child td { + border-top: none; +} + +table#miczPrefs tr:last-child td { + border-bottom: none; +} + +.autocomplete-container { + position: relative; +} + +.autocomplete-list { + position: absolute; + top: 100%; + left: 0; + right: 0; + background-color: white; + border: 1px solid #ccc; + z-index: 1000; + max-height: 200px; + overflow-y: auto; + padding: 0; + margin: 0; + list-style: none; + font-size: small; +} + +.autocomplete-list li { + padding: 8px; + cursor: pointer; +} + +.autocomplete-list li:hover { + background-color: #f0f0f0; +} + +.autocomplete-list li.active { + background-color: #ddd; +} + +.hidden { + display: none; +} + +.unsaved{ + color: red; +} + + +@media (prefers-color-scheme: dark) { + body { + background-color: #1C1B22; + color: rgb(251, 251, 254); + } + + a:link { color: #409EFF; } + a:visited { color: #409EFF; } + a:hover { color: #66B1FF; } + a:active { color: #66B1FF; } + a:active { color: #66B1FF; } + + .autocomplete-list { + background-color: #2E2F36; + border: 1px solid #2E2F36; + } + + .autocomplete-list li:hover { + background-color: #4c4e58; + } + + .autocomplete-list li.active { + background-color: #4c4e58; + } +} \ No newline at end of file diff --git a/pages/get-task/mzta-get-task.html b/pages/get-task/mzta-get-task.html new file mode 100644 index 00000000..98027d85 --- /dev/null +++ b/pages/get-task/mzta-get-task.html @@ -0,0 +1,73 @@ + + + + + ThunderAI - __MSG_GetTask_PageTitle__ + + + + +
+

__MSG_GetTask_PageTitle__

+

__MSG_GetTask_info_default__

+
+
__MSG_get_calendar_event_prompt_prefs_title__
+ + + + + +
__MSG_prefs_OptionText_calendar_enforce_timezone__ + +
+
+ __MSG_GetCalendarEvent_prompt_text_title__ +
__MSG_prefs_OptionText_btnManagePrompts_infoline__ __MSG_customPrompts_managePrompts_help__ +
__MSG_prefs_OptionText_GetCalendarEvent_infoline2__
+
+
+ + +
+
+
+
+ + + + \ No newline at end of file diff --git a/pages/get-task/mzta-get-task.js b/pages/get-task/mzta-get-task.js new file mode 100644 index 00000000..2b33e297 --- /dev/null +++ b/pages/get-task/mzta-get-task.js @@ -0,0 +1,149 @@ +/* + * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] + * Copyright (C) 2024 - 2025 Mic (m@micz.it) + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import { prefs_default } from '../../options/mzta-options-default.js'; +import { taLogger } from '../../js/mzta-logger.js'; +import { getSpecialPrompts, setSpecialPrompts } from "../../js/mzta-prompts.js"; +import { getPlaceholders } from "../../js/mzta-placeholders.js"; +import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js"; + +let autocompleteSuggestions = []; +let taLog = new taLogger("mzta-get-calendar-event-page",true); + +document.addEventListener('DOMContentLoaded', async () => { + + i18n.updateDocument(); + await restoreOptions(); + + document.querySelectorAll(".option-input").forEach(element => { + element.addEventListener("change", saveOptions); + }); + + let get_calendar_event_textarea = document.getElementById('get_task_prompt_text'); + let get_calendar_event_save_btn = document.getElementById('btn_save_prompt'); + let get_calendar_event_reset_btn = document.getElementById('btn_reset_prompt'); + + let specialPrompts = await getSpecialPrompts(); + let get_calendar_event_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_get_task'); + + get_calendar_event_textarea.addEventListener('input', (event) => { + get_calendar_event_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_get_task_full_text')); + get_calendar_event_save_btn.disabled = (event.target.value === get_calendar_event_prompt.text); + if(get_calendar_event_save_btn.disabled){ + document.getElementById('get_task_prompt_unsaved').classList.add('hidden'); + } else { + document.getElementById('get_task_prompt_unsaved').classList.remove('hidden'); + } + }); + + get_calendar_event_reset_btn.addEventListener('click', () => { + get_calendar_event_textarea.value = browser.i18n.getMessage('prompt_get_task_full_text'); + get_calendar_event_reset_btn.disabled = true; + let event = new Event('input', { bubbles: true, cancelable: true }); + get_calendar_event_textarea.dispatchEvent(event); + }); + + get_calendar_event_save_btn.addEventListener('click', () => { + specialPrompts.find(prompt => prompt.id === 'prompt_get_task').text = get_calendar_event_textarea.value; + setSpecialPrompts(specialPrompts); + get_calendar_event_save_btn.disabled = true; + document.getElementById('get_task_prompt_unsaved').classList.add('hidden'); + browser.runtime.sendMessage({command: "reload_menus"}); + }); + + if(get_calendar_event_prompt.text === 'prompt_get_task_full_text'){ + get_calendar_event_prompt.text = browser.i18n.getMessage(get_calendar_event_prompt.text); + } + get_calendar_event_textarea.value = get_calendar_event_prompt.text; + get_calendar_event_reset_btn.disabled = (get_calendar_event_textarea.value === browser.i18n.getMessage('prompt_get_task_full_text')); + + autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(p => ({command: '{%'+p.id+'%}', type: p.type})); + textareaAutocomplete(get_calendar_event_textarea, autocompleteSuggestions, 1); // type_value = 1, only when reading an email + +}); + + + +// Methods to manage options, derived from: /options/mzta-options.js + +function saveOptions(e) { + e.preventDefault(); + let options = {}; + let element = e.target; + + switch (element.type) { + case 'checkbox': + options[element.id] = element.checked; + break; + case 'number': + options[element.id] = element.valueAsNumber; + break; + case 'text': + case 'password': + options[element.id] = element.value.trim(); + break; + default: + if (element.tagName === 'SELECT') { + options[element.id] = element.value; + }else{ + console.error("[ThunderAI] Unhandled input type:", element.type); + } + } + + browser.storage.sync.set(options); +} + +async function restoreOptions() { + function setCurrentChoice(result) { + document.querySelectorAll(".option-input").forEach(element => { + taLog.log("Options restoring " + element.id + " = " + (element.id=="chatgpt_api_key" || element.id=="openai_comp_api_key" ? "****************" : result[element.id])); + switch (element.type) { + case 'checkbox': + element.checked = result[element.id] || false; + break; + case 'number': + let default_number_value = 0; + if(element.id == 'chatgpt_win_height') default_number_value = prefs_default.chatgpt_win_height; + if(element.id == 'chatgpt_win_width') default_number_value = prefs_default.chatgpt_win_width; + element.value = result[element.id] ?? default_number_value; + break; + case 'text': + case 'password': + let default_text_value = ''; + if(element.id == 'default_chatgpt_lang') default_text_value = prefs_default.default_chatgpt_lang; + element.value = result[element.id] || default_text_value; + break; + default: + if (element.tagName === 'SELECT') { + let default_select_value = ''; + if(element.id == 'reply_type') default_select_value = 'reply_all'; + if(element.id == 'connection_type') default_select_value = 'chatgpt_web'; + element.value = result[element.id] || default_select_value; + if (element.value === '') { + element.selectedIndex = -1; + } + }else{ + console.error("[ThunderAI] Unhandled input type:", element.type); + } + } + }); + } + + let getting = await browser.storage.sync.get(prefs_default); + setCurrentChoice(getting); +} \ No newline at end of file