@progress/kendo-angular-common
Version:
Kendo UI for Angular - Utility Package
742 lines (708 loc) • 26.3 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* 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, __extends } from 'tslib';
import { Input, Output, EventEmitter, 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';
var isDocumentAvailable = function () { return typeof document !== 'undefined'; };
var isChanged = function (propertyName, changes, skipFirstChange) {
if (skipFirstChange === void 0) { skipFirstChange = true; }
return (typeof changes[propertyName] !== 'undefined' &&
(!changes[propertyName].isFirstChange() || !skipFirstChange) &&
changes[propertyName].previousValue !== changes[propertyName].currentValue);
};
var anyChanged = function (propertyNames, changes, skipFirstChange) {
if (skipFirstChange === void 0) { skipFirstChange = true; }
return propertyNames.some(function (name) { return isChanged(name, changes, skipFirstChange); });
};
var hasObservers = function (emitter) { return emitter && emitter.observers.length > 0; };
var guid = function () {
var id = "";
for (var i = 0; i < 32; i++) {
var 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;
};
var DraggableDirective = /** @class */ (function () {
function DraggableDirective(element, ngZone) {
this.element = element;
this.ngZone = ngZone;
this.enableDrag = true;
this.kendoPress = new EventEmitter();
this.kendoDrag = new EventEmitter();
this.kendoRelease = new EventEmitter();
}
DraggableDirective.prototype.ngOnInit = function () {
this.toggleDraggable();
};
DraggableDirective.prototype.ngOnChanges = function (changes) {
if (isChanged('enableDrag', changes)) {
this.toggleDraggable();
}
};
DraggableDirective.prototype.ngOnDestroy = function () {
this.destroyDraggable();
};
DraggableDirective.prototype.toggleDraggable = function () {
var _this = this;
if (isDocumentAvailable()) {
this.destroyDraggable();
if (this.enableDrag) {
this.draggable = new Draggable({
drag: function (e) { return _this.kendoDrag.next(e); },
press: function (e) { return _this.kendoPress.next(e); },
release: function (e) { return _this.kendoRelease.next(e); }
});
this.ngZone.runOutsideAngular(function () { return _this.draggable.bindTo(_this.element.nativeElement); });
}
}
};
DraggableDirective.prototype.destroyDraggable = function () {
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);
return DraggableDirective;
}());
/**
* @hidden
*/
var DraggableModule = /** @class */ (function () {
function DraggableModule() {
}
DraggableModule = __decorate([
NgModule({
declarations: [DraggableDirective],
exports: [DraggableDirective],
imports: [CommonModule]
})
], DraggableModule);
return DraggableModule;
}());
var closestInScope = function (node, predicate, scope) {
while (node && node !== scope && !predicate(node)) {
node = node.parentNode;
}
if (node !== scope) {
return node;
}
};
var closest = function (node, predicate) {
while (node && !predicate(node)) {
node = node.parentNode;
}
return node;
};
var contains = function (parent, node, matchSelf) {
if (matchSelf === void 0) { matchSelf = false; }
var outside = !closest(node, function (child) { return child === parent; });
if (outside) {
return false;
}
var el = closest(node, function (child) { return child === node; });
return el && (matchSelf || el !== parent);
};
var findElement = function (node, predicate, matchSelf) {
if (matchSelf === void 0) { matchSelf = true; }
if (!node) {
return;
}
if (matchSelf && predicate(node)) {
return node;
}
node = node.firstChild;
while (node) {
if (node.nodeType === 1) {
var element = findElement(node, predicate);
if (element) {
return element;
}
}
node = node.nextSibling;
}
};
var focusableRegex = /^(?:a|input|select|option|textarea|button|object)$/i;
var isFocusable = function (element) {
if (!element.tagName) {
return false;
}
var tagName = element.tagName.toLowerCase();
var hasTabIndex = Boolean(element.getAttribute('tabIndex'));
var focusable = !element.disabled && focusableRegex.test(tagName);
return focusable || hasTabIndex;
};
var isVisible = function (element) {
var rect = element.getBoundingClientRect();
var hasSize = rect.width > 0 && rect.height > 0;
var 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';
};
var isFocusableWithTabKey = function (element, checkVisibility) {
if (checkVisibility === void 0) { checkVisibility = true; }
if (!isFocusable(element)) {
return false;
}
var tabIndex = element.getAttribute('tabIndex');
var visible = !checkVisibility || isVisible(element);
return visible && tabIndex !== '-1';
};
var findFocusableChild = function (element, checkVisibility) {
if (checkVisibility === void 0) { checkVisibility = true; }
return findElement(element, function (node) { return isFocusableWithTabKey(node, checkVisibility); }, false);
};
var findFocusable = function (element, checkVisibility) {
if (checkVisibility === void 0) { checkVisibility = true; }
return findElement(element, function (node) { return isFocusableWithTabKey(node, checkVisibility); });
};
var toClassList = function (classNames) { return String(classNames).trim().split(' '); };
var hasClasses = function (element, classNames) {
var namesList = toClassList(classNames);
return Boolean(toClassList(element.className).find(function (className) { return namesList.indexOf(className) >= 0; }));
};
var matchesClasses = function (classNames) {
return function (element) { return hasClasses(element, classNames); };
};
var NODE_NAME_PREDICATES = {};
var matchesNodeName = function (nodeName) {
if (!NODE_NAME_PREDICATES[nodeName]) {
NODE_NAME_PREDICATES[nodeName] = function (element) {
return String(element.nodeName).toLowerCase() === nodeName.toLowerCase();
};
}
return NODE_NAME_PREDICATES[nodeName];
};
/**
* Normalizes a scroll position value in RTL mode.
*/
function rtlScrollPosition(position, element, initial) {
var 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
*/
var EventsOutsideAngularDirective = /** @class */ (function () {
function EventsOutsideAngularDirective(element, ngZone, renderer) {
this.element = element;
this.ngZone = ngZone;
this.renderer = renderer;
this.events = {};
}
EventsOutsideAngularDirective.prototype.ngOnInit = function () {
var _this = this;
if (!this.element || !this.element.nativeElement) {
return;
}
var events = this.events;
this.subscriptions = [];
this.ngZone.runOutsideAngular(function () {
for (var name_1 in events) {
if (events.hasOwnProperty(name_1)) {
_this.subscriptions.push(_this.renderer.listen(_this.element.nativeElement, name_1, _this.scope ? events[name_1].bind(_this.scope) : events[name_1]));
}
}
});
};
EventsOutsideAngularDirective.prototype.ngOnDestroy = function () {
if (this.subscriptions) {
for (var 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);
return EventsOutsideAngularDirective;
}());
/**
* @hidden
*/
var EventsModule = /** @class */ (function () {
function EventsModule() {
}
EventsModule = __decorate([
NgModule({
declarations: [EventsOutsideAngularDirective],
exports: [EventsOutsideAngularDirective]
})
], EventsModule);
return EventsModule;
}());
var ResizeService = /** @class */ (function () {
function ResizeService(resizeBatchService) {
this.resizeBatchService = resizeBatchService;
this.resize = new EventEmitter();
this.acceptedSize = false;
this.state = 0 /* Initial */;
}
ResizeService.prototype.acceptSize = function (size) {
if (size === void 0) { size = this.measure(); }
this.lastWidth = size.width;
this.lastHeight = size.height;
this.acceptedSize = true;
};
ResizeService.prototype.checkChanges = function () {
if (!isDocumentAvailable()) {
return;
}
if (this.state === 0 /* Initial */) {
this.state = 1 /* Initializing */;
// batch initial measure
this.resizeBatchService.schedule(this, this.init);
}
};
ResizeService.prototype.destroy = function () {
this.resizeBatchService.cancel(this);
};
ResizeService.prototype.checkSize = function () {
if (!this.parentElement) {
return;
}
var _a = this.measure(), width = _a.width, height = _a.height;
var sameSize = width === this.lastWidth && height === this.lastHeight;
if (sameSize) {
return;
}
this.lastWidth = width;
this.lastHeight = height;
this.acceptedSize = false;
this.resize.emit();
return true;
};
ResizeService.prototype.initSize = function () {
var size = this.measure();
this.lastWidth = size.width;
this.lastHeight = size.height;
};
ResizeService.prototype.measure = function () {
var width = 0;
var height = 0;
if (this.parentElement) {
height = this.parentElement.offsetHeight;
width = this.parentElement.offsetWidth;
}
return { height: height, width: width };
};
return ResizeService;
}());
// tslint:disable:deprecation
var div = function (style) {
var el = document.createElement('div');
el.style.cssText = style;
return el;
};
var computedProp = function (elem, prop) {
return getComputedStyle(elem, null).getPropertyValue(prop);
};
var WRAP_STYLE = 'position: absolute; display: block; left: 0; top: 0; right: 0; bottom: 0; z-index: -1;' +
'overflow: hidden; visibility: hidden;';
var EXPAND_CHILD_STYLE = 'position: absolute; left: 0; top: 0; transition: 0s;';
var SHRINK_CHILD_STYLE = EXPAND_CHILD_STYLE + 'width: 200%; height: 200%;';
var ResizeCompatService = /** @class */ (function (_super) {
__extends(ResizeCompatService, _super);
function ResizeCompatService(resizeBatchService, element, ngZone) {
var _this = _super.call(this, resizeBatchService) || this;
_this.element = element;
_this.ngZone = ngZone;
return _this;
}
ResizeCompatService.prototype.checkChanges = function () {
if (this.state === 2 /* Initialized */) {
if (!this.resizeBatchService.isScheduled(this)) {
this.resizeBatchService.schedule(this, this.checkSize);
}
return;
}
_super.prototype.checkChanges.call(this);
};
ResizeCompatService.prototype.destroy = function () {
_super.prototype.destroy.call(this);
if (this.subscription) {
this.subscription.unsubscribe();
}
if (this.expand) {
var 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;
}
};
ResizeCompatService.prototype.checkSize = function () {
if (_super.prototype.checkSize.call(this)) {
this.reset();
return true;
}
};
ResizeCompatService.prototype.init = function () {
var 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();
};
ResizeCompatService.prototype.render = function () {
var 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);
var shrinkChild = div(SHRINK_CHILD_STYLE);
this.shrink.appendChild(shrinkChild);
element.appendChild(this.shrink);
};
ResizeCompatService.prototype.reset = function () {
var expandChild = this.expandChild;
expandChild.style.width = 100000 + 'px';
expandChild.style.height = 100000 + 'px';
var expand = this.expand;
expand.scrollLeft = 100000;
expand.scrollTop = 100000;
var shrink = this.shrink;
shrink.scrollLeft = 100000;
shrink.scrollTop = 100000;
};
ResizeCompatService.prototype.subscribe = function () {
var _this = this;
this.ngZone.runOutsideAngular(function () {
_this.subscription = merge(fromEvent(_this.shrink, 'scroll'), fromEvent(_this.expand, 'scroll'))
.subscribe(function () {
_this.checkSize();
});
});
};
return ResizeCompatService;
}(ResizeService));
var HAS_OBSERVER = typeof ResizeObserver !== 'undefined';
/**
* @hidden
*/
var ResizeObserverService = /** @class */ (function (_super) {
__extends(ResizeObserverService, _super);
function ResizeObserverService(resizeBatchService, element, ngZone) {
var _this = _super.call(this, resizeBatchService) || this;
_this.element = element;
_this.ngZone = ngZone;
return _this;
}
ResizeObserverService.supported = function () {
return HAS_OBSERVER;
};
ResizeObserverService.prototype.destroy = function () {
_super.prototype.destroy.call(this);
if (this.resizeObserver) {
this.resizeObserver.disconnect();
this.resizeObserver = null;
}
this.parentElement = null;
};
ResizeObserverService.prototype.init = function () {
var _this = this;
this.parentElement = this.element.nativeElement.parentElement;
this.initSize();
this.state = 2 /* Initialized */;
this.ngZone.runOutsideAngular(function () {
_this.resizeObserver = new ResizeObserver(function () {
_this.checkSize();
});
_this.resizeObserver.observe(_this.parentElement);
});
};
return ResizeObserverService;
}(ResizeService));
/* tslint:disable:align */
/**
* @hidden
*/
var ResizeBatchService = /** @class */ (function () {
function ResizeBatchService(ngZone) {
this.ngZone = ngZone;
this.scheduled = [];
this.resolvedPromise = Promise.resolve(null);
this.flush = this.flush.bind(this);
}
ResizeBatchService.prototype.schedule = function (instance, method) {
var _this = this;
this.scheduled.push({ instance: instance, method: method });
if (!this.subscription) {
this.ngZone.runOutsideAngular(function () {
_this.subscription = from(_this.resolvedPromise)
.subscribe(_this.flush);
});
}
};
ResizeBatchService.prototype.isScheduled = function (instance) {
return Boolean(this.scheduled.find(function (item) { return item.instance === instance; }));
};
ResizeBatchService.prototype.cancel = function (instance) {
var scheduled = this.scheduled;
var count = scheduled.length;
for (var idx = 0; idx < count; idx++) {
if (scheduled[idx].instance === instance) {
scheduled.splice(idx, 1);
if (!scheduled.length) {
this.unsubscribe();
}
return;
}
}
};
ResizeBatchService.prototype.ngOnDestroy = function () {
this.unsubscribe();
};
ResizeBatchService.prototype.unsubscribe = function () {
if (this.subscription) {
this.subscription.unsubscribe();
this.subscription = null;
}
};
ResizeBatchService.prototype.flush = function () {
this.scheduled.forEach(function (item) {
item.method.call(item.instance);
});
this.scheduled = [];
this.unsubscribe();
};
ResizeBatchService = __decorate([
Injectable(),
__metadata("design:paramtypes", [NgZone])
], ResizeBatchService);
return ResizeBatchService;
}());
/**
* Emit up to 10 resize events per second by default.
* Chosen as a compromise between responsiveness and performance.
*/
var DEFAULT_RATE_LIMIT = 10;
/**
* Resize Sensor Component
*
* Triggers a "resize" event whenever the parent DOM element size changes.
*/
var ResizeSensorComponent = /** @class */ (function () {
function ResizeSensorComponent(resizeBatchService, element, ngZone) {
var _this = this;
/**
* 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();
var serviceType = ResizeObserverService.supported() ? ResizeObserverService : ResizeCompatService;
this.resizeService = new serviceType(resizeBatchService, element, ngZone);
var throttleTime = 1000 / (this.rateLimit || DEFAULT_RATE_LIMIT);
this.subscription = this.resizeService.resize
.pipe(auditTime(throttleTime))
.subscribe(function () {
if (!_this.resizeService.acceptedSize) {
_this.resize.emit();
}
});
}
ResizeSensorComponent.prototype.ngAfterViewChecked = function () {
this.resizeService.checkChanges();
};
ResizeSensorComponent.prototype.ngOnDestroy = function () {
this.subscription.unsubscribe();
this.resizeService.destroy();
};
ResizeSensorComponent.prototype.acceptSize = function (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);
return ResizeSensorComponent;
}());
var COMPONENT_DIRECTIVES = [ResizeSensorComponent];
/**
* Resize Sensor module
*/
var ResizeSensorModule = /** @class */ (function () {
function ResizeSensorModule() {
}
ResizeSensorModule = __decorate([
NgModule({
declarations: [COMPONENT_DIRECTIVES],
exports: [COMPONENT_DIRECTIVES],
providers: [ResizeBatchService]
})
], ResizeSensorModule);
return ResizeSensorModule;
}());
var KendoInput = /** @class */ (function () {
function KendoInput() {
}
return 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 = {}));
var PreventableEvent = /** @class */ (function () {
function PreventableEvent() {
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.
*/
PreventableEvent.prototype.preventDefault = function () {
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`.
*/
PreventableEvent.prototype.isDefaultPrevented = function () {
return this.prevented;
};
return PreventableEvent;
}());
/**
* 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 };