debugger.lzx

<!--
 * debugger.lzx
 **************************************************************************-->
<library>


<!--
 N.B. this (singleton) class actually implements only the Debug Console interface.  The debugger proper is part of the LFC.
-->

<include href="base/basebutton.lzx"/>
<include href="utils/layouts"/>
<include href="utils/states/resizestate.lzx"/>
<include href="utils/states/dragstate.lzx"/>
<include href="utils/command.lzx"/>
<include href="newcontent.lzx"/>

<include href="lz/tooltip/tooltip.lzx"/>

<!-- for prefs window -->
<include href="lz/checkbox.lzx"/>
<include href="lz/window.lzx"/>
<include href="lz/slider.lzx"/>


 <!-- IMAGE RESOURCES -->

 <!-- Buttons --> 

 <resource name="closeBtn_rsc">
   <frame src="images/buttons/autoPng/closebtn0001.png"/>
   <frame src="images/buttons/autoPng/closebtn0002.png"/>
   <frame src="images/buttons/autoPng/closebtn0003.png"/>
 </resource>
 <resource name="evalBtn_rsc">
   <frame src="images/buttons/autoPng/evalbtn0001.png"/>
   <frame src="images/buttons/autoPng/evalbtn0002.png"/>
   <frame src="images/buttons/autoPng/evalbtn0003.png"/>
 </resource>
 <resource name="minBtn_rsc">
   <frame src="images/buttons/autoPng/minbtn0001.png"/>
   <frame src="images/buttons/autoPng/minbtn0002.png"/>
   <frame src="images/buttons/autoPng/minbtn0003.png"/>
 </resource>
 <resource name="expBtn_rsc">
   <frame src="images/buttons/autoPng/expbtn0001.png"/>
   <frame src="images/buttons/autoPng/expbtn0002.png"/>
   <frame src="images/buttons/autoPng/expbtn0003.png"/>
 </resource>

 <resource name="prefsBtn_rsc">
        <frame src="images/buttons/autoPng/prefsbtn0001.png"/>
        <frame src="images/buttons/autoPng/prefsbtn0002.png"/>
        <frame src="images/buttons/autoPng/prefsbtn0003.png"/>
 </resource>

 <resource name="tfdownBtn_rsc">
   <frame src="images/buttons/autoPng/tfdownbtn0001.png"/>
   <frame src="images/buttons/autoPng/tfdownbtn0002.png"/>
   <frame src="images/buttons/autoPng/tfdownbtn0003.png"/>
 </resource>
 <resource name="tfupBtn_rsc">
   <frame src="images/buttons/autoPng/tfupbtn0001.png"/>
   <frame src="images/buttons/autoPng/tfupbtn0002.png"/>
   <frame src="images/buttons/autoPng/tfupbtn0003.png"/>
 </resource>
 <resource name="clear1_rsc">
   <frame src="images/buttons/autoPng/clear10001.png"/>
   <frame src="images/buttons/autoPng/clear10002.png"/>
   <frame src="images/buttons/autoPng/clear10003.png"/>
 </resource>
 <resource name="bug_rsc">
   <frame src="images/buttons/autoPng/bug0001.png"/>
   <frame src="images/buttons/autoPng/bug0002.png"/>
   <frame src="images/buttons/autoPng/bug0003.png"/>
 </resource>

 <resource src="images/shadowbottom.swf" name="shadowBottom_rsc"/>
 <resource src="images/shadowcorner.swf" name="shadowCorner_rsc"/>
 <resource src="images/shadowleft.swf" name="shadowLeft_rsc"/>
 <resource src="images/shadowright.swf" name="shadowRight_rsc"/>
 <resource src="images/shadowtop.swf" name="shadowTop_rsc"/>

 <resource src="images/bottomleftbtm.swf" name="bottomLeftBtm_rsc"/>
 <resource src="images/bottomleftmid.swf" name="bottomLeftMid_rsc"/>
 <resource src="images/bottomlefttop.swf" name="bottomLeftTop_rsc"/>
 <resource src="images/bottomrghtbtm.swf" name="bottomRghtBtm_rsc"/>
 <resource src="images/bottomrghtmid.swf" name="bottomRghtMid_rsc"/>
 <resource src="images/bottomrghttop.swf" name="bottomRghtTop_rsc"/>
 <resource src="images/bottom.swf" name="bottom_rsc"/>


 <resource name="grabber_rsc">
   <frame src="images/grabber.swf"/>
   <frame src="images/grabberover.swf"/>
 </resource>

 <resource src="images/handleover.swf" name="handleOver_rsc"/>
 <resource src="images/handle.swf" name="handle_rsc"/>
 <resource src="images/leftright.swf" name="leftRight_rsc"/>

 <resource name="resizer_rsc">
   <frame src="images/resizer.swf"/>
   <frame src="images/resizerover.swf"/>
 </resource>

 <resource src="images/title.swf" name="title_rsc"/>
 <resource src="images/topleft.swf" name="topLeft_rsc"/>
 <resource src="images/topright.swf" name="topRight_rsc"/>
 <resource src="images/top.swf" name="top_rsc"/>



<!--- 
    Drop shadow for the bottom of the debugger window

    @keywords private
-->
<class name="debugger_shadow_bottom"> 
     <resizelayout axis="x"/> 
     <view resource="shadowLeft_rsc"/> 
     <view resource="shadowBottom_rsc" stretches="width" options="releasetolayout"/> 
</class> 


<!--- 
    Drop shadow for the right side of the debugger window 

    @keywords private
-->
<class name="debugger_shadow_right"> 
    <stableborderlayout axis="y"/> 
    <view resource="shadowTop_rsc"/> 
    <view resource="shadowRight_rsc" stretches="height"/> 
    <view resource="shadowCorner_rsc"/> 
