|
import type { BackendContext } from '@vue-devtools/app-backend-api' |
|
import type { ID, ScreenshotOverlayRenderContext } from '@vue/devtools-api' |
|
import { SharedData } from '@vue-devtools/shared-utils' |
|
import { JobQueue } from './util/queue' |
|
import { builtinLayers } from './timeline-builtins' |
|
|
|
let overlay: HTMLDivElement |
|
let image: HTMLImageElement |
|
let container: HTMLDivElement |
|
|
|
const jobQueue = new JobQueue() |
|
|
|
interface Screenshot { |
|
id: ID |
|
time: number |
|
image: string |
|
events: ID[] |
|
} |
|
|
|
export async function showScreenshot(screenshot: Screenshot, ctx: BackendContext) { |
|
await jobQueue.queue('showScreenshot', async () => { |
|
if (screenshot) { |
|
if (!container) { |
|
createElements() |
|
} |
|
|
|
image.src = screenshot.image |
|
image.style.visibility = screenshot.image ? 'visible' : 'hidden' |
|
|
|
clearContent() |
|
|
|
const events = screenshot.events.map(id => ctx.timelineEventMap.get(id)).filter(Boolean).map(eventData => ({ |
|
layer: builtinLayers.concat(ctx.timelineLayers).find(layer => layer.id === eventData.layerId), |
|
event: { |
|
...eventData.event, |
|
layerId: eventData.layerId, |
|
renderMeta: {}, |
|
}, |
|
})) |
|
|
|
const renderContext: ScreenshotOverlayRenderContext = { |
|
screenshot, |
|
events: events.map(({ event }) => event), |
|
index: 0, |
|
} |
|
|
|
for (let i = 0; i < events.length; i++) { |
|
const { layer, event } = events[i] |
|
if (layer.screenshotOverlayRender) { |
|
renderContext.index = i |
|
try { |
|
const result = await layer.screenshotOverlayRender(event, renderContext) |
|
if (result !== false) { |
|
if (typeof result === 'string') { |
|
container.innerHTML += result |
|
} |
|
else { |
|
container.appendChild(result) |
|
} |
|
} |
|
} |
|
catch (e) { |
|
if (SharedData.debugInfo) { |
|
console.error(e) |
|
} |
|
} |
|
} |
|
} |
|
|
|
showElement() |
|
} |
|
else { |
|
hideElement() |
|
} |
|
}) |
|
} |
|
|
|
function createElements() { |
|
overlay = document.createElement('div') |
|
overlay.style.position = 'fixed' |
|
overlay.style.zIndex = '9999999999999' |
|
overlay.style.pointerEvents = 'none' |
|
overlay.style.left = '0' |
|
overlay.style.top = '0' |
|
overlay.style.width = '100vw' |
|
overlay.style.height = '100vh' |
|
overlay.style.backgroundColor = 'rgba(0,0,0,0.5)' |
|
overlay.style.overflow = 'hidden' |
|
|
|
const imageBox = document.createElement('div') |
|
imageBox.style.position = 'relative' |
|
overlay.appendChild(imageBox) |
|
|
|
image = document.createElement('img') |
|
imageBox.appendChild(image) |
|
|
|
container = document.createElement('div') |
|
container.style.position = 'absolute' |
|
container.style.left = '0' |
|
container.style.top = '0' |
|
imageBox.appendChild(container) |
|
|
|
const style = document.createElement('style') |
|
style.innerHTML = '.__vuedevtools_no-scroll { overflow: hidden; }' |
|
document.head.appendChild(style) |
|
} |
|
|
|
function showElement() { |
|
if (!overlay.parentNode) { |
|
document.body.appendChild(overlay) |
|
document.body.classList.add('__vuedevtools_no-scroll') |
|
} |
|
} |
|
|
|
function hideElement() { |
|
if (overlay && overlay.parentNode) { |
|
overlay.parentNode.removeChild(overlay) |
|
|
|
document.body.classList.remove('__vuedevtools_no-scroll') |
|
|
|
clearContent() |
|
} |
|
} |
|
|
|
function clearContent() { |
|
while (container.firstChild) { |
|
container.removeChild(container.lastChild) |
|
} |
|
} |
|
|