Add selector specificity.

This commit is contained in:
Natalie Weizenbaum 2016-08-04 14:19:35 -07:00
parent efaf64020f
commit a88670da4e
8 changed files with 104 additions and 1 deletions

View File

@ -11,7 +11,7 @@ export 'selector/list.dart';
export 'selector/namespaced_identifier.dart';
export 'selector/placeholder.dart';
export 'selector/pseudo.dart';
export 'selector/simple.dart';
export 'selector/simple.dart' hide baseSpecificity;
export 'selector/type.dart';
export 'selector/universal.dart';

View File

@ -10,11 +10,34 @@ class ComplexSelector extends Selector {
// Indices of [components] that are followed by line breaks.
final List<int> lineBreaks;
int get minSpecificity {
if (_minSpecificity == null) _computeSpecificity();
return _minSpecificity;
}
int _minSpecificity;
int get maxSpecificity {
if (_maxSpecificity == null) _computeSpecificity();
return _maxSpecificity;
}
int _maxSpecificity;
ComplexSelector(Iterable<ComplexSelectorComponent> components,
{Iterable<int> lineBreaks})
: components = new List.unmodifiable(components),
lineBreaks = new List.unmodifiable(lineBreaks);
void _computeSpecificity() {
_minSpecificity = 0;
_maxSpecificity = 0;
for (var component in components) {
if (component is CompoundSelector) {
_minSpecificity += component.minSpecificity;
_maxSpecificity += component.maxSpecificity;
}
}
}
String toString() => components.join(" ");
}

View File

@ -7,6 +7,18 @@ import '../selector.dart';
class CompoundSelector extends Selector implements ComplexSelectorComponent {
final List<SimpleSelector> components;
int get minSpecificity {
if (_minSpecificity == null) _computeSpecificity();
return _minSpecificity;
}
int _minSpecificity;
int get maxSpecificity {
if (_maxSpecificity == null) _computeSpecificity();
return _maxSpecificity;
}
int _maxSpecificity;
CompoundSelector(Iterable<SimpleSelector> components)
: components = new List.unmodifiable(components);
@ -15,5 +27,14 @@ class CompoundSelector extends Selector implements ComplexSelectorComponent {
bool isSuperselector(CompoundSelector selector);
void _computeSpecificity() {
_minSpecificity = 0;
_maxSpecificity = 0;
for (var simple in components) {
_minSpecificity += simple.minSpecificity;
_maxSpecificity += simple.maxSpecificity;
}
}
String toString() => components.join("");
}

View File

@ -2,11 +2,15 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'dart:math' as math;
import '../selector.dart';
class IDSelector extends SimpleSelector {
final String name;
int get minSpecificity => math.pow(super.minSpecificity, 2);
IDSelector(this.name);
List<SimpleSelector> unify(List<SimpleSelector> compound) {

View File

@ -2,6 +2,8 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'dart:math' as math;
import 'package:charcode/charcode.dart';
import '../selector.dart';
@ -15,6 +17,18 @@ class PseudoSelector extends SimpleSelector {
final SelectorList selector;
int get minSpecificity {
if (_minSpecificity == null) _computeSpecificity();
return _minSpecificity;
}
int _minSpecificity;
int get maxSpecificity {
if (_maxSpecificity == null) _computeSpecificity();
return _maxSpecificity;
}
int _maxSpecificity;
PseudoSelector(this.name, this.type, {this.argument, this.selector});
List<SimpleSelector> unify(List<SimpleSelector> compound) {
@ -40,6 +54,36 @@ class PseudoSelector extends SimpleSelector {
return result;
}
void _computeSpecificity() {
if (type == PseudoType.element) {
_minSpecificity = 1;
_maxSpecificity = 1;
return;
}
if (selector == null) {
_minSpecificity = super.minSpecificity;
_maxSpecificity = super.maxSpecificity;
}
if (name == 'not') {
_minSpecificity = 0;
_maxSpecificity = 0;
for (var complex in selector.members) {
_minSpecificity = math.max(_minSpecificity, complex.minSpecificity);
_maxSpecificity = math.max(_maxSpecificity, complex.maxSpecificity);
}
} else {
// This is higher than any selector's specificity can actually be.
_minSpecificity = math.pow(super.minSpecificity, 3);
_maxSpecificity = 0;
for (var complex in selector.members) {
_minSpecificity = math.min(_minSpecificity, complex.minSpecificity);
_maxSpecificity = math.max(_maxSpecificity, complex.maxSpecificity);
}
}
}
// This intentionally uses identity for the selector list, if one is available.
bool operator==(other) =>
other is PseudoSelector &&

View File

@ -5,6 +5,13 @@
import '../selector.dart';
abstract class SimpleSelector extends Selector {
// 1000 is the base used for calculating selector specificity.
//
// The spec says this should be "sufficiently high"; it's extremely unlikely
// that any single selector sequence will contain 1,000 simple selectors.
int get minSpecificity => 1000;
int get maxSpecificity => minSpecificity;
List<SimpleSelector> unify(List<SimpleSelector> compound) {
if (compound.contains(this)) return compound;

View File

@ -7,6 +7,8 @@ import '../selector.dart';
class TypeSelector extends SimpleSelector {
final NamespacedIdentifier name;
int get minSpecificity => 1;
TypeSelector(this.name);
List<SimpleSelector> unify(List<SimpleSelector> compound) {

View File

@ -8,6 +8,8 @@ import '../selector.dart';
class UniversalSelector extends SimpleSelector {
final String namespace;
int get minSpecificity => 0;
UniversalSelector({this.namespace});
List<SimpleSelector> unify(List<SimpleSelector> compound) {