ContextCheck - News Context Analyzer

Understand news context by viewing multiple perspectives and source comparisons

Size

16.1 KB

Version

1.1.1

Created

Jan 5, 2026

Updated

29 days ago

1// ==UserScript==
2// @name		ContextCheck - News Context Analyzer
3// @description		Understand news context by viewing multiple perspectives and source comparisons
4// @version		1.1.1
5// @match		https://*.cnn.com/*
6// @match		https://*.bbc.com/*
7// @match		https://*.nytimes.com/*
8// @match		https://*.theguardian.com/*
9// @match		https://*.washingtonpost.com/*
10// @match		https://*.reuters.com/*
11// @match		https://*.apnews.com/*
12// @match		https://*.nbcnews.com/*
13// @match		https://*.foxnews.com/*
14// @match		https://*.aljazeera.com/*
15// @match		https://*.bloomberg.com/*
16// @match		https://*.wsj.com/*
17// @match		https://*.usatoday.com/*
18// @match		https://*.cbsnews.com/*
19// @match		https://*.abcnews.go.com/*
20// @icon		https://robomonkey.io/favicon.ico
21// ==/UserScript==
22(function() {
23    'use strict';
24    
25    console.log('ContextCheck: Extension loaded');
26    
27    // Mock data generator for realistic demo results
28    function generateMockResults(headline, url) {
29        const mockScenarios = [
30            {
31                sourcesFound: 12,
32                agreements: [
33                    "Event occurred on the reported date and location",
34                    "Key figures and organizations involved are confirmed across sources",
35                    "Timeline of major events is consistent"
36                ],
37                differences: [
38                    "Estimated numbers vary between 5,000-8,000 depending on source",
39                    "Some outlets emphasize economic impact, others focus on social aspects",
40                    "Attribution of responsibility differs between regional and international sources"
41                ],
42                confidence: "High"
43            },
44            {
45                sourcesFound: 8,
46                agreements: [
47                    "Core facts about the announcement are verified",
48                    "Official statements match across multiple outlets"
49                ],
50                differences: [
51                    "Interpretation of long-term implications varies significantly",
52                    "Expert opinions quoted differ based on political leaning",
53                    "Regional sources provide additional context not found in international coverage"
54                ],
55                confidence: "Medium"
56            },
57            {
58                sourcesFound: 5,
59                agreements: [
60                    "Basic details of the incident are consistent",
61                    "Primary source quotes match across reports"
62                ],
63                differences: [
64                    "Limited independent verification available",
65                    "Conflicting reports about specific details and timing",
66                    "Some sources cite anonymous officials while others use named sources"
67                ],
68                confidence: "Low"
69            }
70        ];
71        
72        // Randomly select a scenario for demo purposes
73        const scenario = mockScenarios[Math.floor(Math.random() * mockScenarios.length)];
74        return scenario;
75    }
76    
77    // Add styles
78    function addStyles() {
79        const styles = `
80            #contextcheck-button {
81                position: fixed;
82                bottom: 30px;
83                right: 30px;
84                z-index: 999999;
85                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
86                color: white;
87                border: none;
88                border-radius: 50px;
89                padding: 16px 28px;
90                font-size: 15px;
91                font-weight: 600;
92                cursor: pointer;
93                box-shadow: 0 8px 24px rgba(102, 126, 234, 0.4);
94                transition: all 0.3s ease;
95                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
96                display: flex;
97                align-items: center;
98                gap: 8px;
99            }
100            
101            #contextcheck-button:hover {
102                transform: translateY(-2px);
103                box-shadow: 0 12px 32px rgba(102, 126, 234, 0.5);
104            }
105            
106            #contextcheck-button:active {
107                transform: translateY(0);
108            }
109            
110            #contextcheck-button::before {
111                content: "🔍";
112                font-size: 18px;
113            }
114            
115            #contextcheck-popup {
116                position: fixed;
117                top: 50%;
118                left: 50%;
119                transform: translate(-50%, -50%);
120                z-index: 1000000;
121                background: white;
122                border-radius: 16px;
123                box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
124                width: 90%;
125                max-width: 600px;
126                max-height: 80vh;
127                overflow-y: auto;
128                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
129                animation: slideIn 0.3s ease;
130            }
131            
132            @keyframes slideIn {
133                from {
134                    opacity: 0;
135                    transform: translate(-50%, -45%);
136                }
137                to {
138                    opacity: 1;
139                    transform: translate(-50%, -50%);
140                }
141            }
142            
143            #contextcheck-overlay {
144                position: fixed;
145                top: 0;
146                left: 0;
147                right: 0;
148                bottom: 0;
149                background: rgba(0, 0, 0, 0.5);
150                z-index: 999999;
151                animation: fadeIn 0.3s ease;
152            }
153            
154            @keyframes fadeIn {
155                from { opacity: 0; }
156                to { opacity: 1; }
157            }
158            
159            .contextcheck-header {
160                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
161                color: white;
162                padding: 24px;
163                border-radius: 16px 16px 0 0;
164                display: flex;
165                justify-content: space-between;
166                align-items: center;
167            }
168            
169            .contextcheck-header h2 {
170                margin: 0;
171                font-size: 22px;
172                font-weight: 700;
173            }
174            
175            .contextcheck-close {
176                background: rgba(255, 255, 255, 0.2);
177                border: none;
178                color: white;
179                font-size: 24px;
180                width: 36px;
181                height: 36px;
182                border-radius: 50%;
183                cursor: pointer;
184                display: flex;
185                align-items: center;
186                justify-content: center;
187                transition: background 0.2s;
188            }
189            
190            .contextcheck-close:hover {
191                background: rgba(255, 255, 255, 0.3);
192            }
193            
194            .contextcheck-content {
195                padding: 32px;
196            }
197            
198            .contextcheck-loading {
199                text-align: center;
200                padding: 40px 20px;
201            }
202            
203            .contextcheck-spinner {
204                width: 50px;
205                height: 50px;
206                border: 4px solid #f3f3f3;
207                border-top: 4px solid #667eea;
208                border-radius: 50%;
209                animation: spin 1s linear infinite;
210                margin: 0 auto 20px;
211            }
212            
213            @keyframes spin {
214                0% { transform: rotate(0deg); }
215                100% { transform: rotate(360deg); }
216            }
217            
218            .contextcheck-loading-text {
219                font-size: 18px;
220                color: #333;
221                font-weight: 500;
222            }
223            
224            .contextcheck-results {
225                animation: fadeIn 0.5s ease;
226            }
227            
228            .contextcheck-stat {
229                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
230                color: white;
231                padding: 16px;
232                border-radius: 12px;
233                text-align: center;
234                margin-bottom: 24px;
235                font-size: 18px;
236                font-weight: 600;
237            }
238            
239            .contextcheck-section {
240                margin-bottom: 28px;
241            }
242            
243            .contextcheck-section h3 {
244                font-size: 16px;
245                font-weight: 700;
246                color: #333;
247                margin: 0 0 12px 0;
248                display: flex;
249                align-items: center;
250                gap: 8px;
251            }
252            
253            .contextcheck-section h3::before {
254                font-size: 20px;
255            }
256            
257            .contextcheck-section.agreements h3::before {
258                content: "✓";
259                color: #10b981;
260            }
261            
262            .contextcheck-section.differences h3::before {
263                content: "⚡";
264                color: #f59e0b;
265            }
266            
267            .contextcheck-section ul {
268                margin: 0;
269                padding-left: 20px;
270                list-style: none;
271            }
272            
273            .contextcheck-section li {
274                margin-bottom: 10px;
275                padding-left: 24px;
276                position: relative;
277                color: #555;
278                line-height: 1.6;
279                font-size: 14px;
280            }
281            
282            .contextcheck-section.agreements li::before {
283                content: "•";
284                position: absolute;
285                left: 0;
286                color: #10b981;
287                font-weight: bold;
288                font-size: 20px;
289            }
290            
291            .contextcheck-section.differences li::before {
292                content: "•";
293                position: absolute;
294                left: 0;
295                color: #f59e0b;
296                font-weight: bold;
297                font-size: 20px;
298            }
299            
300            .contextcheck-confidence {
301                background: #f9fafb;
302                border-radius: 12px;
303                padding: 16px;
304                display: flex;
305                justify-content: space-between;
306                align-items: center;
307                margin-bottom: 20px;
308            }
309            
310            .contextcheck-confidence-label {
311                font-weight: 600;
312                color: #333;
313                font-size: 15px;
314            }
315            
316            .contextcheck-confidence-value {
317                padding: 6px 16px;
318                border-radius: 20px;
319                font-weight: 700;
320                font-size: 14px;
321            }
322            
323            .contextcheck-confidence-value.high {
324                background: #d1fae5;
325                color: #065f46;
326            }
327            
328            .contextcheck-confidence-value.medium {
329                background: #fef3c7;
330                color: #92400e;
331            }
332            
333            .contextcheck-confidence-value.low {
334                background: #fee2e2;
335                color: #991b1b;
336            }
337            
338            .contextcheck-disclaimer {
339                background: #fef3c7;
340                border-left: 4px solid #f59e0b;
341                padding: 14px;
342                border-radius: 8px;
343                font-size: 13px;
344                color: #78350f;
345                line-height: 1.5;
346            }
347            
348            .contextcheck-disclaimer::before {
349                content: "ℹ️ ";
350                margin-right: 6px;
351            }
352        `;
353        
354        const styleElement = document.createElement('style');
355        styleElement.textContent = styles;
356        document.head.appendChild(styleElement);
357        console.log('ContextCheck: Styles added');
358    }
359    
360    // Create floating button
361    function createButton() {
362        const button = document.createElement('button');
363        button.id = 'contextcheck-button';
364        button.textContent = 'Check Context';
365        button.addEventListener('click', openPopup);
366        document.body.appendChild(button);
367        console.log('ContextCheck: Button created');
368    }
369    
370    // Create popup
371    function createPopup() {
372        // Create overlay
373        const overlay = document.createElement('div');
374        overlay.id = 'contextcheck-overlay';
375        overlay.addEventListener('click', closePopup);
376        
377        // Create popup
378        const popup = document.createElement('div');
379        popup.id = 'contextcheck-popup';
380        
381        popup.innerHTML = `
382            <div class="contextcheck-header">
383                <h2>🔍 ContextCheck</h2>
384                <button class="contextcheck-close" onclick="document.getElementById('contextcheck-overlay').click()">×</button>
385            </div>
386            <div class="contextcheck-content">
387                <div class="contextcheck-loading">
388                    <div class="contextcheck-spinner"></div>
389                    <div class="contextcheck-loading-text">Analyzing sources…</div>
390                </div>
391            </div>
392        `;
393        
394        document.body.appendChild(overlay);
395        document.body.appendChild(popup);
396        console.log('ContextCheck: Popup created');
397        
398        // Simulate loading and show results
399        setTimeout(() => {
400            showResults();
401        }, 2000);
402    }
403    
404    // Show results
405    function showResults() {
406        const headline = document.title;
407        const url = window.location.href;
408        const results = generateMockResults(headline, url);
409        
410        const content = document.querySelector('.contextcheck-content');
411        
412        const agreementsList = results.agreements.map(item => `<li>${item}</li>`).join('');
413        const differencesList = results.differences.map(item => `<li>${item}</li>`).join('');
414        const confidenceClass = results.confidence.toLowerCase();
415        
416        content.innerHTML = `
417            <div class="contextcheck-results">
418                <div class="contextcheck-stat">
419                    📰 Sources found: ${results.sourcesFound}
420                </div>
421                
422                <div class="contextcheck-section agreements">
423                    <h3>What most sources agree on</h3>
424                    <ul>
425                        ${agreementsList}
426                    </ul>
427                </div>
428                
429                <div class="contextcheck-section differences">
430                    <h3>Where reports differ</h3>
431                    <ul>
432                        ${differencesList}
433                    </ul>
434                </div>
435                
436                <div class="contextcheck-confidence">
437                    <span class="contextcheck-confidence-label">Confidence Level:</span>
438                    <span class="contextcheck-confidence-value ${confidenceClass}">${results.confidence}</span>
439                </div>
440                
441                <div class="contextcheck-disclaimer">
442                    This provides context, not factual verification.
443                </div>
444            </div>
445        `;
446        
447        console.log('ContextCheck: Results displayed', results);
448    }
449    
450    // Open popup
451    function openPopup() {
452        console.log('ContextCheck: Opening popup');
453        createPopup();
454    }
455    
456    // Close popup
457    function closePopup() {
458        console.log('ContextCheck: Closing popup');
459        const overlay = document.getElementById('contextcheck-overlay');
460        const popup = document.getElementById('contextcheck-popup');
461        if (overlay) overlay.remove();
462        if (popup) popup.remove();
463    }
464    
465    // Initialize
466    function init() {
467        console.log('ContextCheck: Initializing...');
468        addStyles();
469        
470        // Wait for body to be ready
471        if (document.body) {
472            createButton();
473        } else {
474            const observer = new MutationObserver(() => {
475                if (document.body) {
476                    createButton();
477                    observer.disconnect();
478                }
479            });
480            observer.observe(document.documentElement, { childList: true });
481        }
482    }
483    
484    // Start when DOM is ready
485    if (document.readyState === 'loading') {
486        document.addEventListener('DOMContentLoaded', init);
487    } else {
488        init();
489    }
490    
491})();