דילוג לתוכן
  • חוקי הפורום
  • פופולרי
  • לא נפתר
  • משתמשים
  • חיפוש גוגל בפורום
  • צור קשר
עיצובים
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • ברירת מחדל (ללא עיצוב (ברירת מחדל))
  • ללא עיצוב (ברירת מחדל)
כיווץ
מתמחים טופ
  1. דף הבית
  2. מחשבים וטכנולוגיה
  3. עזרה הדדית - מחשבים וטכנולוגיה
  4. המלצה | 🧠 שדרגו את הדפדפן שלכם עם AI Suite Pro – חבילת ה-AI האולטימטיבית לגלישה! 🧠

המלצה | 🧠 שדרגו את הדפדפן שלכם עם AI Suite Pro – חבילת ה-AI האולטימטיבית לגלישה! 🧠

מתוזמן נעוץ נעול הועבר עזרה הדדית - מחשבים וטכנולוגיה
54 פוסטים 8 כותבים 416 צפיות 13 עוקבים
  • מהישן לחדש
  • מהחדש לישן
  • הכי הרבה הצבעות
תגובה
  • תגובה כנושא
התחברו כדי לפרסם תגובה
נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
  • פרוזיפ פרוזי

    @יוסי-רחמים כתב בהמלצה | 🧠 שדרגו את הדפדפן שלכם עם AI Suite Pro – חבילת ה-AI האולטימטיבית לגלישה! 🧠:

    לבינתיים לא

    אז בכל זאת...
    יש מידע מדוע הוא אינו עובד לי?

    י מנותק
    י מנותק
    יוסי רחמים
    כתב נערך לאחרונה על ידי
    #41

    @פרוזי ובדף תוספים אם מופיע שגיאה

    פרוזיפ תגובה 1 תגובה אחרונה
    0
    • י יוסי רחמים

      @פרוזי ובדף תוספים אם מופיע שגיאה

      פרוזיפ מנותק
      פרוזיפ מנותק
      פרוזי
      מדריכים עימוד
      כתב נערך לאחרונה על ידי פרוזי
      #42

      @יוסי-רחמים כתב בהמלצה | 🧠 שדרגו את הדפדפן שלכם עם AI Suite Pro – חבילת ה-AI האולטימטיבית לגלישה! 🧠:

      @פרוזי ובדף תוספים אם מופיע שגיאה

      AI Tooltip Error: TypeError: Failed to fetch
      הקשר
      https://mitmachim.top/topic/83852/המלצה-שדרגו-את-הדפדפן-שלכם-עם-ai-suite-pro-חבילת-ה-ai-האולטימטיבית-לגלישה?_=1748123175980
      התחקות אחר ערימה
      content.js:334 (handleTooltipAIAction)

      // === Global Variables & Constants ===
      const API_URL = 'https://php-render-test.onrender.com/main-ai.php';
      const CHAT_SIDEBAR_ID = 'ai-chat-sidebar-custom';
      const FAB_ID = 'ai-fab-button';
      const FAB_MENU_ID = 'ai-fab-menu';
      const THEME_STORAGE_KEY = 'aiSuiteProTheme';
      const ONBOARDING_SHOWN_KEY_PREFIX_CS = 'aiSuiteProOnboardingShown_v';
      
      // --- Tooltip State & Variables ---
      let currentTooltip = null;
      let tooltipAiHelperWrapper = null;
      let tooltipActionListVisible = false;
      
      // --- Chat State & Variables ---
      let aiChatSidebarInstance = null;
      
      // --- FAB State & Variables ---
      let fabMenuVisible = false;
      let fabButtonElement = null;
      let fabMenuElement = null;
      
      // --- Theme State ---
      let currentTheme = 'light'; // Default
      
      console.log("AI Suite Pro: content.js loaded. Version 1.1.1 (Auto Save Chat, UI Fixes)");
      
      // === Helper Functions for Custom Actions ===
      function searchSelectedOnGoogle(selectionObject) {
          const query = selectionObject ? selectionObject.toString().trim() : "";
          if (query) {
              window.open(`https://www.google.com/search?q=${encodeURIComponent(query)}`, '_blank');
          } else {
              alert("אנא סמן טקסט לחיפוש בגוגל.");
          }
      }
      
      async function shareCurrentPage() {
          const pageTitle = document.title;
          const pageUrl = window.location.href;
          if (navigator.share) {
              try {
                  await navigator.share({ title: pageTitle, text: `בדוק את הדף הזה: ${pageTitle}`, url: pageUrl });
              } catch (error) {
                  console.error('Error sharing page:', error);
                  copyLinkToClipboard(pageUrl, pageTitle, "שגיאה בשיתוף, הקישור הועתק במקום:");
              }
          } else {
              copyLinkToClipboard(pageUrl, pageTitle, "שיתוף Web API לא נתמך, הקישור הועתק:");
          }
      }
      
      function copyLinkToClipboard(url, title = "", prefixMessage = "") {
          navigator.clipboard.writeText(url)
              .then(() => {
                  const message = `${prefixMessage ? prefixMessage + " " : ""}הקישור לדף "${title || url}" הועתק ללוח!`;
                  showTooltipPopup(message, "", 2500); // Auto-dismiss after 2.5s
              })
              .catch(err => {
                  console.error('Failed to copy link: ', err);
                  alert('שגיאה בהעתקת הקישור.');
              });
      }
      
      // === CONFIGURATIONS ===
      const QUICK_ACTION_IDS = [ 'summarize_selected', 'translate_selected_custom_dialog', 'explain_contextual_selected', 'google_search_selected', 'share_page', 'open_ai_chat' ];
      const allActionsConfig = {
          summarize_selected: { id: 'summarize_selected', label: '📝', title: 'סכם מסומן', shortLabel: 'סכם', command: 'סכם את הטקסט המסומן הבא בצורה תמציתית: ', type: 'selected_text' },
          translate_selected_custom_dialog: { id: 'translate_selected_custom_dialog', label: '🌐', title: 'תרגם מסומן...', shortLabel: 'תרגם', type: 'prompt_language_selected_custom_dialog', baseCommand: 'תרגם את הטקסט המסומן הבא ל{LANG}: ' },
          explain_contextual_selected: { id: 'explain_contextual_selected', label: '💡', title: 'הסבר מסומן בהקשר', shortLabel: 'הסבר', type: 'explain_with_context' },
          google_search_selected: { id: 'google_search_selected', label: '🔍', title: 'חפש מסומן בגוגל', shortLabel: 'חפש', type: 'custom_action', actionFn: () => searchSelectedOnGoogle(window.getSelection()) },
          share_page: { id: 'share_page', label: '🔗', title: 'שתף דף זה', shortLabel: 'שתף', type: 'custom_action', actionFn: shareCurrentPage },
          open_ai_chat: { id: 'open_ai_chat', label: '💬', title: 'פתח צ\'אט AI', shortLabel: 'צ\'אט', type: 'custom_action', actionFn: launchAIChatSidebar },
          page_analysis: { categoryLabel: 'ניתוח כל הדף', actions: [
              { id: 'summarize_page', label: '📄', title: 'סכם את כל הדף', command: 'סכם את תוכן הדף הבא: ', type: 'full_page_text' },
              { id: 'keywords_page', label: '🔑', title: 'מילות מפתח מהדף', command: 'חלץ מילות מפתח עיקריות מתוכן הדף הבא: ', type: 'full_page_text' },
              { id: 'translate_page_custom_dialog', label: '🌍', title: 'תרגם את כל הדף...', type: 'prompt_language_page_custom_dialog', baseCommand: 'תרגם את כל תוכן הדף הבא ל{LANG}: ' },
              { id: 'fact_check_page', label: '✔️', title: 'אמת את העובדות שבדף הזה', command: 'בדוק את העובדות המוצגות בטקסט הבא וחפש אישורים או סתירות ממקורות אמינים: ', type: 'full_page_text' },
              { id: 'teach_me_page_info', label: '🧑‍🏫', title: 'למד אותי את המידע שבדף', command: 'הסבר לי את המושגים והמידע העיקריים המוצגים בטקסט הבא בצורה פשוטה וברורה, כאילו אתה מלמד אותי את הנושא: ', type: 'full_page_text' },
              { id: 'page_to_qa', label: '❓️', title: 'הפוך תוכן דף לשאלות ותשובות', command: 'הפוך את תוכן הדף הבא לפורמט של שאלות ותשובות המסכמות את המידע העיקרי: ', type: 'full_page_text' }
          ]},
          selected_text_extended: { categoryLabel: 'פעולות נוספות על מסומן', actions: [
              { id: 'improve_selected', label: '✍️', title: 'שפר ניסוח (מסומן)', command: 'תקן ושפר ניסוח של הטקסט המסומן הבא: ', type: 'selected_text' },
              { id: 'ask_on_selected_custom_dialog', label: '❓', title: 'שאל על המסומן...', type: 'prompt_question_custom_dialog', baseCommand: 'בהתייחס לטקסט המסומן הבא: "{TEXT}". ענה על השאלה: "{QUESTION}"' },
          ]}
      };
      
      // === THEME MANAGEMENT ===
      function applyTheme(theme) {
          document.documentElement.setAttribute('data-theme', theme);
          currentTheme = theme;
          const themeToggleBtn = aiChatSidebarInstance?.getThemeToggleButton();
          if (themeToggleBtn) {
              themeToggleBtn.innerHTML = theme === 'dark' ? '☀️' : '🌙';
              themeToggleBtn.title = theme === 'dark' ? 'מצב בהיר' : 'מצב כהה';
          }
      }
      
      function toggleTheme() {
          const newTheme = currentTheme === 'light' ? 'dark' : 'light';
          applyTheme(newTheme);
          chrome.storage.local.set({ [THEME_STORAGE_KEY]: newTheme });
      }
      
      function loadThemePreference() {
          chrome.storage.local.get(THEME_STORAGE_KEY, (result) => {
              applyTheme(result[THEME_STORAGE_KEY] || 'light');
          });
      }
      
      // === ONBOARDING ===
      function checkForOnboarding() {
          chrome.storage.local.get(['showAiSuiteProOnboarding'], (result) => {
              if (result.showAiSuiteProOnboarding) {
                  const onboardingVersion = result.showAiSuiteProOnboarding;
                  const shownKey = ONBOARDING_SHOWN_KEY_PREFIX_CS + onboardingVersion;
      
                  chrome.storage.local.get([shownKey], (shownResult) => {
                      if (!shownResult[shownKey]) {
                          showOnboardingFlow(onboardingVersion);
                          chrome.storage.local.set({ [shownKey]: true });
                          // This content script instance handled it.
                          // Background script won't clear this, this specific instance clears its trigger
                          chrome.storage.local.remove('showAiSuiteProOnboarding', () => {
                              if (chrome.runtime.lastError) {
                                  console.error("Error removing onboarding flag:", chrome.runtime.lastError.message);
                              }
                          });
                      }
                  });
              }
          });
      }
      
      function showOnboardingFlow(version) {
          const existingOverlay = document.querySelector('.ai-custom-prompt-overlay.onboarding');
          if (existingOverlay) existingOverlay.remove();
      
          const overlay = document.createElement('div');
          overlay.className = 'ai-custom-prompt-overlay visible onboarding';
          overlay.style.zIndex = "2147483648"; // Ensure it's on top
      
          const dialog = document.createElement('div');
          dialog.className = 'ai-custom-prompt-dialog';
          dialog.style.maxWidth = "550px";
          dialog.innerHTML = `
              <div class="prompt-title" style="font-size: 22px;">🎉 ברוכים הבאים ל-AI Suite Pro ${version}!</div>
              <div class="prompt-message" style="text-align: right; line-height: 1.7;">
                  <p>גלה את היכולות החדשות והמשופרות:</p>
                  <ul>
                      <li><strong>מצב כהה:</strong> הפעל מצב כהה לנוחות צפייה דרך כפתור ה-🌙 בצ'אט.</li>
                      <li><strong>שמירת היסטוריית צ'אטים:</strong> שמור, טען ומחק שיחות צ'אט באמצעות הכפתורים 💾 (שמירה) ו-📜 (היסטוריה) בצ'אט. הצ'אטים נשמרים אוטומטית!</li>
                      <li><strong>סרגל כלים מהיר:</strong> סמן טקסט בכל אתר כדי לגשת לפעולות AI מהירות.</li>
                      <li><strong>צ'אט AI מתקדם:</strong> פתח את הצ'אט מלחצן התוסף או מהתפריטים השונים.</li>
                      <li><strong>כפתור פעולות צף (FAB):</strong> גש לפעולות AI על כל הדף דרך הכפתור 🧠 בפינה הימנית תחתונה.</li>
                  </ul>
                  <p>אנו מקווים שתהנה מהשימוש בתוסף!</p>
              </div>
              <div class="prompt-actions" style="justify-content: center;">
                  <button class="prompt-button primary onboard-dismiss-btn">הבנתי, נתחיל!</button>
              </div>
          `;
      
          overlay.appendChild(dialog);
          document.body.appendChild(overlay);
      
          const dismissBtn = dialog.querySelector('.onboard-dismiss-btn');
          const closeAndRemove = () => {
              overlay.classList.remove('visible');
              setTimeout(() => overlay.remove(), 300);
          };
          dismissBtn.onclick = closeAndRemove;
          overlay.onclick = (e) => { if (e.target === overlay) closeAndRemove(); };
          dialog.addEventListener('keydown', (e) => { if (e.key === 'Escape') closeAndRemove(); });
          dismissBtn.focus();
      }
      
      
      // === UI HELPER FUNCTIONS ===
      function getPageContentForAI() { let text = ""; if (document.body) text = (document.querySelector('main article') || document.querySelector('article') || document.querySelector('main') || document.body).innerText || ""; return text.substring(0, 10000); }
      function ensureTooltipAiHelperWrapper() { if (!tooltipAiHelperWrapper) { tooltipAiHelperWrapper = document.createElement('div'); tooltipAiHelperWrapper.id = 'ai-text-helper-wrapper'; document.body.appendChild(tooltipAiHelperWrapper); } }
      function showTooltipProcessingUI(actionText = "מעבד...") {
      ensureTooltipAiHelperWrapper(); tooltipAiHelperWrapper.innerHTML = '';
      const banner = document.createElement("div"); banner.className = "processing-banner"; banner.innerText = actionText;
      tooltipAiHelperWrapper.appendChild(banner); const progressContainer = document.createElement("div"); progressContainer.className = "progress-container"; const progressBar = document.createElement("div"); progressBar.className = "progress-bar";
      progressContainer.appendChild(progressBar); tooltipAiHelperWrapper.appendChild(progressContainer); let startTime = Date.now(); let intervalId = setInterval(() => { let progress = Math.min(100, (Date.now() - startTime) / 80); progressBar.style.width = progress + "%"; }, 100); return () => { clearInterval(intervalId); if(tooltipAiHelperWrapper) tooltipAiHelperWrapper.innerHTML = '';}; }
      function showTooltipPopup(responseText, originalText = "", autoDismissDelay = 0) {
      ensureTooltipAiHelperWrapper(); tooltipAiHelperWrapper.innerHTML = ''; const popupOverlay = document.createElement("div"); popupOverlay.className = "popup-overlay visible"; const popup = document.createElement("div"); popup.className = "popup"; popup.tabIndex = -1; const popupContent = document.createElement("div"); popupContent.className = "popup-content"; popupContent.innerHTML = ''; const lines = responseText.split('\n'); lines.forEach((line, index) => { if (index > 0) popupContent.appendChild(document.createElement('br')); popupContent.appendChild(document.createTextNode(line)); });
      popup.appendChild(popupContent); const actionsBar = document.createElement("div"); actionsBar.className = "popup-actions"; const closeButton = document.createElement("button"); closeButton.className = "close"; closeButton.innerHTML = "✖"; closeButton.title = "סגור"; closeButton.onclick = () => { if (tooltipAiHelperWrapper) tooltipAiHelperWrapper.innerHTML = ''; };
      actionsBar.appendChild(closeButton); popup.appendChild(actionsBar); popupOverlay.appendChild(popup); tooltipAiHelperWrapper.appendChild(popupOverlay); popup.focus(); popupOverlay.addEventListener("keydown", (e) => { if (e.key === "Escape") closeButton.click(); });
      popupOverlay.addEventListener('click', (event) => { if (event.target === popupOverlay) closeButton.click(); }); if (autoDismissDelay > 0) { setTimeout(() => { if (popupOverlay.classList.contains('visible') && popupOverlay.parentNode) { closeButton.click(); } }, autoDismissDelay); } }
      function getSentenceAroundSelection(selection) {
          if (!selection || selection.rangeCount === 0) return null;
          const range = selection.getRangeAt(0);
          const selectedText = selection.toString();
          if (!selectedText.trim()) return null;
          let node = range.commonAncestorContainer;
          if (node.nodeType !== Node.ELEMENT_NODE) node = node.parentNode;
          if (!node || typeof node.innerText !== 'string') return null;
          const fullText = node.innerText;
          const selectionStartIndex = fullText.indexOf(selectedText);
          if (selectionStartIndex === -1) return selectedText;
          let sentenceStart = selectionStartIndex;
          while (sentenceStart > 0 && !['.', '!', '?', '\n'].includes(fullText[sentenceStart - 1])) { sentenceStart--; }
          while (sentenceStart < selectionStartIndex && /\s/.test(fullText[sentenceStart])) { sentenceStart++; }
          let sentenceEnd = selectionStartIndex + selectedText.length;
          while (sentenceEnd < fullText.length && !['.', '!', '?', '\n'].includes(fullText[sentenceEnd])) { sentenceEnd++; }
          if (sentenceEnd < fullText.length && ['.', '!', '?'].includes(fullText[sentenceEnd])) { sentenceEnd++; }
          let sentence = fullText.substring(sentenceStart, sentenceEnd).trim();
          if (!sentence.includes(selectedText)) {
              const searchWindow = 200;
              const windowStart = Math.max(0, selectionStartIndex - searchWindow);
              const windowEnd = Math.min(fullText.length, selectionStartIndex + selectedText.length + searchWindow);
              const textWindow = fullText.substring(windowStart, windowEnd);
              const localSelectionStart = selectedText ? textWindow.indexOf(selectedText) : -1;
              if(localSelectionStart !== -1) {
                  let localSentenceStart = localSelectionStart;
                  while(localSentenceStart > 0 && !['.','!','?','\n'].includes(textWindow[localSentenceStart-1])) localSentenceStart--;
                  while(localSentenceStart < localSelectionStart && /\s/.test(textWindow[localSentenceStart])) localSentenceStart++;
                  let localSentenceEnd = localSelectionStart + selectedText.length;
                  while(localSentenceEnd < textWindow.length && !['.','!','?','\n'].includes(textWindow[localSentenceEnd])) localSentenceEnd++;
                  if(localSentenceEnd < textWindow.length && ['.','!','?'].includes(textWindow[localSentenceEnd])) localSentenceEnd++;
                  sentence = textWindow.substring(localSentenceStart, localSentenceEnd).trim();
              } else {
                  sentence = selectedText;
              }
          }
          return sentence;
      }
      function showCustomPrompt({ title = "קלט נדרש", message, inputPlaceholder = "", inputType = "text", defaultValue = "" }) {
          return new Promise((resolve) => {
              const existingOverlay = document.querySelector('.ai-custom-prompt-overlay:not(.onboarding)');
              if (existingOverlay) existingOverlay.remove();
              const overlay = document.createElement('div');
              overlay.className = 'ai-custom-prompt-overlay';
              const dialog = document.createElement('div');
              dialog.className = 'ai-custom-prompt-dialog';
              dialog.innerHTML = ` <div class="prompt-header"> ${title ? `<div class="prompt-title">${title}</div>` : ''} </div> ${message ? `<div class="prompt-message">${message}</div>` : ''} <input type="${inputType}" class="prompt-input-field" placeholder="${inputPlaceholder}" value="${defaultValue}"> <div class="prompt-actions"> <button class="prompt-button secondary cancel-btn">ביטול</button> <button class="prompt-button primary confirm-btn">אישור</button> </div> `;
              overlay.appendChild(dialog);
              document.body.appendChild(overlay);
              const inputField = dialog.querySelector('.prompt-input-field');
              const confirmBtn = dialog.querySelector('.confirm-btn');
              const cancelBtn = dialog.querySelector('.cancel-btn');
              requestAnimationFrame(() => { overlay.classList.add('visible'); inputField.focus(); inputField.select(); });
              const closeDialog = (value) => { overlay.classList.remove('visible'); setTimeout(() => { overlay.remove(); resolve(value); }, 200); };
              confirmBtn.onclick = () => closeDialog(inputField.value);
              cancelBtn.onclick = () => closeDialog(null);
              overlay.onclick = (e) => { if (e.target === overlay) closeDialog(null); };
              inputField.onkeydown = (e) => { if (e.key === 'Enter') { e.preventDefault(); closeDialog(inputField.value); } else if (e.key === 'Escape') { e.preventDefault(); closeDialog(null);}};
          });
      }
      
      // === TOOLTIP/ACTION BUTTON CREATION & HANDLING ===
      async function createTooltipActionButton(actionId, actionConfig, selectionObject, type = 'quick') {
          const button = document.createElement('button'); button.className = 'tooltip-button'; button.title = actionConfig.title || '';
          const iconSpan = document.createElement('span'); iconSpan.className = 'tooltip-icon'; iconSpan.textContent = actionConfig.label || ''; button.appendChild(iconSpan);
          if (type === 'quick' && actionConfig.shortLabel) { const textSpan = document.createElement('span'); textSpan.textContent = actionConfig.shortLabel || ''; button.appendChild(textSpan); }
          else if (type === 'list' && actionConfig.title) { const textSpan = document.createElement('span'); textSpan.textContent = actionConfig.title || ''; button.appendChild(textSpan); }
          button.addEventListener('click', async (e) => {
              e.stopPropagation(); removeTooltip(); let fullPrompt = ""; let contentForAI = ""; let actionTitleForDisplay = actionConfig.title;
              const selectedText = selectionObject ? selectionObject.toString().trim() : "";
              switch (actionConfig.type) {
                  case 'selected_text': if (!selectedText) { alert("אנא סמן טקסט."); return; } contentForAI = selectedText; fullPrompt = actionConfig.command + contentForAI; break;
                  case 'explain_with_context': if (!selectedText) { alert("אנא סמן טקסט להסבר."); return; } const sentence = getSentenceAroundSelection(selectionObject); contentForAI = sentence || selectedText; fullPrompt = `הסבר את החלק המסומן (בתוך גרשיים כפולות) בהקשר של המשפט המלא: "${selectedText}".\nהמשפט המלא הוא: ${contentForAI}`; actionTitleForDisplay = "הסבר בהקשר"; break;
                  case 'full_page_text': contentForAI = getPageContentForAI(); if (!contentForAI) { alert("אין תוכן בדף."); return; } fullPrompt = actionConfig.command + contentForAI; break;
                  case 'prompt_language_selected_custom_dialog': if (!selectedText) { alert("אנא סמן טקסט."); return; } contentForAI = selectedText; const targetLangSel = await showCustomPrompt({ title: "תרגום טקסט מסומן", message: `לאיזו שפה לתרגם את הטקסט: "${selectedText.substring(0,50)}..."?`, inputPlaceholder: "לדוגמה: אנגלית, ספרדית" }); if (targetLangSel && targetLangSel.trim() !== "") { fullPrompt = actionConfig.baseCommand.replace('{LANG}', targetLangSel) + contentForAI; actionTitleForDisplay = `תרגום ל${targetLangSel}`; } else return; break;
                  case 'prompt_language_page_custom_dialog': contentForAI = getPageContentForAI(); if (!contentForAI) { alert("אין תוכן בדף."); return; } const targetLangPage = await showCustomPrompt({ title: "תרגום כל הדף", message: "לאיזו שפה לתרגם את כל תוכן הדף הנוכחי?", inputPlaceholder: "לדוגמה: אנגלית, צרפתית" }); if (targetLangPage && targetLangPage.trim() !== "") { fullPrompt = actionConfig.baseCommand.replace('{LANG}', targetLangPage) + contentForAI; actionTitleForDisplay = `תרגום דף ל${targetLangPage}`; } else return; break;
                  case 'prompt_question_custom_dialog': if (!selectedText) { alert("אנא סמן טקסט."); return; } contentForAI = selectedText; const userQ = await showCustomPrompt({ title: "שאל על הטקסט המסומן", message: `הקלד את שאלתך על הטקסט: "${selectedText.substring(0,100)}..."`, inputPlaceholder: "שאלתך כאן..." }); if (userQ && userQ.trim() !== "") { fullPrompt = actionConfig.baseCommand.replace('{TEXT}', selectedText).replace('{QUESTION}', userQ); } else return; break;
                  case 'custom_action': if (actionConfig.actionFn) { actionConfig.actionFn(); } else { console.warn("Custom action with no actionFn:", actionConfig.id); } return;
                  default: if (actionConfig.command) { fullPrompt = actionConfig.command + (selectedText || ""); } else { console.warn("Tooltip action default case with no command:", actionConfig); return; } break;
              }
              if (fullPrompt) await handleTooltipAIAction(fullPrompt, contentForAI, actionTitleForDisplay);
          });
          return button;
      }
      function removeTooltip() { const tooltipToRemove = currentTooltip; tooltipActionListVisible = false; currentTooltip = null; if (tooltipToRemove) { tooltipToRemove.classList.remove('visible'); setTimeout(() => { if (tooltipToRemove && tooltipToRemove.parentNode) tooltipToRemove.remove(); }, 200); } }
      async function createTooltip(x, y, selectionObject) {
          removeTooltip();
          const newTooltipElement = document.createElement('div'); newTooltipElement.className = 'ai-helper-tooltip';
          const quickActionsBar = document.createElement('div'); quickActionsBar.className = 'tooltip-quick-actions';
          const buttonPromises = QUICK_ACTION_IDS.map(id => { const cfg = allActionsConfig[id]; if (cfg) return createTooltipActionButton(id, cfg, selectionObject, 'quick'); return Promise.resolve(null); });
          try { const buttonElements = await Promise.all(buttonPromises); buttonElements.forEach(buttonElement => { if (buttonElement && buttonElement instanceof Node) quickActionsBar.appendChild(buttonElement); else if (buttonElement) { console.error("createTooltip: Received non-Node element for quick action:", buttonElement); quickActionsBar.appendChild(buttonElement); } }); } catch (error) { console.error("createTooltip: Error awaiting quick action buttons:", error); }
          newTooltipElement.appendChild(quickActionsBar);
          const moreToggle = document.createElement('button'); moreToggle.className = 'tooltip-more-actions-toggle'; moreToggle.innerHTML = 'עוד <span class="tooltip-icon">▾</span>'; moreToggle.addEventListener('click', async (e) => { e.stopPropagation(); await toggleTooltipActionList(newTooltipElement, selectionObject); });
          newTooltipElement.appendChild(moreToggle);
          try { document.body.appendChild(newTooltipElement); } catch (error) { console.error("createTooltip: Error appending tooltip to body:", error); return; }
          const rect = newTooltipElement.getBoundingClientRect(); let left = x - rect.width / 2; let top = y - rect.height - 10; if (left < 0) left = 5; if (left + rect.width > window.innerWidth) left = window.innerWidth - rect.width - 5; if (top < 0) top = y + 15;
          newTooltipElement.style.left = `${left + window.scrollX}px`; newTooltipElement.style.top = `${top + window.scrollY}px`; currentTooltip = newTooltipElement; tooltipActionListVisible = false;
          setTimeout(() => { if (currentTooltip === newTooltipElement && newTooltipElement.parentNode) newTooltipElement.classList.add('visible'); else if (newTooltipElement.parentNode) newTooltipElement.remove(); }, 10);
      }
      async function toggleTooltipActionList(tooltipElement, selectionObject) {
          if (!tooltipElement) { console.warn("toggleTooltipActionList: tooltipElement is null"); return; }
          let actionList = tooltipElement.querySelector('.tooltip-action-list');
          if (!actionList) {
              actionList = document.createElement('div'); actionList.className = 'tooltip-action-list';
              const allButtonPromisesWithDetails = [];
              Object.keys(allActionsConfig).forEach(categoryKey => {
                  const categoryConfig = allActionsConfig[categoryKey];
                  if (categoryConfig.categoryLabel && categoryConfig.actions && Array.isArray(categoryConfig.actions)) {
                      categoryConfig.actions.forEach(actionCfg => {
                          if (actionCfg && actionCfg.id && !QUICK_ACTION_IDS.includes(actionCfg.id)) {
                              const buttonPromise = createTooltipActionButton(actionCfg.id, actionCfg, selectionObject, 'list')
                                  .then(buttonNode => ({ button: buttonNode, categoryKey: categoryKey, originalConfig: actionCfg }))
                                  .catch(error => { console.error(`Error creating button for ${actionCfg.id} in category ${categoryKey}:`, error); const errorPlaceholder = document.createElement('span'); errorPlaceholder.textContent = `Error: ${actionCfg.id}`; errorPlaceholder.style.color = 'red'; return { button: errorPlaceholder, categoryKey: categoryKey, originalConfig: actionCfg }; });
                              allButtonPromisesWithDetails.push(buttonPromise);
                          }
                      });
                  }
              });
              try {
                  const resolvedButtonsWithDetails = await Promise.all(allButtonPromisesWithDetails);
                  const buttonsByCategory = {};
                  resolvedButtonsWithDetails.forEach(item => { if (!buttonsByCategory[item.categoryKey]) buttonsByCategory[item.categoryKey] = []; buttonsByCategory[item.categoryKey].push(item.button); });
                  Object.keys(allActionsConfig).forEach(categoryKey => {
                      const categoryConfig = allActionsConfig[categoryKey];
                      if (categoryConfig.categoryLabel && buttonsByCategory[categoryKey] && buttonsByCategory[categoryKey].length > 0) {
                          const categoryTitleElement = document.createElement('div'); categoryTitleElement.className = 'tooltip-category-title'; categoryTitleElement.textContent = categoryConfig.categoryLabel; actionList.appendChild(categoryTitleElement);
                          buttonsByCategory[categoryKey].forEach(buttonNode => { if (buttonNode && buttonNode instanceof Node) actionList.appendChild(buttonNode); });
                      }
                  });
              } catch (error) { console.error("toggleTooltipActionList: Error awaiting list action buttons:", error); }
              tooltipElement.appendChild(actionList);
          }
          tooltipActionListVisible = !tooltipActionListVisible; actionList.style.display = tooltipActionListVisible ? 'block' : 'none';
      }
      async function handleTooltipAIAction(fullPrompt, contextText = "", actionName = "פעולה") {
          const cleanupProcessingUI = showTooltipProcessingUI(actionName);
          try {
              const response = await fetch(API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: fullPrompt }) });
              cleanupProcessingUI();
              if (!response.ok) { const errTxt = await response.text(); let displayError = `שגיאת שרת (${response.status})`; try { const errJson = JSON.parse(errTxt); if (errJson && errJson.error) { displayError += `: ${errJson.error}`; } else { displayError += `: ${errTxt.substring(0,100)}`; } } catch (e) { displayError += `: ${errTxt.substring(0,100)}`; } showTooltipPopup(displayError, contextText); return; }
              const data = await response.json();
              if (data && data.text) showTooltipPopup(data.text, contextText); else showTooltipPopup("לא התקבלה תשובה תקינה מהשרת.", contextText);
          } catch (error) {
              cleanupProcessingUI(); console.error("AI Tooltip Error:", error); showTooltipPopup(`שגיאת תקשורת: ${error.message}`, contextText);
          }
      }
      
      // === FAB (Floating Action Button) CODE ===
      async function createFabMenuItem(actionId, actionConfig) {
          const button = document.createElement('button');
          button.className = 'fab-menu-button';
          button.title = actionConfig.title || '';
          const iconSpan = document.createElement('span');
          iconSpan.className = 'fab-menu-icon';
          iconSpan.textContent = actionConfig.label || '';
          button.appendChild(iconSpan);
          const textSpan = document.createElement('span');
          textSpan.className = 'fab-menu-text';
          textSpan.textContent = actionConfig.title || '';
          button.appendChild(textSpan);
          button.addEventListener('click', async (e) => {
              e.stopPropagation();
              hideFabMenu();
              let fullPrompt = "";
              let contentForAI = "";
              let actionTitleForDisplay = actionConfig.title;
              switch (actionConfig.type) {
                  case 'full_page_text': contentForAI = getPageContentForAI(); if (!contentForAI) { alert("אין תוכן בדף."); return; } fullPrompt = actionConfig.command + contentForAI; break;
                  case 'prompt_language_page_custom_dialog': contentForAI = getPageContentForAI(); if (!contentForAI) { alert("אין תוכן בדף."); return; } const targetLangPage = await showCustomPrompt({ title: "תרגום כל הדף", message: "לאיזו שפה לתרגם את כל תוכן הדף הנוכחי?", inputPlaceholder: "לדוגמה: אנגלית, צרפתית" }); if (targetLangPage && targetLangPage.trim() !== "") { fullPrompt = actionConfig.baseCommand.replace('{LANG}', targetLangPage) + contentForAI; actionTitleForDisplay = `תרגום דף ל${targetLangPage}`; } else return; break;
                  case 'custom_action': if (actionConfig.actionFn) actionConfig.actionFn(); else console.warn("FAB custom action with no actionFn:", actionConfig.id); return;
                  default: console.warn("FAB action with unhandled type or no command:", actionConfig); return;
              }
              if (fullPrompt) await handleTooltipAIAction(fullPrompt, contentForAI, actionTitleForDisplay);
          });
          return button;
      }
      async function populateFabMenu() {
          if (!fabMenuElement) return;
          fabMenuElement.innerHTML = '';
          const pageActionPromises = [];
          if (allActionsConfig.open_ai_chat) { pageActionPromises.push(createFabMenuItem('open_ai_chat_fab', { ...allActionsConfig.open_ai_chat, title: "פתח צ'אט AI" })); }
          Object.values(allActionsConfig).forEach(categoryOrAction => {
              if (categoryOrAction.categoryLabel && categoryOrAction.actions) {
                  categoryOrAction.actions.forEach(actionCfg => { if (actionCfg.type === 'full_page_text' || actionCfg.type === 'prompt_language_page_custom_dialog' || actionCfg.id === 'share_page') { pageActionPromises.push(createFabMenuItem(actionCfg.id, actionCfg)); } });
              } else if (categoryOrAction.id && (categoryOrAction.type === 'full_page_text' || categoryOrAction.type === 'prompt_language_page_custom_dialog' || categoryOrAction.id === 'share_page')) {
                  if (categoryOrAction.id !== 'open_ai_chat') pageActionPromises.push(createFabMenuItem(categoryOrAction.id, categoryOrAction));
              }
          });
          const buttons = await Promise.all(pageActionPromises);
          buttons.forEach(button => { if (button) fabMenuElement.appendChild(button); });
      }
      function showFabMenu() {
          if (!fabMenuElement || !fabButtonElement) return;
          populateFabMenu();
          const fabRect = fabButtonElement.getBoundingClientRect();
          const menuHeightEstimate = fabMenuElement.childElementCount * 40;
          let bottomPosition = window.innerHeight - fabRect.top + 10;
          let rightPosition = window.innerWidth - fabRect.right;
          if ((fabRect.top - menuHeightEstimate - 10) < 0 && (fabRect.bottom + menuHeightEstimate + 10) < window.innerHeight) {  bottomPosition = window.innerHeight - fabRect.bottom - menuHeightEstimate - 10; } else if ((fabRect.top - menuHeightEstimate - 10) < 0) {  bottomPosition = 10; }
          fabMenuElement.style.bottom = `${bottomPosition}px`;
          fabMenuElement.style.right = `${rightPosition}px`;
          fabMenuElement.style.left = 'auto';
          fabMenuElement.classList.add('visible');
          fabMenuVisible = true;
      }
      function hideFabMenu() { if (!fabMenuElement) return; fabMenuElement.classList.remove('visible'); fabMenuVisible = false; }
      function toggleFabMenu() { if (fabMenuVisible) hideFabMenu(); else showFabMenu(); }
      function createFab() {
          if (document.getElementById(FAB_ID)) return;
          fabButtonElement = document.createElement('button');
          fabButtonElement.id = FAB_ID;
          fabButtonElement.title = "פעולות AI על הדף";
          fabButtonElement.innerHTML = `🧠`;
          fabButtonElement.addEventListener('click', (e) => { e.stopPropagation(); toggleFabMenu(); });
          document.body.appendChild(fabButtonElement);
          fabMenuElement = document.createElement('div');
          fabMenuElement.id = FAB_MENU_ID;
          document.body.appendChild(fabMenuElement);
      }
      
      // === INITIALIZATION FUNCTION ===
      function initializeExtension() {
          loadThemePreference();
          checkForOnboarding();
          createFab();
      }
      
      if (document.readyState === 'complete' || document.readyState === 'interactive') {
          initializeExtension();
      } else {
          document.addEventListener('DOMContentLoaded', initializeExtension);
      }
      
      
      // === EVENT LISTENERS ===
      document.addEventListener('mouseup', (event) => {
          if (fabMenuVisible && fabMenuElement && !fabMenuElement.contains(event.target) && event.target !== fabButtonElement && !fabButtonElement.contains(event.target)) hideFabMenu();
          if (event.target.closest('#ai-text-helper-wrapper') || event.target.closest('.ai-helper-tooltip') || event.target.closest(`#${CHAT_SIDEBAR_ID}`) || event.target.closest('.ai-custom-prompt-overlay') || event.target.matches('input, textarea, [contenteditable="true"]')  || event.target.closest(`#${FAB_ID}`) || event.target.closest(`#${FAB_MENU_ID}`)) return;
          const selection = window.getSelection();
          const selectedText = selection ? selection.toString().trim() : "";
          if (selectedText.length > 1 && selectedText.length < 10000) {
              if (selection && selection.rangeCount > 0) { const range = selection.getRangeAt(0); const rect = range.getBoundingClientRect(); if (rect && (rect.width > 0 || rect.height > 0)) createTooltip(rect.left + rect.width / 2, rect.top, selection); else if (!tooltipActionListVisible) removeTooltip(); }
              else if (!tooltipActionListVisible) removeTooltip();
          } else if (!tooltipActionListVisible) removeTooltip();
      });
      document.addEventListener('mousedown', (event) => { if (currentTooltip && !currentTooltip.contains(event.target) && !event.target.closest(`#${CHAT_SIDEBAR_ID}`) && !event.target.closest('.ai-custom-prompt-overlay') && !event.target.closest('#ai-text-helper-wrapper')) removeTooltip(); });
      document.addEventListener('keydown', (event) => {
          if (event.key === 'Escape') {
              const customPromptOverlay = document.querySelector('.ai-custom-prompt-overlay.visible:not(.onboarding)'); // Prioritize non-onboarding prompts
              if (customPromptOverlay) { const cancelBtn = customPromptOverlay.querySelector('.cancel-btn'); if (cancelBtn) cancelBtn.click(); return; }
              const onboardingOverlay = document.querySelector('.ai-custom-prompt-overlay.visible.onboarding');
              if (onboardingOverlay) { const dismissBtn = onboardingOverlay.querySelector('.onboard-dismiss-btn'); if(dismissBtn) dismissBtn.click(); return; }
      
              if (aiChatSidebarInstance && aiChatSidebarInstance.isHistoryPanelOpen()) { aiChatSidebarInstance.closeHistoryPanel();
              } else if (fabMenuVisible) { hideFabMenu();
              } else if (currentTooltip) { removeTooltip();
              } else if (tooltipAiHelperWrapper && tooltipAiHelperWrapper.innerHTML !== '') { tooltipAiHelperWrapper.innerHTML = '';
              } else if (aiChatSidebarInstance && aiChatSidebarInstance.isOpen()) { aiChatSidebarInstance.close(); }
          }
      });
      
      // === AI CHAT SIDEBAR ===
      function launchAIChatSidebar() {
          if (aiChatSidebarInstance && aiChatSidebarInstance.isOpen()) { aiChatSidebarInstance.close(); return; }
          if (aiChatSidebarInstance) { aiChatSidebarInstance.open(); return; }
          aiChatSidebarInstance = (() => {
              let sidebarElement = null;
              let chatTitleEl, clearChatBtnEl, closeChatBtnEl, themeToggleBtnEl, renameChatBtnEl, viewHistoryBtnEl;
              let messagesAreaEl, inputFieldEl, sendBtnEl;
              let historyPanelEl, historyListEl;
              let chatMessages = [];
              let isLoading = false;
              let _isOpen = false;
              const MAX_HISTORY_MESSAGES_TO_SEND = 10;
              const CHAT_HISTORY_STORAGE_KEY = 'aiChatHistory';
              let currentChatSessionId = null;
              let autoSaveTimer = null;
              const AUTO_SAVE_DEBOUNCE = 3000; // 3 seconds
              function generateChatId() { return `chat_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`; }
              function formatChatTitle(date) { return `צ'אט ${date.toLocaleDateString('he-IL', {day:'2-digit',month:'2-digit',year:'numeric'})} ${date.toLocaleTimeString('he-IL', {hour:'2-digit', minute:'2-digit'})}`; }
              function updateChatTitleDisplay(title) { if (chatTitleEl) { const displayTitle = title || formatChatTitle(new Date()); chatTitleEl.textContent = displayTitle.length > 30 ? displayTitle.substring(0, 27) + "..." : displayTitle; } }
              function createSidebarDOM() {
                  sidebarElement = document.createElement('aside'); sidebarElement.id = CHAT_SIDEBAR_ID;
                  sidebarElement.innerHTML = ` <header class="chat-header"> <span class="chat-title" id="ai-chat-title">AI Chat</span> <div class="header-controls"> <button id="ai-chat-rename-btn" class="chat-control-btn" title="שמור בשם אחר / עדכן שם">✏️</button> <button id="ai-chat-history-btn" class="chat-control-btn" title="היסטוריית צ'אטים">📜</button> <button id="ai-chat-theme-toggle-btn" class="chat-control-btn" title="מצב כהה">🌙</button> <button id="ai-chat-clear-btn" class="chat-control-btn" title="צ'אט חדש">➕</button> <button id="ai-chat-close-btn" class="chat-control-btn" title="סגור (Esc)">✖</button> </div> </header> <main class="chat-main-content"> <div class="chat-messages-area" id="ai-chat-messages-area"></div> </main> <div class="chat-input-container"> <textarea class="chat-input-field" id="ai-chat-input-field" placeholder="הקלד הודעה..." rows="1"></textarea> <button class="chat-send-button" id="ai-chat-send-btn" title="שלח"> <svg viewBox="0 0 24 24"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"></path></svg> </button> </div> <div id="ai-chat-history-panel" class="chat-history-panel"> <div class="history-panel-header"> <h3>היסטוריית צ'אטים</h3> <button id="ai-chat-history-close-btn" class="chat-control-btn">×</button> </div> <div id="ai-chat-history-list" class="history-panel-list"> </div> </div> `;
                  document.body.appendChild(sidebarElement);
                  chatTitleEl = sidebarElement.querySelector('#ai-chat-title'); renameChatBtnEl = sidebarElement.querySelector('#ai-chat-rename-btn'); viewHistoryBtnEl = sidebarElement.querySelector('#ai-chat-history-btn'); themeToggleBtnEl = sidebarElement.querySelector('#ai-chat-theme-toggle-btn'); clearChatBtnEl = sidebarElement.querySelector('#ai-chat-clear-btn'); closeChatBtnEl = sidebarElement.querySelector('#ai-chat-close-btn'); messagesAreaEl = sidebarElement.querySelector('#ai-chat-messages-area'); inputFieldEl = sidebarElement.querySelector('#ai-chat-input-field'); sendBtnEl = sidebarElement.querySelector('#ai-chat-send-btn'); historyPanelEl = sidebarElement.querySelector('#ai-chat-history-panel'); historyListEl = sidebarElement.querySelector('#ai-chat-history-list');
                  const historyCloseBtn = sidebarElement.querySelector('#ai-chat-history-close-btn');
                  if(historyCloseBtn) historyCloseBtn.onclick = closeHistoryPanel;
                  attachEventListeners();
                  if (themeToggleBtnEl) { themeToggleBtnEl.innerHTML = currentTheme === 'dark' ? '☀️' : '🌙'; themeToggleBtnEl.title = currentTheme === 'dark' ? 'מצב בהיר' : 'מצב כהה'; }
              }
              function attachEventListeners() {
                  closeChatBtnEl.onclick = close; themeToggleBtnEl.onclick = () => { toggleTheme(); };
                  if (renameChatBtnEl) renameChatBtnEl.onclick = promptAndSaveChatName;
                  if (viewHistoryBtnEl) viewHistoryBtnEl.onclick = openHistoryPanel;
                  clearChatBtnEl.onclick = () => { startNewChat(); if(inputFieldEl) inputFieldEl.focus(); }; sendBtnEl.onclick = handleSendMessage;
                  inputFieldEl.addEventListener('keydown', e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSendMessage(); } });
                  inputFieldEl.addEventListener('input', autoResizeInput);
              }
              function autoResizeInput() { inputFieldEl.style.height = 'auto'; inputFieldEl.style.height = (Math.min(inputFieldEl.scrollHeight, 120)) + 'px'; }
              function setLoadingState(loading) {
                  isLoading = loading; sendBtnEl.disabled = loading; inputFieldEl.disabled = loading;
                  let loadingDiv = messagesAreaEl.querySelector('.chat-message.loading');
                  if (loading) { if (!loadingDiv) { loadingDiv = document.createElement('div'); loadingDiv.className = 'chat-message loading'; const dots = document.createElement('div'); dots.className = 'loading-dots'; for (let i = 0; i < 3; i++) dots.appendChild(document.createElement('span')); loadingDiv.appendChild(dots); messagesAreaEl.appendChild(loadingDiv); } messagesAreaEl.scrollTop = messagesAreaEl.scrollHeight; } else if (loadingDiv) loadingDiv.remove();
              }
              function addMessageToHistory(role, content) { chatMessages.push({ role, content }); triggerAutoSave(); }
              function addMessageToUI(text, type, addToHistoryArr = true) {
                  const msgDiv = document.createElement('div'); msgDiv.className = `chat-message ${type}`; msgDiv.innerHTML = '';
                  const lines = text.split('\n');
                  lines.forEach((line, index) => {
                      if (index > 0) msgDiv.appendChild(document.createElement('br'));
                      const parts = line.split(/\*\*(.*?)\*\*/g);
                      parts.forEach((part, partIndex) => { if (partIndex % 2 === 1) { const strong = document.createElement('strong'); strong.textContent = part; msgDiv.appendChild(strong); } else { msgDiv.appendChild(document.createTextNode(part)); } });
                  });
                  if (messagesAreaEl) { const loadingDiv = messagesAreaEl.querySelector('.chat-message.loading'); if (loadingDiv) messagesAreaEl.insertBefore(msgDiv, loadingDiv); else messagesAreaEl.appendChild(msgDiv); messagesAreaEl.scrollTop = messagesAreaEl.scrollHeight; } else { console.error("addMessageToUI (IIFE): messagesAreaEl is not defined!"); }
                  if (addToHistoryArr && (type === 'user' || type === 'assistant')) { addMessageToHistory(type, text); }
              }
              async function getChatSession(sessionId) { try { const result = await chrome.storage.local.get(CHAT_HISTORY_STORAGE_KEY); const history = result[CHAT_HISTORY_STORAGE_KEY] || []; return history.find(session => session.id === sessionId); } catch (e) { console.error("Error fetching chat session:", e); return null;} }
              async function autoSaveCurrentChat(isClosing = false) {
                  if (chatMessages.length === 0) return;
                  const sessionIdToSave = currentChatSessionId || generateChatId();
                  let currentTitle = formatChatTitle(new Date());
                  if(currentChatSessionId){ const existingSession = await getChatSession(currentChatSessionId); if(existingSession) currentTitle = existingSession.title; } // Keep existing title on auto-save unless it's a new chat
                  const chatSession = { id: sessionIdToSave, title: currentTitle, messages: [...chatMessages], createdAt: (await getChatSession(sessionIdToSave))?.createdAt || Date.now(), updatedAt: Date.now() };
                  try {
                      const result = await chrome.storage.local.get(CHAT_HISTORY_STORAGE_KEY);
                      const history = result[CHAT_HISTORY_STORAGE_KEY] || [];
                      const existingIndex = history.findIndex(session => session.id === sessionIdToSave);
                      if (existingIndex > -1) { history[existingIndex] = chatSession; } else { history.unshift(chatSession); }
                      await chrome.storage.local.set({ [CHAT_HISTORY_STORAGE_KEY]: history });
                      currentChatSessionId = sessionIdToSave; // Ensure it's set for subsequent auto-saves
                      updateChatTitleDisplay(chatSession.title);
                      if (!isClosing) { console.log(`Chat "${chatSession.title}" auto-saved.`); }
                      if (historyPanelEl && historyPanelEl.classList.contains('visible')) { openHistoryPanel(); } // Refresh history panel if open
                  } catch (error) { console.error("Error auto-saving chat:", error); }
              }
              function triggerAutoSave() { clearTimeout(autoSaveTimer); autoSaveTimer = setTimeout(() => autoSaveCurrentChat(), AUTO_SAVE_DEBOUNCE); }
              async function promptAndSaveChatName() {
                  if (!currentChatSessionId || chatMessages.length === 0) { showTooltipPopup("אין צ'אט פעיל לשמירה או שינוי שם.", "", 2000); return; }
                  let existingSession = await getChatSession(currentChatSessionId);
                  let defaultTitle = existingSession ? existingSession.title : formatChatTitle(new Date());
                  const promptedTitle = await showCustomPrompt({ title: "שנה שם צ'אט", message: `הזן כותרת חדשה לצ'אט "${defaultTitle}":`, defaultValue: defaultTitle, inputPlaceholder: "כותרת הצ'אט" });
                  if (promptedTitle === null) { console.log("Chat rename cancelled."); return; }
                  const finalTitle = promptedTitle.trim() === "" ? defaultTitle : promptedTitle.trim();
                  existingSession.title = finalTitle; existingSession.updatedAt = Date.now();
                  try {
                      const result = await chrome.storage.local.get(CHAT_HISTORY_STORAGE_KEY);
                      const history = result[CHAT_HISTORY_STORAGE_KEY] || [];
                      const existingIndex = history.findIndex(session => session.id === currentChatSessionId);
                      if (existingIndex > -1) { history[existingIndex] = existingSession; } else { history.unshift(existingSession); } // Should not happen if currentChatSessionId is valid
                      await chrome.storage.local.set({ [CHAT_HISTORY_STORAGE_KEY]: history });
                      updateChatTitleDisplay(finalTitle); showTooltipPopup(`כותרת הצ'אט עודכנה ל-"${finalTitle}"!`, "", 2000);
                      if (historyPanelEl.classList.contains('visible')) openHistoryPanel();
                  } catch (error) { console.error("Error renaming chat:", error); showTooltipPopup("שגיאה בשינוי שם הצ'אט.", "", 2000); }
              }
              async function openHistoryPanel() {
                  try {
                      const result = await chrome.storage.local.get(CHAT_HISTORY_STORAGE_KEY);
                      const history = result[CHAT_HISTORY_STORAGE_KEY] || [];
                      history.sort((a, b) => (b.updatedAt || b.createdAt) - (a.updatedAt || a.createdAt));
                      historyListEl.innerHTML = '';
                      if (history.length === 0) { historyListEl.innerHTML = '<p class="empty-history-message">אין צ\'אטים שמורים.</p>'; } else {
                          history.forEach(session => {
                              const itemEl = document.createElement('div'); itemEl.className = 'history-item';
                              itemEl.innerHTML = ` <div class="history-item-info"> <span class="history-item-title">${session.title}</span> <span class="history-item-date">${new Date(session.updatedAt || session.createdAt).toLocaleString('he-IL', {day:'2-digit', month:'2-digit', year:'numeric', hour:'2-digit', minute:'2-digit'})}</span> </div> <div class="history-item-actions"> <button class="history-load-btn" title="טען צ'אט">✔️</button> <button class="history-delete-btn" title="מחק צ'אט">🗑️</button> </div> `;
                              itemEl.querySelector('.history-load-btn').onclick = () => loadChatSession(session.id);
                              itemEl.querySelector('.history-delete-btn').onclick = () => deleteChatSession(session.id);
                              historyListEl.appendChild(itemEl);
                          });
                      }
                      historyPanelEl.classList.add('visible');
                  } catch (error) { console.error("Error loading history:", error); historyListEl.innerHTML = '<p class="empty-history-message">שגיאה בטעינת היסטוריה.</p>'; }
              }
              function closeHistoryPanel() { if (historyPanelEl) historyPanelEl.classList.remove('visible'); }
              async function loadChatSession(sessionId) {
                  try {
                      const sessionToLoad = await getChatSession(sessionId);
                      if (sessionToLoad) {
                          messagesAreaEl.innerHTML = ''; chatMessages = [...sessionToLoad.messages]; currentChatSessionId = sessionToLoad.id;
                          chatMessages.forEach(msg => addMessageToUI(msg.content, msg.role, false));
                          updateChatTitleDisplay(sessionToLoad.title);
                          clearTimeout(autoSaveTimer); // Clear any pending auto-save from previous chat
                          closeHistoryPanel(); inputFieldEl.focus();
                      } else { showTooltipPopup("הצ'אט לא נמצא.", "", 2000); }
                  } catch (error) { console.error("Error loading chat session:", error); showTooltipPopup("שגיאה בטעינת הצ'אט.", "", 2000); }
              }
              async function deleteChatSession(sessionId) {
                  if (!confirm("האם אתה בטוח שברצונך למחוק צ'אט זה?")) return;
                  try {
                      const result = await chrome.storage.local.get(CHAT_HISTORY_STORAGE_KEY);
                      let history = result[CHAT_HISTORY_STORAGE_KEY] || [];
                      history = history.filter(s => s.id !== sessionId);
                      await chrome.storage.local.set({ [CHAT_HISTORY_STORAGE_KEY]: history });
                      if (currentChatSessionId === sessionId) { startNewChat(); }
                      openHistoryPanel(); showTooltipPopup("הצ'אט נמחק.", "", 1500);
                  } catch (error) { console.error("Error deleting chat session:", error); showTooltipPopup("שגיאה במחיקת הצ'אט.", "", 2000); }
              }
              function startNewChat() {
                  messagesAreaEl.innerHTML = ''; chatMessages = []; currentChatSessionId = generateChatId();
                  updateChatTitleDisplay(formatChatTitle(new Date()));
                  addMessageToUI("הצ'אט נוקה. איך אפשר לעזור היום?", "assistant", false);
                  clearTimeout(autoSaveTimer);
              }
              async function sendQueryToAPI() {
                  const currentUserInput = inputFieldEl.value.trim();
                  if (currentUserInput) { addMessageToUI(currentUserInput, 'user'); inputFieldEl.value = ''; autoResizeInput(); }
                  else if (chatMessages.length === 0) { addMessageToUI("שלום! איך אוכל לעזור לך היום?", "assistant", false); return; }
                  setLoadingState(true);
                  const messagesForPrompt = chatMessages.slice(-MAX_HISTORY_MESSAGES_TO_SEND);
                  let promptString = ""; messagesForPrompt.forEach(msg => { const prefix = msg.role === 'user' ? 'המשתמש' : 'AI'; promptString += `${prefix}: ${msg.content}\n`; });
                  const apiPayload = { text: promptString.trim() };
                  try {
                      const response = await fetch(API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(apiPayload) });
                      if (!response.ok) { const errorText = await response.text(); let displayError = `שגיאת שרת (${response.status})`; try { const errJson = JSON.parse(errorText); if (errJson && errJson.error) { displayError += `: ${errJson.error}`; } else { displayError += `: ${errorText.substring(0,100)}`; } } catch (e) { displayError += `: ${errorText.substring(0,100)}`; } addMessageToUI(displayError, 'server-error', false); throw new Error(displayError); }
                      const data = await response.json();
                      const reply = data.text || "לא התקבלה תשובה ברורה מהשרת.";
                      addMessageToUI(reply, 'assistant');
                      triggerAutoSave(); // Auto-save after AI reply
                  } catch (e) {
                      console.error("AI Chat API Error:", e.message);
                      if (!messagesAreaEl.querySelector('.chat-message.server-error')) { addMessageToUI(`שגיאה בתקשורת: ${e.message}`, 'server-error', false); }
                  } finally {
                      setLoadingState(false); if(inputFieldEl) inputFieldEl.focus();
                  }
              }
              function handleSendMessage() { sendQueryToAPI(); }
              async function open() {
                  if (!sidebarElement) createSidebarDOM();
                  requestAnimationFrame(() => { if(sidebarElement) sidebarElement.classList.add('open'); });
                  _isOpen = true; if(inputFieldEl) inputFieldEl.focus();
                  if (!currentChatSessionId) { // Only start new if no current session (e.g., first open or after explicit new chat)
                      currentChatSessionId = generateChatId();
                      updateChatTitleDisplay(formatChatTitle(new Date()));
                      if (chatMessages.length === 0) { addMessageToUI("שלום! איך אוכל לעזור לך היום?", "assistant", false); }
                  } else { // If there's a session ID, try to load its title
                      const session = await getChatSession(currentChatSessionId);
                      if (session) { updateChatTitleDisplay(session.title); } else { // Stale ID, start fresh
                          currentChatSessionId = generateChatId();
                          updateChatTitleDisplay(formatChatTitle(new Date()));
                          if (chatMessages.length === 0) addMessageToUI("שלום! איך אוכל לעזור לך היום?", "assistant", false);
                      }
                  }
              }
              async function close() {
                  clearTimeout(autoSaveTimer); // Clear pending auto-save
                  if (chatMessages.length > 0 && currentChatSessionId) { await autoSaveCurrentChat(true); } // Perform final save on close
                  if (sidebarElement) sidebarElement.classList.remove('open');
                  _isOpen = false;
                  if (historyPanelEl && historyPanelEl.classList.contains('visible')) closeHistoryPanel();
              }
              return { open, close, isOpen: () => _isOpen, getThemeToggleButton: () => themeToggleBtnEl, isHistoryPanelOpen: () => historyPanelEl && historyPanelEl.classList.contains('visible'), closeHistoryPanel };
          })();
          aiChatSidebarInstance.open();
      }
      // === END OF CHAT SIDEBAR CODE ===
      
      chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
          if (request.type === "TOGGLE_AI_CHAT_SIDEBAR") {
              if (!aiChatSidebarInstance) { launchAIChatSidebar(); sendResponse({status: "Sidebar launched and opened"});
              } else if (aiChatSidebarInstance.isOpen()) { aiChatSidebarInstance.close(); sendResponse({status: "Sidebar closed"});
              } else { aiChatSidebarInstance.open(); sendResponse({status: "Sidebar opened"});
              }
              return true;
          }
      });
      console.log("AI Suite Pro (Tooltip, Chat, Custom Dialog, Dark Mode, History, Onboarding, AutoSave) content script initialized. Version 1.1.1");
      

      ויש שם עוד שגיאה אבל נראה לי זה אותו רעיון רק כל פעולה שאני רוצה לבצע הוא יוצר עוד שגיאה

      שמח לעזור

      תגובה 1 תגובה אחרונה
      0
      • י יוסי רחמים

        מה הופך את AI Suite Pro למיוחד?
        טולטיפ הקסם:
        📝 סיכום בזק: סמנו טקסט ארוך וקבלו תמצית בהירה.
        🌐 תרגום מיידי: תרגמו קטעים לכל שפה שתבחרו.
        💡 הסבר בהקשר: הבינו מונחים מסובכים במשפט המקורי.
        🔍 חיפוש חכם: חפשו את הטקסט המסומן בגוגל בלחיצה.
        🔗 שיתוף קל: שתפו את הדף הנוכחי בקלות.
        ניתוח דף מלא:
        📄 סיכום עמוד שלם: הבינו את עיקרי הדברים במאמרים ארוכים.
        ✔️ אימות עובדות: קבלו הערכה על אמינות המידע.
        🧑‍🏫 למידה מודרכת: בקשו מה-AI "ללמד" אתכם את תוכן הדף.
        ❓ שאלות ותשובות: הפכו כל טקסט למבנה Q&A מועיל.
        צ'אט AI מתקדם:
        💬 סרגל צ'אט צידי, זמין תמיד.
        🧠 זוכר את מהלך השיחה להמשכיות טבעית.
        💡 שאלו כל דבר, קבלו תשובות מבוססות הקשר.
        כפתור פעולה צף (FAB):
        🔘 גישה נוחה לפעולות על כל הדף, בלי צורך בסימון טקסט.
        AI Suite Pro – כי הידע והיעילות שלכם חשובים!
        התקינו היום ותתחילו לגלוש חכם יותר, מהר יותר ועם הבנה עמוקה יותר.
        AI.zip

        התוסף עודכן

        נוסף היסטוריה לצאטים
        נוספה חלונית צדדית לצאט
        כפתור שאל על דף זה

        התקנת תוסף Chrome מקובץ ZIP:

        1. חלצו את קובץ ה-ZIP:

          • מצאו את קובץ ה-.zip של התוסף.
          • לחצו עליו קליק ימני ובחרו "חלץ הכל..." (Extract All...).
          • שמרו את התיקייה שנוצרה במקום שקל למצוא.
        2. בכרום, פתחו את דף התוספים:

          • בשורת הכתובת, הקלידו: chrome://extensions
          • לחצו Enter.
        3. הפעילו "מצב מפתח":

          • בדף התוספים, מצאו את המתג "מצב מפתח" (Developer mode) והפעילו אותו (בדרך כלל בפינה העליונה).
        4. טענו את התיקייה שחולצה:

          • לחצו על הכפתור "טען תוסף שלא נארז" (Load unpacked).
          • בחלון שנפתח, נווטו אל התיקייה שחילצתם בשלב 1 (זו שמכילה את קובץ ה-manifest.json).
          • בחרו את התיקייה ולחצו "בחר תיקייה" (Select Folder).

        זהו! התוסף מותקן ומוכן לשימוש.
        f66d7ecc-8b17-4e00-81dd-41da303711c0-image.png
        b8b8e6c0-76f1-4e6f-8207-c72229157f57-image.png

        א מחובר
        א מחובר
        אלוף תימן
        כתב נערך לאחרונה על ידי
        #43

        @יוסי-רחמים זה חינמי

        י תגובה 1 תגובה אחרונה
        2
        • א אלוף תימן

          @יוסי-רחמים זה חינמי

          י מנותק
          י מנותק
          יוסי רחמים
          כתב נערך לאחרונה על ידי
          #44

          @אלוף-תימן כן

          פרוזיפ תגובה 1 תגובה אחרונה
          2
          • י יוסי רחמים

            @אלוף-תימן כן

            פרוזיפ מנותק
            פרוזיפ מנותק
            פרוזי
            מדריכים עימוד
            כתב נערך לאחרונה על ידי פרוזי
            #45

            @יוסי-רחמים נראה שזה כן קשור לנטפרי לפי מה שאני מבין...

            יש מישהו בנטפרי שזה עובד לו?
            אם תשנה את זה ל API אישי לכאו' זה אמור לעזור...

            שמח לעזור

            י תגובה 1 תגובה אחרונה
            1
            • פרוזיפ פרוזי

              @יוסי-רחמים נראה שזה כן קשור לנטפרי לפי מה שאני מבין...

              יש מישהו בנטפרי שזה עובד לו?
              אם תשנה את זה ל API אישי לכאו' זה אמור לעזור...

              י מנותק
              י מנותק
              יוסי רחמים
              כתב נערך לאחרונה על ידי
              #46

              @פרוזי לא יודע אם זה יעזור API אישי(מה יהיה ההבדל מהAPI האישי שלי לשל כל אחד אחר?)
              אבל לא יודע... אשמח למידע ממישהו שמבין

              תגובה 1 תגובה אחרונה
              0
              • י. פל.י י. פל.

                @יוסי-רחמים
                אני מעלה לך גרסה חדשה, לא גמורה, אבל לא יודע כמה אוכל להמשיך כעת...

                י. פל.י מנותק
                י. פל.י מנותק
                י. פל.
                כתב נערך לאחרונה על ידי
                #47

                @י.-פל. כתב בהמלצה | 🧠 שדרגו את הדפדפן שלכם עם AI Suite Pro – חבילת ה-AI האולטימטיבית לגלישה! 🧠:

                @יוסי-רחמים
                אני מעלה לך גרסה חדשה, לא גמורה, אבל לא יודע כמה אוכל להמשיך כעת...

                אתה מתכנן לקבל?

                כתבתי ברדמי את השינויים שלדעתי נצרכים, מי רוצה להמשיך?
                כרגע הכל כאן:
                https://github.com/Y-PLONI/AI-Suite-Pro
                עד ש @יוסי-רחמים יקבל את הPR.

                י תגובה 1 תגובה אחרונה
                1
                • י. פל.י י. פל.

                  @י.-פל. כתב בהמלצה | 🧠 שדרגו את הדפדפן שלכם עם AI Suite Pro – חבילת ה-AI האולטימטיבית לגלישה! 🧠:

                  @יוסי-רחמים
                  אני מעלה לך גרסה חדשה, לא גמורה, אבל לא יודע כמה אוכל להמשיך כעת...

                  אתה מתכנן לקבל?

                  כתבתי ברדמי את השינויים שלדעתי נצרכים, מי רוצה להמשיך?
                  כרגע הכל כאן:
                  https://github.com/Y-PLONI/AI-Suite-Pro
                  עד ש @יוסי-רחמים יקבל את הPR.

                  י מנותק
                  י מנותק
                  יוסי רחמים
                  כתב נערך לאחרונה על ידי יוסי רחמים
                  #48

                  @י.-פל. קיבלתי🫡
                  (האמת שכבר עשיתי כמה שינויים בתוסף אז אני יצטרך בהמשך לשלב את מה שעשית)

                  י. פל.י תגובה 1 תגובה אחרונה
                  0
                  • י יוסי רחמים

                    @י.-פל. קיבלתי🫡
                    (האמת שכבר עשיתי כמה שינויים בתוסף אז אני יצטרך בהמשך לשלב את מה שעשית)

                    י. פל.י מנותק
                    י. פל.י מנותק
                    י. פל.
                    כתב נערך לאחרונה על ידי י. פל.
                    #49

                    @יוסי-רחמים כתב בהמלצה | 🧠 שדרגו את הדפדפן שלכם עם AI Suite Pro – חבילת ה-AI האולטימטיבית לגלישה! 🧠:

                    @י.-פל. קיבלתי🫡
                    (האמת שכבר עשיתי כמה שינויים בתוסף אז אני יצטרך בהמשך לשלב את מה שעשית)

                    אז למה קיבלת?
                    איפה אנחנו אוחזים, תכל'ס?
                    צריך פשוט להחליט מי עושה מה, וככה נוכל להתקדם מהר יותר!
                    [אתה פשוט יכול לפתוח בעיה, ואז להקצות אלי/אליך/מישהו אחר שיתנדב].

                    י תגובה 1 תגובה אחרונה
                    1
                    • י. פל.י י. פל.

                      @יוסי-רחמים כתב בהמלצה | 🧠 שדרגו את הדפדפן שלכם עם AI Suite Pro – חבילת ה-AI האולטימטיבית לגלישה! 🧠:

                      @י.-פל. קיבלתי🫡
                      (האמת שכבר עשיתי כמה שינויים בתוסף אז אני יצטרך בהמשך לשלב את מה שעשית)

                      אז למה קיבלת?
                      איפה אנחנו אוחזים, תכל'ס?
                      צריך פשוט להחליט מי עושה מה, וככה נוכל להתקדם מהר יותר!
                      [אתה פשוט יכול לפתוח בעיה, ואז להקצות אלי/אליך/מישהו אחר שיתנדב].

                      י מנותק
                      י מנותק
                      יוסי רחמים
                      כתב נערך לאחרונה על ידי יוסי רחמים
                      #50

                      @י.-פל. הזיפ של התוסף כאן למעלה.לעדכן אותו בגיטהב?(זה יהרוס את מה שעשית)
                      (ביקשו חלונית צדדית אז עשיתי🤔)

                      י. פל.י 2 תגובות תגובה אחרונה
                      1
                      • י יוסי רחמים

                        @י.-פל. הזיפ של התוסף כאן למעלה.לעדכן אותו בגיטהב?(זה יהרוס את מה שעשית)
                        (ביקשו חלונית צדדית אז עשיתי🤔)

                        י. פל.י מנותק
                        י. פל.י מנותק
                        י. פל.
                        כתב נערך לאחרונה על ידי
                        #51

                        @יוסי-רחמים כתב בהמלצה | 🧠 שדרגו את הדפדפן שלכם עם AI Suite Pro – חבילת ה-AI האולטימטיבית לגלישה! 🧠:

                        @י.-פל. הזיפ של התוסף כאן למעלה.לעדכן אותו בגיטהב?(זה יהרוס את מה שעשית)

                        1. אתה הבעלים.
                        2. אם הוא לא שולח ישירות לג'מיני - הוא לא שווה למשתמשי נטפרי.
                        י תגובה 1 תגובה אחרונה
                        1
                        • י יוסי רחמים

                          @י.-פל. הזיפ של התוסף כאן למעלה.לעדכן אותו בגיטהב?(זה יהרוס את מה שעשית)
                          (ביקשו חלונית צדדית אז עשיתי🤔)

                          י. פל.י מנותק
                          י. פל.י מנותק
                          י. פל.
                          כתב נערך לאחרונה על ידי
                          #52

                          @יוסי-רחמים כתב בהמלצה | 🧠 שדרגו את הדפדפן שלכם עם AI Suite Pro – חבילת ה-AI האולטימטיבית לגלישה! 🧠:

                          (ביקשו חלונית צדדית אז עשיתי)

                          1
                          י
                          יוסי רחמים
                          @י.-פל. הזיפ של התוסף כאן למעלה.לעדכן אותו בגיטהב?(זה יהרוס את מה שעשית)
                          (ביקשו חלונית צדדית אז עשיתי)

                          זה אמור להיות פונקציה צדדית, לא?

                          תגובה 1 תגובה אחרונה
                          0
                          • י. פל.י י. פל.

                            @יוסי-רחמים כתב בהמלצה | 🧠 שדרגו את הדפדפן שלכם עם AI Suite Pro – חבילת ה-AI האולטימטיבית לגלישה! 🧠:

                            @י.-פל. הזיפ של התוסף כאן למעלה.לעדכן אותו בגיטהב?(זה יהרוס את מה שעשית)

                            1. אתה הבעלים.
                            2. אם הוא לא שולח ישירות לג'מיני - הוא לא שווה למשתמשי נטפרי.
                            י מנותק
                            י מנותק
                            יוסי רחמים
                            כתב נערך לאחרונה על ידי
                            #53

                            @י.-פל. API שאני שם מראש של גמיני זה לא טוב?מה העניין בAPI אישי?
                            והפכתי את זה לחלונית צד

                            לאציל תגובה 1 תגובה אחרונה
                            0
                            • י יוסי רחמים

                              @י.-פל. API שאני שם מראש של גמיני זה לא טוב?מה העניין בAPI אישי?
                              והפכתי את זה לחלונית צד

                              לאציל מנותק
                              לאציל מנותק
                              לאצי
                              כתב נערך לאחרונה על ידי לאצי
                              #54

                              @יוסי-רחמים הסיבה שהוא לא פועל כעת בנטפרי היא לכאו' מפני שכתובת השרת בה נמצא מפתח הAPI - חסומה בנטפרי.

                              כתובת השרת היא https://php-render-test.onrender.com/main-ai.php, אבל שם אני לא מגיע לשום מקום, ואילו כשאני חוזר אחד אחורה ל https://php-render-test.onrender.com/ אני מגיע לצ'אט AI. למה זה ומה זה?

                              ואגב, אם שמת לב א"א להשתמש אתו בג'מיני עצמו. עשיתי אימות עובדות עם התוסף בשיחה הזו https://g.co/gemini/share/d56116801f85 שהובאה כאן https://mitmachim.top/post/963192
                              והוא כותב לי 2b4f0ad0-2df8-4224-9287-f0796e4541ce-image.png

                              כלומר, התשובה שלו בתוך דף של ג'מיני היא כשל ג'מיני עצמו, כאילו הוא גם חלק מהשיחה ולא כמישהו חיצוני שמסכם/מנתח את הדף. סתם נקודה למחשבה.

                              תגובה 1 תגובה אחרונה
                              0

                              • התחברות

                              • אין לך חשבון עדיין? הרשמה

                              • התחברו או הירשמו כדי לחפש.
                              • פוסט ראשון
                                פוסט אחרון
                              0
                              • חוקי הפורום
                              • פופולרי
                              • לא נפתר
                              • משתמשים
                              • חיפוש גוגל בפורום
                              • צור קשר