</class> 

    <!-- Special context menu item for debugger commands -->
    <class name="debugmenuitem" extends="contextmenuitem">
      <attribute name="argument" value="null"/>
      <event name="onargument"/>
      <setter name="argument" args="argument">
        if ((this.arguments == 0 && argument == null) || this.validArgument(argument)) {
          this.argument = argument;
          this.setAttribute('isapplicable', this.applicable());
          if (this.isapplicable) {
            this.updateCaption();
          }
          if (this.onargument.ready) { this.onargument.sendEvent(argument); }
        }
      </setter>
      <!-- The tricky part here is that menu items keep their last valid argument -->
      <method name="validArgument" args="argument">
        return (argument != null);
      </method>
      <attribute name="isapplicable" type="boolean" value="false"/>
      <method name="applicable">
        return this.arguments == 0 || this.argument != null;
      </method>
      // Visible only if debug window is visible and applicable
      <attribute name="visible" value="${this.parent.parent.visible && this.isapplicable}"/>
      <attribute name="description" type="string" value="${null}"/>
      <attribute name="command" type="string" value="${this.name}"/>
      <attribute name="arguments" type="number" value="1"/>
      <attribute name="argumentFormat" type="string" value="w"/>
      <method name="descriptionString">
        if (this.arguments == 0) {
          return Debug.formatToString("%s", this.description);
        } else {
          return Debug.formatToString(
            "%s '%0.48" + this.argumentFormat + "'",
            this.description, this.argument);
        }
      </method>
      <method name="commandEchoString">
        if (this.arguments == 0) {
          return Debug.formatToString("Debug.%s()", this.command);
        } else {
          return Debug.formatToString("Debug.%s(%0.64w)", this.command, this.argument);
        }
      </method>
      <method name="updateCaption">
        this.setAttribute('caption', (this.description ? this.descriptionString() : this.commandEchoString()));
      </method>
      <handler name="oninit">
        this.updateCaption();
      </handler>
      <event name="onnode"/>
      <handler name="onselect" method="execute"/>
      <method name="execute" args="ignore">
        Debug.freshPrompt();
        Debug.echo(this.commandEchoString());
        if (this.arguments == 0) {
          var result = Debug[this.command]();
        } else if (this.arguments == 1) {
          var result = Debug[this.command](this.argument);
        } else {
          var result = Debug[this.command].apply(Debug, this.argument);
        }
        if (result) {
          Debug.displayResult(result);
          if (result is LzNode) {
            if (this.onnode.ready) { this.onnode.sendEvent(result); }
          }
        }
      </method>
    </class>

<!--- 
    The Laszlo debugger window. An instance will be automatically
    instantiated when the application is compiled in debug mode
    (requested by either using the
    <code>canvas</code> <code>debug</code> attribute or by loading the
    application using the <code>?debug=true</code> option).  

    @keywords private_constructor
