File Coverage

blib/lib/POE/XUL/Style.pm
Criterion Covered Total %
statement 79 85 92.9
branch 29 38 76.3
condition 9 15 60.0
subroutine 15 15 100.0
pod 0 5 0.0
total 132 158 83.5


line stmt bran cond sub pod time code
1             package POE::XUL::Style;
2             # $Id$
3             # Copyright Philip Gwyn 2008-2010. All rights reserved.
4              
5 21     21   66 use strict;
  21         20  
  21         489  
6 21     21   65 use warnings;
  21         19  
  21         442  
7              
8 21     21   67 use Scalar::Util qw( refaddr );
  21         22  
  21         752  
9              
10 21     21   65 use Carp;
  21         20  
  21         2240  
11              
12 17     17   581 use overload '""' => sub { $_[0]->as_string },
13 11     11   35 '+' => sub { refaddr $_[0] },
14 76     76   308 'bool' => sub { 1 },
15 21     21   5419 fallback => 1;
  21         4370  
  21         275  
16              
17 21     21   1507 use constant DEBUG => 0;
  21         19  
  21         20705  
18              
19             our $VERSION = '0.0601';
20              
21             my %EQUIV = qw(
22             border-top border
23             border-left border
24             border-bottom border
25             border-right border
26             overflow-x overflow
27             overflow-y overflow
28             -moz-outline outline
29             );
30              
31             my %SUBSET = ( # property ... offsets
32             'margin-top' => [ 'margin', 0, 0, 0, 0 ],
33             'margin-right' => [ 'margin', 0, 1, 1, 1 ],
34             'margin-bottom' => [ 'margin', 0, 0, 2, 2 ],
35             'margin-left' => [ 'margin', 0, 1, 1, 3 ],
36             'padding-top' => [ 'padding', 0, 0, 0, 0 ],
37             'padding-right' => [ 'padding', 0, 1, 1, 1 ],
38             'padding-bottom' => [ 'padding', 0, 0, 2, 2 ],
39             'padding-left' => [ 'padding', 0, 1, 1, 3 ],
40             'border-width' => [ 'border', 0, 0, 0 ],
41             'border-style' => [ 'border', 1, 1, 1 ],
42             'border-color' => [ 'border', 2, 2, 2 ],
43             'border-top-width' => [ 'border-top', 0, 0, 0 ],
44             'border-top-style' => [ 'border-top', 1, 1, 1 ],
45             'border-top-color' => [ 'border-top', 2, 2, 2 ],
46             'border-right-width' => [ 'border-right', 0, 0, 0 ],
47             'border-right-style' => [ 'border-right', 1, 1, 1 ],
48             'border-right-color' => [ 'border-right', 2, 2, 2 ],
49             'border-bottom-width' => [ 'border-bottom', 0, 0, 0 ],
50             'border-bottom-style' => [ 'border-bottom', 1, 1, 1 ],
51             'border-bottom-color' => [ 'border-bottom', 2, 2, 2 ],
52             'border-left-width' => [ 'border-left', 0, 0, 0 ],
53             'border-left-style' => [ 'border-left', 1, 1, 1 ],
54             'border-left-color' => [ 'border-left', 2, 2, 2 ],
55             'outline-width' => [ 'outline', 0, 0, 0 ],
56             'outline-style' => [ 'outline', 1, 1, 1 ],
57             'outline-color' => [ 'outline', 2, 2, 2 ],
58             '-moz-outline-width' => [ '-moz-outline', 0, 0, 0 ],
59             '-moz-outline-style' => [ '-moz-outline', 1, 1, 1 ],
60             '-moz-outline-color' => [ '-moz-outline', 2, 2, 2 ],
61             'list-style-type' => [ 'list-style', 0, 0, 0 ],
62             'list-style-position' => [ 'list-style', 1, 1, 1 ],
63             'list-style-image' => [ 'list-style', 2, 2, 2 ],
64             # http://developer.mozilla.org/en/docs/CSS:-moz-border-radius says:
65             # "If fewer than 4 values are given, the list of values is repeated
66             # to fill the remaining values."
67             # I take this to mean:
68             # 1 -> tl=1 tr=1 br=1 bl=1
69             # 1 2 -> tl=1 tr=2 br=1 bl=2
70             # 1 2 3 -> tl=1 tr=2 br=3 bl=1
71             '-moz-border-radius-topleft' => [ '-moz-border-radius', 0, 0, 0, 0 ],
72             '-moz-border-radius-topright' => [ '-moz-border-radius', 0, 1, 1, 1 ],
73             '-moz-border-radius-bottomright' => [ '-moz-border-radius', 0, 0, 2, 2 ],
74             '-moz-border-radius-bottomleft' => [ '-moz-border-radius', 0, 1, 0, 3 ],
75             );
76              
77             ##############################################################
78             sub new
79             {
80 19     19 0 41 my( $package, $init ) = @_;
81 19         60 my $self = bless { properties => {}, text => [] }, $package;
82 19 100       70 $self->parse( $init ) if $init;
83 19         41 return $self;
84             }
85              
86             ##############################################################
87             sub as_string
88             {
89 19     19 0 291 my( $self ) = @_;
90 19         18 return join '', @{ $self->{text} };
  19         136  
91             }
92              
93             ##############################################################
94             sub parse
95             {
96 17     17 0 675 my( $self, $string ) = @_;
97 17 50       51 return unless defined $string;
98             # TODO : add ; to last property text
99 17         34 while( $string ) {
100             # line starts with a comment
101 42 100       297 if( $string =~ s,^(\s*/\*[^*]*\*+([^/*][^*]*\*+)*/\s*),,s ) {
    50          
    50          
102 4         5 push @{ $self->{text} }, $1;
  4         13  
103             }
104             # line start with whitespace
105             elsif( $string =~ s,^(\s+),,s ) {
106 0         0 my $ws = $1;
107 0 0 0     0 if( @{ $self->{text} } and $self->{text}[-1] =~ /\s+$/ ) {
  0         0  
108 0         0 $self->{text}[-1] .= $ws;
109             }
110             else {
111 0         0 push @{ $self->{text} }, $ws;
  0         0  
112             }
113             }
114             # property: value
115             # Note this fails for property: "some; value"; please DON'T DO THAT
116             elsif( $string =~ s,^((-?[_a-z][-_a-zA-Z]*)\s*:\s*(.*?)\s*(\Z|;\s*)),,is ) {
117 38         28 push @{ $self->{text} }, $1;
  38         98  
118             $self->{prop}{lc $2} = {
119             # name => lc( $2 ),
120 38         180 text=>\$self->{text}[-1],
121             value => $3
122             };
123             }
124             }
125             }
126              
127             ##############################################################
128             sub get
129             {
130 70     70 0 67 my( $self, $key ) = @_;
131 70         67 $key = lc $key;
132 70         47 my $rv;
133 70 100 66     208 if( $self->{prop}{ $key } ) {
    100          
    100          
134 37         98 $rv = $self->{prop}{ $key }{value};
135             }
136             elsif( $EQUIV{$key} and $self->{prop}{ $EQUIV{$key} } ) {
137 3         4 $rv = $self->{prop}{ $EQUIV{$key} }{value};
138             }
139             elsif( $SUBSET{ $key } ) {
140 26         21 my $subset = $SUBSET{$key};
141 26         38 my $value = $self->get( $subset->[0] );
142 26 50       38 if( $value ) {
143 26         58 my @values = split ' ', $value, $#$subset;
144 26         26 my $n = 0+@values;
145 26 50       61 $rv = $values[ $subset->[$n] ] if $n > 0;
146             }
147             }
148 70 100       90 $rv = '' unless defined $rv;
149 70         213 return $rv;
150             }
151              
152              
153             ##############################################################
154             sub set
155             {
156 18     18 0 21 my( $self, $key, $value ) = @_;
157 18         21 $key = lc $key;
158 18         27 my $prop = $self->{prop}{ $key };
159 18         22 $value =~ s/;\s*$//;
160 18 100       92 unless( $prop ) {
161             # special case...
162 9 50 66     39 return if !$value and $key eq 'display';
163              
164             $self->{text}[-1] .= ";"
165 9 100 100     10 if @{$self->{text}} and $self->{text}[-1] !~ m([;/]\s*$)s;
  9         56  
166 9         10 push @{ $self->{text} }, "$key: $value;\n";
  9         23  
167             $self->{prop}{ $key } = { value => $value,
168             # name => $key,
169 9         41 text => \$self->{text}[-1]
170             };
171             }
172             else {
173             # special case...
174 9 100 66     37 if( !$value and $key eq 'display' ) {
175 5         6 ${ $prop->{text} } = '';
  5         9  
176 5         11 delete $self->{prop}{ lc $key };
177             }
178             else {
179 4         4 ${ $prop->{text} } =~ s/\Q$prop->{value}/$value/;
  4         58  
180 4         8 $prop->{value} = $value;
181             }
182             }
183 18 100       51 $POE::XUL::Node::CM->after_style_change( $self, $key, $value )
184             if $POE::XUL::Node::CM;
185 18         33 return;
186             }
187              
188             ##############################################################
189             sub AUTOLOAD
190             {
191 62     62   116 my( $self, $value ) = @_;
192 62         57 my $key = our $AUTOLOAD;
193 62 50       147 return if $key =~ /DESTROY$/;
194 62         224 $key =~ s/^.*:://;
195              
196 62         222 $key =~ s/([A-Z])/-\L$1/g;
197 62 100       106 if( 1 == @_ ) {
198 44         76 return $self->get( $key );
199             }
200             else {
201 18         37 return $self->set( $key, $value );
202             }
203            
204             }
205              
206             1;
207              
208             __END__