0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-04-15 03:01:37 -05:00

Added comment-counts script

refs https://github.com/TryGhost/Team/issues/1664
This commit is contained in:
Kevin Ansfield 2022-07-08 11:37:35 +02:00 committed by Simon Backx
parent e1a3adea6a
commit 6ea545afe1
6 changed files with 146 additions and 0 deletions

View file

@ -17,6 +17,7 @@ const tpl = require('@tryghost/tpl');
const themeEngine = require('./frontend/services/theme-engine');
const appService = require('./frontend/services/apps');
const cardAssetService = require('./frontend/services/card-assets');
const commentCountsAssetService = require('./frontend/services/comment-counts-assets');
const routerManager = require('./frontend/services/routing').routerManager;
const settingsCache = require('./shared/settings-cache');
const urlService = require('./server/services/url');
@ -63,6 +64,10 @@ class Bridge {
const cardAssetConfig = this.getCardAssetConfig();
debug('reload card assets config', cardAssetConfig);
await cardAssetService.load(cardAssetConfig);
// TODO: is this in the right place?
// rebuild asset files
await commentCountsAssetService.load();
} catch (err) {
logging.error(new errors.InternalServerError({
message: tpl(messages.activateFailed, {theme: loadedTheme.name}),

View file

@ -215,6 +215,10 @@ module.exports = async function ghost_head(options) { // eslint-disable-line cam
head.push(`<link rel="stylesheet" type="text/css" href="${getAssetUrl('public/cards.min.css')}">`);
}
if (labs.isSet('comments') && settingsCache.get('enable_comments') !== 'off') {
head.push(`<script defer src="${getAssetUrl('public/comment-counts.min.js')}" data-ghost-comments-counts-api="${urlUtils.getSiteUrl(true)}members/api/comments/counts/"></script>`);
}
if (!_.isEmpty(globalCodeinjection)) {
head.push(globalCodeinjection);
}

View file

@ -0,0 +1,4 @@
const CommentCountsAssetsService = require('./service');
let commentCountsAssets = new CommentCountsAssetsService();
module.exports = commentCountsAssets;

View file

@ -0,0 +1,59 @@
// const debug = require('@tryghost/debug')('comments-counts-assets');
const Minifier = require('@tryghost/minifier');
const path = require('path');
const fs = require('fs').promises;
const logging = require('@tryghost/logging');
const config = require('../../../shared/config');
class CommentCountsAssetsService {
constructor(options = {}) {
this.src = options.src || path.join(config.get('paths').assetSrc, 'comment-counts');
this.dest = options.dest || config.getContentPath('public');
this.minifier = new Minifier({src: this.src, dest: this.dest});
this.files = [];
}
generateGlobs() {
return {
'comment-counts.min.js': 'js/*.js'
};
}
async minify(globs) {
try {
return await this.minifier.minify(globs);
} catch (error) {
if (error.code === 'EACCES') {
logging.error('Ghost was not able to write comment-count asset files due to permissions.');
return;
}
throw error;
}
}
async clearFiles() {
this.files = [];
const rmFile = async (name) => {
await fs.unlink(path.join(this.dest, name));
};
let promises = [
// @deprecated switch this to use fs.rm when we drop support for Node v12
rmFile('comment-counts.min.js')
];
// We don't care if removing these files fails as it's valid for them to not exist
return Promise.allSettled(promises);
}
async load() {
await this.clearFiles();
const globs = this.generateGlobs();
this.files = await this.minify(globs);
}
}
module.exports = CommentCountsAssetsService;

View file

@ -0,0 +1,71 @@
(async function () {
const countsMap = {};
const fetchingIds = new Set();
const api = document.querySelector('[data-ghost-comments-counts-api]')
.dataset.ghostCommentsCountsApi;
const debounce = function (func, timeout = 100) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => func.apply(this, args), timeout);
};
};
const addIdsFromElement = function (node) {
const countElems = node.querySelectorAll?.('[data-ghost-comment-count]') || [];
countElems.forEach((countElem) => {
if (!countsMap[countElem.dataset.ghostCommentCount]) {
fetchingIds.add(countElem.dataset.ghostCommentCount);
}
});
};
const renderCounts = function () {
for (const [id, count] of Object.entries(countsMap)) {
const countElems = document.querySelectorAll(`[data-ghost-comment-count="${id}"]`);
countElems.forEach((e) => {
e.innerHTML = e.innerHTML.replace('#', count);
e.style.display = '';
});
}
};
const fetchCounts = async function () {
const ids = Array.from(fetchingIds);
fetchingIds.clear();
const rawRes = await fetch(api, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ids})
});
const res = await rawRes.json();
for (const [id, count] of Object.entries(res)) {
countsMap[id] = count;
}
renderCounts();
};
const countElemObserver = new MutationObserver((mutationsList) => {
mutationsList.forEach((mutation) => {
mutation.addedNodes.forEach((addedNode) => {
addIdsFromElement(addedNode);
debounce(fetchCounts);
});
});
});
countElemObserver.observe(document.body, {subtree: true, childList: true});
addIdsFromElement(document.body);
fetchCounts();
})();

View file

@ -72,6 +72,9 @@ module.exports = function setupSiteApp(routerConfig) {
siteApp.use(mw.servePublicFile('built', 'public/cards.min.css', 'text/css', constants.ONE_YEAR_S));
siteApp.use(mw.servePublicFile('built', 'public/cards.min.js', 'application/javascript', constants.ONE_YEAR_S));
// Comment counts
siteApp.use(mw.servePublicFile('built', 'public/comment-counts.min.js', 'application/javascript', constants.ONE_YEAR_S));
// Serve blog images using the storage adapter
siteApp.use(STATIC_IMAGE_URL_PREFIX, mw.handleImageSizes, storage.getStorage('images').serve());
// Serve blog media using the storage adapter