-->
<class name="LzDebugWindow" font="monospace" fontsize="11" fontstyle="plain" oninit="initEvalView()" pixellock="true">

    <method name="init">
        super.init();
        // Hide from screen readers
        if ($as2) {
            var mc = this.getDisplayObject();
            mc._accImpl = {stub: true};
        }
    </method>
    <!-- Will be applied in construct if no width specified -->
    <attribute name="default_width" value="false"/>
    <state applied="${parent.default_width}">
      <attribute name="width" value="${canvas.width * .9}"/>
    </state>
    <!-- Will be applied in construct if no height specified -->
    <attribute name="default_height" value="false"/>
    <state applied="${parent.default_height}">
      <attribute name="height" value="${canvas.height *.5}"/>
    </state>
    <!-- Will be applied in construct if no x specified -->
    <attribute name="keep_width_on_canvas" value="false"/>
    <state applied="${parent.keep_width_on_canvas}">
      <attribute name="x" value="${canvas.width * .95 - this.width}"/>
    </state>
    <!-- Will be applied in construct if no y specified -->
    <attribute name="keep_height_on_canvas" value="false"/>
    <state applied="${parent.keep_height_on_canvas}">
      <attribute name="y" value="${canvas.height * .95 - this.height}"/>
    </state>
    <!-- Remove the above if resize happens -->
    <handler name="onapply" reference="resize">
      this.setAttribute('default_width', false);
      this.setAttribute('default_height', false);
      this.setAttribute('keep_width_on_canvas', false);
      this.setAttribute('keep_height_on_canvas', false);
    </handler>
    <!-- Remove the above if drag happens -->
    <handler name="onapply" reference="drag">
      this.setAttribute('default_width', false);
      this.setAttribute('default_height', false);
      this.setAttribute('keep_width_on_canvas', false);
      this.setAttribute('keep_height_on_canvas', false);
    </handler>

    <!-- ATTRIBUTES -->
    <attribute name="title" value="" type="string"/>
    <attribute name="closeable" value="true"/> 
    <attribute name="resizable" value="true"/>

    <attribute name="smallInputAreaHeight" value="29"/>
    <attribute name="savedInputAreaHeight" value="53"/>
    <attribute name="debuggerBorderWidth" value="5"/>

    <attribute name="savedXPos" value="10"/>
    <attribute name="savedYPos" value="10"/>
    <attribute name="savedWidth" value="340"/>
    <attribute name="savedHeight" value="125"/>

    <attribute name="consoleRemote" value="false"/> 
    <attribute name="clientBridge"/>

    <attribute name="minimized" value="false"/>
    <attribute name="autoscroll" value="true"/>

    <attribute name="initstage" value="immediate"/>

    <attribute name="persist" value="false"/>
    <attribute name="commandhistory" value="[]"/>
    <attribute name="commandhistory_ptr" value="0"/>

    <attribute name="focustrap" value="true"/>
    <attribute name="lineheight" value="13"/>
    <attribute name="options" value="ignorelayout"/>

    <attribute name="isLoaded" value="false"/>

    <attribute name="evalloader" value="null"/>

    <!-- METHODS -->
    <method name="construct" args="parent, args">
      super.construct(parent, args);
      this.setAttribute('default_width', ! (this.hassetwidth));
      this.setAttribute('default_height', ! (this.hassetheight));
      // We have to cheat here: there is no public way to tell if the
      // user has constrained x or y
      this.setAttribute('keep_width_on_canvas', ! ('x' in args || this.__LZhasConstraint('x')));
      this.setAttribute('keep_height_on_canvas', ! ('y' in args || this.__LZhasConstraint('y')));
      this.commandhistory_ptr = this.commandhistory.length;
    </method>

    <setter name="width" args="w"> 
        super.setAttribute('width', Math.max( 170 , Math.min( w , canvas.width) ) ); 
    </setter> 

    <setter name="height" args="h"> 
        super.setAttribute ('height', Math.max( 112 , Math.min( h , canvas.height) ) ); 
        if (this.isLoaded) {
           this.middle.content.updateDisplay();
       }
    </setter> 

    <setter name="x" args="x"> 
        super.setAttribute ('x', Math.max( 0-(this.width-10), Math.min( x , canvas.width - 4) ) ); 
    </setter> 

    <setter name="y" args="y"> 
        super.setAttribute ('y', Math.max( 0 , Math.min( y , canvas.height - 4) ) ); 
    </setter> 

    <contextmenu name="menu"/>
    <node name="debuggeritems">
      <debugmenuitem name="showHide" caption="Show/Hide Debugger" visible="true">
        <method name="execute" args="ignore">
          this.classroot.setAttribute('visible', (! this.classroot.visible));
        </method>
      </debugmenuitem>
      <debugmenuitem name="versionInfo" separatorbefore="true" description="Show Version Information" arguments="0"/>
      <!-- We make the error commands always visible, so people know they are there -->
      <!-- We only enable them when they are applicable -->
      <debugmenuitem name="inspectError" command="inspect" description="Show Details of" visible="${this.classroot.visible}" enabled="${this.argument is LzSourceMessage}" argument="'Last Error'" argumentFormat="s">
      </debugmenuitem>
      <debugmenuitem name="bugReport" command="bugReport" description="Show Bug Report for" visible="${this.classroot.visible}" enabled="${this.argument is LzSourceMessage}" argument="'Last Error'" argumentFormat="s"/>
      <debugmenuitem name="inspectTarget" separatorbefore="true" command="inspect" description="Show Details of">
        <handler name="onnode" args="node">
          this.classroot.lastNode = node;
        </handler>
      </debugmenuitem>
      <debugmenuitem name="inspectNode" command="inspect" description="Show Details of">
        <method name="applicable">
          return this.argument != this.parent.inspectTarget.argument;
        </method>
      </debugmenuitem>
      <debugmenuitem name="showSubviews" description="Show Subviews of">
        <method name="validArgument" args="arg">
          return (arg is LzNode && arg.subviews.length > 0);
        </method>
      </debugmenuitem>
      <debugmenuitem name="showParent" description="Show Parent of">
        <method name="validArgument" args="arg">
          return (arg is LzNode && arg.parent && arg.parent !== arg);
        </method>
        <handler name="onnode" args="node">
          this.classroot.lastNode = node;
        </handler>
      </debugmenuitem>
      <debugmenuitem name="explainStyles" command="explainStyleBindings" description="Show Style Bindings of">
        <method name="validArgument" args="arg">
          return (arg is LzNode) && (arg.__LZCSSStyledAttrs != null);
        </method>
      </debugmenuitem>
      <debugmenuitem name="inspect_" command="inspect" description="Show Details of"/>
      <debugmenuitem name="inspect__" command="inspect" description="Show Details of"/>
      <debugmenuitem name="inspect___" command="inspect" description="Show Details of"/>
    </node>
    <node name="controlitems">
      <!-- Useful things for the debug window -->
      <contextmenuitem name="Preferences" caption="Debugger Peferences" separatorbefore="true" visible="${this.classroot.visible}">
        <handler name="onselect">
          this.classroot.showprefs();
        </handler>
      </contextmenuitem>
      <contextmenuitem name="Clear" caption="Clear Debugger Window" visible="${this.classroot.visible}">
        <handler name="onselect">
          this.classroot.clear();
        </handler>
      </contextmenuitem>
    </node>

    <attribute name="contextTarget" value="null"/>
    <attribute name="lastNode" value="null"/>
    <method name="nodeTarget">
      return this.lastNode || ((this.contextTarget is LzNode) ? (this.lastNode = this.contextTarget) : null);
    </method>

    <method name="updateMenu" args="menu, target">
      var visible = this.visible;

      menu.showHide.setAttribute('caption', Debug.formatToString("%s Debugger", visible ? "Hide" : "Show"));

      menu.inspectError.setAttribute('argument', Debug.lastError);
      menu.bugReport.setAttribute('argument', Debug.lastError);

      var _ = Debug.environment._;
      this.contextTarget = target || ((_ is LzNode) ? _ : canvas);
      var nodeTarget = this.nodeTarget();

      menu.inspectTarget.setAttribute('argument', target);

      menu.inspectNode.setAttribute('argument', nodeTarget);
      if (menu.explainStyles.validArgument(target)) {
          menu.explainStyles.setAttribute('argument', target);
      } else {
          menu.explainStyles.setAttribute('argument', nodeTarget);
      }
      if (menu.showSubviews.validArgument(target)) {
          menu.showSubviews.setAttribute('argument', target);
      } else {
          menu.showSubviews.setAttribute('argument', nodeTarget);
      }
      if (menu.showParent.validArgument(target)) {
          menu.showParent.setAttribute('argument', target);
      } else {
          menu.showParent.setAttribute('argument', nodeTarget);
      }

      menu.inspect_.setAttribute('argument', Debug.environment._);
      menu.inspect__.setAttribute('argument', Debug.environment.__);
      menu.inspect__.setAttribute('argument', Debug.environment.__);
    </method>

    <!-- The debugger context menu items that should be added to any context menu -->
    <method name="contextMenuItems" args="menu, target">
      this.updateMenu(this.debuggeritems, target);
      var dbgmenu = (this.menu === menu);
      // add control items at end if displaying debugger context menu
      var items = this.debuggeritems.subnodes.concat(dbgmenu ? this.controlitems.subnodes : []);
      // add separator if displaying user (= non-debugger) context menu
      items[0].setAttribute("separatorbefore", ! dbgmenu);
      return items;
    </method>

<method name="initEvalView">
      
       if ($dhtml) {
       } else {
           this.evalloader = new LzDebugEvalLoader(this);
           // To support clickable links in swf9, we need to add an as3 event listener
           // on the output LzText's flash textfield object.
           if ($as3) {
               this.evalloader.addTextLinkCallback(this.middle.content.textpane);
           }
       }

       this.middle.content.textpane.setAttribute('contextmenu', this.menu);
       this.loaded();
       var text = this.bottom.center.input;
       this.lineheight = text.getTextHeight();
       this.setAttribute("smallInputAreaHeight", this.lineheight + 16);
       this.inspectDel = new lz.Delegate(this, "inspectObject");
       this.inspectDel.register(lz.GlobalMouse, "onmousedown");
       this.moveCaretDel = new lz.Delegate(this, 'sendCaretToEOL');
       this.restoreDebuggerState();
     
    </method>

<method name="handleFocus">
      
      this.bringToFront();
      if (this.bottom.center.input.height > this.smallInputAreaHeight) {
        this._cmd_eval.active = false;
        this._cmd_hist_prev.active = false;
        this._cmd_hist_next.active = false;
        this._cmd_complete_tab.active = false;
//         this._cmd_complete_dot.active = false;
//         this._cmd_complete_bracket.active = false;
//         this._cmd_complete_paren.active = false;
      } else {
        this._cmd_eval.active = true;
        this._cmd_hist_prev.active = true;
        this._cmd_hist_next.active = true;
        this._cmd_complete_tab.active = true;
//         this._cmd_complete_dot.active = true;
//         this._cmd_complete_bracket.active = true;
//         this._cmd_complete_paren.active = true;
      }
      
    </method>

<method name="handleBlur">
       
       this._cmd_eval.active = false;
       this._cmd_hist_prev.active = false;
       this._cmd_hist_next.active = false;
       this._cmd_complete_tab.active = false;
//        this._cmd_complete_dot.active = false;
//        this._cmd_complete_bracket.active = false;
//        this._cmd_complete_paren.active = false;
       
    </method>


    <!-- *** Commands *** -->
    <command name="_cmd_eval" onselect="parent.doEval()" key="['Enter']" active="false"/>
    <command name="_cmd_hist_prev" onselect="parent.doCommandHistory(-1)" key="['uparrow']" active="false"/>
    <command name="_cmd_hist_next" onselect="parent.doCommandHistory(1)" key="['downarrow']" active="false"/>
    <command name="_cmd_complete_tab" onselect="parent.doCommandCompletion('\t')" key="['tab']" active="false"/>
    
    
    
    >

    <!-- send the input text field to server for compile/eval -->
    <method name="doEval">
      
       var expr = this.bottom.center.input.text;
       this.commandhistory[this.commandhistory.length] = expr;
       this.commandhistory_ptr = this.commandhistory.length;
       if (this.persistedData) {
            this.persistedData.data.commandhistory = this.commandhistory;
       }
       this.clientBridge.doEval(expr);
       // Clear the input text field
       if (!this.bottom.center.input.multiline) {
           this.bottom.center.input.clearText();
       }
       
    </method>

    <method name="remoteEval" args="expr, count">
      // Will try to compile as 'Debug.displayResult(expr);' and if
      // that fails, will try to compile as a series of statements
      // (with no display).  Finally, will compile
      // 'Debug.__write(<error message>)' if both of those fail.
      this.evalloader.doEval(expr, count);
    </method>

    <!--- Clear the output from the debug window -->
<method name="clearWindow">
      this.middle.content.clear();
    </method>

<method name="stuffInput" args="str">
        var infield = this.bottom.center.input;
        lz.Focus.setFocus(infield);
        infield.setAttribute('text', str);
        lz.Timer.addTimer(this.moveCaretDel, 1);
    </method>

<method name="sendCaretToEOL" args="ignore=null">
        var infield = this.bottom.center.input;
        lz.Focus.setFocus(infield);
        var content = infield.text;
        infield.setSelection(content.length, content.length);
    </method>

<method name="doCommandHistory" args="offset">
        
        var ptr = this.commandhistory_ptr;
        var expr;
        // Save any partial input
        if ((offset < 0) &&
            (ptr == this.commandhistory.length) &&
            (expr = this.bottom.center.input.text)) {
          this.commandhistory[this.commandhistory.length] = expr;
          this.commandhistory_ptr = this.commandhistory.length;
          if (this.persistedData) { this.persistedData.data.commandhistory = this.commandhistory; }
        }
        ptr += offset;
        ptr = Math.max(0, Math.min(this.commandhistory.length-1, ptr));
        this.stuffInput(this.commandhistory[ptr]);
        this.commandhistory_ptr = ptr;
        
    </method>

    <attribute name="lastpart" value="null"/>
    <attribute name="lastobj" value="null"/>
