Replace term.js with xterm.js
This commit is contained in:
parent
229671f485
commit
cddcb1f40a
6 changed files with 57 additions and 257 deletions
|
|
@ -1,3 +1,4 @@
|
|||
@import "~xterm/lib/xterm.css";
|
||||
@import "term.css";
|
||||
|
||||
/* Our terminal or logs */
|
||||
|
|
|
|||
|
|
@ -18,13 +18,13 @@
|
|||
*/
|
||||
"use strict";
|
||||
import React from 'react';
|
||||
import './console.css';
|
||||
import { Terminal as Term } from 'xterm';
|
||||
let cockpit = require("cockpit");
|
||||
let _ = cockpit.gettext;
|
||||
let moment = require("moment");
|
||||
let Term = require("term.js-cockpit");
|
||||
let Journal = require("journal");
|
||||
let $ = require("jquery");
|
||||
require("console.css");
|
||||
require("bootstrap-slider");
|
||||
|
||||
let padInt = function (n, w) {
|
||||
|
|
@ -1143,7 +1143,9 @@ export class Player extends React.Component {
|
|||
cols: this.state.cols,
|
||||
rows: this.state.rows,
|
||||
screenKeys: true,
|
||||
useStyle: true
|
||||
useStyle: true,
|
||||
/* Exposes the xterm-accessibility-tree */
|
||||
screenReaderMode: true,
|
||||
});
|
||||
|
||||
term.on('title', this.handleTitleChange);
|
||||
|
|
@ -1242,35 +1244,35 @@ export class Player extends React.Component {
|
|||
</div>
|
||||
<div className="panel-footer">
|
||||
<Slider length={this.buf.pos} mark={this.state.currentTsPost} fastForwardFunc={this.fastForwardToTS} play={this.play} pause={this.pause} paused={this.state.paused} />
|
||||
<button title="Play/Pause - Hotkey: p" type="button" ref="playbtn"
|
||||
<button id="player-play-pause" title="Play/Pause - Hotkey: p" type="button" ref="playbtn"
|
||||
className="btn btn-default btn-lg margin-right-btn play-btn"
|
||||
onClick={this.playPauseToggle}>
|
||||
<i className={"fa fa-" + (this.state.paused ? "play" : "pause")}
|
||||
aria-hidden="true" />
|
||||
</button>
|
||||
<button title="Skip Frame - Hotkey: ." type="button"
|
||||
<button id="player-skip-frame" title="Skip Frame - Hotkey: ." type="button"
|
||||
className="btn btn-default btn-lg margin-right-btn"
|
||||
onClick={this.skipFrame}>
|
||||
<i className="fa fa-step-forward" aria-hidden="true" />
|
||||
</button>
|
||||
<button title="Restart Playback - Hotkey: Shift-R" type="button"
|
||||
<button id="player-restart" title="Restart Playback - Hotkey: Shift-R" type="button"
|
||||
className="btn btn-default btn-lg" onClick={this.rewindToStart}>
|
||||
<i className="fa fa-fast-backward" aria-hidden="true" />
|
||||
</button>
|
||||
<button title="Fast-forward to end - Hotkey: Shift-G" type="button"
|
||||
<button id="player-fast-forward" title="Fast-forward to end - Hotkey: Shift-G" type="button"
|
||||
className="btn btn-default btn-lg margin-right-btn"
|
||||
onClick={this.fastForwardToEnd}>
|
||||
<i className="fa fa-fast-forward" aria-hidden="true" />
|
||||
</button>
|
||||
<button title="Speed /2 - Hotkey: {" type="button"
|
||||
<button id="player-speed-down" title="Speed /2 - Hotkey: {" type="button"
|
||||
className="btn btn-default btn-lg" onClick={this.speedDown}>
|
||||
/2
|
||||
</button>
|
||||
<button title="Reset Speed - Hotkey: Backspace" type="button"
|
||||
<button id="player-speed-reset" title="Reset Speed - Hotkey: Backspace" type="button"
|
||||
className="btn btn-default btn-lg" onClick={this.speedReset}>
|
||||
1:1
|
||||
</button>
|
||||
<button title="Speed x2 - Hotkey: }" type="button"
|
||||
<button id="player-speed-up" title="Speed x2 - Hotkey: }" type="button"
|
||||
className="btn btn-default btn-lg margin-right-btn"
|
||||
onClick={this.speedUp}>
|
||||
x2
|
||||
|
|
@ -1278,16 +1280,16 @@ export class Player extends React.Component {
|
|||
<span>{speedStr}</span>
|
||||
<span style={to_right}>
|
||||
<span className="session_time">{formatDuration(this.state.currentTsPost)} / {formatDuration(this.buf.pos)}</span>
|
||||
<button title="Drag'n'Pan" type="button" className="btn btn-default btn-lg"
|
||||
<button id="player-drag-pan" title="Drag'n'Pan" type="button" className="btn btn-default btn-lg"
|
||||
onClick={this.dragPan}>
|
||||
<i className={"fa fa-" + (this.state.drag_pan ? "hand-rock-o" : "hand-paper-o")}
|
||||
aria-hidden="true" /></button>
|
||||
<button title="Zoom In - Hotkey: =" type="button" className="btn btn-default btn-lg"
|
||||
<button id="player-zoom-in" title="Zoom In - Hotkey: =" type="button" className="btn btn-default btn-lg"
|
||||
onClick={this.zoomIn} disabled={this.state.term_zoom_max}>
|
||||
<i className="fa fa-search-plus" aria-hidden="true" /></button>
|
||||
<button title="Fit To - Hotkey: Z" type="button" className="btn btn-default btn-lg"
|
||||
<button id="player-fit-to" title="Fit To - Hotkey: Z" type="button" className="btn btn-default btn-lg"
|
||||
onClick={this.fitTo}><i className="fa fa-expand" aria-hidden="true" /></button>
|
||||
<button title="Zoom Out - Hotkey: -" type="button" className="btn btn-default btn-lg"
|
||||
<button id="player-zoom-out" title="Zoom Out - Hotkey: -" type="button" className="btn btn-default btn-lg"
|
||||
onClick={this.zoomOut} disabled={this.state.term_zoom_min}>
|
||||
<i className="fa fa-search-minus" aria-hidden="true" /></button>
|
||||
</span>
|
||||
|
|
|
|||
192
src/terminal.jsx
192
src/terminal.jsx
|
|
@ -1,192 +0,0 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2016 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Player from "./player";
|
||||
|
||||
"use strict";
|
||||
|
||||
var React = require("react");
|
||||
var Term = require("term");
|
||||
let $ = require("jquery");
|
||||
|
||||
require("console.css");
|
||||
require("jquery-resizable");
|
||||
require("jquery-resizable/resizable.css");
|
||||
|
||||
/*
|
||||
* A terminal component that communicates over a cockpit channel.
|
||||
*
|
||||
* The only required property is 'channel', which must point to a cockpit
|
||||
* stream channel.
|
||||
*
|
||||
* The size of the terminal can be set with the 'rows' and 'cols'
|
||||
* properties. If those properties are not given, the terminal will fill
|
||||
* its container.
|
||||
*
|
||||
* If the 'onTitleChanged' callback property is set, it will be called whenever
|
||||
* the title of the terminal changes.
|
||||
*
|
||||
* Call focus() to set the input focus on the terminal.
|
||||
*/
|
||||
var Terminal = React.createClass({
|
||||
propTypes: {
|
||||
// cols: React.PropTypes.number,
|
||||
rows: React.PropTypes.number,
|
||||
channel: React.PropTypes.object.isRequired,
|
||||
onTitleChanged: React.PropTypes.func
|
||||
},
|
||||
|
||||
componentWillMount: function () {
|
||||
var term = new Term({
|
||||
cols: this.state.cols || 80,
|
||||
rows: this.state.rows || 25,
|
||||
screenKeys: true,
|
||||
useStyle: true
|
||||
});
|
||||
|
||||
term.on('data', function(data) {
|
||||
if (this.props.channel.valid)
|
||||
this.props.channel.send(data);
|
||||
}.bind(this));
|
||||
|
||||
if (this.props.onTitleChanged)
|
||||
term.on('title', this.props.onTitleChanged);
|
||||
|
||||
this.setState({ terminal: term });
|
||||
},
|
||||
|
||||
componentDidMount: function () {
|
||||
this.state.terminal.open(this.refs.terminal);
|
||||
this.connectChannel();
|
||||
|
||||
let term = this.refs.terminal;
|
||||
let onWindowResize = this.onWindowResize;
|
||||
|
||||
$(function() {
|
||||
$(term).resizable({
|
||||
direction: ['right', 'bottom'],
|
||||
stop: function() {
|
||||
onWindowResize();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
if (!this.props.rows) {
|
||||
window.addEventListener('resize', this.onWindowResize);
|
||||
this.onWindowResize();
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUpdate: function (nextProps, nextState) {
|
||||
if (nextState.cols !== this.state.cols || nextState.rows !== this.state.rows) {
|
||||
this.state.terminal.resize(nextState.cols, nextState.rows);
|
||||
this.props.channel.control({
|
||||
window: {
|
||||
rows: nextState.rows,
|
||||
cols: nextState.cols
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (nextProps.channel !== this.props.channel) {
|
||||
this.state.terminal.reset();
|
||||
this.disconnectChannel();
|
||||
}
|
||||
},
|
||||
|
||||
componentDidUpdate: function (prevProps) {
|
||||
if (prevProps.channel !== this.props.channel)
|
||||
this.connectChannel();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
let style = {
|
||||
'min-width': '300px',
|
||||
'min-height': '100px',
|
||||
};
|
||||
// ensure react never reuses this div by keying it with the terminal widget
|
||||
return <div ref="terminal" style={style} className="console-ct" key={this.state.terminal} />;
|
||||
},
|
||||
|
||||
componentWillUnmount: function () {
|
||||
this.disconnectChannel();
|
||||
this.state.terminal.destroy();
|
||||
},
|
||||
|
||||
onChannelMessage: function (event, data) {
|
||||
if (this.state.terminal) {
|
||||
this.state.terminal.write(data);
|
||||
}
|
||||
},
|
||||
|
||||
onChannelClose: function (event, options) {
|
||||
var term = this.state.terminal;
|
||||
term.write('\x1b[31m' + (options.problem || 'disconnected') + '\x1b[m\r\n');
|
||||
term.cursorHidden = true;
|
||||
term.refresh(term.y, term.y);
|
||||
},
|
||||
|
||||
connectChannel: function () {
|
||||
var channel = this.props.channel;
|
||||
if (channel && channel.valid) {
|
||||
channel.addEventListener('message', this.onChannelMessage.bind(this));
|
||||
channel.addEventListener('close', this.onChannelClose.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
disconnectChannel: function () {
|
||||
if (this.props.channel) {
|
||||
this.props.channel.removeEventListener('message', this.onChannelMessage);
|
||||
this.props.channel.removeEventListener('close', this.onChannelClose);
|
||||
}
|
||||
},
|
||||
|
||||
focus: function () {
|
||||
if (this.state.terminal)
|
||||
this.state.terminal.focus();
|
||||
},
|
||||
|
||||
onWindowResize: function () {
|
||||
if (this.refs) {
|
||||
var padding = 2 * 11;
|
||||
var node = this.getDOMNode();
|
||||
var terminal = this.refs.terminal.querySelector('.terminal');
|
||||
|
||||
var ch = document.createElement('div');
|
||||
ch.textContent = 'M';
|
||||
terminal.appendChild(ch);
|
||||
var height = ch.offsetHeight; // offsetHeight is only correct for block elements
|
||||
ch.style.display = 'inline';
|
||||
var width = ch.offsetWidth;
|
||||
terminal.removeChild(ch);
|
||||
|
||||
this.setState({
|
||||
rows: Math.floor((node.parentElement.clientHeight - padding) / height),
|
||||
cols: Math.floor((node.parentElement.clientWidth - padding) / width)
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
send: function(value) {
|
||||
this.state.terminal.send(value);
|
||||
}
|
||||
});
|
||||
|
||||
// module.exports = { Terminal: Terminal };
|
||||
export class Terminal;
|
||||
Loading…
Add table
Add a link
Reference in a new issue