Skip to content

Commit

Permalink
Use switch widget instead of dismiss (#8075)
Browse files Browse the repository at this point in the history
* Use switch widget instead of dismiss

* Fix hacks

* Fix tests

* Remove dismiss widget
  • Loading branch information
jonasfj authored Sep 26, 2024
1 parent a87dc2a commit b940213
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 123 deletions.
8 changes: 5 additions & 3 deletions app/lib/frontend/templates/views/shared/layout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,11 @@ d.Node pageLayoutNode({
d.div(
classes: ['dismisser'],
attributes: {
'data-widget': 'dismiss',
'data-dismiss-target': '.announcement-banner',
'data-dismiss-message-id': announcementBannerHash,
'data-widget': 'switch',
'data-switch-target': '.announcement-banner',
'data-switch-enabled': 'dismissed',
'data-switch-initial-state': 'false',
'data-switch-state-id': announcementBannerHash,
},
text: 'x',
),
Expand Down
117 changes: 0 additions & 117 deletions pkg/web_app/lib/src/widget/dismiss/widget.dart

This file was deleted.

127 changes: 127 additions & 0 deletions pkg/web_app/lib/src/widget/switch/widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright (c) 2024, 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.

import 'dart:js_interop';

import 'package:collection/collection.dart';
import 'package:web/web.dart';

import '../../web_util.dart';

/// Create a switch widget on [element].
///
/// A `data-switch-target` is required, this must be a CSS selector for the
/// element(s) that are affected when this widget is clicked.
///
/// The optional `data-switch-initial-state` property may be used to provide an
/// initial state. The initial state is used if state can be loaded from
/// `localStorage` (because there is none). If not provided, initial state is
/// derived from document state.
///
/// The optional `data-switch-state-id` property may be used to provide an
/// identifier for the sttae of this switch in `localStorage`. If supplied state
/// will be sync'ed across windows.
///
/// The optional `data-switch-enabled` property may be used to specify a space
/// separated list of classes to be applied to `data-switch-target` when the
/// switch is enabled.
///
/// The optional `data-switch-disabled` property may be used to specify a space
/// separated list of classes to be applied to `data-switch-target` when the
/// switch is disabled.
void create(HTMLElement element, Map<String, String> options) {
final target = options['target'];
if (target == null) {
throw UnsupportedError('data-switch-target required');
}
final initialState_ = options['initial-state'];
final stateId = options['state-id'];
final enabledClassList = (options['enabled'] ?? '')
.split(' ')
.where((s) => s.isNotEmpty)
.toSet()
.toList();
final disabledClassList = (options['disabled'] ?? '')
.split(' ')
.where((s) => s.isNotEmpty)
.toSet()
.toList();

void applyState(bool enabled) {
for (final e in document.querySelectorAll(target).toList()) {
if (e.isA<HTMLElement>()) {
final element = e as HTMLHtmlElement;
if (enabled) {
for (final c in enabledClassList) {
element.classList.add(c);
}
for (final c in disabledClassList) {
element.classList.remove(c);
}
} else {
for (final c in enabledClassList) {
element.classList.remove(c);
}
for (final c in disabledClassList) {
element.classList.add(c);
}
}
}
}
}

bool? initialState;
if (stateId != null) {
void onStorage(StorageEvent e) {
if (e.key == 'switch-$stateId' && e.storageArea == window.localStorage) {
applyState(e.newValue == 'true');
}
}

window.addEventListener('storage', onStorage.toJS);
final state = window.localStorage.getItem('switch-$stateId');
if (state != null) {
initialState = state == 'true';
}
}

// Set initialState, if present
if (initialState_ != null) {
initialState ??= initialState_ == 'true';
}
// If there are no classes to be applied, this is weird, but then we can't
// infer an initial state.
if (enabledClassList.isEmpty && disabledClassList.isEmpty) {
initialState ??= false;
}
// Infer initial state from document state, unless loaded from localStorage
initialState ??= document
.querySelectorAll(target)
.toList()
.where((e) => e.isA<HTMLElement>())
.map((e) => e as HTMLElement)
.every(
(e) =>
enabledClassList.every((c) => e.classList.contains(c)) &&
disabledClassList.none((c) => e.classList.contains(c)),
);

applyState(initialState);
var state = initialState;

void onClick(MouseEvent e) {
if (e.defaultPrevented) {
return;
}
e.preventDefault();

state = !state;
applyState(state);
if (stateId != null) {
window.localStorage.setItem('switch-$stateId', state.toString());
}
}

element.addEventListener('click', onClick.toJS);
}
4 changes: 2 additions & 2 deletions pkg/web_app/lib/src/widget/widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import 'package:web/web.dart';

import '../web_util.dart';
import 'completion/widget.dart' deferred as completion;
import 'dismiss/widget.dart' deferred as dismiss;
import 'switch/widget.dart' deferred as switch_;

/// Function to create an instance of the widget given an element and options.
///
Expand All @@ -32,7 +32,7 @@ typedef _WidgetLoaderFn = FutureOr<_WidgetFn> Function();
/// Map from widget name to widget loader
final _widgets = <String, _WidgetLoaderFn>{
'completion': () => completion.loadLibrary().then((_) => completion.create),
'dismiss': () => dismiss.loadLibrary().then((_) => dismiss.create),
'switch': () => switch_.loadLibrary().then((_) => switch_.create),
};

Future<_WidgetFn> _noSuchWidget() async =>
Expand Down
1 change: 1 addition & 0 deletions pkg/web_app/test/deferred_import_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ void main() {
],
'completion/': [],
'dismiss/': [],
'switch/': [],
};

for (final file in files) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/web_css/lib/src/_base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ pre {
}

&.dismissed {
display: none;
visibility: hidden;
}

z-index: 0;
Expand Down

0 comments on commit b940213

Please sign in to comment.