OLD | NEW |
| (Empty) |
1 library selector; | |
2 | |
3 import 'package:html5lib/dom.dart'; | |
4 | |
5 class ContainsSelector { | |
6 String selector; | |
7 RegExp regexp; | |
8 | |
9 ContainsSelector(this.selector, regexp) { | |
10 this.regexp = new RegExp(regexp); | |
11 } | |
12 } | |
13 | |
14 RegExp _SELECTOR_REGEXP = new RegExp(r'^(?:([\w\-]+)|(?:\.([\w\-]+))|(?:\[([\w\-
\*]+)(?:=([^\]]*))?\]))'); | |
15 RegExp _COMMENT_COMPONENT_REGEXP = new RegExp(r'^\[([\w\-]+)(?:\=(.*))?\]$'); | |
16 RegExp _CONTAINS_REGEXP = new RegExp(r'^:contains\(\/(.+)\/\)$'); // | |
17 RegExp _ATTR_CONTAINS_REGEXP = new RegExp(r'^\[\*=\/(.+)\/\]$'); // | |
18 | |
19 class _SelectorPart { | |
20 final String element; | |
21 final String className; | |
22 final String attrName; | |
23 final String attrValue; | |
24 | |
25 const _SelectorPart.fromElement(String this.element) | |
26 : className = null, attrName = null, attrValue = null; | |
27 | |
28 const _SelectorPart.fromClass(String this.className) | |
29 : element = null, attrName = null, attrValue = null; | |
30 | |
31 | |
32 const _SelectorPart.fromAttribute(String this.attrName, String this.attrValue) | |
33 : element = null, className = null; | |
34 | |
35 toString() => | |
36 element == null | |
37 ? (className == null | |
38 ? (attrValue == '' ? '[$attrName]' : '[$attrName=$attrValue]') | |
39 : '.$className') | |
40 : element; | |
41 } | |
42 | |
43 List<_SelectorPart> _splitCss(String selector) { | |
44 List<_SelectorPart> parts = []; | |
45 var remainder = selector; | |
46 var match; | |
47 while (!remainder.isEmpty) { | |
48 if ((match = _SELECTOR_REGEXP.firstMatch(remainder)) != null) { | |
49 if (match[1] != null) { | |
50 parts.add(new _SelectorPart.fromElement(match[1].toLowerCase())); | |
51 } else if (match[2] != null) { | |
52 parts.add(new _SelectorPart.fromClass(match[2].toLowerCase())); | |
53 } else if (match[3] != null) { | |
54 var attrValue = match[4] == null ? '' : match[4].toLowerCase(); | |
55 parts.add(new _SelectorPart.fromAttribute(match[3].toLowerCase(), | |
56 attrValue)); | |
57 } else { | |
58 throw "Missmatched RegExp $_SELECTOR_REGEXP on $remainder"; | |
59 } | |
60 } else { | |
61 throw "Unknown selector format '$remainder'."; | |
62 } | |
63 remainder = remainder.substring(match.end); | |
64 } | |
65 return parts; | |
66 } | |
67 | |
68 bool matchesNode(Node node, String selector) { | |
69 var match, selectorParts; | |
70 if ((match = _CONTAINS_REGEXP.firstMatch(selector)) != null) { | |
71 if (node is! Text) { | |
72 return false; | |
73 } | |
74 return new RegExp(match.group(1)).hasMatch((node as Text).value); | |
75 } else if ((match = _ATTR_CONTAINS_REGEXP.firstMatch(selector)) != null) { | |
76 if (node is! Element) { | |
77 return false; | |
78 } | |
79 var regexp = new RegExp(match.group(1)); | |
80 for (String attrName in node.attributes.keys) { | |
81 if (regexp.hasMatch(node.attributes[attrName])) { | |
82 return true; | |
83 } | |
84 } | |
85 return false; | |
86 } else if ((selectorParts = _splitCss(selector)) != null) { | |
87 if (node is! Element) { | |
88 return false; | |
89 } | |
90 String nodeName = node.tagName.toLowerCase(); | |
91 | |
92 bool stillGood = true; | |
93 selectorParts.forEach((_SelectorPart part) { | |
94 if (part.element != null) { | |
95 if (nodeName != part.element) { | |
96 stillGood = false; | |
97 } | |
98 } else if (part.className != null) { | |
99 if (node.attributes['class'] == null || | |
100 !node.attributes['class'].split(' ').contains(part.className)) { | |
101 stillGood = false; | |
102 } | |
103 } else if (part.attrName != null) { | |
104 String matchingKey = _matchingKey(node.attributes.keys, part.attrName); | |
105 if (matchingKey == null || part.attrValue == '' ? | |
106 node.attributes[matchingKey] == null : | |
107 node.attributes[matchingKey] != part.attrValue) { | |
108 stillGood = false; | |
109 } | |
110 } | |
111 }); | |
112 | |
113 return stillGood; | |
114 } | |
115 | |
116 throw new ArgumentError('Unsupported Selector: $selector'); | |
117 } | |
118 | |
119 String _matchingKey(Iterable keys, String attrName) => | |
120 keys.firstWhere( | |
121 (key) => new RegExp('^${attrName.replaceAll('*', r'[\w\-]+')}\$').hasMat
ch(key.toString()), | |
122 orElse: () => null); | |
OLD | NEW |