File Coverage

blib/lib/Mojo/DOM/Role/Style.pm
Criterion Covered Total %
statement 59 69 85.5
branch 12 16 75.0
condition 21 26 80.7
subroutine 11 12 91.6
pod 1 1 100.0
total 104 124 83.8


line stmt bran cond sub pod time code
1 4     4   1710899 use strict;
  4         8  
  4         128  
2 4     4   13 use warnings;
  4         7  
  4         519  
3              
4             package Mojo::DOM::Role::Style::Value;
5              
6             # use Scalar::Util qw/blessed/;
7              
8             use overload
9 5     5   159 '""' => sub { ${$_[0]}[0] },
  5         27  
10 6     6   11 '%{}' => sub { ${$_[0]}[1] },
  6         27  
11 4     4   26 fallback => 1;
  4         6  
  4         37  
12              
13             sub new {
14 11     11   19 my ($class, $css, $hash) = @_;
15 11         74 return bless [$css, $hash], $class;
16             }
17              
18             package Mojo::DOM::Role::Style;
19              
20             # ABSTRACT: Adds a style method to Mojo::DOM
21              
22 4     4   526 use Mojo::Base -role;
  4         6  
  4         30  
23 4     4   2246 use List::Util qw/uniq/;
  4         8  
  4         4147  
24              
25             sub style {
26 16     16 1 4129 my $self = shift;
27              
28 16   100     39 my $css = $self->attr('style') // '';
29 16         192 my ($h, $k) = _from_css($css);
30              
31             # Getter - no args
32 16 100       39 return Mojo::DOM::Role::Style::Value->new($css, $h) unless @_;
33              
34             # Single string arg - get one property value
35 5 100 100     30 if (@_ == 1 && !ref $_[0] && defined $_[0] && $_[0] !~ /:/) {
      100        
      66        
36 1         6 return $h->{$_[0]};
37             }
38              
39 4 50 100     12 if (@_ == 1 && !ref $_[0] && defined $_[0] && $_[0] =~ /:/) {
      66        
      33        
40 0         0 $self->attr(style => $_[0]);
41 0         0 return $self
42             }
43              
44             # Undef - remove style attribute entirely
45 4 100 100     8 if (@_ == 1 && !defined $_[0]) {
46 1         4 $self->attr({style => undef});
47 1         16 return $self;
48             }
49              
50             # Hashref - merge into existing style
51 3 100 66     11 if (@_ == 1 && ref $_[0] eq 'HASH') {
52 2         2 $h->{$_} = $_[0]->{$_} for keys %{$_[0]};
  2         9  
53 2         4 my $new = _to_css($h, $k);
54 2         5 $self->attr(style => $new);
55             # return Mojo::DOM::Role::Style::Value->new($new, $h);
56 2         39 return $self
57             }
58              
59             # Flat list - replace entire style
60 1 50       5 if (@_ % 2 == 0) {
61 1         1 my @keys = do { my %seen; grep { !$seen{$_}++ } @_[ grep { !($_ % 2) } 0 .. $#_ ] };
  1         2  
  1         2  
  1         4  
  2         4  
62 1         2 my $new = _to_css({@_}, \@keys);
63 1         4 $self->attr(style => $new);
64             # return Mojo::DOM::Role::Style::Value->new($new, {@_});
65 1         15 return $self;
66             }
67             }
68              
69             sub _to_css {
70 3     3   4 my ($h, $k) = @_;
71 3         14 $k = [ uniq(@$k, keys %$h) ];
72 3         6 return join ';', map { $_ . ':' . $h->{$_} } @$k;
  7         19  
73             }
74              
75             sub __from_css {
76 0     0   0 my $css = shift;
77 0 0       0 return ({}, []) unless $css;
78              
79 0         0 my $k = [ map { /^([^:]+?)\s*:/; $1 } split /\s*;\s*/, $css ];
  0         0  
  0         0  
80 0         0 my $h = { map { split /\s*:\s*/, $_, 2 } split /\s*;\s*/, $css };
  0         0  
81              
82 0         0 return ($h, $k);
83             }
84              
85             sub _from_css {
86 16     16   24 my $css = shift;
87 16 100       45 return ({}, []) unless $css;
88              
89 15         93 my @declarations = split /\s*;\s*(?![^(]*\))/, $css;
90              
91 15         24 my $k = [ map { /^([^:]+?)\s*:/; $1 } @declarations ];
  41         115  
  41         75  
92 15         25 my $h = { map { split /\s*:\s*/, $_, 2 } @declarations };
  41         119  
93              
94 15         38 return ($h, $k);
95             }
96              
97             1;
98              
99             =encoding utf8
100             =encoding utf8
101              
102             =head1 NAME
103              
104             Mojo::DOM::Role::Style - Manage inline CSS styles on Mojo::DOM elements
105              
106             =head1 SYNOPSIS
107              
108             use Mojo::DOM;
109              
110             my $dom = Mojo::DOM->new('
hello
')
111             ->with_roles('+Style');
112              
113             # Get the full style - stringifies to the CSS string
114             my $style = $dom->at('div')->style;
115             say $style; # "color:red;font-size:12pt"
116             say $style->{'color'}; # "red"
117              
118             # Get a single property
119             my $color = $dom->at('div')->style('color');
120              
121             # Replace with a raw CSS string
122             $dom->at('div')->style('color:blue;font-size:14pt');
123              
124             # Replace with a flat list
125             $dom->at('div')->style(color => 'blue', 'font-size' => '14pt');
126              
127             # Merge into the existing style
128             $dom->at('div')->style({'font-weight' => 'bold'});
129              
130             # Remove the style attribute entirely
131             $dom->at('div')->style(undef);
132              
133             =head1 DESCRIPTION
134              
135             L is a role that adds a convenience method for
136             reading and manipulating the C