ng-terminal
Version:
NgTerminal is a terminal component on Angular 17 or higher.
638 lines • 96.4 kB
JavaScript
import { Component, ViewChild, Input, Output, EventEmitter, ChangeDetectionStrategy, } from '@angular/core';
import { Terminal } from '@xterm/xterm';
import { FitAddon } from '@xterm/addon-fit';
import { Subject } from 'rxjs';
import { LinearRenderService, } from './linear-render.service';
import * as i0 from "@angular/core";
import * as i1 from "./logging.service";
import * as i2 from "angular-resizable-element";
import * as i3 from "@angular/common";
import * as i4 from "./global-style/global-style.component";
export class NgTerminalComponent {
/**
* A datsource is an observable where NgTerminal reads charactors.
*/
set _dataSource(dataSource) {
if (!dataSource)
return;
if (this.dataSourceSubscription != undefined)
this.dataSourceSubscription.unsubscribe();
this.dataSource = dataSource;
this.dataSourceSubscription = this.dataSource.subscribe((data) => this.write(data));
}
/**
* Toggle draggable.
*/
set draggable(draggable) {
this._draggable = draggable;
}
get draggable() {
return this._draggable;
}
setMinWidth(width) {
this._minWidthInput = width;
}
setMinHeight(height) {
this._minHeightInput = height;
}
setDraggable(draggable) {
this._draggable = draggable;
this.lastDraggedPosition = undefined; // Reset position values
}
setXtermOptions(options) {
this._xtermOptions = options;
this.linearRender.pushAndHandle({ time: new Date(), type: 'none' });
}
setRows(rows) {
if (this._rowsInput != rows) {
this._rowsInput = rows;
this.linearRender.pushAndHandle({
time: new Date(),
type: 'rowChanged',
});
}
}
setCols(cols) {
if (this._colsInput != cols) {
this._colsInput = cols;
this.linearRender.pushAndHandle({
time: new Date(),
type: 'columnChanged',
});
}
}
setStyle(styleObject) {
if (JSON.stringify(this._stylesInput ?? {}) !=
JSON.stringify(styleObject ?? {})) {
this._stylesInput = styleObject;
this.linearRender.pushAndHandle({
time: new Date(),
type: 'none',
});
}
}
constructor(renderer, //Render is being used for fast rendering without markForCheck().
hostRef, loggingService) {
this.renderer = renderer;
this.hostRef = hostRef;
this.loggingService = loggingService;
this.dataSubject = new Subject();
this.keySubject = new Subject();
this.keyInputSubjectSubscription = undefined;
this.keyEventSubjectSubscription = undefined;
this.allLogsSubjectSubscription = undefined;
this.dataSourceSubscription = undefined;
this.resizableObservers = [];
this.dataSource = undefined;
this.paddingSize = 5;
this.stylesForResizeBox = { display: 'block' };
/**
* @deprecated use (data)='' instead.
* An emitter emits printable characters pushed from xterm's onData() when a user typed on the terminal.
*/
this.keyInputEmitter = new EventEmitter();
/**
* @deprecated use (key)='' instead.
* An emitter emits key and keybaord event pushed from xterm's onKey() when a user typed on the terminal.
*/
this.keyEventEmitter = new EventEmitter();
/**
* An emitter emits printable characters pushed from xterm's onData() when a user typed on the terminal.
*/
this.dataEmitter = this.keyInputEmitter;
/**
* An emitter emits key and keybaord event pushed from xterm's onKey() when a user typed on the terminal.
*/
this.keyEmitter = this.keyEventEmitter;
/**
* An wrapper of {@link ITerminalOptions} for Xterm.
*/
this._xtermOptions = {};
this.lastDraggedPosition = undefined;
this._draggable = false;
this._stylesInput = {};
this.handleToCheckLazyContainer = undefined;
this.lastDetectedWidth = 0;
this.linearRender = new LinearRenderService(hostRef);
}
setup() {
if (this.xterm) {
this.xterm.onData((input) => {
this.dataSubject.next(input);
});
this.xterm.onKey((e) => {
this.keySubject.next(e);
});
}
this.keyInputSubjectSubscription = this.dataSubject.subscribe((data) => {
this.keyInputEmitter.emit(data);
});
this.keyEventSubjectSubscription = this.keySubject.subscribe((e) => {
this.keyEventEmitter.emit(e);
});
this.setupResizeObservers();
// if (ob3) this.resizableObservers.push(ob3);
this.allLogsSubjectSubscription =
this.linearRender.renderObservable.subscribe((change) => {
if (change)
this.coordinateOuterAndTerminal(change);
else
this.coordinateOuterAndTerminal(change);
this.linearRender.handleNextOne();
});
this.linearRender.handleNextOne();
}
/**
* set dimensions
*/
setOuterDimensions(left, top, width, height) {
this.linearRender.pushAndHandle({
time: new Date(),
type: 'dragged',
dragged: { draggedWidth: `${width}px`, draggedHeight: `${height}px` },
});
}
applyStylesToResizeBox() {
Object.keys(this.stylesForResizeBox)
.map((key) => {
return { key, value: this.stylesForResizeBox[key] };
})
.forEach(({ key, value }) => {
if (this.resizeBox) {
if (value)
this.renderer.setStyle(this.resizeBox.nativeElement, key, value);
else {
this.renderer.removeStyle(this.resizeBox.nativeElement, key);
}
}
});
this.stylesForResizeBox = this.stylesForResizeBox; //invalidate
}
ngOnInit() { }
/**
* It creates new terminal in #terminal.
*/
ngAfterViewInit() {
this.fitAddon = new FitAddon();
this.xterm = new Terminal({
allowProposedApi: true,
});
if (!this.terminalOuter.nativeElement.isConnected) {
this.handleToCheckLazyContainer = setInterval(() => {
if (this.terminalOuter.nativeElement.isConnected) {
try {
this.loggingService.log(() => console.debug("The container's been connected."));
this.xterm.open(this.terminalOuter.nativeElement);
this.xterm.loadAddon(this.fitAddon);
this.setup();
this.linearRender.pushAndHandle({ time: new Date(), type: 'none' });
}
finally {
if (this.handleToCheckLazyContainer)
clearInterval(this.handleToCheckLazyContainer);
}
}
}, 500);
}
else {
this.xterm.open(this.terminalOuter.nativeElement);
this.xterm.loadAddon(this.fitAddon);
this.setup();
this.linearRender.pushAndHandle({ time: new Date(), type: 'none' });
}
}
ngOnChanges(changes) {
this.loggingService.log(() => console.group('onChanges'));
this.loggingService.log(() => console.debug('prop: ', changes));
this.loggingService.log(() => console.groupEnd());
if (changes?.['_rowsInput']) {
if (changes?.['_rowsInput']?.previousValue !=
changes?.['_rowsInput']?.currentValue) {
this.linearRender.pushAndHandle({
time: new Date(),
type: 'rowChanged',
});
}
}
if (changes?.['_colsInput']) {
if (changes?.['_colsInput']?.previousValue !=
changes?.['_colsInput']?.currentValue) {
this.linearRender.pushAndHandle({
time: new Date(),
type: 'columnChanged',
});
}
}
if (changes?.['draggable'])
this.linearRender.pushAndHandle({ time: new Date(), type: 'none' });
}
/**
* It serves a callback function to adjust the dimensions of the xterm-screen, xterm-view, and resize box
* after making any changes to the outer box, rows, or columns, or when the resize box is being dragged.
*
* There several factors that affect dimensions, as I mentioned earlier.
* Regardless of whether the draggable feature is on, if new row or column value is input, this value will be applied.
* - Draggable = New specified Row/Column value > Full (Default)
* @param change This argument represents a single change that occured.
* @returns
*/
coordinateOuterAndTerminal(change) {
this.loggingService.log(() => console.debug(`changeList: ${JSON.stringify(change)}`));
if (!this.xterm)
return;
const isHostElementVisible = this.hostRef.nativeElement?.offsetParent !== null;
if (!isHostElementVisible) {
// Do nothing if the host element is invisible.
this.loggingService.log(() => console.debug('`display` of host element was set to `none`'));
return;
}
this.doUpdateXtermStyles();
this.doAdjustDimensionOfResizeBox(change);
this.doAdjustSizeOfXtermScreen(change);
this.doUpdateViewportAndResizeBoxWithPixcelUnit();
}
/**
* apply options to the xterm terminal
* @returns
*/
doUpdateXtermStyles() {
if (!this.xterm)
return;
this.xterm.options = { ...this._xtermOptions };
// apply the theme to the background of the handle
if (this._xtermOptions.theme?.background) {
if (!this.resizeHandleStyleRule)
this.resizeHandleStyleRule = this.findCssStyleRule('.resize-handle[');
if (this.resizeHandleStyleRule)
this.resizeHandleStyleRule.style.backgroundColor =
this._xtermOptions.theme.background;
}
if (this._xtermOptions.theme?.border) {
if (!this.resizeHandleActiveStyleRule)
this.resizeHandleActiveStyleRule =
this.findCssStyleRule('.handle-active');
if (this.resizeHandleActiveStyleRule)
this.resizeHandleActiveStyleRule.style.backgroundColor =
this._xtermOptions.theme.border;
}
}
/**
* If the resize handles are moved, the resize box adjusts to the new dimensions;
* otherwise, it defaults to a maximized size.
* @param change
*/
doAdjustDimensionOfResizeBox(change) {
this.stylesForResizeBox = {
...this.stylesForResizeBox,
...this._stylesInput,
width: this.stylesForResizeBox.width,
height: this.stylesForResizeBox.height,
};
// Reset styles of the resize element
if (change.type === 'dragged') {
const minWidth = this._minWidthInput ?? 24;
const minHeight = this._minHeightInput ?? 24;
const width = parseInt(change.dragged.draggedWidth) > minWidth
? change.dragged.draggedWidth
: `${minWidth}px`;
const height = parseInt(change.dragged.draggedHeight) > minHeight
? change.dragged.draggedHeight
: `${minHeight}px`;
this.stylesForResizeBox.width = width;
this.stylesForResizeBox.height = height;
this.lastDraggedPosition = {
width,
height,
};
this.applyStylesToResizeBox();
}
else if (!(this.draggable && this.lastDraggedPosition)) {
// When `_colsInput` and `draggable` is not enabled,
// it fits the size to the host element.
const currentHostWidth = getComputedStyle(this.hostRef.nativeElement).width;
const detectBoxWidth = getComputedStyle(this.detectBox.nativeElement).width;
let smallParent = false;
if (parseFloat(detectBoxWidth) < parseFloat(currentHostWidth)) {
// the width of the parent is smaller than that of resize-box element
smallParent = true;
}
if (smallParent) {
// It's been written to solve https://github.com/qwefgh90/ng-terminal/issues/79
// If the width of the flex-box (that is the parent of the host element) is smaller than that of child element, the host element is adjusted to the width of child element
// host element: 1000px, resize-box(child): 985px -> host element: 985px, resize-box(child): 970px -> ... -> stop
// This code check if the parent element (that is the parent of `<ng-terminal>), is smaller than `.resize-box`
// and ensures that the width of the `<ng-terminal>` adjusts to match that of the parent element rather than the child elements, in the subsequent events.
this.stylesForResizeBox.width = `${parseFloat(detectBoxWidth)}px`;
this.applyStylesToResizeBox();
}
else {
// but if the dimension of host element is resized, update width and height
// If `_rowsInput` is specified, NgTerminal keep the current height; otherwise, the height is set to 100%
if (!this._rowsInput)
this.stylesForResizeBox.height = '100%';
if (!this._colsInput)
this.stylesForResizeBox.width = '100%';
this.applyStylesToResizeBox();
}
}
}
/**
* This function uses fitAddon() to adjust the dimension of xterm-screen to character unit
* If the draggable value is true or there are no fixed values for the row or column,
* it fits the xterm terminal boxes into the resize box;
* otherwise, it resizes the xterm terminal with specified row and column values.
*/
doAdjustSizeOfXtermScreen(change) {
if (!this.xterm)
return;
if ((change.type == 'rowChanged' && this._rowsInput) ||
(change.type == 'columnChanged' && this._colsInput)) {
this.xterm.resize(this._colsInput ?? this.xterm.cols, this._rowsInput ?? this.xterm.rows);
}
else {
if (this.xterm.element) {
// The fitAddon.fit() operation doesn't recognize the padding values of terminalOuter.
// It seems to be using the padding values of xterm element instead.
// Therefore, we establish a brief time frame to adjust the padding values before and after executing fitAddon.fit().
// If this line is removed, when dragging resize-box vertically, the width is decreased.
this.xterm.element.style.paddingLeft = `${this.paddingSize}px`;
this.printDimension('Before fitAddon.fit() of Xterm');
this.fitAddon?.fit();
this.printDimension('After fitAddon.fit() of Xterm');
this.xterm.element.style.paddingLeft = `${0}px`;
}
}
}
/**
* This functions sets width of the resize box, xterm-viewport and xterm-screen with specific pixel values.
*/
doUpdateViewportAndResizeBoxWithPixcelUnit() {
if (this.xterm?.element) {
let xtermScreen = this.xterm.element.getElementsByClassName('xterm-screen')[0];
let xtermViewport = this.xterm.element.getElementsByClassName('xterm-viewport')[0];
const screenWidth = xtermScreen.clientWidth;
const screenHeight = xtermScreen.clientHeight;
const core = this.underlying._core;
const scrollBarWidth = core.viewport.scrollBarWidth;
const hostWidth = parseInt(getComputedStyle(this.hostRef.nativeElement).width);
// It fixes a bug where the viewport's width isn't updated by fitAddon.fit()
this.renderer.setStyle(xtermViewport, 'width', `${screenWidth + scrollBarWidth}px`);
// It adjusts the dimension of the resize box to the xterm-screen element.
const calulatedBoxWidth = screenWidth + scrollBarWidth + this.paddingSize * 2;
const componentElement = this.hostRef.nativeElement;
const componentWith = parseInt(getComputedStyle(componentElement).width);
const restrictedWidth = calulatedBoxWidth > componentWith ? componentWith : calulatedBoxWidth;
this.stylesForResizeBox = {
...this.stylesForResizeBox,
width: `${restrictedWidth}px`,
height: `${screenHeight + this.paddingSize * 2}px`,
};
this.applyStylesToResizeBox();
this.printDimension('After update the dimensions for all boxes with pixel values');
}
}
printDimension(title) {
if (this.xterm?.element) {
let resizeBox = this.resizeBox.nativeElement;
let xtermScreen = this.xterm.element.getElementsByClassName('xterm-screen')[0];
let xtermViewport = this.xterm.element.getElementsByClassName('xterm-viewport')[0];
const screenWidth = xtermScreen.clientWidth;
const screenHeight = xtermScreen.clientHeight;
this.loggingService.log(() => console.group(`${title}`));
this.loggingService.log(() => console.debug(`width(resizeBox): ${getComputedStyle(resizeBox).width},
width(viewport): ${getComputedStyle(xtermViewport).width},
width(screen): ${screenWidth}
scrollBarWidth: ${this.scrollBarWidth}`));
this.loggingService.log(() => console.debug(`height(resizeBox): ${getComputedStyle(resizeBox).height},
height(viewport) ${getComputedStyle(xtermViewport).height},
height(screen): ${screenHeight}`));
this.loggingService.log(() => console.groupEnd());
}
}
/**
* If pushAndHandle() were used, there could be an issue
* because it can adjust the size of elements during a loop of ResizeObserver.
*/
setupResizeObservers() {
this.resizableObservers = [];
let ob1 = this.observeXtermViewportDimension();
let ob2 = this.observeHostDimension();
if (ob1)
this.resizableObservers.push(ob1);
if (ob2)
this.resizableObservers.push(ob2);
}
observeXtermViewportDimension() {
let xtermViewport = this.terminalOuter.nativeElement.querySelector('.xterm-viewport');
if (xtermViewport) {
const resizeObserver = new ResizeObserver((entries) => {
const outerDivWidth = this.terminalOuter.nativeElement?.clientWidth;
const outerDivHeight = this.terminalOuter.nativeElement?.clientHeight;
for (let entry of entries) {
if (entry.contentBoxSize.length > 0) {
let width = entry.target.clientWidth;
let height = entry.target.clientHeight;
if ((outerDivWidth && width > outerDivWidth) ||
(outerDivHeight && height > outerDivHeight)) {
this.loggingService.log(() => console.debug('Changes on a xterm viewport element will be handled.'));
this.linearRender.pushAndHandle({
time: new Date(),
type: 'xtermViewportExceedingOuterDiv',
xtermViewportExceedingOuterDiv: {
width: `${width}`,
height: `${height}`,
outerDivWidth: `${outerDivWidth}`,
outerDivHeight: `${outerDivHeight}`,
},
}, true);
}
}
}
});
resizeObserver.observe(xtermViewport);
return resizeObserver;
}
else {
this.loggingService.log(() => console.error('Invalid state is detected. xterm element should exist below .terminal-outer.'));
}
return undefined;
}
observeHostDimension() {
let hostElement = this.hostRef.nativeElement;
let detectBox = this.detectBox.nativeElement;
if (hostElement && detectBox) {
const resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
if (entry.target === hostElement) {
if (entry.contentBoxSize.length > 0) {
let width = getComputedStyle(entry.target).width;
let height = getComputedStyle(entry.target).height;
if (parseInt(width) >= 0 && parseInt(height) >= 0) {
this.loggingService.log(() => console.debug('Changes on a host element will be handled.'));
this.linearRender.pushAndHandle({
time: new Date(),
type: 'hostResized',
hostResized: { width: `${width}`, height: `${height}` },
}, true);
}
}
}
if (entry.target === detectBox) {
if (entry.contentBoxSize.length > 0) {
let width = getComputedStyle(entry.target).width;
if (parseInt(width) >= 0 &&
parseInt(width) <= this.lastDetectedWidth) {
this.loggingService.log(() => console.debug('Changes on a detect-box element will be handled.'));
this.linearRender.pushAndHandle({
time: new Date(),
type: 'detectBoxResized',
detectBoxResized: { width: `${width}` },
}, true);
}
this.lastDetectedWidth = parseInt(width);
}
}
}
});
resizeObserver.observe(hostElement);
resizeObserver.observe(detectBox);
return resizeObserver;
}
else {
this.loggingService.log(() => console.error('Invalid state is detected. xterm element should exist below .terminal-outer.'));
}
return undefined;
}
/**
* clean all resources
*/
ngOnDestroy() {
this.resizableObservers.forEach((ob) => ob.disconnect());
if (this.keyInputSubjectSubscription)
this.keyInputSubjectSubscription.unsubscribe();
if (this.dataSourceSubscription)
this.dataSourceSubscription.unsubscribe();
if (this.keyEventSubjectSubscription)
this.keyEventSubjectSubscription.unsubscribe();
if (this.allLogsSubjectSubscription)
this.allLogsSubjectSubscription.unsubscribe();
if (this.handleToCheckLazyContainer)
clearInterval(this.handleToCheckLazyContainer);
if (this.xterm)
this.xterm.dispose();
this.loggingService.log(() => console.debug('All resources has been cleaned up.'));
}
write(chars) {
this.xterm?.write(chars);
}
get keyInput() {
return this.dataSubject;
}
onData() {
return this.dataSubject;
}
get keyEventInput() {
return this.keySubject;
}
onKey() {
return this.keySubject;
}
get underlying() {
return this.xterm;
}
get isDraggableOnEdgeActivated() {
// return this.displayOption.activateDraggableOnEdge != undefined && this.displayOption.fixedGrid == undefined;
return this._draggable;
}
get scrollBarWidth() {
const core = this.underlying._core;
return core.viewport.scrollBarWidth;
}
/**
* After user coordinate dimensions of terminal, it's called.
* @param left
* @param top
* @param width
* @param height
*/
onResizeEnd(left, top, width, height) {
this.setOuterDimensions(left, top, width, height);
}
/**
* Before onResizeEnd is called, it valiates dimensions to change.
* @param re dimension to be submitted from resizable stuff
*/
validatorFactory() {
const comp = this;
return (re) => {
if (this._draggable) {
return true;
}
else
return false;
};
}
findCssStyleRule(containingSelector) {
for (let i = 0; i < document.styleSheets.length; i++) {
let sheet = document.styleSheets.item(i);
if (sheet) {
for (let i = 0; i < sheet.cssRules.length; i++) {
let rule = sheet.cssRules.item(i);
if ('selectorText' in rule)
if (rule.selectorText.includes(containingSelector))
return rule;
}
}
}
return undefined;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgTerminalComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i1.LoggingService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: NgTerminalComponent, selector: "ng-terminal", inputs: { _dataSource: ["dataSource", "_dataSource"], _rowsInput: ["rows", "_rowsInput"], _colsInput: ["cols", "_colsInput"], _minWidthInput: ["minWidth", "_minWidthInput"], _minHeightInput: ["minHeight", "_minHeightInput"], draggable: "draggable", _xtermOptions: ["xtermOptions", "_xtermOptions"] }, outputs: { keyInputEmitter: "keyInput", keyEventEmitter: "keyEvent", dataEmitter: "data", keyEmitter: "key" }, providers: [LinearRenderService], viewQueries: [{ propertyName: "terminalOuter", first: true, predicate: ["terminal"], descendants: true, static: true }, { propertyName: "resizeBox", first: true, predicate: ["resizeBox"], descendants: true, static: true }, { propertyName: "detectBox", first: true, predicate: ["detectBox"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<!-- Hierarchy: parent element(user) > host element(ng-terminal) > resize-box element > outer element -->\n<global-style></global-style>\n<div mwlResizable #resizeBox class=\"resize-box\" [validateResize]=\"validatorFactory()\" [enableGhostResize]=\"true\"\n (resizeEnd)=\"onResizeEnd($event.rectangle.left, $event.rectangle.top, $event.rectangle.width??0, $event.rectangle.height??0)\">\n <div #terminal class=\"terminal-outer\">\n </div>\n <div class=\"resize-handle resize-handle-top\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n [resizeEdges]=\"{ top: false }\"></div>\n <div class=\"resize-handle resize-handle-left\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n [resizeEdges]=\"{ left: false }\"></div>\n <div class=\"resize-handle resize-handle-right\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n [resizeEdges]=\"isDraggableOnEdgeActivated ? { right: true } : { right: false }\"></div>\n <div class=\"resize-handle resize-handle-bottom\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n [resizeEdges]=\"isDraggableOnEdgeActivated ? { bottom: true } : { bottom: false }\"></div>\n</div>\n<div #detectBox style=\"width: 100%; height: 0px; position: absolute;\">\n</div>", styles: [".terminal-outer{box-sizing:border-box;height:100%;width:100%;padding:5px}:host{display:block;height:100%;width:100%}.resize-box{box-sizing:border-box;height:100%;width:100%;position:relative}div>.handle-active{z-index:100;background-color:#85858a!important}.resize-handle{background-color:#000}.resize-handle-top.handle-active,.resize-handle-bottom.handle-active{cursor:row-resize}.resize-handle-left.handle-active,.resize-handle-right.handle-active{cursor:col-resize}.resize-handle-top,.resize-handle-bottom{position:absolute;height:5px;width:100%}.resize-handle-top{top:0}.resize-handle-bottom{bottom:0}.resize-handle-left,.resize-handle-right{position:absolute;height:100%;width:5px}.resize-handle-left{left:0;top:0}.resize-handle-right{right:0;top:0}\n"], dependencies: [{ kind: "directive", type: i2.ResizableDirective, selector: "[mwlResizable]", inputs: ["validateResize", "enableGhostResize", "resizeSnapGrid", "resizeCursors", "ghostElementPositioning", "allowNegativeResizes", "mouseMoveThrottleMS"], outputs: ["resizeStart", "resizing", "resizeEnd"], exportAs: ["mwlResizable"] }, { kind: "directive", type: i2.ResizeHandleDirective, selector: "[mwlResizeHandle]", inputs: ["resizeEdges", "resizableContainer"] }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i4.GlobalStyleComponent, selector: "global-style" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgTerminalComponent, decorators: [{
type: Component,
args: [{ selector: 'ng-terminal', providers: [LinearRenderService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Hierarchy: parent element(user) > host element(ng-terminal) > resize-box element > outer element -->\n<global-style></global-style>\n<div mwlResizable #resizeBox class=\"resize-box\" [validateResize]=\"validatorFactory()\" [enableGhostResize]=\"true\"\n (resizeEnd)=\"onResizeEnd($event.rectangle.left, $event.rectangle.top, $event.rectangle.width??0, $event.rectangle.height??0)\">\n <div #terminal class=\"terminal-outer\">\n </div>\n <div class=\"resize-handle resize-handle-top\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n [resizeEdges]=\"{ top: false }\"></div>\n <div class=\"resize-handle resize-handle-left\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n [resizeEdges]=\"{ left: false }\"></div>\n <div class=\"resize-handle resize-handle-right\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n [resizeEdges]=\"isDraggableOnEdgeActivated ? { right: true } : { right: false }\"></div>\n <div class=\"resize-handle resize-handle-bottom\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n [resizeEdges]=\"isDraggableOnEdgeActivated ? { bottom: true } : { bottom: false }\"></div>\n</div>\n<div #detectBox style=\"width: 100%; height: 0px; position: absolute;\">\n</div>", styles: [".terminal-outer{box-sizing:border-box;height:100%;width:100%;padding:5px}:host{display:block;height:100%;width:100%}.resize-box{box-sizing:border-box;height:100%;width:100%;position:relative}div>.handle-active{z-index:100;background-color:#85858a!important}.resize-handle{background-color:#000}.resize-handle-top.handle-active,.resize-handle-bottom.handle-active{cursor:row-resize}.resize-handle-left.handle-active,.resize-handle-right.handle-active{cursor:col-resize}.resize-handle-top,.resize-handle-bottom{position:absolute;height:5px;width:100%}.resize-handle-top{top:0}.resize-handle-bottom{bottom:0}.resize-handle-left,.resize-handle-right{position:absolute;height:100%;width:5px}.resize-handle-left{left:0;top:0}.resize-handle-right{right:0;top:0}\n"] }]
}], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i1.LoggingService }], propDecorators: { keyInputEmitter: [{
type: Output,
args: ['keyInput']
}], keyEventEmitter: [{
type: Output,
args: ['keyEvent']
}], dataEmitter: [{
type: Output,
args: ['data']
}], keyEmitter: [{
type: Output,
args: ['key']
}], _dataSource: [{
type: Input,
args: ['dataSource']
}], _rowsInput: [{
type: Input,
args: ['rows']
}], _colsInput: [{
type: Input,
args: ['cols']
}], _minWidthInput: [{
type: Input,
args: ['minWidth']
}], _minHeightInput: [{
type: Input,
args: ['minHeight']
}], draggable: [{
type: Input,
args: ['draggable']
}], _xtermOptions: [{
type: Input,
args: ['xtermOptions']
}], terminalOuter: [{
type: ViewChild,
args: ['terminal', { static: true }]
}], resizeBox: [{
type: ViewChild,
args: ['resizeBox', { static: true }]
}], detectBox: [{
type: ViewChild,
args: ['detectBox', { static: true }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctdGVybWluYWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvbmctdGVybWluYWwvc3JjL2xpYi9uZy10ZXJtaW5hbC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZy10ZXJtaW5hbC9zcmMvbGliL25nLXRlcm1pbmFsLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBRVQsU0FBUyxFQUVULEtBQUssRUFDTCxNQUFNLEVBQ04sWUFBWSxFQUdaLHVCQUF1QixHQU94QixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQW9CLFFBQVEsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUMxRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFNUMsT0FBTyxFQUFFLE9BQU8sRUFBNEIsTUFBTSxNQUFNLENBQUM7QUFFekQsT0FBTyxFQUNMLG1CQUFtQixHQUVwQixNQUFNLHlCQUF5QixDQUFDOzs7Ozs7QUFVakMsTUFBTSxPQUFPLG1CQUFtQjtJQStDOUI7O09BRUc7SUFDSCxJQUNJLFdBQVcsQ0FBQyxVQUEwQztRQUN4RCxJQUFJLENBQUMsVUFBVTtZQUFFLE9BQU87UUFDeEIsSUFBSSxJQUFJLENBQUMsc0JBQXNCLElBQUksU0FBUztZQUMxQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDNUMsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7UUFDN0IsSUFBSSxDQUFDLHNCQUFzQixHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FDL0QsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FDakIsQ0FBQztJQUNKLENBQUM7SUEwQkQ7O09BRUc7SUFDSCxJQUNJLFNBQVMsQ0FBQyxTQUFrQjtRQUM5QixJQUFJ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