Skip to content

Commit

Permalink
New Tab Page WebUI: Partially refactor all observing and messaging to…
Browse files Browse the repository at this point in the history
… MessageHandler

Following best practices from chromium webui documentation, move towards using DataSource keys for the initial page data, and FireWebUIListener for updating data.
We're still manually setting data on the render_host in the WebUIController, but this refactor allows us to use FireWebUIListener now, and move towards using DataSource for that data in the future. MessageHandler allows us to use an established JS lifecycle to ensure that data is only sent to the correct contexts at the correct time.

Use FireWebUIListener for 'stats-updated' instead of expecting a global 'statsUpdated' function to exist (which was causing some JS errors).
  • Loading branch information
petemill committed Jun 28, 2019
1 parent e59303c commit 4a97fbe
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 99 deletions.
2 changes: 2 additions & 0 deletions browser/ui/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ source_set("ui") {
"webui/basic_ui.h",
"webui/brave_adblock_ui.cc",
"webui/brave_adblock_ui.h",
"webui/brave_new_tab_message_handler.cc",
"webui/brave_new_tab_message_handler.h",
"webui/brave_new_tab_ui.cc",
"webui/brave_new_tab_ui.h",
"webui/brave_web_ui_controller_factory.cc",
Expand Down
79 changes: 79 additions & 0 deletions browser/ui/webui/brave_new_tab_message_handler.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) 2019 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.

#include "brave/browser/ui/webui/brave_new_tab_message_handler.h"

#include "base/bind.h"
#include "base/values.h"
#include "brave/browser/ui/webui/brave_new_tab_ui.h"
#include "brave/browser/search_engines/search_engine_provider_util.h"
#include "brave/common/pref_names.h"
#include "chrome/browser/profiles/profile.h"
#include "components/prefs/pref_service.h"

BraveNewTabMessageHandler::BraveNewTabMessageHandler(BraveNewTabUI* web_ui)
: new_tab_web_ui_(web_ui) {
}

BraveNewTabMessageHandler::~BraveNewTabMessageHandler() {}

void BraveNewTabMessageHandler::OnJavascriptAllowed() {
// Observe relevant preferences
PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
pref_change_registrar_.Init(prefs);
// Stats
pref_change_registrar_.Add(kAdsBlocked,
base::Bind(&BraveNewTabMessageHandler::OnStatsChanged,
base::Unretained(this)));
pref_change_registrar_.Add(kTrackersBlocked,
base::Bind(&BraveNewTabMessageHandler::OnStatsChanged,
base::Unretained(this)));
pref_change_registrar_.Add(kHttpsUpgrades,
base::Bind(&BraveNewTabMessageHandler::OnStatsChanged,
base::Unretained(this)));
// Private New Tab Page preferences
pref_change_registrar_.Add(kUseAlternativeSearchEngineProvider,
base::Bind(&BraveNewTabMessageHandler::OnPrivatePropertiesChanged,
base::Unretained(this)));
pref_change_registrar_.Add(kAlternativeSearchEngineProviderInTor,
base::Bind(&BraveNewTabMessageHandler::OnPrivatePropertiesChanged,
base::Unretained(this)));
}

void BraveNewTabMessageHandler::OnJavascriptDisallowed() {
pref_change_registrar_.RemoveAll();
}

void BraveNewTabMessageHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback(
"newTabPageInitialized",
base::BindRepeating(
&BraveNewTabMessageHandler::HandleInitialized,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"toggleAlternativePrivateSearchEngine",
base::BindRepeating(
&BraveNewTabMessageHandler::HandleToggleAlternativeSearchEngineProvider,
base::Unretained(this)));
}

void BraveNewTabMessageHandler::HandleInitialized(const base::ListValue* args) {
AllowJavascript();
}

void BraveNewTabMessageHandler::HandleToggleAlternativeSearchEngineProvider(
const base::ListValue* args) {
brave::ToggleUseAlternativeSearchEngineProvider(
Profile::FromWebUI(web_ui()));
}

void BraveNewTabMessageHandler::OnPrivatePropertiesChanged() {
new_tab_web_ui_->OnPrivatePropertiesChanged();
}

void BraveNewTabMessageHandler::OnStatsChanged() {
new_tab_web_ui_->OnStatsChanged();
FireWebUIListener("stats-updated");
}
40 changes: 40 additions & 0 deletions browser/ui/webui/brave_new_tab_message_handler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2019 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef BRAVE_BROWSER_UI_WEBUI_BRAVE_NEW_TAB_MESSAGE_HANDLER_H_
#define BRAVE_BROWSER_UI_WEBUI_BRAVE_NEW_TAB_MESSAGE_HANDLER_H_

#include "components/prefs/pref_change_registrar.h"
#include "content/public/browser/web_ui_message_handler.h"

class Profile;
class BraveNewTabUI;

