DEV: Convert helpers into plain functions (#22385)

Since 0fa92529ed, helpers can now be implemented as plain JS functions. This makes them much easier to write/read, and also makes them usable in `<template>` gjs files.
This commit is contained in:
Jarek Radosz 2023-07-20 20:45:40 +02:00 committed by GitHub
parent 238d71bcad
commit 9bbd5efbec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 174 additions and 162 deletions

View File

@ -5,7 +5,7 @@ import discourseComputed from "discourse-common/utils/decorators";
import { observes } from "@ember-decorators/object";
import I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality";
import { POPULAR_THEMES } from "discourse-common/helpers/popular-themes";
import { POPULAR_THEMES } from "discourse-common/lib/popular-themes";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { action, set } from "@ember/object";

View File

@ -1,4 +1,6 @@
import I18n from "I18n";
import { htmlHelper } from "discourse-common/lib/helpers";
import { htmlSafe } from "@ember/template";
export default htmlHelper((key, params) => I18n.t(key, params.hash));
export default function boundI18n(key, options) {
return htmlSafe(I18n.t(key, options));
}

View File

@ -1,14 +1,12 @@
import { htmlHelper } from "discourse-common/lib/helpers";
import { htmlSafe } from "@ember/template";
const validDirections = ["top", "right", "bottom", "left"];
export default htmlHelper((color, direction) => {
const borderColor = `#${color}`;
export default function borderColor(color, direction) {
const borderProperty =
direction && validDirections.includes(direction)
? `border-${direction}-color`
: "border-color";
return `${borderProperty}: ${borderColor} `;
});
return htmlSafe(`${borderProperty}: #${color} `);
}

View File

@ -1,11 +1,11 @@
import { htmlSafe } from "@ember/template";
import { avatarImg } from "discourse-common/lib/avatar-utils";
import { htmlHelper } from "discourse-common/lib/helpers";
import { isEmpty } from "@ember/utils";
export default htmlHelper((avatarTemplate, size) => {
export default function boundAvatarTemplate(avatarTemplate, size) {
if (isEmpty(avatarTemplate)) {
return "<div class='avatar-placeholder'></div>";
return htmlSafe("<div class='avatar-placeholder'></div>");
} else {
return avatarImg({ size, avatarTemplate });
return htmlSafe(avatarImg({ size, avatarTemplate }));
}
});
}

View File

@ -1,14 +1,16 @@
import { htmlSafe } from "@ember/template";
import { addExtraUserClasses } from "discourse/helpers/user-avatar";
import { avatarImg } from "discourse-common/lib/avatar-utils";
import { get } from "@ember/object";
import { htmlHelper } from "discourse-common/lib/helpers";
import { isEmpty } from "@ember/utils";
export default htmlHelper((user, size) => {
export default function boundAvatar(user, size) {
if (isEmpty(user)) {
return "<div class='avatar-placeholder'></div>";
return htmlSafe("<div class='avatar-placeholder'></div>");
}
const avatarTemplate = get(user, "avatar_template");
return avatarImg(addExtraUserClasses(user, { size, avatarTemplate }));
});
return htmlSafe(
avatarImg(
addExtraUserClasses(user, { size, avatarTemplate: user.avatar_template })
)
);
}

View File

@ -1,4 +1 @@
import { categoryLinkHTML } from "discourse/helpers/category-link";
import { htmlHelper } from "discourse-common/lib/helpers";
export default htmlHelper(categoryLinkHTML);
export { categoryLinkHTML as default } from "discourse/helpers/category-link";

View File

@ -1,6 +1,11 @@
import { htmlSafe } from "@ember/template";
import { autoUpdatingRelativeAge } from "discourse/lib/formatter";
import { htmlHelper } from "discourse-common/lib/helpers";
export default htmlHelper((dt) =>
autoUpdatingRelativeAge(new Date(dt), { format: "medium", title: true })
);
export default function boundDate(dt) {
return htmlSafe(
autoUpdatingRelativeAge(new Date(dt), {
format: "medium",
title: true,
})
);
}

View File

@ -1,3 +1,9 @@
import { htmlHelper } from "discourse-common/lib/helpers";
import deprecated from "discourse-common/lib/deprecated";
export default htmlHelper((str) => str[0].toUpperCase() + str.slice(1));
export default function capitalizeString(str) {
deprecated("capitalize-string helper is deprecated", {
id: "discourse.capitalize-string",
since: "3.1.0.beta6",
});
return str[0].toUpperCase() + str.slice(1);
}

View File

@ -1,3 +1,5 @@
import { htmlHelper } from "discourse-common/lib/helpers";
import { htmlSafe } from "@ember/template";
export default htmlHelper((color) => `--category-color: #${color};`);
export default function categoryColorVariable(color) {
return htmlSafe(`--category-color: #${color};`);
}

View File

@ -1,8 +1,7 @@
import { helper } from "@ember/component/helper";
function concatClass(args) {
export default function concatClass(...args) {
const classes = args.compact().join(" ");
return classes.length ? classes : undefined;
}
export default helper(concatClass);
if (classes.length) {
return classes;
}
}

View File

@ -1,4 +1,6 @@
import { htmlHelper } from "discourse-common/lib/helpers";
import { htmlSafe } from "@ember/template";
import { isEmpty } from "@ember/utils";
export default htmlHelper((str) => (isEmpty(str) ? "&mdash;" : str));
export default function dashIfEmpty(str) {
return isEmpty(str) ? htmlSafe("&mdash;") : str;
}

View File

@ -1,8 +1,5 @@
import Helper from "@ember/component/helper";
import { dasherize as emberDasherize } from "@ember/string";
function dasherize([value]) {
return emberDasherize((value || "").replace(".", "-"));
export default function dasherize(value = "") {
return emberDasherize(value.replace(".", "-"));
}
export default Helper.helper(dasherize);

View File

@ -1,20 +1,17 @@
import Helper from "@ember/component/helper";
import { get } from "@ember/object";
export function formatCurrency([reviewable, fieldId]) {
export default function editableValue(reviewable, fieldId) {
// The field `category_id` corresponds to `category`
if (fieldId === "category_id") {
fieldId = "category.id";
}
let value = get(reviewable, fieldId);
const value = get(reviewable, fieldId);
// If it's an array, say tags, make a copy so we aren't mutating the original
if (Array.isArray(value)) {
value = value.slice(0);
return value.slice(0);
}
return value;
}
export default Helper.helper(formatCurrency);

View File

@ -1,16 +1,15 @@
import { convertIconClass, iconHTML } from "discourse-common/lib/icon-library";
import { htmlHelper } from "discourse-common/lib/helpers";
import { isEmpty } from "@ember/utils";
import { htmlSafe } from "@ember/template";
export default htmlHelper(function ({ icon, image }) {
export default function iconOrImage({ icon, image }) {
if (!isEmpty(image)) {
return `<img src='${image}'>`;
return htmlSafe(`<img src='${image}'>`);
}
if (isEmpty(icon)) {
return "";
}
icon = convertIconClass(icon);
return iconHTML(icon);
});
return htmlSafe(iconHTML(convertIconClass(icon)));
}

View File

@ -1,10 +1,14 @@
import { registerHelper } from "discourse-common/lib/helpers";
import deprecated from "discourse-common/lib/deprecated";
import { relativeAge } from "discourse/lib/formatter";
registerHelper("inline-date", function ([dt]) {
// TODO: Remove this in 1.13 or greater
export default function inlineDate(dt) {
deprecated("inline-date helper is deprecated", {
id: "discourse.inline-date",
since: "3.1.0.beta6",
});
if (dt.value) {
dt = dt.value();
}
return relativeAge(new Date(dt));
});
}

View File

@ -1,17 +1,15 @@
import { htmlHelper } from "discourse-common/lib/helpers";
import { htmlSafe } from "@ember/template";
function renderSpinner(cssClass) {
export function renderSpinner(cssClass) {
let html = "<div class='spinner";
if (cssClass) {
html += " " + cssClass;
}
return html + "'></div>";
}
let spinnerHTML = renderSpinner();
export default htmlHelper((params) => {
const hash = params.hash;
return renderSpinner(hash && hash.size ? hash.size : undefined);
});
export const spinnerHTML = renderSpinner();
export { spinnerHTML, renderSpinner };
export default function loadingSpinner({ size } = {}) {
return htmlSafe(renderSpinner(size));
}

View File

@ -1,5 +1,5 @@
import I18n from "I18n";
import { htmlHelper } from "discourse-common/lib/helpers";
import { htmlSafe } from "@ember/template";
const TITLE_SUBS = {
all: "all_time",
@ -9,68 +9,69 @@ const TITLE_SUBS = {
daily: "today",
};
export default htmlHelper((period, options) => {
export default function periodTitle(period, { showDateRange, fullDay } = {}) {
const title = I18n.t("filters.top." + (TITLE_SUBS[period] || "this_week"));
if (options.hash.showDateRange) {
let dateString = "";
let finish;
if (options.hash.fullDay) {
finish = moment().utc().subtract(1, "days");
} else {
finish = moment();
}
switch (period) {
case "yearly":
dateString =
finish
.clone()
.subtract(1, "year")
.format(I18n.t("dates.long_with_year_no_time")) +
" " +
finish.format(I18n.t("dates.long_with_year_no_time"));
break;
case "quarterly":
dateString =
finish
.clone()
.subtract(3, "month")
.format(I18n.t("dates.long_no_year_no_time")) +
" " +
finish.format(I18n.t("dates.long_no_year_no_time"));
break;
case "weekly":
let start;
if (options.hash.fullDay) {
start = finish.clone().subtract(1, "week");
} else {
start = finish.clone().subtract(6, "days");
}
dateString =
start.format(I18n.t("dates.long_no_year_no_time")) +
" " +
finish.format(I18n.t("dates.long_no_year_no_time"));
break;
case "monthly":
dateString =
finish
.clone()
.subtract(1, "month")
.format(I18n.t("dates.long_no_year_no_time")) +
" " +
finish.format(I18n.t("dates.long_no_year_no_time"));
break;
case "daily":
dateString = finish
.clone()
.format(I18n.t("dates.full_no_year_no_time"));
break;
}
return `<span class="date-section">${title}</span><span class='top-date-string'>${dateString}</span>`;
} else {
return title;
if (!showDateRange) {
return htmlSafe(title);
}
});
let dateString = "";
let finish;
if (fullDay) {
finish = moment().utc().subtract(1, "days");
} else {
finish = moment();
}
switch (period) {
case "yearly":
dateString =
finish
.clone()
.subtract(1, "year")
.format(I18n.t("dates.long_with_year_no_time")) +
" " +
finish.format(I18n.t("dates.long_with_year_no_time"));
break;
case "quarterly":
dateString =
finish
.clone()
.subtract(3, "month")
.format(I18n.t("dates.long_no_year_no_time")) +
" " +
finish.format(I18n.t("dates.long_no_year_no_time"));
break;
case "weekly":
let start;
if (fullDay) {
start = finish.clone().subtract(1, "week");
} else {
start = finish.clone().subtract(6, "days");
}
dateString =
start.format(I18n.t("dates.long_no_year_no_time")) +
" " +
finish.format(I18n.t("dates.long_no_year_no_time"));
break;
case "monthly":
dateString =
finish
.clone()
.subtract(1, "month")
.format(I18n.t("dates.long_no_year_no_time")) +
" " +
finish.format(I18n.t("dates.long_no_year_no_time"));
break;
case "daily":
dateString = finish.clone().format(I18n.t("dates.full_no_year_no_time"));
break;
}
return htmlSafe(
`<span class="date-section">${title}</span><span class='top-date-string'>${dateString}</span>`
);
}

View File

@ -1,14 +1,16 @@
import { EDITED } from "discourse/models/reviewable-history";
import I18n from "I18n";
import { htmlHelper } from "discourse-common/lib/helpers";
import { htmlStatus } from "discourse/helpers/reviewable-status";
import { iconHTML } from "discourse-common/lib/icon-library";
import { htmlSafe } from "@ember/template";
export default htmlHelper(function (rh) {
export default function reviewableHistoryDescription(rh) {
switch (rh.reviewable_history_type) {
case EDITED:
return iconHTML("pencil-alt") + " " + I18n.t("review.history.edited");
return htmlSafe(
iconHTML("pencil-alt") + " " + I18n.t("review.history.edited")
);
default:
return htmlStatus(rh.status);
return htmlSafe(htmlStatus(rh.status));
}
});
}

View File

@ -6,8 +6,8 @@ import {
REJECTED,
} from "discourse/models/reviewable";
import I18n from "I18n";
import { htmlHelper } from "discourse-common/lib/helpers";
import { iconHTML } from "discourse-common/lib/icon-library";
import { htmlSafe } from "@ember/template";
function dataFor(status, type) {
switch (status) {
@ -74,13 +74,13 @@ export function htmlStatus(status, type) {
let icon = data.icon ? iconHTML(data.icon) : "";
return `
<span class="${data.cssClass || data.name}">
${icon}
${I18n.t("review.statuses." + data.name + ".title")}
</span>
<span class="${data.cssClass || data.name}">
${icon}
${I18n.t("review.statuses." + data.name + ".title")}
</span>
`;
}
export default htmlHelper((status, type) => {
return htmlStatus(status, type);
});
export default function (status, type) {
return htmlSafe(htmlStatus(status, type));
}

View File

@ -1,27 +1,28 @@
import I18n from "I18n";
import { escapeExpression } from "discourse/lib/utilities";
import { htmlHelper } from "discourse-common/lib/helpers";
import { iconHTML } from "discourse-common/lib/icon-library";
import { htmlSafe } from "@ember/template";
export default htmlHelper((user, args) => {
export default function userStatus(user, { currentUser } = {}) {
if (!user) {
return;
}
const name = escapeExpression(user.get("name"));
let currentUser;
if (args && args.hash) {
currentUser = args.hash.currentUser;
const name = escapeExpression(user.name);
if (user.admin && currentUser?.staff) {
return htmlSafe(
iconHTML("shield-alt", {
label: I18n.t("user.admin", { user: name }),
})
);
}
if (currentUser && user.get("admin") && currentUser.get("staff")) {
return iconHTML("shield-alt", {
label: I18n.t("user.admin", { user: name }),
});
if (user.moderator) {
return htmlSafe(
iconHTML("shield-alt", {
label: I18n.t("user.moderator", { user: name }),
})
);
}
if (user.get("moderator")) {
return iconHTML("shield-alt", {
label: I18n.t("user.moderator", { user: name }),
});
}
});
}