Created
September 21, 2016 13:21
-
-
Save Vheissu/a7939b81f498d4e6e18fd83586522f5d to your computer and use it in GitHub Desktop.
Dynamic using enhance
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div>Stuff here</div> | |
<button click.delegate="loadm1($event)">Load M1</button> | |
<button click.delegate="loadm2($event)">Load M2</button> | |
<button click.delegate="loadm2again($event)">Load Another M2</button> | |
<div id="m1holder"></div> | |
<div id="m2holder"></div> | |
<div id="m2holderagain"></div> | |
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {inject} from 'aurelia-framework'; | |
import {Container} from 'aurelia-dependency-injection'; | |
import {TemplatingEngine, ViewSlot, ViewResources, View } from 'aurelia-templating'; | |
@inject(Container, TemplatingEngine, ViewResources) | |
export class BasicUse { | |
constructor(container:Container, templatingEngine:TemplatingEngine, viewResources:ViewResources){ | |
this.templatingEngine = templatingEngine; | |
this.container = container; | |
this.instruction = { | |
//viewResources: viewResources, | |
//currentController: null | |
}; | |
} | |
loadmod(container, viewmodel){ | |
debugger; | |
var childID = container + "child"; | |
var content = "<div id='containertest'><compose view-model='${viewmodel}' id='"+childID+"'></compose></div>"; | |
$("#" + container).append("<div>" + content + "</div>"); | |
let el = document.getElementById('containertest'); | |
this.templatingEngine.enhance({ element: el, bindingContext: {viewmodel: viewmodel, childID: childID}}); | |
} | |
loadm1(e){ | |
this.loadmod("m1holder", "m1"); | |
} | |
loadm2(e){ | |
this.loadmod("m2holder", "m2"); | |
} | |
loadm2again(e){ | |
this.loadmod("m2holderagain", "m2"); | |
} | |
onSelect(e){ | |
let menuId = $(e.item).children(".k-link").children(".d-menuitem").attr("data-id"); | |
if(typeof(menuId) === 'undefined')return; | |
let menuName = $(e.item).children(".k-link").text(); | |
let moduleDivId = 'module' + (this.tabStrip.items().length + 1); | |
console.log('Selected: ' + menuId + ", " + menuName); | |
this.tabStrip.append({ | |
text: '<span>' + menuName + '</span>', | |
content: '<compose view-model="' + menuId + '" id="' + moduleDivId + '"></compose>', | |
encoded: false | |
}); | |
let el = document.getElementById(moduleDivId); | |
let view = this.templatingEngine.enhance({ element: el, bindingContext: {}, overrideContext: {}}); | |
view.bind(); | |
view.attached(); | |
var tabstrip = $("#tabstrip").data("kendoTabStrip"); | |
var lastTab = tabstrip.tabGroup.children("li").last(); | |
tabstrip.select(lastTab); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {customAttribute,customElement,inlineView,bindable,CompositionEngine,ViewSlot} from 'aurelia-templating'; | |
import {DOM} from 'aurelia-pal'; | |
import {transient,Container} from 'aurelia-dependency-injection'; | |
import {Origin} from 'aurelia-metadata'; | |
/** | |
* An abstract base class for implementors of the basic Renderer API. | |
*/ | |
export class Renderer { | |
/** | |
* Gets an anchor for the ViewSlot to insert a view into. | |
* @returns A DOM element. | |
*/ | |
getDialogContainer(): any { | |
throw new Error('DialogRenderer must implement getDialogContainer().'); | |
} | |
/** | |
* Displays the dialog. | |
* @returns Promise A promise that resolves when the dialog has been displayed. | |
*/ | |
showDialog(dialogController: DialogController): Promise<any> { | |
throw new Error('DialogRenderer must implement showDialog().'); | |
} | |
/** | |
* Hides the dialog. | |
* @returns Promise A promise that resolves when the dialog has been hidden. | |
*/ | |
hideDialog(dialogController: DialogController): Promise<any> { | |
throw new Error('DialogRenderer must implement hideDialog().'); | |
} | |
} | |
/** | |
* Call a lifecycle method on a viewModel if it exists. | |
* @function | |
* @param instance The viewModel instance. | |
* @param name The lifecycle method name. | |
* @param model The model to pass to the lifecycle method. | |
* @returns Promise The result of the lifecycle method. | |
*/ | |
export function invokeLifecycle(instance: any, name: string, model: any) { | |
if (typeof instance[name] === 'function') { | |
let result = instance[name](model); | |
if (result instanceof Promise) { | |
return result; | |
} | |
if (result !== null && result !== undefined) { | |
return Promise.resolve(result); | |
} | |
return Promise.resolve(true); | |
} | |
return Promise.resolve(true); | |
} | |
@customAttribute('attach-focus') | |
export class AttachFocus { | |
static inject = [Element]; | |
value = true; | |
constructor(element) { | |
this.element = element; | |
} | |
attached() { | |
if (this.value && this.value !== 'false') { | |
this.element.focus(); | |
} | |
} | |
valueChanged(newValue) { | |
this.value = newValue; | |
} | |
} | |
@customElement('ai-dialog') | |
@inlineView(` | |
<template> | |
<slot></slot> | |
</template> | |
`) | |
export class AiDialog { | |
} | |
@customElement('ai-dialog-body') | |
@inlineView(` | |
<template> | |
<slot></slot> | |
</template> | |
`) | |
export class AiDialogBody { | |
} | |
/** | |
* The result of a dialog open operation. | |
*/ | |
export class DialogResult { | |
/** | |
* Indicates whether or not the dialog was cancelled. | |
*/ | |
wasCancelled: boolean = false; | |
/** | |
* The data returned from the dialog. | |
*/ | |
output: any; | |
/** | |
* Creates an instance of DialogResult (Used Internally) | |
*/ | |
constructor(cancelled: boolean, output: any) { | |
this.wasCancelled = cancelled; | |
this.output = output; | |
} | |
} | |
export let dialogOptions = { | |
lock: true, | |
centerHorizontalOnly: false, | |
startingZIndex: 1000 | |
}; | |
/** | |
* A controller object for a Dialog instance. | |
*/ | |
export class DialogController { | |
/** | |
* The settings used by this controller. | |
*/ | |
settings: any; | |
/** | |
* Creates an instance of DialogController. | |
*/ | |
constructor(renderer: DialogRenderer, settings: any, resolve: Function, reject: Function) { | |
let defaultSettings = renderer ? renderer.defaultSettings || {} : {}; | |
this.renderer = renderer; | |
this.settings = Object.assign({}, defaultSettings, settings); | |
this._resolve = resolve; | |
this._reject = reject; | |
} | |
/** | |
* Closes the dialog with a successful output. | |
* @param output The returned success output. | |
*/ | |
ok(output?: any): Promise<DialogResult> { | |
return this.close(true, output); | |
} | |
/** | |
* Closes the dialog with a cancel output. | |
* @param output The returned cancel output. | |
*/ | |
cancel(output?: any): Promise<DialogResult> { | |
return this.close(false, output); | |
} | |
/** | |
* Closes the dialog with an error result. | |
* @param message An error message. | |
* @returns Promise An empty promise object. | |
*/ | |
error(message: any): Promise<void> { | |
return invokeLifecycle(this.viewModel, 'deactivate') | |
.then(() => { | |
return this.renderer.hideDialog(this); | |
}).then(() => { | |
this.controller.unbind(); | |
this._reject(message); | |
}); | |
} | |
/** | |
* Closes the dialog. | |
* @param ok Whether or not the user input signified success. | |
* @param output The specified output. | |
* @returns Promise An empty promise object. | |
*/ | |
close(ok: boolean, output?: any): Promise<DialogResult> { | |
return invokeLifecycle(this.viewModel, 'canDeactivate').then(canDeactivate => { | |
if (canDeactivate) { | |
return invokeLifecycle(this.viewModel, 'deactivate') | |
.then(() => { | |
return this.renderer.hideDialog(this); | |
}).then(() => { | |
let result = new DialogResult(!ok, output); | |
this.controller.unbind(); | |
this._resolve(result); | |
return result; | |
}); | |
} | |
return Promise.resolve(); | |
}); | |
} | |
} | |
let containerTagName = 'ai-dialog-container'; | |
let overlayTagName = 'ai-dialog-overlay'; | |
let transitionEvent = (function() { | |
let transition = null; | |
return function() { | |
if (transition) return transition; | |
let t; | |
let el = DOM.createElement('fakeelement'); | |
let transitions = { | |
'transition': 'transitionend', | |
'OTransition': 'oTransitionEnd', | |
'MozTransition': 'transitionend', | |
'WebkitTransition': 'webkitTransitionEnd' | |
}; | |
for (t in transitions) { | |
if (el.style[t] !== undefined) { | |
transition = transitions[t]; | |
return transition; | |
} | |
} | |
}; | |
}()); | |
@transient() | |
export class DialogRenderer { | |
dialogControllers = []; | |
escapeKeyEvent = (e) => { | |
if (e.keyCode === 27) { | |
let top = this.dialogControllers[this.dialogControllers.length - 1]; | |
if (top && top.settings.lock !== true) { | |
top.cancel(); | |
} | |
} | |
}; | |
constructor() { | |
this.defaultSettings = dialogOptions; | |
} | |
getDialogContainer() { | |
return DOM.createElement('div'); | |
} | |
showDialog(dialogController: DialogController) { | |
if (!dialogController.showDialog) { | |
return this._createDialogHost(dialogController).then(() => { | |
return dialogController.showDialog(); | |
}); | |
} | |
return dialogController.showDialog(); | |
} | |
hideDialog(dialogController: DialogController) { | |
return dialogController.hideDialog().then(() => { | |
return dialogController.destroyDialogHost(); | |
}); | |
} | |
_createDialogHost(dialogController: DialogController) { | |
let settings = dialogController.settings; | |
let modalOverlay = DOM.createElement(overlayTagName); | |
let modalContainer = DOM.createElement(containerTagName); | |
let wrapper = document.createElement('div'); | |
let anchor = dialogController.slot.anchor; | |
wrapper.appendChild(anchor); | |
modalContainer.appendChild(wrapper); | |
let body = DOM.querySelectorAll('body')[0]; | |
let closeModalClick = (e) => { | |
if (!settings.lock && !e._aureliaDialogHostClicked) { | |
dialogController.cancel(); | |
} else { | |
return false; | |
} | |
}; | |
let stopPropagation = (e) => { e._aureliaDialogHostClicked = true; }; | |
dialogController.showDialog = (() => { | |
let promise; | |
return () => { | |
if (promise) return promise; | |
if (!this.dialogControllers.length) { | |
DOM.addEventListener('keyup', this.escapeKeyEvent); | |
} | |
this.dialogControllers.push(dialogController); | |
dialogController.slot.attached(); | |
if (typeof settings.position === 'function') { | |
settings.position(modalContainer, modalOverlay); | |
} else { | |
dialogController.centerDialog(); | |
} | |
modalContainer.addEventListener('click', closeModalClick); | |
anchor.addEventListener('click', stopPropagation); | |
promise = new Promise((resolve) => { | |
modalContainer.addEventListener(transitionEvent(), onTransitionEnd); | |
function onTransitionEnd(e) { | |
if (e.target !== modalContainer) { | |
return; | |
} | |
modalContainer.removeEventListener(transitionEvent(), onTransitionEnd); | |
resolve(); | |
} | |
modalOverlay.classList.add('active'); | |
modalContainer.classList.add('active'); | |
body.classList.add('ai-dialog-open'); | |
}); | |
return promise; | |
}; | |
})(); | |
dialogController.hideDialog = (() => { | |
let promise; | |
return () => { | |
modalContainer.removeEventListener('click', closeModalClick); | |
anchor.removeEventListener('click', stopPropagation); | |
let i = this.dialogControllers.indexOf(dialogController); | |
if (i !== -1) { | |
this.dialogControllers.splice(i, 1); | |
} | |
if (!this.dialogControllers.length) { | |
DOM.removeEventListener('keyup', this.escapeKeyEvent); | |
} | |
promise = new Promise((resolve) => { | |
modalContainer.addEventListener(transitionEvent(), onTransitionEnd); | |
function onTransitionEnd() { | |
modalContainer.removeEventListener(transitionEvent(), onTransitionEnd); | |
resolve(); | |
} | |
modalOverlay.classList.remove('active'); | |
modalContainer.classList.remove('active'); | |
if (!this.dialogControllers.length) { | |
body.classList.remove('ai-dialog-open'); | |
} | |
}); | |
return promise; | |
}; | |
})(); | |
dialogController.centerDialog = () => { | |
if (settings.centerHorizontalOnly) return; | |
centerDialog(modalContainer); | |
}; | |
dialogController.destroyDialogHost = (() => { | |
let promise; | |
return () => { | |
if (promise) return promise; | |
body.removeChild(modalOverlay); | |
body.removeChild(modalContainer); | |
dialogController.slot.detached(); | |
promise = Promise.resolve(); | |
return promise; | |
}; | |
})(); | |
modalOverlay.style.zIndex = this.defaultSettings.startingZIndex; | |
modalContainer.style.zIndex = this.defaultSettings.startingZIndex; | |
let lastContainer = Array.from(body.querySelectorAll(containerTagName)).pop(); | |
if (lastContainer) { | |
lastContainer.parentNode.insertBefore(modalContainer, lastContainer.nextSibling); | |
lastContainer.parentNode.insertBefore(modalOverlay, lastContainer.nextSibling); | |
} else { | |
body.insertBefore(modalContainer, body.firstChild); | |
body.insertBefore(modalOverlay, body.firstChild); | |
} | |
return Promise.resolve(); | |
} | |
} | |
function centerDialog(modalContainer) { | |
const child = modalContainer.children[0]; | |
const vh = Math.max(DOM.querySelectorAll('html')[0].clientHeight, window.innerHeight || 0); | |
child.style.marginTop = Math.max((vh - child.offsetHeight) / 2, 30) + 'px'; | |
child.style.marginBottom = Math.max((vh - child.offsetHeight) / 2, 30) + 'px'; | |
} | |
/** | |
* * View-model for footer of Dialog. | |
* */ | |
@customElement('ai-dialog-footer') | |
@inlineView(` | |
<template> | |
<slot></slot> | |
<template if.bind="buttons.length > 0"> | |
<button type="button" class="btn btn-default" repeat.for="button of buttons" click.trigger="close(button)">\${button}</button> | |
</template> | |
</template> | |
`) | |
export class AiDialogFooter { | |
static inject = [DialogController]; | |
@bindable buttons: any[] = []; | |
@bindable useDefaultButtons: boolean = false; | |
constructor(controller: DialogController) { | |
this.controller = controller; | |
} | |
close(buttonValue: string) { | |
if (AiDialogFooter.isCancelButton(buttonValue)) { | |
this.controller.cancel(buttonValue); | |
} else { | |
this.controller.ok(buttonValue); | |
} | |
} | |
useDefaultButtonsChanged(newValue: boolean) { | |
if (newValue) { | |
this.buttons = ['Cancel', 'Ok']; | |
} | |
} | |
static isCancelButton(value: string) { | |
return value === 'Cancel'; | |
} | |
} | |
@customElement('ai-dialog-header') | |
@inlineView(` | |
<template> | |
<button type="button" class="dialog-close" aria-label="Close" if.bind="!controller.settings.lock" click.trigger="controller.cancel()"> | |
<span aria-hidden="true">×</span> | |
</button> | |
<div class="dialog-header-content"> | |
<slot></slot> | |
</div> | |
</template> | |
`) | |
export class AiDialogHeader { | |
static inject = [DialogController]; | |
constructor(controller) { | |
this.controller = controller; | |
} | |
} | |
/** | |
* A service allowing for the creation of dialogs. | |
*/ | |
export class DialogService { | |
static inject = [Container, CompositionEngine]; | |
constructor(container: Container, compositionEngine: CompositionEngine) { | |
this.container = container; | |
this.compositionEngine = compositionEngine; | |
this.controllers = []; | |
this.hasActiveDialog = false; | |
} | |
/** | |
* Opens a new dialog. | |
* @param settings Dialog settings for this dialog instance. | |
* @return Promise A promise that settles when the dialog is closed. | |
*/ | |
open(settings?: Object): Promise<DialogResult> { | |
let dialogController; | |
let promise = new Promise((resolve, reject) => { | |
let childContainer = this.container.createChild(); | |
dialogController = new DialogController(childContainer.get(Renderer), settings, resolve, reject); | |
childContainer.registerInstance(DialogController, dialogController); | |
let host = dialogController.renderer.getDialogContainer(); | |
let instruction = { | |
container: this.container, | |
childContainer: childContainer, | |
model: dialogController.settings.model, | |
viewModel: dialogController.settings.viewModel, | |
viewSlot: new ViewSlot(host, true), | |
host: host | |
}; | |
return _getViewModel(instruction, this.compositionEngine).then(returnedInstruction => { | |
dialogController.viewModel = returnedInstruction.viewModel; | |
dialogController.slot = returnedInstruction.viewSlot; | |
return invokeLifecycle(dialogController.viewModel, 'canActivate', dialogController.settings.model).then(canActivate => { | |
if (canActivate) { | |
this.controllers.push(dialogController); | |
this.hasActiveDialog = !!this.controllers.length; | |
return this.compositionEngine.compose(returnedInstruction).then(controller => { | |
dialogController.controller = controller; | |
dialogController.view = controller.view; | |
return dialogController.renderer.showDialog(dialogController); | |
}); | |
} | |
}); | |
}); | |
}); | |
return promise.then((result) => { | |
let i = this.controllers.indexOf(dialogController); | |
if (i !== -1) { | |
this.controllers.splice(i, 1); | |
this.hasActiveDialog = !!this.controllers.length; | |
} | |
return result; | |
}); | |
} | |
} | |
function _getViewModel(instruction, compositionEngine) { | |
if (typeof instruction.viewModel === 'function') { | |
instruction.viewModel = Origin.get(instruction.viewModel).moduleId; | |
} | |
if (typeof instruction.viewModel === 'string') { | |
return compositionEngine.ensureViewModel(instruction); | |
} | |
return Promise.resolve(instruction); | |
} | |
let defaultRenderer = DialogRenderer; | |
let resources = { | |
'ai-dialog': './ai-dialog', | |
'ai-dialog-header': './ai-dialog-header', | |
'ai-dialog-body': './ai-dialog-body', | |
'ai-dialog-footer': './ai-dialog-footer', | |
'attach-focus': './attach-focus' | |
}; | |
let defaultCSSText = `ai-dialog-container,ai-dialog-overlay{position:fixed;top:0;right:0;bottom:0;left:0}ai-dialog,ai-dialog-container>div>div{min-width:300px;margin:auto;display:block}ai-dialog-overlay{opacity:0}ai-dialog-overlay.active{opacity:1}ai-dialog-container{display:block;transition:opacity .2s linear;opacity:0;overflow-x:hidden;overflow-y:auto;-webkit-overflow-scrolling:touch}ai-dialog-container.active{opacity:1}ai-dialog-container>div{padding:30px}ai-dialog-container>div>div{width:-moz-fit-content;width:-webkit-fit-content;width:fit-content;height:-moz-fit-content;height:-webkit-fit-content;height:fit-content}ai-dialog-container,ai-dialog-container>div,ai-dialog-container>div>div{outline:0}ai-dialog{box-shadow:0 5px 15px rgba(0,0,0,.5);border:1px solid rgba(0,0,0,.2);border-radius:5px;padding:3;width:-moz-fit-content;width:-webkit-fit-content;width:fit-content;height:-moz-fit-content;height:-webkit-fit-content;height:fit-content;border-image-source:initial;border-image-slice:initial;border-image-width:initial;border-image-outset:initial;border-image-repeat:initial;background:#fff}ai-dialog>ai-dialog-header{display:block;padding:16px;border-bottom:1px solid #e5e5e5}ai-dialog>ai-dialog-header>button{float:right;border:none;display:block;width:32px;height:32px;background:0 0;font-size:22px;line-height:16px;margin:-14px -16px 0 0;padding:0;cursor:pointer}ai-dialog>ai-dialog-body{display:block;padding:16px}ai-dialog>ai-dialog-footer{display:block;padding:6px;border-top:1px solid #e5e5e5;text-align:right}ai-dialog>ai-dialog-footer button{color:#333;background-color:#fff;padding:6px 12px;font-size:14px;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid #ccc;border-radius:4px;margin:5px 0 5px 5px}ai-dialog>ai-dialog-footer button:disabled{cursor:default;opacity:.45}ai-dialog>ai-dialog-footer button:hover:enabled{color:#333;background-color:#e6e6e6;border-color:#adadad}.ai-dialog-open{overflow:hidden}`; | |
/** | |
* A configuration builder for the dialog plugin. | |
*/ | |
export class DialogConfiguration { | |
constructor(aurelia) { | |
this.aurelia = aurelia; | |
this.settings = dialogOptions; | |
this.resources = []; | |
this.cssText = defaultCSSText; | |
} | |
/** | |
* Selects the Aurelia conventional defaults for the dialog plugin. | |
* @return This instance. | |
*/ | |
useDefaults(): DialogConfiguration { | |
return this.useRenderer(defaultRenderer) | |
.useCSS(defaultCSSText) | |
.useStandardResources(); | |
} | |
/** | |
* Exports the standard set of dialog behaviors to Aurelia's global resources. | |
* @return This instance. | |
*/ | |
useStandardResources(): DialogConfiguration { | |
return this.useResource('ai-dialog') | |
.useResource('ai-dialog-header') | |
.useResource('ai-dialog-body') | |
.useResource('ai-dialog-footer') | |
.useResource('attach-focus'); | |
} | |
/** | |
* Exports the chosen dialog element or view to Aurelia's global resources. | |
* @param resourceName The name of the dialog resource to export. | |
* @return This instance. | |
*/ | |
useResource(resourceName: string): DialogConfiguration { | |
this.resources.push(resourceName); | |
return this; | |
} | |
/** | |
* Configures the plugin to use a specific dialog renderer. | |
* @param renderer An object with a Renderer interface. | |
* @param settings Global settings for the renderer. | |
* @return This instance. | |
*/ | |
useRenderer(renderer: Renderer, settings?: Object): DialogConfiguration { | |
this.renderer = renderer; | |
this.settings = Object.assign(this.settings, settings || {}); | |
return this; | |
} | |
/** | |
* Configures the plugin to use specific css. | |
* @param cssText The css to use in place of the default styles. | |
* @return This instance. | |
*/ | |
useCSS(cssText: string): DialogConfiguration { | |
this.cssText = cssText; | |
return this; | |
} | |
_apply() { | |
this.aurelia.singleton(Renderer, this.renderer); | |
this.resources.forEach(resourceName => this.aurelia.globalResources(resources[resourceName])); | |
DOM.injectStyles(this.cssText); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Creates an instance of Error that aggregates and preserves an innerError. | |
* @param message The error message. | |
* @param innerError The inner error message to aggregate. | |
* @param skipIfAlreadyAggregate Indicates to not wrap the inner error if it itself already has an innerError. | |
* @return The Error instance. | |
*/ | |
export function AggregateError(message: string, innerError?: Error, skipIfAlreadyAggregate?: boolean): Error { | |
if (innerError) { | |
if (innerError.innerError && skipIfAlreadyAggregate) { | |
return innerError; | |
} | |
const separator = '\n------------------------------------------------\n'; | |
message += `${separator}Inner Error:\n`; | |
if (typeof(innerError) === 'string' ) { | |
message += `Message: ${innerError}`; | |
} else { | |
if (innerError.message) { | |
message += `Message: ${innerError.message}`; | |
} else { | |
message += `Unknown Inner Error Type. Displaying Inner Error as JSON:\n ${JSON.stringify(innerError, null, ' ')}`; | |
} | |
if (innerError.stack) { | |
message += `\nInner Error Stack:\n${innerError.stack}`; | |
message += '\nEnd Inner Error Stack'; | |
} | |
} | |
message += separator; | |
} | |
let e = new Error(message); | |
if (innerError) { | |
e.innerError = innerError; | |
} | |
return e; | |
} | |
/** | |
* Enables discovery of what features the runtime environment supports. | |
*/ | |
interface Feature { | |
/** | |
* Does the runtime environment support ShadowDOM? | |
*/ | |
shadowDOM: boolean; | |
/** | |
* Does the runtime environment support the css scoped attribute? | |
*/ | |
scopedCSS: boolean; | |
/** | |
* Does the runtime environment support native HTMLTemplateElement? | |
*/ | |
htmlTemplateElement: boolean; | |
/** | |
* Does the runtime environment support native DOM mutation observers? | |
*/ | |
mutationObserver: boolean; | |
} | |
/** | |
* The singleton instance of the Feature discovery API. | |
*/ | |
export const FEATURE: Feature = {}; | |
/** | |
* The runtime's performance API. | |
*/ | |
interface Performance { | |
/** | |
* Gets a DOMHighResTimeStamp. | |
* @return The timestamp, measured in milliseconds, accurate to one thousandth of a millisecond. | |
*/ | |
now(): number; | |
} | |
/** | |
* Represents the core APIs of the runtime environment. | |
*/ | |
interface Platform { | |
/** | |
* The runtime environment's global. | |
*/ | |
global: any, | |
/** | |
* A function wich does nothing. | |
*/ | |
noop: Function; | |
/** | |
* The runtime's location API. | |
*/ | |
location: Object; | |
/** | |
* The runtime's history API. | |
*/ | |
history: Object; | |
/** | |
* The runtime's performance API | |
*/ | |
performance: Performance; | |
/** | |
* Registers a function to call when the system is ready to update (repaint) the display. | |
* @param callback The function to call. | |
* @return A long integer value, the request id, that uniquely identifies the entry in the callback list. | |
*/ | |
requestAnimationFrame(callback: (animationFrameStart: number) => void): number; | |
/** | |
* The runtime's XMLHttpRequest API. | |
*/ | |
XMLHttpRequest: XMLHttpRequest; | |
/** | |
* Iterate all modules loaded by the script loader. | |
* @param callback A callback that will receive each module id along with the module object. Return true to end enumeration. | |
*/ | |
eachModule(callback: (key: string, value: Object) => boolean): void; | |
/** | |
* Add a global event listener. | |
* @param eventName A string representing the event type to listen for. | |
* @param callback The function that receives a notification when an event of the specified type occurs. | |
* @param capture If true, useCapture indicates that the user wishes to initiate capture. | |
*/ | |
addEventListener(eventName: string, callback: Function, capture?: boolean): void; | |
/** | |
* Remove a global event listener. | |
* @param eventName A string representing the event type to listen for. | |
* @param callback The function to remove from the event. | |
* @param capture Specifies whether the listener to be removed was registered as a capturing listener or not. | |
*/ | |
removeEventListener(eventName: string, callback: Function, capture?: boolean): void; | |
} | |
/** | |
* The singleton instance of the Platform API. | |
*/ | |
export const PLATFORM: Platform = { | |
noop: function() {}, | |
eachModule() {} | |
}; | |
PLATFORM.global = (function() { | |
// Workers don’t have `window`, only `self` | |
if (typeof self !== 'undefined') { | |
return self; | |
} | |
if (typeof global !== 'undefined') { | |
return global; | |
} | |
// Not all environments allow eval and Function | |
// Use only as a last resort: | |
return new Function('return this')(); | |
})(); | |
/** | |
* Represents the core APIs of the DOM. | |
*/ | |
interface Dom { | |
/** | |
* The global DOM Element type. | |
*/ | |
Element: Element; | |
/** | |
* The global DOM SVGElement type. | |
*/ | |
SVGElement: SVGElement; | |
/** | |
* A key representing a DOM boundary. | |
*/ | |
boundary: string; | |
/** | |
* The document title. | |
*/ | |
title: string; | |
/** | |
* The document's active/focused element. | |
*/ | |
activeElement: Element; | |
/** | |
* Add an event listener to the document. | |
* @param eventName A string representing the event type to listen for. | |
* @param callback The function that receives a notification when an event of the specified type occurs. | |
* @param capture If true, useCapture indicates that the user wishes to initiate capture. | |
*/ | |
addEventListener(eventName: string, callback: Function, capture: boolean): void; | |
/** | |
* Remove an event listener from the document. | |
* @param eventName A string representing the event type to listen for. | |
* @param callback The function to remove from the event. | |
* @param capture Specifies whether the listener to be removed was registered as a capturing listener or not. | |
*/ | |
removeEventListener(eventName: string, callback: Function, capture: boolean): void; | |
/** | |
* Adopts a node from an external document. | |
* @param node The node to be adopted. | |
* @return The adopted node able to be used in the document. | |
*/ | |
adoptNode(node: Node): Node; | |
/** | |
* Creates the specified HTML element or an HTMLUnknownElement if the given element name isn't a known one. | |
* @param tagName A string that specifies the type of element to be created. | |
* @return The created element. | |
*/ | |
createElement(tagName: string): Element; | |
/** | |
* Creates a new Text node. | |
* @param text A string to populate the new Text node. | |
* @return A Text node. | |
*/ | |
createTextNode(text: string): Text; | |
/** | |
* Creates a new Comment node. | |
* @param text A string to populate the new Comment node. | |
* @return A Comment node. | |
*/ | |
createComment(text: string): Comment; | |
/** | |
* Creates a new DocumentFragment. | |
* @return A DocumentFragment. | |
*/ | |
createDocumentFragment(): DocumentFragment; | |
/** | |
* Creates a new MutationObserver. | |
* @param callback A callback that will recieve the change records with the mutations. | |
* @return A MutationObservere. | |
*/ | |
createMutationObserver(callback: Function): MutationObserver; | |
/** | |
* Creates a new CustomEvent. | |
* @param eventType A string representing the event type. | |
* @param options An options object specifying bubbles:boolean, cancelable:boolean and/or detail:Object information. | |
* @return A CustomEvent. | |
*/ | |
createCustomEvent(eventType: string, options: Object): CustomEvent; | |
/** | |
* Dispatches an event on the document. | |
* @param evt The event to dispatch. | |
*/ | |
dispatchEvent(evt: Event): void; | |
/** | |
* Gives the values of all the CSS properties of an element after applying the active stylesheets and resolving any basic computation those values may contain. | |
* @param element The Element for which to get the computed style. | |
* @return The computed styles. | |
*/ | |
getComputedStyle(element: Element): CSSStyleDeclaration; | |
/** | |
* Locates an element in the document according to its id. | |
* @param id The id to search the document for. | |
* @return The found element. | |
*/ | |
getElementById(id: string): Element; | |
/** | |
* Performs a query selector on the document and returns all located matches. | |
* @param query The query to use in searching the document. | |
* @return A list of all matched elements in the document. | |
*/ | |
querySelectorAll(query: string): NodeList; | |
/** | |
* Gets the element that is the next sibling of the provided element. | |
* @param element The element whose next sibling is being located. | |
* @return The next sibling Element of the provided Element. | |
*/ | |
nextElementSibling(element: Node): Element; | |
/** | |
* Creates an HTMLTemplateElement using the markup provided. | |
* @param markup A string containing the markup to turn into a template. Note: This string must contain the template element as well. | |
* @return The instance of HTMLTemplateElement that was created from the provided markup. | |
*/ | |
createTemplateFromMarkup(markup: string): Element; | |
/** | |
* Appends a node to the parent, if provided, or the document.body otherwise. | |
* @param newNode The node to append. | |
* @param parentNode The node to append to, otherwise the document.body. | |
*/ | |
appendNode(newNode: Node, parentNode?:Node): void; | |
/** | |
* Replaces a node in the parent with a new node. | |
* @param newNode The node to replace the old node with. | |
* @param node The node that is being replaced. | |
* @param parentNode The node that the current node is parented to. | |
*/ | |
replaceNode(newNode: Node, node: Node, parentNode?: Node): void; | |
/** | |
* Removes the specified node from the parent node. | |
* @param node The node to remove. | |
* @param parentNode The parent node from which the node will be removed. | |
*/ | |
removeNode(node: Node, parentNode?: Node): void; | |
/** | |
* Injects styles into the destination element, or the document.head if no destination is provided. | |
* @param styles The css text to injext. | |
* @param destination The destination element to inject the css text into. If not specified it will default to the document.head. | |
* @param prepend Indicates whether or not the styles should be prepended to the destination. By default they are appended. | |
* @return The Style node that was created. | |
*/ | |
injectStyles(styles: string, destination?: Element, prepend?:boolean): Node; | |
} | |
/** | |
* The singleton instance of the Dom API. | |
*/ | |
export const DOM: Dom = {}; | |
/** | |
* Enables initializing a specific implementation of the Platform Abstraction Layer (PAL). | |
* @param callback Allows providing a callback which configures the three PAL singletons with their platform-specific implementations. | |
*/ | |
export function initializePAL(callback: (platform: Platform, feature: Feature, dom: Dom) => void): void { | |
if (typeof Object.getPropertyDescriptor !== 'function') { | |
Object.getPropertyDescriptor = function(subject, name) { | |
let pd = Object.getOwnPropertyDescriptor(subject, name); | |
let proto = Object.getPrototypeOf(subject); | |
while (typeof pd === 'undefined' && proto !== null) { | |
pd = Object.getOwnPropertyDescriptor(proto, name); | |
proto = Object.getPrototypeOf(proto); | |
} | |
return pd; | |
}; | |
} | |
callback(PLATFORM, FEATURE, DOM); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<title>Aurelia KendoUI bridge</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2016.1.226/styles/kendo.common.min.css"> | |
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2016.1.226/styles/kendo.rtl.min.css"> | |
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2016.1.226/styles/kendo.default.min.css"> | |
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2016.1.226/styles/kendo.mobile.all.min.css"> | |
<script src="https://kendo.cdn.telerik.com/2016.1.226/js/jszip.min.js"></script> | |
<script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script> | |
</head> | |
<body aurelia-app="main"> | |
<h1>Loading...</h1> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.6/system.js"></script> | |
<script src="https://rawgit.com/aurelia-ui-toolkits/aurelia-kendoui-bundles/0.3.5/config2.js"></script> | |
<!--script src="https://rawgit.com/aurelia/dialog/d58eb9c23c602f4339ef1386e206a6041a06d87e/dist/es2015/index.js"></script>--> | |
<script> | |
System.import('aurelia-bootstrapper'); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<input ak-datepicker="k-widget.bind: datepicker" /> | |
${readonly} | |
<button type="button" click.delegate="click($event)">change</button> | |
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {transient} from 'aurelia-dependency-injection'; | |
@transient() | |
export class M1 { | |
click(event){ | |
this.readonly = !this.readonly; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<!--<ak-combobox k-value.two-way="size">--> | |
<!-- <select style="width: 100%;">--> | |
<!-- <option>X-Small</option>--> | |
<!-- <option>Small</option>--> | |
<!-- <option>Medium</option>--> | |
<!-- <option>Large</option>--> | |
<!-- <option>X-Large</option>--> | |
<!-- <option>2X-Large</option>--> | |
<!-- </select>--> | |
<!-- </ak-combobox>--> | |
Value: ${cnt} | |
<button type="button" click.delegate="click($event)">change</button> | |
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class M2 { | |
cnt = 1; | |
click(event){ | |
this.cnt = this.cnt + 1; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function configure(aurelia) { | |
aurelia.use | |
.standardConfiguration() | |
.developmentLogging() | |
.plugin('aurelia-kendoui-bridge', kendo => { | |
debugger; | |
kendo.pro(); | |
} | |
) | |
.plugin('aurelia-dialog', config => { | |
debugger; | |
config.useDefaults(); | |
config.settings.lock = true; | |
config.settings.centerHorizontalOnly = false; | |
config.settings.startingZIndex = 5; | |
}); | |
aurelia.start().then(a => a.setRoot()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment