Author: ptw
Date: 2007-10-15 20:33:27 -0700 (Mon, 15 Oct 2007)
New Revision: 6857

Modified:
   openlaszlo/trunk/WEB-INF/lps/lfc/debugger/LzDebug.lzs
   openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/dhtml/LzDebug.js
   openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/swf/LzDebug.as
Log:
Change 20070930-ptw-P by [EMAIL PROTECTED] on 2007-09-30 18:01:29 EDT
    in /Users/ptw/OpenLaszlo/ringding-2
    for http://svn.openlaszlo.org/openlaszlo/trunk

Summary: Don't trust length as an indicator of array elements

Bugs Fixed:
LPP-4441 'Debugger misbehaves when debugging objects with "length" attribute.'

Technical Reviewer: [EMAIL PROTECTED] (Message-ID: <[EMAIL PROTECTED]>)
QA Reviewer: hminsky (pending)
Doc Reviewer: jsundman (pending)

Documentation:
NOTE:  If you have Firebug enabled in Firefox, the LZX debugger echos
all messages to the Firebug console, preserving objects.  The Firebug
debugger will attempt to interpret an object with a `length` field as
an array and try to print every array element.  This may cause a
'Script Running Slowly' error.  Disabling Firebug will prevent that.

Details:
    Don't trust length to indicate how many properties are in an
    object (or elements in an array).  Instead, get the properties
    from the object using `for ... in`.  We still present any object
    with a `length` property that is non-negative as an array, but we
    won't try to iterate through the entire array.  This is useful for
    sparse arrays, but also for objects that just happen to have a
    non-negative length property.

    LzDebug.lzs:  Added Debug.objectOwnProperties that gets the names
    of all the 'own' properties of the object.  If the object has a
    non-negative `length` property, accumulate the properties that are
    between 0 and that length in a separate list of indices.

    LzDebug.{as,js}:  Use that to print and inspect objects and arrays
    without falling into the trap of iterating from 0 to length.
    Basically, the old presentation style is preserved, but we iterate
    _only_ over the properties the object actually has.

Tests:
    lzx> Debug.write({1: 'one', 97: 'ninety-seven', a: 'eh?', floogle: 'snort', 
length: 100000000, __proto__: {bar: 'bletch'}})
    ?\194?\171Object(100000000)#127| [..., one, ..., ninety-seven]?\194?\187
    lzx> Debug.inspect([..., one, ..., ninety-seven])
    ?\194?\171Object(100000000)#127| [..., one, ..., ninety-seven]?\194?\187 {
      a: 'eh?'
      floogle: 'snort'
      length: 100000000
      1: 'one'
      97: 'ninety-seven'
    }
    [..., one, ..., ninety-seven]
    lzx> Debug.write({length:'0'})
    {length: 0}
    lzx> Debug.write({length:0})
    ?\194?\171Object(0)#174| []?\194?\187
    lzx>

    Above completes without "Script Running Slowly".  Tested in SWF
    and DHTML (with Firebug disabled, see Documentation NOTE above).

    smokecheck passes in DHTML and SWF (which tests Debug.format,
    which uses __String, showing that the expected presentation is preserved).



