diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4673c2b7..3374d609 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,9 +4,17 @@
+
__MSG_customPrompts_btnSaveAll__
diff --git a/js/mzta-chatgpt.js b/js/mzta-chatgpt.js
index 9d2f3d28..a0cbcd5c 100644
--- a/js/mzta-chatgpt.js
+++ b/js/mzta-chatgpt.js
@@ -72,17 +72,38 @@ async function chatgpt_getFromDOM(pos) {
// Removing the new buttons that let the user change model and insert a number (4 or 3.5 at the end of the text)
let parser = new DOMParser();
let doc = parser.parseFromString(responseDivs[responseDivs.length - 1].innerHTML, 'text/html');
+ if(!mztaKeepFormatting) { // Return only TEXT
// Select the div with class 'empty:hidden'
- let divToRemove = doc.querySelector('div.empty\\\\:hidden');
- if (divToRemove) {
- divToRemove.remove();
+ let divToRemove = doc.querySelector('div.empty\\\\:hidden');
+ if (divToRemove) {
+ divToRemove.remove();
+ }
+ // Extract the new HTML string
+ responseDivs[responseDivs.length - 1].innerHTML = doc.body.innerHTML;
+ response = responseDivs[responseDivs.length - 1].textContent;
+ response = response.replace(/^ChatGPT(?:ChatGPT)?/, ''); // strip sender name
+ response = response.trim().replace(/^"|"$/g, ''); // strip quotation marks
+ response = "
" + response + "
";
+ //console.log(">>>>>>>>> response: " + JSON.stringify(response));
+ let parser_2 = new DOMParser();
+ let doc_response = parser_2.parseFromString(response, 'text/html');
+ //console.log(">>>>>>>>> doc_response: " + JSON.stringify(doc_response.body.innerHTML));
+ replaceNewlinesWithBr(doc_response.body)
+ response = doc_response.body.innerHTML;
+ // response = responseDivs[responseDivs.length - 1].innerHTML;
+ } else { // Return HTML
+ // Tags to exclude
+ //console.log(">>>>>>>>> doc.body.innerHTML original: " + doc.body.innerHTML);
+ const excludeTags = ['div', 'text', 'svg', 'path', 'button'];
+ const includeTags = ['p', 'ul'];
+ // removeTags(doc.body, excludeTags);
+ response = removeTagsAndReturnHTML(doc.body, excludeTags, includeTags)
+ //console.log(">>>>>>>>> doc.body.innerHTML final: " + doc.body.innerHTML);
+ // response = doc.body.innerHTML;
}
- // Extract the new HTML string
- responseDivs[responseDivs.length - 1].innerHTML = doc.body.innerHTML;
- response = responseDivs[responseDivs.length - 1].textContent;
- //console.log('chatgpt_getFromDOM: '+response);
+ //console.log('chatgpt_getFromDOM final response: '+response);
//console.log('chatgpt_getFromDOM: [HTML] ' + responseDivs[responseDivs.length - 1].innerHTML.replace(/
]*>/gi, '').replace(/<\\/div>/gi, '').replace(/
]*>/gi, '').replace(/<\\/svg>/gi, '').replace(/]*>/gi, '').replace(/<\\/path>/gi, '').replace(/]*>/gi, '').replace(/<\\/text>/gi, '').replace(/]*>/gi, '').replace(/<\\/span>/gi, '').replace(/]*>/gi, '').replace(/<\\/button>/gi, ''));
- } else { // get nth response
+ } else { // get nth response --- HERE ONLY TEXT FROM RESPONSE, NO HTML
const nthOfResponse = (
// Calculate base number
@@ -107,9 +128,7 @@ async function chatgpt_getFromDOM(pos) {
);
response = responseDivs[nthOfResponse - 1].textContent;
}
- response = response.replace(/^ChatGPT(?:ChatGPT)?/, ''); // strip sender name
- response = response.trim().replace(/^"|"$/g, ''); // strip quotation marks
- //console.log('chatgpt_getFromDOM: ' + response);
+ //console.log('>>>>>>>>>>>>>> chatgpt_getFromDOM: ' + JSON.stringify(response));
}
return response;
}
@@ -337,6 +356,63 @@ async function doProceed(message, customText = ''){
operation_done();
}
+
+function removeTagsAndReturnHTML(rootElement, removeTags, preserveTags) {
+ const fragment = document.createDocumentFragment();
+
+ function handleElement(element) {
+ let child = element.firstChild;
+ while (child) {
+ const nextSibling = child.nextSibling;
+ if (preserveTags.includes(child.nodeName.toLowerCase())) {
+ //console.log(">>>>>>>>>>>> preserve child: " + child.tagName.toLowerCase());
+ fragment.appendChild(child);
+ } else if (child.nodeType === Node.ELEMENT_NODE) {
+ //console.log(">>>>>>>>>>>> handleElement(child): " + child.tagName.toLowerCase());
+ handleElement(child);
+ }
+ child = nextSibling;
+ }
+ }
+
+ removeTags.forEach(tag => {
+ const elements = Array.from(rootElement.getElementsByTagName(tag));
+ elements.forEach(element => {
+ handleElement(element);
+ element.parentNode.insertBefore(fragment.cloneNode(true), element);
+ element.parentNode.removeChild(element);
+ //console.log(">>>>>>>>>>>> removeChild: " + element.tagName.toLowerCase());
+ });
+ });
+
+ replaceNewlinesWithBr(rootElement);
+ //console.log(">>>>>>>>>>>> rootElement.innerHTML: " + rootElement.innerHTML);
+ // Return the updated HTML as a string
+ return rootElement.innerHTML;
+}
+
+// Replace newline characters with tags
+function replaceNewlinesWithBr(node) {
+ for (let child of Array.from(node.childNodes)) {
+ if (child.nodeType === Node.TEXT_NODE) {
+ const parts = child.textContent.split('\\n');
+ if (parts.length > 1) {
+ const fragment = document.createDocumentFragment();
+ parts.forEach((part, index) => {
+ fragment.appendChild(document.createTextNode(part));
+ if (index < parts.length - 1) {
+ fragment.appendChild(document.createElement('br'));
+ }
+ });
+ child.parentNode.replaceChild(fragment, child);
+ }
+ } else if (child.nodeType === Node.ELEMENT_NODE) {
+ replaceNewlinesWithBr(child);
+ }
+ }
+}
+
+
// In the content script
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.command === "chatgpt_send") {
diff --git a/js/mzta-compose-script.js b/js/mzta-compose-script.js
index a5d4077a..12617313 100644
--- a/js/mzta-compose-script.js
+++ b/js/mzta-compose-script.js
@@ -16,24 +16,6 @@
* along with this program. If not, see .
*/
-// Some methods are a modified version derived from https://github.com/ali-raheem/Aify/blob/13ff87583bc520fb80f555ab90a90c5c9df797a7/plugin/content_scripts/compose.js
-
-const makeParagraphs = (text, func) => {
- const chunks = text.split(/\n{2,}/);
- if (chunks.length == 1) {
- return func(document.createTextNode(text));
- }
- const paragraphs = chunks.map((t) => {
- const p = document.createElement("p");
- p.innerText = t;
- return p;
- });
- for (let i = paragraphs.length - 1; i >= 0; i--) {
- func(paragraphs[i]);
- }
-};
-
-
browser.runtime.onMessage.addListener(async (message) => {
switch (message.command) {
case "getSelectedText":
@@ -50,9 +32,9 @@ switch (message.command) {
}
const r = sel.getRangeAt(0);
r.deleteContents();
- makeParagraphs(message.text, function (p) {
- r.insertNode(p);
- });
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(message.text, 'text/html');
+ r.insertNode(doc.body);
browser.runtime.sendMessage({command: "compose_reloadBody", tabId: message.tabId});
break;
diff --git a/js/mzta-utils.js b/js/mzta-utils.js
index 8ba040b9..1e5e9bfc 100644
--- a/js/mzta-utils.js
+++ b/js/mzta-utils.js
@@ -78,11 +78,11 @@ export async function setBody(tabId, fullHtmlBody){
await messenger.compose.setComposeDetails(tabId, {body: fullHtmlBody});
}
-export async function replaceBody(tabId, text){
+export async function replaceBody(tabId, replyHtml) {
let composeDetails = await messenger.compose.getComposeDetails(tabId);
let originalHtmlBody = composeDetails.body;
//console.log('originalHtmlBody: ' + originalHtmlBody);
- let fullBody = insertText(text, originalHtmlBody);
+ let fullBody = insertHtml(replyHtml, originalHtmlBody);
//console.log('fullBody: ' + fullBody);
await messenger.compose.setComposeDetails(tabId, {body: fullBody});
}
@@ -90,9 +90,10 @@ export async function replaceBody(tabId, text){
// The following methods are a modified version derived from https://github.com/ali-raheem/Aify/blob/13ff87583bc520fb80f555ab90a90c5c9df797a7/plugin/content_scripts/compose.js
-const insertText = function (text, fullBody_string) {
+const insertHtml = function (replyHtml, fullBody_string) {
const parser = new DOMParser();
let fullBody = parser.parseFromString(fullBody_string, "text/html");
+ let reply = parser.parseFromString(replyHtml, "text/html");
// looking for the first quoted mail or the signature, which come first in case of "signature above the quote".
const prefix_quote = fullBody.getElementsByClassName("moz-cite-prefix");
@@ -119,25 +120,18 @@ const insertText = function (text, fullBody_string) {
}
let final_p = document.createElement("p");
- final_p.innerHTML = "
";
+ let br1 = document.createElement("br");
+ let br2 = document.createElement("br");
+ final_p.appendChild(br1);
+ final_p.appendChild(br2);
fullBody.body.insertBefore(final_p, fullBody.body.firstChild);
- makeParagraphs(text, function (p) {
- fullBody.body.insertBefore(p, fullBody.body.firstChild);
+ //fullBody.body.insertBefore(reply, fullBody.body.firstChild);
+ let fragment = document.createDocumentFragment();
+ Array.from(reply.body.childNodes).forEach(node => {
+ if (node.parentNode === reply.body) {
+ fragment.appendChild(node.cloneNode(true));
+ }
});
+ fullBody.body.insertBefore(fragment, fullBody.body.firstChild);
return fullBody.body.innerHTML;
-}
-
-const makeParagraphs = (text, func) => {
- const chunks = text.split(/\n{2,}/);
- if (chunks.length == 1) {
- return func(document.createTextNode(text));
- }
- const paragraphs = chunks.map((t) => {
- const p = document.createElement("p");
- p.innerText = t;
- return p;
- });
- for (let i = paragraphs.length - 1; i >= 0; i--) {
- func(paragraphs[i]);
- }
-};
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/manifest.json b/manifest.json
index 59b48e64..6e17b005 100644
--- a/manifest.json
+++ b/manifest.json
@@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "ThunderAI",
"description": "__MSG_extensionDescription__",
- "version": "1.1.3",
+ "version": "1.1.4",
"author": "Mic (m@micz.it)",
"homepage_url": "https://micz.it/thunderbird-addon-thunderai/",
"browser_specific_settings": {
diff --git a/mzta-background.js b/mzta-background.js
index 1f2eefcb..9c3e886a 100644
--- a/mzta-background.js
+++ b/mzta-background.js
@@ -19,7 +19,7 @@
import { mzta_script } from './js/mzta-chatgpt.js';
import { prefs_default } from './options/mzta-options-default.js';
import { mzta_Menus } from './js/mzta-menus.js';
-import { getCurrentIdentity, getOriginalBody, reloadBody, replaceBody, setBody } from './js/mzta-utils.js';
+import { getCurrentIdentity, getOriginalBody, replaceBody, setBody } from './js/mzta-utils.js';
var createdWindowID = null;
var original_html = '';
@@ -69,6 +69,7 @@ messenger.runtime.onMessage.addListener(async (message, sender, sendResponse) =>
return true;
case 'chatgpt_replyMessage':
const paragraphsHtmlString = message.text;
+ //console.log(">>>>>>>>>>>> paragraphsHtmlString: " + paragraphsHtmlString);
let prefs = await browser.storage.sync.get({reply_type: 'reply_all'});
//console.log('reply_type: ' + prefs.reply_type);
let replyType = 'replyToAll';
@@ -100,7 +101,7 @@ messenger.runtime.onMessage.addListener(async (message, sender, sendResponse) =>
const listener = (tabId, changeInfo, updatedTab) => {
if (tabIsLoaded(updatedTab)) {
browser.tabs.onUpdated.removeListener(listener);
- console.log(">>>>>>>>>>>> reply_tab: " + tabId);
+ //console.log(">>>>>>>>>>>> reply_tab: " + tabId);
resolve();
}
}
@@ -138,6 +139,7 @@ messenger.runtime.onMessage.addListener(async (message, sender, sendResponse) =>
async function openChatGPT(promptText, action, curr_tabId, do_custom_text = 0) {
let prefs = await browser.storage.sync.get(prefs_default);
prefs = checkScreenDimensions(prefs);
+ //console.log(">>>>>>>>>>>>>>>> prefs: " + JSON.stringify(prefs));
console.log('[ThunderAI] Prompt length: ' + promptText.length);
if(promptText.length > 30000 ){
// Prompt too long for ChatGPT
@@ -178,6 +180,7 @@ async function openChatGPT(promptText, action, curr_tabId, do_custom_text = 0) {
let mztaForceCompletionDesc="`+ browser.i18n.getMessage("chatgpt_force_completion") +`";
let mztaForceCompletionTitle="`+ browser.i18n.getMessage("chatgpt_force_completion_title") +`";
let mztaDoCustomText=`+ do_custom_text +`;
+ let mztaKeepFormatting=`+ prefs.chatgpt_keep_formatting +`;
`;
browser.tabs.executeScript(createdTab.id, { code: pre_script + mzta_script, matchAboutBlank: false })
diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js
index 4cfc2112..e747ef8d 100644
--- a/options/mzta-options-default.js
+++ b/options/mzta-options-default.js
@@ -20,4 +20,5 @@ export const prefs_default = {
chatgpt_win_height: 800,
chatgpt_win_width: 700,
chatpgt_use_gpt4: false,
+ chatgpt_keep_formatting: false,
}
\ No newline at end of file
diff --git a/options/mzta-options.css b/options/mzta-options.css
index 27483aea..92c96f24 100644
--- a/options/mzta-options.css
+++ b/options/mzta-options.css
@@ -61,6 +61,7 @@ div#miczStatusPage{
left: 0px;
bottom: 2px;
padding: 2px 0px 0px 5px;
+ text-transform: capitalize;
}
div#miczDescription h1{
@@ -90,4 +91,12 @@ span.dims_label{
text-align: center;
width: 100%;
margin: 10px 0px;
+}
+
+div#miczTranslate{
+ width: 100%;
+ text-align: center;
+ font-size: 14px;
+ font-weight: bold;
+ margin-bottom: 1em;
}
\ No newline at end of file
diff --git a/options/mzta-options.html b/options/mzta-options.html
index 9896bba0..67e54083 100644
--- a/options/mzta-options.html
+++ b/options/mzta-options.html
@@ -59,6 +59,17 @@
+
+
+ __MSG_prefs_OptionText_chatpgt_keep_formatting__
+
+
+
+
+ __MSG_prefs_OptionText_chatpgt_keep_formatting_info__
+
+
+
__MSG_prefs_OptionText_chatpgt_use_gpt4__
@@ -80,6 +91,7 @@
__MSG_prefsInfoDesc_2__
__MSG_prefsInfoDesc_3__
+
diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html
index 5ae0af11..911ec50c 100644
--- a/options/mzta-release-notes.html
+++ b/options/mzta-release-notes.html
@@ -7,7 +7,14 @@
ThunderAI Release Notes
-
Version 1.1.3 - 18/06/2024
+
Version 1.1.4 - 28/06/2024
+
+ Added an option to import text with formatting from ChatGPT, set to false by default [#70 ], [#77 ].
+ Improve the message warning to choose the right model [#76 ].
+ Added a description in the Custom Prompts page about default prompts [#74 ].
+ Added a link to the translate page in the options window [#68 ].
+
+
Version 1.1.3 - 18/06/2024
Fixed a bug in replying to a message [#70 ].