Skip to content

Commit 20155c3

Browse files
authored
[web_app] Minor cleanup and consistency improvements (#8145)
1 parent df1872f commit 20155c3

20 files changed

+112
-105
lines changed

pkg/web_app/lib/src/_dom_helper.dart

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import 'package:mdc_web/mdc_web.dart' show MDCDialog;
99
import 'deferred/markdown.dart' deferred as md;
1010

1111
/// Displays a message via the modal window.
12-
Future modalMessage(String title, Element content) async {
12+
Future<void> modalMessage(String title, Element content) async {
1313
await modalWindow(
1414
titleText: title,
1515
content: content,
@@ -85,9 +85,9 @@ Element _buildDialog({
8585

8686
/// The callback will be called with `true` when "OK" was clicked, and `false`
8787
/// when "Cancel" was clicked.
88-
required Function(bool) closing,
88+
required void Function(bool) closing,
8989
}) =>
90-
Element.div()
90+
DivElement()
9191
..classes.add('mdc-dialog')
9292
..attributes.addAll({
9393
'role': 'alertdialog',
@@ -96,25 +96,25 @@ Element _buildDialog({
9696
'aria-describedby': 'pub-dialog-content',
9797
})
9898
..children = [
99-
Element.div()
99+
DivElement()
100100
..classes.add('mdc-dialog__container')
101101
..children = [
102-
Element.div()
102+
DivElement()
103103
..classes.add('mdc-dialog__surface')
104104
..children = [
105-
Element.tag('h2')
105+
HeadingElement.h2()
106106
..classes.add('mdc-dialog__title')
107107
..id = 'pub-dialog-title'
108108
..innerText = titleText,
109-
Element.div()
109+
DivElement()
110110
..classes.add('mdc-dialog__content')
111111
..id = 'pub-dialog-content'
112112
..children = [content],
113113
Element.footer()
114114
..classes.add('mdc-dialog__actions')
115115
..children = [
116116
if (isQuestion)
117-
Element.tag('button')
117+
ButtonElement()
118118
..classes.addAll([
119119
'mdc-button',
120120
'mdc-dialog__button',
@@ -126,11 +126,11 @@ Element _buildDialog({
126126
closing(false);
127127
})
128128
..children = [
129-
Element.span()
129+
SpanElement()
130130
..classes.add('mdc-button__label')
131131
..innerText = cancelButtonText ?? 'Cancel',
132132
],
133-
Element.tag('button')
133+
ButtonElement()
134134
..classes.addAll([
135135
'mdc-button',
136136
'mdc-dialog__button',
@@ -142,18 +142,18 @@ Element _buildDialog({
142142
closing(true);
143143
})
144144
..children = [
145-
Element.span()
145+
SpanElement()
146146
..classes.add('mdc-button__label')
147147
..innerText = okButtonText ?? 'Ok',
148148
],
149149
],
150150
],
151151
],
152-
Element.div()..classes.add('mdc-dialog__scrim'),
152+
DivElement()..classes.add('mdc-dialog__scrim'),
153153
];
154154

155155
/// Creates an [Element] with unformatted [text] content.
156-
Element text(String text) => Element.div()..text = text;
156+
Element text(String text) => DivElement()..text = text;
157157

158158
/// Creates an [Element] with Markdown-formatted content.
159159
Future<Element> markdown(String text) async {
@@ -203,12 +203,12 @@ bool _isInsideContent(Element e, Element content) {
203203
/// Disables all focusable elements, except for the elements inside
204204
/// [allowedComponents]. Returns a [Function] that will restore the
205205
/// original focusability state of the disabled elements.
206-
Function disableAllFocusability({
206+
void Function() disableAllFocusability({
207207
required List<Element> allowedComponents,
208208
}) {
209209
final focusableElements =
210210
document.body!.querySelectorAll(_focusableSelectors.join(', '));
211-
final restoreFocusabilityFns = <Function>[];
211+
final restoreFocusabilityFns = <void Function()>[];
212212
for (final e in focusableElements) {
213213
if (allowedComponents.any((content) => _isInsideContent(e, content))) {
214214
continue;
@@ -224,7 +224,7 @@ Function disableAllFocusability({
224224

225225
/// Update [e] to disable focusability and return a [Function] that can be
226226
/// called to revert its original state.
227-
Function _disableFocusability(Element e) {
227+
void Function() _disableFocusability(Element e) {
228228
final isLink = e.tagName.toLowerCase() == 'a';
229229
final hasTabindex = e.hasAttribute('tabindex');
230230
final attributesToSet = <String, String>{

pkg/web_app/lib/src/account.dart

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55
import 'dart:async';
66
import 'dart:html';
77

8-
import 'package:web_app/src/page_data.dart';
9-
108
import 'admin_pages.dart' deferred as admin_pages;
119
import 'api_client/api_client.dart' deferred as api_client;
10+
import 'page_data.dart';
1211

1312
final _signInButton = document.getElementById('-account-login');
1413
final isNotAuthenticated = _signInButton != null;
@@ -29,8 +28,8 @@ void _initSessionMonitor() {
2928
return;
3029
}
3130

32-
final minCheckDelay = Duration(minutes: 5);
33-
final authenticationThreshold = Duration(minutes: 55);
31+
const minCheckDelay = Duration(minutes: 5);
32+
const authenticationThreshold = Duration(minutes: 55);
3433
final maxDurationBetweenChecks = authenticationThreshold - minCheckDelay;
3534
final sessionExpiresThreshold = authenticationThreshold - (minCheckDelay * 2);
3635

@@ -86,7 +85,7 @@ void _initSessionMonitor() {
8685
// unless the user session timed out or expired.
8786
//
8887
// In any of the above cases, defaulting to the default frequency is safe.
89-
await Future.delayed(minCheckDelay);
88+
await Future<void>.delayed(minCheckDelay);
9089
} else {
9190
// When the session is active, we can run the next check just before the
9291
// authentication threshold maxes out. Added sanity checks to bound the delay
@@ -99,7 +98,7 @@ void _initSessionMonitor() {
9998
} else if (nextCheck < minCheckDelay) {
10099
nextCheck = minCheckDelay;
101100
}
102-
await Future.delayed(nextCheck);
101+
await Future<void>.delayed(nextCheck);
103102
}
104103

105104
// Update session information and label.

pkg/web_app/lib/src/admin_pages.dart

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ void _initGenericForm() {
3737
button.onClick.listen((event) async {
3838
final body = <String, Object?>{};
3939
for (final field in form.querySelectorAll('[name]')) {
40-
final name = field.attributes['name']!;
40+
final name = field.getAttribute('name')!;
4141
if (field is InputElement &&
4242
!(field.disabled ?? false) &&
4343
field.value != null) {
@@ -54,7 +54,7 @@ void _initGenericForm() {
5454
api_client.sendJson(verb: 'POST', path: endpoint, body: body),
5555
successMessage: null,
5656
onSuccess: (r) async {
57-
final result = r ?? <String, dynamic>{};
57+
final result = r ?? {};
5858
// Goto a new location to display the feedback message.
5959
if (onSuccessGotoUrl != null) {
6060
window.location.href = onSuccessGotoUrl;
@@ -125,10 +125,9 @@ class _PkgAdminWidget {
125125
.getElementById('-admin-restore-retract-package-version-button');
126126
_restoreRetractPackageVersionButton?.onClick
127127
.listen((_) => _restoreRetracted());
128-
if (_inviteUploaderContent != null) {
129-
_inviteUploaderContent!.remove();
130-
_inviteUploaderContent!.classes.remove('modal-content-hidden');
131-
}
128+
_inviteUploaderContent
129+
?..classes.remove('modal-content-hidden')
130+
..remove();
132131
for (final btn
133132
in document.querySelectorAll('.-pub-remove-uploader-button')) {
134133
btn.onClick.listen((_) => _removeUploader(btn.dataset['email']!));
@@ -205,7 +204,7 @@ class _PkgAdminWidget {
205204
isQuestion: true,
206205
okButtonText: 'Invite',
207206
content: _inviteUploaderContent!,
208-
onExecute: () => _doInviteUploader(),
207+
onExecute: _doInviteUploader,
209208
);
210209
}
211210

@@ -495,7 +494,7 @@ class _PublisherAdminWidget {
495494
isQuestion: true,
496495
okButtonText: 'Add',
497496
content: _addMemberContent!,
498-
onExecute: () => _inviteMember(),
497+
onExecute: _inviteMember,
499498
);
500499
}
501500

@@ -553,7 +552,7 @@ class _ConsentWidget {
553552

554553
void _updateButtons(bool? granted) {
555554
final text = granted! ? 'Consent accepted.' : 'Consent rejected.';
556-
_buttons!.replaceWith(Element.p()..text = text);
555+
_buttons!.replaceWith(ParagraphElement()..text = text);
557556
}
558557

559558
Future<void> _accept() async {

pkg/web_app/lib/src/deferred/markdown.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import 'package:markdown/markdown.dart' as md;
88

99
/// Creates an [Element] with Markdown-formatted content.
1010
Future<Element> markdown(String text) async {
11-
return Element.div()
11+
return DivElement()
1212
..setInnerHtml(
1313
md.markdownToHtml(text),
1414
validator: NodeValidator(uriPolicy: _UnsafeUriPolicy()),

pkg/web_app/lib/src/foldable.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import 'dart:async';
66
import 'dart:html';
7-
import 'dart:math' show min, max;
7+
import 'dart:math' show max, min;
88

99
void setupFoldable() {
1010
_setEventForFoldable();
@@ -61,7 +61,7 @@ void _setEventForFoldable() {
6161

6262
final foldableIcon = h.querySelector('.foldable-icon');
6363
if (foldableIcon != null) {
64-
foldableIcon.attributes['tabindex'] = '0';
64+
foldableIcon.setAttribute('tabindex', '0');
6565
}
6666

6767
// listen on trigger events

pkg/web_app/lib/src/gtm_js.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ library;
77

88
import 'dart:js_interop';
99

10-
import 'package:web/web.dart' as dart_html;
10+
import 'package:web/web.dart' as web;
1111

1212
@JS('dataLayer.push')
1313
external void _push(JSAny? data);
1414

15-
void _pushMap(Map<String, dynamic> data) {
15+
void _pushMap(Map<String, Object?> data) {
1616
_push(data.jsify());
1717
}
1818

@@ -25,7 +25,7 @@ void gtmCustomEvent({
2525
'event': 'custom-event', // hardcoded, used in GTM Trigger
2626
'customEventCategory': category,
2727
'customEventAction': action,
28-
'customEventLabel': 'path:${dart_html.window.location.pathname}',
28+
'customEventLabel': 'path:${web.window.location.pathname}',
2929
'customEventValue': '1',
3030
});
3131
}

pkg/web_app/lib/src/hoverable.dart

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ void _setEventForHoverable() {
3434

3535
/// Deactivates the active hover (hiding the hovering panel).
3636
void deactivateHover(_) {
37-
if (_activeHover != null) {
38-
_activeHover!.classes.remove('hover');
37+
if (_activeHover case final activeHoverElement?) {
38+
activeHoverElement.classes.remove('hover');
3939
_activeHover = null;
4040
}
4141
}
@@ -46,7 +46,7 @@ void registerHoverable(Element h) {
4646
if (h != _activeHover) {
4747
deactivateHover(e);
4848
_activeHover = h;
49-
_activeHover!.classes.add('hover');
49+
h.classes.add('hover');
5050
e.stopPropagation();
5151
}
5252
});
@@ -77,16 +77,17 @@ void _setEventForPackageTitleCopyToClipboard() {
7777
Future<void> _animateCopyFeedback(Element feedback) async {
7878
feedback.classes.add('visible');
7979
await window.animationFrame;
80-
await Future.delayed(Duration(milliseconds: 1600));
80+
await Future<void>.delayed(Duration(milliseconds: 1600));
8181
feedback.classes.add('fadeout');
8282
await window.animationFrame;
8383
// NOTE: keep in sync with _variables.scss 0.9s animation with the key
8484
// $copy-feedback-transition-opacity-delay
85-
await Future.delayed(Duration(milliseconds: 900));
85+
await Future<void>.delayed(Duration(milliseconds: 900));
8686
await window.animationFrame;
8787

88-
feedback.classes.remove('visible');
89-
feedback.classes.remove('fadeout');
88+
feedback.classes
89+
..remove('visible')
90+
..remove('fadeout');
9091
}
9192

9293
void _copyToClipboard(String text) {
@@ -127,7 +128,7 @@ void _setupCopyAndFeedbackButton({
127128
required Element feedback,
128129
required String Function() textFn,
129130
}) {
130-
copy.attributes['tabindex'] = '0';
131+
copy.setAttribute('tabindex', '0');
131132

132133
Future<void> doCopy() async {
133134
final text = textFn();

pkg/web_app/lib/src/likes.dart

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,18 @@ import 'dart:html';
77

88
import 'package:_pub_shared/format/number_format.dart';
99
import 'package:mdc_web/mdc_web.dart' show MDCIconButtonToggle;
10-
import 'package:web_app/src/_dom_helper.dart';
11-
import 'package:web_app/src/account.dart';
1210

11+
import '_dom_helper.dart';
12+
import 'account.dart';
1313
import 'api_client/api_client.dart' deferred as api_client;
1414
import 'page_data.dart';
1515

1616
Future<void> _done = Future.value();
1717

1818
/// Ensure only one task runs at the same time.
1919
void _enqueue(Future<void> Function() task) {
20-
_done = _done.then((_) => task(), onError: (e) => print('Action failed: $e'));
20+
_done = _done.then((_) => task(),
21+
onError: (Object? e) => print('Action failed: $e'));
2122
}
2223

2324
void setupLikesList() {
@@ -52,7 +53,7 @@ void setupLikes() {
5253
if (likeButton == null) return;
5354

5455
final iconButtonToggle = MDCIconButtonToggle(likeButton);
55-
int likesDelta = 0;
56+
var likesDelta = 0;
5657

5758
// keep in-sync with app/lib/frontend/templates/views/shared/detail/header.dart
5859
String likesString() {

pkg/web_app/lib/src/mobile_nav.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ void _setEventForDetailMetadataToggle() {
3636

3737
var isVisible = false;
3838
// ignore: cancel_subscriptions
39-
StreamSubscription? stateSubscription;
39+
StreamSubscription<void>? stateSubscription;
4040
final currentTitle = document.head?.querySelector('title')?.text?.trim();
4141
final currentUrl = window.location.toString();
4242
document.querySelectorAll('.detail-metadata-toggle').forEach((e) {

pkg/web_app/lib/src/page_data.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ import 'package:_pub_shared/data/page_data.dart';
88

99
/// The server-provided config/data for the current page.
1010
///
11-
/// This is the <meta name="pub-page-data" content="[json-data]"> embedded in
11+
/// This is the `<meta name="pub-page-data" content="[json-data]">` embedded in
1212
/// the `head` section of the HTML page.
1313
final PageData pageData = _extractData();
1414

1515
PageData _extractData() {
1616
final meta = document.head?.querySelector('meta[name="pub-page-data"]');
1717
if (meta != null) {
1818
try {
19-
final text = meta.attributes['content']!;
20-
final map = pageDataJsonCodec.decode(text) as Map<String, dynamic>;
19+
final text = meta.getAttribute('content')!;
20+
final map = pageDataJsonCodec.decode(text) as Map<String, Object?>;
2121
return PageData.fromJson(map);
2222
} catch (_) {
2323
// ignore exception

0 commit comments

Comments
 (0)