1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/metro/base/content/jsshell/shell.html Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,770 @@ 1.4 +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 1.5 + 1.6 +<html onclick="keepFocusInTextbox(event)"> 1.7 +<head> 1.8 +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> 1.9 +<title>JavaScript Shell 1.4</title> 1.10 + 1.11 +<script type="text/javascript"> 1.12 +var 1.13 + histList = [""], 1.14 + histPos = 0, 1.15 + _scope = {}, 1.16 + _win, // a top-level context 1.17 + question, // {String} the input command that's being evaluated. Accessed via 1.18 + // |Shell.question| from the target window for evaluation. 1.19 + _in, // {HTMLTextAreaElement} the textarea containing the input 1.20 + _out, // {HTMLDivElement} the output is printed to this element 1.21 + tooManyMatches = null, 1.22 + lastError = null, 1.23 + _jsVer = 0 // determines the way to execute the commands, see run() 1.24 + ; 1.25 + 1.26 +function refocus() 1.27 +{ 1.28 + _in.blur(); // Needed for Mozilla to scroll correctly. 1.29 + _in.focus(); 1.30 +} 1.31 + 1.32 +function init() 1.33 +{ 1.34 + _in = document.getElementById("input"); 1.35 + _out = document.getElementById("output"); 1.36 + 1.37 + _win = window; 1.38 + 1.39 + if (opener && !opener.closed) 1.40 + { 1.41 + println("Using bookmarklet version of shell: commands will run in opener's context.", "message"); 1.42 + _win = opener; 1.43 + } 1.44 + 1.45 + /* Run a series of (potentially async, but quick) tests to determine the 1.46 + * way to run code in this browser (for run()). Sets window._jsVer based 1.47 + * on the tests. */ 1.48 + _jsVer = 0; 1.49 + for (var jsVerToTry=19; jsVerToTry>=15; jsVerToTry--) { 1.50 + run(window, "if(_jsVer < " + jsVerToTry + ") { " + 1.51 + "_jsVer=" + jsVerToTry + "; }", jsVerToTry); 1.52 + } 1.53 + 1.54 + initTarget(); 1.55 + 1.56 + recalculateInputHeight(); 1.57 + refocus(); 1.58 +} 1.59 + 1.60 +/** 1.61 + * Runs |code| in |_win|'s context. 1.62 + * @param overridenJSVer {int} (optional) overrides the default (specified by _jsVer) 1.63 + * way to run the code. 1.64 + */ 1.65 +function run(_win, code, overridenJSVer) { 1.66 + var jsVerToUse = overridenJSVer ? overridenJSVer : _jsVer; 1.67 + if (jsVerToUse <= 15) { 1.68 + _win.location.href = "javascript:" + code + "; void 0"; 1.69 + } else { 1.70 + var sc = _win.document.createElement("script"); 1.71 + sc.type="application/javascript;version=" + jsVerToUse/10; 1.72 + sc.src="data:application/x-javascript," + code; 1.73 + _win.document.body.appendChild(sc); // runs the script asynchronously 1.74 + } 1.75 +} 1.76 + 1.77 +function initTarget() 1.78 +{ 1.79 + _win.Shell = window; 1.80 + _win.print = shellCommands.print; 1.81 +} 1.82 + 1.83 + 1.84 +// Unless the user is selected something, refocus the textbox. 1.85 +// (requested by caillon, brendan, asa) 1.86 +function keepFocusInTextbox(e) 1.87 +{ 1.88 + var g = e.srcElement ? e.srcElement : e.target; // IE vs. standard 1.89 + 1.90 + while (!g.tagName) 1.91 + g = g.parentNode; 1.92 + var t = g.tagName.toUpperCase(); 1.93 + if (t=="A" || t=="INPUT") 1.94 + return; 1.95 + 1.96 + if (window.getSelection) { 1.97 + // Mozilla 1.98 + if (String(window.getSelection())) 1.99 + return; 1.100 + } 1.101 + else { 1.102 + // IE 1.103 + if ( document.selection.createRange().text ) 1.104 + return; 1.105 + } 1.106 + 1.107 + refocus(); 1.108 +} 1.109 + 1.110 +function inputKeydown(e) { 1.111 + // Use onkeydown because IE doesn't support onkeypress for arrow keys 1.112 + 1.113 + //alert(e.keyCode + " ^ " + e.keycode); 1.114 + 1.115 + if (e.shiftKey && e.keyCode == 13) { // shift-enter 1.116 + // don't do anything; allow the shift-enter to insert a line break as normal 1.117 + } else if (e.keyCode == 13) { // enter 1.118 + // execute the input on enter 1.119 + try { go(); } catch(er) { alert(er); }; 1.120 + setTimeout(function() { _in.value = ""; }, 0); // can't preventDefault on input, so clear it later 1.121 + } else if (e.keyCode == 38) { // up 1.122 + // go up in history if at top or ctrl-up 1.123 + if (e.ctrlKey || caretInFirstLine(_in)) 1.124 + hist(true); 1.125 + } else if (e.keyCode == 40) { // down 1.126 + // go down in history if at end or ctrl-down 1.127 + if (e.ctrlKey || caretInLastLine(_in)) 1.128 + hist(false); 1.129 + } else if (e.keyCode == 9) { // tab 1.130 + tabcomplete(); 1.131 + setTimeout(function() { refocus(); }, 0); // refocus because tab was hit 1.132 + } else { } 1.133 + 1.134 + setTimeout(recalculateInputHeight, 0); 1.135 + 1.136 + //return true; 1.137 +}; 1.138 + 1.139 +function caretInFirstLine(textbox) 1.140 +{ 1.141 + // IE doesn't support selectionStart/selectionEnd 1.142 + if (textbox.selectionStart == undefined) 1.143 + return true; 1.144 + 1.145 + var firstLineBreak = textbox.value.indexOf("\n"); 1.146 + 1.147 + return ((firstLineBreak == -1) || (textbox.selectionStart <= firstLineBreak)); 1.148 +} 1.149 + 1.150 +function caretInLastLine(textbox) 1.151 +{ 1.152 + // IE doesn't support selectionStart/selectionEnd 1.153 + if (textbox.selectionEnd == undefined) 1.154 + return true; 1.155 + 1.156 + var lastLineBreak = textbox.value.lastIndexOf("\n"); 1.157 + 1.158 + return (textbox.selectionEnd > lastLineBreak); 1.159 +} 1.160 + 1.161 +function recalculateInputHeight() 1.162 +{ 1.163 + var rows = _in.value.split(/\n/).length 1.164 + + 1 // prevent scrollbar flickering in Mozilla 1.165 + + (window.opera ? 1 : 0); // leave room for scrollbar in Opera 1.166 + 1.167 + if (_in.rows != rows) // without this check, it is impossible to select text in Opera 7.60 or Opera 8.0. 1.168 + _in.rows = rows; 1.169 +} 1.170 + 1.171 +function println(s, type) 1.172 +{ 1.173 + if((s=String(s))) 1.174 + { 1.175 + var newdiv = document.createElement("div"); 1.176 + newdiv.appendChild(document.createTextNode(s)); 1.177 + newdiv.className = type; 1.178 + _out.appendChild(newdiv); 1.179 + return newdiv; 1.180 + } 1.181 + return false; 1.182 +} 1.183 + 1.184 +function printWithRunin(h, s, type) 1.185 +{ 1.186 + var div = println(s, type); 1.187 + if (div) { 1.188 + var head = document.createElement("strong"); 1.189 + head.appendChild(document.createTextNode(h + ": ")); 1.190 + div.insertBefore(head, div.firstChild); 1.191 + } 1.192 +} 1.193 + 1.194 + 1.195 +var shellCommands = 1.196 +{ 1.197 +load : function load(url) 1.198 +{ 1.199 + var s = _win.document.createElement("script"); 1.200 + s.type = "text/javascript"; 1.201 + s.src = url; 1.202 + _win.document.getElementsByTagName("head")[0].appendChild(s); 1.203 + println("Loading " + url + "...", "message"); 1.204 +}, 1.205 + 1.206 +clear : function clear() 1.207 +{ 1.208 + var CHILDREN_TO_PRESERVE = 3; 1.209 + while (_out.childNodes[CHILDREN_TO_PRESERVE]) 1.210 + _out.removeChild(_out.childNodes[CHILDREN_TO_PRESERVE]); 1.211 +}, 1.212 + 1.213 +print : function print(s) { println(s, "print"); }, 1.214 + 1.215 +// the normal function, "print", shouldn't return a value 1.216 +// (suggested by brendan; later noticed it was a problem when showing others) 1.217 +pr : function pr(s) 1.218 +{ 1.219 + shellCommands.print(s); // need to specify shellCommands so it doesn't try window.print()! 1.220 + return s; 1.221 +}, 1.222 + 1.223 +props : function props(e, onePerLine) 1.224 +{ 1.225 + if (e === null) { 1.226 + println("props called with null argument", "error"); 1.227 + return; 1.228 + } 1.229 + 1.230 + if (e === undefined) { 1.231 + println("props called with undefined argument", "error"); 1.232 + return; 1.233 + } 1.234 + 1.235 + var ns = ["Methods", "Fields", "Unreachables"]; 1.236 + var as = [[], [], []]; // array of (empty) arrays of arrays! 1.237 + var p, j, i; // loop variables, several used multiple times 1.238 + 1.239 + var protoLevels = 0; 1.240 + 1.241 + for (p = e; p; p = p.__proto__) 1.242 + { 1.243 + for (i=0; i<ns.length; ++i) 1.244 + as[i][protoLevels] = []; 1.245 + ++protoLevels; 1.246 + } 1.247 + 1.248 + for(var a in e) 1.249 + { 1.250 + // Shortcoming: doesn't check that VALUES are the same in object and prototype. 1.251 + 1.252 + var protoLevel = -1; 1.253 + try 1.254 + { 1.255 + for (p = e; p && (a in p); p = p.__proto__) 1.256 + ++protoLevel; 1.257 + } 1.258 + catch(er) { protoLevel = 0; } // "in" operator throws when param to props() is a string 1.259 + 1.260 + var type = 1; 1.261 + try 1.262 + { 1.263 + if ((typeof e[a]) == "function") 1.264 + type = 0; 1.265 + } 1.266 + catch (er) { type = 2; } 1.267 + 1.268 + as[type][protoLevel].push(a); 1.269 + } 1.270 + 1.271 + function times(s, n) { return n ? s + times(s, n-1) : ""; } 1.272 + 1.273 + for (j=0; j<protoLevels; ++j) 1.274 + for (i=0;i<ns.length;++i) 1.275 + if (as[i][j].length) 1.276 + printWithRunin( 1.277 + ns[i] + times(" of prototype", j), 1.278 + (onePerLine ? "\n\n" : "") + as[i][j].sort().join(onePerLine ? "\n" : ", ") + (onePerLine ? "\n\n" : ""), 1.279 + "propList" 1.280 + ); 1.281 +}, 1.282 + 1.283 +blink : function blink(node) 1.284 +{ 1.285 + if (!node) throw("blink: argument is null or undefined."); 1.286 + if (node.nodeType == null) throw("blink: argument must be a node."); 1.287 + if (node.nodeType == 3) throw("blink: argument must not be a text node"); 1.288 + if (node.documentElement) throw("blink: argument must not be the document object"); 1.289 + 1.290 + function setOutline(o) { 1.291 + return function() { 1.292 + if (node.style.outline != node.style.bogusProperty) { 1.293 + // browser supports outline (Firefox 1.1 and newer, CSS3, Opera 8). 1.294 + node.style.outline = o; 1.295 + } 1.296 + else if (node.style.MozOutline != node.style.bogusProperty) { 1.297 + // browser supports MozOutline (Firefox 1.0.x and older) 1.298 + node.style.MozOutline = o; 1.299 + } 1.300 + else { 1.301 + // browser only supports border (IE). border is a fallback because it moves things around. 1.302 + node.style.border = o; 1.303 + } 1.304 + } 1.305 + } 1.306 + 1.307 + function focusIt(a) { 1.308 + return function() { 1.309 + a.focus(); 1.310 + } 1.311 + } 1.312 + 1.313 + if (node.ownerDocument) { 1.314 + var windowToFocusNow = (node.ownerDocument.defaultView || node.ownerDocument.parentWindow); // Moz vs. IE 1.315 + if (windowToFocusNow) 1.316 + setTimeout(focusIt(windowToFocusNow.top), 0); 1.317 + } 1.318 + 1.319 + for(var i=1;i<7;++i) 1.320 + setTimeout(setOutline((i%2)?'3px solid red':'none'), i*100); 1.321 + 1.322 + setTimeout(focusIt(window), 800); 1.323 + setTimeout(focusIt(_in), 810); 1.324 +}, 1.325 + 1.326 +scope : function scope(sc) 1.327 +{ 1.328 + if (!sc) sc = {}; 1.329 + _scope = sc; 1.330 + println("Scope is now " + sc + ". If a variable is not found in this scope, window will also be searched. New variables will still go on window.", "message"); 1.331 +}, 1.332 + 1.333 +mathHelp : function mathHelp() 1.334 +{ 1.335 + printWithRunin("Math constants", "E, LN2, LN10, LOG2E, LOG10E, PI, SQRT1_2, SQRT2", "propList"); 1.336 + printWithRunin("Math methods", "abs, acos, asin, atan, atan2, ceil, cos, exp, floor, log, max, min, pow, random, round, sin, sqrt, tan", "propList"); 1.337 +}, 1.338 + 1.339 +ans : undefined 1.340 +}; 1.341 + 1.342 + 1.343 +function hist(up) 1.344 +{ 1.345 + // histList[0] = first command entered, [1] = second, etc. 1.346 + // type something, press up --> thing typed is now in "limbo" 1.347 + // (last item in histList) and should be reachable by pressing 1.348 + // down again. 1.349 + 1.350 + var L = histList.length; 1.351 + 1.352 + if (L == 1) 1.353 + return; 1.354 + 1.355 + if (up) 1.356 + { 1.357 + if (histPos == L-1) 1.358 + { 1.359 + // Save this entry in case the user hits the down key. 1.360 + histList[histPos] = _in.value; 1.361 + } 1.362 + 1.363 + if (histPos > 0) 1.364 + { 1.365 + histPos--; 1.366 + // Use a timeout to prevent up from moving cursor within new text 1.367 + // Set to nothing first for the same reason 1.368 + setTimeout( 1.369 + function() { 1.370 + _in.value = ''; 1.371 + _in.value = histList[histPos]; 1.372 + var caretPos = _in.value.length; 1.373 + if (_in.setSelectionRange) 1.374 + _in.setSelectionRange(caretPos, caretPos); 1.375 + }, 1.376 + 0 1.377 + ); 1.378 + } 1.379 + } 1.380 + else // down 1.381 + { 1.382 + if (histPos < L-1) 1.383 + { 1.384 + histPos++; 1.385 + _in.value = histList[histPos]; 1.386 + } 1.387 + else if (histPos == L-1) 1.388 + { 1.389 + // Already on the current entry: clear but save 1.390 + if (_in.value) 1.391 + { 1.392 + histList[histPos] = _in.value; 1.393 + ++histPos; 1.394 + _in.value = ""; 1.395 + } 1.396 + } 1.397 + } 1.398 +} 1.399 + 1.400 +function tabcomplete() 1.401 +{ 1.402 + /* 1.403 + * Working backwards from s[from], find the spot 1.404 + * where this expression starts. It will scan 1.405 + * until it hits a mismatched ( or a space, 1.406 + * but it skips over quoted strings. 1.407 + * If stopAtDot is true, stop at a '.' 1.408 + */ 1.409 + function findbeginning(s, from, stopAtDot) 1.410 + { 1.411 + /* 1.412 + * Complicated function. 1.413 + * 1.414 + * Return true if s[i] == q BUT ONLY IF 1.415 + * s[i-1] is not a backslash. 1.416 + */ 1.417 + function equalButNotEscaped(s,i,q) 1.418 + { 1.419 + if(s.charAt(i) != q) // not equal go no further 1.420 + return false; 1.421 + 1.422 + if(i==0) // beginning of string 1.423 + return true; 1.424 + 1.425 + if(s.charAt(i-1) == '\\') // escaped? 1.426 + return false; 1.427 + 1.428 + return true; 1.429 + } 1.430 + 1.431 + var nparens = 0; 1.432 + var i; 1.433 + for(i=from; i>=0; i--) 1.434 + { 1.435 + if(s.charAt(i) == ' ') 1.436 + break; 1.437 + 1.438 + if(stopAtDot && s.charAt(i) == '.') 1.439 + break; 1.440 + 1.441 + if(s.charAt(i) == ')') 1.442 + nparens++; 1.443 + else if(s.charAt(i) == '(') 1.444 + nparens--; 1.445 + 1.446 + if(nparens < 0) 1.447 + break; 1.448 + 1.449 + // skip quoted strings 1.450 + if(s.charAt(i) == '\'' || s.charAt(i) == '\"') 1.451 + { 1.452 + //dump("skipping quoted chars: "); 1.453 + var quot = s.charAt(i); 1.454 + i--; 1.455 + while(i >= 0 && !equalButNotEscaped(s,i,quot)) { 1.456 + //dump(s.charAt(i)); 1.457 + i--; 1.458 + } 1.459 + //dump("\n"); 1.460 + } 1.461 + } 1.462 + return i; 1.463 + } 1.464 + 1.465 + // XXX should be used more consistently (instead of using selectionStart/selectionEnd throughout code) 1.466 + // XXX doesn't work in IE, even though it contains IE-specific code 1.467 + function getcaretpos(inp) 1.468 + { 1.469 + if(inp.selectionEnd != null) 1.470 + return inp.selectionEnd; 1.471 + 1.472 + if(inp.createTextRange) 1.473 + { 1.474 + var docrange = _win.Shell.document.selection.createRange(); 1.475 + var inprange = inp.createTextRange(); 1.476 + if (inprange.setEndPoint) 1.477 + { 1.478 + inprange.setEndPoint('EndToStart', docrange); 1.479 + return inprange.text.length; 1.480 + } 1.481 + } 1.482 + 1.483 + return inp.value.length; // sucks, punt 1.484 + } 1.485 + 1.486 + function setselectionto(inp,pos) 1.487 + { 1.488 + if(inp.selectionStart) { 1.489 + inp.selectionStart = inp.selectionEnd = pos; 1.490 + } 1.491 + else if(inp.createTextRange) { 1.492 + var docrange = _win.Shell.document.selection.createRange(); 1.493 + var inprange = inp.createTextRange(); 1.494 + inprange.move('character',pos); 1.495 + inprange.select(); 1.496 + } 1.497 + else { // err... 1.498 + /* 1.499 + inp.select(); 1.500 + if(_win.Shell.document.getSelection()) 1.501 + _win.Shell.document.getSelection() = ""; 1.502 + */ 1.503 + } 1.504 + } 1.505 + // get position of cursor within the input box 1.506 + var caret = getcaretpos(_in); 1.507 + 1.508 + if(caret) { 1.509 + //dump("----\n"); 1.510 + var dotpos, spacepos, complete, obj; 1.511 + //dump("caret pos: " + caret + "\n"); 1.512 + // see if there's a dot before here 1.513 + dotpos = findbeginning(_in.value, caret-1, true); 1.514 + //dump("dot pos: " + dotpos + "\n"); 1.515 + if(dotpos == -1 || _in.value.charAt(dotpos) != '.') { 1.516 + dotpos = caret; 1.517 +//dump("changed dot pos: " + dotpos + "\n"); 1.518 + } 1.519 + 1.520 + // look backwards for a non-variable-name character 1.521 + spacepos = findbeginning(_in.value, dotpos-1, false); 1.522 + //dump("space pos: " + spacepos + "\n"); 1.523 + // get the object we're trying to complete on 1.524 + if(spacepos == dotpos || spacepos+1 == dotpos || dotpos == caret) 1.525 + { 1.526 + // try completing function args 1.527 + if(_in.value.charAt(dotpos) == '(' || 1.528 + (_in.value.charAt(spacepos) == '(' && (spacepos+1) == dotpos)) 1.529 + { 1.530 + var fn,fname; 1.531 + var from = (_in.value.charAt(dotpos) == '(') ? dotpos : spacepos; 1.532 + spacepos = findbeginning(_in.value, from-1, false); 1.533 + 1.534 + fname = _in.value.substr(spacepos+1,from-(spacepos+1)); 1.535 + //dump("fname: " + fname + "\n"); 1.536 + try { 1.537 + with(_win.Shell._scope) 1.538 + with(_win) 1.539 + with(Shell.shellCommands) 1.540 + fn = eval(fname); 1.541 + } 1.542 + catch(er) { 1.543 + //dump('fn is not a valid object\n'); 1.544 + return; 1.545 + } 1.546 + if(fn == undefined) { 1.547 + //dump('fn is undefined'); 1.548 + return; 1.549 + } 1.550 + if(fn instanceof Function) 1.551 + { 1.552 + // Print function definition, including argument names, but not function body 1.553 + if(!fn.toString().match(/function .+?\(\) +\{\n +\[native code\]\n\}/)) 1.554 + println(fn.toString().match(/function .+?\(.*?\)/), "tabcomplete"); 1.555 + } 1.556 + 1.557 + return; 1.558 + } 1.559 + else 1.560 + obj = _win; 1.561 + } 1.562 + else 1.563 + { 1.564 + var objname = _in.value.substr(spacepos+1,dotpos-(spacepos+1)); 1.565 + //dump("objname: |" + objname + "|\n"); 1.566 + try { 1.567 + with(_win.Shell._scope) 1.568 + with(_win) 1.569 + obj = eval(objname); 1.570 + } 1.571 + catch(er) { 1.572 + printError(er); 1.573 + return; 1.574 + } 1.575 + if(obj == undefined) { 1.576 + // sometimes this is tabcomplete's fault, so don't print it :( 1.577 + // e.g. completing from "print(document.getElements" 1.578 + // println("Can't complete from null or undefined expression " + objname, "error"); 1.579 + return; 1.580 + } 1.581 + } 1.582 + //dump("obj: " + obj + "\n"); 1.583 + // get the thing we're trying to complete 1.584 + if(dotpos == caret) 1.585 + { 1.586 + if(spacepos+1 == dotpos || spacepos == dotpos) 1.587 + { 1.588 + // nothing to complete 1.589 + //dump("nothing to complete\n"); 1.590 + return; 1.591 + } 1.592 + 1.593 + complete = _in.value.substr(spacepos+1,dotpos-(spacepos+1)); 1.594 + } 1.595 + else { 1.596 + complete = _in.value.substr(dotpos+1,caret-(dotpos+1)); 1.597 + } 1.598 + //dump("complete: " + complete + "\n"); 1.599 + // ok, now look at all the props/methods of this obj 1.600 + // and find ones starting with 'complete' 1.601 + var matches = []; 1.602 + var bestmatch = null; 1.603 + for(var a in obj) 1.604 + { 1.605 + //a = a.toString(); 1.606 + //XXX: making it lowercase could help some cases, 1.607 + // but screws up my general logic. 1.608 + if(a.substr(0,complete.length) == complete) { 1.609 + matches.push(a); 1.610 + ////dump("match: " + a + "\n"); 1.611 + // if no best match, this is the best match 1.612 + if(bestmatch == null) 1.613 + { 1.614 + bestmatch = a; 1.615 + } 1.616 + else { 1.617 + // the best match is the longest common string 1.618 + function min(a,b){ return ((a<b)?a:b); } 1.619 + var i; 1.620 + for(i=0; i< min(bestmatch.length, a.length); i++) 1.621 + { 1.622 + if(bestmatch.charAt(i) != a.charAt(i)) 1.623 + break; 1.624 + } 1.625 + bestmatch = bestmatch.substr(0,i); 1.626 + ////dump("bestmatch len: " + i + "\n"); 1.627 + } 1.628 + ////dump("bestmatch: " + bestmatch + "\n"); 1.629 + } 1.630 + } 1.631 + bestmatch = (bestmatch || ""); 1.632 + ////dump("matches: " + matches + "\n"); 1.633 + var objAndComplete = (objname || obj) + "." + bestmatch; 1.634 + //dump("matches.length: " + matches.length + ", tooManyMatches: " + tooManyMatches + ", objAndComplete: " + objAndComplete + "\n"); 1.635 + if(matches.length > 1 && (tooManyMatches == objAndComplete || matches.length <= 10)) { 1.636 + 1.637 + printWithRunin("Matches: ", matches.join(', '), "tabcomplete"); 1.638 + tooManyMatches = null; 1.639 + } 1.640 + else if(matches.length > 10) 1.641 + { 1.642 + println(matches.length + " matches. Press tab again to see them all", "tabcomplete"); 1.643 + tooManyMatches = objAndComplete; 1.644 + } 1.645 + else { 1.646 + tooManyMatches = null; 1.647 + } 1.648 + if(bestmatch != "") 1.649 + { 1.650 + var sstart; 1.651 + if(dotpos == caret) { 1.652 + sstart = spacepos+1; 1.653 + } 1.654 + else { 1.655 + sstart = dotpos+1; 1.656 + } 1.657 + _in.value = _in.value.substr(0, sstart) 1.658 + + bestmatch 1.659 + + _in.value.substr(caret); 1.660 + setselectionto(_in,caret + (bestmatch.length - complete.length)); 1.661 + } 1.662 + } 1.663 +} 1.664 + 1.665 +function printQuestion(q) 1.666 +{ 1.667 + println(q, "input"); 1.668 +} 1.669 + 1.670 +function printAnswer(a) 1.671 +{ 1.672 + if (a !== undefined) { 1.673 + println(a, "normalOutput"); 1.674 + shellCommands.ans = a; 1.675 + } 1.676 +} 1.677 + 1.678 +function printError(er) 1.679 +{ 1.680 + var lineNumberString; 1.681 + 1.682 + lastError = er; // for debugging the shell 1.683 + if (er.name) 1.684 + { 1.685 + // lineNumberString should not be "", to avoid a very wacky bug in IE 6. 1.686 + lineNumberString = (er.lineNumber != undefined) ? (" on line " + er.lineNumber + ": ") : ": "; 1.687 + println(er.name + lineNumberString + er.message, "error"); // Because IE doesn't have error.toString. 1.688 + } 1.689 + else 1.690 + println(er, "error"); // Because security errors in Moz /only/ have toString. 1.691 +} 1.692 + 1.693 +/** 1.694 + * Evaluates |s| or current input (_in.value) in the previously set up context. 1.695 + * @param {String} s - (optional) command to evaluate. 1.696 + */ 1.697 +function go(s) 1.698 +{ 1.699 + // save the command to eval in |question|, so that the target window can access 1.700 + // it when evaluating. 1.701 + _in.value = question = s ? s : _in.value; 1.702 + 1.703 + if (question == "") 1.704 + return; 1.705 + 1.706 + histList[histList.length-1] = question; 1.707 + histList[histList.length] = ""; 1.708 + histPos = histList.length - 1; 1.709 + 1.710 + // Unfortunately, this has to happen *before* the JavaScript is run, so that 1.711 + // print() output will go in the right place. 1.712 + _in.value=''; 1.713 + recalculateInputHeight(); 1.714 + printQuestion(question); 1.715 + 1.716 + if (_win.closed) { 1.717 + printError("Target window has been closed."); 1.718 + return; 1.719 + } 1.720 + 1.721 + try { ("Shell" in _win) } 1.722 + catch(er) { 1.723 + printError("The JavaScript Shell cannot access variables in the target window. The most likely reason is that the target window now has a different page loaded and that page has a different hostname than the original page."); 1.724 + return; 1.725 + } 1.726 + 1.727 + if (!("Shell" in _win)) 1.728 + initTarget(); // silent 1.729 + 1.730 + // Evaluate Shell.question using _win's eval (this is why eval isn't in the |with|, IIRC). 1.731 + run(_win, "try{ Shell.printAnswer(eval('with(Shell._scope) with(Shell.shellCommands) {' + Shell.question + String.fromCharCode(10) + '}')); } catch(er) { Shell.printError(er); }; setTimeout(Shell.refocus, 0);"); 1.732 +} 1.733 + 1.734 +</script> 1.735 + 1.736 +<!-- for http://ted.mielczarek.org/code/mozilla/extensiondev/ --> 1.737 +<script type="text/javascript" src="chrome://extensiondev/content/chromeShellExtras.js"></script> 1.738 + 1.739 +<style type="text/css"> 1.740 + body { background: white; color: black; } 1.741 + 1.742 + #output { 1.743 + /* Preserve line breaks, but wrap too if browser supports it */ 1.744 + white-space: pre; 1.745 + white-space: -moz-pre-wrap; 1.746 + white-space: pre-wrap; 1.747 + } 1.748 + 1.749 + h3 { margin-top: 0; margin-bottom: 0em; } 1.750 + h3 + div { margin: 0; } 1.751 + 1.752 + form { margin: 0; padding: 0; } 1.753 + #input { width: 100%; border: none; padding: 0; overflow: auto; } 1.754 + 1.755 + .input { color: blue; background: white; font: inherit; font-weight: bold; margin-top: .5em; /* background: #E6E6FF; */ } 1.756 + .normalOutput { color: black; background: white; } 1.757 + .print { color: brown; background: white; } 1.758 + .error { color: red; background: white; } 1.759 + .propList { color: green; background: white; } 1.760 + .message { color: green; background: white; } 1.761 + .tabcomplete { color: purple; background: white; } 1.762 +</style> 1.763 +</head> 1.764 + 1.765 +<body onload="init()"> 1.766 + 1.767 +<div id="output"><h3>JavaScript Shell 1.4</h3><div>Features: autocompletion of property names with Tab, multiline input with Shift+Enter, input history with (Ctrl+) Up/Down, <a accesskey="M" href="javascript:go('scope(Math); mathHelp();');" title="Accesskey: M">Math</a>, <a accesskey="H" href="http://www.squarefree.com/shell/?ignoreReferrerFrom=shell1.4" title="Accesskey: H">help</a></div><div>Values and functions: ans, print(string), <a accesskey="P" href="javascript:go('props(ans)')" title="Accesskey: P">props(object)</a>, <a accesskey="B" href="javascript:go('blink(ans)')" title="Accesskey: B">blink(node)</a>, <a accesskey="C" href="javascript:go('clear()')" title="Accesskey: C">clear()</a>, load(scriptURL), scope(object)</div></div> 1.768 + 1.769 +<div><textarea id="input" class="input" wrap="off" spellcheck="false" onkeydown="inputKeydown(event)" rows="1"></textarea></div> 1.770 + 1.771 +</body> 1.772 + 1.773 +</html>