<method name="doCommandCompletion" args="char">
      
        var leader = '';
        var expr = this.bottom.center.input.text;
        // Find the last completable expression
        // TODO: [2006-11-23 ptw] If not in a partial member
        // expression, find next enclosing call expression (to print arg
        // list)
        // TODO: [2006-11-23 ptw] Skip over balanced quotes and parens.
        for (var i = expr.length - 1; i >= 0; i--) {
          // last puncutation other than '.'
          if(" \n\r(){}[];,=><!~?:|&+-*/^%".indexOf(expr.charAt(i)) >= 0) {
            leader = expr.substring(0, i + 1);
            expr = expr.substring(i + 1);
//             Debug.debug('leader', leader, 'expr', expr);
            break;
          }
        }
        var objs = expr.split('.');
        var part = null;
        if (objs[0]['constructor']) {
          var obj = globalValue(objs[0]) || global;
        } else {
          var obj = global;
        }
        // descend to the partial member
        for (var i = (obj == global ? 0 : 1); i < objs.length; i++) {
          part = objs[i];
          if (this.lastobj == obj &&
              this.lastpart == part) {
            // 2nd time through
            break;
          } else if (part in obj) {
            // use eval for more generality?
            obj = obj[objs[i]];
            part = null;
          } else {
            // no match
            break;
          }
        }
        // Some built-ins are not instanceof Object
        if (obj instanceof Object || typeof(obj) == 'object') {
          ;
        } else if (obj['constructor'] instanceof Function) {
          // primitives have methods of constructor prototype
          obj = obj.constructor.prototype;
        } else {
          // don't know how to find possibilities
          Debug.info('No possible completions of %#w', part);
          return;
        }
//         Debug.debug('lastobj', this.lastobj, 'lastpart', this.lastpart, 'obj', obj);
        if (this.lastobj == obj) {
          // 2nd time and no partial
          if (i == objs.length) {
            expr = objs.join('.');
            // Infer next separator
            if (char == '\t') {
              if (obj instanceof Function) {
                expr += '(';
              } else if (obj instanceof Array) {
                expr += '[';
              } else if (obj instanceof Object) {
                expr += '.';
              }
            } else {
              expr += char;
            }
//             Debug.debug('no part');
            this.stuffInput(leader + expr);
            return;
          }
        } else {
          // looking at new partial
          this.lastobj = obj;
          this.lastpart = null;
        }
        // Compute longest match and accumulate choices
        var longest = null;
        var choices = null;
//           if ($as2) {
//             var enumerableSlots = [];
//             for (var e in obj) { enumerableSlots.push(e); }
//             // reveal all slots
//             ASSetPropFlags(obj, null, 0, 1);
//           }
        for (var poss in obj) {
          if (poss.indexOf(part) == 0) {
            var p = obj[poss];
            // possibility must be compatible with completion char
            var compat = true;
            switch (char) {
              case '\t':
                break;
              case '.':
                if (! (p instanceof Object)) compat = false;
                break;
              case '[':
                if (! (p instanceof Array)) compat = false;
                break;
              case '(':
                if (! (p instanceof Function)) compat = false;
                break;
            }
            if (! compat) continue;
            // accumulate choices
            if (choices == null) {
              choices = [ poss ];
            } else {
              choices.push(poss);
            }
            // compute longest match
            if (longest == null) {
              longest = poss;
            } else {
              for (var j = 0;
                   ((j < poss.length) &&
                    (j < longest.length) &&
                    (poss.charAt(j) == longest.charAt(j)));
                   j++);
              longest = longest.substring(0, j);
            }
          }
        }
//           if ($as2) {
//             // Reset the enumerability
//             // Make everything unenumerable, and then expose your saved list
//             ASSetPropFlags(x, null, 1, 1);
//             ASSetPropFlags(x, enumerableSlots, 0, 1);
//           }
        if (longest != null) {
//             Debug.debug('longest',longest,'choices',choices);
          if (choices.length > 1) {
            // 2nd time or not too many, print choices
            if ((choices.length < 8) || (longest == this.lastpart)) {
              choices.sort(function (a, b) {
                var al = a.toLowerCase();
                var bl = b.toLowerCase();
                return ((al > bl)?1:0) - ((al < bl)?1:0);
              });
              Debug.info('Possible completions: %s', choices.join(' '));
            } else {
              this.lastpart = longest;
              Debug.info('%d possibilities: press %#w again to see them all', choices.length, char);
            }
          } else {
            this.lastobj = obj[longest];
            this.lastpart = null;
          }
          objs[i] = longest;
          expr = objs.join('.');
          this.stuffInput(leader + expr);
        }
     
    </method>

<method name="stuffObjectId" args="id">
        this.bottom.center.input.setAttribute('text', this.ObjectForID(id));
    </method>

<method name="inspectObject" args="obj">
    if (lz.Keys.isKeyDown('capslock')) {
      // force and ID, so the object can be inspected
      var id = Debug.IDForObject(obj, true);
      Debug.displayResult(obj);
    }
   </method>

<method name="setTitle" args="t">
        this.top.title.setAttribute('text', t )
    </method>


    <!--- Toggle the debug window from minimized to maximized size -->
<method name="toggleMinimizeWindow">
        var _dbgw = this.width;
        var _dbgh = this.height;
        var _dbgx = this.x;
        var _dbgy = this.y;
        this.animate("x", this.savedXPos, 333, false);
        this.animate("y", this.savedYPos, 333, false);
        this.animate("width", this.savedWidth, 333, false);
        this.animate("height", this.savedHeight, 333, false);
        this.savedXPos = _dbgx;
        this.savedYPos = _dbgy;
        this.savedWidth = _dbgw;
        this.savedHeight = _dbgh;
        this.minimized = !this.minimized;
        // If debug window height is being minimized, set to single line input area
        if (this.minimized) {
            this.bottom.left.doSingleLine();
        }
        this.adjustMultiline();
        this.top.controls.min.setAttribute('visible', !this.minimized);
        this.top.controls.exp.setAttribute('visible', this.minimized);
    </method>

    <dragstate name="drag"/>
    <resizestate name="resize">
    </resizestate>

    <handler name="onremove" reference="drag" method="saveDebuggerState"/>
    <handler name="onremove" reference="resize" method="saveDebuggerState"/>
            
