mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-02-25 16:11:19 +01:00
Server-side rendering of topic events (#9733)
* style: reformat list of helpers exported * refactor: move topic events partial into a helper, invoke helper in topic.tpl (see persona), update how events are added to the DOM via addTopicEvents closes #9731 * style: lint
This commit is contained in:
@@ -10,7 +10,8 @@ define('forum/topic/posts', [
|
||||
'components',
|
||||
'translator',
|
||||
'hooks',
|
||||
], function (pagination, infinitescroll, postTools, images, navigator, components, translator, hooks) {
|
||||
'helpers',
|
||||
], function (pagination, infinitescroll, postTools, images, navigator, components, translator, hooks, helpers) {
|
||||
var Posts = { };
|
||||
|
||||
Posts.onNewPost = function (data) {
|
||||
@@ -281,56 +282,13 @@ define('forum/topic/posts', [
|
||||
posts.find('[component="post/content"] img:not(.not-responsive)').addClass('img-responsive');
|
||||
Posts.addBlockquoteEllipses(posts);
|
||||
hidePostToolsForDeletedPosts(posts);
|
||||
addNecroPostMessage(Posts.addTopicEvents);
|
||||
addNecroPostMessage();
|
||||
};
|
||||
|
||||
Posts.addTopicEvents = function (events) {
|
||||
events = events || ajaxify.data.events;
|
||||
if (!events || !Array.isArray(events)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.topicPostSort !== 'newest_to_oldest' && config.topicPostSort !== 'oldest_to_newest') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter out events already in DOM
|
||||
const eventIdsInDOM = Array.from(document.querySelectorAll('[component="topic/event"]')).map(el => parseInt(el.getAttribute('data-topic-event-id'), 10));
|
||||
events = events.filter(event => !eventIdsInDOM.includes(event.id));
|
||||
|
||||
let postTimestamps = ajaxify.data.posts.map(post => post.timestamp);
|
||||
|
||||
const reverse = config.topicPostSort === 'newest_to_oldest';
|
||||
events = events.slice(0);
|
||||
if (reverse) {
|
||||
events.reverse();
|
||||
postTimestamps = postTimestamps.slice(1); // OP is always at top, so exclude from calculations
|
||||
}
|
||||
|
||||
Promise.all(events.map((event) => {
|
||||
const beforeIdx = postTimestamps.findIndex(
|
||||
timestamp => (reverse ? (timestamp < event.timestamp) : (timestamp > event.timestamp))
|
||||
);
|
||||
let postEl;
|
||||
if (beforeIdx > -1) {
|
||||
postEl = document.querySelector(`[component="post"][data-pid="${ajaxify.data.posts[beforeIdx + (reverse ? 1 : 0)].pid}"]`);
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
event.isAdminOrMod = ajaxify.data.privileges.isAdminOrMod;
|
||||
app.parseAndTranslate('partials/topic/event', event, function (html) {
|
||||
html = html.get(0);
|
||||
|
||||
if (postEl) {
|
||||
document.querySelector('[component="topic"]').insertBefore(html, postEl);
|
||||
} else {
|
||||
document.querySelector('[component="topic"]').append(html);
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
})).then(() => {
|
||||
const html = helpers.renderEvents.call(ajaxify.data, events);
|
||||
translator.translate(html, (translated) => {
|
||||
document.querySelector('[component="topic"]').insertAdjacentHTML('beforeend', translated);
|
||||
$('[component="topic/event"] .timeago').timeago();
|
||||
});
|
||||
};
|
||||
|
||||
@@ -14,23 +14,25 @@
|
||||
Benchpress.setGlobal('false', false);
|
||||
|
||||
var helpers = {
|
||||
displayMenuItem: displayMenuItem,
|
||||
buildMetaTag: buildMetaTag,
|
||||
buildLinkTag: buildLinkTag,
|
||||
stringify: stringify,
|
||||
escape: escape,
|
||||
stripTags: stripTags,
|
||||
generateCategoryBackground: generateCategoryBackground,
|
||||
generateChildrenCategories: generateChildrenCategories,
|
||||
generateTopicClass: generateTopicClass,
|
||||
membershipBtn: membershipBtn,
|
||||
spawnPrivilegeStates: spawnPrivilegeStates,
|
||||
localeToHTML: localeToHTML,
|
||||
renderTopicImage: renderTopicImage,
|
||||
renderDigestAvatar: renderDigestAvatar,
|
||||
userAgentIcons: userAgentIcons,
|
||||
buildAvatar: buildAvatar,
|
||||
register: register,
|
||||
displayMenuItem,
|
||||
buildMetaTag,
|
||||
buildLinkTag,
|
||||
stringify,
|
||||
escape,
|
||||
stripTags,
|
||||
generateCategoryBackground,
|
||||
generateChildrenCategories,
|
||||
generateTopicClass,
|
||||
membershipBtn,
|
||||
spawnPrivilegeStates,
|
||||
localeToHTML,
|
||||
renderTopicImage,
|
||||
renderTopicEvents,
|
||||
renderEvents,
|
||||
renderDigestAvatar,
|
||||
userAgentIcons,
|
||||
buildAvatar,
|
||||
register,
|
||||
__escape: identity,
|
||||
};
|
||||
|
||||
@@ -208,6 +210,46 @@
|
||||
return '<img component="user/picture" data-uid="' + topicObj.user.uid + '" src="' + topicObj.user.picture + '" class="user-img" title="' + topicObj.user.username + '" />';
|
||||
}
|
||||
|
||||
function renderTopicEvents(index) {
|
||||
const start = this.posts[index].timestamp;
|
||||
const end = this.posts[index + 1] ? this.posts[index + 1].timestamp : Date.now();
|
||||
const events = this.events.filter(event => event.timestamp >= start && event.timestamp < end);
|
||||
if (!events.length) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return renderEvents.call(this, events);
|
||||
}
|
||||
|
||||
function renderEvents(events) {
|
||||
return events.reduce((html, event) => {
|
||||
html += `<li component="topic/event" class="timeline-event" data-topic-event-id="${event.id}">
|
||||
<div class="timeline-badge">
|
||||
<i class="fa ${event.icon || 'fa-circle'}"></i>
|
||||
</div>
|
||||
<span class="timeline-text">
|
||||
${event.href ? `<a href="${relative_path}${event.href}>${event.text}</a>` : event.text}
|
||||
</span>
|
||||
`;
|
||||
|
||||
if (event.user) {
|
||||
if (!event.user.system) {
|
||||
html += `<span><a href="${relative_path}/user/${event.user.userslug}">${buildAvatar(event.user, 'xs', true)} ${event.user.username}</a></span> `;
|
||||
} else {
|
||||
html += `<span class="timeline-text">[[global:system-user]]</span> `;
|
||||
}
|
||||
}
|
||||
|
||||
html += `<span class="timeago timeline-text" title="${event.timestampISO}"></span>`;
|
||||
|
||||
if (this.privileges.isAdminOrMod) {
|
||||
html += ` <span component="topic/event/delete" data-topic-event-id="{id}" class="timeline-text pointer" title="[[topic:delete-event]]"><i class="fa fa-trash"></i></span>`;
|
||||
}
|
||||
|
||||
return html;
|
||||
}, '');
|
||||
}
|
||||
|
||||
function renderDigestAvatar(block) {
|
||||
if (block.teaser) {
|
||||
if (block.teaser.user.picture) {
|
||||
|
||||
Reference in New Issue
Block a user