Modified: openlaszlo/trunk/WEB-INF/lps/lfc/debugger/LzDebug.lzs
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/debugger/LzDebug.lzs       2007-10-16 
02:46:17 UTC (rev 6856)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/debugger/LzDebug.lzs       2007-10-16 
03:33:27 UTC (rev 6857)
@@ -464,20 +464,23 @@
 };
 
 /**
- * Fills two arrays with the object's own properties.  If the object has a
- * 'length' property (i.e., might be intended as an Array), numeric
- * names that fall between 0 and the value of length are added to the
- * `indices` array, otherwise they are added to the `names` array.  If
- * either array is null, those properties will be omitted altogether.
- * @param obj:Object the object to examine
- * @param names:Array the array to append names to
- * @param indices:Array the array to append indices to
- * @param limit:Number don't accumulate more than this many properties
- * (used to limit computation on large objects), default Infinity
+ * Fills two arrays with the object's own properties.  If the object
+ * has a non-negative integer 'length' property (i.e., might be
+ * intended as an Array), numeric names that fall between 0 and the
+ * value of length are added to the `indices` array, otherwise they
+ * are added to the `names` array.  If either array is null, those
+ * properties will be omitted altogether.  @param obj:Object the
+ * object to examine @param names:Array the array to append names to
+ * @param indices:Array the array to append indices to @param
+ * limit:Number don't accumulate more than this many properties (used
+ * to limit computation on large objects), default Infinity
  */
 Debug.objectOwnProperties = function (obj, names, indices, limit) {
   if (!limit) { limit = Infinity; };
-  var alen = (('length' in obj) && (! isNaN(obj.length)) && (obj.length >= 0)) 
? obj.length : false;
+  // Check for 'array-ness'
+  var alen = (('length' in obj) &&
+              (Math.floor(obj.length) === obj.length) &&
+              (obj.length >= 0)) ? obj.length : false;
   var hopp = 'hasOwnProperty' in obj;
   var proto = (('__proto__' in obj) ? obj.__proto__ :
                (('constructor' in obj) ? obj.constructor.prototype : false));
@@ -487,7 +490,10 @@
         // Heuristic to find getter slots (there is no way to ask if a
         // property is a getter)
         (proto && (obj[key] !== proto[key]))) {
-      if ((alen != false) && (! isNaN(key)) && (0 <= key) && (key < alen)) {
+      if ((alen != false) &&
+          // Only `==` here because all keys are strings
+          (Math.floor(key) == key) &&
+          (0 <= key) && (key < alen)) {
         if (indices) {
           // Ensure indices are numbers, not strings
           indices.push(Number(key));

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/dhtml/LzDebug.js
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/dhtml/LzDebug.js 
2007-10-16 02:46:17 UTC (rev 6856)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/dhtml/LzDebug.js 
2007-10-16 03:33:27 UTC (rev 6857)
@@ -282,40 +282,13 @@
       else if (thing instanceof String) {
         // handled above, but don't fall into array
       }
-      // Print arrays (actually, anything with a numeric length
-      // property) in abbreviated format (what about arrays that have
-      // non-numeric props?)
-      else if ((typeof(thing.length) == 'number')) {
-        // No pretty for subclasses or non-arrays
-        if (thing.constructor !== Array) {
-          pretty = (! unique);
-        }
-        var ellip = true;
-        var tl = thing.length
-        // Don't accumulate beyond limit
-        for (var e = 0; (e < tl) && (s.length < limit); e++) {
-          // skip non-existent elements
-          if ((typeof(thing[e]) == 'undefined')) {
-            if (ellip) {
-              s += '..., ';
-              ellip = false;
-            }
-          } else {
-            ellip = true;
-            // TODO: [2005-06-22 ptw] Use __String in case element is huge
-            s += String(thing[e]) + ', ';
-          }
-        }
-        if (s != '')
-          s = s.substring(0, s.length - 2);
-        s = '[' + s + ']';
-      }
       // If it has a user-defined toString method, use that, but defend
       // against broken methods
       // TODO [2006-04-11 ptw] try/catch around user method calls
-      else if ((thing['toString']) &&
-               (this.toString instanceof Function) &&
+      else if (('toString' in thing) &&
+               (thing.toString instanceof Function) &&
                (thing.toString !== Object.prototype.toString) &&
+               (thing.toString !== Array.prototype.toString) &&
                (typeof(thing.toString()) != 'undefined') &&
                (thing.toString() != 'undefined')) {
         // No pretty for these, you don't know if the user toString is
@@ -323,42 +296,68 @@
         pretty = (! unique);
         s = String(thing);
       }
-      // Print unidentified objects as abbreviated list of props
+      // Print unidentified objects and arrays as abbreviated list of props
       else {
-        // No pretty for subclasses or non-objects
-        if ((! thing instanceof Object) || (thing.constructor !== Object)) {
+        var names = [];
+        // Treat any object with a non-negative integer length as an array
+        var indices = (('length' in thing) &&
+                       (Math.floor(thing.length) === thing.length) &&
+                       (thing.length >= 0)) ? [] : null;
+
+        this.objectOwnProperties(thing, names, indices, limit);
+        if (indices) { indices.sort(); }
+
+        // No pretty for subclasses or non-objects or array-like objects
+        // that are not Arrays.
+        if (! (indices ?
+               ((thing instanceof Array) && (thing.constructor === Array)) :
+               ((thing instanceof Object) && (thing.constructor === Object)))) 
{
           pretty = (! unique);
         }
-        var ellip = true;
-        for (var e in thing) {
-          var v = thing[e];
-          var tv = typeof(v);
-          var dtv = this.__typeof(v);
-          // Don't enumerate inherited props, unless you can't tell
-          // (i.e., __proto__ chain is broken
-          // Ignore "empty" properties and methods, ignore internal
-          // slots and slots that have an internal type
-          if (((! (thing instanceof Object)) || thing.hasOwnProperty(e)) &&
-              (tv != 'undefined') &&
-              (tv != 'function') &&
-              (('' + v) != '') &&
-              (! this.internalProperty(e)) &&
-              (! this.internalProperty(dtv))) {
-            ellip = true;
-            // TODO: [2005-06-22 ptw] Use __String in case element is huge
-            s += '' + e + ': ' + String(v) + ', ';
-          } else {
-            if (ellip) {
+        if (indices) {
+          // Present as an array, Don't accumulate beyond limit
+          var next = 0;
+          for (var i = 0; (i < indices.length) && (s.length < limit); i ++) {
+            var key = indices[i];
+            if (key != next) {
               s += '..., ';
-              ellip = false;
             }
+            // TODO: [2005-06-22 ptw] Use __String in case element is huge
+            s += String(thing[key]) + ', ';
+            next = key + 1;
           }
-          // Don't accumulate beyond limit
-          if (s.length > limit) break;
+          if (s != '')
+            s = s.substring(0, s.length - 2);
+          s = '[' + s + ']';
+        } else {
+          var ellip = true;
+          // Present as an object, Don't accumulate beyond limit
+          for (var i = 0; (i < names.length) && (s.length < limit); i ++) {
+            var e = names[i];
+            var v = thing[e];
+            var tv = typeof(v);
+            var dtv = this.__typeof(v);
+            // Ignore "empty" properties and methods, ignore internal
+            // slots and slots that have an internal type
+            if ((tv != 'undefined') &&
+                (tv != 'function') &&
+                (('' + v) != '') &&
+                (! this.internalProperty(e)) &&
+                (! this.internalProperty(dtv))) {
+              ellip = true;
+              // TODO: [2005-06-22 ptw] Use __String in case element is huge
+              s += '' + e + ': ' + String(v) + ', ';
+            } else {
+              if (ellip) {
+                s += '..., ';
+                ellip = false;
+              }
+            }
+          }
+          if (s != '')
+            s = s.substring(0, s.length - 2);
+          s = '{' + s + '}';
         }
-        if (s != '')
-          s = s.substring(0, s.length - 2);
-        s = '{' + s + '}';
       }
     } else {
       // Shouldn't ever get here
@@ -445,8 +444,12 @@
     // Print properties with abbreviated length
     this.printLength = this.inspect.printLength;
 
-    var keys = [];
-    var arraylen = typeof(obj.length) == 'number' ? obj.length : null;
+    var names = [];
+    // Treat any object with a non-negative integer length as an array
+    var indices = (('length' in obj) &&
+                   (Math.floor(obj.length) === obj.length) &&
+                   (obj.length >= 0)) ? [] : null;
+
     if (si) {
       // print unenumerable properties of ECMA objects
       // TODO: [2006-04-11 ptw] enumerate Global/Number/Math/Regexp
@@ -454,78 +457,59 @@
       for (var p in {callee: true, length: true, constructor: true, prototype: 
true}) {
         try {
           if (hasProto && obj.hasOwnProperty(p)) {
-            keys.push(p);
+            names.push(p);
           }
         } catch (e) {};
       }
     }
-    for (var key in obj) {
-      // Print only local slots
-      try {
-        if ((! hasProto) ||
-            obj.hasOwnProperty(key) ||
-            // or getter slots (this is a heuristic -- there is no way to
-            // ask if a property is a getter)
-            (function () { try { return obj[key] } catch (e) {} })() !== 
-            (function () { try { return obj.constructor.prototype[key] } catch 
(e) {} })()
-            ) {
-          // Print array slots later, in order
-          if (arraylen && (key >= 0) && (key < arraylen)) {
-          } else if (si ||
-                     ((! this.internalProperty(key)) &&
-                      // Only show slots with internal type if showing
-                      // internals
-                      (! this.internalProperty(this.__typeof(obj[key]))))) {
-            keys.push(key);
-          }
-        }
-      } catch (e) {};
-    }
 
-    keys.sort(function (a, b) {
-        var al = a.toLowerCase();
-        var bl = b.toLowerCase();
-        return (al > bl) - (al < bl);
-      });
+    this.objectOwnProperties(obj, names, indices);
+
+    names.sort(function (a, b) {
+      var al = a.toLowerCase();
+      var bl = b.toLowerCase();
+      return (al > bl) - (al < bl);
+    });
+    if (indices) { indices.sort(); }
     var description = "";
-    var kl = keys.length;
+    var nnames = names.length;
     var val;
     var wid = 0;
-    // Align all keys if annotating 'weight'
+    // Align all names if annotating 'weight'
     if (this.markGeneration > 0) {
-      for (var i = 0; i < kl; i++) {
-        var kil = keys[i].length;
-        if (kil > wid) { wid = kil; }
+      for (var i = 0; i < nnames; i++) {
+        var keywidth = names[i].length;
+        if (keywidth > wid) { wid = keywidth; }
       }
     }
-    if (arraylen) {
-      var kil = ('' + arraylen).length;
-      if (kil > wid) { wid = kil; }
+    if (indices) {
+      var keywidth = ('' + obj.length).length;
+      if (keywidth > wid) { wid = keywidth; }
     }
     var last;
-    for (var i = 0; i < kl; i++) {
-      var key = keys[i];
+    for (var i = 0; i < nnames; i++) {
+      var key = names[i];
       // Some runtimes duplicate inherited slots
       if (key != last) {
         last = key;
         val = obj[key];
-        description += '  ' + this.computeSlotDescription(obj, key, val, wid) 
+ '\n';
+        if (si ||
+            ((! this.internalProperty(key)) &&
+             // Only show slots with internal type if showing
+             // internals
+             (! this.internalProperty(this.__typeof(val))))) {
+               description += '  ' + this.computeSlotDescription(obj, key, 
val, wid) + '\n';
+        }
       }
     }
 
-    if (arraylen &&
-        // Don't print the characters of a string
-        (! ((typeof obj == 'string') || (obj instanceof String)))) {
-      for (var key = 0; key < arraylen; key++) {
-        // Skip non-existent elements, but don't bother with ellipses,
-        // since we are displaying the key here
-        if ((! hasProto) ||
-            obj.hasOwnProperty(key)) {
-          val = obj[key];
-          if(typeof(val) != 'undefined') {
-            description += '  ' + this.computeSlotDescription(obj, key, val, 
wid) + '\n';
-          }
-        }
+    if (indices) {
+      for (var i = 0; i < indices.length; i++) {
+        var key = indices[i];
+        val = obj[key];
+        // Don't bother with ellipses, since we are displaying the key
+        // here
+        description += '  ' + this.computeSlotDescription(obj, key, val, wid) 
+ '\n';
       }
     }
   } finally {

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/swf/LzDebug.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/swf/LzDebug.as   
2007-10-16 02:46:17 UTC (rev 6856)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/swf/LzDebug.as   
2007-10-16 03:33:27 UTC (rev 6857)
@@ -225,12 +225,12 @@
     }
   }
   return null;
-}
+};
 
 /**
   * @access private
   */
-  Debug.__String = function (thing, pretty, limit, unique) {
+Debug.__String = function (thing, pretty, limit, unique) {
   switch (arguments.length) {
     case 1:
       pretty = this.printPretty;
@@ -343,38 +343,12 @@
     else if (thing instanceof String) {
       // handled above, but don't fall into array
     }
-    // Print arrays (actually, anything with a numeric length
-    // property) in abbreviated format (what about arrays that have
-    // non-numeric props?)
-    else if (typeof(thing.length) == 'number') {
-      // No pretty for subclasses or non-arrays
-      if (op !== Array.prototype) {
-        pretty = (! unique);
-      }
-      var ellip = true;
-      var tl = thing.length
-      // Don't accumulate beyond limit
-      for (var e = 0; (e < tl) && (s.length < limit); e++) {
-        // skip non-existent elements
-        if (typeof(thing[e]) == 'undefined') {
-          if (ellip) {
-            s += '..., ';
-            ellip = false;
-          }
-        } else {
-          ellip = true;
-          // TODO: [2005-06-22 ptw] Use __String in case element is huge
-          s += String(thing[e]) + ', ';
-        }
-      }
-      if (s != '')
-        s = s.substring(0, s.length - 2);
-      s = '[' + s + ']';
-    }
     // If it has a user-defined toString method, use that, but defend
     // against broken methods
-    else if ((thing['toString'] instanceof Function) &&
+    else if (('toString' in thing) &&
+             (thing.toString instanceof Function) &&
              (thing.toString !== Object.prototype.toString) &&
+             (thing.toString !== Array.prototype.toString) &&
              (typeof(thing.toString()) != 'undefined') &&
              (thing.toString() != 'undefined')) {
       // No pretty for these, you don't know if the user toString is
@@ -382,42 +356,68 @@
       pretty = (! unique);
       s = String(thing);
     }
-    // Print unidentified objects as abbreviated list of props
+    // Print unidentified objects and arrays as abbreviated list of props
     else {
-      // No pretty for subclasses or non-objects
-      if (op !== Object.prototype) {
+      var names = [];
+      // Treat any object with a non-negative integer length as an array
+      var indices = (('length' in thing) &&
+                     (Math.floor(thing.length) === thing.length) &&
+                     (thing.length >= 0)) ? [] : null;
+
+      this.objectOwnProperties(thing, names, indices, limit);
+      if (indices) { indices.sort(); }
+
+      // No pretty for subclasses or non-objects or array-like objects
+      // that are not Arrays.
+      if (! (indices ?
+               ((thing instanceof Array) && (thing.constructor === Array)) :
+               ((thing instanceof Object) && (thing.constructor === Object)))) 
{
         pretty = (! unique);
       }
-      var ellip = true;
-      for (var e in thing) {
-        var v = thing[e];
-        var tv = typeof(v);
-        var dtv = this.__typeof(v);
-        // Don't enumerate inherited props, unless you can't tell
-        // (i.e., __proto__ chain is broken
-        // Ignore "empty" properties and methods, ignore internal
-        // slots and slots that have an internal type
-        if (((! (thing instanceof Object)) || thing.hasOwnProperty(e)) &&
-            (tv != 'undefined') &&
-            (tv != 'function') &&
-            (('' + v) != '') &&
-            (! this.internalProperty(e)) &&
-            (! this.internalProperty(dtv))) {
-          ellip = true;
-          // TODO: [2005-06-22 ptw] Use __String in case element is huge
-          s += '' + e + ': ' + String(v) + ', ';
-        } else {
-          if (ellip) {
+      if (indices) {
+        // Present as an array, Don't accumulate beyond limit
+        var next = 0;
+        for (var i = 0; (i < indices.length) && (s.length < limit); i ++) {
+          var key = indices[i];
+          if (key != next) {
             s += '..., ';
-            ellip = false;
           }
+          // TODO: [2005-06-22 ptw] Use __String in case element is huge
+          s += String(thing[key]) + ', ';
+          next = key + 1;
         }
-        // Don't accumulate beyond limit
-        if (s.length > limit) break;
+        if (s != '')
+          s = s.substring(0, s.length - 2);
+        s = '[' + s + ']';
+      } else {
+        var ellip = true;
+        // Present as an object, Don't accumulate beyond limit
+        for (var i = 0; (i < names.length) && (s.length < limit); i ++) {
+          var e = names[i];
+          var v = thing[e];
+          var tv = typeof(v);
+          var dtv = this.__typeof(v);
+          // Ignore "empty" properties and methods, ignore internal
+          // slots and slots that have an internal type
+          if ((tv != 'undefined') &&
+              (tv != 'function') &&
+              (('' + v) != '') &&
+              (! this.internalProperty(e)) &&
+              (! this.internalProperty(dtv))) {
+            ellip = true;
+            // TODO: [2005-06-22 ptw] Use __String in case element is huge
+            s += '' + e + ': ' + String(v) + ', ';
+          } else {
+            if (ellip) {
+              s += '..., ';
+              ellip = false;
+            }
+          }
+        }
+        if (s != '')
+          s = s.substring(0, s.length - 2);
+        s = '{' + s + '}';
       }
-      if (s != '')
-        s = s.substring(0, s.length - 2);
-      s = '{' + s + '}';
     }
   } else {
     // Shouldn't ever get here
@@ -511,42 +511,25 @@
     ASSetPropFlags(obj, null, 0, 1);
   }
 
-  var keys = [];
-  var arraylen = typeof(obj.length) == 'number' ? obj.length : null;
+  var names = [];
+  // Treat any object with a non-negative integer length as an array
+  var indices = (('length' in obj) &&
+                 (Math.floor(obj.length) === obj.length) &&
+                 (obj.length >= 0)) ? [] : null;
+
   if (si) {
     // print 'invisible' properties of MovieClip's
     if (obj instanceof MovieClip) {
       for (var p in {_x: 0, _y: 0, _visible: true, _xscale: 100,
                      _yscale: 100, _opacity: 100, _rotation: 0,
                      _currentframe: 1}) {
-        keys.push(p);
+        names.push(p);
       }
     }
   }
-  for (var key in obj) {
-    // Print only local slots
-    if ((! hasProto) ||
-        obj.hasOwnProperty(key) ||
-        // attached movie clips don't show up as 'hasOwnProperty' (but
-        // hasOwnProperty is more accurate -- consider if an instance
-        // copies a prototype property)
-        (obj[key] !== obj.__proto__[key]) ||
-        // or getter slots (this is a heuristic -- there is no way to
-        // ask if a property is a getter)
-        (obj.__proto__.hasOwnProperty(key) &&
-         (typeof(obj.__proto__[key]) == 'undefined'))
-        ) {
-      // Print array slots later, in order
-      if (arraylen && (key >= 0) && (key < arraylen)) {
-      } else if (si ||
-                 ((! this.internalProperty(key)) &&
-                  // Only show slots with internal type if showing
-                  // internals
-                  (! this.internalProperty(this.__typeof(obj[key]))))) {
-        keys.push(key);
-      }
-    }
-  }
+
+  this.objectOwnProperties(obj, names, indices);
+
   if (si) {
     // Reset the enumerability
     // Make everything unenumerable, and then expose your saved list
@@ -554,42 +537,53 @@
     ASSetPropFlags(obj, enumerableSlots, 0, 1);
   }
 
-  keys.sort(function (a, b) {
+  names.sort(function (a, b) {
     var al = a.toLowerCase();
     var bl = b.toLowerCase();
     return (al > bl) - (al < bl);
   });
+  if (indices) { indices.sort(); }
   var description = "";
-  var kl = keys.length;
+  var nnames = names.length;
   var val;
   var wid = 0;
-  // Align all keys if annotating 'weight'
+  // Align all names if annotating 'weight'
   if (this.markGeneration > 0) {
-    for (var i = 0; i < kl; i++) {
-      var kil = keys[i].length;
-      if (kil > wid) { wid = kil; }
+    for (var i = 0; i < nnames; i++) {
+      var keywidth = names[i].length;
+      if (keywidth > wid) { wid = keywidth; }
     }
   }
-  if (arraylen) {
-    var kil = ('' + arraylen).length;
-    if (kil > wid) { wid = kil; }
+  if (indices) {
+    var keywidth = ('' + obj.length).length;
+    if (keywidth > wid) { wid = keywidth; }
   }
   // indent
   wid = (wid + 2)
-  for (var i = 0; i < kl; i++) {
-    var key = keys[i];
-    val = obj[key];
-    description += this.computeSlotDescription(obj, key, val, wid);
+  var last;
+  for (var i = 0; i < nnames; i++) {
+    var key = names[i];
+    // Some runtimes duplicate inherited slots
+    if (key != last) {
+      last = key;
+      val = obj[key];
+      if (si ||
+          ((! this.internalProperty(key)) &&
+           // Only show slots with internal type if showing
+           // internals
+           (! this.internalProperty(this.__typeof(val))))) {
+             description += this.computeSlotDescription(obj, key, val, wid);
+      }
+    }
   }
 
-  if (arraylen) {
-    for (var key = 0; key < arraylen; key++) {
+  if (indices) {
+    for (var i = 0; i < indices.length; i++) {
+      var key = indices[i];
       val = obj[key];
-      // Skip non-existent elements, but don't bother with ellipses,
-      // since we are displaying the key here
-      if (typeof(val) != 'undefined') {
-        description += this.computeSlotDescription(obj, key, val, wid);
-      }
+      // Don't bother with ellipses, since we are displaying the key
+      // here
+      description += this.computeSlotDescription(obj, key, val, wid);
     }
   }
 


_______________________________________________
Laszlo-checkins mailing list
[email protected]
http://www.openlaszlo.org/mailman/listinfo/laszlo-checkins

Reply via email to