<method name="saveDebuggerState" args="d">
    if (this.persistedData) {
        this.persistedData.data['_pdbgwidth'] = this.width;
        this.persistedData.data['_pdbgheight'] = this.height;
        this.persistedData.data['_pdbgx'] = this.x;
        this.persistedData.data['_pdbgy'] = this.y;
    }
    </method>

<method name="restoreDebuggerState">
  
     if ($dhtml) {
     } else {
       // restore persistedDataed data
       this.persistedData = LzBrowserKernel.getPersistedObject('__lzdebugger');
       if (this.persistedData && this.persistedData.data['commandhistory']) {
           this.commandhistory = this.persistedData.data.commandhistory;
           if (this.commandhistory) {
               this.commandhistory_ptr = this.commandhistory.length;
           }
       }
       if (this.persist && this.persistedData) {
           for (var i in this.persistedData.data) {
               if (this[i] != null) {
                   this[i] = this.persistedData.data[i];
                   //Debug.write('restored', i, this[i]);
               }
           }

           if (this.persistedData.data['_pdbgwidth'] != null) {
               this.setAttribute('width', this.persistedData.data._pdbgwidth);
           }
           if (this.persistedData.data['_pdbgheight'] != null) {
               this.setAttribute('height', this.persistedData.data._pdbgheight);
           }
           if (this.persistedData.data['_pdbgx'] != null) {
               this.setAttribute('x', this.persistedData.data._pdbgx);
           }
           if (this.persistedData.data['_pdbgy'] != null) {
               this.setAttribute('y', this.persistedData.data._pdbgy);
           }
       }
     }
       
    </method>

    <!-- Start Views -->
    <resizelayout axis="y"/>

    <!-- START TOP (dragger area + title + minimize + controls) -->
    <view name="top" width="${parent.width}" height="24" pixellock="true" clip="true" oninit="this.controls.bringToFront()"> 
        <view name="background" width="${parent.width}" clip="true" onmouseover="grabber.setAttribute('frame', 2)" onmouseout="grabber.setAttribute('frame', 1)" onmousedown="classroot.bringToFront(); parent.parent.drag.setAttribute('applied', true)" onmouseup="parent.parent.drag.setAttribute('applied', false)" oninit="this.right.bringToFront()">
            <stableborderlayout axis="x"/>
            <view name="left" resource="topLeft_rsc"/>
            <view name="center" stretches="width" resource="top_rsc"/>
            <view name="right" resource="topRight_rsc"/>
            <view name="grabber" resource="grabber_rsc" pixellock="true" options="ignorelayout" x="${(parent.parent.logo.width + parent.parent.logo.x) + (((parent.width - parent.parent.logo.width) - this.width) / 2)}" y="11"/>
       </view>

       <view name="controls" width="${parent.width}" y="7">
         <basebutton name="close" pixellock="true" x="${parent.width - this.width - 7}" resource="closeBtn_rsc" onclick="classroot.setAttribute('visible', false)">
            <tooltip>Close debug window</tooltip>
          </basebutton>
          <basebutton name="min" pixellock="true" x="${parent.close.x - this.width}" resource="minBtn_rsc" onclick="classroot.toggleMinimizeWindow()">
             <tooltip>Minimize debug window</tooltip>
           </basebutton>
           <basebutton name="exp" visible="false" pixellock="true" x="${parent.close.x - this.width}" resource="expBtn_rsc" onclick="classroot.toggleMinimizeWindow()">
              <tooltip>Expand debug window</tooltip>
            </basebutton>
           <!--  clear debug history -->
           <basebutton name="clear" pixellock="true" x="${parent.min.x - this.width}" onclick="classroot.clear()" resource="clear1_rsc">
              <tooltip>Clear debug window</tooltip>
            </basebutton>
       </view>

       <view name="logo" resource="title_rsc" x="9" y="8"/>
 
<method name="appname">
         
         var url = lz.Browser.getBaseURL();
         var i = url.lastIndexOf("/");
         url = url.substring(i+1);
         return url;
         
       </method>

       <text name="title" width="${parent.width-140}" x="140" y="6"/>

    </view>

    <!-- START MIDDLE (output area + scroll bar) -->

    <view name="middle" options="releasetolayout" width="${parent.width}" pixellock="true">
        <stableborderlayout axis="x"/>
        <view name="left" resource="leftRight_rsc" stretches="height" height="${parent.height}"/>
        <_dbg_lztextscroller name="content" bgcolor="#FFFFFF" options="releasetolayout" height="${parent.height}"/>
        <view name="right" resource="leftRight_rsc" stretches="height" height="${parent.height}"/>
   </view> 
   <!-- END MIDDLE -->

   <!-- preferences dialog -->
   <modaldialog name="debugprefs" title="Debugger Options" width="350" initstage="late">
        <simplelayout spacing="10"/>
        <checkbox align="left" onvalue="classroot.setWrapLines(this.value)">Wrap lines</checkbox>
        <checkbox align="left" onvalue="Debug.showInternalProperties = this.value">Show Internal Properties</checkbox>

        <view>
          <text>printLength</text>
          <slider x="100" value="Debug.printLength" onvalue="Debug.printLength = this.value" minvalue="64" maxvalue="65536" showvalue="true"/>
        </view>

        <view>
          <text>printDepth</text>
          <slider x="100" value="Debug.printDepth" onvalue="Debug.printDepth = this.value" minvalue="1" maxvalue="256" showvalue="true"/>
        </view>

        <view>
          <text>Opacity</text>
          <slider x="100" onvalue="Debug.window.setAttribute('opacity', this.value/100)" value="100" minvalue="10" maxvalue="100" showvalue="true"/>
        </view>

        <view align="right" layout="axis:x; spacing:10">
            <button onclick="parent.parent.close()" isdefault="true">OK</button>
        </view>
    </modaldialog>

    <method name="showprefs">
      this.debugprefs.open();
    </method>

