mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
refactor: add placeholders on demand
remove emptylines/whitespace from tpls
This commit is contained in:
@@ -104,10 +104,10 @@
|
||||
"nodebb-plugin-ntfy": "1.7.4",
|
||||
"nodebb-plugin-spam-be-gone": "2.2.2",
|
||||
"nodebb-rewards-essentials": "1.0.0",
|
||||
"nodebb-theme-harmony": "1.2.57",
|
||||
"nodebb-theme-harmony": "1.2.58",
|
||||
"nodebb-theme-lavender": "7.1.8",
|
||||
"nodebb-theme-peace": "2.2.5",
|
||||
"nodebb-theme-persona": "13.3.20",
|
||||
"nodebb-theme-persona": "13.3.21",
|
||||
"nodebb-widget-essentials": "7.0.16",
|
||||
"nodemailer": "6.9.13",
|
||||
"nprogress": "0.2.0",
|
||||
|
||||
@@ -36,7 +36,7 @@ define('forum/topic/postTools', [
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
$('[component="topic"]').on('show.bs.dropdown', '.moderator-tools', function () {
|
||||
$('[component="topic"]').on('show.bs.dropdown', '[component="post/tools"]', function () {
|
||||
const $this = $(this);
|
||||
const dropdownMenu = $this.find('.dropdown-menu');
|
||||
const { top } = this.getBoundingClientRect();
|
||||
@@ -45,6 +45,10 @@ define('forum/topic/postTools', [
|
||||
if (dropdownMenu.attr('data-loaded')) {
|
||||
return;
|
||||
}
|
||||
dropdownMenu.html(helpers.generatePlaceholderWave([
|
||||
3, 5, 9, 7, 10, 'divider', 10,
|
||||
]));
|
||||
|
||||
const postEl = $this.parents('[data-pid]');
|
||||
const pid = postEl.attr('data-pid');
|
||||
const index = parseInt(postEl.attr('data-index'), 10);
|
||||
|
||||
@@ -8,21 +8,22 @@ define('forum/topic/replies', ['forum/topic/posts', 'hooks', 'alerts', 'api'], f
|
||||
const post = button.closest('[data-pid]');
|
||||
const pid = post.data('pid');
|
||||
const open = button.find('[component="post/replies/open"]');
|
||||
const loading = button.find('[component="post/replies/loading"]');
|
||||
const close = button.find('[component="post/replies/close"]');
|
||||
|
||||
if (open.is(':not(.hidden)') && loading.is('.hidden')) {
|
||||
open.addClass('hidden');
|
||||
loading.removeClass('hidden');
|
||||
if (open.attr('loading') !== '1' && open.attr('loaded') !== '1') {
|
||||
open.attr('loading', '1')
|
||||
.removeClass('fa-chevron-down')
|
||||
.addClass('fa-spin fa-spinner');
|
||||
|
||||
api.get(`/posts/${pid}/replies`, {}, function (err, { replies }) {
|
||||
const postData = replies;
|
||||
loading.addClass('hidden');
|
||||
open.removeAttr('loading')
|
||||
.attr('loaded', '1')
|
||||
.removeClass('fa-spin fa-spinner')
|
||||
.addClass('fa-chevron-up');
|
||||
if (err) {
|
||||
open.removeClass('hidden');
|
||||
return alerts.error(err);
|
||||
}
|
||||
|
||||
close.removeClass('hidden');
|
||||
postData.forEach((post, index) => {
|
||||
if (post) {
|
||||
post.index = index;
|
||||
@@ -50,10 +51,11 @@ define('forum/topic/replies', ['forum/topic/posts', 'hooks', 'alerts', 'api'], f
|
||||
hooks.fire('action:posts.loaded', { posts: postData });
|
||||
});
|
||||
});
|
||||
} else if (close.is(':not(.hidden)')) {
|
||||
close.addClass('hidden');
|
||||
open.removeClass('hidden');
|
||||
loading.addClass('hidden');
|
||||
} else if (open.attr('loaded') === '1') {
|
||||
open.removeAttr('loaded')
|
||||
.removeAttr('loading')
|
||||
.removeClass('fa-spin fa-spinner fa-chevron-up')
|
||||
.addClass('fa-chevron-down');
|
||||
post.find('[component="post/replies"]').slideUp('fast', function () {
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
@@ -11,7 +11,8 @@ define('forum/topic/threadTools', [
|
||||
'bootbox',
|
||||
'alerts',
|
||||
'bootstrap',
|
||||
], function (components, translator, handleBack, posts, api, hooks, bootbox, alerts, bootstrap) {
|
||||
'helpers',
|
||||
], function (components, translator, handleBack, posts, api, hooks, bootbox, alerts, bootstrap, helpers) {
|
||||
const ThreadTools = {};
|
||||
|
||||
ThreadTools.init = function (tid, topicContainer) {
|
||||
@@ -211,6 +212,7 @@ define('forum/topic/threadTools', [
|
||||
if (dropdownMenu.attr('data-loaded')) {
|
||||
return;
|
||||
}
|
||||
dropdownMenu.html(helpers.generatePlaceholderWave([8, 8, 8]));
|
||||
const data = await socket.emit('topics.loadTopicTools', { tid: ajaxify.data.tid, cid: ajaxify.data.cid });
|
||||
const html = await app.parseAndTranslate('partials/topic/topic-menu-list', data);
|
||||
$(dropdownMenu).attr('data-loaded', 'true').html(html);
|
||||
|
||||
@@ -25,12 +25,14 @@ module.exports = function (utils, Benchpress, relative_path) {
|
||||
userAgentIcons,
|
||||
buildAvatar,
|
||||
increment,
|
||||
generateWroteReplied,
|
||||
generateRepliedTo,
|
||||
generateWrote,
|
||||
isoTimeToLocaleString,
|
||||
shouldHideReplyContainer,
|
||||
humanReadableNumber,
|
||||
formattedNumber,
|
||||
generatePlaceholderWave,
|
||||
register,
|
||||
__escape: identity,
|
||||
};
|
||||
@@ -295,34 +297,24 @@ module.exports = function (utils, Benchpress, relative_path) {
|
||||
if (!userObj) {
|
||||
userObj = this;
|
||||
}
|
||||
|
||||
classNames = classNames || '';
|
||||
const attributes = new Map([
|
||||
['alt', userObj.username],
|
||||
['title', userObj.username],
|
||||
['data-uid', userObj.uid],
|
||||
['loading', 'lazy'],
|
||||
['aria-label', `[[aria:user-avatar-for, ${userObj.username}]]`],
|
||||
['class', `avatar ${classNames}${rounded ? ' avatar-rounded' : ''}`],
|
||||
]);
|
||||
const styles = [`--avatar-size: ${size};`];
|
||||
const attr2String = attributes => Array.from(attributes).reduce((output, [prop, value]) => {
|
||||
output += ` ${prop}="${value}"`;
|
||||
return output;
|
||||
}, '');
|
||||
classNames = classNames || '';
|
||||
|
||||
attributes.set('class', `avatar ${classNames}${rounded ? ' avatar-rounded' : ''}`);
|
||||
|
||||
let output = '';
|
||||
|
||||
if (userObj.picture) {
|
||||
attributes.set('component', component || 'avatar/picture');
|
||||
output += '<img ' + attr2String(attributes) + ' src="' + userObj.picture + '" style="' + styles.join(' ') + '" onError="this.remove();" itemprop="image" />';
|
||||
output += `<img${attr2String(attributes)} alt="${userObj.username}" loading="lazy" component="${component || 'avatar/picture'}" src="${userObj.picture}" style="${styles.join(' ')}" onError="this.remove()" itemprop="image" />`;
|
||||
}
|
||||
|
||||
attributes.set('component', component || 'avatar/icon');
|
||||
styles.push('background-color: ' + userObj['icon:bgColor'] + ';');
|
||||
output += '<span ' + attr2String(attributes) + ' style="' + styles.join(' ') + '">' + userObj['icon:text'] + '</span>';
|
||||
|
||||
output += `<span${attr2String(attributes)} component="${component || 'avatar/icon'}" style="${styles.join(' ')} background-color: ${userObj['icon:bgColor']}">${userObj['icon:text']}</span>`;
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -330,6 +322,13 @@ module.exports = function (utils, Benchpress, relative_path) {
|
||||
return String(value + parseInt(inc, 10));
|
||||
}
|
||||
|
||||
function generateWroteReplied(post, timeagoCutoff) {
|
||||
if (post.toPid) {
|
||||
return generateRepliedTo(post, timeagoCutoff);
|
||||
}
|
||||
return generateWrote(post, timeagoCutoff);
|
||||
}
|
||||
|
||||
function generateRepliedTo(post, timeagoCutoff) {
|
||||
const displayname = post.parent && post.parent.displayname ?
|
||||
post.parent.displayname : '[[global:guest]]';
|
||||
@@ -367,6 +366,21 @@ module.exports = function (utils, Benchpress, relative_path) {
|
||||
return utils.addCommas(number);
|
||||
}
|
||||
|
||||
function generatePlaceholderWave(items) {
|
||||
const html = items.map((i) => {
|
||||
if (i === 'divider') {
|
||||
return '<li class="dropdown-divider"></li>';
|
||||
}
|
||||
return `
|
||||
<li class="dropdown-item placeholder-wave">
|
||||
<div class="placeholder" style="width: 20px;"></div>
|
||||
<div class="placeholder col-${i}"></div>
|
||||
</li>`;
|
||||
});
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function register() {
|
||||
Object.keys(helpers).forEach(function (helperName) {
|
||||
Benchpress.registerHelper(helperName, helpers[helperName]);
|
||||
|
||||
@@ -89,7 +89,9 @@ apiController.loadConfig = async function (req) {
|
||||
size: meta.config.topicThumbSize,
|
||||
},
|
||||
emailPrompt: meta.config.emailPrompt,
|
||||
useragent: req.useragent,
|
||||
useragent: {
|
||||
isSafari: req.useragent.isSafari,
|
||||
},
|
||||
fontawesome: {
|
||||
pro: fontawesome_pro,
|
||||
styles: fontawesome_styles,
|
||||
|
||||
@@ -114,7 +114,7 @@ async function compile() {
|
||||
let files = await plugins.getActive();
|
||||
files = await getTemplateDirs(files);
|
||||
files = await getTemplateFiles(files);
|
||||
|
||||
const minify = process.env.NODE_ENV !== 'development';
|
||||
await Promise.all(Object.keys(files).map(async (name) => {
|
||||
const filePath = files[name];
|
||||
let imported = await fs.promises.readFile(filePath, 'utf8');
|
||||
@@ -122,6 +122,11 @@ async function compile() {
|
||||
|
||||
await mkdirp(path.join(viewsPath, path.dirname(name)));
|
||||
|
||||
// remove empty lines and whitespace
|
||||
if (minify) {
|
||||
imported = imported.split('\n').map(line => line.trim()).filter(Boolean).join('\n');
|
||||
}
|
||||
|
||||
await fs.promises.writeFile(path.join(viewsPath, name), imported);
|
||||
const compiled = await Benchpress.precompile(imported, { filename: name });
|
||||
await fs.promises.writeFile(path.join(viewsPath, name.replace(/\.tpl$/, '.js')), compiled);
|
||||
|
||||
Reference in New Issue
Block a user