| // Copyright 2007 Google Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| /** |
| * @fileoverview |
| * Javascript code for the interactive AJAX shell. |
| * |
| * Part of http://code.google.com/p/google-app-engine-samples/. |
| * |
| * Includes a function (shell.runStatement) that sends the current python |
| * statement in the shell prompt text box to the server, and a callback |
| * (shell.done) that displays the results when the XmlHttpRequest returns. |
| * |
| * Also includes cross-browser code (shell.getXmlHttpRequest) to get an |
| * XmlHttpRequest. |
| */ |
| |
| /** |
| * Shell namespace. |
| * @type {Object} |
| */ |
| var shell = {} |
| |
| /** |
| * The shell history. history is an array of strings, ordered oldest to |
| * newest. historyCursor is the current history element that the user is on. |
| * |
| * The last history element is the statement that the user is currently |
| * typing. When a statement is run, it's frozen in the history, a new history |
| * element is added to the end of the array for the new statement, and |
| * historyCursor is updated to point to the new element. |
| * |
| * @type {Array} |
| */ |
| shell.history = ['']; |
| |
| /** |
| * See {shell.history} |
| * @type {number} |
| */ |
| shell.historyCursor = 0; |
| |
| /** |
| * A constant for the XmlHttpRequest 'done' state. |
| * @type Number |
| */ |
| shell.DONE_STATE = 4; |
| |
| /** |
| * A cross-browser function to get an XmlHttpRequest object. |
| * |
| * @return {XmlHttpRequest?} a new XmlHttpRequest |
| */ |
| shell.getXmlHttpRequest = function() { |
| if (window.XMLHttpRequest) { |
| return new XMLHttpRequest(); |
| } else if (window.ActiveXObject) { |
| try { |
| return new ActiveXObject('Msxml2.XMLHTTP'); |
| } catch(e) { |
| return new ActiveXObject('Microsoft.XMLHTTP'); |
| } |
| } |
| |
| return null; |
| }; |
| |
| /** |
| * This is the prompt textarea's onkeypress handler. Depending on the key that |
| * was pressed, it will run the statement, navigate the history, or update the |
| * current statement in the history. |
| * |
| * @param {Event} event the keypress event |
| * @return {Boolean} false to tell the browser not to submit the form. |
| */ |
| shell.onPromptKeyPress = function(event) { |
| var statement = document.getElementById('statement'); |
| |
| if (this.historyCursor == this.history.length - 1) { |
| // we're on the current statement. update it in the history before doing |
| // anything. |
| this.history[this.historyCursor] = statement.value; |
| } |
| |
| // should we pull something from the history? |
| if (event.ctrlKey && event.keyCode == 38 /* up arrow */) { |
| if (this.historyCursor > 0) { |
| statement.value = this.history[--this.historyCursor]; |
| } |
| return false; |
| } else if (event.ctrlKey && event.keyCode == 40 /* down arrow */) { |
| if (this.historyCursor < this.history.length - 1) { |
| statement.value = this.history[++this.historyCursor]; |
| } |
| return false; |
| } else if (!event.altKey) { |
| // probably changing the statement. update it in the history. |
| this.historyCursor = this.history.length - 1; |
| this.history[this.historyCursor] = statement.value; |
| } |
| |
| // should we submit? |
| var ctrlEnter = (document.getElementById('submit_key').value == 'ctrl-enter'); |
| if (event.keyCode == 13 /* enter */ && !event.altKey && !event.shiftKey && |
| event.ctrlKey == ctrlEnter) { |
| return this.runStatement(); |
| } |
| }; |
| |
| /** |
| * The XmlHttpRequest callback. If the request succeeds, it adds the command |
| * and its resulting output to the shell history div. |
| * |
| * @param {XmlHttpRequest} req the XmlHttpRequest we used to send the current |
| * statement to the server |
| */ |
| shell.done = function(req) { |
| if (req.readyState == this.DONE_STATE) { |
| var statement = document.getElementById('statement') |
| statement.className = 'prompt'; |
| |
| // add the command to the shell output |
| var output = document.getElementById('output'); |
| |
| output.value += '\n>>> ' + statement.value; |
| statement.value = ''; |
| |
| // add a new history element |
| this.history.push(''); |
| this.historyCursor = this.history.length - 1; |
| |
| // add the command's result |
| var result = req.responseText.replace(/^\s*|\s*$/g, ''); // trim whitespace |
| if (result != '') |
| output.value += '\n' + result; |
| |
| // scroll to the bottom |
| output.scrollTop = output.scrollHeight; |
| if (output.createTextRange) { |
| var range = output.createTextRange(); |
| range.collapse(false); |
| range.select(); |
| } |
| } |
| }; |
| |
| /** |
| * This is the form's onsubmit handler. It sends the python statement to the |
| * server, and registers shell.done() as the callback to run when it returns. |
| * |
| * @return {Boolean} false to tell the browser not to submit the form. |
| */ |
| shell.runStatement = function() { |
| var form = document.getElementById('form'); |
| |
| // build a XmlHttpRequest |
| var req = this.getXmlHttpRequest(); |
| if (!req) { |
| document.getElementById('ajax-status').innerHTML = |
| "<span class='error'>Your browser doesn't support AJAX. :(</span>"; |
| return false; |
| } |
| |
| req.onreadystatechange = function() { shell.done(req); }; |
| |
| // build the query parameter string |
| var params = ''; |
| for (i = 0; i < form.elements.length; i++) { |
| var elem = form.elements[i]; |
| if (elem.type != 'submit' && elem.type != 'button' && elem.id != 'caret') { |
| var value = escape(elem.value).replace(/\+/g, '%2B'); // escape ignores + |
| params += '&' + elem.name + '=' + value; |
| } |
| } |
| |
| // send the request and tell the user. |
| document.getElementById('statement').className = 'prompt processing'; |
| req.open(form.method, form.action + '?' + params, true); |
| req.setRequestHeader('Content-type', |
| 'application/x-www-form-urlencoded;charset=UTF-8'); |
| req.send(null); |
| |
| return false; |
| }; |