| 17 | } |
| 18 | |
| 19 | export class Sandbox { |
| 20 | static async create(options) { |
| 21 | this.emptyPath = options.emptyPath || "./" |
| 22 | let frame = document.createElement("iframe") |
| 23 | frame.src = this.emptyPath + "empty.html" |
| 24 | if (options.place) { |
| 25 | options.place(frame) |
| 26 | } else { |
| 27 | frame.style.height = "0px" |
| 28 | frame.style.border = "none" |
| 29 | document.body.appendChild(frame) |
| 30 | } |
| 31 | await awaitEvent(frame, "load") |
| 32 | |
| 33 | let box = new Sandbox(frame) |
| 34 | let scripts = (options.loadFiles || []).map(file => { |
| 35 | let script = box.win.document.createElement("script") |
| 36 | script.src = file |
| 37 | box.win.document.body.appendChild(script) |
| 38 | return awaitEvent(script, "load") |
| 39 | }) |
| 40 | await Promise.all(scripts) |
| 41 | return box |
| 42 | } |
| 43 | |
| 44 | constructor(frame) { |
| 45 | this.startedAt = null |
| 46 | this.extraSecs = 2 |
| 47 | this.output = null |
| 48 | this.handleDeps = true |
| 49 | |
| 50 | this.callbacks = {} |
| 51 | // Used to cancel existing events when new code is loaded |
| 52 | this.timeouts = []; this.intervals = []; this.frames = [] |
| 53 | this.framePos = 0 |
| 54 | |
| 55 | // Loaded CommonJS modules |
| 56 | this.loaded = new Cached(name => resolved.compute(name).then(({name, code}) => this.evalModule(name, code))) |
| 57 | |
| 58 | this.frame = frame |
| 59 | this.win = frame.contentWindow |
| 60 | this.setupEnv() |
| 61 | |
| 62 | const resize = () => { |
| 63 | if (this.frame.style.display != "none") this.resizeFrame() |
| 64 | } |
| 65 | this.frame.addEventListener("load", resize) |
| 66 | let resizeTimeout = null |
| 67 | const scheduleResize = () => { |
| 68 | this.win.clearTimeout(resizeTimeout) |
| 69 | this.win.__setTimeout(resize, 200) |
| 70 | } |
| 71 | this.win.addEventListener("keydown", scheduleResize) |
| 72 | this.win.addEventListener("mousedown", scheduleResize) |
| 73 | } |
| 74 | |
| 75 | async run(code, output) { |
| 76 | if (output) this.output = output |
nothing calls this directly
no outgoing calls
no test coverage detected