Remove Marker as a name for null (#136)
The checks against `== Marker` won't upgrade a nullable variable to
non-nullable like `== null` would.
- Replace `Marker` with `null`. Remove the field.
- Add a doc comment on the class to link to the parsing spec and
describe the usage of `null`.
- Add a doc comment on `add` to describe it's difference from the normal
`List.add`.
- Add some comments and a link to an issue filed about a likely bug in
this method.
diff --git a/lib/parser.dart b/lib/parser.dart
index 940753c..363aa23 100644
--- a/lib/parser.dart
+++ b/lib/parser.dart
@@ -1504,7 +1504,7 @@
final matchingElements = [];
for (Node node in tree.activeFormattingElements.reversed) {
- if (node == Marker) {
+ if (node == null) {
break;
} else if (isMatchingFormattingElement(node as Element, element)) {
matchingElements.add(node);
@@ -1743,7 +1743,7 @@
void startTagAppletMarqueeObject(StartTagToken token) {
tree.reconstructActiveFormattingElements();
tree.insertElement(token);
- tree.activeFormattingElements.add(Marker);
+ tree.activeFormattingElements.add(null);
parser.framesetOK = false;
}
@@ -2434,7 +2434,7 @@
void startTagCaption(StartTagToken token) {
clearStackToTableContext();
- tree.activeFormattingElements.add(Marker);
+ tree.activeFormattingElements.add(null);
tree.insertElement(token);
parser.phase = parser._inCaptionPhase;
}
@@ -3054,7 +3054,7 @@
clearStackToTableRowContext();
tree.insertElement(token);
parser.phase = parser._inCellPhase;
- tree.activeFormattingElements.add(Marker);
+ tree.activeFormattingElements.add(null);
}
Token startTagTableOther(StartTagToken token) {
diff --git a/lib/src/treebuilder.dart b/lib/src/treebuilder.dart
index a1f0da1..3687464 100644
--- a/lib/src/treebuilder.dart
+++ b/lib/src/treebuilder.dart
@@ -10,29 +10,33 @@
import 'token.dart';
import 'utils.dart';
-// The scope markers are inserted when entering object elements,
-// marquees, table cells, and table captions, and are used to prevent formatting
-// from "leaking" into tables, object elements, and marquees.
-const Element Marker = null;
-
-// TODO(jmesserly): this should extend ListBase<Element>, but my simple attempt
-// didn't work.
-class ActiveFormattingElements extends ListProxy<Element> {
- // Override the "add" method.
- // TODO(jmesserly): I'd rather not override this; can we do this in the
- // calling code instead?
+/// Open elements in the formatting category, most recent element last.
+///
+/// `null` is used as the "marker" entry to prevent style from leaking when
+/// entering some elements.
+///
+/// https://html.spec.whatwg.org/multipage/parsing.html#list-of-active-formatting-elements
+class ActiveFormattingElements extends ListProxy<Element /*?*/ > {
+ /// Push an element into the active formatting elements.
+ ///
+ /// Prevents equivalent elements from appearing more than 3 times following
+ /// the last `null` marker. If adding [node] would cause there to be more than
+ /// 3 equivalent elements the earliest identical element is removed.
+ // TODO - Earliest equivalent following a marker, as opposed to earliest
+ // identical regardless of marker position, should be removed.
@override
void add(Element node) {
var equalCount = 0;
- if (node != Marker) {
+ if (node != null) {
for (var element in reversed) {
- if (element == Marker) {
+ if (element == null) {
break;
}
if (_nodesEqual(element, node)) {
equalCount += 1;
}
if (equalCount == 3) {
+ // TODO - https://github.com/dart-lang/html/issues/135
remove(element);
break;
}
@@ -165,12 +169,12 @@
// Step 2 and step 3: we start with the last element. So i is -1.
var i = activeFormattingElements.length - 1;
var entry = activeFormattingElements[i];
- if (entry == Marker || openElements.contains(entry)) {
+ if (entry == null || openElements.contains(entry)) {
return;
}
// Step 6
- while (entry != Marker && !openElements.contains(entry)) {
+ while (entry != null && !openElements.contains(entry)) {
if (i == 0) {
//This will be reset to 0 below
i = -1;
@@ -209,7 +213,7 @@
void clearActiveFormattingElements() {
var entry = activeFormattingElements.removeLast();
- while (activeFormattingElements.isNotEmpty && entry != Marker) {
+ while (activeFormattingElements.isNotEmpty && entry != null) {
entry = activeFormattingElements.removeLast();
}
}
@@ -221,7 +225,7 @@
for (var item in activeFormattingElements.reversed) {
// Check for Marker first because if it's a Marker it doesn't have a
// name attribute.
- if (item == Marker) {
+ if (item == null) {
break;
} else if (item.localName == name) {
return item;