Almost-minimal filesystem based blog.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

251 lines
5.9 KiB

  1. package Display::Markup;
  2. use strict;
  3. use warnings;
  4. use base qw(Exporter);
  5. our @EXPORT_OK = qw(line_parse image_markup gallery);
  6. use File::Basename;
  7. use Display::Image qw(image_size gallery);
  8. use Text::Textile;
  9. # Some useful defaults:
  10. my %tags = (
  11. retcon => q{div class="retcon"},
  12. freeverse => 'p',
  13. list => "ul>\n<li"
  14. );
  15. my %end_tags = (
  16. retcon => 'div',
  17. freeverse => 'p',
  18. list => "li>\n</ul"
  19. );
  20. my %blank_lines = (
  21. freeverse => "</p>\n\n<p>",
  22. list => "</li>\n\n<li>"
  23. );
  24. my %newlines = (
  25. freeverse => "<br />\n"
  26. );
  27. my %dashes = (
  28. freeverse => ' &mdash; '
  29. );
  30. =item line_parse
  31. Performs substitutions on lines called by fragment_slurp, at least. Calls
  32. image_markup, Text::Textile, Wala::wiki_page_to_html, eval_perl. Returns
  33. string.
  34. Parses some special markup, specifically:
  35. <perl>embedded perl</perl>
  36. ${variable} interpolation from %DISPLAY_CONF
  37. <textile></textile> - Text::Textile to HTML
  38. <wala></wala> - Wala::wikify();
  39. <freeverse></freeverse>
  40. <retcon></retcon>
  41. <list></list>
  42. <gallery>directory_name</gallery>
  43. <image>filename.ext
  44. optional alt tag</image>
  45. =cut
  46. sub line_parse {
  47. my $self = shift;
  48. my ($everything, $file) = (@_);
  49. # Take care of <wala>, <textile>, <gallery>, and <image> tags:
  50. #$everything =~ s/<wala>(.*?)<\/wala>/Wala::wikify($1)/seg;
  51. textile_process($everything);
  52. $everything =~ s!<gallery>(.*?)</gallery>!$self->gallery_markup($file, $1)!seg;
  53. $everything =~ s!<image>(.*?)</image>!$self->image_markup($file, $1)!seg;
  54. foreach my $key (keys %tags) {
  55. # Set some replacements, unless they've been explicitly set already:
  56. $end_tags{$key} ||= $tags{$key};
  57. $blank_lines{$key} ||= "\n\n";
  58. $newlines{$key} ||= "\n";
  59. $dashes{$key} ||= " -- ";
  60. # Transform blocks:
  61. while ($everything =~ m/(<$key>.*?<\/$key>)/s) {
  62. my $block = $1;
  63. # Save the bits between instances of the block:
  64. my (@interstices) = split /\Q$block\E/s, $everything;
  65. # Tags that surround the block:
  66. $block =~ s{\n?<$key>\n?}{<$tags{$key}>}gs;
  67. $block =~ s{\n?</$key>\n?}{</$end_tags{$key}>}gs;
  68. # Dashes, blank lines, and newlines:
  69. $block = dashes($dashes{$key}, $block);
  70. $block =~ s/\n\n/$blank_lines{$key}/gs;
  71. $block = newlines($newlines{$key}, $block);
  72. # ...and slap it all back together as $everything
  73. $everything = join $block, @interstices;
  74. }
  75. }
  76. return $everything;
  77. }
  78. sub newlines {
  79. my ($replacement, $block) = @_;
  80. # Single newlines (i.e., line ends) within the block,
  81. # except those preceded by a double-quote, which probably
  82. # indicates a still-open tag:
  83. $block =~ s/(?<=[^"\n]) # not a double-quote or newline
  84. # don't capture
  85. \n # end-of-line
  86. (?=[^\n]) # not a newline
  87. # don't capture
  88. /$replacement/xgs;
  89. return $block;
  90. }
  91. # might need a rewrite.
  92. sub dashes {
  93. my ($replacement, $block) =@_;
  94. $block =~ s/(\s+) # whitespace - no capture
  95. \-{2} # two dashes
  96. (\n|\s+|$) # newline, whitespace, or eol
  97. /$1${replacement}$2/xgs;
  98. return $block;
  99. }
  100. =item textile_process
  101. Inline replace <textile> markup in a string.
  102. Trying to implement some caching here, though it's questionable whether
  103. this makes any sense. There's also a closure which should retain the
  104. Text::Textile object between invocations, potentially saving some time at
  105. the expense of a little memory.
  106. =cut
  107. { my %cache;
  108. my $textile;
  109. sub textile_process {
  110. my $replacement;
  111. unless (defined $textile) {
  112. # head_offset: use h1., h2. in Textile formatting:
  113. $textile = Text::Textile->new( head_offset => 2 );
  114. }
  115. while ( $_[0] =~ m/<textile>(.*?)<\/textile>/sx ) {
  116. my $block = $1;
  117. if (exists $cache{$block}) {
  118. $replacement = $cache{$block};
  119. } else {
  120. $replacement = $textile->process($block);
  121. $cache{$block} = $replacement;
  122. }
  123. $_[0] =~ s/<textile>\Q$block\E<\/textile>/$replacement/sg;
  124. }
  125. return;
  126. }
  127. }
  128. =item image_markup
  129. Parse out an image tag and return the appropriate html.
  130. Relies on image_size from Display::Image.
  131. =cut
  132. sub image_markup {
  133. my $self = shift;
  134. my ($file, $block) = @_;
  135. # Get a basename and directory for the file referencing the image:
  136. my ($basename, $dir) = fileparse($file);
  137. # Truncated file date that just includes date + sub docs:
  138. my ($file_date) = $dir =~ m{([0-9]{4}/ # year
  139. [0-9]{1,2}/ # month
  140. [0-9]{1,2}/ # day
  141. ([a-z]*/)*)$ # sub-entries
  142. }x;
  143. # Process the contents of the <image> tag:
  144. my ($image_url, $alt_text, $title_text) = split /\n/, $block;
  145. $alt_text ||= q{};
  146. $title_text ||= $alt_text;
  147. # Resolve relative paths:
  148. my $image_file;
  149. if (-e "$dir/$image_url" ) {
  150. $image_file = "$dir/$image_url";
  151. $image_url = "${file_date}${image_url}";
  152. } elsif (-e $self->root_dir . "/$image_url") {
  153. $image_file = $self->root_dir . "/$image_url";
  154. }
  155. # Get width & height in pixels for known filetypes:
  156. my ($width, $height) = image_size($image_file);
  157. # This probably relies on mod_rewrite working:
  158. $image_url = $self->image_url_root . $image_url;
  159. return <<"IMG";
  160. <img src="$image_url"
  161. width="$width"
  162. height="$height"
  163. alt="$alt_text"
  164. title="$title_text" />
  165. IMG
  166. }
  167. =item gallery_markup
  168. Generate a gallery of images.
  169. =cut
  170. sub gallery_markup {
  171. my $self = shift;
  172. my ($file, $block) = @_;
  173. my ($dir, $basedir) = fileparse($file);
  174. if (-d "$basedir/$file") {
  175. return gallery("$basedir/$file", "");
  176. }
  177. }
  178. # Encapsulate some ugly file-location functionality.
  179. sub resolve_file {
  180. }
  181. 1;