File Coverage

blib/lib/Mo/utils/CSS.pm
Criterion Covered Total %
statement 148 148 100.0
branch 74 74 100.0
condition 18 18 100.0
subroutine 30 30 100.0
pod 5 5 100.0
total 275 275 100.0


line stmt bran cond sub pod time code
1             package Mo::utils::CSS;
2              
3 7     7   188159 use base qw(Exporter);
  7         13  
  7         916  
4 7     7   61 use strict;
  7         23  
  7         171  
5 7     7   27 use warnings;
  7         11  
  7         389  
6              
7 7     7   6398 use Error::Pure qw(err);
  7         36991  
  7         177  
8 7     7   3698 use Graphics::ColorNames::CSS;
  7         21859  
  7         402  
9 7     7   51 use List::Util 1.33 qw(any none);
  7         1597  
  7         1101  
10 7     7   3271 use Mo::utils::Array qw(check_array);
  7         24714  
  7         181  
11 7     7   5075 use Mo::utils::Number::Utils qw(sub_check_percent);
  7         4665  
  7         192  
12 7     7   413 use Readonly;
  7         15  
  7         23696  
13              
14             Readonly::Array our @EXPORT_OK => qw(check_array_css_color check_css_border
15             check_css_class check_css_color check_css_unit);
16             Readonly::Array our @ABSOLUTE_LENGTHS => qw(cm mm in px pt pc);
17             Readonly::Array our @BORDER_GLOBAL => qw(inherit initial revert revert-layer unset);
18             Readonly::Array our @BORDER_STYLES => qw(none hidden dotted dashed solid double groove ridge inset outset);
19             Readonly::Array our @BORDER_WIDTHS => qw(thin medium thick);
20             Readonly::Array our @RELATIVE_LENGTHS => qw(em ex ch rem vw vh vmin vmax %);
21             Readonly::Array our @COLOR_FUNC => qw(rgb rgba hsl hsla);
22              
23             our $VERSION = 0.13;
24              
25             sub check_array_css_color {
26 4     4 1 242018 my ($self, $key) = @_;
27              
28 4 100       13 if (! exists $self->{$key}) {
29 1         2 return;
30             }
31              
32 3         16 check_array($self, $key);
33              
34 2         17 foreach my $css_color (@{$self->{$key}}) {
  2         6  
35 9         13 _check_color($css_color, $key);
36             }
37              
38 1         7 return;
39             }
40              
41             sub check_css_border {
42 46     46 1 332656 my ($self, $key) = @_;
43              
44 46 100       137 _check_key($self, $key) && return;
45              
46             # Global values.
47 44 100   210   274 if (any { $self->{$key} eq $_ } @BORDER_GLOBAL) {
  210         1416  
48 5         83 return;
49             }
50              
51 39         455 my @parts = split m/\s+/ms, $self->{$key}, 3;
52 39 100       143 if (@parts == 1) {
    100          
53 2         13 _check_border_style($self->{$key}, $key);
54             } elsif (@parts == 2) {
55              
56             # Border style on first place.
57 23 100   145   83 if (any { $parts[0] eq $_ } @BORDER_STYLES) {
  145 100       739  
58 17         91 _check_color($parts[1], $key, $self->{$key});
59              
60             # Border style on second place.
61 35     35   328 } elsif (any { $parts[1] eq $_ } @BORDER_STYLES) {
62 5 100   13   56 if (none { $parts[0] eq $_ } @BORDER_WIDTHS) {
  13         152  
63 4         51 _check_unit($parts[0], $key, $self->{$key});
64             }
65              
66             } else {
67             err "Parameter '$key' hasn't border style.",
68 1         15 'Value', $self->{$key},
69             ;
70             }
71             } else {
72 14 100   39   64 if (none { $parts[0] eq $_ } @BORDER_WIDTHS) {
  39         312  
73 11         103 _check_unit($parts[0], $key, $self->{$key});
74             }
75 14         94 _check_border_style($parts[1], $key, $self->{$key});
76 13         39 _check_color($parts[2], $key, $self->{$key});
77             }
78              
79 17         187 return;
80             }
81              
82             sub check_css_class {
83 8     8 1 257795 my ($self, $key) = @_;
84              
85 8 100       20 _check_key($self, $key) && return;
86              
87 6 100       40 if ($self->{$key} !~ m/^[a-zA-Z0-9\-_]+$/ms) {
    100          
88             err "Parameter '$key' has bad CSS class name.",
89 1         5 'Value', $self->{$key},
90             ;
91             } elsif ($self->{$key} =~ m/^\d/ms) {
92             err "Parameter '$key' has bad CSS class name (number on begin).",
93 1         14 'Value', $self->{$key},
94             ;
95             }
96              
97 4         6 return;
98             }
99              
100             sub check_css_color {
101 34     34 1 423595 my ($self, $key) = @_;
102              
103 34 100       107 _check_key($self, $key) && return;
104              
105 32         108 _check_color($self->{$key}, $key);
106              
107 8         29 return;
108             }
109              
110             sub check_css_unit {
111 23     23 1 264374 my ($self, $key) = @_;
112              
113 23 100       47 _check_key($self, $key) && return;
114              
115 21         44 _check_unit($self->{$key}, $key);
116              
117 17         30 return;
118             }
119              
120             sub _check_alpha {
121 13     13   38 my ($alpha, $key, $func, $error_value) = @_;
122              
123 13 100 100     141 if ($alpha !~ m/^[\d\.]+$/ms || $alpha > 1) {
124 6         53 err "Parameter '$key' has bad $func alpha.",
125             'Value', $error_value,
126             ;
127             }
128              
129 7         25 return;
130             }
131              
132             sub _check_border_style {
133 16     16   45 my ($value, $key, $error_value) = @_;
134              
135 16 100       73 if (! defined $error_value) {
136 2         7 $error_value = $value;
137             }
138              
139 16 100   96   77 if (none { $value eq $_ } @BORDER_STYLES) {
  96         668  
140 2         28 err "Parameter '$key' has bad border style.",
141             'Value', $error_value,
142             ;
143             }
144              
145 14         182 return;
146             }
147              
148             sub _check_color {
149 71     71   192 my ($value, $key, $error_value) = @_;
150              
151 71 100       166 if (! defined $error_value) {
152 41         62 $error_value = $value;
153             }
154              
155 71         219 my $funcs = join '|', @COLOR_FUNC;
156 71 100       2581 if ($value =~ m/^#(.*)$/ms) {
    100          
157 13         47 my $rgb = $1;
158 13 100 100     84 if (length $rgb == 3 || length $rgb == 6 || length $rgb == 8) {
      100        
159 11 100       51 if ($rgb !~ m/^[0-9A-Fa-f]+$/ms) {
160 2         12 err "Parameter '$key' has bad rgb color (bad hex number).",
161             'Value', $error_value,
162             ;
163             }
164             } else {
165 2         11 err "Parameter '$key' has bad rgb color (bad length).",
166             'Value', $error_value,
167             ;
168             }
169             } elsif ($value =~ m/^($funcs)\((.*)\)$/ms) {
170 48         134 my $func = $1;
171 48         113 my $args_string = $2;
172 48         371 my @args = split m/\s*,\s*/ms, $args_string;
173 48 100       168 if ($func eq 'rgb') {
    100          
    100          
174 9 100       28 if (@args != 3) {
175 3         17 err "Parameter '$key' has bad rgb color (bad number of arguments).",
176             'Value', $error_value,
177             ;
178             }
179 6         36 _check_colors([@args[0 .. 2]], $key, $func, $error_value);
180             } elsif ($func eq 'rgba') {
181 12 100       36 if (@args != 4) {
182 3         16 err "Parameter '$key' has bad rgba color (bad number of arguments).",
183             'Value', $error_value,
184             ;
185             }
186 9         53 _check_colors([@args[0 .. 2]], $key, $func, $error_value);
187 6         29 _check_alpha($args[3], $key, $func, $error_value);
188             } elsif ($func eq 'hsl') {
189 15 100       43 if (@args != 3) {
190 3         20 err "Parameter '$key' has bad hsl color (bad number of arguments).",
191             'Value', $error_value,
192             ;
193             }
194 12         46 _check_degree($args[0], $key, $func, $error_value);
195 9         68 _check_percent([@args[1 .. 2]], $key, $func.' percent', $error_value);
196             # hsla
197             } else {
198 12 100       40 if (@args != 4) {
199 3         16 err "Parameter '$key' has bad hsla color (bad number of arguments).",
200             'Value', $error_value,
201             ;
202             }
203 9         32 _check_degree($args[0], $key, $func, $error_value);
204 9         73 _check_percent([@args[1 .. 2]], $key, $func.' percent', $error_value);
205 7         33 _check_alpha($args[3], $key, $func, $error_value);
206             }
207             } else {
208 10 100   841   48 if (none { $value eq $_ } keys %{Graphics::ColorNames::CSS->NamesRgbTable}) {
  841         4555  
  10         95  
209 3         23 err "Parameter '$key' has bad color name.",
210             'Value', $error_value,
211             ;
212             }
213             }
214              
215 30         309 return;
216             }
217              
218             sub _check_colors {
219 15     15   42 my ($value_ar, $key, $func, $error_value) = @_;
220              
221 15         25 foreach my $i (@{$value_ar}) {
  15         35  
222 45 100 100     253 if ($i !~ m/^\d+$/ms || $i > 255) {
223 6         25 err "Parameter '$key' has bad $func color (bad number).",
224             'Value', $error_value,
225             ;
226             }
227             }
228              
229 9         24 return;
230             }
231              
232             sub _check_degree {
233 21     21   62 my ($angle, $key, $func, $error_value) = @_;
234              
235 21 100 100     154 if ($angle !~ m/^\d+$/ms || $angle > 360) {
236 3         15 err "Parameter '$key' has bad $func degree.",
237             'Value', $error_value,
238             ;
239             }
240              
241 18         38 return;
242             }
243              
244             sub _check_key {
245 111     111   190 my ($self, $key) = @_;
246              
247 111 100 100     597 if (! exists $self->{$key} || ! defined $self->{$key}) {
248 8         33 return 1;
249             }
250              
251 103         267 return 0;
252             }
253              
254             sub _check_percent {
255 18     18   48 my ($value_ar, $key, $func, $error_value) = @_;
256              
257 18         30 foreach my $i (@{$value_ar}) {
  18         45  
258 29         353 sub_check_percent($i, $key, $func, $error_value);
259             }
260              
261 11         205 return;
262             }
263              
264             sub _check_unit {
265 36     36   89 my ($value, $key, $error_value) = @_;
266              
267 36 100       72 if (! defined $error_value) {
268 21         21 $error_value = $value;
269             }
270              
271 36         307 my ($num, $unit) = $value =~ m/^(\d*\.?\d+)([^\d]*)$/ms;
272 36 100       88 if (! $num) {
273 3         18 err "Parameter '$key' doesn't contain unit number.",
274             'Value', $error_value,
275             ;
276             }
277 33 100       63 if (! $unit) {
278 2         20 err "Parameter '$key' doesn't contain unit name.",
279             'Value', $error_value,
280             ;
281             }
282 31 100   245   138 if (none { $_ eq $unit } (@ABSOLUTE_LENGTHS, @RELATIVE_LENGTHS)) {
  245         1426  
283 2         23 err "Parameter '$key' contain bad unit.",
284             'Unit', $unit,
285             'Value', $error_value,
286             ;
287             }
288              
289 29         282 return;
290             }
291              
292             1;
293              
294             __END__
295              
296             =pod
297              
298             =encoding utf8
299              
300             =head1 NAME
301              
302             Mo::utils::CSS - Mo CSS utilities.
303              
304             =head1 SYNOPSIS
305              
306             use Mo::utils::CSS qw(check_array_css_color check_css_border check_css_class check_css_color check_css_unit);
307              
308             check_array_css_color($self, $key);
309             check_css_border($self, $key);
310             check_css_class($self, $key);
311             check_css_color($self, $key);
312             check_css_unit($self, $key);
313              
314             =head1 DESCRIPTION
315              
316             Mo utilities for checking of CSS style things.
317              
318             =head1 SUBROUTINES
319              
320             =head2 C<check_array_css_color>
321              
322             check_array_css_color($self, $key);
323              
324             I<Since version 0.03.>
325              
326             Check parameter defined by C<$key> which is reference to array.
327             Check if all values are CSS colors.
328              
329             Put error if check isn't ok.
330              
331             Returns undef.
332              
333             =head2 C<check_css_border>
334              
335             check_css_border($self, $key);
336              
337             I<Since version 0.07.>
338              
339             Check parameter defined by C<$key> if it's CSS border.
340             Value could be undefined.
341              
342             Put error if check isn't ok.
343              
344             Returns undef.
345              
346             =head2 C<check_css_class>
347              
348             check_css_class($self, $key);
349              
350             I<Since version 0.02.>
351              
352             Check parameter defined by C<$key> if it's CSS class name.
353             Value could be undefined.
354              
355             Put error if check isn't ok.
356              
357             Returns undef.
358              
359             =head2 C<check_css_color>
360              
361             check_css_color($self, $key);
362              
363             I<Since version 0.03.>
364              
365             Check parameter defined by C<$key> if it's CSS color.
366             Value could be undefined.
367              
368             Put error if check isn't ok.
369              
370             Returns undef.
371              
372             =head2 C<check_css_unit>
373              
374             check_css_unit($self, $key);
375              
376             I<Since version 0.01. Described functionality since version 0.07.>
377              
378             Check parameter defined by C<$key> if it's CSS unit.
379             Value could be undefined.
380              
381             Put error if check isn't ok.
382              
383             Returns undef.
384              
385             =head1 ERRORS
386              
387             check_array_css_color():
388             Parameter '%s' has bad color name.
389             Value: %s
390             Parameter '%s' has bad hsl color (bad number of arguments).
391             Value: %s
392             Parameter '%s' has bad hsl degree.
393             Value: %s
394             Parameter '%s' has bad hsl percent (missing %).
395             Value: %s
396             Parameter '%s' has bad hsl percent.
397             Value: %s
398             Parameter '%s' has bad hsla alpha.
399             Value: %s
400             Parameter '%s' has bad hsla color (bad number of arguments).
401             Value: %s
402             Parameter '%s' has bad hsla degree.
403             Value: %s
404             Parameter '%s' has bad hsla percent (missing %).
405             Value: %s
406             Parameter '%s' has bad hsla percent.
407             Value: %s
408             Parameter '%s' has bad rgb color (bad hex number).
409             Value: %s
410             Parameter '%s' has bad rgb color (bad length).
411             Value: %s
412             Parameter '%s' has bad rgb color (bad number).
413             Value: %s
414             Parameter '%s' has bad rgb color (bad number of arguments).
415             Value: %s
416             Parameter '%s' has bad rgba alpha.
417             Value: %s
418             Parameter '%s' has bad rgba color (bad number).
419             Value: %s
420             Parameter '%s' has bad rgba color (bad number of arguments).
421             Value: %s
422             Parameter '%s' must be a array.
423             Value: %s
424             Reference: %s
425              
426             check_css_border()
427             Parameter '%s' contain bad unit.
428             Unit: %s
429             Value: %s
430             Parameter '%s' doesn't contain unit name.
431             Value: %s
432             Parameter '%s' doesn't contain unit number.
433             Value: %s
434             Parameter '%s' has bad color name.
435             Value: %s
436             Parameter '%s' has bad hsl color (bad number of arguments).
437             Value: %s
438             Parameter '%s' has bad hsl degree.
439             Value: %s
440             Parameter '%s' has bad hsl percent (missing %).
441             Value: %s
442             Parameter '%s' has bad hsl percent.
443             Value: %s
444             Parameter '%s' has bad hsla alpha.
445             Value: %s
446             Parameter '%s' has bad hsla color (bad number of arguments).
447             Value: %s
448             Parameter '%s' has bad hsla degree.
449             Value: %s
450             Parameter '%s' has bad hsla percent (missing %).
451             Value: %s
452             Parameter '%s' has bad hsla percent.
453             Value: %s
454             Parameter '%s' has bad rgb color (bad hex number).
455             Value: %s
456             Parameter '%s' has bad rgb color (bad length).
457             Value: %s
458             Parameter '%s' has bad rgb color (bad number).
459             Value: %s
460             Parameter '%s' has bad rgb color (bad number of arguments).
461             Value: %s
462             Parameter '%s' has bad rgba alpha.
463             Value: %s
464             Parameter '%s' has bad rgba color (bad number).
465             Value: %s
466             Parameter '%s' has bad rgba color (bad number of arguments).
467             Value: %s
468             Parameter '%s' hasn't border style.
469             Value: %s
470             Parameter '%s' must be a array.
471             Value: %s
472             Reference: %s
473              
474             check_css_class():
475             Parameter '%s' has bad CSS class name.
476             Value: %s
477             Parameter '%s' has bad CSS class name (number on begin).
478             Value: %s
479              
480             check_css_color():
481             Parameter '%s' has bad color name.
482             Value: %s
483             Parameter '%s' has bad hsl color (bad number of arguments).
484             Value: %s
485             Parameter '%s' has bad hsl degree.
486             Value: %s
487             Parameter '%s' has bad hsl percent (missing %).
488             Value: %s
489             Parameter '%s' has bad hsl percent.
490             Value: %s
491             Parameter '%s' has bad hsla alpha.
492             Value: %s
493             Parameter '%s' has bad hsla color (bad number of arguments).
494             Value: %s
495             Parameter '%s' has bad hsla degree.
496             Value: %s
497             Parameter '%s' has bad hsla percent (missing %).
498             Value: %s
499             Parameter '%s' has bad hsla percent.
500             Value: %s
501             Parameter '%s' has bad rgb color (bad hex number).
502             Value: %s
503             Parameter '%s' has bad rgb color (bad length).
504             Value: %s
505             Parameter '%s' has bad rgb color (bad number).
506             Value: %s
507             Parameter '%s' has bad rgb color (bad number of arguments).
508             Value: %s
509             Parameter '%s' has bad rgba alpha.
510             Value: %s
511             Parameter '%s' has bad rgba color (bad number).
512             Value: %s
513             Parameter '%s' has bad rgba color (bad number of arguments).
514             Value: %s
515              
516             check_css_unit():
517             Parameter '%s' contain bad unit.
518             Unit: %s
519             Value: %s
520             Parameter '%s' doesn't contain unit name.
521             Value: %s
522             Parameter '%s' doesn't contain unit number.
523             Value: %s
524              
525             =head1 EXAMPLE1
526              
527             =for comment filename=check_array_css_color_ok.pl
528              
529             use strict;
530             use warnings;
531              
532             use Mo::utils::CSS qw(check_array_css_color);
533              
534             my $self = {
535             'key' => [
536             'red',
537             '#F00', '#FF0000', '#FF000000',
538             'rgb(255,0,0)', 'rgba(255,0,0,0.3)',
539             'hsl(120, 100%, 50%)', 'hsla(120, 100%, 50%, 0.3)',
540             ],
541             };
542             check_array_css_color($self, 'key');
543              
544             # Print out.
545             print "ok\n";
546              
547             # Output:
548             # ok
549              
550             =head1 EXAMPLE2
551              
552             =for comment filename=check_array_css_color_fail.pl
553              
554             use strict;
555             use warnings;
556              
557             use Error::Pure;
558             use Mo::utils::CSS qw(check_array_css_color);
559              
560             $Error::Pure::TYPE = 'Error';
561              
562             my $self = {
563             'key' => ['xxx'],
564             };
565             check_array_css_color($self, 'key');
566              
567             # Print out.
568             print "ok\n";
569              
570             # Output like:
571             # #Error [...CSS.pm:?] Parameter 'key' has bad color name.
572              
573             =head1 EXAMPLE3
574              
575             =for comment filename=check_css_border_ok.pl
576              
577             use strict;
578             use warnings;
579              
580             use Mo::utils::CSS qw(check_css_border);
581              
582             my $self = {
583             'key' => '1px solid red',
584             };
585             check_css_border($self, 'key');
586              
587             # Print out.
588             print "ok\n";
589              
590             # Output:
591             # ok
592              
593             =head1 EXAMPLE4
594              
595             =for comment filename=check_css_border_fail.pl
596              
597             use strict;
598             use warnings;
599              
600             use Error::Pure;
601             use Mo::utils::CSS qw(check_css_border);
602              
603             $Error::Pure::TYPE = 'Error';
604              
605             my $self = {
606             'key' => 'bad',
607             };
608             check_css_border($self, 'key');
609              
610             # Print out.
611             print "ok\n";
612              
613             # Output like:
614             # #Error [...CSS.pm:?] Parameter 'key' has bad border style.
615              
616             =head1 EXAMPLE5
617              
618             =for comment filename=check_css_class_ok.pl
619              
620             use strict;
621             use warnings;
622              
623             use Mo::utils::CSS qw(check_css_class);
624              
625             my $self = {
626             'key' => 'foo-bar',
627             };
628             check_css_class($self, 'key');
629              
630             # Print out.
631             print "ok\n";
632              
633             # Output:
634             # ok
635              
636             =head1 EXAMPLE6
637              
638             =for comment filename=check_css_class_fail.pl
639              
640             use strict;
641             use warnings;
642              
643             use Error::Pure;
644             use Mo::utils::CSS qw(check_css_class);
645              
646             $Error::Pure::TYPE = 'Error';
647              
648             my $self = {
649             'key' => '1xxx',
650             };
651             check_css_class($self, 'key');
652              
653             # Print out.
654             print "ok\n";
655              
656             # Output like:
657             # #Error [...CSS.pm:?] Parameter 'key' has bad CSS class name (number of begin).
658              
659             =head1 EXAMPLE7
660              
661             =for comment filename=check_css_color_ok.pl
662              
663             use strict;
664             use warnings;
665              
666             use Mo::utils::CSS qw(check_css_color);
667              
668             my $self = {
669             'key' => '#F00',
670             };
671             check_css_color($self, 'key');
672              
673             # Print out.
674             print "ok\n";
675              
676             # Output:
677             # ok
678              
679             =head1 EXAMPLE8
680              
681             =for comment filename=check_css_color_fail.pl
682              
683             use strict;
684             use warnings;
685              
686             use Error::Pure;
687             use Mo::utils::CSS qw(check_css_color);
688              
689             $Error::Pure::TYPE = 'Error';
690              
691             my $self = {
692             'key' => 'xxx',
693             };
694             check_css_color($self, 'key');
695              
696             # Print out.
697             print "ok\n";
698              
699             # Output like:
700             # #Error [...CSS.pm:?] Parameter 'key' has bad color name.
701              
702             =head1 EXAMPLE9
703              
704             =for comment filename=check_css_unit_ok.pl
705              
706             use strict;
707             use warnings;
708              
709             use Mo::utils::CSS qw(check_css_unit);
710              
711             my $self = {
712             'key' => '123px',
713             };
714             check_css_unit($self, 'key');
715              
716             # Print out.
717             print "ok\n";
718              
719             # Output:
720             # ok
721              
722             =head1 EXAMPLE10
723              
724             =for comment filename=check_css_unit_fail.pl
725              
726             use strict;
727             use warnings;
728              
729             use Error::Pure;
730             use Mo::utils::CSS qw(check_css_unit);
731              
732             $Error::Pure::TYPE = 'Error';
733              
734             my $self = {
735             'key' => '12',
736             };
737             check_css_unit($self, 'key');
738              
739             # Print out.
740             print "ok\n";
741              
742             # Output like:
743             # #Error [...CSS.pm:?] Parameter 'key' doesn't contain unit name.
744              
745             =head1 DEPENDENCIES
746              
747             L<Error::Pure>,
748             L<Exporter>,
749             L<Graphics::ColorNames::CSS>,
750             L<List::Util>,
751             L<Mo::utils::Array>,
752             L<Mo::utils::Number::Utils>,
753             L<Readonly>.
754              
755             =head1 SEE ALSO
756              
757             =over
758              
759             =item L<Mo>
760              
761             Micro Objects. Mo is less.
762              
763             =item L<Mo::utils>
764              
765             Mo utilities.
766              
767             =item L<Mo::utils::Language>
768              
769             Mo language utilities.
770              
771             =item L<Wikibase::Datatype::Utils>
772              
773             Wikibase datatype utilities.
774              
775             =back
776              
777             =head1 REPOSITORY
778              
779             L<https://github.com/michal-josef-spacek/Mo-utils-CSS>
780              
781             =head1 AUTHOR
782              
783             Michal Josef Špaček L<mailto:skim@cpan.org>
784              
785             L<http://skim.cz>
786              
787             =head1 LICENSE AND COPYRIGHT
788              
789             © 2023-2025 Michal Josef Špaček
790              
791             BSD 2-Clause License
792              
793             =head1 VERSION
794              
795             0.13
796              
797             =cut