Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 99 additions & 89 deletions packages/sandcastle/src/Bucket.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useRef } from "react";
import { useCallback, useEffect, useRef } from "react";
import { embedInSandcastleTemplate } from "./Helpers";
import "./Bucket.css";
import { ConsoleMessageType } from "./ConsoleMirror";
Expand Down Expand Up @@ -35,103 +35,106 @@ function Bucket({
const bucket = useRef<HTMLIFrameElement>(null);
const lastRunNumber = useRef<number>(Number.NEGATIVE_INFINITY);

function activateBucketScripts(
bucketFrame: HTMLIFrameElement,
code: string,
html: string,
) {
const bucketDoc = bucketFrame.contentDocument;
if (!bucketDoc) {
return;
}

const headNodes = bucketDoc.head.childNodes;
let node;
const nodes: HTMLScriptElement[] = [];
let i, len;
for (i = 0, len = headNodes.length; i < len; ++i) {
node = headNodes[i];
// header is included in blank frame.
if (
node instanceof HTMLScriptElement &&
node.src.indexOf("Sandcastle-header.js") < 0 &&
node.src.indexOf("Cesium.js") < 0
) {
nodes.push(node);
const activateBucketScripts = useCallback(
function activateBucketScripts(
bucketFrame: HTMLIFrameElement,
code: string,
html: string,
) {
const bucketDoc = bucketFrame.contentDocument;
if (!bucketDoc) {
return;
}
}

for (i = 0, len = nodes.length; i < len; ++i) {
bucketDoc.head.removeChild(nodes[i]);
}

// Apply user HTML to bucket.
const htmlElement = bucketDoc.createElement("div");
htmlElement.innerHTML = html;
bucketDoc.body.appendChild(htmlElement);

const onScriptTagError = function () {
if (bucketFrame.contentDocument === bucketDoc) {
// @ts-expect-error this has type any because it's from anywhere inside the bucket
appendConsole("error", `Error loading ${this.src}`);
appendConsole(
"error",
"Make sure Cesium is built, see the Contributor's Guide for details.",
);
const headNodes = bucketDoc.head.childNodes;
let node;
const nodes: HTMLScriptElement[] = [];
let i, len;
for (i = 0, len = headNodes.length; i < len; ++i) {
node = headNodes[i];
// header is included in blank frame.
if (
node instanceof HTMLScriptElement &&
node.src.indexOf("Sandcastle-header.js") < 0 &&
node.src.indexOf("Cesium.js") < 0
) {
nodes.push(node);
}
}
};

// Load each script after the previous one has loaded.
const loadScript = function () {
if (bucketFrame.contentDocument !== bucketDoc) {
// A newer reload has happened, abort this.
return;
for (i = 0, len = nodes.length; i < len; ++i) {
bucketDoc.head.removeChild(nodes[i]);
}
if (nodes.length > 0) {
while (nodes.length > 0) {
node = nodes.shift();
if (!node) {
continue;
}
const scriptElement = bucketDoc.createElement("script");
let hasSrc = false;
for (
let j = 0, numAttrs = node.attributes.length;
j < numAttrs;
++j
) {
const name = node.attributes[j].name;
const val = node.attributes[j].value;
scriptElement.setAttribute(name, val);
if (name === "src" && val) {
hasSrc = true;

// Apply user HTML to bucket.
const htmlElement = bucketDoc.createElement("div");
htmlElement.innerHTML = html;
bucketDoc.body.appendChild(htmlElement);

const onScriptTagError = function () {
if (bucketFrame.contentDocument === bucketDoc) {
// @ts-expect-error this has type any because it's from anywhere inside the bucket
appendConsole("error", `Error loading ${this.src}`);
appendConsole(
"error",
"Make sure Cesium is built, see the Contributor's Guide for details.",
);
}
};

// Load each script after the previous one has loaded.
const loadScript = function () {
if (bucketFrame.contentDocument !== bucketDoc) {
// A newer reload has happened, abort this.
return;
}
if (nodes.length > 0) {
while (nodes.length > 0) {
node = nodes.shift();
if (!node) {
continue;
}
const scriptElement = bucketDoc.createElement("script");
let hasSrc = false;
for (
let j = 0, numAttrs = node.attributes.length;
j < numAttrs;
++j
) {
const name = node.attributes[j].name;
const val = node.attributes[j].value;
scriptElement.setAttribute(name, val);
if (name === "src" && val) {
hasSrc = true;
}
}
scriptElement.innerHTML = node.innerHTML;
if (hasSrc) {
scriptElement.onload = loadScript;
scriptElement.onerror = onScriptTagError;
bucketDoc.head.appendChild(scriptElement);
} else {
bucketDoc.head.appendChild(scriptElement);
loadScript();
}
}
scriptElement.innerHTML = node.innerHTML;
if (hasSrc) {
scriptElement.onload = loadScript;
scriptElement.onerror = onScriptTagError;
bucketDoc.head.appendChild(scriptElement);
} else {
bucketDoc.head.appendChild(scriptElement);
loadScript();
}
}
} else {
// Apply user JS to bucket
const element = bucketDoc.createElement("script");
element.type = "module";
} else {
// Apply user JS to bucket
const element = bucketDoc.createElement("script");
element.type = "module";

// Firefox line numbers are zero-based, not one-based.
const isFirefox = navigator.userAgent.indexOf("Firefox/") >= 0;
// Firefox line numbers are zero-based, not one-based.
const isFirefox = navigator.userAgent.indexOf("Firefox/") >= 0;

element.textContent = embedInSandcastleTemplate(code, isFirefox);
bucketDoc.body.appendChild(element);
}
};
element.textContent = embedInSandcastleTemplate(code, isFirefox);
bucketDoc.body.appendChild(element);
}
};

loadScript();
}
loadScript();
},
[appendConsole],
);

useEffect(() => {
if (
Expand Down Expand Up @@ -197,7 +200,14 @@ function Bucket({
};
window.addEventListener("message", messageHandler);
return () => window.removeEventListener("message", messageHandler);
}, [code, html, highlightLine, resetConsole, appendConsole]);
}, [
code,
html,
highlightLine,
resetConsole,
appendConsole,
activateBucketScripts,
]);

return (
<div className="bucket-container">
Expand Down