From cc8514a335e24ab1b4be11d435cb8a867e1fe85c Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Fri, 20 Feb 2026 08:36:46 +0200 Subject: [PATCH 1/6] Improved the theming of the embedded JavaDoc --- .../assets/css/extended/cn1-javadoc-embed.css | 84 +++++++++---------- docs/website/assets/js/cn1-javadoc.js | 51 +++++++++-- 2 files changed, 86 insertions(+), 49 deletions(-) diff --git a/docs/website/assets/css/extended/cn1-javadoc-embed.css b/docs/website/assets/css/extended/cn1-javadoc-embed.css index 3f6f917093..c92f681842 100644 --- a/docs/website/assets/css/extended/cn1-javadoc-embed.css +++ b/docs/website/assets/css/extended/cn1-javadoc-embed.css @@ -16,35 +16,35 @@ padding: 0.7rem; background: var(--entry); color: var(--content); - --body-text-color: var(--content); - --block-text-color: var(--content); - --body-background-color: var(--entry); - --section-background-color: var(--entry); - --detail-background-color: var(--entry); + --body-text-color: var(--content) !important; + --block-text-color: var(--content) !important; + --body-background-color: var(--entry) !important; + --section-background-color: var(--entry) !important; + --detail-background-color: var(--entry) !important; --code-background-color: var(--code-bg); --pre-background-color: var(--code-bg); --pre-text-color: var(--content); --snippet-background-color: var(--code-bg); --snippet-text-color: var(--content); - --table-header-color: color-mix(in srgb, var(--entry) 70%, var(--theme) 30%); - --even-row-color: var(--entry); - --odd-row-color: color-mix(in srgb, var(--entry) 90%, var(--theme) 10%); - --border-color: var(--border); - --title-color: var(--primary); - --link-color: var(--primary); - --link-color-active: var(--primary); - --toc-background-color: var(--theme); - --toc-hover-color: color-mix(in srgb, var(--entry) 80%, var(--theme) 20%); - --toc-highlight-color: color-mix(in srgb, var(--entry) 70%, var(--theme) 30%); - --navbar-background-color: color-mix(in srgb, var(--entry) 70%, #1f4a75 30%); - --navbar-text-color: var(--primary); - --subnav-background-color: color-mix(in srgb, var(--entry) 78%, var(--theme) 22%); - --subnav-link-color: var(--primary); - --selected-background-color: color-mix(in srgb, var(--primary) 26%, var(--entry) 74%); - --selected-text-color: var(--content); - --search-input-background-color: var(--entry); - --search-input-text-color: var(--content); - --search-input-placeholder-color: var(--secondary); + --table-header-color: color-mix(in srgb, var(--entry) 70%, var(--theme) 30%) !important; + --even-row-color: var(--entry) !important; + --odd-row-color: color-mix(in srgb, var(--entry) 90%, var(--theme) 10%) !important; + --border-color: var(--border) !important; + --title-color: var(--primary) !important; + --link-color: var(--primary) !important; + --link-color-active: var(--primary) !important; + --toc-background-color: var(--theme) !important; + --toc-hover-color: color-mix(in srgb, var(--entry) 80%, var(--theme) 20%) !important; + --toc-highlight-color: color-mix(in srgb, var(--entry) 70%, var(--theme) 30%) !important; + --navbar-background-color: color-mix(in srgb, var(--entry) 70%, #1f4a75 30%) !important; + --navbar-text-color: var(--primary) !important; + --subnav-background-color: color-mix(in srgb, var(--entry) 78%, var(--theme) 22%) !important; + --subnav-link-color: var(--primary) !important; + --selected-background-color: color-mix(in srgb, var(--primary) 26%, var(--entry) 74%) !important; + --selected-text-color: var(--content) !important; + --search-input-background-color: var(--entry) !important; + --search-input-text-color: var(--content) !important; + --search-input-placeholder-color: var(--secondary) !important; } .cn1-javadoc .main-grid { @@ -57,22 +57,22 @@ body.dark .cn1-javadoc { background: var(--theme); - --body-background-color: var(--theme); - --section-background-color: var(--theme); - --detail-background-color: var(--theme); - --table-header-color: color-mix(in srgb, var(--theme) 70%, #1b2b40 30%); - --even-row-color: var(--theme); - --odd-row-color: color-mix(in srgb, var(--theme) 86%, #0d1726 14%); - --toc-background-color: #101a2a; - --toc-hover-color: #172439; - --toc-highlight-color: #1d2d45; - --navbar-background-color: #1b2d45; - --subnav-background-color: #152235; - --subnav-link-color: #cfe2ff; - --link-color: #b7d2ff; - --link-color-active: #d6e6ff; - --title-color: #e3edff; - --search-input-background-color: #111b2b; - --search-input-text-color: #e9eef7; - --search-input-placeholder-color: #8ea1bc; + --body-background-color: var(--theme) !important; + --section-background-color: var(--theme) !important; + --detail-background-color: var(--theme) !important; + --table-header-color: color-mix(in srgb, var(--theme) 70%, #1b2b40 30%) !important; + --even-row-color: var(--theme) !important; + --odd-row-color: color-mix(in srgb, var(--theme) 86%, #0d1726 14%) !important; + --toc-background-color: #101a2a !important; + --toc-hover-color: #172439 !important; + --toc-highlight-color: #1d2d45 !important; + --navbar-background-color: #1b2d45 !important; + --subnav-background-color: #152235 !important; + --subnav-link-color: #cfe2ff !important; + --link-color: #b7d2ff !important; + --link-color-active: #d6e6ff !important; + --title-color: #e3edff !important; + --search-input-background-color: #111b2b !important; + --search-input-text-color: #e9eef7 !important; + --search-input-placeholder-color: #8ea1bc !important; } diff --git a/docs/website/assets/js/cn1-javadoc.js b/docs/website/assets/js/cn1-javadoc.js index 99b92f7b67..d593105177 100644 --- a/docs/website/assets/js/cn1-javadoc.js +++ b/docs/website/assets/js/cn1-javadoc.js @@ -2,6 +2,37 @@ const root = document.querySelector(".cn1-javadoc"); if (!root) return; + if (window.location.pathname === "/javadoc") { + window.history.replaceState(null, "", "/javadoc/"); + } + + let currentDocPath = "/javadoc/_index-raw.html"; + let searchAssetsLoaded = false; + + const ensureSearchAssets = (fetchPath) => { + window.pathtoroot = calcPathToRoot(fetchPath); + if (!searchAssetsLoaded && typeof window.loadScripts === "function") { + window.loadScripts(document, "script"); + searchAssetsLoaded = true; + } + }; + + const resolveHref = (rawHref) => { + if (!rawHref) return null; + if (rawHref.startsWith("http://") || rawHref.startsWith("https://") || rawHref.startsWith("//")) { + return rawHref; + } + if (rawHref.startsWith("/")) { + return `${window.location.origin}${rawHref}`; + } + const base = `${window.location.origin}${currentDocPath}`; + try { + return new URL(rawHref, base).toString(); + } catch (_e) { + return null; + } + }; + const toRoute = (href) => { let url; try { @@ -11,8 +42,11 @@ } if (url.origin !== window.location.origin) return null; if (!url.pathname.startsWith("/javadoc")) return null; + if (url.pathname === "/javadoc" || url.pathname === "/javadoc/") { + return { fetchPath: "/javadoc/_index-raw.html", browserPath: "/javadoc/" }; + } if (!url.pathname.endsWith(".html")) return null; - return url.pathname === "/javadoc/index.html" + return (url.pathname === "/javadoc/index.html" || url.pathname === "/javadoc/_index-raw.html") ? { fetchPath: "/javadoc/_index-raw.html", browserPath: "/javadoc/" } : { fetchPath: url.pathname, browserPath: url.pathname }; }; @@ -30,10 +64,8 @@ const doc = new DOMParser().parseFromString(html, "text/html"); if (!doc.body) return; root.innerHTML = doc.body.innerHTML; - window.pathtoroot = calcPathToRoot(route.fetchPath); - if (typeof window.loadScripts === "function") { - window.loadScripts(document, "script"); - } + currentDocPath = route.fetchPath; + ensureSearchAssets(route.fetchPath); if (pushState) { window.history.pushState({ cn1Javadoc: route.browserPath }, "", route.browserPath); } @@ -43,8 +75,11 @@ root.addEventListener("click", (event) => { const link = event.target.closest("a[href]"); if (!link || link.target || link.hasAttribute("download")) return; - if (link.getAttribute("href").startsWith("#")) return; - const route = toRoute(link.href); + const rawHref = link.getAttribute("href"); + if (!rawHref || rawHref.startsWith("#")) return; + const resolved = resolveHref(rawHref); + if (!resolved) return; + const route = toRoute(resolved); if (!route) return; event.preventDefault(); loadIntoContainer(route, true).catch(() => {}); @@ -55,4 +90,6 @@ if (!route) return; loadIntoContainer(route, false).catch(() => {}); }); + + ensureSearchAssets(currentDocPath); })(); From eb846af0beb285e709aa0ff09582e08429e0ebf6 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Fri, 20 Feb 2026 09:33:08 +0200 Subject: [PATCH 2/6] Added website preview and fixed build issues --- .github/workflows/website-docs.yml | 111 ++++++++++++++++++++++++++++- docs/website/.lycheeignore | 25 +++++++ scripts/website/build.sh | 14 +++- 3 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 docs/website/.lycheeignore diff --git a/.github/workflows/website-docs.yml b/.github/workflows/website-docs.yml index 99c75af9ae..bf02797727 100644 --- a/.github/workflows/website-docs.yml +++ b/.github/workflows/website-docs.yml @@ -24,6 +24,8 @@ jobs: env: CLOUDFLARE_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN || secrets.CF_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID || secrets.CF_ACCOUNT_ID }} + CF_PAGES_PROJECT_NAME: ${{ vars.CLOUDFLARE_PAGES_PROJECT_NAME || secrets.CLOUDFLARE_PAGES_PROJECT_NAME || secrets.CF_PAGES_PROJECT_NAME || 'codenameone' }} + CF_PAGES_PRODUCTION_BRANCH: ${{ vars.CLOUDFLARE_PAGES_PRODUCTION_BRANCH || secrets.CLOUDFLARE_PAGES_PRODUCTION_BRANCH || 'main' }} steps: - name: Check out repository uses: actions/checkout@v4 @@ -141,10 +143,13 @@ jobs: - name: Validate internal links and images uses: lycheeverse/lychee-action@v2 with: + lycheeVersion: latest + workingDirectory: docs/website args: >- --offline --no-progress - docs/website/public/**/*.html + --root-dir public + public/**/*.html - name: Reject absolute codenameone.com links run: | @@ -196,6 +201,106 @@ jobs: path: docs/website/public if-no-files-found: error + - name: Check Cloudflare preview deploy credentials + if: ${{ github.event_name == 'pull_request' && env.CLOUDFLARE_TOKEN == '' }} + run: | + echo "::warning::Skipping Cloudflare Pages preview deploy because no API token secret is configured. Set CLOUDFLARE_TOKEN (preferred) or CF_API_TOKEN." + + - name: Deploy PR preview to Cloudflare Pages + id: cf_preview + if: ${{ github.event_name == 'pull_request' && env.CLOUDFLARE_TOKEN != '' }} + env: + CLOUDFLARE_API_TOKEN: ${{ env.CLOUDFLARE_TOKEN }} + PREVIEW_BRANCH: pr-${{ github.event.pull_request.number }}-website-preview + run: | + set -euo pipefail + deploy_output="$(npx --yes wrangler@4 pages deploy docs/website/public \ + --project-name "${CF_PAGES_PROJECT_NAME}" \ + --branch "${PREVIEW_BRANCH}" 2>&1)" + echo "${deploy_output}" + preview_url="$(printf '%s\n' "${deploy_output}" | grep -Eo 'https://[A-Za-z0-9._-]+\.pages\.dev' | tail -n1 || true)" + if [ -z "${preview_url}" ]; then + echo "Could not determine Cloudflare preview URL from deploy output." >&2 + exit 1 + fi + echo "preview_url=${preview_url}" >> "${GITHUB_OUTPUT}" + echo "preview_branch=${PREVIEW_BRANCH}" >> "${GITHUB_OUTPUT}" + + - name: Publish Cloudflare preview link in CI summary + if: ${{ steps.cf_preview.outputs.preview_url != '' }} + run: | + { + echo "## Cloudflare Preview" + echo + echo "- URL: ${{ steps.cf_preview.outputs.preview_url }}" + echo "- Branch: \`${{ steps.cf_preview.outputs.preview_branch }}\`" + } >> "${GITHUB_STEP_SUMMARY}" + + - name: Prune older Cloudflare preview deployments for this PR branch + if: ${{ steps.cf_preview.outputs.preview_url != '' }} + env: + CLOUDFLARE_API_TOKEN: ${{ env.CLOUDFLARE_TOKEN }} + PREVIEW_BRANCH: ${{ steps.cf_preview.outputs.preview_branch }} + PREVIEW_URL: ${{ steps.cf_preview.outputs.preview_url }} + run: | + set -euo pipefail + api_base="https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/pages/projects/${CF_PAGES_PROJECT_NAME}/deployments" + tmp_json="$(mktemp)" + curl -sS \ + -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \ + -H "Content-Type: application/json" \ + "${api_base}" > "${tmp_json}" + + cat > /tmp/cf_preview_cleanup.py <<'PY' + import json + import sys + + path, preview_branch, preview_url = sys.argv[1:] + data = json.load(open(path, encoding="utf-8")) + result = data.get("result", []) or [] + + def aliases_of(dep): + aliases = dep.get("aliases") or [] + out = [] + for a in aliases: + if isinstance(a, str): + out.append(a) + elif isinstance(a, dict): + v = a.get("url") + if isinstance(v, str): + out.append(v) + return out + + def branch_of(dep): + trig = dep.get("deployment_trigger") or {} + meta = trig.get("metadata") or {} + return meta.get("branch") + + current_id = None + for dep in result: + if preview_url in aliases_of(dep): + current_id = dep.get("id") + break + + for dep in result: + dep_id = dep.get("id") + if not dep_id or dep_id == current_id: + continue + if branch_of(dep) == preview_branch: + print(dep_id) + PY + + python3 /tmp/cf_preview_cleanup.py "${tmp_json}" "${PREVIEW_BRANCH}" "${PREVIEW_URL}" > /tmp/cf_deployments_to_delete.txt + + while IFS= read -r dep_id; do + [ -z "${dep_id}" ] && continue + echo "Deleting old preview deployment: ${dep_id}" + curl -sS -X DELETE \ + -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \ + -H "Content-Type: application/json" \ + "${api_base}/${dep_id}" >/dev/null + done < /tmp/cf_deployments_to_delete.txt + - name: Check Cloudflare deploy credentials if: ${{ github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master') && env.CLOUDFLARE_TOKEN == '' }} run: | @@ -214,5 +319,5 @@ jobs: accountId: ${{ env.CLOUDFLARE_ACCOUNT_ID }} command: >- pages deploy docs/website/public - --project-name=${{ vars.CLOUDFLARE_PAGES_PROJECT_NAME || secrets.CLOUDFLARE_PAGES_PROJECT_NAME || secrets.CF_PAGES_PROJECT_NAME || 'codenameone' }} - --branch=${{ vars.CLOUDFLARE_PAGES_PRODUCTION_BRANCH || secrets.CLOUDFLARE_PAGES_PRODUCTION_BRANCH || 'main' }} + --project-name=${{ env.CF_PAGES_PROJECT_NAME }} + --branch=${{ env.CF_PAGES_PRODUCTION_BRANCH }} diff --git a/docs/website/.lycheeignore b/docs/website/.lycheeignore new file mode 100644 index 0000000000..747022332c --- /dev/null +++ b/docs/website/.lycheeignore @@ -0,0 +1,25 @@ +# Legacy HTML aliases handled via Cloudflare _redirects (not local files in offline mode) +^file://.*/public/demos\.html$ +^file://.*/public/gallery\.html$ +^file://.*/public/monetization\.html$ +^file://.*/public/tutorials-resources-learn-java-mobile-videos-courses-ios-android\.html$ + +# Legacy demo slug links that resolve via redirects in production +^file://.*/public/demo-[^/]+/?$ + +# Legacy direct .html links are redirect-backed in production but absent as local files. +^file://.*/public/.*\.html(#.*)?$ + +# Redirect-backed docs aliases +^file://.*/public/(manual|downloads?|build-server)(/.*)?(#.*)?$ +^file://.*/public/developer-guide/(Fonts|Images|Supported-Properties)(#.*)?$ +^file://.*/public/introduction/how-do-i/how-do-i-access-native-device-functionality-invoke-native-interfaces/?$ + +# Demo binary/app folders are redirect/external targets, not local static artifacts. +^file://.*/public/demos/[A-Za-z0-9_-]+(/.*)?$ + +# Redirect-only PDF route (target is generated in _redirects) +^file://.*/public/files/developer-guide\.pdf$ + +# Other externalized file assets that are linked but not present in local static output +^file://.*/public/files/.*\.(pdf|xlsx)$ diff --git a/scripts/website/build.sh b/scripts/website/build.sh index d4fe2ab0ad..359367145f 100755 --- a/scripts/website/build.sh +++ b/scripts/website/build.sh @@ -208,7 +208,19 @@ def process(css): return "".join(out) with open(out_path, "w", encoding="utf-8") as f: - f.write(process(src)) + scoped = process(src) + # Inline scoped stylesheet is injected on /javadoc/ pages, so make asset refs absolute. + # This keeps icons/fonts resolvable from both /javadoc/ and deep class pages loaded in-page. + import re + def repl(m): + raw = m.group(1).strip().strip('"\'') + if (raw.startswith("data:") or raw.startswith("http://") or raw.startswith("https://") + or raw.startswith("/") or raw.startswith("#")): + return f"url({m.group(1)})" + normalized = raw.lstrip("./") + return f"url('/javadoc/resource-files/{normalized}')" + scoped = re.sub(r"url\(([^)]+)\)", repl, scoped) + f.write(scoped) PY fi } From 37c7dd30f9bb4107e11f4ccb0ceef6d1598c49b4 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Fri, 20 Feb 2026 10:35:26 +0200 Subject: [PATCH 3/6] Additional refinement to JavaDoc dark theme support --- .github/workflows/website-docs.yml | 47 ++++++++++++++++++- .../assets/css/extended/cn1-javadoc-embed.css | 45 +++++++++++++++++- docs/website/assets/js/cn1-javadoc.js | 14 ++++++ 3 files changed, 103 insertions(+), 3 deletions(-) diff --git a/.github/workflows/website-docs.yml b/.github/workflows/website-docs.yml index bf02797727..f79b69b4d1 100644 --- a/.github/workflows/website-docs.yml +++ b/.github/workflows/website-docs.yml @@ -17,6 +17,7 @@ on: permissions: contents: read + pull-requests: write jobs: build: @@ -24,8 +25,8 @@ jobs: env: CLOUDFLARE_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN || secrets.CF_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID || secrets.CF_ACCOUNT_ID }} - CF_PAGES_PROJECT_NAME: ${{ vars.CLOUDFLARE_PAGES_PROJECT_NAME || secrets.CLOUDFLARE_PAGES_PROJECT_NAME || secrets.CF_PAGES_PROJECT_NAME || 'codenameone' }} - CF_PAGES_PRODUCTION_BRANCH: ${{ vars.CLOUDFLARE_PAGES_PRODUCTION_BRANCH || secrets.CLOUDFLARE_PAGES_PRODUCTION_BRANCH || 'main' }} + CF_PAGES_PROJECT_NAME: ${{ vars.CLOUDFLARE_PAGES_PROJECT_NAME || 'codenameone' }} + CF_PAGES_PRODUCTION_BRANCH: ${{ vars.CLOUDFLARE_PAGES_PRODUCTION_BRANCH || 'main' }} steps: - name: Check out repository uses: actions/checkout@v4 @@ -236,6 +237,48 @@ jobs: echo "- Branch: \`${{ steps.cf_preview.outputs.preview_branch }}\`" } >> "${GITHUB_STEP_SUMMARY}" + - name: Comment Cloudflare preview link on PR + if: ${{ github.event_name == 'pull_request' && steps.cf_preview.outputs.preview_url != '' }} + uses: actions/github-script@v7 + with: + script: | + const marker = ''; + const body = [ + marker, + '## Cloudflare Preview', + '', + `- URL: ${{ steps.cf_preview.outputs.preview_url }}`, + `- Branch: \`${{ steps.cf_preview.outputs.preview_branch }}\``, + ].join('\n'); + + const { owner, repo } = context.repo; + const issue_number = context.issue.number; + const comments = await github.paginate(github.rest.issues.listComments, { + owner, + repo, + issue_number, + per_page: 100, + }); + const existing = comments.find((comment) => + comment.user?.type === 'Bot' && comment.body?.includes(marker) + ); + + if (existing) { + await github.rest.issues.updateComment({ + owner, + repo, + comment_id: existing.id, + body, + }); + } else { + await github.rest.issues.createComment({ + owner, + repo, + issue_number, + body, + }); + } + - name: Prune older Cloudflare preview deployments for this PR branch if: ${{ steps.cf_preview.outputs.preview_url != '' }} env: diff --git a/docs/website/assets/css/extended/cn1-javadoc-embed.css b/docs/website/assets/css/extended/cn1-javadoc-embed.css index c92f681842..5361ec5494 100644 --- a/docs/website/assets/css/extended/cn1-javadoc-embed.css +++ b/docs/website/assets/css/extended/cn1-javadoc-embed.css @@ -1,5 +1,6 @@ .post-single--api-javadoc { - max-width: min(1700px, 98vw); + max-width: min(2200px, 99vw); + width: 100%; } .cn1-javadoc-links { @@ -16,6 +17,8 @@ padding: 0.7rem; background: var(--entry); color: var(--content); + overflow: visible; + --code-bg: color-mix(in srgb, var(--entry) 90%, var(--theme) 10%); --body-text-color: var(--content) !important; --block-text-color: var(--content) !important; --body-background-color: var(--entry) !important; @@ -51,12 +54,52 @@ margin: 0; } +.cn1-javadoc .header, +.cn1-javadoc .sub-nav, +.cn1-javadoc .top-nav, +.cn1-javadoc .flex-content { + overflow: visible !important; +} + +.cn1-javadoc .table-header, +.cn1-javadoc .table-sub-heading-color, +.cn1-javadoc .summary-table div[class^="col-"], +.cn1-javadoc .summary-table div[class*=" col-"] { + min-height: 2.25rem; + height: auto !important; + line-height: 1.35 !important; + padding-top: 0.4rem !important; + padding-bottom: 0.4rem !important; + overflow: visible !important; +} + +.cn1-javadoc input[type="search"], +.cn1-javadoc input#search-input, +.cn1-javadoc #search-input, +.cn1-javadoc .search-input { + pointer-events: auto !important; + position: relative; + z-index: 30; +} + +.cn1-javadoc pre, +.cn1-javadoc code, +.cn1-javadoc pre code, +.cn1-javadoc .snippet-container, +.cn1-javadoc .snippet-container pre, +.cn1-javadoc .block pre, +.cn1-javadoc .block code { + background: var(--code-bg) !important; + color: var(--content) !important; +} + .cn1-javadoc a { color: var(--primary); } body.dark .cn1-javadoc { background: var(--theme); + --code-bg: #141f31; --body-background-color: var(--theme) !important; --section-background-color: var(--theme) !important; --detail-background-color: var(--theme) !important; diff --git a/docs/website/assets/js/cn1-javadoc.js b/docs/website/assets/js/cn1-javadoc.js index d593105177..836ba074db 100644 --- a/docs/website/assets/js/cn1-javadoc.js +++ b/docs/website/assets/js/cn1-javadoc.js @@ -9,12 +9,25 @@ let currentDocPath = "/javadoc/_index-raw.html"; let searchAssetsLoaded = false; + const reviveSearchUi = () => { + const inputs = root.querySelectorAll('input[type="search"], input#search-input, #search-input'); + inputs.forEach((input) => { + input.removeAttribute("disabled"); + input.readOnly = false; + input.tabIndex = 0; + input.style.pointerEvents = "auto"; + input.style.position = "relative"; + input.style.zIndex = "30"; + }); + }; + const ensureSearchAssets = (fetchPath) => { window.pathtoroot = calcPathToRoot(fetchPath); if (!searchAssetsLoaded && typeof window.loadScripts === "function") { window.loadScripts(document, "script"); searchAssetsLoaded = true; } + reviveSearchUi(); }; const resolveHref = (rawHref) => { @@ -66,6 +79,7 @@ root.innerHTML = doc.body.innerHTML; currentDocPath = route.fetchPath; ensureSearchAssets(route.fetchPath); + reviveSearchUi(); if (pushState) { window.history.pushState({ cn1Javadoc: route.browserPath }, "", route.browserPath); } From 5d6a8ebf31049d46f007f2a063cff856d619083f Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Fri, 20 Feb 2026 10:48:11 +0200 Subject: [PATCH 4/6] Additional fixes for javadoc search --- .../assets/css/extended/cn1-javadoc-embed.css | 14 ++++++++++++-- docs/website/assets/js/cn1-javadoc.js | 5 ----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/website/assets/css/extended/cn1-javadoc-embed.css b/docs/website/assets/css/extended/cn1-javadoc-embed.css index 5361ec5494..bbc3139497 100644 --- a/docs/website/assets/css/extended/cn1-javadoc-embed.css +++ b/docs/website/assets/css/extended/cn1-javadoc-embed.css @@ -1,6 +1,16 @@ +.main:has(.post-single--api-javadoc) { + max-width: 100vw; + width: 100vw; + padding-left: 0; + padding-right: 0; +} + .post-single--api-javadoc { - max-width: min(2200px, 99vw); + max-width: 100vw; width: 100%; + margin: 0; + padding-left: 0; + padding-right: 0; } .cn1-javadoc-links { @@ -13,7 +23,7 @@ .cn1-javadoc { border: 1px solid var(--border); - border-radius: 12px; + border-radius: 0; padding: 0.7rem; background: var(--entry); color: var(--content); diff --git a/docs/website/assets/js/cn1-javadoc.js b/docs/website/assets/js/cn1-javadoc.js index 836ba074db..be4d894486 100644 --- a/docs/website/assets/js/cn1-javadoc.js +++ b/docs/website/assets/js/cn1-javadoc.js @@ -7,7 +7,6 @@ } let currentDocPath = "/javadoc/_index-raw.html"; - let searchAssetsLoaded = false; const reviveSearchUi = () => { const inputs = root.querySelectorAll('input[type="search"], input#search-input, #search-input'); @@ -23,10 +22,6 @@ const ensureSearchAssets = (fetchPath) => { window.pathtoroot = calcPathToRoot(fetchPath); - if (!searchAssetsLoaded && typeof window.loadScripts === "function") { - window.loadScripts(document, "script"); - searchAssetsLoaded = true; - } reviveSearchUi(); }; From d5c008dac6df6bd92f30ec9c5d116bb164581f25 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Fri, 20 Feb 2026 11:09:10 +0200 Subject: [PATCH 5/6] Improvements to JavaDoc layout and search --- .../assets/css/extended/cn1-javadoc-embed.css | 34 +++++++++++++++++-- docs/website/assets/js/cn1-javadoc.js | 22 ++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/docs/website/assets/css/extended/cn1-javadoc-embed.css b/docs/website/assets/css/extended/cn1-javadoc-embed.css index bbc3139497..555bd541a8 100644 --- a/docs/website/assets/css/extended/cn1-javadoc-embed.css +++ b/docs/website/assets/css/extended/cn1-javadoc-embed.css @@ -1,6 +1,7 @@ -.main:has(.post-single--api-javadoc) { +.cn1-javadoc-page .main { max-width: 100vw; width: 100vw; + margin: 0; padding-left: 0; padding-right: 0; } @@ -61,13 +62,19 @@ } .cn1-javadoc .main-grid { + width: 100% !important; + max-width: none !important; margin: 0; } .cn1-javadoc .header, .cn1-javadoc .sub-nav, .cn1-javadoc .top-nav, -.cn1-javadoc .flex-content { +.cn1-javadoc .flex-content, +.cn1-javadoc .main-content, +.cn1-javadoc .contentContainer { + width: 100% !important; + max-width: none !important; overflow: visible !important; } @@ -92,6 +99,29 @@ z-index: 30; } +.cn1-javadoc-page .ui-autocomplete, +.cn1-javadoc-page .ui-menu { + background: var(--entry) !important; + color: var(--content) !important; + border: 1px solid var(--border) !important; + box-shadow: 0 10px 24px rgba(0, 0, 0, 0.28) !important; + opacity: 1 !important; + max-width: min(92vw, 48rem) !important; + overflow: auto !important; + z-index: 2000 !important; +} + +.cn1-javadoc-page .ui-menu .ui-menu-item-wrapper { + color: var(--content) !important; +} + +.cn1-javadoc-page .ui-menu .ui-state-active, +.cn1-javadoc-page .ui-menu .ui-menu-item-wrapper.ui-state-active { + background: color-mix(in srgb, var(--primary) 22%, var(--entry) 78%) !important; + border-color: var(--border) !important; + color: var(--content) !important; +} + .cn1-javadoc pre, .cn1-javadoc code, .cn1-javadoc pre code, diff --git a/docs/website/assets/js/cn1-javadoc.js b/docs/website/assets/js/cn1-javadoc.js index be4d894486..1d2be2d703 100644 --- a/docs/website/assets/js/cn1-javadoc.js +++ b/docs/website/assets/js/cn1-javadoc.js @@ -1,6 +1,7 @@ (() => { const root = document.querySelector(".cn1-javadoc"); if (!root) return; + document.body.classList.add("cn1-javadoc-page"); if (window.location.pathname === "/javadoc") { window.history.replaceState(null, "", "/javadoc/"); @@ -18,6 +19,24 @@ input.style.position = "relative"; input.style.zIndex = "30"; }); + clampSearchPopup(); + }; + + const clampSearchPopup = () => { + document.querySelectorAll(".ui-autocomplete").forEach((menu) => { + menu.style.maxWidth = "min(92vw, 48rem)"; + menu.style.background = "var(--entry)"; + menu.style.color = "var(--content)"; + menu.style.border = "1px solid var(--border)"; + menu.style.boxShadow = "0 10px 24px rgba(0, 0, 0, 0.28)"; + menu.style.opacity = "1"; + menu.style.transform = "translateX(0)"; + const rect = menu.getBoundingClientRect(); + let dx = 0; + if (rect.right > window.innerWidth - 8) dx = (window.innerWidth - 8) - rect.right; + if (rect.left < 8) dx = 8 - rect.left; + if (dx !== 0) menu.style.transform = `translateX(${dx}px)`; + }); }; const ensureSearchAssets = (fetchPath) => { @@ -99,6 +118,9 @@ if (!route) return; loadIntoContainer(route, false).catch(() => {}); }); + window.addEventListener("resize", clampSearchPopup); + root.addEventListener("input", clampSearchPopup, true); + root.addEventListener("focusin", clampSearchPopup, true); ensureSearchAssets(currentDocPath); })(); From 9e654d87ffe3bf87bd1f4dcfe42a1a621afdafaa Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Fri, 20 Feb 2026 11:49:58 +0200 Subject: [PATCH 6/6] Improved search and width of embedded docs --- .../assets/css/extended/cn1-javadoc-embed.css | 8 ++++++++ docs/website/assets/js/cn1-javadoc.js | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/docs/website/assets/css/extended/cn1-javadoc-embed.css b/docs/website/assets/css/extended/cn1-javadoc-embed.css index 555bd541a8..887b2c51f3 100644 --- a/docs/website/assets/css/extended/cn1-javadoc-embed.css +++ b/docs/website/assets/css/extended/cn1-javadoc-embed.css @@ -6,6 +6,14 @@ padding-right: 0; } +body.cn1-javadoc-page .main:has(> .post-single--api-javadoc) { + max-width: 100vw !important; + width: 100vw !important; + margin: 0 !important; + padding-left: 0 !important; + padding-right: 0 !important; +} + .post-single--api-javadoc { max-width: 100vw; width: 100%; diff --git a/docs/website/assets/js/cn1-javadoc.js b/docs/website/assets/js/cn1-javadoc.js index 1d2be2d703..32f1511f43 100644 --- a/docs/website/assets/js/cn1-javadoc.js +++ b/docs/website/assets/js/cn1-javadoc.js @@ -113,6 +113,19 @@ loadIntoContainer(route, true).catch(() => {}); }); + document.addEventListener("click", (event) => { + const link = event.target.closest(".ui-autocomplete a[href], .ui-menu a[href]"); + if (!link || link.target || link.hasAttribute("download")) return; + const rawHref = link.getAttribute("href"); + if (!rawHref || rawHref.startsWith("#")) return; + const resolved = resolveHref(rawHref); + if (!resolved) return; + const route = toRoute(resolved); + if (!route) return; + event.preventDefault(); + loadIntoContainer(route, true).catch(() => {}); + }, true); + window.addEventListener("popstate", () => { const route = toRoute(window.location.href); if (!route) return;