File Coverage

blib/lib/HTML/Obj2HTML/Plugin/SemanticUIForms.pm
Criterion Covered Total %
statement 6 48 12.5
branch 0 30 0.0
condition 0 3 0.0
subroutine 2 4 50.0
pod n/a
total 8 85 9.4


line stmt bran cond sub pod time code
1             package HTML::Obj2HTML::Plugin::SemanticUI;
2              
3 1     1   644 use strict;
  1         2  
  1         30  
4 1     1   5 use warnings;
  1         2  
  1         3500  
5              
6             my @semanticnumbers = qw(zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen);
7             HTML::Obj2HTML::register_extension("form", {
8             attr => { class => "ui form" }
9             });HTML::Obj2HTML::register_extension("select", {
10             attr => { class => "ui dropdown" }
11             });
12              
13              
14             # Top level field objects (don't contain the actual inputs)
15             HTML::Obj2HTML::register_extension("field", {
16             tag => 'div',
17             before => sub {
18             my $obj = shift;
19             if (ref $obj eq "HASH") {
20             if (!defined $obj->{_}) { $obj->{_} = []; }
21             my $label = genhelplabel($obj);
22             if ($label) {
23             unshift(@{$obj->{"_"}}, "label", $obj->{label});
24             }
25             }
26             return undef;
27             },
28             attr => { class => 'field' }
29             });
30              
31             HTML::Obj2HTML::register_extension("fields", {
32             tag => "div",
33             before => sub {
34             my $o = shift;
35             if (ref $o ne "HASH") { return ""; }
36             $o->{class} = "ui ".$semanticnumbers[$o->{num}]." fields";
37             delete($o->{num});
38             return "";
39             }
40             });
41              
42              
43              
44              
45              
46              
47             # Semantic-UI full field objects. These include the 'field' div and the input.
48             HTML::Obj2HTML::register_extension("checkboxfield", {
49             tag => "",
50             before => sub {
51             my $obj = shift;
52             if (ref $obj ne "HASH") { return ""; }
53             return HTML::Obj2HTML::gen(commonfield($obj, [ checkbox => $obj ]));
54             }
55             });
56             HTML::Obj2HTML::register_extension("radiofield", {
57             tag => "",
58             before => sub {
59             my $obj = shift;
60             if (ref $obj ne "HASH") { return ""; }
61             return HTML::Obj2HTML::gen(commonfield($obj, [ radio => $obj ]));
62             }
63             });
64              
65             HTML::Obj2HTML::register_extension("inputfield", {
66             tag => "",
67             before => sub {
68             my $obj = shift;
69              
70             if (ref $obj ne "HASH") { return ""; }
71              
72             my $readonly = HTML::Obj2HTML::get_opt("readonly") || $obj->{readonly};
73             delete($obj->{readonly});
74              
75             if ($readonly) {
76             return HTML::Obj2HTML::gen(commonfield($obj, [ span => $obj->{value} ]));
77             } else {
78             return HTML::Obj2HTML::gen(commonfield($obj, [ input => $obj ]));
79             }
80             }
81             });
82              
83             HTML::Obj2HTML::register_extension("textareafield", {
84             tag => "",
85             before => sub {
86             my $obj = shift;
87             if (ref $obj ne "HASH") { return ""; }
88             if (defined $obj->{value}) {
89             my $val = $obj->{value};
90             delete($obj->{value});
91             $val =~ s/^\s+//g;
92             $val =~ s/\s+$//g;
93             $obj->{_} = "$val";
94             } else {
95             $obj->{_} = "";
96             }
97              
98             my $readonly = HTML::Obj2HTML::get_opt("readonly") || $obj->{readonly};
99             delete($obj->{readonly});
100             if ($readonly) {
101             if ($obj->{class} =~ /editor/) {
102             return HTML::Obj2HTML::gen(commonfield($obj, [ div => [ raw => $obj->{_} ] ]));
103             } else {
104             return HTML::Obj2HTML::gen(commonfield($obj, [ div => [ md => $obj->{_} ] ]));
105             }
106             } else {
107             return HTML::Obj2HTML::gen(commonfield($obj, [ textarea => $obj ]));
108             }
109              
110             }
111             });
112             HTML::Obj2HTML::register_extension("htmlfield", {
113             tag => "",
114             before => sub {
115             my $obj = shift;
116             if (ref $obj ne "HASH") { return ""; }
117             if ($obj->{class} !~ /editor/) {
118             if ($obj->{class}) { $obj->{class} .= " "; }
119             $obj->{class} .= "editor";
120             }
121             return [ textareafield => $obj ];
122             }
123             });
124              
125             HTML::Obj2HTML::register_extension("selectfield", {
126             tag => "",
127             before => sub {
128             my $obj = shift;
129             if (ref $obj ne "HASH") { return ""; }
130              
131             my $readonly = HTML::Obj2HTML::get_opt("readonly") || $obj->{readonly};
132             delete($obj->{readonly});
133              
134             if ($obj->{class}) { $obj->{class}.=" "; }
135             $obj->{class}.= "ui dropdown";
136             # if ($obj->{multiple}) { $obj->{class}.= " fluid"; }
137              
138             my $db = $obj->{db} || $HTML::Obj2HTML::db;
139             delete($obj->{db});
140              
141             if ($obj->{options} && ref $obj->{options} eq "ARRAY") {
142             my @contents = ();
143             if (defined $obj->{inclblank}) { push(@contents, option => { value => "", _ => $obj->{inclblank} }); }
144             for (my $i = 0; $i <= $#{$obj->{hiddenoptions}}; $i+=2) {
145             my $v = $obj->{hiddenoptions}->[$i];
146             my $t = $obj->{hiddenoptions}->[$i+1];
147             if ((!$obj->{multiple} && defined $obj->{value} && "$obj->{value}" eq "$v") ||
148             ($obj->{multiple} && defined $obj->{value} && ($obj->{value} & $v))) {
149             if ($readonly) {
150             push(@contents, div => $t);
151             } else {
152             push(@contents, option => { value => $v, _ => $t, selected => 1 });
153             }
154             }
155             }
156             for (my $i = 0; $i <= $#{$obj->{options}}; $i+=2) {
157             my $v = $obj->{options}->[$i];
158             my $t = $obj->{options}->[$i+1];
159             my $opt = { value => $v, _ => $t };
160             if (!$obj->{multiple}) {
161             if (defined $obj->{value} && "$obj->{value}" eq "$v") { $opt->{selected} = 1; }
162             } else {
163             if (defined $obj->{value} && ($obj->{value} & $v)) { $opt->{selected} = 1; }
164             if (defined $obj->{values}) {
165             if (grep {"$_" eq "$v"} @{$obj->{values}}) { $opt->{selected} = 1; }
166             }
167             }
168              
169             if ($readonly) {
170             if ($opt->{selected}) {
171             push(@contents, div => $opt->{_});
172             }
173             } else {
174             push(@contents, option => $opt);
175             }
176             }
177             $obj->{_} = \@contents;
178             delete($obj->{values});
179             delete($obj->{options});
180             delete($obj->{hiddenoptions});
181             }
182             if ($obj->{optionsql} && ref $obj->{optionsql} eq "ARRAY") {
183             my @contents = ();
184             if (defined $obj->{inclblank}) { push(@contents, option => { value => "", _ => $obj->{inclblank} }); }
185             if (!$obj->{valuefield}) { $obj->{valuefield} = "id"; }
186             if (!$obj->{textfield}) { $obj->{textfield} = "name"; }
187             for (my $r = $db->for(@{$obj->{optionsql}}); $r->more; $r->next) {
188             my $opt = { value => $r->{$obj->{valuefield}}, _ => $r->{$obj->{textfield}} };
189             if (!$obj->{multiple}) {
190             if (defined $obj->{value} && "$obj->{value}" eq "$r->{$obj->{valuefield}}") { $opt->{selected} = 1; }
191             } else {
192             if (defined $obj->{selectedfield} && $r->{$obj->{selectedfield}}) {
193             $opt->{selected} = 1;
194             } elsif (defined $obj->{value} && ($obj->{value} & $r->{$obj->{valuefield}})) {
195             $opt->{selected} = 1;
196             }
197             if (defined $obj->{values}) {
198             if (grep({$_ eq $r->{$obj->{valuefield}}} @{$obj->{values}})) { $opt->{selected} = 1; }
199             }
200             }
201             if ($readonly) {
202             if ($opt->{selected}) {
203             push(@contents, div => $opt->{_});
204             }
205             } else {
206             push(@contents, option => $opt);
207             }
208             }
209             $obj->{_} = \@contents;
210             delete($obj->{values});
211             delete($obj->{optionsql});
212             delete($obj->{valuefield});
213             delete($obj->{textfield});
214             }
215             if (!$obj->{_}) { $obj->{_} = []; }
216             delete($obj->{value});
217             delete($obj->{inclblank});
218              
219             if ($readonly) {
220             return HTML::Obj2HTML::gen(commonfield($obj, $obj->{_}));
221             } else {
222             return HTML::Obj2HTML::gen(commonfield($obj, [ select => $obj ]));
223             }
224              
225             }
226             });
227             HTML::Obj2HTML::register_extension("datefield", {
228             tag => "",
229             before => sub {
230             my $obj = shift;
231             if (ref $obj ne "HASH") { return ""; }
232              
233             my $readonly = HTML::Obj2HTML::get_opt("readonly") || $obj->{readonly};
234             delete($obj->{readonly});
235             if ($readonly) {
236             return HTML::Obj2HTML::gen(commonfield($obj, [ span => $obj->{value} ] ));
237             } else {
238             return HTML::Obj2HTML::gen(commonfield($obj, [
239             div => { class => "ui calendar ".$obj->{class}, _ => [
240             div => { class => "ui input left icon", _ => [
241             i => { class => "calendar icon", _ => [] },
242             input => { type => "text", name => $obj->{name}, placeholder => $obj->{placeholder}, value => $obj->{value} }
243             ]}
244             ]}
245             ]));
246             }
247             }
248             });
249              
250              
251              
252              
253             # Low level inputs - no "field" div
254             HTML::Obj2HTML::register_extension("checkbox", {
255             tag => "",
256             before => sub {
257             my $obj = shift;
258              
259             if (ref $obj ne "HASH") { return ""; }
260              
261             my $readonly = HTML::Obj2HTML::get_opt("readonly") || $obj->{readonly};
262             delete($obj->{readonly});
263              
264             # TO-FIX: This should be multi param as multiple checkboxes might have the same name resulting in multiple values
265             if (!defined $obj->{value}) { $obj->{value} = 1; }
266             if (defined $obj->{name}) {
267             my $cgi = HTML::Obj2HTML::get_opt("CGI-params");
268             if (defined $cgi) {
269             my $val = $cgi->param($obj->{name});
270             if (defined $val && "$val" eq $obj->{value}) { $obj->{checked} = 1; } else { delete($obj->{checked}); }
271             }
272             }
273              
274             if ($readonly) {
275             return HTML::Obj2HTML::gen([ div => [
276             if => { cond => $obj->{checked}, true => [ icon => 'green check' ], false => [ icon => 'red close' ]},
277             _ => " ".$obj->{label}
278             ]]);
279             } else {
280             my $label = $obj->{label}; delete($obj->{label});
281             if (!$label && $obj->{checkboxlabel}) { $label = $obj->{checkboxlabel}; delete($obj->{checkboxlabel}); }
282             $obj->{if} = { cond => $obj->{checked}, true => { checked => 1 } }; delete($obj->{checked});
283             $obj->{type} = "checkbox";
284             return HTML::Obj2HTML::gen([
285             div => { class => 'ui checkbox', _ => [
286             input => $obj, label => $label
287             ] }
288             ]);
289             }
290             }
291             });
292             HTML::Obj2HTML::register_extension("radio", {
293             tag => "",
294             before => sub {
295             my $obj = shift;
296              
297             if (ref $obj ne "HASH") { return ""; }
298              
299             my $readonly = HTML::Obj2HTML::get_opt("readonly") || $obj->{readonly};
300             delete($obj->{readonly});
301              
302             if (!defined $obj->{value}) { $obj->{value} = 1; }
303             if (defined $obj->{name}) {
304             my $cgi = HTML::Obj2HTML::get_opt("CGI-params");
305             if (defined $cgi) {
306             my $val = $cgi->param($obj->{name});
307             if (defined $val && "$val" eq $obj->{value}) { $obj->{checked} = 1; } else { delete($obj->{checked}); }
308             }
309             }
310              
311             if ($readonly) {
312             return HTML::Obj2HTML::gen([ div => [
313             if => { cond => $obj->{checked}, true => [ icon => 'check' ] },
314             _ => " ".$obj->{label}
315             ]]);
316             } else {
317             my $label = $obj->{label}; delete($obj->{label});
318             if (!$label && $obj->{radiolabel}) { $label = $obj->{radiolabel}; delete($obj->{radiolabel}); }
319             $obj->{if} = { cond => $obj->{checked}, true => { checked => 1 } }; delete($obj->{checked});
320             $obj->{type} = "radio";
321             return HTML::Obj2HTML::gen([
322             div => { class => 'ui radio checkbox', _ => [
323             input => $obj, label => $label
324             ] }
325             ]);
326             }
327             }
328             });
329             HTML::Obj2HTML::register_extension("labeledinput", {
330             tag => "",
331             before => sub {
332             my $obj = shift;
333              
334             if (ref $obj ne "HASH") { return ""; }
335              
336             my $readonly = HTML::Obj2HTML::get_opt("readonly") || $obj->{readonly};
337             delete($obj->{readonly});
338              
339             if (defined $obj->{name}) {
340             my $cgi = HTML::Obj2HTML::get_opt("CGI-params");
341             if (defined $cgi) {
342             my $val = $cgi->param($obj->{name});
343             if (defined $val) { $obj->{value} = $val; }
344             }
345             }
346              
347             if ($readonly) {
348             return [ div => $obj->{value}." ".$obj->{label} ];
349             } else {
350             my $label = $obj->{label}; delete($obj->{label});
351              
352             # The has we were passed actually belongs to a child element, we need to copy and clear.
353             my $inputobj = {};
354             for (keys %$obj) { $inputobj->{$_} = $obj->{$_}; delete $obj->{$_}; }
355              
356             return [ div => { class => "ui right labeled input", _ => [
357             input => $inputobj,
358             div => { class => "ui basic label", _ => $label }
359             ]}];
360             }
361             }
362             });
363             HTML::Obj2HTML::register_extension("dateinput", {
364             tag => "",
365             before => sub {
366             my $obj = shift;
367              
368             if (ref $obj ne "HASH") { return ""; }
369              
370             return HTML::Obj2HTML::gen([
371             div => { class => "ui calendar dateonly", _ => [
372             div => { class => "ui input left icon", _ => [
373             i => { class => "calendar icon", _ => [] },
374             labeledinput => $obj
375             ]}
376             ]}
377             ]);
378             }
379             });
380              
381             HTML::Obj2HTML::register_extension("hiddeninput", {
382             tag => "input",
383             attr => { type => "hidden" }
384             });
385              
386              
387              
388              
389              
390             HTML::Obj2HTML::register_extension("submit", {
391             tag => "",
392             before => sub {
393             my $obj = shift;
394             if (ref $obj ne "HASH") { $obj = { _ => $obj }; }
395             my $readonly = HTML::Obj2HTML::get_opt("readonly") || $obj->{readonly};
396             delete($obj->{readonly});
397             if ($readonly) {
398             return [];
399             }
400             if (!ref $obj) { $obj = { value => $obj }; } else { $obj->{value} = $obj->{label}; delete($obj->{label}); }
401             if (defined $obj->{class}) { $obj->{class} .= " ui button"; } else { $obj->{class}.="ui positive button"; }
402             $obj->{type} = "submit";
403             return [ input => $obj ];
404             },
405             });
406              
407             HTML::Obj2HTML::register_extension("cancel", {
408             tag => "",
409             before => sub {
410             my $obj = shift;
411             if (ref $obj ne "HASH") { $obj = { _ => $obj }; }
412             my $readonly = HTML::Obj2HTML::get_opt("readonly") || $obj->{readonly};
413             delete($obj->{readonly});
414             if ($readonly) {
415             return [];
416             }
417             if (!ref $obj) { $obj = { value => $obj }; } else { $obj->{value} = $obj->{label}; delete($obj->{label}); }
418             if ($obj->{class}) { $obj->{class} .= " "; }
419             $obj->{class}.="ui negative button";
420             return [ a => $obj ];
421             },
422             });
423              
424              
425              
426              
427              
428             HTML::Obj2HTML::register_extension("helplabel", {
429             tag => "label",
430             before => sub {
431             my $o = shift;
432             if (ref $o ne "HASH") { $o = { helptext => $o }; }
433             $o->{_} = [ _ => $o->{label} ];
434             if ($o->{helptext}) {
435             push(@{$o->{_}}, help => { text => $o->{helptext} });
436             }
437             if ($o->{helphtml}) {
438             push(@{$o->{_}}, help => { html => $o->{helphtml} });
439             }
440             delete($o->{label});
441             delete($o->{helptext});
442             delete($o->{helphtml});
443             return "";
444             }
445             });
446              
447             sub genhelplabel {
448 0     0     my $obj = shift;
449 0 0         if (ref $obj ne "HASH") { $obj = { _ => $obj }; }
  0            
450 0 0         if ($obj->{label}) {
451 0           my $label = $obj->{label};
452 0           my @errorlabel = ();
453 0 0         if ($obj->{error}) {
454 0           @errorlabel = (i => { style => 'margin-left: 5px;', class => 'red circular icon exclamation', 'data-content' => $obj->{error} });
455             }
456 0 0         if ($obj->{helptext}) {
    0          
    0          
457 0           $label = [ _ => $label, \@errorlabel, i => { style => 'margin-left: 5px;', class => 'blue circular icon help', 'data-content' => $obj->{helptext}, _ => [] } ];
458 0           delete($obj->{helptext});
459             } elsif ($obj->{helphtml}) {
460 0           $label = [ _ => $label, \@errorlabel, i => { style => 'margin-left: 5px;', class => 'blue circular icon help', 'data-html' => $obj->{helphtml}, _ => [] } ];
461 0           delete($obj->{helphtml});
462             } elsif (@errorlabel) {
463 0           $label = [ _ => $label, \@errorlabel ];
464             }
465 0           delete($obj->{label});
466 0           return $label;
467             }
468 0           return;
469             }
470             sub commonfield {
471 0     0     my $obj = shift;
472 0           my $field = shift;
473              
474 0 0         if (ref $obj ne "HASH") { return ""; }
  0            
475 0           my $val = HTML::Obj2HTML::get_opt("data-formvalidator-results");
476 0 0         if (defined $val) {
477 0 0 0       if (!defined $obj->{error} || !$obj->{error}) {
478 0 0         if ($val->missing($obj->{name})) { $obj->{error} = "This field is required"; }
  0 0          
479 0           elsif ($val->invalid($obj->{name})) { $obj->{error} = "This field is invalid"; }
480             }
481             }
482 0           my $class = "field";
483 0           my $label = genhelplabel($obj);
484 0 0         if ($label) {
485 0           unshift(@{$field}, "label", $label);
  0            
486             };
487 0 0         if ($obj->{required}) {
488 0           $class .= " required";
489 0           delete($obj->{required});
490             }
491 0 0         if ($obj->{error}) {
492 0           $class .= " error";
493 0           delete($obj->{error});
494             }
495 0 0         if ($obj->{uiwidth}) {
496 0           $class .= " $semanticnumbers[$obj->{uiwidth}] wide";
497 0           delete($obj->{uiwidth});
498             }
499 0           return [ div => { class => $class, _ => $field }];
500             }
501             1;