File Coverage

blib/lib/Tags/HTML/Login/Access.pm
Criterion Covered Total %
statement 66 66 100.0
branch 14 14 100.0
condition n/a
subroutine 13 13 100.0
pod 1 1 100.0
total 94 94 100.0


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