Skip to content

[MV3 Debug Extension] Update Chrome APIs to be backwards compatible with MV2 #1951

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 5 additions & 13 deletions dwds/debug_extension_mv3/web/background.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
library background;

import 'dart:async';
import 'dart:html';

import 'package:dwds/data/debug_info.dart';
import 'package:js/js.dart';
Expand Down Expand Up @@ -42,7 +41,7 @@ void _registerListeners() {
_updateIcon(info.tabId);
}));
chrome.windows.onFocusChanged.addListener(allowInterop((_) async {
final currentTab = await _getTab();
final currentTab = await activeTab;
if (currentTab?.id != null) {
_updateIcon(currentTab!.id);
}
Expand All @@ -51,7 +50,7 @@ void _registerListeners() {
.addListener(allowInterop(_detectNavigationAwayFromDartApp));

// Detect clicks on the Dart Debug Extension icon.
chrome.action.onClicked.addListener(allowInterop(
onExtensionIconClicked(allowInterop(
(Tab tab) => attachDebugger(
tab.id,
trigger: Trigger.extensionIcon,
Expand Down Expand Up @@ -97,7 +96,7 @@ void _handleRuntimeMessages(
await setStorageObject<DebugInfo>(
type: StorageObject.debugInfo, value: debugInfo, tabId: dartTab.id);
// Update the icon to show that a Dart app has been detected:
final currentTab = await _getTab();
final currentTab = await activeTab;
if (currentTab?.id == dartTab.id) {
_setDebuggableIcon();
}
Expand Down Expand Up @@ -142,15 +141,14 @@ void _updateIcon(int activeTabId) async {
}

void _setDebuggableIcon() {
chrome.action
.setIcon(IconInfo(path: 'static_assets/dart.png'), /*callback*/ null);
setExtensionIcon(IconInfo(path: 'static_assets/dart.png'));
}

void _setDefaultIcon() {
final iconPath = isDevMode()
? 'static_assets/dart_dev.png'
: 'static_assets/dart_grey.png';
chrome.action.setIcon(IconInfo(path: iconPath), /*callback*/ null);
setExtensionIcon(IconInfo(path: iconPath));
}

Future<DebugInfo?> _fetchDebugInfo(int tabId) {
Expand All @@ -159,9 +157,3 @@ Future<DebugInfo?> _fetchDebugInfo(int tabId) {
tabId: tabId,
);
}

Future<Tab?> _getTab() async {
final query = QueryInfo(active: true, currentWindow: true);
final tabs = List<Tab>.from(await promiseToFuture(chrome.tabs.query(query)));
return tabs.isNotEmpty ? tabs.first : null;
}
11 changes: 6 additions & 5 deletions dwds/debug_extension_mv3/web/chrome_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -292,13 +292,14 @@ class OnChangedHandler {
@JS()
@anonymous
class Tabs {
external Object query(QueryInfo queryInfo);
external dynamic query(
QueryInfo queryInfo, void Function(List<Tab>) callback);

external Object create(TabInfo tabInfo);
external dynamic create(TabInfo tabInfo, void Function(Tab) callback);

external Object get(int tabId);
external dynamic get(int tabId, void Function(Tab?) callback);

external Object remove(int tabId);
external dynamic remove(int tabId, void Function()? callback);

external OnActivatedHandler get onActivated;

Expand Down Expand Up @@ -378,7 +379,7 @@ class NavigationInfo {
@JS()
@anonymous
class Windows {
external Object create(WindowInfo? createData);
external dynamic create(WindowInfo? createData, Function(WindowObj) callback);

external OnFocusChangedHandler get onFocusChanged;
}
Expand Down
2 changes: 1 addition & 1 deletion dwds/debug_extension_mv3/web/debug_session.dart
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ void _handleDebuggerDetach(Debuggee source, DetachReason reason) async {
final devToolsTab = await getTab(devToolsTabId);
if (devToolsTab != null) {
debugLog('Closing DevTools tab...');
chrome.tabs.remove(devToolsTabId);
await removeTab(devToolsTabId);
}
}

Expand Down
11 changes: 3 additions & 8 deletions dwds/debug_extension_mv3/web/lifeline_ports.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'package:js/js.dart';

import 'chrome_api.dart';
import 'logger.dart';
import 'utils.dart';

// Switch to true to enable debug logs.
// TODO(elliette): Enable / disable with flag while building the extension.
Expand All @@ -22,7 +23,7 @@ Port? lifelinePort;
int? lifelineTab;
final dartTabs = <int>{};

void maybeCreateLifelinePort(int tabId) {
Future<void> maybeCreateLifelinePort(int tabId) async {
// Keep track of current Dart tabs that are being debugged. This way if one of
// them is closed, we can reconnect the lifeline port to another one:
dartTabs.add(tabId);
Expand All @@ -39,13 +40,7 @@ void maybeCreateLifelinePort(int tabId) {
// will connect to the port:
debugLog('Creating lifeline port.');
lifelineTab = tabId;
chrome.scripting.executeScript(
InjectDetails(
target: Target(tabId: tabId),
files: ['lifeline_connection.dart.js'],
),
/*callback*/ null,
);
await injectScript('lifeline_connection.dart.js', tabId: tabId);
}

void maybeRemoveLifelinePort(int removedTabId) {
Expand Down
77 changes: 64 additions & 13 deletions dwds/debug_extension_mv3/web/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,80 @@ import 'package:js/js.dart';

import 'chrome_api.dart';

Future<Tab> createTab(String url, {bool inNewWindow = false}) async {
Future<Tab> createTab(String url, {bool inNewWindow = false}) {
final completer = Completer<Tab>();
if (inNewWindow) {
final windowPromise = chrome.windows.create(
chrome.windows.create(
WindowInfo(focused: true, url: url),
allowInterop(
(WindowObj windowObj) {
completer.complete(windowObj.tabs.first);
},
),
);
} else {
chrome.tabs.create(
TabInfo(
active: true,
url: url,
),
allowInterop(
(Tab tab) {
completer.complete(tab);
},
),
);
final windowObj = await promiseToFuture<WindowObj>(windowPromise);
return windowObj.tabs.first;
}
final tabPromise = chrome.tabs.create(TabInfo(
active: true,
url: url,
));
return promiseToFuture<Tab>(tabPromise);
return completer.future;
}

Future<Tab?> getTab(int tabId) {
return promiseToFuture<Tab?>(chrome.tabs.get(tabId));
final completer = Completer<Tab?>();
chrome.tabs.get(tabId, allowInterop((tab) {
completer.complete(tab);
}));
return completer.future;
}

Future<Tab?> getActiveTab() async {
Future<Tab?> get activeTab async {
final completer = Completer<Tab?>();
final query = QueryInfo(active: true, currentWindow: true);
final tabs = List<Tab>.from(await promiseToFuture(chrome.tabs.query(query)));
return tabs.isNotEmpty ? tabs.first : null;
chrome.tabs.query(query, allowInterop((List tabs) {
if (tabs.isNotEmpty) {
completer.complete(tabs.first as Tab);
} else {
completer.complete(null);
}
}));
return completer.future;
}

Future<bool> removeTab(int tabId) {
final completer = Completer<bool>();
chrome.tabs.remove(tabId, allowInterop(() {
completer.complete(true);
}));
return completer.future;
}

Future<bool> injectScript(String scriptName, {required int tabId}) {
final completer = Completer<bool>();
chrome.scripting.executeScript(
InjectDetails(
target: Target(tabId: tabId),
files: [scriptName],
), allowInterop(() {
completer.complete(true);
}));
return completer.future;
}

void onExtensionIconClicked(void Function(Tab) callback) {
chrome.action.onClicked.addListener(callback);
}

void setExtensionIcon(IconInfo info) {
chrome.action.setIcon(info, /*callback*/ null);
}

bool? _isDevMode;
Expand Down