From 0f6aacda7913452c8c9ca52a58e5d1bc7a95eb43 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 26 Feb 2025 00:26:25 +0000 Subject: [PATCH 001/183] updated translation target commit --- turbo/handbook/page_refreshes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/page_refreshes.md b/turbo/handbook/page_refreshes.md index 30c4a065..6c6c8657 100644 --- a/turbo/handbook/page_refreshes.md +++ b/turbo/handbook/page_refreshes.md @@ -2,7 +2,7 @@ title: "モーフィングによるスムーズなページリフレッシュ" description: "Turbo はモーフィングとスクロール位置の保存によってスムースなページの更新を可能にします" order: 3 -commit: "0b2c287" +commit: "8849e6b" --- # モーフィングによるスムーズなページリフレッシュ From 07e5e60b8fc44c68edf4576f5b2ddbee38f01353 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 1 Mar 2025 00:29:21 +0000 Subject: [PATCH 002/183] updated translation target commit --- turbo/handbook/page_refreshes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/page_refreshes.md b/turbo/handbook/page_refreshes.md index 6c6c8657..ab69c2a8 100644 --- a/turbo/handbook/page_refreshes.md +++ b/turbo/handbook/page_refreshes.md @@ -2,7 +2,7 @@ title: "モーフィングによるスムーズなページリフレッシュ" description: "Turbo はモーフィングとスクロール位置の保存によってスムースなページの更新を可能にします" order: 3 -commit: "8849e6b" +commit: "b2d93bd" --- # モーフィングによるスムーズなページリフレッシュ From f93c90d40558a1cb9f0b1a0e68b967f8e2bb7e74 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 4 Mar 2025 00:26:50 +0000 Subject: [PATCH 003/183] updated translation target commit --- turbo/handbook/page_refreshes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/page_refreshes.md b/turbo/handbook/page_refreshes.md index ab69c2a8..336b1c4a 100644 --- a/turbo/handbook/page_refreshes.md +++ b/turbo/handbook/page_refreshes.md @@ -2,7 +2,7 @@ title: "モーフィングによるスムーズなページリフレッシュ" description: "Turbo はモーフィングとスクロール位置の保存によってスムースなページの更新を可能にします" order: 3 -commit: "b2d93bd" +commit: "b8487ee" --- # モーフィングによるスムーズなページリフレッシュ From 3631360f9886f2cd9aaf85885db242a255ed910c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 30 Mar 2025 00:30:42 +0000 Subject: [PATCH 004/183] updated translation target commit --- turbo/handbook/page_refreshes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/page_refreshes.md b/turbo/handbook/page_refreshes.md index 336b1c4a..6cd1ce24 100644 --- a/turbo/handbook/page_refreshes.md +++ b/turbo/handbook/page_refreshes.md @@ -2,7 +2,7 @@ title: "モーフィングによるスムーズなページリフレッシュ" description: "Turbo はモーフィングとスクロール位置の保存によってスムースなページの更新を可能にします" order: 3 -commit: "b8487ee" +commit: "5731979" --- # モーフィングによるスムーズなページリフレッシュ From a19f6d8e60b3ad835e641a64cfabbe64ec11330f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 8 Apr 2025 00:27:46 +0000 Subject: [PATCH 005/183] updated translation target commit --- turbo/handbook/page_refreshes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/page_refreshes.md b/turbo/handbook/page_refreshes.md index 6cd1ce24..919c0b9a 100644 --- a/turbo/handbook/page_refreshes.md +++ b/turbo/handbook/page_refreshes.md @@ -2,7 +2,7 @@ title: "モーフィングによるスムーズなページリフレッシュ" description: "Turbo はモーフィングとスクロール位置の保存によってスムースなページの更新を可能にします" order: 3 -commit: "5731979" +commit: "14aafc8" --- # モーフィングによるスムーズなページリフレッシュ From b17f5cc5c8cb3a028ef9a95525ebc809b2525981 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 19 Apr 2025 00:27:19 +0000 Subject: [PATCH 006/183] updated translation target commit --- turbo/handbook/page_refreshes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/page_refreshes.md b/turbo/handbook/page_refreshes.md index 919c0b9a..3824199d 100644 --- a/turbo/handbook/page_refreshes.md +++ b/turbo/handbook/page_refreshes.md @@ -2,7 +2,7 @@ title: "モーフィングによるスムーズなページリフレッシュ" description: "Turbo はモーフィングとスクロール位置の保存によってスムースなページの更新を可能にします" order: 3 -commit: "14aafc8" +commit: "074b32a" --- # モーフィングによるスムーズなページリフレッシュ From 958f79229be57597bc009c0bc7b6a90e0e284561 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 21 Apr 2025 00:30:40 +0000 Subject: [PATCH 007/183] updated translation target commit --- turbo/handbook/page_refreshes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/page_refreshes.md b/turbo/handbook/page_refreshes.md index 3824199d..6e50f13d 100644 --- a/turbo/handbook/page_refreshes.md +++ b/turbo/handbook/page_refreshes.md @@ -2,7 +2,7 @@ title: "モーフィングによるスムーズなページリフレッシュ" description: "Turbo はモーフィングとスクロール位置の保存によってスムースなページの更新を可能にします" order: 3 -commit: "074b32a" +commit: "aa10dcf" --- # モーフィングによるスムーズなページリフレッシュ From 8446e586fc178fa72004751f71da270e546065a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 19:23:58 +0000 Subject: [PATCH 008/183] Bump sass from 1.85.0 to 1.85.1 Bumps [sass](https://github.com/sass/dart-sass) from 1.85.0 to 1.85.1. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.85.0...1.85.1) --- updated-dependencies: - dependency-name: sass dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8d4436f2..624d46ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "markdown-it-anchor": "^9.2.0", "markdown-it-toc-done-right": "^4.2.0", "npm-run-all": "^4.1.5", - "sass": "^1.85.0" + "sass": "^1.85.1" } }, "node_modules/@11ty/dependency-tree": { @@ -3449,9 +3449,9 @@ } }, "node_modules/sass": { - "version": "1.85.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.85.0.tgz", - "integrity": "sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==", + "version": "1.85.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.85.1.tgz", + "integrity": "sha512-Uk8WpxM5v+0cMR0XjX9KfRIacmSG86RH4DCCZjLU2rFh5tyutt9siAXJ7G+YfxQ99Q6wrRMbMlVl6KqUms71ag==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 98fad189..dd12f340 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "markdown-it-anchor": "^9.2.0", "markdown-it-toc-done-right": "^4.2.0", "npm-run-all": "^4.1.5", - "sass": "^1.85.0" + "sass": "^1.85.1" }, "scripts": { "serve": "npm-run-all -s clean build:11ty build:css -p watch:** --silent", From 58a4bd3d47a358cbe7d0729c0660ef76c5d53bf6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 20:59:20 +0000 Subject: [PATCH 009/183] Bump sass from 1.85.1 to 1.86.0 Bumps [sass](https://github.com/sass/dart-sass) from 1.85.1 to 1.86.0. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.85.1...1.86.0) --- updated-dependencies: - dependency-name: sass dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 624d46ff..2049a9b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "markdown-it-anchor": "^9.2.0", "markdown-it-toc-done-right": "^4.2.0", "npm-run-all": "^4.1.5", - "sass": "^1.85.1" + "sass": "^1.86.0" } }, "node_modules/@11ty/dependency-tree": { @@ -3449,9 +3449,9 @@ } }, "node_modules/sass": { - "version": "1.85.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.85.1.tgz", - "integrity": "sha512-Uk8WpxM5v+0cMR0XjX9KfRIacmSG86RH4DCCZjLU2rFh5tyutt9siAXJ7G+YfxQ99Q6wrRMbMlVl6KqUms71ag==", + "version": "1.86.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.86.0.tgz", + "integrity": "sha512-zV8vGUld/+mP4KbMLJMX7TyGCuUp7hnkOScgCMsWuHtns8CWBoz+vmEhoGMXsaJrbUP8gj+F1dLvVe79sK8UdA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index dd12f340..c72ef788 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "markdown-it-anchor": "^9.2.0", "markdown-it-toc-done-right": "^4.2.0", "npm-run-all": "^4.1.5", - "sass": "^1.85.1" + "sass": "^1.86.0" }, "scripts": { "serve": "npm-run-all -s clean build:11ty build:css -p watch:** --silent", From 3c189383a04c33033796d443fbc76ea5c0558533 Mon Sep 17 00:00:00 2001 From: n-hagiwara Date: Fri, 21 Mar 2025 10:09:59 +0900 Subject: [PATCH 010/183] =?UTF-8?q?index=E3=81=AEtitle=E3=81=AE=E5=A4=89?= =?UTF-8?q?=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.md b/index.md index bae3ee8c..900c82f3 100644 --- a/index.md +++ b/index.md @@ -1,5 +1,5 @@ --- -title: "はじめに" +title: "Hotwire ドキュメント(有志翻訳版)" description: "Turboは、クライアントサイドのJavaScriptフレームワークを使用することなく、高速でモダンなウェブアプリケーションを作成するためのいくつかの技術を提供します。" layout: "base.html" --- From ed279c183a817579857afe11dc7cdc5e5dd01c0c Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara Date: Tue, 7 May 2024 10:43:19 +0900 Subject: [PATCH 011/183] =?UTF-8?q?Turbo=E3=83=89=E3=83=A9=E3=82=A4?= =?UTF-8?q?=E3=83=96=E3=81=AE=E6=8C=99=E5=8B=95=E3=81=AB=E3=81=A4=E3=81=84?= =?UTF-8?q?=E3=81=A6=E3=81=AE=E8=AA=AC=E6=98=8E=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/hotwired/turbo-site/compare/3b06afbf5470af387902e5dd1470c9cefcdc1735..c397c3157a26844bac57995896f06c5fbde02d0b#diff-bbdef0a885cb8943c969dbffeb1a982a34a085722b7a77dfcde431b3249c28e5R18-R19 --- turbo/handbook/drive.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 6e3bfb2e..39b7dc69 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -18,6 +18,8 @@ Turbo ドライブは、ページ・ナビゲーションを、ある*アクシ アクセスは、ページの描画のために、クリックから始まるすべてのナビゲーション・ライフサイクルを要求します。そのサイクルには、ブラウザ履歴の更新や、ネットワーク・リクエストの発行、キャッシュからのページのコピーの再構築、最終的なレスポンスの描画、スクロール位置の更新も含まれます。 +描画中、Turbo ドライブはリクエストしているドキュメントの``の内容をレスポンスのドキュメントの``で置き換えます。``の内容もマージし、必要に応じて``要素の`lang`属性を更新します。``要素を置き換える代わりにマージするポイントは、``または`<meta>`タグが変わった時にそれらは期待どおり更新され、アセットのリンクが変わらない時にそのリンクに対して再び処理しないところです。 + アクセスには二つの種類があります。_アプリケーション・アクセス_、_advance_ あるいは _replace_ のアクションを伴うものと、_リストア・アクセス_、_restore_ のアクションを伴うものです。 ## アプリケーション・アクセス From 31f6f8accfcfedb5aa5d78306b9e1987533bee9c Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Mon, 17 Jun 2024 21:14:25 +0900 Subject: [PATCH 012/183] =?UTF-8?q?Custom=20Rendering=E3=81=AE=E7=AB=A0?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 39b7dc69..f6968cd2 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -82,6 +82,43 @@ Application visits can be canceled before they start, regardless of whether they リストア・アクセスは、`turbo:before-visit` を発火しないのでキャンセルすることができません。 Turbo ドライブは、リストア・アクセスを、*すでに存在する*アクセス履歴への応答の場合に発行します。よくあるのは、ブラウザバックやブラウザで前に進む場合です。 +## 描画のカスタム + +ドキュメント全体に対して `turbo:before-render` イベントリスナーを追加し、 `event.detail.render` プロパティをオーバーライドすることで、アプリケーションの描画プロセスをカスタマイズできます。 + +例えば、[morphdom]で、リクエストを投げたドキュメントの `<body>` 要素を、レスポンスのドキュメントにある `<body>` 要素にマージできます。 + +```javascript +import morphdom from "morphdom" + +addEventListener("turbo:before-render", (event) => { + event.detail.render = (currentElement, newElement) => { + morphdom(currentElement, newElement) + } +}) +``` + +[morphdom]: https://github.com/patrick-steele-idem/morphdom + +<details> +<summary>原文</summary> + +Applications can customize the rendering process by adding a document-wide `turbo:before-render` event listener and overriding the `event.detail.render` property. + +For example, you could merge the response document's `<body>` element into the requesting document's `<body>` element with [morphdom](https://github.com/patrick-steele-idem/morphdom): + +```javascript +import morphdom from "morphdom" + +addEventListener("turbo:before-render", (event) => { + event.detail.render = (currentElement, newElement) => { + morphdom(currentElement, newElement) + } +}) +``` + +</details> + ## 描画の一時停止 アプリケーションは描画を一時停止して、実行前に追加で下準備をすることができます。 From eb03abfddb87e7d305a1c8434d572a897d7627cc Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Mon, 17 Jun 2024 21:33:17 +0900 Subject: [PATCH 013/183] =?UTF-8?q?Requiring=20Confirmation=20for=20a=20Vi?= =?UTF-8?q?sit=E3=81=AE=E7=AB=A0=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index f6968cd2..9c544efa 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -168,6 +168,31 @@ document.addEventListener('turbo:before-fetch-request', async (event) => { アクセシビリティの観点からも、 GET 以外のリクエストには実際のフォームとボタンを使うのが望ましいでしょう。 +## アクセス前に確認ダイアログを表示する + +リンクに `data-turbo-confirm` 属性を付けると、アクセス前に確認ダイアログが表示できます。 + +```html +<a href="/articles" data-turbo-confirm="このページから離れますか?">Back to articles</a> +<a href="/articles/54" data-turbo-method="delete" data-turbo-confirm="本当に記事を削除しますか?">Delete the article</a> +``` + +確認時に呼ぶメソッドは `Turbo.setConfirmMethod` を使って、変更できます。確認時に呼ぶメソッドのデフォルトは、ブラウザに組み込まれてる `confirm` です。 + +<details> +<summary>原文</summary> + +Decorate links with `data-turbo-confirm`, and confirmation will be required for a visit to proceed. + +```html +<a href="/articles" data-turbo-confirm="Do you want to leave this page?">Back to articles</a> +<a href="/articles/54" data-turbo-method="delete" data-turbo-confirm="Are you sure you want to delete the article?">Delete the article</a> +``` + +Use `Turbo.setConfirmMethod` to change the method that gets called for confirmation. The default is the browser's built in `confirm`. + +</details> + ## 特定のリンク/フォームでの Turbo ドライブの無効化 Turbo ドライブは、対象となる要素かその親要素で `data-turbo="false"` を宣言することで、要素単位で無効化することができます。 From 1430a3eceb041a0ad91c76869818ffc44537525f Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Mon, 17 Jun 2024 22:33:45 +0900 Subject: [PATCH 014/183] =?UTF-8?q?View=20transitions=E3=81=AE=E7=AB=A0?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 54 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 9c544efa..d9111705 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -233,6 +233,60 @@ import { Turbo } from "@hotwired/turbo-rails" Turbo.session.drive = false ``` +## ビュートランジション + +[ビュートランジション API]を[サポートしているブラウザ]では、Turboはページ間を移動するときにビュートランジションをトリガーします。 + +Turbo は、現在と次のページの両方に以下の `<meta>` 要素があるときに、ビュートランジションをトリガーします。 + +```html +<meta name="view-transition" content="same-origin" /> +``` + +Turbo は `<html>` 要素に `data-turbo-visit-direction` 属性を追加することで、トランジションの方向を指定できます。その属性の値として以下のものを使えます。 + +- `forward`: ページを全て変える方向 +- `back`: ページを前のページに戻す方向 +- `none`: ページの一部を置き換える方向 + +この属性を使えば、トランジション中で実行されるアニメーションをカスタマイズできます。 + +```css +html[data-turbo-visit-direction="forward"]::view-transition-old(sidebar):only-child { + animation: slide-to-right 0.5s ease-out; +} +``` + +[サポートしているブラウザ]: https://caniuse.com/?search=View%20Transition%20API +[ビュートランジション API]: https://developer.mozilla.org/ja/docs/Web/API/View_Transitions_API + +<details> +<summary>原文</summary> + +In [browsers that support](https://caniuse.com/?search=View%20Transition%20API) the [View Transition API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API) Turbo can trigger view transitions when navigating between pages. + +Turbo triggers a view transition when both the current and the next page have this meta tag: + +``` +<meta name="view-transition" content="same-origin" /> +``` + +Turbo also adds a `data-turbo-visit-direction` attribute to the `<html>` element to indicate the direction of the transition. The attribute can have one of the following values: + +- `forward` in advance visits. +- `back` in restoration visits. +- `none` in replace visits. + +You can use this attribute to customize the animations that are performed during a transition: + +```css +html[data-turbo-visit-direction="forward"]::view-transition-old(sidebar):only-child { + animation: slide-to-right 0.5s ease-out; +} +``` + +</details> + ## 進行状況を表示する Turbo ドライブのナビゲーション中、ブラウザはその進行状況インジケータを表示しません。 Turbo ドライブは、リクエスト発行中のフィードバックを示すため、CSS ベースのプログレスバーを導入しています。 From e68a0987c5505f69cee215cb22a0b0cd6c15e3a6 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 18 Jun 2024 01:27:28 +0900 Subject: [PATCH 015/183] =?UTF-8?q?Prefetching=20Links=20on=20Hover?= =?UTF-8?q?=E3=81=AE=E7=AB=A0=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 100 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index d9111705..2c59e842 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -409,4 +409,102 @@ Turbo が POST リクエストに通常の200ステータスの応答を許さ ## フォーム送信後のストリーミング サーバーはフォームの送信に対して、レスポンス・ボディ内の一つ以上の `<turbo-stream>` 要素を伴う `Content-Type: text/vnd.turbo-stream.html` [Turboストリーム](/turbo/handbook/streams)メッセージで応答することもあります。この応答によって、ナビゲーションなしに、ページの複数箇所を更新することができます。 -<br><br> + +## ホバーでリンク先のプリフェッチ + +Turbo は、ユーザーがリンクをクリックする前に発生した`mouseenter` イベントでリンク先を自動で読み込みます。これにより、リンク・ナビゲーションの待ち時間が短縮されます。通常、クリック・ナビゲーション単位で500から800ミリ秒の速度が向上します。 + +リンク先のプリフェッチは、Turbo v8からデフォルトで有効になっています。ただ、以下のメタタグをページに追加すれば、無効化できます。 + +```html +<meta name="turbo-prefetch" content="false"> +``` + +ユーザーが少しの間だけリンクをホバーしただけでリンク先をプリフェッチしないように、Turbo はリンク先をプリフェッチする前に100ミリ秒待ちます。 + +HTML要素、あるいは、その祖先に `data-turbo-prefetch="false"`をつけることで、プリフェッチ機能を要素ごとに無効化できます。 + +```html +<html> + <head> + <meta name="turbo-prefetch" content="true"> + </head> + <body> + <a href="/articles">Articles</a> <!-- このリンク先はプリフェッチされます --> + <a href="/about" data-turbo-prefetch="false">About</a> <!-- このリンク先はプリフェッチされません --> + <div data-turbo-prefetch="false"`> + <!-- このdiv内のリンクはプリフェッチされません --> + </div> + </body> +</html> +``` + +`turbo:before-prefetch` イベントをインターセプトして `event.preventDefault()` を呼ぶことで、プログラムでプリフェッチ機能を無効化できます。 + +```javascript +document.addEventListener("turbo:before-prefetch", (event) => { + if (isSavingData() || hasSlowInternet()) { + event.preventDefault() + } +}) + +function isSavingData() { + return navigator.connection?.saveData +} + +function hasSlowInternet() { + return navigator.connection?.effectiveType === "slow-2g" || + navigator.connection?.effectiveType === "2g" +} +``` + + +<details> +<summary>原文</summary> + +Turbo can also speed up perceived link navigation latency by automatically loading links on `mouseenter` events, and before the user clicks the link. This usually leads to a speed bump of 500-800ms per click navigation. + +Prefetching links is enabled by default since Turbo v8, but you can disable it by adding this meta tag to your page: + +```html +<meta name="turbo-prefetch" content="false"> +``` + +To avoid prefetching links that the user is briefly hovering, Turbo waits 100ms after the user hovers over the link before prefetching it. But you may want to disable the prefetching behavior on certain links leading to pages with expensive rendering. + +You can disable the behavior on a per-element basis by annotating the element or any of its ancestors with `data-turbo-prefetch="false"`. + +```html +<html> + <head> + <meta name="turbo-prefetch" content="true"> + </head> + <body> + <a href="/articles">Articles</a> <!-- This link is prefetched --> + <a href="/about" data-turbo-prefetch="false">About</a> <!-- Not prefetched --> + <div data-turbo-prefetch="false"`> + <!-- Links inside this div will not be prefetched --> + </div> + </body> +</html> +``` + +You can also disable the behaviour programatically by intercepting the `turbo:before-prefetch` event and calling `event.preventDefault()`. + +```javascript +document.addEventListener("turbo:before-prefetch", (event) => { + if (isSavingData() || hasSlowInternet()) { + event.preventDefault() + } +}) + +function isSavingData() { + return navigator.connection?.saveData +} + +function hasSlowInternet() { + return navigator.connection?.effectiveType === "slow-2g" || + navigator.connection?.effectiveType === "2g" +} +``` +</details> From f267a94fd1e56125cf1239b8c5f904e32dd23a77 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 18 Jun 2024 09:00:50 +0900 Subject: [PATCH 016/183] =?UTF-8?q?Preload=20Links=20Into=20the=20Cache?= =?UTF-8?q?=E3=81=AE=E7=AB=A0=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 71 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 2c59e842..4e7425e0 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -508,3 +508,74 @@ function hasSlowInternet() { } ``` </details> + +## リンク先をキャッシュにプリロード + +[data-turbo-preload] 属性を使えば、リンク先をTurbo ドライブのキャッシュにプリロードできます。 + +これにより、ページに初めてアクセスする前でもページのプレビューが提供され、ページアクセスが高速に感じられます。これはアプリケーション上で最も重要なページのプリロードに使えます。過剰な使用は、不要なコンテントを読み込むことになるので、避けてください。 + +すべての `<a>` 要素がプリロードされるわけではありません。以下のような `[data-turbo-preload]` 属性を持つリンクはプリロードされません。 + +* 他のドメインにアクセスするリンク +* ある `<turbo-frame>` 要素に対して適用される `[data-turbo-frame]` 属性を持つリンク +* 先祖要素の `<turbo-frame>` に対して適用されるリンク +* `[data-turbo="false"]` 属性を持つリンク +* `[data-turbo-stream]` 属性を持つリンク +* `[data-turbo-method]` 属性を持つリンク +* 先祖要素が `[data-turbo="false"]` 属性を持つリンク +* 先祖要素が `[data-turbo-prefetch="false"]` 属性を持つリンク + +<br><br> + +プリロードされた `<a>` 要素は [turbo:before-fetch-request] と [turbo:before-fetch-response] イベントをディスパッチすることに注意してください。`turbo:before-fetch-request` イベントがプリロードにより発生したのかそれとも他のメカニズムにより発生したのかの区別は、リクエストの `X-Sec-Purpose` ヘッダーに `"prefetch"`がセットされているかどうかで確認できます(`X-Sec-Purpose` ヘッダーの値は `event.detail.fetchOptions.headers["X-Sec-Purpose"]` プロパティから取得できます)。 + +```js +addEventListener("turbo:before-fetch-request", (event) => { + if (event.detail.fetchOptions.headers["X-Sec-Purpose"] === "prefetch") { + // 追加のプリロード設定を行う + } else { + // 何かを行う + } +}) +``` + + +[data-turbo-preload]: /hotwire_ja/turbo/reference/attributes#data-attributes +[turbo:before-fetch-request]: /hotwire_ja/turbo/reference/events#turbo%3Abefore-fetch-request +[turbo:before-fetch-response]: /hotwire_ja/turbo/reference/events#turbo%3Abefore-fetch-response + +<details> +<summary>原文</summary> + +Preload links into Turbo Drive's cache using the [data-turbo-preload][] boolean attribute. + +This will make page transitions feel lightning fast by providing a preview of a page even before the first visit. Use it to preload the most important pages in your application. Avoid over usage, as it will lead to loading content that is not needed. + +Not every `<a>` element can be preloaded. The `[data-turbo-preload]` attribute +won't have any effect on links that: + +* navigate to another domain +* have a `[data-turbo-frame]` attribute that drives a `<turbo-frame>` element +* drive an ancestor `<turbo-frame>` element +* have the `[data-turbo="false"]` attribute +* have the `[data-turbo-stream]` attribute +* have a `[data-turbo-method]` attribute +* have an ancestor with the `[data-turbo="false"]` attribute +* have an ancestor with the `[data-turbo-prefetch="false"]` attribute + +It also dovetails nicely with pages that leverage [Eager-Loading Frames](/reference/frames#eager-loaded-frame) or [Lazy-Loading Frames](/reference/frames#lazy-loaded-frame). As you can preload the structure of the page and show the user a meaningful loading state while the interesting content loads. +<br><br> + +Note that preloaded `<a>` elements will dispatch [turbo:before-fetch-request](/reference/events) and [turbo:before-fetch-response](/reference/events) events. To distinguish a preloading `turbo:before-fetch-request` initiated event from an event initiated by another mechanism, check whether the request's `X-Sec-Purpose` header (read from the `event.detail.fetchOptions.headers["X-Sec-Purpose"]` property) is set to `"prefetch"`: + +```js +addEventListener("turbo:before-fetch-request", (event) => { + if (event.detail.fetchOptions.headers["X-Sec-Purpose"] === "prefetch") { + // do additional preloading setup… + } else { + // do something else… + } +}) +``` +</details> From d8deeff10da533fc1cc4b2f5d98727141daa96fb Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 18 Jun 2024 10:25:34 +0900 Subject: [PATCH 017/183] =?UTF-8?q?=E3=83=AA=E3=82=AF=E3=82=A8=E3=82=B9?= =?UTF-8?q?=E3=83=88=E3=81=AE=E4=B8=80=E6=99=82=E5=81=9C=E6=AD=A2=E3=81=AE?= =?UTF-8?q?=E6=96=87=E8=A8=80=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 4e7425e0..6c7dbf17 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -121,7 +121,7 @@ addEventListener("turbo:before-render", (event) => { ## 描画の一時停止 -アプリケーションは描画を一時停止して、実行前に追加で下準備をすることができます。 +アプリケーションは描画を一時停止して、続行する前に追加で下準備をすることができます。 `turbo:before-render` イベントを待ち受けることで、描画が始まろうとする瞬間に気づくことができます。そこで、`event.preventDefault()` で描画を停止させましょう。下準備が終わったら、`event.detail.resume()` を呼ぶことで描画を再開します。 From da308992588198a76f23f14607df949b38195de1 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 18 Jun 2024 10:31:27 +0900 Subject: [PATCH 018/183] =?UTF-8?q?=E6=96=87=E5=AD=97=E5=88=97=E3=81=AB?= =?UTF-8?q?=E3=81=AF=E3=83=80=E3=83=96=E3=83=AB=E3=82=AF=E3=82=A9=E3=83=86?= =?UTF-8?q?=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92=E4=BD=BF=E3=81=86?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 6c7dbf17..86d2bfce 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -128,7 +128,7 @@ addEventListener("turbo:before-render", (event) => { アクセスにexitのアニメーションを追加する例です。 ```javascript -document.addEventListener('turbo:before-render', async (event) => { +document.addEventListener("turbo:before-render", async (event) => { event.preventDefault() await animateOut() @@ -146,11 +146,11 @@ document.addEventListener('turbo:before-render', async (event) => { リクエストに `Authorization` ヘッダを設定する例です。 ```javascript -document.addEventListener('turbo:before-fetch-request', async (event) => { +document.addEventListener("turbo:before-fetch-request", async (event) => { event.preventDefault() const token = await getSessionToken(window.app) - event.detail.fetchOptions.headers['Authorization'] = `Bearer ${token}` + event.detail.fetchOptions.headers["Authorization"] = `Bearer ${token}` event.detail.resume() }) From 2bf907679a11314bab4f4c998379d75a22606254 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 18 Jun 2024 10:53:49 +0900 Subject: [PATCH 019/183] =?UTF-8?q?=E3=82=A2=E3=82=BB=E3=83=83=E3=83=88?= =?UTF-8?q?=E5=A4=89=E6=9B=B4=E6=99=82=E3=81=AE=E3=83=AA=E3=83=AD=E3=83=BC?= =?UTF-8?q?=E3=83=89=E3=81=AE=E7=AB=A0=E3=81=AE=E6=96=87=E7=AB=A0=E3=82=92?= =?UTF-8?q?=E6=9C=80=E6=96=B0=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 86d2bfce..920c2f05 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -318,11 +318,9 @@ html[data-turbo-visit-direction="forward"]::view-transition-old(sidebar):only-ch ## アセット変更時のリロード +前述した通り、Turbo ドライブは `<head>` 要素のコンテントをマージします。しかし、CSS または JavaScript が変更された場合、これらCSS、JavaScriptのマージは既存のものを評価した上で行われます。大抵、このマージは厄介なコンフリクトを引き起こします。そのような場合、Ajaxではない標準のリクエストで新しいドキュメントを完全な形で取得する必要があります。 - Turbo ドライブは、あるページから別のページへの遷移時に `<head>` 内のアセット要素のURLを追跡し、URLが変更されていればフル・リロードを発行します。これによってユーザーは、最新のアプリケーションのスクリプトやスタイルを入手できます。 - - -アセット要素を `data-turbo-track="reload"` をつけてアノテーションし、アセットのURLにバージョン識別番号をつけます。識別子は番号でも、最終更新日時でもよいですし、アセットの内容のダイジェストならもっといいでしょう。次の例のようにします。 +これは、アセット要素に `data-turbo-track="reload"` をつけてアノテーションし、アセットのURLにバージョン識別番号をつけるだけで実現できます。識別子は番号でも、最終更新日時でもよいですし、アセットの内容のダイジェストならもっといいでしょう。次の例のようにします。 ```html <head> From 550aa19a8b13b85be0c6b7e5cc32d4da8dabb540 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 9 Jul 2024 10:28:08 +0900 Subject: [PATCH 020/183] =?UTF-8?q?=E5=8E=9F=E6=96=87=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 316 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 314 insertions(+), 2 deletions(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 920c2f05..de184e2a 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -12,6 +12,13 @@ Turbo ドライブは、ページ単位のナビゲーションを強化する ${toc} +<details> +<summary>原文</summary> + +Turbo Drive is the part of Turbo that enhances page-level navigation. It watches for link clicks and form submissions, performs them in the background, and updates the page without doing a full reload. It's the evolution of a library previously known as [Turbolinks](https://github.com/turbolinks/turbolinks). + +</details> + ## ページ・ナビゲーションの基本 Turbo ドライブは、ページ・ナビゲーションを、ある*アクション*をともなった、ある*ロケーション* (URL)へのアクセスという形で表現します。 @@ -22,6 +29,20 @@ Turbo ドライブは、ページ・ナビゲーションを、ある*アクシ アクセスには二つの種類があります。_アプリケーション・アクセス_、_advance_ あるいは _replace_ のアクションを伴うものと、_リストア・アクセス_、_restore_ のアクションを伴うものです。 +<details> +<summary>原文</summary> + +Turbo Drive models page navigation as a *visit* to a *location* (URL) with an *action*. + +Visits represent the entire navigation lifecycle from click to render. That includes changing browser history, issuing the network request, restoring a copy of the page from cache, rendering the final response, and updating the scroll position. + +During rendering, Turbo Drive replaces the contents of the requesting document's `<body>` with the contents of the response document's `<body>`, merges the contents of their `<head>`s too, and updates the `lang` attribute of the `<html>` element as needed. The point of merging instead of replacing the `<head>` elements is that if `<title>` or `<meta>` tags change, say, they will be updated as expected, but if links to assets are the same, they won't be touched and therefore the browser won't process them again. + +There are two types of visit: an _application visit_, which has an action of _advance_ or _replace_, and a _restoration visit_, which has an action of _restore_. + +</details> + + ## アプリケーション・アクセス アプリケーション・アクセスは、Turbo ドライブが使えるリンクのクリック、あるいはプログラムによる[`Turbo.visit(location)`](https://turbo.hotwired.dev/reference/drive#turbodrivevisit) の呼び出しです。 @@ -60,8 +81,46 @@ Turbo.visit("/edit", { action: "replace" }) Turbo ドライブ [iOS adapter](https://github.com/hotwired/turbo-ios)を用いるアプリケーションは一般に、最上位の view コントローラーを閉じ、新しい view コントローラーをナビゲーション・スタック上にアニメーションなしでpushすることで更新を扱います。 -## リストア・アクセス +<details> +<summary>原文</summary> + +Application visits are initiated by clicking a Turbo Drive-enabled link, or programmatically by calling [`Turbo.visit(location)`](/reference/drive#turbodrivevisit). + +An application visit always issues a network request. When the response arrives, Turbo Drive renders its HTML and completes the visit. + +If possible, Turbo Drive will render a preview of the page from cache immediately after the visit starts. This improves the perceived speed of frequent navigation between the same pages. + +If the visit’s location includes an anchor, Turbo Drive will attempt to scroll to the anchored element. Otherwise, it will scroll to the top of the page. + +Application visits result in a change to the browser’s history; the visit’s _action_ determines how. + +![Advance visit action](https://s3.amazonaws.com/turbolinks-docs/images/advance.svg) + +The default visit action is _advance_. During an advance visit, Turbo Drives pushes a new entry onto the browser’s history stack using [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState). + +Applications using the Turbo Drive [iOS adapter](https://github.com/hotwired/turbo-ios) typically handle advance visits by pushing a new view controller onto the navigation stack. Similarly, applications using the [Android adapter](https://github.com/hotwired/turbo-android) typically push a new activity onto the back stack. + +![Replace visit action](https://s3.amazonaws.com/turbolinks-docs/images/replace.svg) + +You may wish to visit a location without pushing a new history entry onto the stack. The _replace_ visit action uses [`history.replaceState`](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState) to discard the topmost history entry and replace it with the new location. + +To specify that following a link should trigger a replace visit, annotate the link with `data-turbo-action="replace"`: + +```html +<a href="/edit" data-turbo-action="replace">Edit</a> +``` + +To programmatically visit a location with the replace action, pass the `action: "replace"` option to `Turbo.visit`: + +```js +Turbo.visit("/edit", { action: "replace" }) +``` + +Applications using the Turbo Drive [iOS adapter](https://github.com/hotwired/turbo-ios) typically handle replace visits by dismissing the topmost view controller and pushing a new view controller onto the navigation stack without animation. +</details> + +## リストア・アクセス Turbo ドライブは、ブラウザバックやブラウザで前に進むボタンでの移動があった場合に、自動的にリストア・アクセスを開始します。[iOS](https://github.com/hotwired/turbo-ios) あるいは [Android](https://github.com/hotwired/turbo-android) アダプタを使うアプリケーションは、ナビゲーション・スタック内で後ろに戻る動きがあった場合に、リストア・アクセスを開始します。 @@ -73,6 +132,21 @@ Turbo.visit("/edit", { action: "replace" }) リストア・アクセスは _restore_ アクションを伴い、Turbo ドライブはそれを内部的な利用のために取っておいてあります。わざわざリンクにアノテーションをしたり、`Turbo.visit` を `restore` アクションと共に発動したりするべきではありません。 +<details> +<summary>原文</summary> + +Turbo Drive automatically initiates a restoration visit when you navigate with the browser’s Back or Forward buttons. Applications using the [iOS](https://github.com/hotwired/turbo-ios) or [Android](https://github.com/hotwired/turbo-android) adapters initiate a restoration visit when moving backward in the navigation stack. + +![Restore visit action](https://s3.amazonaws.com/turbolinks-docs/images/restore.svg) + +If possible, Turbo Drive will render a copy of the page from cache without making a request. Otherwise, it will retrieve a fresh copy of the page over the network. See [Understanding Caching](/handbook/building#understanding-caching) for more details. + +Turbo Drive saves the scroll position of each page before navigating away and automatically returns to this saved position on restoration visits. + +Restoration visits have an action of _restore_ and Turbo Drive reserves them for internal use. You should not attempt to annotate links or invoke `Turbo.visit` with an action of `restore`. + +</details> + ## アクセスを開始前にキャンセルする Application visits can be canceled before they start, regardless of whether they were initiated by a link click or a call to [`Turbo.visit`](https://turbo.hotwired.dev/reference/drive#turbovisit). @@ -82,6 +156,17 @@ Application visits can be canceled before they start, regardless of whether they リストア・アクセスは、`turbo:before-visit` を発火しないのでキャンセルすることができません。 Turbo ドライブは、リストア・アクセスを、*すでに存在する*アクセス履歴への応答の場合に発行します。よくあるのは、ブラウザバックやブラウザで前に進む場合です。 +<details> +<summary>原文</summary> + +Application visits can be canceled before they start, regardless of whether they were initiated by a link click or a call to [`Turbo.visit`](/reference/drive#turbovisit). + +Listen for the `turbo:before-visit` event to be notified when a visit is about to start, and use `event.detail.url` (or `$event.originalEvent.detail.url`, when using jQuery) to check the visit’s location. Then cancel the visit by calling `event.preventDefault()`. + +Restoration visits cannot be canceled and do not fire `turbo:before-visit`. Turbo Drive issues restoration visits in response to history navigation that has *already taken place*, typically via the browser’s Back or Forward buttons. + +</details> + ## 描画のカスタム ドキュメント全体に対して `turbo:before-render` イベントリスナーを追加し、 `event.detail.render` プロパティをオーバーライドすることで、アプリケーションの描画プロセスをカスタマイズできます。 @@ -137,6 +222,23 @@ document.addEventListener("turbo:before-render", async (event) => { }) ``` +<details> +<summary>原文</summary> + +Listen for the `turbo:before-render` event to be notified when rendering is about to start, and pause it using `event.preventDefault()`. Once the preparation is done continue rendering by calling `event.detail.resume()`. + +An example use case is adding exit animation for visits: +```javascript +document.addEventListener("turbo:before-render", async (event) => { + event.preventDefault() + + await animateOut() + event.detail.resume() +}) +``` + +</details> + ## リクエストの一時停止 アプリケーションはリクエストを一時停止して、実行前に追加で下準備をすることができます。 @@ -156,6 +258,27 @@ document.addEventListener("turbo:before-fetch-request", async (event) => { }) ``` +<details> +<summary>原文</summary> + +Application can pause request and make additional preparation before it will be executed. + +Listen for the `turbo:before-fetch-request` event to be notified when a request is about to start, and pause it using `event.preventDefault()`. Once the preparation is done continue request by calling `event.detail.resume()`. + +An example use case is setting `Authorization` header for the request: +```javascript +document.addEventListener("turbo:before-fetch-request", async (event) => { + event.preventDefault() + + const token = await getSessionToken(window.app) + event.detail.fetchOptions.headers["Authorization"] = `Bearer ${token}` + + event.detail.resume() +}) +``` + +</details> + ## 異なるメソッドでアクセスを行う デフォルトでは、リンクのクリックはサーバへ `GET` リクエストを送ります。しかし、これを `data-turbo-method` で変更することができます。 @@ -168,6 +291,21 @@ document.addEventListener("turbo:before-fetch-request", async (event) => { アクセシビリティの観点からも、 GET 以外のリクエストには実際のフォームとボタンを使うのが望ましいでしょう。 +<details> +<summary>原文</summary> + +By default, link clicks send a `GET` request to your server. But you can change this with `data-turbo-method`: + +```html +<a href="/articles/54" data-turbo-method="delete">Delete the article</a> +``` + +The link will get converted into a hidden form next to the `a` element in the DOM. This means that the link can't appear inside another form, as you can't have nested forms. + +You should also consider that for accessibility reasons, it's better to use actual forms and buttons for anything that's not a GET. + +</details> + ## アクセス前に確認ダイアログを表示する リンクに `data-turbo-confirm` 属性を付けると、アクセス前に確認ダイアログが表示できます。 @@ -233,6 +371,43 @@ import { Turbo } from "@hotwired/turbo-rails" Turbo.session.drive = false ``` +<details> +<summary>原文</summary> + +Turbo Drive can be disabled on a per-element basis by annotating the element or any of its ancestors with `data-turbo="false"`. + +```html +<a href="/" data-turbo="false">Disabled</a> +<form action="/messages" method="post" data-turbo="false"> + ... +</form> +<div data-turbo="false"> + <a href="/">Disabled</a> + <form action="/messages" method="post"> + ... + </form> +</div> +``` + +To reenable when an ancestor has opted out, use `data-turbo="true"`: + +```html +<div data-turbo="false"> + <a href="/" data-turbo="true">Enabled</a> +</div> +``` + +Links or forms with Turbo Drive disabled will be handled normally by the browser. + +If you want Drive to be opt-in rather than opt-out, then you can set `Turbo.session.drive = false`; then, `data-turbo="true"` is used to enable Drive on a per-element basis. If you're importing Turbo in a JavaScript pack, you can do this globally: + +```js +import { Turbo } from "@hotwired/turbo-rails" +Turbo.session.drive = false +``` + +</details> + ## ビュートランジション [ビュートランジション API]を[サポートしているブラウザ]では、Turboはページ間を移動するときにビュートランジションをトリガーします。 @@ -316,6 +491,38 @@ html[data-turbo-visit-direction="forward"]::view-transition-old(sidebar):only-ch [aria-busy]: https://www.w3.org/TR/wai-aria/#aria-busy +<details> +<summary>原文</summary> + +During Turbo Drive navigation, the browser will not display its native progress indicator. Turbo Drive installs a CSS-based progress bar to provide feedback while issuing a request. + +The progress bar is enabled by default. It appears automatically for any page that takes longer than 500ms to load. (You can change this delay with the [`Turbo.setProgressBarDelay`](/reference/drive#turbodrivesetprogressbardelay) method.) + +The progress bar is a `<div>` element with the class name `turbo-progress-bar`. Its default styles appear first in the document and can be overridden by rules that come later. + +For example, the following CSS will result in a thick green progress bar: + +```css +.turbo-progress-bar { + height: 5px; + background-color: green; +} +``` + +To disable the progress bar entirely, set its `visibility` style to `hidden`: + +```css +.turbo-progress-bar { + visibility: hidden; +} +``` + +In tandem with the progress bar, Turbo Drive will also toggle the [`[aria-busy]` attribute][aria-busy] on the page's `<html>` element during page navigations started from Visits or Form Submissions. Turbo Drive will set `[aria-busy="true"]` when the navigation begins, and will remove the `[aria-busy]` attribute when the navigation completes. + +[aria-busy]: https://www.w3.org/TR/wai-aria/#aria-busy + +</details> + ## アセット変更時のリロード 前述した通り、Turbo ドライブは `<head>` 要素のコンテントをマージします。しかし、CSS または JavaScript が変更された場合、これらCSS、JavaScriptのマージは既存のものを評価した上で行われます。大抵、このマージは厄介なコンフリクトを引き起こします。そのような場合、Ajaxではない標準のリクエストで新しいドキュメントを完全な形で取得する必要があります。 @@ -330,6 +537,23 @@ html[data-turbo-visit-direction="forward"]::view-transition-old(sidebar):only-ch </head> ``` +<details> +<summary>原文</summary> + +As we saw above, Turbo Drive merges the contents of the `<head>` elements. However, if CSS or JavaScript change, that merge would evaluate them on top of the existing one. Typically, this would lead to undesirable conflicts. In such cases, it's necessary to fetch a completely new document through a standard, non-Ajax request. + +To accomplish this, just annotate those asset elements with `data-turbo-track="reload"` and include a version identifier in your asset URLs. The identifier could be a number, a last-modified timestamp, or better, a digest of the asset’s contents, as in the following example. + +```html +<head> + ... + <link rel="stylesheet" href="/application-258e88d.css" data-turbo-track="reload"> + <script src="/application-cbd3cd4.js" data-turbo-track="reload"></script> +</head> +``` + +</details> + ## 特定のトリガーで確実にフル・リロードを行う @@ -342,9 +566,24 @@ html[data-turbo-visit-direction="forward"]::view-transition-old(sidebar):only-ch </head> ``` - この設定は、Trubo ドライブのページ変更とうまく協調できないサードパーティ JavaScript ライブラリの回避方法として有用です。 +<details> +<summary>原文</summary> + +You can ensure visits to a certain page will always trigger a full reload by including a `<meta name="turbo-visit-control">` element in the page’s `<head>`. + +```html +<head> + ... + <meta name="turbo-visit-control" content="reload"> +</head> +``` + +This setting may be useful as a workaround for third-party JavaScript libraries that don’t interact well with Turbo Drive page changes. + +</details> + ## ルートロケーションの設定 @@ -362,6 +601,24 @@ html[data-turbo-visit-direction="forward"]::view-transition-old(sidebar):only-ch </head> ``` +<details> +<summary>原文</summary> + +By default, Turbo Drive only loads URLs with the same origin—i.e. the same protocol, domain name, and port—as the current document. A visit to any other URL falls back to a full page load. + +In some cases, you may want to further scope Turbo Drive to a path on the same origin. For example, if your Turbo Drive application lives at `/app`, and the non-Turbo Drive help site lives at `/help`, links from the app to the help site shouldn’t use Turbo Drive. + +Include a `<meta name="turbo-root">` element in your pages’ `<head>` to scope Turbo Drive to a particular root location. Turbo Drive will only load same-origin URLs that are prefixed with this path. + +```html +<head> + ... + <meta name="turbo-root" content="/app"> +</head> +``` + +</details> + ## フォームの送信 Turbo ドライブは、リンクのクリックと似たやり方でフォームの送信を扱います。主な違いは、フォームの送信は HTTP の POST メソッドを使って状態をもつリクエストを発行できますが、リンクのクリックは HTTP の状態を持たない GET リクエストしか発行できません。 @@ -392,6 +649,41 @@ addEventListener("turbo:submit-start", ({ target }) => { [submitter]: https://developer.mozilla.org/ja/docs/Web/API/SubmitEvent/submitter [HTMLFormElement.requestSubmit()]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit +<details> +<summary>原文</summary> + +Turbo Drive handles form submissions in a manner similar to link clicks. The key difference is that form submissions can issue stateful requests using the HTTP POST method, while link clicks only ever issue stateless HTTP GET requests. + +Throughout a submission, Turbo Drive will dispatch a series of [events][] that +target the `<form>` element and [bubble up][] through the document: + +1. `turbo:submit-start` +2. `turbo:before-fetch-request` +3. `turbo:before-fetch-response` +4. `turbo:submit-end` + +During a submission, Turbo Drive will set the "submitter" element's [disabled][] attribute when the submission begins, then remove the attribute after the submission ends. When submitting a `<form>` element, browsers will treat the `<input type="submit">` or `<button>` element that initiated the submission as the [submitter][]. To submit a `<form>` element programmatically, invoke the [HTMLFormElement.requestSubmit()][] method and pass an `<input type="submit">` or `<button>` element as an optional parameter. + +If there are other changes you'd like to make during a `<form>` submission (for +example, disabling _all_ [fields within a submitted `<form>`][elements]), you +can declare your own event listeners: + +```js +addEventListener("turbo:submit-start", ({ target }) => { + for (const field of target.elements) { + field.disabled = true + } +}) +``` + +[events]: /reference/events +[bubble up]: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_bubbling_and_capture +[elements]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements +[disabled]: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled +[submitter]: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter +[HTMLFormElement.requestSubmit()]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit + +</details> ## フォーム送信後のリダイレクト @@ -404,10 +696,30 @@ Turbo が POST リクエストに通常の200ステータスの応答を許さ フォーム送信が GET リクエストの場合は、フォームに `data-turbo-frame` ターゲットを与えられることで直接レスポンスを描画します。描画の一部としてURLを更新したい場合は、 `data-turbo-action` 属性を渡します。 +<details> +<summary>原文</summary> + +After a stateful request from a form submission, Turbo Drive expects the server to return an [HTTP 303 redirect response](https://en.wikipedia.org/wiki/HTTP_303), which it will then follow and use to navigate and update the page without reloading. + +The exception to this rule is when the response is rendered with either a 4xx or 5xx status code. This allows form validation errors to be rendered by having the server respond with `422 Unprocessable Entity` and a broken server to display a "Something Went Wrong" screen on a `500 Internal Server Error`. + +The reason Turbo doesn't allow regular rendering on 200's from POST requests is that browsers have built-in behavior for dealing with reloads on POST visits where they present a "Are you sure you want to submit this form again?" dialogue that Turbo can't replicate. Instead, Turbo will stay on the current URL upon a form submission that tries to render, rather than change it to the form action, since a reload would then issue a GET against that action URL, which may not even exist. + +If the form submission is a GET request, you may render the directly rendered response by giving the form a `data-turbo-frame` target. If you'd like the URL to update as part of the rendering also pass a `data-turbo-action` attribute. + +</details> + ## フォーム送信後のストリーミング サーバーはフォームの送信に対して、レスポンス・ボディ内の一つ以上の `<turbo-stream>` 要素を伴う `Content-Type: text/vnd.turbo-stream.html` [Turboストリーム](/turbo/handbook/streams)メッセージで応答することもあります。この応答によって、ナビゲーションなしに、ページの複数箇所を更新することができます。 +<details> +<summary>原文</summary> + +Servers may also respond to form submissions with a [Turbo Streams](streams) message by sending the header `Content-Type: text/vnd.turbo-stream.html` followed by one or more `<turbo-stream>` elements in the response body. This lets you update multiple parts of the page without navigating. + +</details> + ## ホバーでリンク先のプリフェッチ Turbo は、ユーザーがリンクをクリックする前に発生した`mouseenter` イベントでリンク先を自動で読み込みます。これにより、リンク・ナビゲーションの待ち時間が短縮されます。通常、クリック・ナビゲーション単位で500から800ミリ秒の速度が向上します。 From 429be1a5a2b356364ae0fef296e53a9c46dada9c Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 9 Jul 2024 10:31:49 +0900 Subject: [PATCH 021/183] =?UTF-8?q?=E3=82=8F=E3=81=8B=E3=82=8A=E3=82=84?= =?UTF-8?q?=E3=81=99=E3=81=84=E6=96=87=E7=AB=A0=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index de184e2a..05a8bcca 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -25,7 +25,7 @@ Turbo ドライブは、ページ・ナビゲーションを、ある*アクシ アクセスは、ページの描画のために、クリックから始まるすべてのナビゲーション・ライフサイクルを要求します。そのサイクルには、ブラウザ履歴の更新や、ネットワーク・リクエストの発行、キャッシュからのページのコピーの再構築、最終的なレスポンスの描画、スクロール位置の更新も含まれます。 -描画中、Turbo ドライブはリクエストしているドキュメントの`<body>`の内容をレスポンスのドキュメントの`<body>`で置き換えます。`<head>`の内容もマージし、必要に応じて`<html>`要素の`lang`属性を更新します。`<head>`要素を置き換える代わりにマージするポイントは、`<title>`または`<meta>`タグが変わった時にそれらは期待どおり更新され、アセットのリンクが変わらない時にそのリンクに対して再び処理しないところです。 +描画中、Turbo ドライブはリクエストしているドキュメントの`<body>`の内容をレスポンスのドキュメントの`<body>`で置き換えます。`<head>`の内容もマージし、必要に応じて`<html>`要素の`lang`属性を更新します。`<head>`要素を置き換える代わりにマージするポイントは、`<title>`または`<meta>`タグは変更があれば期待どおり更新され、アセットのリンクが変わらない場合はそのリンクに対してブラウザが再び処理しないところです。 アクセスには二つの種類があります。_アプリケーション・アクセス_、_advance_ あるいは _replace_ のアクションを伴うものと、_リストア・アクセス_、_restore_ のアクションを伴うものです。 From c128c49ebfecfd5da8e0f331b08532ab54a56768 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 27 Aug 2024 10:43:19 +0900 Subject: [PATCH 022/183] =?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=89=E5=86=85?= =?UTF-8?q?=E3=81=AE=E8=8B=B1=E6=96=87=E3=82=92=E6=97=A5=E6=9C=AC=E8=AA=9E?= =?UTF-8?q?=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 05a8bcca..2ed06f76 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -284,7 +284,7 @@ document.addEventListener("turbo:before-fetch-request", async (event) => { デフォルトでは、リンクのクリックはサーバへ `GET` リクエストを送ります。しかし、これを `data-turbo-method` で変更することができます。 ```html -<a href="/articles/54" data-turbo-method="delete">Delete the article</a> +<a href="/articles/54" data-turbo-method="delete">記事を削除する</a> ``` リンクは隠されたformに変換され、DOM内の `a` 要素の次の位置に配置されます。これは、リンクは別のフォームの中には配置できないということです。フォームをネストすることはできないからです。 @@ -311,8 +311,8 @@ You should also consider that for accessibility reasons, it's better to use actu リンクに `data-turbo-confirm` 属性を付けると、アクセス前に確認ダイアログが表示できます。 ```html -<a href="/articles" data-turbo-confirm="このページから離れますか?">Back to articles</a> -<a href="/articles/54" data-turbo-method="delete" data-turbo-confirm="本当に記事を削除しますか?">Delete the article</a> +<a href="/articles" data-turbo-confirm="このページから離れますか?">記事に戻る</a> +<a href="/articles/54" data-turbo-method="delete" data-turbo-confirm="本当に記事を削除しますか?">記事を削除する</a> ``` 確認時に呼ぶメソッドは `Turbo.setConfirmMethod` を使って、変更できます。確認時に呼ぶメソッドのデフォルトは、ブラウザに組み込まれてる `confirm` です。 @@ -336,14 +336,14 @@ Use `Turbo.setConfirmMethod` to change the method that gets called for confirmat Turbo ドライブは、対象となる要素かその親要素で `data-turbo="false"` を宣言することで、要素単位で無効化することができます。 ```html -<a href="/" data-turbo="false">Disabled</a> +<a href="/" data-turbo="false">無効化</a> <form action="/messages" method="post" data-turbo="false"> ... </form> <div data-turbo="false"> - <a href="/">Disabled</a> + <a href="/">無効化</a> <form action="/messages" method="post"> ... </form> @@ -740,8 +740,8 @@ HTML要素、あるいは、その祖先に `data-turbo-prefetch="false"`をつ <meta name="turbo-prefetch" content="true"> </head> <body> - <a href="/articles">Articles</a> <!-- このリンク先はプリフェッチされます --> - <a href="/about" data-turbo-prefetch="false">About</a> <!-- このリンク先はプリフェッチされません --> + <a href="/articles">記事</a> <!-- このリンク先はプリフェッチされます --> + <a href="/about" data-turbo-prefetch="false">概要</a> <!-- このリンク先はプリフェッチされません --> <div data-turbo-prefetch="false"`> <!-- このdiv内のリンクはプリフェッチされません --> </div> From 7987f25219563e82ac7d8bc729a1524d14b08890 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 27 Aug 2024 10:45:49 +0900 Subject: [PATCH 023/183] =?UTF-8?q?=E9=80=81=E3=82=8A=E4=BB=AE=E5=90=8D?= =?UTF-8?q?=E3=81=AE=E7=94=A8=E6=B3=95=E3=82=92=E3=83=95=E3=82=A9=E3=83=BC?= =?UTF-8?q?=E3=83=9E=E3=83=AB=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 2ed06f76..fd799f97 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -315,7 +315,7 @@ You should also consider that for accessibility reasons, it's better to use actu <a href="/articles/54" data-turbo-method="delete" data-turbo-confirm="本当に記事を削除しますか?">記事を削除する</a> ``` -確認時に呼ぶメソッドは `Turbo.setConfirmMethod` を使って、変更できます。確認時に呼ぶメソッドのデフォルトは、ブラウザに組み込まれてる `confirm` です。 +確認時に呼ぶメソッドは `Turbo.setConfirmMethod` を使って、変更できます。確認時に呼ぶメソッドのデフォルトは、ブラウザに組み込まれている `confirm` です。 <details> <summary>原文</summary> From ea9174bc237681b031df6ab8b3f997d6ab386eb9 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 27 Aug 2024 10:46:15 +0900 Subject: [PATCH 024/183] =?UTF-8?q?=E7=A9=BA=E7=99=BD=E3=81=8C=E3=81=AA?= =?UTF-8?q?=E3=81=A3=E3=81=9F=E3=81=AE=E3=81=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index fd799f97..82af0f66 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -410,7 +410,7 @@ Turbo.session.drive = false ## ビュートランジション -[ビュートランジション API]を[サポートしているブラウザ]では、Turboはページ間を移動するときにビュートランジションをトリガーします。 +[ビュートランジション API]を[サポートしているブラウザ]では、Turbo はページ間を移動するときにビュートランジションをトリガーします。 Turbo は、現在と次のページの両方に以下の `<meta>` 要素があるときに、ビュートランジションをトリガーします。 From e8ae0a0e1852e7534053bf2334b667b028173718 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 27 Aug 2024 10:50:01 +0900 Subject: [PATCH 025/183] =?UTF-8?q?=EF=BC=91=E3=81=A4=E3=81=A0=E3=81=91?= =?UTF-8?q?=E3=82=BB=E3=83=83=E3=83=88=E3=81=A7=E3=81=8D=E3=82=8B=E3=81=93?= =?UTF-8?q?=E3=81=A8=E3=81=8C=E3=82=8F=E3=81=8B=E3=82=8A=E3=82=84=E3=81=99?= =?UTF-8?q?=E3=81=84=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 82af0f66..47d7fc9f 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -418,7 +418,7 @@ Turbo は、現在と次のページの両方に以下の `<meta>` 要素があ <meta name="view-transition" content="same-origin" /> ``` -Turbo は `<html>` 要素に `data-turbo-visit-direction` 属性を追加することで、トランジションの方向を指定できます。その属性の値として以下のものを使えます。 +Turbo は `<html>` 要素に `data-turbo-visit-direction` 属性を追加することで、トランジションの方向を指定できます。その属性の値として以下のいずれかを使えます。 - `forward`: ページを全て変える方向 - `back`: ページを前のページに戻す方向 From f1a82f58b2ed8a38269983b9ee17e0d50192d139 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 8 Oct 2024 10:43:07 +0900 Subject: [PATCH 026/183] =?UTF-8?q?=E6=95=B0=E5=80=A4=E3=81=AE=E5=B7=A6?= =?UTF-8?q?=E5=8F=B3=E3=81=AB=E3=82=B9=E3=83=9A=E3=83=BC=E3=82=B9=E3=81=8C?= =?UTF-8?q?=E5=85=A5=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 47d7fc9f..79aa6316 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -722,7 +722,7 @@ Servers may also respond to form submissions with a [Turbo Streams](streams) mes ## ホバーでリンク先のプリフェッチ -Turbo は、ユーザーがリンクをクリックする前に発生した`mouseenter` イベントでリンク先を自動で読み込みます。これにより、リンク・ナビゲーションの待ち時間が短縮されます。通常、クリック・ナビゲーション単位で500から800ミリ秒の速度が向上します。 +Turbo は、ユーザーがリンクをクリックする前に発生した`mouseenter` イベントでリンク先を自動で読み込みます。これにより、リンク・ナビゲーションの待ち時間が短縮されます。通常、クリック・ナビゲーション単位で 500 から 800 ミリ秒の速度が向上します。 リンク先のプリフェッチは、Turbo v8からデフォルトで有効になっています。ただ、以下のメタタグをページに追加すれば、無効化できます。 From 6ac45916267cf6888228d6a687b9c3f545dffddb Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 8 Oct 2024 10:44:59 +0900 Subject: [PATCH 027/183] =?UTF-8?q?=E4=B8=80=E3=81=BE=E3=81=A8=E3=81=BE?= =?UTF-8?q?=E3=82=8A=E3=81=AE=E7=94=A8=E8=AA=9E=E3=81=A7=E3=81=82=E3=82=8B?= =?UTF-8?q?=E3=81=93=E3=81=A8=E3=81=8C=E3=82=8F=E3=81=8B=E3=82=8A=E3=82=84?= =?UTF-8?q?=E3=81=99=E3=81=84=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 79aa6316..6bf91cab 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -724,7 +724,7 @@ Servers may also respond to form submissions with a [Turbo Streams](streams) mes Turbo は、ユーザーがリンクをクリックする前に発生した`mouseenter` イベントでリンク先を自動で読み込みます。これにより、リンク・ナビゲーションの待ち時間が短縮されます。通常、クリック・ナビゲーション単位で 500 から 800 ミリ秒の速度が向上します。 -リンク先のプリフェッチは、Turbo v8からデフォルトで有効になっています。ただ、以下のメタタグをページに追加すれば、無効化できます。 +リンク先のプリフェッチは、Turbo v8 からデフォルトで有効になっています。ただ、以下のメタタグをページに追加すれば、無効化できます。 ```html <meta name="turbo-prefetch" content="false"> From 1e3c00eee27b708e0bd502405a28dce6f0ad90bb Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 8 Oct 2024 10:48:31 +0900 Subject: [PATCH 028/183] =?UTF-8?q?=E8=8B=B1=E8=AA=9E=E3=81=AE=E7=94=A8?= =?UTF-8?q?=E8=AA=9E=E3=81=AE=E5=B7=A6=E5=8F=B3=E3=81=AB=E3=82=B9=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=82=B9=E3=81=8C=E7=A9=BA=E3=81=84=E3=81=A6=E3=81=84?= =?UTF-8?q?=E3=81=AA=E3=81=8B=E3=81=A3=E3=81=9F=E3=81=AE=E3=81=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 6bf91cab..a080c69b 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -732,7 +732,7 @@ Turbo は、ユーザーがリンクをクリックする前に発生した`mous ユーザーが少しの間だけリンクをホバーしただけでリンク先をプリフェッチしないように、Turbo はリンク先をプリフェッチする前に100ミリ秒待ちます。 -HTML要素、あるいは、その祖先に `data-turbo-prefetch="false"`をつけることで、プリフェッチ機能を要素ごとに無効化できます。 +HTML要素、あるいは、その祖先に `data-turbo-prefetch="false"` をつけることで、プリフェッチ機能を要素ごとに無効化できます。 ```html <html> @@ -821,7 +821,7 @@ function hasSlowInternet() { ## リンク先をキャッシュにプリロード -[data-turbo-preload] 属性を使えば、リンク先をTurbo ドライブのキャッシュにプリロードできます。 +[data-turbo-preload] 属性を使えば、リンク先を Turbo ドライブのキャッシュにプリロードできます。 これにより、ページに初めてアクセスする前でもページのプレビューが提供され、ページアクセスが高速に感じられます。これはアプリケーション上で最も重要なページのプリロードに使えます。過剰な使用は、不要なコンテントを読み込むことになるので、避けてください。 From cac64ef0bd7abb72edbd6b6811e1d247cae0a86c Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 8 Oct 2024 10:56:23 +0900 Subject: [PATCH 029/183] =?UTF-8?q?=E7=9C=9F=E5=81=BD=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E3=81=A7=E3=81=82=E3=82=8B=E3=81=A8=E3=81=84=E3=81=86=E6=83=85?= =?UTF-8?q?=E5=A0=B1=E3=81=8C=E6=8A=9C=E3=81=91=E3=81=A6=E3=81=84=E3=81=9F?= =?UTF-8?q?=E3=81=AE=E3=81=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index a080c69b..115176b7 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -821,7 +821,7 @@ function hasSlowInternet() { ## リンク先をキャッシュにプリロード -[data-turbo-preload] 属性を使えば、リンク先を Turbo ドライブのキャッシュにプリロードできます。 +真偽属性の [data-turbo-preload] を使えば、リンク先を Turbo ドライブのキャッシュにプリロードできます。 これにより、ページに初めてアクセスする前でもページのプレビューが提供され、ページアクセスが高速に感じられます。これはアプリケーション上で最も重要なページのプリロードに使えます。過剰な使用は、不要なコンテントを読み込むことになるので、避けてください。 From cb898908ffeb7d1ef6c364a89808c5d7477eae30 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Tue, 8 Oct 2024 10:59:58 +0900 Subject: [PATCH 030/183] =?UTF-8?q?=E9=9D=9E=E5=B8=B8=E3=81=AB=E9=AB=98?= =?UTF-8?q?=E9=80=9F=E3=81=A7=E3=81=82=E3=82=8B=E3=81=93=E3=81=A8=E3=81=8C?= =?UTF-8?q?=E3=82=8F=E3=81=8B=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 115176b7..40135ee3 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -823,7 +823,7 @@ function hasSlowInternet() { 真偽属性の [data-turbo-preload] を使えば、リンク先を Turbo ドライブのキャッシュにプリロードできます。 -これにより、ページに初めてアクセスする前でもページのプレビューが提供され、ページアクセスが高速に感じられます。これはアプリケーション上で最も重要なページのプリロードに使えます。過剰な使用は、不要なコンテントを読み込むことになるので、避けてください。 +これにより、ページに初めてアクセスする前でもページのプレビューが提供されるので、ページアクセスが非常に高速に感じられます。これはアプリケーション上で最も重要なページのプリロードに使えます。過剰な使用は、不要なコンテントを読み込むことになるので、避けてください。 すべての `<a>` 要素がプリロードされるわけではありません。以下のような `[data-turbo-preload]` 属性を持つリンクはプリロードされません。 From b1db2cf501c411f6fa0f73d12cdf9ffb1d9eced4 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Sun, 3 Nov 2024 17:46:10 +0900 Subject: [PATCH 031/183] =?UTF-8?q?`data-turbo-preload`=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E3=82=92=E3=81=A4=E3=81=91=E3=82=8B=E3=81=93=E3=81=A8=E3=81=A7?= =?UTF-8?q?=E3=83=97=E3=83=AA=E3=83=AD=E3=83=BC=E3=83=89=E3=81=97=E3=81=AA?= =?UTF-8?q?=E3=81=84=E3=81=A8=E6=80=9D=E3=82=8F=E3=82=8C=E3=81=AA=E3=81=84?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 40135ee3..b5170348 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -825,7 +825,7 @@ function hasSlowInternet() { これにより、ページに初めてアクセスする前でもページのプレビューが提供されるので、ページアクセスが非常に高速に感じられます。これはアプリケーション上で最も重要なページのプリロードに使えます。過剰な使用は、不要なコンテントを読み込むことになるので、避けてください。 -すべての `<a>` 要素がプリロードされるわけではありません。以下のような `[data-turbo-preload]` 属性を持つリンクはプリロードされません。 +すべての `<a>` 要素がプリロードされるわけではありません。以下のようなリンクは `[data-turbo-preload]` 属性を付与してもプリロードしません。 * 他のドメインにアクセスするリンク * ある `<turbo-frame>` 要素に対して適用される `[data-turbo-frame]` 属性を持つリンク From 0aaed1989983929749211ebfa073656c4033649c Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Sun, 3 Nov 2024 20:49:41 +0900 Subject: [PATCH 032/183] =?UTF-8?q?=E7=BF=BB=E8=A8=B3=E3=81=97=E5=BF=98?= =?UTF-8?q?=E3=82=8C=E3=81=A6=E3=81=84=E3=81=9F=E6=96=87=E7=AB=A0=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index b5170348..73745b30 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -836,6 +836,8 @@ function hasSlowInternet() { * 先祖要素が `[data-turbo="false"]` 属性を持つリンク * 先祖要素が `[data-turbo-prefetch="false"]` 属性を持つリンク +また、[フレームの事前読み込み]や[フレームの遅延読み込み]を使ったページでも、プリロードはうまく噛み合います。ページの構造をプリロードし、興味があるコンテンツを読み込んでいる間、読み込んでいる状態を示すことができるからです。 + <br><br> プリロードされた `<a>` 要素は [turbo:before-fetch-request] と [turbo:before-fetch-response] イベントをディスパッチすることに注意してください。`turbo:before-fetch-request` イベントがプリロードにより発生したのかそれとも他のメカニズムにより発生したのかの区別は、リクエストの `X-Sec-Purpose` ヘッダーに `"prefetch"`がセットされているかどうかで確認できます(`X-Sec-Purpose` ヘッダーの値は `event.detail.fetchOptions.headers["X-Sec-Purpose"]` プロパティから取得できます)。 @@ -850,7 +852,8 @@ addEventListener("turbo:before-fetch-request", (event) => { }) ``` - +[フレームの事前読み込み]: /hotwire_ja/turbo/reference/frames#フレームの事前読み込み +[フレームの遅延読み込み]: /hotwire_ja/turbo/reference/frames#フレームの遅延読み込み [data-turbo-preload]: /hotwire_ja/turbo/reference/attributes#data-attributes [turbo:before-fetch-request]: /hotwire_ja/turbo/reference/events#turbo%3Abefore-fetch-request [turbo:before-fetch-response]: /hotwire_ja/turbo/reference/events#turbo%3Abefore-fetch-response From 380ec23520a0777b8414e7439fce0e73521193c2 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Mon, 4 Nov 2024 13:47:59 +0900 Subject: [PATCH 033/183] =?UTF-8?q?=E3=83=93=E3=83=A5=E3=83=BC=E3=83=88?= =?UTF-8?q?=E3=83=A9=E3=83=B3=E3=82=B8=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92?= =?UTF-8?q?=E5=AE=9F=E8=A1=8C=E3=81=99=E3=82=8B=E6=9D=A1=E4=BB=B6=E3=81=8C?= =?UTF-8?q?=E3=82=8F=E3=81=8B=E3=82=8A=E3=82=84=E3=81=99=E3=81=84=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 73745b30..3ad0ed5b 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -418,11 +418,11 @@ Turbo は、現在と次のページの両方に以下の `<meta>` 要素があ <meta name="view-transition" content="same-origin" /> ``` -Turbo は `<html>` 要素に `data-turbo-visit-direction` 属性を追加することで、トランジションの方向を指定できます。その属性の値として以下のいずれかを使えます。 +Turbo は `<html>` 要素に `data-turbo-visit-direction` 属性を追加することで、ビュートランジションを実行するアクセスを指定できます。その属性の値として以下のいずれかを使えます。 -- `forward`: ページを全て変える方向 -- `back`: ページを前のページに戻す方向 -- `none`: ページの一部を置き換える方向 +- `forward`: advance アクションのアクセス +- `back`: restore アクションのアクセス +- `none`: replace アクションのアクセス この属性を使えば、トランジション中で実行されるアニメーションをカスタマイズできます。 From b95aced6b7356b9343ff11e35c6844e088e0777f Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Sun, 23 Mar 2025 16:40:37 +0900 Subject: [PATCH 034/183] =?UTF-8?q?`a=20meaningful`=E3=81=AE=E8=A1=A8?= =?UTF-8?q?=E7=8F=BE=E3=81=8C=E5=90=AB=E3=81=BE=E3=82=8C=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 3ad0ed5b..39cf4f6c 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -836,7 +836,7 @@ function hasSlowInternet() { * 先祖要素が `[data-turbo="false"]` 属性を持つリンク * 先祖要素が `[data-turbo-prefetch="false"]` 属性を持つリンク -また、[フレームの事前読み込み]や[フレームの遅延読み込み]を使ったページでも、プリロードはうまく噛み合います。ページの構造をプリロードし、興味があるコンテンツを読み込んでいる間、読み込んでいる状態を示すことができるからです。 +また、[フレームの事前読み込み]や[フレームの遅延読み込み]を使ったページでも、プリロードはうまく噛み合います。ページの構造をプリロードし、興味があるコンテンツを読み込んでいる間、ユーザーに意味のある読み込み状態を示すことができるからです。 <br><br> From 496bab54c8e70f1ed096ac91c6df24f59d9f35cf Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Sun, 23 Mar 2025 16:53:14 +0900 Subject: [PATCH 035/183] =?UTF-8?q?=E5=8E=9F=E6=96=87=E3=81=AB=E3=82=B5?= =?UTF-8?q?=E3=82=AF=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=BF=E3=82=A4=E3=83=88?= =?UTF-8?q?=E3=83=AB=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 39cf4f6c..4b380164 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -15,6 +15,8 @@ ${toc} <details> <summary>原文</summary> +# Navigate with Turbo Drive + Turbo Drive is the part of Turbo that enhances page-level navigation. It watches for link clicks and form submissions, performs them in the background, and updates the page without doing a full reload. It's the evolution of a library previously known as [Turbolinks](https://github.com/turbolinks/turbolinks). </details> @@ -32,6 +34,8 @@ Turbo ドライブは、ページ・ナビゲーションを、ある*アクシ <details> <summary>原文</summary> +## Page Navigation Basics + Turbo Drive models page navigation as a *visit* to a *location* (URL) with an *action*. Visits represent the entire navigation lifecycle from click to render. That includes changing browser history, issuing the network request, restoring a copy of the page from cache, rendering the final response, and updating the scroll position. @@ -84,6 +88,8 @@ Turbo.visit("/edit", { action: "replace" }) <details> <summary>原文</summary> +## Application Visits + Application visits are initiated by clicking a Turbo Drive-enabled link, or programmatically by calling [`Turbo.visit(location)`](/reference/drive#turbodrivevisit). An application visit always issues a network request. When the response arrives, Turbo Drive renders its HTML and completes the visit. @@ -135,6 +141,8 @@ Applications using the Turbo Drive [iOS adapter](https://github.com/hotwired/tur <details> <summary>原文</summary> +## Restoration Visits + Turbo Drive automatically initiates a restoration visit when you navigate with the browser’s Back or Forward buttons. Applications using the [iOS](https://github.com/hotwired/turbo-ios) or [Android](https://github.com/hotwired/turbo-android) adapters initiate a restoration visit when moving backward in the navigation stack. ![Restore visit action](https://s3.amazonaws.com/turbolinks-docs/images/restore.svg) @@ -159,6 +167,8 @@ Application visits can be canceled before they start, regardless of whether they <details> <summary>原文</summary> +## Canceling Visits Before They Start + Application visits can be canceled before they start, regardless of whether they were initiated by a link click or a call to [`Turbo.visit`](/reference/drive#turbovisit). Listen for the `turbo:before-visit` event to be notified when a visit is about to start, and use `event.detail.url` (or `$event.originalEvent.detail.url`, when using jQuery) to check the visit’s location. Then cancel the visit by calling `event.preventDefault()`. @@ -188,6 +198,8 @@ addEventListener("turbo:before-render", (event) => { <details> <summary>原文</summary> +## Custom Rendering + Applications can customize the rendering process by adding a document-wide `turbo:before-render` event listener and overriding the `event.detail.render` property. For example, you could merge the response document's `<body>` element into the requesting document's `<body>` element with [morphdom](https://github.com/patrick-steele-idem/morphdom): @@ -225,6 +237,10 @@ document.addEventListener("turbo:before-render", async (event) => { <details> <summary>原文</summary> +## Pausing Rendering + +Applications can pause rendering and make additional preparations before continuing. + Listen for the `turbo:before-render` event to be notified when rendering is about to start, and pause it using `event.preventDefault()`. Once the preparation is done continue rendering by calling `event.detail.resume()`. An example use case is adding exit animation for visits: @@ -261,6 +277,8 @@ document.addEventListener("turbo:before-fetch-request", async (event) => { <details> <summary>原文</summary> +## Pausing Requests + Application can pause request and make additional preparation before it will be executed. Listen for the `turbo:before-fetch-request` event to be notified when a request is about to start, and pause it using `event.preventDefault()`. Once the preparation is done continue request by calling `event.detail.resume()`. @@ -294,6 +312,8 @@ document.addEventListener("turbo:before-fetch-request", async (event) => { <details> <summary>原文</summary> +## Performing Visits With a Different Method + By default, link clicks send a `GET` request to your server. But you can change this with `data-turbo-method`: ```html @@ -320,6 +340,8 @@ You should also consider that for accessibility reasons, it's better to use actu <details> <summary>原文</summary> +## Requiring Confirmation for a Visit + Decorate links with `data-turbo-confirm`, and confirmation will be required for a visit to proceed. ```html @@ -374,6 +396,8 @@ Turbo.session.drive = false <details> <summary>原文</summary> +## Disabling Turbo Drive on Specific Links or Forms + Turbo Drive can be disabled on a per-element basis by annotating the element or any of its ancestors with `data-turbo="false"`. ```html @@ -438,6 +462,8 @@ html[data-turbo-visit-direction="forward"]::view-transition-old(sidebar):only-ch <details> <summary>原文</summary> +## View transitions + In [browsers that support](https://caniuse.com/?search=View%20Transition%20API) the [View Transition API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API) Turbo can trigger view transitions when navigating between pages. Turbo triggers a view transition when both the current and the next page have this meta tag: @@ -494,6 +520,8 @@ html[data-turbo-visit-direction="forward"]::view-transition-old(sidebar):only-ch <details> <summary>原文</summary> +## Displaying Progress + During Turbo Drive navigation, the browser will not display its native progress indicator. Turbo Drive installs a CSS-based progress bar to provide feedback while issuing a request. The progress bar is enabled by default. It appears automatically for any page that takes longer than 500ms to load. (You can change this delay with the [`Turbo.setProgressBarDelay`](/reference/drive#turbodrivesetprogressbardelay) method.) @@ -540,6 +568,8 @@ In tandem with the progress bar, Turbo Drive will also toggle the [`[aria-busy]` <details> <summary>原文</summary> +## Reloading When Assets Change + As we saw above, Turbo Drive merges the contents of the `<head>` elements. However, if CSS or JavaScript change, that merge would evaluate them on top of the existing one. Typically, this would lead to undesirable conflicts. In such cases, it's necessary to fetch a completely new document through a standard, non-Ajax request. To accomplish this, just annotate those asset elements with `data-turbo-track="reload"` and include a version identifier in your asset URLs. The identifier could be a number, a last-modified timestamp, or better, a digest of the asset’s contents, as in the following example. @@ -571,6 +601,8 @@ To accomplish this, just annotate those asset elements with `data-turbo-track="r <details> <summary>原文</summary> +## Ensuring Specific Pages Trigger a Full Reload + You can ensure visits to a certain page will always trigger a full reload by including a `<meta name="turbo-visit-control">` element in the page’s `<head>`. ```html @@ -604,6 +636,8 @@ This setting may be useful as a workaround for third-party JavaScript libraries <details> <summary>原文</summary> +## Setting a Root Location + By default, Turbo Drive only loads URLs with the same origin—i.e. the same protocol, domain name, and port—as the current document. A visit to any other URL falls back to a full page load. In some cases, you may want to further scope Turbo Drive to a path on the same origin. For example, if your Turbo Drive application lives at `/app`, and the non-Turbo Drive help site lives at `/help`, links from the app to the help site shouldn’t use Turbo Drive. @@ -652,6 +686,8 @@ addEventListener("turbo:submit-start", ({ target }) => { <details> <summary>原文</summary> +## Form Submissions + Turbo Drive handles form submissions in a manner similar to link clicks. The key difference is that form submissions can issue stateful requests using the HTTP POST method, while link clicks only ever issue stateless HTTP GET requests. Throughout a submission, Turbo Drive will dispatch a series of [events][] that @@ -699,6 +735,8 @@ Turbo が POST リクエストに通常の200ステータスの応答を許さ <details> <summary>原文</summary> +## Redirecting After a Form Submission + After a stateful request from a form submission, Turbo Drive expects the server to return an [HTTP 303 redirect response](https://en.wikipedia.org/wiki/HTTP_303), which it will then follow and use to navigate and update the page without reloading. The exception to this rule is when the response is rendered with either a 4xx or 5xx status code. This allows form validation errors to be rendered by having the server respond with `422 Unprocessable Entity` and a broken server to display a "Something Went Wrong" screen on a `500 Internal Server Error`. @@ -716,6 +754,8 @@ If the form submission is a GET request, you may render the directly rendered re <details> <summary>原文</summary> +## Streaming After a Form Submission + Servers may also respond to form submissions with a [Turbo Streams](streams) message by sending the header `Content-Type: text/vnd.turbo-stream.html` followed by one or more `<turbo-stream>` elements in the response body. This lets you update multiple parts of the page without navigating. </details> @@ -772,6 +812,8 @@ function hasSlowInternet() { <details> <summary>原文</summary> +## Prefetching Links on Hover + Turbo can also speed up perceived link navigation latency by automatically loading links on `mouseenter` events, and before the user clicks the link. This usually leads to a speed bump of 500-800ms per click navigation. Prefetching links is enabled by default since Turbo v8, but you can disable it by adding this meta tag to your page: @@ -861,6 +903,8 @@ addEventListener("turbo:before-fetch-request", (event) => { <details> <summary>原文</summary> +## Preload Links Into the Cache + Preload links into Turbo Drive's cache using the [data-turbo-preload][] boolean attribute. This will make page transitions feel lightning fast by providing a preview of a page even before the first visit. Use it to preload the most important pages in your application. Avoid over usage, as it will lead to loading content that is not needed. From 986bb5e7bbad61d7bbfbcde136d3c66bb28d8084 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Sun, 23 Mar 2025 16:57:25 +0900 Subject: [PATCH 036/183] =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=88=E3=83=AB?= =?UTF-8?q?=E3=82=92=E5=8E=9F=E6=96=87=E3=81=AE=E6=96=87=E6=B3=95=E3=81=AB?= =?UTF-8?q?=E5=90=88=E3=82=8F=E3=81=9B=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 4b380164..235e69bf 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -177,7 +177,7 @@ Restoration visits cannot be canceled and do not fire `turbo:before-visit`. Turb </details> -## 描画のカスタム +## 描画処理をカスタマイズする ドキュメント全体に対して `turbo:before-render` イベントリスナーを追加し、 `event.detail.render` プロパティをオーバーライドすることで、アプリケーションの描画プロセスをカスタマイズできます。 From ee9569e57d6d3547808a749f3e7fc183c60b03b4 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Sun, 23 Mar 2025 16:58:41 +0900 Subject: [PATCH 037/183] =?UTF-8?q?=E6=96=87=E8=A8=80=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 235e69bf..9e14868f 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -179,7 +179,7 @@ Restoration visits cannot be canceled and do not fire `turbo:before-visit`. Turb ## 描画処理をカスタマイズする -ドキュメント全体に対して `turbo:before-render` イベントリスナーを追加し、 `event.detail.render` プロパティをオーバーライドすることで、アプリケーションの描画プロセスをカスタマイズできます。 +ドキュメント全体に対して `turbo:before-render` イベントリスナーを追加し、 `event.detail.render` プロパティを上書きすることで、アプリケーションの描画処理をカスタマイズできます。 例えば、[morphdom]で、リクエストを投げたドキュメントの `<body>` 要素を、レスポンスのドキュメントにある `<body>` 要素にマージできます。 From 3f2f604e975f374b397c45a70e81a5f9940eb678 Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Sun, 23 Mar 2025 17:10:04 +0900 Subject: [PATCH 038/183] =?UTF-8?q?view=20transition=E3=81=AE=E7=BF=BB?= =?UTF-8?q?=E8=A8=B3=E3=82=92mdn=E3=81=AE=E7=BF=BB=E8=A8=B3=E3=81=AB?= =?UTF-8?q?=E5=90=88=E3=82=8F=E3=81=9B=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 9e14868f..805443ee 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -432,17 +432,17 @@ Turbo.session.drive = false </details> -## ビュートランジション +## ビュー遷移 -[ビュートランジション API]を[サポートしているブラウザ]では、Turbo はページ間を移動するときにビュートランジションをトリガーします。 +[ビュー遷移 API]を[サポートしているブラウザ]では、Turbo はページ間を移動するときにビュー遷移を発火をします。 -Turbo は、現在と次のページの両方に以下の `<meta>` 要素があるときに、ビュートランジションをトリガーします。 +Turbo は、現在と次のページの両方に以下の `<meta>` 要素があるときに、ビュー遷移を発火します。 ```html <meta name="view-transition" content="same-origin" /> ``` -Turbo は `<html>` 要素に `data-turbo-visit-direction` 属性を追加することで、ビュートランジションを実行するアクセスを指定できます。その属性の値として以下のいずれかを使えます。 +Turbo は `<html>` 要素に `data-turbo-visit-direction` 属性を追加することで、ビュート遷移を実行するアクセスを指定できます。その属性の値として以下のいずれかを使えます。 - `forward`: advance アクションのアクセス - `back`: restore アクションのアクセス @@ -457,7 +457,7 @@ html[data-turbo-visit-direction="forward"]::view-transition-old(sidebar):only-ch ``` [サポートしているブラウザ]: https://caniuse.com/?search=View%20Transition%20API -[ビュートランジション API]: https://developer.mozilla.org/ja/docs/Web/API/View_Transitions_API +[ビュー遷移 API]: https://developer.mozilla.org/ja/docs/Web/API/View_Transitions_API <details> <summary>原文</summary> From 0a3457ee70dac4c3d7ebf6706ea460c7d6927bbb Mon Sep 17 00:00:00 2001 From: Yasuhiro Sugawara <yasu@sonicgarden.jp> Date: Sun, 23 Mar 2025 17:12:32 +0900 Subject: [PATCH 039/183] =?UTF-8?q?=E6=96=87=E8=A8=80=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 805443ee..07c76d4c 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -555,7 +555,7 @@ In tandem with the progress bar, Turbo Drive will also toggle the [`[aria-busy]` 前述した通り、Turbo ドライブは `<head>` 要素のコンテントをマージします。しかし、CSS または JavaScript が変更された場合、これらCSS、JavaScriptのマージは既存のものを評価した上で行われます。大抵、このマージは厄介なコンフリクトを引き起こします。そのような場合、Ajaxではない標準のリクエストで新しいドキュメントを完全な形で取得する必要があります。 -これは、アセット要素に `data-turbo-track="reload"` をつけてアノテーションし、アセットのURLにバージョン識別番号をつけるだけで実現できます。識別子は番号でも、最終更新日時でもよいですし、アセットの内容のダイジェストならもっといいでしょう。次の例のようにします。 +これは、アセット要素に `data-turbo-track="reload"` をつけてアノテーションし、アセットのURLにバージョン識別番号をつけるだけで実現できます。識別子は番号でも、最終更新日時でもよいですし、次の例のようにアセットの内容のダイジェストならもっといいでしょう。 ```html <head> From e5e659ec1e445bdbcbc0226f64d9f61ce46f4b4c Mon Sep 17 00:00:00 2001 From: akira888 <a.cup.of.happiness@gmail.com> Date: Fri, 28 Mar 2025 09:42:55 +0900 Subject: [PATCH 040/183] =?UTF-8?q?chore:=20merge=E3=81=AB=E3=82=88?= =?UTF-8?q?=E3=82=8B=E3=82=B3=E3=83=9F=E3=83=83=E3=83=88=E3=83=8F=E3=83=83?= =?UTF-8?q?=E3=82=B7=E3=83=A5=E3=81=AE=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 07c76d4c..ab638cd2 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -2,7 +2,7 @@ title: "Turbo ドライブを使ったナビゲート" description: "Turbo ドライブは、ページ全体の再読み込みの必要を無くすことで、リンクとフォームの送信を高速化します。" order: 2 -commit: "3b06afb" +commit: "c397c31" --- # Turbo ドライブを使ったナビゲート From daca4c7a980c40e9aee7889baec5916a44d9fcdd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 20:20:14 +0000 Subject: [PATCH 041/183] Bump sass from 1.86.0 to 1.86.3 Bumps [sass](https://github.com/sass/dart-sass) from 1.86.0 to 1.86.3. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.86.0...1.86.3) --- updated-dependencies: - dependency-name: sass dependency-version: 1.86.3 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2049a9b4..86b0aed0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "markdown-it-anchor": "^9.2.0", "markdown-it-toc-done-right": "^4.2.0", "npm-run-all": "^4.1.5", - "sass": "^1.86.0" + "sass": "^1.86.3" } }, "node_modules/@11ty/dependency-tree": { @@ -3449,9 +3449,9 @@ } }, "node_modules/sass": { - "version": "1.86.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.86.0.tgz", - "integrity": "sha512-zV8vGUld/+mP4KbMLJMX7TyGCuUp7hnkOScgCMsWuHtns8CWBoz+vmEhoGMXsaJrbUP8gj+F1dLvVe79sK8UdA==", + "version": "1.86.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.86.3.tgz", + "integrity": "sha512-iGtg8kus4GrsGLRDLRBRHY9dNVA78ZaS7xr01cWnS7PEMQyFtTqBiyCrfpTYTZXRWM94akzckYjh8oADfFNTzw==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index c72ef788..854800a4 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "markdown-it-anchor": "^9.2.0", "markdown-it-toc-done-right": "^4.2.0", "npm-run-all": "^4.1.5", - "sass": "^1.86.0" + "sass": "^1.86.3" }, "scripts": { "serve": "npm-run-all -s clean build:11ty build:css -p watch:** --silent", From 0c06b15a44a8305db539b83c8dac021cc35afdaf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com> Date: Tue, 4 Mar 2025 00:26:58 +0000 Subject: [PATCH 042/183] updated translation target commit --- turbo/handbook/installing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/installing.md b/turbo/handbook/installing.md index 199dc4f2..38c53f0d 100644 --- a/turbo/handbook/installing.md +++ b/turbo/handbook/installing.md @@ -2,7 +2,7 @@ title: "アプリケーションに Turbo をインストール" description: "アプリケーションにTurboをインストールする方法を学びましょう。" order: 8 -commit: "0b2c287" +commit: "b8487ee" --- # アプリケーションに Turbo をインストール From a3903904a7abc4ef99571fc82e7635cd51fcef0e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com> Date: Sun, 30 Mar 2025 00:30:53 +0000 Subject: [PATCH 043/183] updated translation target commit --- turbo/handbook/installing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/installing.md b/turbo/handbook/installing.md index 38c53f0d..a85f1a59 100644 --- a/turbo/handbook/installing.md +++ b/turbo/handbook/installing.md @@ -2,7 +2,7 @@ title: "アプリケーションに Turbo をインストール" description: "アプリケーションにTurboをインストールする方法を学びましょう。" order: 8 -commit: "b8487ee" +commit: "5731979" --- # アプリケーションに Turbo をインストール From f43424dc8f2b38231e87d18d80a37451a45119ac Mon Sep 17 00:00:00 2001 From: yakitorii <yuki.torii.23@gmail.com> Date: Fri, 4 Apr 2025 10:01:52 +0900 Subject: [PATCH 044/183] =?UTF-8?q?=E7=BF=BB=E8=A8=B3=E3=81=A8=E5=8E=9F?= =?UTF-8?q?=E6=96=87=E3=82=92=E3=82=A2=E3=83=83=E3=83=97=E3=83=87=E3=83=BC?= =?UTF-8?q?=E3=83=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/installing.md | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/turbo/handbook/installing.md b/turbo/handbook/installing.md index a85f1a59..61e7b49d 100644 --- a/turbo/handbook/installing.md +++ b/turbo/handbook/installing.md @@ -20,36 +20,60 @@ Turbo can either be referenced in compiled form via the Turbo distributable scri ## コンパイル済みスクリプト -Skypack のような CDN バンドラーを利用してリリースされた最新の Turbo を使用できます。詳細は、[https://www.skypack.dev/view/@hotwired/turbo](https://www.skypack.dev/view/@hotwired/turbo) を参照してください。 +jsDelivr のような CDN バンドラーを利用してリリースされた最新の Turbo を使用できます。 +下の `<script>` タグをアプリケーションの `<head>` の中に含めるだけです。 または[unpkgからコンパイルされたパッケージをダウンロードできます](https://unpkg.com/browse/@hotwired/turbo@latest/dist/)。 <details> <summary>原文</summary> ## In Compiled Form +You can float on the latest release of Turbo using a CDN bundler like jsDelivr. Just include a `<script>` tag in the `<head>` of your application: -You can float on the latest release of Turbo using a CDN bundler like Skypack. See <a href="https://www.skypack.dev/view/@hotwired/turbo">https://www.skypack.dev/view/@hotwired/turbo</a> for more details. Or <a href="https://unpkg.com/browse/@hotwired/turbo@latest/dist/">download the compiled packages from unpkg</a>. +```html +<head> + <script type="module" src="https://cdn.jsdelivr.net/npm/@hotwired/turbo@latest/dist/turbo.es2017-esm.min.js"></script> +</head> +``` + +Or <a href="https://unpkg.com/browse/@hotwired/turbo@latest/dist/">download the compiled packages from unpkg</a>. </details> ## npm パッケージ -パッケージングツールの `npm` や `yarn` を利用して npm から Turbo をインストールできます。下記のようにコード内で require や import できます。 +パッケージングツールの `npm` や `yarn` を利用して npm から Turbo をインストールできます。 +もし `Turbo.visit()` といった Turbo の関数を使うなら、下記のように Turbo の関数をコードにインポートします。 ```javascript import * as Turbo from "@hotwired/turbo"; ``` +もし `Turbo.visit()` のような Turbo の関数を使わ *ない* 場合は、下記のようにTurbo の関数をインポートしてください。 +これにより、一部のバンドラーにおいてツリーシェイクや未使用変数の問題を回避することができます。詳しくはMDNの [副作用のためだけにモジュールをインポートする](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/import#%E5%89%AF%E4%BD%9C%E7%94%A8%E3%81%AE%E3%81%9F%E3%82%81%E3%81%A0%E3%81%91%E3%81%AB%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%82%92%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B)をご覧ください。 + +```javascript +import "@hotwired/turbo"; +``` + <details> <summary>原文</summary> ## As An npm Package -You can install Turbo from npm via the `npm` or `yarn` packaging tools. Then require or import that in your code: +You can install Turbo from npm via the `npm` or `yarn` packaging tools. + +If you using any Turbo functions such as `Turbo.visit()` import the `Turbo` functions into your code: ```javascript import * as Turbo from "@hotwired/turbo" ``` +If you're *not* using any Turbo functions such as `Turbo.visit()` import the library. This avoids issues with tree-shaking and unused variables in some bundlers. See [Import a module for its side effects only](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/import#import_a_module_for_its_side_effects_only) on MDN. + +```javascript +import "@hotwired/turbo"; +``` + </details> ## Ruby on Rails アプリケーション From ea9b3f0582001a492ef4c650cb05ebb316cf5b60 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 00:27:58 +0000 Subject: [PATCH 045/183] updated translation target commit --- turbo/handbook/installing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/installing.md b/turbo/handbook/installing.md index 61e7b49d..f08a60a3 100644 --- a/turbo/handbook/installing.md +++ b/turbo/handbook/installing.md @@ -2,7 +2,7 @@ title: "アプリケーションに Turbo をインストール" description: "アプリケーションにTurboをインストールする方法を学びましょう。" order: 8 -commit: "5731979" +commit: "14aafc8" --- # アプリケーションに Turbo をインストール From 49785b03677acb40b9923df9d46840dfc8d2c159 Mon Sep 17 00:00:00 2001 From: Akira Yagi <a.cup.of.happiness@gmail.com> Date: Fri, 11 Apr 2025 09:53:20 +0900 Subject: [PATCH 046/183] =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=82=AB=E3=83=AB?= =?UTF-8?q?=E7=92=B0=E5=A2=83=E3=81=A7=E3=82=B5=E3=82=A4=E3=83=88=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E7=A2=BA=E8=AA=8D=E3=81=84=E3=81=9F=E3=81=A0=E3=81=8D?= =?UTF-8?q?=E3=81=9F=E3=81=84=E6=97=A8=E3=82=92=E8=BF=BD=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bf4a79ad..ecf88b2b 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ ## はじめに 翻訳作業は、このリポジトリをフォークして、フォークしたリポジトリで作業を行ってください。 どのページを翻訳するかは[issues](https://github.com/everyleaf/hotwire_ja/issues)ベースで行います。 +追記: Git scraping で差分を自動検出しPRに起こす仕組みを試験導入中です 「新規翻訳」というラベルのついているissueで着手の宣言を行ってから作業を始めてください。 すでに着手宣言されている、もしくはアサインされているissueしかない場合は、しばらくお待ちください。 @@ -14,7 +15,8 @@ 1. このリポジトリをフォークします 2. issueのdescriptionにある翻訳対象のリンクとファイルの設置場所を参考に、mdファイルをブランチに追加します 3. 原文(英文)を`<details>~</details>`にしまい込む形で残してください(コードサンプルは含まない)。訳文の1行下に対応する原文を置きます。`<details>`には`<summary>原文</summary>`をつけてください([見本](https://github.com/everyleaf/hotwire_ja/blob/281d8a39097cbacc9c36331fd7e496c6d8729c3e/turbo/reference/events.md)) -4. PRを作成する際は該当issueへのリンクと、着手した原文のコミットハッシュをdescriptionに記載の上、レビューに出してください +4. ローカルで表示確認していただきたいです。projectのTOPディレクトリにて `npm run serve` を実行していただくと、ローカル環境で静的サイトが構築されます。 +5. PRを作成する際は該当issueへのリンクと、着手した原文のコミットハッシュをdescriptionに記載の上、レビューに出してください ## 気にしていただきたいこと - 文中のリンク先について From 9b6afef2457893fac6afa66fbefa75eaa344e81b Mon Sep 17 00:00:00 2001 From: daiki tagami <toda0310@gmail.com> Date: Sat, 5 Apr 2025 17:10:49 +0900 Subject: [PATCH 047/183] =?UTF-8?q?turbo=20handbook=20streams=E9=83=A8?= =?UTF-8?q?=E5=88=86=E3=81=AE=E7=BF=BB=E8=A8=B3=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/streams.md | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/turbo/handbook/streams.md b/turbo/handbook/streams.md index 4faa64f7..928ebb1f 100644 --- a/turbo/handbook/streams.md +++ b/turbo/handbook/streams.md @@ -2,7 +2,7 @@ title: "Turbo ストリームを利用してみよう" description: "Turbo ストリームは、WebSocketやSSEを利用して、またはフォームの送信に応答して、HTMLと一連のCRUDのようなアクションを使用してページの変更を配信します。" order: 5 -commit: "93fa57b" +commit: "5731979" --- # Turbo ストリームを利用してみよう @@ -24,7 +24,7 @@ They can be used to surgically update the DOM after a user action such as removi ## メッセージとアクションの配信 -一つの Turbo ストリームメッセージは、`<turbo-stream>` 要素から構成される HTML の一部です。そのストリームメッセージは、下記の8つの実行可能なストリームアクションを示します。 +一つの Turbo ストリームメッセージは、`<turbo-stream>` 要素から構成される HTML の一部です。そのストリームメッセージは、下記の9つの実行可能なストリームアクションを示します。 ```html <turbo-stream action="append" target="messages"> @@ -105,10 +105,12 @@ Turboストリームは、ドキュメント内のどんな要素でも、[id](h WebSocket、SSE やフォーム送信の応答としての 1 つのストリームメッセージの中で、任意の数のストリーム要素をレンダリングできます。 +また、ページ内に挿入された `<turbo-stream>` 要素は(フルページやフレームのロードなどによって)、Turboによって処理された後DOMから削除されます。これにより、ページやフレームが読み込まれたときにストリームアクションが自動的に実行されるようになります。 + <details> <summary>原文</summary> -A Turbo Streams message is a fragment of HTML consisting of `<turbo-stream>` elements. The stream message below demonstrates the eight possible stream actions: +A Turbo Streams message is a fragment of HTML consisting of `<turbo-stream>` elements. The stream message below demonstrates the nine possible stream actions: ```html <turbo-stream action="append" target="messages"> @@ -196,6 +198,8 @@ resolved by an [id](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_att You can render any number of stream elements in a single stream message from a WebSocket, SSE or in response to a form submission. +Also, any `<turbo-stream>` element that's inserted into the page (e.g. through full page or frame load), will be processed by Turbo and then removed from the dom. This allows stream actions to be executed automatically when a page or frame is loaded. + </details> ## 複数のターゲットを利用したアクション @@ -411,7 +415,7 @@ The same is especially true for WebSocket updates. On poor connections, or if th ## JavaScript の実行に関してはどうでしょう? -Turbo ストリームは、意図的に 8 つのアクションを利用するように制限します。それは、append, prepend, (insert) before, (insert) after, replace, update, remove そして refresh です。 +Turbo ストリームは、意図的に 9 つのアクションを利用するように制限します。それは、append, prepend, (insert) before, (insert) after, replace, update, remove, morph そして refresh です。 もし上記のアクションが実行されたときに、追加の挙動をトリガーしたいならば、[Stimulus](https://stimulus.hotwired.dev) コントローラーを利用することで、その挙動を実現すべきです。 この制限によって、Turbo ストリームがワイヤー上での HTML 配信という必要不可欠なタスクに専念することができ、追加のロジックは JavaScript 専用のファイル内に留められます。 @@ -421,16 +425,16 @@ Turbo ストリームの重要な利点は、続けて起こる全ての更新 <details> <summary>原文</summary> -Turbo Streams consciously restricts you to eight actions: append, prepend, (insert) before, (insert) after, replace, update, remove, and refresh. If you want to trigger additional behavior when these actions are carried out, you should attach behavior using <a href="https://stimulus.hotwired.dev">Stimulus</a> controllers. This restriction allows Turbo Streams to focus on the essential task of delivering HTML over the wire, leaving additional logic to live in dedicated JavaScript files. +Turbo Streams consciously restricts you to nine actions: append, prepend, (insert) before, (insert) after, replace, update, remove, morph, and refresh. If you want to trigger additional behavior when these actions are carried out, you should attach behavior using <a href="https://stimulus.hotwired.dev">Stimulus</a> controllers. This restriction allows Turbo Streams to focus on the essential task of delivering HTML over the wire, leaving additional logic to live in dedicated JavaScript files. Embracing these constraints will keep you from turning individual responses into a jumble of behaviors that cannot be reused and which make the app hard to follow. The key benefit from Turbo Streams is the ability to reuse templates for initial rendering of a page through all subsequent updates. </details> ## カスタム・アクション -デフォルトでは、Turbo ストリームは [`action` 属性に8つの値](https://turbo.hotwired.dev/reference/streams#the-seven-actions)をサポートしています。もしアプリケーションが他の属性をサポートする必要が出てきたら、`event.detail.render` 関数をオーバーライドしましょう。 +デフォルトでは、Turbo ストリームは [`action` 属性に9つの値](https://turbo.hotwired.dev/reference/streams#the-seven-actions)をサポートしています。もしアプリケーションが他の属性をサポートする必要が出てきたら、`event.detail.render` 関数をオーバーライドしましょう。 -例えば、8つのアクションに加えて `<turbo-stream>` 要素に `[action="alert"]` あるいは `[action="log"]` をサポートするよう拡張したい場合、`turbo:before-stream-render` リスナーにカスタムした振る舞いを宣言できます。 +例えば、9つのアクションに加えて `<turbo-stream>` 要素に `[action="alert"]` あるいは `[action="log"]` をサポートするよう拡張したい場合、`turbo:before-stream-render` リスナーにカスタムした振る舞いを宣言できます。 ```javascript @@ -464,9 +468,9 @@ StreamActions.log = function () { <details> <summary>原文</summary> -By default, Turbo Streams support [eight values for its `action` attribute](https://turbo.hotwired.dev/reference/streams#the-seven-actions). If your application needs to support other behaviors, you can override the `event.detail.render` function. +By default, Turbo Streams support [nine values for its `action` attribute](https://turbo.hotwired.dev/reference/streams#the-seven-actions). If your application needs to support other behaviors, you can override the `event.detail.render` function. -For example, if you'd like to expand upon the eight actions to support `<turbo-stream>` elements with `[action="alert"]` or `[action="log"]`, you could declare a `turbo:before-stream-render` listener to provide custom behavior: +For example, if you'd like to expand upon the nine actions to support `<turbo-stream>` elements with `[action="alert"]` or `[action="log"]`, you could declare a `turbo:before-stream-render` listener to provide custom behavior: ```javascript addEventListener("turbo:before-stream-render", ((event) => { @@ -506,7 +510,7 @@ Turbo に付随した全ての技術の中で、バックエンドフレーム この gem は、Rails 内の WebScoket と非同期なレンダリングに対する組み込み済みのサポートを、それぞれ Action Cable や Active Job フレームワークを利用して実現しています。 Active Record にミックスインされた [Broadcastable](https://github.com/hotwired/turbo-rails/blob/main/app/models/concerns/turbo/broadcastable.rb) を利用することで、 -Webscoket の更新を直接ドメインモデルからトリガーできます。さらに [Turbo::Streams::TagBuilder](https://github.com/hotwired/turbo-rails/blob/main/app/models/turbo/streams/tag_builder.rb) を利用することで、インラインなコントローラーのレスポンスまたは専用テンプレート内で `<turbo-stream>` 要素をレンダリングできます。同時に、シンプルな DSL を通して、レンダリングに関する 5 つのアクションを実行できます。 +Webscoket の更新を直接ドメインモデルからトリガーできます。さらに [Turbo::Streams::TagBuilder](https://github.com/hotwired/turbo-rails/blob/main/app/models/turbo/streams/tag_builder.rb) を利用することで、インラインなコントローラーのレスポンスまたは専用テンプレート内で `<turbo-stream>` 要素をレンダリングできます。同時に、シンプルな DSL を通して、レンダリングに関する 8 つのアクションを実行できます。 しかしながら、Trubo 自体は、バックエンドに対して一切関知しません。他のエコシステム内の異なるフレームワークで密な統合を作成するためにも Rails に対する参考実装をみることを推奨します。 @@ -528,7 +532,7 @@ Mercure は、サーバーアプリケーションに対して便利な方法を <summary>原文</summary> Of all the techniques that are included with Turbo, it's with Turbo Streams you'll see the biggest advantage from close integration with your backend framework. As part of the official Hotwire suite, we've created a reference implementation for what such an integration can look like in the <a href="https://github.com/hotwired/turbo-rails">turbo-rails gem</a>. This gem relies on the built-in support for both WebSockets and asynchronous rendering present in Rails through the Action Cable and Active Job frameworks, respectively. -Using the <a href="https://github.com/hotwired/turbo-rails/blob/main/app/models/concerns/turbo/broadcastable.rb">Broadcastable</a> concern mixed into Active Record, you can trigger WebSocket updates directly from your domain model. And using the <a href="https://github.com/hotwired/turbo-rails/blob/main/app/models/turbo/streams/tag_builder.rb">Turbo::Streams::TagBuilder</a>, you can render `<turbo-stream>` elements in inline controller responses or dedicated templates, invoking the five actions with associated rendering through a simple DSL. +Using the <a href="https://github.com/hotwired/turbo-rails/blob/main/app/models/concerns/turbo/broadcastable.rb">Broadcastable</a> concern mixed into Active Record, you can trigger WebSocket updates directly from your domain model. And using the <a href="https://github.com/hotwired/turbo-rails/blob/main/app/models/turbo/streams/tag_builder.rb">Turbo::Streams::TagBuilder</a>, you can render `<turbo-stream>` elements in inline controller responses or dedicated templates, invoking the eight actions with associated rendering through a simple DSL. Turbo itself is completely backend-agnostic, though. So we encourage other frameworks in other ecosystems to look at the reference implementation provided for Rails to create their own tight integration. From 9ac2c273dd6fe8b90fd3570fcadae5c496175558 Mon Sep 17 00:00:00 2001 From: Tagami Daiki <toda0310@gmail.com> Date: Fri, 11 Apr 2025 14:09:21 +0900 Subject: [PATCH 048/183] =?UTF-8?q?=E6=9C=80=E6=96=B0=E3=81=AEcommit?= =?UTF-8?q?=E3=83=8F=E3=83=83=E3=82=B7=E3=83=A5=E5=80=A4=E3=81=AB=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/streams.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/streams.md b/turbo/handbook/streams.md index 928ebb1f..832c5ebb 100644 --- a/turbo/handbook/streams.md +++ b/turbo/handbook/streams.md @@ -2,7 +2,7 @@ title: "Turbo ストリームを利用してみよう" description: "Turbo ストリームは、WebSocketやSSEを利用して、またはフォームの送信に応答して、HTMLと一連のCRUDのようなアクションを使用してページの変更を配信します。" order: 5 -commit: "5731979" +commit: "14aafc8" --- # Turbo ストリームを利用してみよう From 50459509ec929f00b6f390c3c20c92e311c6c1ac Mon Sep 17 00:00:00 2001 From: daiki tagami <toda0310@gmail.com> Date: Fri, 11 Apr 2025 22:52:43 +0900 Subject: [PATCH 049/183] Update turbo/handbook/streams.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 半角英数字の前後にスペースを入れる Co-authored-by: takuya kodama <a.s.takuya1026@gmail.com> --- turbo/handbook/streams.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/streams.md b/turbo/handbook/streams.md index 832c5ebb..3fc52858 100644 --- a/turbo/handbook/streams.md +++ b/turbo/handbook/streams.md @@ -105,7 +105,7 @@ Turboストリームは、ドキュメント内のどんな要素でも、[id](h WebSocket、SSE やフォーム送信の応答としての 1 つのストリームメッセージの中で、任意の数のストリーム要素をレンダリングできます。 -また、ページ内に挿入された `<turbo-stream>` 要素は(フルページやフレームのロードなどによって)、Turboによって処理された後DOMから削除されます。これにより、ページやフレームが読み込まれたときにストリームアクションが自動的に実行されるようになります。 +また、ページ内に挿入された `<turbo-stream>` 要素は(フルページやフレームのロードなどによって)、Turbo によって処理された後、DOM から削除されます。これにより、ページやフレームが読み込まれたときにストリームアクションが自動的に実行されるようになります。 <details> <summary>原文</summary> From 0a2ff27203cedd4376badfae5caa9f5e69989534 Mon Sep 17 00:00:00 2001 From: daiki tagami <toda0310@gmail.com> Date: Fri, 11 Apr 2025 22:53:13 +0900 Subject: [PATCH 050/183] =?UTF-8?q?=E5=8D=8A=E8=A7=92=E8=8B=B1=E6=95=B0?= =?UTF-8?q?=E5=AD=97=E3=81=AE=E5=89=8D=E5=BE=8C=E3=81=AB=E3=82=B9=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=82=B9=E3=82=92=E5=85=A5=E3=82=8C=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: takuya kodama <a.s.takuya1026@gmail.com> --- turbo/handbook/streams.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/streams.md b/turbo/handbook/streams.md index 3fc52858..098465cf 100644 --- a/turbo/handbook/streams.md +++ b/turbo/handbook/streams.md @@ -432,7 +432,7 @@ Embracing these constraints will keep you from turning individual responses into ## カスタム・アクション -デフォルトでは、Turbo ストリームは [`action` 属性に9つの値](https://turbo.hotwired.dev/reference/streams#the-seven-actions)をサポートしています。もしアプリケーションが他の属性をサポートする必要が出てきたら、`event.detail.render` 関数をオーバーライドしましょう。 +デフォルトでは、Turbo ストリームは [`action` 属性に 9 つの値](https://turbo.hotwired.dev/reference/streams#the-seven-actions)をサポートしています。もしアプリケーションが他の属性をサポートする必要が出てきたら、`event.detail.render` 関数をオーバーライドしましょう。 例えば、9つのアクションに加えて `<turbo-stream>` 要素に `[action="alert"]` あるいは `[action="log"]` をサポートするよう拡張したい場合、`turbo:before-stream-render` リスナーにカスタムした振る舞いを宣言できます。 From bcdcc365b84345d3b738e48990a79fd7e24c4f2c Mon Sep 17 00:00:00 2001 From: daiki tagami <toda0310@gmail.com> Date: Fri, 11 Apr 2025 22:53:25 +0900 Subject: [PATCH 051/183] =?UTF-8?q?=E5=8D=8A=E8=A7=92=E8=8B=B1=E6=95=B0?= =?UTF-8?q?=E5=AD=97=E3=81=AE=E5=89=8D=E5=BE=8C=E3=81=AB=E3=82=B9=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=82=B9=E3=82=92=E5=85=A5=E3=82=8C=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: takuya kodama <a.s.takuya1026@gmail.com> --- turbo/handbook/streams.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/streams.md b/turbo/handbook/streams.md index 098465cf..46857de3 100644 --- a/turbo/handbook/streams.md +++ b/turbo/handbook/streams.md @@ -434,7 +434,7 @@ Embracing these constraints will keep you from turning individual responses into デフォルトでは、Turbo ストリームは [`action` 属性に 9 つの値](https://turbo.hotwired.dev/reference/streams#the-seven-actions)をサポートしています。もしアプリケーションが他の属性をサポートする必要が出てきたら、`event.detail.render` 関数をオーバーライドしましょう。 -例えば、9つのアクションに加えて `<turbo-stream>` 要素に `[action="alert"]` あるいは `[action="log"]` をサポートするよう拡張したい場合、`turbo:before-stream-render` リスナーにカスタムした振る舞いを宣言できます。 +例えば、9 つのアクションに加えて `<turbo-stream>` 要素に `[action="alert"]` あるいは `[action="log"]` をサポートするよう拡張したい場合、`turbo:before-stream-render` リスナーにカスタムした振る舞いを宣言できます。 ```javascript From a2ae6c53d06a4eee3eeefc88dccfb0b1fd70f3bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 May 2025 19:58:05 +0000 Subject: [PATCH 052/183] Bump sass from 1.86.3 to 1.88.0 Bumps [sass](https://github.com/sass/dart-sass) from 1.86.3 to 1.88.0. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.86.3...1.88.0) --- updated-dependencies: - dependency-name: sass dependency-version: 1.88.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 86b0aed0..078b7b8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "markdown-it-anchor": "^9.2.0", "markdown-it-toc-done-right": "^4.2.0", "npm-run-all": "^4.1.5", - "sass": "^1.86.3" + "sass": "^1.88.0" } }, "node_modules/@11ty/dependency-tree": { @@ -3449,9 +3449,9 @@ } }, "node_modules/sass": { - "version": "1.86.3", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.86.3.tgz", - "integrity": "sha512-iGtg8kus4GrsGLRDLRBRHY9dNVA78ZaS7xr01cWnS7PEMQyFtTqBiyCrfpTYTZXRWM94akzckYjh8oADfFNTzw==", + "version": "1.88.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.88.0.tgz", + "integrity": "sha512-sF6TWQqjFvr4JILXzG4ucGOLELkESHL+I5QJhh7CNaE+Yge0SI+ehCatsXhJ7ymU1hAFcIS3/PBpjdIbXoyVbg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 854800a4..eca99ad8 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "markdown-it-anchor": "^9.2.0", "markdown-it-toc-done-right": "^4.2.0", "npm-run-all": "^4.1.5", - "sass": "^1.86.3" + "sass": "^1.88.0" }, "scripts": { "serve": "npm-run-all -s clean build:11ty build:css -p watch:** --silent", From fc6700ee9fb38949af52a5ee1584e94a9a59573a Mon Sep 17 00:00:00 2001 From: yakitorii <yuki.torii.23@gmail.com> Date: Fri, 21 Mar 2025 09:25:40 +0900 Subject: [PATCH 053/183] =?UTF-8?q?=E3=83=88=E3=83=83=E3=83=97=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=82=92=E5=88=86=E5=B2=90=E7=94=A8=E3=81=AB?= =?UTF-8?q?=E7=94=A8=E6=84=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.md | 156 +++++++++++++++---------------------------------------- 1 file changed, 42 insertions(+), 114 deletions(-) diff --git a/index.md b/index.md index 900c82f3..fb06d3e2 100644 --- a/index.md +++ b/index.md @@ -1,119 +1,47 @@ --- title: "Hotwire ドキュメント(有志翻訳版)" -description: "Turboは、クライアントサイドのJavaScriptフレームワークを使用することなく、高速でモダンなウェブアプリケーションを作成するためのいくつかの技術を提供します。" +description: "HotwireはモダンなWebアプリケーションを構築するにあたっての新しいアプローチです。多量のJavaScriptを書くことなく、サーバーサイドからJSONではなくHTMLを送ります。このサイトでは、Hotwireの主要技術であるTurboとStimulusについて、公式ドキュメントのReferenceとHandbookの翻訳を掲載します" layout: "base.html" --- -# はじめに - -Turboは 高速でモダンで、そして進歩的に改良されたWebアプリケーションを、JavaScriptをあまり使わずに作るためのいくつかの技術をまとめたものです。 -Turboは流行のクライアントサイドフレームワークの代替手段を提供します。 -流行のクライアントサイドフレームワークとは、全てのロジックをフロントエンドに置いて、あなたのアプリのサーバーサイドをJSON APIに毛が生えたようなものに制限してしまうものです。 - -Turbo を使えば、サーバーにHTMLを直接配布させることができます。それはつまり、すべてのロジック、例えばパーミッションをチェックしたり、ドメインモデルとやりとりしたり、その他アプリケーションのプログラミングに関わるあらゆることを、多かれ少なかれ、お好みのプログラミング言語に限定して書くことができるということです。 -もう、JSONに分たれた両側(クライアントサイドとサーバーサイド)に、同じロジックを複製して書かなくて良いのです。全てのロジックはサーバ上で動き、ブラウザは、最終的なHTMLを扱うだけになります。 - -Wire上でHTMLを扱うことの利点については、<a href="https://hotwired.dev/">Hotwireサイト</a>で詳しく知ることができます。以下は、Turboがこれを可能にするテクニックについて書いていきます。 - -## Turbo ドライブ: 永続的プロセス内でのページの変更 - -今までのシングルページ・アプリケーションを、古臭くいちいちページ遷移するやり方と比べたときの主な魅力は、動作のスピードです。SPAがそのスピードを可能にできるのは、アプリケーションのプロセスをいちいち破棄することなく、本当にページが遷移する際にのみ初期化するからです。 - -Turboドライブは、それと同じスピードを、SPAと同じ永続的プロセスモデルによって可能にしています。ただしそのために、その枠組みにのっとったアプリケーションを職人芸で組み上げる必要はありません。メンテナンスの必要なクライアントサイドのルーターも、慎重に管理しなければならないステート(状態)もありません。永続的プロセスはTurboによって管理されるため、プログラマは自分のサーバーサイドのコードだけを書けばいいのです。まるで、ゼロ年代初頭ーーいまのSPAモンスターの複雑性と関わりなく穏やかだったころに、時が戻ったように! - -これは、同じドメインにリンクされた`<a href>`がクリックされるたびに、それを横から掠め取ることで実現されます。具体的には、対象範囲のリンクをクリックするたび、Turboドライブは、ブラウザがそのリンクに遷移するのを押しとどめ、ブラウザのURLを<a href="https://developer.mozilla.org/ja/docs/Web/API/History">History API</a>を使って更新し、<a href="https://developer.mozilla.org/ja/docs/Web/API/fetch">`fetch`</a>を使って新しいページをリクエストし、それからHTMLレスポンスを描画します。 - -フォームでも同じ扱いをします。フォームがサブミットされると、それはTurboドライブの`fetch`リクエストに変換され、TurboドライブはそのリクエストからのリダイレクトとHTMLレスポンスの描画を行います。 - -描画中、Turboドライブは現在の`<body>`要素を即座に置き換え、`<head>`要素の内容をマージします。JavaScriptの<a href="https://developer.mozilla.org/ja/docs/Web/API/Window">Window</a>と<a href="https://developer.mozilla.org/ja/docs/Web/API/Document">document objects</a>、そしてその`<html>` 要素は、前の描画から次の描画へと移る際も保持されます。 - - -*Turboドライブと直接やり取りして、ユーザーのアクションがどのように画面遷移につながるか、リクエストのライフサイクルへフックするかを制御することもできますが、ほとんどの場合、いくつかの規約を採用することで、置き換え時のスピードを速くすることができます。 - -## Turboフレーム: 複雑なページをパーツに分ける - -多くのWebアプリケーションは、いくつかの独立したセグメントを含んだページを提供します。例えば意見を交わせるディスカッションのためのページであれば、トップにナビゲーションバー、中央にメッセージのリスト、下に新しいメッセージの投稿フォーム、そして関連トピックの並んだサイドバーといった具合です。このディスカッション・ページを生成しようとするなら、普通は、一連のやり方で各セグメントを生成し、それを一つにまとめて、その結果を単一のHTMLレスポンスとしてブラウザに送ることになるでしょう。 - -Turboフレームを使うと、これらの独立したセグメントを、それぞれ別のフレームに配置することができます。そのフレームは、自身のナビゲーションの範囲が限定されており、遅延して読み込まれる場合があります。範囲の限定されたナビゲーションとはつまり、フレーム内でのすべてのやり取り、たとえばリンクのクリックやフォームの送信がフレームの内側で起こり、ページの他の部分は更新やリロードが起こらないということです。 - -独立したセグメントを、それ専用のナビゲーション・コンテキスト内にラップするためには、`<turbo-frame>`で囲みます。 -例としては下記のようになります。 - -```html -<turbo-frame id="new_message"> - <form action="/messages" method="post"> - ... - </form> -</turbo-frame> -``` - -上記のフォームを送信した際、Turbo は、リダイレクトされた HTML レスポンスから`<turbo-frame id="new_message">`要素に合致する部分を抽出し、既存の`new_message`フレーム要素の中身と、取得した要素の内容を入れ替えます。ページ内の他の部分は、そのまま残ります。 - -フレームは、ナビゲーションの範囲を限定するだけでなく、その内容の読み込みを遅延させることもあります。フレームの読み込みを遅延させるためには、自動的に読み込まれるURLを値にもった`src`属性を付与します。範囲の限定されたナビゲーションを使って、Turboは結果のレスポンスから合致するフレームを探索・抽出し、内容を置き換えます。 - -```html -<turbo-frame id="messages" src="/messages"> - <p>This message will be replaced by the response from /messages.</p> -</turbo-frame> -``` - -これは、古めかしいフレーム、ともすると`<iframe>`のように思えるかもしれません。しかしTurboフレームは、同一のDOMの一部であり、"実際の"フレームと関連した奇妙さや妥協は一切ありません。Turboフレームは共通のCSSでスタイル付けされ、共通のJavaScriptのコンテキストの一部であり、どのような追加のコンテンツセキュリティ制限の下にも置かれません。 - -それぞれのセグメントを独立したコンテキストに変えるだけでなく、Turboフレームは下記のことを可能にします。 - -1.**効果的なキャッシュ**。以前、例に出したディスカッション・ページでは、関連話題を集めたサイドバーは、新しい関連トピックが現れるたびに一旦キャッシュを破棄する必要があります。しかしその際、中央のメッセージリストはキャッシュの破棄は必要ではありません。全てのものが単一ページを構成する場合、独立したセグメントのうちどれかがキャッシュを破棄すると、すべてのキャッシュが破棄されます。フレームを使えば、各セグメントは独立してキャッシュするため、より少ない独立キーで、より長持ちするキャッシュを得ることができます。 -1.**並行実行**。遅延読み込みされるそれぞれのフレームは、それぞれ独自のHTTPリクエスト/レスポンスで生成されます。つまり、それぞれ個別のプロセスで扱うことが可能です。プロセスを手で管理することなしに、並行実行が可能になるのです。表示を完了するまで400msかかる複雑な構成のページは、フレームによって分割できるかもしれません。そのフレームは、最初のリクエストにたったの50msしかかからず、それぞれ三つの遅延読み込みのフレームにも50msずつかかるとしましょう。そうすると、全てのページは100msで表示を完了することができます。なぜなら、それぞれ三つのフレームは、一つずつ順番に処理されるのではなく、同時に実行されるからです。 -1.**モバイル対応**。モバイルアプリでは、たいてい、大きくて複雑な構成のページにすることはできません。各セグメントは、その目的のためだけの画面を必要とします。Turboフレームで構成されたアプリケーションでは、複巣の要素を組み合わせたページを、それぞれのセグメントに分割する準備ができています。これらのセグメントはネイティブアプリのSheetやスクリーンに、そのまま使うことができます(というのも、各セグメントは、それぞれ専用のURLを持っているからです)。 - - -## Turboストリーム: Deliver live page changes - -非同期なアクションに応答してページの一部を変化させることで、アプリケーションをとても生き生きしたものにできます。Turboフレームはそのような更新を、一つのフレーム内でのHTTPプロトコルでの直接のやりとりに応じて行います。一方で、Turboストリームは、ページのどの部分であってもその更新に、WebSocketコネクションやSSE(Sever-sent events)、その他のトランスポートを使います。(<a href="http://itsnotatypo.com">imbox</a>を見てください。ここでは、新しいemailの着信が、自動的に反映されます)。 - -Turboストリームは、`<turbo-stream>` 要素を、7つの基本のアクション、`append`、 `prepend`、 `replace`、 `update`、 `remove`、 `before`、 `after`とともに導入します。これらのアクションは、あなたが操作したい要素の ID を指定する`target`属性と一緒に使われます。そのアクションと`target`属性によって、ページをリフレッシュするのに必要とされる全てのミューテーションをエンコードできます。いくつかのストリーム要素を一つのストリームメッセージにまとめることさえできます。簡単に、挿入や置き換えをしたい HTML を`<a href="https://developer.mozilla.org/ja/docs/Web/HTML/Element/template">template tag</a>`で囲います。あとはTurboがやってくれます。 - -```html -<turbo-stream action="append" target="messages"> - <template> - <div id="message_1">My new message!</div> - </template> -</turbo-stream> -``` - -このストリーム要素は、My new message! を含んだ`div`を取得し、ID`messages`のついたコンテナに追加します。 -次のコードは、既存の要素を置き換えるだけです。 - -```html -<turbo-stream action="replace" target="message_1"> - <template> - <div id="message_1">This changes the existing message!</div> - </template> -</turbo-stream> -``` - -Turboストリームは、かつてのRailsの世界、初めは<a href="https://weblog.rubyonrails.org/2006/3/28/rails-1-1-rjs-active-record-respond_to-integration-tests-and-500-other-things/">RJS</a>と呼ばれ、次に<a href="https://signalvnoise.com/posts/3697-server-generated-javascript-responses">SJR</a>と呼ばれたものと概念的に連続しています。けれど、それをJavaScriptを書く必要がなく実現しています。 -それらの利点は維持されています。 - -1. **サーバーサイドテンプレートの再利用**: リアルタイムなページの変更は、最初にページがロードされた時に使われたのと同じサーバサイドテンプレートを使って生成されています。 -1. **Wire上のHTML**: 送っているものは全てHTMLなので、プロセスを更新するのにクライアントサイドのJavascriptは、必要ありません(もちろん、Turboの後ろでは動いてますが)。そう、HTMLのペイロードは、同等の内容のJSONよりも少し大きいかもしれません。gzip を使うことで、たいていは、その差異は無視できるものです。そして、JSONを取得して、HTMLに変換するのに必要な全てのクライアントサイドの労力を節約できます。 -1. **より単純な制御フロー**: WebSocket、SSEやフォーム時の送信に対してのメッセージが来たときに、次に何が起こるかは明らかです。そこには、ルーティングやイベントの連鎖、そのほかの必要な回り道はありません。どのように変化するかを教えてくれるシングルタグに囲まれたHTMLが変更されるだけです。 - - -今や、RJSとSJRと違って、Turboストリームの部品として、独自に定義したJavaScriptの関数を呼ぶことはできません。しかし、これは特色であって、バグではありません。独自に定義したJavaScript関数を呼ぶようなテクニックは、レスポンスにともなって、あまりに多くのJavaScriptが送られるようになる時、容易にこんがらかった混沌を生み出してしまいます。Turboは、DOMを更新することだけに、正面から取り組みます。そして、そのほかの振る舞いについては、 <a href="https://stimulus.hotwired.dev">Stimulus</a>のアクションを使ってライフサイクル・コールバックと結びつけることを期待しています。 - -## Turboネイティブ: iOSとAndroid両用のハイブリッド・アプリケーション - -Turboネイティブは、iOSとAndroid両用のハイブリッド・アプリケーションを構築するための理想です。サーバーサイドでレンダリングされた既存のHTMLを使って、ネイティブ・ラッパーにアプリの機能性の基礎的な範囲を確保することができます。そして、節約したすべての時間を、非常に忠実度の高いネイティブ・コントローラーから利益を得られるいくつかの画面をよりよくすることに使うことができるのです。 - -Basecampのようなアプリケーションは、何百もの画面を持っています。これらの画面の一つ一つを書き直すのは、骨折りばかりが膨大で、得られるものはほとんどありません。ネイティブならではの火力は、ハイ・ファイを必要とする高度なタッチ性能に取っておくほうがいいでしょう。Basecampのinbox内の”新着お知らせ"といった機能は、たとえば、使用感がしっくりくるスワイプコントロールの使い所です。しかしほとんどのページ、たとえば単独のメッセージを表示するようなページでは、完全なネイディブで作ったからといって、特に得られるものはありません。 - -ハイブリッドでアプリを作ると、開発プロセスをスピードアップするだけでなく、より自由に、遅くて厄介なアプリストアのリリースプロセスを経ることなくアプリを更新できるようになります。HTMLで完結するものはなんでも、Webアプリケーション内で変更し、すぐに全てのユーザーに届けられます。ビッグ・テックが変更を受け入れるのも、ユーザーがアプリを更新するのも待つことはありません。 - -TurboネイディブはiOSとAndoroidのために利用可能な推奨開発プラクティスを利用することを前提としています。Turboネイティブは、ネイティブのAPIを抽象化して遠ざけたフレームワークではありません。また、ネイティブコードを、プラットフォーム間で共用できるようにする試みでさえありません。共用部分は、HTMLです。このHTMLは、サーバーサイドでレンダリングされます。しかし、ネイティブの制御は推奨されるネイディブのAPIで書かれます。 - -より詳しいドキュメントは<a href="https://github.com/hotwired/turbo-ios">Turboネイティブ: iOS</a>と<a href="https://github.com/hotwired/turbo-android">Turboネイティブ: Android</a> のリポジトリを見てください。Turboの力でどんなかっこいいアプリが作られるかを感じるには、HEYのネイティブアプリ<a href="https://apps.apple.com/us/app/hey-email/id1506603805">iOS版</a> と <a href="https://play.google.com/store/apps/details?id=com.basecamp.hey&hl=en_US&gl=US">Android版</a>を見てください。 - - -## バックエンド・フレームワークとの統合 - -Turboを使うのに、バックエンド・フレームワークは必要ありません。全ての機能は、さらなる抽象化なしに、直接に使われるように設計されています。しかし、もしTurboと統合されたバックエンド・フレームワークを使う機会があるのなら、人生はより単純になるでしょう。[その中のRuby on Railsむけの統合のための実装例がこちらです。](https://github.com/hotwired/turbo-rails). +<main id="content"> + <h1>HOTWIRE - HTML Over The Wire</h1> + <div class="description"> + <div> + Hotwireは、モダンなWebアプリをつくるための”もう一つの"アプローチです。JavaScriptを多用しません。"wire"を通じて、JSONの代わりにHTMLを送ります。ページの読み込み速度は早く、テンプレートの描画はサーバー上で行い、よりシンプルで生産的な開発体験を提供します。あらゆるプログラミング言語で動き、そして従来のシングルページ・アプリケーションで想定されるスピードやレスポンシブ性はそのままです。 + </div> + + <div> + HTML-over-the-wire のアプローチを単なるインスピレーションとして独自のツールに活かすこともできますし、37signals のチームが HEY のために設計した Hotwire フレームワークを活用することもできます。これらのフレームワークは互いに連携し、全プラットフォームをまたぐ完全なソリューションを提供します。 + </div> + </div> + <section> + <h2>Turbo</h2> + <div class="description"> + Hotwireの中心となるのがTurboです。Turboは、ページの切り替えやフォームの送信を高速化し、複雑なページをコンポーネントに分割し、WebSocketを使って部分的なページ更新をストリーミングするための一連の、それぞれを補完しあう技術です。しかも、一切JavaScriptを書く必要がありません。 + </div> + <ul> + <li> <a href="/turbo/handbook/introduction/">Handbook</a> </li> + <li> <a href="/turbo/reference/drive/">Reference</a> </li> + <li> <a href="/turbo/handbook/installing/">インストール</a> </li> + </ul> + </section> + <section> + <h2>Stimulus</h2> + <div class="description"> + <details> + Turboは通常、従来ならJavaScriptが必要だったインタラクティブな動作の少なくとも80%を担ってくれますが、それでも少しだけカスタムコードが必要になる場面はあります。そんなときに役立つのがStimulusです。Stimulusは、HTMLを中心としたアプローチで状態管理やサーバーとの連携を簡単に実現します。 + <summary> + 原文 + </summary> + While Turbo usually takes care of at least 80% of the interactivity that traditionally would have required JavaScript, there are still cases where a dash of custom code is required. Stimulus makes this easy with a HTML-centric approach to state and wiring. + </details> + </div> + <ul> + <li> <a href="/stimulus/handbook/introduction/">Handbook</a> </li> + <li> <a href="/stimulus/reference/controllers/">Reference</a> </li> + </ul> + </section> +</main> +<footer> +</footer> From a67733c6a950f0afbdb2a8dfb86ba583be4eacbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= <nakajimatakuya@next-group.jp> Date: Tue, 19 Dec 2023 17:42:18 +0900 Subject: [PATCH 054/183] =?UTF-8?q?stimulus=E7=94=A8=E3=81=AElayout,=20par?= =?UTF-8?q?tial=E3=83=86=E3=83=B3=E3=83=97=E3=83=AC=E3=82=92=E4=BD=9C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _includes/stimulus--navigation.html | 8 +++++ _includes/stimulus--section-nav.html | 5 ++++ layouts/base.html | 1 + layouts/stimulus--base.html | 45 ++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 _includes/stimulus--navigation.html create mode 100644 _includes/stimulus--section-nav.html create mode 100644 layouts/stimulus--base.html diff --git a/_includes/stimulus--navigation.html b/_includes/stimulus--navigation.html new file mode 100644 index 00000000..d26db1b4 --- /dev/null +++ b/_includes/stimulus--navigation.html @@ -0,0 +1,8 @@ +<nav class="nav"> + <ul class="nav__list "> + <li> + <a class="nav__list-link active" href="/stimulus/handbook/introduction">Handbook</a> + {% include 'stimulus--section-nav.html', section: 'stimulus_handbook' %} + </li> + </ul> +</nav> diff --git a/_includes/stimulus--section-nav.html b/_includes/stimulus--section-nav.html new file mode 100644 index 00000000..b5c49eba --- /dev/null +++ b/_includes/stimulus--section-nav.html @@ -0,0 +1,5 @@ +<ul class="nav__sublist active"> + <li> + <a class="nav__sublist-link" href="/stimulus/handbook/introduction">はじめに</a> + </li> +</ul> diff --git a/layouts/base.html b/layouts/base.html index 6e0fde28..8b8b31e3 100644 --- a/layouts/base.html +++ b/layouts/base.html @@ -25,6 +25,7 @@ <ul class="jump__list"> <li><a class="jump__list-link jump__list-link--hotwire" href="/">Hotwire ドキュメント(有志翻訳版):</a></li> <li><a class="jump__list-link jump__list-link--active" href="/">Turbo</a></li> + <li><a class="jump__list-link" href="/stimulus/handbook/introduction">Stimulus</a></li> </ul> </nav> <main class="grid docs"> diff --git a/layouts/stimulus--base.html b/layouts/stimulus--base.html new file mode 100644 index 00000000..9c7be91f --- /dev/null +++ b/layouts/stimulus--base.html @@ -0,0 +1,45 @@ +--- +title: Hotwire +--- +<!doctype html> +<html lang="ja"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content="{{ description }}"> + <link rel="stylesheet" href="/assets/main.css"> + <title>{% if section_title %}{{ section_title }}: {% endif %}{{ title }} + + + +
+ +
+ {% render 'stimulus--navigation.html' %} +
+ +
+ {{ content }} +
+ +
+ + From 281e3978834e1c203a180eb819e2ca6238b4302e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Tue, 19 Dec 2023 17:44:31 +0900 Subject: [PATCH 055/183] add handbook/introduction --- stimulus/handbook/introduction.md | 76 +++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 stimulus/handbook/introduction.md diff --git a/stimulus/handbook/introduction.md b/stimulus/handbook/introduction.md new file mode 100644 index 00000000..f92c8c4e --- /dev/null +++ b/stimulus/handbook/introduction.md @@ -0,0 +1,76 @@ +--- +title: "はじめに" +description: "Stimulusはすでに持っているHTMLに簡単なアノテーションを加えることで要素とJavaScriptオブジェクトを接続することができるフレームワークです。" +layout: "stimulus--base.html" +--- + +# はじめに + +## Stimulusについて + +Stimulusは控えめな野心を持ったJavaScriptフレームワークです。 他のフロントエンドフレームワークとは異なり、Stimulusは静的、またはサーバーレンダリングされたHTML、つまり「すでに持っているHTML」にシンプルなアノテーションを与えることで要素とJavaScriptオブジェクトを接続させるように設計されています。 + +これらのJavaScriptオブジェクトはコントローラと呼びます。 Stimulusはページを監視し、HTML中に`data-controller`属性が表れるのを待ちます。 Stimulusはこの属性の値から対応するコントローラクラスを見つけ、そのクラスの新しいインスタンスを作成し、要素に接続します。 + +class属性がHTMLとCSSをつなぐ橋であるように、Stimulusの`data-controller`属性はHTMLとJavaScript をつなぐ橋なのです。 + +
+ 原文 +Stimulus is a JavaScript framework with modest ambitions. Unlike other front-end frameworks, Stimulus is designed to enhance static or server-rendered HTML—the “HTML you already have”—by connecting JavaScript objects to elements on the page using simple annotations. + +These JavaScript objects are called controllers, and Stimulus continuously monitors the page waiting for HTML data-controller attributes to appear. For each attribute, Stimulus looks at the attribute’s value to find a corresponding controller class, creates a new instance of that class, and connects it to the element. + +You can think of it this way: just like the class attribute is a bridge connecting HTML to CSS, Stimulus’s data-controller attribute is a bridge connecting HTML to JavaScript. +
+ + +コントローラーの他にも、3つの主要なStimulusのコンセプトがあります。 + +* actions: `data-action`属性を使用してコントローラのメソッドをDOM イベントに接続します。 +* targets: コントローラ内の重要な要素を取得します。 +* values: コントローラの設定された要素のデータ属性の読み取り、書き込み、変更監視を行います。 + +Stimulus のデータ属性の使用は、CSSがコンテンツとプレゼンテーションを分離するのと同じように、コンテンツと振る舞いを分離するのに役立ちます。さらに、Stimulus の規約は関連するコードを名前によってグループ化することを自然に促します。 + +その結果、Stimulus は小さくて再利用可能なコントローラを構築するのに役立ち、コードがごった煮になるのを防いでくれます。 + +
+ 原文 + +Aside from controllers, the three other major Stimulus concepts are: + +actions, which connect controller methods to DOM events using data-action attributes +targets, which locate elements of significance within a controller +values, which read, write, and observe data attributes on the controller’s element +Stimulus’s use of data attributes helps separate content from behavior in the same way CSS separates content from presentation. Further, Stimulus’s conventions naturally encourage you to group related code by name. + +In turn, Stimulus helps you build small, reusable controllers, giving you just enough structure to keep your code from devolving into “JavaScript soup.” +
+ +## このドキュメントについて + +このハンドブックは、いくつかの完全に機能するコントローラを書く方法を示すことによって、Stimulusのコアコンセプトをガイドします。各章はその前の章を土台としています。最初から最後まで、あなたは以下の方法を学ぶことができます: + +* テキストフィールド入力された名前宛の挨拶テキストを表示する。 +* ボタンがクリックされたときに、テキストフィールドからクリップボードにテキストをコピーする。 +* 複数のスライドを持つスライドショーをナビゲートする +* サーバからHTMLをページの要素に自動的に取り込む +* 自分のアプリケーションにStimulusをセットアップする + +ここでの演習を終えた後はStimulus APIに関する技術的な詳細を理解するためにリファレンスドキュメントが役に立つかもしれません。 + +それでは始めましょう! + +
+ 原文 +This handbook will guide you through Stimulus’s core concepts by demonstrating how to write several fully functional controllers. Each chapter builds on the one before it; from start to finish, you’ll learn how to: + +print a greeting addressed to the name in a text field +copy text from a text field to the system clipboard when a button is clicked +navigate through a slide show with multiple slides +fetch HTML from the server into an element on the page automatically +set up Stimulus in your own application +Once you’ve completed the exercises here, you may find the reference documentation helpful for understanding technical details about the Stimulus API. + +Let’s get started! +
From 6c7b9d02af5379b0cb634bc090c7f2103d01f4a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Tue, 19 Dec 2023 19:30:55 +0900 Subject: [PATCH 056/183] add hello-stimulus --- _includes/stimulus--section-nav.html | 3 + stimulus/handbook/hello-stimulus.md | 405 +++++++++++++++++++++++++++ 2 files changed, 408 insertions(+) create mode 100644 stimulus/handbook/hello-stimulus.md diff --git a/_includes/stimulus--section-nav.html b/_includes/stimulus--section-nav.html index b5c49eba..87b52a99 100644 --- a/_includes/stimulus--section-nav.html +++ b/_includes/stimulus--section-nav.html @@ -2,4 +2,7 @@
  • はじめに
  • +
  • + Hello, Stimulus +
  • diff --git a/stimulus/handbook/hello-stimulus.md b/stimulus/handbook/hello-stimulus.md new file mode 100644 index 00000000..8b5dd447 --- /dev/null +++ b/stimulus/handbook/hello-stimulus.md @@ -0,0 +1,405 @@ +--- +title: "Hello, Stimulus" +description: "簡単なコントローラを作ってみましょう。" +layout: "stimulus--base.html" +--- + +# Hello, Stimulus + +Stimulus がどのように機能するかを学ぶ最良の方法は、簡単なコントローラを作ることです。この章ではその方法を紹介します。 + +
    + 原文 +The best way to learn how Stimulus works is to build a simple controller. This chapter will show you how. +
    + +## 前提条件 + +手順を進めていくためにStimulus-starterプロジェクトのコピーを用意してください。こは、Stimulus を使うためにあらかじめ設定された白紙のアプリケーションです。 + +おすすめのやり方はGlitch上でstimulus-starterを編集することです。 何もインストールせずにブラウザ上で作業することができます。 + +Remix on Glitch + +Glitchではなくテキストエディタで快適に作業したい場合は、Stimulus-starterを手元にcloneしてセットアップする必要があります: + +```sh +$ git clone https://github.com/hotwired/stimulus-starter.git +$ cd stimulus-starter +$ yarn install +$ yarn start +``` + +その後、ブラウザで http://localhost:9000/ にアクセスしてみてください + +(`stimulus-starter`プロジェクトは依存関係の管理にYarnパッケージ・マネージャーを使用しているので、最初にYarnパッケージ・マネージャーがインストールされていることを確認してください) + +
    + 原文 +Prerequisites +To follow along, you’ll need a running copy of the stimulus-starter project, which is a preconfigured blank slate for exploring Stimulus. + +We recommend remixing stimulus-starter on Glitch so you can work entirely in your browser without installing anything: + +Remix on Glitch + +Or, if you’d prefer to work from the comfort of your own text editor, you’ll need to clone and set up stimulus-starter: + +```sh +$ git clone https://github.com/hotwired/stimulus-starter.git +$ cd stimulus-starter +$ yarn install +$ yarn start +``` + +Then visit http://localhost:9000/ in your browser. + +(Note that the stimulus-starter project uses the Yarn package manager for dependency management, so make sure you have that installed first.) +
    + + + +## すべての始まりはHTMLから + +テキストフィールドとボタンを使った簡単な練習から始めましょう。ボタンをクリックすると、コンソールにテキストフィールドの値が表示されます。 + +すべてのStimulusプロジェクトはHTMLから始まります。public/index.htmlを開き、冒頭のタグの直後に以下のマークアップを追加します: + +```html +
    + + +
    +``` + +ブラウザでページをリロードすると、テキストフィールドとボタンが表示されるはずです。 + +
    + 原文 +Let’s begin with a simple exercise using a text field and a button. When you click the button, we’ll display the value of the text field in the console. + +Every Stimulus project starts with HTML. Open public/index.html and add the following markup just after the opening tag: + +```html +
    + + +
    +``` + +Reload the page in your browser and you should see the text field and button. + +
    + +## コントローラーでHTMLに命を吹き込む + +Stimulusの最も重要なポイントはDOM 要素をJavaScript オブジェクトに自動的に接続することです。 これらのオブジェクトはコントローラと呼ばれます。 + +フレームワークの組み込みコントローラクラスを継承して、最初のコントローラを作成しましょう。src/controllers/ フォルダに hello_controller.js という名前の新しいファイルを作成します。そして、その中に以下のコードを記述します: + +```javascript +// src/controllers/hello_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { +} +``` + +
    + 原文 +At its core, Stimulus’s purpose is to automatically connect DOM elements to JavaScript objects. Those objects are called controllers. + +Let’s create our first controller by extending the framework’s built-in Controller class. Create a new file named hello_controller.js in the src/controllers/ folder. Then place the following code inside: + +```javascript +// src/controllers/hello_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { +} +``` +
    + + +## コントローラとDOMをつなぐ識別子(identifier) + +次に、このコントローラをどのようにHTMLに接続するかをStimulusに伝える必要があります。これを行うには、`
    `の`data-controller`属性に識別子を記述します: + +```html +
    + + +
    +``` + +識別子は要素とコントローラの間のリンクの役割を果たします。 この場合、識別子`hello`はStimulusにコントローラクラスのインスタンスを`hello_controller.js`に作成するよう指示します。 コントローラの自動ロードの仕組みについては、インストールガイドを参照してください。 + +
    + 原文 +Next, we need to tell Stimulus how this controller should be connected to our HTML. We do this by placing an identifier in the data-controller attribute on our `div`: + +```html +
    + + +
    +``` + +Identifiers serve as the link between elements and controllers. In this case, the identifier hello tells Stimulus to create an instance of the controller class in hello_controller.js. You can learn more about how automatic controller loading works in the Installation Guide. +
    + +## これでうまくいっているのか? + +ブラウザでページをリロードすると何も変わっていないことがわかります。 コントローラーが動作しているかどうかを知るにはどうすればいいのでしょうか? + +一つの方法は、コントローラがドキュメントに接続されるたびにStimulusが呼び出す`connect()` メソッドに`console.log`を記述することです。 + +`hello_controller.js`の`connect()`メソッドを次のように実装します: + +```javascript +// src/controllers/hello_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + connect() { + console.log("Hello, Stimulus!", this.element) + } +} +``` + +ページを再度読み込み、開発者コンソールを開いてください。「Hello, Stimulus!」と表示され、その後に `
    ` が表示されるはずです。 + +
    + 原文 +Reload the page in your browser and you’ll see that nothing has changed. How do we know whether our controller is working or not? + +One way is to put a log statement in the connect() method, which Stimulus calls each time a controller is connected to the document. + +Implement the connect() method in hello_controller.js as follows: + +```javascript +// src/controllers/hello_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + connect() { + console.log("Hello, Stimulus!", this.element) + } +} +``` + +Reload the page again and open the developer console. You should see Hello, Stimulus! followed by a representation of our `div`. +
    + +## ActionはDOMイベントに反応する + +それでは、「Greet」ボタンをクリックしたときにログが表示されるようにコードを変更する方法を見てみましょう。 + +まず、`connect()`の名前を`greete()`に変更します: + +```javascript +// src/controllers/hello_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + greet() { + console.log("Hello, Stimulus!", this.element) + } +} +``` + +ボタンのクリックイベントが発生したときに`greet()` メソッドを呼び出したい。Stimulus では、イベントを処理するコントローラのメソッドをアクションメソッドと呼びます。 + +アクションメソッドをボタンのクリックイベントに接続するには、public/index.htmlを開き、ボタンに`data-action`属性を追加します: + +```html +
    + + +
    +``` + +> ### アクションの記述子について +> +> `data-action`属性の値である`click->hello#greet`はアクション記述子と呼びます。 この記述子は以下を表しています: +> +> * `click` はイベント名である +> * `hello` はコントローラの識別子である +> * `greet` は呼び出すアクションメソッドの名前である + +ブラウザでページを読み込み、開発者コンソールを開いてください。Greet」ボタンをクリックすると、ログメッセージが表示されるはずです。 + +
    + 原文 +Now let’s see how to change the code so our log message appears when we click the “Greet” button instead. + +Start by renaming connect() to greet(): + +```javascript +// src/controllers/hello_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + greet() { + console.log("Hello, Stimulus!", this.element) + } +} +``` + +We want to call the greet() method when the button’s click event is triggered. In Stimulus, controller methods which handle events are called action methods. + +To connect our action method to the button’s click event, open public/index.html and add a data-action attribute to the button: + +```html +
    + + +
    +``` + +> ﹟Action Descriptors Explained +> +> The data-action value click->hello#greet is called an action descriptor. This particular descriptor says: +> +> * click is the event name +> * hello is the controller identifier +> * greet is the name of the method to invoke + +Load the page in your browser and open the developer console. You should see the log message appear when you click the “Greet” button. +
    + +## Targetsは重要な要素をコントローラのプロパティにマッピングする + +テキストフィールドに入力した名前を使って「Hello, {名前}」と出力されるようにアクションを変更して、練習を終了します。 + +まずコントローラ内でinput要素を参照する必要があります。そして、`value`プロパティを読み込んでその内容を取得します。 + +Stimulusでは、重要な要素をターゲットとしてマークすることができるので、対応するプロパティを通してコントローラ内で簡単に参照することができます。`public/index.html`を開き、input 要素に`data-hello-target`属性を追加します: + +```html +
    + + +
    +``` + +次に、コントローラのターゲット定義のリストに`name`を追加して、ターゲットのプロパティを作成します。 Stimulus は自動的に`this.nameTarget`プロパティを作成し、最初にマッチしたターゲット要素を返します。このプロパティを使用して要素の値を読み取り、挨拶文の文字列を作成します。 + +やってみましょう。 `hello_controller.js`を開き、次のように更新します: + +```javascript +// src/controllers/hello_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "name" ] + + greet() { + const element = this.nameTarget + const name = element.value + console.log(`Hello, ${name}!`) + } +} +``` + +次にブラウザでページをリロードし、開発者コンソールを開きます。 入力フィールドにあなたの名前を入力し、「Greet」ボタンをクリックしてください。 Hello world! + +
    + 原文 + +We’ll finish the exercise by changing our action to say hello to whatever name we’ve typed in the text field. + +In order to do that, first we need a reference to the input element inside our controller. Then we can read the value property to get its contents. + +Stimulus lets us mark important elements as targets so we can easily reference them in the controller through corresponding properties. Open public/index.html and add a data-hello-target attribute to the input element: + +```html +
    + + +
    +``` + +Next, we’ll create a property for the target by adding name to our controller’s list of target definitions. Stimulus will automatically create a this.nameTarget property which returns the first matching target element. We can use this property to read the element’s value and build our greeting string. + +Let’s try it out. Open hello_controller.js and update it like so: + +```javascript +// src/controllers/hello_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "name" ] + + greet() { + const element = this.nameTarget + const name = element.value + console.log(`Hello, ${name}!`) + } +} +``` + +Then reload the page in your browser and open the developer console. Enter your name in the input field and click the “Greet” button. Hello, world! +
    + +## コントローラをよりシンプルに + +StimulusコントローラはJavaScriptのクラスのインスタンスであり、そのメソッドはイベントハンドラとして動作します。 + +つまり、標準的なリファクタリングテクニックを自由に使えるということです。 例えば、入力された名前を返す`name` getter を作ることで`greet()`メソッドをすっきりさせることができます: + +```javascript +// src/controllers/hello_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "name" ] + + greet() { + console.log(`Hello, ${this.name}!`) + } + + get name() { + return this.nameTarget.value + } +} +``` + +
    + 原文 +We’ve seen that Stimulus controllers are instances of JavaScript classes whose methods can act as event handlers. + +That means we have an arsenal of standard refactoring techniques at our disposal. For example, we can clean up our greet() method by extracting a name getter: + +```javascript +// src/controllers/hello_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "name" ] + + greet() { + console.log(`Hello, ${this.name}!`) + } + + get name() { + return this.nameTarget.value + } +} +``` +
    + + +## おさらいと次のステップ + +おめでとう! あなたにとって最初のStimulusコントローラを書くことができました! + +ここではフレームワークの最も重要な概念であるコントローラ、アクション、ターゲットについて説明しました。 次の章では、これらを組み合わせて、実際にBasecampから抽出したコントローラを作ってみましょう。 + + +
    + 原文 +Congratulations—you’ve just written your first Stimulus controller! + +We’ve covered the framework’s most important concepts: controllers, actions, and targets. In the next chapter, we’ll see how to put those together to build a real-life controller taken right from Basecamp. +
    From 56ad7d77fb893faf57d02c49c3d09e21cc29a3e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Wed, 20 Dec 2023 19:32:57 +0900 Subject: [PATCH 057/183] add building-something-real --- _includes/stimulus--section-nav.html | 3 + stimulus/handbook/building-something-real.md | 348 +++++++++++++++++++ 2 files changed, 351 insertions(+) create mode 100644 stimulus/handbook/building-something-real.md diff --git a/_includes/stimulus--section-nav.html b/_includes/stimulus--section-nav.html index 87b52a99..1456b3bb 100644 --- a/_includes/stimulus--section-nav.html +++ b/_includes/stimulus--section-nav.html @@ -5,4 +5,7 @@
  • Hello, Stimulus
  • +
  • + 実際に使えるものを作る +
  • diff --git a/stimulus/handbook/building-something-real.md b/stimulus/handbook/building-something-real.md new file mode 100644 index 00000000..46317377 --- /dev/null +++ b/stimulus/handbook/building-something-real.md @@ -0,0 +1,348 @@ +--- +title: "実際に使えるものを作る" +description: "簡単なコントローラを作ってみましょう。" +layout: "stimulus--base.html" +--- + +# 実際に使えるものを作る + +Hello, Stimulusの章で、はじめてコントローラを実装し、StimulusがHTMLとJavaScriptをどのように接続するかを学びました。 次は、Basecampで使われているコントローラを再現して、実際のアプリケーションで使えるものを見てみましょう。 + +
    + 原文 +We’ve implemented our first controller and learned how Stimulus connects HTML to JavaScript. Now let’s take a look at something we can use in a real application by recreating a controller from Basecamp. +
    + +## 「クリップボードにコピーする」機能を作る + +BasecampのUIには、以下のようなボタンがよく見られる: + +

    スクリーンショット。 電子メールアドレスが入力されたテキストフィールドと、その右側にある「クリップボードにコピー」ボタンを示している。

    + +これらのボタンをクリックすると、URLやメールアドレスなどのテキストがクリップボードにコピーされます。 + +ウェブプラットフォームにはシステムのクリップボードにアクセスするAPIがありますが、それを行うHTML要素はありません。 クリップボードにコピー」ボタンを実装するには、JavaScriptを使う必要があります。 + +
    + 原文 +Scattered throughout Basecamp’s UI are buttons like these: + +Screenshot showing a text field with an email address inside and a ”Copy to clipboard“ button to the right +When you click one of these buttons, Basecamp copies a bit of text, such as a URL or an email address, to your clipboard. + +The web platform has an API for accessing the system clipboard, but there’s no HTML element that does what we need. To implement a “Copy to clipboard” button, we must use JavaScript. +
    + +## コピーボタンの実装 + +例えば、PINを生成して他の人にアクセスを許可できるアプリがあるとします。 生成されたPINを簡単に共有できるように、クリップボードにコピーするボタンと一緒に表示しておけば便利です。 + +`public/index.html`を開き、``の中身を以下のように置き換えます: + +```html +
    + PIN: + +
    +``` + +
    + 原文 +Let’s say we have an app which allows us to grant someone else access by generating a PIN for them. It would be convenient if we could display that generated PIN alongside a button to copy it to the clipboard for easy sharing. + +Open public/index.html and replace the contents of `` with a rough sketch of the button: + +```html +
    + PIN: + +
    +``` +
    + +## コントローラーのセットアップ + +次に、`src/controllers/clipboard_controller.js`を作成し、空のメソッド`copy()`を追加します: + +```javascript +// src/controllers/clipboard_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + copy() { + } +} +``` + +次に、外側の`
    `に`data-controller="clipboard"`を追加します。 この属性が要素に現れると、Stimulusはコントローラのインスタンスを接続します: + +```html +
    +``` + +
    + 原文 +Next, create src/controllers/clipboard_controller.js and add an empty method copy(): + +```javascript +// src/controllers/clipboard_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + copy() { + } +} +``` +Then add data-controller="clipboard" to the outer `
    `. Any time this attribute appears on an element, Stimulus will connect an instance of our controller: + +```html +
    +``` +
    + + +## Targetを定義する + +クリップボードAPIを呼び出す前にその内容を選択できるように、テキストフィールドへの参照が必要になります。 テキストフィールドに`data-clipboard-target="source"`を追加します: + +```html +PIN: +``` + +コントローラにターゲット定義を追加し、`this.sourceTarget`プロパティでテキストフィールド要素にアクセスできるようにします: + +```javascript +export default class extends Controller { + static targets = [ "source" ] + + // ... +} +``` + +> ### static targets = ... の行は何ですか? +> +> Stimulusはコントローラクラスをロードするとき、`targets`と呼ばれる静的配列からターゲット名を抽出します。 配列内の各ターゲット名に対して、Stimulusは3つの新しいプロパティをコントローラに追加します。 ここでは、ターゲット名が"source"なので以下のようなプロパティになります: +> +> `this.sourceTarget` コントローラのスコープ内の最初のsourceターゲットとして評価されます。sourceターゲットが存在しない場合、プロパティへのアクセスはエラーとなります。 +> +> `this.sourceTargets` コントローラのスコープ内の全てのsourceターゲットの配列として評価されます。 +> +> `this.hasSourceTarget` sourceターゲットがある場合は`true`に、ない場合は`false`に評価されます。 +> +> targetsについての詳細はリファレンスを参照して下さい。 + + +
    + 原文 +We’ll need a reference to the text field so we can select its contents before invoking the clipboard API. Add data-clipboard-target="source" to the text field: + +```html +PIN: +``` + +Now add a target definition to the controller so we can access the text field element as this.sourceTarget: + +```javascript +export default class extends Controller { + static targets = [ "source" ] + + // ... +} +``` + +> ## What’s With That static targets Line? +> +> When Stimulus loads your controller class, it looks for target name strings in a static array called targets. For each target name in the array, Stimulus adds three new properties to your controller. Here, our "source" target name becomes the following properties: +> +> * this.sourceTarget evaluates to the first source target in your controller’s scope. If there is no source target, accessing the property throws an error. +> * this.sourceTargets evaluates to an array of all source targets in the controller’s scope. +> * this.hasSourceTarget evaluates to true if there is a source target or false if not. +> +> You can read more about targets in the reference documentation. +
    + + +## Actionをつなぐ + +これで、コピーボタンをフックする準備ができました。 + +ボタンをクリックすると、コントローラの`copy()`メソッドが呼び出されるようにしたいので、`data-action="clipboard#copy"`を追加します: + +```html + +``` + +> ### アクションの省略記法について +> +> アクション記述子から`click->`が省略されていることにお気づきかもしれません。 これは Stimulus が` +``` + +> ### Common Events Have a Shorthand Action Notation +> +> You might have noticed we’ve omitted click-> from the action descriptor. That’s because Stimulus defines click as the default event for actions on ` +
    +``` + +ページをリロードし、両方のボタンが機能することを確認しましょう。 + +
    + 原文 +So far we’ve seen what happens when there’s one instance of a controller on the page at a time. + +It’s not unusual to have multiple instances of a controller on the page simultaneously. For example, we might want to display a list of PINs, each with its own Copy button. + +Our controller is reusable: any time we want to provide a way to copy a bit of text to the clipboard, all we need is markup on the page with the right annotations. + +Let’s go ahead and add another PIN to the page. Copy and paste the
    so there are two identical PIN fields, then change the value attribute of the second: + +```html +
    + PIN: + +
    +``` + +Reload the page and confirm that both buttons work. +
    + + +## アクションとターゲットはあらゆる要素に適用できる + +では、もうひとつPINフィールドを追加しましょう。今回はボタンの代わりにコピーリンクを使います: + +```html +
    + PIN: + Copy to Clipboard +
    +``` + +Stimulusでは、適切な`data-action`属性さえあれば、どんな種類の要素でもアクションメソッドを呼び出すことができます。 + +今回の場合、リンクをクリックするとブラウザはリンクのhrefをたどります。 アクションの中で`event.preventDefault()`を呼び出すことで、このデフォルトの動作をキャンセルすることができます: + +```javascript +copy(event) { + event.preventDefault() + navigator.clipboard.writeText(this.sourceTarget.value) +} +``` + +同様に、`source`ターゲットは``である必要はありません。 コントローラが期待しているのは、`value`プロパティと`select()`メソッドだけです。 つまり、代わりに` +``` + +
    + 原文 +Now let’s add one more PIN field. This time we’ll use a Copy link instead of a button: + +```html +
    + PIN: + Copy to Clipboard +
    +``` + +Stimulus lets us use any kind of element we want as long as it has an appropriate data-action attribute. + +Note that in this case, clicking the link will also cause the browser to follow the link’s href. We can cancel this default behavior by calling event.preventDefault() in the action: + +```javascript +copy(event) { + event.preventDefault() + navigator.clipboard.writeText(this.sourceTarget.value) +} +``` +Similarly, our source target need not be an ``. The controller only expects it to have a value property and a select() method. That means we can use a ` +``` +
    + +## おさらいと次のステップ + +この章では、ブラウザAPIをStimulusコントローラでラップする実例を見てきました。 コントローラの複数のインスタンスを一度にページに表示する方法を確認し、アクションとターゲットがHTMLとJavaScriptを疎結合に保つ方法が分かりましたね。 + +次は、コントローラの設計を少し変更するだけで、より堅牢な実装ができることを見てみましょう。 + +
    + 原文 +In this chapter we looked at a real-life example of wrapping a browser API in a Stimulus controller. We saw how multiple instances of the controller can appear on the page at once, and we explored how actions and targets keep your HTML and JavaScript loosely coupled. + +Now let’s see how small changes to the controller’s design can lead us to a more robust implementation. +
    From de7c9b2aaadcc8a43e3a0e32ba2d2a1c190cd56b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Thu, 21 Dec 2023 14:43:18 +0900 Subject: [PATCH 058/183] add designing-for-resilience --- _includes/stimulus--section-nav.html | 3 + stimulus/handbook/designing-for-resilience.md | 152 ++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 stimulus/handbook/designing-for-resilience.md diff --git a/_includes/stimulus--section-nav.html b/_includes/stimulus--section-nav.html index 1456b3bb..8dd08489 100644 --- a/_includes/stimulus--section-nav.html +++ b/_includes/stimulus--section-nav.html @@ -8,4 +8,7 @@
  • 実際に使えるものを作る
  • +
  • + 弾力性のある設計 +
  • diff --git a/stimulus/handbook/designing-for-resilience.md b/stimulus/handbook/designing-for-resilience.md new file mode 100644 index 00000000..dfc0617a --- /dev/null +++ b/stimulus/handbook/designing-for-resilience.md @@ -0,0 +1,152 @@ +--- +title: "弾力性のある設計" +description: "プログレッシブエンハンスメントな設計をしてネットワーク障害時やレガシーブラウザ環境でも使うことができるアプリケーションを作りましょう" +layout: "stimulus--base.html" +--- + +# 弾力性のある設計 + +クリップボードAPIは現在のブラウザでは十分にサポートされていますが、それでも古いブラウザを使用している少数の人々が私たちのアプリケーションを使用することが予想されます。 + +また、時々アプリケーションへのアクセスに問題が発生することも想定しておかなければなりません。 例えば、断続的なネットワーク接続やCDNの一時的な障害などによって、JavaScriptの一部またはすべてがロードされない可能性があります。 + +古いブラウザのサポートは労力に見合わないものと見なしたり、ネットワークの問題はブラウザをリフレッシュすることで解決する一時的な不具合と見なしたりしたくなるものです。 しかし、多くの場合、このようなタイプの問題の影響を優雅に回避するように機能を構築するのは簡単なことです。 + +一般的にプログレッシブ・エンハンスメントと呼ばれるこの弾力的なアプローチは、基本的な機能をHTMLとCSSで実装し、その基本的なエクスペリエンスに対する段階的なアップグレードをCSSとJavaScriptでレイヤー化します。 そして基礎となるテクノロジーがブラウザでサポートされるようになったときにそのアップグレードを段階的に提供するのです。 + +
    + 原文 +Although the clipboard API is well-supported in current browsers, we might still expect to have a small number of people with older browsers using our application. + +We should also expect people to have problems accessing our application from time to time. For example, intermittent network connectivity or CDN availability could prevent some or all of our JavaScript from loading. + +It’s tempting to write off support for older browsers as not worth the effort, or to dismiss network issues as temporary glitches that resolve themselves after a refresh. But often it’s trivially easy to build features in a way that’s gracefully resilient to these types of problems. + +This resilient approach, commonly known as progressive enhancement, is the practice of delivering web interfaces such that the basic functionality is implemented in HTML and CSS, and tiered upgrades to that base experience are layered on top with CSS and JavaScript, progressively, when their underlying technologies are supported by the browser. +
    + +## プログレッシブエンハンスメントな作りのPINフィールド + +PINフィールドを段階的に強化し、ブラウザがサポートしていない限りコピーボタンが見えないようにする方法を見てみましょう。 そうすれば、機能しないボタンを誰かに見せることを避けることができます。 + +まず、CSSでコピーボタンを隠すことから始めます。 それから、Stimulus コントローラでクリップボードAPIのサポート状況を機能テストします。 APIがサポートされていれば、ボタンを表示するためにコントローラ要素にクラス名を追加します。 + +まず、`data-controller`属性を持つ div 要素に`data-clipboard-supported-class="clipboard-supported"`を追加します: + +```html +
    +``` + +次に、button要素に`class="clipboard-button"`を追加します: + +```html + +``` + +次に、以下のスタイルを`public/main.css`に追加します: + +```css +.clipboard-button { + display: none; +} + +.clipboard--supported .clipboard-button { + display: initial; +} +``` + +Stimulusコントローラ側では、まず`data-clipboard-supported-class`属性に記されている`supported`という名前を静的プロパティのclassesに追加します: + +```javascript +static classes = [ "supported" ] +``` + +これで、HTML内の特定のCSSクラスを制御できるようになり、コントローラがさまざまなCSSアプローチに簡単に適応できるようになります。 このように追加されたクラスは、`this.supportedClass`という名前でアクセスすることができます。 + +次にクリップボードAPIがサポートされているかどうかをテストする`connect()`メソッドをコントローラに追加し、サポートされているようであればコントローラの要素にクラス名を追加します: + + +```javascript +connect() { + if ("clipboard" in navigator) { + this.element.classList.add(this.supportedClass); + } +} +``` + +このメソッドは、コントローラのクラス本体のどこにでも置くことができます。 + +この実装により、ブラウザのJavaScriptを無効にしてページをリロードすると、コピーボタンが表示されなくなります。 + +これでPINフィールドを段階的に強化することができました。 コピーボタンの初期状態は非表示で、JavaScriptがクリップボードAPIのサポートを検出したときだけ表示されるようになります。 + +
    + 原文 +Let’s look at how we can progressively enhance our PIN field so that the Copy button is invisible unless it’s supported by the browser. That way we can avoid showing someone a button that doesn’t work. + +We’ll start by hiding the Copy button in CSS. Then we’ll feature-test support for the Clipboard API in our Stimulus controller. If the API is supported, we’ll add a class name to the controller element to reveal the button. + +We start off by adding data-clipboard-supported-class="clipboard--supported" to the div element that has the data-controller attribute: + +```html +
    +``` + +Then add class="clipboard-button" to the button element: + +```html + +``` + +Then add the following styles to public/main.css: + +```css +.clipboard-button { + display: none; +} + +.clipboard--supported .clipboard-button { + display: initial; +} +``` + +First we’ll add the data-clipboard-supported-class attribute inside the controller as a static class: + +```javascript + static classes = [ "supported" ] +``` + +This will let us control the specific CSS class in the HTML, so our controller becomes even more easily adaptable to different CSS approaches. The specific class added like this can be accessed via this.supportedClass. + +Now add a connect() method to the controller which will test to see if the clipboard API is supported and add a class name to the controller’s element: + +```javascript +connect() { + if ("clipboard" in navigator) { + this.element.classList.add(this.supportedClass); + } +} +``` + +You can place this method anywhere in the controller’s class body. + +If you wish, disable JavaScript in your browser, reload the page, and notice the Copy button is no longer visible. + +We have progressively enhanced the PIN field: its Copy button’s baseline state is hidden, becoming visible only when our JavaScript detects support for the clipboard API. + +
    + +## おさらいと次のステップ + +この章では、クリップボードコントローラーを、古いブラウザや劣悪なネットワーク環境にも耐えられるように優しく修正しました。 + +次は Stimulus コントローラでどのように状態を管理するかについて学びましょう。 + +
    + 原文 +In this chapter we gently modified our clipboard controller to be resilient against older browsers and degraded network conditions. + +Next, we’ll learn about how Stimulus controllers manage state. +
    + + From 4841fa3f35a92a34a95d9daf8f495dc224bb6c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Fri, 22 Dec 2023 14:37:03 +0900 Subject: [PATCH 059/183] add managing-state --- _includes/stimulus--section-nav.html | 3 + stimulus/handbook/managing-state.md | 485 +++++++++++++++++++++++++++ 2 files changed, 488 insertions(+) create mode 100644 stimulus/handbook/managing-state.md diff --git a/_includes/stimulus--section-nav.html b/_includes/stimulus--section-nav.html index 8dd08489..536efc84 100644 --- a/_includes/stimulus--section-nav.html +++ b/_includes/stimulus--section-nav.html @@ -11,4 +11,7 @@
  • 弾力性のある設計
  • +
  • + ステート管理 +
  • diff --git a/stimulus/handbook/managing-state.md b/stimulus/handbook/managing-state.md new file mode 100644 index 00000000..24661891 --- /dev/null +++ b/stimulus/handbook/managing-state.md @@ -0,0 +1,485 @@ +--- +title: "ステート管理" +description: "Stimulusでアプリケーションのステート管理はどのように行われるのかを見ていきましょう" +layout: "stimulus--base.html" +--- + +# ステート管理 + +近年のフレームワークのほとんどは、JavaScriptでステートを保持することを推奨しています。 DOMを書き込み専用のレンダリングターゲットとして扱い、サーバから送られてくるJSONを使用するクライアントサイドのテンプレートによってUIを構築するアプローチです。 + +一方でStimulus は異なるアプローチをとります。 StimulusアプリケーションのステートはDOM内の属性として存在し、コントローラ自体はほとんどステートを持ちません。 このアプローチにより、初期状態のドキュメント、Ajaxリクエスト、Turbo visit、あるいは別のJavaScriptライブラリなど、どこからでも HTML を扱うことができ、明示的な初期化ステップなしに、関連するコントローラが自動的に起動させることができます。 + +
    + 原文 +Most contemporary frameworks encourage you to keep state in JavaScript at all times. They treat the DOM as a write-only rendering target, reconciled by client-side templates consuming JSON from the server. + +Stimulus takes a different approach. A Stimulus application’s state lives as attributes in the DOM; controllers themselves are largely stateless. This approach makes it possible to work with HTML from anywhere—the initial document, an Ajax request, a Turbo visit, or even another JavaScript library—and have associated controllers spring to life automatically without any explicit initialization step. +
    + +## スライドショーの構築 + +前章では、Stimulus コントローラで要素にクラス名を追加することで、ドキュメント内の単純な状態を管理する方法を学びました。 しかし、単純なフラグだけでなく、値を保存する必要がある場合はどうすればよいのでしょうか? + +ここでは、現在選択されているスライドのインデックスを属性に保持するスライドショーコントローラを作成することで、この疑問を解決します。 + +いつものように、HTMLから始めましょう: + +```html +
    + + + +
    🐵
    +
    🙈
    +
    🙉
    +
    🙊
    +
    +``` + +各スライドターゲットは、スライドショー内の1つのスライドを表します。 今回つくるコントローラは、一度に1つのスライドだけを表示する責務を負います。 + +それではコントローラを作成しましょう。 `src/controllers/slideshow_controller.js` を作成し、以下のように記述します: + +```javascript +// src/controllers/slideshow_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "slide" ] + + initialize() { + this.index = 0 + this.showCurrentSlide() + } + + next() { + this.index++ + this.showCurrentSlide() + } + + previous() { + this.index-- + this.showCurrentSlide() + } + + showCurrentSlide() { + this.slideTargets.forEach((element, index) => { + element.hidden = index !== this.index + }) + } +} +``` + +このコントローラは`showCurrentSlide()`を定義し、各スライドターゲットをループし、インデックスが一致すれば`hidden`属性をトグルします。 + +最初のスライドを表示してコントローラを初期化し、`next()`と`previous()` で現在のスライドを進めたり巻き戻したりします。 + +> ### ライフサイクル・コールバックの説明 +> +> `initialize()`メソッドは何をするもので、以前に使用した`connect()`メソッドとどう違うのでしょうか +> +> これらのメソッドはStimulusのライフサイクルコールバックメソッドで、コントローラがドキュメントに入ったり出たりするときに、関連する状態をセットアップしたりテールダウンしたりするのに便利です。 +> +> | mathod | Stimulusによって呼び出されるタイミング... | +> | initialize() | コントローラが最初にインスタンス化されたとき(一度だけ) | +> | connect() | コントローラが DOM に接続されたとき(何度でも) | +> | disconnect() | コントローラが DOM から切断されたとき(何度でも) | + +ページを再読み込みし、Next ボタンが次のスライドに進むことを確認します。 + + + +
    + 原文 +## Building a Slideshow + +In the last chapter, we learned how a Stimulus controller can maintain simple state in the document by adding a class name to an element. But what do we do when we need to store a value, not just a simple flag? + +We’ll investigate this question by building a slideshow controller which keeps its currently selected slide index in an attribute. + +As usual, we’ll begin with HTML: + +```html +
    + + + +
    🐵
    +
    🙈
    +
    🙉
    +
    🙊
    +
    +``` + +Each slide target represents a single slide in the slideshow. Our controller will be responsible for making sure only one slide is visible at a time. + +Let’s draft our controller. Create a new file, src/controllers/slideshow_controller.js, as follows: + +```javascript +// src/controllers/slideshow_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "slide" ] + + initialize() { + this.index = 0 + this.showCurrentSlide() + } + + next() { + this.index++ + this.showCurrentSlide() + } + + previous() { + this.index-- + this.showCurrentSlide() + } + + showCurrentSlide() { + this.slideTargets.forEach((element, index) => { + element.hidden = index !== this.index + }) + } +} +``` + +Our controller defines a method, showCurrentSlide(), which loops over each slide target, toggling the hidden attribute if its index matches. + +We initialize the controller by showing the first slide, and the next() and previous() action methods advance and rewind the current slide. + +> ### Lifecycle Callbacks Explained +> +> What does the initialize() method do? How is it different from the connect() method we’ve used before? +> +> These are Stimulus lifecycle callback methods, and they’re useful for setting up or tearing down associated state when your controller enters or leaves the document. +> +> Method Invoked by Stimulus… +> initialize() Once, when the controller is first instantiated +> connect() Anytime the controller is connected to the DOM +> disconnect() Anytime the controller is disconnected from the DOM +> Reload the page and confirm that the Next button advances to the next slide. +
    + + + +## Reading Initial State from the DOM + +コントローラが、`this.index`プロパティで、その状態(現在選択されているスライド)をどのように追跡しているかに注目してください。 + +ここで、スライドショーの1つを最初のスライドではなく2番目のスライドを表示した状態で開始したいとします。 マークアップで開始インデックスを指示するにはどうすればよいでしょうか? + +1つの方法は、HTMLデータ属性を利用して初期インデックスを受け渡すことです。 例えば、以下のようにコントローラの要素に`data-index`属性を追加します: + +```html +
    +``` + +そして、`initialize()`メソッドでその属性を読み込んで整数に変換し、`showCurrentSlide()`から参照できるようにします: + +```javascript +initialize() { + this.index = Number(this.element.dataset.index) + this.showCurrentSlide() +} +``` + +これでやりたいことは実現できるかもしれませんが、これではまだ幾分扱いにくく感じます。 インデックスをインクリメントして結果をDOMに永続化することができなかったり、属性名を考えたりする必要があります。 + +
    + 原文 + +Notice how our controller tracks its state—the currently selected slide—in the this.index property. + +Now say we’d like to start one of our slideshows with the second slide visible instead of the first. How can we encode the start index in our markup? + +One way might be to load the initial index with an HTML data attribute. For example, we could add a data-index attribute to the controller’s element: + +```html +
    +``` + +Then, in our initialize() method, we could read that attribute, convert it to an integer, and pass it to showCurrentSlide(): + +```javascript +initialize() { + this.index = Number(this.element.dataset.index) + this.showCurrentSlide() +} +``` + +This might get the job done, but it’s clunky, requires us to make a decision about what to name the attribute, and doesn’t help us if we want to access the index again or increment it and persist the result in the DOM. +
    + + +## Valuesを使う + +Stimulusコントローラはデータ属性に自動的にマッピングされる型付き値プロパティをサポートしています。 コントローラクラスの先頭に`values`の定義を追加します: + +```javascript +static values = { index: Number } +``` + +Stimulusは、`data-slideshow-index-value`属性に関連付けられた`this.indexValue`プロパティを作成し、数値にキャストした結果にアクセスできるようにしてくれます。 + +実際に見てみましょう。関連するdata属性をHTMLに追加します: + +```html +
    +``` + +次に、コントローラに静的な`values`の定義を追加し、`initialize()`メソッドを変更して`this.indexValu`の値をログにだすようにしてみましょう: + +```javascript +export default class extends Controller { + static values = { index: Number } + + initialize() { + console.log(this.indexValue) + console.log(typeof this.indexValue) + } + + // … +} +``` + +ページをリロードし、コンソールを確認してみましょう。 `1`と`Number`が表示されているはずです。 + + +
    + 原文 +Stimulus controllers support typed value properties which automatically map to data attributes. When we add a value definition to the top of our controller class: + +```javascript + static values = { index: Number } +``` + +Stimulus will create a this.indexValue controller property associated with a data-slideshow-index-value attribute, and handle the numeric conversion for us. + +Let’s see that in action. Add the associated data attribute to our HTML: + +```html +
    +``` + +Then add a static values definition to the controller and change the initialize() method to log this.indexValue: + +```javascript +export default class extends Controller { + static values = { index: Number } + + initialize() { + console.log(this.indexValue) + console.log(typeof this.indexValue) + } + + // … +} +``` + +Reload the page and verify that the console shows 1 and Number. +
    + +## static valuesの行の意味 + +ターゲットと同様に、`values`という静的オブジェクトプロパティに値を記述して定義します。 ここでは、`index`という単一の数値を定義しています。 値の定義については、リファレンスを参照してください。 + +それでは、コントローラの`initialize()`と他のメソッドを修正して、`this.index`の代わりに`this.indexValue`を使用するようにしましょう: + +```javascript +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "slide" ] + static values = { index: Number } + + initialize() { + this.showCurrentSlide() + } + + next() { + this.indexValue++ + this.showCurrentSlide() + } + + previous() { + this.indexValue-- + this.showCurrentSlide() + } + + showCurrentSlide() { + this.slideTargets.forEach((element, index) => { + element.hidden = index !== this.indexValue + }) + } +} +``` + +ページをリロードし、Webインスペクタを使って、controller要素の`data-slideshow-index-value`属性が、次のスライドに移るたびに変化することを確認しましょう。 + + +
    + 原文 +Similar to targets, you define values in a Stimulus controller by describing them in a static object property called values. In this case, we’ve defined a single numeric value called index. You can read more about value definitions in the reference documentation. + +Now let’s update initialize() and the other methods in the controller to use this.indexValue instead of this.index. Here’s how the controller should look when we’re done: + +```javascript +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "slide" ] + static values = { index: Number } + + initialize() { + this.showCurrentSlide() + } + + next() { + this.indexValue++ + this.showCurrentSlide() + } + + previous() { + this.indexValue-- + this.showCurrentSlide() + } + + showCurrentSlide() { + this.slideTargets.forEach((element, index) => { + element.hidden = index !== this.indexValue + }) + } +} +``` + +Reload the page and use the web inspector to confirm the controller element’s data-slideshow-index-value attribute changes as you move from one slide to the next. +
    + +## Change Callbacks + +修正したコントローラは元のバージョンより改善されていますが、`this.showCurrentSlide()`を繰り返し呼び出しているのが目立ちます。 コントローラの初期化時と、`this.indexValue`を更新した時にたびたびドキュメントの状態を手動で更新しなければなりません。 + +Stimulusの`ValueChanged`コールバックを定義することで、繰り返しを一掃し、インデックス値が変更されるたびにコントローラがどのように応答すべきかを指定することができます。 + +まず、`initialize()`メソッドを削除し、新しいメソッド`indexValueChanged()`を定義します。 次に、`next()`と`previous()`から`this.showCurrentSlide()`の呼び出しを削除します: + +```javascript +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "slide" ] + static values = { index: Number } + + next() { + this.indexValue++ + } + + previous() { + this.indexValue-- + } + + indexValueChanged() { + this.showCurrentSlide() + } + + showCurrentSlide() { + this.slideTargets.forEach((element, index) => { + element.hidden = index !== this.indexValue + }) + } +} +``` + +ページをリロードし、スライドショーの動作が同じであることを確認しましょう。 + +Stimulusは初期化時および`data-slideshow-index-value`属性の変更に応じて`indexValueChanged()`メソッドを呼び出します。 Webインスペクタで属性をいじれば、コントローラがそれに応答してスライドを変更します。 ぜひ試してみてください! + +
    + 原文 +Our revised controller improves on the original version, but the repeated calls to this.showCurrentSlide() stand out. We have to manually update the state of the document when the controller initializes and after every place where we update this.indexValue. + +We can define a Stimulus value change callback to clean up the repetition and specify how the controller should respond whenever the index value changes. + +First, remove the initialize() method and define a new method, indexValueChanged(). Then remove the calls to this.showCurrentSlide() from next() and previous(): + +```javascript +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "slide" ] + static values = { index: Number } + + next() { + this.indexValue++ + } + + previous() { + this.indexValue-- + } + + indexValueChanged() { + this.showCurrentSlide() + } + + showCurrentSlide() { + this.slideTargets.forEach((element, index) => { + element.hidden = index !== this.indexValue + }) + } +} +``` + +Reload the page and confirm the slideshow behavior is the same. + +Stimulus calls the indexValueChanged() method at initialization and in response to any change to the data-slideshow-index-value attribute. You can even fiddle with the attribute in the web inspector and the controller will change slides in response. Go ahead—try it out! +
    + +## デフォルト値を指定する + +`static values`の行を少し変更すればデフォルト値を設定することも可能です。 デフォルト値の指定は次のように行います: + +```javascript +static values = { index: { type: Number, default: 2 } } +``` + +controller要素に`data-slideshow-index-value`属性が定義されていなければ、インデックスを2から開始します。 他の値があれば、デフォルトが必要なものとそうでないものを混在させることができます: + +```javascript +static values = { index: Number, effect: { type: String, default: "kenburns" } } +``` + +
    + 原文 +It’s also possible to set a default values as part of the static definition. This is done like so: + +```javascript + static values = { index: { type: Number, default: 2 } } +``` + +That would start the index at 2, if no data-slideshow-index-value attribute was defined on the controller element. If you had other values, you can mix and match what needs a default and what doesn’t: + +```javascript + static values = { index: Number, effect: { type: String, default: "kenburns" } } +``` +
    + +## おさらいと次のステップ + +この章では、`values`を使用してスライドショーコントローラの現在のインデックス値を読み取り、永続化する方法について見てきました。 + +ユーザビリティの観点からは、このコントローラは不完全です。最初のスライドを表示している時、Previousボタンは何もしてくれません。 内部的には、`indexValue`は`0`から`-1`まで減少します。 `-1`の代わりに、値を最後のスライドインデックスにして、ループするようにしたいですね(Nextボタンにも同様の問題があります)。 + +次の章では、Stimulusコントローラで外部リソースにアクセスする方法を見ていきます。 + + +
    + 原文 +In this chapter we’ve seen how to use the values to load and persist the current index of a slideshow controller. + +From a usability perspective, our controller is incomplete. The Previous button appears to do nothing when you are looking at the first slide. Internally, indexValue decrements from 0 to -1. Could we make the value wrap around to the last slide index instead? (There’s a similar problem with the Next button.) + +Next we’ll look at how to keep track of external resources, such as timers and HTTP requests, in Stimulus controllers. +
    From 0abc42344a5ff5e12049f9eeec53de69d48b5a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Fri, 22 Dec 2023 18:56:06 +0900 Subject: [PATCH 060/183] add working-with-external-resources --- _includes/stimulus--section-nav.html | 3 + .../working-with-external-resources.md | 443 ++++++++++++++++++ 2 files changed, 446 insertions(+) create mode 100644 stimulus/handbook/working-with-external-resources.md diff --git a/_includes/stimulus--section-nav.html b/_includes/stimulus--section-nav.html index 536efc84..f15e4363 100644 --- a/_includes/stimulus--section-nav.html +++ b/_includes/stimulus--section-nav.html @@ -14,4 +14,7 @@
  • ステート管理
  • +
  • + 外部リソースの利用 +
  • diff --git a/stimulus/handbook/working-with-external-resources.md b/stimulus/handbook/working-with-external-resources.md new file mode 100644 index 00000000..6bfc4d66 --- /dev/null +++ b/stimulus/handbook/working-with-external-resources.md @@ -0,0 +1,443 @@ +--- +title: "外部リソースの利用" +description: "Stimulusで外部リソースを取得して情報を更新したり、タイマーを使ったりする方法を見ていきましょう。" +layout: "stimulus--base.html" +--- + +# 外部リソースの利用 + +前章では、valuesを使用してコントローラの内部状態をロードし、永続化する方法を学びました。 + +時折コントローラーは外部リソースの状態を取得しなければならない場合があります。 ここでの外部とは、DOMやStimulusの一部ではないものを指します。 例えば、HTTPリクエストを発行し、リクエストの状態の変化に応じて応答する必要があるかもしれません。 あるいは、タイマーを開始し、コントローラがdisconnectした時にタイマーを停止する必要があるかもしれません。 この章では、こういったケースに対応するための方法を説明します。 + +
    + 原文 +In the last chapter we learned how to load and persist a controller’s internal state using values. + +Sometimes our controllers need to track the state of external resources, where by external we mean anything that isn’t in the DOM or a part of Stimulus. For example, we may need to issue an HTTP request and respond as the request’s state changes. Or we may want to start a timer and then stop it when the controller is no longer connected. In this chapter we’ll see how to do both of those things. +
    + +## HTMLの非同期読み込み + +リモートのHTMLスニペットを読み込んで挿入することで、ページの一部を非同期に生成する方法を学びましょう。 Basecampでは、このテクニックを使うことで、最初のページ読み込みを高速に保ち、ビューにユーザー固有のコンテンツを含まないようにして、より効率的にキャッシュできるようにしています。 + +汎用のコンテンツローダーコントローラを作成し、サーバから取得したHTMLスニペットを要素に埋め込みます。 そして、それを使って、メールの受信トレイにあるような未読メッセージのリストを読み込みます。 + +`public/index.html`に受信トレイをスケッチすることから始めましょう: + +```javascript +
    +``` + +次に、メッセージ・リスト用のHTMLを含む`public/messages.html`ファイルを新規作成します: + +```javascript +
      +
    1. New Message: Stimulus Launch Party
    2. +
    3. Overdue: Finish Stimulus 1.0
    4. +
    +``` + +(実際のアプリケーションでは、このHTMLをサーバー上で動的に生成することになるが、デモでは静的なファイルを使うことにします) + +これで、コントローラを実装できるようになりました: + +```javascript +// src/controllers/content_loader_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static values = { url: String } + + connect() { + this.load() + } + + load() { + fetch(this.urlValue) + .then(response => response.text()) + .then(html => this.element.innerHTML = html) + } +} +``` + +コントローラが接続されると、要素の`data-content-loader-url-value`属性で指定されたURLへのFetchリクエストを開始します。 そして、返されたHTMLを要素の`innerHTML`プロパティに代入して表示させます。 + +ブラウザの開発者コンソールでネットワークタブを開き、ページをリロードします。 最初のページロードを表すリクエストと、それに続く`messages.html`へのリクエストが表示されましたね。 + +
    + 原文 +Let’s learn how to populate parts of a page asynchronously by loading and inserting remote fragments of HTML. We use this technique in Basecamp to keep our initial page loads fast, and to keep our views free of user-specific content so they can be cached more effectively. + +We’ll build a general-purpose content loader controller which populates its element with HTML fetched from the server. Then we’ll use it to load a list of unread messages like you’d see in an email inbox. + +Begin by sketching the inbox in public/index.html: + +```javascript +
    +``` + +Then create a new public/messages.html file with some HTML for our message list: + +```javascript +
      +
    1. New Message: Stimulus Launch Party
    2. +
    3. Overdue: Finish Stimulus 1.0
    4. +
    +``` + +(In a real application you’d generate this HTML dynamically on the server, but for demonstration purposes we’ll just use a static file.) + +Now we can implement our controller: + +```javascript +// src/controllers/content_loader_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static values = { url: String } + + connect() { + this.load() + } + + load() { + fetch(this.urlValue) + .then(response => response.text()) + .then(html => this.element.innerHTML = html) + } +} +``` + +When the controller connects, we kick off a Fetch request to the URL specified in the element’s data-content-loader-url-value attribute. Then we load the returned HTML by assigning it to our element’s innerHTML property. + +Open the network tab in your browser’s developer console and reload the page. You’ll see a request representing the initial page load, followed by our controller’s subsequent request to messages.html. +
    + +## タイマーを利用した自動更新 + +受信トレイを定期的に更新し、常に最新の状態にするようにコントローラを改善してみましょう。 + +`data-content-loader-refresh-interval-value`属性を新たに作り、コントローラの内容をリロードする頻度をミリ秒単位で指定できるようにしましょう: + +```javascript +
    +``` + +これで、設定したインターバルでコントローラをチェックし、存在すれば更新するように実装することができます。 + +コントローラで`static values`の定義に、HTML側に記述した`url`と`refreshInterval`の二つを追加し、新しいメソッド`startRefreshing()`を定義します: + +```javascript +export default class extends Controller { + static values = { url: String, refreshInterval: Number } + + startRefreshing() { + setInterval(() => { + this.load() + }, this.refreshIntervalValue) + } + + // … +} +``` + +次に、`connect()`メソッドを更新して、インターバル値が存在する場合は`startRefreshing()`メソッドを呼び出すようにしましょう: + +```javascript +connect() { + this.load() + + if (this.hasRefreshIntervalValue) { + this.startRefreshing() + } +} +``` + +ページをリロードし、開発者コンソールを見てみましょう。 5秒に一度、新しいリクエストが飛んでいることがわかります。 それが確認できたら`public/messages.html`に変更を加えて、その変更後のメッセージが受信箱に表示されるのを待ちましょう。 + + +
    + 原文 + +Let’s improve our controller by changing it to periodically refresh the inbox so it’s always up-to-date. + +We’ll use the data-content-loader-refresh-interval-value attribute to specify how often the controller should reload its contents, in milliseconds: + +```javascript +
    +``` + +Now we can update the controller to check for the interval and, if present, start a refresh timer. + +Add a static values definition to the controller, and define a new method startRefreshing(): + +```javascript +export default class extends Controller { + static values = { url: String, refreshInterval: Number } + + startRefreshing() { + setInterval(() => { + this.load() + }, this.refreshIntervalValue) + } + + // … +} +``` + +Then update the connect() method to call startRefreshing() if an interval value is present: + +```javascript + connect() { + this.load() + + if (this.hasRefreshIntervalValue) { + this.startRefreshing() + } + } +``` + +Reload the page and observe a new request once every five seconds in the developer console. Then make a change to public/messages.html and wait for it to appear in the inbox. +
    + +## リソースの取得のインターバルの解除 + +今のままではコントローラが接続されたときにタイマーは開始されますが、決して停止することはありません。 つまり、コントローラに対応する要素が消えてしまった場合でも、 コントローラはバックグラウンドでHTTPリクエストを投げ続けることになってしまいます。 + +この問題を解決するに、`startRefreshing()`メソッドを変更してタイマーへの参照を保持するようにします: + +```javascript +startRefreshing() { + this.refreshTimer = setInterval(() => { + this.load() + }, this.refreshIntervalValue) +} +``` + +そして、対応する`stopRefreshing()`メソッドを下に追加して、タイマーをキャンセルすることができるように実装します: + +```javascript +stopRefreshing() { + if (this.refreshTimer) { + clearInterval(this.refreshTimer) + } +} +``` + +最後に、コントローラが切断されたときにタイマーをキャンセルするようにStimulusに指示するために、`disconnect()`メソッドを追加します: + +```javascript +disconnect() { + this.stopRefreshing() +} +``` + +これで、コンテンツローダーコントローラーが、DOMに接続されている間だけリクエストを発行するように修正することができました。 + +完成系のコントローラを見てみましょう: + +```javascript +// src/controllers/content_loader_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static values = { url: String, refreshInterval: Number } + + connect() { + this.load() + + if (this.hasRefreshIntervalValue) { + this.startRefreshing() + } + } + + disconnect() { + this.stopRefreshing() + } + + load() { + fetch(this.urlValue) + .then(response => response.text()) + .then(html => this.element.innerHTML = html) + } + + startRefreshing() { + this.refreshTimer = setInterval(() => { + this.load() + }, this.refreshIntervalValue) + } + + stopRefreshing() { + if (this.refreshTimer) { + clearInterval(this.refreshTimer) + } + } +} +``` + +
    + 原文 +We start our timer when the controller connects, but we never stop it. That means if our controller’s element were to disappear, the controller would continue to issue HTTP requests in the background. + +We can fix this issue by modifying our startRefreshing() method to keep a reference to the timer: + +```javascript + startRefreshing() { + this.refreshTimer = setInterval(() => { + this.load() + }, this.refreshIntervalValue) + } +``` + +Then we can add a corresponding stopRefreshing() method below to cancel the timer: + +```javascript + stopRefreshing() { + if (this.refreshTimer) { + clearInterval(this.refreshTimer) + } + } +``` + +Finally, to instruct Stimulus to cancel the timer when the controller disconnects, we’ll add a disconnect() method: + +```javascript + disconnect() { + this.stopRefreshing() + } +``` + +Now we can be sure a content loader controller will only issue requests when it’s connected to the DOM. + +Let’s take a look at our final controller class: + +```javascript +// src/controllers/content_loader_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static values = { url: String, refreshInterval: Number } + + connect() { + this.load() + + if (this.hasRefreshIntervalValue) { + this.startRefreshing() + } + } + + disconnect() { + this.stopRefreshing() + } + + load() { + fetch(this.urlValue) + .then(response => response.text()) + .then(html => this.element.innerHTML = html) + } + + startRefreshing() { + this.refreshTimer = setInterval(() => { + this.load() + }, this.refreshIntervalValue) + } + + stopRefreshing() { + if (this.refreshTimer) { + clearInterval(this.refreshTimer) + } + } +} +``` +
    + +## アクションパラメータを利用する + +もしローダーを複数の異なるソースで動作させたいのであれば、アクションパラメーターが使えます。 次のHTMLを見てみましょう: + +```html + +``` + +そうすれば、loadアクションでそのパラメーターを参照することができます: + +```javascript +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + load({ params }) { + fetch(params.url) + .then(response => response.text()) + .then(html => this.element.innerHTML = html) + } +} +``` + +paramsを分解して`url`パラメータだけを取得することもできます: + +```javascript +load({ params: { url } }) { + fetch(url) + .then(response => response.text()) + .then(html => this.element.innerHTML = html) +} +``` + +
    + 原文 +If we wanted to make the loader work with multiple different sources, we could do it using action parameters. Take this HTML: + +```html + +``` + +Then we can use those parameters through the load action: + +```javascript +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + load({ params }) { + fetch(params.url) + .then(response => response.text()) + .then(html => this.element.innerHTML = html) + } +} +``` + +We could even destruct the params to just get the URL parameter: + +```javascript + load({ params: { url } }) { + fetch(url) + .then(response => response.text()) + .then(html => this.element.innerHTML = html) + } +``` +
    + +## おさらいと次のステップ + +この章では、Stimulus のライフサイクルコールバックを使用して外部リソースを取得および解放する方法を見てきました。 + +次に、独自のアプリケーションにStimulus をインストールして設定する方法を説明します。 + +
    + 原文 +In this chapter we’ve seen how to acquire and release external resources using Stimulus lifecycle callbacks. + +Next we’ll see how to install and configure Stimulus in your own application. +
    From 03f144aa5d547de271ca836e4f47e9242f0fbc02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Fri, 22 Dec 2023 19:48:39 +0900 Subject: [PATCH 061/183] add installing --- _includes/stimulus--section-nav.html | 3 + stimulus/handbook/installing.md | 295 +++++++++++++++++++++++++++ 2 files changed, 298 insertions(+) create mode 100644 stimulus/handbook/installing.md diff --git a/_includes/stimulus--section-nav.html b/_includes/stimulus--section-nav.html index f15e4363..a6c9b0cf 100644 --- a/_includes/stimulus--section-nav.html +++ b/_includes/stimulus--section-nav.html @@ -17,4 +17,7 @@
  • 外部リソースの利用
  • +
  • + アプリケーションにStimulusをインストールする +
  • diff --git a/stimulus/handbook/installing.md b/stimulus/handbook/installing.md new file mode 100644 index 00000000..2ea24443 --- /dev/null +++ b/stimulus/handbook/installing.md @@ -0,0 +1,295 @@ +--- +title: "アプリケーションにStimulusをインストールする" +description: "様々なシステム環境のアプリケーションでStimulusをインストールする方法について" +layout: "stimulus--base.html" +--- + +# アプリケーションにStimulusをインストールする + +アプリケーションにStimulusをインストールするには、JavaScriptのバンドルに`@hotwired/stimulus` npm パッケージを追加します。あるいはバンドラーを利用してない場合は、` + + +
    + + … +
    + + +``` + +
    + 原文 + +If you prefer not to use a build system, you can load Stimulus in a ` + + +
    + + … +
    + + +``` +
    + +## Stimulusのデフォルトの属性規則を上書きする + +Stimulusが使用する`data-*`属性がプロジェクト内の他のライブラリと衝突する場合、Stimulus Applicationを作成する際に上書きして変更することができます。 + +* `data-controller` +* `data-action` +* `data-target` + +これらのStimulusのコア属性はオーバーライドすることができます(参照:schema.ts): + +```javascript +// src/application.js +import { Application, defaultSchema } from "@hotwired/stimulus" + +const customSchema = { + ...defaultSchema, + actionAttribute: 'data-stimulus-action' +} + +window.Stimulus = Application.start(document.documentElement, customSchema); +``` + +
    + 原文 + +In case Stimulus data-* attributes conflict with another library in your project, they can be overridden when creating the Stimulus Application. + +* data-controller +* data-action +* data-target + +These core Stimulus attributes can be overridden (see: schema.ts): + +```javascript +// src/application.js +import { Application, defaultSchema } from "@hotwired/stimulus" + +const customSchema = { + ...defaultSchema, + actionAttribute: 'data-stimulus-action' +} + +window.Stimulus = Application.start(document.documentElement, customSchema); +``` +
    + +## エラーハンドリング + +Stimulusからのアプリケーションコードへの呼び出しはすべて`try ... catch`ブロックでラップされます。 + +あなたのコードがエラーをスローした場合、それは Stimulus によってキャッチされ、コントローラ名、呼び出されたイベントまたはライフサイクル関数などの詳細情報を含め、ブラウザコンソールに記録されます。 `window.onerror`を定義したエラー追跡システムを使用している場合、Stimulusはそのシステムにもエラーを渡します。 + +`Application#handleError`を定義することで、Stimulus がエラーを処理する方法をオーバーライドすることもできます: + +```javascript +// src/application.js +import { Application } from "@hotwired/stimulus" +window.Stimulus = Application.start() + +Stimulus.handleError = (error, message, detail) => { + console.warn(message, detail) + ErrorTrackingSystem.captureException(error) +} +``` + +
    + 原文 + +All calls from Stimulus to your application’s code are wrapped in a try ... catch block. + +If your code throws an error, it will be caught by Stimulus and logged to the browser console, including extra detail such as the controller name and event or lifecycle function being called. If you use an error tracking system that defines window.onerror, Stimulus will also pass the error on to it. + +You can override how Stimulus handles errors by defining Application#handleError: + +```javascript +// src/application.js +import { Application } from "@hotwired/stimulus" +window.Stimulus = Application.start() + +Stimulus.handleError = (error, message, detail) => { + console.warn(message, detail) + ErrorTrackingSystem.captureException(error) +} +``` +
    + +## デバッグ + +Stimulusアプリケーションを`window.Stimulus`に割り当てている場合、`Stimulus.debug = true`でコンソールからデバッグモードをオンにすることができます。 このフラグはソースコードでアプリケーションインスタンスを作成するときにも設定できます。 + +
    + 原文 + +If you’ve assigned your Stimulus application to window.Stimulus, you can turn on debugging mode from the console with Stimulus.debug = true. You can also set this flag when you’re configuring your application instance in the source code. +
    + +## ブラウザサポート + +Stimulusは、すべてのエバーグリーンブラウザ(デスクトップおよびモバイル)をサポートしています。 また、Stimulus 3+はInternet Explorer 11をサポートしていません(しかし、その場合`@stimulus/polyfills`とStimulus 2を使用することができます)。 + +
    + 原文 + +Stimulus supports all evergreen, self-updating desktop and mobile browsers out of the box. Stimulus 3+ does not support Internet Explorer 11 (but you can use Stimulus 2 with the @stimulus/polyfills for that). +
    From 2ffab3165947eaa335137f156a46e9fd5800d15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Mon, 25 Dec 2023 19:26:59 +0900 Subject: [PATCH 062/183] add origin --- _includes/stimulus--section-nav.html | 3 + stimulus/handbook/origin.md | 171 +++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 stimulus/handbook/origin.md diff --git a/_includes/stimulus--section-nav.html b/_includes/stimulus--section-nav.html index a6c9b0cf..343bb4af 100644 --- a/_includes/stimulus--section-nav.html +++ b/_includes/stimulus--section-nav.html @@ -1,4 +1,7 @@
    ``` -これを読めば、何が起こっているのかがよく分かると思います。 Stimulusについて何も知らなくても、コントローラのコードそのものを見なくても。 ほとんど擬似コードのようなものですね。 これは、外部のJavaScriptファイルがイベントハンドラを適用するHTMLのスライスを読み取ることとは大きく異なります。 また、現代のJavaScriptフレームワークの多くで失われている関心ごとの分離も維持されています。 +これを読めば、何が起こっているのかがよく分かると思います。 Stimulusについて何も知らなくても、コントローラのコードそのものを見なくても。 ほとんど擬似コードのようなものですね。 これは、イベントハンドラが外部のJavaScriptファイルで設定されているHTMLを読み取ることとは大きく異なります。 また、現代のJavaScriptフレームワークの多くで失われている関心ごとの分離も維持されています。 見てわかるように、StimulusはHTMLの作成に悩まされることはありません。 JavaScriptでHTMLを作成する代わりに、既存のHTMLドキュメントにアタッチします。 HTMLは、ほとんどの場合、ページロード時(最初のヒットまたはTurbo経由)、またはDOMを変更するAjaxリクエスト経由のいずれかの時にサーバ側でレンダリングされます。 From 8af123e6b4a580a4740590a5aed26b32aab96529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Tue, 23 Jan 2024 19:26:28 +0900 Subject: [PATCH 079/183] =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC?= =?UTF-8?q?=E5=AF=BE=E5=BF=9C=20=E5=8D=98=E8=AA=9E=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stimulus/handbook/origin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stimulus/handbook/origin.md b/stimulus/handbook/origin.md index b8e84407..48b59444 100644 --- a/stimulus/handbook/origin.md +++ b/stimulus/handbook/origin.md @@ -84,7 +84,7 @@ Stimulusが適用されたHTMLを見ると、プログレッシブエンハン
    ``` -これを読めば、何が起こっているのかがよく分かると思います。 Stimulusについて何も知らなくても、コントローラのコードそのものを見なくても。 ほとんど擬似コードのようなものですね。 これは、イベントハンドラが外部のJavaScriptファイルで設定されているHTMLを読み取ることとは大きく異なります。 また、現代のJavaScriptフレームワークの多くで失われている関心ごとの分離も維持されています。 +これを読めば、何が起こっているのかがよく分かると思います。 Stimulusについて何も知らなくても、コントローラのコードそのものを見なくても。 ほとんど擬似コードのようなものですね。 これは、イベントハンドラが外部のJavaScriptファイルで設定されているHTMLを読み取ることとは大きく異なります。 また、現代のJavaScriptフレームワークの多くで失われている関心事の分離も維持されています。 見てわかるように、StimulusはHTMLの作成に悩まされることはありません。 JavaScriptでHTMLを作成する代わりに、既存のHTMLドキュメントにアタッチします。 HTMLは、ほとんどの場合、ページロード時(最初のヒットまたはTurbo経由)、またはDOMを変更するAjaxリクエスト経由のいずれかの時にサーバ側でレンダリングされます。 From ac0fbb932629b79b4de6d4548ff2d4133834dfed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Tue, 23 Jan 2024 19:29:05 +0900 Subject: [PATCH 080/183] =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC?= =?UTF-8?q?=E5=AF=BE=E5=BF=9C=20=E6=96=87=E8=A8=80=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stimulus/handbook/origin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stimulus/handbook/origin.md b/stimulus/handbook/origin.md index 48b59444..5707142c 100644 --- a/stimulus/handbook/origin.md +++ b/stimulus/handbook/origin.md @@ -86,7 +86,7 @@ Stimulusが適用されたHTMLを見ると、プログレッシブエンハン これを読めば、何が起こっているのかがよく分かると思います。 Stimulusについて何も知らなくても、コントローラのコードそのものを見なくても。 ほとんど擬似コードのようなものですね。 これは、イベントハンドラが外部のJavaScriptファイルで設定されているHTMLを読み取ることとは大きく異なります。 また、現代のJavaScriptフレームワークの多くで失われている関心事の分離も維持されています。 -見てわかるように、StimulusはHTMLの作成に悩まされることはありません。 JavaScriptでHTMLを作成する代わりに、既存のHTMLドキュメントにアタッチします。 HTMLは、ほとんどの場合、ページロード時(最初のヒットまたはTurbo経由)、またはDOMを変更するAjaxリクエスト経由のいずれかの時にサーバ側でレンダリングされます。 +見てわかるように、StimulusはHTMLの作成に悩まされることはありません。 JavaScriptでHTMLを作成するのではなく、既存のHTMLドキュメントにアタッチします。 HTMLは、ほとんどの場合、ページロード時(最初のヒットまたはTurbo経由)、またはDOMを変更するAjaxリクエスト経由のいずれかの時にサーバ側でレンダリングされます。 Stimulusは、こうして作られた既存のHTML文書を操作することに主眼をおいています。 時にStimulusは、要素を隠したり、アニメーションさせたり、ハイライトさせたりするCSSクラスを追加したりします。 グループ化された要素を再配置することもあります。 キャッシュ可能なUTC時間を表示可能なローカル時間に変換する場合もそうです。 From 67b29b3c918a18a783ea06ac34bb5c183e163e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Wed, 31 Jan 2024 10:54:55 +0900 Subject: [PATCH 081/183] =?UTF-8?q?=E6=9C=AC=E5=AE=B6=E3=81=AE=E5=A4=89?= =?UTF-8?q?=E6=9B=B4=E3=81=AB=E8=BF=BD=E9=9A=8F=20#748?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stimulus/handbook/origin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stimulus/handbook/origin.md b/stimulus/handbook/origin.md index 5707142c..f2d99777 100644 --- a/stimulus/handbook/origin.md +++ b/stimulus/handbook/origin.md @@ -8,7 +8,7 @@ layout: "stimulus--base.html" [Basecamp](https://basecamp.com/)ではJavaScriptをたくさん書いていますが、現代的な意味での「JavaScriptアプリケーション」を作るためにJavaScriptを使っているわけではありません。 Basecampのアプリケーションは、サーバーサイドでレンダリングされたHTMLを核に、JavaScriptを散りばめるようにしてできています。 -これが、[Majestic Monolith](https://m.signalvnoise.com/the-majestic-monolith/)のやり方です。 Basecampは、Ruby on Railsで作成された単一のコントローラ、ビュー、モデルで、ネイティブモバイルアプリを含む6つのプラットフォームで動作しています。 一箇所で更新可能な単一の共有インターフェイスを持つということは、多くのプラットフォームがあるにもかかわらず、少人数のチームで業務を遂行するための鍵となっています。 +これが、[Majestic Monolith](https://signalvnoise.com/svn3/the-majestic-monolith/)のやり方です。 Basecampは、Ruby on Railsで作成された単一のコントローラ、ビュー、モデルで、ネイティブモバイルアプリを含む6つのプラットフォームで動作しています。 一箇所で更新可能な単一の共有インターフェイスを持つということは、多くのプラットフォームがあるにもかかわらず、少人数のチームで業務を遂行するための鍵となっています。 それによって、昔のような高い生産性を体験できます。 一人のプログラマーが、間接的なレイヤーや分散システムに囚われることなく、貪欲に前進することができた時代に戻るのです。 JavaScriptベースのクライアントアプリケーションのために、サーバーサイドアプリケーションに、ただただJSONの生成だけをさせることが正しい方法だと皆が考える前の時代です。 From d67e2c1fa49085b2bc18a24dac63b0af300ca96a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Thu, 1 Feb 2024 13:50:41 +0900 Subject: [PATCH 082/183] =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC?= =?UTF-8?q?=E5=AF=BE=E5=BF=9C=20DHH=E3=81=AE=E5=90=8D=E5=89=8D=E3=82=92?= =?UTF-8?q?=E6=9C=AB=E5=B0=BE=E3=81=AB=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stimulus/handbook/origin.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stimulus/handbook/origin.md b/stimulus/handbook/origin.md index f2d99777..c252ac87 100644 --- a/stimulus/handbook/origin.md +++ b/stimulus/handbook/origin.md @@ -151,6 +151,8 @@ Basecampでも、必要に応じて、いくつかの重たいアプローチを ぜひお試しください。 +David Heinemeier Hansson +
    原文 At Basecamp we’ve used this architecture across several different versions of Basecamp and other applications for years. GitHub has used a similar approach to great effect. This is not only a valid alternative to the mainstream understanding of what a “modern” web application looks like, it’s an incredibly compelling one. @@ -166,4 +168,6 @@ This set of alternative frameworks is about avoiding the heavy lifting as much a Above all, it’s a toolkit for small teams who want to compete on fidelity and reach with much larger teams using more laborious, mainstream approaches. Give it a go. + +David Heinemeier Hansson
    From 94b8319c3e74a174ece9027effdcde0c66b3bf52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Thu, 1 Feb 2024 14:46:46 +0900 Subject: [PATCH 083/183] =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC?= =?UTF-8?q?=E5=AF=BE=E5=BF=9C=20=E9=9B=A3=E3=81=97=E3=81=84=E8=A8=80?= =?UTF-8?q?=E3=81=84=E5=9B=9E=E3=81=97=E3=81=AE=E8=A8=80=E3=81=84=E6=8F=9B?= =?UTF-8?q?=E3=81=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stimulus/handbook/origin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stimulus/handbook/origin.md b/stimulus/handbook/origin.md index c252ac87..cf32fd59 100644 --- a/stimulus/handbook/origin.md +++ b/stimulus/handbook/origin.md @@ -141,7 +141,7 @@ Basecampでは、このアーキテクチャをBasecampのいくつかのバー 実際のところ、現代の主流なアプローチは無駄に複雑で、もっと速く、もっと少ないコストでできるはずだという、私たちがBasecampで[Ruby on Rails](https://rubyonrails.org/)を開発した時と同じような感覚があるのです。 -しかも、選ぶ必要もありません。 StimulusとTurboは、他の重いアプローチと組み合わせても効果的です。アプリケーションの80%が重たいアプローチを必要としない場合は、当社の2パックパンチ(Stimulus/Turbo)の使用をご検討ください。 そして、アプリケーションの中でそれをすることで本当にメリットがある部分にだけ、重たいアプローチを導入してもよいでしょう。 +しかも、選ぶ必要もありません。 StimulusとTurboは、他の重いアプローチと組み合わせても効果的です。アプリケーションの80%が重たいアプローチを必要としない場合は、当社の2パックパンチ(Stimulus/Turbo)の使用をご検討ください。 そして、本当にメリットがある部分にだけ、重たいアプローチの導入を検討しましょう。 Basecampでも、必要に応じて、いくつかの重たいアプローチを採用しています。 たとえばカレンダーみたいなものははクライアントサイドレンダリングを使っています。 Basecamp上のテキストエディタは[Trix](https://trix-editor.org/)で、これはStimulusのコントローラとは関係のない完全なテキストプロセッサです。 From a9184903f111e16a7666cb516002f307e953e01f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Thu, 1 Feb 2024 14:48:14 +0900 Subject: [PATCH 084/183] =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC?= =?UTF-8?q?=E5=AF=BE=E5=BF=9C=20=E9=9B=A3=E3=81=97=E3=81=84=E8=A1=A8?= =?UTF-8?q?=E7=8F=BE=E3=81=AE=E8=A8=80=E3=81=84=E6=8F=9B=E3=81=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stimulus/handbook/origin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stimulus/handbook/origin.md b/stimulus/handbook/origin.md index cf32fd59..2132d9cd 100644 --- a/stimulus/handbook/origin.md +++ b/stimulus/handbook/origin.md @@ -141,7 +141,7 @@ Basecampでは、このアーキテクチャをBasecampのいくつかのバー 実際のところ、現代の主流なアプローチは無駄に複雑で、もっと速く、もっと少ないコストでできるはずだという、私たちがBasecampで[Ruby on Rails](https://rubyonrails.org/)を開発した時と同じような感覚があるのです。 -しかも、選ぶ必要もありません。 StimulusとTurboは、他の重いアプローチと組み合わせても効果的です。アプリケーションの80%が重たいアプローチを必要としない場合は、当社の2パックパンチ(Stimulus/Turbo)の使用をご検討ください。 そして、本当にメリットがある部分にだけ、重たいアプローチの導入を検討しましょう。 +しかも、選ぶ必要もありません。 StimulusとTurboは、他の重いアプローチと組み合わせても効果的です。アプリケーションの80%が重たいアプローチを必要としない場合は、Stimulus、Turboの使用をご検討ください。 そして、本当にメリットがある部分にだけ、重たいアプローチの導入を検討しましょう。 Basecampでも、必要に応じて、いくつかの重たいアプローチを採用しています。 たとえばカレンダーみたいなものははクライアントサイドレンダリングを使っています。 Basecamp上のテキストエディタは[Trix](https://trix-editor.org/)で、これはStimulusのコントローラとは関係のない完全なテキストプロセッサです。 From a0442dc42a3cbe31d7a9d33caa4cb02fb7ae733b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Thu, 1 Feb 2024 14:49:19 +0900 Subject: [PATCH 085/183] =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC?= =?UTF-8?q?=E5=AF=BE=E5=BF=9C=20=E4=B8=8A=E9=95=B7=E3=81=AA=E8=A1=A8?= =?UTF-8?q?=E7=8F=BE=E3=81=AE=E9=99=A4=E5=8E=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stimulus/handbook/origin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stimulus/handbook/origin.md b/stimulus/handbook/origin.md index 2132d9cd..a842406d 100644 --- a/stimulus/handbook/origin.md +++ b/stimulus/handbook/origin.md @@ -135,7 +135,7 @@ It really is a remarkably different paradigm. One that I’m sure many veteran J If, on the other hand, you have nagging sense that what you’re working on does not warrant the intense complexity and application separation such contemporary techniques imply, then you’re likely to find refuge in our approach. -## Stimulusとそれに関連するアイデアは、自然に抽出されたもの +## Stimulusと関連するアイデアは、自然に抽出されたもの Basecampでは、このアーキテクチャをBasecampのいくつかのバージョンや他のアプリケーションで長年使ってきました。 GitHubも同様のアプローチで大きな効果を上げています。 これは、 「モダンな」 Webアプリケーションがどのようなものであるかについての主流の考え方に対する有効な代替案であるだけでなく、信じられないほど説得力のあるものです。 From 681ae822600ba56a9923ba046557601a64c20e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Mon, 5 Feb 2024 11:59:29 +0900 Subject: [PATCH 086/183] =?UTF-8?q?=20=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC?= =?UTF-8?q?=E5=AF=BE=E5=BF=9C=20=E4=BA=8C=E5=88=86=E5=88=86=E5=89=B2?= =?UTF-8?q?=E3=81=A8=E8=A8=80=E3=81=84=E6=8F=9B=E3=81=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stimulus/handbook/origin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stimulus/handbook/origin.md b/stimulus/handbook/origin.md index a842406d..39ee5625 100644 --- a/stimulus/handbook/origin.md +++ b/stimulus/handbook/origin.md @@ -118,7 +118,7 @@ There are cases where you’d want Stimulus to create new DOM elements, and you そのため、Stimulusは現代のJavaScriptフレームワークの大半とは大きく異なっています。 ほとんどすべてのフレームワークは、ある種のテンプレート言語を介してJSONをDOM要素に変換することに重点を置いています。 これらのフレームワークの多くは、空のページを作成し、そのページをJSONを元にしたテンプレートレンダリングによって作成された要素のみで埋めるために使用します。 -Stimulusはまた、ステートの扱いに関しても他のフレームワークと大きく異なります。 ほとんどのフレームワークは、JavaScriptオブジェクト内に状態を保持する方法を持ち、その状態に基づいてHTMLをレンダリングします。Stimulusは正反対の方法をとります。 ステートはHTML上に保存されるため、コントローラーはページの変更の間に破棄されますが、キャッシュされたHTMLが再び表示されたときに元の状態のまま再初期化されます。 +Stimulusはまた、ステートの扱いに関しても他のフレームワークと大きく異なります。 ほとんどのフレームワークは、JavaScriptオブジェクト内に状態を保持する方法を持ち、その状態に基づいてHTMLをレンダリングします。Stimulusは正反対の方法をとります。 ステートはHTML上に保存されます。 そのため、ページの変更の際にコントローラは破棄されますが、HTMLがキャッシュから再び表示されたときに元のステートを維持したまま復元することができます。 これは本当に驚くほど異なるパラダイムです。 現代のフレームワークを使い慣れたJavaScript開発者の多くは、これを馬鹿にし、あざ笑うことだと思います。 React + Reduxのような大混乱の中でアプリケーションを維持するのにかかる複雑さと労力に満足しているなら、Turbo + Stimulusはあなたにとって魅力的なものではないかもしれません。 From 66b536b79d45c01bc990f75b3e3e1718463b4adc Mon Sep 17 00:00:00 2001 From: "nakajima a.k.a. nazomikan" Date: Mon, 30 Sep 2024 12:56:57 +0900 Subject: [PATCH 087/183] Update stimulus/handbook/building-something-real.md Co-authored-by: Akira Yagi --- stimulus/handbook/building-something-real.md | 1 + 1 file changed, 1 insertion(+) diff --git a/stimulus/handbook/building-something-real.md b/stimulus/handbook/building-something-real.md index 452b582e..84f2b003 100644 --- a/stimulus/handbook/building-something-real.md +++ b/stimulus/handbook/building-something-real.md @@ -10,6 +10,7 @@ layout: "stimulus--base.html"
    原文 + We’ve implemented our first controller and learned how Stimulus connects HTML to JavaScript. Now let’s take a look at something we can use in a real application by recreating a controller from Basecamp.
    From 555b66864d14585eafa9333dd2c379fdb606141d Mon Sep 17 00:00:00 2001 From: "nakajima a.k.a. nazomikan" Date: Mon, 30 Sep 2024 12:57:59 +0900 Subject: [PATCH 088/183] Update stimulus/handbook/building-something-real.md Co-authored-by: Akira Yagi --- stimulus/handbook/building-something-real.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stimulus/handbook/building-something-real.md b/stimulus/handbook/building-something-real.md index 84f2b003..8f478a4a 100644 --- a/stimulus/handbook/building-something-real.md +++ b/stimulus/handbook/building-something-real.md @@ -6,7 +6,7 @@ layout: "stimulus--base.html" # 実際に使えるものを作る -Hello, Stimulusの章で、はじめてコントローラを実装し、StimulusがHTMLとJavaScriptをどのように接続するかを学びました。 次は、Basecampで使われているコントローラを再現して、実際のアプリケーションで使えるものを見てみましょう。 +Hello, Stimulusの章で、はじめてコントローラを実装し、 Stimulus が HTML と JavaScript をどのように接続するかを学びました。 次は、Basecamp で使われているコントローラを再現して、実際のアプリケーションで使えるものを見てみましょう。
    原文 From b47b4dfc7e3c6797cbff926d1077eb3dd23e9bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Wed, 27 Dec 2023 18:22:00 +0900 Subject: [PATCH 089/183] add stimulus/reference dir --- stimulus/reference/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 stimulus/reference/.gitkeep diff --git a/stimulus/reference/.gitkeep b/stimulus/reference/.gitkeep new file mode 100644 index 00000000..e69de29b From 7eda273f79c63613fc875a41a5a6ea58d5acf00f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Tue, 9 Jan 2024 14:24:27 +0900 Subject: [PATCH 090/183] add actions --- stimulus/reference/actions.md | 703 ++++++++++++++++++++++++++++++++++ 1 file changed, 703 insertions(+) create mode 100644 stimulus/reference/actions.md diff --git a/stimulus/reference/actions.md b/stimulus/reference/actions.md new file mode 100644 index 00000000..63a6f623 --- /dev/null +++ b/stimulus/reference/actions.md @@ -0,0 +1,703 @@ +--- +title: Actions +description: "アクションはコントローラでDOMイベントを処理する方法です" +layout: "base.html" +--- + +# Actions + +アクションは、コントローラでDOM イベントを処理する方法です。 + +```html +
    + +
    +``` + +```javascript +// controllers/gallery_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + next(event) { + // … + } +} +``` + +アクションは次に示すものをつなぎあわせたものです。 + +* コントローラのメソッド +* コントロラー要素 +* DOMイベントリスナ + +
    + 原文 + +_Actions_ are how you handle DOM events in your controllers. + +```html +
    + +
    +``` + +```javascript +// controllers/gallery_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + next(event) { + // … + } +} +``` + +An action is a connection between: + +* a controller method +* the controller's element +* a DOM event listener +
    + +## Descriptors + +`data-action`属性の値である`click->gallery#next`は _アクション記述子_ と呼ばれます。 この記述子の場合は: + +* `click` は購読するDOMイベント名 +* `gallery` はコントローラの識別子 +* `next` は呼び出すメソッド前 + +になります。 + +
    + 原文 + +The `data-action` value `click->gallery#next` is called an _action descriptor_. In this descriptor: + +* `click` is the name of the DOM event to listen for +* `gallery` is the controller identifier +* `next` is the name of the method to invoke +
    + +### イベント省略記法 + +Stimulusでは要素ごとにデフォルトのイベントが定められています。 デフォルトのイベントを購読する場合はアクション記述子内のイベント名を省略して、記述子全体を短くすることができます。 + +上記のクリックイベントの購読はボタン要素に設定する場合、次のように記述できます。 + +```html + +``` + +以下の表は要素ごとのデフォルトイベントの一覧を示したものです。 + +要素 | デフォルトイベント +----------------- | ------------- +a | click +button | click +details | toggle +form | submit +input | input +input type=submit | click +select | change +textarea | input + + +
    + 原文 + +Stimulus lets you shorten the action descriptors for some common element/event pairs, such as the button/click pair above, by omitting the event name: + +```html + +``` + +The full set of these shorthand pairs is as follows: + +Element | Default Event +----------------- | ------------- +a | click +button | click +details | toggle +form | submit +input | input +input type=submit | click +select | change +textarea | input +
    + +## キーボードイベントのフィルタ構文 + +[KeyboardEvent](https://developer.mozilla.org/ja/docs/Web/API/KeyboardEvent)を購読する場合、特定のキーが押された時だけ処理を実行したいということもあると思います。 + +以下の例のように、アクション記述子のイベント名の後に`.esc`を追加することで、`Escapeキー`にのみ反応するイベントリスナを設置することができます。 + +```html +
    +
    +``` + +このフィルタ構文は、発生したイベントがキーボードイベントである場合にのみ機能します。 + +以下の表はフィルタとキーの対応の一覧です。 + +フィルタ | キー名 +--------- | -------- +enter | Enter +tab | Tab +esc | Escape +space | " " +up | ArrowUp +down | ArrowDown +left | ArrowLeft +right | ArrowRight +home | Home +end | End +page_up | PageUp +page_down | PageDown +[a-z] | [a-z] +[0-9] | [0-9] + +ここにないキーをサポートする必要がある場合は、カスタムスキーマを使ってフィルタをカスタマイズすることができます。 + +```javascript +import { Application, defaultSchema } from "@hotwired/stimulus" + +const customSchema = { + ...defaultSchema, + keyMappings: { ...defaultSchema.keyMappings, at: "@" }, +} + +const app = Application.start(document.documentElement, customSchema) +``` + +修飾キーを使った複合的なイベントを購読したい場合は、`ctrl+a`のように書くことができます。 + +```html +
    ...
    +``` + +以下の表はStimulusがサポートする修飾キーの一覧です。 + +| 修飾キー | ノート | +| -------- | ------------------ | +| `alt` | `option` (MacOS) | +| `ctrl` | | +| `meta` | `Command` (MacOS) | +| `shift` | | + +
    + 原文 +There may be cases where [KeyboardEvent](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent) Actions should only call the Controller method when certain keystrokes are used. + +You can install an event listener that responds only to the `Escape` key by adding `.esc` to the event name of the action descriptor, as in the following example. + +```html +
    +
    +``` + +This will only work if the event being fired is a keyboard event. + +The correspondence between these filter and keys is shown below. + +Filter | Key Name +-------- | -------- +enter | Enter +tab | Tab +esc | Escape +space | " " +up | ArrowUp +down | ArrowDown +left | ArrowLeft +right | ArrowRight +home | Home +end | End +page_up | PageUp +page_down | PageDown +[a-z] | [a-z] +[0-9] | [0-9] + +If you need to support other keys, you can customize the modifiers using a custom schema. + +```javascript +import { Application, defaultSchema } from "@hotwired/stimulus" + +const customSchema = { + ...defaultSchema, + keyMappings: { ...defaultSchema.keyMappings, at: "@" }, +} + +const app = Application.start(document.documentElement, customSchema) +``` + +If you want to subscribe to a compound filter using a modifier key, you can write it like `ctrl+a`. + +```html +
    ...
    +``` + +The list of supported modifier keys is shown below. + +| Modifier | Notes | +| -------- | ------------------ | +| `alt` | `option` on MacOS | +| `ctrl` | | +| `meta` | Command key on MacOS | +| `shift` | | +
    + +### グローバルイベント + +しばしば`window`や`document`オブジェクトで発生するイベントを購読したいことがあります。 + +次の例のように、アクション記述子のイベント名に(フィルター修飾子があっても良い)`@window`または`@document`を追加すると、それぞれ`window`または`document`にイベントを購読することができます: + +```html +
    +
    +``` + +
    + 原文 + +Sometimes a controller needs to listen for events dispatched on the global `window` or `document` objects. + +You can append `@window` or `@document` to the event name (along with any filter modifier) in an action descriptor to install the event listener on `window` or `document`, respectively, as in the following example: + +```html +
    +
    +``` +
    + +### アクションオプション + +[DOMイベントリスナのオプション](https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener#Parameters)は、アクション記述子に1つ以上のアクションオプションを追加することで指定できます。 + +```html +
    + +``` + +Stimulusは次のアクションオプションをサポートしています。 + +アクションオプション | 対応するDOMイベントリスナのオプション +-------------------- | ----------------------------- +`:capture` | `{ capture: true }` +`:once` | `{ once: true }` +`:passive` | `{ passive: true }` +`:!passive` | `{ passive: false }` + +これに加えて、Stimulusではネイティブにサポートされていない以下のアクションオプションをサポートしています: + +カスタムアクションオプション | 説明 +---------------------------- | ----------- +`:stop` | `.stopPropagation()` をメソッドの実行前に呼び出す +`:prevent` | `.preventDefault()` をメソッドの実行前に呼び出す +`:self` | イベントが自身の要素で発生した時のみメソッドを呼び出す + +独自のアクションオプションを新規に登録したい場合は、`Application.registerActionOption`メソッドを使用します。 + +例えば、`
    `要素が開閉されるたびにディスパッチする`toggleイベント`を、開かれた時だけにフィルタリングするカスタム`:open`アクションオプションを作れば、開かれた時だけにイベントをルーティングするのに役立ちます: + +```javascript +import { Application } from "@hotwired/stimulus" + +const application = Application.start() + +application.registerActionOption("open", ({ event }) => { + if (event.type == "toggle") { + return event.target.open == true + } else { + return true + } +}) +``` + +アクションオプションに`!`のプレフィックスをつけた場合、アクションオプションを定義した関数の引数のプロパティ`value`に`false`が渡るため、以下のように変更すれば`:!open`アクションオプションで要素が閉じられる度にイベントをルーティングすることができるようになります。 + +```javascript +import { Application } from "@hotwired/stimulus" + +const application = Application.start() + +application.registerActionOption("open", ({ event, value }) => { + if (event.type == "toggle") { + return event.target.open == value + } else { + return true + } +}) +``` + +イベントがコントローラアクションにルーティングされないようにするには、`registerActionOption`のコールバック関数は`false`を返す必要があります。 逆に、イベントをコントローラのアクションにルーティングするためには、`true`を返します。 + +このコールバックは、以下のキーを持つオブジェクト引数を受け取ります: + +| キー | 説明 | +| ---------- | ----------------------------------------------------------------------------------------------------- | +| name | String: オプション名 (例の場合であれば `"open"`) | +| value | Boolean: オプションに`!`がついてるかどうか (`:open` であれば `true`, `:!open` なら `false` になる) | +| event | Event: イベントの実体 (後述のアクションパラメータ `params` を含む) | +| element | Element: アクション記述子を設定した要素 | +| controller | 呼び出されるメソッドを持つコントローラの実体 | + +
    + 原文 + +You can append one or more _action options_ to an action descriptor if you need to specify [DOM event listener options](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Parameters). + +```html +
    + +``` + +Stimulus supports the following action options: + +Action option | DOM event listener option +------------- | ------------------------- +`:capture` | `{ capture: true }` +`:once` | `{ once: true }` +`:passive` | `{ passive: true }` +`:!passive` | `{ passive: false }` + +On top of that, Stimulus also supports the following action options which are not natively supported by the DOM event listener options: + +Custom action option | Description +-------------------- | ----------- +`:stop` | calls `.stopPropagation()` on the event before invoking the method +`:prevent` | calls `.preventDefault()` on the event before invoking the method +`:self` | only invokes the method if the event was fired by the element itself + +You can register your own action options with the `Application.registerActionOption` method. + +For example, consider that a `
    ` element will dispatch a [toggle][] +event whenever it's toggled. A custom `:open` action option would help +to route events whenever the element is toggled _open_: + +```javascript +import { Application } from "@hotwired/stimulus" + +const application = Application.start() + +application.registerActionOption("open", ({ event }) => { + if (event.type == "toggle") { + return event.target.open == true + } else { + return true + } +}) +``` + +Similarly, a custom `:!open` action option could route events whenever the +element is toggled _closed_. Declaring the action descriptor option with a `!` +prefix will yield a `value` argument set to `false` in the callback: + +```javascript +import { Application } from "@hotwired/stimulus" + +const application = Application.start() + +application.registerActionOption("open", ({ event, value }) => { + if (event.type == "toggle") { + return event.target.open == value + } else { + return true + } +}) +``` + +In order to prevent the event from being routed to the controller action, the +`registerActionOption` callback function must return `false`. Otherwise, to +route the event to the controller action, return `true`. + +The callback accepts a single object argument with the following keys: + +| Name | Description | +| ---------- | ----------------------------------------------------------------------------------------------------- | +| name | String: The option's name (`"open"` in the example above) | +| value | Boolean: The value of the option (`:open` would yield `true`, `:!open` would yield `false`) | +| event | [Event][]: The event instance, including with the `params` action parameters on the submitter element | +| element | [Element]: The element where the action descriptor is declared | +| controller | The `Controller` instance which would receive the method call | + +[toggle]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLDetailsElement/toggle_event +[Event]: https://developer.mozilla.org/en-US/docs/web/api/event +[Element]: https://developer.mozilla.org/en-US/docs/Web/API/element +
    + + +## イベントオブジェクト + +_アクションメソッド_ は、アクションのイベントリスナとなるコントローラ内のメソッドです。 + +アクションメソッドの最初の引数は _DOMイベントオブジェクト_ です。 イベントにアクセスしたい理由は、次のようなものがあります: + +* キーボードイベントからキーコードを読み取る +* マウスイベントの座標を読み取る +* 入力イベントからデータを読み取る +* `submitter`となる要素からパラメータを読み取る +* イベントに対するブラウザのデフォルト動作を阻止する +* どの要素がこのイベントをディスパッチしたかを調べる + +以下の基本的なプロパティは、すべてのイベントに共通して存在します: + +Eventのプロパティ | 値 +------------------- | ----- +event.type | イベント名 (例. `"click"`) +event.target | イベントをディスパッチした要素 (つまり、クリックされた最も内側の要素) +event.currentTarget | イベントリスナが設定されてる要素 (`data-action`が設定されてる要素、あるいはグローバルリスナの場合 `document` か `window`) +event.params | アクションの`submitter`となる要素から渡されるアクションパラメータ + +以下のイベントの持つメソッドを使えば、イベントの処理方法を細かく制御できます: + +Eventのメソッド | 結果 +----------------------- | ------ +event.preventDefault() | イベントのデフォルトの挙動をキャンセルする (例えばリンク先への遷移やフォームの送信など) +event.stopPropagation() | 親要素へのイベントの伝播をストップさせる + +
    + 原文 + +An _action method_ is the method in a controller which serves as an action's event listener. + +The first argument to an action method is the DOM _event object_. You may want access to the event for a number of reasons, including: + +* to read the key code from a keyboard event +* to read the coordinates of a mouse event +* to read data from an input event +* to read params from the action submitter element +* to prevent the browser's default behavior for an event +* to find out which element dispatched an event before it bubbled up to this action + +The following basic properties are common to all events: + +Event Property | Value +------------------- | ----- +event.type | The name of the event (e.g. `"click"`) +event.target | The target that dispatched the event (i.e. the innermost element that was clicked) +event.currentTarget | The target on which the event listener is installed (either the element with the `data-action` attribute, or `document` or `window`) +event.params | The action params passed by the action submitter element + +
    The following event methods give you more control over how events are handled: + +Event Method | Result +----------------------- | ------ +event.preventDefault() | Cancels the event's default behavior (e.g. following a link or submitting a form) +event.stopPropagation() | Stops the event before it bubbles up to other listeners on parent elements +
    + + +## マルチアクション + +`data-action`属性の値は、スペースで区切られたアクション記述子のリストです。 + +任意の要素が複数のアクションを持つことはよくあります。 たとえば、次のinput要素は、フォーカスが当たった時に`field`コントローラの`highlight()` メソッドを呼び出し、要素の値が変わるたびに`search`コントローラの`update()`メソッドを呼び出します: + +```html + +``` + +要素が同じイベントに対して複数のアクションを持つ場合、Stimulusは左から右へ、それらの記述子に記載示されている順にアクションを呼び出します。 + +アクションの呼び出しチェーンは、アクション内で`Event#stopImmediatePropagation()`を呼び出すことで、任意の時点で停止させることができます。 その場合、呼び出された関数より右側に追加されたアクションは無視されます: + +```javascript +highlight: function(event) { + event.stopImmediatePropagation() + // ... +} +``` + +
    + 原文 + +The `data-action` attribute's value is a space-separated list of action descriptors. + +It's common for any given element to have many actions. For example, the following input element calls a `field` controller's `highlight()` method when it gains focus, and a `search` controller's `update()` method every time the element's value changes: + +```html + +``` + +When an element has more than one action for the same event, Stimulus invokes the actions from left to right in the order that their descriptors appear. + +The action chain can be stopped at any point by calling `Event#stopImmediatePropagation()` within an action. Any additional actions to the right will be ignored: + +```javascript +highlight: function(event) { + event.stopImmediatePropagation() + // ... +} +``` +
    + +## 命名規則 + +アクション名は、コントローラのメソッドに直接対応するので、常にキャメルケースで指定します。 + +`click`や`onClick`、`handleClick`のように、単にイベント名を繰り返しただけのアクション名は避けましょう: + +```html + +``` + +代わりに、呼び出された時に何が起こるかに基づいてアクションメソッドに名前をつけましょう: + +```html + +``` + +これによって、コントローラのソースを見ることなく、要素の持つ振る舞いが予測できるようになります。 + +
    + 原文 + +Always use camelCase to specify action names, since they map directly to methods on your controller. + +Avoid action names that simply repeat the event's name, such as `click`, `onClick`, or `handleClick`: + +```html + +``` + +Instead, name your action methods based on what will happen when they're called: + +```html + +``` + +This will help you reason about the behavior of a block of HTML without having to look at the controller source. +
    + + +## アクションパラメータ + +アクションは`submitter`要素から渡されるパラメータを受け取ることができます。 パラメータは`data-[識別子]-[パラメータ名]-param`の書式で記述します。 パラメータは、渡したい先のアクションが宣言されている要素に指定する必要があります。 + +すべてのパラメータは、その値から推測される`Number`、`String`、`Object`、`Boolean`のいずれかに自動的に型変換されます: + +data属性 | パラメータ | 型 +----------------------------------------------- | -------------------- | -------- +`data-item-id-param="12345"` | `12345` | Number +`data-item-url-param="/votes"` | `"/votes"` | String +`data-item-payload-param='{"value":"1234567"}'` | `{ value: 1234567 }` | Object +`data-item-active-param="true"` | `true` | Boolean + + +
    以下の設定について考えてみよう: + +```html +
    + +
    +``` + +この時、`ItemController#upvote`と`SpinnerController#start`の両方が呼び出されますが、識別子が`item`なのでパラメータが渡されるのは前者だけです: + +```javascript +// ItemController +upvote(event) { + // { id: 12345, url: "/votes", active: true, payload: { value: 1234567 } } + console.log(event.params) +} + +// SpinnerController +start(event) { + // {} + console.log(event.params) +} +``` + +イベントオブジェクトの持つプロパティのうち、paramsの他に何も必要なければ、以下のように分解してparamsだけを受け取ることもできます: + +```javascript +upvote({ params }) { + // { id: 12345, url: "/votes", active: true, payload: { value: 1234567 } } + console.log(params) +} +``` + +Or destruct only the params we need, in case multiple actions on the same controller share the same submitter element: +または、同じコントローラの複数のアクションが同じ`submitter`要素を共有しており、一方には不必要であるパラメータが混在している場合、必要なパラメータのみに分解して受け取ることもできます: + +```javascript +upvote({ params: { id, url } }) { + console.log(id) // 12345 + console.log(url) // "/votes" +} +``` + +
    + 原文 + +Actions can have parameters that are be passed from the submitter element. They follow the format of `data-[identifier]-[param-name]-param`. Parameters must be specified on the same element as the action they intend to be passed to is declared. + +All parameters are automatically typecast to either a `Number`, `String`, `Object`, or `Boolean`, inferred by their value: + +Data attribute | Param | Type +----------------------------------------------- | -------------------- | -------- +`data-item-id-param="12345"` | `12345` | Number +`data-item-url-param="/votes"` | `"/votes"` | String +`data-item-payload-param='{"value":"1234567"}'` | `{ value: 1234567 }` | Object +`data-item-active-param="true"` | `true` | Boolean + + +
    Consider this setup: + +```html +
    + +
    +``` + +It will call both `ItemController#upvote` and `SpinnerController#start`, but only the former will have any parameters passed to it: + +```javascript +// ItemController +upvote(event) { + // { id: 12345, url: "/votes", active: true, payload: { value: 1234567 } } + console.log(event.params) +} + +// SpinnerController +start(event) { + // {} + console.log(event.params) +} +``` + +If we don't need anything else from the event, we can destruct the params: + +```javascript +upvote({ params }) { + // { id: 12345, url: "/votes", active: true, payload: { value: 1234567 } } + console.log(params) +} +``` + +Or destruct only the params we need, in case multiple actions on the same controller share the same submitter element: + +```javascript +upvote({ params: { id, url } }) { + console.log(id) // 12345 + console.log(url) // "/votes" +} +``` +
    From 58981a32cbb76925c8ff28e7d84061b852553a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Wed, 27 Dec 2023 18:01:12 +0900 Subject: [PATCH 091/183] add controllers --- stimulus/reference/controllers.md | 583 ++++++++++++++++++++++++++++++ 1 file changed, 583 insertions(+) create mode 100644 stimulus/reference/controllers.md diff --git a/stimulus/reference/controllers.md b/stimulus/reference/controllers.md new file mode 100644 index 00000000..52843c70 --- /dev/null +++ b/stimulus/reference/controllers.md @@ -0,0 +1,583 @@ +--- +title: Controllers +description: "コントローラはStimulusアプリケーションの基本的な構成単位です" +layout: "base.html" +--- + +# Controllers + +コントローラは、Stimulusアプリケーションの基本的な構成単位です。 + +```javascript +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + // … +} +``` + +コントローラーは、アプリケーションで定義するJavaScriptクラスのインスタンスです。 各コントローラクラスは、`@hotwired/stimulus`モジュールによってエクスポートされた`Controller`基底クラスを継承します。 + +
    + 原文 + +A controller is the basic organizational unit of a Stimulus application. + +```javascript +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + // … +} +``` + +Controllers are instances of JavaScript classes that you define in your application. Each controller class inherits from the Controller base class exported by the @hotwired/stimulus module. +
    + +## プロパティ + +すべてのコントローラーはStimulus Applicationインスタンスに属し、HTML要素に関連付けられます。 コントローラクラス内では... + +* `this.application`プロパティで`application`に +* `this.element`プロパティでコントローラを設定したHTML要素に +* `this.identifier`プロパティでコントローラ名に + +それぞれアクセスすることができます。 + +
    + 原文 + +Every controller belongs to a Stimulus Application instance and is associated with an HTML element. Within a controller class, you can access the controller’s: + +* application, via the this.application property +* HTML element, via the this.element property +* identifier, via the this.identifier property +
    + +## モジュール + +コントローラクラスは1ファイルに1つずつJavaScriptモジュール形式で定義します。 前述の例のように、各コントローラクラスをモジュールのデフォルトオブジェクトとしてエクスポートします。 + +これらのモジュールを`controllers/`ディレクトリに置きます。 ファイル名は`[識別子]_controller.js`とし、`[識別子]`には各コントローラの識別子が入ります。 + +
    + 原文 + +Define your controller classes in JavaScript modules, one per file. Export each controller class as the module’s default object, as in the example above. + +Place these modules in the controllers/ directory. Name the files [identifier]_controller.js, where [identifier] corresponds to each controller’s identifier. +
    + +## コントローラ識別子 + +`識別子`は、HTMLでコントローラークラスを参照するために使用する名前です。 + +要素に`data-controller`属性を追加すると、Stimulusは属性の値から識別子を読み取り、対応するコントローラークラスの新しいインスタンスを作成します。 + +たとえば、下記の要素には、`controllers/reference_controller.js` で定義されているコントローラクラスのインスタンスが割り当てられます。 + +```html +
    +``` + +以下に、Stimulusが識別子に対応するコントローラファイルを特定する時の対応関係を示します。 + +| コントローラーファイルの名前 | 対応するコントローラ名 | +|---|---| +| clipboard_controller.js | clipboard | +| date_picker_controller.js | date-picker | +| users/list_item_controller.js | users--list-item | +| local-time-controller.js| local-time | + + +
    + 原文 +An identifier is the name you use to reference a controller class in HTML. + +When you add a data-controller attribute to an element, Stimulus reads the identifier from the attribute’s value and creates a new instance of the corresponding controller class. + +For example, this element has a controller which is an instance of the class defined in controllers/reference_controller.js: + +```html +
    +``` + +The following is an example of how Stimulus will generate identifiers for controllers in its require context: + +| If your controller file is named…| its identifier will be… | +|---|---| +| clipboard_controller.js | clipboard | +| date_picker_controller.js | date-picker | +| users/list_item_controller.js | users--list-item | +| local-time-controller.js| local-time | +
    + +## スコープ + +Stimulus がコントローラを要素に接続すると、その要素とすべての子孫要素がコントローラのスコープになります。 + +例えば、次のHTMLの`
    `と`

    `はコントローラのスコープに含まれますが、その外側の`
    `要素はスコープに含まれません。 + +```html +
    +
    +

    Reference

    +
    +
    +``` + +
    + 原文 + +When Stimulus connects a controller to an element, that element and all of its children make up the controller’s scope. + +For example, the `
    ` and `

    ` below are part of the controller’s scope, but the surrounding `
    ` element is not. + +```html +
    +
    +

    Reference

    +
    +
    +``` +

    + +## ネスト時のスコープ + +コントローラがネストしている場合、各コントローラは、内側のコントローラのスコープを除いた自分自身のスコープのみを認識します。 + +たとえば、以下の`#parent`に設定された`list`コントローラは、そのスコープ内にあるアイテムのターゲットのみを認識し、`#child`に設定された`list`コントローラのターゲットは自身のターゲットとは認識しません。 + +```html +
      +
    • One
    • +
    • Two
    • +
    • +
        +
      • I am
      • +
      • a nested list
      • +
      +
    • +
    +``` + +
    + 原文 +When nested, each controller is only aware of its own scope excluding the scope of any controllers nested within. + +For example, the #parent controller below is only aware of the item targets directly within its scope, but not any targets of the #child controller. + +```html +
      +
    • One
    • +
    • Two
    • +
    • +
        +
      • I am
      • +
      • a nested list
      • +
      +
    • +
    +``` +
    + +## マルチコントローラ + +`data-controller`属性の値は、スペースで区切られた識別子のリストです: + +```html +
    +``` + +ページ上の要素に複数のコントローラが設定されるのはよくあることです。 上の例では、`
    `には`clipboard`と`list-item`という2つのコントローラが設定されています。 + +同様に、ページ上の複数の要素に同じコントローラが適用されることもよくあります: + +```html +
      +
    • One
    • +
    • Two
    • +
    • Three
    • +
    +``` + +ここでは、それぞれの`
  • `ごとに`list-item`コントローラのインスタンスが生成されます。 + +
    + 原文 + +The data-controller attribute’s value is a space-separated list of identifiers: + +```html +
    +``` + +It’s common for any given element on the page to have many controllers. In the example above, the `
    ` has two connected controllers, clipboard and list-item. + +Similarly, it’s common for multiple elements on the page to reference the same controller class: + +```html +
      +
    • One
    • +
    • Two
    • +
    • Three
    • +
    +``` + +Here, each `
  • ` has its own instance of the list-item controller. +
  • + +## 命名規則 + +コントローラクラスのメソッド名やプロパティ名には、常にキャメルケースを使用します。 + +識別子が複数の単語から構成される場合は、単語をケバブケースで記述します (つまり、次のようにダッシュを使用します: `date-picker`, `list-item`)。 + +ファイル名は、複数の単語をアンダースコアまたはダッシュで区切ります(snake_caseまたはkebab-case:`controllers/date_picker_controller.js`、`controllers/list-item-controller.js`)。 + +
    + 原文 + +Always use camelCase for method and property names in a controller class. + +When an identifier is composed of more than one word, write the words in kebab-case (i.e., by using dashes: date-picker, list-item). + +In filenames, separate multiple words using either underscores or dashes (snake_case or kebab-case: controllers/date_picker_controller.js, controllers/list-item-controller.js). +
    + +## コントローラの登録 + +Stimulus for Railsをimport-maps と一緒に使うか、Webpackで`@hotwired/stimulus-webpack-helpers`パッケージを使うと、アプリケーションは自動的に上記の規約に従ってコントローラクラスをロードして登録します。 + +もしそれらを使わない場合、各コントローラクラスを手動で読み込んで登録する必要があります。 + +
    + 原文 +If you use Stimulus for Rails with an import map or Webpack together with the @hotwired/stimulus-webpack-helpers package, your application will automatically load and register controller classes following the conventions above. + +If not, your application must manually load and register each controller class. +
    + +### コントローラの手動登録 + +コントローラクラスを手動で登録するには、まずクラスをインポートし、`application`オブジェクトの`register`メソッドを呼び出します: + +```javascript +import ReferenceController from "./controllers/reference_controller" + +application.register("reference", ReferenceController) +``` + +モジュールとしてインポートする代わりに、インラインでコントローラクラスを登録することもできます: + +```javascript +import { Controller } from "@hotwired/stimulus" + +application.register("reference", class extends Controller { + // … +}) +``` + +
    + 原文 +To manually register a controller class with an identifier, first import the class, then call the Application#register method on your application object: + +```javascript +import ReferenceController from "./controllers/reference_controller" + +application.register("reference", ReferenceController) +``` + +You can also register a controller class inline instead of importing it from a module: + +```javascript +import { Controller } from "@hotwired/stimulus" + +application.register("reference", class extends Controller { + // … +}) +``` +
    + +### 環境要因に基づくコントローラの登録キャンセル + +特定の環境要因 (たとえば指定したユーザーエージェントなど) が満たされた場合にのみコントローラを登録したい場合は、 `shouldLoad`(静的)ゲッターを上書きすることで可能です: + +```javascript +class UnloadableController extends ApplicationController { + static get shouldLoad() { + return false + } +} + +// This controller will not be loaded +application.register("unloadable", UnloadableController) +``` + +
    + 原文 + +If you only want a controller registered and loaded if certain environmental factors are met – such a given user agent – you can overwrite the static shouldLoad method: + +```javascript +class UnloadableController extends ApplicationController { + static get shouldLoad() { + return false + } +} + +// This controller will not be loaded +application.register("unloadable", UnloadableController) +``` +
    + +### コントローラ登録時に発火するコールバック + +コントローラが登録された直後に何らかの動作をさせたい場合は、`afterLoad`(静的)メソッドを追加します: + +```javascript +class SpinnerButton extends Controller { + static legacySelector = ".legacy-spinner-button" + + static afterLoad(identifier, application) { + // アプリケーションインスタンスにアクセスして、'data-controller' に当たる属性名を読み込む。 + const { controllerAttribute } = application.schema + + // レガシーボタンに本コントローラがアタッチされるように属性をセットする + const updateLegacySpinners = () => { + document.querySelector(this.legacySelector).forEach((element) => { + element.setAttribute(controllerAttribute, identifier) + }) + } + + // このafterLoadメソッドはこのとローラが登録されるとすぐに呼び出されるので、 + // DOMはまだロードされていないかもしれないのでそこをケアする + if (document.readyState == "loading") { + document.addEventListener("DOMContentLoaded", updateLegacySpinners) + } else { + updateLegacySpinners() + } + } +} + +// このコントローラは、従来のスピナーボタンを変更し、本コントローラを適用させます。 +application.register("spinner-button", SpinnerButton) +``` + +`afterLoad`メソッドはコントローラが登録されるとすぐに呼び出されます。 この関数には、2つの引数(コントローラの登録時に指定された識別子と登録先の`Application`のインスタンス)が渡ります。 実行時のコンテキストは元のコントローラクラスです。 + +
    + 原文 + +If you want to trigger some behaviour once a controller has been registered you can add a static afterLoad method: + +```javascript +class SpinnerButton extends Controller { + static legacySelector = ".legacy-spinner-button" + + static afterLoad(identifier, application) { + // use the application instance to read the configured 'data-controller' attribute + const { controllerAttribute } = application.schema + + // update any legacy buttons with the controller's registered identifier + const updateLegacySpinners = () => { + document.querySelector(this.legacySelector).forEach((element) => { + element.setAttribute(controllerAttribute, identifier) + }) + } + + // called as soon as registered so DOM may not have loaded yet + if (document.readyState == "loading") { + document.addEventListener("DOMContentLoaded", updateLegacySpinners) + } else { + updateLegacySpinners() + } + } +} + +// This controller will update any legacy spinner buttons to use the controller +application.register("spinner-button", SpinnerButton) +``` + +The afterLoad method will get called as soon as the controller has been registered, even if no controlled elements exist in the DOM. The function will be called bound to the original controller constructor along with two arguments; the identifier that was used when registering the controller and the Stimulus application instance. + +
    + +## イベントを使ったコントローラ間の連携 + +コントローラ間で連携を行う必要がある場合はイベントを使用します。 コントローラクラスにはカスタムイベントを発生させるための`dispatch`という便利なメソッドが用意されています。 このメソッドは`eventName`を第1引数にとりますが、実際のイベント名は、プレフィックスとして自動的にコントローラの識別子をコロンで区切りで挿入したものになります。 ペイロードは`detail`に保持することができます。 これは次のように動作します: + +```javascript +class ClipboardController extends Controller { + static targets = [ "source" ] + + copy() { + this.dispatch("copy", { detail: { content: this.sourceTarget.value } }) + navigator.clipboard.writeText(this.sourceTarget.value) + } +} +``` + +このイベントは、次のようにして別のコントローラーのアクションにルーティングできます。 + +```html +
    + PIN: + +
    +``` + +この指定により`Clipboard#copy`アクションが呼び出されると、`Effects#flash`アクションも呼び出されるようになります。 + +```javascript +class EffectsController extends Controller { + flash({ detail: { content } }) { + console.log(content) // 1234 + } +} +``` + +2つのコントローラが同じHTML要素に属していない場合は、イベント購読側のコントローラの要素に`data-action`属性を追加する必要があります。 また、購読側コントローラの要素がイベント発行側コントローラの要素の親 (または同じ) でない場合は、イベント名の後に`@window`を追加する必要があります。 + +```html +
    +``` + +`dispatch`は、第2引数として以下のような追加オプションを受け付ける: + +| option | デフォルト値 | ノート | +|---|---|---| +| `detail` | `{}` (空オブジェクト) | [CustomEvent.detail](https://developer.mozilla.org/ja/docs/Web/API/CustomEvent/detail)を参照 | +| `target` | `this.element` | [See Event.target](https://developer.mozilla.org/ja/docs/Web/API/Event/target)を参照 | +| `prefix` | `this.identifier` | プレフィックスがfalseyの場合(`null`や`false`など)は`eventName`がそのまま使用される。文字列を指定した場合は、`eventName`の前に指定した文字列とコロンが付加されます。 | +| `bubbles` | `true` | [Event.bubbles](https://developer.mozilla.org/ja/docs/Web/API/Event/bubbles)を参照 | +| `cancelable` | `true` | [Event.cancelable](https://developer.mozilla.org/ja/docs/Web/API/Event/cancelable)を参照 | + +`dispatch`は生成された`CustomEvent`を返すので、これを使って以下のように他のリスナからイベントをキャンセルさせることができます: + +```javascript +class ClipboardController extends Controller { + static targets = [ "source" ] + + copy() { + const event = this.dispatch("copy", { cancelable: true }) + if (event.defaultPrevented) return + navigator.clipboard.writeText(this.sourceTarget.value) + } +} +``` + +```javascript +class EffectsController extends Controller { + flash(event) { + // ディスパッチされたイベントによって引き起こされるデフォルトの振る舞いを防ぎます + event.preventDefault() + } +} +``` + +
    + 原文 + +If you need controllers to communicate with each other, you should use events. The Controller class has a convenience method called dispatch that makes this easier. It takes an eventName as the first argument, which is then automatically prefixed with the name of the controller separated by a colon. The payload is held in detail. It works like this: + +```javascript +class ClipboardController extends Controller { + static targets = [ "source" ] + + copy() { + this.dispatch("copy", { detail: { content: this.sourceTarget.value } }) + navigator.clipboard.writeText(this.sourceTarget.value) + } +} +``` + +And this event can then be routed to an action on another controller: + +```html +
    + PIN: + +
    +``` + +So when the Clipboard#copy action is invoked, the Effects#flash action will be too: + +```javascript +class EffectsController extends Controller { + flash({ detail: { content } }) { + console.log(content) // 1234 + } +} +``` + +If the two controllers don’t belong to the same HTML element, the data-action attribute needs to be added to the receiving controller’s element. And if the receiving controller’s element is not a parent (or same) of the emitting controller’s element, you need to add @window to the event: + +```html +
    +``` + +dispatch accepts additional options as the second parameter as follows: + +| option | default | notes | +|---|---| +| detail | {} empty object | See CustomEvent.detail | +| target | this.element | See Event.target | +| prefix | this.identifier | If the prefix is falsey (e.g. null or false), only the eventName will be used. If you provide a string value the eventName will be prepended with the provided string and a colon. | +| bubbles | true | See Event.bubbles | +| cancelable | true | See Event.cancelable | + +dispatch will return the generated CustomEvent, you can use this to provide a way for the event to be cancelled by any other listeners as follows: + +```javascript +class ClipboardController extends Controller { + static targets = [ "source" ] + + copy() { + const event = this.dispatch("copy", { cancelable: true }) + if (event.defaultPrevented) return + navigator.clipboard.writeText(this.sourceTarget.value) + } +} +``` + +```javascript +class EffectsController extends Controller { + flash(event) { + // this will prevent the default behaviour as determined by the dispatched event + event.preventDefault() + } +} +``` +
    + +## コントローラから別のコントローラを直接呼び出す + +何らかの理由でコントローラ間の通信にイベントを使用できない場合は、`application`オブジェクトの`getControllerForElementAndIdentifier`メソッドを使うことができます。 これは、イベントを使用する一般的な方法では解決できないような特殊な問題がある場合にのみ使用すべきです: + +```javascript +class MyController extends Controller { + static targets = [ "other" ] + + copy() { + const otherController = this.application.getControllerForElementAndIdentifier(this.otherTarget, 'other') + otherController.otherMethod() + } +} +``` + +
    + 原文 +If for some reason it is not possible to use events to communicate between controllers, you can reach a controller instance via the getControllerForElementAndIdentifier method from the application. This should only be used if you have a unique problem that cannot be solved through the more general way of using events, but if you must, this is how: + +```javascript +class MyController extends Controller { + static targets = [ "other" ] + + copy() { + const otherController = this.application.getControllerForElementAndIdentifier(this.otherTarget, 'other') + otherController.otherMethod() + } +} +``` +
    From ad16d0b8f9c8d866221c4a3f5ee46ec863c4c3ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Wed, 27 Dec 2023 18:21:01 +0900 Subject: [PATCH 092/183] add lifecycle-callbacks --- stimulus/reference/lifecycle_callbacks.md | 186 ++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 stimulus/reference/lifecycle_callbacks.md diff --git a/stimulus/reference/lifecycle_callbacks.md b/stimulus/reference/lifecycle_callbacks.md new file mode 100644 index 00000000..abb63417 --- /dev/null +++ b/stimulus/reference/lifecycle_callbacks.md @@ -0,0 +1,186 @@ +--- +title: ライフサイクルコールバック +description: "ライフサイクルコールバックは、コントローラや特定のターゲットがドキュメントに接続したり切断したりするたびに応答するメソッドです" +layout: "base.html" +--- + +# ライフサイクルコールバック + +ライフサイクルコールバックと呼ばれる特別なメソッドを使用すると、コントローラや特定のターゲットがドキュメントに接続したり切断したりするたびに応答できるようになります。 + +```javascript +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + connect() { + // … + } +} +``` + +
    + 原文 +Special methods called _lifecycle callbacks_ allow you to respond whenever a controller or certain targets connects to and disconnects from the document. + +```javascript +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + connect() { + // … + } +} +``` +
    + +## メソッド一覧 + +コントローラには、以下のライフサイクルコールバックメソッドを定義することができます: + +| Method | Stimulusによって呼び出されるタイミング… | +| ------------ | -------------------- | +| initialize() | コントローラが最初にインスタンス化されたとき(一度だけ) | +| [name]TargetConnected(target: Element) | ターゲットがDOMに接続されるたび | +| connect() | コントローラーがDOMに接続されるたび | +| [name]TargetDisconnected(target: Element) | ターゲットがDOMから切り離されるたび | +| disconnect() | コントローラーがDOMから切り離されるたび | + +
    + 原文 + +You may define any of the following methods in your controller: + +| Method | Invoked by Stimulus… | +| ------------ | -------------------- | +| initialize() | Once, when the controller is first instantiated | +| [name]TargetConnected(target: Element) | Anytime a target is connected to the DOM | +| connect() | Anytime the controller is connected to the DOM | +| [name]TargetDisconnected(target: Element) | Anytime a target is disconnected from the DOM | +| disconnect() | Anytime the controller is disconnected from the DOM | +
    + + +## Connection + +コントローラがドキュメントに接続されるのは、以下の条件の両方が真の場合です: + +* その要素がドキュメント内に存在する (つまり、`document.documentElement`である``要素の子孫である) +* 要素の`data-controller`属性にその識別子が存在する + +コントローラが接続されると、Stimulusは`connect()`メソッドを呼び出します。 + +
    + 原文 +A controller is _connected_ to the document when both of the following conditions are true: + +* its element is present in the document (i.e., a descendant of `document.documentElement`, the `` element) +* its identifier is present in the element's `data-controller` attribute + +When a controller becomes connected, Stimulus calls its `connect()` method. +
    + +### ターゲット + +ターゲットがドキュメントに接続されるのは、以下の両方の条件が真である場合です: + +* その要素が、対応するコントローラ要素の子孫としてドキュメントに存在する。 +* その識別子が要素の`data-{identifier}-target`属性に存在する。 + +ターゲットが接続されると、Stimulusはコントローラの`[name]TargetConnected()`メソッドを呼び出し、ターゲット要素をパラメータとして渡します。 `name]TargetConnected()`ライフサイクルコールバックは、コントローラの`connect()`コールバックより *前に* 起動します。 + +
    + 原文 +A target is _connected_ to the document when both of the following conditions are true: + +* its element is present in the document as a descendant of its corresponding controller's element +* its identifier is present in the element's `data-{identifier}-target` attribute + +When a target becomes connected, Stimulus calls its controller's `[name]TargetConnected()` method, passing the target element as a parameter. The `[name]TargetConnected()` lifecycle callbacks will fire *before* the controller's `connect()` callback. +
    + +## Disconnection + +接続されたコントローラは、以下のケースのように、前述の条件のいずれかが偽になると切断されます: + +* その要素が`Node#removeChild()`または`ChildNode#remove()`で明示的にドキュメントから削除される +* 要素の親要素がドキュメントから削除される +* 要素の親要素が、`Element#innerHTML=`によってその内容を置き換えられる +* 要素の`data-controller`属性が削除または変更される +* Turboによるページ遷移時など、ドキュメントの``要素がまるっと更新される + +コントローラが切断されると、Stimulus は`disconnect()`メソッドを呼び出します。 + +
    + 原文 +A connected controller will later become _disconnected_ when either of the preceding conditions becomes false, such as under any of the following scenarios: + +* the element is explicitly removed from the document with `Node#removeChild()` or `ChildNode#remove()` +* one of the element's parent elements is removed from the document +* one of the element's parent elements has its contents replaced by `Element#innerHTML=` +* the element's `data-controller` attribute is removed or modified +* the document installs a new `` element, such as during a Turbo page change + +When a controller becomes disconnected, Stimulus calls its `disconnect()` method. +
    + +### ターゲット + +接続されたターゲットは、以下のケースのように、前述の条件のいずれかが偽になると切断されます: + +* その要素が`Node#removeChild()`または`ChildNode#remove()`で明示的にドキュメントから削除される +* 要素の親要素がドキュメントから削除される +* 要素の親要素が、`Element#innerHTML=`によってその内容を置き換えられる +* 要素の`data-{identifier}-target`属性が削除または変更される +* Turboによるページ遷移時など、ドキュメントの``要素がまるっと更新される + +ターゲットが切断されると、Stimulusはコントローラの`[name]TargetDisconnected()`メソッドを呼び出し、ターゲット要素をパラメータとして渡します。 `name]TargetDisconnected()`ライフサイクルのコールバックは、コントローラの`disconnect()`コールバックより *前に* 起動します。 + +
    + 原文 + +A connected target will later become _disconnected_ when either of the preceding conditions becomes false, such as under any of the following scenarios: + +* the element is explicitly removed from the document with `Node#removeChild()` or `ChildNode#remove()` +* one of the element's parent elements is removed from the document +* one of the element's parent elements has its contents replaced by `Element#innerHTML=` +* the element's `data-{identifier}-target` attribute is removed or modified +* the document installs a new `` element, such as during a Turbo page change + +When a target becomes disconnected, Stimulus calls its controller's `[name]TargetDisconnected()` method, passing the target element as a parameter. The `[name]TargetDisconnected()` lifecycle callbacks will fire *before* the controller's `disconnect()` callback. +
    + +## Reconnection + +切断されたコントローラは、後で再び接続される可能性があります。 + +これが発生した場合 (ドキュメントからコントローラーの要素を削除してから再アタッチした後など) 、Stimulusは要素の以前のコントローラーインスタンスを再利用し、その`connect()`メソッドを再び呼び出します。 + +同様に、切断されたターゲットも後で再び接続される可能性があります。 Stimulusはコントローラの`[name]TargetConnected()`メソッドも同様に再び呼び出します。 + +
    + 原文 + +A disconnected controller may become connected again at a later time. + +When this happens, such as after removing the controller's element from the document and then re-attaching it, Stimulus will reuse the element's previous controller instance, calling its `connect()` method multiple times. + +Similarly, a disconnected target may be connected again at a later time. Stimulus will invoke its controller's `[name]TargetConnected()` method multiple times. +
    + +## 順序とタイミング + +Stimulusは[DOM `MutationObserver` API](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver)を使用して非同期にページの変更を監視します。 + +つまりこれは、Stimulusがドキュメントに変更が加えられた際、各変更の次の[マイクロタスク](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/)でコントローラのライフサイクルメソッドを非同期に呼び出すことを意味します。 + +ライフサイクルメソッドは発生順に実行されるため、コントローラの`connect()`メソッドが2回呼び出されるような時は、常に`disconnect()`が間に1度呼び出されることになります。 同様に、特定のターゲットに対するコントローラーの`[name]TargetConnected()`が2回呼ばれる時は、同じターゲットに対する`[name]TargetDisconnected()`が間に1度呼ばれることになります。 + +
    + 原文 + +Stimulus watches the page for changes asynchronously using the [DOM `MutationObserver` API](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver). + +This means that Stimulus calls your controller's lifecycle methods asynchronously after changes are made to the document, in the next [microtask](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/) following each change. + +Lifecycle methods still run in the order they occur, so two calls to a controller's `connect()` method will always be separated by one call to `disconnect()`. Similarly, two calls to a controller's `[name]TargetConnected()` for a given target will always be separated by one call to `[name]TargetDisconnected()` for that same target. +
    From 1f767e80fb939f9248d7b5b1d8f9d65f5c0f0725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Tue, 9 Jan 2024 17:59:22 +0900 Subject: [PATCH 093/183] add targets --- stimulus/reference/targets.md | 250 ++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 stimulus/reference/targets.md diff --git a/stimulus/reference/targets.md b/stimulus/reference/targets.md new file mode 100644 index 00000000..cc5d990a --- /dev/null +++ b/stimulus/reference/targets.md @@ -0,0 +1,250 @@ +--- +title: Targets +description: "Targetを使うとコントローラで扱いたい重要な要素を参照することができます" +layout: "base.html" +--- + +# Targets + +_ターゲット_ を使えば、重要な要素を論理名で参照することができます。 + +```html +
    + +
    +
    +
    +``` + +
    + 原文 +_Targets_ let you reference important elements by name. + +```html +
    + +
    +
    +
    +``` +
    + +## 属性と論理名 + +`data-search-target`属性は _ターゲット属性_ と呼ばれます。 その値はスペースで区切られたターゲットの論理名のリストで、`search`コントローラ内の要素を参照するために使用できます。 + +```html +
    +
    +
    +``` + +
    + 原文 +The `data-search-target` attribute is called a _target attribute_, and its value is a space-separated list of _target names_ which you can use to refer to the element in the `search` controller. + +```html +
    +
    +
    +``` +
    + +## 定義の仕方 + +コントローラクラスで、`static targets`配列を定義してターゲットの論理名を列挙します: + +```js +// controllers/search_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "query", "errorMessage", "results" ] + // … +} +``` + +
    + 原文 +Define target names in your controller class using the `static targets` array: + +```js +// controllers/search_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "query", "errorMessage", "results" ] + // … +} +``` +
    + +## プロパティ + +`static targets`で定義された各ターゲットの論理名に対して、Stimulusは以下のプロパティをコントローラに追加します(ここで、`[name]`はターゲットの論理名に対応します): + +Kind | Name | Value +----------- | ---------------------- | ----- +単数 | `this.[name]Target` | スコープ内で最初にマッチしたターゲット +複数 | `this.[name]Targets` | スコープ内でマッチした全てのターゲットの配列 +存在有無 | `this.has[Name]Target` | スコープ内に一致するターゲットがあるかどうかを示すbool値 + +
    **注:** 単数系のターゲットプロパティにアクセスすると、一致する要素がない場合にエラーがスローされます。 + +
    + 原文 +For each target name defined in the `static targets` array, Stimulus adds the following properties to your controller, where `[name]` corresponds to the target's name: + +Kind | Name | Value +----------- | ---------------------- | ----- +Singular | `this.[name]Target` | The first matching target in scope +Plural | `this.[name]Targets` | An array of all matching targets in scope +Existential | `this.has[Name]Target` | A boolean indicating whether there is a matching target in scope + +
    **Note:** Accessing the singular target property will throw an error when there is no matching element. +
    + +## ターゲットの共有 + +要素は複数のターゲット属性を持つことができ、そうすることで複数のコントローラで同じ要素を参照するターゲットを持つことができます。 + +```html +
    + + + … +
    +``` + +上記のチェックボックス要素はそれぞれ`this.projectsTarget`と`this.messagesTarget`として`search`コントローラ内でアクセスできます。 + +また、`checkbox`コントローラの内部では、`this.inputTargets`は両方のチェックボックスを含む配列を返します。 + +
    + 原文 +Elements can have more than one target attribute, and it's common for targets to be shared by multiple controllers. + +```html +
    + + + … +
    +``` + +In the example above, the checkboxes are accessible inside the `search` controller as `this.projectsTarget` and `this.messagesTarget`, respectively. + +Inside the `checkbox` controller, `this.inputTargets` returns an array with both checkboxes. + +
    + +## オプショナルなターゲット + +コントローラが、存在するかどうかわからないターゲットと連携する必要がある場合は、`has[name]Target`プロパティの値に基づいてコードを条件付けします: + +```js +if (this.hasResultsTarget) { + this.resultsTarget.innerHTML = "…" +} +``` + +
    + 原文 +If your controller needs to work with a target which may or may not be present, condition your code based on the value of the existential target property: + +```js +if (this.hasResultsTarget) { + this.resultsTarget.innerHTML = "…" +} +``` +
    + +## 接続/切断時のコールバック + +_ターゲット要素のコールバック_ を使用すると、コントローラのスコープ内にターゲット要素が追加または削除されるたびに実行したい処理を記述することができます。 + +このコールバック関数はコントローラに`[name]TargetConnected`または`[name]TargetDisconnected`というメソッドとして定義します。 これらのメソッドは、最初の引数として対象の`target`要素を受け取ります。 + +Stimulusは、`connect()`ライフサイクルフックの実行後、`disconnect()` ライフサイクルフックが呼び出されるまでの間、ターゲット要素が追加または削除されるたびに各ターゲット要素のコールバックを呼び出します。 + +```js +export default class extends Controller { + static targets = [ "item" ] + + itemTargetConnected(element) { + this.sortElements(this.itemTargets) + } + + itemTargetDisconnected(element) { + this.sortElements(this.itemTargets) + } + + // Private + sortElements(itemTargets) { /* ... */ } +} +``` + +**注** `[name]TargetConnected`および`[name]TargetDisconnected`コールバックの実行中、ターゲット要素の監視に使われている`MutationObserver`インスタンスは一時的に停止します。 つまり、コールバックの中で同名のターゲットを追加または削除した場合、対応するコールバックは呼び出されません。 + +
    + 原文 +Target _element callbacks_ let you respond whenever a target element is added or +removed within the controller's element. + +Define a method `[name]TargetConnected` or `[name]TargetDisconnected` in the controller, where `[name]` is the name of the target you want to observe for additions or removals. The method receives the element as the first argument. + +Stimulus invokes each element callback any time its target elements are added or removed after `connect()` and before `disconnect()` lifecycle hooks. + +```js +export default class extends Controller { + static targets = [ "item" ] + + itemTargetConnected(element) { + this.sortElements(this.itemTargets) + } + + itemTargetDisconnected(element) { + this.sortElements(this.itemTargets) + } + + // Private + sortElements(itemTargets) { /* ... */ } +} +``` + +**Note** During the execution of `[name]TargetConnected` and +`[name]TargetDisconnected` callbacks, the `MutationObserver` instances behind +the scenes are paused. This means that if a callback add or removes a target +with a matching name, the corresponding callback _will not_ be invoked again. +
    + +## 命名規則 + +ターゲットの論理名は、コントローラのプロパティに直接対応するため、常にキャメルケースを使用して指定します: + +```html + + +``` + +```js +export default class extends Controller { + static targets = [ "camelCase" ] +} +``` + +
    + 原文 +Always use camelCase to specify target names, since they map directly to properties on your controller: + +```html + + +``` + +```js +export default class extends Controller { + static targets = [ "camelCase" ] +} +``` +
    From 8fb3cfdae5c18af2484480867d13dc0b9f6daa3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Tue, 9 Jan 2024 19:12:02 +0900 Subject: [PATCH 094/183] add outlets --- stimulus/reference/outlets.md | 372 ++++++++++++++++++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 stimulus/reference/outlets.md diff --git a/stimulus/reference/outlets.md b/stimulus/reference/outlets.md new file mode 100644 index 00000000..f8b87ab3 --- /dev/null +++ b/stimulus/reference/outlets.md @@ -0,0 +1,372 @@ +--- +title: Outlets +description: "Outletを使うとコントローラが別のコントローラ(と要素)を参照することができます" +layout: "base.html" +--- + +# Outlets + +_アウトレット_ を使用すると、コントローラから別のコントローラのインスタンスとそのコントローラ要素を参照することができます。 + +アウトレットを使用することで、コントローラの連携や調整をカスタムイベントなしに行うことができます。 + +[ターゲット](/stimulus/reference/targets)と概念的には似ていますが、コントローラのインスタンスとそれに関連するコントローラ要素を参照するという違いがあります。 + +```html +
    +
    ...
    +
    ...
    + ... +
    + +... + +
    + ... +
    +``` + +**ターゲット**は、そのコントローラ要素のスコープ内でマークされた要素を参照しますが、アウトレットで参照したいコントローラ要素はページ上のどこにでも置くことができ、必ずしもコントローラのスコープ内にある必要はありません。 + +
    + 原文 +_Outlets_ let you reference Stimulus _controller instances_ and their _controller element_ from within another Stimulus Controller by using CSS selectors. + +The use of Outlets helps with cross-controller communication and coordination as an alternative to dispatching custom events on controller elements. + +They are conceptually similar to [Stimulus Targets](https://stimulus.hotwired.dev/reference/targets) but with the difference that they reference a Stimulus controller instance plus its associated controller element. + +```html +
    +
    ...
    +
    ...
    + ... +
    + +... + +
    + ... +
    +``` + +While a **target** is a specifically marked element **within the scope** of its own controller element, an **outlet** can be located **anywhere on the page** and doesn't necessarily have to be within the controller scope. +
    + +## 属性と名前 + +`data-chat-user-status-outlet`属性は、_アウトレット属性_ と呼ばれ、その値は参照先のコントローラ要素を指し示す[CSSセレクタ](https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Selectors)です。 参照元コントローラのアウトレット識別子は、参照先のコントローラの識別子と同じでなければなりません。 + +```html +data-[identifier]-[outlet]-outlet="[selector]" +``` + +```html +
    +``` + +
    + 原文 +The `data-chat-user-status-outlet` attribute is called an _outlet attribute_, and its value is a [CSS selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors) which you can use to refer to other controller elements which should be available as outlets on the _host controller_. The outlet identifier in the host controller must be the same as the target controller's identifier. + +```html +data-[identifier]-[outlet]-outlet="[selector]" +``` + +```html +
    +``` + +
    + +## 定義の仕方 + +コントローラクラスで、`static outlets`配列を定義して参照したいコントローラの識別子を列挙します。 この配列の各要素であるコントローラ識別子に対応するコントローラをアウトレットとして使用できることを宣言します: + +```js +// chat_controller.js + +export default class extends Controller { + static outlets = [ "user-status" ] + + connect () { + this.userStatusOutlets.forEach(status => ...) + } +} +``` + +
    + 原文 +Define controller identifiers in your controller class using the `static outlets` array. This array declares which other controller identifiers can be used as outlets on this controller: + + +```js +// chat_controller.js + +export default class extends Controller { + static outlets = [ "user-status" ] + + connect () { + this.userStatusOutlets.forEach(status => ...) + } +} +``` +
    + +## プロパティ + +Stimulusは`static outlets`配列で定義された各アウトレットに対応した5つのプロパティをコントローラに追加します: + +| 種類 | プロパティ名 | 返り値の型 | 説明 +| ---- | ------------- | ----------- | ----------- +| 存在有無 | `has[Name]Outlet` | `Boolean` | `[name]`アウトレットの有無をテストする +| 単数 | `[name]Outlet` | `Controller` | 最初の `[name]`アウトレットのControllerインスタンスを返します。 もし存在しない場合はエラーをスローします +| 複数 | `[name]Outlets` | `Array` | すべての`[name]` アウトレットのControllerインスタンスを返します。 +| 単数 | `[name]OutletElement` | `Element` | 最初の`[name]`アウトレットのコントローラ要素を返します。 もし存在しない場合はエラーをスローします +| 複数 | `[name]OutletElements` | `Array` | すべての`[name]`アウトレットのコントローラ要素を返します。 + +**注:** ネストされた Stimulusコントローラプロパティ(識別子に`--`を含むもの)をアウトレットで参照する場合は名前空間の区切り文字を省略してください: + +```js +// chat_controller.js + +export default class extends Controller { + static outlets = [ "admin--user-status" ] + + selectAll(event) { + // これはundefinedとなります + this.admin__UserStatusOutlets + + // adomin--user-statusコントローラインスタンスの配列が得られます + this.adminUserStatusOutlets + } +} +``` + +
    + 原文 +For each outlet defined in the `static outlets` array, Stimulus adds five properties to your controller, where `[name]` corresponds to the outlet's controller identifier: + +| Kind | Property name | Return Type | Effect +| ---- | ------------- | ----------- | ----------- +| Existential | `has[Name]Outlet` | `Boolean` | Tests for presence of a `[name]` outlet +| Singular | `[name]Outlet` | `Controller` | Returns the `Controller` instance of the first `[name]` outlet or throws an exception if none is present +| Plural | `[name]Outlets` | `Array` | Returns the `Controller` instances of all `[name]` outlets +| Singular | `[name]OutletElement` | `Element` | Returns the Controller `Element` of the first `[name]` outlet or throws an exception if none is present +| Plural | `[name]OutletElements` | `Array` | Returns the Controller `Element`'s of all `[name]` outlets + +**Note:** For nested Stimulus controller properties, make sure to omit namespace delimiters in order to correctly access the referenced outlet: + +```js +// chat_controller.js + +export default class extends Controller { + static outlets = [ "admin--user-status" ] + + selectAll(event) { + // returns undefined + this.admin__UserStatusOutlets + + // returns controller reference + this.adminUserStatusOutlets + } +} +``` +
    + +## コントローラとコントローラ要素にアクセスする + +`[name]Outlet`と`[name]Outlets`のプロパティからコントローラのインスタンスが返されるので、そのコントローラインスタンスが定義する`Values`、`Classes`、`Targets`、その他すべてのプロパティや関数にアクセスすることもできます: + +```js +this.userStatusOutlet.idValue +this.userStatusOutlet.imageTarget +this.userStatusOutlet.activeClasses +``` + +また、アウトレットで参照する先のコントローラで独自に定義した関数を呼び出すこともできます: + +```js +// user_status_controller.js + +export default class extends Controller { + markAsSelected(event) { + // ... + } +} + +// chat_controller.js + +export default class extends Controller { + static outlets = [ "user-status" ] + + selectAll(event) { + this.userStatusOutlets.forEach(status => status.markAsSelected(event)) + } +} +``` + +同様に、アウトレット要素では、[Element](https://developer.mozilla.org/ja/docs/Web/API/Element)の任意の関数またはプロパティを呼び出すことができます。 + +```js +this.userStatusOutletElement.dataset.value +this.userStatusOutletElement.getAttribute("id") +this.userStatusOutletElements.map(status => status.hasAttribute("selected")) +``` + +
    + 原文 +Since you get back a `Controller` instance from the `[name]Outlet` and `[name]Outlets` properties you are also able to access the Values, Classes, Targets and all of the other properties and functions that controller instance defines: + +```js +this.userStatusOutlet.idValue +this.userStatusOutlet.imageTarget +this.userStatusOutlet.activeClasses +``` + +You are also able to invoke any function the outlet controller may define: + +```js +// user_status_controller.js + +export default class extends Controller { + markAsSelected(event) { + // ... + } +} + +// chat_controller.js + +export default class extends Controller { + static outlets = [ "user-status" ] + + selectAll(event) { + this.userStatusOutlets.forEach(status => status.markAsSelected(event)) + } +} +``` + +Similarly with the Outlet Element, it allows you to call any function or property on [`Element`](https://developer.mozilla.org/en-US/docs/Web/API/Element): + +```js +this.userStatusOutletElement.dataset.value +this.userStatusOutletElement.getAttribute("id") +this.userStatusOutletElements.map(status => status.hasAttribute("selected")) +``` +
    + +## アウトレットのコールバック + +アウトレットコールバックは、Stimulusによって呼び出される特別な名前の関数で、アウトレットがページに追加または削除されるたびに実行したい処理を記述できます。 + +アウトレットの変化を監視するには、`[name]OutletConnected()`または`[name]OutletDisconnected()` という名前の関数を定義します。 + +```js +// chat_controller.js + +export default class extends Controller { + static outlets = [ "user-status" ] + + userStatusOutletConnected(outlet, element) { + // ... + } + + userStatusOutletDisconnected(outlet, element) { + // ... + } +} +``` + +
    + 原文 +Outlet callbacks are specially named functions called by Stimulus to let you respond to whenever an outlet is added or removed from the page. + +To observe outlet changes, define a function named `[name]OutletConnected()` or `[name]OutletDisconnected()`. + +```js +// chat_controller.js + +export default class extends Controller { + static outlets = [ "user-status" ] + + userStatusOutletConnected(outlet, element) { + // ... + } + + userStatusOutletDisconnected(outlet, element) { + // ... + } +} +``` +
    + +### アウトレットは存在するものとして扱われる + +ControllerのOutletプロパティにアクセスする際、対応するアウトレットが少なくとも1つ存在することを検証します。 一致するアウトレットが見つからない場合、Stimulusはエラーをスローします。 + +```html +Missing outlet element "user-status" for "chat" controller +``` + +
    + 原文 +When you access an Outlet property in a Controller, you assert that at least one corresponding Outlet is present. If the declaration is missing and no matching outlet is found Stimulus will throw an exception: + +```html +Missing outlet element "user-status" for "chat" controller +``` +
    + +### オプショナルなアウトレット + +アウトレットがオプショナルである場合、または少なくともアウトレットが一つは存在することを保証したい場合は、まず`has[Name]Outlet`プロパティを使用してアウトレットの存在を確認する必要があります: + +```js +if (this.hasUserStatusOutlet) { + this.userStatusOutlet.safelyCallSomethingOnTheOutlet() +} +``` + +
    + 原文 +If an Outlet is optional or you want to assert that at least Outlet is present, you must first check the presence of the Outlet using the existential property: + +```js +if (this.hasUserStatusOutlet) { + this.userStatusOutlet.safelyCallSomethingOnTheOutlet() +} +``` +
    + +### コントローラ識別子を持たない要素を参照した場合 + +Stimulusは、対応する`data-controller`と識別子を持たない要素をアウトレットとして宣言しようとすると、エラーをスローします。 + +```html +
    + +
    +``` + +この場合、結果は次のようになります。 + +```html +Missing "data-controller=user-status" attribute on outlet element for "chat" controller` +``` + +
    + 原文 +Stimulus will throw an exception if you try to declare an element as an outlet which doesn't have a corresponding `data-controller` and identifier on it: + + +```html +
    + +
    +``` + +Would result in: +```html +Missing "data-controller=user-status" attribute on outlet element for "chat" controller` +``` +
    From da7a39a4c93e8d2c38c9d9eceda28870648b2a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Mon, 15 Jan 2024 20:14:12 +0900 Subject: [PATCH 095/183] add css-classes --- stimulus/reference/css_classes.md | 268 ++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 stimulus/reference/css_classes.md diff --git a/stimulus/reference/css_classes.md b/stimulus/reference/css_classes.md new file mode 100644 index 00000000..fa09360f --- /dev/null +++ b/stimulus/reference/css_classes.md @@ -0,0 +1,268 @@ +--- +title: CSS Classes +description: CSSクラスを論理名でコントローラから参照できるようにする" +layout: "base.html" +--- + +# CSS Classes + +HTMLの _CSSクラス_ は、`class`属性を使用して要素にスタイルのセットを定義します。 + +CSSクラスは、プログラムでスタイルを変更したりアニメーションを再生したりするのに便利です。 例えば、Stimulusコントローラで、バックグラウンドでなんらかの操作を実行しているときに読み込み中のUIを表示させるために`loading`を要素につけるといったこともできます。 + +```html +
    +``` + +```css +.search--busy { + background-image: url(throbber.svg) no-repeat; +} +``` + +Stimulusでは、JavaScript内でCSSクラスを文字列としてハードコーディングする代わりに、データ属性とコントローラプロパティの組み合わせを使用して、 _論理名_ で参照することができます。 + +
    + 原文 +In HTML, a _CSS class_ defines a set of styles which can be applied to elements using the `class` attribute. + +CSS classes are a convenient tool for changing styles and playing animations programmatically. For example, a Stimulus controller might add a "loading" class to an element when it is performing an operation in the background, and then style that class in CSS to display a progress indicator: + +```html + +``` + +```css +.search--busy { + background-image: url(throbber.svg) no-repeat; +} +``` + +As an alternative to hard-coding classes with JavaScript strings, Stimulus lets you refer to CSS classes by _logical name_ using a combination of data attributes and controller properties. +
    + +## 定義の仕方 + +`static classes`配列を使用して、コントローラでCSSクラスの論理名を定義します。 + +```js +// controllers/search_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static classes = [ "loading" ] + + // … +} +``` + +
    + 原文 +Define CSS classes by logical name in your controller using the `static classes` array: + +```js +// controllers/search_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static classes = [ "loading" ] + + // … +} +``` +
    + +## 属性 + +コントローラの`static classes`配列で定義されている論理名は、コントローラ要素の _classデータ属性_ にマップされます。 + +```html + + +
    +``` + +コントローラ識別子と論理名を`data-[identifier]-[logical-name]-class`の形式で結合して、classデータ属性を作ります。 この属性の値には、単一のCSSクラス名または複数のクラス名のリストを指定することができます。 + +**注:** classデータ属性は、`data-controller`属性と同じ要素に指定する必要があります。 + +論理名に複数のCSSクラスを指定する場合は、クラスをスペースで区切ります。 + +```html +
    + +
    +``` + +
    + 原文 + +The logical names defined in the controller's `static classes` array map to _CSS class attributes_ on the controller's element. + +```html +
    + +
    +``` + +Construct a CSS class attribute by joining together the controller identifier and logical name in the format `data-[identifier]-[logical-name]-class`. The attribute's value can be a single CSS class name or a list of multiple class names. + +**Note:** CSS class attributes must be specified on the same element as the `data-controller` attribute. + +If you want to specify multiple CSS classes for a logical name, separate the classes with spaces: + +```html +
    + +
    +``` +
    + +## プロパティ + +`static classes`配列で定義された論理名ごとに、Stimulusは次のプロパティをコントローラに追加します。 + +Kind | Name | Value +-------- | ---------------------------- | ----- +単数 | `this.[logicalName]Class` | `logicalName`に対応するclassデータ属性の値 +複数形 | `this.[logicalName]Classes` | 対応するclassデータ属性に含まれる全てのクラスをスペースで分割した配列 +存在有無 | `this.has[LogicalName]Class` | classデータ属性が存在するかどうかを示すbool値 + +
    これらのプロパティと [DOM classList API](https://developer.mozilla.org/ja/docs/Web/API/Element/classList) の`add() `および`remove() `メソッドを使用して要素にCSSクラスを適用します。 + +たとえば、(ajax通信などの)結果をフェッチする前に`search`コントローラの要素に読み込みインジケータを表示するには、次のように`loadResults`関数を実装します。 + +```js +export default class extends Controller { + static classes = [ "loading" ] + + loadResults() { + this.element.classList.add(this.loadingClass) + + fetch(/* … */) + } +} +``` + +classデータ属性にクラス名のリストが含まれている場合、単数系のcss-classプロパティ(`loadingClass`)はリスト内の最初のクラスを返します。 + +classデータ属性に記述された全てのクラス名に配列としてアクセスするには、複数形のcss-classプロパティを使用します。 これを [スプレッド構文](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax) と組み合わせると、複数のクラスを一度に適用することができます。 + +```js +export default class extends Controller { + static classes = [ "loading" ] + + loadResults() { + this.element.classList.add(...this.loadingClasses) + + fetch(/* … */) + } +} +``` + +**注:** 一致するclassデータ属性が存在しない場合にcss-classプロパティにアクセスしようとすると、Stimulusはエラーをスローします。 + +
    + 原文 +For each logical name defined in the `static classes` array, Stimulus adds the following _CSS class properties_ to your controller: + +Kind | Name | Value +----------- | ---------------------------- | ----- +Singular | `this.[logicalName]Class` | The value of the CSS class attribute corresponding to `logicalName` +Plural | `this.[logicalName]Classes` | An array of all classes in the corresponding CSS class attribute, split by spaces +Existential | `this.has[LogicalName]Class` | A boolean indicating whether or not the CSS class attribute is present + +
    Use these properties to apply CSS classes to elements with the `add()` and `remove()` methods of the [DOM `classList` API](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList). + +For example, to display a loading indicator on the `search` controller's element before fetching results, you might implement the `loadResults` action like so: + +```js +export default class extends Controller { + static classes = [ "loading" ] + + loadResults() { + this.element.classList.add(this.loadingClass) + + fetch(/* … */) + } +} +``` + +If a CSS class attribute contains a list of class names, its singular CSS class property returns the first class in the list. + +Use the plural CSS class property to access all class names as an array. Combine this with [spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) to apply multiple classes at once: + +```js +export default class extends Controller { + static classes = [ "loading" ] + + loadResults() { + this.element.classList.add(...this.loadingClasses) + + fetch(/* … */) + } +} +``` + +**Note:** Stimulus will throw an error if you attempt to access a CSS class property when a matching CSS class attribute is not present. + +
    + +## 命名規則 + +`static classes`定義で論理名を指定する際はキャメルケースを使用します。 論理名はキャメルケースのままcss-classプロパティにマップされます。 + +```js +export default class extends Controller { + static classes = [ "loading", "noResults" ] + + loadResults() { + // … + if (results.length == 0) { + this.element.classList.add(this.noResultsClass) + } + } +} +``` + +HTMLでは、classデータ属性をケバブケースで記述します。 + +```html +
    +``` + +classデータ属性を作成する場合は、[コントローラ:命名規則](/stimulus/reference/controllers/#%E5%91%BD%E5%90%8D%E8%A6%8F%E5%89%87)で説明されている識別子の規則に従います。 + +
    + 原文 +Use camelCase to specify logical names in CSS class definitions. Logical names map to camelCase CSS class properties: + +```js +export default class extends Controller { + static classes = [ "loading", "noResults" ] + + loadResults() { + // … + if (results.length == 0) { + this.element.classList.add(this.noResultsClass) + } + } +} +``` + +In HTML, write CSS class attributes in kebab-case: + +```html + +``` + +When constructing CSS class attributes, follow the conventions for identifiers as described in [Controllers: Naming Conventions](controllers#naming-conventions). +
    From bffef68e328d990bcc2be21177f22e58b487d5a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Mon, 15 Jan 2024 16:38:04 +0900 Subject: [PATCH 096/183] add values --- stimulus/reference/values.md | 305 +++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 stimulus/reference/values.md diff --git a/stimulus/reference/values.md b/stimulus/reference/values.md new file mode 100644 index 00000000..f6babb10 --- /dev/null +++ b/stimulus/reference/values.md @@ -0,0 +1,305 @@ +--- +title: Values +description: "Valuesを使うことでコントローラ要素に設定したデータ属性を読み書きすることができます" +layout: "base.html" +--- + +# Values + +コントローラ要素に設定された[HTMLデータ属性](https://developer.mozilla.org/ja/docs/Web/HTML/Global_attributes/data-*)は、コントローラの特別なプロパティを使用して、型付けされた値として読み書きできます。 + +```html +
    +
    +``` + +上記のHTMLスニペットを参考にして、valueデータ属性を`data-controller`属性を設定したのと同じ要素に設置しましょう。 + +```js +// controllers/loader_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static values = { + url: String + } + + connect() { + fetch(this.urlValue).then(/* … */) + } +} +``` + +
    + 原文 +You can read and write [HTML data attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-*) on controller elements as typed _values_ using special controller properties. + +```html +
    +
    +``` + +As per the given HTML snippet, remember to place the data attributes for values on the same element as the `data-controller` attribute. + +```js +// controllers/loader_controller.js +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static values = { + url: String + } + + connect() { + fetch(this.urlValue).then(/* … */) + } +} +``` +
    + +## 定義の仕方 + +`static values`オブジェクトを使用して、コントローラ内で`values`を定義します。 各valueの論理名を左側に、その型を右側に記述します。 + +```js +export default class extends Controller { + static values = { + url: String, + interval: Number, + params: Object + } + + // … +} +``` + +
    + 原文 +Define values in a controller using the `static values` object. Put each value's _name_ on the left and its _type_ on the right. + +```js +export default class extends Controller { + static values = { + url: String, + interval: Number, + params: Object + } + + // … +} +``` +
    + +## 型 + +valueの型は、`Array`、`Boolean`、`Number`、`Object`、または`String`のいずれかです。 型は、JavaScriptとHTMLのデータ属性間で相互に値を変換する方法を決定します。 + +| 型 | エンコード方法 | デコード方法 | +| ------- | ------------------------ | --------------------------------------- | +| Array | `JSON.stringify(array)` | `JSON.parse(value)` | +| Boolean | `boolean.toString()` | `!(value == "0" \|\| value == "false")` | +| Number | `number.toString()` | `Number(value.replace(/_/g, ""))` | +| Object | `JSON.stringify(object)` | `JSON.parse(value)` | +| String | Itself | Itself | + +
    + 原文 +A value's type is one of `Array`, `Boolean`, `Number`, `Object`, or `String`. The type determines how the value is transcoded between JavaScript and HTML. + +| Type | Encoded as… | Decoded as… | +| ------- | ------------------------ | --------------------------------------- | +| Array | `JSON.stringify(array)` | `JSON.parse(value)` | +| Boolean | `boolean.toString()` | `!(value == "0" \|\| value == "false")` | +| Number | `number.toString()` | `Number(value.replace(/_/g, ""))` | +| Object | `JSON.stringify(object)` | `JSON.parse(value)` | +| String | Itself | Itself | + +
    + +## プロパティと属性 + +Stimulus はコントローラで定義された各valueのゲッター、セッター、および存在有無を示すプロパティを自動的に生成します。 これらのプロパティは、コントローラ要素のデータ属性にリンクされます: + +種類 | プロパティ名 | 振る舞い +---- | ------------- | ------ +Getter | `this.[name]Value` | `data-[identifier]-[name]-value`を読み取る +Setter | `this.[name]Value=` | `data-[identifier]-[name]-value`に書き込む +Existential | `this.has[Name]Value` | `data-[identifier]-[name]-value`があるかどうか検証する + +
    + 原文 +Stimulus automatically generates getter, setter, and existential properties for each value defined in a controller. These properties are linked to data attributes on the controller's element: + +Kind | Property name | Effect +---- | ------------- | ------ +Getter | `this.[name]Value` | Reads `data-[identifier]-[name]-value` +Setter | `this.[name]Value=` | Writes `data-[identifier]-[name]-value` +Existential | `this.has[Name]Value` | Tests for `data-[identifier]-[name]-value` +
    + +### ゲッター + +valueのゲッターは、関連付けられたデータ属性の値を指定した型にデコードします。 + +コントローラの要素にdata属性がない場合、ゲッターはvalueの型に応じた _デフォルト値_ を返します: + +型 | デフォルト値 +---- | ------------- +Array | `[]` +Boolean | `false` +Number | `0` +Object | `{}` +String | `""` + +
    + 原文 +The getter for a value decodes the associated data attribute into an instance of the value's type. + +If the data attribute is missing from the controller's element, the getter returns a _default value_, depending on the value's type: + +Type | Default value +---- | ------------- +Array | `[]` +Boolean | `false` +Number | `0` +Object | `{}` +String | `""` +
    + +### セッター + +valueのセッターは、コントローラの要素に関連付けられたデータ属性に書き込みをします。 + +コントローラの要素からvaluesデータ属性を削除するには、valueセッターに`undefined`を代入します。 + +
    + 原文 +The setter for a value sets the associated data attribute on the controller's element. + +To remove the data attribute from the controller's element, assign `undefined` to the value. + +
    + +### 存在有無プロパティ + +valueの存在有無プロパティは、関連付けられたデータ属性がコントローラーの要素に存在する場合は`true`、しない場合に`false`を返します。 + +
    + 原文 +The existential property for a value evaluates to `true` when the associated data attribute is present on the controller's element and `false` when it is absent. + +
    + +## 変更コールバック + +_ValueChangedコールバック_ を使用すると、対応するvalueデータ属性が変更されるたびに処理を呼び出すことができます。 + +まずコントローラーでメソッド`[name]ValueChanged`を定義します。 この`[name]`は変更を監視するvalueの論理名です。 このメソッドは、最初の引数としてデコード済みの現在の値を受け取り、2番目の引数としてデコード済みの変更前の値を受け取ります。 + +Stimulusは、コントローラが初期化された後、関連付けられているデータ属性が変更されるたびに、それぞれの`ValueChangedコールバック`を呼び出します。 これには、valueセッターへの代入の結果としての変更も含まれます。 + +```js +export default class extends Controller { + static values = { url: String } + + urlValueChanged() { + fetch(this.urlValue).then(/* … */) + } +} +``` + +
    + 原文 +Value _change callbacks_ let you respond whenever a value's data attribute changes. + +Define a method `[name]ValueChanged` in the controller, where `[name]` is the name of the value you want to observe for changes. The method receives its decoded value as the first argument and the decoded previous value as the second argument. + +Stimulus invokes each change callback after the controller is initialized and again any time its associated data attribute changes. This includes changes as a result of assignment to the value's setter. + +```js +export default class extends Controller { + static values = { url: String } + + urlValueChanged() { + fetch(this.urlValue).then(/* … */) + } +} +``` +
    + +### 変更前のvalue + +`[name]ValueChanged`コールバックで変更前の値にアクセスするには、第二引数を指定します。 + +```js +export default class extends Controller { + static values = { url: String } + + urlValueChanged(value, previousValue) { + /* … */ + } +} +``` + +この第二引数には好きな名前を付けることができます。 例として`urlValueChanged(current, old)`のように定義できます。 + +
    + 原文 +You can access the previous value of a `[name]ValueChanged` callback by defining the callback method with two arguments in your controller. + +```js +export default class extends Controller { + static values = { url: String } + + urlValueChanged(value, previousValue) { + /* … */ + } +} +``` + +The two arguments can be named as you like. You could also use `urlValueChanged(current, old)`. + +
    + +## デフォルト値 + +コントローラ要素で指定されていないvalueデータ属性の値は、コントローラ側で定義されたデフォルト値があればそれが適用されます。 + +```js +export default class extends Controller { + static values = { + url: { type: String, default: '/bill' }, + interval: { type: Number, default: 5 }, + clicked: Boolean + } +} +``` + +デフォルト値を使用する場合、valueの定義は`{ type, default }`の展開形式を使用します。 この形式は、デフォルト値を使用しない通常の形式と混在させることができます。 + +
    + 原文 +Values that have not been specified on the controller element can be set by defaults specified in the controller definition: + +```js +export default class extends Controller { + static values = { + url: { type: String, default: '/bill' }, + interval: { type: Number, default: 5 }, + clicked: Boolean + } +} +``` + +When a default is used, the expanded form of `{ type, default }` is used. This form can be mixed with the regular form that does not use a default. + +
    + +## 命名規則 + +valueの名前は、JavaScriptではキャメルケース、HTMLではケバブケースで記述します。 例えば、`loader`コントローラの`contentType`というvalueは、関連するデータ属性として`data-loader-content-type-value`を持ちます。 + +
    + 原文 +Write value names as camelCase in JavaScript and kebab-case in HTML. For example, a value named `contentType` in the `loader` controller will have the associated data attribute `data-loader-content-type-value`. +
    From 3bbace361a46403bd9c23d5f7c66c57b1fc462a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=AD=E5=B3=B6=20=E6=8B=93=E5=93=89?= Date: Mon, 15 Jan 2024 20:40:43 +0900 Subject: [PATCH 097/183] add using-typescript --- stimulus/reference/using_typescript.md | 153 +++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 stimulus/reference/using_typescript.md diff --git a/stimulus/reference/using_typescript.md b/stimulus/reference/using_typescript.md new file mode 100644 index 00000000..6c19c72c --- /dev/null +++ b/stimulus/reference/using_typescript.md @@ -0,0 +1,153 @@ +--- +title: Using Typescript +description: "Stimulusの各プロパティの型を定義する方法について" +layout: "base.html" +--- + +# Typescriptを使う + +Stimulus自体は[TypeScript](https://www.typescriptlang.org/)で記述されており、そのパッケージ上で直接型を提供します。 このドキュメントでは、Stimulusプロパティの型を定義する方法を示します。 + +
    + 原文 +Stimulus itself is written in [TypeScript](https://www.typescriptlang.org/) and provides types directly over its package. +The following documentation shows how to define types for Stimulus properties. +
    + +## コントローラ要素の型を定義する + +デフォルトでは、コントローラー要素は`Element型`です。 コントローラ要素の型をオーバーライドするには、[Generic Type](https://www.typescriptlang.org/docs/handbook/2/generics.html)を指定します。 たとえば、要素の型を`HTMLFormElement`とすることを想定している場合は次のようにします。 + +```ts +import { Controller } from "@hotwired/stimulus" + +export default class MyController extends Controller { + submit() { + new FormData(this.element) + } +} +``` + +
    + 原文 +By default, the `element` of the controller is of type `Element`. You can override the type of the controller element by specifiying it as a [Generic Type](https://www.typescriptlang.org/docs/handbook/2/generics.html). For example, if the element type is expected to be a `HTMLFormElement`: + +```ts +import { Controller } from "@hotwired/stimulus" + +export default class MyController extends Controller { + submit() { + new FormData(this.element) + } +} +``` +
    + +## Valueプロパティの型定義 + +valuesの各プロパティは、Stimulusによって自動生成されるのでそれを上書きしないよう`declare`キーワードを使用して型定義します。 + +```ts +import { Controller } from "@hotwired/stimulus" + +export default class MyController extends Controller { + static values = { + code: String + } + + declare codeValue: string + declare readonly hasCodeValue: boolean +} +``` + +> declareキーワードは、既存のStimulusプロパティのオーバーライドを回避し、TypeScriptの型を定義します。 + +
    + 原文 +You can define the properties of configured values using the TypeScript `declare` keyword. You just need to define the properties if you are making use of them within the controller. + +```ts +import { Controller } from "@hotwired/stimulus" + +export default class MyController extends Controller { + static values = { + code: String + } + + declare codeValue: string + declare readonly hasCodeValue: boolean +} +``` + +> The `declare` keyword avoids overriding the existing Stimulus property, and just defines the type for TypeScript. +
    + +## Targetプロパティの型定義 + +ターゲットの各プロパティは、Stimulusによって自動生成されるのでそれを上書きしないよう`declare`キーワードを使用して型定義します。 + +`[name]Target`および`[name]Targets`プロパティの戻り値の型は、`Element型`を継承したものであれば何でも構いません。 その時々に合った最適な型をお選びください。 汎用HTML要素として定義する場合は、`Element`または`HTMLElement`を使います。 + +```ts +import { Controller } from "@hotwired/stimulus" + +export default class MyController extends Controller { + static targets = [ "input" ] + + declare readonly hasInputTarget: boolean + declare readonly inputTarget: HTMLInputElement + declare readonly inputTargets: HTMLInputElement[] +} +``` + +> declareキーワードは、既存のStimulusプロパティのオーバーライドを回避し、TypeScriptの型を定義します。 + +
    + 原文 +You can define the properties of configured targets using the TypeScript `declare` keyword. You just need to define the properties if you are making use of them within the controller. + + The return types of the `[name]Target` and `[name]Targets` properties can be any inheriting from the `Element` type. Choose the best type which fits your needs. Pick either `Element` or `HTMLElement` if you want to define it as a generic HTML element. + +```ts +import { Controller } from "@hotwired/stimulus" + +export default class MyController extends Controller { + static targets = [ "input" ] + + declare readonly hasInputTarget: boolean + declare readonly inputTarget: HTMLInputElement + declare readonly inputTargets: HTMLInputElement[] +} +``` + +> The `declare` keyword avoids overriding the existing Stimulus property, and just defines the type for TypeScript. +
    + +## カスタムプロパティやメソッドの型定義 + +その他のカスタムなプロパティは、コントローラクラスにTypeScriptのやり方で直接定義することができます: + +```ts +import { Controller } from "@hotwired/stimulus" + +export default class MyController extends Controller { + container: HTMLElement +} +``` + +詳細については、[TypeScriptドキュメント](https://www.typescriptlang.org/docs/handbook/intro.html)を参照してください。 + +
    + 原文 +Other custom properties can be defined the TypeScript way on the controller class: + +```ts +import { Controller } from "@hotwired/stimulus" + +export default class MyController extends Controller { + container: HTMLElement +} +``` + +Read more in the [TypeScript Documentation](https://www.typescriptlang.org/docs/handbook/intro.html). +
    From 3dd2c5f59243af94d34899fb4108a532ae67df9d Mon Sep 17 00:00:00 2001 From: "nakajima a.k.a. nazomikan" Date: Thu, 23 May 2024 11:06:31 +0900 Subject: [PATCH 098/183] =?UTF-8?q?=E6=96=87=E6=9C=AB=E8=AA=BF=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yuki Torii --- stimulus/reference/css_classes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stimulus/reference/css_classes.md b/stimulus/reference/css_classes.md index fa09360f..4d39106b 100644 --- a/stimulus/reference/css_classes.md +++ b/stimulus/reference/css_classes.md @@ -6,7 +6,7 @@ layout: "base.html" # CSS Classes -HTMLの _CSSクラス_ は、`class`属性を使用して要素にスタイルのセットを定義します。 +HTMLの _CSSクラス_ は、`class`属性を使用して、要素に適用されるスタイルのセットを定義します。 CSSクラスは、プログラムでスタイルを変更したりアニメーションを再生したりするのに便利です。 例えば、Stimulusコントローラで、バックグラウンドでなんらかの操作を実行しているときに読み込み中のUIを表示させるために`loading`を要素につけるといったこともできます。 From 81162ed1490786546a3d55c56f8f2fa649f10458 Mon Sep 17 00:00:00 2001 From: akira888 Date: Sat, 22 Mar 2025 20:37:44 +0900 Subject: [PATCH 099/183] =?UTF-8?q?layout=E3=82=92document=E6=AF=8E?= =?UTF-8?q?=E3=81=AB=E5=A4=89=E6=9B=B4=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _includes/footer.html | 9 +++++++++ _includes/turbo-navigation.html | 14 ++++++++++++++ layouts/base.html | 24 +++--------------------- layouts/turbo-docs.html | 15 +++++++++++++++ turbo/handbook/handbook.json | 5 +++-- turbo/reference/reference.json | 5 +++-- 6 files changed, 47 insertions(+), 25 deletions(-) create mode 100644 _includes/footer.html create mode 100644 _includes/turbo-navigation.html create mode 100644 layouts/turbo-docs.html diff --git a/_includes/footer.html b/_includes/footer.html new file mode 100644 index 00000000..5fb7b0c6 --- /dev/null +++ b/_includes/footer.html @@ -0,0 +1,9 @@ + diff --git a/_includes/turbo-navigation.html b/_includes/turbo-navigation.html new file mode 100644 index 00000000..3a384edb --- /dev/null +++ b/_includes/turbo-navigation.html @@ -0,0 +1,14 @@ + diff --git a/layouts/base.html b/layouts/base.html index 8b8b31e3..7b4515e7 100644 --- a/layouts/base.html +++ b/layouts/base.html @@ -24,30 +24,12 @@
    - -
    - {% include 'navigation.html' %} -
    - -
    - {{ content }} -
    - + {{ content }}
    diff --git a/layouts/turbo-docs.html b/layouts/turbo-docs.html new file mode 100644 index 00000000..1f2581fa --- /dev/null +++ b/layouts/turbo-docs.html @@ -0,0 +1,15 @@ +--- +layout: base.html +title: Hotwire +--- +
    + {% include 'turbo-navigation.html' %} +
    + +
    + {{ content }} +
    + +
    + {% include 'footer.html' %} +
    diff --git a/turbo/handbook/handbook.json b/turbo/handbook/handbook.json index b6865c23..8b772204 100644 --- a/turbo/handbook/handbook.json +++ b/turbo/handbook/handbook.json @@ -2,7 +2,8 @@ "tags": [ "turbo_handbook" ], - "layout": "base.html", + "layout": "turbo-docs.html", "section_title": "Turbo ハンドブック: Hotwire ドキュメント(有志翻訳版)", - "section_code": "turbo_handbook" + "section_code": "turbo_handbook", + "document_type": "turbo" } diff --git a/turbo/reference/reference.json b/turbo/reference/reference.json index 7dca3124..bf684701 100644 --- a/turbo/reference/reference.json +++ b/turbo/reference/reference.json @@ -2,7 +2,8 @@ "tags": [ "turbo_reference" ], - "layout": "base.html", + "layout": "turbo-docs.html", "section_title": "Turbo リファレンス: Hotwire ドキュメント(有志翻訳版)", - "section_code": "turbo_reference" + "section_code": "turbo_reference", + "document_type": "turbo" } From 6178c50990ee13a23ef5f568a6a744df044dd878 Mon Sep 17 00:00:00 2001 From: akira888 Date: Sat, 22 Mar 2025 20:34:31 +0900 Subject: [PATCH 100/183] =?UTF-8?q?stimulus=20layout=E3=81=AE=E4=BD=9C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _includes/stimulus-navigation.html | 15 +++++++ layouts/stimulus--base.html | 45 ------------------- layouts/stimulus-docs.html | 15 +++++++ stimulus/handbook/building-something-real.md | 2 +- stimulus/handbook/designing-for-resilience.md | 2 +- stimulus/handbook/handbook.json | 9 ++++ stimulus/handbook/hello-stimulus.md | 2 +- stimulus/handbook/installing.md | 2 +- stimulus/handbook/introduction.md | 2 +- stimulus/handbook/managing-state.md | 2 +- stimulus/handbook/origin.md | 1 - .../working-with-external-resources.md | 2 +- stimulus/reference/actions.md | 2 +- stimulus/reference/controllers.md | 2 +- stimulus/reference/css_classes.md | 2 +- stimulus/reference/lifecycle_callbacks.md | 2 +- stimulus/reference/outlets.md | 2 +- stimulus/reference/reference.json | 9 ++++ stimulus/reference/targets.md | 2 +- stimulus/reference/using_typescript.md | 2 +- stimulus/reference/values.md | 2 +- 21 files changed, 63 insertions(+), 61 deletions(-) create mode 100644 _includes/stimulus-navigation.html delete mode 100644 layouts/stimulus--base.html create mode 100644 layouts/stimulus-docs.html create mode 100644 stimulus/handbook/handbook.json create mode 100644 stimulus/reference/reference.json diff --git a/_includes/stimulus-navigation.html b/_includes/stimulus-navigation.html new file mode 100644 index 00000000..a239f349 --- /dev/null +++ b/_includes/stimulus-navigation.html @@ -0,0 +1,15 @@ + + diff --git a/layouts/stimulus--base.html b/layouts/stimulus--base.html deleted file mode 100644 index 9c7be91f..00000000 --- a/layouts/stimulus--base.html +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Hotwire ---- - - - - - - - - {% if section_title %}{{ section_title }}: {% endif %}{{ title }} - - - -
    - -
    - {% render 'stimulus--navigation.html' %} -
    - -
    - {{ content }} -
    - -
    - - diff --git a/layouts/stimulus-docs.html b/layouts/stimulus-docs.html new file mode 100644 index 00000000..85d0ada5 --- /dev/null +++ b/layouts/stimulus-docs.html @@ -0,0 +1,15 @@ +--- +layout: base.html +title: Hotwire +--- +
    + {% include 'stimulus-navigation.html' %} +
    + +
    + {{ content }} +
    + +
    + {% include 'footer.html' %} +
    diff --git a/stimulus/handbook/building-something-real.md b/stimulus/handbook/building-something-real.md index 8f478a4a..e6899245 100644 --- a/stimulus/handbook/building-something-real.md +++ b/stimulus/handbook/building-something-real.md @@ -1,7 +1,7 @@ --- title: "実際に使えるものを作る" description: "簡単なコントローラを作ってみましょう。" -layout: "stimulus--base.html" + --- # 実際に使えるものを作る diff --git a/stimulus/handbook/designing-for-resilience.md b/stimulus/handbook/designing-for-resilience.md index dfc0617a..1121a193 100644 --- a/stimulus/handbook/designing-for-resilience.md +++ b/stimulus/handbook/designing-for-resilience.md @@ -1,7 +1,7 @@ --- title: "弾力性のある設計" description: "プログレッシブエンハンスメントな設計をしてネットワーク障害時やレガシーブラウザ環境でも使うことができるアプリケーションを作りましょう" -layout: "stimulus--base.html" + --- # 弾力性のある設計 diff --git a/stimulus/handbook/handbook.json b/stimulus/handbook/handbook.json new file mode 100644 index 00000000..852eefd2 --- /dev/null +++ b/stimulus/handbook/handbook.json @@ -0,0 +1,9 @@ +{ + "tags": [ + "stimulus_handbook" + ], + "layout": "stimulus-docs.html", + "section_title": "Stimulus ハンドブック: Hotwire ドキュメント(有志翻訳版)", + "section_code": "stimulus_handbook", + "document_type": "stimulus" +} diff --git a/stimulus/handbook/hello-stimulus.md b/stimulus/handbook/hello-stimulus.md index 8b5dd447..83c4a741 100644 --- a/stimulus/handbook/hello-stimulus.md +++ b/stimulus/handbook/hello-stimulus.md @@ -1,7 +1,7 @@ --- title: "Hello, Stimulus" description: "簡単なコントローラを作ってみましょう。" -layout: "stimulus--base.html" + --- # Hello, Stimulus diff --git a/stimulus/handbook/installing.md b/stimulus/handbook/installing.md index 2ea24443..5f1cfe5b 100644 --- a/stimulus/handbook/installing.md +++ b/stimulus/handbook/installing.md @@ -1,7 +1,7 @@ --- title: "アプリケーションにStimulusをインストールする" description: "様々なシステム環境のアプリケーションでStimulusをインストールする方法について" -layout: "stimulus--base.html" + --- # アプリケーションにStimulusをインストールする diff --git a/stimulus/handbook/introduction.md b/stimulus/handbook/introduction.md index ab598570..b96c4a86 100644 --- a/stimulus/handbook/introduction.md +++ b/stimulus/handbook/introduction.md @@ -1,7 +1,7 @@ --- title: "はじめに" description: "Stimulusはすでに持っているHTMLに簡単なアノテーションを加えることで要素とJavaScriptオブジェクトを接続することができるフレームワークです。" -layout: "stimulus--base.html" + --- # はじめに diff --git a/stimulus/handbook/managing-state.md b/stimulus/handbook/managing-state.md index 24661891..26e0db65 100644 --- a/stimulus/handbook/managing-state.md +++ b/stimulus/handbook/managing-state.md @@ -1,7 +1,7 @@ --- title: "ステート管理" description: "Stimulusでアプリケーションのステート管理はどのように行われるのかを見ていきましょう" -layout: "stimulus--base.html" + --- # ステート管理 diff --git a/stimulus/handbook/origin.md b/stimulus/handbook/origin.md index 39ee5625..ac6affe8 100644 --- a/stimulus/handbook/origin.md +++ b/stimulus/handbook/origin.md @@ -1,7 +1,6 @@ --- title: "Stimulusの原点" description: "Stimulusが他のフレームワークとどう違うか、何を求められて生まれたものかについて" -layout: "stimulus--base.html" --- # Stimulusの原点 diff --git a/stimulus/handbook/working-with-external-resources.md b/stimulus/handbook/working-with-external-resources.md index 6bfc4d66..0b977fa2 100644 --- a/stimulus/handbook/working-with-external-resources.md +++ b/stimulus/handbook/working-with-external-resources.md @@ -1,7 +1,7 @@ --- title: "外部リソースの利用" description: "Stimulusで外部リソースを取得して情報を更新したり、タイマーを使ったりする方法を見ていきましょう。" -layout: "stimulus--base.html" + --- # 外部リソースの利用 diff --git a/stimulus/reference/actions.md b/stimulus/reference/actions.md index 63a6f623..ddda1f57 100644 --- a/stimulus/reference/actions.md +++ b/stimulus/reference/actions.md @@ -1,7 +1,7 @@ --- title: Actions description: "アクションはコントローラでDOMイベントを処理する方法です" -layout: "base.html" + --- # Actions diff --git a/stimulus/reference/controllers.md b/stimulus/reference/controllers.md index 52843c70..889a2488 100644 --- a/stimulus/reference/controllers.md +++ b/stimulus/reference/controllers.md @@ -1,7 +1,7 @@ --- title: Controllers description: "コントローラはStimulusアプリケーションの基本的な構成単位です" -layout: "base.html" + --- # Controllers diff --git a/stimulus/reference/css_classes.md b/stimulus/reference/css_classes.md index 4d39106b..34e4a3f9 100644 --- a/stimulus/reference/css_classes.md +++ b/stimulus/reference/css_classes.md @@ -1,7 +1,7 @@ --- title: CSS Classes description: CSSクラスを論理名でコントローラから参照できるようにする" -layout: "base.html" + --- # CSS Classes diff --git a/stimulus/reference/lifecycle_callbacks.md b/stimulus/reference/lifecycle_callbacks.md index abb63417..630f701c 100644 --- a/stimulus/reference/lifecycle_callbacks.md +++ b/stimulus/reference/lifecycle_callbacks.md @@ -1,7 +1,7 @@ --- title: ライフサイクルコールバック description: "ライフサイクルコールバックは、コントローラや特定のターゲットがドキュメントに接続したり切断したりするたびに応答するメソッドです" -layout: "base.html" + --- # ライフサイクルコールバック diff --git a/stimulus/reference/outlets.md b/stimulus/reference/outlets.md index f8b87ab3..8434e05c 100644 --- a/stimulus/reference/outlets.md +++ b/stimulus/reference/outlets.md @@ -1,7 +1,7 @@ --- title: Outlets description: "Outletを使うとコントローラが別のコントローラ(と要素)を参照することができます" -layout: "base.html" + --- # Outlets diff --git a/stimulus/reference/reference.json b/stimulus/reference/reference.json new file mode 100644 index 00000000..8e160f23 --- /dev/null +++ b/stimulus/reference/reference.json @@ -0,0 +1,9 @@ +{ + "tags": [ + "stimulus_reference" + ], + "layout": "stimulus-docs.html", + "section_title": "Stimulus リファレンス: Hotwire ドキュメント(有志翻訳版)", + "section_code": "stimulus_reference", + "document_type": "stimulus" +} diff --git a/stimulus/reference/targets.md b/stimulus/reference/targets.md index cc5d990a..3588ad35 100644 --- a/stimulus/reference/targets.md +++ b/stimulus/reference/targets.md @@ -1,7 +1,7 @@ --- title: Targets description: "Targetを使うとコントローラで扱いたい重要な要素を参照することができます" -layout: "base.html" + --- # Targets diff --git a/stimulus/reference/using_typescript.md b/stimulus/reference/using_typescript.md index 6c19c72c..7e2b014e 100644 --- a/stimulus/reference/using_typescript.md +++ b/stimulus/reference/using_typescript.md @@ -1,7 +1,7 @@ --- title: Using Typescript description: "Stimulusの各プロパティの型を定義する方法について" -layout: "base.html" + --- # Typescriptを使う diff --git a/stimulus/reference/values.md b/stimulus/reference/values.md index f6babb10..8aa83520 100644 --- a/stimulus/reference/values.md +++ b/stimulus/reference/values.md @@ -1,7 +1,7 @@ --- title: Values description: "Valuesを使うことでコントローラ要素に設定したデータ属性を読み書きすることができます" -layout: "base.html" + --- # Values From 90431ba75c17b38bd7e38557bc8c208bb37f1f5f Mon Sep 17 00:00:00 2001 From: akira888 Date: Sun, 23 Mar 2025 02:33:11 +0900 Subject: [PATCH 101/183] =?UTF-8?q?stimulus=20=E3=81=AE=E3=83=8A=E3=83=93?= =?UTF-8?q?=E3=82=B2=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92=E5=8B=95?= =?UTF-8?q?=E7=9A=84=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eleventy.js | 12 ++++++++++++ _includes/stimulus-navigation.html | 2 +- layouts/base.html | 2 +- stimulus/handbook/building-something-real.md | 2 +- stimulus/handbook/designing-for-resilience.md | 2 +- stimulus/handbook/hello-stimulus.md | 2 +- stimulus/handbook/installing.md | 2 +- stimulus/handbook/introduction.md | 2 +- stimulus/handbook/managing-state.md | 2 +- stimulus/handbook/origin.md | 1 + stimulus/handbook/working-with-external-resources.md | 2 +- stimulus/reference/actions.md | 2 +- stimulus/reference/controllers.md | 2 +- stimulus/reference/css_classes.md | 2 +- stimulus/reference/lifecycle_callbacks.md | 2 +- stimulus/reference/outlets.md | 2 +- stimulus/reference/targets.md | 2 +- stimulus/reference/using_typescript.md | 2 +- stimulus/reference/values.md | 2 +- 19 files changed, 30 insertions(+), 17 deletions(-) diff --git a/.eleventy.js b/.eleventy.js index 605d04bc..e1593393 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -41,6 +41,18 @@ export default function (eleventyConfig) { }); }) + eleventyConfig.addCollection('stimulus_handbook', collectionApi => { + return collectionApi.getFilteredByTag('stimulus_handbook').sort((a, b) => { + return a.data.order - b.data.order; + }); + }) + + eleventyConfig.addCollection('stimulus_reference', collectionApi => { + return collectionApi.getFilteredByTag('stimulus_reference').sort((a, b) => { + return a.data.order - b.data.order; + }); + }) + eleventyConfig.addPlugin(EleventyHtmlBasePlugin); eleventyConfig.addPlugin(syntaxHighlight); eleventyConfig.addPassthroughCopy({'_assets': 'assets'}); diff --git a/_includes/stimulus-navigation.html b/_includes/stimulus-navigation.html index a239f349..034494e3 100644 --- a/_includes/stimulus-navigation.html +++ b/_includes/stimulus-navigation.html @@ -7,7 +7,7 @@ {% include 'section-nav.html', section: 'stimulus_handbook' %}
  • - Reference + Reference {% include 'section-nav.html', section: 'stimulus_reference' %}
  • diff --git a/layouts/base.html b/layouts/base.html index 7b4515e7..9ad4c0b6 100644 --- a/layouts/base.html +++ b/layouts/base.html @@ -25,7 +25,7 @@
    diff --git a/stimulus/handbook/building-something-real.md b/stimulus/handbook/building-something-real.md index e6899245..e31ea7aa 100644 --- a/stimulus/handbook/building-something-real.md +++ b/stimulus/handbook/building-something-real.md @@ -1,7 +1,7 @@ --- title: "実際に使えるものを作る" description: "簡単なコントローラを作ってみましょう。" - +order: 3 --- # 実際に使えるものを作る diff --git a/stimulus/handbook/designing-for-resilience.md b/stimulus/handbook/designing-for-resilience.md index 1121a193..3a8e92d6 100644 --- a/stimulus/handbook/designing-for-resilience.md +++ b/stimulus/handbook/designing-for-resilience.md @@ -1,7 +1,7 @@ --- title: "弾力性のある設計" description: "プログレッシブエンハンスメントな設計をしてネットワーク障害時やレガシーブラウザ環境でも使うことができるアプリケーションを作りましょう" - +order: 4 --- # 弾力性のある設計 diff --git a/stimulus/handbook/hello-stimulus.md b/stimulus/handbook/hello-stimulus.md index 83c4a741..7d668157 100644 --- a/stimulus/handbook/hello-stimulus.md +++ b/stimulus/handbook/hello-stimulus.md @@ -1,7 +1,7 @@ --- title: "Hello, Stimulus" description: "簡単なコントローラを作ってみましょう。" - +order: 2 --- # Hello, Stimulus diff --git a/stimulus/handbook/installing.md b/stimulus/handbook/installing.md index 5f1cfe5b..6f095d03 100644 --- a/stimulus/handbook/installing.md +++ b/stimulus/handbook/installing.md @@ -1,7 +1,7 @@ --- title: "アプリケーションにStimulusをインストールする" description: "様々なシステム環境のアプリケーションでStimulusをインストールする方法について" - +order: 7 --- # アプリケーションにStimulusをインストールする diff --git a/stimulus/handbook/introduction.md b/stimulus/handbook/introduction.md index b96c4a86..9a0fa1fa 100644 --- a/stimulus/handbook/introduction.md +++ b/stimulus/handbook/introduction.md @@ -1,7 +1,7 @@ --- title: "はじめに" description: "Stimulusはすでに持っているHTMLに簡単なアノテーションを加えることで要素とJavaScriptオブジェクトを接続することができるフレームワークです。" - +order: 1 --- # はじめに diff --git a/stimulus/handbook/managing-state.md b/stimulus/handbook/managing-state.md index 26e0db65..ce106ac2 100644 --- a/stimulus/handbook/managing-state.md +++ b/stimulus/handbook/managing-state.md @@ -1,7 +1,7 @@ --- title: "ステート管理" description: "Stimulusでアプリケーションのステート管理はどのように行われるのかを見ていきましょう" - +order: 5 --- # ステート管理 diff --git a/stimulus/handbook/origin.md b/stimulus/handbook/origin.md index ac6affe8..e5df2e2f 100644 --- a/stimulus/handbook/origin.md +++ b/stimulus/handbook/origin.md @@ -1,6 +1,7 @@ --- title: "Stimulusの原点" description: "Stimulusが他のフレームワークとどう違うか、何を求められて生まれたものかについて" +order: 0 --- # Stimulusの原点 diff --git a/stimulus/handbook/working-with-external-resources.md b/stimulus/handbook/working-with-external-resources.md index 0b977fa2..53ffa993 100644 --- a/stimulus/handbook/working-with-external-resources.md +++ b/stimulus/handbook/working-with-external-resources.md @@ -1,7 +1,7 @@ --- title: "外部リソースの利用" description: "Stimulusで外部リソースを取得して情報を更新したり、タイマーを使ったりする方法を見ていきましょう。" - +order: 6 --- # 外部リソースの利用 diff --git a/stimulus/reference/actions.md b/stimulus/reference/actions.md index ddda1f57..ba9818a4 100644 --- a/stimulus/reference/actions.md +++ b/stimulus/reference/actions.md @@ -1,7 +1,7 @@ --- title: Actions description: "アクションはコントローラでDOMイベントを処理する方法です" - +order: 2 --- # Actions diff --git a/stimulus/reference/controllers.md b/stimulus/reference/controllers.md index 889a2488..3cbf8f80 100644 --- a/stimulus/reference/controllers.md +++ b/stimulus/reference/controllers.md @@ -1,7 +1,7 @@ --- title: Controllers description: "コントローラはStimulusアプリケーションの基本的な構成単位です" - +order: 0 --- # Controllers diff --git a/stimulus/reference/css_classes.md b/stimulus/reference/css_classes.md index 34e4a3f9..2f4caa8d 100644 --- a/stimulus/reference/css_classes.md +++ b/stimulus/reference/css_classes.md @@ -1,7 +1,7 @@ --- title: CSS Classes description: CSSクラスを論理名でコントローラから参照できるようにする" - +order: 6 --- # CSS Classes diff --git a/stimulus/reference/lifecycle_callbacks.md b/stimulus/reference/lifecycle_callbacks.md index 630f701c..b94cce9a 100644 --- a/stimulus/reference/lifecycle_callbacks.md +++ b/stimulus/reference/lifecycle_callbacks.md @@ -1,7 +1,7 @@ --- title: ライフサイクルコールバック description: "ライフサイクルコールバックは、コントローラや特定のターゲットがドキュメントに接続したり切断したりするたびに応答するメソッドです" - +order: 1 --- # ライフサイクルコールバック diff --git a/stimulus/reference/outlets.md b/stimulus/reference/outlets.md index 8434e05c..737f0041 100644 --- a/stimulus/reference/outlets.md +++ b/stimulus/reference/outlets.md @@ -1,7 +1,7 @@ --- title: Outlets description: "Outletを使うとコントローラが別のコントローラ(と要素)を参照することができます" - +order: 4 --- # Outlets diff --git a/stimulus/reference/targets.md b/stimulus/reference/targets.md index 3588ad35..881d1786 100644 --- a/stimulus/reference/targets.md +++ b/stimulus/reference/targets.md @@ -1,7 +1,7 @@ --- title: Targets description: "Targetを使うとコントローラで扱いたい重要な要素を参照することができます" - +order: 3 --- # Targets diff --git a/stimulus/reference/using_typescript.md b/stimulus/reference/using_typescript.md index 7e2b014e..47042ffe 100644 --- a/stimulus/reference/using_typescript.md +++ b/stimulus/reference/using_typescript.md @@ -1,7 +1,7 @@ --- title: Using Typescript description: "Stimulusの各プロパティの型を定義する方法について" - +order: 7 --- # Typescriptを使う diff --git a/stimulus/reference/values.md b/stimulus/reference/values.md index 8aa83520..c5cd0eb9 100644 --- a/stimulus/reference/values.md +++ b/stimulus/reference/values.md @@ -1,7 +1,7 @@ --- title: Values description: "Valuesを使うことでコントローラ要素に設定したデータ属性を読み書きすることができます" - +order: 5 --- # Values From c55043cd1e41fa2adea76c6b97c09ffb9ab293dd Mon Sep 17 00:00:00 2001 From: akira888 Date: Sun, 23 Mar 2025 02:34:33 +0900 Subject: [PATCH 102/183] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _includes/stimulus--navigation.html | 8 -------- _includes/stimulus--section-nav.html | 26 -------------------------- stimulus/reference/.gitkeep | 0 3 files changed, 34 deletions(-) delete mode 100644 _includes/stimulus--navigation.html delete mode 100644 _includes/stimulus--section-nav.html delete mode 100644 stimulus/reference/.gitkeep diff --git a/_includes/stimulus--navigation.html b/_includes/stimulus--navigation.html deleted file mode 100644 index d26db1b4..00000000 --- a/_includes/stimulus--navigation.html +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/_includes/stimulus--section-nav.html b/_includes/stimulus--section-nav.html deleted file mode 100644 index 343bb4af..00000000 --- a/_includes/stimulus--section-nav.html +++ /dev/null @@ -1,26 +0,0 @@ - diff --git a/stimulus/reference/.gitkeep b/stimulus/reference/.gitkeep deleted file mode 100644 index e69de29b..00000000 From 414dd7944873c5bd033beca39e9b01b2d67b393b Mon Sep 17 00:00:00 2001 From: akira888 Date: Sun, 23 Mar 2025 02:37:22 +0900 Subject: [PATCH 103/183] =?UTF-8?q?navigation=20=E7=99=BB=E9=8C=B2?= =?UTF-8?q?=E5=87=A6=E7=90=86=E3=82=92=E3=81=BE=E3=81=A8=E3=82=81=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eleventy.js | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/.eleventy.js b/.eleventy.js index e1593393..6a21dba4 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -29,29 +29,20 @@ export default function (eleventyConfig) { }); }); - eleventyConfig.addCollection('turbo_handbook', collectionApi => { - return collectionApi.getFilteredByTag('turbo_handbook').sort((a, b) => { - return a.data.order - b.data.order; + const navigations = [ + 'turbo_handbook', + 'turbo_reference', + 'stimulus_handbook', + 'stimulus_reference', + ]; + + navigations.forEach((nav) => { + eleventyConfig.addCollection(nav, collectionApi => { + return collectionApi.getFilteredByTag(nav).sort((a, b) => { + return a.data.order - b.data.order; + }); }); - }) - - eleventyConfig.addCollection('turbo_reference', collectionApi => { - return collectionApi.getFilteredByTag('turbo_reference').sort((a, b) => { - return a.data.order - b.data.order; - }); - }) - - eleventyConfig.addCollection('stimulus_handbook', collectionApi => { - return collectionApi.getFilteredByTag('stimulus_handbook').sort((a, b) => { - return a.data.order - b.data.order; - }); - }) - - eleventyConfig.addCollection('stimulus_reference', collectionApi => { - return collectionApi.getFilteredByTag('stimulus_reference').sort((a, b) => { - return a.data.order - b.data.order; - }); - }) + }); eleventyConfig.addPlugin(EleventyHtmlBasePlugin); eleventyConfig.addPlugin(syntaxHighlight); From 1157dccb87a6c24c005e8d3c1eeb832cad71907b Mon Sep 17 00:00:00 2001 From: yakitorii Date: Fri, 11 Apr 2025 09:48:06 +0900 Subject: [PATCH 104/183] =?UTF-8?q?details=20=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit トップページであり原文参照の必要性が低いと判断した --- index.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/index.md b/index.md index fb06d3e2..04c36c66 100644 --- a/index.md +++ b/index.md @@ -29,13 +29,7 @@ layout: "base.html"

    Stimulus

    -
    - Turboは通常、従来ならJavaScriptが必要だったインタラクティブな動作の少なくとも80%を担ってくれますが、それでも少しだけカスタムコードが必要になる場面はあります。そんなときに役立つのがStimulusです。Stimulusは、HTMLを中心としたアプローチで状態管理やサーバーとの連携を簡単に実現します。 - - 原文 - - While Turbo usually takes care of at least 80% of the interactivity that traditionally would have required JavaScript, there are still cases where a dash of custom code is required. Stimulus makes this easy with a HTML-centric approach to state and wiring. -
    + Turboは通常、従来ならJavaScriptが必要だったインタラクティブな動作の少なくとも80%を担ってくれますが、それでも少しだけカスタムコードが必要になる場面はあります。そんなときに役立つのがStimulusです。Stimulusは、HTMLを中心としたアプローチで状態管理やサーバーとの連携を簡単に実現します。
    • Handbook
    • From f9a85f56c666328eb544bf6af6b7641bcfb48ab6 Mon Sep 17 00:00:00 2001 From: Yuki Torii Date: Fri, 11 Apr 2025 09:49:29 +0900 Subject: [PATCH 105/183] =?UTF-8?q?=E8=8B=B1=E5=8D=98=E8=AA=9E=E5=89=8D?= =?UTF-8?q?=E5=BE=8C=E3=81=AE=E3=82=B9=E3=83=9A=E3=83=BC=E3=82=B9=E9=96=8B?= =?UTF-8?q?=E3=81=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Akira Yagi --- index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.md b/index.md index 04c36c66..dfa2c34a 100644 --- a/index.md +++ b/index.md @@ -8,7 +8,7 @@ layout: "base.html"

      HOTWIRE - HTML Over The Wire

      - Hotwireは、モダンなWebアプリをつくるための”もう一つの"アプローチです。JavaScriptを多用しません。"wire"を通じて、JSONの代わりにHTMLを送ります。ページの読み込み速度は早く、テンプレートの描画はサーバー上で行い、よりシンプルで生産的な開発体験を提供します。あらゆるプログラミング言語で動き、そして従来のシングルページ・アプリケーションで想定されるスピードやレスポンシブ性はそのままです。 + Hotwire は、モダンな Web アプリをつくるための”もう一つの"アプローチです。JavaScript を多用しません。"wire"を通じて、JSON の代わりに HTML を送ります。ページの読み込み速度は早く、テンプレートの描画はサーバー上で行い、よりシンプルで生産的な開発体験を提供します。あらゆるプログラミング言語で動き、そして従来のシングルページ・アプリケーションで想定されるスピードやレスポンシブ性はそのままです。
      From e2df2262c9b713be1b5d58d4b2b81e57f161d230 Mon Sep 17 00:00:00 2001 From: Yuki Torii Date: Fri, 11 Apr 2025 09:49:39 +0900 Subject: [PATCH 106/183] =?UTF-8?q?=E8=8B=B1=E5=8D=98=E8=AA=9E=E5=89=8D?= =?UTF-8?q?=E5=BE=8C=E3=81=AE=E3=82=B9=E3=83=9A=E3=83=BC=E3=82=B9=E9=96=8B?= =?UTF-8?q?=E3=81=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Akira Yagi --- index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.md b/index.md index dfa2c34a..cdaabb85 100644 --- a/index.md +++ b/index.md @@ -18,7 +18,7 @@ layout: "base.html"

      Turbo

      - Hotwireの中心となるのがTurboです。Turboは、ページの切り替えやフォームの送信を高速化し、複雑なページをコンポーネントに分割し、WebSocketを使って部分的なページ更新をストリーミングするための一連の、それぞれを補完しあう技術です。しかも、一切JavaScriptを書く必要がありません。 + Hotwire の中心となるのが Turbo です。Turbo は、ページの切り替えやフォームの送信を高速化し、複雑なページをコンポーネントに分割し、WebSocket を使って部分的なページ更新をストリーミングするための一連の、それぞれを補完しあう技術です。しかも、一切 JavaScript を書く必要がありません。
      • Handbook
      • From 651d0e49a2cd86503d18af494018b52302cdd5d6 Mon Sep 17 00:00:00 2001 From: Yuki Torii Date: Fri, 11 Apr 2025 09:50:44 +0900 Subject: [PATCH 107/183] =?UTF-8?q?=E8=8B=B1=E5=8D=98=E8=AA=9E=E5=89=8D?= =?UTF-8?q?=E5=BE=8C=E3=81=AE=E3=82=B9=E3=83=9A=E3=83=BC=E3=82=B9=E9=96=8B?= =?UTF-8?q?=E3=81=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.md b/index.md index cdaabb85..053df9fe 100644 --- a/index.md +++ b/index.md @@ -29,7 +29,7 @@ layout: "base.html"

        Stimulus

        - Turboは通常、従来ならJavaScriptが必要だったインタラクティブな動作の少なくとも80%を担ってくれますが、それでも少しだけカスタムコードが必要になる場面はあります。そんなときに役立つのがStimulusです。Stimulusは、HTMLを中心としたアプローチで状態管理やサーバーとの連携を簡単に実現します。 + Turbo は通常、従来なら JavaScript が必要だったインタラクティブな動作の少なくとも80%を担ってくれますが、それでも少しだけカスタムコードが必要になる場面はあります。そんなときに役立つのが Stimulus です。Stimulus は、HTML を中心としたアプローチで状態管理やサーバーとの連携を簡単に実現します。
        • Handbook
        • From c6ef1b103a0decf5953f1e7ad41a20016cfaf6da Mon Sep 17 00:00:00 2001 From: Akira Yagi Date: Fri, 25 Apr 2025 10:52:28 +0900 Subject: [PATCH 108/183] Update stimulus/reference/css_classes.md Co-authored-by: Yuki Torii --- stimulus/reference/css_classes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stimulus/reference/css_classes.md b/stimulus/reference/css_classes.md index 2f4caa8d..fefc2819 100644 --- a/stimulus/reference/css_classes.md +++ b/stimulus/reference/css_classes.md @@ -264,5 +264,5 @@ In HTML, write CSS class attributes in kebab-case: data-search-no-results-class="search--empty"> ``` -When constructing CSS class attributes, follow the conventions for identifiers as described in [Controllers: Naming Conventions](controllers#naming-conventions). +When constructing CSS class attributes, follow the conventions for identifiers as described in [Controllers: Naming Conventions](https://stimulus.hotwired.dev/reference/css-classes#naming-conventions).

    From 8aac042203efe3950eb443ee4fc7a750d952f373 Mon Sep 17 00:00:00 2001 From: Akira Yagi Date: Fri, 25 Apr 2025 10:52:55 +0900 Subject: [PATCH 109/183] Update stimulus/handbook/hello-stimulus.md Co-authored-by: Yuki Torii --- stimulus/handbook/hello-stimulus.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stimulus/handbook/hello-stimulus.md b/stimulus/handbook/hello-stimulus.md index 7d668157..5d7678d5 100644 --- a/stimulus/handbook/hello-stimulus.md +++ b/stimulus/handbook/hello-stimulus.md @@ -132,7 +132,7 @@ export default class extends Controller {
    ``` -識別子は要素とコントローラの間のリンクの役割を果たします。 この場合、識別子`hello`はStimulusにコントローラクラスのインスタンスを`hello_controller.js`に作成するよう指示します。 コントローラの自動ロードの仕組みについては、インストールガイドを参照してください。 +識別子は要素とコントローラの間のリンクの役割を果たします。 この場合、識別子`hello`はStimulusにコントローラクラスのインスタンスを`hello_controller.js`に作成するよう指示します。 コントローラの自動ロードの仕組みについては、インストールガイドを参照してください。
    原文 From d38e4b5a1ddcf396689efbc33ba49faa6fb36fc2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 26 Feb 2025 00:26:22 +0000 Subject: [PATCH 110/183] updated translation target commit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index ab638cd2..bd1aae62 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -2,7 +2,7 @@ title: "Turbo ドライブを使ったナビゲート" description: "Turbo ドライブは、ページ全体の再読み込みの必要を無くすことで、リンクとフォームの送信を高速化します。" order: 2 -commit: "c397c31" +commit: "8849e6b" --- # Turbo ドライブを使ったナビゲート From c5e5507d5e174b085a749e2300c28a602e1dfd65 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 1 Mar 2025 00:29:19 +0000 Subject: [PATCH 111/183] updated translation target commit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index bd1aae62..232ac2e9 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -2,7 +2,7 @@ title: "Turbo ドライブを使ったナビゲート" description: "Turbo ドライブは、ページ全体の再読み込みの必要を無くすことで、リンクとフォームの送信を高速化します。" order: 2 -commit: "8849e6b" +commit: "b2d93bd" --- # Turbo ドライブを使ったナビゲート From 82317a20f53813062b5ed3ad31fd311bdfa9d4ce Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 4 Mar 2025 00:26:48 +0000 Subject: [PATCH 112/183] updated translation target commit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 232ac2e9..f1393756 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -2,7 +2,7 @@ title: "Turbo ドライブを使ったナビゲート" description: "Turbo ドライブは、ページ全体の再読み込みの必要を無くすことで、リンクとフォームの送信を高速化します。" order: 2 -commit: "b2d93bd" +commit: "b8487ee" --- # Turbo ドライブを使ったナビゲート From 8f4d6d52044c7991bbdb6657d68e228c8ed6e9fd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 30 Mar 2025 00:30:39 +0000 Subject: [PATCH 113/183] updated translation target commit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index f1393756..a8dc23ea 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -2,7 +2,7 @@ title: "Turbo ドライブを使ったナビゲート" description: "Turbo ドライブは、ページ全体の再読み込みの必要を無くすことで、リンクとフォームの送信を高速化します。" order: 2 -commit: "b8487ee" +commit: "5731979" --- # Turbo ドライブを使ったナビゲート From 01fe0919715614f136e689d91ea3300cd7dae3bc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 8 Apr 2025 00:27:43 +0000 Subject: [PATCH 114/183] updated translation target commit --- turbo/handbook/drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index a8dc23ea..3a3d280c 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -2,7 +2,7 @@ title: "Turbo ドライブを使ったナビゲート" description: "Turbo ドライブは、ページ全体の再読み込みの必要を無くすことで、リンクとフォームの送信を高速化します。" order: 2 -commit: "5731979" +commit: "14aafc8" --- # Turbo ドライブを使ったナビゲート From a9096b4f7da3c467d87e159c05978560f4bb0efc Mon Sep 17 00:00:00 2001 From: n-hagiwara Date: Fri, 18 Apr 2025 10:03:26 +0900 Subject: [PATCH 115/183] =?UTF-8?q?14aafc8=20=E3=81=BE=E3=81=A7=E3=81=AE?= =?UTF-8?q?=E7=BF=BB=E8=A8=B3=E3=81=A8=E5=8E=9F=E6=96=87=E3=81=AE=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo/handbook/drive.md | 285 ++++++++++++++++++++++++++++++++-------- 1 file changed, 228 insertions(+), 57 deletions(-) diff --git a/turbo/handbook/drive.md b/turbo/handbook/drive.md index 3a3d280c..5f051e46 100644 --- a/turbo/handbook/drive.md +++ b/turbo/handbook/drive.md @@ -181,18 +181,18 @@ Restoration visits cannot be canceled and do not fire `turbo:before-visit`. Turb ドキュメント全体に対して `turbo:before-render` イベントリスナーを追加し、 `event.detail.render` プロパティを上書きすることで、アプリケーションの描画処理をカスタマイズできます。 -例えば、[morphdom]で、リクエストを投げたドキュメントの `` 要素を、レスポンスのドキュメントにある `` 要素にマージできます。 +例えば、[idiomorph]または[morphdom]で、リクエストを投げたドキュメントの `` 要素を、レスポンスのドキュメントにある `` 要素にマージできます。 ```javascript -import morphdom from "morphdom" +import { Idiomorph } from "idiomorph" addEventListener("turbo:before-render", (event) => { event.detail.render = (currentElement, newElement) => { - morphdom(currentElement, newElement) + Idiomorph.morph(currentElement, newElement) } }) ``` - +[idiomorph]: https://github.com/bigskysoftware/idiomorph [morphdom]: https://github.com/patrick-steele-idem/morphdom
    @@ -202,14 +202,14 @@ addEventListener("turbo:before-render", (event) => { Applications can customize the rendering process by adding a document-wide `turbo:before-render` event listener and overriding the `event.detail.render` property. -For example, you could merge the response document's `` element into the requesting document's `` element with [morphdom](https://github.com/patrick-steele-idem/morphdom): ++For example, you could merge the response document's `` element into the requesting document's `` element with [idiomorph](https://github.com/bigskysoftware/idiomorph) or [morphdom](https://github.com/patrick-steele-idem/morphdom): ```javascript -import morphdom from "morphdom" +import { Idiomorph } from "idiomorph" addEventListener("turbo:before-render", (event) => { event.detail.render = (currentElement, newElement) => { - morphdom(currentElement, newElement) + Idiomorph.morph(currentElement, newElement) } }) ``` @@ -305,9 +305,7 @@ document.addEventListener("turbo:before-fetch-request", async (event) => { 記事を削除する ``` -リンクは隠されたformに変換され、DOM内の `a` 要素の次の位置に配置されます。これは、リンクは別のフォームの中には配置できないということです。フォームをネストすることはできないからです。 - -アクセシビリティの観点からも、 GET 以外のリクエストには実際のフォームとボタンを使うのが望ましいでしょう。 +アクセシビリティの観点から、 GET 以外のリクエストには実際のフォームとボタンを使うのが望ましいでしょう。
    原文 @@ -320,36 +318,34 @@ By default, link clicks send a `GET` request to your server. But you can change Delete the article ``` -The link will get converted into a hidden form next to the `a` element in the DOM. This means that the link can't appear inside another form, as you can't have nested forms. - -You should also consider that for accessibility reasons, it's better to use actual forms and buttons for anything that's not a GET. +You should consider that for accessibility reasons, it's better to use actual forms and buttons for anything that's not a GET.
    ## アクセス前に確認ダイアログを表示する -リンクに `data-turbo-confirm` 属性を付けると、アクセス前に確認ダイアログが表示できます。 +リンクに `data-turbo-confirm`と`data-turbo-method`両方の属性を付けると、アクセス前に確認ダイアログが表示できます。 ```html 記事に戻る 記事を削除する ``` -確認時に呼ぶメソッドは `Turbo.setConfirmMethod` を使って、変更できます。確認時に呼ぶメソッドのデフォルトは、ブラウザに組み込まれている `confirm` です。 +確認時に呼ぶメソッドは `Turbo.config.forms.confirm = confirmMethod` を使って、変更できます。確認時に呼ぶメソッドのデフォルトは、ブラウザに組み込まれている `confirm` です。
    原文 ## Requiring Confirmation for a Visit -Decorate links with `data-turbo-confirm`, and confirmation will be required for a visit to proceed. +Decorate links with both `data-turbo-confirm` and `data-turbo-method`, and confirmation will be required for a visit to proceed. ```html -Back to articles +Back to articles Delete the article ``` -Use `Turbo.setConfirmMethod` to change the method that gets called for confirmation. The default is the browser's built in `confirm`. +Use `Turbo.config.forms.confirm = confirmMethod` to change the method that gets called for confirmation. The default is the browser's built in `confirm`.
    @@ -361,13 +357,13 @@ Use `Turbo.setConfirmMethod` to change the method that gets called for confirmat 無効化 - ... +
    無効化
    - ... +
    ``` @@ -403,12 +399,12 @@ Turbo Drive can be disabled on a per-element basis by annotating the element or ```html Disabled
    - ... +
    Disabled
    - ... +
    ``` @@ -559,7 +555,7 @@ In tandem with the progress bar, Turbo Drive will also toggle the [`[aria-busy]` ```html - ... + @@ -576,7 +572,7 @@ To accomplish this, just annotate those asset elements with `data-turbo-track="r ```html - ... + @@ -584,6 +580,47 @@ To accomplish this, just annotate those asset elements with `data-turbo-track="r
    +## 変更時のアセットの削除 + +前述した通り、Turbo ドライブは `` 要素のコンテントをマージします。 +ページが他のページにはないCSSスタイルシートのような外部アセットに依存している場合、ページから離れるときにそれらの外部アセットを削除すると便利です。 + +`` 要素または ` + +``` + +
    +原文 + +## Removing Assets When They Change + +As we saw above, Turbo Drive merges the contents of the `` elements. When a page depends on external assets like CSS stylesheets that other pages do not, it can be useful to remove them when navigating away from the page. + +Rendering a `` or ` + +``` + +Note that rendering `