Commit f42152de authored by Leonard Grey's avatar Leonard Grey Committed by Commit Bot

Commander WebUI scaffolding

No actual WebUI code added yet; this is just the layer that sets
everything up and handles communication.

Bug: 1014639
Change-Id: Ie121d6c02d4d92b84eb24d3412291f93b40de09f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2380670Reviewed-by: default avatardpapad <dpapad@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Commit-Queue: Leonard Grey <lgrey@chromium.org>
Cr-Commit-Position: refs/heads/master@{#807610}
parent 579eac05
......@@ -53,6 +53,7 @@
</structures>
<includes>
<if expr="is_win or is_macosx or desktop_linux or chromeos">
<include name="IDR_COMMANDER_HTML" file="resources\commander\commander.html" type="BINDATA" />
<include name="IDR_DISCARDS_MOJO_API_JS" file="resources\discards\mojo_api.js" type="BINDATA" />
<include name="IDR_DISCARDS_DATABASE_TAB_JS" file="${root_gen_dir}\chrome\browser\resources\discards\database_tab.js" use_base_dir="false" type="BINDATA" />
<include name="IDR_DISCARDS_DISCARDS_MAIN_JS" file="${root_gen_dir}\chrome\browser\resources\discards\discards_main.js" use_base_dir="false" type="BINDATA" />
......
lgrey@chromium.org
ellyjones@chromium.org
# COMPONENT: UI>Browser
<!doctype html>
<html dir="$i18n{textdirection}">
<head>
<meta charset="utf-8">
</head>
<body>
Hello, commander!
</body>
</html>
......@@ -1304,6 +1304,10 @@ static_library("ui") {
"webui/bookmarks/bookmarks_ui.h",
"webui/chrome_web_contents_handler.cc",
"webui/chrome_web_contents_handler.h",
"webui/commander/commander_handler.cc",
"webui/commander/commander_handler.h",
"webui/commander/commander_ui.cc",
"webui/commander/commander_ui.h",
"webui/customize_themes/chrome_customize_themes_handler.cc",
"webui/customize_themes/chrome_customize_themes_handler.h",
"webui/devtools_ui.cc",
......
......@@ -11,13 +11,13 @@
#include "chrome/browser/ui/commander/commander_view_model.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/theme_copying_widget.h"
#include "chrome/browser/ui/webui/commander/commander_ui.h"
#include "chrome/common/webui_url_constants.h"
#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "base/debug/stack_trace.h"
namespace {
// TODO(lgrey): Temporary
constexpr gfx::Size kDefaultSize(400, 30);
......@@ -98,6 +98,11 @@ void CommanderFrontendViews::Show(Browser* browser) {
web_view_->set_owner(parent);
web_view_->SetSize(kDefaultSize);
web_view_->LoadInitialURL(GURL(chrome::kChromeUICommanderURL));
CommanderUI* controller = static_cast<CommanderUI*>(
web_view_->GetWebContents()->GetWebUI()->GetController());
controller->handler()->set_delegate(this);
web_view_ptr_ = widget_->SetContentsView(std::move(web_view_));
widget_->CenterWindow(kDefaultSize);
......@@ -145,6 +150,10 @@ void CommanderFrontendViews::OnHeightChanged(int new_height) {
web_view_ptr_->SetSize(size);
}
void CommanderFrontendViews::OnHandlerEnabled(bool is_enabled) {
is_handler_enabled_ = is_enabled;
}
void CommanderFrontendViews::OnViewModelUpdated(
commander::CommanderViewModel view_model) {
DCHECK(is_showing());
......@@ -152,6 +161,13 @@ void CommanderFrontendViews::OnViewModelUpdated(
Hide();
return;
}
if (!is_handler_enabled_)
// TODO(lgrey): Think through whether it makes sense to stash the view model
// and send it when the handler becomes available again.
return;
CommanderUI* controller = static_cast<CommanderUI*>(
web_view_->GetWebContents()->GetWebUI()->GetController());
controller->handler()->ViewModelUpdated(std::move(view_model));
// TODO(lgrey): Pass view model to WebUI.
}
......
......@@ -11,6 +11,7 @@
#include "base/memory/weak_ptr.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/webui/commander/commander_handler.h"
class CommanderWebView;
......@@ -28,7 +29,8 @@ struct CommanderViewModel;
// this class is responsible for setting up the infrastructure to host the
// WebUI in its own widget and mediating between the WebUI implementation and
// the controller.
class CommanderFrontendViews : public commander::CommanderFrontend {
class CommanderFrontendViews : public commander::CommanderFrontend,
public CommanderHandler::Delegate {
public:
explicit CommanderFrontendViews(commander::CommanderBackend* backend);
~CommanderFrontendViews() override;
......@@ -37,17 +39,12 @@ class CommanderFrontendViews : public commander::CommanderFrontend {
void Show(Browser* browser) override;
void Hide() override;
// TODO(lgrey): When the WebUI layer is added, these declarations should
// be moved to the CommanderHandler::Delegate interface.
// Called when the text is changed in the WebUI interface.
void OnTextChanged(const base::string16& text);
// Called when an option is selected (clicked or enter pressed) in the WebUI
// interface.
void OnOptionSelected(size_t option_index, int result_set_id);
// Called when the WebUI interface wants to dismiss the UI.
void OnDismiss();
// Called when the WebUI interface's content height has changed.
void OnHeightChanged(int new_height);
// CommanderHandler::Delegate overrides;
void OnTextChanged(const base::string16& text) override;
void OnOptionSelected(size_t option_index, int result_set_id) override;
void OnDismiss() override;
void OnHeightChanged(int new_height) override;
void OnHandlerEnabled(bool is_enabled) override;
private:
// Receives view model updates from |backend_|.
......@@ -83,7 +80,8 @@ class CommanderFrontendViews : public commander::CommanderFrontend {
std::unique_ptr<CommanderWebView> web_view_;
// The browser |widget_| is attached to.
Browser* browser_;
// Whether the web UI interface is loaded and ready to accept view models.
bool is_handler_enabled_ = false;
base::WeakPtrFactory<CommanderFrontendViews> weak_ptr_factory_{this};
};
......
......@@ -34,6 +34,7 @@
#include "chrome/browser/ui/webui/chromeos/account_manager/account_migration_welcome_ui.h"
#include "chrome/browser/ui/webui/chromeos/chrome_url_disabled/chrome_url_disabled_ui.h"
#include "chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.h"
#include "chrome/browser/ui/webui/commander/commander_ui.h"
#include "chrome/browser/ui/webui/components/components_ui.h"
#include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
#include "chrome/browser/ui/webui/crashes_ui.h"
......@@ -557,6 +558,8 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
// Bookmarks are part of NTP on Android.
if (url.host_piece() == chrome::kChromeUIBookmarksHost)
return &NewWebUI<BookmarksUI>;
if (url.host_piece() == chrome::kChromeUICommanderHost)
return &NewWebUI<CommanderUI>;
// Downloads list on Android uses the built-in download manager.
if (url.host_piece() == chrome::kChromeUIDownloadsHost)
return &NewWebUI<DownloadsUI>;
......
// Copyright 2020 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.
#include "chrome/browser/ui/webui/commander/commander_handler.h"
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/commander/commander_view_model.h"
const char CommanderHandler::Delegate::kKey[] =
"CommanderHandler::Delegate::kKey";
CommanderHandler::CommanderHandler() = default;
CommanderHandler::~CommanderHandler() = default;
void CommanderHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback(
"textChanged", base::BindRepeating(&CommanderHandler::HandleTextChanged,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"optionSelected",
base::BindRepeating(&CommanderHandler::HandleOptionSelected,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"dismiss", base::BindRepeating(&CommanderHandler::HandleDismiss,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"heightChanged",
base::BindRepeating(&CommanderHandler::HandleHeightChanged,
base::Unretained(this)));
}
void CommanderHandler::OnJavascriptDisallowed() {
if (delegate_)
delegate_->OnHandlerEnabled(false);
}
void CommanderHandler::OnJavascriptAllowed() {
if (delegate_)
delegate_->OnHandlerEnabled(true);
}
void CommanderHandler::HandleTextChanged(const base::ListValue* args) {
AllowJavascript();
CHECK_EQ(1u, args->GetSize());
std::string text = args->GetList()[0].GetString();
if (delegate_)
delegate_->OnTextChanged(base::UTF8ToUTF16(text));
}
void CommanderHandler::HandleOptionSelected(const base::ListValue* args) {
AllowJavascript();
CHECK_EQ(2u, args->GetSize());
int index = args->GetList()[0].GetInt();
int result_set_id = args->GetList()[1].GetInt();
if (delegate_)
delegate_->OnOptionSelected(index, result_set_id);
}
void CommanderHandler::HandleDismiss(const base::ListValue* args) {
if (delegate_)
delegate_->OnDismiss();
}
void CommanderHandler::HandleHeightChanged(const base::ListValue* args) {
CHECK_EQ(1u, args->GetSize());
int new_height = args->GetList()[0].GetInt();
if (delegate_)
delegate_->OnHeightChanged(new_height);
}
void CommanderHandler::ViewModelUpdated(
commander::CommanderViewModel view_model) {
if (view_model.action ==
commander::CommanderViewModel::Action::kDisplayResults) {
base::Value list(base::Value::Type::LIST);
for (commander::CommandItemViewModel& item : view_model.items) {
// TODO(lgrey): This is temporary, just so we can display something.
// We will also need to pass on the result set id, and match ranges for
// each item.
list.Append(item.title);
}
FireWebUIListener("view-model-updated", list);
} else {
DCHECK_EQ(view_model.action,
commander::CommanderViewModel::Action::kPrompt);
// TODO(lgrey): Handle kPrompt. kDismiss is handled higher up the stack.
}
}
// Copyright 2020 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 CHROME_BROWSER_UI_WEBUI_COMMANDER_COMMANDER_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_COMMANDER_COMMANDER_HANDLER_H_
#include "chrome/browser/ui/commander/commander_view_model.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_message_handler.h"
// Handles serializing and unserializing communication between the commander
// backend and WebUI interface.
class CommanderHandler : public content::WebUIMessageHandler {
public:
// The delegate allows CommanderHandler to send messages up to the
// browser-side commander system.
class Delegate {
public:
// The key under which the delegate is expected to be stashed in the
// containing web contents.
static const char kKey[];
// Called when the text is changed in the WebUI interface.
virtual void OnTextChanged(const base::string16& text) = 0;
// Called when an option is selected (clicked or enter pressed) in the WebUI
// interface.
virtual void OnOptionSelected(size_t option_index, int result_set_id) = 0;
// Called when the WebUI interface wants to dismiss the UI.
virtual void OnDismiss() = 0;
// Called when the WebUI interface's content height has changed.
virtual void OnHeightChanged(int new_height) = 0;
// Called when the web interface's availability changes (for example, if
// the renderer crashes, this should be called with false).
virtual void OnHandlerEnabled(bool is_enabled) = 0;
};
CommanderHandler();
~CommanderHandler() override;
// Called when a new view model should be displayed.
void ViewModelUpdated(commander::CommanderViewModel view_model);
void set_delegate(Delegate* delegate) { delegate_ = delegate; }
// WebUIMessageHandler overrides.
void RegisterMessages() override;
void OnJavascriptAllowed() override;
void OnJavascriptDisallowed() override;
private:
// WebUI message handlers
// Handles text changes in the primary textfield. Expects a single string
// argument.
void HandleTextChanged(const base::ListValue* args);
// Handles the user selecting one of the available command options.
// Expects two numeric argument representing the index of the chosen command,
// and the result set id of the active view model (see documentation in
// commander::CommanderViewModel).
void HandleOptionSelected(const base::ListValue* args);
// Handles the user pressing "Escape", or otherwise indicating they would
// like to dismiss the UI. No arguments expected.
void HandleDismiss(const base::ListValue* args);
// Handles the display height of the UI changing. Expects one numeric argument
// representing the new height.
void HandleHeightChanged(const base::ListValue* args);
Delegate* delegate_ = nullptr;
};
#endif // CHROME_BROWSER_UI_WEBUI_COMMANDER_COMMANDER_HANDLER_H_
// Copyright 2020 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.
#include "chrome/browser/ui/webui/commander/commander_ui.h"
#include <memory>
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/commander/commander_handler.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/grit/browser_resources.h"
#include "content/public/browser/web_ui_data_source.h"
CommanderUI::CommanderUI(content::WebUI* web_ui)
: content::WebUIController(web_ui) {
auto handler = std::make_unique<CommanderHandler>();
handler_ = handler.get();
web_ui->AddMessageHandler(std::move(handler));
content::WebUIDataSource* source =
content::WebUIDataSource::Create(chrome::kChromeUICommanderHost);
source->AddResourcePath("index.html", IDR_COMMANDER_HTML);
source->SetDefaultResource(IDR_COMMANDER_HTML);
Profile* profile = Profile::FromWebUI(web_ui);
content::WebUIDataSource::Add(profile, source);
}
CommanderUI::~CommanderUI() = default;
// Copyright 2020 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 CHROME_BROWSER_UI_WEBUI_COMMANDER_COMMANDER_UI_H_
#define CHROME_BROWSER_UI_WEBUI_COMMANDER_COMMANDER_UI_H_
#include "content/public/browser/web_ui_controller.h"
class CommanderHandler;
// Entry point for the Commander WebUI interface.
class CommanderUI : public content::WebUIController {
public:
explicit CommanderUI(content::WebUI* web_ui);
~CommanderUI() override;
// Disallow copy and assign
CommanderUI(const CommanderUI& other) = delete;
CommanderUI& operator=(const CommanderUI& other) = delete;
CommanderHandler* handler() { return handler_; }
private:
CommanderHandler* handler_;
};
#endif // CHROME_BROWSER_UI_WEBUI_COMMANDER_COMMANDER_UI_H_
// Copyright 2020 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.
#include "chrome/browser/ui/webui/commander/commander_ui.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/commander/commander_view_model.h"
#include "chrome/browser/ui/webui/commander/commander_handler.h"
#include "chrome/common/chrome_isolated_world_ids.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_web_ui.h"
namespace {
class TestCommanderHandler : public CommanderHandler {
public:
explicit TestCommanderHandler(content::WebUI* web_ui) { set_web_ui(web_ui); }
};
} // namespace
// This actually tests the whole WebUI communication layer as a unit:
// CommanderUI and CommanderHandler.
class CommanderUITest : public InProcessBrowserTest,
public CommanderHandler::Delegate {
public:
void SetUpOnMainThread() override {
contents_ = content::WebContents::Create(
content::WebContents::CreateParams(browser()->profile()));
contents_->GetController().LoadURL(
GURL(chrome::kChromeUICommanderURL), content::Referrer(),
ui::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
CommanderUI* controller =
static_cast<CommanderUI*>(contents_->GetWebUI()->GetController());
controller->handler()->set_delegate(this);
ASSERT_TRUE(content::WaitForLoadStop(contents_.get()));
EXPECT_EQ(contents_->GetLastCommittedURL().host(),
chrome::kChromeUICommanderHost);
}
void TearDownOnMainThread() override {
contents_.reset();
dismiss_invocation_count_ = 0;
text_changed_invocations_.clear();
option_selected_invocations_.clear();
height_changed_invocations_.clear();
}
protected:
void ExecuteJS(std::string js) {
ASSERT_TRUE(content::ExecuteScript(contents_.get(), js));
}
// CommanderHandler::Delegate implementation.
void OnTextChanged(const base::string16& text) override {
text_changed_invocations_.push_back(text);
}
void OnOptionSelected(size_t option_index, int result_set_id) override {
option_selected_invocations_.emplace_back(option_index, result_set_id);
}
void OnDismiss() override { dismiss_invocation_count_++; }
void OnHeightChanged(int new_height) override {
height_changed_invocations_.emplace_back(new_height);
}
void OnHandlerEnabled(bool enabled) override {}
const std::vector<base::string16> text_changed_invocations() {
return text_changed_invocations_;
}
const std::vector<std::pair<size_t, int>> option_selected_invocations() {
return option_selected_invocations_;
}
const std::vector<int> height_changed_invocations() {
return height_changed_invocations_;
}
size_t dismiss_invocation_count() { return dismiss_invocation_count_; }
private:
std::unique_ptr<content::WebContents> contents_;
size_t dismiss_invocation_count_ = 0;
std::vector<base::string16> text_changed_invocations_;
std::vector<std::pair<size_t, int>> option_selected_invocations_;
std::vector<int> height_changed_invocations_;
};
IN_PROC_BROWSER_TEST_F(CommanderUITest, Dismiss) {
EXPECT_EQ(dismiss_invocation_count(), 0u);
ExecuteJS("chrome.send('dismiss')");
EXPECT_EQ(dismiss_invocation_count(), 1u);
}
IN_PROC_BROWSER_TEST_F(CommanderUITest, HeightChanged) {
EXPECT_EQ(height_changed_invocations().size(), 0u);
ExecuteJS("chrome.send('heightChanged', [42])");
ASSERT_EQ(height_changed_invocations().size(), 1u);
ASSERT_EQ(height_changed_invocations().back(), 42);
}
IN_PROC_BROWSER_TEST_F(CommanderUITest, TextChanged) {
EXPECT_EQ(text_changed_invocations().size(), 0u);
ExecuteJS("chrome.send('textChanged', ['orange'])");
ASSERT_EQ(text_changed_invocations().size(), 1u);
ASSERT_EQ(text_changed_invocations().back(), base::ASCIIToUTF16("orange"));
}
IN_PROC_BROWSER_TEST_F(CommanderUITest, OptionSelected) {
EXPECT_EQ(option_selected_invocations().size(), 0u);
ExecuteJS("chrome.send('optionSelected', [13, 586])");
ASSERT_EQ(option_selected_invocations().size(), 1u);
std::pair<size_t, int> expected({13, 586});
ASSERT_EQ(option_selected_invocations().back(), expected);
}
TEST(CommanderHandlerTest, ViewModelPassed) {
content::TestWebUI test_web_ui;
auto handler = std::make_unique<TestCommanderHandler>(&test_web_ui);
commander::CommanderViewModel vm;
vm.action = commander::CommanderViewModel::Action::kDisplayResults;
base::string16 item_title = base::ASCIIToUTF16("Test item");
std::vector<gfx::Range> item_ranges;
vm.items.emplace_back(item_title, item_ranges);
handler->AllowJavascriptForTesting();
handler->ViewModelUpdated(std::move(vm));
const content::TestWebUI::CallData& call_data =
*test_web_ui.call_data().back();
EXPECT_EQ("cr.webUIListenerCallback", call_data.function_name());
EXPECT_EQ("view-model-updated", call_data.arg1()->GetString());
EXPECT_EQ("Test item", call_data.arg2()->GetList()[0].GetString());
}
......@@ -381,6 +381,8 @@ const char kChromeUITabStripURL[] = "chrome://tab-strip";
#endif
#if !defined(OS_ANDROID)
const char kChromeUICommanderHost[] = "commander";
const char kChromeUICommanderURL[] = "chrome://commander";
const char kChromeUITabSearchHost[] = "tab-search";
const char kChromeUITabSearchURL[] = "chrome://tab-search/";
#endif
......
......@@ -334,6 +334,8 @@ extern const char kChromeUITabStripURL[];
#endif
#if !defined(OS_ANDROID)
extern const char kChromeUICommanderHost[];
extern const char kChromeUICommanderURL[];
extern const char kChromeUITabSearchHost[];
extern const char kChromeUITabSearchURL[];
#endif
......
......@@ -1472,6 +1472,7 @@ if (!is_android) {
"../browser/ui/webui/chromeos/bluetooth_pairing_dialog_browsertest-inl.h",
"../browser/ui/webui/chromeos/machine_learning/machine_learning_internals_browsertest.cc",
"../browser/ui/webui/chromeos/machine_learning/machine_learning_internals_browsertest.h",
"../browser/ui/webui/commander/commander_ui_browsertest.cc",
"../browser/ui/webui/constrained_web_dialog_ui_browsertest.cc",
"../browser/ui/webui/extensions/extension_settings_browsertest.cc",
"../browser/ui/webui/extensions/extension_settings_browsertest.h",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment