ObjectPropertiesSection.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. export default class ObjectPropertiesSection extends UI.TreeOutlineInShadow{constructor(object,title,linkifier,emptyPlaceholder,ignoreHasOwnProperty,extraProperties,showOverflow){super();this._object=object;this._editable=true;if(!showOverflow){this.hideOverflow();}
  2. this.setFocusable(true);this.setShowSelectionOnKeyboardFocus(true);this._objectTreeElement=new RootElement(object,linkifier,emptyPlaceholder,ignoreHasOwnProperty,extraProperties);this.appendChild(this._objectTreeElement);if(typeof title==='string'||!title){this.titleElement=this.element.createChild('span');this.titleElement.textContent=title||'';}else{this.titleElement=title;this.element.appendChild(title);}
  3. if(!this.titleElement.hasAttribute('tabIndex')){this.titleElement.tabIndex=-1;}
  4. this.element._section=this;this.registerRequiredCSS('object_ui/objectValue.css');this.registerRequiredCSS('object_ui/objectPropertiesSection.css');this.rootElement().childrenListElement.classList.add('source-code','object-properties-section');}
  5. static defaultObjectPresentation(object,linkifier,skipProto,readOnly){const objectPropertiesSection=ObjectPropertiesSection.defaultObjectPropertiesSection(object,linkifier,skipProto,readOnly);if(!object.hasChildren){return objectPropertiesSection.titleElement;}else{return objectPropertiesSection.element;}}
  6. static defaultObjectPropertiesSection(object,linkifier,skipProto,readOnly){const titleElement=createElementWithClass('span','source-code');const shadowRoot=UI.createShadowRootWithCoreStyles(titleElement,'object_ui/objectValue.css');shadowRoot.appendChild(ObjectPropertiesSection.createValueElement(object,false,true));const objectPropertiesSection=new ObjectPropertiesSection(object,titleElement,linkifier);objectPropertiesSection.editable=false;if(skipProto){objectPropertiesSection.skipProto();}
  7. if(readOnly){objectPropertiesSection.setEditable(false);}
  8. return objectPropertiesSection;}
  9. static CompareProperties(propertyA,propertyB){const a=propertyA.name;const b=propertyB.name;if(a==='__proto__'){return 1;}
  10. if(b==='__proto__'){return-1;}
  11. if(!propertyA.enumerable&&propertyB.enumerable){return 1;}
  12. if(!propertyB.enumerable&&propertyA.enumerable){return-1;}
  13. if(a.startsWith('_')&&!b.startsWith('_')){return 1;}
  14. if(b.startsWith('_')&&!a.startsWith('_')){return-1;}
  15. if(propertyA.symbol&&!propertyB.symbol){return 1;}
  16. if(propertyB.symbol&&!propertyA.symbol){return-1;}
  17. if(propertyA.private&&!propertyB.private){return 1;}
  18. if(propertyB.private&&!propertyA.private){return-1;}
  19. return String.naturalOrderComparator(a,b);}
  20. static createNameElement(name,isPrivate){if(name===null){return UI.html`<span class="name"></span>`;}
  21. if(/^\s|\s$|^$|\n/.test(name)){return UI.html`<span class="name">"${name.replace(/\n/g, '\u21B5')}"</span>`;}
  22. if(isPrivate){return UI.html`<span class="name">
  23. <span class="private-property-hash">${name[0]}</span>${name.substring(1)}
  24. </span>`;}
  25. return UI.html`<span class="name">${name}</span>`;}
  26. static valueElementForFunctionDescription(description,includePreview,defaultName){const valueElement=createElementWithClass('span','object-value-function');description=description||'';const text=description.replace(/^function [gs]et /,'function ').replace(/^function [gs]et\(/,'function\(').replace(/^[gs]et /,'');defaultName=defaultName||'';const asyncMatch=text.match(/^(async\s+function)/);const isGenerator=text.startsWith('function*');const isGeneratorShorthand=text.startsWith('*');const isBasic=!isGenerator&&text.startsWith('function');const isClass=text.startsWith('class ')||text.startsWith('class{');const firstArrowIndex=text.indexOf('=>');const isArrow=!asyncMatch&&!isGenerator&&!isBasic&&!isClass&&firstArrowIndex>0;let textAfterPrefix;if(isClass){textAfterPrefix=text.substring('class'.length);const classNameMatch=/^[^{\s]+/.exec(textAfterPrefix.trim());let className=defaultName;if(classNameMatch){className=classNameMatch[0].trim()||defaultName;}
  27. addElements('class',textAfterPrefix,className);}else if(asyncMatch){textAfterPrefix=text.substring(asyncMatch[1].length);addElements('async \u0192',textAfterPrefix,nameAndArguments(textAfterPrefix));}else if(isGenerator){textAfterPrefix=text.substring('function*'.length);addElements('\u0192*',textAfterPrefix,nameAndArguments(textAfterPrefix));}else if(isGeneratorShorthand){textAfterPrefix=text.substring('*'.length);addElements('\u0192*',textAfterPrefix,nameAndArguments(textAfterPrefix));}else if(isBasic){textAfterPrefix=text.substring('function'.length);addElements('\u0192',textAfterPrefix,nameAndArguments(textAfterPrefix));}else if(isArrow){const maxArrowFunctionCharacterLength=60;let abbreviation=text;if(defaultName){abbreviation=defaultName+'()';}else if(text.length>maxArrowFunctionCharacterLength){abbreviation=text.substring(0,firstArrowIndex+2)+' {\u2026}';}
  28. addElements('',text,abbreviation);}else{addElements('\u0192',text,nameAndArguments(text));}
  29. valueElement.title=description.trimEndWithMaxLength(500);return valueElement;function nameAndArguments(contents){const startOfArgumentsIndex=contents.indexOf('(');const endOfArgumentsMatch=contents.match(/\)\s*{/);if(startOfArgumentsIndex!==-1&&endOfArgumentsMatch&&endOfArgumentsMatch.index>startOfArgumentsIndex){const name=contents.substring(0,startOfArgumentsIndex).trim()||defaultName;const args=contents.substring(startOfArgumentsIndex,endOfArgumentsMatch.index+1);return name+args;}
  30. return defaultName+'()';}
  31. function addElements(prefix,body,abbreviation){const maxFunctionBodyLength=200;if(prefix.length){valueElement.createChild('span','object-value-function-prefix').textContent=prefix+' ';}
  32. if(includePreview){valueElement.createTextChild(body.trim().trimEndWithMaxLength(maxFunctionBodyLength));}else{valueElement.createTextChild(abbreviation.replace(/\n/g,' '));}}}
  33. static createValueElementWithCustomSupport(value,wasThrown,showPreview,parentElement,linkifier){if(value.customPreview()){const result=(new ObjectUI.CustomPreviewComponent(value)).element;result.classList.add('object-properties-section-custom-section');return result;}
  34. return ObjectPropertiesSection.createValueElement(value,wasThrown,showPreview,parentElement,linkifier);}
  35. static createValueElement(value,wasThrown,showPreview,parentElement,linkifier){let valueElement;const type=value.type;const subtype=value.subtype;const description=value.description;if(type==='object'&&subtype==='internal#location'){const rawLocation=value.debuggerModel().createRawLocationByScriptId(value.value.scriptId,value.value.lineNumber,value.value.columnNumber);if(rawLocation&&linkifier){return linkifier.linkifyRawLocation(rawLocation,'');}
  36. valueElement=createUnknownInternalLocationElement();}else if(type==='string'&&typeof description==='string'){valueElement=createStringElement();}else if(type==='function'){valueElement=ObjectPropertiesSection.valueElementForFunctionDescription(description);}else if(type==='object'&&subtype==='node'&&description){valueElement=createNodeElement();}else if(type==='number'&&description&&description.indexOf('e')!==-1){valueElement=createNumberWithExponentElement();if(parentElement)
  37. {parentElement.classList.add('hbox');}}else{valueElement=createElementWithClass('span','object-value-'+(subtype||type));valueElement.title=description||'';if(value.preview&&showPreview){const previewFormatter=new ObjectUI.RemoteObjectPreviewFormatter();previewFormatter.appendObjectPreview(valueElement,value.preview,false);}else if(description.length>ObjectUI.ObjectPropertiesSection._maxRenderableStringLength){valueElement.appendChild(UI.createExpandableText(description,50));}else{valueElement.textContent=description;}}
  38. if(wasThrown){const wrapperElement=createElementWithClass('span','error value');wrapperElement.appendChild(UI.formatLocalized('[Exception: %s]',[valueElement]));return wrapperElement;}
  39. valueElement.classList.add('value');return valueElement;function createUnknownInternalLocationElement(){const valueElement=createElementWithClass('span');valueElement.textContent='<'+Common.UIString('unknown')+'>';valueElement.title=description||'';return valueElement;}
  40. function createStringElement(){const valueElement=createElementWithClass('span','object-value-string');const text=description.replace(/\n/g,'\u21B5');valueElement.createChild('span','object-value-string-quote').textContent='"';if(description.length>ObjectUI.ObjectPropertiesSection._maxRenderableStringLength){valueElement.appendChild(UI.createExpandableText(text,50));}else{valueElement.createTextChild(text);}
  41. valueElement.createChild('span','object-value-string-quote').textContent='"';valueElement.title=description||'';return valueElement;}
  42. function createNodeElement(){const valueElement=createElementWithClass('span','object-value-node');ObjectUI.RemoteObjectPreviewFormatter.createSpansForNodeTitle(valueElement,(description));valueElement.addEventListener('click',event=>{Common.Revealer.reveal(value);event.consume(true);},false);valueElement.addEventListener('mousemove',()=>SDK.OverlayModel.highlightObjectAsDOMNode(value),false);valueElement.addEventListener('mouseleave',()=>SDK.OverlayModel.hideDOMNodeHighlight(),false);return valueElement;}
  43. function createNumberWithExponentElement(){const valueElement=createElementWithClass('span','object-value-number');const numberParts=description.split('e');valueElement.createChild('span','object-value-scientific-notation-mantissa').textContent=numberParts[0];valueElement.createChild('span','object-value-scientific-notation-exponent').textContent='e'+numberParts[1];valueElement.classList.add('object-value-scientific-notation-number');valueElement.title=description||'';return valueElement;}}
  44. static formatObjectAsFunction(func,element,linkify,includePreview){return func.debuggerModel().functionDetailsPromise(func).then(didGetDetails);function didGetDetails(response){if(linkify&&response&&response.location){element.classList.add('linkified');element.addEventListener('click',()=>Common.Revealer.reveal(response.location)&&false);}
  45. let defaultName=includePreview?'':'anonymous';if(response&&response.functionName){defaultName=response.functionName;}
  46. const valueElement=ObjectPropertiesSection.valueElementForFunctionDescription(func.description,includePreview,defaultName);element.appendChild(valueElement);}}
  47. static _isDisplayableProperty(property,parentProperty){if(!parentProperty||!parentProperty.synthetic){return true;}
  48. const name=property.name;const useless=(parentProperty.name==='[[Entries]]'&&(name==='length'||name==='__proto__'));return!useless;}
  49. skipProto(){this._skipProto=true;}
  50. expand(){this._objectTreeElement.expand();}
  51. setEditable(value){this._editable=value;}
  52. objectTreeElement(){return this._objectTreeElement;}
  53. enableContextMenu(){this.element.addEventListener('contextmenu',this._contextMenuEventFired.bind(this),false);}
  54. _contextMenuEventFired(event){const contextMenu=new UI.ContextMenu(event);contextMenu.appendApplicableItems(this._object);if(this._object instanceof SDK.LocalJSONObject){contextMenu.viewSection().appendItem(ls`Expand recursively`,this._objectTreeElement.expandRecursively.bind(this._objectTreeElement,Number.MAX_VALUE));contextMenu.viewSection().appendItem(ls`Collapse children`,this._objectTreeElement.collapseChildren.bind(this._objectTreeElement));}
  55. contextMenu.show();}
  56. titleLessMode(){this._objectTreeElement.listItemElement.classList.add('hidden');this._objectTreeElement.childrenListElement.classList.add('title-less-mode');this._objectTreeElement.expand();}}
  57. const _arrayLoadThreshold=100;export const _maxRenderableStringLength=10000;export class ObjectPropertiesSectionsTreeOutline extends UI.TreeOutlineInShadow{constructor(options){super();this.registerRequiredCSS('object_ui/objectValue.css');this.registerRequiredCSS('object_ui/objectPropertiesSection.css');this._editable=!(options&&options.readOnly);this.contentElement.classList.add('source-code');this.contentElement.classList.add('object-properties-section');this.hideOverflow();}}
  58. export class RootElement extends UI.TreeElement{constructor(object,linkifier,emptyPlaceholder,ignoreHasOwnProperty,extraProperties){const contentElement=createElement('slot');super(contentElement);this._object=object;this._extraProperties=extraProperties||[];this._ignoreHasOwnProperty=!!ignoreHasOwnProperty;this._emptyPlaceholder=emptyPlaceholder;this.setExpandable(true);this.selectable=true;this.toggleOnClick=true;this.listItemElement.classList.add('object-properties-section-root-element');this._linkifier=linkifier;}
  59. onexpand(){if(this.treeOutline){this.treeOutline.element.classList.add('expanded');}}
  60. oncollapse(){if(this.treeOutline){this.treeOutline.element.classList.remove('expanded');}}
  61. ondblclick(e){return true;}
  62. async onpopulate(){return ObjectPropertyTreeElement._populate(this,this._object,!!this.treeOutline._skipProto,this._linkifier,this._emptyPlaceholder,this._ignoreHasOwnProperty,this._extraProperties);}}
  63. export class ObjectPropertyTreeElement extends UI.TreeElement{constructor(property,linkifier){super();this.property=property;this.toggleOnClick=true;this._highlightChanges=[];this._linkifier=linkifier;this.listItemElement.addEventListener('contextmenu',this._contextMenuFired.bind(this),false);}
  64. static async _populate(treeElement,value,skipProto,linkifier,emptyPlaceholder,flattenProtoChain,extraProperties,targetValue){if(value.arrayLength()>_arrayLoadThreshold){treeElement.removeChildren();ArrayGroupingTreeElement._populateArray(treeElement,value,0,value.arrayLength()-1,linkifier);return;}
  65. let allProperties;if(flattenProtoChain){allProperties=await value.getAllProperties(false,true);}else{allProperties=await SDK.RemoteObject.loadFromObjectPerProto(value,true);}
  66. const properties=allProperties.properties;const internalProperties=allProperties.internalProperties;treeElement.removeChildren();if(!properties){return;}
  67. extraProperties=extraProperties||[];for(let i=0;i<extraProperties.length;++i){properties.push(extraProperties[i]);}
  68. ObjectPropertyTreeElement.populateWithProperties(treeElement,properties,internalProperties,skipProto,targetValue||value,linkifier,emptyPlaceholder);}
  69. static populateWithProperties(treeNode,properties,internalProperties,skipProto,value,linkifier,emptyPlaceholder){internalProperties=internalProperties||[];const entriesProperty=internalProperties.find(property=>property.name==='[[Entries]]');if(entriesProperty){entriesProperty.parentObject=value;const treeElement=new ObjectPropertyTreeElement(entriesProperty,linkifier);treeElement.setExpandable(true);treeElement.expand();treeNode.appendChild(treeElement);}
  70. const tailProperties=[];let protoProperty=null;for(let i=0;i<properties.length;++i){const property=properties[i];property.parentObject=value;if(!ObjectPropertiesSection._isDisplayableProperty(property,treeNode.property)){continue;}
  71. if(property.name==='__proto__'&&!property.isAccessorProperty()){protoProperty=property;continue;}
  72. if(property.isOwn&&property.getter){const getterProperty=new SDK.RemoteObjectProperty('get '+property.name,property.getter,false);getterProperty.parentObject=value;tailProperties.push(getterProperty);}
  73. if(property.isOwn&&property.setter){const setterProperty=new SDK.RemoteObjectProperty('set '+property.name,property.setter,false);setterProperty.parentObject=value;tailProperties.push(setterProperty);}
  74. const canShowProperty=property.getter||!property.isAccessorProperty();if(canShowProperty&&property.name!=='__proto__'){treeNode.appendChild(new ObjectPropertyTreeElement(property,linkifier));}}
  75. for(let i=0;i<tailProperties.length;++i){treeNode.appendChild(new ObjectPropertyTreeElement(tailProperties[i],linkifier));}
  76. if(!skipProto&&protoProperty){treeNode.appendChild(new ObjectPropertyTreeElement(protoProperty,linkifier));}
  77. for(const property of internalProperties){property.parentObject=value;const treeElement=new ObjectPropertyTreeElement(property,linkifier);if(property.name==='[[Entries]]'){continue;}
  78. treeNode.appendChild(treeElement);}
  79. ObjectPropertyTreeElement._appendEmptyPlaceholderIfNeeded(treeNode,emptyPlaceholder);}
  80. static _appendEmptyPlaceholderIfNeeded(treeNode,emptyPlaceholder){if(treeNode.childCount()){return;}
  81. const title=createElementWithClass('div','gray-info-message');title.textContent=emptyPlaceholder||Common.UIString('No properties');const infoElement=new UI.TreeElement(title);treeNode.appendChild(infoElement);}
  82. static createRemoteObjectAccessorPropertySpan(object,propertyPath,callback){const rootElement=createElement('span');const element=rootElement.createChild('span');element.textContent=Common.UIString('(...)');if(!object){return rootElement;}
  83. element.classList.add('object-value-calculate-value-button');element.title=Common.UIString('Invoke property getter');element.addEventListener('click',onInvokeGetterClick,false);function onInvokeGetterClick(event){event.consume();object.callFunction(invokeGetter,[{value:JSON.stringify(propertyPath)}]).then(callback);}
  84. function invokeGetter(arrayStr){let result=this;const properties=JSON.parse(arrayStr);for(let i=0,n=properties.length;i<n;++i){result=result[properties[i]];}
  85. return result;}
  86. return rootElement;}
  87. setSearchRegex(regex,additionalCssClassName){let cssClasses=UI.highlightedSearchResultClassName;if(additionalCssClassName){cssClasses+=' '+additionalCssClassName;}
  88. this.revertHighlightChanges();this._applySearch(regex,this.nameElement,cssClasses);const valueType=this.property.value.type;if(valueType!=='object'){this._applySearch(regex,this.valueElement,cssClasses);}
  89. return!!this._highlightChanges.length;}
  90. _applySearch(regex,element,cssClassName){const ranges=[];const content=element.textContent;regex.lastIndex=0;let match=regex.exec(content);while(match){ranges.push(new TextUtils.SourceRange(match.index,match[0].length));match=regex.exec(content);}
  91. if(ranges.length){UI.highlightRangesWithStyleClass(element,ranges,cssClassName,this._highlightChanges);}}
  92. revertHighlightChanges(){UI.revertDomChanges(this._highlightChanges);this._highlightChanges=[];}
  93. async onpopulate(){const propertyValue=(this.property.value);console.assert(propertyValue);const skipProto=this.treeOutline?this.treeOutline._skipProto:true;const targetValue=this.property.name!=='__proto__'?propertyValue:this.property.parentObject;await ObjectPropertyTreeElement._populate(this,propertyValue,skipProto,this._linkifier,undefined,undefined,undefined,targetValue);}
  94. ondblclick(event){const inEditableElement=event.target.isSelfOrDescendant(this.valueElement)||(this.expandedValueElement&&event.target.isSelfOrDescendant(this.expandedValueElement));if(!this.property.value.customPreview()&&inEditableElement&&(this.property.writable||this.property.setter)){this._startEditing();}
  95. return false;}
  96. onenter(){if(!this.property.value.customPreview()&&(this.property.writable||this.property.setter)){this._startEditing();return true;}
  97. return false;}
  98. onattach(){this.update();this._updateExpandable();}
  99. onexpand(){this._showExpandedValueElement(true);}
  100. oncollapse(){this._showExpandedValueElement(false);}
  101. _showExpandedValueElement(value){if(!this.expandedValueElement){return;}
  102. if(value){this._rowContainer.replaceChild(this.expandedValueElement,this.valueElement);}else{this._rowContainer.replaceChild(this.valueElement,this.expandedValueElement);}}
  103. _createExpandedValueElement(value){const needsAlternateValue=value.hasChildren&&!value.customPreview()&&value.subtype!=='node'&&value.type!=='function'&&(value.type!=='object'||value.preview);if(!needsAlternateValue){return null;}
  104. const valueElement=createElementWithClass('span','value');if(value.description==='Object'){valueElement.textContent='';}else{valueElement.setTextContentTruncatedIfNeeded(value.description||'');}
  105. valueElement.classList.add('object-value-'+(value.subtype||value.type));valueElement.title=value.description||'';return valueElement;}
  106. update(){this.nameElement=ObjectPropertiesSection.createNameElement(this.property.name,this.property.private);if(!this.property.enumerable){this.nameElement.classList.add('object-properties-section-dimmed');}
  107. if(this.property.synthetic){this.nameElement.classList.add('synthetic-property');}
  108. this._updatePropertyPath();const isInternalEntries=this.property.synthetic&&this.property.name==='[[Entries]]';if(isInternalEntries){this.valueElement=createElementWithClass('span','value');}else if(this.property.value){const showPreview=this.property.name!=='__proto__';this.valueElement=ObjectPropertiesSection.createValueElementWithCustomSupport(this.property.value,this.property.wasThrown,showPreview,this.listItemElement,this._linkifier);}else if(this.property.getter){this.valueElement=ObjectPropertyTreeElement.createRemoteObjectAccessorPropertySpan(this.property.parentObject,[this.property.name],this._onInvokeGetterClick.bind(this));}else{this.valueElement=createElementWithClass('span','object-value-undefined');this.valueElement.textContent=Common.UIString('<unreadable>');this.valueElement.title=Common.UIString('No property getter');}
  109. const valueText=this.valueElement.textContent;if(this.property.value&&valueText&&!this.property.wasThrown){this.expandedValueElement=this._createExpandedValueElement(this.property.value);}
  110. this.listItemElement.removeChildren();if(isInternalEntries){this._rowContainer=UI.html`<span class='name-and-value'>${this.nameElement}</span>`;}else{this._rowContainer=UI.html`<span class='name-and-value'>${this.nameElement}: ${this.valueElement}</span>`;}
  111. this.listItemElement.appendChild(this._rowContainer);}
  112. _updatePropertyPath(){if(this.nameElement.title){return;}
  113. const name=this.property.name;if(this.property.synthetic){this.nameElement.title=name;return;}
  114. const useDotNotation=/^(_|\$|[A-Z])(_|\$|[A-Z]|\d)*$/i;const isInteger=/^[1-9]\d*$/;const parentPath=(this.parent.nameElement&&!this.parent.property.synthetic)?this.parent.nameElement.title:'';if(this.property.private||useDotNotation.test(name)){this.nameElement.title=parentPath?`${parentPath}.${name}`:name;}else if(isInteger.test(name)){this.nameElement.title=parentPath+'['+name+']';}else{this.nameElement.title=parentPath+'["'+JSON.stringify(name)+'"]';}}
  115. _contextMenuFired(event){const contextMenu=new UI.ContextMenu(event);contextMenu.appendApplicableItems(this);if(this.property.symbol){contextMenu.appendApplicableItems(this.property.symbol);}
  116. if(this.property.value){contextMenu.appendApplicableItems(this.property.value);}
  117. if(!this.property.synthetic&&this.nameElement&&this.nameElement.title){const copyPathHandler=Host.InspectorFrontendHost.copyText.bind(Host.InspectorFrontendHost,this.nameElement.title);contextMenu.clipboardSection().appendItem(ls`Copy property path`,copyPathHandler);}
  118. if(this.property.parentObject instanceof SDK.LocalJSONObject){contextMenu.viewSection().appendItem(ls`Expand recursively`,this.expandRecursively.bind(this,Number.MAX_VALUE));contextMenu.viewSection().appendItem(ls`Collapse children`,this.collapseChildren.bind(this));}
  119. contextMenu.show();}
  120. _startEditing(){if(this._prompt||!this.treeOutline._editable||this._readOnly){return;}
  121. this._editableDiv=this._rowContainer.createChild('span','editable-div');let text=this.property.value.description;if(this.property.value.type==='string'&&typeof text==='string'){text='"'+text+'"';}
  122. this._editableDiv.setTextContentTruncatedIfNeeded(text,Common.UIString('<string is too large to edit>'));const originalContent=this._editableDiv.textContent;this.setExpandable(false);this.listItemElement.classList.add('editing-sub-part');this.valueElement.classList.add('hidden');this._prompt=new ObjectPropertyPrompt();const proxyElement=this._prompt.attachAndStartEditing(this._editableDiv,this._editingCommitted.bind(this,originalContent));proxyElement.classList.add('property-prompt');this.listItemElement.getComponentSelection().selectAllChildren(this._editableDiv);proxyElement.addEventListener('keydown',this._promptKeyDown.bind(this,originalContent),false);}
  123. _editingEnded(){this._prompt.detach();delete this._prompt;this._editableDiv.remove();this._updateExpandable();this.listItemElement.scrollLeft=0;this.listItemElement.classList.remove('editing-sub-part');this.select();}
  124. _editingCancelled(){this.valueElement.classList.remove('hidden');this._editingEnded();}
  125. async _editingCommitted(originalContent){const userInput=this._prompt.text();if(userInput===originalContent){this._editingCancelled();return;}
  126. this._editingEnded();await this._applyExpression(userInput);}
  127. _promptKeyDown(originalContent,event){if(isEnterKey(event)){event.consume();this._editingCommitted(originalContent);return;}
  128. if(event.key==='Escape'){event.consume();this._editingCancelled();return;}}
  129. async _applyExpression(expression){const property=SDK.RemoteObject.toCallArgument(this.property.symbol||this.property.name);expression=ObjectUI.JavaScriptREPL.wrapObjectLiteral(expression.trim());if(this.property.synthetic){let invalidate=false;if(expression){invalidate=await this.property.setSyntheticValue(expression);}
  130. if(invalidate){const parent=this.parent;parent.invalidateChildren();parent.onpopulate();}else{this.update();}
  131. return;}
  132. const errorPromise=expression?this.property.parentObject.setPropertyValue(property,expression):this.property.parentObject.deleteProperty(property);const error=await errorPromise;if(error){this.update();return;}
  133. if(!expression){this.parent.removeChild(this);}else{const parent=this.parent;parent.invalidateChildren();parent.onpopulate();}}
  134. _onInvokeGetterClick(result){if(!result.object){return;}
  135. this.property.value=result.object;this.property.wasThrown=result.wasThrown;this.update();this.invalidateChildren();this._updateExpandable();}
  136. _updateExpandable(){if(this.property.value){this.setExpandable(!this.property.value.customPreview()&&this.property.value.hasChildren&&!this.property.wasThrown);}else{this.setExpandable(false);}}
  137. path(){return this.nameElement.title;}}
  138. class ArrayGroupingTreeElement extends UI.TreeElement{constructor(object,fromIndex,toIndex,propertyCount,linkifier){super(String.sprintf('[%d \u2026 %d]',fromIndex,toIndex),true);this.toggleOnClick=true;this._fromIndex=fromIndex;this._toIndex=toIndex;this._object=object;this._readOnly=true;this._propertyCount=propertyCount;this._linkifier=linkifier;}
  139. static async _populateArray(treeNode,object,fromIndex,toIndex,linkifier){await ArrayGroupingTreeElement._populateRanges(treeNode,object,fromIndex,toIndex,true,linkifier);}
  140. static async _populateRanges(treeNode,object,fromIndex,toIndex,topLevel,linkifier){const jsonValue=await object.callFunctionJSON(packRanges,[{value:fromIndex},{value:toIndex},{value:ArrayGroupingTreeElement._bucketThreshold},{value:ArrayGroupingTreeElement._sparseIterationThreshold},{value:ArrayGroupingTreeElement._getOwnPropertyNamesThreshold}]);await callback(jsonValue);function packRanges(fromIndex,toIndex,bucketThreshold,sparseIterationThreshold,getOwnPropertyNamesThreshold){let ownPropertyNames=null;const consecutiveRange=(toIndex-fromIndex>=sparseIterationThreshold)&&ArrayBuffer.isView(this);const skipGetOwnPropertyNames=consecutiveRange&&(toIndex-fromIndex>=getOwnPropertyNamesThreshold);function*arrayIndexes(object){if(toIndex-fromIndex<sparseIterationThreshold){for(let i=fromIndex;i<=toIndex;++i){if(i in object){yield i;}}}else{ownPropertyNames=ownPropertyNames||Object.getOwnPropertyNames(object);for(let i=0;i<ownPropertyNames.length;++i){const name=ownPropertyNames[i];const index=name>>>0;if((''+index)===name&&fromIndex<=index&&index<=toIndex){yield index;}}}}
  141. let count=0;if(consecutiveRange){count=toIndex-fromIndex+1;}else{for(const i of arrayIndexes(this))
  142. ++count;}
  143. let bucketSize=count;if(count<=bucketThreshold){bucketSize=count;}else{bucketSize=Math.pow(bucketThreshold,Math.ceil(Math.log(count)/Math.log(bucketThreshold))-1);}
  144. const ranges=[];if(consecutiveRange){for(let i=fromIndex;i<=toIndex;i+=bucketSize){const groupStart=i;let groupEnd=groupStart+bucketSize-1;if(groupEnd>toIndex){groupEnd=toIndex;}
  145. ranges.push([groupStart,groupEnd,groupEnd-groupStart+1]);}}else{count=0;let groupStart=-1;let groupEnd=0;for(const i of arrayIndexes(this)){if(groupStart===-1){groupStart=i;}
  146. groupEnd=i;if(++count===bucketSize){ranges.push([groupStart,groupEnd,count]);count=0;groupStart=-1;}}
  147. if(count>0){ranges.push([groupStart,groupEnd,count]);}}
  148. return{ranges:ranges,skipGetOwnPropertyNames:skipGetOwnPropertyNames};}
  149. async function callback(result){if(!result){return;}
  150. const ranges=(result.ranges);if(ranges.length===1){await ArrayGroupingTreeElement._populateAsFragment(treeNode,object,ranges[0][0],ranges[0][1],linkifier);}else{for(let i=0;i<ranges.length;++i){const fromIndex=ranges[i][0];const toIndex=ranges[i][1];const count=ranges[i][2];if(fromIndex===toIndex){await ArrayGroupingTreeElement._populateAsFragment(treeNode,object,fromIndex,toIndex,linkifier);}else{treeNode.appendChild(new ArrayGroupingTreeElement(object,fromIndex,toIndex,count,linkifier));}}}
  151. if(topLevel){await ArrayGroupingTreeElement._populateNonIndexProperties(treeNode,object,result.skipGetOwnPropertyNames,linkifier);}}}
  152. static async _populateAsFragment(treeNode,object,fromIndex,toIndex,linkifier){const result=await object.callFunction(buildArrayFragment,[{value:fromIndex},{value:toIndex},{value:ArrayGroupingTreeElement._sparseIterationThreshold}]);if(!result.object||result.wasThrown){return;}
  153. const arrayFragment=result.object;const allProperties=await arrayFragment.getAllProperties(false,true);arrayFragment.release();const properties=allProperties.properties;if(!properties){return;}
  154. properties.sort(ObjectPropertiesSection.CompareProperties);for(let i=0;i<properties.length;++i){properties[i].parentObject=this._object;const childTreeElement=new ObjectPropertyTreeElement(properties[i],linkifier);childTreeElement._readOnly=true;treeNode.appendChild(childTreeElement);}
  155. function buildArrayFragment(fromIndex,toIndex,sparseIterationThreshold){const result=Object.create(null);if(toIndex-fromIndex<sparseIterationThreshold){for(let i=fromIndex;i<=toIndex;++i){if(i in this){result[i]=this[i];}}}else{const ownPropertyNames=Object.getOwnPropertyNames(this);for(let i=0;i<ownPropertyNames.length;++i){const name=ownPropertyNames[i];const index=name>>>0;if(String(index)===name&&fromIndex<=index&&index<=toIndex){result[index]=this[index];}}}
  156. return result;}}
  157. static async _populateNonIndexProperties(treeNode,object,skipGetOwnPropertyNames,linkifier){const result=await object.callFunction(buildObjectFragment,[{value:skipGetOwnPropertyNames}]);if(!result.object||result.wasThrown){return;}
  158. const allProperties=await result.object.getOwnProperties(true);result.object.release();if(!allProperties.properties){return;}
  159. const properties=allProperties.properties;properties.sort(ObjectPropertiesSection.CompareProperties);for(const property of properties){property.parentObject=this._object;if(!ObjectPropertiesSection._isDisplayableProperty(property,treeNode.property)){continue;}
  160. const childTreeElement=new ObjectPropertyTreeElement(property,linkifier);childTreeElement._readOnly=true;treeNode.appendChild(childTreeElement);}
  161. function buildObjectFragment(skipGetOwnPropertyNames){const result={__proto__:this.__proto__};if(skipGetOwnPropertyNames){return result;}
  162. const names=Object.getOwnPropertyNames(this);for(let i=0;i<names.length;++i){const name=names[i];if(String(name>>>0)===name&&name>>>0!==0xffffffff){continue;}
  163. const descriptor=Object.getOwnPropertyDescriptor(this,name);if(descriptor){Object.defineProperty(result,name,descriptor);}}
  164. return result;}}
  165. async onpopulate(){if(this._propertyCount>=ArrayGroupingTreeElement._bucketThreshold){await ArrayGroupingTreeElement._populateRanges(this,this._object,this._fromIndex,this._toIndex,false,this._linkifier);return;}
  166. await ArrayGroupingTreeElement._populateAsFragment(this,this._object,this._fromIndex,this._toIndex,this._linkifier);}
  167. onattach(){this.listItemElement.classList.add('object-properties-section-name');}}
  168. ArrayGroupingTreeElement._bucketThreshold=100;ArrayGroupingTreeElement._sparseIterationThreshold=250000;ArrayGroupingTreeElement._getOwnPropertyNamesThreshold=500000;export class ObjectPropertyPrompt extends UI.TextPrompt{constructor(){super();this.initialize(ObjectUI.javaScriptAutocomplete.completionsForTextInCurrentContext.bind(ObjectUI.javaScriptAutocomplete));}}
  169. export class ObjectPropertiesSectionsTreeExpandController{constructor(treeOutline){this._expandedProperties=new Set();treeOutline.addEventListener(UI.TreeOutline.Events.ElementAttached,this._elementAttached,this);treeOutline.addEventListener(UI.TreeOutline.Events.ElementExpanded,this._elementExpanded,this);treeOutline.addEventListener(UI.TreeOutline.Events.ElementCollapsed,this._elementCollapsed,this);}
  170. watchSection(id,section){section[ObjectPropertiesSectionsTreeExpandController._treeOutlineId]=id;if(this._expandedProperties.has(id)){section.expand();}}
  171. stopWatchSectionsWithId(id){for(const property of this._expandedProperties){if(property.startsWith(id+':')){this._expandedProperties.delete(property);}}}
  172. _elementAttached(event){const element=(event.data);if(element.isExpandable()&&this._expandedProperties.has(this._propertyPath(element))){element.expand();}}
  173. _elementExpanded(event){const element=(event.data);this._expandedProperties.add(this._propertyPath(element));}
  174. _elementCollapsed(event){const element=(event.data);this._expandedProperties.delete(this._propertyPath(element));}
  175. _propertyPath(treeElement){const cachedPropertyPath=treeElement[ObjectPropertiesSectionsTreeExpandController._cachedPathSymbol];if(cachedPropertyPath){return cachedPropertyPath;}
  176. let current=treeElement;let sectionRoot=current;const rootElement=treeElement.treeOutline.rootElement();let result;while(current!==rootElement){let currentName='';if(current.property){currentName=current.property.name;}else{currentName=typeof current.title==='string'?current.title:current.title.textContent;}
  177. result=currentName+(result?'.'+result:'');sectionRoot=current;current=current.parent;}
  178. const treeOutlineId=sectionRoot[ObjectPropertiesSectionsTreeExpandController._treeOutlineId];result=treeOutlineId+(result?':'+result:'');treeElement[ObjectPropertiesSectionsTreeExpandController._cachedPathSymbol]=result;return result;}}
  179. ObjectPropertiesSectionsTreeExpandController._cachedPathSymbol=Symbol('cachedPath');ObjectPropertiesSectionsTreeExpandController._treeOutlineId=Symbol('treeOutlineId');export class Renderer{render(object,options){if(!(object instanceof SDK.RemoteObject)){return Promise.reject(new Error('Can\'t render '+object));}
  180. options=options||{};const title=options.title;const section=new ObjectPropertiesSection(object,title);if(!title){section.titleLessMode();}
  181. section.editable=!!options.editable;return Promise.resolve(({node:section.element,tree:section}));}}
  182. self.ObjectUI=self.ObjectUI||{};ObjectUI=ObjectUI||{};ObjectUI.ArrayGroupingTreeElement=ArrayGroupingTreeElement;ObjectUI.ObjectPropertiesSection=ObjectPropertiesSection;ObjectUI.ObjectPropertiesSection._maxRenderableStringLength=_maxRenderableStringLength;ObjectUI.ObjectPropertiesSectionsTreeOutline=ObjectPropertiesSectionsTreeOutline;ObjectUI.ObjectPropertiesSection.RootElement=RootElement;ObjectUI.ObjectPropertiesSection.Renderer=Renderer;ObjectUI.ObjectPropertyTreeElement=ObjectPropertyTreeElement;ObjectUI.ObjectPropertyPrompt=ObjectPropertyPrompt;ObjectUI.ObjectPropertiesSectionsTreeExpandController=ObjectPropertiesSectionsTreeExpandController;ObjectUI.ObjectPropertiesSectionsTreeOutlineOptions;