diff --git a/3-frames-and-windows/01-popup-windows/article.md b/3-frames-and-windows/01-popup-windows/article.md index c372856a83..1d16e32afb 100644 --- a/3-frames-and-windows/01-popup-windows/article.md +++ b/3-frames-and-windows/01-popup-windows/article.md @@ -9,45 +9,36 @@ window.open('http://javascript.info/') ... すると、指定された URL で新しいウィンドウが開きます。ほとんどのモダンブラウザは、別ウィンドウではなく新しいタブとして開くよう設定されています。 -## ポップアップブロック +ポップアップはとても古くから存在します。当初の考えは、メインのウィンドウを閉じることなく別のコンテンツを表示することでした。現時点では、それをするための他の方法があります: [fetch](info:fetch) を使うことでコンテンツを動的に読み込むことができ、それを動的に生成された `
` の中で表示することができます。ですから、ポップアップは私達が普段使用するものではありません。 -ポップアップはとても古くから存在します。当初の考えは、メインのウィンドウを閉じることなく別のコンテンツを表示することでした。現時点では、それをするための他の方法があります: JavaScript はサーバへリクエストを送ることができるので、ポップアップはめったに使われません。しかし、それでも依然として便利なときはあります。 +さらにポップアップは、複数のウィンドウを同時には表示しないモバイルデバイスでは手際を要します。 -過去、悪意のあるサイトはポップアップを大いに乱用しました。悪意のあるページは広告を含むウィンドウを何度も開く事ができました。そのため、現在多くのブラウザはポップアップをブロックし、ユーザを守ろうとしています。 +それでも、ポップアップがいまだに使われるタスクが存在します。例えば OAuth 認証(Google や Facebook などへのログイン)。なぜなら: -**ほとんどのブラウザは、`onclick` などユーザがトリガーしたイベントハンドラ外から呼ばれた場合には、ポップアップをブロックします。** +1. ポップアップは独立した JavaScript 環境を持つウィンドウです。ですから、第三者の信頼されていないサイトから開くポップアップは安全です。 +2. ポップアップを開くことは非常に簡単です。 +3. ポップアップはナビゲート(URLの変更)可能で、ポップアップを開いたウィンドウにメッセージを送ることができます。 -これについて考える場合、少し注意が必要です。もしコードが直接 `onclick` 内にあればそれは簡単です。しかし、ポップアップは `setTimeout` で開くでしょうか? +## ポップアップブロック -このコードを試してみましょう: +過去、悪意のあるサイトはポップアップを大いに乱用しました。悪意のあるページは広告を含むウィンドウを何度も開く事ができました。そのため、現在多くのブラウザはポップアップをブロックし、ユーザを守ろうとしています。 -```js run -// 3秒後に開く -setTimeout(() => window.open('http://google.com'), 3000); -``` +**ほとんどのブラウザは、`onclick` などユーザがトリガーしたイベントハンドラ外から呼ばれた場合には、ポップアップをブロックします。** -Chrome ではポップアップは開きますが、Firefox ではブロックされます。 +これについて考える場合、少し注意が必要です。もしコードが直接 `onclick` 内にあればそれは簡単です。しかし、ポップアップは `setTimeout` で開くでしょうか? -...そして、これは Firefox でも機能します。: +例えば: +```js +// ポップアップはブロックされます +window.open('https://javascript.info'); -```js run -// 1秒後に開く -setTimeout(() => window.open('http://google.com'), 1000); +// ポップアップは許可されます +button.onclick = () => { + window.open('https://javascript.info'); +}; ``` -違いは、Firefox は 2000ms 以下のタイムアウトは許容することです。しかし、その後は "信頼" がなくなり、"ユーザ操作の範囲外" であると想定します。そのため、最初のはブロックされ、2つ目は開きました。 - -## モダンな使用方法 - -現在、JavaScriptを使用してデータをロードし、ページ上に表示する方法は数多くあります。しかし、ポップアップがベストな選択肢である状況はまだあります。 - -例えば、多くのお店は相談にのる方法としてオンラインチャットを使います。訪問者がボタンを押すと、`window.open` が実行され、チャットをするポップアップが開きます。 - -なぜ、ここではページ内ではなくポップアップが良いのでしょう? - -1. ポップアップは独立した JavaScript 環境を持つ別ウィンドウです。なので、チャットサービスはメインの店舗サイトのスクリプトと統合する必要がありません。 -2. ポップアップはサイトに追加するのが非常に簡単で、オーバーヘッドがほとんどありません。スクリプトの追加は不要で小さいボタンだけです。 -3. ポップアップは利用者がページを離れても持続させることができます。例えば、相談で利用者に新しい "スーパークーラー" のページを訪れるようにアドバイスします。利用者はメインウィンドウでそのページへ行きますが、チャットは無くなりません。 +このように、ユーザは望まないポップアップからある程度は守られていますが、その機能は完全には無効にされていません。 ## window.open @@ -76,9 +67,9 @@ params - `scrollbars` (yes/no) -- 新しいウィンドウのスクロールバーを無効にします。非推奨です。 -あまりサポートされていないブラウザ固有の機能も数多くありますが、通常は使用されていません。例については、window.open in MDN を確認してみてください。 +あまりサポートされていないブラウザ固有の機能も数多くありますが、通常は使用されていません。例については、MDN の window.open を確認してみてください。 -## 例: a minimalistic window +## 例: 最小限のウィンドウ ブラウザがどの機能の無効化を許容するか、最小セットの機能でウィンドウを開いてみましょう。: @@ -91,7 +82,7 @@ open('/', 'test', params); ここでは、ほとんどの "ウィンドウの機能 は無効にされ、ウィンドウは画面外に配置されています。実行して実際に何が起きるのかを見てください。ほとんどのブラウザはゼロ値の `width/height` や画面外の `left/top` といったおかしなものを "直します"。例えば、Chrome はフルスクリーンになるよう、画面幅/高さでウィンドウを開きます。 -通常の配置オプションで `width`, `height`, `left`, `top` 座標を追加追加しましょう。: +通常の配置オプションと妥当な `width`, `height`, `left`, `top` 座標を追加しましょう。: ```js run let params = `scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no, @@ -105,20 +96,30 @@ open('/', 'test', params); 設定が省略された際のルール: - `open` 呼び出しで 3つ目の引数がない場合、もしくはそれが空の場合、デフォルトのウィンドウパラメータが使われます。 -- params の文字列はあるが、一部の機能の yes/no が省略されている場合、省略された機能はブラウザで許可されていれば無効になります。そのため、params を指定した場合には、明示的に必要なすべての機能に yes を設定してください。 +- params の文字列はあるが、一部の機能の yes/no が省略されている場合、省略された機能はブラウザで許可されていれば無効になります。そのため、params を指定する場合には、明示的に必要なすべての機能に yes を設定してください。 - params に `left/top` がない場合、ブラウザは最後に開いたウィンドウの近くに新しいウィンドウを開こうとします。 - `width/height` がない場合、新しいウィンドウは最後に開いたウィンドウと同じサイズになります。 ## ポップアップにアクセスする -`open` 呼び出しは、新しいウィンドウへの参照を返します。それはプロパティを操作したり、位置を替えたりと言ったことをするのに利用できます。 +`open` 呼び出しは、新しいウィンドウへの参照を返します。それはプロパティを操作したり、位置を変えたりといったことをするのに利用できます。 + +この例では、ポップアップの内容を JavaScript で生成します: + +```js +let newWin = window.open("about:blank", "hello", "width=200,height=200"); + +newWin.document.write("Hello, world!"); +``` -下の例では、新しいウィンドウのコンテンツはロード後に変更されます。 +またこちらでは、コンテンツをロード後に変更します: ```js run let newWindow = open('/', 'example', 'width=300,height=300') newWindow.focus(); +alert(newWindow.location.href); // (*) about:blank, 読み込みはまだ始まっていません + newWindow.onload = function() { let html = `
Welcome!
`; *!* @@ -127,63 +128,132 @@ newWindow.onload = function() { }; ``` -外部の `document` コンテンツは、同じオリジン(同じ protocol://domain:port) からのウィンドウに対してのみアクセス可能であることに注意してください。 +注意してください: `window.open` の直後は、新しいウィンドウはまだ読み込まれていません。これは `(*)` の行にある `alert` で示されています。ですから、変更するために `onload` を待っています。 `newWin.document` 用に `DOMContentLoaded` ハンドラを使うこともできます。 -別のサイトの URL を持つウィンドウの場合、`newWindow.location=...` による割り当てでロケーションを変更することができますが、そのロケーションやコンテンツにアクセスすることはできます。これはユーザの安全のためであり、悪意のあるページが `http://gmail.com` のポップアップを開いてもデータを読む事ができないようにするためです。後ほど詳しく話します。 +```warn header="同一生成元ポリシー" +ウィンドウは、同じ元(同じプロトコル://ドメイン:ポート)から生成された場合のみ、互いのコンテンツに自由にアクセスすることができます。 + +そうでなければ、例えばメインウィンドウが `site.com` から生成され、ポップアップが `gmail.com` から生成された場合、ユーザの安全性のため不可能となります。詳しくは、 の章を確認してください。 +``` ## 開いた元(opener)のウィンドウにアクセスする -ポップアップは "opener" ウィンドウにもアクセスすることができます。その中で、それを開いたウィンドウにアクセスするには `window.opener` を使います。ポップアップ以外のすべてのウィンドウの場合、それは `null` です。 +ポップアップは `window.opener` 参照を用いることでも "opener" ウィンドウにアクセスできます。ポップアップ以外のすべてのウィンドウの場合、それは `null` です。 + +以下のコードを実行すると、 opener ウィンドウ(現在のウィンドウ)の内容が "Test" に置き換わります: + +```js run +let newWin = window.open("about:blank", "hello", "width=200,height=200"); + +newWin.document.write( + "