diff --git a/_locales/en/messages.json b/_locales/en/messages.json index e5a0c071..21e142a7 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1575,5 +1575,21 @@ "customDataPH_Import": { "message": "Import new data placeholders", "description": "" + }, + "customDataPH_form_label_Text": { + "message": "Data Placeholder Text", + "description": "" + }, + "customDataPH_saving_custom": { + "message": "Saving custom data placeholders...", + "description": "" + }, + "customDataPH_saved": { + "message": "Custom data placeholders saved!", + "description": "" + }, + "customDataPH_btnAddNewCommit": { + "message": "Add the Data Placeholder", + "description": "" } } \ No newline at end of file diff --git a/pages/customdataplaceholders/mzta-custom-dataplaceholders.css b/pages/customdataplaceholders/mzta-custom-dataplaceholders.css new file mode 100644 index 00000000..888459df --- /dev/null +++ b/pages/customdataplaceholders/mzta-custom-dataplaceholders.css @@ -0,0 +1,360 @@ +@media (prefers-color-scheme: light) { + table th { + background-color: #ffffff; + } + + #command_palette{ + background-color: #ffffff; + } + + table.prompts_list tr:nth-child(even) { + background-color: #e9e9e9; + } + + table.prompts_list tr:nth-child(odd) { + background-color: #f3f3f3; + } +} + +table { + border-collapse: collapse; + border-spacing: 0; + border: 1px solid #ccc; +} + +thead { + position: sticky; + top: 26px; + z-index: 90; +} + +#command_palette{ + position: sticky; + top: 0; + padding-top: 1px; + height: 26px; + width: 100%; + z-index: 90; +} + +#btnNew{ + float: right; +} + +#btnSaveAll{ + float: left; +} + +#msgDisplay{ + padding-left: 40px; +} + +table tr { + border-bottom: 1px solid #ccc; +} + +table.prompts_list th { + padding: 8px; + text-align: left; +} + +table td { + border: 1px solid #ddd; + padding: 8px; +} + +table td.w08{ + width: 8vw; +} + +table td.w17{ + width: 17vw; +} + +table td.w19{ + width: 19vw; +} + +table td.w25{ + width: 25vw; +} + +table td.w40{ + width: 40vw; +} + +table.prompts_list td.properties{ + white-space: nowrap; +} + +table .sort { + background-image: url(../images/listjs-arrow-sort-inactive.png); + background-repeat: no-repeat; + background-position: right center; + padding-right: 14px; + cursor: pointer; + cursor: hand; +} + +table .sort.asc { + background-image: url(../images/listjs-arrow-sort-active-down.png); +} + +table .sort.desc { + background-image: url(../images/listjs-arrow-sort-active-up.png); +} + +tbody.list tr{ + vertical-align: top; +} + +.hiddendata{ + display: none; +} + +#formNew{ + display: none; + width: 100%; + padding-bottom: 7px; +} + +.text_output{ + width: 98%; + height: 9em; +} + +.go_right_float{ + float: right; +} + +.go_right{ + width: 100%; + text-align: right; +} + +.width_all{ + width: 100%; +} + +.small_label{ + font-size: small; + font-style: italic; +} + +.field_title{ + font-weight: bold; +} + +.field_title_s{ + font-weight: bold; + font-size: small; +} + +.field_title_us{ + font-weight: bold; + font-size: smaller; +} + +label, .id_show, .text_show, .name_show, .type_show, .action_show{ + font-size: small; +} + +#txtIdNew, .id_output{ + text-transform: lowercase; +} + +#import_export{ + position: absolute; + right:10px; + top:10px; + text-align: right; +} + +#btnExportAll{ + margin-bottom: 3px; +} + +.storage_space{ + font-size: 0.8em; + font-weight: normal; + font-style: italic; + color: rgb(41, 41, 41); + text-align: right; + margin-right: 1px; +} + +.page_title{ + margin-bottom: 0px; +} + +.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; +} + +.need_custom_text_span, .need_selected_span{ + padding-right: 2px; +} + +#chatgpt_web_additional_info_toggle td{ + padding:0px 5px; + font-style: italic; +} + +#chatgpt_web_additional_info, #chatgpt_web_additional_info_toggle, .chatgpt_web_additional_info, .chatgpt_web_additional_info_toggle, .chatgpt_web_additional_info_show{ + background-color: rgb(255, 209, 183); + display:none; +} + +.chatgpt_web_models_list_table{ + background-color: rgb(255, 209, 183); + border:0; +} + +.chatgpt_web_models_list_table *{ + border:0; +} + +.chatgpt_web_models_list_table td{ + padding:2px; +} + +#chatgpt_web_additional_info_toggle, .chatgpt_web_additional_info_toggle{ + cursor: pointer; +} + +#chatgpt_web_additional_info_toggle:hover, .chatgpt_web_additional_info_toggle:hover{ + background-color: rgb(255, 189, 153); + text-decoration: underline; +} + +#chatgpt_web_additional_info_toggle td{ + text-align: center; +} + +#chatgpt_web_additional_info td{ + vertical-align: top; +} + +.chatgpt_web_additional_info_toggle{ + width: -moz-available; + text-align: center; + margin-top: 10px; +} + +.chatgpt_web_additional_info_show{ + flex-direction: column; + justify-content: space-between; + height: 100%; + padding: 3px; + margin-top: 5px; +} + +.chatgpt_web_additional_info_row{ + display: flex; +} + +.chatgpt_web_additional_info_row span{ + margin-right: 0.4em; +} + +input.input_additional[type="text"]{ + width: -moz-available; +} + +.small_info{ + font-size:smaller; +} + +.conntype_chatgpt_web_option{ + cursor: pointer; +} + +@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; } + + table { + background-color: #1C1B22; + border: 1px solid #ccc; + } + + table.prompts_list th { + background-color: #4c4e58; + border: 1px solid rgb(251, 251, 254); + color: rgb(194, 194, 194); + } + + #command_palette{ + background-color: inherit; + } + + table.prompts_list tr:nth-child(even) { + background-color: #2E2F36; + } + + .storage_space{ + color: rgb(182, 182, 182); + } + + .autocomplete-list { + background-color: #2E2F36; + border: 1px solid #2E2F36; + } + + .autocomplete-list li:hover { + background-color: #4c4e58; + } + + .autocomplete-list li.active { + background-color: #4c4e58; + } + + #chatgpt_web_additional_info, #chatgpt_web_additional_info_toggle, .chatgpt_web_additional_info, .chatgpt_web_additional_info_toggle, .chatgpt_web_additional_info_show, .chatgpt_web_models_list_table{ + background-color: rgb(39, 11, 0); + color: rgb(182, 182, 182); + } + + #chatgpt_web_additional_info_toggle:hover, .chatgpt_web_additional_info_toggle:hover{ + background-color: rgb(88, 25, 0); + } +} \ No newline at end of file diff --git a/pages/customdataplaceholders/mzta-custom-dataplaceholders.html b/pages/customdataplaceholders/mzta-custom-dataplaceholders.html new file mode 100644 index 00000000..ea95d2b4 --- /dev/null +++ b/pages/customdataplaceholders/mzta-custom-dataplaceholders.html @@ -0,0 +1,91 @@ + + + + + ThunderAI - __MSG_customDataPH_manageDataPH__ + + + + +
+

__MSG_customDataPH_manageDataPH__

+

__MSG_customDataPH_manageDataPH_info_default__
+ __MSG_customPrompts_managePrompts_info_default_3__ +
__MSG_prefs_OptionText_btnManagePrompts_infoline__ __MSG_more_info_string__

+
+
+
+ +
+
+ + + +
+
+ + + + + + + + + + +
+ +
+ thunderai_custom_ +
[__MSG_customPrompts_form_label_ID_rules__] +
+ +
+
+ + +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
* __MSG_customPrompts_form_required_fields__
+
+
+
+
+ + + + + + + + + + + + +
__MSG_customPrompts_form_label_ID____MSG_customPrompts_form_label_Name____MSG_customDataPH_form_label_Text____MSG_customPrompts_Properties__ 
+
+
__MSG_StorageSpace__:
+ + + + + \ No newline at end of file diff --git a/pages/customdataplaceholders/mzta-custom-dataplaceholders.js b/pages/customdataplaceholders/mzta-custom-dataplaceholders.js new file mode 100644 index 00000000..20f89755 --- /dev/null +++ b/pages/customdataplaceholders/mzta-custom-dataplaceholders.js @@ -0,0 +1,628 @@ +/* + * 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 { getLocalStorageUsedSpace, sanitizeHtml, isThunderbird128OrGreater } from "../../js/mzta-utils.js"; +import { taLogger } from "../../js/mzta-logger.js"; +import { getPlaceholders, setCustomPlaceholders, getCustomPlaceholders, prepareCustomDataPHsForExport, prepareCustomDataPHsForImport, placeholdersUtils } from "../../js/mzta-placeholders.js"; +import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js"; + +let prefs = null; +var customDataPHsList = null; +var somethingChanged = false; +var idnumMax = 0; +var msgTimeout = null; +let taLog = null; +let autocompleteSuggestions = []; + +document.addEventListener('DOMContentLoaded', async () => { + + prefs = await browser.storage.sync.get({ do_debug: prefs_default.do_debug }); + taLog = new taLogger("mzta-custom-dataplaceholders", prefs.do_debug); + + setStorageSpace(); + + let values = await getCustomPlaceholders(); + + //console.log('>>>>>>>>>>>>>>>> values: ' + JSON.stringify(values)); + + loadCustomDataPHsList(values); + + const btnSaveAll = document.getElementById('btnSaveAll'); + btnSaveAll.disabled = true; + + // Disable save button and handle save actions + function handleSaveAllClick(e) { + e.preventDefault(); + saveAll(); + clearFields(); + } + btnSaveAll.addEventListener('click', handleSaveAllClick); + + const btnNew = document.getElementById('btnNew'); + + // Show the new item form + function handleNewClick(e) { + e.preventDefault(); + e.target.disabled = true; + document.getElementById('formNew').style.display = 'block'; + window.scrollTo({ + top: 0, + behavior: 'smooth' + }); + } + btnNew.addEventListener('click', handleNewClick); + + // for the new prompt form + let btnNew_elements = document.querySelectorAll(".input_new"); + if(btnNew_elements) { + btnNew_elements.forEach(element => { + element.addEventListener('change', (e) => { + e.preventDefault(); + checkFields(); + }); + }); + } + + const textareas = document.querySelectorAll('.editor'); + autocompleteSuggestions = (await getPlaceholders()) + .filter(p => p.is_default == "1") + .map(p => ({ command: '{%' + p.id + '%}', type: p.type })); + + // console.log('>>>>>>>>>>> suggestions: ' + JSON.stringify(suggestions)); + + textareas.forEach(textarea => { + textareaAutocomplete(textarea, autocompleteSuggestions); + textareas.forEach(textarea => { + textarea.addEventListener('input', (e) => { + checkPromptsConfigForPlaceholders(e.target); + }); + textareaAutocomplete(textarea, autocompleteSuggestions); + }); + }); + + i18n.updateDocument(); + + //To add a new item + var txtIdNew = document.getElementById('txtIdNew'); + var txtNameNew = document.getElementById('txtNameNew'); + var txtTextNew = document.getElementById('txtTextNew'); + var selectTypeNew = document.getElementById('selectTypeNew'); + var checkboxNeedSelectedNew = document.getElementById('checkboxNeedSelectedNew'); + var checkboxNeedCustomTextNew = document.getElementById('checkboxNeedCustomTextNew'); + + const btnAddNew = document.getElementById('btnAddNew'); + btnAddNew.addEventListener('click', (e) => { + e.preventDefault(); + if(!checkFields()) { + return; + } + let newItemData = { + id: String(txtIdNew.value.trim()).toLocaleLowerCase(), + name: txtNameNew.value.trim(), + text: txtTextNew.value.trim(), + type: selectTypeNew.value, + need_selected: (checkboxNeedSelectedNew.checked) ? 1 : 0, + need_custom_text: (checkboxNeedCustomTextNew.checked) ? 1 : 0, + enabled: 1, + is_default: 0, + idnum: idnumMax + 1, + }; + + let newItem = customDataPHsList.add(newItemData); + idnumMax++; + let curr_idnum = newItem[0].values().idnum; + let checkboxes = document.querySelectorAll(`tr[data-idnum="${curr_idnum}"] input[type="checkbox"]`); + checkSelectedBoxes(checkboxes); + let editBtn = document.querySelector(`tr[data-idnum="${curr_idnum}"] button.btnEditItem`); + //console.log(`>>>>>>>>>>>> tr[data-idnum="${curr_idnum}"] button.btnEditItem`); + editBtn.addEventListener('click', handleEditClick); + //console.log('>>>>>>>>>>>>> editBtn: ' + JSON.stringify(editBtn)); + let deleteBtn = document.querySelector(`tr[data-idnum="${curr_idnum}"] button.btnDeleteItem`); + //console.log(`>>>>>>>>>>>> tr[data-idnum="${curr_idnum}"] button.btnDeleteItem`); + deleteBtn.addEventListener('click', handleDeleteClick); + let okBtn = document.querySelector(`tr[data-idnum="${curr_idnum}"] button.btnConfirmItem`); + okBtn.addEventListener('click', handleConfirmClick); + let cancelBtn = document.querySelector(`tr[data-idnum="${curr_idnum}"] button.btnCancelItem`); + cancelBtn.addEventListener('click', handleCancelClick); + // console.log('>>>>>>>>>>>>> deleteBtn: ' + JSON.stringify(deleteBtn)); + // console.log('>>>>>>>>>>>>> newItem: ' + JSON.stringify(newItem)); + document.getElementById('btnNew').disabled = false; + clearFields(); + setSomethingChanged(); + i18n.updateDocument(); + window.scrollTo({ + top: document.body.scrollHeight, + behavior: 'smooth' + }); + }); + + //Import Export + const btnExportAll = document.getElementById('btnExportAll'); + btnExportAll.addEventListener('click', (e) => { + e.preventDefault(); + exportPrompts(); + }); + + async function exportPrompts() { + const manifest = browser.runtime.getManifest(); + const addonVersion = manifest.version; + const outputPrompts = preparePromptsForExport(await getPrompts()); + let outputObj = {id: 'thunderai-prompts', addon_version: addonVersion, prompts: outputPrompts}; + const blob = new Blob([JSON.stringify(outputObj, null, 2)], { + type: "application/json", + }); + const currentDate = new Date(); + const time_stamp = `${currentDate.getFullYear()}${String(currentDate.getMonth() + 1).padStart(2, '0')}${String(currentDate.getDate()).padStart(2, '0')}${String(currentDate.getHours()).padStart(2, '0')}${String(currentDate.getMinutes()).padStart(2, '0')}${String(currentDate.getSeconds()).padStart(2, '0')}`; + messenger.downloads.download({ + url: URL.createObjectURL(blob), + filename: `thunderai-prompts-${time_stamp}.json`, + saveAs: true, + }); + } + + const btnImport = document.getElementById('btnImport'); + btnImport.addEventListener('click', (e) => { + e.preventDefault(); + importPrompts(); + }); + + function importPrompts() { + if(confirm(browser.i18n.getMessage("importPrompts_confirmText") + '\n' + browser.i18n.getMessage("customPrompts_managePrompts_info_default_2") + '\n' + browser.i18n.getMessage("customPrompts_managePrompts_info_default_3"))) { + //ask the user to choose a JSON file, and then read it, check if the serialized JSON is valid as generated from exportPrompts(), and if so, add it to the list + const input = document.createElement('input'); + input.type = 'file'; + input.accept = '.json'; + input.click(); + input.onchange = async () => { + setMessage(browser.i18n.getMessage('customPrompts_start_import')); + const file = input.files[0]; + const reader = new FileReader(); + reader.onload = async () => { + const json = reader.result; + try { + const obj = JSON.parse(json); + if(obj.id !== 'thunderai-prompts') { + alert(browser.i18n.getMessage("importPrompts_invalidFile")); + setMessage(browser.i18n.getMessage('importPrompts_invalidFile'),'red'); + return; + } + // if(obj.addon_version !== manifest.version) { + // alert(browser.i18n.getMessage("importPrompts_invalidVersion")); + // return; + // } + if(!Array.isArray(obj.prompts)) { + alert(browser.i18n.getMessage("importPrompts_invalidPrompts")); + setMessage(browser.i18n.getMessage('customPrompts_invalidPrompts'),'red'); + return; + } + //setCustomPrompts(obj.prompts); + customDataPHsList.clear(); + loadCustomDataPHsList(await preparePromptsForImport(obj.prompts)); + setSomethingChanged(); + i18n.updateDocument(); + // browser.runtime.sendMessage({command: "reload_menus"}); + setMessage(browser.i18n.getMessage('customPrompts_import_completed'), 'orange'); + // msgTimeout = setTimeout(() => { + // clearMessage(); + // }, 10000); + } catch(err) { + alert(browser.i18n.getMessage("importPrompts_invalidFile") + ' ' + err); + setMessage(browser.i18n.getMessage('importPrompts_invalidFile'),'red'); + return; + } + }; + reader.readAsText(file); + }; + + }; + } + +}, { once: true }); + +//========= handling an item in a row +function handleEditClick(e) { + e.preventDefault(); + const tr = e.target.parentNode.parentNode; + //console.log('>>>>>>>> tr: ' + tr.getAttribute('data-idnum')); + e.target.style.display = 'none'; // Edit btn + tr.querySelector('.btnConfirmItem').style.display = 'inline'; // Save btn + tr.querySelector('.btnCancelItem').style.display = 'inline'; // Cancel btn +// tr.querySelector('.btnEditItem').style.display = 'none'; // Edit btn + tr.querySelector('.btnDeleteItem').style.display = 'none'; // Delete btn + showItemRowEditor(tr); +} + +function showItemRowEditor(tr) { + tr.querySelector('.id_output').style.display = 'inline'; + tr.querySelector('.id_show').style.display = 'none'; + tr.querySelector('.name_output').style.display = 'inline'; + tr.querySelector('.name_show').style.display = 'none'; + const text_output = tr.querySelector('.text_output'); + text_output.style.display = 'inline'; + textareaAutocomplete(text_output, autocompleteSuggestions) + tr.querySelector('.text_show').style.display = 'none'; + tr.querySelector('.type_output').style.display = 'inline'; + tr.querySelector('.type_show').style.display = 'none'; + tr.querySelector('input.need_selected').disabled = false; + tr.querySelector('input.need_custom_text').disabled = false; +} + +function hideItemRowEditor(tr) { + tr.querySelector('.id_output').style.display = 'none'; + tr.querySelector('.id_show').style.display = 'inline'; + tr.querySelector('.name_output').style.display = 'none'; + tr.querySelector('.name_show').style.display = 'inline'; + tr.querySelector('.text_output').style.display = 'none'; + tr.querySelector('.text_show').style.display = 'inline'; + tr.querySelector('.type_output').style.display = 'none'; + tr.querySelector('.type_show').style.display = 'inline'; + tr.querySelector('input.need_selected').disabled = true; + tr.querySelector('input.need_custom_text').disabled = true; +} + +// Confirm and log deletion action +function handleDeleteClick(e) { + e.preventDefault(); + const checkConfirm = window.confirm(browser.i18n.getMessage("customPrompts_btnDelete_confirmText")); + if (!checkConfirm) { + return; + } + const tr = e.target.parentNode.parentNode; + //console.log('>>>>>>>> tr: ' + tr.getAttribute('data-idnum')); + customDataPHsList.remove("id", tr.querySelector('span.id').innerText); + setSomethingChanged(); +} + +function handleCancelClick(e) { + e.preventDefault(); + const tr = e.target.parentNode.parentNode; + e.target.style.display = 'none'; // Cancel btn + tr.querySelector('.btnConfirmItem').style.display = 'none'; // Save btn +// tr.querySelector('.btnCancelItem').style.display = 'none'; // Cancel btn + tr.querySelector('.btnEditItem').style.display = 'inline'; // Edit btn + tr.querySelector('.btnDeleteItem').style.display = 'inline'; // Delete btn + tr.querySelector('.id_output').value = tr.querySelector('.id_show').innerText.toLocaleUpperCase(); + tr.querySelector('.name_output').value = tr.querySelector('.name_show').innerText; + tr.querySelector('.text_output').value = sanitizeHtml(tr.querySelector('.text_show').innerHTML).replace(//gi, "\n"); + tr.querySelector('.type_output').value = tr.querySelector('.type').innerText; + hideItemRowEditor(tr); +} + +function handleConfirmClick(e) { + e.preventDefault(); + const tr = e.target.parentNode.parentNode; + e.target.style.display = 'none'; // Ok btn +// tr.querySelector('.btnConfirmItem').style.display = 'none'; // Ok btn + tr.querySelector('.btnCancelItem').style.display = 'none'; // Cancel btn + tr.querySelector('.btnEditItem').style.display = 'inline'; // Edit btn + tr.querySelector('.btnDeleteItem').style.display = 'inline'; // Delete btn + // Update item data + tr.querySelector('.id_show').innerText = String(tr.querySelector('.id_output').value).toLocaleLowerCase(); + tr.querySelector('.name_show').innerText = tr.querySelector('.name_output').value; + tr.querySelector('.text_show').innerText = tr.querySelector('.text_output').value; + tr.querySelector('.type').innerText = tr.querySelector('.type_output').value; + tr.querySelector('.type_show').innerText = tr.querySelector('.type_output').selectedOptions[0].text; + // the checkboxes update is handled directly by themselves + hideItemRowEditor(tr); + setSomethingChanged(); +} + +// Handle checkbox changes and log new state +function handleCheckboxChange(e) { + e.preventDefault(); + e.target.setAttribute('checked_val', e.target.checked ? '1' : '0'); + //console.log('>>>>>>>> checked_val: ' + e.target.getAttribute('checked_val')); + if (e.target.classList.contains('need_selected') || e.target.classList.contains('need_custom_text') || e.target.classList.contains('need_selected_new') || e.target.classList.contains('need_custom_text_new')) { + let textarea = e.target.closest('tr').querySelector('.text_output'); + checkPromptsConfigForPlaceholders(textarea); + } + +} + +// Enable save button on input change +function handleInputChange(e) { + e.preventDefault(); + setSomethingChanged(); +} + +//========= handling an item in a row - END + + +function loadCustomDataPHsList(values){ + // console.log('>>>>>>>> loadCustomDataPHsList values: ' + JSON.stringify(values)); + let options = { + valueNames: [ + { data: ['idnum'] }, + 'is_default', + 'id', + 'name', + 'text', + 'type', + { name: 'need_selected', attr: 'checked_val'}, + { name: 'need_custom_text', attr: 'checked_val'}, + { name: 'enabled', attr: 'checked_val'} + ], + item: function(values) { + values.id = placeholdersUtils.stripCustomDataPH_ID_Prefix(values.id); + let type_output = ''; + switch(String(values.type)){ + case "0": + type_output = `__MSG_customPrompts_add_to_menu_always__`; + break; + case "1": + type_output = `__MSG_customPrompts_add_to_menu_reading__`; + break; + case "2": + type_output = `__MSG_customPrompts_add_to_menu_composing__`; + break; + } + let output = ` + thunderai_custom_ + + + +
+ + +
+ + __MSG_customPrompts_add_to_menu__: +
+ ` + type_output + ` + ` + + ` + + + +
+ +
+ + + + + + + + +

+ + + + `; + //console.log('>>>>>>>> values.name: ' + JSON.stringify(values.name)); + idnumMax = Math.max(idnumMax, values.idnum); + return output; + } + }; + + // console.log('>>>>>>>>>>>>> options: ' + JSON.stringify(options)); + // console.log('>>>>>>>>>>>>> values: ' + JSON.stringify(values)); + + customDataPHsList = new List('all_custom_dataplaceholders', options, values); + + checkSelectedBoxes(); + let btnEditItem_elements = document.querySelectorAll(".btnEditItem"); + btnEditItem_elements.forEach(element => { + element.addEventListener('click', handleEditClick); + }); + + let btnDeleteItem_elements = document.querySelectorAll(".btnDeleteItem"); + btnDeleteItem_elements.forEach(element => { + element.addEventListener('click', handleDeleteClick); + }); + + let btnCancelItem_elements = document.querySelectorAll(".btnCancelItem"); + btnCancelItem_elements.forEach(element => { + element.addEventListener('click', handleCancelClick); + }); + + let btnConfirmItem_elements = document.querySelectorAll(".btnConfirmItem"); + btnConfirmItem_elements.forEach(element => { + element.addEventListener('click', handleConfirmClick); + }); + + let checkbox_elements = document.querySelectorAll("input[type='checkbox']"); + checkbox_elements.forEach(element => { + element.addEventListener('change', handleCheckboxChange); + }); + + document.querySelectorAll('.input_mod').forEach(element => { + element.addEventListener('change', handleInputChange); + }); +} + +function checkFields() { + //console.log('>>>>>>>>>>>>> typeof customDataPHsList: ' + typeof customDataPHsList); + //console.log('>>>>>>>>>>>>> Array.isArray(customDataPHsList): ' + Array.isArray(customDataPHsList)); + // the id must be unique and without spaces + let is_error = false; + let id_value = document.getElementById('txtIdNew').value.trim(); + if ((id_value == '')|| + (/\s/.test(id_value))) { + inputSetError('txtIdNew'); + is_error = true; + } else { + let exists = customDataPHsList.get("id", id_value); + //console.log('>>>>>>>>>>>>> exists: ' + JSON.stringify(exists)); + if(exists && exists.length > 0) { + inputSetError('txtIdNew'); + is_error = true; + } else { + inputClearError('txtIdNew'); + } + } + if (document.getElementById('txtNameNew').value.trim() == '') { + inputSetError('txtNameNew'); + is_error = true; + } else { + inputClearError('txtNameNew'); + } + if (document.getElementById('txtTextNew').value.trim() == '') { + inputSetError('txtTextNew'); + is_error = true; + } else { + inputClearError('txtTextNew'); + } + document.getElementById('btnAddNew').disabled = is_error; + return !is_error; +} + + +function clearFields() { + document.getElementById('txtIdNew').value = ''; + document.getElementById('txtNameNew').value = ''; + document.getElementById('txtTextNew').value = ''; + document.getElementById('selectTypeNew').value = '0'; + document.getElementById('checkboxNeedSelectedNew').value = '0'; + document.getElementById('checkboxNeedCustomTextNew').value = '0'; + document.getElementById('formNew').style.display = 'none'; +} + +function inputSetError(input) { + document.getElementById(input).style.borderColor = 'red'; +} + +function inputClearError(input) { + document.getElementById(input).style.borderColor = 'green'; +} + +function setSomethingChanged(){ + clearTimeout(msgTimeout); + somethingChanged = true; + document.getElementById('btnSaveAll').disabled = false; + let msgDisplay = document.getElementById('msgDisplay'); + msgDisplay.textContent = browser.i18n.getMessage('customPrompts_unsaved_changes'); + msgDisplay.style.display = 'inline'; + msgDisplay.style.color = 'red'; +} + +function setNothingChanged(){ + somethingChanged = false; + document.getElementById('btnSaveAll').disabled = true; + let msgDisplay = document.getElementById('msgDisplay'); + msgDisplay.disabled = true; + msgDisplay.textContent = '' + msgDisplay.style.display = 'none'; + msgDisplay.style.color = ''; +} + +function checkSelectedBoxes(checkboxes = null) { + if(checkboxes == null){ + checkboxes = [ + ...document.querySelectorAll('.need_selected[type="checkbox"]'), + ...document.querySelectorAll('.need_custom_text[type="checkbox"]'), + ...document.querySelectorAll('.enabled[type="checkbox"]'), + ]; + } + + // Iterate through the checkboxes + checkboxes.forEach(checkbox => { + // Check if the 'checked' attribute is "0" + if (checkbox.getAttribute('checked_val') == "0") { + // Uncheck the checkbox + checkbox.checked = false; + } else { + checkbox.checked = true; + } + }); +} + +//Save all custom data placeholders +async function saveAll() { + setMessage(browser.i18n.getMessage('customDataPH_start_saving')); + setNothingChanged(); + if(customDataPHsList != null) { + setMessage(browser.i18n.getMessage('customPrompts_reindexing_list')); + customDataPHsList.reIndex(); + let newCustomDataPHs = customDataPHsList.items.filter(item => item.values().is_default == 0).map(item => item.values()); + taLog.log('newCustomDataPlaceholders: ' + JSON.stringify(newCustomDataPHs)); + // newCustomDataPHs.forEach(prompt => { + // console.log('>>>>>>>>>>>>> id: ' + JSON.stringify(prompt)); + // }); + //console.log('>>>>>>>>>>>>> saveAll: ' + JSON.stringify(newCustomDataPHs)); + await setCustomPlaceholders(newCustomDataPHs); + setMessage(browser.i18n.getMessage('customDataPH_saved'),'green'); + msgTimeout = setTimeout(() => { + clearMessage(); + }, 10000) + } + setStorageSpace(); +} + +function setMessage(msg, color = '') { + clearTimeout(msgTimeout); + let msgDisplay = document.getElementById('msgDisplay'); + msgDisplay.textContent = msg; + msgDisplay.style.display = 'inline'; + msgDisplay.style.color = color; +} + +function clearMessage() { + let msgDisplay = document.getElementById('msgDisplay'); + msgDisplay.textContent = ''; + msgDisplay.style.display = 'none'; + msgDisplay.style.color = ''; +} + +async function setStorageSpace() { + let storage_space = await getLocalStorageUsedSpace(); + document.getElementById('storage_space').textContent = storage_space; +} + + +if(await isThunderbird128OrGreater()){ + window.addEventListener('beforeunload', function (event) { + // Check if any changes have been made (Only for Thunderbird 128+ see https://github.com/micz/ThunderAI/issues/88) + if (somethingChanged) { + event.preventDefault(); + } + }); +} + +function checkPromptsConfigForPlaceholders(textarea){ + // check additional_text and selected_text placeholders presence and the corrispondent checkboxes + let tr_ancestor = textarea.closest('tr'); + let need_custom_text_element = tr_ancestor.querySelector('.need_custom_text') || tr_ancestor.querySelector('.need_custom_text_new'); + if(String(textarea.value).indexOf('{%additional_text%}') != -1){ + if(!need_custom_text_element.checked){ + need_custom_text_element.closest('.need_custom_text_span').style.border = '2px solid red'; + }else{ + need_custom_text_element.closest('.need_custom_text_span').style.border = ''; + } + }else{ + need_custom_text_element.closest('.need_custom_text_span').style.border = ''; + } + + let tr_ancestor2 = textarea.closest('tr'); + let selected_text_element = tr_ancestor2.querySelector('.need_selected') || tr_ancestor2.querySelector('.need_selected_new'); + if((String(textarea.value).indexOf('{%selected_text%}') != -1)||(String(textarea.value).indexOf('{%selected_html%}') != -1)){ + if(!selected_text_element.checked){ + selected_text_element.closest('.need_selected_span').style.border = '2px solid red'; + }else{ + selected_text_element.closest('.need_selected_span').style.border = ''; + } + }else{ + selected_text_element.closest('.need_selected_span').style.border = ''; + } +} \ No newline at end of file