Project Viewer + Profile Viewer + Alternative Articles + Enhanced Article Experience
// ==UserScript==
// @name The Information
// @namespace http://tampermonkey.net/
// @version 2.0
// @description Project Viewer + Profile Viewer + Alternative Articles + Enhanced Article Experience
// @author UniverseDev
// @icon https://www.google.com/s2/favicons?domain=theinformation.com&sz=64
// @license MIT
// @match https://www.theinformation.com/*
// @grant GM.xmlHttpRequest
// ==/UserScript==
(function() {
'use strict';
const modalCSS = `
#premiumModalOverlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.65);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
animation: fadeIn 0.4s ease-out forwards;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
#premiumModalContent {
background: linear-gradient(135deg, #ffffff 0%, #f7f7f7 100%);
border-radius: 12px;
padding: 25px 35px;
max-width: 500px;
width: 90%;
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.25);
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
position: relative;
animation: slideIn 0.5s ease-out forwards;
}
@keyframes slideIn {
from { transform: translateY(-20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
#premiumModalClose {
position: absolute;
top: 12px;
right: 15px;
background: none;
border: none;
font-size: 28px;
line-height: 1;
color: #aaa;
cursor: pointer;
transition: color 0.3s ease;
}
#premiumModalClose:hover {
color: #e74c3c;
}
#premiumModalHeader {
font-size: 24px;
margin-bottom: 12px;
font-weight: 600;
color: #2c3e50;
text-align: center;
border-bottom: 1px solid #ddd;
padding-bottom: 8px;
}
#premiumModalContent p {
margin: 12px 0;
line-height: 1.6;
color: #34495e;
font-size: 15px;
}
#premiumModalContent a {
color: #2980b9;
text-decoration: none;
font-weight: 500;
}
#premiumModalContent a:hover {
text-decoration: underline;
}
`;
const styleElem = document.createElement('style');
styleElem.type = 'text/css';
styleElem.textContent = modalCSS;
document.head.appendChild(styleElem);
const enhancedStyle = document.createElement('style');
enhancedStyle.textContent = `
.article-display {
margin: 20px 20px 40px 20px;
padding: 20px;
background: #ffffff;
font-family: Arial, sans-serif;
}
.article-picture {
max-width: 100%;
height: auto;
margin-bottom: 10px;
}
.authors {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin-top: 10px;
}
.author {
max-width: 300px;
border: 1px solid #ccc;
padding: 15px;
border-radius: 5px;
}
.author img {
width: 80px;
height: 80px;
border-radius: 50%;
margin-bottom: 10px;
}
.related-article {
display: flex;
flex-direction: column;
margin-bottom: 20px;
padding: 16px;
border-top: 1px solid #ccc;
}
.related-article img {
width: 100%;
max-width: 300px;
height: auto;
margin-bottom: 16px;
}
.related-article .text {
flex: 1;
}
.related-article .highlight {
font-weight: bold;
color: magenta;
margin-bottom: 12px;
}
.related-article h4 {
margin: 0 0 12px 0;
font-size: 1.2em;
}
.related-article .meta {
color: gray;
font-size: 0.9em;
}
.related-article .excerpt {
font-size: 0.9em;
color: #555;
margin-top: 10px;
}
.related-article .comments {
color: #666;
font-size: 0.9em;
margin-top: 5px;
}
.json-buttons {
display: flex;
gap: 10px;
margin-top: 20px;
}
.json-toggle-btn {
padding: 5px 10px;
font-size: 0.9em;
background-color: #ffffff;
color: #007bff;
border: 2px solid #007bff;
cursor: pointer;
border-radius: 5px;
transition: background-color 0.3s, color 0.3s;
}
.json-toggle-btn:hover {
background-color: #007bff;
color: #ffffff;
}
.json-data {
display: none;
margin-top: 20px;
padding: 10px;
background: #eee;
border: 1px solid #ccc;
white-space: pre-wrap;
word-wrap: break-word;
overflow-x: auto;
}
.article-display a {
color: inherit;
text-decoration: none;
}
.article-display a:hover {
color: #ff00ff;
text-decoration: none;
}
.exclusive {
font-weight: bold;
color: #ff00ff;
}
.exclusive-article {
border: 2px solid #ff00ff;
background-color: #fff0f5;
padding: 10px;
}
.article-display .summary a {
font-weight: bold;
}
@media (min-width: 640px) {
.related-article {
flex-direction: row;
}
.related-article img {
margin-right: 24px;
margin-bottom: 0;
}
}
`;
document.head.appendChild(enhancedStyle);
function createPremiumModal(dataset) {
const overlay = document.createElement('div');
overlay.id = 'premiumModalOverlay';
const modal = document.createElement('div');
modal.id = 'premiumModalContent';
const closeButton = document.createElement('button');
closeButton.id = 'premiumModalClose';
closeButton.innerHTML = '×';
closeButton.addEventListener('click', () => overlay.remove());
modal.appendChild(closeButton);
const header = document.createElement('div');
header.id = 'premiumModalHeader';
header.textContent = dataset.name || 'Project Information';
modal.appendChild(header);
if (dataset.description) {
const description = document.createElement('p');
description.textContent = dataset.description;
modal.appendChild(description);
}
if (dataset.url) {
const projLink = document.createElement('p');
projLink.innerHTML = `<a href="${dataset.url}" target="_blank">Visit Project Page</a>`;
modal.appendChild(projLink);
}
if (dataset.distribution && Array.isArray(dataset.distribution)) {
const downloadHeader = document.createElement('p');
downloadHeader.style.fontWeight = '600';
downloadHeader.style.marginTop = '18px';
downloadHeader.textContent = 'Download Data:';
modal.appendChild(downloadHeader);
dataset.distribution.forEach(dist => {
if (dist.contentUrl && dist.encodingFormat) {
const dlLink = document.createElement('p');
dlLink.innerHTML = `<a href="${dist.contentUrl}" target="_blank">Download (${dist.encodingFormat})</a>`;
modal.appendChild(dlLink);
}
});
}
overlay.appendChild(modal);
document.body.appendChild(overlay);
}
function extractDataset() {
const scripts = document.querySelectorAll('script[type="application/ld+json"]');
let dataset = null;
scripts.forEach(script => {
try {
let jsonData = script.textContent.trim();
jsonData = jsonData.replace(/[-\u001F\u007F-\u009F]/g, "").replace(/\r?\n|\r/g, " ");
const parsedData = JSON.parse(jsonData);
if (Array.isArray(parsedData)) {
parsedData.forEach(item => {
if (item['@type'] === 'Dataset') {
dataset = item;
}
});
} else if (parsedData['@type'] === 'Dataset') {
dataset = parsedData;
}
} catch (e) {}
});
return dataset;
}
function renderProfile(data) {
const person = data.mainEntity || {};
const name = person.name || 'Unknown Author';
const image = person.image || 'https://tii.imgix.net/production/articles/article_default_rebrand.jpg?auto=format&w=250';
const url = person.url || '';
const description = person.description || 'No description available.';
const articles = person.hasPart ? person.hasPart.filter(item => item['@type'] === 'Article') : [];
let twitterLink = '';
let linkedinLink = '';
let instagramLink = '';
if (person.sameAs && Array.isArray(person.sameAs)) {
const twitterUrl = person.sameAs.find(url => url.includes('twitter.com'));
if (twitterUrl) {
twitterLink = `
<div class="social-container">
<a href="${twitterUrl}" target="_blank" rel="noreferrer">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 22 22" class="h-20 w-20">
<path d="m12.912 9.502 7.85-9.124h-1.86L12.084 8.3 6.642.378H.362l8.233 11.98-8.232 9.569h1.86l7.198-8.367 5.749 8.367h6.278L12.911 9.502Zm-2.548 2.962-.834-1.193-6.637-9.493H5.75l5.356 7.661.834 1.193 6.962 9.958h-2.857l-5.681-8.126Z" fill="currentColor"></path>
</svg>
</a>
</div>`;
}
const linkedinUrl = person.sameAs.find(url => url.includes('linkedin.com'));
if (linkedinUrl) {
linkedinLink = `
<div class="social-container">
<a href="${linkedinUrl}" target="_blank" rel="noreferrer">
<img src="https://ti-assets.theinformation.com/packs/static/assets/images/linkedin_black-c57c74e581aeee118000.svg" alt="LinkedIn logo">
</a>
</div>`;
}
const instagramUrl = person.sameAs.find(url => url.includes('instagram.com'));
if (instagramUrl) {
instagramLink = `
<div class="social-container">
<a href="${instagramUrl}" target="_blank" rel="noreferrer">
<img src="https://ti-assets.theinformation.com/packs/static/assets/images/instagram_black-d4024b0f2e939d8d4a18.svg" alt="Instagram logo">
</a>
</div>`;
}
}
const location = person.address || '';
const locationHtml = location ? `
<a class="location-wrapper" href="/directory?location=${encodeURIComponent(location)}">
<img src="https://ti-assets.theinformation.com/packs/static/assets/images/directory/location_icon_grey-34cc69ba964d4c7025b9.svg" role="presentation">
<div>${location}</div>
</a>` : '';
const container = document.querySelector('.ProfileContent') || document.body;
if (!container) return;
const profileDiv = document.createElement('div');
profileDiv.id = 'Subscriber';
profileDiv.className = 'container';
let html = `
<div class="profile-start row">
<div class="col-sm-12 col-md-8 w-full sm:w-auto col">
<div class="profile-image-wrapper">
<div class="profile-img">
<img src="${image}" alt="${name}">
</div>
<div class="profile-header-detail">
<div class="profile-header">
<h1 class="name-container">${name}</h1>
</div>
<div class="profile-header-wrapper">
<div class="profile-subheader">
<div>Staff Member</div>
<div class="dot-middle">.</div>
<a href="/directory?ai_query=works%20for%20%22The%20Information%22">The Information</a>
</div>
<div class="profile-subheader">Subscriber since 2013</div>
<div class="social-contact-container" id="profile-seo-container">
<div class="social-contact-wrapper">
${twitterLink}
${linkedinLink}
${instagramLink}
${url ? `
<div class="social-container">
<a href="${url}" target="_blank" rel="noreferrer">
<img src="https://ti-assets.theinformation.com/packs/static/assets/images/link_black-833a178216f9aad547f0.svg" role="presentation">
</a>
</div>` : ''}
</div>
${locationHtml}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="ProfileContent container">
<div class="row">
<div class="col-sm-12 col-md-2 profile-detail-nav col">
<ul class="profile-nav">
<li><a class="link-nav"><div class="profile-nav-icon"><svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="w-24"><path d="M12 0C5.381 0 0 5.381 0 12s5.381 12 12 12 12-5.381 12-12S18.619 0 12 0Zm0 6.872a3.774 3.774 0 0 1 3.764 3.764A3.774 3.774 0 0 1 12 14.4a3.774 3.774 0 0 1-3.764-3.764A3.774 3.774 0 0 1 12 6.872ZM5.432 19.276v-.556a2.906 2.906 0 0 1 2.905-2.905h7.326a2.905 2.905 0 0 1 2.905 2.905v.556A9.795 9.795 0 0 1 12 21.802a9.795 9.795 0 0 1-6.568-2.526Z" fill="currentColor"></path></svg></div>About</a></li>
<li><a class="link-nav"><div class="profile-nav-icon"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="none" class="w-18 h-20"><path fill="currentColor" d="M16 0H3C1.794 0 0 .799 0 3v14c0 2.201 1.794 3 3 3h15v-2H3.012C2.55 17.988 2 17.805 2 17c0-.101.009-.191.024-.273.112-.575.583-.717.987-.727H17c.018 0 .031-.009.049-.01H18V2c0-1.103-.897-2-2-2Zm0 14H2V3c0-.806.55-.988 1-1h7v7l2-1 2 1V2h2v12Z"></path></svg></div>Articles</a></li>
<li><a class="link-nav"><div class="profile-nav-icon"><svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26" class="w-[26px]"><path d="M25.15 4.52v-.087l-.076-.043-6.19-3.52-.074-.042-.075.042-5.725 3.257L7.283.87 7.208.827 7.134.87.944 4.41l-.076.044v.087L.85 18.18v.087l.076.043 12.008 6.82.074.043.075-.043 6.19-3.521.076-.043V14.969l5.725-3.278.076-.044V4.52Zm-22.682.231 4.741-2.696 4.657 2.649h-.002l.084.048-4.74 2.696-4.74-2.697Zm15.805 16.2-4.725 2.688v-5.37l4.725-2.689v5.371ZM14.09 4.741l4.722-2.686 4.704 2.675-4.722 2.686-4.704-2.675ZM7.747 8.37l4.725-2.687v5.35l-4.725 2.687V8.37Zm5.245 8.946L8.307 14.65l4.685-2.665 4.737 2.676-4.737 2.654ZM24.074 5.66v5.37l-4.726 2.689V8.349l4.726-2.688Z" fill="currentColor" stroke="currentColor" stroke-width=".3"></path></svg></div>Topics</a></li>
</ul>
</div>
<div class="col-sm-12 col-md-10 profile-detail-wrapper col">
<div class="section-container" id="About">
<div class="section-header">About</div>
<div class="section-detail">${description.replace(/\r\n/g, ' ')}</div>
</div>
<div class="section-container" id="Articles">
<div class="section-header">Articles</div>
<div class="section-detail">
<div>
`;
articles.forEach((article, index) => {
const articleImage = article.image || 'https://tii.imgix.net/production/articles/article_default_rebrand.jpg?auto=format&w=250';
const date = new Date(article.datePublished).toLocaleString('en-US', {
year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit', timeZoneName: 'short'
});
html += `
<div class="zHO_NLr7ewdHOaxGnkLl">
<div class="sfDgx1CT0jYy_F44fvMz" data-test="article-or-briefing-feed-item">
<div class="ost5fDu0w_utvvWjnhwA">
<div class="WGoBkCwesGqC7Fvf6poD"></div>
<a href="${article.url}" class="no-link track-click article-link relative" id="article-${index}" data-type="link" data-name="article title" data-location="feed">
<div class="y4HMnE6OwEbmQz2QhBGZ">${article.headline}</div>
</a>
<div class="RlSVo1yyINvbwsj5E850">By <span><a href="${url}">${name}</a></span><span> · ${date}</span></div>
<div class="k70eEce7kcJDsOPtef9D"><a href="${article.url}">${article.headline}...</a></div>
</div>
<div class="iq1CRsBjkqjCqMKyrNRQ">
<a href="${article.url}" class="track-link relative" id="article-image-${index}" data-type="link" data-name="article image" data-location="feed">
<img class="article-image max-xs:max-w-full" width="270" height="151.875" src="${articleImage}">
</a>
</div>
</div>
</div>
`;
});
html += `
</div>
</div>
</div>
</div>
</div>
</div>
`;
profileDiv.innerHTML = html;
if (container.classList.contains('ProfileContent')) {
container.innerHTML = profileDiv.querySelector('.ProfileContent').innerHTML;
} else {
container.insertBefore(profileDiv, container.firstChild);
}
}
function loadAndRenderProfile() {
const scriptTags = document.querySelectorAll('script[type="application/ld+json"]');
for (const scriptTag of scriptTags) {
try {
const data = JSON.parse(scriptTag.textContent);
if (data['@type'] === 'ProfilePage' && data.mainEntity) {
renderProfile(data);
break;
}
} catch (e) {}
}
}
function parseGoogleItem(item) {
return {
title: item.querySelector('title')?.textContent || '',
url: item.querySelector('link')?.textContent || '',
source: item.querySelector('source')?.textContent || 'Unknown',
date: item.querySelector('pubDate')?.textContent || ''
};
}
function parseBingItem(item) {
const description = item.querySelector('description')?.textContent || '';
const actualUrlMatch = description.match(/href="([^"]+)"/);
const actualUrl = actualUrlMatch ? actualUrlMatch[1] : item.querySelector('link')?.textContent || '';
const publication = item.getElementsByTagName('news:publication')[0];
const source = publication?.getElementsByTagName('news:name')[0]?.textContent || 'Unknown';
return {
title: item.querySelector('title')?.textContent || '',
url: actualUrl,
source: source,
date: item.querySelector('pubDate')?.textContent || ''
};
}
function normalizeUrl(url) {
try {
const urlObj = new URL(url);
return urlObj.hostname + urlObj.pathname;
} catch (e) {
return url;
}
}
function fetchRss(url, parseItem) {
return new Promise(resolve => {
GM.xmlHttpRequest({
method: 'GET',
url: url,
onload: function(response) {
if (response.status === 200) {
const xmlText = response.responseText;
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlText, 'text/xml');
const items = xmlDoc.querySelectorAll('item');
const parsedArticles = Array.from(items).map(parseItem);
resolve({ articles: parsedArticles, error: null });
} else {
resolve({ articles: [], error: `Error loading articles from ${url}` });
}
},
onerror: function(error) {
resolve({ articles: [], error: error.message });
}
});
});
}
function linkTwitterHandles(element) {
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);
const textNodes = [];
let node;
while (node = walker.nextNode()) {
let parent = node.parentNode;
let insideAnchor = false;
while (parent && parent !== element) {
if (parent.tagName === 'A') {
insideAnchor = true;
break;
}
parent = parent.parentNode;
}
if (!insideAnchor) {
textNodes.push(node);
}
}
textNodes.forEach(textNode => {
const text = textNode.textContent;
const regex = /(?<!\w)@(\w{1,15})\b/g;
let match;
let lastIndex = 0;
const fragments = [];
while ((match = regex.exec(text)) !== null) {
const before = text.substring(lastIndex, match.index);
if (before) {
fragments.push(document.createTextNode(before));
}
const handle = match[0];
const username = match[1];
const a = document.createElement('a');
a.href = `https://twitter.com/${username}`;
a.target = '_blank';
a.rel = 'noopener noreferrer';
a.textContent = handle;
fragments.push(a);
lastIndex = regex.lastIndex;
}
if (lastIndex < text.length) {
fragments.push(document.createTextNode(text.substring(lastIndex)));
}
if (fragments.length > 0) {
const parent = textNode.parentNode;
fragments.forEach(fragment => {
parent.insertBefore(fragment, textNode);
});
parent.removeChild(textNode);
}
});
}
const pathname = window.location.pathname;
if (pathname.startsWith('/articles/')) {
const pageTitle = document.title;
const articleTitle = pageTitle.split(' | ')[0];
const googleRssUrl = `https://news.google.com/rss/search?q=${encodeURIComponent(articleTitle)}`;
const bingRssUrl = `https://www.bing.com/news/search?q=${encodeURIComponent(articleTitle)}&format=rss`;
const container = document.createElement('div');
container.style.cssText = `
position: fixed;
top: 150px;
right: 10px;
width: 300px;
max-height: 80vh;
overflow-y: auto;
background: white;
padding: 15px;
font-family: Arial, sans-serif;
z-index: 9999;
`;
container.innerHTML = '<h3 style="margin: 0 0 15px 0; color: #000; font-size: 18px; font-weight: bold;">Alternative Articles</h3><p style="margin: 0; color: #666;">Loading...</p>';
document.body.appendChild(container);
Promise.all([
fetchRss(googleRssUrl, parseGoogleItem),
fetchRss(bingRssUrl, parseBingItem)
]).then(results => {
const allArticles = results.flatMap(result => result.articles);
const errors = results.map(result => result.error).filter(Boolean);
const filteredArticles = allArticles.filter(article =>
!article.url.toLowerCase().includes('theinformation.com') &&
!article.source.toLowerCase().includes('the information')
);
const uniqueArticles = Array.from(new Map(filteredArticles.map(article => [normalizeUrl(article.url), article])).values());
uniqueArticles.sort((a, b) => {
const dateA = a.date ? new Date(a.date) : new Date(0);
const dateB = b.date ? new Date(b.date) : new Date(0);
return dateB - dateA;
});
const topArticles = uniqueArticles.slice(0, 10);
if (topArticles.length > 0) {
const articlesHtml = topArticles.map(article => `
<div style="margin-bottom: 20px;">
<a href="${article.url}" target="_blank" style="display: block; color: #000; font-weight: bold; font-size: 16px; text-decoration: none; margin-bottom: 5px;">${article.title}</a>
<small style="color: #666; font-size: 12px;">${article.source} - ${article.date ? new Date(article.date).toLocaleDateString() : 'Unknown date'}</small>
</div>
`).join('');
container.innerHTML = `
<h3 style="margin: 0 0 15px 0; color: #000; font-size: 18px; font-weight: bold;">Alternative Articles <a href="#" style="float: right; font-size: 14px; color: #666; text-decoration: none;" id="close-alternatives">✕</a></h3>
${articlesHtml}
`;
} else {
container.innerHTML = '<h3 style="margin: 0 0 15px 0; color: #000; font-size: 18px; font-weight: bold;">Alternative Articles</h3><p style="margin: 0; color: #666;">No articles found.</p>';
}
container.querySelector('#close-alternatives')?.addEventListener('click', (e) => {
e.preventDefault();
container.style.display = 'none';
});
if (errors.length > 0) {
const errorHtml = errors.map(error => `<p style="margin: 15px 0 10px 0; color: #666;">${error}</p>`).join('');
container.insertAdjacentHTML('beforeend', errorHtml);
}
});
}
window.addEventListener('load', () => {
if (location.pathname.startsWith('/projects/')) {
const dataset = extractDataset();
if (dataset) createPremiumModal(dataset);
}
if (location.pathname.startsWith('/u')) {
loadAndRenderProfile();
setTimeout(loadAndRenderProfile, 1800);
}
const scriptTag = document.querySelector('script[type="application/json"][data-component-name="Article"]');
if (scriptTag) {
let jsonData;
try {
jsonData = JSON.parse(scriptTag.textContent);
} catch (e) {
return;
}
const displayDiv = document.createElement('div');
displayDiv.className = 'article-display';
if (jsonData.article.picture && jsonData.article.id) {
const img = document.createElement('img');
img.src = `https://tii.imgix.net/production/articles/${jsonData.article.id}/${jsonData.article.picture}?auto=compress&fit=crop&auto=format`;
img.alt = jsonData.article.title || 'Article Picture';
img.className = 'article-picture';
img.setAttribute('loading', 'lazy');
displayDiv.appendChild(img);
if (jsonData.article.pictureCaption) {
const captionP = document.createElement('p');
captionP.textContent = jsonData.article.pictureCaption;
captionP.style.fontStyle = 'italic';
displayDiv.appendChild(captionP);
}
}
const titleH1 = document.createElement('h1');
titleH1.textContent = jsonData.article.title || 'Untitled Article';
if (jsonData.article.highlight && jsonData.article.highlight.startsWith('Exclusive:')) {
const exclusiveSpan = document.createElement('span');
exclusiveSpan.textContent = ' (Exclusive)';
exclusiveSpan.className = 'exclusive';
titleH1.appendChild(exclusiveSpan);
}
displayDiv.appendChild(titleH1);
const publishedP = document.createElement('p');
const publishedAt = jsonData.article.publishedAt;
let publishedText = 'Published: ';
if (publishedAt) {
const publishedDate = new Date(publishedAt);
publishedText += isNaN(publishedDate.getTime())
? publishedAt
: publishedDate.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });
} else {
publishedText += 'Not available';
}
publishedP.textContent = publishedText;
publishedP.style.color = '#666';
displayDiv.appendChild(publishedP);
if (jsonData.article.highlight) {
const highlightP = document.createElement('p');
let highlightText = jsonData.article.highlight;
if (highlightText.startsWith('Exclusive:')) {
highlightText = '<span class="exclusive">Exclusive:</span>' + highlightText.slice(10);
}
highlightP.innerHTML = highlightText;
highlightP.style.fontStyle = 'italic';
displayDiv.appendChild(highlightP);
}
if (jsonData.article.authors && jsonData.article.authors.length > 0) {
const authorsDiv = document.createElement('div');
authorsDiv.className = 'authors';
jsonData.article.authors.forEach(author => {
const authorDiv = document.createElement('div');
authorDiv.className = 'author';
if (author.picture) {
const imgLink = document.createElement('a');
imgLink.href = `https://www.theinformation.com/u/${author.username}`;
imgLink.target = '_blank';
imgLink.rel = 'noopener noreferrer';
const img = document.createElement('img');
img.src = author.picture;
img.alt = author.name || 'Author Picture';
img.setAttribute('loading', 'lazy');
imgLink.appendChild(img);
authorDiv.appendChild(imgLink);
}
const nameP = document.createElement('p');
nameP.innerHTML = `<a href="https://www.theinformation.com/u/${author.username}" target="_blank" rel="noopener noreferrer"><strong>${author.name || 'Unnamed Author'}</strong></a>`;
const bioText = author.bio && author.bio.trim() ? author.bio : author.fullBio;
if (author.twitter) {
const twitterUsername = author.twitter.replace(/^@/, '');
if (!bioText || !bioText.includes(`@${twitterUsername}`)) {
nameP.innerHTML += ` - <a href="https://twitter.com/${twitterUsername}" target="_blank" rel="noopener noreferrer">@${twitterUsername}</a>`;
}
}
authorDiv.appendChild(nameP);
if (bioText) {
const bioP = document.createElement('p');
bioP.innerHTML = bioText;
linkTwitterHandles(bioP);
bioP.querySelectorAll('a').forEach(a => {
a.target = '_blank';
a.rel = 'noopener noreferrer';
});
authorDiv.appendChild(bioP);
}
authorsDiv.appendChild(authorDiv);
});
displayDiv.appendChild(authorsDiv);
}
if (jsonData.article.freeBlurb) {
const summaryH3 = document.createElement('h3');
summaryH3.textContent = 'Summary';
displayDiv.appendChild(summaryH3);
const summaryDiv = document.createElement('div');
summaryDiv.className = 'summary';
summaryDiv.innerHTML = jsonData.article.freeBlurb;
summaryDiv.querySelectorAll('a').forEach(a => {
a.target = '_blank';
a.rel = 'noopener noreferrer';
});
displayDiv.appendChild(summaryDiv);
}
if (jsonData.article.pickups && jsonData.article.pickups.length > 0) {
displayDiv.appendChild(document.createElement('hr'));
const pickupsH3 = document.createElement('h3');
pickupsH3.textContent = jsonData.article.pickups.length > 1 ? 'Sources' : 'Source';
displayDiv.appendChild(pickupsH3);
const pickupsUl = document.createElement('ul');
jsonData.article.pickups.forEach(pickup => {
const li = document.createElement('li');
li.innerHTML = `<a href="${pickup.url}" target="_blank" rel="noopener noreferrer">${pickup.title}</a> (${pickup.publication})`;
pickupsUl.appendChild(li);
});
displayDiv.appendChild(pickupsUl);
}
if (jsonData.mostPopularArticles && jsonData.mostPopularArticles.length > 0) {
displayDiv.appendChild(document.createElement('hr'));
const popularH3 = document.createElement('h3');
popularH3.textContent = 'Most Popular Articles';
displayDiv.appendChild(popularH3);
jsonData.mostPopularArticles.forEach(article => {
const articleDiv = document.createElement('article');
articleDiv.className = 'related-article';
const textDiv = document.createElement('div');
textDiv.className = 'text';
if (article.highlight) {
const highlightP = document.createElement('p');
highlightP.className = 'highlight';
let highlightText = article.highlight;
if (highlightText.startsWith('Exclusive:')) {
highlightText = '<span class="exclusive">Exclusive:</span>' + highlightText.slice(10);
}
highlightP.innerHTML = highlightText;
textDiv.appendChild(highlightP);
}
const titleH4 = document.createElement('h4');
titleH4.innerHTML = `<a href="https://www.theinformation.com/articles/${article.slug}" target="_blank" rel="noopener noreferrer">${article.title || 'Untitled'}</a>`;
textDiv.appendChild(titleH4);
if (article.publishedAt) {
const metaP = document.createElement('p');
metaP.className = 'meta';
const publishedDate = new Date(article.publishedAt);
metaP.textContent = isNaN(publishedDate.getTime())
? article.publishedAt
: publishedDate.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });
textDiv.appendChild(metaP);
}
articleDiv.appendChild(textDiv);
displayDiv.appendChild(articleDiv);
});
}
if (jsonData.relatedArticles && jsonData.relatedArticles.length > 0) {
displayDiv.appendChild(document.createElement('hr'));
const relatedH3 = document.createElement('h3');
relatedH3.textContent = 'Related Articles';
displayDiv.appendChild(relatedH3);
jsonData.relatedArticles.forEach(article => {
const articleDiv = document.createElement('article');
articleDiv.className = 'related-article';
if (article.highlight && article.highlight.startsWith('Exclusive:')) {
articleDiv.classList.add('exclusive-article');
}
if (article.picture && article.id) {
const imgLink = document.createElement('a');
imgLink.href = article.url;
imgLink.target = '_blank';
imgLink.rel = 'noopener noreferrer';
const img = document.createElement('img');
img.src = `https://tii.imgix.net/production/articles/${article.id}/${article.picture}?auto=compress&fit=crop&auto=format`;
img.alt = article.title || 'Related Article';
img.setAttribute('loading', 'lazy');
imgLink.appendChild(img);
articleDiv.appendChild(imgLink);
}
const textDiv = document.createElement('div');
textDiv.className = 'text';
if (article.highlight) {
const highlightP = document.createElement('p');
highlightP.className = 'highlight';
let highlightText = article.highlight;
if (highlightText.startsWith('Exclusive:')) {
highlightText = '<span class="exclusive">Exclusive:</span>' + highlightText.slice(10);
}
highlightP.innerHTML = highlightText;
textDiv.appendChild(highlightP);
}
const titleH4 = document.createElement('h4');
titleH4.innerHTML = `<a href="${article.url}" target="_blank" rel="noopener noreferrer">${article.title || 'Untitled'}</a>`;
textDiv.appendChild(titleH4);
if (article.authors || article.publishedAt) {
const metaP = document.createElement('p');
metaP.className = 'meta';
let metaText = '';
if (article.authors && article.authors.length > 0) {
metaText += 'By ' + article.authors.map(a => a.name).join(', ');
}
if (article.publishedAt) {
const publishedDate = new Date(article.publishedAt);
metaText += (metaText ? ' • ' : '') + (isNaN(publishedDate.getTime())
? article.publishedAt
: publishedDate.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }));
}
metaP.textContent = metaText;
textDiv.appendChild(metaP);
}
if (article.excerpt && article.excerpt.long) {
const excerptP = document.createElement('p');
excerptP.className = 'excerpt';
excerptP.textContent = article.excerpt.long;
textDiv.appendChild(excerptP);
}
if (article.commentCount > 0) {
const commentsP = document.createElement('p');
commentsP.className = 'comments';
commentsP.textContent = `${article.commentCount} comment${article.commentCount > 1 ? 's' : ''}`;
textDiv.appendChild(commentsP);
}
articleDiv.appendChild(textDiv);
displayDiv.appendChild(articleDiv);
});
}
const buttonsDiv = document.createElement('div');
buttonsDiv.className = 'json-buttons';
const jsonButton = document.createElement('button');
jsonButton.textContent = '{}';
jsonButton.title = 'Toggle JSON view';
jsonButton.className = 'json-toggle-btn';
buttonsDiv.appendChild(jsonButton);
displayDiv.appendChild(buttonsDiv);
const jsonDiv = document.createElement('div');
jsonDiv.className = 'json-data';
const pre = document.createElement('pre');
pre.textContent = JSON.stringify(jsonData, null, 2);
jsonDiv.appendChild(pre);
displayDiv.appendChild(jsonDiv);
jsonButton.addEventListener('click', () => {
const isHidden = jsonDiv.style.display === 'none' || jsonDiv.style.display === '';
jsonDiv.style.display = isHidden ? 'block' : 'none';
jsonButton.textContent = isHidden ? 'Hide JSON' : '{}';
});
document.body.insertBefore(displayDiv, document.body.firstChild);
}
});
})();