-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
css_class_set.dart
242 lines (203 loc) · 7.35 KB
/
css_class_set.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
// Copyright (c) 2012, 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.
part of html_common;
abstract class CssClassSetImpl extends SetBase<String> implements CssClassSet {
static final RegExp _validTokenRE = new RegExp(r'^\S+$');
String _validateToken(String value) {
if (_validTokenRE.hasMatch(value)) return value;
throw new ArgumentError.value(value, 'value', 'Not a valid class token');
}
String toString() {
return readClasses().join(' ');
}
/**
* Adds the class [value] to the element if it is not on it, removes it if it
* is.
*
* If [shouldAdd] is true, then we always add that [value] to the element. If
* [shouldAdd] is false then we always remove [value] from the element.
*/
bool toggle(String value, [bool? shouldAdd]) {
_validateToken(value);
Set<String> s = readClasses();
bool result = false;
if (shouldAdd == null) shouldAdd = !s.contains(value);
if (shouldAdd) {
s.add(value);
result = true;
} else {
s.remove(value);
}
writeClasses(s);
return result;
}
/**
* Returns [:true:] if classes cannot be added or removed from this
* [:CssClassSet:].
*/
bool get frozen => false;
// interface Iterable - BEGIN
Iterator<String> get iterator => readClasses().iterator;
// interface Iterable - END
// interface Collection - BEGIN
void forEach(void f(String element)) {
readClasses().forEach(f);
}
String join([String separator = ""]) => readClasses().join(separator);
Iterable<T> map<T>(T f(String e)) => readClasses().map<T>(f);
Iterable<String> where(bool f(String element)) => readClasses().where(f);
Iterable<T> expand<T>(Iterable<T> f(String element)) =>
readClasses().expand<T>(f);
bool every(bool f(String element)) => readClasses().every(f);
bool any(bool f(String element)) => readClasses().any(f);
bool get isEmpty => readClasses().isEmpty;
bool get isNotEmpty => readClasses().isNotEmpty;
int get length => readClasses().length;
String reduce(String combine(String value, String element)) {
return readClasses().reduce(combine);
}
T fold<T>(T initialValue, T combine(T previousValue, String element)) {
return readClasses().fold<T>(initialValue, combine);
}
// interface Collection - END
// interface Set - BEGIN
/**
* Determine if this element contains the class [value].
*
* This is the Dart equivalent of jQuery's
* [hasClass](http://api.jquery.com/hasClass/).
*/
bool contains(Object? value) {
if (value is! String) return false;
_validateToken(value);
return readClasses().contains(value);
}
/** Lookup from the Set interface. Not interesting for a String set. */
String? lookup(Object? value) => contains(value) ? value as String : null;
/**
* Add the class [value] to element.
*
* This is the Dart equivalent of jQuery's
* [addClass](http://api.jquery.com/addClass/).
*/
bool add(String value) {
_validateToken(value);
// TODO - figure out if we need to do any validation here
// or if the browser natively does enough.
return modify((s) => s.add(value)) ?? false;
}
/**
* Remove the class [value] from element, and return true on successful
* removal.
*
* This is the Dart equivalent of jQuery's
* [removeClass](http://api.jquery.com/removeClass/).
*/
bool remove(Object? value) {
if (value is! String) return false;
_validateToken(value);
Set<String> s = readClasses();
bool result = s.remove(value);
writeClasses(s);
return result;
}
/**
* Add all classes specified in [iterable] to element.
*
* This is the Dart equivalent of jQuery's
* [addClass](http://api.jquery.com/addClass/).
*/
void addAll(Iterable<String> iterable) {
// TODO - see comment above about validation.
modify((s) => s.addAll(iterable.map(_validateToken)));
}
/**
* Remove all classes specified in [iterable] from element.
*
* This is the Dart equivalent of jQuery's
* [removeClass](http://api.jquery.com/removeClass/).
*/
void removeAll(Iterable<Object?> iterable) {
modify((s) => s.removeAll(iterable));
}
/**
* Toggles all classes specified in [iterable] on element.
*
* Iterate through [iterable]'s items, and add it if it is not on it, or
* remove it if it is. This is the Dart equivalent of jQuery's
* [toggleClass](http://api.jquery.com/toggleClass/).
* If [shouldAdd] is true, then we always add all the classes in [iterable]
* element. If [shouldAdd] is false then we always remove all the classes in
* [iterable] from the element.
*/
void toggleAll(Iterable<String> iterable, [bool? shouldAdd]) {
iterable.forEach((e) => toggle(e, shouldAdd));
}
void retainAll(Iterable<Object?> iterable) {
modify((s) => s.retainAll(iterable));
}
void removeWhere(bool test(String name)) {
modify((s) => s.removeWhere(test));
}
void retainWhere(bool test(String name)) {
modify((s) => s.retainWhere(test));
}
bool containsAll(Iterable<Object?> collection) =>
readClasses().containsAll(collection);
Set<String> intersection(Set<Object?> other) =>
readClasses().intersection(other);
Set<String> union(Set<String> other) => readClasses().union(other);
Set<String> difference(Set<Object?> other) => readClasses().difference(other);
String get first => readClasses().first;
String get last => readClasses().last;
String get single => readClasses().single;
List<String> toList({bool growable: true}) =>
readClasses().toList(growable: growable);
Set<String> toSet() => readClasses().toSet();
Iterable<String> take(int n) => readClasses().take(n);
Iterable<String> takeWhile(bool test(String value)) =>
readClasses().takeWhile(test);
Iterable<String> skip(int n) => readClasses().skip(n);
Iterable<String> skipWhile(bool test(String value)) =>
readClasses().skipWhile(test);
String firstWhere(bool test(String value), {String orElse()?}) =>
readClasses().firstWhere(test, orElse: orElse);
String lastWhere(bool test(String value), {String orElse()?}) =>
readClasses().lastWhere(test, orElse: orElse);
String singleWhere(bool test(String value), {String orElse()?}) =>
readClasses().singleWhere(test, orElse: orElse);
String elementAt(int index) => readClasses().elementAt(index);
void clear() {
// TODO(sra): Do this without reading the classes.
modify((s) => s.clear());
}
// interface Set - END
/**
* Helper method used to modify the set of css classes on this element.
*
* f - callback with:
* s - a Set of all the css class name currently on this element.
*
* After f returns, the modified set is written to the
* className property of this element.
*/
modify(f(Set<String> s)) {
Set<String> s = readClasses();
var ret = f(s);
writeClasses(s);
return ret;
}
/**
* Read the class names from the Element class property,
* and put them into a set (duplicates are discarded).
* This is intended to be overridden by specific implementations.
*/
Set<String> readClasses();
/**
* Join all the elements of a set into one string and write
* back to the element.
* This is intended to be overridden by specific implementations.
*/
void writeClasses(Set<String> s);
}