1 // Copyright 2007 Google Inc.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
17 * Javascript code for the interactive AJAX shell.
19 * Part of http://code.google.com/p/google-app-engine-samples/.
21 * Includes a function (shell.runStatement) that sends the current python
22 * statement in the shell prompt text box to the server, and a callback
23 * (shell.done) that displays the results when the XmlHttpRequest returns.
25 * Also includes cross-browser code (shell.getXmlHttpRequest) to get an
36 * The shell history. history is an array of strings, ordered oldest to
37 * newest. historyCursor is the current history element that the user is on.
39 * The last history element is the statement that the user is currently
40 * typing. When a statement is run, it's frozen in the history, a new history
41 * element is added to the end of the array for the new statement, and
42 * historyCursor is updated to point to the new element.
52 shell.historyCursor = 0;
55 * A constant for the XmlHttpRequest 'done' state.
61 * A cross-browser function to get an XmlHttpRequest object.
63 * @return {XmlHttpRequest?} a new XmlHttpRequest
65 shell.getXmlHttpRequest = function() {
66 if (window.XMLHttpRequest) {
67 return new XMLHttpRequest();
68 } else if (window.ActiveXObject) {
70 return new ActiveXObject('Msxml2.XMLHTTP');
72 return new ActiveXObject('Microsoft.XMLHTTP');
80 * This is the prompt textarea's onkeypress handler. Depending on the key that
81 * was pressed, it will run the statement, navigate the history, or update the
82 * current statement in the history.
84 * @param {Event} event the keypress event
85 * @return {Boolean} false to tell the browser not to submit the form.
87 shell.onPromptKeyPress = function(event) {
88 var statement = document.getElementById('statement');
90 if (this.historyCursor == this.history.length - 1) {
91 // we're on the current statement. update it in the history before doing
93 this.history[this.historyCursor] = statement.value;
96 // should we pull something from the history?
97 if (event.shiftKey && event.keyCode == 38 /* up arrow */) {
98 if (this.historyCursor > 0) {
99 statement.value = this.history[--this.historyCursor];
102 } else if (event.shiftKey && event.keyCode == 40 /* down arrow */) {
103 if (this.historyCursor < this.history.length - 1) {
104 statement.value = this.history[++this.historyCursor];
107 } else if (!event.altKey) {
108 // probably changing the statement. update it in the history.
109 this.historyCursor = this.history.length - 1;
110 this.history[this.historyCursor] = statement.value;
114 var ctrlEnter = (document.getElementById('submit_key').value == 'ctrl-enter');
115 if (event.keyCode == 13 /* enter */ && !event.altKey && !event.shiftKey &&
116 event.ctrlKey == ctrlEnter) {
117 return this.runStatement();
122 * The XmlHttpRequest callback. If the request succeeds, it adds the command
123 * and its resulting output to the shell history div.
125 * @param {XmlHttpRequest} req the XmlHttpRequest we used to send the current
126 * statement to the server
128 shell.done = function(req) {
129 if (req.readyState == this.DONE_STATE) {
130 var statement = document.getElementById('statement')
131 statement.className = 'prompt';
133 // add the command to the shell output
134 var output = document.getElementById('output');
136 output.value += '\n>>> ' + statement.value;
137 statement.value = '';
139 // add a new history element
140 this.history.push('');
141 this.historyCursor = this.history.length - 1;
143 // add the command's result
144 var result = req.responseText.replace(/^\s*|\s*$/g, ''); // trim whitespace
146 output.value += '\n' + result;
148 // scroll to the bottom
149 output.scrollTop = output.scrollHeight;
150 if (output.createTextRange) {
151 var range = output.createTextRange();
152 range.collapse(false);
159 * This is the form's onsubmit handler. It sends the python statement to the
160 * server, and registers shell.done() as the callback to run when it returns.
162 * @return {Boolean} false to tell the browser not to submit the form.
164 shell.runStatement = function() {
165 var form = document.getElementById('form');
167 // build a XmlHttpRequest
168 var req = this.getXmlHttpRequest();
170 document.getElementById('ajax-status').innerHTML =
171 "<span class='error'>Your browser doesn't support AJAX. :(</span>";
175 req.onreadystatechange = function() { shell.done(req); };
177 // build the query parameter string
179 for (i = 0; i < form.elements.length; i++) {
180 var elem = form.elements[i];
181 if (elem.type != 'submit' && elem.type != 'button' && elem.id != 'caret') {
182 var value = escape(elem.value).replace(/\+/g, '%2B'); // escape ignores +
183 params += '&' + elem.name + '=' + value;
187 // send the request and tell the user.
188 document.getElementById('statement').className = 'prompt processing';
189 req.open(form.method, form.action + '?' + params, true);
190 req.setRequestHeader('Content-type',
191 'application/x-www-form-urlencoded;charset=UTF-8');