In the past, the result of template compilation would be stored directly in `Ember.TEMPLATES`. Following the move to more modern ember-cli-based compilation, templates are now compiled to es6 modules. To handle forward/backwards compatibility during these changes we had logic in `discourse-boot` which would extract templates from the es6 modules and store them into the legacy-style `Ember.TEMPLATES` object. This commit removes that shim, and updates our resolver to fetch templates directly from es6 modules. This is closer to how 'vanilla' Ember handles template resolution. We still have a lot of discourse-specific logic, but now it is centralised in one location and should be easier to understand and normalize in future. This commit should not introduce any behaviour change.
134 lines
3.5 KiB
JavaScript
134 lines
3.5 KiB
JavaScript
import { buildRawConnectorCache } from "discourse-common/lib/raw-templates";
|
|
import deprecated from "discourse-common/lib/deprecated";
|
|
import DiscourseTemplateMap from "discourse-common/lib/discourse-template-map";
|
|
|
|
let _connectorCache;
|
|
let _rawConnectorCache;
|
|
let _extraConnectorClasses = {};
|
|
let _classPaths;
|
|
|
|
export function resetExtraClasses() {
|
|
_extraConnectorClasses = {};
|
|
_classPaths = undefined;
|
|
}
|
|
|
|
// Note: In plugins, define a class by path and it will be wired up automatically
|
|
// eg: discourse/connectors/<OUTLET NAME>/<CONNECTOR NAME>
|
|
export function extraConnectorClass(name, obj) {
|
|
_extraConnectorClasses[name] = obj;
|
|
}
|
|
|
|
const DefaultConnectorClass = {
|
|
actions: {},
|
|
shouldRender: () => true,
|
|
setupComponent() {},
|
|
teardownComponent() {},
|
|
};
|
|
|
|
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);
|
|
}
|
|
});
|
|
}
|
|
|
|
export function clearCache() {
|
|
_connectorCache = null;
|
|
_rawConnectorCache = null;
|
|
}
|
|
|
|
function findClass(outletName, uniqueName) {
|
|
if (!_classPaths) {
|
|
_classPaths = {};
|
|
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
|
|
return;
|
|
}
|
|
_classPaths[`${outlet}/${un}`] = possibleConnectorClass;
|
|
});
|
|
}
|
|
|
|
const id = `${outletName}/${uniqueName}`;
|
|
let foundClass = _extraConnectorClasses[id] || _classPaths[id];
|
|
|
|
return foundClass
|
|
? Object.assign({}, DefaultConnectorClass, foundClass)
|
|
: 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(
|
|
DiscourseTemplateMap.keys(),
|
|
(outletName, resource, uniqueName) => {
|
|
_connectorCache[outletName] = _connectorCache[outletName] || [];
|
|
|
|
_connectorCache[outletName].push({
|
|
outletName,
|
|
templateName: resource,
|
|
template: require(DiscourseTemplateMap.resolve(resource)).default,
|
|
classNames: `${outletName}-outlet ${uniqueName}`,
|
|
connectorClass: findClass(outletName, uniqueName),
|
|
});
|
|
}
|
|
);
|
|
}
|
|
|
|
export function connectorsFor(outletName) {
|
|
if (!_connectorCache) {
|
|
buildConnectorCache();
|
|
}
|
|
return _connectorCache[outletName] || [];
|
|
}
|
|
|
|
export function renderedConnectorsFor(outletName, args, context) {
|
|
return connectorsFor(outletName).filter((con) => {
|
|
return con.connectorClass.shouldRender(args, context);
|
|
});
|
|
}
|
|
|
|
export function rawConnectorsFor(outletName) {
|
|
if (!_rawConnectorCache) {
|
|
_rawConnectorCache = buildRawConnectorCache(findOutlets);
|
|
}
|
|
return _rawConnectorCache[outletName] || [];
|
|
}
|
|
|
|
export function buildArgsWithDeprecations(args, deprecatedArgs) {
|
|
const output = {};
|
|
|
|
Object.keys(args).forEach((key) => {
|
|
Object.defineProperty(output, key, { value: args[key] });
|
|
});
|
|
|
|
Object.keys(deprecatedArgs).forEach((key) => {
|
|
Object.defineProperty(output, key, {
|
|
get() {
|
|
deprecated(`${key} is deprecated`, {
|
|
id: "discourse.plugin-connector.deprecated-arg",
|
|
});
|
|
|
|
return deprecatedArgs[key];
|
|
},
|
|
});
|
|
});
|
|
|
|
return output;
|
|
}
|