(function() { document.addEventListener('DOMContentLoaded', function() { var mediaBtn = document.getElementById('pfeai-media-button'); if (mediaBtn) { mediaBtn.addEventListener('click', function(e) { e.preventDefault(); if (window.PFEditorialAI) { PFEditorialAI.togglePanel(); } }); } }); if (typeof tinymce === 'undefined') { return; } tinymce.create('tinymce.plugins.PFEditorialAI', { init: function(editor, url) { editor.on('init', function() { PFEditorialAI.createPanel(editor); PFEditorialAI.bindTooltipEvents(); PFEditorialAI.preloadSavedData(); }); }, getInfo: function() { return { longname: 'PF Editorial AI', author: 'PatsFans + AI', version: '5.2.7' }; } }); tinymce.PluginManager.add('pfeai_plugin', tinymce.plugins.PFEditorialAI); window.PFEditorialAI = { panelCreated: false, panelEl: null, loadingEl: null, analysisEl: null, titlesEl: null, ideasEl: null, transcriptEl: null, socialEl: null, savedEl: null, factsEl: null, linksEl: null, isMinimized: false, // Cache window tracking cacheWindowStart: null, cacheWindowTimer: null, cacheWindowDuration: 4 * 60 * 1000, // 4 minutes (conservative estimate) tasksInWindow: 0, /** * SECURITY: Escape HTML to prevent XSS * This function must be used for ALL user/API data inserted into the DOM */ escapeHtml: function(str) { if (str === null || str === undefined) return ''; return String(str) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); }, /** * SECURITY: Sanitize for textarea/input values */ escapeAttr: function(str) { if (str === null || str === undefined) return ''; return String(str) .replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, ''') .replace(//g, '>'); }, /** * Cache Window Indicator - shows when implicit caching is active */ startCacheWindow: function(fromCache) { var self = this; // If result was from app cache, don't start/extend the API cache window if (fromCache) return; this.tasksInWindow++; // Start or extend the cache window this.cacheWindowStart = Date.now(); // Clear existing timer if (this.cacheWindowTimer) { clearInterval(this.cacheWindowTimer); } // Update indicator immediately this.updateCacheIndicator(); // Update every second this.cacheWindowTimer = setInterval(function() { self.updateCacheIndicator(); }, 1000); }, updateCacheIndicator: function() { var indicator = document.getElementById('pfeai-cache-indicator'); if (!indicator) return; if (!this.cacheWindowStart) { indicator.style.display = 'none'; return; } var elapsed = Date.now() - this.cacheWindowStart; var remaining = this.cacheWindowDuration - elapsed; if (remaining <= 0) { // Cache window expired indicator.style.display = 'none'; this.cacheWindowStart = null; this.tasksInWindow = 0; if (this.cacheWindowTimer) { clearInterval(this.cacheWindowTimer); this.cacheWindowTimer = null; } return; } // Show indicator indicator.style.display = 'block'; var minutes = Math.floor(remaining / 60000); var seconds = Math.floor((remaining % 60000) / 1000); var timeStr = minutes + ':' + (seconds < 10 ? '0' : '') + seconds; var savingsText = this.tasksInWindow > 1 ? ' · ' + (this.tasksInWindow - 1) + ' task' + (this.tasksInWindow > 2 ? 's' : '') + ' cached' : ''; indicator.innerHTML = '⚡ Cache active: ' + timeStr + ' remaining' + savingsText + '
Run more tasks now to save tokens'; }, getProvider: function() { var select = document.getElementById('pfeai-provider-select'); return select ? select.value : 'gemini'; }, getSafeContent: function(editor) { try { if (editor && !editor.isHidden()) return editor.getContent({ format: 'raw' }); var textArea = document.getElementById('content'); return textArea ? textArea.value : ''; } catch (e) { return ''; } }, getSafeText: function(editor) { try { if (editor && !editor.isHidden()) return editor.getContent({ format: 'text' }); var textArea = document.getElementById('content'); return textArea ? textArea.value : ''; } catch (e) { return ''; } }, createPanel: function(editor) { if (this.panelCreated) return; // FIX: Inject Layout Push Styles directly to ensure they work var style = document.createElement('style'); style.innerHTML = 'body.pfeai-panel-open #wpbody-content { margin-right: 360px !important; transition: margin-right 0.3s ease; } body.pfeai-panel-open .pfeai-panel { right: 0; box-shadow: -2px 0 5px rgba(0,0,0,0.1); }'; document.head.appendChild(style); var panel = document.createElement('div'); panel.id = 'pfeai-panel'; var html = ''; html += '
'; html += '
'; html += '
'; html += '
'; html += ' '; html += '
'; html += '
PF Editorial AI
'; html += '
'; html += ' '; html += '
'; html += '
'; html += '
'; html += '
'; html += ' '; html += ' '; html += '
'; html += '
'; html += '
Click to expand
'; html += '
'; html += ' '; html += '
'; html += '
'; if (PFEAI.saved_data.clipboard) { html += '
'; html += ''; html += ''; html += '
'; } html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; // Only show Clear Topics button if there's cached ideas data if (PFEAI.saved_data.ideas && PFEAI.saved_data.ideas.ideas) { html += '
'; html += ''; html += ''; html += '
'; } else { html += ' '; } html += ' '; html += '
'; html += '
'; html += ' '; html += '
'; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; if (PFEAI.saved_data.clipboard) { html += ' '; } html += '
'; html += '
'; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += ' '; html += '
'; html += '
'; html += '
'; panel.innerHTML = html; document.body.appendChild(panel); this.panelEl = panel; this.loadingEl = panel.querySelector('.pfeai-loading'); this.analysisEl = { highlights: panel.querySelector('.pfeai-tab-content[data-tab="highlights"]'), suggestions: panel.querySelector('.pfeai-tab-content[data-tab="suggestions"]'), gaps: panel.querySelector('.pfeai-tab-content[data-tab="gaps"]') }; this.titlesEl = panel.querySelector('.pfeai-tab-content[data-tab="titles"]'); this.seoEl = panel.querySelector('.pfeai-tab-content[data-tab="seo"]'); this.ideasEl = panel.querySelector('.pfeai-tab-content[data-tab="ideas"]'); this.transcriptEl = panel.querySelector('.pfeai-tab-content[data-tab="transcript"]'); this.socialEl = panel.querySelector('.pfeai-tab-content[data-tab="social"]'); this.savedEl = panel.querySelector('.pfeai-tab-content[data-tab="saved"]'); this.factsEl = panel.querySelector('.pfeai-tab-content[data-tab="facts"]'); this.linksEl = panel.querySelector('.pfeai-tab-content[data-tab="links"]'); this.faqEl = panel.querySelector('.pfeai-tab-content[data-tab="faq"]'); panel.querySelector('.pfeai-faq-btn').addEventListener('click', function() { self.runFAQ(editor); }); panel.querySelector('#btn-internal-links').addEventListener('click', function() { var btnText = this.innerText; if (btnText.indexOf('View Links') !== -1) { self.showResults('links'); } else { self.runInternalLinks(editor); } }); panel.querySelector('#btn-search').addEventListener('click', function() { self.showResults('search'); }); var self = this; panel.querySelector('.pfeai-close').addEventListener('click', function(e) { e.stopPropagation(); self.togglePanel(false); }); panel.querySelector('.pfeai-minimize-btn').addEventListener('click', function(e) { e.stopPropagation(); self.toggleMinimize(); }); panel.querySelector('.pfeai-back-btn').addEventListener('click', function(e) { e.stopPropagation(); self.showMenu(); }); var viewSavedBtn = document.getElementById('btn-view-saved'); if (viewSavedBtn) { viewSavedBtn.addEventListener('click', function() { self.showResults('saved'); }); } var clearSavedBtn = document.getElementById('btn-clear-saved'); if (clearSavedBtn) { clearSavedBtn.addEventListener('click', function() { if (confirm('Are you sure you want to clear your saved draft? This cannot be undone.')) { self.clearClipboard(); } }); } panel.querySelector('#btn-scan').addEventListener('click', function() { var btnText = this.innerText; if (btnText.indexOf('View Analysis') !== -1) { self.showResults('highlights'); } else { self.runAnalysis(editor); } }); panel.querySelector('#btn-social').addEventListener('click', function() { var btnText = this.innerText; if (btnText.indexOf('View Social') !== -1) { self.showResults('social'); } else { self.runSocialPack(editor); } }); panel.querySelector('#btn-transcript').addEventListener('click', function() { var btnText = this.innerText; if (btnText.indexOf('View Transcript') !== -1) { self.showResults('transcript'); } else { self.runTranscriptScan(editor); } }); panel.querySelector('#btn-titles').addEventListener('click', function() { var btnText = this.innerText; if (btnText.indexOf('View Titles') !== -1) { self.showResults('titles'); } else { self.runTitles(editor); } }); panel.querySelector('#btn-ideas').addEventListener('click', function() { var btnText = this.innerText; if (btnText.indexOf('View Topics') !== -1) { self.showResults('ideas'); } else { self.runArticleIdeas(editor); } }); var clearIdeasBtn = panel.querySelector('#btn-clear-ideas'); if (clearIdeasBtn) { clearIdeasBtn.addEventListener('click', function() { if (confirm('Clear cached Topic Ideas? This will reset the Topics tab.')) { self.clearIdeasCache(); } }); } panel.querySelector('.pfeai-tagline-btn').addEventListener('click', function() { self.runTagline(editor); }); panel.querySelector('.pfeai-tags-btn').addEventListener('click', function() { self.runTagSuggestions(editor); }); panel.querySelector('.pfeai-meta-btn').addEventListener('click', function() { self.runMetaDescFromMenu(editor); }); panel.querySelectorAll('.pfeai-tab').forEach(function(btn) { btn.addEventListener('click', function() { self.switchTab(this.getAttribute('data-tab')); }); }); this.panelCreated = true; }, runSocialPack: function(editor, forceRefresh) { var self = this; var contentHtml = this.getSafeContent(editor); var title = (document.getElementById('title') || {}).value || ''; if (!title) { alert('Please enter a title.'); return; } this.showResults('social'); this.setLoading(true); fetch(PFEAI.rest_url + 'social-pack?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ content: contentHtml, title: title, post_id: PFEAI.post_id, provider: this.getProvider(), force_refresh: forceRefresh || false }) }) .then(function(r){return r.json()}).then(function(json){ self.setLoading(false); if(json.tweets) { self.renderSocialPack(json); var timestamp = json.generated_at || Date.now()/1000; self.setCachedState('btn-social', 'View Social Posts', 'social', timestamp, json.from_cache); self.startCacheWindow(json.from_cache); } else if (json.code) { self.socialEl.innerHTML = '

Error: ' + self.escapeHtml(json.message) + '

'; } }).catch(function(e) { self.setLoading(false); console.error(e); }); }, renderSocialPack: function(data) { var self = this; this.socialEl.innerHTML = '

Social Posts

'; (data.tweets || []).forEach(function(t, idx) { self.createSocialCard('Twitter / X ('+(idx+1)+')', t, self.socialEl); }); if (data.facebook) self.createSocialCard('Facebook', data.facebook, self.socialEl); if (data.meta_desc) self.createSocialCard('Meta Description (SEO)', data.meta_desc, self.socialEl); }, createSocialCard: function(label, text, container) { var card = document.createElement('div'); card.className = 'pfeai-card'; card.style.background = '#f5f5f5'; var labelEl = document.createElement('strong'); labelEl.textContent = label; card.appendChild(labelEl); var textEl = document.createElement('p'); textEl.style.fontSize = '12px'; textEl.style.marginBottom = '5px'; textEl.textContent = text; card.appendChild(textEl); var copyBtn = document.createElement('button'); copyBtn.className = 'button button-small'; copyBtn.textContent = 'Copy'; copyBtn.onclick = function() { navigator.clipboard.writeText(text); copyBtn.textContent = 'Copied!'; setTimeout(function(){ copyBtn.textContent = 'Copy'; }, 1500); }; card.appendChild(copyBtn); container.appendChild(card); }, runAnalysis: function(editor, forceRefresh) { var self = this; var contentHtml = this.getSafeContent(editor); var title = (document.getElementById('title') || {}).value || ''; if (!title) { alert('Please enter a title.'); return; } this.showResults('highlights'); this.setLoading(true); fetch(PFEAI.rest_url + 'analyze?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ content: contentHtml, title: title, post_id: PFEAI.post_id, provider: this.getProvider(), force_refresh: forceRefresh || false }) }) .then(function(r){return r.json()}).then(function(json){ self.setLoading(false); if(json.highlights) { self.renderAnalysis(json); var timestamp = json.generated_at || Date.now()/1000; self.setCachedState('btn-scan', 'View Analysis Results', 'highlights', timestamp, json.from_cache); self.startCacheWindow(json.from_cache); } else if (json.code) { self.analysisEl.highlights.innerHTML = '

Error: ' + self.escapeHtml(json.message) + '

'; } }).catch(function(e) { self.setLoading(false); console.error(e); }); }, runTitles: function(editor, forceRefresh) { var self = this; var contentHtml = this.getSafeContent(editor); var title = (document.getElementById('title') || {}).value || ''; this.showResults('titles'); this.setLoading(true); fetch(PFEAI.rest_url + 'seo-titles?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ content: contentHtml, title: title, post_id: PFEAI.post_id, provider: this.getProvider(), force_refresh: forceRefresh || false }) }) .then(function(r){return r.json()}).then(function(json){ self.setLoading(false); if(json.titles) { self.renderTitles(json); var timestamp = json.generated_at || Date.now()/1000; self.setCachedState('btn-titles', 'View Titles', 'titles', timestamp, json.from_cache); self.startCacheWindow(json.from_cache); } else if (json.code) { self.titlesEl.innerHTML = '

Error: ' + self.escapeHtml(json.message) + '

'; } }); }, runTranscriptScan: function(editor, forceRefresh) { var self = this; var contentText = this.getSafeText(editor); if (contentText.length < 50) { alert('Please paste transcript.'); return; } this.showResults('transcript'); this.setLoading(true); fetch(PFEAI.rest_url + 'transcript-scan?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ content: contentText, post_id: PFEAI.post_id, provider: this.getProvider(), force_refresh: forceRefresh || false }) }) .then(function(r){return r.json()}) .then(function(json){ self.setLoading(false); var suggestions = null; if (json.suggestions && Array.isArray(json.suggestions)) { suggestions = json.suggestions; } else if (json.title && json.context) { suggestions = [json]; } if (suggestions && suggestions.length > 0) { self.renderTranscriptSuggestions(suggestions, contentText); var timestamp = json.generated_at || Date.now()/1000; self.setCachedState('btn-transcript', 'View Transcript Results', 'transcript', timestamp, json.from_cache); self.startCacheWindow(json.from_cache); } else if (json.code) { self.transcriptEl.innerHTML = '

Error: ' + self.escapeHtml(json.message) + '

'; } else { self.transcriptEl.innerHTML = '

Unexpected response format. Please click "Rescan" to refresh.

'; } }) .catch(function(err) { self.setLoading(false); self.transcriptEl.innerHTML = '

Request failed: ' + self.escapeHtml(err.message) + '

'; }); }, runTranscriptOutline: function(title, content, clickedCard) { var self = this; var resDiv = document.getElementById('pfeai-transcript-result'); resDiv.innerHTML = '

Generating outline...

This may take up to 30 seconds for longer transcripts.

'; if (!title) { resDiv.innerHTML = '

Error: No headline selected. Please click a headline above.

'; return; } if (!content || content.length < 50) { resDiv.innerHTML = '

Error: Transcript content is too short or missing.

'; return; } var controller = new AbortController(); var timeoutId = setTimeout(function() { controller.abort(); }, 180000); fetch(PFEAI.rest_url + 'transcript-outline?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ selected_title: title, content: content, provider: this.getProvider() }), signal: controller.signal }) .then(function(r) { clearTimeout(timeoutId); if (!r.ok) { throw new Error('Server returned status ' + r.status); } return r.json(); }) .then(function(json) { if (json.code) { resDiv.innerHTML = '

Error: ' + self.escapeHtml(json.message) + '

Try selecting a different headline or click Rescan.

'; return; } if (json.blurb) { self.renderTranscriptOutlineResult(json, title); } else { resDiv.innerHTML = '

AI response was incomplete. Please try again.

Response received but missing required content.

'; } }) .catch(function(err) { clearTimeout(timeoutId); var errorMsg = 'Error generating outline.'; if (err.name === 'AbortError') { errorMsg = 'Request timed out. The transcript may be too long.'; } else if (err.message) { errorMsg = err.message; } resDiv.innerHTML = '

' + self.escapeHtml(errorMsg) + '

Try again or select a different headline.

'; }); }, runArticleIdeas: function(editor, forceRefresh) { var self = this; var title = (document.getElementById('title') || {}).value || ''; var contentText = this.getSafeText(editor).trim(); if (!forceRefresh && (title.length > 0 || contentText.length > 5)) { alert('To generate fresh Topic Inspiration, please clear the Title and Content editor first.'); return; } this.showResults('ideas'); this.setLoading(true); var fetchIdeas = function() { fetch(PFEAI.rest_url + 'article-ideas?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ title: '', post_id: PFEAI.post_id, provider: self.getProvider(), force_refresh: forceRefresh || false }) }) .then(function(r){return r.json()}).then(function(json){ self.setLoading(false); if(json.ideas) { self.renderIdeasInteractive(json); self.setCachedState('btn-ideas', 'View Topics', 'ideas', Date.now()/1000); } else if (json.code) { self.ideasEl.innerHTML = '

Error: ' + self.escapeHtml(json.message) + '

'; } }).catch(function(e) { self.setLoading(false); console.error(e); }); }; if (forceRefresh) { fetch(PFEAI.rest_url + 'clear-ideas-cache?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ post_id: PFEAI.post_id }) }) .then(function() { fetchIdeas(); }) .catch(function() { fetchIdeas(); }); } else { fetchIdeas(); } }, runIdeaOutline: function(title, context) { var self = this; var resDiv = document.getElementById('pfeai-idea-result'); if(!resDiv) return; resDiv.innerHTML = '

Drafting outline...

This may take up to 30 seconds.

'; var controller = new AbortController(); var timeoutId = setTimeout(function() { controller.abort(); }, 180000); fetch(PFEAI.rest_url + 'idea-outline?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ idea_title: title, context: context, provider: this.getProvider() }), signal: controller.signal }) .then(function(r) { clearTimeout(timeoutId); if (!r.ok) { throw new Error('Server returned status ' + r.status); } return r.json(); }) .then(function(json) { if (json.code) { resDiv.innerHTML = '

Error: ' + self.escapeHtml(json.message) + '

'; return; } if(json.blurb) { self.renderIdeaOutlineResult(json, title); } else { resDiv.innerHTML = '

AI response was incomplete. Please try again.

'; } }) .catch(function(err) { clearTimeout(timeoutId); var errorMsg = 'Error generating outline.'; if (err.name === 'AbortError') { errorMsg = 'Request timed out. Please try again.'; } else if (err.message) { errorMsg = err.message; } resDiv.innerHTML = '

' + self.escapeHtml(errorMsg) + '

'; }); }, runTagline: function(editor) { var self = this; var c = this.getSafeContent(editor); var t = (document.getElementById('title') || {}).value || ''; if (!t) { alert('Enter title first'); return; } var btn = this.panelEl.querySelector('.pfeai-tagline-btn'); var originalText = btn ? btn.textContent : ''; if (btn) { btn.disabled = true; btn.innerHTML = ' Thinking...'; } fetch(PFEAI.rest_url + 'generate-tagline?_t=' + Date.now(), { method: 'POST', headers: {'Content-Type':'application/json','X-WP-Nonce':PFEAI.nonce}, body:JSON.stringify({content:c, title:t, provider: this.getProvider()}) }) .then(function(r){ return r.json(); }) .then(function(j){ if (btn) { btn.disabled = false; btn.textContent = originalText; } if(j.tagline) { document.getElementById('pftwt_tagline').value = j.tagline; self.startCacheWindow(false); } else if (j.code) { alert('Error: ' + j.message); } else { alert('No tagline was generated. Please try again.'); } }) .catch(function(e) { if (btn) { btn.disabled = false; btn.textContent = originalText; } alert('Error: ' + e.message); }); }, runTagSuggestions: function(editor) { var self = this; var c = this.getSafeContent(editor); var t = (document.getElementById('title') || {}).value || ''; if (!c || c.length < 50) { alert('Please add more content before generating tags.'); return; } var btn = this.panelEl.querySelector('.pfeai-tags-btn'); var originalText = btn ? btn.textContent : ''; if (btn) { btn.disabled = true; btn.innerHTML = ' Thinking...'; } fetch(PFEAI.rest_url + 'suggest-tags?_t=' + Date.now(), { method: 'POST', headers: {'Content-Type':'application/json','X-WP-Nonce':PFEAI.nonce}, body:JSON.stringify({content:c, title:t, provider: this.getProvider()}) }) .then(function(r){ return r.json(); }) .then(function(j){ if (btn) { btn.disabled = false; btn.textContent = originalText; } if (j.code) { alert('Error generating tags: ' + (j.message || j.code)); return; } if(j.tags && j.tags.length > 0 && jQuery) { var $ = jQuery; var tagsAdded = 0; var tagBox = $('#post_tag'); if (window.tagBox && typeof window.tagBox.flushTags === 'function') { var $input = $('#new-tag-post_tag'); j.tags.forEach(function(tag) { $input.val(tag); window.tagBox.flushTags(tagBox, false, 1); tagsAdded++; }); } else { var $input = $('#new-tag-post_tag'); var $addBtn = $('#post_tag .tagadd'); j.tags.forEach(function(tag, index) { setTimeout(function() { $input.val(tag); $addBtn.trigger('click'); var e = $.Event('keypress'); e.which = 13; $input.trigger(e); tagsAdded++; if (index === j.tags.length - 1) { setTimeout(function() { if (window.tagBox && typeof window.tagBox.get === 'function') { window.tagBox.get('post_tag'); } }, 100); } }, index * 50); }); } self.startCacheWindow(false); if (btn) { btn.textContent = 'Added ' + j.tags.length + ' tags!'; setTimeout(function() { btn.textContent = originalText; }, 2000); } } else { alert('No tags were generated. Please try again.'); } }) .catch(function(e) { if (btn) { btn.disabled = false; btn.textContent = originalText; } alert('Error: ' + e.message); }); }, runMetaDescFromMenu: function(editor) { var self = this; var title = (document.getElementById('title') || {}).value || ''; var content = this.getSafeContent(editor); if (!title && !content) { alert('Please add a title or content first.'); return; } var btn = this.panelEl.querySelector('.pfeai-meta-btn'); var originalText = btn ? btn.textContent : ''; if (btn) { btn.disabled = true; btn.innerHTML = ' Thinking...'; } fetch(PFEAI.rest_url + 'generate-meta-desc?_t=' + Date.now(), { method: 'POST', headers: {'Content-Type':'application/json','X-WP-Nonce':PFEAI.nonce}, body: JSON.stringify({content: content, title: title, provider: this.getProvider()}) }) .then(function(r){return r.json()}) .then(function(j){ if (btn) { btn.disabled = false; btn.textContent = originalText; } if(j.meta_description) { self.showResults('seo'); var textarea = document.getElementById('pfeai-meta-description'); if (textarea) { textarea.value = j.meta_description; self.updateSerpPreview(); } self.startCacheWindow(false); if (btn) { btn.textContent = 'Generated!'; setTimeout(function() { btn.textContent = originalText; }, 2000); } } else if (j.code) { alert('Error: ' + j.message); } else { alert('No meta description was generated. Please try again.'); } }) .catch(function(e) { if (btn) { btn.disabled = false; btn.textContent = originalText; } alert('Error: ' + e.message); }); }, runMetaDescription: function() { var self = this; var title = (document.getElementById('title') || {}).value || ''; var content = this.getSafeContent(tinymce.activeEditor); if (!title && !content) { alert('Please add a title or content first.'); return; } var btn = document.getElementById('pfeai-generate-meta-btn'); if (btn) { btn.textContent = 'Generating...'; btn.disabled = true; } fetch(PFEAI.rest_url + 'generate-meta-desc?_t=' + Date.now(), { method: 'POST', headers: {'Content-Type':'application/json','X-WP-Nonce':PFEAI.nonce}, body: JSON.stringify({content: content, title: title, provider: this.getProvider()}) }) .then(function(r){return r.json()}) .then(function(j){ if (btn) { btn.innerHTML = '✨ Generate New Meta Description'; btn.disabled = false; } if(j.meta_description) { var textarea = document.getElementById('pfeai-meta-description'); if (textarea) { textarea.value = j.meta_description; self.updateSerpPreview(); } self.startCacheWindow(false); } else if (j.code) { alert('Error: ' + j.message); } }) .catch(function(e) { if (btn) { btn.innerHTML = '✨ Generate New Meta Description'; btn.disabled = false; } }); }, runFAQ: function(editor) { var self = this; var c = this.getSafeContent(editor); var t = (document.getElementById('title') || {}).value || ''; if (!c || c.length < 100) { alert('Please write or paste the article content first so the AI can generate accurate FAQs.'); return; } this.showResults('faq'); this.setLoading(true); fetch(PFEAI.rest_url + 'generate-faq?_t=' + Date.now(), { method: 'POST', headers: {'Content-Type':'application/json','X-WP-Nonce':PFEAI.nonce}, body: JSON.stringify({content: c, title: t, provider: this.getProvider()}) }) .then(function(r){ return r.json(); }) .then(function(j){ self.setLoading(false); if(j.faq && j.faq.length > 0) { self.renderFAQ(j.faq, editor); self.startCacheWindow(false); } else if (j.code) { self.faqEl.innerHTML = '

Error: ' + self.escapeHtml(j.message) + '

'; } else { self.faqEl.innerHTML = '

Failed to generate FAQ. Please try again.

'; } }) .catch(function(e) { self.setLoading(false); self.faqEl.innerHTML = '

Error: ' + self.escapeHtml(e.message) + '

'; }); }, renderFAQ: function(faqData, editor) { var self = this; if (!this.faqEl) return; this.faqEl.innerHTML = ''; var header = document.createElement('h4'); header.style.margin = '0 0 10px 0'; header.textContent = 'Review & Edit FAQ'; this.faqEl.appendChild(header); var instruction = document.createElement('p'); instruction.style.fontSize = '11px'; instruction.style.color = '#666'; instruction.textContent = 'Review your FAQs below. Clicking the button will send them down to the "Article FAQ & Schema" box at the bottom of your post screen. Remember to click the WordPress Update/Publish button to save them!'; this.faqEl.appendChild(instruction); var faqContainer = document.createElement('div'); faqContainer.id = 'pfeai-faq-inputs-container'; faqData.forEach(function(item, index) { var box = document.createElement('div'); box.style.background = '#fff'; box.style.padding = '10px'; box.style.marginBottom = '10px'; box.style.border = '1px solid #ddd'; box.style.borderRadius = '4px'; var qLabel = document.createElement('strong'); qLabel.style.fontSize = '11px'; qLabel.textContent = 'Question ' + (index + 1); box.appendChild(qLabel); var qInput = document.createElement('input'); qInput.type = 'text'; qInput.className = 'pfeai-faq-q'; qInput.style.width = '100%'; qInput.style.marginBottom = '8px'; qInput.value = item.question || ''; box.appendChild(qInput); var aLabel = document.createElement('strong'); aLabel.style.fontSize = '11px'; aLabel.textContent = 'Answer ' + (index + 1); box.appendChild(aLabel); var aInput = document.createElement('textarea'); aInput.className = 'pfeai-faq-a'; aInput.style.width = '100%'; aInput.style.height = '50px'; aInput.style.fontSize = '12px'; aInput.value = item.answer || ''; box.appendChild(aInput); faqContainer.appendChild(box); }); this.faqEl.appendChild(faqContainer); var insertBtn = document.createElement('button'); insertBtn.type = 'button'; insertBtn.className = 'button button-primary'; insertBtn.style.width = '100%'; insertBtn.innerHTML = '↓ Send to FAQ Meta Box'; insertBtn.onclick = function() { var qInputs = faqContainer.querySelectorAll('.pfeai-faq-q'); var aInputs = faqContainer.querySelectorAll('.pfeai-faq-a'); var transferCount = 0; for (var i = 0; i < qInputs.length; i++) { var qText = qInputs[i].value.trim(); var aText = aInputs[i].value.trim(); var metaQ = document.getElementById('pfeai_meta_q_' + i); var metaA = document.getElementById('pfeai_meta_a_' + i); if (metaQ && metaA) { metaQ.value = qText; metaA.value = aText; if (qText && aText) transferCount++; } } if (transferCount === 0) { alert('Could not locate the FAQ Meta Box on the screen. Please ensure "Article FAQ & Schema" is checked in your Screen Options at the top right.'); return; } insertBtn.innerHTML = '✓ Sent to Meta Box!'; setTimeout(function() { insertBtn.innerHTML = '↓ Send to FAQ Meta Box'; }, 2000); }; this.faqEl.appendChild(insertBtn); }, updateSerpPreview: function(selectedTitle) { var titleEl = document.getElementById('pfeai-serp-title'); var descEl = document.getElementById('pfeai-serp-desc'); var charCount = document.getElementById('pfeai-meta-char-count'); var titleCharNote = document.getElementById('pfeai-title-char-note'); var metaTextarea = document.getElementById('pfeai-meta-description'); if (selectedTitle && titleEl) { titleEl.textContent = selectedTitle; if (selectedTitle.length > 60) { titleEl.textContent = selectedTitle.substring(0, 57) + '...'; } } if (titleCharNote && titleEl) { var currentTitle = selectedTitle || titleEl.textContent; if (currentTitle === '(Select a title above)') currentTitle = ''; var titleLen = currentTitle.length; var titleColor = titleLen <= 60 ? '#2e7d32' : '#c62828'; titleCharNote.innerHTML = 'Title: ' + titleLen + '/60 chars ' + (titleLen <= 60 ? '✓' : '(may be truncated)'); } if (metaTextarea && descEl) { var desc = metaTextarea.value; if (desc) { descEl.textContent = desc.length > 155 ? desc.substring(0, 152) + '...' : desc; } else { descEl.textContent = '(Enter a meta description above)'; } } if (metaTextarea && charCount) { var len = metaTextarea.value.length; var color = '#666'; var status = ''; if (len === 0) { color = '#666'; } else if (len < 120) { color = '#e65100'; status = ' (too short)'; } else if (len >= 120 && len <= 155) { color = '#2e7d32'; status = ' ✓ optimal'; } else if (len > 155 && len <= 160) { color = '#e65100'; status = ' (slightly long)'; } else { color = '#c62828'; status = ' (will be truncated)'; } charCount.innerHTML = '' + len + ' / 155 characters' + status + ''; } }, saveToClipboard: function(title, html, redirectToNew) { fetch(PFEAI.rest_url + 'save-clipboard?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ title: title, content: html }) }) .then(function(){ if (redirectToNew) { window.open('/patriots/blog/wp-admin/post-new.php', '_blank'); } else { alert('Saved! You can now access this draft in the "Saved" tab on any new post.'); location.reload(); } }); }, clearClipboard: function() { fetch(PFEAI.rest_url + 'clear-clipboard?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce } }) .then(function(r) { return r.json(); }) .then(function(json) { if (json.success) { alert('Saved draft cleared.'); location.reload(); } }) .catch(function(e) { console.error(e); }); }, clearIdeasCache: function() { fetch(PFEAI.rest_url + 'clear-ideas-cache?_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': PFEAI.nonce }, body: JSON.stringify({ post_id: PFEAI.post_id }) }) .then(function(r) { return r.json(); }) .then(function(json) { if (json.success) { alert('Topics cache cleared.'); location.reload(); } }) .catch(function(e) { console.error(e); }); }, togglePanel: function(forceState) { if (!this.panelEl) return; var open = this.panelEl.classList.contains('pfeai-open'); var shouldOpen = (typeof forceState === 'boolean') ? forceState : !open; if (shouldOpen) { this.panelEl.classList.add('pfeai-open'); document.body.classList.add('pfeai-panel-open'); this.updateTranscriptVisibility(); if (this.isMinimized) document.body.classList.add('pfeai-panel-minimized'); else document.body.classList.remove('pfeai-panel-minimized'); } else { this.panelEl.classList.remove('pfeai-open'); document.body.classList.remove('pfeai-panel-open'); } }, showMenu: function() { this.panelEl.classList.remove('pfeai-show-results'); }, showResults: function(activeTab) { this.panelEl.classList.add('pfeai-show-results'); if (activeTab) this.switchTab(activeTab); }, updateTranscriptVisibility: function() { var isTranscript = false; var labels = document.querySelectorAll('.categorychecklist label'); for (var i = 0; i < labels.length; i++) { if (labels[i].innerText.indexOf('Patriots Transcripts') !== -1) { var input = labels[i].querySelector('input[type="checkbox"]'); if (input && input.checked) isTranscript = true; } } var btn = document.getElementById('btn-transcript'); var tab = document.getElementById('tab-transcript'); if (isTranscript) { if (btn) btn.style.display = 'block'; if (tab) tab.style.display = 'inline-block'; } else { if (btn) btn.style.display = 'none'; if (tab) tab.style.display = 'none'; } }, preloadSavedData: function() { if (!PFEAI.saved_data) return; if (PFEAI.saved_data.transcript && PFEAI.saved_data.transcript.suggestions) { this.renderTranscriptSuggestions(PFEAI.saved_data.transcript.suggestions, ''); this.setCachedState('btn-transcript', 'View Transcript Results', 'transcript', PFEAI.saved_data.transcript.generated_at); } if (PFEAI.saved_data.analysis && PFEAI.saved_data.analysis.highlights) { this.renderAnalysis(PFEAI.saved_data.analysis); this.setCachedState('btn-scan', 'View Analysis Results', 'highlights', PFEAI.saved_data.analysis.generated_at); } if (PFEAI.saved_data.titles && PFEAI.saved_data.titles.titles) { this.renderTitles(PFEAI.saved_data.titles); this.setCachedState('btn-titles', 'View Titles', 'titles', PFEAI.saved_data.titles.generated_at); } if (PFEAI.saved_data.ideas && PFEAI.saved_data.ideas.ideas) { this.renderIdeasInteractive(PFEAI.saved_data.ideas); this.setCachedState('btn-ideas', 'View Topics', 'ideas', PFEAI.saved_data.ideas.generated_at); } if (PFEAI.saved_data.social && PFEAI.saved_data.social.tweets) { this.renderSocialPack(PFEAI.saved_data.social); this.setCachedState('btn-social', 'View Social Posts', 'social', PFEAI.saved_data.social.generated_at); } if (PFEAI.saved_data.clipboard && this.savedEl) { this.renderSavedDraft(PFEAI.saved_data.clipboard); } if (PFEAI.saved_data.fact_check && PFEAI.saved_data.fact_check.factChecks) { this.renderFacts(PFEAI.saved_data.fact_check.factChecks); this.setCachedState('btn-fact-check', 'View Fact Check', 'facts', PFEAI.saved_data.fact_check.generated_at); } if (PFEAI.saved_data.links && PFEAI.saved_data.links.links) { this.renderInternalLinks(PFEAI.saved_data.links, null); this.setCachedState('btn-internal-links', '\uD83D\uDD17 View Links', 'links', PFEAI.saved_data.links.generated_at); } // Always render the SEO tab this.renderSeoTab(); // Render the Search Insights data this.renderGSCPanel(); }, setCachedState: function(btnId, newText, tabName, timestamp) { var btn = document.getElementById(btnId); if (btn) { if (btnId === 'btn-transcript' || btnId === 'btn-ideas' || btnId === 'btn-social') { btn.innerHTML = '' + this.escapeHtml(newText) + '
(Click to see saved)'; } else { btn.textContent = newText; } } var container = this.panelEl.querySelector('.pfeai-tab-content[data-tab="' + tabName + '"]'); if (container) { var existingHeader = container.querySelector('.pfeai-cache-header'); if (existingHeader) existingHeader.remove(); var dateStr = timestamp ? new Date(timestamp * 1000).toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'}) : ''; var header = document.createElement('div'); header.className = 'pfeai-cache-header'; header.style.background = '#e1f5fe'; header.style.padding = '8px'; header.style.marginBottom = '10px'; header.style.display = 'flex'; header.style.justifyContent = 'space-between'; header.style.alignItems = 'center'; header.style.borderRadius = '4px'; var savedSpan = document.createElement('span'); savedSpan.style.fontSize = '11px'; savedSpan.style.color = '#0277bd'; savedSpan.textContent = 'Saved ' + dateStr; header.appendChild(savedSpan); var rescanBtn = document.createElement('button'); rescanBtn.className = 'button button-small'; rescanBtn.textContent = 'Rescan / Start Over'; (function(name) { rescanBtn.onclick = function() { if (name === 'highlights') window.PFEditorialAI.runAnalysis(tinymce.activeEditor, true); if (name === 'transcript') window.PFEditorialAI.runTranscriptScan(tinymce.activeEditor, true); if (name === 'titles') window.PFEditorialAI.runTitles(tinymce.activeEditor, true); if (name === 'ideas') window.PFEditorialAI.runArticleIdeas(tinymce.activeEditor, true); if (name === 'social') window.PFEditorialAI.runSocialPack(tinymce.activeEditor, true); if (name === 'facts') window.PFEditorialAI.runFactCheck(tinymce.activeEditor, true); if (name === 'links') window.PFEditorialAI.runInternalLinks(tinymce.activeEditor, true); }; })(tabName); header.appendChild(rescanBtn); container.insertBefore(header, container.firstChild); } }, renderAnalysis: function(data) { var self = this; var hEl = this.analysisEl.highlights; hEl.innerHTML = ''; (data.highlights || []).forEach(function(h) { var c = document.createElement('div'); c.className = 'pfeai-card'; var typeEl = document.createElement('strong'); typeEl.textContent = (h.type || '').toUpperCase(); c.appendChild(typeEl); var msgEl = document.createElement('p'); msgEl.textContent = h.message || ''; c.appendChild(msgEl); var quoteEl = document.createElement('div'); quoteEl.className = 'pfeai-card-quote'; quoteEl.textContent = '"' + (h.quote || '') + '"'; c.appendChild(quoteEl); var suggEl = document.createElement('div'); suggEl.className = 'pfeai-card-suggestion'; suggEl.textContent = h.suggestion || ''; c.appendChild(suggEl); hEl.appendChild(c); }); var sEl = this.analysisEl.suggestions; sEl.innerHTML = ''; var ulS = document.createElement('ul'); ulS.className = 'pfeai-list'; (data.summarySuggestions || []).forEach(function(s){ var li = document.createElement('li'); li.textContent = s; ulS.appendChild(li); }); sEl.appendChild(ulS); var gEl = this.analysisEl.gaps; gEl.innerHTML = ''; var ulG = document.createElement('ul'); ulG.className = 'pfeai-list'; (data.contentGaps || []).forEach(function(g){ var li = document.createElement('li'); li.textContent = g; ulG.appendChild(li); }); gEl.appendChild(ulG); var fEl = self.factsEl; if (fEl) { fEl.innerHTML = ''; var checks = data.factChecks || []; var factsHeading = document.createElement('h4'); factsHeading.style.margin = '0 0 4px 0'; factsHeading.style.color = '#1A2635'; factsHeading.textContent = 'Stats & Data Verification'; fEl.appendChild(factsHeading); var factsNote = document.createElement('p'); factsNote.style.fontSize = '11px'; factsNote.style.color = '#666'; factsNote.style.margin = '0 0 12px 0'; factsNote.textContent = 'AI-reviewed claims found in the article. Always cross-check flagged items before publishing.'; fEl.appendChild(factsNote); if (checks.length === 0) { var noFacts = document.createElement('p'); noFacts.style.color = '#666'; noFacts.style.fontSize = '13px'; noFacts.textContent = 'No specific stats or data claims detected in this article.'; fEl.appendChild(noFacts); } else { var counts = { 'Likely Accurate': 0, 'Needs Verification': 0, 'Potentially Incorrect': 0, 'May Be Outdated': 0 }; checks.forEach(function(fc) { if (counts[fc.verdict] !== undefined) counts[fc.verdict]++; }); var badgeRow = document.createElement('div'); badgeRow.style.cssText = 'display:flex; flex-wrap:wrap; gap:6px; margin-bottom:12px;'; var badgeDefs = [ { key: 'Likely Accurate', bg: '#e8f5e9', color: '#2e7d32', icon: '✓' }, { key: 'Needs Verification', bg: '#fff8e1', color: '#f57c00', icon: '⚠' }, { key: 'May Be Outdated', bg: '#e3f2fd', color: '#1565c0', icon: '📅' }, { key: 'Potentially Incorrect', bg: '#ffebee', color: '#c62828', icon: '✗' } ]; badgeDefs.forEach(function(bd) { if (!counts[bd.key]) return; var badge = document.createElement('span'); badge.style.cssText = 'background:' + bd.bg + '; color:' + bd.color + '; border:1px solid ' + bd.color + '; border-radius:12px; padding:2px 8px; font-size:11px; font-weight:700;'; badge.textContent = bd.icon + ' ' + counts[bd.key] + ' ' + bd.key; badgeRow.appendChild(badge); }); fEl.appendChild(badgeRow); var styleMap = { 'Likely Accurate': { border: '#4caf50', bg: '#f9fbe7', tagBg: '#e8f5e9', tagColor: '#2e7d32', icon: '✓' }, 'Needs Verification': { border: '#ff9800', bg: '#fffde7', tagBg: '#fff3e0', tagColor: '#e65100', icon: '⚠' }, 'May Be Outdated': { border: '#2196f3', bg: '#e8f4fd', tagBg: '#e3f2fd', tagColor: '#1565c0', icon: '📅' }, 'Potentially Incorrect': { border: '#f44336', bg: '#fff5f5', tagBg: '#ffebee', tagColor: '#c62828', icon: '✗' } }; checks.forEach(function(fc) { var verdict = fc.verdict || 'Needs Verification'; var s = styleMap[verdict] || styleMap['Needs Verification']; var card = document.createElement('div'); card.className = 'pfeai-fact-card'; card.style.cssText = 'background:' + s.bg + '; border-left:4px solid ' + s.border + '; border-radius:3px; padding:8px 10px; margin-bottom:8px;'; var tag = document.createElement('span'); tag.style.cssText = 'display:inline-block; background:' + s.tagBg + '; color:' + s.tagColor + '; border:1px solid ' + s.border + '; border-radius:10px; padding:1px 7px; font-size:10px; font-weight:700; margin-bottom:5px;'; tag.textContent = s.icon + ' ' + verdict; card.appendChild(tag{"id":56301,"date":"2024-11-04T08:17:16","date_gmt":"2024-11-04T13:17:16","guid":{"rendered":"https:\/\/www.patsfans.com\/patriots\/blog\/?p=56301"},"modified":"2024-11-04T08:17:16","modified_gmt":"2024-11-04T13:17:16","slug":"morse-18-observations-from-a-frustrating-patriots-loss-to-tennessee","status":"publish","type":"post","link":"https:\/\/www.patsfans.com\/patriots\/blog\/2024\/11\/04\/morse-18-observations-from-a-frustrating-patriots-loss-to-tennessee\/","title":{"rendered":"MORSE: 18 Observations from a Frustrating Patriots Loss to Tennessee"},"content":{"rendered":"

This team is so damn frustrating.\u00a0 The Opening drive by the Titans set me off right away.\u00a0 The Patriots had them at 3rd<\/sup> and 12 and Dietrich Wise blows up the field and lost his containment lane, allowing Mason Rudolph to scramble for a key 1st<\/sup> down.<\/p>\n

This play infuriated me.\u00a0 Wise has made the same mistake over and over again losing containment.\u00a0 Selfish looking for the sack to pad his stats.\u00a0 They made Rudolph look like an All-Pro going 20\/33 for 240 yards 2 TDs and a bad INT.<\/p>\n

 <\/p>\n