forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tab_modal_dialog_manager.h
202 lines (165 loc) · 8.63 KB
/
tab_modal_dialog_manager.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_JAVASCRIPT_DIALOGS_TAB_MODAL_DIALOG_MANAGER_H_
#define COMPONENTS_JAVASCRIPT_DIALOGS_TAB_MODAL_DIALOG_MANAGER_H_
#include <memory>
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "build/build_config.h"
#include "components/javascript_dialogs/tab_modal_dialog_manager_delegate.h"
#include "components/javascript_dialogs/tab_modal_dialog_view.h"
#include "content/public/browser/javascript_dialog_manager.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
namespace javascript_dialogs {
// A class that serves as the JavaScriptDialogManager for tab modal JavaScript
// dialogs.
//
// This implements two different functionalities for JavaScript dialogs.
//
// window.alert() dialogs are tab-modal dialogs. If a tab calls alert() while it
// is foremost, a dialog is displayed and the renderer is held blocked. When the
// user switches to a different tab, or if the dialog is shown while the tab is
// not foremost, while the dialog is shown, the renderer is not held blocked.
//
// window.confirm() and window.prompt() dialogs are auto-dismissing,
// dialogs that close when the user switches away to a different tab. Because
// JavaScript dialogs are synchronous and block arbitrary sets of renderers,
// they cannot be made tab-modal. Therefore the next best option is to make them
// auto-closing, so that they never block the user's access to other renderers.
//
// References:
// http://bit.ly/project-oldspice
class TabModalDialogManager
: public content::JavaScriptDialogManager,
public content::WebContentsObserver,
public content::WebContentsUserData<TabModalDialogManager> {
public:
enum class DismissalCause {
// This is used for a UMA histogram. Please never alter existing values,
// only append new ones.
// The tab helper is destroyed. By current design, the dialog is always torn
// down before the tab helper is destroyed, so we never see the
// |kTabHelperDestroyed| enum. However, that might not always be the case.
// It's better to have a simple rule in the code of "when you close a dialog
// you must provide a UMA enum reason why" and have some enums that never
// happen than have haphazard code that enforces no rules.
kTabHelperDestroyed = 0,
// Subsequent dialog pops up.
kSubsequentDialogShown = 1,
// HandleJavaScriptDialog() is called. In practice, this can happen whenever
// browser choose to accept/cancel the dialog without user's interaction.
kHandleDialogCalled = 2,
// CancelDialogs() is called. In practice, this can happen whenever browser
// choose to close the dialog without user's interaction. Besides, this can
// also happen when tab is closed by user on a Mac platform.
kCancelDialogsCalled = 3,
// Tab is made hidden by opening a new tab, switching to another tab, etc.
// Note that only Prompt() and Confirm() can be dismissed for this cause;
// it won't affect Alert().
kTabHidden = 4,
// Another browser instance is made active.
kBrowserSwitched = 5,
// Accept/Cancel button is clicked by user.
kDialogButtonClicked = 6,
// Navigation occurs.
kTabNavigated = 7,
// Tab's contents was replaced.
kTabSwitchedOut = 8,
// CloseDialog() is called. In practice, this happens when tab is closed by
// user on a non-Mac platform.
kDialogClosed = 9,
kMaxValue = kDialogClosed,
};
~TabModalDialogManager() override;
void BrowserActiveStateChanged();
void CloseDialogWithReason(DismissalCause reason);
void SetDialogShownCallbackForTesting(base::OnceClosure callback);
bool IsShowingDialogForTesting() const;
void ClickDialogButtonForTesting(bool accept,
const base::string16& user_input);
using DialogDismissedCallback = base::OnceCallback<void(DismissalCause)>;
void SetDialogDismissedCallbackForTesting(DialogDismissedCallback callback);
// JavaScriptDialogManager:
void RunJavaScriptDialog(content::WebContents* web_contents,
content::RenderFrameHost* render_frame_host,
content::JavaScriptDialogType dialog_type,
const base::string16& message_text,
const base::string16& default_prompt_text,
DialogClosedCallback callback,
bool* did_suppress_message) override;
void RunBeforeUnloadDialog(content::WebContents* web_contents,
content::RenderFrameHost* render_frame_host,
bool is_reload,
DialogClosedCallback callback) override;
bool HandleJavaScriptDialog(content::WebContents* web_contents,
bool accept,
const base::string16* prompt_override) override;
void CancelDialogs(content::WebContents* web_contents,
bool reset_state) override;
// WebContentsObserver:
void OnVisibilityChanged(content::Visibility visibility) override;
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override;
private:
friend class content::WebContentsUserData<TabModalDialogManager>;
TabModalDialogManager(
content::WebContents* web_contents,
std::unique_ptr<TabModalDialogManagerDelegate> delegate);
// Logs the cause of a dialog dismissal in UMA.
void LogDialogDismissalCause(DismissalCause cause);
// Handles the case when the user switches away from a tab.
void HandleTabSwitchAway(DismissalCause cause);
// This closes any open dialog. It is safe to call if there is no currently
// open dialog.
void CloseDialog(DismissalCause cause,
bool success,
const base::string16& user_input);
// There can be at most one dialog (pending or not) being shown at any given
// time on a tab. Depending on the type of the dialog, the variables
// |dialog_|, |pending_dialog_|, and |dialog_callback_| can be present in
// different combinations.
//
// No dialog:
// |dialog_|, |pending_dialog_|, and |dialog_callback_| are null.
// alert() dialog:
// Either |dialog_| or |pending_dialog_| is not null. If the dialog is shown
// while the tab was foremost, the dialog is be created and a weak pointer
// to it is held in |dialog_|. If the dialog is attempted while the tab
// is not foremost, the call to create the dialog-to-be is held in
// |pending_dialog_| until the tab is brought foremost. At that time the
// callback will be made, |pending_dialog_| will be null, and the dialog
// will live, referenced by |dialog_|. As for |dialog_callback_|, if the
// dialog is shown while the tab was foremost, |dialog_callback_| is not
// null. If the dialog was shown while the tab was not foremost, or if the
// tab was switched to be non-foremost, the renderer is not held blocked,
// and |dialog_callback_| will be null (because it will have been called to
// free up the renderer.)
// confirm() and prompt() dialogs:
// Both |dialog_| and |dialog_callback_| are not null. |pending_dialog_| is
// null, as only alert() dialogs can be in a pending state.
// The dialog being displayed on the observed WebContents, if any. At any
// given time at most one of |dialog_| and |pending_dialog_| can be non-null.
base::WeakPtr<TabModalDialogView> dialog_;
base::OnceCallback<base::WeakPtr<TabModalDialogView>()> pending_dialog_;
// The callback to return a result for a dialog. Not null if the renderer is
// waiting for a result; null if there is no |dialog_| or if the dialog is an
// alert() dialog and the callback has already been called.
content::JavaScriptDialogManager::DialogClosedCallback dialog_callback_;
// The type of dialog being displayed. Only valid when |dialog_| or
// |pending_dialog_| is non-null.
content::JavaScriptDialogType dialog_type_ =
content::JavaScriptDialogType::JAVASCRIPT_DIALOG_TYPE_ALERT;
// A closure to be fired when a dialog is shown. For testing only.
base::OnceClosure dialog_shown_;
// A closure to be fired when a dialog is dismissed. For testing only.
DialogDismissedCallback dialog_dismissed_;
std::unique_ptr<TabModalDialogManagerDelegate> delegate_;
WEB_CONTENTS_USER_DATA_KEY_DECL();
DISALLOW_COPY_AND_ASSIGN(TabModalDialogManager);
};
} // namespace javascript_dialogs
#endif // COMPONENTS_JAVASCRIPT_DIALOGS_TAB_MODAL_DIALOG_MANAGER_H_