Index: lib/dom/templates/html/impl/impl_Element.darttemplate |
diff --git a/lib/dom/templates/html/impl/impl_Element.darttemplate b/lib/dom/templates/html/impl/impl_Element.darttemplate |
index f7542b2b8a0356aefdfe1a3ddcebec4e97b31067..95d62620845e54de424736e8844427cdcb054050 100644 |
--- a/lib/dom/templates/html/impl/impl_Element.darttemplate |
+++ b/lib/dom/templates/html/impl/impl_Element.darttemplate |
@@ -305,11 +305,11 @@ class _ElementList extends _ListWrapper<Element> implements ElementList { |
new _ElementList(super.getRange(start, length)); |
} |
-class ElementAttributeMap implements Map<String, String> { |
+class _ElementAttributeMap implements AttributeMap { |
final _ElementImpl _element; |
- ElementAttributeMap._wrap(this._element); |
+ _ElementAttributeMap(this._element); |
bool containsValue(String value) { |
final attributes = _element.$dom_attributes; |
@@ -329,8 +329,8 @@ class ElementAttributeMap implements Map<String, String> { |
return _element.$dom_getAttribute(key); |
} |
- void operator []=(String key, String value) { |
- _element.$dom_setAttribute(key, value); |
+ void operator []=(String key, value) { |
+ _element.$dom_setAttribute(key, '$value'); |
} |
String putIfAbsent(String key, String ifAbsent()) { |
@@ -393,6 +393,203 @@ class ElementAttributeMap implements Map<String, String> { |
} |
} |
+/** |
+ * Provides a Map abstraction on top of data-* attributes, similar to the |
+ * dataSet in the old DOM. |
+ */ |
+class _DataAttributeMap implements AttributeMap { |
+ |
+ final Map<String, String> $dom_attributes; |
+ |
+ _DataAttributeMap(this.$dom_attributes); |
+ |
+ // interface Map |
+ |
+ // TODO: Use lazy iterator when it is available on Map. |
+ bool containsValue(String value) => getValues().some((v) => v == value); |
+ |
+ bool containsKey(String key) => $dom_attributes.containsKey(_attr(key)); |
+ |
+ String operator [](String key) => $dom_attributes[_attr(key)]; |
+ |
+ void operator []=(String key, value) { |
+ $dom_attributes[_attr(key)] = '$value'; |
+ } |
+ |
+ String putIfAbsent(String key, String ifAbsent()) { |
+ $dom_attributes.putIfAbsent(_attr(key), ifAbsent); |
+ } |
+ |
+ String remove(String key) => $dom_attributes.remove(_attr(key)); |
+ |
+ void clear() { |
+ // Needs to operate on a snapshot since we are mutating the collection. |
+ for (String key in getKeys()) { |
+ remove(key); |
+ } |
+ } |
+ |
+ void forEach(void f(String key, String value)) { |
+ $dom_attributes.forEach((String key, String value) { |
+ if (_matches(key)) { |
+ f(_strip(key), value); |
+ } |
+ }); |
+ } |
+ |
+ Collection<String> getKeys() { |
+ final keys = new List<String>(); |
+ $dom_attributes.forEach((String key, String value) { |
+ if (_matches(key)) { |
+ keys.add(_strip(key)); |
+ } |
+ }); |
+ return keys; |
+ } |
+ |
+ Collection<String> getValues() { |
+ final values = new List<String>(); |
+ $dom_attributes.forEach((String key, String value) { |
+ if (_matches(key)) { |
+ values.add(value); |
+ } |
+ }); |
+ return values; |
+ } |
+ |
+ int get length() => getKeys().length; |
+ |
+ // TODO: Use lazy iterator when it is available on Map. |
+ bool isEmpty() => length == 0; |
+ |
+ // Helpers. |
+ String _attr(String key) => 'data-$key'; |
+ bool _matches(String key) => key.startsWith('data-'); |
+ String _strip(String key) => key.substring(5); |
+} |
+ |
+class _CssClassSet implements Set<String> { |
+ |
+ final _ElementImpl _element; |
+ |
+ _CssClassSet(this._element); |
+ |
+ String toString() => _formatSet(_read()); |
+ |
+ // interface Iterable - BEGIN |
+ Iterator<String> iterator() => _read().iterator(); |
+ // interface Iterable - END |
+ |
+ // interface Collection - BEGIN |
+ void forEach(void f(String element)) { |
+ _read().forEach(f); |
+ } |
+ |
+ Collection map(f(String element)) => _read().map(f); |
+ |
+ Collection<String> filter(bool f(String element)) => _read().filter(f); |
+ |
+ bool every(bool f(String element)) => _read().every(f); |
+ |
+ bool some(bool f(String element)) => _read().some(f); |
+ |
+ bool isEmpty() => _read().isEmpty(); |
+ |
+ int get length() =>_read().length; |
+ |
+ // interface Collection - END |
+ |
+ // interface Set - BEGIN |
+ bool contains(String value) => _read().contains(value); |
+ |
+ void add(String value) { |
+ // TODO - figure out if we need to do any validation here |
+ // or if the browser natively does enough |
+ _modify((s) => s.add(value)); |
+ } |
+ |
+ bool remove(String value) { |
+ Set<String> s = _read(); |
+ bool result = s.remove(value); |
+ _write(s); |
+ return result; |
+ } |
+ |
+ void addAll(Collection<String> collection) { |
+ // TODO - see comment above about validation |
+ _modify((s) => s.addAll(collection)); |
+ } |
+ |
+ void removeAll(Collection<String> collection) { |
+ _modify((s) => s.removeAll(collection)); |
+ } |
+ |
+ bool isSubsetOf(Collection<String> collection) => |
+ _read().isSubsetOf(collection); |
+ |
+ bool containsAll(Collection<String> collection) => |
+ _read().containsAll(collection); |
+ |
+ Set<String> intersection(Collection<String> other) => |
+ _read().intersection(other); |
+ |
+ void clear() { |
+ _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. |
+ */ |
+ void _modify( f(Set<String> s)) { |
+ Set<String> s = _read(); |
+ f(s); |
+ _write(s); |
+ } |
+ |
+ /** |
+ * Read the class names from the Element class property, |
+ * and put them into a set (duplicates are discarded). |
+ */ |
+ Set<String> _read() { |
+ // TODO(mattsh) simplify this once split can take regex. |
+ Set<String> s = new Set<String>(); |
+ for (String name in _classname().split(' ')) { |
+ String trimmed = name.trim(); |
+ if (!trimmed.isEmpty()) { |
+ s.add(trimmed); |
+ } |
+ } |
+ return s; |
+ } |
+ |
+ /** |
+ * Read the class names as a space-separated string. This is meant to be |
+ * overridden by subclasses. |
+ */ |
+ String _classname() => _element.$dom_className; |
+ |
+ /** |
+ * Join all the elements of a set into one string and write |
+ * back to the element. |
+ */ |
+ void _write(Set s) { |
+ _element.$dom_className = _formatSet(s); |
+ } |
+ |
+ String _formatSet(Set<String> s) { |
+ // TODO(mattsh) should be able to pass Set to String.joins http:/b/5398605 |
+ List list = new List.from(s); |
+ return Strings.join(list, ' '); |
+ } |
+} |
+ |
class _SimpleClientRect implements ClientRect { |
final num left; |
final num top; |
@@ -458,21 +655,11 @@ class _ElementRectImpl implements ElementRect { |
class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { |
- // TODO(jacobr): caching these may hurt performance. |
- ElementAttributeMap _elementAttributeMap; |
- _CssClassSet _cssClassSet; |
- _DataAttributeMap _dataAttributes; |
- |
/** |
* @domName Element.hasAttribute, Element.getAttribute, Element.setAttribute, |
* Element.removeAttribute |
*/ |
- Map<String, String> get attributes() { |
- if (_elementAttributeMap === null) { |
- _elementAttributeMap = new ElementAttributeMap._wrap(this); |
- } |
- return _elementAttributeMap; |
- } |
+ _ElementAttributeMap get attributes() => new _ElementAttributeMap(this); |
void set attributes(Map<String, String> value) { |
Map<String, String> attributes = this.attributes; |
@@ -493,12 +680,7 @@ class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { |
ElementList queryAll(String selectors) => |
new _FrozenElementList._wrap($dom_querySelectorAll(selectors)); |
- Set<String> get classes() { |
- if (_cssClassSet === null) { |
- _cssClassSet = new _CssClassSet(this); |
- } |
- return _cssClassSet; |
- } |
+ _CssClassSet get classes() => new _CssClassSet(this); |
void set classes(Collection<String> value) { |
_CssClassSet classSet = classes; |
@@ -506,15 +688,11 @@ class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { |
classSet.addAll(value); |
} |
- Map<String, String> get dataAttributes() { |
- if (_dataAttributes === null) { |
- _dataAttributes = new _DataAttributeMap(attributes); |
- } |
- return _dataAttributes; |
- } |
+ Map<String, String> get dataAttributes() => |
+ new _DataAttributeMap(attributes); |
void set dataAttributes(Map<String, String> value) { |
- Map<String, String> dataAttributes = this.dataAttributes; |
+ final dataAttributes = this.dataAttributes; |
dataAttributes.clear(); |
for (String key in value.getKeys()) { |
dataAttributes[key] = value[key]; |