return function () {
$self = url('/@object/@action/' . urlencode('htmx/redirect'));
// Where the button may send the browser: a fixed list, so the request can never choose a foreign URL (open redirect)
$targets = [
'here' => ['This demo again', $self . '?redirected=1'],
'install' => ['The Install page', url('/@object/install')],
'table' => ['The htmx table demo', url('/@object/@action/' . urlencode('htmx/table'))],
];
$htmx = _class('htmx');
// One URL, two answers (fragment or page): keep caches from mixing them up
header('Vary: HX-Request, HX-History-Restore-Request');
if ($htmx->_wants_fragment() && is_post()) {
$to = (is_string($_POST['to'] ?? null) ? $_POST['to'] : '');
if ( ! _class('csrf_guard')->check() || ! isset($targets[$to])) {
return $htmx->_result('<div class="alert alert-danger">Refused: unknown target or missing CSRF token.</div>');
}
// sends "HX-Redirect: <url>" and ends the request; htmx then loads that URL as a full page
return $htmx->_redirect($targets[$to][1]);
}
asset('htmx');
$intro = '<p class="docs-demo-intro">A server-driven redirect for htmx: an htmx request cannot follow a normal 302 with a full page
(htmx would swap the new page into the target), so the module answers with the <code>HX-Redirect</code> header from
<code>_class(\'htmx\')->_redirect($url)</code> and htmx navigates the whole window. The target comes from a fixed list, never from
the request. Other helpers: <code>_location()</code> (<code>HX-Location</code>, an htmx navigation without a reload) and
<code>_refresh()</code> (<code>HX-Refresh</code>). Classes: <code>yf_htmx</code>, <code>yf_csrf_guard</code>.</p>';
$done = isset($_GET['redirected']) ? '<div class="alert alert-success">You arrived here through <code>HX-Redirect</code>.</div>' : '';
$options = '';
foreach ($targets as $name => $info) {
$options .= '<option value="' . $name . '">' . _prepare_html($info[0], 0) . '</option>';
}
$headers = htmlspecialchars(json_encode(['X-CSRF-Token' => _class('csrf_guard')->session_token()]), ENT_QUOTES);
return $intro . $done
. '<form class="form-inline docs-demo-htmx-redirect" hx-post="' . $self . '" hx-target="#hx-redirect-result" hx-headers="' . $headers . '">'
. '<select name="to" class="form-control form-select">' . $options . '</select> '
. '<button type="submit" class="btn btn-primary">Go (HX-Redirect)</button> '
. '<button type="submit" name="to" value="evil" class="btn btn-default btn-outline-secondary">Try a target that is not on the list</button>'
. '</form><div id="hx-redirect-result" class="docs-demo-result-box"></div>';
};