diff --git a/app/assets/javascripts/discourse-common/addon/lib/discourse-template-map.js b/app/assets/javascripts/discourse-common/addon/lib/discourse-template-map.js
new file mode 100644
index 0000000000..51ec2c6c3c
--- /dev/null
+++ b/app/assets/javascripts/discourse-common/addon/lib/discourse-template-map.js
@@ -0,0 +1,102 @@
+const pluginRegex = /^discourse\/plugins\/([^\/]+)\/(.*)$/;
+const themeRegex = /^discourse\/theme-([^\/]+)\/(.*)$/;
+
+function appendToCache(cache, key, value) {
+ let cachedValue = cache.get(key);
+ cachedValue ??= [];
+ cachedValue.push(value);
+ cache.set(key, cachedValue);
+}
+
+const NAMESPACES = ["discourse/", "wizard/", "admin/"];
+
+function isInRecognisedNamespace(moduleName) {
+ for (const ns of NAMESPACES) {
+ if (moduleName.startsWith(ns)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+function isTemplate(moduleName) {
+ return moduleName.includes("/templates/");
+}
+
+/**
+ * This class provides takes set of core/plugin/theme modules, finds the template modules,
+ * and makes an efficient lookup table for the resolver to use. It takes care of sourcing
+ * component/route templates from themes/plugins, and also handles template overrides.
+ */
+class DiscourseTemplateMap {
+ coreTemplates = new Map();
+ pluginTemplates = new Map();
+ themeTemplates = new Map();
+ prioritizedCaches = [
+ this.themeTemplates,
+ this.pluginTemplates,
+ this.coreTemplates,
+ ];
+
+ /**
+ * Reset the TemplateMap to use the supplied module names. It is expected that the list
+ * will be generated using `Object.keys(requirejs.entries)`.
+ */
+ setModuleNames(moduleNames) {
+ this.coreTemplates.clear();
+ this.pluginTemplates.clear();
+ this.themeTemplates.clear();
+ for (const moduleName of moduleNames) {
+ if (isInRecognisedNamespace(moduleName) && isTemplate(moduleName)) {
+ this.#add(moduleName);
+ }
+ }
+ }
+
+ #add(originalPath) {
+ let path = originalPath;
+
+ let pluginMatch, themeMatch, cache;
+ if ((pluginMatch = path.match(pluginRegex))) {
+ path = pluginMatch[2];
+ cache = this.pluginTemplates;
+ } else if ((themeMatch = path.match(themeRegex))) {
+ path = themeMatch[2];
+ cache = this.themeTemplates;
+ } else {
+ cache = this.coreTemplates;
+ }
+
+ path = path.replace(/^discourse\/templates\//, "");
+
+ appendToCache(cache, path, originalPath);
+ }
+
+ /**
+ * Resolve a template name to a module name, taking into account
+ * theme/plugin namespaces and overrides.
+ */
+ resolve(name) {
+ for (const cache of this.prioritizedCaches) {
+ const val = cache.get(name);
+ if (val) {
+ return val[val.length - 1];
+ }
+ }
+ }
+
+ /**
+ * List all available template keys, after theme/plugin namespaces have
+ * been stripped.
+ */
+ keys() {
+ const uniqueKeys = new Set([
+ ...this.coreTemplates.keys(),
+ ...this.pluginTemplates.keys(),
+ ...this.themeTemplates.keys(),
+ ]);
+ return [...uniqueKeys];
+ }
+}
+
+export default new DiscourseTemplateMap();
diff --git a/app/assets/javascripts/discourse-common/addon/lib/raw-templates.js b/app/assets/javascripts/discourse-common/addon/lib/raw-templates.js
index 2b88dfc82b..b979d7c8ff 100644
--- a/app/assets/javascripts/discourse-common/addon/lib/raw-templates.js
+++ b/app/assets/javascripts/discourse-common/addon/lib/raw-templates.js
@@ -32,11 +32,25 @@ export function findRawTemplate(name) {
export function buildRawConnectorCache(findOutlets) {
let result = {};
- findOutlets(__DISCOURSE_RAW_TEMPLATES, (outletName, resource) => {
- result[outletName] = result[outletName] || [];
- result[outletName].push({
- template: __DISCOURSE_RAW_TEMPLATES[resource],
- });
- });
+ findOutlets(
+ Object.keys(__DISCOURSE_RAW_TEMPLATES),
+ (outletName, resource) => {
+ result[outletName] ??= [];
+ result[outletName].push({
+ template: __DISCOURSE_RAW_TEMPLATES[resource],
+ });
+ }
+ );
return result;
}
+
+export function eagerLoadRawTemplateModules() {
+ for (const [key, value] of Object.entries(requirejs.entries)) {
+ if (
+ key.includes("/templates/") &&
+ value.deps.includes("discourse-common/lib/raw-templates")
+ ) {
+ require(key);
+ }
+ }
+}
diff --git a/app/assets/javascripts/discourse-common/addon/resolver.js b/app/assets/javascripts/discourse-common/addon/resolver.js
index 079161f604..45c0655643 100644
--- a/app/assets/javascripts/discourse-common/addon/resolver.js
+++ b/app/assets/javascripts/discourse-common/addon/resolver.js
@@ -1,10 +1,10 @@
-import Ember from "ember";
import { dasherize, decamelize } from "@ember/string";
import deprecated from "discourse-common/lib/deprecated";
import { findHelper } from "discourse-common/lib/helpers";
import SuffixTrie from "discourse-common/lib/suffix-trie";
import Resolver from "ember-resolver";
import { buildResolver as buildLegacyResolver } from "discourse-common/lib/legacy-resolver";
+import DiscourseTemplateMap from "discourse-common/lib/discourse-template-map";
let _options = {};
let moduleSuffixTrie = null;
@@ -287,21 +287,19 @@ export function buildResolver(baseName) {
resolveTemplate(parsedName) {
return (
- this.findPluginMobileTemplate(parsedName) ||
- this.findPluginTemplate(parsedName) ||
this.findMobileTemplate(parsedName) ||
this.findTemplate(parsedName) ||
this.findAdminTemplate(parsedName) ||
this.findWizardTemplate(parsedName) ||
this.findLoadingTemplate(parsedName) ||
this.findConnectorTemplate(parsedName) ||
- Ember.TEMPLATES.not_found
+ this.discourseTemplateModule("not_found")
);
}
findLoadingTemplate(parsedName) {
if (parsedName.fullNameWithoutType.match(/loading$/)) {
- return Ember.TEMPLATES.loading;
+ return this.discourseTemplateModule("loading");
}
}
@@ -312,17 +310,7 @@ export function buildResolver(baseName) {
.replace("template:connectors/", "template:")
.replace("components/", "")
);
- return this.findTemplate(connectorParsedName, "javascripts/");
- }
- }
-
- findPluginTemplate(parsedName) {
- return this.findTemplate(parsedName, "javascripts/");
- }
-
- findPluginMobileTemplate(parsedName) {
- if (_options.mobileView) {
- return this.findTemplate(parsedName, "javascripts/mobile/");
+ return this.findTemplate(connectorParsedName);
}
}
@@ -332,31 +320,43 @@ export function buildResolver(baseName) {
}
}
+ /**
+ * Given a template path, this function will return a template, taking into account
+ * priority rules for theme and plugin overrides. See `lib/discourse-template-map.js`
+ */
+ discourseTemplateModule(name) {
+ const resolvedName = DiscourseTemplateMap.resolve(name);
+ if (resolvedName) {
+ return require(resolvedName).default;
+ }
+ }
+
findTemplate(parsedName, prefix) {
prefix = prefix || "";
const withoutType = parsedName.fullNameWithoutType,
underscored = decamelize(withoutType).replace(/-/g, "_"),
- segments = withoutType.split("/"),
- templates = Ember.TEMPLATES;
+ segments = withoutType.split("/");
return (
// Convert dots and dashes to slashes
- templates[prefix + withoutType.replace(/[\.-]/g, "/")] ||
+ this.discourseTemplateModule(
+ prefix + withoutType.replace(/[\.-]/g, "/")
+ ) ||
// Default unmodified behavior of original resolveTemplate.
- templates[prefix + withoutType] ||
+ this.discourseTemplateModule(prefix + withoutType) ||
// Underscored without namespace
- templates[prefix + underscored] ||
+ this.discourseTemplateModule(prefix + underscored) ||
// Underscored with first segment as directory
- templates[prefix + underscored.replace("_", "/")] ||
+ this.discourseTemplateModule(prefix + underscored.replace("_", "/")) ||
// Underscore only the last segment
- templates[
+ this.discourseTemplateModule(
`${prefix}${segments.slice(0, -1).join("/")}/${segments[
segments.length - 1
].replace(/-/g, "_")}`
- ] ||
+ ) ||
// All dasherized
- templates[prefix + withoutType.replace(/\//g, "-")]
+ this.discourseTemplateModule(prefix + withoutType.replace(/\//g, "-"))
);
}
@@ -364,17 +364,15 @@ export function buildResolver(baseName) {
// (similar to how discourse lays out templates)
findAdminTemplate(parsedName) {
if (parsedName.fullNameWithoutType === "admin") {
- return Ember.TEMPLATES["admin/templates/admin"];
+ return this.discourseTemplateModule("admin/templates/admin");
}
let namespaced, match;
if (parsedName.fullNameWithoutType.startsWith("components/")) {
return (
- // Built-in
this.findTemplate(parsedName, "admin/templates/") ||
- // Plugin
- this.findTemplate(parsedName, "javascripts/admin/")
+ this.findTemplate(parsedName, "admin/") // Nested under discourse/templates/admin (e.g. from plugins)
);
} else if (/^admin[_\.-]/.test(parsedName.fullNameWithoutType)) {
namespaced = parsedName.fullNameWithoutType.slice(6);
@@ -389,11 +387,9 @@ export function buildResolver(baseName) {
if (namespaced) {
let adminParsedName = this.parseName(`template:${namespaced}`);
resolved =
- // Built-in
this.findTemplate(adminParsedName, "admin/templates/") ||
this.findTemplate(parsedName, "admin/templates/") ||
- // Plugin
- this.findTemplate(adminParsedName, "javascripts/admin/");
+ this.findTemplate(adminParsedName, "admin/"); // Nested under discourse/templates/admin (e.g. from plugin)
}
return resolved;
@@ -401,7 +397,7 @@ export function buildResolver(baseName) {
findWizardTemplate(parsedName) {
if (parsedName.fullNameWithoutType === "wizard") {
- return Ember.TEMPLATES["wizard/templates/wizard"];
+ return this.discourseTemplateModule("wizard/templates/wizard");
}
let namespaced;
@@ -415,10 +411,10 @@ export function buildResolver(baseName) {
}
if (namespaced) {
- let adminParsedName = this.parseName(
+ let wizardParsedName = this.parseName(
`template:wizard/templates/${namespaced}`
);
- return this.findTemplate(adminParsedName);
+ return this.findTemplate(wizardParsedName);
}
}
};
diff --git a/app/assets/javascripts/discourse/app/components/reviewable-item.js b/app/assets/javascripts/discourse/app/components/reviewable-item.js
index fed71c9789..10cae579f6 100644
--- a/app/assets/javascripts/discourse/app/components/reviewable-item.js
+++ b/app/assets/javascripts/discourse/app/components/reviewable-item.js
@@ -9,7 +9,7 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
import { action, set } from "@ember/object";
import showModal from "discourse/lib/show-modal";
import { inject as service } from "@ember/service";
-import Ember from "ember";
+import { getOwner } from "discourse-common/lib/get-owner";
let _components = {};
@@ -106,12 +106,11 @@ export default Component.extend({
return _components[type];
}
- let dasherized = dasherize(type);
- let templatePath = `components/${dasherized}`;
- let template =
- Ember.TEMPLATES[`${templatePath}`] ||
- Ember.TEMPLATES[`javascripts/${templatePath}`];
- _components[type] = template ? dasherized : null;
+ const dasherized = dasherize(type);
+ const componentExists = getOwner(this).hasRegistration(
+ `component:${dasherized}`
+ );
+ _components[type] = componentExists ? dasherized : null;
return _components[type];
},
diff --git a/app/assets/javascripts/discourse/app/initializers/eager-load-raw-templates.js b/app/assets/javascripts/discourse/app/initializers/eager-load-raw-templates.js
new file mode 100644
index 0000000000..47be0b1303
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/initializers/eager-load-raw-templates.js
@@ -0,0 +1,9 @@
+import { eagerLoadRawTemplateModules } from "discourse-common/lib/raw-templates";
+
+export default {
+ name: "eager-load-raw-templates",
+
+ initialize() {
+ eagerLoadRawTemplateModules();
+ },
+};
diff --git a/app/assets/javascripts/discourse/app/initializers/populate-template-map.js b/app/assets/javascripts/discourse/app/initializers/populate-template-map.js
new file mode 100644
index 0000000000..4d198fed51
--- /dev/null
+++ b/app/assets/javascripts/discourse/app/initializers/populate-template-map.js
@@ -0,0 +1,8 @@
+import discourseTemplateMap from "discourse-common/lib/discourse-template-map";
+
+export default {
+ name: "populate-template-map",
+ initialize() {
+ discourseTemplateMap.setModuleNames(Object.keys(requirejs.entries));
+ },
+};
diff --git a/app/assets/javascripts/discourse/app/lib/plugin-connectors.js b/app/assets/javascripts/discourse/app/lib/plugin-connectors.js
index a276c1fe1b..0a9e07146c 100644
--- a/app/assets/javascripts/discourse/app/lib/plugin-connectors.js
+++ b/app/assets/javascripts/discourse/app/lib/plugin-connectors.js
@@ -1,6 +1,6 @@
import { buildRawConnectorCache } from "discourse-common/lib/raw-templates";
import deprecated from "discourse-common/lib/deprecated";
-import Ember from "ember";
+import DiscourseTemplateMap from "discourse-common/lib/discourse-template-map";
let _connectorCache;
let _rawConnectorCache;
@@ -25,11 +25,11 @@ const DefaultConnectorClass = {
teardownComponent() {},
};
-function findOutlets(collection, callback) {
- Object.keys(collection).forEach(function (res) {
- if (res.includes("/connectors/")) {
- const segments = res.split("/");
- let outletName = segments[segments.length - 2];
+function findOutlets(keys, callback) {
+ keys.forEach(function (res) {
+ const segments = res.split("/");
+ if (segments.includes("connectors")) {
+ const outletName = segments[segments.length - 2];
const uniqueName = segments[segments.length - 1];
callback(outletName, res, uniqueName);
@@ -45,7 +45,7 @@ export function clearCache() {
function findClass(outletName, uniqueName) {
if (!_classPaths) {
_classPaths = {};
- findOutlets(require._eak_seen, (outlet, res, un) => {
+ findOutlets(Object.keys(require._eak_seen), (outlet, res, un) => {
const possibleConnectorClass = requirejs(res).default;
if (possibleConnectorClass.__id) {
// This is the template, not the connector class
@@ -63,20 +63,31 @@ function findClass(outletName, uniqueName) {
: DefaultConnectorClass;
}
+/**
+ * Clear the cache of connectors. Should only be used in tests when
+ * `requirejs.entries` is changed.
+ */
+export function expireConnectorCache() {
+ _connectorCache = null;
+}
+
function buildConnectorCache() {
_connectorCache = {};
- findOutlets(Ember.TEMPLATES, (outletName, resource, uniqueName) => {
- _connectorCache[outletName] = _connectorCache[outletName] || [];
+ findOutlets(
+ DiscourseTemplateMap.keys(),
+ (outletName, resource, uniqueName) => {
+ _connectorCache[outletName] = _connectorCache[outletName] || [];
- _connectorCache[outletName].push({
- outletName,
- templateName: resource.replace("javascripts/", ""),
- template: Ember.TEMPLATES[resource],
- classNames: `${outletName}-outlet ${uniqueName}`,
- connectorClass: findClass(outletName, uniqueName),
- });
- });
+ _connectorCache[outletName].push({
+ outletName,
+ templateName: resource,
+ template: require(DiscourseTemplateMap.resolve(resource)).default,
+ classNames: `${outletName}-outlet ${uniqueName}`,
+ connectorClass: findClass(outletName, uniqueName),
+ });
+ }
+ );
}
export function connectorsFor(outletName) {
diff --git a/app/assets/javascripts/discourse/public/assets/scripts/discourse-boot.js b/app/assets/javascripts/discourse/public/assets/scripts/discourse-boot.js
index d9d96d27b9..964fb0b5bf 100644
--- a/app/assets/javascripts/discourse/public/assets/scripts/discourse-boot.js
+++ b/app/assets/javascripts/discourse/public/assets/scripts/discourse-boot.js
@@ -3,50 +3,6 @@
throw "Unsupported browser detected";
}
- // TODO: Remove this and have resolver find the templates
- const discoursePrefix = "discourse/templates/";
- const adminPrefix = "admin/templates/";
- const wizardPrefix = "wizard/templates/";
- const discoursePrefixLength = discoursePrefix.length;
-
- const pluginRegex = /^discourse\/plugins\/([^\/]+)\//;
- const themeRegex = /^discourse\/theme-([^\/]+)\//;
-
- Object.keys(requirejs.entries).forEach(function (key) {
- let templateKey;
- let pluginName;
- let themeId;
- if (key.startsWith(discoursePrefix)) {
- templateKey = key.slice(discoursePrefixLength);
- } else if (key.startsWith(adminPrefix) || key.startsWith(wizardPrefix)) {
- templateKey = key;
- } else if (
- (pluginName = key.match(pluginRegex)?.[1]) &&
- key.includes("/templates/") &&
- require(key).default.__id // really is a template
- ) {
- // This logic mimics the old sprockets compilation system which used to
- // output templates directly to `Ember.TEMPLATES` with this naming logic
- templateKey = key.slice(`discourse/plugins/${pluginName}/`.length);
- templateKey = templateKey.replace("discourse/templates/", "");
- templateKey = `javascripts/${templateKey}`;
- } else if (
- (themeId = key.match(themeRegex)?.[1]) &&
- key.includes("/templates/")
- ) {
- // And likewise for themes - this mimics the old logic
- templateKey = key.slice(`discourse/theme-${themeId}/`.length);
- templateKey = templateKey.replace("discourse/templates/", "");
- if (!templateKey.startsWith("javascripts/")) {
- templateKey = `javascripts/${templateKey}`;
- }
- }
-
- if (templateKey) {
- Ember.TEMPLATES[templateKey] = require(key).default;
- }
- });
-
window.__widget_helpers = require("discourse-widget-hbs/helpers").default;
// TODO: Eliminate this global
diff --git a/app/assets/javascripts/discourse/tests/acceptance/custom-html-template-test.js b/app/assets/javascripts/discourse/tests/acceptance/custom-html-template-test.js
index 117084efd7..c6825446a0 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/custom-html-template-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/custom-html-template-test.js
@@ -2,15 +2,14 @@ import { acceptance, query } from "discourse/tests/helpers/qunit-helpers";
import { hbs } from "ember-cli-htmlbars";
import { test } from "qunit";
import { visit } from "@ember/test-helpers";
-import Ember from "ember";
+import { registerTemplateModule } from "discourse/tests/helpers/template-module-helper";
acceptance("CustomHTML template", function (needs) {
needs.hooks.beforeEach(() => {
- Ember.TEMPLATES["top"] = hbs`TOP`;
- });
-
- needs.hooks.afterEach(() => {
- delete Ember.TEMPLATES["top"];
+ registerTemplateModule(
+ "discourse/templates/top",
+ hbs`TOP`
+ );
});
test("renders custom template", async function (assert) {
diff --git a/app/assets/javascripts/discourse/tests/acceptance/modal-test.js b/app/assets/javascripts/discourse/tests/acceptance/modal-test.js
index f2257ab9f3..398c18eda4 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/modal-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/modal-test.js
@@ -10,7 +10,7 @@ import { test } from "qunit";
import I18n from "I18n";
import { hbs } from "ember-cli-htmlbars";
import showModal from "discourse/lib/show-modal";
-import Ember from "ember";
+import { registerTemplateModule } from "../helpers/template-module-helper";
acceptance("Modal", function (needs) {
let _translations;
@@ -54,9 +54,10 @@ acceptance("Modal", function (needs) {
await triggerKeyEvent("#main-outlet", "keydown", "Escape");
assert.ok(!exists(".d-modal:visible"), "ESC should close the modal");
- Ember.TEMPLATES[
- "modal/not-dismissable"
- ] = hbs`{{#d-modal-body title="" class="" dismissable=false}}test{{/d-modal-body}}`;
+ registerTemplateModule(
+ "discourse/templates/modal/not-dismissable",
+ hbs`{{#d-modal-body title="" class="" dismissable=false}}test{{/d-modal-body}}`
+ );
showModal("not-dismissable", {});
await settled();
@@ -78,7 +79,10 @@ acceptance("Modal", function (needs) {
});
test("rawTitle in modal panels", async function (assert) {
- Ember.TEMPLATES["modal/test-raw-title-panels"] = hbs``;
+ registerTemplateModule(
+ "discourse/templates/modal/test-raw-title-panels",
+ hbs``
+ );
const panels = [
{ id: "test1", rawTitle: "Test 1" },
{ id: "test2", rawTitle: "Test 2" },
@@ -96,10 +100,11 @@ acceptance("Modal", function (needs) {
});
test("modal title", async function (assert) {
- Ember.TEMPLATES["modal/test-title"] = hbs``;
- Ember.TEMPLATES[
- "modal/test-title-with-body"
- ] = hbs`{{#d-modal-body}}test{{/d-modal-body}}`;
+ registerTemplateModule("discourse/templates/modal/test-title", hbs``);
+ registerTemplateModule(
+ "discourse/templates/modal/test-title-with-body",
+ hbs`{{#d-modal-body}}test{{/d-modal-body}}`
+ );
await visit("/");
diff --git a/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-connector-class-test.js b/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-connector-class-test.js
index 712a07fa13..89fb051f26 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-connector-class-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-connector-class-test.js
@@ -9,9 +9,9 @@ import { action } from "@ember/object";
import { extraConnectorClass } from "discourse/lib/plugin-connectors";
import { hbs } from "ember-cli-htmlbars";
import { test } from "qunit";
-import Ember from "ember";
+import { registerTemplateModule } from "discourse/tests/helpers/template-module-helper";
-const PREFIX = "javascripts/single-test/connectors";
+const PREFIX = "discourse/plugins/some-plugin/templates/connectors";
acceptance("Plugin Outlet - Connector Class", function (needs) {
needs.hooks.beforeEach(() => {
@@ -49,25 +49,22 @@ acceptance("Plugin Outlet - Connector Class", function (needs) {
},
});
- Ember.TEMPLATES[
- `${PREFIX}/user-profile-primary/hello`
- ] = hbs`{{model.username}}
+ registerTemplateModule(
+ `${PREFIX}/user-profile-primary/hello`,
+ hbs`{{model.username}}
- {{hello}}`;
- Ember.TEMPLATES[
- `${PREFIX}/user-profile-primary/hi`
- ] = hbs`
- {{hi}}`;
- Ember.TEMPLATES[
- `${PREFIX}/user-profile-primary/dont-render`
- ] = hbs`I'm not rendered!`;
- });
-
- needs.hooks.afterEach(() => {
- delete Ember.TEMPLATES[`${PREFIX}/user-profile-primary/hello`];
- delete Ember.TEMPLATES[`${PREFIX}/user-profile-primary/hi`];
- delete Ember.TEMPLATES[`${PREFIX}/user-profile-primary/dont-render`];
+ {{hello}}`
+ );
+ registerTemplateModule(
+ `${PREFIX}/user-profile-primary/hi`,
+ hbs`
+ {{hi}}`
+ );
+ registerTemplateModule(
+ `${PREFIX}/user-profile-primary/dont-render`,
+ hbs`I'm not rendered!`
+ );
});
test("Renders a template into the outlet", async function (assert) {
diff --git a/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-decorator-test.js b/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-decorator-test.js
index c287449f09..e269882d8d 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-decorator-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-decorator-test.js
@@ -7,16 +7,22 @@ import { hbs } from "ember-cli-htmlbars";
import { test } from "qunit";
import { visit } from "@ember/test-helpers";
import { withPluginApi } from "discourse/lib/plugin-api";
-import Ember from "ember";
+import { registerTemplateModule } from "../helpers/template-module-helper";
-const PREFIX = "javascripts/single-test/connectors";
+const PREFIX = "discourse/plugins/some-plugin/templates/connectors";
acceptance("Plugin Outlet - Decorator", function (needs) {
needs.user();
needs.hooks.beforeEach(() => {
- Ember.TEMPLATES[`${PREFIX}/discovery-list-container-top/foo`] = hbs`FOO`;
- Ember.TEMPLATES[`${PREFIX}/discovery-list-container-top/bar`] = hbs`BAR`;
+ registerTemplateModule(
+ `${PREFIX}/discovery-list-container-top/foo`,
+ hbs`FOO`
+ );
+ registerTemplateModule(
+ `${PREFIX}/discovery-list-container-top/bar`,
+ hbs`BAR`
+ );
withPluginApi("0.8.38", (api) => {
api.decoratePluginOutlet(
@@ -37,11 +43,6 @@ acceptance("Plugin Outlet - Decorator", function (needs) {
});
});
- needs.hooks.afterEach(() => {
- delete Ember.TEMPLATES[`${PREFIX}/discovery-list-container-top/foo`];
- delete Ember.TEMPLATES[`${PREFIX}/discovery-list-container-top/bar`];
- });
-
test("Calls the plugin callback with the rendered outlet", async function (assert) {
await visit("/");
diff --git a/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-multi-template-test.js b/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-multi-template-test.js
index b5e70c3a5a..ba81c83a1f 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-multi-template-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-multi-template-test.js
@@ -6,21 +6,17 @@ import {
import { hbs } from "ember-cli-htmlbars";
import { test } from "qunit";
import { visit } from "@ember/test-helpers";
-import Ember from "ember";
+import { registerTemplateModule } from "../helpers/template-module-helper";
-const HELLO = "javascripts/multi-test/connectors/user-profile-primary/hello";
+const HELLO =
+ "discourse/plugins/my-plugin/templates/connectors/user-profile-primary/hello";
const GOODBYE =
- "javascripts/multi-test/connectors/user-profile-primary/goodbye";
+ "discourse/plugins/my-plugin/templates/connectors/user-profile-primary/goodbye";
acceptance("Plugin Outlet - Multi Template", function (needs) {
needs.hooks.beforeEach(() => {
- Ember.TEMPLATES[HELLO] = hbs`Hello`;
- Ember.TEMPLATES[GOODBYE] = hbs`Goodbye`;
- });
-
- needs.hooks.afterEach(() => {
- delete Ember.TEMPLATES[HELLO];
- delete Ember.TEMPLATES[GOODBYE];
+ registerTemplateModule(HELLO, hbs`Hello`);
+ registerTemplateModule(GOODBYE, hbs`Goodbye`);
});
test("Renders a template into the outlet", async function (assert) {
diff --git a/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-single-template-test.js b/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-single-template-test.js
index 1f9e06d096..e1a0cc62c0 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-single-template-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/plugin-outlet-single-template-test.js
@@ -6,20 +6,17 @@ import {
import { hbs } from "ember-cli-htmlbars";
import { test } from "qunit";
import { visit } from "@ember/test-helpers";
-import Ember from "ember";
+import { registerTemplateModule } from "../helpers/template-module-helper";
-const CONNECTOR =
- "javascripts/single-test/connectors/user-profile-primary/hello";
+const CONNECTOR_MODULE =
+ "discourse/theme-12/templates/connectors/user-profile-primary/hello";
acceptance("Plugin Outlet - Single Template", function (needs) {
needs.hooks.beforeEach(() => {
- Ember.TEMPLATES[
- CONNECTOR
- ] = hbs`{{model.username}}`;
- });
-
- needs.hooks.afterEach(() => {
- delete Ember.TEMPLATES[CONNECTOR];
+ registerTemplateModule(
+ CONNECTOR_MODULE,
+ hbs`{{model.username}}`
+ );
});
test("Renders a template into the outlet", async function (assert) {
diff --git a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js
index 5c2c3a609b..da71ce3683 100644
--- a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js
+++ b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js
@@ -76,6 +76,7 @@ import { resetNotificationTypeRenderers } from "discourse/lib/notification-types
import { resetUserMenuTabs } from "discourse/lib/user-menu/tab";
import { reset as resetLinkLookup } from "discourse/lib/link-lookup";
import { resetModelTransformers } from "discourse/lib/model-transformers";
+import { cleanupTemporaryTemplateRegistrations } from "./template-module-helper";
export function currentUser() {
return User.create(sessionFixtures["/session/current.json"].current_user);
@@ -207,6 +208,7 @@ export function testCleanup(container, app) {
resetUserMenuTabs();
resetLinkLookup();
resetModelTransformers();
+ cleanupTemporaryTemplateRegistrations();
}
export function discourseModule(name, options) {
diff --git a/app/assets/javascripts/discourse/tests/helpers/template-module-helper.js b/app/assets/javascripts/discourse/tests/helpers/template-module-helper.js
new file mode 100644
index 0000000000..ae1930d805
--- /dev/null
+++ b/app/assets/javascripts/discourse/tests/helpers/template-module-helper.js
@@ -0,0 +1,40 @@
+import DiscourseTemplateMap from "discourse-common/lib/discourse-template-map";
+import { expireConnectorCache } from "discourse/lib/plugin-connectors";
+
+const modifications = [];
+
+function generateTemplateModule(template) {
+ return function (_exports) {
+ Object.defineProperty(_exports, "__esModule", {
+ value: true,
+ });
+ _exports.default = template;
+ };
+}
+
+export function registerTemplateModule(moduleName, template) {
+ const modificationData = {
+ moduleName,
+ existingModule: requirejs.entries[moduleName],
+ };
+ delete requirejs.entries[moduleName];
+ define(moduleName, ["exports"], generateTemplateModule(template));
+ modifications.push(modificationData);
+ expireConnectorCache();
+ DiscourseTemplateMap.setModuleNames(Object.keys(requirejs.entries));
+}
+
+export function cleanupTemporaryTemplateRegistrations() {
+ for (const modificationData of modifications.reverse()) {
+ const { moduleName, existingModule } = modificationData;
+ delete requirejs.entries[moduleName];
+ if (existingModule) {
+ requirejs.entries[moduleName] = existingModule;
+ }
+ }
+ if (modifications.length) {
+ expireConnectorCache();
+ DiscourseTemplateMap.setModuleNames(Object.keys(requirejs.entries));
+ }
+ modifications.clear();
+}
diff --git a/app/assets/javascripts/discourse/tests/unit/ember/resolver-test.js b/app/assets/javascripts/discourse/tests/unit/ember/resolver-test.js
index 14aafdb325..04e48df1a1 100644
--- a/app/assets/javascripts/discourse/tests/unit/ember/resolver-test.js
+++ b/app/assets/javascripts/discourse/tests/unit/ember/resolver-test.js
@@ -1,8 +1,8 @@
import { buildResolver, setResolverOption } from "discourse-common/resolver";
import { module, test } from "qunit";
-import Ember from "ember";
+import { registerTemplateModule } from "discourse/tests/helpers/template-module-helper";
+import DiscourseTemplateMap from "discourse-common/lib/discourse-template-map";
-let originalTemplates;
let resolver;
function lookupTemplate(assert, name, expectedTemplate, message) {
@@ -11,57 +11,71 @@ function lookupTemplate(assert, name, expectedTemplate, message) {
assert.strictEqual(result, expectedTemplate, message);
}
-function setTemplates(lookupTemplateStrings) {
- lookupTemplateStrings.forEach(function (lookupTemplateString) {
- Ember.TEMPLATES[lookupTemplateString] = lookupTemplateString;
- });
+function setTemplates(templateModuleNames) {
+ for (const name of templateModuleNames) {
+ registerTemplateModule(name, name);
+ }
}
const DiscourseResolver = buildResolver("discourse");
module("Unit | Ember | resolver", function (hooks) {
hooks.beforeEach(function () {
- originalTemplates = Ember.TEMPLATES;
- Ember.TEMPLATES = {};
-
+ DiscourseTemplateMap.setModuleNames(Object.keys(requirejs.entries));
resolver = DiscourseResolver.create({
namespace: { modulePrefix: "discourse" },
});
});
- hooks.afterEach(function () {
- Ember.TEMPLATES = originalTemplates;
- });
-
test("finds templates in top level dir", function (assert) {
- setTemplates(["foobar", "fooBar", "foo_bar", "foo.bar"]);
+ setTemplates([
+ "discourse/templates/foobar",
+ "discourse/templates/fooBar",
+ "discourse/templates/foo_bar",
+ "discourse/templates/foo.bar",
+ ]);
// Default unmodified behavior
- lookupTemplate(assert, "template:foobar", "foobar", "by lowcased name");
+ lookupTemplate(
+ assert,
+ "template:foobar",
+ "discourse/templates/foobar",
+ "by lowcased name"
+ );
// Default unmodified behavior
- lookupTemplate(assert, "template:fooBar", "fooBar", "by camel cased name");
+ lookupTemplate(
+ assert,
+ "template:fooBar",
+ "discourse/templates/fooBar",
+ "by camel cased name"
+ );
// Default unmodified behavior
lookupTemplate(
assert,
"template:foo_bar",
- "foo_bar",
+ "discourse/templates/foo_bar",
"by underscored name"
);
// Default unmodified behavior
- lookupTemplate(assert, "template:foo.bar", "foo.bar", "by dotted name");
+ lookupTemplate(
+ assert,
+ "template:foo.bar",
+ "discourse/templates/foo.bar",
+ "by dotted name"
+ );
});
test("finds templates in first-level subdir", function (assert) {
- setTemplates(["foo/bar_baz"]);
+ setTemplates(["discourse/templates/foo/bar_baz"]);
// Default unmodified behavior
lookupTemplate(
assert,
"template:foo/bar_baz",
- "foo/bar_baz",
+ "discourse/templates/foo/bar_baz",
"with subdir defined by slash"
);
@@ -69,7 +83,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:foo.bar_baz",
- "foo/bar_baz",
+ "discourse/templates/foo/bar_baz",
"with subdir defined by dot"
);
@@ -77,7 +91,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:foo-bar_baz",
- "foo/bar_baz",
+ "discourse/templates/foo/bar_baz",
"with subdir defined by dash"
);
@@ -85,7 +99,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:fooBarBaz",
- "foo/bar_baz",
+ "discourse/templates/foo/bar_baz",
"with subdir defined by first camel case and the rest of camel cases converted to underscores"
);
@@ -93,19 +107,25 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:foo_bar_baz",
- "foo/bar_baz",
+ "discourse/templates/foo/bar_baz",
"with subdir defined by first underscore"
);
});
test("resolves precedence between overlapping top level dir and first level subdir templates", function (assert) {
- setTemplates(["fooBar", "foo_bar", "foo.bar", "foo/bar", "baz/qux"]);
+ setTemplates([
+ "discourse/templates/fooBar",
+ "discourse/templates/foo_bar",
+ "discourse/templates/foo.bar",
+ "discourse/templates/foo/bar",
+ "discourse/templates/baz/qux",
+ ]);
// Directories are prioritized when dotted
lookupTemplate(
assert,
"template:foo.bar",
- "foo/bar",
+ "discourse/templates/foo/bar",
"preferring first level subdir for dotted name"
);
@@ -113,7 +133,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:foo-bar",
- "foo/bar",
+ "discourse/templates/foo/bar",
"preferring first level subdir for dotted name"
);
@@ -121,7 +141,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:fooBar",
- "fooBar",
+ "discourse/templates/fooBar",
"preferring top level dir for camel cased name"
);
@@ -129,7 +149,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:foo_bar",
- "foo_bar",
+ "discourse/templates/foo_bar",
"preferring top level dir for underscored name"
);
@@ -137,19 +157,19 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:baz-qux",
- "baz/qux",
+ "discourse/templates/baz/qux",
"fallback subdir for dashed name"
);
});
test("finds templates in subdir deeper than one level", function (assert) {
- setTemplates(["foo/bar/baz/qux"]);
+ setTemplates(["discourse/templates/foo/bar/baz/qux"]);
// Default unmodified
lookupTemplate(
assert,
"template:foo/bar/baz/qux",
- "foo/bar/baz/qux",
+ "discourse/templates/foo/bar/baz/qux",
"for subdirs defined by slashes"
);
@@ -157,7 +177,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:foo.bar.baz.qux",
- "foo/bar/baz/qux",
+ "discourse/templates/foo/bar/baz/qux",
"for subdirs defined by dots"
);
@@ -165,7 +185,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:foo/bar/bazQux",
- "foo/bar/baz/qux",
+ "discourse/templates/foo/bar/baz/qux",
"for subdirs defined by slashes plus one camel case"
);
@@ -173,7 +193,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:foo/bar/baz_qux",
- "foo/bar/baz/qux",
+ "discourse/templates/foo/bar/baz/qux",
"for subdirs defined by slashes plus one underscore"
);
@@ -211,7 +231,12 @@ module("Unit | Ember | resolver", function (hooks) {
});
test("resolves mobile templates to 'mobile/' namespace", function (assert) {
- setTemplates(["mobile/foo", "bar", "mobile/bar", "baz"]);
+ setTemplates([
+ "discourse/templates/mobile/foo",
+ "discourse/templates/bar",
+ "discourse/templates/mobile/bar",
+ "discourse/templates/baz",
+ ]);
setResolverOption("mobileView", true);
@@ -219,7 +244,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:foo",
- "mobile/foo",
+ "discourse/templates/mobile/foo",
"finding mobile version even if normal one is not present"
);
@@ -227,7 +252,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:bar",
- "mobile/bar",
+ "discourse/templates/mobile/bar",
"preferring mobile version when both mobile and normal versions are present"
);
@@ -235,71 +260,87 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:baz",
- "baz",
+ "discourse/templates/baz",
"falling back to a normal version when mobile version is not present"
);
});
- test("resolves plugin templates to 'javascripts/' namespace", function (assert) {
- setTemplates(["javascripts/foo", "bar", "javascripts/bar", "baz"]);
+ test("resolves templates to plugin and theme namespaces", function (assert) {
+ setTemplates([
+ "discourse/plugins/my-plugin/discourse/templates/foo",
+ "discourse/templates/bar",
+ "discourse/plugins/my-plugin/discourse/templates/bar",
+ "discourse/templates/baz",
+ "discourse/plugins/my-plugin/discourse/templates/baz",
+ "discourse/theme-12/discourse/templates/baz",
+ "discourse/templates/qux",
+ ]);
- // Default with javascripts/ added
+ // Defined in plugin only
lookupTemplate(
assert,
"template:foo",
- "javascripts/foo",
+ "discourse/plugins/my-plugin/discourse/templates/foo",
"finding plugin version even if normal one is not present"
);
- // Default with javascripts/ added, takes precedence
+ // Defined in core and plugin
lookupTemplate(
assert,
"template:bar",
- "javascripts/bar",
- "preferring plugin version when both versions are present"
+ "discourse/plugins/my-plugin/discourse/templates/bar",
+ "prefers plugin version over core"
);
- // Default when javascripts version not present
+ // Defined in core and plugin and theme
lookupTemplate(
assert,
"template:baz",
- "baz",
- "falling back to a normal version when plugin version is not present"
+ "discourse/theme-12/discourse/templates/baz",
+ "prefers theme version over plugin and core"
+ );
+
+ // Defined in core only
+ lookupTemplate(
+ assert,
+ "template:qux",
+ "discourse/templates/qux",
+ "uses core if there are no theme/plugin definitions"
);
});
- test("resolves plugin mobile templates to 'javascripts/mobile/' namespace", function (assert) {
+ test("resolves plugin mobile templates", function (assert) {
setTemplates([
- "javascripts/mobile/foo",
- "javascripts/mobile/bar",
- "javascripts/bar",
- "javascripts/mobile/baz",
- "mobile/baz",
+ "discourse/plugins/my-plugin/discourse/templates/mobile/foo",
+ "discourse/plugins/my-plugin/discourse/templates/mobile/bar",
+ "discourse/plugins/my-plugin/discourse/templates/bar",
+ "discourse/plugins/my-plugin/discourse/templates/mobile/baz",
+ "discourse/templates/mobile/baz",
]);
setResolverOption("mobileView", true);
- // Default with javascripts/mobile/ added
+ // Default with plugin template override
lookupTemplate(
assert,
"template:foo",
- "javascripts/mobile/foo",
+ "discourse/plugins/my-plugin/discourse/templates/mobile/foo",
"finding plugin version even if normal one is not present"
);
- // Default with javascripts/mobile added, takes precedence over non-mobile
+ // Default with plugin mobile added, takes precedence over non-mobile
lookupTemplate(
assert,
"template:bar",
- "javascripts/mobile/bar",
+ "discourse/plugins/my-plugin/discourse/templates/mobile/bar",
"preferring plugin mobile version when both non-mobile plugin version is also present"
);
- // Default with javascripts/mobile when non-plugin mobile version is present
+ // Default with when non-plugin mobile version is present
lookupTemplate(
assert,
"template:baz",
- "javascripts/mobile/baz",
+ "discourse/plugins/my-plugin/discourse/templates/mobile/baz",
"preferring plugin mobile version over non-plugin mobile version"
);
});
@@ -307,13 +348,13 @@ module("Unit | Ember | resolver", function (hooks) {
test("resolves templates with 'admin' prefix", function (assert) {
setTemplates([
"admin/templates/foo",
- "adminBar",
- "admin_bar",
- "admin.bar",
+ "discourse/templates/adminBar",
+ "discourse/templates/admin_bar",
+ "discourse/templates/admin.bar",
"admin/templates/bar",
"admin/templates/dashboard_general",
- "admin-baz-qux",
- "javascripts/admin/plugin-template",
+ "discourse/templates/admin-baz-qux",
+ "discourse/plugins/my-plugin/discourse/templates/admin/plugin-template",
"admin/templates/components/my-admin-component",
]);
@@ -353,7 +394,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:adminBar",
- "adminBar",
+ "discourse/templates/adminBar",
"but not when template with the exact camel cased name exists"
);
@@ -361,7 +402,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:admin_bar",
- "admin_bar",
+ "discourse/templates/admin_bar",
"but not when template with the exact underscored name exists"
);
@@ -369,7 +410,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:admin.bar",
- "admin.bar",
+ "discourse/templates/admin.bar",
"but not when template with the exact dotted name exists"
);
@@ -383,14 +424,14 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:admin-baz/qux",
- "admin-baz-qux",
+ "discourse/templates/admin-baz-qux",
"also tries dasherized"
);
lookupTemplate(
assert,
"template:admin-plugin/template",
- "javascripts/admin/plugin-template",
+ "discourse/plugins/my-plugin/discourse/templates/admin/plugin-template",
"looks up templates in plugins"
);
@@ -412,7 +453,7 @@ module("Unit | Ember | resolver", function (hooks) {
test("resolves component templates with 'admin' prefix to 'admin/templates/' namespace", function (assert) {
setTemplates([
"admin/templates/components/foo",
- "components/bar",
+ "discourse/templates/components/bar",
"admin/templates/components/bar",
]);
@@ -428,7 +469,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:components/bar",
- "components/bar",
+ "discourse/templates/components/bar",
"uses standard match when both exist"
);
});
@@ -437,54 +478,59 @@ module("Unit | Ember | resolver", function (hooks) {
// close to Ember's default behavior.
// See https://guides.emberjs.com/release/routing/loading-and-error-substates/
test("resolves loading templates", function (assert) {
- setTemplates(["fooloading", "foo/loading", "foo_loading", "loading"]);
+ setTemplates([
+ "discourse/templates/fooloading",
+ "discourse/templates/foo/loading",
+ "discourse/templates/foo_loading",
+ "discourse/templates/loading",
+ ]);
lookupTemplate(
assert,
"template:fooloading",
- "fooloading",
+ "discourse/templates/fooloading",
"exact match without separator"
);
lookupTemplate(
assert,
"template:foo/loading",
- "foo/loading",
+ "discourse/templates/foo/loading",
"exact match with slash"
);
lookupTemplate(
assert,
"template:foo_loading",
- "foo_loading",
+ "discourse/templates/foo_loading",
"exact match underscore"
);
lookupTemplate(
assert,
"template:barloading",
- "loading",
+ "discourse/templates/loading",
"fallback without separator"
);
lookupTemplate(
assert,
"template:bar/loading",
- "loading",
+ "discourse/templates/loading",
"fallback with slash"
);
lookupTemplate(
assert,
"template:bar.loading",
- "loading",
+ "discourse/templates/loading",
"fallback with dot"
);
lookupTemplate(
assert,
"template:bar_loading",
- "loading",
+ "discourse/templates/loading",
"fallback underscore"
);
@@ -493,61 +539,66 @@ module("Unit | Ember | resolver", function (hooks) {
test("resolves connector templates", function (assert) {
setTemplates([
- "javascripts/foo",
- "javascripts/connectors/foo-bar/baz_qux",
- "javascripts/connectors/foo-bar/camelCase",
+ "discourse/plugins/my-plugin/discourse/templates/foo",
+ "discourse/plugins/my-plugin/discourse/templates/connectors/foo-bar/baz_qux",
+ "discourse/plugins/my-plugin/discourse/templates/connectors/foo-bar/camelCase",
]);
lookupTemplate(
assert,
"template:connectors/foo",
- "javascripts/foo",
- "looks up in javascripts/ namespace"
+ "discourse/plugins/my-plugin/discourse/templates/foo",
+ "looks up in plugin namespace"
);
lookupTemplate(
assert,
"template:connectors/components/foo",
- "javascripts/foo",
+ "discourse/plugins/my-plugin/discourse/templates/foo",
"removes components segment"
);
lookupTemplate(
assert,
"template:connectors/foo-bar/baz-qux",
- "javascripts/connectors/foo-bar/baz_qux",
+ "discourse/plugins/my-plugin/discourse/templates/connectors/foo-bar/baz_qux",
"underscores last segment"
);
lookupTemplate(
assert,
"template:connectors/foo-bar/camelCase",
- "javascripts/connectors/foo-bar/camelCase",
+ "discourse/plugins/my-plugin/discourse/templates/connectors/foo-bar/camelCase",
"handles camelcase file names"
);
lookupTemplate(
assert,
resolver.normalize("template:connectors/foo-bar/camelCase"),
- "javascripts/connectors/foo-bar/camelCase",
+ "discourse/plugins/my-plugin/discourse/templates/connectors/foo-bar/camelCase",
"handles camelcase file names when normalized"
);
});
test("returns 'not_found' template when template name cannot be resolved", function (assert) {
- setTemplates(["not_found"]);
+ setTemplates(["discourse/templates/not_found"]);
- lookupTemplate(assert, "template:foo/bar/baz", "not_found", "");
+ lookupTemplate(
+ assert,
+ "template:foo/bar/baz",
+ "discourse/templates/not_found",
+ ""
+ );
});
test("resolves templates with 'wizard' prefix", function (assert) {
setTemplates([
"wizard/templates/foo",
- "wizard_bar",
- "wizard.bar",
+ "discourse/templates/wizard_bar",
+ "discourse/templates/wizard.bar",
"wizard/templates/bar",
"wizard/templates/dashboard_general",
- "wizard-baz-qux",
+ "discourse/templates/wizard-baz-qux",
"javascripts/wizard/plugin-template",
]);
@@ -579,7 +630,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:wizard_bar",
- "wizard_bar",
+ "discourse/templates/wizard_bar",
"but not when template with the exact underscored name exists"
);
@@ -587,7 +638,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:wizard.bar",
- "wizard.bar",
+ "discourse/templates/wizard.bar",
"but not when template with the exact dotted name exists"
);
@@ -601,7 +652,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:wizard-baz/qux",
- "wizard-baz-qux",
+ "discourse/templates/wizard-baz-qux",
"also tries dasherized"
);
});
@@ -609,7 +660,7 @@ module("Unit | Ember | resolver", function (hooks) {
test("resolves component templates with 'wizard' prefix to 'wizard/templates/' namespace", function (assert) {
setTemplates([
"wizard/templates/components/foo",
- "components/bar",
+ "discourse/templates/components/bar",
"wizard/templates/components/bar",
]);
@@ -625,7 +676,7 @@ module("Unit | Ember | resolver", function (hooks) {
lookupTemplate(
assert,
"template:components/bar",
- "components/bar",
+ "discourse/templates/components/bar",
"uses standard match when both exist"
);
});
diff --git a/plugins/styleguide/assets/javascripts/discourse/lib/styleguide.js b/plugins/styleguide/assets/javascripts/discourse/lib/styleguide.js
index 8b1610d07d..aac2b772ef 100644
--- a/plugins/styleguide/assets/javascripts/discourse/lib/styleguide.js
+++ b/plugins/styleguide/assets/javascripts/discourse/lib/styleguide.js
@@ -1,3 +1,4 @@
+import DiscourseTemplateMap from "discourse-common/lib/discourse-template-map";
let _allCategories = null;
let _sectionsById = {};
let _notes = {};
@@ -30,7 +31,7 @@ export function allCategories() {
// Find a list of sections based on what templates are available
// eslint-disable-next-line no-undef
- Object.keys(Ember.TEMPLATES).forEach((e) => {
+ DiscourseTemplateMap.keys().forEach((e) => {
let regexp = new RegExp(`styleguide\/(${paths})\/(\\d+)?\\-?([^\\/]+)$`);
let matches = e.match(regexp);
if (matches) {