Merge remote-tracking branch 'ups/v3' into 1159_linefeed

This commit is contained in:
Daniel Imms
2017-12-19 13:26:48 -08:00
41 changed files with 862 additions and 712 deletions
+3
View File
@@ -23,3 +23,6 @@ fixtures/typings-test/*.js
dist/
src/utils/TestUtils.ts
src/xterm.js
# Keep the demo builds out of Git
demo/dist/
+2 -2
View File
@@ -1,4 +1,4 @@
FROM node:6.9
FROM node:6
MAINTAINER Paris Kasidiaris <paris@sourcelair.com>
# Set the working directory
@@ -6,7 +6,7 @@ WORKDIR /usr/src/app
# Set an entrypoint, to automatically install node modules
ENTRYPOINT ["/bin/bash", "-c", "if [[ ! -d node_modules ]]; then npm install; fi; exec \"${@:0}\";"]
CMD ["npm", "run", "dev"]
CMD ["npm", "run", "start"]
# First, install dependencies to improve layer caching
COPY package.json /usr/src/app/
-1
View File
@@ -1 +0,0 @@
web: npm run dev
+16 -33
View File
@@ -49,50 +49,33 @@ To start using xterm.js on your browser, add the `xterm.js` and `xterm.css` to t
Finally instantiate the `Terminal` object and then call the `open` function with the DOM object of the `div`.
### Addons
Addons are JavaScript modules that attach functions to the `Terminal` prototype to extend its functionality. There are a handful available in the main repository in the `dist/addons` directory, you can even write your own (though they may break when the internals of xterm.js change across versions).
To use an addon, just include the JavaScript file after xterm.js and before the `Terminal` object has been instantiated. The function should then be exposed on the `Terminal` object:
```html
<script src="node_modules/xterm/dist/xterm.js"></script>
<script src="node_modules/xterm/dist/addons/fit/fit.js"></script>
```
```js
// Instantiate the terminal and call fit
var xterm = new Terminal();
xterm.fit();
```
### Importing
If the environment allows it, you can import xterm.js like so:
The proposed way to load xterm.js is via the ES6 module syntax.
```ts
// CommonJS
var Terminal = require('xterm').Terminal;
// ES6 / TypeScript
```javascript
import { Terminal } from 'xterm';
```
Importing addons in this environment can be done using a `Terminal.loadAddon` call:
*Note: There are currently no typings for addons so you will need to upcast if using TypeScript, eg. `(<any>xterm).fit()`.*
```ts
import { Terminal } from 'xterm';
### Addons
// Notice it's called statically on the type, not an object
Terminal.loadAddon('fit');
Addons are JavaScript modules that extend the `Terminal` prototype with new methods and attributes to provide additional functionality. There are a handful available in the main repository in the `src/addons` directory and you can even write your own, by using xterm.js' public API.
// Instantiate the terminal and call fit
var xterm = new Terminal();
xterm.fit();
To use an addon, just import the JavaScript module and pass it to `Terminal`'s `applyAddon` method:
```javascript
import { Terminal } from xterm;
import * as fit from 'xterm/lib/addons/fit/fit';
Terminal.applyAddon(fit);
var xterm = new Terminal(); // Instantiate the terminal
xterm.fit(); // Use the `fit` method, provided by the `fit` addon
```
*Note: There are currently no typings for addons so you will need to upcast if using TypeScript, eg. `(<any>xterm).fit()`*
## Browser Support
Since xterm.js is typically implemented as a developer tool, only modern browsers are supported officially. Here is a list of the versions we aim to support:
+6 -2
View File
@@ -17,8 +17,12 @@ app.get('/style.css', function(req, res){
res.sendFile(__dirname + '/style.css');
});
app.get('/main.js', function(req, res){
res.sendFile(__dirname + '/main.js');
app.get('/dist/bundle.js', function(req, res){
res.sendFile(__dirname + '/dist/bundle.js');
});
app.get('/dist/bundle.js.map', function(req, res){
res.sendFile(__dirname + '/dist/bundle.js.map');
});
app.post('/terminals', function (req, res) {
+1 -7
View File
@@ -7,12 +7,6 @@
<link rel="stylesheet" href="style.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.auto.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/1.0.0/fetch.min.js"></script>
<script src="/build/xterm.js" ></script>
<script src="/build/addons/attach/attach.js" ></script>
<script src="/build/addons/fit/fit.js" ></script>
<script src="/build/addons/fullscreen/fullscreen.js" ></script>
<script src="/build/addons/search/search.js" ></script>
<script src="/build/addons/winptyCompat/winptyCompat.js" ></script>
</head>
<body>
<h1>xterm.js: xterm, in the browser</h1>
@@ -71,6 +65,6 @@
</div>
</div>
<p><strong>Attention:</strong> The demo is a barebones implementation and is designed for xterm.js evaluation purposes only. Exposing the demo to the public as is would introduce security risks for the host.</p>
<script src="main.js" defer ></script>
<script src="dist/bundle.js" defer ></script>
</body>
</html>
+18 -1
View File
@@ -1,3 +1,18 @@
import * as Terminal from '../build/xterm';
import * as attach from '../build/addons/attach/attach';
import * as fit from '../build/addons/fit/fit';
import * as fullscreen from '../build/addons/fullscreen/fullscreen';
import * as search from '../build/addons/search/search';
import * as winptyCompat from '../build/addons/winptyCompat/winptyCompat';
Terminal.applyAddon(attach);
Terminal.applyAddon(fit);
Terminal.applyAddon(fullscreen);
Terminal.applyAddon(search);
Terminal.applyAddon(winptyCompat);
var term,
protocol,
socketURL,
@@ -76,6 +91,7 @@ function createTerminal() {
scrollback: parseInt(optionElements.scrollback.value, 10),
tabStopWidth: parseInt(optionElements.tabstopwidth.value, 10)
});
window.term = term; // Expose `term` to window for debugging purposes
term.on('resize', function (size) {
if (!pid) {
return;
@@ -90,8 +106,9 @@ function createTerminal() {
socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/';
term.open(terminalContainer);
term.fit();
term.winptyCompatInit();
term.fit();
term.focus();
// fit is called within a setTimeout, cols and rows need this.
setTimeout(function () {
-9
View File
@@ -1,9 +0,0 @@
version: '2'
services:
web:
build: ./
volumes:
- ./:/usr/src/app
ports:
- 3000:3000
+9
View File
@@ -0,0 +1,9 @@
version: "3"
services:
web:
build: .
volumes:
- ./:/usr/src/app
ports:
- ${XTERMJS_PORT:3000}:3000
+23 -18
View File
@@ -16,6 +16,7 @@ const source = require('vinyl-source-stream');
const sourcemaps = require('gulp-sourcemaps');
const ts = require('gulp-typescript');
const util = require('gulp-util');
const webpack = require('webpack-stream');
let buildDir = process.env.BUILD_DIR || 'build';
let tsProject = ts.createProject('tsconfig.json');
@@ -44,30 +45,31 @@ gulp.task('tsc', function () {
tsResult.dts.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest(outDir))
);
fs.emptyDirSync(`${outDir}/addons/search`);
fs.emptyDirSync(`${outDir}/addons/winptyCompat`);
let addons = ['attach', 'fit', 'fullscreen', 'search', 'terminado', 'winptyCompat', 'zmodem'];
let addonStreams = addons.map(function(addon) {
fs.emptyDirSync(`${outDir}/addons/${addon}`);
let tsProjectSearchAddon = ts.createProject('./src/addons/search/tsconfig.json');
let tsResultSearchAddon = tsProjectSearchAddon.src().pipe(sourcemaps.init()).pipe(tsProjectSearchAddon());
let tscSearchAddon = tsResultSearchAddon.js.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest(`${outDir}/addons/search`));
let tsProjectAddon = ts.createProject(`./src/addons/${addon}/tsconfig.json`);
let tsResultAddon = tsProjectAddon.src().pipe(sourcemaps.init()).pipe(tsProjectAddon());
let tscAddon = tsResultAddon.js
.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''}))
.pipe(gulp.dest(`${outDir}/addons/${addon}`));
let tsProjectWinptyCompatAddon = ts.createProject('./src/addons/winptyCompat/tsconfig.json');
let tsResultWinptyCompatAddon = tsProjectWinptyCompatAddon.src().pipe(sourcemaps.init()).pipe(tsProjectWinptyCompatAddon());
let tscWinptyCompatAddon = tsResultWinptyCompatAddon.js.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''})).pipe(gulp.dest(`${outDir}/addons/winptyCompat`));
return tscAddon;
});
// Copy all addons from ${srcDir}/ to ${outDir}/
let copyAddons = gulp.src([
`${srcDir}/addons/**/*`,
`!${srcDir}/addons/search`,
`!${srcDir}/addons/search/**`,
`!${srcDir}/addons/winptyCompat`,
`!${srcDir}/addons/winptyCompat/**`
`${srcDir}/addons/**/**`
]).pipe(gulp.dest(`${outDir}/addons`));
// Copy stylesheets from ${srcDir}/ to ${outDir}/
let copyStylesheets = gulp.src(`${srcDir}/**/*.css`).pipe(gulp.dest(outDir));
return merge(tsc, tscSearchAddon, tscWinptyCompatAddon, copyAddons, copyStylesheets);
// Join all streams into a single array
let streams = [tsc].concat(addonStreams).concat([copyAddons, copyStylesheets]);
return merge.apply(this, streams);
});
/**
@@ -136,10 +138,7 @@ gulp.task('browserify-addons', ['tsc'], function() {
// Copy all add-ons from outDir to buildDir
let copyAddons = gulp.src([
// Copy JS addons
`${outDir}/addons/**/*`,
// Exclude TS addons from copy as they are being built via browserify
`!${outDir}/addons/search`,
`!${outDir}/addons/search/**`,
`${outDir}/addons/**/*`
]).pipe(gulp.dest(`${buildDir}/addons`));
return merge(searchBundle, winptyCompatBundle, copyAddons);
@@ -195,6 +194,12 @@ gulp.task('sorcery-addons', ['browserify-addons'], function () {
chain.writeSync();
});
gulp.task('webpack', ['build'], function() {
return gulp.src('demo/main.js')
.pipe(webpack(require('./webpack.config.js')))
.pipe(gulp.dest('demo/dist/'));
});
/**
* Submit coverage results to coveralls.io
*/
+122 -23
View File
@@ -1,6 +1,6 @@
{
"name": "xterm",
"version": "2.8.1",
"version": "2.9.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -44,6 +44,12 @@
"integrity": "sha512-7F3/P6MkTPA0QxOstRqfcnoReCUy5V/QG92cyBoZSPnqdX44L8TtNELSVfN56gAttm3YWj9cEi8FRIPVq0WmeQ==",
"dev": true
},
"@types/text-encoding": {
"version": "0.0.32",
"resolved": "https://registry.npmjs.org/@types/text-encoding/-/text-encoding-0.0.32.tgz",
"integrity": "sha512-kQ79aFmYcD/DR3QKo6wXyvNrKi7PunY0KYTBUhHjHl0SXwWuLRl9Leh73YtnsSJMBi9qSiK+fxWhdJNQPbhc9A==",
"dev": true
},
"@types/tough-cookie": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.0.tgz",
@@ -555,12 +561,29 @@
"integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=",
"dev": true
},
"clone-buffer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
"integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=",
"dev": true
},
"clone-stats": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
"integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=",
"dev": true
},
"cloneable-readable": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.0.0.tgz",
"integrity": "sha1-pikNQT8hemEjL5XkWP84QYz7ARc=",
"dev": true,
"requires": {
"inherits": "2.0.3",
"process-nextick-args": "1.0.7",
"through2": "2.0.3"
}
},
"combine-source-map": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.7.2.tgz",
@@ -620,6 +643,15 @@
}
}
},
"concat-with-sourcemaps": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.0.4.tgz",
"integrity": "sha1-9Vs74q60dgGxCi1SWcz7cP0vHdY=",
"dev": true,
"requires": {
"source-map": "0.5.6"
}
},
"console-browserify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
@@ -662,6 +694,16 @@
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true
},
"crc-32": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.1.1.tgz",
"integrity": "sha1-XXOdXkxuNSrYME1zIj1IP+Va240=",
"dev": true,
"requires": {
"exit-on-epipe": "1.0.1",
"printj": "1.1.0"
}
},
"create-ecdh": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz",
@@ -1021,6 +1063,12 @@
}
}
},
"exit-on-epipe": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz",
"integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==",
"dev": true
},
"express": {
"version": "4.13.4",
"resolved": "https://registry.npmjs.org/express/-/express-4.13.4.tgz",
@@ -4190,6 +4238,51 @@
}
}
},
"gulp-concat": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz",
"integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=",
"dev": true,
"requires": {
"concat-with-sourcemaps": "1.0.4",
"through2": "2.0.3",
"vinyl": "2.1.0"
},
"dependencies": {
"clone": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz",
"integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=",
"dev": true
},
"clone-stats": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
"integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
"dev": true
},
"replace-ext": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
"integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
"dev": true
},
"vinyl": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.1.0.tgz",
"integrity": "sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=",
"dev": true,
"requires": {
"clone": "2.1.1",
"clone-buffer": "1.0.0",
"clone-stats": "1.0.0",
"cloneable-readable": "1.0.0",
"remove-trailing-separator": "1.0.2",
"replace-ext": "1.0.0"
}
}
}
},
"gulp-coveralls": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/gulp-coveralls/-/gulp-coveralls-0.1.4.tgz",
@@ -9519,28 +9612,19 @@
"duplexer2": "0.0.2"
}
},
"nan": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz",
"integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=",
"dev": true
},
"node-pty": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-0.4.1.tgz",
"integrity": "sha1-qAs1/le2TwVasZsteqYE2DYVXAQ=",
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-0.7.3.tgz",
"integrity": "sha1-S7NqJKYu6fMzLi4jENZkLZ2u0fc=",
"dev": true,
"requires": {
"extend": "1.2.1",
"nan": "2.2.1"
},
"dependencies": {
"extend": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz",
"integrity": "sha1-oPX9bPyDpf5J72mNYOyKYk3UV2w=",
"dev": true
},
"nan": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.2.1.tgz",
"integrity": "sha1-1oaT9rNLtB1mvGizpPne/HnXFJs=",
"dev": true
}
"nan": "2.8.0"
}
},
"nodemon": {
@@ -10899,6 +10983,12 @@
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
"dev": true
},
"printj": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/printj/-/printj-1.1.0.tgz",
"integrity": "sha512-NbiNBOQ0GioHyeD3ni8wZB7ZmfU7mxIrqhWR5XSreX3rUVvk5UOwpzxOnWqrLdCtoBbdQ40sEwC+nXxxjlUo0A==",
"dev": true
},
"process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
@@ -12271,9 +12361,9 @@
"dev": true
},
"typescript": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.2.2.tgz",
"integrity": "sha1-YGAiUIR5tV/6NotY/uljoD39eww=",
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.4.2.tgz",
"integrity": "sha1-+DlfhdRZJ2BnyYiqQYN6j4KHCEQ=",
"dev": true
},
"umd": {
@@ -12547,6 +12637,15 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
"dev": true
},
"zmodem.js": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/zmodem.js/-/zmodem.js-0.1.6.tgz",
"integrity": "sha1-QNeLS0uYQiBo5CB5II/wgFcLrdk=",
"dev": true,
"requires": {
"crc-32": "1.1.1"
}
}
}
}
+6 -3
View File
@@ -42,6 +42,7 @@
"@types/jsdom": "^11.0.1",
"@types/mocha": "^2.2.33",
"@types/node": "^6.0.41",
"@types/text-encoding": "0.0.32",
"browserify": "^13.3.0",
"chai": "3.5.0",
"docdash": "0.4.0",
@@ -68,20 +69,22 @@
"typescript": "~2.4.0",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0",
"webpack": "^3.10.0",
"webpack-stream": "^4.0.0",
"zmodem.js": "^0.1.5"
},
"scripts": {
"prestart": "npm run build",
"prestart": "gulp webpack",
"start": "node demo/app",
"prestart-zmodem": "npm run build",
"start-zmodem": "node build/addons/zmodem/demo/app",
"dev": "nodemon -e js,ts,css --watch src --watch demo --exec npm start",
"lint": "tslint src/*.ts src/**/*.ts",
"test": "gulp test",
"build:docs": "jsdoc -c jsdoc.json",
"build": "gulp build",
"prepublish": "npm run build",
"coveralls": "gulp coveralls"
"coveralls": "gulp coveralls",
"webpack": "gulp webpack"
},
"dependencies": {}
}
+5 -4
View File
@@ -3,8 +3,9 @@
* @license MIT
*/
import { assert, expect } from 'chai';
import { assert, expect } from 'chai';
import { Terminal } from './Terminal';
import * as attach from './addons/attach/attach';
import { MockViewport, MockCompositionHelper, MockRenderer } from './utils/TestUtils.test';
import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX } from './Buffer';
@@ -42,9 +43,9 @@ describe('term.js addons', () => {
};
});
it('should load addons with Terminal.loadAddon', () => {
Terminal.loadAddon('attach');
// Test that addon was loaded successfully, adding attach to Terminal's
it('should apply addons with Terminal.applyAddon', () => {
Terminal.applyAddon(attach);
// Test that addon was applied successfully, adding attach to Terminal's
// prototype.
assert.equal(typeof (<any>Terminal).prototype.attach, 'function');
});
+4 -21
View File
@@ -47,12 +47,6 @@ import { MouseZoneManager } from './input/MouseZoneManager';
import { initialize as initializeCharAtlas } from './renderer/CharAtlas';
import { IRenderer } from './renderer/Interfaces';
// Declares required for loadAddon
declare var exports: any;
declare var module: any;
declare var define: any;
declare var require: any;
// Let it work inside Node.js for automated testing purposes.
const document = (typeof window !== 'undefined') ? window.document : null;
@@ -687,22 +681,11 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
}
/**
* Attempts to load an add-on using CommonJS or RequireJS (whichever is available).
* @param {string} addon The name of the addon to load
* @static
* Apply the provided addon on the `Terminal` class.
* @param addon The addon to apply.
*/
public static loadAddon(addon: string, callback?: Function): boolean | any {
// TODO: Improve return type and documentation
if (typeof exports === 'object' && typeof module === 'object') {
// CommonJS
return require('./addons/' + addon + '/' + addon);
} else if (typeof define === 'function') {
// RequireJS
return (<any>require)(['./addons/' + addon + '/' + addon], callback);
} else {
console.error('Cannot load a module without a CommonJS or RequireJS environment.');
return false;
}
public static applyAddon(addon: any): void {
addon.apply(Terminal);
}
/**
-141
View File
@@ -1,141 +0,0 @@
/**
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
* @license MIT
*
* Implements the attach method, that attaches the terminal to a WebSocket stream.
*/
(function (attach) {
if (typeof exports === 'object' && typeof module === 'object') {
/*
* CommonJS environment
*/
module.exports = attach(require('../../Terminal').Terminal);
} else if (typeof define == 'function') {
/*
* Require.js is available
*/
define(['../../xterm'], attach);
} else {
/*
* Plain browser environment
*/
attach(window.Terminal);
}
})(function (Terminal) {
'use strict';
var exports = {};
/**
* Attaches the given terminal to the given socket.
*
* @param {Terminal} term - The terminal to be attached to the given socket.
* @param {WebSocket} socket - The socket to attach the current terminal.
* @param {boolean} bidirectional - Whether the terminal should send data
* to the socket as well.
* @param {boolean} buffered - Whether the rendering of incoming data
* should happen instantly or at a maximum
* frequency of 1 rendering per 10ms.
*/
exports.attach = function (term, socket, bidirectional, buffered) {
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional;
term.socket = socket;
term._flushBuffer = function () {
term.write(term._attachSocketBuffer);
term._attachSocketBuffer = null;
};
term._pushToBuffer = function (data) {
if (term._attachSocketBuffer) {
term._attachSocketBuffer += data;
} else {
term._attachSocketBuffer = data;
setTimeout(term._flushBuffer, 10);
}
};
var myTextDecoder;
term._getMessage = function (ev) {
var str;
if (typeof ev.data === "object") {
if (ev.data instanceof ArrayBuffer) {
if (!myTextDecoder) {
myTextDecoder = new TextDecoder();
}
str = myTextDecoder.decode( ev.data );
}
else {
throw "TODO: handle Blob?";
}
}
if (buffered) {
term._pushToBuffer(str || ev.data);
} else {
term.write(str || ev.data);
}
};
term._sendData = function (data) {
socket.send(data);
};
socket.addEventListener('message', term._getMessage);
if (bidirectional) {
term.on('data', term._sendData);
}
socket.addEventListener('close', term.detach.bind(term, socket));
socket.addEventListener('error', term.detach.bind(term, socket));
};
/**
* Detaches the given terminal from the given socket
*
* @param {Terminal} term - The terminal to be detached from the given socket.
* @param {WebSocket} socket - The socket from which to detach the current
* terminal.
*/
exports.detach = function (term, socket) {
term.off('data', term._sendData);
socket = (typeof socket == 'undefined') ? term.socket : socket;
if (socket) {
socket.removeEventListener('message', term._getMessage);
}
delete term.socket;
};
/**
* Attaches the current terminal to the given socket
*
* @param {WebSocket} socket - The socket to attach the current terminal.
* @param {boolean} bidirectional - Whether the terminal should send data
* to the socket as well.
* @param {boolean} buffered - Whether the rendering of incoming data
* should happen instantly or at a maximum
* frequency of 1 rendering per 10ms.
*/
Terminal.prototype.attach = function (socket, bidirectional, buffered) {
return exports.attach(this, socket, bidirectional, buffered);
};
/**
* Detaches the current terminal from the given socket.
*
* @param {WebSocket} socket - The socket from which to detach the current
* terminal.
*/
Terminal.prototype.detach = function (socket) {
return exports.detach(this, socket);
};
return exports;
});
+20
View File
@@ -0,0 +1,20 @@
/**
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { assert, expect } from 'chai';
import * as attach from './attach'
class MockTerminal {}
describe('attach addon', () => {
describe('apply', () => {
it('should do register the `attach` and `detach` methods', () => {
attach.apply(MockTerminal);
assert.equal(typeof (<any>MockTerminal).prototype.attach, 'function');
assert.equal(typeof (<any>MockTerminal).prototype.detach, 'function');
});
});
});
+119
View File
@@ -0,0 +1,119 @@
/**
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
* @license MIT
*
* Implements the attach method, that attaches the terminal to a WebSocket stream.
*/
/**
* Attaches the given terminal to the given socket.
*
* @param {Terminal} term - The terminal to be attached to the given socket.
* @param {WebSocket} socket - The socket to attach the current terminal.
* @param {boolean} bidirectional - Whether the terminal should send data
* to the socket as well.
* @param {boolean} buffered - Whether the rendering of incoming data
* should happen instantly or at a maximum
* frequency of 1 rendering per 10ms.
*/
export function attach(term, socket, bidirectional, buffered) {
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional;
term.socket = socket;
term._flushBuffer = function() {
term.write(term._attachSocketBuffer);
term._attachSocketBuffer = null;
};
term._pushToBuffer = function(data) {
if (term._attachSocketBuffer) {
term._attachSocketBuffer += data;
} else {
term._attachSocketBuffer = data;
setTimeout(term._flushBuffer, 10);
}
};
var myTextDecoder;
term._getMessage = function(ev) {
var str;
if (typeof ev.data === "object") {
if (ev.data instanceof ArrayBuffer) {
if (!myTextDecoder) {
myTextDecoder = new TextDecoder();
}
str = myTextDecoder.decode( ev.data );
}
else {
throw "TODO: handle Blob?";
}
}
if (buffered) {
term._pushToBuffer(str || ev.data);
} else {
term.write(str || ev.data);
}
};
term._sendData = function(data) {
socket.send(data);
};
socket.addEventListener('message', term._getMessage);
if (bidirectional) {
term.on('data', term._sendData);
}
socket.addEventListener('close', term.detach.bind(term, socket));
socket.addEventListener('error', term.detach.bind(term, socket));
};
/**
* Detaches the given terminal from the given socket
*
* @param {Terminal} term - The terminal to be detached from the given socket.
* @param {WebSocket} socket - The socket from which to detach the current
* terminal.
*/
export function detach(term, socket) {
term.off('data', term._sendData);
socket = (typeof socket == 'undefined') ? term.socket : socket;
if (socket) {
socket.removeEventListener('message', term._getMessage);
}
delete term.socket;
};
export function apply(terminalConstructor) {
/**
* Attaches the current terminal to the given socket
*
* @param {WebSocket} socket - The socket to attach the current terminal.
* @param {boolean} bidirectional - Whether the terminal should send data
* to the socket as well.
* @param {boolean} buffered - Whether the rendering of incoming data
* should happen instantly or at a maximum
* frequency of 1 rendering per 10ms.
*/
terminalConstructor.prototype.attach = function(socket, bidirectional, buffered) {
return attach(this, socket, bidirectional, buffered);
};
/**
* Detaches the current terminal from the given socket.
*
* @param {WebSocket} socket - The socket from which to detach the current
* terminal.
*/
terminalConstructor.prototype.detach = function(socket) {
return detach(this, socket);
};
}
+10
View File
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"rootDir": ".",
"outDir": "../../../lib/addons/attach/",
"sourceMap": true,
"removeComments": true
}
}
-81
View File
@@ -1,81 +0,0 @@
/**
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
* @license MIT
*
* Fit terminal columns and rows to the dimensions of its DOM element.
*
* ## Approach
*
* Rows: Truncate the division of the terminal parent element height by the
* terminal row height.
* Columns: Truncate the division of the terminal parent element width by the
* terminal character width (apply display: inline at the terminal
* row and truncate its width with the current number of columns).
*/
(function (fit) {
if (typeof exports === 'object' && typeof module === 'object') {
/*
* CommonJS environment
*/
module.exports = fit(require('../../Terminal').Terminal);
} else if (typeof define == 'function') {
/*
* Require.js is available
*/
define(['../../xterm'], fit);
} else {
/*
* Plain browser environment
*/
fit(window.Terminal);
}
})(function (Terminal) {
var exports = {};
exports.proposeGeometry = function (term) {
if (!term.element.parentElement) {
return null;
}
var parentElementStyle = window.getComputedStyle(term.element.parentElement);
var parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));
var parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17);
var elementStyle = window.getComputedStyle(term.element);
var elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom'));
var elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left'));
var availableHeight = parentElementHeight - elementPaddingVer;
var availableWidth = parentElementWidth - elementPaddingHor;
var geometry = {
cols: Math.floor(availableWidth / term.charMeasure.width),
rows: Math.floor(availableHeight / Math.floor(term.charMeasure.height * term.getOption('lineHeight')))
};
return geometry;
};
exports.fit = function (term) {
// Wrap fit in a setTimeout as charMeasure needs time to get initialized
// after calling Terminal.open
setTimeout(function () {
var geometry = exports.proposeGeometry(term);
if (geometry) {
// Force a full render
if (term.rows !== geometry.rows || term.cols !== geometry.cols) {
term.renderer.clear();
term.resize(geometry.cols, geometry.rows);
}
}
}, 0);
};
Terminal.prototype.proposeGeometry = function () {
return exports.proposeGeometry(this);
};
Terminal.prototype.fit = function () {
return exports.fit(this);
};
return exports;
});
+20
View File
@@ -0,0 +1,20 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { assert, expect } from 'chai';
import * as fit from './fit'
class MockTerminal {}
describe('fit addon', () => {
describe('apply', () => {
it('should do register the `proposeGeometry` and `fit` methods', () => {
fit.apply(MockTerminal);
assert.equal(typeof (<any>MockTerminal).prototype.proposeGeometry, 'function');
assert.equal(typeof (<any>MockTerminal).prototype.fit, 'function');
});
});
});

Some files were not shown because too many files have changed in this diff Show More