Skip to content

Commit

Permalink
tec: Change how modals are rendered
Browse files Browse the repository at this point in the history
Turbo 7.2 introduces the event `turbo:frame-missing` if the response
doesn't contain a matching frame. If this event is fired, Turbo will
perform a full-page navigation.

This allows to simplify a common use-case with forms in modals:

- the form is rendered with a `<turbo-frame id="modal-content">` and is
  loaded in the modal
- when the submitted form is successful, the controller returns a
  response _without_ any turbo-frame with id `modal-content` (and so
  Turbo follows the redirection)
- when the submitted form contains error, the controller returns the
  form with errors in a turbo-frame with id `modal-content` (and so
  Turbo loads its content in the modal)

Before that, I had to use a pretty complicated hack based on Turbo
Stream which rendered the forms conditionnaly with the normal layout
(e.g. `feeds/new.phtml`) or in a `<turbo-stream>` element (e.g.
`feeds/new.turbo_stream.phtml`). Now, the expected behaviour comes for
free, I just have to declare a view to be available for modals :).

Reference: hotwired/turbo#445
Revert commit: 7045806
  • Loading branch information
marienfressinaud committed Oct 7, 2022
1 parent 2d08f05 commit fcabfbe
Show file tree
Hide file tree
Showing 33 changed files with 365 additions and 448 deletions.
3 changes: 1 addition & 2 deletions src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ public function __construct()

\Minz\Output\View::$extensions_to_content_types['.atom.xml.php'] = 'application/xml';
\Minz\Output\View::$extensions_to_content_types['.opml.xml.php'] = 'text/x-opml';
\Minz\Output\View::$extensions_to_content_types['.turbo_stream.phtml'] = 'text/vnd.turbo-stream.html';
\Minz\Output\View::$extensions_to_content_types['.xsl.php'] = 'application/xslt+xml';
}

Expand Down Expand Up @@ -133,7 +132,7 @@ public function run($request)
'autoload_modal_url' => $autoload_modal_url,
'now' => \Minz\Time::now(),
'javascript_configuration' => json_encode(include('utils/javascript_configuration.php')),
'turbo_frame' => $request->header('HTTP_TURBO_FRAME'),
'modal_requested' => $request->header('HTTP_TURBO_FRAME') === 'modal-content',
'demo' => $app_conf['demo'],
'registrations_opened' => $app_conf['registrations_opened'],
]);
Expand Down
5 changes: 5 additions & 0 deletions src/assets/javascripts/controllers/modal_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ export default class extends Controller {
}

connect () {
// Set the id of the content turbo-frame. It must not be set directly
// in the HTML, or Turbo will try to load its content when a form in
// the modal redirects to a new page (instead of showing the full HTML).
this.contentTarget.setAttribute('id', 'modal-content');

this.element.addEventListener('open-modal', this.open.bind(this));

// handle modal shortcuts
Expand Down
16 changes: 3 additions & 13 deletions src/controllers/Feeds.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,18 +99,8 @@ public function create($request)
return Response::redirect('login', ['redirect_to' => $from]);
}

if ($request->isAccepting('text/vnd.turbo-stream.html')) {
// This allows to display the errors within the modal instead of
// sending a whole new page. This is a bit hacky so I'm going
// to use this method only where absolutely needed.
// @see https://github.com/hotwired/turbo/issues/138#issuecomment-847699281
$view_file = 'feeds/new.turbo_stream.phtml';
} else {
$view_file = 'feeds/new.phtml';
}

