The Browser object
The Browser
object can be used to control browser. Here are some use-cases:
- Showing modals, alerts, popups.
- Retrieving browser info, current URL.
- Accessing local storage, cookies.
- Navigation, routing.
#
Showing alert inside browserFirst, you'll need to modify initializeDraymanFramework
function inside public/index.html
. Add browser commands function and alert function as shown below:
...
<script> initializeDraymanFramework({ browserCommands: () => ({ alert: async ({ text }) => { alert(text); }, }), });</script>
...
Functions defined inside browserCommands
will be executed by your browser. In our example we have added alert
function which shows an alert inside browser when Drayman component asks to do so. And here is how Drayman component can do this:
export const component: DraymanComponent = async ({ Browser }) => { return () => { return ( <button onclick={async () => { await Browser.alert({ text: "Hello, world!" }); }} > Alert! </button> ); };};
We have exposed Browser
object and told Drayman to execute alert
function when user clicks a button.
#
Retrieving data from browserFunctions defined inside browserCommands
also can return some useful data:
...
<script> initializeDraymanFramework({ browserCommands: () => ({ getCurrentUrl: async () => { return window.location.href; }, }), });</script>
...
Now this function can be used inside Drayman component:
export const component: DraymanComponent = async ({ Browser }) => { const currentUrl = await Browser.getCurrentUrl();
return () => { return <h3>You are now here: {currentUrl}</h3>; };};
In result user will see something like this:
You are now here: http://localhost:3033/
#
Executing callbacksYou can also execute callbacks inside browserCommands
. This can be useful if you are creating some interactive views (modals) and you need to wait for some user interaction.
Let's modify our previous alert example:
...
<script> initializeDraymanFramework({ browserCommands: (emit) => ({ alert: async ({ text, onClose }) => { alert(text); emit(onClose, { text: "You have closed an alert!" }); }, }), });</script>
...
Pay attention on how emit
parameter of browserCommands
was introduced. It is used to tell Drayman to execute passed callbacks. In our case we are executing onClose
callback after alert
is executed. It also passes text
parameter. Now modify home.tsx
component:
export const component: DraymanComponent = async ({ Browser, forceUpdate }) => { let closed = false; let textFromBrowser = "";
return () => { return ( <> <button onclick={async () => { await Browser.alert({ text: "Hello, world!", onClose: async ({ text }) => { closed = true; textFromBrowser = text; await forceUpdate(); }, }); }} > Alert! </button> {closed && <h3>{textFromBrowser}</h3>} </> ); };};
Now when user clicks a button, an alert will be shown. After closing an alert, a text from passed text
parameter "You have closed an alert!" will be shown on page:
You have closed an alert!
tip
You can pass any JSON-serializable data to callbacks, for example, document.cookie
or some items from localStorage
.
#
Callback configuration optionsdebounce
#
Delays invoking callback until debounce
milliseconds have elapsed since the last time the debounced callback was invoked.
debounce
accepts number
(ms to delay).
This option is useful, for example, when viewport of the browser was resized and you need to execute callback only after user has stopped resizing it:
...
<script> initializeDraymanFramework({ browserCommands: (emit) => ({ events: async ({ onViewportChanged }) => { window.onresize = () => { emit( onViewportChanged, { width: window.innerWidth, height: window.innerHeight, }, { debounce: 500, } ); }; }, }), });</script>
...
export const component: DraymanComponent<any> = async ({ Browser, forceUpdate,}) => { let dimensions = ``;
Browser.events({ onViewportChanged: async (data) => { dimensions = `${data.width}x${data.height}`; await forceUpdate(); }, });
return () => { return <div>{dimensions}</div>; };};
In the example above, onViewportChanged
callback will be executed and text of window dimensions will be updated only after user has stopped resizing browser window for 500ms.
#
Referencing elementsSometimes UI interactivity like focusing elements, opening modals and drag-and-dropping is easier to implement on front-end side. In Drayman this can be done in three steps:
- Mark elements that need to be referenced with
ref
attribute and any unique name. - Define some browser command which will do something with referenced element. Element references will be passed as the second parameter of the browser command.
- Execute browser command function by passing an array of required element references.
Let's, for example, see how this can be done if we want to focus some element:
export const component: DraymanComponent = async ({ Browser }) => { return () => { return ( <> <input type="text" // set up reference ref="my-input" /> <button id="focus-btn" onclick={async () => { // execute Browser function with referenced element await Browser.focus(null, ["my-input"]); }} > Focus input </button> </> ); };};
...
<script> initializeDraymanFramework({ browserCommands: () => ({ // your elements will appear as the second parameter of Browser function focus: async (data, [element]) => { element.focus(); }, }), });</script>
...
#
Element referencing optionsWhen interacting with elements in a browser environment, especially within dynamic content, you can enhance control and flexibility by passing an object with specific options (wait
, ref
, customSelector
) instead of a simple string reference. This method allows for detailed configuration of how and when elements are targeted.
wait
option#
Use the wait
option to delay actions until the targeted element is available. This is crucial for content that loads dynamically, ensuring actions are performed only when the element exists.
Example: Waiting for an element before setting its text
export const component: DraymanComponent = async ({ Browser, forceUpdate, props,}) => { let renderTextElement = false;
setTimeout(async () => { renderTextElement = true; await forceUpdate(); }, 2000);
return () => { return ( <> <div id="error" ref="error"></div> {!!renderTextElement && <div id="text" ref="text"></div>} <button id="btn" onclick={async () => { await Browser.setText( { text: "Hello World!", }, [{ ref: "text", wait: true }, "error"] ); }} > Set text </button> </> ); };};
...
<script> initializeDraymanFramework({ browserCommands: () => ({ setText: async ({ text }, [element, errorElement]) => { try { element.innerText = text; } catch (err) { errorElement.innerText = err.message; } }, }), });</script>
...
ref
option#
The ref
option targets elements by their reference name within the component. It functions similarly to when you pass a reference name as a string.
customSelector
option#
The customSelector
option enables targeting using CSS selectors, offering flexibility for complex scenarios or when dealing with dynamically generated identifiers.
Example: Targeting an element with a custom CSS selector
export const component: DraymanComponent = async ({ Browser }) => { return () => { return ( <> <div id="text-id"></div> <button id="btn" onclick={async () => { await Browser.setText( { text: "Hello World!", }, [{ customSelector: "#text-id" }] ); }} > Set text </button> </> ); };};