blib/lib/Web/PerlDistSite/MenuItem.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 18 | 105 | 17.1 |
branch | 0 | 36 | 0.0 |
condition | 0 | 22 | 0.0 |
subroutine | 6 | 17 | 35.2 |
pod | 0 | 7 | 0.0 |
total | 24 | 187 | 12.8 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package Web::PerlDistSite::MenuItem; 2: use utf8; 3: 4: our $VERSION = '0.001007'; 5: 6: use Moo; 7: use Web::PerlDistSite::Common -lexical, -all; 8: 9: use HTML::HTML5::Writer; 10: use HTML::HTML5::Sanity; 11: use XML::LibXML::PrettyPrint; 12: 13: has project => ( 14: is => 'rw', 15: isa => Object, 16: weak_ref => true, 17: trigger => sub ( $self, $new_val, $old_val=undef ) { 18: $_->project( $new_val ) for $self->children->@*; 19: }, 20: ); 21: 22: has name => ( 23: is => 'ro', 24: isa => Str, 25: required => true, 26: ); 27: 28: has title => ( 29: is => 'ro', 30: isa => Str, 31: required => true, 32: ); 33: 34: has href => ( 35: is => 'lazy', 36: isa => Str, 37: builder => true, 38: ); 39: 40: has rel => ( 41: is => 'ro', 42: isa => Str, 43: default => 'related', 44: ); 45: 46: has target => ( 47: is => 'ro', 48: isa => Str, 49: default => '_self', 50: ); 51: 52: has icon => ( 53: is => 'ro', 54: isa => Str, 55: ); 56: 57: has children => ( 58: is => 'rw', 59: isa => ArrayRef->of( 60: InstanceOf 61: ->of( 'Web::PerlDistSite::MenuItem' ) 62: ->plus_constructors( HashRef, 'from_hashref' ) 63: ), 64: coerce => true, 65: default => sub { [] }, 66: ); 67: 68: sub from_hashref ( $class, $hashref ) { 69: 70: if ( exists $hashref->{divider} ) { 71: $class .= '::Divider'; 72: } 73: elsif ( exists $hashref->{pod} ) { 74: $class .= '::Pod'; 75: } 76: elsif ( exists $hashref->{source} and $hashref->{source} =~ /.pod/ ) { 77: $class .= '::PodFile'; 78: } 79: elsif ( exists $hashref->{source} and $hashref->{source} =~ /.md/ ) { 80: $class .= '::MarkdownFile'; 81: } 82: elsif ( exists $hashref->{source} and $hashref->{source} =~ /.html/ ) { 83: $class .= '::HTMLFile'; 84: } 85: 86: return Module::Runtime::use_module( $class )->new( $hashref ); 87: } 88: 89: sub system_path ( $self ) { 90: path( $self->project->dist_dir )->child( $self->name . '.html' ) 91: } 92: 93: sub write_page ( $self ) { 94: return $self; 95: } 96: 97: sub write_pages ( $self ) { 98: $self->write_page; 99: $_->write_pages for $self->children->@*; 100: } 101: 102: sub _build_href ( $self ) { 103: if ( $self->name ) { 104: if ( $self->name eq 'github' ) { 105: return $self->project->github; 106: } 107: if ( $self->name eq 'metacpan' ) { 108: return 'https://metacpan.org/dist/' . $self->project->name; 109: } 110: if ( $self->name eq 'issues' ) { 111: return $self->project->issues // ( $self->project->github . '/issues' ); 112: } 113: } 114: return $self->project->root_url . $self->name . '.html'; 115: } 116: 117: sub _compile_dom ( $self, $dom ) { 118: state $p = do { 119: my $pp = XML::LibXML::PrettyPrint->new; 120: push $pp->{element}{preserves_whitespace}->@*, sub ( $node ) { 121: return undef unless $node->can( 'tagName' ); 122: return 1 if $node->tagName eq 'code' and $node->parentNode->tagName eq 'pre'; 123: return undef; 124: }; 125: unshift $pp->{element}{inline}->@*, sub ( $node ) { 126: return undef unless $node->can( 'tagName' ); 127: return 1 if $node->tagName eq 'pre' and $node->getElementsByTagName( 'code' )->size; 128: return undef; 129: }; 130: unshift $pp->{element}{compact}->@*, 'a'; 131: $pp; 132: }; 133: state $w = HTML::HTML5::Writer->new( markup => 'xhtml', polyglot => true ); 134: my $sane = fix_document( $dom ); 135: $p->pretty_print( $sane ); 136: return $w->document( $sane ); 137: } 138: 139: sub nav_item ( $self, $active_item ) { 140: my $icon = $self->icon // ''; 141: if ( length $icon ) { 142: $icon .= ' '; 143: } 144: 145: if ( $self->children->@* ) { 146: my @items = map $_->dropdown_item( $active_item ), $self->children->@*; 147: return sprintf( 148: '<li class="nav-item dropdown"><a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">%s%s</a><ul class="dropdown-menu">%s</ul></li>', 149: $icon, 150: esc_html( $self->title ), 151: join( q{}, @items ), 152: ); 153: } 154: elsif ( $self == $active_item ) { 155: return sprintf( 156: '<li class="nav-item"><a class="nav-link active" rel="%s" target="%s" href="%s">%s%s</a></li>', 157: esc_html( $self->rel ), 158: esc_html( $self->target ), 159: esc_html( $self->href ), 160: $icon, 161: esc_html( $self->title ), 162: ); 163: } 164: else { 165: return sprintf( 166: '<li class="nav-item"><a class="nav-link" rel="%s" target="%s" href="%s">%s%s</a></li>', 167: esc_html( $self->rel ), 168: esc_html( $self->target ), 169: esc_html( $self->href ), 170: $icon, 171: esc_html( $self->title ), 172: ); 173: } 174: } 175: 176: sub dropdown_item ( $self, $active_item ) { 177: my $icon = $self->icon // ''; 178: if ( length $icon ) { 179: $icon .= ' '; 180: } 181: 182: if ( $self == $active_item ) { 183: return sprintf( 184: '<li><a class="dropdown-item active" rel="%s" target="%s" href="%s">%s%s</a></li>', 185: esc_html( $self->rel ), 186: esc_html( $self->target ), 187: esc_html( $self->href ), 188: $icon, 189: esc_html( $self->title ), 190: ); 191: } 192: else { 193: return sprintf( 194: '<li><a class="dropdown-item" rel="%s" target="%s" href="%s">%s%s</a></li>', 195: esc_html( $self->rel ), 196: esc_html( $self->target ), 197: esc_html( $self->href ), 198: $icon, 199: esc_html( $self->title ), 200: ); 201: } 202: } 203: 204: sub page_title ( $self ) { 205: return sprintf( '%s — %s', $self->project->name, $self->title ); 206: } 207: 208: 1; 209: |