line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
2
|
|
|
2
|
|
449673
|
use 5.024000; |
|
2
|
|
|
|
|
19
|
|
2
|
2
|
|
|
2
|
|
11
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
39
|
|
3
|
2
|
|
|
2
|
|
9
|
use warnings; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
119
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package Story::Interact::WWW; |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:TOBYINK'; |
8
|
|
|
|
|
|
|
our $VERSION = '0.001004'; |
9
|
|
|
|
|
|
|
|
10
|
2
|
|
|
2
|
|
12
|
use constant DISTRIBUTION => 'Story-Interact-WWW'; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
125
|
|
11
|
|
|
|
|
|
|
|
12
|
2
|
|
|
2
|
|
970
|
use Mojo::ShareDir; |
|
2
|
|
|
|
|
411920
|
|
|
2
|
|
|
|
|
126
|
|
13
|
2
|
|
|
2
|
|
20
|
use Mojo::Base 'Mojolicious', -signatures; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
10
|
|
14
|
2
|
|
|
2
|
|
632993
|
use Mojo::Util qw( xml_escape ); |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
95
|
|
15
|
2
|
|
|
2
|
|
942
|
use Story::Interact::State (); |
|
2
|
|
|
|
|
705334
|
|
|
2
|
|
|
|
|
79
|
|
16
|
2
|
|
|
2
|
|
978
|
use Text::Markdown::Hoedown; |
|
2
|
|
|
|
|
2337
|
|
|
2
|
|
|
|
|
2688
|
|
17
|
|
|
|
|
|
|
|
18
|
0
|
|
|
0
|
1
|
|
sub startup ( $self ) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
|
20
|
0
|
|
|
|
|
|
$self->log->info( 'Story::Interact::State->VERSION = ' . Story::Interact::State->VERSION ); |
21
|
|
|
|
|
|
|
|
22
|
0
|
|
|
|
|
|
$self->secrets( [ __PACKAGE__ . '/' . $VERSION ] ); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# Setup app config, paths, etc. |
25
|
0
|
|
|
|
|
|
$self->plugin( 'Config', { file => 'si_www.conf' } ); |
26
|
0
|
|
|
|
|
|
unshift( |
27
|
|
|
|
|
|
|
$self->static->paths->@*, |
28
|
|
|
|
|
|
|
$self->home->rel_file( 'local/public' ), |
29
|
|
|
|
|
|
|
Mojo::ShareDir->new( DISTRIBUTION, 'public' ), |
30
|
|
|
|
|
|
|
); |
31
|
0
|
|
|
|
|
|
unshift( |
32
|
|
|
|
|
|
|
$self->renderer->paths->@*, |
33
|
|
|
|
|
|
|
$self->home->rel_file( 'local/templates' ), |
34
|
|
|
|
|
|
|
Mojo::ShareDir->new( DISTRIBUTION, 'templates' ), |
35
|
|
|
|
|
|
|
); |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# Story list |
38
|
|
|
|
|
|
|
{ |
39
|
0
|
|
|
|
|
|
$self->routes->get( '/' )->to( |
40
|
0
|
|
|
0
|
|
|
cb => sub ($c) { |
|
0
|
|
|
|
|
|
|
41
|
0
|
|
|
|
|
|
my $stories = $self->config( 'story' ); |
42
|
|
|
|
|
|
|
my @keys = sort { |
43
|
0
|
|
0
|
|
|
|
( $stories->{$a}{title} // 'Story' ) cmp ( $stories->{$b}{title} // 'Story' ) |
|
0
|
|
0
|
|
|
|
|
44
|
|
|
|
|
|
|
} keys %$stories; |
45
|
0
|
|
|
|
|
|
my $html = ' |
46
|
0
|
|
|
|
|
|
for my $k ( @keys ) { |
47
|
|
|
|
|
|
|
$html .= sprintf( |
48
|
|
|
|
|
|
|
'%s', |
49
|
|
|
|
|
|
|
xml_escape( $c->url_for( "/story/$k" ) ), |
50
|
0
|
|
|
|
|
|
xml_escape( $stories->{$k}{title} ), |
51
|
|
|
|
|
|
|
); |
52
|
|
|
|
|
|
|
} |
53
|
0
|
|
|
|
|
|
$html .= ''; |
54
|
0
|
|
|
|
|
|
$c->stash->{title} = 'Stories'; |
55
|
0
|
|
|
|
|
|
$c->stash->{story_list} = $html; |
56
|
0
|
|
|
|
|
|
$c->render( template => 'index' ); |
57
|
|
|
|
|
|
|
}, |
58
|
0
|
|
|
|
|
|
)->name( 'index' ); |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
# HTML + JavaScript story harness |
62
|
|
|
|
|
|
|
{ |
63
|
0
|
|
|
|
|
|
$self->routes->get( '/story/:story' )->to( |
|
0
|
|
|
|
|
|
|
64
|
0
|
|
|
0
|
|
|
cb => sub ($c) { |
|
0
|
|
|
|
|
|
|
65
|
0
|
|
|
|
|
|
my $story_id = $c->stash( 'story' ); |
66
|
0
|
|
|
|
|
|
my $story_config = $self->config( 'story' )->{$story_id}; |
67
|
0
|
|
|
|
|
|
$c->stash->{api} = $c->url_for('/api'); |
68
|
0
|
|
|
|
|
|
$c->stash->{story_id} = $story_id; |
69
|
0
|
|
0
|
|
|
|
$c->stash->{title} = $story_config->{title} // 'Story'; |
70
|
0
|
|
0
|
|
|
|
$c->stash->{storage_key} = $story_config->{storage_key} // $story_id; |
71
|
0
|
|
0
|
|
|
|
$c->render( template => $story_config->{template} // 'story' ); |
72
|
|
|
|
|
|
|
}, |
73
|
0
|
|
|
|
|
|
)->name( 'story' ); |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# API endpoint to get a blank slate state |
77
|
|
|
|
|
|
|
{ |
78
|
0
|
|
|
|
|
|
$self->routes->get( '/api/state/init' )->to( |
|
0
|
|
|
|
|
|
|
79
|
0
|
|
|
0
|
|
|
cb => sub ($c) { |
|
0
|
|
|
|
|
|
|
80
|
0
|
|
|
|
|
|
my $blank = Story::Interact::State->new; |
81
|
0
|
|
|
|
|
|
$c->render( json => { state => $blank->dump } ); |
82
|
|
|
|
|
|
|
}, |
83
|
0
|
|
|
|
|
|
)->name( 'api-state-init' ); |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# API endpoint to read a page |
87
|
|
|
|
|
|
|
{ |
88
|
0
|
|
|
0
|
|
|
my $render_html = sub ( $page ) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
89
|
0
|
|
|
|
|
|
my $markdown = join "\n\n", @{ $page->text }; |
|
0
|
|
|
|
|
|
|
90
|
0
|
|
|
|
|
|
return markdown( $markdown ); |
91
|
0
|
|
|
|
|
|
}; |
92
|
0
|
|
|
|
|
|
$self->routes->post( '/api/story/:story/page/:page' )->to( |
93
|
0
|
|
|
0
|
|
|
cb => sub ($c) { |
|
0
|
|
|
|
|
|
|
94
|
0
|
|
|
|
|
|
my $story_id = $c->stash( 'story' ); |
95
|
0
|
|
|
|
|
|
my $page_id = $c->stash( 'page' ); |
96
|
0
|
|
|
|
|
|
$c->log->info("Request for page `$page_id` from story `$story_id`"); |
97
|
0
|
|
|
|
|
|
my $story_config = $self->config( 'story' )->{$story_id}; |
98
|
0
|
|
|
|
|
|
my $page_source = $story_config->{page_source}; |
99
|
0
|
|
0
|
|
|
|
my $munge_state = $story_config->{state_munge} // sub {}; |
100
|
0
|
|
0
|
|
|
|
my $munge = $story_config->{data_munge} // sub {}; |
101
|
0
|
|
|
|
|
|
my $state = Story::Interact::State->load( $c->req->json( '/state' ) ); |
102
|
0
|
|
|
|
|
|
$munge_state->( $c, $state ); |
103
|
|
|
|
|
|
|
|
104
|
0
|
0
|
|
|
|
|
if ( $page_id =~ /\A(.+)\?(.+)\z/ms ) { |
105
|
0
|
|
|
|
|
|
$page_id = $1; |
106
|
0
|
|
|
|
|
|
require URI::Query; |
107
|
0
|
|
|
|
|
|
my $params = URI::Query->new( $2 )->hash; |
108
|
0
|
|
|
|
|
|
$state->params( $params ); |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
else { |
111
|
0
|
|
|
|
|
|
$state->params( {} ); |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
0
|
|
|
|
|
|
my $page = $page_source->get_page( $state, $page_id ); |
115
|
0
|
|
|
|
|
|
my %data = ( |
116
|
|
|
|
|
|
|
%$page, |
117
|
|
|
|
|
|
|
state => $state->dump, |
118
|
|
|
|
|
|
|
html => $render_html->( $page ), |
119
|
|
|
|
|
|
|
); |
120
|
0
|
|
|
|
|
|
$munge->( \%data, $page, $state ); |
121
|
0
|
|
|
|
|
|
$c->render( json => \%data ); |
122
|
|
|
|
|
|
|
}, |
123
|
0
|
|
|
|
|
|
)->name( 'api-story-page' ); |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# Done! |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
1; |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
__END__ |