File Coverage

blib/lib/OCBNET/CSS3/Styles.pm
Criterion Covered Total %
statement 86 92 93.4
branch 33 38 86.8
condition 4 10 40.0
subroutine 10 12 83.3
pod 0 9 0.0
total 133 161 82.6


line stmt bran cond sub pod time code
1             ###################################################################################################
2             # Copyright 2013/2014 by Marcel Greter
3             # This file is part of OCBNET-CSS3 (GPL3)
4             ####################################################################################################
5             package OCBNET::CSS3::Styles;
6             ####################################################################################################
7             our $VERSION = '0.2.5';
8             ####################################################################################################
9            
10 11     11   61 use strict;
  11         85  
  11         353  
11 11     11   50 use warnings;
  11         21  
  11         271  
12            
13             ####################################################################################################
14 11     11   58 use Scalar::Util 'blessed';
  11         21  
  11         16131  
15             ####################################################################################################
16            
17             our %matcher;
18             our %default;
19             our %setter;
20             our %getter;
21             our %list;
22            
23             ####################################################################################################
24            
25             # static function only
26             # never call as method
27             sub register
28             {
29            
30             # get input arguments of static call
31 62     62 0 107 my ($key, $matcher, $default, $list) = @_;
32            
33             # store the matcher by key
34 62         139 $matcher{$key} = $matcher;
35            
36             # store the defaults by key
37 62         107 $default{$key} = $default;
38            
39             # store list attribute
40             # means we store as array
41             # and can parse comma lists
42 62         162 $list{$key} = $list;
43            
44             }
45             # EO fn register
46            
47             # static function only
48             # never call as method
49             sub setter
50             {
51            
52             # get input arguments of static call
53 0     0 0 0 my ($key, $setter) = @_;
54            
55             # store the matcher by key
56 0         0 $setter{$key} = $setter;
57            
58             }
59             # EO setter
60            
61             # static function only
62             # never call as method
63             sub getter
64             {
65            
66             # get input arguments of static call
67 2     2 0 4 my ($key, $getter) = @_;
68            
69             # store the matcher by key
70 2         6 $getter{$key} = $getter;
71            
72             }
73             # EO getter
74            
75             ####################################################################################################
76            
77             # create a new object
78             # ***************************************************************************************
79             sub new
80             {
81            
82             # package name
83 211     211 0 1076 my ($pckg, $node) = @_;
84            
85             # create a new instance
86 211         550 my $self = { 'node' => $node, 'ids' => {} };
87            
88             # bless instance into package
89 211         1092 return bless $self, $pckg;
90            
91             }
92             # EO constructor
93            
94             ####################################################################################################
95            
96             # basic getter
97             # ***************************************************************************************
98 72     72 0 279 sub node { $_[0]->{'node'} }
99            
100             ####################################################################################################
101            
102             # set key/value pair
103             # ***************************************************************************************
104             sub set
105             {
106            
107             # list variable
108             # parse optional
109 136     136 0 172 my %longhands;
110            
111             # get input arguments
112 136         284 my ($self, $key, $value) = @_;
113            
114             # check if we have a matcher
115 136 100       293 if (exists $matcher{$key})
116             {
117            
118             # get the configured matcher
119             # might be a shorthand value
120 113         172 my $matcher = $matcher{$key};
121            
122             # rewrite longhand to shorthand
123 113 100       280 if (ref($matcher) eq 'Regexp')
124             {
125             # must only match that single keys regex
126 82         313 $matcher = { 'ordered' => [ [ $key ] ] };
127             }
128            
129             # matcher is a shorthand
130 113 100       245 if (ref($matcher) eq 'HASH')
131             {
132            
133             # create arrays for all longhands
134 112 100       116 $longhands{$_} = [] foreach @{$matcher->{'prefix'} || []};
  112         617  
135 112 100       139 $longhands{$_->[0]} = [] foreach @{$matcher->{'ordered'} || []};
  112         633  
136             # $longhands{$_} = [] foreach @{$matcher->{'postfix'} || []};
137            
138             # parse list
139             # exit if not
140 112         380 while (1)
141             {
142            
143             # declare variables
144 121         131 my ($prop);
145            
146             # get optional options from shorthand
147             # create a copy of the array, so we can
148             # manipulate them later for loop control
149 121 100       116 my $prefix = [ @{$matcher->{'prefix'} || []} ];
  121         468  
150 121 100       153 my $ordered = [ @{$matcher->{'ordered'} || []} ];
  121         377  
151             # my $postfix = [ @{$matcher->{'postfix'} || []} ];
152            
153             # set defaults for all optional longhands
154 121         166 push @{$longhands{$_}}, $default{$_} foreach @{$prefix};
  121         252  
  58         239  
155 121         131 push @{$longhands{$_->[0]}}, $default{$_->[0]} foreach @{$ordered};
  121         186  
  154         533  
156             # push @{$longhands{$_}}, $default{$_} foreach @{$postfix};
157            
158             # optional prefixes (can occur in any order)
159 121         201 for (my $i = 0; $i < scalar(@{$prefix}); $i++)
  194         495  
160             {
161            
162             # get property name
163 73         119 my $prop = $prefix->[$i];
164            
165             # get the configured matcher
166             # might be a shorthand value
167 73         129 my $regex = $matcher{$prop};
168            
169 73 100       183 if (ref($regex) eq 'HASH')
170 13         33 { $regex = $regex->{'matcher'} }
171            
172             # test if we have found this property
173 73 100       22753 if ($value =~ s/\A\s*($regex)\s*//s)
174             {
175             # matches this property
176 30         116 $longhands{$prop}->[-1] = $1;
177             # remove from search and
178 30         39 splice(@{$prefix}, $i, 1);
  30         66  
179             # restart loop
180 30         45 $i = -1; next;
  30         382  
181             }
182             # EO match regex
183            
184             }
185             # EO each prefix
186            
187             # mandatory longhands
188 121         125 foreach $prop (@{$ordered})
  121         194  
189             {
190            
191             # get property name
192 154         194 my $name = $prop->[0];
193             # get optinal alternative
194             # string: eval to this if nothing set
195             # regexp: is optionally fallowed by this
196 154         177 my $alt = $prop->[1];
197            
198             # get the configured matcher
199             # might be a shorthand value
200 154         216 my $regex = $matcher{$name};
201            
202             # optional alternative
203             # delimited from property
204 154 100       324 if (ref($alt) eq 'Regexp')
205             {
206             # test if we found the delimiter
207             # if not the value is not mandatory
208 1 50       22 next unless ($value =~ s/\A\s*($alt)\s*//s)
209             }
210            
211             # test if we have found this property
212 154 100 33     14018 if ($value =~ s/\A\s*($regex)\s*//s)
    50          
213             {
214             # matches this property
215 120         829 $longhands{$name}->[-1] = $1;
216             }
217             # EO match regex
218            
219             # has another alternative (string)
220             elsif (defined $alt && ref($alt) eq '')
221             {
222             # eval to another longhand property
223             # this property should be parsed already
224 34         122 $longhands{$name}->[-1] = $longhands{$alt}->[-1];
225             }
226            
227             }
228             # EO each longhand
229            
230             # # optional postfixes (can occur in any order)
231             # for (my $i = 0; $i < scalar(@{$postfix}); $i++)
232             # {
233            
234             # # get property name
235             # my $prop = $postfix->[$i];
236            
237             # # get the configured matcher
238             # # might be a shorthand value
239             # my $regex = $matcher{$prop};
240            
241             # # test if we have found this property
242             # if ($value =~ s/\A\s*($regex)\s*//s)
243             # {
244             # # matches this property
245             # $longhands{$prop}->[-1] = $1;
246             # # remove from search and
247             # splice(@{$postfix}, $i, 1);
248             # # restart loop
249             # $i = -1; next;
250             # }
251             # # EO match regex
252            
253             # }
254             # # EO each postfix
255            
256             # check if we should parse in list mode
257             # if we find a comma we will parse again
258 121 100 100     571 next if $list{$key} && $value =~ s/\A\s*,\s*//s;
259            
260             # end loop
261 112         325 last;
262            
263             }
264             # EO while 1
265            
266            
267             }
268             # EO if HASH
269            
270             # assertion for hash type
271 1         8 else { die "unknown type"; }
272            
273             }
274             # EO if matcher
275             else
276             {
277             # trim whitespace for value
278 23         110 $value =~ s/(?:\A\s+|\s+\z)//g;
279             # store the original value
280 23         83 $longhands{$key} = [ $value ];
281             }
282            
283             # check if we have a new id
284 135 100       303 if ($longhands{'css-id'})
285             {
286             # store all ids in our global hash
287 36         43 foreach my $id (@{$longhands{'css-id'}})
  36         93  
288 36         93 { $self->root->{'ids'}->{$id} = $self->node; }
289             }
290             # EO if css-id
291            
292             #####################################################
293             # implement action to setup styles
294             #####################################################
295             # print "x" x 40, "\n";
296             # foreach my $name (keys %longhands)
297             # { printf "%s => %s\n", $name, join(", ", @{$longhands{$name}}); }
298             #####################################################
299            
300             # overwrite styles with longhands
301 135         382 foreach my $name (keys %longhands)
302             {
303             # check if key is another shorthand
304 216 100       493 if (ref($matcher{$name}) eq 'HASH')
305             {
306             # pass this "shorthand" value to parse longhands
307 11         21 $self->set($name, join(',', @{$longhands{$name}}));
  11         67  
308             }
309             # it's a longhand
310             else
311             {
312             # just store the parsed value
313 205         356 $self->{$name} = $longhands{$name};
314             # call setter hook if one was defined
315 205 50       531 $setter{$name}->($self) if $setter{$name};
316             }
317             }
318             # EO each longhand
319            
320             # return results
321 135         803 return \ %longhands;
322            
323             }
324             # EO sub set
325            
326             ####################################################################################################
327            
328             # get value of a longhand
329             # ***************************************************************************************
330             sub get
331             {
332            
333             # get input arguments
334 0     0 0 0 my ($self, $key, $idx) = @_;
335            
336             # check if found in current styles
337 0 0 0     0 if (exists $self->{$key}->[$idx || 0])
338 0   0     0 { return $self->{$key}->[$idx || 0]; }
339            
340             # nothing found
341 0         0 return undef;
342            
343             }
344            
345             ####################################################################################################
346            
347             # get list of all longhands
348             # ***************************************************************************************
349             sub list
350             {
351            
352             # get input arguments
353 72     72 0 113 my ($self, $key) = @_;
354            
355             # check if found in current styles
356 72 100       165 if (exists $self->{$key})
357 62         73 { return @{$self->{$key}}; }
  62         247  
358            
359             # nothing found
360 10         37 return ();
361            
362             }
363            
364             ####################################################################################################
365            
366             # access helper for node root
367             # ***************************************************************************************
368 36     36 0 76 sub root { shift->node->root(@_) }
369            
370             ####################################################################################################
371             ####################################################################################################
372             1;
373