mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Support setting padding on the .xterm element (#1208)
* Support padding on the .xterm element
This commit is contained in:
@@ -64,6 +64,10 @@
|
|||||||
<label for="rows">Rows</label>
|
<label for="rows">Rows</label>
|
||||||
<input type="number" id="rows" />
|
<input type="number" id="rows" />
|
||||||
</div>
|
</div>
|
||||||
|
<div style="display: inline-block; margin-right: 16px;">
|
||||||
|
<label for="padding">Padding</label>
|
||||||
|
<input type="number" id="padding" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+11
-6
@@ -33,23 +33,27 @@ var terminalContainer = document.getElementById('terminal-container'),
|
|||||||
bellStyle: document.querySelector('#option-bell-style')
|
bellStyle: document.querySelector('#option-bell-style')
|
||||||
},
|
},
|
||||||
colsElement = document.getElementById('cols'),
|
colsElement = document.getElementById('cols'),
|
||||||
rowsElement = document.getElementById('rows');
|
rowsElement = document.getElementById('rows'),
|
||||||
|
paddingElement = document.getElementById('padding');
|
||||||
|
|
||||||
function setTerminalSize() {
|
function setTerminalSize() {
|
||||||
var cols = parseInt(colsElement.value, 10);
|
var cols = parseInt(colsElement.value, 10);
|
||||||
var rows = parseInt(rowsElement.value, 10);
|
var rows = parseInt(rowsElement.value, 10);
|
||||||
var viewportElement = document.querySelector('.xterm-viewport');
|
var width = (cols * term.renderer.dimensions.actualCellWidth + term.viewport.scrollBarWidth).toString() + 'px';
|
||||||
var scrollBarWidth = viewportElement.offsetWidth - viewportElement.clientWidth;
|
|
||||||
var width = (cols * term.renderer.dimensions.actualCellWidth + 20 /*room for scrollbar*/).toString() + 'px';
|
|
||||||
var height = (rows * term.renderer.dimensions.actualCellHeight).toString() + 'px';
|
var height = (rows * term.renderer.dimensions.actualCellHeight).toString() + 'px';
|
||||||
|
|
||||||
terminalContainer.style.width = width;
|
terminalContainer.style.width = width;
|
||||||
terminalContainer.style.height = height;
|
terminalContainer.style.height = height;
|
||||||
term.resize(cols, rows);
|
term.fit();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPadding() {
|
||||||
|
term.element.style.padding = parseInt(paddingElement.value, 10).toString() + 'px';
|
||||||
|
term.fit();
|
||||||
}
|
}
|
||||||
|
|
||||||
colsElement.addEventListener('change', setTerminalSize);
|
colsElement.addEventListener('change', setTerminalSize);
|
||||||
rowsElement.addEventListener('change', setTerminalSize);
|
rowsElement.addEventListener('change', setTerminalSize);
|
||||||
|
paddingElement.addEventListener('change', setPadding);
|
||||||
|
|
||||||
actionElements.findNext.addEventListener('keypress', function (e) {
|
actionElements.findNext.addEventListener('keypress', function (e) {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
@@ -119,6 +123,7 @@ function createTerminal() {
|
|||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
colsElement.value = term.cols;
|
colsElement.value = term.cols;
|
||||||
rowsElement.value = term.rows;
|
rowsElement.value = term.rows;
|
||||||
|
paddingElement.value = 0;
|
||||||
|
|
||||||
// Set terminal size again to set the specific dimensions on the demo
|
// Set terminal size again to set the specific dimensions on the demo
|
||||||
setTerminalSize();
|
setTerminalSize();
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
|
|||||||
* @param event The mouse event.
|
* @param event The mouse event.
|
||||||
*/
|
*/
|
||||||
private _getMouseBufferCoords(event: MouseEvent): [number, number] {
|
private _getMouseBufferCoords(event: MouseEvent): [number, number] {
|
||||||
const coords = this._terminal.mouseHelper.getCoords(event, this._terminal.element, this._charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows, true);
|
const coords = this._terminal.mouseHelper.getCoords(event, this._terminal.screenElement, this._charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows, true);
|
||||||
if (!coords) {
|
if (!coords) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -329,7 +329,7 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
|
|||||||
* @param event The mouse event.
|
* @param event The mouse event.
|
||||||
*/
|
*/
|
||||||
private _getMouseEventScrollAmount(event: MouseEvent): number {
|
private _getMouseEventScrollAmount(event: MouseEvent): number {
|
||||||
let offset = MouseHelper.getCoordsRelativeToElement(event, this._terminal.element)[1];
|
let offset = MouseHelper.getCoordsRelativeToElement(event, this._terminal.screenElement)[1];
|
||||||
const terminalHeight = this._terminal.rows * Math.ceil(this._charMeasure.height * this._terminal.options.lineHeight);
|
const terminalHeight = this._terminal.rows * Math.ceil(this._charMeasure.height * this._terminal.options.lineHeight);
|
||||||
if (offset >= 0 && offset <= terminalHeight) {
|
if (offset >= 0 && offset <= terminalHeight) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+11
-7
@@ -96,6 +96,7 @@ const DEFAULT_OPTIONS: ITerminalOptions = {
|
|||||||
export class Terminal extends EventEmitter implements ITerminal, IInputHandlingTerminal {
|
export class Terminal extends EventEmitter implements ITerminal, IInputHandlingTerminal {
|
||||||
public textarea: HTMLTextAreaElement;
|
public textarea: HTMLTextAreaElement;
|
||||||
public element: HTMLElement;
|
public element: HTMLElement;
|
||||||
|
public screenElement: HTMLElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The HTMLElement that the terminal is created in, set by Terminal.open.
|
* The HTMLElement that the terminal is created in, set by Terminal.open.
|
||||||
@@ -609,15 +610,18 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
|
|||||||
this.viewportScrollArea.classList.add('xterm-scroll-area');
|
this.viewportScrollArea.classList.add('xterm-scroll-area');
|
||||||
this.viewportElement.appendChild(this.viewportScrollArea);
|
this.viewportElement.appendChild(this.viewportScrollArea);
|
||||||
|
|
||||||
this._mouseZoneManager = new MouseZoneManager(this);
|
this.screenElement = document.createElement('div');
|
||||||
this.on('scroll', () => this._mouseZoneManager.clearAll());
|
this.screenElement.classList.add('xterm-screen');
|
||||||
this.linkifier.attachToDom(this._mouseZoneManager);
|
|
||||||
|
|
||||||
// Create the container that will hold helpers like the textarea for
|
// Create the container that will hold helpers like the textarea for
|
||||||
// capturing DOM Events. Then produce the helpers.
|
// capturing DOM Events. Then produce the helpers.
|
||||||
this.helperContainer = document.createElement('div');
|
this.helperContainer = document.createElement('div');
|
||||||
this.helperContainer.classList.add('xterm-helpers');
|
this.helperContainer.classList.add('xterm-helpers');
|
||||||
fragment.appendChild(this.helperContainer);
|
this.screenElement.appendChild(this.helperContainer);
|
||||||
|
fragment.appendChild(this.screenElement);
|
||||||
|
|
||||||
|
this._mouseZoneManager = new MouseZoneManager(this);
|
||||||
|
this.on('scroll', () => this._mouseZoneManager.clearAll());
|
||||||
|
this.linkifier.attachToDom(this._mouseZoneManager);
|
||||||
|
|
||||||
this.textarea = document.createElement('textarea');
|
this.textarea = document.createElement('textarea');
|
||||||
this.textarea.classList.add('xterm-helper-textarea');
|
this.textarea.classList.add('xterm-helper-textarea');
|
||||||
@@ -735,7 +739,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
|
|||||||
button = getButton(ev);
|
button = getButton(ev);
|
||||||
|
|
||||||
// get mouse coordinates
|
// get mouse coordinates
|
||||||
pos = self.mouseHelper.getRawByteCoords(ev, self.element, self.charMeasure, self.options.lineHeight, self.cols, self.rows);
|
pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.charMeasure, self.options.lineHeight, self.cols, self.rows);
|
||||||
if (!pos) return;
|
if (!pos) return;
|
||||||
|
|
||||||
sendEvent(button, pos);
|
sendEvent(button, pos);
|
||||||
@@ -761,7 +765,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
|
|||||||
// ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7<
|
// ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7<
|
||||||
function sendMove(ev: MouseEvent): void {
|
function sendMove(ev: MouseEvent): void {
|
||||||
let button = pressed;
|
let button = pressed;
|
||||||
let pos = self.mouseHelper.getRawByteCoords(ev, self.element, self.charMeasure, self.options.lineHeight, self.cols, self.rows);
|
let pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.charMeasure, self.options.lineHeight, self.cols, self.rows);
|
||||||
if (!pos) return;
|
if (!pos) return;
|
||||||
|
|
||||||
// buttons marked as motions
|
// buttons marked as motions
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ export interface IInputHandlingTerminal extends IEventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IViewport {
|
export interface IViewport {
|
||||||
|
scrollBarWidth: number;
|
||||||
syncScrollArea(): void;
|
syncScrollArea(): void;
|
||||||
onWheel(ev: WheelEvent): void;
|
onWheel(ev: WheelEvent): void;
|
||||||
onTouchStart(ev: TouchEvent): void;
|
onTouchStart(ev: TouchEvent): void;
|
||||||
@@ -175,6 +176,7 @@ export interface ILinkHoverEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ITerminal extends PublicTerminal, IElementAccessor, IBufferAccessor, ILinkifierAccessor {
|
export interface ITerminal extends PublicTerminal, IElementAccessor, IBufferAccessor, ILinkifierAccessor {
|
||||||
|
screenElement: HTMLElement;
|
||||||
selectionManager: ISelectionManager;
|
selectionManager: ISelectionManager;
|
||||||
charMeasure: ICharMeasure;
|
charMeasure: ICharMeasure;
|
||||||
renderer: IRenderer;
|
renderer: IRenderer;
|
||||||
@@ -188,6 +190,7 @@ export interface ITerminal extends PublicTerminal, IElementAccessor, IBufferAcce
|
|||||||
buffers: IBufferSet;
|
buffers: IBufferSet;
|
||||||
isFocused: boolean;
|
isFocused: boolean;
|
||||||
mouseHelper: IMouseHelper;
|
mouseHelper: IMouseHelper;
|
||||||
|
viewport: IViewport;
|
||||||
bracketedPasteMode: boolean;
|
bracketedPasteMode: boolean;
|
||||||
applicationCursor: boolean;
|
applicationCursor: boolean;
|
||||||
|
|
||||||
|
|||||||
+9
-7
@@ -7,11 +7,14 @@ import { IColorSet } from './renderer/Types';
|
|||||||
import { ITerminal, IViewport } from './Types';
|
import { ITerminal, IViewport } from './Types';
|
||||||
import { CharMeasure } from './utils/CharMeasure';
|
import { CharMeasure } from './utils/CharMeasure';
|
||||||
|
|
||||||
|
const FALLBACK_SCROLL_BAR_WIDTH = 15;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the viewport of a terminal, the visible area within the larger buffer of output.
|
* Represents the viewport of a terminal, the visible area within the larger buffer of output.
|
||||||
* Logic for the virtual scroll bar is included in this object.
|
* Logic for the virtual scroll bar is included in this object.
|
||||||
*/
|
*/
|
||||||
export class Viewport implements IViewport {
|
export class Viewport implements IViewport {
|
||||||
|
public scrollBarWidth: number = 0;
|
||||||
private currentRowHeight: number = 0;
|
private currentRowHeight: number = 0;
|
||||||
private lastRecordedBufferLength: number = 0;
|
private lastRecordedBufferLength: number = 0;
|
||||||
private lastRecordedViewportHeight: number = 0;
|
private lastRecordedViewportHeight: number = 0;
|
||||||
@@ -31,6 +34,10 @@ export class Viewport implements IViewport {
|
|||||||
private scrollArea: HTMLElement,
|
private scrollArea: HTMLElement,
|
||||||
private charMeasure: CharMeasure
|
private charMeasure: CharMeasure
|
||||||
) {
|
) {
|
||||||
|
// Measure the width of the scrollbar. If it is 0 we can assume it's an OSX overlay scrollbar.
|
||||||
|
// Unfortunately the overlay scrollbar would be hidden underneath the screen element in that case,
|
||||||
|
// therefore we account for a standard amount to make it visible
|
||||||
|
this.scrollBarWidth = (this.viewportElement.offsetWidth - this.scrollArea.offsetWidth) || FALLBACK_SCROLL_BAR_WIDTH;
|
||||||
this.viewportElement.addEventListener('scroll', this.onScroll.bind(this));
|
this.viewportElement.addEventListener('scroll', this.onScroll.bind(this));
|
||||||
|
|
||||||
// Perform this async to ensure the CharMeasure is ready.
|
// Perform this async to ensure the CharMeasure is ready.
|
||||||
@@ -48,13 +55,8 @@ export class Viewport implements IViewport {
|
|||||||
private refresh(): void {
|
private refresh(): void {
|
||||||
if (this.charMeasure.height > 0) {
|
if (this.charMeasure.height > 0) {
|
||||||
this.currentRowHeight = this.terminal.renderer.dimensions.scaledCellHeight / window.devicePixelRatio;
|
this.currentRowHeight = this.terminal.renderer.dimensions.scaledCellHeight / window.devicePixelRatio;
|
||||||
|
this.lastRecordedViewportHeight = this.viewportElement.offsetHeight;
|
||||||
if (this.lastRecordedViewportHeight !== this.terminal.renderer.dimensions.canvasHeight) {
|
const newBufferHeight = Math.round(this.currentRowHeight * this.lastRecordedBufferLength) + (this.lastRecordedViewportHeight - this.terminal.renderer.dimensions.canvasHeight);
|
||||||
this.lastRecordedViewportHeight = this.terminal.renderer.dimensions.canvasHeight;
|
|
||||||
this.viewportElement.style.height = this.lastRecordedViewportHeight + 'px';
|
|
||||||
}
|
|
||||||
|
|
||||||
const newBufferHeight = Math.round(this.currentRowHeight * this.lastRecordedBufferLength);
|
|
||||||
if (this.lastRecordedBufferHeight !== newBufferHeight) {
|
if (this.lastRecordedBufferHeight !== newBufferHeight) {
|
||||||
this.lastRecordedBufferHeight = newBufferHeight;
|
this.lastRecordedBufferHeight = newBufferHeight;
|
||||||
this.scrollArea.style.height = this.lastRecordedBufferHeight + 'px';
|
this.scrollArea.style.height = this.lastRecordedBufferHeight + 'px';
|
||||||
|
|||||||
+10
-5
@@ -28,17 +28,22 @@ export function proposeGeometry(term: Terminal): IGeometry {
|
|||||||
}
|
}
|
||||||
const parentElementStyle = window.getComputedStyle(term.element.parentElement);
|
const parentElementStyle = window.getComputedStyle(term.element.parentElement);
|
||||||
const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));
|
const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));
|
||||||
const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17);
|
const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')));
|
||||||
const elementStyle = window.getComputedStyle(term.element);
|
const elementStyle = window.getComputedStyle(term.element);
|
||||||
const elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom'));
|
const elementPadding = {
|
||||||
const elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left'));
|
top: parseInt(elementStyle.getPropertyValue('padding-top')),
|
||||||
|
bottom: parseInt(elementStyle.getPropertyValue('padding-bottom')),
|
||||||
|
right: parseInt(elementStyle.getPropertyValue('padding-right')),
|
||||||
|
left: parseInt(elementStyle.getPropertyValue('padding-left'))
|
||||||
|
};
|
||||||
|
const elementPaddingVer = elementPadding.top + elementPadding.bottom;
|
||||||
|
const elementPaddingHor = elementPadding.right + elementPadding.left;
|
||||||
const availableHeight = parentElementHeight - elementPaddingVer;
|
const availableHeight = parentElementHeight - elementPaddingVer;
|
||||||
const availableWidth = parentElementWidth - elementPaddingHor;
|
const availableWidth = parentElementWidth - elementPaddingHor - (<any>term).viewport.scrollBarWidth;
|
||||||
const geometry = {
|
const geometry = {
|
||||||
cols: Math.floor(availableWidth / (<any>term).renderer.dimensions.actualCellWidth),
|
cols: Math.floor(availableWidth / (<any>term).renderer.dimensions.actualCellWidth),
|
||||||
rows: Math.floor(availableHeight / (<any>term).renderer.dimensions.actualCellHeight)
|
rows: Math.floor(availableHeight / (<any>term).renderer.dimensions.actualCellHeight)
|
||||||
};
|
};
|
||||||
|
|
||||||
return geometry;
|
return geometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ export class MouseZoneManager implements IMouseZoneManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _findZoneEventAt(e: MouseEvent): IMouseZone {
|
private _findZoneEventAt(e: MouseEvent): IMouseZone {
|
||||||
const coords = this._terminal.mouseHelper.getCoords(e, this._terminal.element, this._terminal.charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows);
|
const coords = this._terminal.mouseHelper.getCoords(e, this._terminal.screenElement, this._terminal.charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows);
|
||||||
if (!coords) {
|
if (!coords) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ export class Renderer extends EventEmitter implements IRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._renderLayers = [
|
this._renderLayers = [
|
||||||
new TextRenderLayer(this._terminal.element, 0, this.colorManager.colors, this._terminal.options.allowTransparency),
|
new TextRenderLayer(this._terminal.screenElement, 0, this.colorManager.colors, this._terminal.options.allowTransparency),
|
||||||
new SelectionRenderLayer(this._terminal.element, 1, this.colorManager.colors),
|
new SelectionRenderLayer(this._terminal.screenElement, 1, this.colorManager.colors),
|
||||||
new LinkRenderLayer(this._terminal.element, 2, this.colorManager.colors, this._terminal),
|
new LinkRenderLayer(this._terminal.screenElement, 2, this.colorManager.colors, this._terminal),
|
||||||
new CursorRenderLayer(this._terminal.element, 3, this.colorManager.colors)
|
new CursorRenderLayer(this._terminal.screenElement, 3, this.colorManager.colors)
|
||||||
];
|
];
|
||||||
this.dimensions = {
|
this.dimensions = {
|
||||||
scaledCharWidth: null,
|
scaledCharWidth: null,
|
||||||
@@ -120,6 +120,10 @@ export class Renderer extends EventEmitter implements IRenderer {
|
|||||||
this._terminal.refresh(0, this._terminal.rows - 1);
|
this._terminal.refresh(0, this._terminal.rows - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resize the screen
|
||||||
|
this._terminal.screenElement.style.width = `${this.dimensions.canvasWidth + this._terminal.viewport.scrollBarWidth}px`;
|
||||||
|
this._terminal.screenElement.style.height = `${this.dimensions.canvasHeight}px`;
|
||||||
|
|
||||||
this.emit('resize', {
|
this.emit('resize', {
|
||||||
width: this.dimensions.canvasWidth,
|
width: this.dimensions.canvasWidth,
|
||||||
height: this.dimensions.canvasHeight
|
height: this.dimensions.canvasHeight
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ export class MockTerminal implements ITerminal {
|
|||||||
isFocused: boolean;
|
isFocused: boolean;
|
||||||
options: ITerminalOptions = {};
|
options: ITerminalOptions = {};
|
||||||
element: HTMLElement;
|
element: HTMLElement;
|
||||||
|
screenElement: HTMLElement;
|
||||||
rowContainer: HTMLElement;
|
rowContainer: HTMLElement;
|
||||||
selectionContainer: HTMLElement;
|
selectionContainer: HTMLElement;
|
||||||
selectionManager: ISelectionManager;
|
selectionManager: ISelectionManager;
|
||||||
@@ -96,6 +97,7 @@ export class MockTerminal implements ITerminal {
|
|||||||
scrollback: number;
|
scrollback: number;
|
||||||
buffers: IBufferSet;
|
buffers: IBufferSet;
|
||||||
buffer: IBuffer;
|
buffer: IBuffer;
|
||||||
|
viewport: IViewport;
|
||||||
applicationCursor: boolean;
|
applicationCursor: boolean;
|
||||||
handler(data: string): void {
|
handler(data: string): void {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
@@ -308,6 +310,7 @@ export class MockRenderer implements IRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class MockViewport implements IViewport {
|
export class MockViewport implements IViewport {
|
||||||
|
scrollBarWidth: number = 0;
|
||||||
onThemeChanged(colors: IColorSet): void {
|
onThemeChanged(colors: IColorSet): void {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-1
@@ -96,9 +96,18 @@
|
|||||||
background-color: #000;
|
background-color: #000;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.xterm canvas {
|
.xterm .xterm-screen {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xterm .xterm-screen canvas {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user