<method name="adjustMultiline">
     
         // when the user drags the splitter to enlarge the input area height,
         // we check if the height is more than a single line, and if so
         // set the view multiline=true

      if (this.bottom.center.input.height > this.smallInputAreaHeight) {
        this.bottom.center.input.setAttribute("multiline", true);
      } else {
        this.bottom.center.input.setAttribute("multiline", false);
      }
      this.middle.content.computeVisibleRegion();
      
   </method>


    <!-- START BOTTOM -->
    <view name="bottom" width="${parent.width}" height="${parent.smallInputAreaHeight}" onmousedown="parent.bringToFront()" pixellock="true">

       <setter name="height" args="h"> 
        // keep a minimum of two lines of text displayed
          var minheight = (classroot.lineheight + 16);
          super.setAttribute('height', Math.max( parent.smallInputAreaHeight , Math.min( h , parent.height - (parent.top.height + minheight)) ) ); 
          if (parent.isLoaded) {
             parent.middle.content.updateDisplay();
         }
       </setter> 

       <state name="splitter">
          <attribute name="height" value="${this.classroot.height - this.classroot.getMouse('y') }"/>
       </state>

       <stableborderlayout axis="x"/>
        <!-- START BOTTOM-LEFT -->
         <view name="left" height="${parent.height}">

<method name="doSingleLine">
             this.upButton.setAttribute('visible', true); 
             this.downButton.setAttribute('visible', false)
             this.parent.center.input.setAttribute("multiline", false);
             classroot.savedInputAreaHeight = Math.max(53, this.parent.height);
             this.parent.animate("height",classroot.smallInputAreaHeight,333,false);
           </method>

<method name="doMultiLine">
             this.downButton.setAttribute('visible', true); 
             this.upButton.setAttribute('visible', false)
             // Check if we have room to grow the input area
             var delta = classroot.savedInputAreaHeight - parent.height;
             delta = Math.min(classroot.middle.height - (classroot.lineheight * 2) , delta);
             if (delta > 0) {
                 this.parent.center.input.setAttribute("multiline", true);
                 // Squish the center content area up
                 this.parent.animate("height",classroot.savedInputAreaHeight,333,false);
             }
           </method>

           <stableborderlayout axis="y"/>
           <view name="leftTop" resource="bottomLeftTop_rsc"/>
           <view name="leftMiddle" stretches="height" resource="bottomLeftMid_rsc"/>
           <view name="leftBottom" resource="bottomLeftBtm_rsc"/>

           <basebutton name="upButton" x="5" y="6" visible="true" pixellock="true" onclick="this.parent.doMultiLine()" resource="tfupBtn_rsc"/>
           <basebutton name="downButton" x="5" y="6" visible="false" pixellock="true" onclick="parent.doSingleLine()" resource="tfdownBtn_rsc"/>
          </view>
        <!-- END BOTTOM-LEFT -->


         <!-- START BOTTOM-CENTER  -->
         <view name="center" bgcolor="#FFFFFF" height="${parent.height}">
              <stableborderlayout axis="y"/>

              <view name="top" stretches="width" width="${parent.width}" options="releasetolayout" resource="bottom_rsc" y="0"/>

               <inputtext name="input" height="18" resize="false" width="${parent.width}" multiline="false" options="releasetolayout"/>

               <handler name="onfocus" reference="this.input">
                   classroot.handleFocus();
               </handler>

               <handler name="onblur" reference="this.input">
                   classroot.handleBlur();
               </handler>

              <view name="bottom" stretches="width" width="${parent.width}" options="releasetolayout" resource="bottom_rsc"/>

             
              <view name="handle" x="${(parent.width / 2)}" resource="handleOver_rsc" onmousedown="parent.parent.splitter.setAttribute('applied', true)" onmouseup="parent.parent.splitter.setAttribute('applied', false); classroot.adjustMultiline()"/>

        </view>
        <!-- END BOTTOM-CENTER -->


         <!-- START BOTTOM-RIGHT -->
        <view name="bottomright" height="${parent.height}">
             <stableborderlayout axis="y"/>
             <view name="rightTop" resource="bottomRghtTop_rsc"/>
             <view name="rightMiddle" stretches="height" resource="bottomRghtMid_rsc"/>
             <view name="rightBottom" resource="bottomRghtBtm_rsc"/>

             <basebutton name="evalbutton" resource="evalBtn_rsc" pixellock="true" onclick="parent.parent.parent.doEval()" x="${parent.width - 42}" y="${(parent.height / 2) - 8}"/>

             <view resource="resizer_rsc" name="resizer" pixellock="true" y="${parent.height - 11}" x="${parent.width - 11}" onmouseover="this.setAttribute('frame', 2);" onmouseout="this.setAttribute('frame', 1);" onmousedown="this.setAttribute('frame', 2); classroot.bringToFront(); classroot.resize.setAttribute('applied', true)" onmouseup="this.setAttribute('frame', 1); classroot.resize.setAttribute('applied', false)"/>

         </view> <!-- END BOTTOM-RIGHT -->
    </view> <!-- END BOTTOM -->

     <debugger_shadow_bottom width="${parent.width}" opacity="0.75" pixellock="true" options="ignorelayout" y="${parent.height}"/>
     <debugger_shadow_right height="${parent.height+4}" x="${parent.width}" pixellock="true" opacity="0.75" options="ignorelayout"/>



