2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2009 Joseph Pecoraro
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * @extends {WebInspector.PropertiesSection}
30 * @param {!WebInspector.RemoteObject} object
31 * @param {?string|!Element=} title
32 * @param {string=} subtitle
33 * @param {?string=} emptyPlaceholder
34 * @param {boolean=} ignoreHasOwnProperty
35 * @param {!Array.<!WebInspector.RemoteObjectProperty>=} extraProperties
36 * @param {function(new:TreeElement, !WebInspector.RemoteObjectProperty)=} treeElementConstructor
38 WebInspector.ObjectPropertiesSection = function(object, title, subtitle, emptyPlaceholder, ignoreHasOwnProperty, extraProperties, treeElementConstructor)
40 this.emptyPlaceholder = (emptyPlaceholder || WebInspector.UIString("No Properties"));
42 this.ignoreHasOwnProperty = ignoreHasOwnProperty;
43 this.extraProperties = extraProperties;
44 this.treeElementConstructor = treeElementConstructor || WebInspector.ObjectPropertyTreeElement;
46 this.skipProto = false;
48 WebInspector.PropertiesSection.call(this, title || "", subtitle);
51 WebInspector.ObjectPropertiesSection._arrayLoadThreshold = 100;
53 WebInspector.ObjectPropertiesSection.prototype = {
54 enableContextMenu: function()
56 this.element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), false);
59 _contextMenuEventFired: function(event)
61 var contextMenu = new WebInspector.ContextMenu(event);
62 contextMenu.appendApplicableItems(this.object);
66 onpopulate: function()
73 if (this.object.arrayLength() > WebInspector.ObjectPropertiesSection._arrayLoadThreshold) {
74 this.propertiesTreeOutline.removeChildren();
75 WebInspector.ArrayGroupingTreeElement._populateArray(this.propertiesTreeOutline, this.object, 0, this.object.arrayLength() - 1);
80 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties
81 * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties
82 * @this {WebInspector.ObjectPropertiesSection}
84 function callback(properties, internalProperties)
88 this.updateProperties(properties, internalProperties);
91 WebInspector.RemoteObject.loadFromObject(this.object, !!this.ignoreHasOwnProperty, callback.bind(this));
94 updateProperties: function(properties, internalProperties, rootTreeElementConstructor, rootPropertyComparer)
96 if (!rootTreeElementConstructor)
97 rootTreeElementConstructor = this.treeElementConstructor;
99 if (!rootPropertyComparer)
100 rootPropertyComparer = WebInspector.ObjectPropertiesSection.CompareProperties;
102 if (this.extraProperties) {
103 for (var i = 0; i < this.extraProperties.length; ++i)
104 properties.push(this.extraProperties[i]);
107 this.propertiesTreeOutline.removeChildren();
109 WebInspector.ObjectPropertyTreeElement.populateWithProperties(this.propertiesTreeOutline,
110 properties, internalProperties,
111 rootTreeElementConstructor, rootPropertyComparer,
112 this.skipProto, this.object);
114 this.propertiesForTest = properties;
116 if (!this.propertiesTreeOutline.children.length) {
117 var title = document.createElementWithClass("div", "info");
118 title.textContent = this.emptyPlaceholder;
119 var infoElement = new TreeElement(title, null, false);
120 this.propertiesTreeOutline.appendChild(infoElement);
124 __proto__: WebInspector.PropertiesSection.prototype
128 * @param {!WebInspector.RemoteObjectProperty} propertyA
129 * @param {!WebInspector.RemoteObjectProperty} propertyB
132 WebInspector.ObjectPropertiesSection.CompareProperties = function(propertyA, propertyB)
134 var a = propertyA.name;
135 var b = propertyB.name;
136 if (a === "__proto__")
138 if (b === "__proto__")
140 if (propertyA.symbol && !propertyB.symbol)
142 if (propertyB.symbol && !propertyA.symbol)
144 return String.naturalOrderComparator(a, b);
149 * @extends {TreeElement}
150 * @param {!WebInspector.RemoteObjectProperty} property
152 WebInspector.ObjectPropertyTreeElement = function(property)
154 this.property = property;
156 // Pass an empty title, the title gets made later in onattach.
157 TreeElement.call(this, "", null, false);
158 this.toggleOnClick = true;
159 this.selectable = false;
162 WebInspector.ObjectPropertyTreeElement.prototype = {
163 onpopulate: function()
165 var propertyValue = /** @type {!WebInspector.RemoteObject} */ (this.property.value);
166 console.assert(propertyValue);
167 WebInspector.ObjectPropertyTreeElement.populate(this, propertyValue);
174 ondblclick: function(event)
176 if (this.property.writable || this.property.setter)
177 this.startEditing(event);
191 this.nameElement = document.createElementWithClass("span", "name");
192 var name = this.property.name;
193 if (/^\s|\s$|^$|\n/.test(name))
194 this.nameElement.createTextChildren("\"", name.replace(/\n/g, "\u21B5"), "\"");
196 this.nameElement.textContent = name;
197 if (!this.property.enumerable)
198 this.nameElement.classList.add("dimmed");
199 if (this.property.isAccessorProperty())
200 this.nameElement.classList.add("properties-accessor-property-name");
201 if (this.property.symbol)
202 this.nameElement.addEventListener("contextmenu", this._contextMenuFired.bind(this, this.property.symbol), false);
204 var separatorElement = document.createElementWithClass("span", "separator");
205 separatorElement.textContent = ": ";
207 if (this.property.value) {
208 this.valueElement = document.createElementWithClass("span", "value");
209 var type = this.property.value.type;
210 var subtype = this.property.value.subtype;
211 var description = this.property.value.description;
215 if (this.property.wasThrown) {
216 prefix = "[Exception: ";
217 valueText = description;
219 } else if (type === "string" && typeof description === "string") {
220 // Render \n as a nice unicode cr symbol.
222 valueText = description.replace(/\n/g, "\u21B5");
224 this.valueElement._originalTextContent = "\"" + description + "\"";
225 } else if (type === "function" && typeof description === "string") {
226 // Render function description until the first \n.
227 valueText = /.*/.exec(description)[0].replace(/\s+$/g, "");
228 this.valueElement._originalTextContent = description;
229 } else if (type !== "object" || subtype !== "node") {
230 valueText = description;
232 this.valueElement.setTextContentTruncatedIfNeeded(valueText || "");
234 this.valueElement.insertBefore(document.createTextNode(prefix), this.valueElement.firstChild);
236 this.valueElement.createTextChild(suffix);
238 if (this.property.wasThrown)
239 this.valueElement.classList.add("error");
241 this.valueElement.classList.add("console-formatted-" + (subtype || type));
243 this.valueElement.addEventListener("contextmenu", this._contextMenuFired.bind(this, this.property.value), false);
244 if (type === "object" && subtype === "node" && description) {
245 WebInspector.DOMPresentationUtils.createSpansForNodeTitle(this.valueElement, description);
246 this.valueElement.addEventListener("mousemove", this._mouseMove.bind(this, this.property.value), false);
247 this.valueElement.addEventListener("mouseout", this._mouseOut.bind(this, this.property.value), false);
249 this.valueElement.title = description || "";
252 this.listItemElement.removeChildren();
254 this.hasChildren = this.property.value.hasChildren && !this.property.wasThrown;
256 if (this.property.getter) {
257 this.valueElement = WebInspector.ObjectPropertyTreeElement.createRemoteObjectAccessorPropertySpan(this.property.parentObject, [this.property.name], this._onInvokeGetterClick.bind(this));
259 this.valueElement = document.createElementWithClass("span", "console-formatted-undefined");
260 this.valueElement.textContent = WebInspector.UIString("<unreadable>");
261 this.valueElement.title = WebInspector.UIString("No property getter");
265 this.listItemElement.appendChildren(this.nameElement, separatorElement, this.valueElement);
268 _contextMenuFired: function(value, event)
270 var contextMenu = new WebInspector.ContextMenu(event);
271 this.populateContextMenu(contextMenu);
272 contextMenu.appendApplicableItems(value);
277 * @param {!WebInspector.ContextMenu} contextMenu
279 populateContextMenu: function(contextMenu)
283 _mouseMove: function(event)
285 this.property.value.highlightAsDOMNode();
288 _mouseOut: function(event)
290 this.property.value.hideDOMNodeHighlight();
293 updateSiblings: function()
295 if (this.parent.root)
296 this.treeOutline.section.update();
298 this.parent.shouldRefreshChildren = true;
304 renderPromptAsBlock: function()
310 * @return {{element: !Element, value: (string|undefined)}}
312 elementAndValueToEdit: function()
315 element: this.valueElement,
316 value: (typeof this.valueElement._originalTextContent === "string") ? this.valueElement._originalTextContent : undefined
321 * @param {!Event=} event
323 startEditing: function(event)
325 var elementAndValueToEdit = this.elementAndValueToEdit();
326 var elementToEdit = elementAndValueToEdit.element;
327 var valueToEdit = elementAndValueToEdit.value;
329 if (WebInspector.isBeingEdited(elementToEdit) || !this.treeOutline.section.editable || this._readOnly)
332 // Edit original source.
333 if (typeof valueToEdit !== "undefined")
334 elementToEdit.setTextContentTruncatedIfNeeded(valueToEdit, WebInspector.UIString("<string is too large to edit>"));
336 var context = { expanded: this.expanded, elementToEdit: elementToEdit, previousContent: elementToEdit.textContent };
338 // Lie about our children to prevent expanding on double click and to collapse subproperties.
339 this.hasChildren = false;
341 this.listItemElement.classList.add("editing-sub-part");
343 this._prompt = new WebInspector.ObjectPropertyPrompt(this.renderPromptAsBlock());
346 * @this {WebInspector.ObjectPropertyTreeElement}
348 function blurListener()
350 this.editingCommitted(null, elementToEdit.textContent, context.previousContent, context);
353 var proxyElement = this._prompt.attachAndStartEditing(elementToEdit, blurListener.bind(this));
354 window.getSelection().setBaseAndExtent(elementToEdit, 0, elementToEdit, 1);
355 proxyElement.addEventListener("keydown", this._promptKeyDown.bind(this, context), false);
361 isEditing: function()
363 return !!this._prompt;
366 editingEnded: function(context)
368 this._prompt.detach();
371 this.listItemElement.scrollLeft = 0;
372 this.listItemElement.classList.remove("editing-sub-part");
373 if (context.expanded)
377 editingCancelled: function(element, context)
379 this.editingEnded(context);
383 editingCommitted: function(element, userInput, previousContent, context)
385 if (userInput === previousContent) {
386 this.editingCancelled(element, context); // nothing changed, so cancel
390 this.editingEnded(context);
391 this.applyExpression(userInput);
394 _promptKeyDown: function(context, event)
396 if (isEnterKey(event)) {
398 this.editingCommitted(null, context.elementToEdit.textContent, context.previousContent, context);
401 if (event.keyIdentifier === "U+001B") { // Esc
403 this.editingCancelled(null, context);
409 * @param {string} expression
411 applyExpression: function(expression)
413 var property = WebInspector.RemoteObject.toCallArgument(this.property.symbol || this.property.name);
414 expression = expression.trim();
416 this.property.parentObject.setPropertyValue(property, expression, callback.bind(this));
418 this.property.parentObject.deleteProperty(property, callback.bind(this));
421 * @param {?Protocol.Error} error
422 * @this {WebInspector.ObjectPropertyTreeElement}
424 function callback(error)
432 // The property was deleted, so remove this tree element.
433 this.parent.removeChild(this);
435 // Call updateSiblings since their value might be based on the value that just changed.
436 this.updateSiblings();
442 * @return {string|undefined}
444 propertyPath: function()
446 if ("_cachedPropertyPath" in this)
447 return this._cachedPropertyPath;
453 if (current.property) {
455 result = current.property.name + "." + result;
457 result = current.property.name;
459 current = current.parent;
460 } while (current && !current.root);
462 this._cachedPropertyPath = result;
467 * @param {?WebInspector.RemoteObject} result
468 * @param {boolean=} wasThrown
470 _onInvokeGetterClick: function(result, wasThrown)
474 this.property.value = result;
475 this.property.wasThrown = wasThrown;
478 this.shouldRefreshChildren = true;
481 __proto__: TreeElement.prototype
485 * @param {!TreeElement} treeElement
486 * @param {!WebInspector.RemoteObject} value
488 WebInspector.ObjectPropertyTreeElement.populate = function(treeElement, value) {
489 if (treeElement.children.length && !treeElement.shouldRefreshChildren)
492 if (value.arrayLength() > WebInspector.ObjectPropertiesSection._arrayLoadThreshold) {
493 treeElement.removeChildren();
494 WebInspector.ArrayGroupingTreeElement._populateArray(treeElement, value, 0, value.arrayLength() - 1);
499 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties
500 * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties
502 function callback(properties, internalProperties)
504 treeElement.removeChildren();
507 if (!internalProperties)
508 internalProperties = [];
510 WebInspector.ObjectPropertyTreeElement.populateWithProperties(treeElement, properties, internalProperties,
511 treeElement.treeOutline.section.treeElementConstructor, WebInspector.ObjectPropertiesSection.CompareProperties,
512 treeElement.treeOutline.section.skipProto, value);
515 WebInspector.RemoteObject.loadFromObjectPerProto(value, callback);
519 * @param {!TreeElement|!TreeOutline} treeElement
520 * @param {!Array.<!WebInspector.RemoteObjectProperty>} properties
521 * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties
522 * @param {function(new:TreeElement, !WebInspector.RemoteObjectProperty)} treeElementConstructor
523 * @param {function (!WebInspector.RemoteObjectProperty, !WebInspector.RemoteObjectProperty): number} comparator
524 * @param {boolean} skipProto
525 * @param {?WebInspector.RemoteObject} value
527 WebInspector.ObjectPropertyTreeElement.populateWithProperties = function(treeElement, properties, internalProperties, treeElementConstructor, comparator, skipProto, value) {
528 properties.sort(comparator);
530 for (var i = 0; i < properties.length; ++i) {
531 var property = properties[i];
532 if (skipProto && property.name === "__proto__")
534 if (property.isAccessorProperty()) {
535 if (property.name !== "__proto__" && property.getter) {
536 property.parentObject = value;
537 treeElement.appendChild(new treeElementConstructor(property));
539 if (property.isOwn) {
540 if (property.getter) {
541 var getterProperty = new WebInspector.RemoteObjectProperty("get " + property.name, property.getter);
542 getterProperty.parentObject = value;
543 treeElement.appendChild(new treeElementConstructor(getterProperty));
545 if (property.setter) {
546 var setterProperty = new WebInspector.RemoteObjectProperty("set " + property.name, property.setter);
547 setterProperty.parentObject = value;
548 treeElement.appendChild(new treeElementConstructor(setterProperty));
552 property.parentObject = value;
553 treeElement.appendChild(new treeElementConstructor(property));
556 if (value && value.type === "function") {
557 // Whether function has TargetFunction internal property.
558 // This is a simple way to tell that the function is actually a bound function (we are not told).
559 // Bound function never has inner scope and doesn't need corresponding UI node.
560 var hasTargetFunction = false;
562 if (internalProperties) {
563 for (var i = 0; i < internalProperties.length; i++) {
564 if (internalProperties[i].name == "[[TargetFunction]]") {
565 hasTargetFunction = true;
570 if (!hasTargetFunction)
571 treeElement.appendChild(new WebInspector.FunctionScopeMainTreeElement(value));
573 if (internalProperties) {
574 for (var i = 0; i < internalProperties.length; i++) {
575 internalProperties[i].parentObject = value;
576 treeElement.appendChild(new treeElementConstructor(internalProperties[i]));
582 * @param {!WebInspector.RemoteObject} object
583 * @param {!Array.<string>} propertyPath
584 * @param {function(?WebInspector.RemoteObject, boolean=)} callback
587 WebInspector.ObjectPropertyTreeElement.createRemoteObjectAccessorPropertySpan = function(object, propertyPath, callback)
589 var rootElement = document.createElement("span");
590 var element = rootElement.createChild("span", "properties-calculate-value-button");
591 element.textContent = WebInspector.UIString("(...)");
592 element.title = WebInspector.UIString("Invoke property getter");
593 element.addEventListener("click", onInvokeGetterClick, false);
595 function onInvokeGetterClick(event)
598 object.getProperty(propertyPath, callback);
606 * @extends {TreeElement}
607 * @param {!WebInspector.RemoteObject} remoteObject
609 WebInspector.FunctionScopeMainTreeElement = function(remoteObject)
611 TreeElement.call(this, "<function scope>", null, false);
612 this.toggleOnClick = true;
613 this.selectable = false;
614 this._remoteObject = remoteObject;
615 this.hasChildren = true;
618 WebInspector.FunctionScopeMainTreeElement.prototype = {
619 onpopulate: function()
621 if (this.children.length && !this.shouldRefreshChildren)
625 * @param {?WebInspector.DebuggerModel.FunctionDetails} response
626 * @this {WebInspector.FunctionScopeMainTreeElement}
628 function didGetDetails(response)
632 this.removeChildren();
634 var scopeChain = response.scopeChain;
637 for (var i = 0; i < scopeChain.length; ++i) {
638 var scope = scopeChain[i];
642 switch (scope.type) {
643 case DebuggerAgent.ScopeType.Local:
644 // Not really expecting this scope type here.
645 title = WebInspector.UIString("Local");
646 isTrueObject = false;
648 case DebuggerAgent.ScopeType.Closure:
649 title = WebInspector.UIString("Closure");
650 isTrueObject = false;
652 case DebuggerAgent.ScopeType.Catch:
653 title = WebInspector.UIString("Catch");
654 isTrueObject = false;
656 case DebuggerAgent.ScopeType.With:
657 title = WebInspector.UIString("With Block");
660 case DebuggerAgent.ScopeType.Global:
661 title = WebInspector.UIString("Global");
665 console.error("Unknown scope type: " + scope.type);
669 var runtimeModel = this._remoteObject.target().runtimeModel;
671 var remoteObject = runtimeModel.createRemoteObject(scope.object);
672 var property = new WebInspector.RemoteObjectProperty(title, remoteObject);
673 property.writable = false;
674 property.parentObject = null;
675 this.appendChild(new this.treeOutline.section.treeElementConstructor(property));
677 var scopeRef = new WebInspector.ScopeRef(i, undefined, this._remoteObject.objectId);
678 var remoteObject = runtimeModel.createScopeRemoteObject(scope.object, scopeRef);
679 var scopeTreeElement = new WebInspector.ScopeTreeElement(title, null, remoteObject);
680 this.appendChild(scopeTreeElement);
684 this._remoteObject.functionDetails(didGetDetails.bind(this));
687 __proto__: TreeElement.prototype
692 * @extends {TreeElement}
693 * @param {string} title
694 * @param {?string} subtitle
695 * @param {!WebInspector.RemoteObject} remoteObject
697 WebInspector.ScopeTreeElement = function(title, subtitle, remoteObject)
699 // TODO: use subtitle parameter.
700 TreeElement.call(this, title, null, false);
701 this.toggleOnClick = true;
702 this.selectable = false;
703 this._remoteObject = remoteObject;
704 this.hasChildren = true;
707 WebInspector.ScopeTreeElement.prototype = {
708 onpopulate: function()
710 WebInspector.ObjectPropertyTreeElement.populate(this, this._remoteObject);
713 __proto__: TreeElement.prototype
718 * @extends {TreeElement}
719 * @param {!WebInspector.RemoteObject} object
720 * @param {number} fromIndex
721 * @param {number} toIndex
722 * @param {number} propertyCount
724 WebInspector.ArrayGroupingTreeElement = function(object, fromIndex, toIndex, propertyCount)
726 TreeElement.call(this, String.sprintf("[%d \u2026 %d]", fromIndex, toIndex), undefined, true);
727 this._fromIndex = fromIndex;
728 this._toIndex = toIndex;
729 this._object = object;
730 this._readOnly = true;
731 this._propertyCount = propertyCount;
732 this._populated = false;
735 WebInspector.ArrayGroupingTreeElement._bucketThreshold = 100;
736 WebInspector.ArrayGroupingTreeElement._sparseIterationThreshold = 250000;
739 * @param {!TreeElement|!TreeOutline} treeElement
740 * @param {!WebInspector.RemoteObject} object
741 * @param {number} fromIndex
742 * @param {number} toIndex
744 WebInspector.ArrayGroupingTreeElement._populateArray = function(treeElement, object, fromIndex, toIndex)
746 WebInspector.ArrayGroupingTreeElement._populateRanges(treeElement, object, fromIndex, toIndex, true);
750 * @param {!TreeElement|!TreeOutline} treeElement
751 * @param {!WebInspector.RemoteObject} object
752 * @param {number} fromIndex
753 * @param {number} toIndex
754 * @param {boolean} topLevel
755 * @this {WebInspector.ArrayGroupingTreeElement}
757 WebInspector.ArrayGroupingTreeElement._populateRanges = function(treeElement, object, fromIndex, toIndex, topLevel)
759 object.callFunctionJSON(packRanges, [{value: fromIndex}, {value: toIndex}, {value: WebInspector.ArrayGroupingTreeElement._bucketThreshold}, {value: WebInspector.ArrayGroupingTreeElement._sparseIterationThreshold}], callback);
762 * @suppressReceiverCheck
764 * @param {number=} fromIndex // must declare optional
765 * @param {number=} toIndex // must declare optional
766 * @param {number=} bucketThreshold // must declare optional
767 * @param {number=} sparseIterationThreshold // must declare optional
769 function packRanges(fromIndex, toIndex, bucketThreshold, sparseIterationThreshold)
771 var ownPropertyNames = null;
776 function doLoop(iterationCallback)
778 if (toIndex - fromIndex < sparseIterationThreshold) {
779 for (var i = fromIndex; i <= toIndex; ++i) {
781 iterationCallback(i);
784 ownPropertyNames = ownPropertyNames || Object.getOwnPropertyNames(this);
785 for (var i = 0; i < ownPropertyNames.length; ++i) {
786 var name = ownPropertyNames[i];
787 var index = name >>> 0;
788 if (String(index) === name && fromIndex <= index && index <= toIndex)
789 iterationCallback(index);
795 function countIterationCallback()
799 doLoop.call(this, countIterationCallback);
801 var bucketSize = count;
802 if (count <= bucketThreshold)
805 bucketSize = Math.pow(bucketThreshold, Math.ceil(Math.log(count) / Math.log(bucketThreshold)) - 1);
811 function loopIterationCallback(i)
813 if (groupStart === -1)
817 if (++count === bucketSize) {
818 ranges.push([groupStart, groupEnd, count]);
823 doLoop.call(this, loopIterationCallback);
826 ranges.push([groupStart, groupEnd, count]);
830 function callback(ranges)
832 if (ranges.length == 1)
833 WebInspector.ArrayGroupingTreeElement._populateAsFragment(treeElement, object, ranges[0][0], ranges[0][1]);
835 for (var i = 0; i < ranges.length; ++i) {
836 var fromIndex = ranges[i][0];
837 var toIndex = ranges[i][1];
838 var count = ranges[i][2];
839 if (fromIndex == toIndex)
840 WebInspector.ArrayGroupingTreeElement._populateAsFragment(treeElement, object, fromIndex, toIndex);
842 treeElement.appendChild(new WebInspector.ArrayGroupingTreeElement(object, fromIndex, toIndex, count));
846 WebInspector.ArrayGroupingTreeElement._populateNonIndexProperties(treeElement, object);
851 * @param {!TreeElement|!TreeOutline} treeElement
852 * @param {!WebInspector.RemoteObject} object
853 * @param {number} fromIndex
854 * @param {number} toIndex
855 * @this {WebInspector.ArrayGroupingTreeElement}
857 WebInspector.ArrayGroupingTreeElement._populateAsFragment = function(treeElement, object, fromIndex, toIndex)
859 object.callFunction(buildArrayFragment, [{value: fromIndex}, {value: toIndex}, {value: WebInspector.ArrayGroupingTreeElement._sparseIterationThreshold}], processArrayFragment.bind(this));
862 * @suppressReceiverCheck
864 * @param {number=} fromIndex // must declare optional
865 * @param {number=} toIndex // must declare optional
866 * @param {number=} sparseIterationThreshold // must declare optional
868 function buildArrayFragment(fromIndex, toIndex, sparseIterationThreshold)
870 var result = Object.create(null);
871 if (toIndex - fromIndex < sparseIterationThreshold) {
872 for (var i = fromIndex; i <= toIndex; ++i) {
877 var ownPropertyNames = Object.getOwnPropertyNames(this);
878 for (var i = 0; i < ownPropertyNames.length; ++i) {
879 var name = ownPropertyNames[i];
880 var index = name >>> 0;
881 if (String(index) === name && fromIndex <= index && index <= toIndex)
882 result[index] = this[index];
889 * @param {?WebInspector.RemoteObject} arrayFragment
890 * @param {boolean=} wasThrown
891 * @this {WebInspector.ArrayGroupingTreeElement}
893 function processArrayFragment(arrayFragment, wasThrown)
895 if (!arrayFragment || wasThrown)
897 arrayFragment.getAllProperties(false, processProperties.bind(this));
900 /** @this {WebInspector.ArrayGroupingTreeElement} */
901 function processProperties(properties, internalProperties)
906 properties.sort(WebInspector.ObjectPropertiesSection.CompareProperties);
907 for (var i = 0; i < properties.length; ++i) {
908 properties[i].parentObject = this._object;
909 var childTreeElement = new treeElement.treeOutline.section.treeElementConstructor(properties[i]);
910 childTreeElement._readOnly = true;
911 treeElement.appendChild(childTreeElement);
917 * @param {!TreeElement|!TreeOutline} treeElement
918 * @param {!WebInspector.RemoteObject} object
919 * @this {WebInspector.ArrayGroupingTreeElement}
921 WebInspector.ArrayGroupingTreeElement._populateNonIndexProperties = function(treeElement, object)
923 object.callFunction(buildObjectFragment, undefined, processObjectFragment.bind(this));
926 * @suppressReceiverCheck
929 function buildObjectFragment()
931 var result = Object.create(this.__proto__);
932 var names = Object.getOwnPropertyNames(this);
933 for (var i = 0; i < names.length; ++i) {
935 // Array index check according to the ES5-15.4.
936 if (String(name >>> 0) === name && name >>> 0 !== 0xffffffff)
938 var descriptor = Object.getOwnPropertyDescriptor(this, name);
940 Object.defineProperty(result, name, descriptor);
946 * @param {?WebInspector.RemoteObject} arrayFragment
947 * @param {boolean=} wasThrown
948 * @this {WebInspector.ArrayGroupingTreeElement}
950 function processObjectFragment(arrayFragment, wasThrown)
952 if (!arrayFragment || wasThrown)
954 arrayFragment.getOwnProperties(processProperties.bind(this));
958 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties
959 * @param {?Array.<!WebInspector.RemoteObjectProperty>=} internalProperties
960 * @this {WebInspector.ArrayGroupingTreeElement}
962 function processProperties(properties, internalProperties)
966 properties.sort(WebInspector.ObjectPropertiesSection.CompareProperties);
967 for (var i = 0; i < properties.length; ++i) {
968 properties[i].parentObject = this._object;
969 var childTreeElement = new treeElement.treeOutline.section.treeElementConstructor(properties[i]);
970 childTreeElement._readOnly = true;
971 treeElement.appendChild(childTreeElement);
976 WebInspector.ArrayGroupingTreeElement.prototype = {
977 onpopulate: function()
982 this._populated = true;
984 if (this._propertyCount >= WebInspector.ArrayGroupingTreeElement._bucketThreshold) {
985 WebInspector.ArrayGroupingTreeElement._populateRanges(this, this._object, this._fromIndex, this._toIndex, false);
988 WebInspector.ArrayGroupingTreeElement._populateAsFragment(this, this._object, this._fromIndex, this._toIndex);
993 this.listItemElement.classList.add("name");
996 __proto__: TreeElement.prototype
1001 * @extends {WebInspector.TextPrompt}
1002 * @param {boolean=} renderAsBlock
1004 WebInspector.ObjectPropertyPrompt = function(renderAsBlock)
1006 WebInspector.TextPrompt.call(this, WebInspector.ExecutionContextSelector.completionsForTextPromptInCurrentContext);
1007 this.setSuggestBoxEnabled(true);
1009 this.renderAsBlock();
1012 WebInspector.ObjectPropertyPrompt.prototype = {
1013 __proto__: WebInspector.TextPrompt.prototype