forked from cssapply/CSSApply
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathCSSSelectorTree.m
More file actions
154 lines (135 loc) · 3.93 KB
/
CSSSelectorTree.m
File metadata and controls
154 lines (135 loc) · 3.93 KB
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
//
// CSSSelectorTree.m
// CSSSample
//
// Created by Sam Stewart on 7/16/11.
// Copyright 2011 Float:Right Ltd. All rights reserved.
//
/**
@class CSSSelectorTree
This custom data structure represents our css tree we inflate after parsing. In fact, it's not really a tree but more of a list of matching "paths".
An example will hopefully clarify this:
*/
#import "CSSSelectorTree.h"
#import "CSSSelector.h"
@implementation CSSSelectorTree
//@dynamic score;
@synthesize nodes = _nodes;
@synthesize rules = _rules;
@synthesize selector = _selector;
- (id)initWithSelector:(CSSSelector *)selector_arg
{
if (self = [super init])
{
_selector = selector_arg;
}
return self;
}
- (void)dealloc
{
_rules = nil;
_nodes = nil;
_selector = nil;
}
/** Convenience method for breaking up multi level selector
into multiple smaller selectors wrapped in subtrees. Builds the subtrees in reverse order of specificity.*/
+ (NSArray*)subtreesFromSelector:(NSString *)selector
{
NSArray *comps = [selector componentsSeparatedByString:@" "];
NSMutableArray *subtrees = [NSMutableArray arrayWithCapacity:20];
for (NSString *comp in comps)
{
CSSSelector *selector = [[CSSSelector alloc] initWithSelectorStr:comp];
CSSSelectorTree *subtree = [[CSSSelectorTree alloc] initWithSelector:selector];
// make sure it's in reverse order.
[subtrees insertObject:subtree atIndex:0];
}
return subtrees;
}
+ (CSSSelectorTree*)chainSubtrees:(NSArray *)subtrees
{
if (![subtrees count]) return nil;
//start with most specific and begin chaining
CSSSelectorTree *cur_parent = [subtrees objectAtIndex:0];
CSSSelectorTree *top_parent = cur_parent;
for (CSSSelectorTree *subtree in subtrees)
{
if (subtree != cur_parent)
{
[cur_parent.nodes addObject:subtree];
cur_parent = subtree; //move into subtree
}
}
return top_parent;
}
#pragma mark Accessors
/*
* Sort nodes so that the least-specific selector is at the top.
*/
- (void)sortNodes
{
[self.nodes sortUsingComparator:(NSComparator)^(CSSSelectorTree *a_sel, CSSSelectorTree *b_sel)
{
[a_sel sortNodes];
[b_sel sortNodes];
NSInteger a_score = [a_sel score];
NSInteger b_score = [b_sel score];
if (a_score < b_score)
return NSOrderedAscending;
else if(a_score > b_score)
return NSOrderedDescending;
else
return NSOrderedSame;
}];
}
/** Searches subnodes for partial matches for the selector you pass in.
Remember, only a few properties have to match for the entire selector to match.
@return Array of CSSSelectorTree nodes.
*/
- (NSArray*)find:(CSSSelector *)selector_arg
{
NSMutableArray *results = [NSMutableArray arrayWithCapacity:20];
for (CSSSelectorTree *node in self.nodes)
{
if ([node.selector doesMatchIntoSelector:selector_arg])
{
[results addObject:node];
}
}
return results;
}
- (BOOL)isLeaf
{
return (self.nodes.count == 0);
}
- (NSString*)name
{
// grab our selector entire selector string..
return self.selector.selector;
}
/** Takes the biggest child score to ensure we reflect the child nodes accurately.
Note: this may not be quite right. How do we know we "own" the biggest node?*/
- (NSInteger)score
{
if ([self isLeaf]) return _selector.score;
NSInteger max_score = 0;
for (CSSSelectorTree* node in self.nodes)
{
//NSInteger score = [node score];
max_score = MAX(max_score, node.score); //(score > max_score ? score : max_score);
}
return max_score;
}
- (NSMutableArray*) nodes
{
if (!_nodes)
{
_nodes = [[NSMutableArray alloc] initWithCapacity:20];
}
return _nodes;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"CSSSelectorTree [%@]", _selector];
}
@end