82 lines
3.2 KiB
JavaScript
82 lines
3.2 KiB
JavaScript
|
import { Application } from '@hotwired/stimulus';
|
||
|
import { isApplicationDebug, eagerControllers, lazyControllers } from './controllers.js';
|
||
|
|
||
|
const controllerAttribute = 'data-controller';
|
||
|
const loadControllers = (application, eagerControllers, lazyControllers) => {
|
||
|
for (const name in eagerControllers) {
|
||
|
registerController(name, eagerControllers[name], application);
|
||
|
}
|
||
|
const lazyControllerHandler = new StimulusLazyControllerHandler(application, lazyControllers);
|
||
|
lazyControllerHandler.start();
|
||
|
};
|
||
|
const startStimulusApp = () => {
|
||
|
const application = Application.start();
|
||
|
application.debug = isApplicationDebug;
|
||
|
loadControllers(application, eagerControllers, lazyControllers);
|
||
|
return application;
|
||
|
};
|
||
|
class StimulusLazyControllerHandler {
|
||
|
constructor(application, lazyControllers) {
|
||
|
this.application = application;
|
||
|
this.lazyControllers = lazyControllers;
|
||
|
}
|
||
|
start() {
|
||
|
this.lazyLoadExistingControllers(document.documentElement);
|
||
|
this.lazyLoadNewControllers(document.documentElement);
|
||
|
}
|
||
|
lazyLoadExistingControllers(element) {
|
||
|
this.queryControllerNamesWithin(element).forEach((controllerName) => this.loadLazyController(controllerName));
|
||
|
}
|
||
|
async loadLazyController(name) {
|
||
|
if (canRegisterController(name, this.application)) {
|
||
|
if (this.lazyControllers[name] === undefined) {
|
||
|
return;
|
||
|
}
|
||
|
const controllerModule = await this.lazyControllers[name]();
|
||
|
registerController(name, controllerModule.default, this.application);
|
||
|
}
|
||
|
}
|
||
|
lazyLoadNewControllers(element) {
|
||
|
new MutationObserver((mutationsList) => {
|
||
|
for (const { attributeName, target, type } of mutationsList) {
|
||
|
switch (type) {
|
||
|
case 'attributes': {
|
||
|
if (attributeName === controllerAttribute &&
|
||
|
target.getAttribute(controllerAttribute)) {
|
||
|
extractControllerNamesFrom(target).forEach((controllerName) => this.loadLazyController(controllerName));
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case 'childList': {
|
||
|
this.lazyLoadExistingControllers(target);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}).observe(element, {
|
||
|
attributeFilter: [controllerAttribute],
|
||
|
subtree: true,
|
||
|
childList: true,
|
||
|
});
|
||
|
}
|
||
|
queryControllerNamesWithin(element) {
|
||
|
return Array.from(element.querySelectorAll(`[${controllerAttribute}]`)).flatMap(extractControllerNamesFrom);
|
||
|
}
|
||
|
}
|
||
|
function registerController(name, controller, application) {
|
||
|
if (canRegisterController(name, application)) {
|
||
|
application.register(name, controller);
|
||
|
}
|
||
|
}
|
||
|
function extractControllerNamesFrom(element) {
|
||
|
const controllerNameValue = element.getAttribute(controllerAttribute);
|
||
|
if (!controllerNameValue) {
|
||
|
return [];
|
||
|
}
|
||
|
return controllerNameValue.split(/\s+/).filter((content) => content.length);
|
||
|
}
|
||
|
function canRegisterController(name, application) {
|
||
|
return !application.router.modulesByIdentifier.has(name);
|
||
|
}
|
||
|
|
||
|
export { loadControllers, startStimulusApp };
|