Compare commits

...

4 commits

Author SHA1 Message Date
1eaf37ee93 feat: pass optional arumgents to VV::include() (#69)
This PR makes `VV::include()` accept optional arguments that will be passed to the included PHP file.

Reviewed-on: https://codeberg.org/vegvisir/vegvisir/pulls/69
2025-05-20 16:41:29 +02:00
a1eea92db3 fix: perform bound soft-navigation of anchor tags on click event (#70)
Having soft-navigation bound on `mousedown` was nice and all for fun, but in practice it caused more problems than whatever the speed benefit would've been. Accessibility aside too...

Reviewed-on: https://codeberg.org/vegvisir/vegvisir/pulls/70
2025-05-20 16:41:13 +02:00
6c35a36fe6 feat: add cancelable VV navigation events (#68)
This PR makes it possible to cancel VV navigations with `Event.preventDefault()`.

```js
VV.shell.addEventListener(VV.EVENT.START, (event) => event.preventDefault());

// This navigation will not happen since it's canceled by the event listener above
new VV("/").navigate();
```

Reviewed-on: https://codeberg.org/vegvisir/vegvisir/pulls/68
2025-05-20 16:40:55 +02:00
vlw
05219a1294 doc(nit): update Vegvisir "slogan" in README (#67)
It's still pretty bad but as least is makes more sense now

Reviewed-on: https://codeberg.org/vegvisir/vegvisir/pulls/67
Co-authored-by: vlw <victor@vlw.se>
Co-committed-by: vlw <victor@vlw.se>
2025-05-20 16:40:23 +02:00
4 changed files with 20 additions and 31 deletions

View file

@ -2,7 +2,7 @@
<img width="100" src="https://href.vlw.se/vegvisir/logo">
</p>
<h1 align="center">Vegvisir</h1>
<p align="center">Vegvisir is a web navigation framework written in and for PHP and JavaScript hobbyists.</p>
<p align="center">Vegvisir is a PHP and JavaScript web navigation framework written as a hobby project.</p>
<p align="center"><a href="https://vegvisir.vlw.se/"><strong>Check out the Vegvisir website for more information</strong></a></p>
<h2 align="center">Key Features</h2>

View file

@ -175,18 +175,23 @@ globalThis.VV = class VV {
return this.target.setAttribute(ATTR_PAGE, pathname);
}
/**
* Disptach navigation events on targets and return true if no event was canceled
* @param {string} name
* @param {Request} request
* @returns {boolean}
*/
#dispatchEvent(name, request) {
const event = new CustomEvent(name, {
cancelable: true,
detail: {
VV: this,
request: request
}
});
// Dispatch event on current target
this.#target.dispatchEvent(event);
// Always dispatch events to document (catch-all)
document.dispatchEvent(event);
// Dispatch event on current target and the document (catch-all)
return this.#target.dispatchEvent(event) && document.dispatchEvent(event);
}
/**
@ -276,7 +281,11 @@ globalThis.VV = class VV {
destination = new Request(destination);
}
this.#dispatchEvent(VV.EVENT.START, destination);
// Bail out if navigation event was canceled
if (!this.#dispatchEvent(VV.EVENT.START, destination)) {
return false;
}
this.loading = true;
// Wait for global delay

View file

@ -32,28 +32,8 @@ const navigateAnchorElement = (element) => {
const bindElement = (element) => {
// Mark current element as bound
element.setAttribute(ATTR_ELEMENT_BOUND, true);
// This flag will be set to true if the "click" event's preventDefault() has been called
let defaultPrevented = false;
element.addEventListener("click", (event) => {
// Bail out and set defaultPrevented flag
if (event.defaultPrevented) {
return defaultPrevented = true;
}
event.preventDefault();
});
// Attach event listener for mousedown events
element.addEventListener("mousedown", (event) => {
// Bail out if preventDefault() has been called on this event or the defaultPrevented flag is set
if (defaultPrevented || event.defaultPrevented) {
return;
}
navigateAnchorElement(element);
});
// Bind event listener for click MouseEvents and perform a VV navigation if default was not prevented
element.addEventListener("click", (event) => !event.defaultPrevented && navigateAnchorElement(element));
};
// Bind selected elements to trigger a Vegvisir soft navigation on load

View file

@ -48,14 +48,14 @@
return self::is_file($pathname) ? file_get_contents($pathname) : "";
}
// Include a PHP file from absolute path or from root of user context
public static function include(string $path, bool $relative = true) {
// Include a PHP file from project_root with optional arguments passed by reference to included file
public static function include(string $path, mixed &...$args) {
$snapshot = new GlobalSnapshot();
// Destruct pathname and query from path
[$pathname, $query] = strpos($path, "?") ? explode("?", $path, 2) : [$path, null];
// Load PHP file relative from user context root
$pathname = $relative ? parent::root(Format::str_append_extension($pathname, ".php")) : Format::str_append_extension($pathname, ".php");
$pathname = parent::root(Format::str_append_extension($pathname, ".php"));
// Return an empty string if file is not found so exection can continue
if (!self::is_file($pathname)) {