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. Exchange the long-lived key on your server through POST /api/access/token, then pass only the returned one-hour token to React.
import { UvaProblemPicker } from "@algojudge/uva-explorer-react";
export function ProblemField() {
return (
<UvaProblemPicker
language="en"
problemNumbers={[100, 101]}
accessToken={accessTokenFromYourServer}
options={{ hideLangPicker: true, showAiPanel: true, showFilters: true, filtersMode: "summary" }}
onConfirm={({ problemNumbers, problems }) => {
console.log(problemNumbers, problems);
}}
style={{ width: "100%", height: 720, border: 0 }}
/>
);
}
<UvaProblemPicker
accessToken={shortLivedAccessToken}
onConfirm={({ problemNumbers }) => console.log(problemNumbers)}
/>
Set src only when using a self-hosted Explorer. The component transfers accessToken in the iframe fragment; UVa Explorer consumes and removes it immediately. Never expose the long-lived access key to browser code.
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 accessToken = undefined; // Fetch this from your application server.
const pickerSrc = accessToken
? `${pickerUrl}#token=${encodeURIComponent(accessToken)}`
: 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, showAiPanel: true, showFilters: true, filtersMode: "summary" }
}, 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