blob: ba3ecf3332c8d59a1ab9c0f0e10e127e6bb61ee9 [file] [log] [blame]
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
@JS()
library popup;
import 'dart:async';
import 'dart:convert';
import 'dart:html';
import 'package:dwds/data/debug_info.dart';
import 'package:js/js.dart';
import 'data_serializers.dart';
import 'data_types.dart';
import 'messaging.dart';
import 'storage.dart';
import 'utils.dart';
const _appIdContainerId = 'appIdContainer';
const _appIdDividerId = 'appIdDivider';
const _appIdSpanId = 'appId';
const _copyIdButtonId = 'copyIdButton';
const _copiedSuccessId = 'copiedSuccess';
const _fileBugButtonId = 'fileBugButton';
const _hiddenClass = 'hidden';
const _launchDevToolsButtonId = 'launchDevToolsButton';
const _loadingSpinnerId = 'loadingSpinner';
const _windowOption = 'windowOption';
const _tabOption = 'tabOption';
Future<int?> get _tabId async {
final tab = await activeTab;
return tab?.id;
}
String? _appId;
Future<void> main() async {
_registerListeners();
await _loadUiAndHideSpinner();
}
void _registerListeners() {
final launchDevToolsButton =
document.getElementById(_launchDevToolsButtonId) as ButtonElement;
launchDevToolsButton.addEventListener('click', _launchDevTools);
final copyButton = document.getElementById(_copyIdButtonId) as ButtonElement;
copyButton.addEventListener('click', _copyAppId);
final fileABugButton =
document.getElementById(_fileBugButtonId) as ButtonElement;
fileABugButton.addEventListener('click', _openIssueTracker);
document.addEventListener('DOMContentLoaded', _updateSettingsFromStorage);
final windowOption = document.getElementById(_windowOption) as InputElement;
windowOption.addEventListener('change', (Event _) {
_saveSettingsToStorage(windowOption.value);
});
final tabOption = document.getElementById(_tabOption) as InputElement;
tabOption.addEventListener('change', (Event _) {
_saveSettingsToStorage(tabOption.value);
});
}
Future<void> _loadUiAndHideSpinner() async {
final inserted = await _insertAppId();
if (inserted) {
_updateElementVisibility(_appIdContainerId, visible: true);
_updateElementVisibility(_appIdDividerId, visible: true);
}
_updateElementVisibility(_loadingSpinnerId, visible: false);
}
Future<DebugInfo?> _fetchDebugInfo(int? tabId) async {
if (tabId == null) return null;
final debugInfo = await fetchStorageObject<DebugInfo>(
type: StorageObject.debugInfo,
tabId: tabId,
);
return debugInfo;
}
Future<bool> _insertAppId() async {
final tabId = await _tabId;
final debugInfo = await _fetchDebugInfo(tabId);
if (debugInfo == null) return false;
final isInternalBuild = debugInfo.isInternalBuild ?? false;
final workspaceName = debugInfo.workspaceName;
if (isInternalBuild && workspaceName != null) {
_appId = '$workspaceName-$tabId';
final appIdSpan = document.getElementById(_appIdSpanId) as SpanElement;
appIdSpan.setInnerHtml(_appId);
return true;
}
return false;
}
Future<void> _openIssueTracker(Event _) async {
final debugInfo = await _fetchDebugInfo(await _tabId);
final isInternalBuild = debugInfo?.isInternalBuild ?? false;
final issueTrackerLink = isInternalBuild
? 'http://b/issues/new?component=775375&template=1791321'
: 'https://github.com/dart-lang/webdev/issues/new?labels=dart-debug-extension&projects=&template=dart_debug_extension.md';
await createTab(issueTrackerLink);
}
Future<void> _launchDevTools(Event _) async {
final tabId = await _tabId;
final json = jsonEncode(
serializers.serialize(
DebugStateChange(
(b) => b
..tabId = tabId
..newState = DebugStateChange.startDebugging,
),
),
);
await sendRuntimeMessage(
type: MessageType.debugStateChange,
body: json,
sender: Script.popup, // change to popup
recipient: Script.background,
);
}
void _copyAppId(Event _) {
if (_appId == null) return;
final clipboard = window.navigator.clipboard;
if (clipboard == null) return;
clipboard.writeText(_appId!);
_updateElementVisibility(_copiedSuccessId, visible: true);
}
Future<void> _updateSettingsFromStorage(Event _) async {
final devToolsOpener = await fetchStorageObject<DevToolsOpener>(
type: StorageObject.devToolsOpener,
);
final openInNewWindow = devToolsOpener?.newWindow ?? false;
_getRadioButton(_windowOption).checked = openInNewWindow;
_getRadioButton(_tabOption).checked = !openInNewWindow;
}
Future<void> _saveSettingsToStorage(String? devToolsOpener) async {
if (devToolsOpener == null) return;
await setStorageObject<DevToolsOpener>(
type: StorageObject.devToolsOpener,
value: DevToolsOpener(
(b) => b..newWindow = devToolsOpener == 'window',
),
);
}
RadioButtonInputElement _getRadioButton(String id) {
return document.getElementById(id) as RadioButtonInputElement;
}
void _updateElementVisibility(String elementId, {required bool visible}) {
final element = document.getElementById(elementId);
if (element == null) return;
if (visible) {
element.classes.remove(_hiddenClass);
} else {
element.classes.add(_hiddenClass);
}
}