File Coverage

blib/lib/Tags/HTML/Login/Access.pm
Criterion Covered Total %
statement 43 62 69.3
branch 4 12 33.3
condition n/a
subroutine 10 13 76.9
pod 1 1 100.0
total 58 88 65.9


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