aurelia-framework
Version:
The aurelia framework brings together all the required core aurelia libraries into a ready-to-go application-building platform.
208 lines (176 loc) • 6.89 kB
text/typescript
import * as TheLogManager from 'aurelia-logging';
import {Container} from 'aurelia-dependency-injection';
import {Loader} from 'aurelia-loader';
import {BindingLanguage, ViewSlot, ViewResources, TemplatingEngine, CompositionTransaction, View, CompositionContext} from 'aurelia-templating';
import {DOM, PLATFORM} from 'aurelia-pal';
import {relativeToFile} from 'aurelia-path';
import {FrameworkConfiguration} from './framework-configuration';
function preventActionlessFormSubmit() {
DOM.addEventListener('submit', evt => {
const target = evt.target as HTMLFormElement;
const action = target.action;
if (target.tagName.toLowerCase() === 'form' && !action) {
evt.preventDefault();
}
}, false);
}
/**
* The framework core that provides the main Aurelia object.
*/
export class Aurelia {
/**
* The DOM Element that Aurelia will attach to.
*/
host: Element;
/**
/**
* The loader used by the application.
*/
loader: Loader;
/**
* The root DI container used by the application.
*/
container: Container;
/**
* The global view resources used by the application.
*/
resources: ViewResources;
/**
* The configuration used during application startup.
*/
use: FrameworkConfiguration;
/** @internal */
private logger: TheLogManager.Logger;
/** @internal */
_started: Promise<this>;
/** @internal */
private hostConfigured: boolean;
/** @internal */
private root: View;
/** @internal */
private configModuleId: string;
/** @internal */
private hostSlot: ViewSlot;
/**
* Creates an instance of Aurelia.
* @param loader The loader for this Aurelia instance to use. If a loader is not specified, Aurelia will use the loader type specified by PLATFORM.Loader.
* @param container The dependency injection container for this Aurelia instance to use. If a container is not specified, Aurelia will create an empty, global container.
* @param resources The resource registry for this Aurelia instance to use. If a resource registry is not specified, Aurelia will create an empty registry.
*/
constructor(loader?: Loader, container?: Container, resources?: ViewResources) {
this.loader = loader || new PLATFORM.Loader();
this.container = container || (new Container()).makeGlobal();
this.resources = resources || new ViewResources();
this.use = new FrameworkConfiguration(this);
this.logger = TheLogManager.getLogger('aurelia');
this.hostConfigured = false;
this.host = null;
this.use.instance(Aurelia, this);
this.use.instance(Loader, this.loader);
this.use.instance(ViewResources, this.resources);
}
/**
* Loads plugins, then resources, and then starts the Aurelia instance.
* @return Returns a Promise with the started Aurelia instance.
*/
start(): Promise<Aurelia> {
if (this._started) {
return this._started;
}
this.logger.info('Aurelia Starting');
return this._started = this.use.apply().then(() => {
preventActionlessFormSubmit();
if (!this.container.hasResolver(BindingLanguage)) {
let message = 'You must configure Aurelia with a BindingLanguage implementation.';
this.logger.error(message);
throw new Error(message);
}
this.logger.info('Aurelia Started');
let evt = DOM.createCustomEvent('aurelia-started', { bubbles: true, cancelable: true });
DOM.dispatchEvent(evt);
return this;
});
}
/**
* Enhances the host's existing elements with behaviors and bindings.
* @param bindingContext A binding context for the enhanced elements.
* @param applicationHost The DOM object that Aurelia will enhance.
* @return Returns a Promise for the current Aurelia instance.
*/
enhance(bindingContext: object = {}, applicationHost: string | Element = null): Promise<Aurelia> {
this._configureHost(applicationHost || DOM.querySelectorAll('body')[0]);
return new Promise(resolve => {
let engine = this.container.get(TemplatingEngine) as TemplatingEngine;
this.root = engine.enhance({container: this.container, element: this.host, resources: this.resources, bindingContext: bindingContext});
this.root.attached();
this._onAureliaComposed();
resolve(this);
});
}
/**
* Instantiates the root component and adds it to the DOM.
* @param root The root component to load upon bootstrap.
* @param applicationHost The DOM object that Aurelia will attach to.
* @return Returns a Promise of the current Aurelia instance.
*/
// eslint-disable-next-line @typescript-eslint/ban-types
setRoot(root: string | Function = null, applicationHost: string | Element = null): Promise<Aurelia> {
let instruction = {} as CompositionContext;
if (this.root && this.root.viewModel && this.root.viewModel.router) {
this.root.viewModel.router.deactivate();
this.root.viewModel.router.reset();
}
this._configureHost(applicationHost);
let engine = this.container.get(TemplatingEngine) as TemplatingEngine;
let transaction = this.container.get(CompositionTransaction);
delete (transaction as any).initialComposition;
if (!root) {
if (this.configModuleId) {
root = relativeToFile('./app', this.configModuleId);
} else {
root = 'app';
}
}
instruction.viewModel = root;
instruction.container = instruction.childContainer = this.container;
instruction.viewSlot = this.hostSlot;
instruction.host = this.host;
return engine.compose(instruction).then((r: View) => {
this.root = r;
instruction.viewSlot.attached();
this._onAureliaComposed();
return this;
});
}
/** @internal */
_configureHost(applicationHost) {
if (this.hostConfigured) {
return;
}
applicationHost = applicationHost || this.host;
if (!applicationHost || typeof applicationHost === 'string') {
this.host = DOM.getElementById(applicationHost || 'applicationHost');
} else {
this.host = applicationHost;
}
if (!this.host) {
throw new Error('No applicationHost was specified.');
}
this.hostConfigured = true;
(this.host as any).aurelia = this;
this.hostSlot = new ViewSlot(this.host, true);
this.hostSlot.transformChildNodesIntoView();
this.container.registerInstance(DOM.boundary, this.host);
}
/** @internal */
_onAureliaComposed() {
let evt = DOM.createCustomEvent('aurelia-composed', { bubbles: true, cancelable: true });
setTimeout(() => DOM.dispatchEvent(evt), 1);
}
}
/** @internal */
declare module 'aurelia-templating' {
interface View {
viewModel: any;
}
}