UNPKG

@progress/kendo-angular-common

Version:
694 lines (660 loc) 22.4 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2020 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { __decorate, __metadata } from 'tslib'; import { EventEmitter, Input, Output, Directive, ElementRef, NgZone, NgModule, Renderer2, Injectable, Component } from '@angular/core'; import Draggable from '@telerik/kendo-draggable'; import { CommonModule } from '@angular/common'; import { auditTime } from 'rxjs/operators'; import { merge, fromEvent, from } from 'rxjs'; const isDocumentAvailable = () => typeof document !== 'undefined'; const isChanged = (propertyName, changes, skipFirstChange = true) => (typeof changes[propertyName] !== 'undefined' && (!changes[propertyName].isFirstChange() || !skipFirstChange) && changes[propertyName].previousValue !== changes[propertyName].currentValue); const anyChanged = (propertyNames, changes, skipFirstChange = true) => propertyNames.some(name => isChanged(name, changes, skipFirstChange)); const hasObservers = (emitter) => emitter && emitter.observers.length > 0; const guid = () => { let id = ""; for (let i = 0; i < 32; i++) { const random = Math.random() * 16 | 0; // tslint:disable-line:no-bitwise if (i === 8 || i === 12 || i === 16 || i === 20) { id += "-"; } // tslint:disable-next-line:no-bitwise id += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)).toString(16); } return id; }; let DraggableDirective = class DraggableDirective { constructor(element, ngZone) { this.element = element; this.ngZone = ngZone; this.enableDrag = true; this.kendoPress = new EventEmitter(); this.kendoDrag = new EventEmitter(); this.kendoRelease = new EventEmitter(); } ngOnInit() { this.toggleDraggable(); } ngOnChanges(changes) { if (isChanged('enableDrag', changes)) { this.toggleDraggable(); } } ngOnDestroy() { this.destroyDraggable(); } toggleDraggable() { if (isDocumentAvailable()) { this.destroyDraggable(); if (this.enableDrag) { this.draggable = new Draggable({ drag: (e) => this.kendoDrag.next(e), press: (e) => this.kendoPress.next(e), release: (e) => this.kendoRelease.next(e) }); this.ngZone.runOutsideAngular(() => this.draggable.bindTo(this.element.nativeElement)); } } } destroyDraggable() { if (this.draggable) { this.draggable.destroy(); this.draggable = null; } } }; __decorate([ Input(), __metadata("design:type", Boolean) ], DraggableDirective.prototype, "enableDrag", void 0); __decorate([ Output(), __metadata("design:type", EventEmitter) ], DraggableDirective.prototype, "kendoPress", void 0); __decorate([ Output(), __metadata("design:type", EventEmitter) ], DraggableDirective.prototype, "kendoDrag", void 0); __decorate([ Output(), __metadata("design:type", EventEmitter) ], DraggableDirective.prototype, "kendoRelease", void 0); DraggableDirective = __decorate([ Directive({ selector: '[kendoDraggable]' }), __metadata("design:paramtypes", [ElementRef, NgZone]) ], DraggableDirective); /** * @hidden */ let DraggableModule = class DraggableModule { }; DraggableModule = __decorate([ NgModule({ declarations: [DraggableDirective], exports: [DraggableDirective], imports: [CommonModule] }) ], DraggableModule); const closestInScope = (node, predicate, scope) => { while (node && node !== scope && !predicate(node)) { node = node.parentNode; } if (node !== scope) { return node; } }; const closest = (node, predicate) => { while (node && !predicate(node)) { node = node.parentNode; } return node; }; const contains = (parent, node, matchSelf = false) => { const outside = !closest(node, (child) => child === parent); if (outside) { return false; } const el = closest(node, (child) => child === node); return el && (matchSelf || el !== parent); }; const findElement = (node, predicate, matchSelf = true) => { if (!node) { return; } if (matchSelf && predicate(node)) { return node; } node = node.firstChild; while (node) { if (node.nodeType === 1) { const element = findElement(node, predicate); if (element) { return element; } } node = node.nextSibling; } }; const focusableRegex = /^(?:a|input|select|option|textarea|button|object)$/i; const isFocusable = (element) => { if (!element.tagName) { return false; } const tagName = element.tagName.toLowerCase(); const hasTabIndex = Boolean(element.getAttribute('tabIndex')); const focusable = !element.disabled && focusableRegex.test(tagName); return focusable || hasTabIndex; }; const isVisible = (element) => { const rect = element.getBoundingClientRect(); const hasSize = rect.width > 0 && rect.height > 0; const hasPosition = rect.x !== 0 && rect.y !== 0; // Elements can have zero size due to styling, but they will still count as visible. // For example, the selection checkbox has no size, but is made visible through styling. return (hasSize || hasPosition) && window.getComputedStyle(element).visibility !== 'hidden'; }; const isFocusableWithTabKey = (element, checkVisibility = true) => { if (!isFocusable(element)) { return false; } const tabIndex = element.getAttribute('tabIndex'); const visible = !checkVisibility || isVisible(element); return visible && tabIndex !== '-1'; }; const findFocusableChild = (element, checkVisibility = true) => { return findElement(element, (node) => isFocusableWithTabKey(node, checkVisibility), false); }; const findFocusable = (element, checkVisibility = true) => { return findElement(element, (node) => isFocusableWithTabKey(node, checkVisibility)); }; const toClassList = (classNames) => String(classNames).trim().split(' '); const hasClasses = (element, classNames) => { const namesList = toClassList(classNames); return Boolean(toClassList(element.className).find((className) => namesList.indexOf(className) >= 0)); }; const matchesClasses = (classNames) => (element) => hasClasses(element, classNames); const NODE_NAME_PREDICATES = {}; const matchesNodeName = (nodeName) => { if (!NODE_NAME_PREDICATES[nodeName]) { NODE_NAME_PREDICATES[nodeName] = (element) => String(element.nodeName).toLowerCase() === nodeName.toLowerCase(); } return NODE_NAME_PREDICATES[nodeName]; }; /** * Normalizes a scroll position value in RTL mode. */ function rtlScrollPosition(position, element, initial) { let result = position; if (initial < 0) { result = -position; } else if (initial > 0) { result = element.scrollWidth - element.offsetWidth - position; } return result; } /* tslint:disable:no-input-rename */ /** * @hidden */ let EventsOutsideAngularDirective = class EventsOutsideAngularDirective { constructor(element, ngZone, renderer) { this.element = element; this.ngZone = ngZone; this.renderer = renderer; this.events = {}; } ngOnInit() { if (!this.element || !this.element.nativeElement) { return; } const events = this.events; this.subscriptions = []; this.ngZone.runOutsideAngular(() => { for (let name in events) { if (events.hasOwnProperty(name)) { this.subscriptions.push(this.renderer.listen(this.element.nativeElement, name, this.scope ? events[name].bind(this.scope) : events[name])); } } }); } ngOnDestroy() { if (this.subscriptions) { for (let idx = 0; idx < this.subscriptions.length; idx++) { this.subscriptions[idx](); } this.subscriptions = null; } } }; __decorate([ Input('kendoEventsOutsideAngular'), __metadata("design:type", Object) ], EventsOutsideAngularDirective.prototype, "events", void 0); __decorate([ Input(), __metadata("design:type", Object) ], EventsOutsideAngularDirective.prototype, "scope", void 0); EventsOutsideAngularDirective = __decorate([ Directive({ selector: '[kendoEventsOutsideAngular]' }), __metadata("design:paramtypes", [ElementRef, NgZone, Renderer2]) ], EventsOutsideAngularDirective); /** * @hidden */ let EventsModule = class EventsModule { }; EventsModule = __decorate([ NgModule({ declarations: [EventsOutsideAngularDirective], exports: [EventsOutsideAngularDirective] }) ], EventsModule); class ResizeService { constructor(resizeBatchService) { this.resizeBatchService = resizeBatchService; this.resize = new EventEmitter(); this.acceptedSize = false; this.state = 0 /* Initial */; } acceptSize(size = this.measure()) { this.lastWidth = size.width; this.lastHeight = size.height; this.acceptedSize = true; } checkChanges() { if (!isDocumentAvailable()) { return; } if (this.state === 0 /* Initial */) { this.state = 1 /* Initializing */; // batch initial measure this.resizeBatchService.schedule(this, this.init); } } destroy() { this.resizeBatchService.cancel(this); } checkSize() { if (!this.parentElement) { return; } const { width, height } = this.measure(); const sameSize = width === this.lastWidth && height === this.lastHeight; if (sameSize) { return; } this.lastWidth = width; this.lastHeight = height; this.acceptedSize = false; this.resize.emit(); return true; } initSize() { const size = this.measure(); this.lastWidth = size.width; this.lastHeight = size.height; } measure() { let width = 0; let height = 0; if (this.parentElement) { height = this.parentElement.offsetHeight; width = this.parentElement.offsetWidth; } return { height, width }; } } // tslint:disable:deprecation const div = style => { const el = document.createElement('div'); el.style.cssText = style; return el; }; const computedProp = (elem, prop) => getComputedStyle(elem, null).getPropertyValue(prop); const WRAP_STYLE = 'position: absolute; display: block; left: 0; top: 0; right: 0; bottom: 0; z-index: -1;' + 'overflow: hidden; visibility: hidden;'; const EXPAND_CHILD_STYLE = 'position: absolute; left: 0; top: 0; transition: 0s;'; const SHRINK_CHILD_STYLE = EXPAND_CHILD_STYLE + 'width: 200%; height: 200%;'; class ResizeCompatService extends ResizeService { constructor(resizeBatchService, element, ngZone) { super(resizeBatchService); this.element = element; this.ngZone = ngZone; } checkChanges() { if (this.state === 2 /* Initialized */) { if (!this.resizeBatchService.isScheduled(this)) { this.resizeBatchService.schedule(this, this.checkSize); } return; } super.checkChanges(); } destroy() { super.destroy(); if (this.subscription) { this.subscription.unsubscribe(); } if (this.expand) { const element = this.element.nativeElement; element.removeChild(this.expand); element.removeChild(this.shrink); this.expand.removeChild(this.expandChild); this.expand = this.expandChild = this.shrink = this.element = null; } } checkSize() { if (super.checkSize()) { this.reset(); return true; } } init() { const parentElement = this.parentElement = this.element.nativeElement.parentElement; if (computedProp(parentElement, 'position') === 'static') { parentElement.style.position = 'relative'; } this.state = 2 /* Initialized */; this.render(); this.reset(); this.initSize(); this.subscribe(); } render() { const element = this.element.nativeElement; element.style.cssText = WRAP_STYLE; element.setAttribute('dir', 'ltr'); this.expand = div(WRAP_STYLE); this.expandChild = div(EXPAND_CHILD_STYLE); this.expand.appendChild(this.expandChild); element.appendChild(this.expand); this.shrink = div(WRAP_STYLE); const shrinkChild = div(SHRINK_CHILD_STYLE); this.shrink.appendChild(shrinkChild); element.appendChild(this.shrink); } reset() { const expandChild = this.expandChild; expandChild.style.width = 100000 + 'px'; expandChild.style.height = 100000 + 'px'; const expand = this.expand; expand.scrollLeft = 100000; expand.scrollTop = 100000; const shrink = this.shrink; shrink.scrollLeft = 100000; shrink.scrollTop = 100000; } subscribe() { this.ngZone.runOutsideAngular(() => { this.subscription = merge(fromEvent(this.shrink, 'scroll'), fromEvent(this.expand, 'scroll')) .subscribe(() => { this.checkSize(); }); }); } } const HAS_OBSERVER = typeof ResizeObserver !== 'undefined'; /** * @hidden */ class ResizeObserverService extends ResizeService { constructor(resizeBatchService, element, ngZone) { super(resizeBatchService); this.element = element; this.ngZone = ngZone; } static supported() { return HAS_OBSERVER; } destroy() { super.destroy(); if (this.resizeObserver) { this.resizeObserver.disconnect(); this.resizeObserver = null; } this.parentElement = null; } init() { this.parentElement = this.element.nativeElement.parentElement; this.initSize(); this.state = 2 /* Initialized */; this.ngZone.runOutsideAngular(() => { this.resizeObserver = new ResizeObserver(() => { this.checkSize(); }); this.resizeObserver.observe(this.parentElement); }); } } /* tslint:disable:align */ /** * @hidden */ let ResizeBatchService = class ResizeBatchService { constructor(ngZone) { this.ngZone = ngZone; this.scheduled = []; this.resolvedPromise = Promise.resolve(null); this.flush = this.flush.bind(this); } schedule(instance, method) { this.scheduled.push({ instance, method }); if (!this.subscription) { this.ngZone.runOutsideAngular(() => { this.subscription = from(this.resolvedPromise) .subscribe(this.flush); }); } } isScheduled(instance) { return Boolean(this.scheduled.find(item => item.instance === instance)); } cancel(instance) { const scheduled = this.scheduled; const count = scheduled.length; for (let idx = 0; idx < count; idx++) { if (scheduled[idx].instance === instance) { scheduled.splice(idx, 1); if (!scheduled.length) { this.unsubscribe(); } return; } } } ngOnDestroy() { this.unsubscribe(); } unsubscribe() { if (this.subscription) { this.subscription.unsubscribe(); this.subscription = null; } } flush() { this.scheduled.forEach(item => { item.method.call(item.instance); }); this.scheduled = []; this.unsubscribe(); } }; ResizeBatchService = __decorate([ Injectable(), __metadata("design:paramtypes", [NgZone]) ], ResizeBatchService); /** * Emit up to 10 resize events per second by default. * Chosen as a compromise between responsiveness and performance. */ const DEFAULT_RATE_LIMIT = 10; /** * Resize Sensor Component * * Triggers a "resize" event whenever the parent DOM element size changes. */ let ResizeSensorComponent = class ResizeSensorComponent { constructor(resizeBatchService, element, ngZone) { /** * The maximum number of resize events to emit per second. * * Defaults to 10. */ this.rateLimit = DEFAULT_RATE_LIMIT; /** * Fires when the parent DOM element has been resized. */ this.resize = new EventEmitter(); const serviceType = ResizeObserverService.supported() ? ResizeObserverService : ResizeCompatService; this.resizeService = new serviceType(resizeBatchService, element, ngZone); const throttleTime = 1000 / (this.rateLimit || DEFAULT_RATE_LIMIT); this.subscription = this.resizeService.resize .pipe(auditTime(throttleTime)) .subscribe(() => { if (!this.resizeService.acceptedSize) { this.resize.emit(); } }); } ngAfterViewChecked() { this.resizeService.checkChanges(); } ngOnDestroy() { this.subscription.unsubscribe(); this.resizeService.destroy(); } acceptSize(size) { this.resizeService.acceptSize(size); } }; __decorate([ Input(), __metadata("design:type", Number) ], ResizeSensorComponent.prototype, "rateLimit", void 0); __decorate([ Output(), __metadata("design:type", EventEmitter) ], ResizeSensorComponent.prototype, "resize", void 0); ResizeSensorComponent = __decorate([ Component({ selector: 'kendo-resize-sensor', template: '' }), __metadata("design:paramtypes", [ResizeBatchService, ElementRef, NgZone]) ], ResizeSensorComponent); const COMPONENT_DIRECTIVES = [ResizeSensorComponent]; /** * Resize Sensor module */ let ResizeSensorModule = class ResizeSensorModule { }; ResizeSensorModule = __decorate([ NgModule({ declarations: [COMPONENT_DIRECTIVES], exports: [COMPONENT_DIRECTIVES], providers: [ResizeBatchService] }) ], ResizeSensorModule); class KendoInput { } /** * Enum with key codes. */ var Keys; (function (Keys) { Keys[Keys["Alt"] = 18] = "Alt"; Keys[Keys["ArrowDown"] = 40] = "ArrowDown"; Keys[Keys["ArrowLeft"] = 37] = "ArrowLeft"; Keys[Keys["ArrowRight"] = 39] = "ArrowRight"; Keys[Keys["ArrowUp"] = 38] = "ArrowUp"; Keys[Keys["Backspace"] = 8] = "Backspace"; Keys[Keys["Control"] = 17] = "Control"; Keys[Keys["Delete"] = 46] = "Delete"; Keys[Keys["Digit0"] = 48] = "Digit0"; Keys[Keys["Digit1"] = 49] = "Digit1"; Keys[Keys["Digit2"] = 50] = "Digit2"; Keys[Keys["Digit3"] = 51] = "Digit3"; Keys[Keys["Digit4"] = 52] = "Digit4"; Keys[Keys["Digit5"] = 53] = "Digit5"; Keys[Keys["Digit6"] = 54] = "Digit6"; Keys[Keys["Digit7"] = 55] = "Digit7"; Keys[Keys["Digit8"] = 56] = "Digit8"; Keys[Keys["Digit9"] = 57] = "Digit9"; Keys[Keys["End"] = 35] = "End"; Keys[Keys["Enter"] = 13] = "Enter"; Keys[Keys["Escape"] = 27] = "Escape"; Keys[Keys["F1"] = 112] = "F1"; Keys[Keys["F2"] = 113] = "F2"; Keys[Keys["F10"] = 121] = "F10"; Keys[Keys["Home"] = 36] = "Home"; Keys[Keys["Insert"] = 45] = "Insert"; Keys[Keys["KeyA"] = 65] = "KeyA"; Keys[Keys["KeyB"] = 66] = "KeyB"; Keys[Keys["KeyC"] = 67] = "KeyC"; Keys[Keys["KeyD"] = 68] = "KeyD"; Keys[Keys["KeyE"] = 69] = "KeyE"; Keys[Keys["KeyF"] = 70] = "KeyF"; Keys[Keys["KeyG"] = 71] = "KeyG"; Keys[Keys["KeyH"] = 72] = "KeyH"; Keys[Keys["KeyI"] = 73] = "KeyI"; Keys[Keys["KeyJ"] = 74] = "KeyJ"; Keys[Keys["KeyK"] = 75] = "KeyK"; Keys[Keys["KeyL"] = 76] = "KeyL"; Keys[Keys["KeyM"] = 77] = "KeyM"; Keys[Keys["KeyN"] = 78] = "KeyN"; Keys[Keys["KeyO"] = 79] = "KeyO"; Keys[Keys["KeyP"] = 80] = "KeyP"; Keys[Keys["KeyQ"] = 81] = "KeyQ"; Keys[Keys["KeyR"] = 82] = "KeyR"; Keys[Keys["KeyS"] = 83] = "KeyS"; Keys[Keys["KeyT"] = 84] = "KeyT"; Keys[Keys["KeyU"] = 85] = "KeyU"; Keys[Keys["KeyV"] = 86] = "KeyV"; Keys[Keys["KeyW"] = 87] = "KeyW"; Keys[Keys["KeyX"] = 88] = "KeyX"; Keys[Keys["KeyY"] = 89] = "KeyY"; Keys[Keys["KeyZ"] = 90] = "KeyZ"; Keys[Keys["NumpadDecimal"] = 110] = "NumpadDecimal"; Keys[Keys["PageDown"] = 34] = "PageDown"; Keys[Keys["PageUp"] = 33] = "PageUp"; Keys[Keys["Shift"] = 16] = "Shift"; Keys[Keys["Space"] = 32] = "Space"; Keys[Keys["Tab"] = 9] = "Tab"; })(Keys || (Keys = {})); class PreventableEvent { constructor() { this.prevented = false; } /** * Prevents the default action for a specified event. * In this way, the source component suppresses * the built-in behavior that follows the event. */ preventDefault() { this.prevented = true; } /** * Returns `true` if the event was prevented * by any of its subscribers. * * @returns `true` if the default action was prevented. * Otherwise, returns `false`. */ isDefaultPrevented() { return this.prevented; } } /** * Generated bundle index. Do not edit. */ export { ResizeService, PreventableEvent, DraggableDirective, DraggableModule, closestInScope, closest, contains, findElement, findFocusableChild, findFocusable, hasClasses, isFocusableWithTabKey, isFocusable, isVisible, matchesClasses, matchesNodeName, rtlScrollPosition, EventsOutsideAngularDirective, EventsModule, ResizeSensorComponent, ResizeBatchService, ResizeCompatService, ResizeObserverService, ResizeSensorModule, KendoInput, isDocumentAvailable, isChanged, anyChanged, hasObservers, guid, Keys };