// Handles messages to and from the New Tab Page javascript
class BraveNewTabMessageHandler : public content::WebUIMessageHandler {
public:
explicit BraveNewTabMessageHandler(BraveNewTabUI* web_ui);
~BraveNewTabMessageHandler() override;

private:
// WebUIMessageHandler implementation.
void RegisterMessages() override;
void OnJavascriptAllowed() override;
void OnJavascriptDisallowed() override;

void HandleInitialized(const base::ListValue* args);
void HandleToggleAlternativeSearchEngineProvider(
const base::ListValue* args);

void OnStatsChanged();
void OnPrivatePropertiesChanged();

PrefChangeRegistrar pref_change_registrar_;
BraveNewTabUI* new_tab_web_ui_;

DISALLOW_COPY_AND_ASSIGN(BraveNewTabMessageHandler);
};

#endif // BRAVE_BROWSER_UI_WEBUI_BRAVE_NEW_TAB_MESSAGE_HANDLER_H_
94 changes: 41 additions & 53 deletions browser/ui/webui/brave_new_tab_ui.cc
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
// Copyright (c) 2019 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.

#include "brave/browser/ui/webui/brave_new_tab_ui.h"

#include <string>

#include "brave/browser/search_engines/search_engine_provider_util.h"
#include "brave/browser/ui/webui/brave_new_tab_message_handler.h"
#include "brave/common/pref_names.h"
#include "brave/common/webui_url_constants.h"
#include "brave/components/brave_new_tab/resources/grit/brave_new_tab_generated_map.h"
Expand All @@ -15,60 +19,26 @@
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_ui_data_source.h"
#include "content/public/browser/web_ui_message_handler.h"

namespace {
class NewTabDOMHandler : public content::WebUIMessageHandler {
public:
NewTabDOMHandler() = default;
~NewTabDOMHandler() override = default;

private:
// WebUIMessageHandler implementation.
void RegisterMessages() override {
web_ui()->RegisterMessageCallback(
"toggleAlternativePrivateSearchEngine",
base::BindRepeating(
&NewTabDOMHandler::HandleToggleAlternativeSearchEngineProvider,
base::Unretained(this)));
}

void HandleToggleAlternativeSearchEngineProvider(
const base::ListValue* args) {
brave::ToggleUseAlternativeSearchEngineProvider(
Profile::FromWebUI(web_ui()));
}

DISALLOW_COPY_AND_ASSIGN(NewTabDOMHandler);
};

} // namespace

BraveNewTabUI::BraveNewTabUI(content::WebUI* web_ui, const std::string& name)
: BasicUI(web_ui, name, kBraveNewTabGenerated,
kBraveNewTabGeneratedSize, IDR_BRAVE_NEW_TAB_HTML) {
Profile* profile = Profile::FromWebUI(web_ui);
PrefService* prefs = profile->GetPrefs();
pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
pref_change_registrar_->Init(prefs);
pref_change_registrar_->Add(kAdsBlocked,
base::Bind(&BraveNewTabUI::OnPreferenceChanged, base::Unretained(this)));
pref_change_registrar_->Add(kTrackersBlocked,
base::Bind(&BraveNewTabUI::OnPreferenceChanged, base::Unretained(this)));
pref_change_registrar_->Add(kHttpsUpgrades,
base::Bind(&BraveNewTabUI::OnPreferenceChanged, base::Unretained(this)));
pref_change_registrar_->Add(kUseAlternativeSearchEngineProvider,
base::Bind(&BraveNewTabUI::OnPreferenceChanged, base::Unretained(this)));
pref_change_registrar_->Add(kAlternativeSearchEngineProviderInTor,
base::Bind(&BraveNewTabUI::OnPreferenceChanged, base::Unretained(this)));

web_ui->AddMessageHandler(std::make_unique<NewTabDOMHandler>());
web_ui->AddMessageHandler(std::make_unique<BraveNewTabMessageHandler>(this));
}

BraveNewTabUI::~BraveNewTabUI() {
}

