2 * Copyright (c) 2013 The Chromium Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
12 // CSP means that we can't kick off the initialization from the html file,
13 // so we do it like this instead.
14 window.onload = function() {
21 * The hterm-powered terminal command.
23 * This class defines a command that can be run in an hterm.Terminal instance.
25 * @param {Object} argv The argument object passed in from the Terminal.
27 function NaClTerm(argv) {
33 var ansiCyan = '\x1b[36m';
34 var ansiReset = '\x1b[0m';
37 * Static initialier called from index.html.
39 * This constructs a new Terminal instance and instructs it to run the NaClTerm
42 NaClTerm.init = function() {
43 var profileName = lib.f.parseQuery(document.location.search)['profile'];
44 var terminal = new hterm.Terminal(profileName);
45 terminal.decorate(document.querySelector('#terminal'));
47 // Useful for console debugging.
48 window.term_ = terminal;
50 // We don't properly support the hterm bell sound, so we need to disable it.
51 terminal.prefs_.definePreference('audible-bell-sound', '');
53 terminal.setAutoCarriageReturn(true);
54 terminal.setCursorPosition(0, 0);
55 terminal.setCursorVisible(true);
56 terminal.runCommandClass(NaClTerm, document.location.hash.substr(1));
62 * Handle messages sent to us from NaCl.
66 NaClTerm.prototype.handleMessage_ = function(e) {
67 if (e.data.indexOf(NaClTerm.prefix) != 0) return;
68 var msg = e.data.substring(NaClTerm.prefix.length);
70 this.bufferedOutput += msg;
77 * Handle load error event from NaCl.
79 NaClTerm.prototype.handleLoadAbort_ = function(e) {
80 term_.io.print('Load aborted.\n');
84 * Handle load abort event from NaCl.
86 NaClTerm.prototype.handleLoadError_ = function(e) {
87 term_.io.print(embed.lastError + '\n');
90 NaClTerm.prototype.doneLoadingUrl = function() {
91 var width = term_.io.terminal_.screenSize.width;
92 term_.io.print('\r' + Array(width+1).join(' '));
93 var message = '\rLoaded ' + this.lastUrl;
95 var kbsize = Math.round(this.lastTotal/1024)
96 message += ' ['+ kbsize + ' KiB]';
98 term_.io.print(message.slice(0, width) + '\n')
102 * Handle load end event from NaCl.
104 NaClTerm.prototype.handleLoad_ = function(e) {
106 this.doneLoadingUrl();
108 term_.io.print('Loaded.\n');
110 term_.io.print(ansiReset);
112 // Now that have completed loading and displaying
113 // loading messages we output any messages from the
114 // NaCl module that were buffered up unto this point
116 term_.io.print(this.bufferedOutput);
117 this.bufferedOutput = ''
121 * Handle load progress event from NaCl.
123 NaClTerm.prototype.handleProgress_ = function(e) {
124 var url = e.url.substring(e.url.lastIndexOf('/') + 1);
126 if (this.lastUrl && this.lastUrl != url)
127 this.doneLoadingUrl()
132 var message = 'Loading ' + url;
133 if (e.lengthComputable && e.total) {
134 var percent = Math.round(e.loaded * 100 / e.total);
135 var kbloaded = Math.round(e.loaded / 1024);
136 var kbtotal = Math.round(e.total / 1024);
137 message += ' [' + kbloaded + ' KiB/' + kbtotal + ' KiB ' + percent + '%]';
140 var width = term_.io.terminal_.screenSize.width;
141 term_.io.print('\r' + message.slice(-width));
143 this.lastTotal = e.total;
147 * Handle crash event from NaCl.
149 NaClTerm.prototype.handleCrash_ = function(e) {
150 term_.io.print(ansiCyan)
151 if (embed.exitStatus == -1) {
152 term_.io.print('Program crashed (exit status -1)\n')
154 term_.io.print('Program exited (status=' + embed.exitStatus + ')\n');
159 NaClTerm.prototype.onTerminalResize_ = function() {
160 var width = term_.io.terminal_.screenSize.width;
161 var height = term_.io.terminal_.screenSize.height;
162 embed.postMessage({'tty_resize': [ width, height ]});
165 NaClTerm.prototype.onVTKeystroke_ = function(str) {
167 message[NaClTerm.prefix] = str;
168 embed.postMessage(message);
172 * This is invoked by the terminal as a result of terminal.runCommandClass().
174 NaClTerm.prototype.run = function() {
175 this.io = this.argv_.io.push();
176 this.bufferedOutput = '';
178 this.io.print(ansiCyan);
180 var mimetype = 'application/x-pnacl';
181 if (navigator.mimeTypes[mimetype] === undefined) {
182 if (mimetype.indexOf('pnacl') != -1)
183 this.io.print('Browser does not support PNaCl or PNaCl is disabled\n');
185 this.io.print('Browser does not support NaCl or NaCl is disabled\n');
189 embed = document.createElement('object');
192 embed.data = NaClTerm.nmf;
193 embed.type = mimetype;
194 embed.addEventListener('message', this.handleMessage_.bind(this));
195 embed.addEventListener('progress', this.handleProgress_.bind(this));
196 embed.addEventListener('load', this.handleLoad_.bind(this));
197 embed.addEventListener('error', this.handleLoadError_.bind(this));
198 embed.addEventListener('abort', this.handleLoadAbort_.bind(this));
199 embed.addEventListener('crash', this.handleCrash_.bind(this));
201 function addParam(name, value) {
202 var param = document.createElement('param');
205 embed.appendChild(param);
208 addParam('ps_tty_prefix', NaClTerm.prefix);
209 addParam('ps_tty_resize', 'tty_resize');
210 addParam('ps_stdin', '/dev/tty');
211 addParam('ps_stdout', '/dev/tty');
212 addParam('ps_stderr', '/dev/tty');
213 addParam('ps_verbosity', '2');
214 addParam('TERM', 'xterm-256color');
216 var args = lib.f.parseQuery(document.location.search);
219 var argname = 'arg' + argn;
220 var arg = args[argname];
221 if (typeof(arg) === 'undefined')
223 addParam(argname, arg);
227 this.io.print('Loading NaCl module.\n')
228 document.body.appendChild(embed);
230 this.io.onVTKeystroke = this.onVTKeystroke_.bind(this);
231 this.io.onTerminalResize = this.onTerminalResize_.bind(this);