browser/metro/base/content/jsshell/shell.html

changeset 0
6474c204b198
     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>

mercurial