Recommended
React component
Install the typed wrapper:
npm install @algojudge/uva-explorer-react
The src property is optional. Omit it to use the hosted UVa Explorer automatically. Private access uses the separate, optional accessKey property.
import { UvaProblemPicker } from "@algojudge/uva-explorer-react";
export function ProblemField() {
return (
<UvaProblemPicker
language="en"
problemNumbers={[100, 101]}
options={{ hideLangPicker: true }}
onConfirm={({ problemNumbers, problems }) => {
console.log(problemNumbers, problems);
}}
style={{ width: "100%", height: 720, border: 0 }}
/>
);
}
<UvaProblemPicker
accessKey={privateAccessKey}
onConfirm={({ problemNumbers }) => console.log(problemNumbers)}
/>
Set src only when using a self-hosted Explorer. The component transfers accessKey in the iframe fragment; UVa Explorer consumes and removes it immediately.
No framework
iframe and postMessage
Validate both the Explorer origin and the iframe window before accepting messages.
<iframe id="uva-picker"
src="https://uvaexplorer.algojudge.app/picker/">
</iframe>
<script>
const pickerUrl = "https://uvaexplorer.algojudge.app/picker/";
const accessKey = undefined; // Optional private dataset key.
const pickerSrc = accessKey
? `${pickerUrl}#key=${encodeURIComponent(accessKey)}`
: pickerUrl;
const pickerOrigin = new URL(pickerUrl).origin;
const picker = document.querySelector("#uva-picker");
picker.src = pickerSrc;
window.addEventListener("message", (event) => {
if (event.origin !== pickerOrigin ||
event.source !== picker.contentWindow) return;
if (event.data?.type === "uva-explorer:ready") {
picker.contentWindow.postMessage({
type: "uva-explorer:init",
version: 1,
requestId: "contest-problems",
language: "en",
problemNumbers: [100, 101],
options: { hideLangPicker: true }
}, pickerOrigin);
}
if (event.data?.type === "uva-explorer:confirm") {
console.log(event.data.problemNumbers, event.data.problems);
}
});
</script>
Your Content Security Policy must allow https://uvaexplorer.algojudge.app in frame-src.
Live example