if (!\Minz\CSRF::validate($csrf)) {
return Response::badRequest($view_file, [
return Response::badRequest('feeds/new.phtml', [
'url' => $url,
'from' => $from,
'error' => _('A security verification failed: you should retry to submit the form.'),
Expand All @@ -127,7 +117,7 @@ public function create($request)

$errors = $default_link->validate();
if ($errors) {
return Response::badRequest($view_file, [
return Response::badRequest('feeds/new.phtml', [
'url' => $url,
'from' => $from,
'errors' => $errors,
Expand All @@ -142,7 +132,7 @@ public function create($request)

$feed_urls = $default_link->feedUrls();
if (count($feed_urls) === 0) {
return Response::badRequest($view_file, [
return Response::badRequest('feeds/new.phtml', [
'url' => $url,
'from' => $from,
'errors' => [
Expand Down
36 changes: 8 additions & 28 deletions src/controllers/collections/Shares.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,6 @@ public function create($request)
]);
}

if ($request->isAccepting('text/vnd.turbo-stream.html')) {
// This allows to display the errors within the modal instead of
// sending a whole new page. This is a bit hacky so I'm going
// to use this method only where absolutely needed.
// @see https://github.com/hotwired/turbo/issues/138#issuecomment-847699281
$view_file = 'collections/shares/index.turbo_stream.phtml';
} else {
$view_file = 'collections/shares/index.phtml';
}

$collection_id = $request->param('id');
$user_id = $request->param('user_id');
$type = $request->param('type');
Expand All @@ -99,7 +89,7 @@ public function create($request)
}

if (!\Minz\CSRF::validate($csrf)) {
return Response::badRequest($view_file, [
return Response::badRequest('collections/shares/index.phtml', [
'collection' => $collection,
'from' => $from,
'type' => $type,
Expand All @@ -109,7 +99,7 @@ public function create($request)
}

if ($current_user->id === $user_id) {
return Response::badRequest($view_file, [
return Response::badRequest('collections/shares/index.phtml', [
'collection' => $collection,
'from' => $from,
'type' => $type,
Expand All @@ -125,7 +115,7 @@ public function create($request)
!models\User::exists($user_id) ||
$support_user->id === $user_id
) {
return Response::badRequest($view_file, [
return Response::badRequest('collections/shares/index.phtml', [
'collection' => $collection,
'from' => $from,
'type' => $type,
Expand All @@ -141,7 +131,7 @@ public function create($request)
'user_id' => $user_id,
]);
if ($existing_collection_share) {
return Response::badRequest($view_file, [
return Response::badRequest('collections/shares/index.phtml', [
'collection' => $collection,
'from' => $from,
'type' => $type,
Expand All @@ -155,7 +145,7 @@ public function create($request)
$collection_share = models\CollectionShare::init($user_id, $collection->id, $type);
$errors = $collection_share->validate();
if ($errors) {
return Response::badRequest($view_file, [
return Response::badRequest('collections/shares/index.phtml', [
'collection' => $collection,
'from' => $from,
'type' => $type,
Expand All @@ -166,7 +156,7 @@ public function create($request)

$collection_share->save();

return Response::ok($view_file, [
return Response::ok('collections/shares/index.phtml', [
'collection' => $collection,
'from' => $from,
'type' => 'read',
Expand Down Expand Up @@ -198,16 +188,6 @@ public function delete($request)
]);
}

if ($request->isAccepting('text/vnd.turbo-stream.html')) {
// This allows to display the errors within the modal instead of
// sending a whole new page. This is a bit hacky so I'm going
// to use this method only where absolutely needed.
// @see https://github.com/hotwired/turbo/issues/138#issuecomment-847699281
$view_file = 'collections/shares/index.turbo_stream.phtml';
} else {
$view_file = 'collections/shares/index.phtml';
}

$csrf = $request->param('csrf');
$collection_share_id = $request->paramInteger('id');
$collection_share = models\CollectionShare::find($collection_share_id);
Expand All @@ -222,7 +202,7 @@ public function delete($request)
}

if (!\Minz\CSRF::validate($csrf)) {
return Response::badRequest($view_file, [
return Response::badRequest('collections/shares/index.phtml', [
'collection' => $collection,
'from' => $from,
'type' => 'read',
Expand All @@ -233,7 +213,7 @@ public function delete($request)

models\CollectionShare::delete($collection_share->id);

return Response::ok($view_file, [
return Response::ok('collections/shares/index.phtml', [
'collection' => $collection,
'from' => $from,
'type' => 'read',
Expand Down
14 changes: 2 additions & 12 deletions src/controllers/links/Repairing.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,18 +89,8 @@ public function create($request)
return Response::notFound('not_found.phtml');
}

if ($request->isAccepting('text/vnd.turbo-stream.html')) {
// This allows to display the errors within the modal instead of
// sending a whole new page. This is a bit hacky so I'm going
// to use this method only where absolutely needed.
// @see https://github.com/hotwired/turbo/issues/138#issuecomment-847699281
$view_file = 'links/repairing/new.turbo_stream.phtml';
} else {
$view_file = 'links/repairing/new.phtml';
}

if (!\Minz\CSRF::validate($csrf)) {
return Response::badRequest($view_file, [
return Response::badRequest('links/repairing/new.phtml', [
'link' => $link,
'url' => $url,
'url_cleared' => $url_cleared,
Expand All @@ -115,7 +105,7 @@ public function create($request)
$link->url = \SpiderBits\Url::sanitize($url);
$errors = $link->validate();
if ($errors) {
return Response::badRequest($view_file, [
return Response::badRequest('links/repairing/new.phtml', [
'link' => $link,
'url' => $url,
'url_cleared' => $url_cleared,
Expand Down
5 changes: 3 additions & 2 deletions src/views/_layouts/base.phtml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
if ($turbo_frame) {
$layout_name = 'turbo_frame.phtml';
$modal_enabled = $modal_enabled ?? false;
if ($modal_enabled && $modal_requested) {
$layout_name = 'modal.phtml';
} elseif ($current_user && !$current_user->isBlocked()) {
$layout_name = 'connected.phtml';
} elseif ($current_user) {
Expand Down
2 changes: 1 addition & 1 deletion src/views/_layouts/connected.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@
</header>

<div data-modal-target="body" class="modal__body">
<turbo-frame id="modal-content" data-modal-target="content" target="_top">
<turbo-frame data-modal-target="content">
<div class="spinner"></div>
</turbo-frame>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<turbo-frame id="<?= $turbo_frame ?>">
<turbo-frame id="modal-content">
<?= $this->safe('content') ?>
</turbo-frame>
2 changes: 1 addition & 1 deletion src/views/_layouts/not_connected.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@
</header>

<div data-modal-target="body" class="modal__body">
<turbo-frame id="modal-content" data-modal-target="content" target="_top">
<turbo-frame data-modal-target="content">
<div class="spinner"></div>
</turbo-frame>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/views/collections/edit.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
'current_tab' => 'collections',
'canonical' => url('edit collection', ['id' => $collection->id]),
'has_errors' => $error || $errors,
'modal_enabled' => true,
]);
?>

Expand Down
1 change: 1 addition & 0 deletions src/views/collections/filters/edit.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
'title' => _('Settings for the news'),
'canonical' => url_full('edit collection filter', ['id' => $collection->id]),
'has_errors' => $error || $errors,
'modal_enabled' => true,
]);
?>

Expand Down
1 change: 1 addition & 0 deletions src/views/collections/groups/edit.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
'title' => _('Collection group'),
'canonical' => url_full('edit group collection', ['id' => $collection->id]),
'has_errors' => $error || $errors,
'modal_enabled' => true,
]);
?>

Expand Down
1 change: 1 addition & 0 deletions src/views/collections/images/edit.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
'title' => _('Collection illustration'),
'canonical' => url_full('edit image collection', ['id' => $collection->id]),
'has_errors' => $error || $errors,
'modal_enabled' => true,
]);
?>

Expand Down
1 change: 1 addition & 0 deletions src/views/collections/links/new.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
'title' => _('New link'),
'canonical' => url_full('new collection link', ['id' => $collection->id]),
'has_errors' => $error || $errors,
'modal_enabled' => true,
]);
?>

Expand Down
1 change: 1 addition & 0 deletions src/views/collections/new.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
'canonical' => url_full('new collection'),
'current_tab' => 'collections',
'has_errors' => $error || $errors,
'modal_enabled' => true,
]);
?>

Expand Down
Loading

0 comments on commit fcabfbe

Please sign in to comment.