Merge pull request #428 from micz/custom_dataplaceholders
Custom dataplaceholders
This commit is contained in:
commit
46dc69fa5b
28 changed files with 1248 additions and 93 deletions
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
<h2>Version 3.6.0 - ??/??/2025</h2>
|
||||
<ul>
|
||||
<li>Now it's possibile to define custom data placeholders to be used in custom prompts [<a href="https://github.com/micz/ThunderAI/issues/156">#156</a>].</li>
|
||||
<li>When replying, it's now possibile to choose a different reply type (between "all" or "sender only") directly in the AI chat window [<a href="https://github.com/micz/ThunderAI/issues/372">#372</a>].</li>
|
||||
<li><i>[All APIs]</i> Added an option to choose to exclude a tag only with an exact match in the excluded words list [<a href="https://github.com/micz/ThunderAI/issues/395">#395</a>].</li>
|
||||
<li><i>[OpenAI API]</i> Added an option to enable the OpenAI storage for API requests [<a href="https://github.com/micz/ThunderAI/issues/406">#406</a>].</li>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
"prompt_this": {
|
||||
"message": "Zeptat se"
|
||||
},
|
||||
"customPrompts_managePrompts_help": {
|
||||
"more_info_string": {
|
||||
"message": "Další informace"
|
||||
},
|
||||
"customPrompts_start_saving": {
|
||||
|
|
@ -80,13 +80,13 @@
|
|||
"customPrompts_form_label_enabled": {
|
||||
"message": "Povoleno"
|
||||
},
|
||||
"customPrompts_btnSaveAll": {
|
||||
"btnSaveAll_string": {
|
||||
"message": "Uložit vše"
|
||||
},
|
||||
"customPrompts_do_reply": {
|
||||
"message": "Odpovědět"
|
||||
},
|
||||
"customPrompts_btnNew": {
|
||||
"btnNew_string": {
|
||||
"message": "Přidat nový"
|
||||
},
|
||||
"customPrompts_close_button": {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"customPrompts_managePrompts": {
|
||||
"message": "Eingabeaufforderungen verwalten"
|
||||
},
|
||||
"customPrompts_managePrompts_help": {
|
||||
"more_info_string": {
|
||||
"message": "Informationen"
|
||||
},
|
||||
"customPrompts_managePrompts_info_default": {
|
||||
|
|
@ -120,10 +120,10 @@
|
|||
"customPrompts_unsaved_changes": {
|
||||
"message": "Es gibt ungespeicherte Änderungen!"
|
||||
},
|
||||
"customPrompts_btnSaveAll": {
|
||||
"btnSaveAll_string": {
|
||||
"message": "Alle speichern"
|
||||
},
|
||||
"customPrompts_btnNew": {
|
||||
"btnNew_string": {
|
||||
"message": "Neu hinzufügen"
|
||||
},
|
||||
"customPrompts_btnAddNewCommit": {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
"message": "Manage Prompts",
|
||||
"description": ""
|
||||
},
|
||||
"customPrompts_managePrompts_help": {
|
||||
"more_info_string": {
|
||||
"message": "More info",
|
||||
"description": ""
|
||||
},
|
||||
|
|
@ -167,11 +167,11 @@
|
|||
"message": "There are unsaved changes!",
|
||||
"description": ""
|
||||
},
|
||||
"customPrompts_btnSaveAll": {
|
||||
"btnSaveAll_string": {
|
||||
"message": "Save All",
|
||||
"description": ""
|
||||
},
|
||||
"customPrompts_btnNew": {
|
||||
"btnNew_string": {
|
||||
"message": "Add New",
|
||||
"description": ""
|
||||
},
|
||||
|
|
@ -315,6 +315,10 @@
|
|||
"message": "Manage your prompts",
|
||||
"description": ""
|
||||
},
|
||||
"prefs_OptionText_btnManageCustomDataPH": {
|
||||
"message": "Manage your data placeholders",
|
||||
"description": ""
|
||||
},
|
||||
"prefsInfoTitle": {
|
||||
"message": "Important Information",
|
||||
"description": ""
|
||||
|
|
@ -1555,5 +1559,61 @@
|
|||
"prefs_OptionText_add_tags_exclusions_exact_match_Info": {
|
||||
"message": "If checked, the tags in the exclusion list will be matched exactly, otherwise they will be matched partially.",
|
||||
"description": ""
|
||||
},
|
||||
"customDataPH_manageDataPH": {
|
||||
"message": "Manage Data Placeholders",
|
||||
"description": ""
|
||||
},
|
||||
"customDataPH_manageDataPH_info_default": {
|
||||
"message": "You can import and export the custom data placeholders. Existing data placeholders with the same ID will be overwritten. Placeholders with new IDs will be added.",
|
||||
"description": ""
|
||||
},
|
||||
"customDataPH_ExportAll": {
|
||||
"message": "Export all custom data placeholders",
|
||||
"description": ""
|
||||
},
|
||||
"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": ""
|
||||
},
|
||||
"importCustomDataPH_confirmText": {
|
||||
"message": "You are about to import new custom data placeholders.",
|
||||
"description": ""
|
||||
},
|
||||
"importCustomDataPH_start_import": {
|
||||
"message": "Starting custom data placeholders import...",
|
||||
"description": ""
|
||||
},
|
||||
"importCustomDataPH_import_completed": {
|
||||
"message": "Custom data placeholders import completed! You need to click on the 'Save All' button to save your changes.",
|
||||
"description": ""
|
||||
},
|
||||
"importCustomDataPH_invalidFile": {
|
||||
"message": "The file you're trying to import is not a valid custom data placeholders file.",
|
||||
"description": ""
|
||||
},
|
||||
"importCustomDataPH_invalidDataPHs": {
|
||||
"message": "The file you're trying to import does not contain any valid custom data placeholders.",
|
||||
"description": ""
|
||||
},
|
||||
"customDataPH_add_to_menu": {
|
||||
"message": "Usable in prompts added to menu",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"prompt_rewrite_formal": {
|
||||
"message": "Reverki formale"
|
||||
},
|
||||
"customPrompts_managePrompts_help": {
|
||||
"more_info_string": {
|
||||
"message": "Pliaj informoj"
|
||||
},
|
||||
"customPrompts_managePrompts": {
|
||||
|
|
@ -20,10 +20,10 @@
|
|||
"customPrompts_form_required_fields": {
|
||||
"message": "Postulataj kampoj"
|
||||
},
|
||||
"customPrompts_btnSaveAll": {
|
||||
"btnSaveAll_string": {
|
||||
"message": "Konservi ĉion"
|
||||
},
|
||||
"customPrompts_btnNew": {
|
||||
"btnNew_string": {
|
||||
"message": "Aldoni novan"
|
||||
},
|
||||
"chatgpt_btn_retry": {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"customPrompts_managePrompts": {
|
||||
"message": "Gérer les prompts"
|
||||
},
|
||||
"customPrompts_managePrompts_help": {
|
||||
"more_info_string": {
|
||||
"message": "Informations"
|
||||
},
|
||||
"customPrompts_managePrompts_info_default": {
|
||||
|
|
@ -120,10 +120,10 @@
|
|||
"customPrompts_unsaved_changes": {
|
||||
"message": "Il y a des modifications non enregistrées !"
|
||||
},
|
||||
"customPrompts_btnSaveAll": {
|
||||
"btnSaveAll_string": {
|
||||
"message": "Tout enregistrer"
|
||||
},
|
||||
"customPrompts_btnNew": {
|
||||
"btnNew_string": {
|
||||
"message": "Ajouter nouveau"
|
||||
},
|
||||
"customPrompts_btnAddNewCommit": {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"customPrompts_managePrompts": {
|
||||
"message": "Upravljaj upitima"
|
||||
},
|
||||
"customPrompts_managePrompts_help": {
|
||||
"more_info_string": {
|
||||
"message": "Više informacija"
|
||||
},
|
||||
"customPrompts_managePrompts_info_default": {
|
||||
|
|
@ -120,10 +120,10 @@
|
|||
"customPrompts_unsaved_changes": {
|
||||
"message": "Ima nespremljenih promjena!"
|
||||
},
|
||||
"customPrompts_btnSaveAll": {
|
||||
"btnSaveAll_string": {
|
||||
"message": "Spremi sve"
|
||||
},
|
||||
"customPrompts_btnNew": {
|
||||
"btnNew_string": {
|
||||
"message": "Dodaj novo"
|
||||
},
|
||||
"customPrompts_btnAddNewCommit": {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"customPrompts_managePrompts": {
|
||||
"message": "Gestisci i prompt"
|
||||
},
|
||||
"customPrompts_managePrompts_help": {
|
||||
"more_info_string": {
|
||||
"message": "Informazioni"
|
||||
},
|
||||
"customPrompts_managePrompts_info_default": {
|
||||
|
|
@ -120,10 +120,10 @@
|
|||
"customPrompts_unsaved_changes": {
|
||||
"message": "Ci sono modifiche non salvate!"
|
||||
},
|
||||
"customPrompts_btnSaveAll": {
|
||||
"btnSaveAll_string": {
|
||||
"message": "Salva Tutto"
|
||||
},
|
||||
"customPrompts_btnNew": {
|
||||
"btnNew_string": {
|
||||
"message": "Aggiungi Nuovo"
|
||||
},
|
||||
"customPrompts_btnAddNewCommit": {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"customPrompts_managePrompts": {
|
||||
"message": "Zarządzaj poleceniami"
|
||||
},
|
||||
"customPrompts_managePrompts_help": {
|
||||
"more_info_string": {
|
||||
"message": "Więcej informacji"
|
||||
},
|
||||
"customPrompts_managePrompts_info_default": {
|
||||
|
|
@ -120,10 +120,10 @@
|
|||
"customPrompts_unsaved_changes": {
|
||||
"message": "Istnieją niezapisane zmiany!"
|
||||
},
|
||||
"customPrompts_btnSaveAll": {
|
||||
"btnSaveAll_string": {
|
||||
"message": "Zapisz wszystko"
|
||||
},
|
||||
"customPrompts_btnNew": {
|
||||
"btnNew_string": {
|
||||
"message": "Dodaj nowe"
|
||||
},
|
||||
"customPrompts_btnAddNewCommit": {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"customPrompts_managePrompts": {
|
||||
"message": "Gerenciar Prompts"
|
||||
},
|
||||
"customPrompts_managePrompts_help": {
|
||||
"more_info_string": {
|
||||
"message": "Mais informações"
|
||||
},
|
||||
"customPrompts_managePrompts_info_default": {
|
||||
|
|
@ -120,10 +120,10 @@
|
|||
"customPrompts_unsaved_changes": {
|
||||
"message": "Existem alterações não salvas!"
|
||||
},
|
||||
"customPrompts_btnSaveAll": {
|
||||
"btnSaveAll_string": {
|
||||
"message": "Salvar Tudo"
|
||||
},
|
||||
"customPrompts_btnNew": {
|
||||
"btnNew_string": {
|
||||
"message": "Adicionar Novo"
|
||||
},
|
||||
"customPrompts_btnAddNewCommit": {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
"ChatGPT_Models_Fetch": {
|
||||
"message": "Обновить список моделей ChatGPT"
|
||||
},
|
||||
"customPrompts_managePrompts_help": {
|
||||
"more_info_string": {
|
||||
"message": "Дополнительная информация"
|
||||
},
|
||||
"customPrompts_btnEdit": {
|
||||
|
|
@ -110,10 +110,10 @@
|
|||
"customPrompts_btnDelete_confirmText": {
|
||||
"message": "Вы уверены, что хотите удалить этот элемент?"
|
||||
},
|
||||
"customPrompts_btnSaveAll": {
|
||||
"btnSaveAll_string": {
|
||||
"message": "Сохранить все"
|
||||
},
|
||||
"customPrompts_btnNew": {
|
||||
"btnNew_string": {
|
||||
"message": "Добавить новый"
|
||||
},
|
||||
"customPrompts_btnAddNewCommit": {
|
||||
|
|
|
|||
|
|
@ -38,13 +38,13 @@
|
|||
"customPrompts_form_label_need_signature": {
|
||||
"message": "始终添加签名"
|
||||
},
|
||||
"customPrompts_btnNew": {
|
||||
"btnNew_string": {
|
||||
"message": "新增"
|
||||
},
|
||||
"chatgpt_win_job_completed": {
|
||||
"message": "完成了!"
|
||||
},
|
||||
"customPrompts_btnSaveAll": {
|
||||
"btnSaveAll_string": {
|
||||
"message": "保存所有变动"
|
||||
},
|
||||
"extensionDescription": {
|
||||
|
|
@ -65,7 +65,7 @@
|
|||
"customPrompts_managePrompts": {
|
||||
"message": "管理提示词"
|
||||
},
|
||||
"customPrompts_managePrompts_help": {
|
||||
"more_info_string": {
|
||||
"message": "更多信息"
|
||||
},
|
||||
"customPrompts_managePrompts_info_default": {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"customPrompts_managePrompts_help": {
|
||||
"more_info_string": {
|
||||
"message": "更多資訊"
|
||||
},
|
||||
"prompt_reply_advanced": {
|
||||
|
|
@ -113,10 +113,10 @@
|
|||
"customPrompts_unsaved_changes": {
|
||||
"message": "有未儲存的變動!"
|
||||
},
|
||||
"customPrompts_btnSaveAll": {
|
||||
"btnSaveAll_string": {
|
||||
"message": "儲存全部"
|
||||
},
|
||||
"customPrompts_btnNew": {
|
||||
"btnNew_string": {
|
||||
"message": "新增"
|
||||
},
|
||||
"customPrompts_btnAddNewCommit": {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'mail_html_body',
|
||||
|
|
@ -48,6 +49,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'mail_typed_text',
|
||||
|
|
@ -55,6 +57,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 2,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'mail_quoted_text',
|
||||
|
|
@ -62,6 +65,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 2,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'mail_subject',
|
||||
|
|
@ -69,6 +73,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'mail_folder_name',
|
||||
|
|
@ -76,6 +81,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 1,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'mail_folder_path',
|
||||
|
|
@ -83,6 +89,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 1,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'selected_text',
|
||||
|
|
@ -90,6 +97,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'selected_html',
|
||||
|
|
@ -97,6 +105,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'additional_text',
|
||||
|
|
@ -104,6 +113,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'junk_score',
|
||||
|
|
@ -111,6 +121,7 @@ const defaultPlaceholders = [
|
|||
default_value: "0",
|
||||
type: 1,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'recipients',
|
||||
|
|
@ -118,6 +129,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'cc_list',
|
||||
|
|
@ -125,6 +137,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'author',
|
||||
|
|
@ -132,6 +145,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'mail_datetime',
|
||||
|
|
@ -139,6 +153,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 1,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'current_datetime',
|
||||
|
|
@ -146,6 +161,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'account_email_address',
|
||||
|
|
@ -153,6 +169,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'tags_current_email',
|
||||
|
|
@ -160,6 +177,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'tags_full_list',
|
||||
|
|
@ -167,6 +185,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'thunderai_def_sign',
|
||||
|
|
@ -174,6 +193,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'thunderai_def_lang',
|
||||
|
|
@ -181,6 +201,7 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
{
|
||||
id: 'empty',
|
||||
|
|
@ -188,12 +209,13 @@ const defaultPlaceholders = [
|
|||
default_value: "",
|
||||
type: 0,
|
||||
is_default: "1",
|
||||
enabled: 1,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
export async function getPlaceholders(onlyEnabled = false){
|
||||
const _defaultPlaceholders = await getDefaultPlaceholders_withProps();
|
||||
const _defaultPlaceholders = await getDefaultPlaceholders();
|
||||
// console.log('>>>>>>>>>>>> getPlaceholders _defaultPlaceholders: ' + JSON.stringify(_defaultPlaceholders));
|
||||
const customPlaceholders = await getCustomPlaceholders();
|
||||
// console.log('>>>>>>>>>>>> getPlaceholders customPlaceholders: ' + JSON.stringify(customPlaceholders));
|
||||
|
|
@ -207,32 +229,14 @@ export async function getPlaceholders(onlyEnabled = false){
|
|||
return output;
|
||||
}
|
||||
|
||||
async function getDefaultPlaceholders_withProps() {
|
||||
let prefs = await browser.storage.local.get({_default_placeholders_properties: null});
|
||||
// console.log('>>>>>>>>>>>> getDefaultPlaceholders_withProps prefs: ' + JSON.stringify(prefs));
|
||||
//let defaultPlaceholders_prop = [...defaultPlaceholders];
|
||||
async function getDefaultPlaceholders() {
|
||||
let defaultPlaceholders_prop = JSON.parse(JSON.stringify(defaultPlaceholders));
|
||||
// console.log('>>>>>>>>>>>> getDefaultPlaceholders_withProps defaultPlaceholders: ' + JSON.stringify(defaultPlaceholders));
|
||||
// console.log('>>>>>>>>>>>> getDefaultPlaceholders_withProps defaultPlaceholders_prop: ' + JSON.stringify(defaultPlaceholders_prop));
|
||||
if(prefs._default_placeholders_properties === null){ // no default Placeholders properties saved
|
||||
defaultPlaceholders_prop.forEach((placeholder) => {
|
||||
placeholder.enabled = 1;
|
||||
})
|
||||
// console.log('>>>>>>>>>>>> getDefaultPlaceholders_withProps [no prop saved] defaultPlaceholders_prop: ' + JSON.stringify(defaultPlaceholders_prop));
|
||||
} else { // we have saved default Placeholders properties
|
||||
defaultPlaceholders_prop.forEach((placeholder) => {
|
||||
if(prefs._default_Placeholders_properties?.[placeholder.id]){
|
||||
placeholder.enabled = prefs._default_Placeholders_properties[placeholder.id].enabled;
|
||||
}else{
|
||||
placeholder.enabled = 1;
|
||||
}
|
||||
})
|
||||
// console.log('>>>>>>>>>>>> getDefaultPlaceholders_withProps [prop saved] defaultPlaceholders_prop: ' + JSON.stringify(defaultPlaceholders_prop));
|
||||
}
|
||||
return defaultPlaceholders_prop;
|
||||
}
|
||||
|
||||
async function getCustomPlaceholders() {
|
||||
export async function getCustomPlaceholders() {
|
||||
let prefs = await browser.storage.local.get({_custom_placeholder: null});
|
||||
if(prefs._custom_placeholder === null){
|
||||
return [];
|
||||
|
|
@ -241,22 +245,61 @@ async function getCustomPlaceholders() {
|
|||
}
|
||||
}
|
||||
|
||||
export async function setDefaultPlaceholdersProperties(placeholders) {
|
||||
let default_placeholders_properties = {};
|
||||
placeholders.forEach((placeholder) => {
|
||||
default_placeholders_properties[placeholder.id] = {enabled: placeholder.enabled};
|
||||
export async function setCustomPlaceholders(placeholders) {
|
||||
placeholders.forEach(ph => {
|
||||
ph.id = placeholdersUtils.validateCustomDataPH_ID(ph.id);
|
||||
ph.is_default = "0";
|
||||
});
|
||||
//console.log('>>>>>>>>>>>>>> default_placeholders_properties: ' + JSON.stringify(default_placeholders_properties));
|
||||
await browser.storage.local.set({_default_placeholders_properties: default_placeholders_properties});
|
||||
await browser.storage.local.set({_custom_placeholder: placeholders});
|
||||
}
|
||||
|
||||
export async function setCustomPlaceholders(placeholders) {
|
||||
await browser.storage.local.set({_custom_placeholder: placeholders});
|
||||
export function prepareCustomDataPHsForExport(placeholders){
|
||||
let output = [...placeholders];
|
||||
output.forEach(placeholder => {
|
||||
if(placeholder.is_default == 0){
|
||||
delete placeholder['idnum'];
|
||||
}
|
||||
});
|
||||
return output;
|
||||
}
|
||||
|
||||
export async function prepareCustomDataPHsForImport(placeholders){
|
||||
// console.log(">>>>>>>>>>> prepareCustomDataPHsForImport prompts: " + JSON.stringify(prompts));
|
||||
const output = await getCustomPlaceholders();
|
||||
// console.log(">>>>>>>>>>> prepareCustomDataPHsForImport output: " + JSON.stringify(output));
|
||||
placeholders.forEach(placeholder => {
|
||||
if(output.some(p => p.id == placeholder.id)){
|
||||
Object.keys(placeholder).forEach(key => {
|
||||
output.find(p => p.id == placeholder.id)[key] = placeholder[key];
|
||||
})
|
||||
}else{
|
||||
output.push(placeholder);
|
||||
}
|
||||
});
|
||||
output.sort((a, b) => a.id.localeCompare(b.id));
|
||||
// console.log(">>>>>>>>>>> prepareCustomDataPHsForImport final output: " + JSON.stringify(output));
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
export const placeholdersUtils = {
|
||||
|
||||
customPrefix: 'thunderai_custom_',
|
||||
|
||||
validateCustomDataPH_ID(placeholder_id){
|
||||
if (!placeholder_id.startsWith(this.customPrefix)) {
|
||||
return this.customPrefix + placeholder_id;
|
||||
}
|
||||
return placeholder_id;
|
||||
},
|
||||
|
||||
stripCustomDataPH_ID_Prefix(placeholder_id){
|
||||
if (placeholder_id.startsWith(this.customPrefix)) {
|
||||
return placeholder_id.substring(this.customPrefix.length);
|
||||
}
|
||||
return placeholder_id;
|
||||
},
|
||||
|
||||
async extractPlaceholders(text) {
|
||||
// Regular expression to match patterns like {%...%}
|
||||
const regex = /{%\s*(.*?)\s*%}/g;
|
||||
|
|
@ -292,6 +335,19 @@ export const placeholdersUtils = {
|
|||
});
|
||||
},
|
||||
|
||||
async replaceCustomPlaceholders(text) {
|
||||
let customPlaceholders = await getCustomPlaceholders(true);
|
||||
// Regular expression to match patterns like {%thunderai_custom_...%}
|
||||
return text.replace(/{%\s*thunderai_custom_(.*?)\s*%}/g, function(match, p1) {
|
||||
// p1 contains the key inside {% %}
|
||||
const currPlaceholder = customPlaceholders.find(ph => ph.id === 'thunderai_custom_' + p1);
|
||||
if (!currPlaceholder) {
|
||||
return match;
|
||||
}
|
||||
return currPlaceholder.text;
|
||||
});
|
||||
},
|
||||
|
||||
hasPlaceholder(text, placeholder = "") {
|
||||
let regex;
|
||||
|
||||
|
|
@ -306,9 +362,30 @@ export const placeholdersUtils = {
|
|||
|
||||
// Check if the specific or any placeholder is present in the text
|
||||
return regex.test(text);
|
||||
},
|
||||
},
|
||||
|
||||
hasCustomPlaceholder(text, placeholder = "") {
|
||||
let regex;
|
||||
|
||||
// If a specific placeholder is provided, we search for it
|
||||
if (placeholder !== "") {
|
||||
// Dynamically build the regex for the specific placeholder
|
||||
regex = new RegExp(`{%\s*${placeholder}\s*%}`);
|
||||
} else {
|
||||
// Otherwise, we search for any placeholder in the format {%thunderai_custom_ ... %}
|
||||
regex = /{%\s*thunderai_custom_(.*?)\s*%}/;
|
||||
}
|
||||
|
||||
// Check if the specific or any placeholder is present in the text
|
||||
return regex.test(text);
|
||||
},
|
||||
|
||||
async getPlaceholdersValues(prompt_text, curr_message, mail_subject, body_text, msg_text, only_typed_text, only_quoted_text, selection_text, selection_html, tags_full_list) {
|
||||
// check if we have custom placeholders
|
||||
if(placeholdersUtils.hasCustomPlaceholder(prompt_text)){
|
||||
prompt_text = await placeholdersUtils.replaceCustomPlaceholders(prompt_text);
|
||||
}
|
||||
|
||||
let currPHs = await placeholdersUtils.extractPlaceholders(prompt_text);
|
||||
// console.log(">>>>>>>>>> currPHs: " + JSON.stringify(currPHs));
|
||||
let finalSubs = {};
|
||||
|
|
|
|||
|
|
@ -587,7 +587,7 @@ const insertHtml = function (replyHtml, fullBody_string) {
|
|||
return fullBody.body.innerHTML;
|
||||
}
|
||||
|
||||
export async function getCustomPromptsUsedSpace(){
|
||||
export async function getLocalStorageUsedSpace(){
|
||||
// we can't use this, see: https://bugzilla.mozilla.org/show_bug.cgi?id=1385832
|
||||
//let customprompts_space = await browser.storage.local.getBytesInUse("_custom_prompt");
|
||||
//let's use a workaround
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
<td colspan="2"><div>__MSG_prefs_SurveyLinkText__<br><a href="https://forms.gle/1qK2wcbuhaRzhwyt9">__MSG_prefs_SurveyLinkText2__</a></div></td>
|
||||
</tr>
|
||||
<tr id="owl_warning">
|
||||
<td colspan="2"><div class="warning">__MSG_prefs_OptionText_owl_warning__ <a href="https://micz.it/thunderbird-addon-thunderai/owl/">__MSG_customPrompts_managePrompts_help__</a></div></td>
|
||||
<td colspan="2"><div class="warning">__MSG_prefs_OptionText_owl_warning__ <a href="https://micz.it/thunderbird-addon-thunderai/owl/">__MSG_more_info_string__</a></div></td>
|
||||
</tr>
|
||||
<tr id="hyprland_warning">
|
||||
<td colspan="2" style="text-align:center;" class="warning"><b>__MSG_hyprland_warning__</b></td>
|
||||
|
|
@ -297,7 +297,7 @@
|
|||
</tr>
|
||||
<tr class="conntype_ollama_api" id="ollama_api_cors_warning">
|
||||
<td colspan="2" style="text-align:center;">
|
||||
__MSG_remember_CORS__ [<a href="https://micz.it/thunderbird-addon-thunderai/ollama-cors-information/">__MSG_customPrompts_managePrompts_help__</a>]
|
||||
__MSG_remember_CORS__ [<a href="https://micz.it/thunderbird-addon-thunderai/ollama-cors-information/">__MSG_more_info_string__</a>]
|
||||
<br><br><b>__MSG_CORS_alternative_1__</b>
|
||||
<br>__MSG_CORS_alternative_2__
|
||||
<br><br><button id="btnGiveAllUrlsPermission_ollama_api">__MSG_CORS_give_allurls_perm__</button>
|
||||
|
|
@ -365,7 +365,7 @@
|
|||
</tr>
|
||||
<tr class="conntype_openai_comp_api" id="openai_comp_api_cors_warning">
|
||||
<td colspan="2" style="text-align:center;">
|
||||
__MSG_maybe_CORS_openai_comp__ [<a href="https://micz.it/thunderbird-addon-thunderai/ollama-cors-information/">__MSG_customPrompts_managePrompts_help__</a>]
|
||||
__MSG_maybe_CORS_openai_comp__ [<a href="https://micz.it/thunderbird-addon-thunderai/ollama-cors-information/">__MSG_more_info_string__</a>]
|
||||
<br><br><b>__MSG_CORS_alternative_1__</b>
|
||||
<br>__MSG_CORS_alternative_2__
|
||||
<br><br><button id="btnGiveAllUrlsPermission_openai_comp_api">__MSG_CORS_give_allurls_perm__</button>
|
||||
|
|
@ -542,14 +542,15 @@
|
|||
</table>
|
||||
<div id="btn_custom_prompts">
|
||||
<button id="btnManagePrompts">__MSG_prefs_OptionText_btnManagePrompts__</button>
|
||||
<br>__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_customPrompts_managePrompts_help__</a>
|
||||
<br>__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_more_info_string__</a>
|
||||
<br><button id="btnManageCustomDataPH">__MSG_prefs_OptionText_btnManageCustomDataPH__</button>
|
||||
</div>
|
||||
<div id="miczDescription">
|
||||
<h1>__MSG_prefsInfoTitle__</h1>
|
||||
<p>
|
||||
<span class="conntype_chatgpt_web">__MSG_prefsInfoDesc_1__<br></span>
|
||||
<span class="conntype_chatgpt_api">__MSG_prefsInfoDesc_2__<br></span>
|
||||
<span class="conntype_ollama_api">__MSG_prefsInfoDesc_3__ [<a href="https://micz.it/thunderbird-addon-thunderai/ollama-cors-information/">__MSG_customPrompts_managePrompts_help__</a>]<br></span>
|
||||
<span class="conntype_ollama_api">__MSG_prefsInfoDesc_3__ [<a href="https://micz.it/thunderbird-addon-thunderai/ollama-cors-information/">__MSG_more_info_string__</a>]<br></span>
|
||||
<span class="conntype_openai_comp_api">__MSG_prefsInfoDesc_4__</span>
|
||||
<br><span>__MSG_prefsInfoDesc_5__
|
||||
<br>__MSG_prefsInfoDesc_6__</span>
|
||||
|
|
|
|||
|
|
@ -482,6 +482,10 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
openTab('../pages/customprompts/mzta-custom-prompts.html');
|
||||
});
|
||||
|
||||
document.getElementById('btnManageCustomDataPH').addEventListener('click', () => {
|
||||
openTab('../pages/customdataplaceholders/mzta-custom-dataplaceholders.html');
|
||||
});
|
||||
|
||||
document.getElementById('btnManageTagsInfo').addEventListener('click', () => {
|
||||
openTab('../pages/addtags/mzta-add-tags.html');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
<div id="miczRelNotes"><h1>ThunderAI Release Notes</h1>
|
||||
<h2>Version 3.6.0 - ??/??/2025</h2>
|
||||
<ul>
|
||||
<li>Now it's possibile to define custom data placeholders to be used in custom prompts [<a href="https://github.com/micz/ThunderAI/issues/156">#156</a>].</li>
|
||||
<li>When replying, it's now possibile to choose a different reply type (between "all" or "sender only") directly in the AI chat window [<a href="https://github.com/micz/ThunderAI/issues/372">#372</a>].</li>
|
||||
<li><i>[All APIs]</i> Added an option to choose to exclude a tag only with an exact match in the excluded words list [<a href="https://github.com/micz/ThunderAI/issues/395">#395</a>].</li>
|
||||
<li><i>[OpenAI API]</i> Added an option to enable the OpenAI storage for API requests [<a href="https://github.com/micz/ThunderAI/issues/406">#406</a>].</li>
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@
|
|||
</table>
|
||||
<div id="addtags_prompt_container">
|
||||
<span class="section_title">__MSG_AddTags_prompt_text_title__</span><span id="addtags_prompt_unsaved" class="unsaved hidden"> __MSG_customPrompts_unsaved_changes__</span>
|
||||
<br><span class="infoline">__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_customPrompts_managePrompts_help__</a>
|
||||
<br><span class="infoline">__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_more_info_string__</a>
|
||||
<br>__MSG_prefs_OptionText_btnManagePrompts_infoline3__
|
||||
<br><b>__MSG_prefs_OptionText_AdvancedPromptResponse_infoline2__</b></span>
|
||||
<br>
|
||||
|
|
|
|||
360
pages/customdataplaceholders/mzta-custom-dataplaceholders.css
Normal file
360
pages/customdataplaceholders/mzta-custom-dataplaceholders.css
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ThunderAI - __MSG_customDataPH_manageDataPH__</title>
|
||||
<link rel="stylesheet" href="mzta-custom-dataplaceholders.css">
|
||||
<link rel="icon" href="../../images/icon-16px.png">
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h1 class="page_title">__MSG_customDataPH_manageDataPH__</h1>
|
||||
<p>__MSG_customDataPH_manageDataPH_info_default__<br>
|
||||
__MSG_customPrompts_managePrompts_info_default_3__
|
||||
<br>__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_more_info_string__</a></p>
|
||||
</div>
|
||||
<div id="import_export">
|
||||
<button id="btnExportAll">__MSG_customDataPH_ExportAll__</button><br>
|
||||
<button id="btnImport">__MSG_customDataPH_Import__</button>
|
||||
</div>
|
||||
<div id="command_palette">
|
||||
<button id="btnSaveAll" disabled>__MSG_btnSaveAll_string__</button>
|
||||
<span id="msgDisplay"></span>
|
||||
<button id="btnNew">__MSG_btnNew_string__</button>
|
||||
</div>
|
||||
<div id="formNew">
|
||||
<table class="width_all">
|
||||
<tr>
|
||||
<td class="w19">
|
||||
<label for="txtIdNew" class="field_title">*__MSG_customPrompts_form_label_ID__:</label>
|
||||
<br>
|
||||
<i>thunderai_custom_</i><input type="text" id="txtIdNew" name="id" class="input_new" tabindex="1">
|
||||
<br><span class="small_label">[__MSG_customPrompts_form_label_ID_rules__]</span>
|
||||
</td>
|
||||
<td rowspan="2" class="w25">
|
||||
<label for="txtTextNew" class="field_title">*__MSG_customDataPH_form_label_Text__:</label>
|
||||
<br>
|
||||
<div class="autocomplete-container">
|
||||
<textarea id="txtTextNew" name="text" class="input_new text_output editor" tabindex="3"></textarea>
|
||||
<ul class="autocomplete-list hidden"></ul>
|
||||
</div>
|
||||
</td>
|
||||
<td rowspan="2" class="w19">
|
||||
<label for="selectTypeNew" class="field_title">__MSG_customDataPH_add_to_menu__:</label>
|
||||
<br>
|
||||
<select id="selectTypeNew" name="type" tabindex="4" class="type_output">
|
||||
<option value="0">__MSG_customPrompts_add_to_menu_always__</option>
|
||||
<option value="1">__MSG_customPrompts_add_to_menu_reading__</option>
|
||||
<option value="2">__MSG_customPrompts_add_to_menu_composing__</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="w19">
|
||||
<label for="txtNameNew" class="field_title">*__MSG_customPrompts_form_label_Name__:</label>
|
||||
<br>
|
||||
<input type="text" id="txtNameNew" name="name" class="input_new" tabindex="2">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="go_right_float">* __MSG_customPrompts_form_required_fields__</div>
|
||||
<br>
|
||||
<div class="go_right"><button id="btnAddNew" disabled>__MSG_customDataPH_btnAddNewCommit__</button></div>
|
||||
</div>
|
||||
<div id="all_custom_dataplaceholders">
|
||||
<table class="prompts_list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort" data-sort="id">__MSG_customPrompts_form_label_ID__</th>
|
||||
<th class="sort" data-sort="name">__MSG_customPrompts_form_label_Name__</th>
|
||||
<th class="sort" data-sort="text">__MSG_customDataPH_form_label_Text__</th>
|
||||
<th>__MSG_customPrompts_Properties__</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="list">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="storage_space">__MSG_StorageSpace__: <span id="storage_space"></span></div>
|
||||
<script src="../_lib/list.js"></script>
|
||||
<script src="mzta-custom-dataplaceholders.js" type="module"></script>
|
||||
<script src="../../js/mzta-i18n.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
564
pages/customdataplaceholders/mzta-custom-dataplaceholders.js
Normal file
564
pages/customdataplaceholders/mzta-custom-dataplaceholders.js
Normal file
|
|
@ -0,0 +1,564 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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,
|
||||
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();
|
||||
exportCustomDataPHs();
|
||||
});
|
||||
|
||||
async function exportCustomDataPHs() {
|
||||
const manifest = browser.runtime.getManifest();
|
||||
const addonVersion = manifest.version;
|
||||
const outputCustomDataPHs = prepareCustomDataPHsForExport(await getCustomPlaceholders());
|
||||
let outputObj = {id: 'thunderai-custom-data-placeholders', addon_version: addonVersion, customdataplaceholders: outputCustomDataPHs};
|
||||
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-custom-data-placeholders-${time_stamp}.json`,
|
||||
saveAs: true,
|
||||
});
|
||||
}
|
||||
|
||||
const btnImport = document.getElementById('btnImport');
|
||||
btnImport.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
importCustomDataPHs();
|
||||
});
|
||||
|
||||
function importCustomDataPHs() {
|
||||
if(confirm(browser.i18n.getMessage("importCustomDataPH_confirmText") + '\n' + browser.i18n.getMessage("customDataPH_manageDataPH_info_default") + '\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 importCustomDataPHs(), 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('importCustomDataPH_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-custom-data-placeholders') {
|
||||
alert(browser.i18n.getMessage("importCustomDataPH_invalidFile"));
|
||||
setMessage(browser.i18n.getMessage('importCustomDataPH_invalidFile'),'red');
|
||||
return;
|
||||
}
|
||||
// if(obj.addon_version !== manifest.version) {
|
||||
// alert(browser.i18n.getMessage("importPrompts_invalidVersion"));
|
||||
// return;
|
||||
// }
|
||||
if(!Array.isArray(obj.customdataplaceholders)) {
|
||||
alert(browser.i18n.getMessage("importCustomDataPH_invalidDataPHs"));
|
||||
setMessage(browser.i18n.getMessage('importCustomDataPH_invalidDataPHs'),'red');
|
||||
return;
|
||||
}
|
||||
customDataPHsList.clear();
|
||||
loadCustomDataPHsList(await prepareCustomDataPHsForImport(obj.customdataplaceholders));
|
||||
setSomethingChanged();
|
||||
i18n.updateDocument();
|
||||
setMessage(browser.i18n.getMessage('importCustomDataPH_import_completed'), 'orange');
|
||||
} catch(err) {
|
||||
alert(browser.i18n.getMessage("importCustomDataPH_invalidFile") + ' ' + err);
|
||||
setMessage(browser.i18n.getMessage('importCustomDataPH_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';
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
// 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(/<br\s*\/?>/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();
|
||||
}
|
||||
|
||||
// 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: '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 = `<tr ` + ((values.is_default == 1) ? 'class="is_default"':'') + `>
|
||||
<td class="w08"><i>thunderai_custom_</i><span class="id id_show"></span><input type="text" class="hiddendata id_output" value="` + values.id + `" /></td>
|
||||
<td class="w08"><span class="name name_show"></span><input type="text" class="hiddendata name_output" value="` + values.name + `" /></td>
|
||||
<td class="w40">
|
||||
<span class="text text_show"></span>
|
||||
<div class="autocomplete-container">
|
||||
<textarea class="hiddendata text_output editor">` + values.text.replace(/<br\s*\/?>/gi, "\n") + `</textarea>
|
||||
<ul class="autocomplete-list hidden"></ul>
|
||||
</div>
|
||||
</td>
|
||||
<td class="w08"><span class="field_title_s">__MSG_customDataPH_add_to_menu__:</span>
|
||||
<br>
|
||||
<span class="type_show">` + type_output + `</span>
|
||||
<select class="type_output hiddendata">
|
||||
<option value="0"` + ((values.type == "0") ? ' selected':'') + `>__MSG_customPrompts_add_to_menu_always__</option>
|
||||
<option value="1"` + ((values.type == "1") ? ' selected':'') + `>__MSG_customPrompts_add_to_menu_reading__</option>
|
||||
<option value="2"` + ((values.type == "2") ? ' selected':'') + `>__MSG_customPrompts_add_to_menu_composing__</option>
|
||||
</select>` +
|
||||
`<span class="type hiddendata"></span>
|
||||
</td>
|
||||
<td class="w17">
|
||||
<label><input type="checkbox" class="enabled input_mod"> __MSG_customPrompts_form_label_enabled__</label>
|
||||
<span class="is_default hiddendata"></span>
|
||||
<span class="position_compose hiddendata"></span>
|
||||
<span class="position_display hiddendata"></span>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btnEditItem"` + ((values.is_default == 1) ? ' disabled':'') + `>__MSG_customPrompts_btnEdit__</button>
|
||||
<button class="btnCancelItem hiddendata"` + ((values.is_default == 1) ? ' disabled':'') + `>__MSG_customPrompts_btnCancel__</button>
|
||||
<br><br>
|
||||
<button class="btnConfirmItem hiddendata"` + ((values.is_default == 1) ? ' disabled':'') + `>__MSG_customPrompts_btnOK__</button>
|
||||
<button class="btnDeleteItem"` + ((values.is_default == 1) ? ' disabled':'') + `>__MSG_customPrompts_btnDelete__</button>
|
||||
</td>
|
||||
</tr>`;
|
||||
//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);
|
||||
});
|
||||
|
||||
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('.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_saving_custom'));
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -11,17 +11,17 @@
|
|||
<h1 class="page_title">__MSG_customPrompts_managePrompts__</h1>
|
||||
<p>__MSG_customPrompts_managePrompts_info_default__<br>
|
||||
__MSG_customPrompts_managePrompts_info_default_2__<br>
|
||||
__MSG_customPrompts_managePrompts_info_default_3__ <a href="https://micz.it/thunderbird-addon-thunderai/custom-prompts/">__MSG_customPrompts_managePrompts_help__</a>
|
||||
<br>__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_customPrompts_managePrompts_help__</a></p>
|
||||
__MSG_customPrompts_managePrompts_info_default_3__ <a href="https://micz.it/thunderbird-addon-thunderai/custom-prompts/">__MSG_more_info_string__</a>
|
||||
<br>__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_more_info_string__</a></p>
|
||||
</div>
|
||||
<div id="import_export">
|
||||
<button id="btnExportAll">__MSG_customPrompts_ExportAll__</button><br>
|
||||
<button id="btnImport">__MSG_customPrompts_Import__</button>
|
||||
</div>
|
||||
<div id="command_palette">
|
||||
<button id="btnSaveAll" disabled>__MSG_customPrompts_btnSaveAll__</button>
|
||||
<button id="btnSaveAll" disabled>__MSG_btnSaveAll_string__</button>
|
||||
<span id="msgDisplay"></span>
|
||||
<button id="btnNew">__MSG_customPrompts_btnNew__</button>
|
||||
<button id="btnNew">__MSG_btnNew_string__</button>
|
||||
</div>
|
||||
<div id="formNew">
|
||||
<table class="width_all">
|
||||
|
|
@ -122,7 +122,7 @@
|
|||
</table>
|
||||
</div>
|
||||
<div class="storage_space">__MSG_StorageSpace__: <span id="storage_space"></span></div>
|
||||
<script src="list.js"></script>
|
||||
<script src="../_lib/list.js"></script>
|
||||
<script src="mzta-custom-prompts.js" type="module"></script>
|
||||
<script src="../../js/mzta-i18n.js"></script>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@
|
|||
|
||||
import { prefs_default } from "../../options/mzta-options-default.js";
|
||||
import { getPrompts, setDefaultPromptsProperties, setCustomPrompts, preparePromptsForExport, preparePromptsForImport } from "../../js/mzta-prompts.js";
|
||||
import { ChatGPTWeb_models, isThunderbird128OrGreater, getCustomPromptsUsedSpace, sanitizeHtml, validateCustomData_ChatGPTWeb, getChatGPTWebModelsList_HTML } from "../../js/mzta-utils.js";
|
||||
import { ChatGPTWeb_models, isThunderbird128OrGreater, getLocalStorageUsedSpace, sanitizeHtml, validateCustomData_ChatGPTWeb, getChatGPTWebModelsList_HTML } from "../../js/mzta-utils.js";
|
||||
import { taLogger } from "../../js/mzta-logger.js";
|
||||
import { getPlaceholders } from "../../js/mzta-placeholders.js";
|
||||
import { getPlaceholders, placeholdersUtils } from "../../js/mzta-placeholders.js";
|
||||
import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js";
|
||||
|
||||
let prefs = null;
|
||||
|
|
@ -88,13 +88,13 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
const textareas = document.querySelectorAll('.editor');
|
||||
autocompleteSuggestions = (await getPlaceholders(true)).map(p => ({command: '{%'+p.id+'%}', type: p.type}));
|
||||
|
||||
// console.log('>>>>>>>>>>> suggestions: ' + JSON.stringify(suggestions));
|
||||
// console.log('>>>>>>>>>>> autocompleteSuggestions: ' + JSON.stringify(autocompleteSuggestions));
|
||||
|
||||
textareas.forEach(textarea => {
|
||||
textareaAutocomplete(textarea, autocompleteSuggestions);
|
||||
textareas.forEach(textarea => {
|
||||
textarea.addEventListener('input', (e) => {
|
||||
checkPromptsConfigForPlaceholders(e.target);
|
||||
textarea.addEventListener('input', async (e) => {
|
||||
await checkPromptsConfigForPlaceholders(e.target);
|
||||
});
|
||||
textareaAutocomplete(textarea, autocompleteSuggestions);
|
||||
});
|
||||
|
|
@ -161,7 +161,6 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
//To add a new item
|
||||
var txtIdNew = document.getElementById('txtIdNew');
|
||||
var txtNameNew = document.getElementById('txtNameNew');
|
||||
|
|
@ -588,13 +587,13 @@ function handleConfirmClick(e) {
|
|||
}
|
||||
|
||||
// Handle checkbox changes and log new state
|
||||
function handleCheckboxChange(e) {
|
||||
async 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);
|
||||
await checkPromptsConfigForPlaceholders(textarea);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -936,7 +935,7 @@ function clearMessage() {
|
|||
}
|
||||
|
||||
async function setStorageSpace() {
|
||||
let storage_space = await getCustomPromptsUsedSpace();
|
||||
let storage_space = await getLocalStorageUsedSpace();
|
||||
document.getElementById('storage_space').textContent = storage_space;
|
||||
}
|
||||
|
||||
|
|
@ -950,11 +949,15 @@ if(await isThunderbird128OrGreater()){
|
|||
});
|
||||
}
|
||||
|
||||
function checkPromptsConfigForPlaceholders(textarea){
|
||||
async function checkPromptsConfigForPlaceholders(textarea){
|
||||
let curr_text = textarea.value;
|
||||
// First substitute the custom data placeholders
|
||||
curr_text = await placeholdersUtils.replaceCustomPlaceholders(curr_text);
|
||||
console.log('>>>>>>>>>> curr_text after custom placeholders: ' + curr_text);
|
||||
// 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(String(curr_text).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{
|
||||
|
|
@ -966,7 +969,7 @@ function checkPromptsConfigForPlaceholders(textarea){
|
|||
|
||||
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((String(curr_text).indexOf('{%selected_text%}') != -1)||(String(curr_text).indexOf('{%selected_html%}') != -1)){
|
||||
if(!selected_text_element.checked){
|
||||
selected_text_element.closest('.need_selected_span').style.border = '2px solid red';
|
||||
}else{
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
</table>
|
||||
<div id="get_calendar_event_container">
|
||||
<span class="section_title">__MSG_GetCalendarEvent_prompt_text_title__</span><span id="get_calendar_event_prompt_unsaved" class="unsaved hidden"> __MSG_customPrompts_unsaved_changes__</span>
|
||||
<br><span class="infoline">__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_customPrompts_managePrompts_help__</a>
|
||||
<br><span class="infoline">__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_more_info_string__</a>
|
||||
<br><b>__MSG_prefs_OptionText_AdvancedPromptResponse_infoline2__</b></span>
|
||||
<br>
|
||||
<div class="autocomplete-container">
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
</table>
|
||||
<div id="get_task_container">
|
||||
<span class="section_title">__MSG_GetCalendarEvent_prompt_text_title__</span><span id="get_task_prompt_unsaved" class="unsaved hidden"> __MSG_customPrompts_unsaved_changes__</span>
|
||||
<br><span class="infoline">__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_customPrompts_managePrompts_help__</a>
|
||||
<br><span class="infoline">__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_more_info_string__</a>
|
||||
<br><b>__MSG_prefs_OptionText_AdvancedPromptResponse_infoline2__</b></span>
|
||||
<br>
|
||||
<div class="autocomplete-container">
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
</table>
|
||||
<div id="spamfilter_container">
|
||||
<span class="section_title">__MSG_SpamFilter_prompt_text_title__</span><span id="spamfilter_prompt_unsaved" class="unsaved hidden"> __MSG_customPrompts_unsaved_changes__</span>
|
||||
<br><span class="infoline">__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_customPrompts_managePrompts_help__</a>
|
||||
<br><span class="infoline">__MSG_prefs_OptionText_btnManagePrompts_infoline__ <a href="https://micz.it/thunderbird-addon-thunderai/data-placeholders/">__MSG_more_info_string__</a>
|
||||
<br><b>__MSG_prefs_OptionText_AdvancedPromptResponse_infoline2__</b></span>
|
||||
<br>
|
||||
<div class="autocomplete-container">
|
||||
|
|
|
|||
Loading…
Reference in a new issue