HTML.pm 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. package Trog::Routes::HTML;
  2. use strict;
  3. use warnings;
  4. no warnings 'experimental';
  5. use feature qw{signatures};
  6. use Trog::Config;
  7. my $conf = Trog::Config::get();
  8. my $template_dir = 'www/templates';
  9. my $theme_dir;
  10. $theme_dir = "themes/$conf->{'general.theme'}" if $conf->{'general.theme'} && -d "www/themes/$conf->{'general.theme'}";
  11. use lib 'www';
  12. # TODO Things which should be themable
  13. our $landing_page = 'default.tx';
  14. our $htmltitle = 'title.tx';
  15. our $midtitle = 'midtitle.tx';
  16. our $rightbar = 'rightbar.tx';
  17. our $leftbar = 'leftbar.tx';
  18. our $footbar = 'footbar.tx';
  19. our %routes = (
  20. '/' => {
  21. method => 'GET',
  22. callback => \&Trog::Routes::HTML::index,
  23. },
  24. '/setup' => {
  25. method => 'GET',
  26. callback => \&Trog::Routes::HTML::setup,
  27. },
  28. '/login' => {
  29. method => 'GET',
  30. callback => \&Trog::Routes::HTML::login,
  31. },
  32. '/auth' => {
  33. method => 'POST',
  34. callback => \&Trog::Routes::HTML::login,
  35. },
  36. '/config' => {
  37. method => 'GET',
  38. auth => 1,
  39. callback => \&Trog::Routes::HTML::config,
  40. },
  41. '/config/save' => {
  42. method => 'POST',
  43. auth => 1,
  44. callback => \&Trog::Routes::HTML::config,
  45. },
  46. '/post' => {
  47. method => 'GET',
  48. auth => 1,
  49. callback => \&Trog::Routes::HTML::post,
  50. },
  51. '/post/save' => {
  52. method => 'POST',
  53. auth => 1,
  54. callback => \&Trog::Routes::HTML::post,
  55. },
  56. '/posts' => {
  57. method => 'GET',
  58. callback => \&Trog::Routes::HTML::posts,
  59. },
  60. '/files' => {
  61. method => 'GET',
  62. callback => \&Trog::Routes::HTML::files
  63. },
  64. );
  65. # Build aliases for /post with extra data
  66. my @post_aliases = qw{news blog wiki video audio about};
  67. @routes{map { "/$_" } @post_aliases} = map { my %copy = %{$routes{'/posts'}}; $copy{data} = { tag => [$_] }; \%copy } @post_aliases;
  68. # Grab theme routes
  69. if ($theme_dir) {
  70. my $theme_mod = "$theme_dir/routes.pm";
  71. if (-f $theme_mod ) {
  72. require $theme_mod;
  73. @routes{keys(%Theme::routes)} = values(%Theme::routes);
  74. }
  75. }
  76. sub index ($query, $input, $render_cb, $content = '', $i_styles = []) {
  77. $input->{theme_dir} = $theme_dir || '';
  78. my $processor = Text::Xslate->new(
  79. path => $template_dir,
  80. );
  81. my $t_processor;
  82. $t_processor = Text::Xslate->new(
  83. path => "www/$theme_dir/templates",
  84. ) if $theme_dir;
  85. $content ||= _pick_processor($rightbar,$processor,$t_processor)->render($landing_page,$input);
  86. my @styles = ('/styles/avatars.css'); #TODO generate file for users
  87. if ($theme_dir) {
  88. unshift(@styles, _themed_style("screen.css")) if -f 'www/'._themed_style("screen.css");
  89. unshift(@styles, _themed_style("structure.css")) if -f 'www/'._themed_style("structure.css");
  90. }
  91. push( @styles, @$i_styles);
  92. #TODO allow theming of print css
  93. return $render_cb->('index.tx',{
  94. user => $query->{user},
  95. theme_dir => $theme_dir,
  96. content => $content,
  97. title => $conf->{'general.title'},
  98. htmltitle => _pick_processor("templates/$htmltitle" ,$processor,$t_processor)->render($htmltitle,$input),
  99. midtitle => _pick_processor("templates/$midtitle" ,$processor,$t_processor)->render($midtitle,$input),
  100. rightbar => _pick_processor("templates/$rightbar" ,$processor,$t_processor)->render($rightbar,$input),
  101. leftbar => _pick_processor("templates/$leftbar" ,$processor,$t_processor)->render($leftbar,$input),
  102. footbar => _pick_processor("templates/$footbar" ,$processor,$t_processor)->render($footbar,$input),
  103. stylesheets => \@styles,
  104. });
  105. }
  106. sub setup ($query, $input, $render_cb) {
  107. return $render_cb->('notconfigured.tx', {
  108. title => 'tCMS Requires Setup to Continue...',
  109. stylesheets => _build_themed_styles('notconfigured.css'),
  110. });
  111. }
  112. sub login ($query, $input, $render_cb) {
  113. # TODO actually do login processing
  114. $query->{failed} //= -1;
  115. return $render_cb->('login.tx', {
  116. title => 'tCMS 2 ~ Login',
  117. to => $query->{to} || '/config',
  118. login_failure => int( $query->{failed} ),
  119. login_message => int( $query->{failed} ) < 1 ? "Login Successful, Redirecting..." : "Login Failed.",
  120. stylesheets => _build_themed_styles('login.css'),
  121. });
  122. }
  123. sub config ($query, $input, $render_cb) {
  124. return $render_cb->('config.tx', {
  125. title => 'Configure tCMS',
  126. stylesheets => _build_themed_styles('config.css'),
  127. });
  128. }
  129. sub config_save ($query, $input, $render_cb) {
  130. return config($query, $input, $render_cb);
  131. }
  132. sub post ($query, $input, $render_cb) {
  133. return $render_cb->('post.tx', {
  134. title => 'New Post',
  135. stylesheets => _build_themed_styles('post.css'),
  136. });
  137. }
  138. sub post_save ($query, $input, $render_cb) {
  139. return post($query, $input, $render_cb);
  140. }
  141. sub posts ($query, $input, $render_cb) {
  142. my $tags = _coerce_array($query->{tag});
  143. require Trog::Data;
  144. my $data = Trog::Data->new($conf);
  145. my $processor ||= Text::Xslate->new(
  146. path => _dir_for_resource('posts.tx'),
  147. );
  148. my $styles = _build_themed_styles('posts.css');
  149. my $content = $processor->render('posts.tx', {
  150. title => "Posts tagged @$tags",
  151. date => 'TODO',
  152. posts => $data->get(
  153. tags => $tags,
  154. like => $query->{like},
  155. ),
  156. });
  157. return Trog::Routes::HTML::index($query, $input, $render_cb, $content, $styles);
  158. }
  159. sub files ($query, $input, $render_cb) {
  160. return $render_cb->('fileman.tx', {
  161. title => 'tCMS File Browser',
  162. stylesheets => _build_themed_styles('fileman.css'),
  163. });
  164. }
  165. # Deal with Params which may or may not be arrays
  166. sub _coerce_array ($param) {
  167. my $p = $param || [];
  168. $p = [$param] if $param && (ref $param ne 'ARRAY');
  169. return $p;
  170. }
  171. sub _build_themed_styles ($style) {
  172. my @styles = ("/styles/$style");
  173. my $ts = _themed_style($style);
  174. push(@styles, $ts) if $theme_dir && -f $ts;
  175. return \@styles;
  176. }
  177. sub _pick_processor($file, $normal, $themed) {
  178. return _dir_for_resource($file) eq $template_dir ? $normal : $themed;
  179. }
  180. # Pick appropriate dir based on whether theme override exists
  181. sub _dir_for_resource ($resource) {
  182. return $theme_dir && -f "www/$theme_dir/$resource" ? $theme_dir : $template_dir;
  183. }
  184. sub _themed_style ($resource) {
  185. return _dir_for_resource("styles/$resource")."/styles/$resource";
  186. }
  187. 1;