// Copyright 2021 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import {App} from '../index.mjs' import {FocusEvent, SelectRelatedEvent} from './events.mjs'; import {DOM, entriesEquals, ExpandableText, V8CustomElement} from './helper.mjs'; DOM.defineCustomElement('view/property-link-table', template => class PropertyLinkTable extends V8CustomElement { _object; _propertyDict; _instanceLinkButtons = false; _showHandler = this._handleShow.bind(this); _showSourcePositionHandler = this._handleShowSourcePosition.bind(this); _showRelatedHandler = this._handleShowRelated.bind(this); _arrayValueSelectHandler = this._handleArrayValueSelect.bind(this); constructor() { super(template); } set instanceLinkButtons(newValue) { this._instanceLinkButtons = newValue; } set propertyDict(propertyDict) { if (entriesEquals(this._propertyDict, propertyDict)) return; if (typeof propertyDict !== 'object') { throw new Error( `Invalid property dict, expected object: ${propertyDict}`); } this._propertyDict = propertyDict; this.requestUpdate(); } _update() { this._fragment = new DocumentFragment(); this._table = DOM.table(); for (let key in this._propertyDict) { const value = this._propertyDict[key]; this._addKeyValue(key, value); } const tableDiv = DOM.div('properties'); tableDiv.appendChild(this._table); this._fragment.appendChild(tableDiv); this._createFooter(); const newContent = DOM.div(); newContent.appendChild(this._fragment); this.$('#content').replaceWith(newContent); newContent.id = 'content'; this._fragment = undefined; } _addKeyValue(key, value) { if (key == 'title') { this._addTitle(value); return; } if (key == '__this__') { this._object = value; return; } const row = this._table.insertRow(); row.insertCell().innerText = key; const cell = row.insertCell(); if (value == undefined) return; if (Array.isArray(value)) { cell.appendChild(this._addArrayValue(value)); return; } else if (App.isClickable(value)) { cell.className = 'clickable'; cell.onclick = this._showHandler; cell.data = value; } if (value.isCode) { cell.classList.add('code'); } new ExpandableText(cell, value.toString()); } _addArrayValue(array) { if (array.length == 0) { return DOM.text('empty'); } else if (array.length > 200) { return DOM.text(`${array.length} items`); } const select = DOM.element('select'); select.onchange = this._arrayValueSelectHandler; for (let value of array) { const option = DOM.element('option'); option.innerText = value === undefined ? '' : value.toString(); option.data = value; select.add(option); } return select; } _addTitle(value) { const title = DOM.element('h3'); title.innerText = value; this._fragment.appendChild(title); } _createFooter() { if (this._object === undefined) return; if (!this._instanceLinkButtons) return; const footer = DOM.div('footer'); let showButton = footer.appendChild(DOM.button('🔍 Details', this._showHandler)); showButton.data = this._object; showButton.title = `Show details for ${this._object}` if (this._object.sourcePosition) { let showSourcePositionButton = footer.appendChild( DOM.button('📍 Source Position', this._showSourcePositionHandler)); showSourcePositionButton.data = this._object; showSourcePositionButton.title = 'Open the source position'; } let showRelatedButton = footer.appendChild(DOM.button('🕸 Related', this._showRelatedHandler)); showRelatedButton.data = this._object; showRelatedButton.title = 'Show all related events in all panels'; this._fragment.appendChild(footer); } _handleArrayValueSelect(event) { const logEntry = event.currentTarget.selectedOptions[0].data; this.dispatchEvent(new FocusEvent(logEntry)); } _handleShow(event) { this.dispatchEvent(new FocusEvent(event.currentTarget.data)); } _handleShowSourcePosition(event) { this.dispatchEvent(new FocusEvent(event.currentTarget.data.sourcePosition)); } _handleShowRelated(event) { this.dispatchEvent(new SelectRelatedEvent(event.currentTarget.data)); } });