File Coverage

blib/lib/Tags/HTML/Login/Register.pm
Criterion Covered Total %
statement 65 66 98.4
branch 11 12 91.6
condition n/a
subroutine 13 13 100.0
pod 1 1 100.0
total 90 92 97.8


line stmt bran cond sub pod time code
1             package Tags::HTML::Login::Register;
2              
3 5     5   579367 use base qw(Tags::HTML);
  5         9  
  5         3004  
4 5     5   46330 use strict;
  5         11  
  5         132  
5 5     5   40 use warnings;
  5         2091  
  5         385  
6              
7 5     5   33 use Class::Utils qw(set_params split_params);
  5         13  
  5         310  
8 5     5   32 use Error::Pure qw(err);
  5         9  
  5         250  
9 5     5   30 use List::Util qw(none);
  5         9  
  5         322  
10 5     5   28 use Readonly;
  5         9  
  5         303  
11 5     5   3087 use Tags::HTML::Messages;
  5         1179417  
  5         7127  
12              
13             Readonly::Array our @FORM_METHODS => qw(post get);
14              
15             our $VERSION = 0.10;
16              
17             # Constructor.
18             sub new {
19 22     22 1 1204873 my ($class, @params) = @_;
20              
21             # Create object.
22 22         191 my ($object_params_ar, $other_params_ar) = split_params(
23             ['css_register', 'form_method', 'lang', 'logo_image_url',
24             'text', 'width'], @params);
25 22         790 my $self = $class->SUPER::new(@{$other_params_ar});
  22         125  
26              
27             # CSS style for register box.
28 19         820 $self->{'css_register'} = 'form-register';
29              
30             # Form method.
31 19         62 $self->{'form_method'} = 'post';
32              
33             # Language.
34 19         51 $self->{'lang'} = 'eng';
35              
36             # Logo.
37 19         67 $self->{'logo_image_url'} = undef;
38              
39             # Language texts.
40 19         195 $self->{'text'} = {
41             'eng' => {
42             'password1_label' => 'Password #1',
43             'password2_label' => 'Password #2',
44             'register' => 'Register',
45             'submit' => 'Register',
46             'username_label' => 'User name',
47             },
48             };
49              
50             # Login box width.
51 19         65 $self->{'width'} = '300px';
52              
53             # Process params.
54 19         35 set_params($self, @{$object_params_ar});
  19         72  
55              
56             # Check form method.
57 19 100   20   372 if (none { $self->{'form_method'} eq $_ } @FORM_METHODS) {
  20         238  
58 1         14 err "Parameter 'form_method' has bad value.";
59             }
60              
61             # TODO Check lang.
62              
63             # Check text for lang
64 18 100       297 if (! defined $self->{'text'}) {
65 1         5 err "Parameter 'text' is required.";
66             }
67 17 100       88 if (ref $self->{'text'} ne 'HASH') {
68 1         17 err "Parameter 'text' must be a hash with language texts.";
69             }
70 16 100       84 if (! exists $self->{'text'}->{$self->{'lang'}}) {
71 1         7 err "Texts for language '$self->{'lang'}' doesn't exist.";
72             }
73              
74             $self->{'_tags_messages'} = Tags::HTML::Messages->new(
75             'css' => $self->{'css'},
76             'flag_no_messages' => 0,
77 15         113 'tags' => $self->{'tags'},
78             );
79              
80             # Object.
81 15         176185 return $self;
82             }
83              
84             # Process 'Tags'.
85             sub _process {
86 7     7   809 my ($self, $messages_ar) = @_;
87              
88 7         17 my $username_id = 'username';
89 7         72 my $password1_id = 'password1';
90 7         18 my $password2_id = 'password2';
91              
92             # Main content.
93             $self->{'tags'}->put(
94             ['b', 'form'],
95             ['a', 'class', $self->{'css_register'}],
96 7         88 ['a', 'method', $self->{'form_method'}],
97              
98             ['b', 'fieldset'],
99             ['b', 'legend'],
100             ['d', $self->_text('register')],
101             ['e', 'legend'],
102             );
103              
104 6 50       1726 if (defined $self->{'logo_image_url'}) {
105             $self->{'tags'}->put(
106             ['b', 'div'],
107             ['a', 'class', 'logo'],
108             ['b', 'img'],
109 0         0 ['a', 'src', $self->{'logo_image_url'}],
110             ['a', 'alt', 'logo'],
111             ['e', 'img'],
112             ['e', 'div'],
113             );
114             }
115              
116 6         44 $self->{'tags'}->put(
117             ['b', 'p'],
118             ['b', 'label'],
119             ['a', 'for', $username_id],
120             ['d', $self->_text('username_label')],
121             ['e', 'label'],
122             ['b', 'input'],
123             ['a', 'type', 'text'],
124             ['a', 'name', $username_id],
125             ['a', 'id', $username_id],
126             ['a', 'autofocus', 'autofocus'],
127             ['e', 'input'],
128             ['e', 'p'],
129              
130             ['b', 'p'],
131             ['b', 'label'],
132             ['a', 'for', $password1_id],
133             ['d', $self->_text('password1_label')],
134             ['e', 'label'],
135             ['b', 'input'],
136             ['a', 'type', 'password'],
137             ['a', 'name', $password1_id],
138             ['a', 'id', $password1_id],
139             ['e', 'input'],
140             ['e', 'p'],
141              
142             ['b', 'p'],
143             ['b', 'label'],
144             ['a', 'for', $password2_id],
145             ['d', $self->_text('password2_label')],
146             ['e', 'label'],
147             ['b', 'input'],
148             ['a', 'type', 'password'],
149             ['a', 'name', $password2_id],
150             ['a', 'id', $password2_id],
151             ['e', 'input'],
152             ['e', 'p'],
153              
154             ['b', 'p'],
155             ['b', 'button'],
156             ['a', 'type', 'submit'],
157             ['a', 'name', 'register'],
158             ['a', 'value', 'register'],
159             ['d', $self->_text('submit')],
160             ['e', 'button'],
161             ['e', 'p'],
162              
163             ['e', 'fieldset'],
164             );
165              
166 6         8473 $self->{'_tags_messages'}->process($messages_ar);
167              
168 3         752 $self->{'tags'}->put(
169             ['e', 'form'],
170             );
171              
172 3         141 return;
173             }
174              
175             # Process 'CSS::Struct'.
176             sub _process_css {
177 3     3   55 my ($self, $message_types_hr) = @_;
178              
179             $self->{'css'}->put(
180             ['s', '.'.$self->{'css_register'}],
181             ['d', 'width', $self->{'width'}],
182             ['d', 'background-color', '#f2f2f2'],
183             ['d', 'padding', '20px'],
184             ['d', 'border-radius', '5px'],
185             ['d', 'box-shadow', '0 0 10px rgba(0, 0, 0, 0.2)'],
186             ['e'],
187              
188             ['s', '.'.$self->{'css_register'}.' fieldset'],
189             ['d', 'border', 'none'],
190             ['d', 'padding', 0],
191             ['d', 'margin-bottom', '20px'],
192             ['e'],
193              
194             ['s', '.'.$self->{'css_register'}.' .logo'],
195             ['d', 'height', '5em'],
196             ['d', 'width', '100%'],
197             ['e'],
198              
199             ['s', '.'.$self->{'css_register'}.' img'],
200             ['d', 'margin', 'auto'],
201             ['d', 'display', 'block'],
202             ['d', 'max-width', '100%'],
203             ['d', 'max-height', '5em'],
204             ['e'],
205              
206             ['s', '.'.$self->{'css_register'}.' legend'],
207             ['d', 'font-weight', 'bold'],
208             ['d', 'margin-bottom', '10px'],
209             ['e'],
210              
211             ['s', '.'.$self->{'css_register'}.' p'],
212             ['d', 'margin', 0],
213             ['d', 'padding', '10px 0'],
214             ['e'],
215              
216             ['s', '.'.$self->{'css_register'}.' label'],
217             ['d', 'display', 'block'],
218             ['d', 'font-weight', 'bold'],
219             ['d', 'margin-bottom', '5px'],
220             ['e'],
221              
222             ['s', '.'.$self->{'css_register'}.' input[type="text"]'],
223             ['s', '.'.$self->{'css_register'}.' input[type="password"]'],
224             ['d', 'width', '100%'],
225             ['d', 'padding', '8px'],
226             ['d', 'border', '1px solid #ccc'],
227             ['d', 'border-radius', '3px'],
228             ['e'],
229              
230             ['s', '.'.$self->{'css_register'}.' button[type="submit"]'],
231             ['d', 'width', '100%'],
232             ['d', 'padding', '10px'],
233             ['d', 'background-color', '#4CAF50'],
234             ['d', 'color', '#fff'],
235             ['d', 'border', 'none'],
236             ['d', 'border-radius', '3px'],
237             ['d', 'cursor', 'pointer'],
238             ['e'],
239              
240             ['s', '.'.$self->{'css_register'}.' button[type="submit"]:hover'],
241             ['d', 'background-color', '#45a049'],
242             ['e'],
243              
244 3         178 ['s', '.'.$self->{'css_register'}.' .messages'],
245             ['d', 'text-align', 'center'],
246             ['e'],
247             );
248              
249 3         3033 $self->{'_tags_messages'}->process_css($message_types_hr);
250              
251 2         154 return;
252             }
253              
254             sub _text {
255 31     31   77 my ($self, $key) = @_;
256              
257 31 100       123 if (! exists $self->{'text'}->{$self->{'lang'}}->{$key}) {
258 1         9 err "Text for lang '$self->{'lang'}' and key '$key' doesn't exist.";
259             }
260              
261 30         421 return $self->{'text'}->{$self->{'lang'}}->{$key};
262             }
263              
264              
265             1;
266              
267             __END__
268              
269             =pod
270              
271             =encoding utf8
272              
273             =head1 NAME
274              
275             Tags::HTML::Login::Register - Tags helper for login register.
276              
277             =head1 SYNOPSIS
278              
279             use Tags::HTML::Login::Register;
280              
281             my $obj = Tags::HTML::Login::Register->new(%params);
282             $obj->process($messages_ar);
283             $obj->process_css($message_types_hr);
284              
285             =head1 METHODS
286              
287             =head2 C<new>
288              
289             my $obj = Tags::HTML::Login::Register->new(%params);
290              
291             Constructor.
292              
293             =over 8
294              
295             =item * C<css>
296              
297             'CSS::Struct::Output' object for L<process_css> processing.
298              
299             Default value is undef.
300              
301             =item * C<css_register>
302              
303             CSS class for form.
304              
305             Default value is 'form-register'.
306              
307             =item * C<form_method>
308              
309             Form method.
310              
311             Possible values are 'post' and 'get'.
312              
313             Default value is 'post'.
314              
315             =item * C<lang>
316              
317             Language in ISO 639-3 code.
318              
319             Default value is 'eng'.
320              
321             =item * C<logo_image_url>
322              
323             URL to logo image.
324              
325             Default value is undef.
326              
327             =item * C<tags>
328              
329             'Tags::Output' object.
330              
331             Default value is undef.
332              
333             =item * C<text>
334              
335             Hash reference with keys defined language in ISO 639-3 code and value with hash
336             reference with texts.
337              
338             Required keys are 'login', 'password_label', 'username_label' and 'submit'.
339              
340             Default value is:
341              
342             {
343             'eng' => {
344             'password1_label' => 'Password #1',
345             'password2_label' => 'Password #2',
346             'register' => 'Register',
347             'username_label' => 'User name',
348             'submit' => 'Register',
349             },
350             }
351              
352             =back
353              
354             Returns instance of object.
355              
356             =head2 C<process>
357              
358             $obj->process($messages_ar);
359              
360             Process Tags structure for register form.
361             Variable C<$message_ar> is reference to array with L<Data::Message::Simple>
362             instances.
363              
364             Returns undef.
365              
366             =head2 C<process_css>
367              
368             $obj->process_css($message_types_hr);
369              
370             Process CSS::Struct structure for register form.
371             Variable C<$message_types_hr> is reference to hash with message type keys and
372             CSS color as value. Message types are defined in L<Data::Message::Simple>.
373              
374             Returns undef.
375              
376             =head1 ERRORS
377              
378             new():
379             From Class::Utils::set_params():
380             Unknown parameter '%s'.
381             From Tags::HTML::new():
382             Parameter 'css' must be a 'CSS::Struct::Output::*' class.
383             Parameter 'tags' must be a 'Tags::Output::*' class.
384              
385             process():
386             From Tags::HTML::process():
387             Parameter 'tags' isn't defined.
388             Bad message data object.
389             Text for lang '%s' and key '%s' doesn't exist.
390              
391             process_css():
392             From Tags::HTML::process_css():
393             Parameter 'css' isn't defined.
394             Message types must be a hash reference.
395              
396             =head1 EXAMPLE1
397              
398             =for comment filename=print_block_html_and_css.pl
399              
400             use strict;
401             use warnings;
402              
403             use CSS::Struct::Output::Indent;
404             use Tags::HTML::Login::Register;
405             use Tags::Output::Indent;
406              
407             # Object.
408             my $css = CSS::Struct::Output::Indent->new;
409             my $tags = Tags::Output::Indent->new;
410             my $obj = Tags::HTML::Login::Register->new(
411             'css' => $css,
412             'tags' => $tags,
413             );
414              
415             # Process login button.
416             $obj->process_css;
417             $obj->process;
418              
419             # Print out.
420             print "CSS\n";
421             print $css->flush."\n\n";
422             print "HTML\n";
423             print $tags->flush."\n";
424              
425             # Output:
426             # CSS
427             # .form-register {
428             # width: ;
429             # background-color: #f2f2f2;
430             # padding: 20px;
431             # border-radius: 5px;
432             # box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
433             # }
434             # .form-register fieldset {
435             # border: none;
436             # padding: 0;
437             # margin-bottom: 20px;
438             # }
439             # .form-register .logo {
440             # height: 5em;
441             # width: 100%;
442             # }
443             # .form-register img {
444             # margin: auto;
445             # display: block;
446             # max-width: 100%;
447             # max-height: 5em;
448             # }
449             # .form-register legend {
450             # font-weight: bold;
451             # margin-bottom: 10px;
452             # }
453             # .form-register p {
454             # margin: 0;
455             # padding: 10px 0;
456             # }
457             # .form-register label {
458             # display: block;
459             # font-weight: bold;
460             # margin-bottom: 5px;
461             # }
462             # .form-register input[type="text"], .form-register input[type="password"] {
463             # width: 100%;
464             # padding: 8px;
465             # border: 1px solid #ccc;
466             # border-radius: 3px;
467             # }
468             # .form-register button[type="submit"] {
469             # width: 100%;
470             # padding: 10px;
471             # background-color: #4CAF50;
472             # color: #fff;
473             # border: none;
474             # border-radius: 3px;
475             # cursor: pointer;
476             # }
477             # .form-register button[type="submit"]:hover {
478             # background-color: #45a049;
479             # }
480             #
481             # HTML
482             # <form class="form-register" method="post">
483             # <fieldset>
484             # <legend>
485             # Register
486             # </legend>
487             # <p>
488             # <label for="username">
489             # </label>
490             # User name
491             # <input type="text" name="username" id="username" autofocus="autofocus">
492             # </input>
493             # </p>
494             # <p>
495             # <label for="password1">
496             # Password #1
497             # </label>
498             # <input type="password" name="password1" id="password1">
499             # </input>
500             # </p>
501             # <p>
502             # <label for="password2">
503             # Password #2
504             # </label>
505             # <input type="password" name="password2" id="password2">
506             # </input>
507             # </p>
508             # <p>
509             # <button type="submit" name="register" value="register">
510             # Register
511             # </button>
512             # </p>
513             # </fieldset>
514             # </form>
515              
516             =head1 EXAMPLE2
517              
518             =for comment filename=plack_app_login_register.pl
519              
520             use strict;
521             use warnings;
522            
523             use CSS::Struct::Output::Indent;
524             use Plack::App::Tags::HTML;
525             use Plack::Runner;
526             use Tags::HTML::Login::Register;
527             use Tags::Output::Indent;
528             use Unicode::UTF8 qw(decode_utf8);
529            
530             my $css = CSS::Struct::Output::Indent->new;
531             my $tags = Tags::Output::Indent->new(
532             'xml' => 1,
533             'preserved' => ['style'],
534             );
535             my $register = Tags::HTML::Login::Register->new(
536             'css' => $css,
537             'tags' => $tags,
538             );
539             $register->process_css;
540             my $app = Plack::App::Tags::HTML->new(
541             'component' => 'Tags::HTML::Container',
542             'data' => [sub {
543             my $self = shift;
544             $register->process;
545             return;
546             }],
547             'css' => $css,
548             'tags' => $tags,
549             )->to_app;
550             Plack::Runner->new->run($app);
551              
552             # Output screenshot is in images/ directory.
553              
554             =begin html
555              
556             <a href="https://raw.githubusercontent.com/michal-josef-spacek/Tags-HTML-Login-Register/master/images/plack_app_login_register.png">
557             <img src="https://raw.githubusercontent.com/michal-josef-spacek/Tags-HTML-Login-Register/master/images/plack_app_login_register.png" alt="Web app example" width="300px" height="300px" />
558             </a>
559              
560             =end html
561              
562             =head1 DEPENDENCIES
563              
564             L<Class::Utils>,
565             L<Error::Pure>,
566             L<List::Util>,
567             L<Readonly>,
568             L<Tags::HTML>,
569             L<Tags::HTML::Messages>.
570              
571             =head1 SEE ALSO
572              
573             =over
574              
575             =item L<Tags::HTML::Login::Access>
576              
577             Tags helper for login access.
578              
579             =item L<Tags::HTML::Login::Button>
580              
581             Tags helper for login button.
582              
583             =back
584              
585             =head1 REPOSITORY
586              
587             L<https://github.com/michal-josef-spacek/Tags-HTML-Login-Register>
588              
589             =head1 AUTHOR
590              
591             Michal Josef Špaček L<mailto:skim@cpan.org>
592              
593             L<http://skim.cz>
594              
595             =head1 LICENSE AND COPYRIGHT
596              
597             © 2021-2025 Michal Josef Špaček
598              
599             BSD 2-Clause License
600              
601             =head1 VERSION
602              
603             0.10
604              
605             =cut