line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
2
|
|
|
|
|
|
|
## CSS Object Oriented - ~/lib/CSS/Object/Builder.pm |
3
|
|
|
|
|
|
|
## Version v0.1.1 |
4
|
|
|
|
|
|
|
## Copyright(c) 2020 DEGUEST Pte. Ltd. |
5
|
|
|
|
|
|
|
## Author: Jacques Deguest <@sitael.local> |
6
|
|
|
|
|
|
|
## Created 2020/06/21 |
7
|
|
|
|
|
|
|
## Modified 2020/06/24 |
8
|
|
|
|
|
|
|
## |
9
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
10
|
|
|
|
|
|
|
package CSS::Object::Builder; |
11
|
|
|
|
|
|
|
BEGIN |
12
|
|
|
|
|
|
|
{ |
13
|
6
|
|
|
6
|
|
53
|
use strict; |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
214
|
|
14
|
6
|
|
|
6
|
|
36
|
use warnings; |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
201
|
|
15
|
6
|
|
|
6
|
|
35
|
use parent qw( Module::Generic ); |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
32
|
|
16
|
6
|
|
|
6
|
|
3978
|
use Devel::Confess; |
|
6
|
|
|
|
|
41150
|
|
|
6
|
|
|
|
|
37
|
|
17
|
6
|
|
|
6
|
|
4164
|
our $VERSION = 'v0.1.0'; |
18
|
|
|
|
|
|
|
}; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub init |
21
|
|
|
|
|
|
|
{ |
22
|
2
|
|
|
2
|
1
|
707
|
my $self = shift( @_ ); |
23
|
2
|
|
50
|
|
|
12
|
my $css = shift( @_ ) || return( $self->error( "No css object was provided." ) ); |
24
|
2
|
50
|
|
|
|
13
|
return( $self->error( "CSS object provided is not a CSS::Object object." ) ) if( !$self->_is_a( $css, 'CSS::Object' ) ); |
25
|
2
|
|
|
|
|
46
|
$self->{_init_strict_use_sub} = 1; |
26
|
2
|
50
|
|
|
|
12
|
$self->SUPER::init( @_ ) || return; |
27
|
2
|
50
|
|
|
|
139
|
$self->css( $css ) || return; |
28
|
2
|
|
|
|
|
63
|
return( $self ); |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
|
31
|
0
|
|
|
0
|
1
|
0
|
sub as_string { return( shift->css->as_string ); } |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
sub at |
34
|
|
|
|
|
|
|
{ |
35
|
1
|
|
|
1
|
1
|
3
|
my $self = shift( @_ ); |
36
|
1
|
|
|
|
|
4
|
my( $name, $value ) = @_; |
37
|
1
|
50
|
|
|
|
12
|
if( $name =~ /^([\-\_][a-zA-Z]+[\-\_])?keyframes/ ) |
38
|
|
|
|
|
|
|
{ |
39
|
1
|
|
|
|
|
3
|
my( $type, $name ) = @_; |
40
|
1
|
|
|
|
|
5
|
return( $self->css->new_keyframes_rule( type => $type, name => $name )->add_to( $self->css ) ); |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
else |
43
|
|
|
|
|
|
|
{ |
44
|
|
|
|
|
|
|
# return( $self->error( "I do not know what kind of rule is \"$type\" for rule name \"$name\"." ) ); |
45
|
0
|
|
|
|
|
0
|
return( $self->css->new_at_rule( name => $name, value => $value )->add_to( $self->css ) ); |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
1
|
|
|
1
|
1
|
379
|
sub charset { return( shift->css->charset( @_ ) ); } |
50
|
|
|
|
|
|
|
|
51
|
1
|
|
|
1
|
1
|
6
|
sub comment { return( shift->css->add_element( CSS::Object::Comment->new( @_ ) ) ); } |
52
|
|
|
|
|
|
|
|
53
|
8
|
|
|
8
|
1
|
33
|
sub css { return( shift->_set_get_object( '__css', 'CSS::Object', @_ ) ); } |
54
|
|
|
|
|
|
|
|
55
|
0
|
|
|
0
|
1
|
0
|
sub current_rule { return( shift->css->elements->last ); } |
56
|
|
|
|
|
|
|
|
57
|
0
|
|
|
0
|
1
|
0
|
sub elements { return( shift->_set_get_array_as_object( 'elements', @_ ) ); } |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub new_rule |
60
|
|
|
|
|
|
|
{ |
61
|
1
|
|
|
1
|
1
|
2
|
my $self = shift( @_ ); |
62
|
1
|
|
50
|
|
|
4
|
my $css = $self->css || return( $self->error( "Our main css object is gone!" ) ); |
63
|
|
|
|
|
|
|
# $self->message( 3, "Creating new CSS::Object::Builder::Rule object with css object '$css' and formatter set to '", $css->format, "'." ); |
64
|
|
|
|
|
|
|
# return( CSS::Object::Builder::Rule->new( @_, |
65
|
|
|
|
|
|
|
# format => $css->format, |
66
|
|
|
|
|
|
|
# debug => $self->debug, |
67
|
|
|
|
|
|
|
# css => $css, |
68
|
|
|
|
|
|
|
# ) ); |
69
|
1
|
|
|
|
|
19
|
my $rule = CSS::Object::Builder::Rule->new( @_, |
70
|
|
|
|
|
|
|
format => $css->format, |
71
|
|
|
|
|
|
|
debug => $self->debug, |
72
|
|
|
|
|
|
|
css => $css, |
73
|
|
|
|
|
|
|
); |
74
|
|
|
|
|
|
|
# $self->message( 3, "Returning rule object '", overload::StrVal( $rule ), "'." ); |
75
|
1
|
|
|
|
|
8
|
return( $rule ); |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub select |
79
|
|
|
|
|
|
|
{ |
80
|
1
|
|
|
1
|
1
|
136
|
my $self = shift( @_ ); |
81
|
1
|
|
50
|
|
|
3
|
my $this = shift( @_ ) || return( $self->error( "No css selector or rule object was provided" ) ); |
82
|
1
|
|
50
|
|
|
3
|
my $css = $self->css || return( $self->error( "Our main css object is gone!" ) ); |
83
|
1
|
|
|
|
|
18
|
my $rule; |
84
|
1
|
50
|
|
|
|
4
|
if( $self->_is_a( $this, 'CSS::Object::Rule' ) ) |
85
|
|
|
|
|
|
|
{ |
86
|
0
|
|
|
|
|
0
|
my $found = 0; |
87
|
|
|
|
|
|
|
$css->elements->foreach(sub |
88
|
|
|
|
|
|
|
{ |
89
|
0
|
0
|
|
0
|
|
0
|
if( overload::StrVal( $_ ) eq overload::StrVal( $rule ) ) |
90
|
|
|
|
|
|
|
{ |
91
|
0
|
|
|
|
|
0
|
$found++; |
92
|
0
|
|
|
|
|
0
|
return; |
93
|
|
|
|
|
|
|
} |
94
|
0
|
|
|
|
|
0
|
}); |
95
|
0
|
|
|
|
|
0
|
$rule = bless( $this, 'CSS::Object::Builder::Rule' ); |
96
|
0
|
|
|
|
|
0
|
$rule->css( $css ); |
97
|
|
|
|
|
|
|
## Unless this object is already added to the CSS::Object we add it now |
98
|
0
|
0
|
|
|
|
0
|
unless( $found ) |
99
|
|
|
|
|
|
|
{ |
100
|
0
|
|
|
|
|
0
|
$rule->add_to( $css ); |
101
|
|
|
|
|
|
|
} |
102
|
0
|
|
|
|
|
0
|
return( $rule ); |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
else |
105
|
|
|
|
|
|
|
{ |
106
|
|
|
|
|
|
|
# $self->message( 3, "Creating new CSS::Object::Builder::Rule object." ); |
107
|
1
|
|
|
|
|
13
|
$rule = $self->new_rule->add_to( $css ); |
108
|
1
|
50
|
|
|
|
4
|
defined( $rule ) || return( $self->error( "Cannot create CSS::Object::Builder::Rule object: ", CSS::Object::Builder::Rule->error ) ); |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
# $self->message( 3, "Rule object is '", overload::StrVal( $rule ), "'." ); |
111
|
1
|
50
|
|
|
|
6
|
if( $self->_is_array( $this ) ) |
112
|
|
|
|
|
|
|
{ |
113
|
1
|
|
|
|
|
11
|
foreach my $s ( @$this ) |
114
|
|
|
|
|
|
|
{ |
115
|
2
|
|
|
|
|
7
|
$css->new_selector( name => $s )->add_to( $rule ); |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
## further calls will be made in the context of the CSS::Object::Builder::Rule package with dynamic method name |
119
|
1
|
|
|
|
|
12
|
return( $rule ); |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
## Dynamic css property name pakcage |
123
|
|
|
|
|
|
|
package CSS::Object::Builder::Rule; |
124
|
|
|
|
|
|
|
BEGIN |
125
|
0
|
|
|
|
|
0
|
{ |
126
|
6
|
|
|
6
|
|
64
|
use strict; |
|
6
|
|
|
|
|
22
|
|
|
6
|
|
|
|
|
152
|
|
127
|
6
|
|
|
6
|
|
32
|
use warnings; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
182
|
|
128
|
6
|
|
|
6
|
|
94
|
use parent qw( CSS::Object::Rule ); |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
34
|
|
129
|
6
|
|
|
6
|
|
341
|
use Devel::Confess; |
|
6
|
|
|
0
|
|
13
|
|
|
6
|
|
|
|
|
25
|
|
130
|
|
|
|
|
|
|
}; |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub init |
133
|
|
|
|
|
|
|
{ |
134
|
1
|
|
|
1
|
|
61
|
my $self = shift( @_ ); |
135
|
1
|
|
|
|
|
72
|
$self->{_init_strict_use_sub} = 1; |
136
|
1
|
|
|
|
|
8
|
$self->SUPER::init( @_ ); |
137
|
1
|
|
|
|
|
3
|
return( $self ); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub comment |
141
|
|
|
|
|
|
|
{ |
142
|
2
|
|
|
2
|
|
6
|
my $self = shift( @_ ); |
143
|
2
|
|
|
|
|
8
|
my $cmt = $self->css->new_comment( @_ ); |
144
|
2
|
50
|
|
|
|
8
|
$cmt->format->indent( $self->elements->length > 0 ? $self->elements->first->format->indent : ' ' ); |
145
|
2
|
|
|
|
|
173
|
return( $self->add_element( $cmt ) ); |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
7
|
|
|
7
|
|
33
|
sub css { return( shift->_set_get_object( 'css', 'CSS::Object', @_ ) ); } |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
AUTOLOAD |
151
|
|
|
|
|
|
|
{ |
152
|
4
|
|
|
4
|
|
42
|
my( $prop_name ) = our $AUTOLOAD =~ /([^:]+)$/; |
153
|
4
|
|
|
|
|
12
|
my $self = shift( @_ ); |
154
|
4
|
50
|
|
|
|
18
|
die( "No method \"$prop_name\" exists in this package \"", __PACKAGE__, "\".\n" ) if( !defined( $self ) ); |
155
|
4
|
|
50
|
|
|
14
|
my $css = $self->css || return( $self->error( "Our main css object is gone!" ) ); |
156
|
4
|
|
|
|
|
84
|
$prop_name =~ tr/_/-/; |
157
|
4
|
50
|
|
|
|
19
|
my $prop_val = $self->_is_array( $_[0] ) |
|
|
50
|
|
|
|
|
|
158
|
|
|
|
|
|
|
? shift( @_ ) |
159
|
|
|
|
|
|
|
: scalar( @_ ) > 1 |
160
|
|
|
|
|
|
|
? [ @_ ] |
161
|
|
|
|
|
|
|
: shift( @_ ); |
162
|
4
|
|
|
|
|
41
|
my $prop = $css->new_property( |
163
|
|
|
|
|
|
|
name => $prop_name, |
164
|
|
|
|
|
|
|
value => $prop_val, |
165
|
|
|
|
|
|
|
debug => $self->debug, |
166
|
|
|
|
|
|
|
); |
167
|
4
|
|
|
|
|
12
|
$prop->format->indent( ' ' ); |
168
|
4
|
|
|
|
|
217
|
$self->elements->push( $prop ); |
169
|
4
|
|
|
|
|
116
|
return( $self ); |
170
|
|
|
|
|
|
|
}; |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
1; |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
__END__ |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=encoding utf-8 |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=head1 NAME |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
CSS::Object::Builder - CSS Object Oriented Builder |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=head1 SYNOPSIS |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
use CSS::Object; |
185
|
|
|
|
|
|
|
my $css = CSS::Object->new( debug => 3 ) || |
186
|
|
|
|
|
|
|
die( CSS::Object->error ); |
187
|
|
|
|
|
|
|
ny $b = $css->builder; |
188
|
|
|
|
|
|
|
$b->select( ['#main_section > .article', 'section .article'] ) |
189
|
|
|
|
|
|
|
->display( 'none' ) |
190
|
|
|
|
|
|
|
->font_size( '+0.2rem' ) |
191
|
|
|
|
|
|
|
->comment( ['Some multiline comment', 'that are made possible with array reference'] ) |
192
|
|
|
|
|
|
|
->text_align( 'center' ) |
193
|
|
|
|
|
|
|
->comment( 'Making it look pretty' ) |
194
|
|
|
|
|
|
|
->padding( 5 ); |
195
|
|
|
|
|
|
|
$b->charset( 'UTF-8' ); |
196
|
|
|
|
|
|
|
$b->at( _webkit_keyframes => 'error' ) |
197
|
|
|
|
|
|
|
->frame( 0, { _webkit_transform => 'translateX( 0px )' }) |
198
|
|
|
|
|
|
|
->frame( 25, { _webkit_transform => 'translateX( 30px )' }) |
199
|
|
|
|
|
|
|
->frame( 45, { _webkit_transform => 'translateX( -30px )' }) |
200
|
|
|
|
|
|
|
->frame( 65, { _webkit_transform => 'translateX( 30px )' }) |
201
|
|
|
|
|
|
|
->frame( 82, { _webkit_transform => 'translateX( -30px )' }) |
202
|
|
|
|
|
|
|
->frame( 94, { _webkit_transform => 'translateX( 30px )' }) |
203
|
|
|
|
|
|
|
->frame( [qw( 35 55 75 87 97 100 )], { _webkit_transform => 'translateX( 0px )' } ); |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=head1 VERSION |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
v0.1.1 |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=head1 DESCRIPTION |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
L<CSS::Object::Builder> is a dynamic object oriented CSS builder |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=head2 new |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
To instantiate a new L<CSS::Object::Builder> object you need to pass it a L<CSS::Object> object and that's it. |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
Optional argument are: |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=over 4 |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=item I<debug> |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
This is an integer. The bigger it is and the more verbose is the output. |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
=back |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=head1 METHODS |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=head2 as_string |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
This is a shorthand for calling L<CSS::Object/as_string> using our L</css> method. |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=head2 at |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
This takes an at-mark type parameter as first argument, and the name of the at-mark rule. It returns an object from the proper class. For example, a C<@keyframes> rule would return a L<CSS::Object::Rule::Keyframes>. |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=head2 charset |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
This takes an encoding as unique argument, and no matter when it is called in the chain of method calls, this will always be placed at the top of the stylesheet. |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=head2 comment |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
Provided with a string or an array reference of comment lines, and this will return an L<CSS::Object::Comment> object. |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=head2 css |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
This sets or gets the required L<CSS::Object> for this parser. The parser uses this method and the underlying object to access L<CSS::Object> methods and store css rules using L<CSS::Object/add_element> |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=head2 current_rule |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
Returns the last added rule from L<CSS::Object> list of rules by calling L<Module::Generic::Array/last> on L<CSS::Object/elements> which returns a L<Module::Generic::Array> object. |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=head2 elements |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
Sets or gets the list of css elements. This is a L<Module::Generic::Array>, but is not used. I should remove it. |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=head2 new_at_rule |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
This creates and returns a new L<CSS::Object::Builder::AtRule> object. This should be moved under L<CSS::Object> |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=head2 new_keyframes_rule |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
This creates and returns a new L<CSS::Object::Builder::KeyframesRule-> object. This should be moved under L<CSS::Object> |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=head2 new_rule |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
This creates and returns a new L<CSS::Object::Builder::Rule> object. L<CSS::Object::Builder::Rule> class allos for dynamic method call to create and add css properties inside a css rule. |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=head2 select |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
This takes either a css selector as a string or an array reference of css selectors. It then returns a L<CSS::Object::Builder::Rule>, which is a special class with dynamic method using AUTOLOAD. This makes it possible to call the hundred of css property as method. |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
Since those css properties are called as perl method, dashes have to be expressed as underline, such as: |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
$b->select( '.my-class' )->_moz_transition( 'all .25s ease' ); |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
This would be interpreted as: |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
.my-class |
282
|
|
|
|
|
|
|
{ |
283
|
|
|
|
|
|
|
-moz-transition: all .25s ease; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
=head1 AUTHOR |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
Jacques Deguest E<lt>F<jack@deguest.jp>E<gt> |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=head1 SEE ALSO |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
L<CSS::Object> |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
Copyright (c) 2020 DEGUEST Pte. Ltd. |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
You can use, copy, modify and redistribute this package and associated |
299
|
|
|
|
|
|
|
files under the same terms as Perl itself. |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=cut |