<method name="clear">
      //------------------------------------------------------------------------------
      // Clears the console
      //------------------------------------------------------------------------------
      // Data to display.
      this.clearWindow();
    </method>

  <!--- Scroll the debugger output window to display the specified  output history line number at the top of the window
         @param Number l: line number
    -->
<method name="setLine" args="l">
        this.middle.content.setLine(l);
    </method>

<method name="addText" args="msg">
     
       var str;
       try {
         if (msg && (msg['toHTML'] is Function)) {
             str = msg.toHTML();
         } else {
             str = String(msg)['toHTML']();
         }
       } catch (e){
           trace('error in addText, e=', e, msg);
           str  = e + ': ' + msg;
       }
       this.addHTMLText(str);
     
  </method>

<method name="echo" args="str, newLine:Boolean=true">
     
      this.addHTMLText('<font color="#00CC00">' + str + '</font>' + (newLine?'\n':''));
     
  </method>

  <!---
    Only called internally, when you know you already have valid HTML
    @keywords private
    -->

<method name="addHTMLText" args="str">
     
       // Funky thing that Henry discovered you have to do to make newlines
       // why wouldn't <br/> work?
       this.middle.content.addText(str.split('\n').join('&#32;\n'));
     
  </method>

<method name="makeObjectLink" args="rep:String, id, attrs=null">
     
      var color = '#0000ff';
      if (attrs && attrs.color) { color = attrs.color };
      if (id != null) {
          if ($as3 || (lz.Browser.getInitArg('lzconsoledebug') == 'true')) {
              // If we're running in swf10, or talking to the remote dev console, we need to format hyperlinks
              // using the as3 textlink event API
              return '<a href="event:objid=' + id + '"><font color="' + color + '">' + rep +"</font></a>";
          } else {
              return '<a href="asfunction:_root.$modules.lz.Debug.displayObj,' + id + '"><font color="' + color + '">' + rep +"</font></a>";
          }
      }
      return rep;
     
  </method>


<!-- Ensures the debugger window is visible, in front, and last output displayed. -->
<method name="ensureVisible">
    if (! this.visible) {
        this.setAttribute('visible', true );
    }
    this.bringToFront();
</method>

<method name="loaded">
     
        //------------------------------------------------------------------------------
        // This is called when the application is loaded.
        //------------------------------------------------------------------------------
        this.isLoaded = true;

        var bridge:LzDebugConsole = new LzDebuggerWindowConsoleBridge(this);
        this.clientBridge = Debug.attachDebugConsole(bridge);

        this.bringToFront();

        Debug.window = this;
      
  </method>

  <handler name="oninit" reference="canvas">
    this.bringToFront();
  </handler>

<method name="setWrapLines" args="val">
    this.middle.content.setWrapLines(val);
  </method>

</class>

</library>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2001-2006, 2008, 2009-2011 Laszlo Systems, Inc.  All Rights Reserved.              *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
<!-- @LZX_VERSION@                                                         -->

Cross References

Includes

Resources

Name Source Image
closeBtn_rsc images/buttons/autoPng/closebtn0001.png
images/buttons/autoPng/closebtn0002.png
images/buttons/autoPng/closebtn0003.png
evalBtn_rsc images/buttons/autoPng/evalbtn0001.png
images/buttons/autoPng/evalbtn0002.png
images/buttons/autoPng/evalbtn0003.png
minBtn_rsc images/buttons/autoPng/minbtn0001.png
images/buttons/autoPng/minbtn0002.png
images/buttons/autoPng/minbtn0003.png
expBtn_rsc images/buttons/autoPng/expbtn0001.png
images/buttons/autoPng/expbtn0002.png
images/buttons/autoPng/expbtn0003.png
prefsBtn_rsc images/buttons/autoPng/prefsbtn0001.png
images/buttons/autoPng/prefsbtn0002.png
images/buttons/autoPng/prefsbtn0003.png
tfdownBtn_rsc images/buttons/autoPng/tfdownbtn0001.png
images/buttons/autoPng/tfdownbtn0002.png
images/buttons/autoPng/tfdownbtn0003.png
tfupBtn_rsc images/buttons/autoPng/tfupbtn0001.png
images/buttons/autoPng/tfupbtn0002.png
images/buttons/autoPng/tfupbtn0003.png
clear1_rsc images/buttons/autoPng/clear10001.png
images/buttons/autoPng/clear10002.png
images/buttons/autoPng/clear10003.png
bug_rsc images/buttons/autoPng/bug0001.png
images/buttons/autoPng/bug0002.png
images/buttons/autoPng/bug0003.png
shadowBottom_rsc images/shadowbottom.swf
shadowCorner_rsc images/shadowcorner.swf
shadowLeft_rsc images/shadowleft.swf
shadowRight_rsc images/shadowright.swf
shadowTop_rsc images/shadowtop.swf
bottomLeftBtm_rsc images/bottomleftbtm.swf
bottomLeftMid_rsc images/bottomleftmid.swf
bottomLeftTop_rsc images/bottomlefttop.swf
bottomRghtBtm_rsc images/bottomrghtbtm.swf
bottomRghtMid_rsc images/bottomrghtmid.swf
bottomRghtTop_rsc images/bottomrghttop.swf
bottom_rsc images/bottom.swf
grabber_rsc images/grabber.swf
images/grabberover.swf
handleOver_rsc images/handleover.swf
handle_rsc images/handle.swf
leftRight_rsc images/leftright.swf
resizer_rsc images/resizer.swf
images/resizerover.swf
title_rsc images/title.swf
topLeft_rsc images/topleft.swf
topRight_rsc images/topright.swf
top_rsc images/top.swf

Classes