Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

Commit

Permalink
refs #7, #9: Improve webterm.
Browse files Browse the repository at this point in the history
 * Include xterm.css into a part of webpack bundle.
   No additional <link> tags are required; it's automatically imported
   when doing `Sorna.loadWebterm();`

 * Modified xterm.css to make it more vibrant and readable.

 * Update README and webpack configs so that you can use `yarn run ...`
   to run pre-configured build/devserver commands using the local
   node_modules directory.

 * Resetting kernel no longer duplicates keypress events.

 * Now the terminal handles CJK and English input/output correctly.
   (tested only on Chrome)
  • Loading branch information
achimnol committed Feb 11, 2017
1 parent 2f4ae3f commit c69d5ec
Show file tree
Hide file tree
Showing 9 changed files with 3,400 additions and 102 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,4 @@ target/

# npm/webpack
node_modules
assets/latest
27 changes: 17 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ This contains a set of media support stubs for the Sorna code execution service.
strings when the user code calls `plt.show()`.
* `assets`
-- The front-end side Javascript assets to utilize JSON-encoded media outputs
generated by above server-side Python packages.
generated by above server-side Python packages as well as web terminals.

Server-side Python packages records the media outputs in the `builtins` module
and Dockerized Sorna REPL scripts pass them to the Sorna Agent along with
the stdout/stderr strings via JSON over ZeroMQ sockets. Upon receiving those results,
the front-end side Javascripts should call `Sorna.Media.handle_all(<media-output-array>,
<result-identifier>, <result-ctonainer>)` where `result-identifier`
the front-end side Javascripts should call `Sorna.Media.handle_all(<media-output-array>,
<result-identifier>, <result-ctonainer>)` where `result-identifier`
should be a unique string for each code block and `result-container` should
be a reference to HTML element such as `<div>` blocks used for rendering the
execution results.
Expand All @@ -28,16 +28,23 @@ execution results.

### Setting up

We use [**yarn**](https://yarnpkg.com) and [**webpack**](https://webpack.js.org)
for bundling Javascript files and CSS resources so that we keep the main script
small (less than 100KB) while the main script loads all the necessary stuffs
dynamically.

Check out [the installation instruction of yarn package
manager](https://yarnpkg.com/en/docs/install) first.

```sh
# Use package.json to install dependencies:
$ npm install
# To get command-line access for webpack:
$ npm install -g webpack webpack-dev-server
# Use package.json to install all dependencies locally:
$ yarn install
# To run a local development server serving auto-rebuilt in-memory bundles:
$ yarn run devserver
# To run the production build:
$ yarn run build
```

Globally installed webpack and webpack-dev-server will automatically call
the local versions at `./node_modules` if they exist.

### Integration with a front-end

You need to specify `Sorna.assetRoot` in Javascript to let our scripts know
Expand Down
12 changes: 6 additions & 6 deletions assets/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
/** Sorna Media Handlers. */

window.Sorna = window.Sorna || { version: '0.9.0' };
if (typeof(Sorna.assetRoot) == 'undefined') {
if (Sorna.assetRoot === undefined) {
// Fallback to the current host address
Sorna.assetRoot = window.location.protocol + '//' + window.location.host;
}
__webpack_public_path__ = Sorna.assetRoot;
__webpack_require__.p = Sorna.assetRoot + '/js/';

import 'babel-polyfill';
require('babel-polyfill');

var fabric_loader = (resolve) => {
require.ensure(['fabric'], function() {
Expand All @@ -27,13 +27,13 @@ var drawing_loader = (resolve) => {
};

Sorna.loadWebterm = (resolve) => {
if (typeof Sorna.Webterm == 'undefined') {
if (Sorna.Webterm === undefined) {
require.ensure(['./webterm.js'], function() {
Sorna.Webterm = require('./webterm.js').default;
resolve();
});
}
// TODO: inject CSS from Sorna.assetRoot
} else
resolve();
};

class _Utils {
Expand Down Expand Up @@ -132,7 +132,7 @@ class _Media {
for (let i = 0; i < items.length; i++) {
let media = items[i];
let impl = this._get_media_impls()[media[0]];
if (impl == undefined)
if (impl === undefined)
continue;
let script_promises = [];
for (let j = 0; j < impl.scripts.length; j++) {
Expand Down
36 changes: 24 additions & 12 deletions assets/js/webterm.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const Terminal = require('xterm');
const SockJS = require('sockjs-client');
const Writable = require('stream').Writable;

require("!!style-loader!css-loader!../vendor/xterm/xterm.css");

function b64EncodeUnicode(str) {
return window.btoa(unescape(encodeURIComponent( str )));
//return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
Expand All @@ -12,10 +14,14 @@ function b64EncodeUnicode(str) {
}

function b64DecodeUnicode(str) {
return decodeURIComponent(escape(window.atob( str )));
//return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {
// return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
//}).join(''));
try {
return decodeURIComponent(escape(window.atob( str )));
//return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {
// return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
//}).join(''));
} catch (e) {
// do nothing
}
}


Expand All @@ -27,6 +33,8 @@ class SocketWritable extends Writable {
}

write(chunk, encoding, cb) {
if (this._sock === null)
return;
let msg = JSON.stringify({
"sid": this._sessId,
"type": "stdin",
Expand All @@ -42,13 +50,10 @@ class Webterm {
this.container = container;
this.term = null;
this.pinger = null;
this.backoff = 0;
this.sessId = sessionId;
this._sock = null;
this._connecting = false;
this._connected = false;
this.streamOnHandlers = {};
this.streamOnceHandlers = {};
this.writable = null;
this.restartLoadingTick = null;
}
Expand All @@ -73,19 +78,26 @@ class Webterm {
return;
}

this.term = new Terminal();
this.term.open(this.container);
let created = false;
if (this.term === null) {
this.term = new Terminal();
this.term.open(this.container);
created = true;
}
this.term.reset();
this.term.write("Loading your terminal...\r\n");

let url = "//" + document.domain
+ (location.port ? (":" + location.port) : "") + "/ws?lang=git";
this._sock = new SockJS(url);

// TODO: remove existing handlers
this.writable = new SocketWritable(this.sessId, this._sock);
this.term.on('data', (data) => {
this.writable.write(data);
});
if (created) {
this.term.on('data', (data) => {
this.writable.write(data);
});
}

let is_settled = false;

Expand Down
Loading

0 comments on commit c69d5ec

Please sign in to comment.