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 { observes } from "@ember-decorators/object";
import I18n from "I18n"; import I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality"; 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 { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
import { action, set } from "@ember/object"; import { action, set } from "@ember/object";

View File

@ -1,4 +1,6 @@
import I18n from "I18n"; 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"]; const validDirections = ["top", "right", "bottom", "left"];
export default htmlHelper((color, direction) => { export default function borderColor(color, direction) {
const borderColor = `#${color}`;
const borderProperty = const borderProperty =
direction && validDirections.includes(direction) direction && validDirections.includes(direction)
? `border-${direction}-color` ? `border-${direction}-color`
: "border-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 { avatarImg } from "discourse-common/lib/avatar-utils";
import { htmlHelper } from "discourse-common/lib/helpers";
import { isEmpty } from "@ember/utils"; import { isEmpty } from "@ember/utils";
export default htmlHelper((avatarTemplate, size) => { export default function boundAvatarTemplate(avatarTemplate, size) {
if (isEmpty(avatarTemplate)) { if (isEmpty(avatarTemplate)) {
return "<div class='avatar-placeholder'></div>"; return htmlSafe("<div class='avatar-placeholder'></div>");
} else { } 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 { addExtraUserClasses } from "discourse/helpers/user-avatar";
import { avatarImg } from "discourse-common/lib/avatar-utils"; 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"; import { isEmpty } from "@ember/utils";
export default htmlHelper((user, size) => { export default function boundAvatar(user, size) {
if (isEmpty(user)) { if (isEmpty(user)) {
return "<div class='avatar-placeholder'></div>"; return htmlSafe("<div class='avatar-placeholder'></div>");
} }
const avatarTemplate = get(user, "avatar_template"); return htmlSafe(
return avatarImg(addExtraUserClasses(user, { size, avatarTemplate })); avatarImg(
}); addExtraUserClasses(user, { size, avatarTemplate: user.avatar_template })
)
);
}

View File

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

View File

@ -1,6 +1,11 @@
import { htmlSafe } from "@ember/template";
import { autoUpdatingRelativeAge } from "discourse/lib/formatter"; import { autoUpdatingRelativeAge } from "discourse/lib/formatter";
import { htmlHelper } from "discourse-common/lib/helpers";
export default htmlHelper((dt) => export default function boundDate(dt) {
autoUpdatingRelativeAge(new Date(dt), { format: "medium", title: true }) 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"; export default function concatClass(...args) {
function concatClass(args) {
const classes = args.compact().join(" "); 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"; 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"; import { dasherize as emberDasherize } from "@ember/string";
function dasherize([value]) { export default function dasherize(value = "") {
return emberDasherize((value || "").replace(".", "-")); 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"; import { get } from "@ember/object";
export function formatCurrency([reviewable, fieldId]) { export default function editableValue(reviewable, fieldId) {
// The field `category_id` corresponds to `category` // The field `category_id` corresponds to `category`
if (fieldId === "category_id") { if (fieldId === "category_id") {
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 it's an array, say tags, make a copy so we aren't mutating the original
if (Array.isArray(value)) { if (Array.isArray(value)) {
value = value.slice(0); return value.slice(0);
} }
return value; return value;
} }
export default Helper.helper(formatCurrency);

View File

@ -1,16 +1,15 @@
import { convertIconClass, iconHTML } from "discourse-common/lib/icon-library"; import { convertIconClass, iconHTML } from "discourse-common/lib/icon-library";
import { htmlHelper } from "discourse-common/lib/helpers";
import { isEmpty } from "@ember/utils"; 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)) { if (!isEmpty(image)) {
return `<img src='${image}'>`; return htmlSafe(`<img src='${image}'>`);
} }
if (isEmpty(icon)) { if (isEmpty(icon)) {
return ""; return "";
} }
icon = convertIconClass(icon); return htmlSafe(iconHTML(convertIconClass(icon)));
return iconHTML(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"; import { relativeAge } from "discourse/lib/formatter";
registerHelper("inline-date", function ([dt]) { export default function inlineDate(dt) {
// TODO: Remove this in 1.13 or greater deprecated("inline-date helper is deprecated", {
id: "discourse.inline-date",
since: "3.1.0.beta6",
});
if (dt.value) { if (dt.value) {
dt = dt.value(); dt = dt.value();
} }
return relativeAge(new Date(dt)); 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"; let html = "<div class='spinner";
if (cssClass) { if (cssClass) {
html += " " + cssClass; html += " " + cssClass;
} }
return html + "'></div>"; return html + "'></div>";
} }
let spinnerHTML = renderSpinner();
export default htmlHelper((params) => { export const spinnerHTML = renderSpinner();
const hash = params.hash;
return renderSpinner(hash && hash.size ? hash.size : undefined);
});
export { spinnerHTML, renderSpinner }; export default function loadingSpinner({ size } = {}) {
return htmlSafe(renderSpinner(size));
}

View File

@ -1,5 +1,5 @@
import I18n from "I18n"; import I18n from "I18n";
import { htmlHelper } from "discourse-common/lib/helpers"; import { htmlSafe } from "@ember/template";
const TITLE_SUBS = { const TITLE_SUBS = {
all: "all_time", all: "all_time",
@ -9,13 +9,17 @@ const TITLE_SUBS = {
daily: "today", 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")); const title = I18n.t("filters.top." + (TITLE_SUBS[period] || "this_week"));
if (options.hash.showDateRange) {
if (!showDateRange) {
return htmlSafe(title);
}
let dateString = ""; let dateString = "";
let finish; let finish;
if (options.hash.fullDay) { if (fullDay) {
finish = moment().utc().subtract(1, "days"); finish = moment().utc().subtract(1, "days");
} else { } else {
finish = moment(); finish = moment();
@ -42,7 +46,7 @@ export default htmlHelper((period, options) => {
break; break;
case "weekly": case "weekly":
let start; let start;
if (options.hash.fullDay) { if (fullDay) {
start = finish.clone().subtract(1, "week"); start = finish.clone().subtract(1, "week");
} else { } else {
start = finish.clone().subtract(6, "days"); start = finish.clone().subtract(6, "days");
@ -63,14 +67,11 @@ export default htmlHelper((period, options) => {
finish.format(I18n.t("dates.long_no_year_no_time")); finish.format(I18n.t("dates.long_no_year_no_time"));
break; break;
case "daily": case "daily":
dateString = finish dateString = finish.clone().format(I18n.t("dates.full_no_year_no_time"));
.clone()
.format(I18n.t("dates.full_no_year_no_time"));
break; break;
} }
return `<span class="date-section">${title}</span><span class='top-date-string'>${dateString}</span>`; return htmlSafe(
} else { `<span class="date-section">${title}</span><span class='top-date-string'>${dateString}</span>`
return title; );
} }
});

View File

@ -1,14 +1,16 @@
import { EDITED } from "discourse/models/reviewable-history"; import { EDITED } from "discourse/models/reviewable-history";
import I18n from "I18n"; import I18n from "I18n";
import { htmlHelper } from "discourse-common/lib/helpers";
import { htmlStatus } from "discourse/helpers/reviewable-status"; import { htmlStatus } from "discourse/helpers/reviewable-status";
import { iconHTML } from "discourse-common/lib/icon-library"; 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) { switch (rh.reviewable_history_type) {
case EDITED: case EDITED:
return iconHTML("pencil-alt") + " " + I18n.t("review.history.edited"); return htmlSafe(
iconHTML("pencil-alt") + " " + I18n.t("review.history.edited")
);
default: default:
return htmlStatus(rh.status); return htmlSafe(htmlStatus(rh.status));
} }
}); }

View File

@ -6,8 +6,8 @@ import {
REJECTED, REJECTED,
} from "discourse/models/reviewable"; } from "discourse/models/reviewable";
import I18n from "I18n"; import I18n from "I18n";
import { htmlHelper } from "discourse-common/lib/helpers";
import { iconHTML } from "discourse-common/lib/icon-library"; import { iconHTML } from "discourse-common/lib/icon-library";
import { htmlSafe } from "@ember/template";
function dataFor(status, type) { function dataFor(status, type) {
switch (status) { switch (status) {
@ -81,6 +81,6 @@ export function htmlStatus(status, type) {
`; `;
} }
export default htmlHelper((status, type) => { export default function (status, type) {
return htmlStatus(status, type); return htmlSafe(htmlStatus(status, type));
}); }

View File

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