refactor: add placeholders on demand

remove emptylines/whitespace from tpls
This commit is contained in:
Barış Soner Uşaklı
2024-06-16 22:56:21 -04:00
parent 461e95d8d6
commit 8f486b1b99
7 changed files with 61 additions and 32 deletions

View File

@@ -104,10 +104,10 @@
"nodebb-plugin-ntfy": "1.7.4", "nodebb-plugin-ntfy": "1.7.4",
"nodebb-plugin-spam-be-gone": "2.2.2", "nodebb-plugin-spam-be-gone": "2.2.2",
"nodebb-rewards-essentials": "1.0.0", "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-lavender": "7.1.8",
"nodebb-theme-peace": "2.2.5", "nodebb-theme-peace": "2.2.5",
"nodebb-theme-persona": "13.3.20", "nodebb-theme-persona": "13.3.21",
"nodebb-widget-essentials": "7.0.16", "nodebb-widget-essentials": "7.0.16",
"nodemailer": "6.9.13", "nodemailer": "6.9.13",
"nprogress": "0.2.0", "nprogress": "0.2.0",

View File

@@ -36,7 +36,7 @@ define('forum/topic/postTools', [
if (!container) { if (!container) {
return; return;
} }
$('[component="topic"]').on('show.bs.dropdown', '.moderator-tools', function () { $('[component="topic"]').on('show.bs.dropdown', '[component="post/tools"]', function () {
const $this = $(this); const $this = $(this);
const dropdownMenu = $this.find('.dropdown-menu'); const dropdownMenu = $this.find('.dropdown-menu');
const { top } = this.getBoundingClientRect(); const { top } = this.getBoundingClientRect();
@@ -45,6 +45,10 @@ define('forum/topic/postTools', [
if (dropdownMenu.attr('data-loaded')) { if (dropdownMenu.attr('data-loaded')) {
return; return;
} }
dropdownMenu.html(helpers.generatePlaceholderWave([
3, 5, 9, 7, 10, 'divider', 10,
]));
const postEl = $this.parents('[data-pid]'); const postEl = $this.parents('[data-pid]');
const pid = postEl.attr('data-pid'); const pid = postEl.attr('data-pid');
const index = parseInt(postEl.attr('data-index'), 10); const index = parseInt(postEl.attr('data-index'), 10);

View File

@@ -8,21 +8,22 @@ define('forum/topic/replies', ['forum/topic/posts', 'hooks', 'alerts', 'api'], f
const post = button.closest('[data-pid]'); const post = button.closest('[data-pid]');
const pid = post.data('pid'); const pid = post.data('pid');
const open = button.find('[component="post/replies/open"]'); 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')) { if (open.attr('loading') !== '1' && open.attr('loaded') !== '1') {
open.addClass('hidden'); open.attr('loading', '1')
loading.removeClass('hidden'); .removeClass('fa-chevron-down')
.addClass('fa-spin fa-spinner');
api.get(`/posts/${pid}/replies`, {}, function (err, { replies }) { api.get(`/posts/${pid}/replies`, {}, function (err, { replies }) {
const postData = replies; const postData = replies;
loading.addClass('hidden'); open.removeAttr('loading')
.attr('loaded', '1')
.removeClass('fa-spin fa-spinner')
.addClass('fa-chevron-up');
if (err) { if (err) {
open.removeClass('hidden');
return alerts.error(err); return alerts.error(err);
} }
close.removeClass('hidden');
postData.forEach((post, index) => { postData.forEach((post, index) => {
if (post) { if (post) {
post.index = index; 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 }); hooks.fire('action:posts.loaded', { posts: postData });
}); });
}); });
} else if (close.is(':not(.hidden)')) { } else if (open.attr('loaded') === '1') {
close.addClass('hidden'); open.removeAttr('loaded')
open.removeClass('hidden'); .removeAttr('loading')
loading.addClass('hidden'); .removeClass('fa-spin fa-spinner fa-chevron-up')
.addClass('fa-chevron-down');
post.find('[component="post/replies"]').slideUp('fast', function () { post.find('[component="post/replies"]').slideUp('fast', function () {
$(this).remove(); $(this).remove();
}); });

View File

@@ -11,7 +11,8 @@ define('forum/topic/threadTools', [
'bootbox', 'bootbox',
'alerts', 'alerts',
'bootstrap', '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 = {}; const ThreadTools = {};
ThreadTools.init = function (tid, topicContainer) { ThreadTools.init = function (tid, topicContainer) {
@@ -211,6 +212,7 @@ define('forum/topic/threadTools', [
if (dropdownMenu.attr('data-loaded')) { if (dropdownMenu.attr('data-loaded')) {
return; return;
} }
dropdownMenu.html(helpers.generatePlaceholderWave([8, 8, 8]));
const data = await socket.emit('topics.loadTopicTools', { tid: ajaxify.data.tid, cid: ajaxify.data.cid }); 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); const html = await app.parseAndTranslate('partials/topic/topic-menu-list', data);
$(dropdownMenu).attr('data-loaded', 'true').html(html); $(dropdownMenu).attr('data-loaded', 'true').html(html);

View File

@@ -25,12 +25,14 @@ module.exports = function (utils, Benchpress, relative_path) {
userAgentIcons, userAgentIcons,
buildAvatar, buildAvatar,
increment, increment,
generateWroteReplied,
generateRepliedTo, generateRepliedTo,
generateWrote, generateWrote,
isoTimeToLocaleString, isoTimeToLocaleString,
shouldHideReplyContainer, shouldHideReplyContainer,
humanReadableNumber, humanReadableNumber,
formattedNumber, formattedNumber,
generatePlaceholderWave,
register, register,
__escape: identity, __escape: identity,
}; };
@@ -295,34 +297,24 @@ module.exports = function (utils, Benchpress, relative_path) {
if (!userObj) { if (!userObj) {
userObj = this; userObj = this;
} }
classNames = classNames || '';
const attributes = new Map([ const attributes = new Map([
['alt', userObj.username],
['title', userObj.username], ['title', userObj.username],
['data-uid', userObj.uid], ['data-uid', userObj.uid],
['loading', 'lazy'], ['class', `avatar ${classNames}${rounded ? ' avatar-rounded' : ''}`],
['aria-label', `[[aria:user-avatar-for, ${userObj.username}]]`],
]); ]);
const styles = [`--avatar-size: ${size};`]; const styles = [`--avatar-size: ${size};`];
const attr2String = attributes => Array.from(attributes).reduce((output, [prop, value]) => { const attr2String = attributes => Array.from(attributes).reduce((output, [prop, value]) => {
output += ` ${prop}="${value}"`; output += ` ${prop}="${value}"`;
return output; return output;
}, ''); }, '');
classNames = classNames || '';
attributes.set('class', `avatar ${classNames}${rounded ? ' avatar-rounded' : ''}`);
let output = ''; let output = '';
if (userObj.picture) { if (userObj.picture) {
attributes.set('component', component || 'avatar/picture'); output += `<img${attr2String(attributes)} alt="${userObj.username}" loading="lazy" component="${component || 'avatar/picture'}" src="${userObj.picture}" style="${styles.join(' ')}" onError="this.remove()" itemprop="image" />`;
output += '<img ' + attr2String(attributes) + ' src="' + userObj.picture + '" style="' + styles.join(' ') + '" onError="this.remove();" itemprop="image" />';
} }
output += `<span${attr2String(attributes)} component="${component || 'avatar/icon'}" style="${styles.join(' ')} background-color: ${userObj['icon:bgColor']}">${userObj['icon:text']}</span>`;
attributes.set('component', component || 'avatar/icon');
styles.push('background-color: ' + userObj['icon:bgColor'] + ';');
output += '<span ' + attr2String(attributes) + ' style="' + styles.join(' ') + '">' + userObj['icon:text'] + '</span>';
return output; return output;
} }
@@ -330,6 +322,13 @@ module.exports = function (utils, Benchpress, relative_path) {
return String(value + parseInt(inc, 10)); 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) { function generateRepliedTo(post, timeagoCutoff) {
const displayname = post.parent && post.parent.displayname ? const displayname = post.parent && post.parent.displayname ?
post.parent.displayname : '[[global:guest]]'; post.parent.displayname : '[[global:guest]]';
@@ -367,6 +366,21 @@ module.exports = function (utils, Benchpress, relative_path) {
return utils.addCommas(number); 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() { function register() {
Object.keys(helpers).forEach(function (helperName) { Object.keys(helpers).forEach(function (helperName) {
Benchpress.registerHelper(helperName, helpers[helperName]); Benchpress.registerHelper(helperName, helpers[helperName]);

View File

@@ -89,7 +89,9 @@ apiController.loadConfig = async function (req) {
size: meta.config.topicThumbSize, size: meta.config.topicThumbSize,
}, },
emailPrompt: meta.config.emailPrompt, emailPrompt: meta.config.emailPrompt,
useragent: req.useragent, useragent: {
isSafari: req.useragent.isSafari,
},
fontawesome: { fontawesome: {
pro: fontawesome_pro, pro: fontawesome_pro,
styles: fontawesome_styles, styles: fontawesome_styles,

View File

@@ -114,7 +114,7 @@ async function compile() {
let files = await plugins.getActive(); let files = await plugins.getActive();
files = await getTemplateDirs(files); files = await getTemplateDirs(files);
files = await getTemplateFiles(files); files = await getTemplateFiles(files);
const minify = process.env.NODE_ENV !== 'development';
await Promise.all(Object.keys(files).map(async (name) => { await Promise.all(Object.keys(files).map(async (name) => {
const filePath = files[name]; const filePath = files[name];
let imported = await fs.promises.readFile(filePath, 'utf8'); let imported = await fs.promises.readFile(filePath, 'utf8');
@@ -122,6 +122,11 @@ async function compile() {
await mkdirp(path.join(viewsPath, path.dirname(name))); 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); await fs.promises.writeFile(path.join(viewsPath, name), imported);
const compiled = await Benchpress.precompile(imported, { filename: name }); const compiled = await Benchpress.precompile(imported, { filename: name });
await fs.promises.writeFile(path.join(viewsPath, name.replace(/\.tpl$/, '.js')), compiled); await fs.promises.writeFile(path.join(viewsPath, name.replace(/\.tpl$/, '.js')), compiled);