- add sources.
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / gonacl_appengine / static / pnacl-demo-lua / naclterm.js
1 /*
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.
5  */
6
7 'use strict';
8
9 lib.rtdep('lib.f',
10           'hterm');
11
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() {
15   lib.init(function() {
16     NaClTerm.init();
17   });
18 };
19
20 /**
21  * The hterm-powered terminal command.
22  *
23  * This class defines a command that can be run in an hterm.Terminal instance.
24  *
25  * @param {Object} argv The argument object passed in from the Terminal.
26  */
27 function NaClTerm(argv) {
28   this.argv_ = argv;
29   this.io = null;
30 };
31
32 var embed;
33 var ansiCyan = '\x1b[36m';
34 var ansiReset = '\x1b[0m';
35
36 /**
37  * Static initialier called from index.html.
38  *
39  * This constructs a new Terminal instance and instructs it to run the NaClTerm
40  * command.
41  */
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'));
46
47   // Useful for console debugging.
48   window.term_ = terminal;
49
50   // We don't properly support the hterm bell sound, so we need to disable it.
51   terminal.prefs_.definePreference('audible-bell-sound', '');
52
53   terminal.setAutoCarriageReturn(true);
54   terminal.setCursorPosition(0, 0);
55   terminal.setCursorVisible(true);
56   terminal.runCommandClass(NaClTerm, document.location.hash.substr(1));
57
58   return true;
59 };
60
61 /**
62  * Handle messages sent to us from NaCl.
63  *
64  * @private
65  */
66 NaClTerm.prototype.handleMessage_ = function(e) {
67   if (e.data.indexOf(NaClTerm.prefix) != 0) return;
68   var msg = e.data.substring(NaClTerm.prefix.length);
69   if (!this.loaded) {
70     this.bufferedOutput += msg;
71   } else {
72     term_.io.print(msg);
73   }
74 }
75
76 /**
77  * Handle load error event from NaCl.
78  */
79 NaClTerm.prototype.handleLoadAbort_ = function(e) {
80   term_.io.print('Load aborted.\n');
81 }
82
83 /**
84  * Handle load abort event from NaCl.
85  */
86 NaClTerm.prototype.handleLoadError_ = function(e) {
87   term_.io.print(embed.lastError + '\n');
88 }
89
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;
94   if (this.lastTotal) {
95     var kbsize = Math.round(this.lastTotal/1024)
96     message += ' ['+ kbsize + ' KiB]';
97   }
98   term_.io.print(message.slice(0, width) + '\n')
99 }
100
101 /**
102  * Handle load end event from NaCl.
103  */
104 NaClTerm.prototype.handleLoad_ = function(e) {
105   if (this.lastUrl)
106     this.doneLoadingUrl();
107   else
108     term_.io.print('Loaded.\n');
109
110   term_.io.print(ansiReset);
111
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
115   this.loaded = true;
116   term_.io.print(this.bufferedOutput);
117   this.bufferedOutput = ''
118 }
119
120 /**
121  * Handle load progress event from NaCl.
122  */
123 NaClTerm.prototype.handleProgress_ = function(e) {
124   var url = e.url.substring(e.url.lastIndexOf('/') + 1);
125
126   if (this.lastUrl && this.lastUrl != url)
127     this.doneLoadingUrl()
128
129   if (!url)
130     return;
131
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 + '%]';
138   }
139
140   var width = term_.io.terminal_.screenSize.width;
141   term_.io.print('\r' + message.slice(-width));
142   this.lastUrl = url;
143   this.lastTotal = e.total;
144 }
145
146 /**
147  * Handle crash event from NaCl.
148  */
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')
153  } else {
154    term_.io.print('Program exited (status=' + embed.exitStatus + ')\n');
155  }
156 }
157
158
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 ]});
163 }
164
165 NaClTerm.prototype.onVTKeystroke_ = function(str) {
166   var message = {};
167   message[NaClTerm.prefix] = str;
168   embed.postMessage(message);
169 }
170
171 /*
172  * This is invoked by the terminal as a result of terminal.runCommandClass().
173  */
174 NaClTerm.prototype.run = function() {
175   this.io = this.argv_.io.push();
176   this.bufferedOutput = '';
177   this.loaded = false;
178   this.io.print(ansiCyan);
179
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');
184     else
185       this.io.print('Browser does not support NaCl or NaCl is disabled\n');
186     return;
187   }
188
189   embed = document.createElement('object');
190   embed.width = 0;
191   embed.height = 0;
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));
200
201   function addParam(name, value) {
202     var param = document.createElement('param');
203     param.name = name;
204     param.value = value;
205     embed.appendChild(param);
206   }
207
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');
215
216   var args = lib.f.parseQuery(document.location.search);
217   var argn = 1;
218   while (true) {
219     var argname = 'arg' + argn;
220     var arg = args[argname];
221     if (typeof(arg) === 'undefined')
222       break;
223     addParam(argname, arg);
224     argn = argn + 1;
225   }
226
227   this.io.print('Loading NaCl module.\n')
228   document.body.appendChild(embed);
229
230   this.io.onVTKeystroke = this.onVTKeystroke_.bind(this);
231   this.io.onTerminalResize = this.onTerminalResize_.bind(this);
232 };