aurelia-kendoui-bridge
Version:
A set of Telerik KendoUI wrappers for Aurelia allowing developers to easily use KendoUI components in their Aurelia application.
200 lines (171 loc) • 6.32 kB
JavaScript
import {inject} from 'aurelia-dependency-injection';
import {TemplatingEngine, ViewResources} from 'aurelia-templating';
import {createOverrideContext} from 'aurelia-binding';
import {Util} from './util';
/**
* An adaptor which uses Aurelia's enhance capability to
* compile any template Kendo wants to have compiled
*/
export class TemplateCompiler {
/**
* We don't need to initialize the TemplateCompiler every time a Kendo controls
* is initialized
*/
isInitialized = false;
constructor(templatingEngine, util) {
this.templatingEngine = templatingEngine;
this.util = util;
}
/**
* Initialize the template compiler and
* patch the angular property to retrieve compilation requests
* from Kendo controls
* @param $parent The overrideContext to use when a template gets compiled
*/
initialize() {
if (this.isInitialized) return;
if (!window.kendo) return;
// all controls derive from kendo.ui.Widget
// override the angular property on these objects, and point it towards handleTemplateEvents
let _this = this;
kendo.ui.Widget.prototype.angular = function(_event, _args) {
_this.handleTemplateEvents(this, _event, _args);
};
kendo.mobile.ui.Widget.prototype.angular = function(_event, _args) {
_this.handleTemplateEvents(this, _event, _args);
};
this.isInitialized = true;
}
/**
* Gets called by Kendo, and filters out compile and cleanup events,
* then calls the compile or cleanup function with the needed arguments
* @param _event Events like 'compile' or 'cleanup'
* @param _args optional array of dataitems
*/
handleTemplateEvents(widget, _event: string, _args?) {
if (_event !== 'compile' && _event !== 'cleanup') return;
// pull the parent context of the widget, or of the options
// in some cases, templates are compiled when a Kendo control's constructor is called
// in these cases we get the parent context of the options instead of the
// widget
let $parent;
let container;
let $angular = widget.$angular || widget.options.$angular;
if ($angular) {
$parent = $angular[0]._$parent;
container = $angular[0]._$container;
}
if (!$parent) return;
let args = _args();
let elements = args.elements; // extract elements from the args
let data = args.data; // extract the dataitems from the args
let scopeFrom = args.scopeFrom;
switch (_event) {
case 'compile':
// we need to pass elements and data to compile
// so that Aurelia can enhance this elements with the correct
// binding context
this.compile($parent, elements, data, scopeFrom, container);
break;
case 'cleanup':
// we don't care about dataitems when we do the cleanup
// so we just pass in the DOM elements
this.cleanup(elements);
break;
default:
break;
}
}
/**
* loops through each element, and find the matching dataitem
* and calls enhanceView(element, dataItem) for each element there is
* @param elements an array of Elements or a kendo.jQuery selector
* @param data optionally an array of dataitems
*/
compile($parent, elements, data, scopeFrom, container) {
for (let i = 0; i < elements.length; i++) {
let element = elements[i];
let ctx = undefined;
if (data && data[i]) {
let _data = data[i];
let dataItem = _data.dataItem || _data.aggregate || _data;
if (!this.util.isObject(dataItem)) {
ctx = {
dataItem: dataItem
};
} else {
ctx = dataItem;
}
} else if (scopeFrom) {
ctx = scopeFrom;
}
if (element instanceof kendo.jQuery) {
element.each((index, elem) => this.enhanceView($parent, elem, ctx, container));
} else {
this.enhanceView($parent, element, ctx, container);
}
}
}
/**
* uses the enhance function of Aurelia's TemplatingEngine
* to "compile" existing DOM elements
* @param element The Element to compile
* @param ctx The dataitem (context) to compile the Element with
*/
enhanceView($parent, element, ctx, container) {
let view = kendo.jQuery(element).data('viewInstance');
kendo.jQuery(element).data('$$kendoScope', ctx);
// check necessary due to https://github.com/aurelia-ui-toolkits/aurelia-kendoui-bridge/issues/308
if (element.querySelectorAll('.au-target').length === 0) {
if (container) {
let childContainer = container.createChild();
let resources = container.get(ViewResources);
view = this.templatingEngine.enhance({
bindingContext: ctx,
overrideContext: createOverrideContext(ctx, $parent),
container: childContainer,
element: element,
resources: resources
});
} else {
view = this.templatingEngine.enhance({
bindingContext: ctx,
overrideContext: createOverrideContext(ctx, $parent),
element: element
});
}
// when we do cleanup, we need to get the view instance
// so we can call detached/unbind
// so we store this view instance in the DOM element using kendo.jQuery.data
kendo.jQuery(element).data('viewInstance', view);
} else {
view.bind(ctx, createOverrideContext(ctx, $parent));
}
view.attached(); // attach it to the DOM
}
/**
* loops through each element kendo asks us to clean up
* calls cleanupView() for each element
* @param element An array of elements
*/
cleanup(elements) {
if (!elements) return;
for (let i = 0; i < elements.length; i++) {
let element = elements[i];
this.cleanupView(element);
}
}
/**
* cleans up the view kendo has asked us to clean up
*/
cleanupView(element) {
// extract Aurelia's View instance from the element
// we stored this in the enhanceView function
let view = kendo.jQuery(element).data('viewInstance');
if (!view) return;
// unbind and detach the view
view.detached();
view.unbind();
}
}