void BraveNewTabUI::CustomizeNewTabWebUIProperties(content::RenderViewHost* render_view_host) {
void BraveNewTabUI::UpdateWebUIProperties() {
// TODO(petemill): move all this data to set on loadTimeData
// on the DataSource via the MessageHandler
auto* render_view_host = GetRenderViewHost();
SetStatsWebUIProperties(render_view_host);
SetPrivateWebUIProperties(render_view_host);
}

void BraveNewTabUI::SetStatsWebUIProperties(
content::RenderViewHost* render_view_host) {
DCHECK(IsSafeToSetWebUIProperties());
Profile* profile = Profile::FromWebUI(web_ui());
PrefService* prefs = profile->GetPrefs();
Expand Down Expand Up @@ -99,13 +69,31 @@ void BraveNewTabUI::CustomizeNewTabWebUIProperties(content::RenderViewHost* rend
}
}

void BraveNewTabUI::UpdateWebUIProperties() {
void BraveNewTabUI::SetPrivateWebUIProperties(
content::RenderViewHost* render_view_host) {
DCHECK(IsSafeToSetWebUIProperties());
Profile* profile = Profile::FromWebUI(web_ui());
PrefService* prefs = profile->GetPrefs();
if (render_view_host) {
render_view_host->SetWebUIProperty(
"useAlternativePrivateSearchEngine",
prefs->GetBoolean(kUseAlternativeSearchEngineProvider) ? "true"
: "false");
render_view_host->SetWebUIProperty(
"isTor", profile->IsTorProfile() ? "true" : "false");
render_view_host->SetWebUIProperty(
"isQwant", brave::IsRegionForQwant(profile) ? "true" : "false");
}
}

void BraveNewTabUI::OnPrivatePropertiesChanged() {
if (IsSafeToSetWebUIProperties()) {
CustomizeNewTabWebUIProperties(GetRenderViewHost());
web_ui()->CallJavascriptFunctionUnsafe("brave_new_tab.statsUpdated");
SetPrivateWebUIProperties(GetRenderViewHost());
}
}

void BraveNewTabUI::OnPreferenceChanged() {
UpdateWebUIProperties();
void BraveNewTabUI::OnStatsChanged() {
if (IsSafeToSetWebUIProperties()) {
SetStatsWebUIProperties(GetRenderViewHost());
}
}
22 changes: 13 additions & 9 deletions browser/ui/webui/brave_new_tab_ui.h
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
// Copyright (c) 2019 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef BRAVE_BROWSER_UI_WEBUI_BRAVE_NEW_TAB_UI_H_
#define BRAVE_BROWSER_UI_WEBUI_BRAVE_NEW_TAB_UI_H_

#include <memory>
#include <string>

#include "brave/browser/ui/webui/basic_ui.h"

class PrefChangeRegistrar;
namespace content {
class RenderViewHost;
}

class BraveNewTabUI : public BasicUI {
public:
BraveNewTabUI(content::WebUI* web_ui, const std::string& host);
~BraveNewTabUI() override;
void OnPreferencesChanged();
void OnPrivatePropertiesChanged();
void OnStatsChanged();

private:
// BasicUI overrides
void UpdateWebUIProperties() override;

void CustomizeNewTabWebUIProperties(content::RenderViewHost* render_view_host);
void OnPreferenceChanged();

std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
void SetStatsWebUIProperties(content::RenderViewHost* render_view_host);
void SetPrivateWebUIProperties(content::RenderViewHost* render_view_host);

DISALLOW_COPY_AND_ASSIGN(BraveNewTabUI);
};
Expand Down
2 changes: 1 addition & 1 deletion browser/ui/webui/brave_new_tab_ui_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ IN_PROC_BROWSER_TEST_F(BraveNewTabUIBrowserTest, BraveNewTabIsDefault) {
bool is_brave_new_tab = false;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
contents,
"window.domAutomationController.send(!!window.brave_new_tab)",
"window.domAutomationController.send(!!document.querySelector(`html[data-test-id='brave-new-tab-page']`))",
&is_brave_new_tab));
ASSERT_TRUE(is_brave_new_tab);
}
Expand Down
2 changes: 1 addition & 1 deletion components/brave_new_tab_ui/brave_new_tab.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!doctype html>
<html>
<html data-test-id="brave-new-tab-page">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
Expand Down
61 changes: 29 additions & 32 deletions components/brave_new_tab_ui/brave_new_tab.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
// Copyright (c) 2019 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.

import * as React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import * as dataFetchAPI from './api/dataFetch'

import Theme from 'brave-ui/theme/brave-default'
import { ThemeProvider } from 'brave-ui/theme'

import * as dataFetchAPI from './api/dataFetch'
// Components
import App from './components/app'

Expand All @@ -21,29 +20,27 @@ import 'emptykit.css'
import '../fonts/poppins.css'
import '../fonts/muli.css'

window.cr.define('brave_new_tab', function () {
'use strict'

function initialize () {
render(
<Provider store={store}>
<ThemeProvider theme={Theme}>
<App />
</ThemeProvider>
</Provider>,
document.getElementById('root'))
window.i18nTemplate.process(window.document, window.loadTimeData)
}

function statsUpdated () {
const actions = dataFetchAPI.getActions()
actions.statsUpdated()
}

return {
initialize,
statsUpdated
}
})

document.addEventListener('DOMContentLoaded', window.brave_new_tab.initialize)
function initialize () {
render(
<Provider store={store}>
<ThemeProvider theme={Theme}>
<App />
</ThemeProvider>
</Provider>,
document.getElementById('root')
)
window.i18nTemplate.process(window.document, window.loadTimeData)
handleAPIEvents()
}

function updateStats () {
const actions = dataFetchAPI.getActions()
actions.statsUpdated()
}

function handleAPIEvents () {
chrome.send('newTabPageInitialized', [])
window.cr.addWebUIListener('stats-updated', updateStats)
}

document.addEventListener('DOMContentLoaded', initialize)
Loading

0 comments on commit 4a97fbe

Please sign in to comment.