show dom elements in value explorer

This commit is contained in:
Dmitry Vasilev
2023-07-17 05:21:05 +03:00
parent 7102e532f2
commit 190e05d21d
4 changed files with 104 additions and 38 deletions

View File

@@ -0,0 +1,16 @@
import _ from 'https://unpkg.com/lodash-es'
const url = 'https://api.github.com/search/repositories?q=stars:%3E1&sort=stars'
const resp = await fetch(url)
const repos = await resp.json()
const langs = _(repos.items)
.map(r => r.language)
.filter(l => l != null)
.countBy()
.toPairs()
.map(([language, count]) => ({language, count}))
import {barY} from "https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6/+esm";
barY(langs, {x: "language", y: "count", sort: {x: "y", reverse: true}, fill: 'purple'})
.plot()

View File

@@ -266,16 +266,23 @@
/* value_explorer */ /* value_explorer */
.embed_value_explorer_container { .embed_value_explorer_container.is_not_dom_el {
height: 0px; height: 0px;
} }
.embed_value_explorer_container.is_dom_el {
padding: 1em;
}
.embed_value_explorer_wrapper { .embed_value_explorer_wrapper {
margin-left: 1em;
/* preserve wrapper from getting clicks for code line left to it */ /* preserve wrapper from getting clicks for code line left to it */
pointer-events: none; pointer-events: none;
} }
.embed_value_explorer_container.is_not_dom_el .embed_value_explorer_wrapper {
margin-left: 1em;
}
.embed_value_explorer_content { .embed_value_explorer_content {
pointer-events: initial; pointer-events: initial;
white-space: pre; white-space: pre;

View File

@@ -169,10 +169,33 @@ export class Editor {
} }
unembed_value_explorer() { unembed_value_explorer() {
if(this.widget != null) { if(this.widget == null) {
this.ace_editor.getSession().widgetManager.removeLineWidget(this.widget) return
this.widget = null
} }
const session = this.ace_editor.getSession()
const widget_bottom = this.widget.el.getBoundingClientRect().bottom
session.widgetManager.removeLineWidget(this.widget)
if(this.widget.is_dom_el) {
/*
if cursor moves below widget, then ace editor first adjusts scroll,
and then widget gets remove, so scroll jerks. We have to set scroll
back
*/
// distance travelled by cursor
const distance = session.selection.getCursor().row - this.widget.row
if(distance > 0) {
const line_height = this.ace_editor.renderer.lineHeight
const scroll = widget_bottom - this.editor_container.getBoundingClientRect().bottom
if(scroll > 0) {
const scrollTop = session.getScrollTop()
session.setScrollTop(session.getScrollTop() - scroll - line_height*distance)
}
}
}
this.widget = null
} }
update_value_explorer_margin() { update_value_explorer_margin() {
@@ -203,10 +226,6 @@ export class Editor {
this.unembed_value_explorer() this.unembed_value_explorer()
const session = this.ace_editor.getSession() const session = this.ace_editor.getSession()
const pos = session.doc.indexToPosition(index)
const row = pos.row
const line_height = this.ace_editor.renderer.lineHeight
let content let content
const container = el('div', {'class': 'embed_value_explorer_container'}, const container = el('div', {'class': 'embed_value_explorer_container'},
@@ -214,7 +233,6 @@ export class Editor {
content = el('div', { content = el('div', {
// Ace editor cannot render widget before the first line. So we // Ace editor cannot render widget before the first line. So we
// render in on the next line and apply translate // render in on the next line and apply translate
'style': `transform: translate(0px, -${line_height}px)`,
'class': 'embed_value_explorer_content', 'class': 'embed_value_explorer_content',
tabindex: 0 tabindex: 0
}) })
@@ -242,7 +260,14 @@ export class Editor {
} }
}) })
let is_dom_el
if(ok) { if(ok) {
if(value instanceof globalThis.app_window.Element && !value.isConnected) {
is_dom_el = true
content.appendChild(value)
} else {
is_dom_el = false
const exp = new ValueExplorer({ const exp = new ValueExplorer({
container: content, container: content,
event_target: container, event_target: container,
@@ -264,15 +289,20 @@ export class Editor {
}) })
exp.render(value) exp.render(value)
}
} else { } else {
is_dom_el = false
content.appendChild(el('span', 'eval_error', stringify_for_header(error))) content.appendChild(el('span', 'eval_error', stringify_for_header(error)))
} }
const widget = this.widget = { const widget = this.widget = {
row, row: is_dom_el
? session.doc.indexToPosition(index + length).row
: session.doc.indexToPosition(index).row,
fixedWidth: true, fixedWidth: true,
el: container, el: container,
content, content,
is_dom_el,
} }
@@ -282,6 +312,13 @@ export class Editor {
session.widgetManager.attach(this.ace_editor); session.widgetManager.attach(this.ace_editor);
} }
if(is_dom_el) {
container.classList.add('is_dom_el')
session.widgetManager.addLineWidget(widget)
} else {
container.classList.add('is_not_dom_el')
const line_height = this.ace_editor.renderer.lineHeight
content.style.transform = `translate(0px, -${line_height}px)`
// update_value_explorer_margin relies on getLastVisibleRow which can be // update_value_explorer_margin relies on getLastVisibleRow which can be
// incorrect because it may be executed right after set_cursor_position // incorrect because it may be executed right after set_cursor_position
// which is async in ace_editor. Use setTimeout // which is async in ace_editor. Use setTimeout
@@ -291,6 +328,8 @@ export class Editor {
}, 0) }, 0)
} }
}
focus_value_explorer(return_to) { focus_value_explorer(return_to) {
if(this.widget != null) { if(this.widget != null) {
this.widget.return_to = return_to this.widget.return_to = return_to

View File

@@ -27,6 +27,10 @@ export const examples = [
path: 'ethers', path: 'ethers',
entrypoint: 'ethers/block_by_timestamp.js', entrypoint: 'ethers/block_by_timestamp.js',
}, },
{
path: 'plot',
entrypoint: 'plot/index.js',
},
].map(e => ({...e, entrypoint: e.entrypoint ?? e.path})) ].map(e => ({...e, entrypoint: e.entrypoint ?? e.path}))
const files_list = examples const files_list = examples