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:
parent
e1a3adea6a
commit
6ea545afe1
6 changed files with 146 additions and 0 deletions
|
@ -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}),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
4
core/frontend/services/comment-counts-assets/index.js
Normal file
4
core/frontend/services/comment-counts-assets/index.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
const CommentCountsAssetsService = require('./service');
|
||||
let commentCountsAssets = new CommentCountsAssetsService();
|
||||
|
||||
module.exports = commentCountsAssets;
|
59
core/frontend/services/comment-counts-assets/service.js
Normal file
59
core/frontend/services/comment-counts-assets/service.js
Normal 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;
|
71
core/frontend/src/comment-counts/js/comment-counts.js
Normal file
71
core/frontend/src/comment-counts/js/comment-counts.js
Normal 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();
|
||||
})();
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue