191 lines
5.1 KiB
Plaintext
191 lines
5.1 KiB
Plaintext
(() => {
|
|
const WESTGATE_LATEST_CONFIG = [
|
|
{
|
|
key: 'announcement',
|
|
cid: 1,
|
|
emptyTitle: 'No announcements yet',
|
|
},
|
|
{
|
|
key: 'patch',
|
|
cid: 10,
|
|
emptyTitle: 'No patch notes yet',
|
|
},
|
|
];
|
|
|
|
const getRelativePath = () => {
|
|
return window.config && window.config.relative_path ? window.config.relative_path : '';
|
|
};
|
|
|
|
const unwrap = (payload) => {
|
|
return payload && payload.response ? payload.response : payload;
|
|
};
|
|
|
|
const textFromHtml = (html) => {
|
|
const el = document.createElement('div');
|
|
el.innerHTML = html || '';
|
|
|
|
const firstParagraph = Array.from(el.querySelectorAll('p'))
|
|
.map((p) => (p.textContent || '').replace(/\s+/g, ' ').trim())
|
|
.find(Boolean);
|
|
|
|
return (firstParagraph || el.textContent || '').replace(/\s+/g, ' ').trim();
|
|
};
|
|
|
|
const truncate = (text, limit = 240) => {
|
|
if (!text || text.length <= limit) {
|
|
return text || '';
|
|
}
|
|
|
|
return `${text.slice(0, limit).replace(/\s+\S*$/, '')}...`;
|
|
};
|
|
|
|
const formatDate = (value) => {
|
|
const timestamp = Number(value);
|
|
if (!timestamp) {
|
|
return '';
|
|
}
|
|
|
|
const date = new Date(timestamp);
|
|
if (Number.isNaN(date.getTime())) {
|
|
return '';
|
|
}
|
|
|
|
return new Intl.DateTimeFormat(undefined, {
|
|
month: 'short',
|
|
day: 'numeric',
|
|
}).format(date);
|
|
};
|
|
|
|
const getJSON = async (url) => {
|
|
const response = await fetch(url, {
|
|
credentials: 'same-origin',
|
|
headers: {
|
|
accept: 'application/json',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Request failed: ${response.status}`);
|
|
}
|
|
|
|
return unwrap(await response.json());
|
|
};
|
|
|
|
const getTopicExcerpt = async (topic) => {
|
|
const relativePath = getRelativePath();
|
|
const topicPath = topic.slug || topic.tid;
|
|
|
|
try {
|
|
const topicData = await getJSON(`${relativePath}/api/topic/${topicPath}?page=1&sort=oldest_to_newest`);
|
|
const firstPost = topicData.posts && topicData.posts[0];
|
|
const firstPostText = textFromHtml(firstPost && firstPost.content);
|
|
|
|
if (firstPostText) {
|
|
return truncate(firstPostText);
|
|
}
|
|
} catch (error) {
|
|
console.warn('[Westgate latest widget original post excerpt]', error);
|
|
}
|
|
|
|
if (topic.mainPost && topic.mainPost.content) {
|
|
const mainPostText = textFromHtml(topic.mainPost.content);
|
|
if (mainPostText) {
|
|
return truncate(mainPostText);
|
|
}
|
|
}
|
|
|
|
if (topic.teaser && topic.teaser.content) {
|
|
return truncate(textFromHtml(topic.teaser.content));
|
|
}
|
|
|
|
return '';
|
|
};
|
|
|
|
const getLatestTopic = async (cid) => {
|
|
const relativePath = getRelativePath();
|
|
const category = await getJSON(`${relativePath}/api/v3/categories/${cid}/topics?sort=recently_created&after=0`);
|
|
const topic = category.topics && category.topics[0];
|
|
|
|
if (!topic) {
|
|
return null;
|
|
}
|
|
|
|
let excerpt = '';
|
|
|
|
try {
|
|
excerpt = await getTopicExcerpt(topic);
|
|
} catch (error) {
|
|
console.warn('[Westgate latest widget excerpt]', error);
|
|
}
|
|
|
|
return {
|
|
title: topic.titleRaw || topic.title || 'Untitled',
|
|
url: `${relativePath}/topic/${topic.slug || topic.tid}`,
|
|
author: topic.user && (topic.user.displayname || topic.user.username),
|
|
date: formatDate(topic.timestamp || topic.lastposttime),
|
|
excerpt,
|
|
};
|
|
};
|
|
|
|
const renderCard = async (root, source) => {
|
|
const card = root.querySelector(`[data-card="${source.key}"]`);
|
|
if (!card) {
|
|
return;
|
|
}
|
|
|
|
const title = card.querySelector('.wg-latest-title');
|
|
const meta = card.querySelector('.wg-latest-meta');
|
|
const excerpt = card.querySelector('.wg-latest-excerpt');
|
|
|
|
card.classList.add('is-loading');
|
|
card.classList.remove('is-empty');
|
|
title.textContent = 'Loading...';
|
|
title.removeAttribute('href');
|
|
meta.textContent = '';
|
|
excerpt.textContent = '';
|
|
|
|
try {
|
|
const topic = await getLatestTopic(source.cid);
|
|
|
|
if (!topic) {
|
|
card.classList.remove('is-loading');
|
|
card.classList.add('is-empty');
|
|
title.textContent = source.emptyTitle;
|
|
return;
|
|
}
|
|
|
|
title.textContent = topic.title;
|
|
title.href = topic.url;
|
|
meta.textContent = [topic.author, topic.date].filter(Boolean).join(' · ');
|
|
excerpt.textContent = topic.excerpt || '';
|
|
card.classList.remove('is-loading', 'is-empty');
|
|
} catch (error) {
|
|
console.warn('[Westgate latest widget]', error);
|
|
card.classList.remove('is-loading');
|
|
card.classList.add('is-empty');
|
|
title.textContent = source.emptyTitle;
|
|
meta.textContent = 'Unable to load right now';
|
|
}
|
|
};
|
|
|
|
const renderLatestStrip = () => {
|
|
const root = document.querySelector('[data-westgate-latest]');
|
|
|
|
if (!root || root.dataset.loaded === '1') {
|
|
return;
|
|
}
|
|
|
|
root.dataset.loaded = '1';
|
|
WESTGATE_LATEST_CONFIG.forEach((source) => renderCard(root, source));
|
|
};
|
|
|
|
document.addEventListener('DOMContentLoaded', renderLatestStrip);
|
|
window.addEventListener('load', renderLatestStrip);
|
|
|
|
if (window.jQuery) {
|
|
window.jQuery(window).on('action:ajaxify.end', renderLatestStrip);
|
|
}
|
|
|
|
renderLatestStrip();
|
|
})();
|