diff --git a/pagefind/features/ui/ui_base.feature b/pagefind/features/ui/ui_base.feature new file mode 100644 index 00000000..88ba40d3 --- /dev/null +++ b/pagefind/features/ui/ui_base.feature @@ -0,0 +1,26 @@ +Feature: Base UI Tests + Background: + Given I have the environment variables: + | PAGEFIND_SOURCE | public | + Given I have a "public/index.html" file with the body: + """ + + + + + """ + + Scenario: Pagefind UI loads + Given I have a "public/cat/index.html" file with the body: + """ +

world

+ """ + When I run my program + Then I should see "Running Pagefind" in stdout + Then I should see the file "public/_pagefind/pagefind.js" + When I serve the "public" directory + When I load "/" + Then There should be no logs + Then The selector ".pagefind-ui" should exist diff --git a/pagefind/tests/browser.rs b/pagefind/tests/browser.rs index ff6b2127..95bb9d32 100644 --- a/pagefind/tests/browser.rs +++ b/pagefind/tests/browser.rs @@ -83,6 +83,35 @@ impl BrowserTester { Ok(()) } + pub async fn selector_exists( + &mut self, + selector: &str, + ) -> Result<(), Box> { + let _ = self + .page + .as_mut() + .expect("No page launched") + .evaluate_function(format!( + " + async function() {{ + const time = Date.now(); + const timeout = 2000; + const selector = \"{}\"; + while (!document.querySelector(selector) && (Date.now() - time) < timeout) {{ + await new Promise(r => setTimeout(r, 50)); + }} + + if (!document.querySelector(selector)) {{ + throw new Error(`${{selector}} did not appear within ${{timeout}}ms`); + }} + }}", + selector + )) + .await?; + + Ok(()) + } + pub async fn contents(&mut self, selector: &str) -> Result> { let el = self .page diff --git a/pagefind/tests/steps/web_steps.rs b/pagefind/tests/steps/web_steps.rs index 6ba6eb3c..bd2dad0a 100644 --- a/pagefind/tests/steps/web_steps.rs +++ b/pagefind/tests/steps/web_steps.rs @@ -48,6 +48,12 @@ async fn eval_js(world: &mut TestWorld, step: &Step) { } } +#[then(regex = "^The selector (?:\"|')(.*)(?:\"|') should exist$")] +async fn selector_exists(world: &mut TestWorld, selector: String) { + let browser = world.ensure_browser().await; + browser.selector_exists(&selector).await; +} + #[then(regex = "^The selector (?:\"|')(.*)(?:\"|') should contain (?:\"|')(.*)(?:\"|')$")] async fn selector_contains(world: &mut TestWorld, selector: String, contents: String) { let browser = world.ensure_browser().await; diff --git a/pagefind_ui/svelte/ui.svelte b/pagefind_ui/svelte/ui.svelte index e578f9ef..0f9d002c 100644 --- a/pagefind_ui/svelte/ui.svelte +++ b/pagefind_ui/svelte/ui.svelte @@ -2,6 +2,7 @@ import Result from "./result.svelte"; export let base_path = "/_pagefind/"; + export let pagefind_options = {}; let val = ""; let pagefind; @@ -21,6 +22,7 @@ initializing = true; if (!pagefind) { pagefind = await import(`${base_path}pagefind.js`); + pagefind.options(pagefind_options || {}); } }; diff --git a/pagefind_ui/ui.js b/pagefind_ui/ui.js index 34a8564a..2e5a3c1d 100644 --- a/pagefind_ui/ui.js +++ b/pagefind_ui/ui.js @@ -1,18 +1,37 @@ -import PagefindUi from './svelte/ui.svelte'; +import Pagefind from './svelte/ui.svelte'; -(() => { - let base_path = "/_pagefind/"; - try { - base_path = new URL(document.currentScript.src).pathname.match(/^(.*\/)(?:pagefind-)?ui.js.*$/)[1]; - } catch (e) { - console.warn("Pagefind couldn't determine the base of the bundle from the import path. Falling back to the default."); - } +class PagefindUi { + constructor(opts) { + let selector = opts.element ?? "[data-pagefind-ui]"; + let bundlePath = opts.bundlePath; + + if (!bundlePath) { + try { + bundlePath = new URL(document.currentScript.src).pathname.match(/^(.*\/)(?:pagefind-)?ui.js.*$/)[1]; + } catch (e) { + bundlePath = "/_pagefind/"; + console.warn(`Pagefind couldn't determine the base of the bundle from the javascript import path. Falling back to the default of ${bundlePath}.`); + console.warn("You can configure this by passing a bundlePath option to PagefindUi"); + } + } - const dom = document.querySelector("[data-pagefind-ui]"); - new PagefindUi({ - target: dom, - props: { - base_path + // Remove the UI-specific config before passing it along to the Pagefind backend + delete opts["element"]; + delete opts["bundlePath"]; + + const dom = document.querySelector(selector); + if (dom) { + new Pagefind({ + target: dom, + props: { + base_path: bundlePath, + pagefind_options: opts, + } + }) + } else { + console.error(`Pagefind UI couldn't find the selector ${selector}`); } - }) -})(); + } +} + +window.PagefindUi = PagefindUi;