blib/lib/Text/Slidez.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 12 | 12 | 100.0 |
branch | n/a | ||
condition | n/a | ||
subroutine | 4 | 4 | 100.0 |
pod | n/a | ||
total | 16 | 16 | 100.0 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package Text::Slidez; | ||||||
2 | $VERSION = v0.0.1; | ||||||
3 | |||||||
4 | 1 | 1 | 1045 | use warnings; | |||
1 | 3 | ||||||
1 | 43 | ||||||
5 | 1 | 1 | 7 | use strict; | |||
1 | 2 | ||||||
1 | 36 | ||||||
6 | 1 | 1 | 17 | use Carp; | |||
1 | 2 | ||||||
1 | 87 | ||||||
7 | |||||||
8 | 1 | 1 | 6 | use base 'Shebangml'; | |||
1 | 1 | ||||||
1 | 892 | ||||||
9 | use Class::Accessor::Classy; | ||||||
10 | lw 'slides'; | ||||||
11 | no Class::Accessor::Classy; | ||||||
12 | |||||||
13 | use XML::Bits qw(T); | ||||||
14 | |||||||
15 | =head1 NAME | ||||||
16 | |||||||
17 | Text::Slidez - format slideshows into XHTML | ||||||
18 | |||||||
19 | =head1 SYNOPSIS | ||||||
20 | |||||||
21 | See L |
||||||
22 | |||||||
23 | use Text::Slidez; | ||||||
24 | |||||||
25 | my $slidez = Text::Slidez->new; | ||||||
26 | $slidez->load('my_slides.hbml'); | ||||||
27 | foreach my $slide ($slidez->slides) { | ||||||
28 | ... | ||||||
29 | } | ||||||
30 | |||||||
31 | =cut | ||||||
32 | |||||||
33 | |||||||
34 | =head2 load | ||||||
35 | |||||||
36 | $slidez->load('my_slides.hbml'); | ||||||
37 | |||||||
38 | =cut | ||||||
39 | |||||||
40 | sub load { | ||||||
41 | my $self = shift; | ||||||
42 | my $input = shift; | ||||||
43 | |||||||
44 | local $self->{ctx}; | ||||||
45 | local $self->{started}; | ||||||
46 | |||||||
47 | $self->process($input); | ||||||
48 | |||||||
49 | # bit of cleanup on the innards: | ||||||
50 | foreach my $slide ($self->slides) { | ||||||
51 | my @kids = | ||||||
52 | grep({not ($_->tag eq '' and "$_" eq '')} $slide->children); | ||||||
53 | shift(@kids) while($kids[0] =~ m/^\s+$/); | ||||||
54 | pop(@kids) if($kids[-1] =~ m/^\n\s*$/); | ||||||
55 | $slide->{children} = [@kids]; | ||||||
56 | } | ||||||
57 | |||||||
58 | #warn join("\n---\n", @{$self->{slides}}); | ||||||
59 | return($self); | ||||||
60 | } # load ############################################################### | ||||||
61 | |||||||
62 | =head2 dump | ||||||
63 | |||||||
64 | Dump a marked-up version of the raw data. | ||||||
65 | |||||||
66 | warn $slidez->dump; | ||||||
67 | |||||||
68 | =cut | ||||||
69 | |||||||
70 | sub dump { | ||||||
71 | my $self = shift; | ||||||
72 | return join("\n---\n", | ||||||
73 | map({join("|", map({"($_)=" . $_->tag} $_->children))} | ||||||
74 | $self->slides) | ||||||
75 | ), "\n"; | ||||||
76 | } # dump ############################################################### | ||||||
77 | |||||||
78 | =head2 format_slide | ||||||
79 | |||||||
80 | Format a single slide for output. | ||||||
81 | |||||||
82 | my $xhtml = $slidez->format_slide($slide, %opts); | ||||||
83 | |||||||
84 | =cut | ||||||
85 | |||||||
86 | sub format_slide { | ||||||
87 | my $self = shift; | ||||||
88 | my ($slide, %opts) = @_; | ||||||
89 | |||||||
90 | my @parts = $self->_part_slide($slide); | ||||||
91 | |||||||
92 | # see if we can deduce a title from the first time we see one | ||||||
93 | unless($opts{title} or $self->{title}) { | ||||||
94 | if($parts[2] and @{$parts[1]} == 0) { | ||||||
95 | my $text = join('', @{$parts[0]}); | ||||||
96 | ($text) = split(/\n/, $text); | ||||||
97 | $text =~ s/<[^>]+>//g; | ||||||
98 | $self->{title} = $text; | ||||||
99 | } | ||||||
100 | } | ||||||
101 | |||||||
102 | my $page = T{html => | ||||||
103 | T{head => | ||||||
104 | T{title => $opts{title}||$self->{title}||'slidez'}, | ||||||
105 | T{meta => | ||||||
106 | ['http-equiv' => "Content-Type", | ||||||
107 | content => "text/html;charset=utf-8"]}, | ||||||
108 | T{meta => | ||||||
109 | ['http-equiv'=>"Content-Style-Type", | ||||||
110 | content => "text/css"]}, | ||||||
111 | T{link => | ||||||
112 | [rel=> 'stylesheet', href => 'style.css', type => 'text/css']}, | ||||||
113 | T{script => [type => 'text/javascript'], | ||||||
114 | $self->_mk_script(%opts); | ||||||
115 | }, | ||||||
116 | }, | ||||||
117 | T{body =>} | ||||||
118 | }; | ||||||
119 | $page->set_doctype('html PUBLIC "-//W3C//DTD XHTML 1.1//EN" | ||||||
120 | "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"'); | ||||||
121 | |||||||
122 | my $div = $page->child(-1)->create_child(div => [class => 'slide']); | ||||||
123 | |||||||
124 | $self->_handle_parts($div, \@parts, | ||||||
125 | calc_width => sub { | ||||||
126 | my $n = $self->_calc_width(shift); | ||||||
127 | $n > 20 ? '900px' : $n . 'em'; | ||||||
128 | }, | ||||||
129 | ); | ||||||
130 | |||||||
131 | return($page); | ||||||
132 | |||||||
133 | } # format_slide ####################################################### | ||||||
134 | |||||||
135 | =head2 as_single_page | ||||||
136 | |||||||
137 | $slidez->as_single_page; | ||||||
138 | |||||||
139 | =cut | ||||||
140 | |||||||
141 | sub as_single_page { | ||||||
142 | my $self = shift; | ||||||
143 | |||||||
144 | my @slides = $self->slides; | ||||||
145 | |||||||
146 | my $page = T{html => | ||||||
147 | T{head => | ||||||
148 | T{title => }, | ||||||
149 | T{meta => | ||||||
150 | ['http-equiv' => "Content-Type", | ||||||
151 | content => "text/html;charset=utf-8"]}, | ||||||
152 | T{meta => | ||||||
153 | ['http-equiv'=>"Content-Style-Type", | ||||||
154 | content => "text/css"]}, | ||||||
155 | T{link => | ||||||
156 | [rel=> 'stylesheet', href => 'style-flat.css', type => 'text/css']}, | ||||||
157 | }, | ||||||
158 | T{body =>} | ||||||
159 | }; | ||||||
160 | $page->set_doctype('html PUBLIC "-//W3C//DTD XHTML 1.1//EN" | ||||||
161 | "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"'); | ||||||
162 | |||||||
163 | my $title = $page->child(0)->child(0); | ||||||
164 | my $body = $page->child(-1); | ||||||
165 | my $outer = $body->create_child(div => [style=> "width: 600px"]); | ||||||
166 | |||||||
167 | for my $i (0..$#slides) { | ||||||
168 | my $div = $outer->create_child(div => [class => 'slide']); | ||||||
169 | |||||||
170 | my @parts = $self->_part_slide($slides[$i]); | ||||||
171 | unless($i) { # look for title on the first slide | ||||||
172 | if($parts[2] and @{$parts[1]} == 0) { | ||||||
173 | my $text = join('', @{$parts[0]}); | ||||||
174 | ($text) = split(/\n/, $text); | ||||||
175 | $text =~ s/^\s+//; | ||||||
176 | $text =~ s/<[^>]+>//g; | ||||||
177 | $title->create_child(''=> $text); | ||||||
178 | } | ||||||
179 | } | ||||||
180 | |||||||
181 | #warn "\n\nhandle $i\n\n\n"; | ||||||
182 | $self->_handle_parts($div, \@parts, | ||||||
183 | calc_width => sub { | ||||||
184 | my $n = $self->_calc_width(shift); | ||||||
185 | $n > 20 ? '500px' : $n . 'em'; | ||||||
186 | }, | ||||||
187 | ); | ||||||
188 | |||||||
189 | $outer->create_child(div => | ||||||
190 | [class => 'wee', style => "width:100%; text-align: right"], | ||||||
191 | )->create_child('' => | ||||||
192 | '' => $i+1 . ' / ' . scalar(@slides)); | ||||||
193 | $outer->create_child(hr =>); | ||||||
194 | } | ||||||
195 | |||||||
196 | return($page); | ||||||
197 | } # as_single_page ##################################################### | ||||||
198 | |||||||
199 | my %span_map = ( | ||||||
200 | L => 'large', | ||||||
201 | M => 'medium', | ||||||
202 | S => 'small', | ||||||
203 | ); | ||||||
204 | |||||||
205 | sub _atag { | ||||||
206 | my $self = shift; | ||||||
207 | my ($tag, $atts) = @_; | ||||||
208 | |||||||
209 | my @attr = $atts ? $atts->atts : (); | ||||||
210 | if(my $class = $span_map{$tag}) { | ||||||
211 | $tag = 'span'; | ||||||
212 | push(@attr, class => $class); | ||||||
213 | } | ||||||
214 | |||||||
215 | my $el = XML::Bits->new($tag, @attr ? \@attr : ()); | ||||||
216 | |||||||
217 | if($self->{ctx}) { | ||||||
218 | croak("no nested slides") if($tag eq 'slide'); | ||||||
219 | $self->{ctx}->add_child($el); | ||||||
220 | $self->{ctx} = $el; | ||||||
221 | } | ||||||
222 | else { | ||||||
223 | if($tag eq 'slide') { | ||||||
224 | croak("no start element") unless($self->{started}); | ||||||
225 | my $sl = $self->{slides} ||= []; | ||||||
226 | $self->{ctx} = $el; | ||||||
227 | push(@$sl, $el); | ||||||
228 | } | ||||||
229 | elsif($tag eq 'slides') { | ||||||
230 | $self->{started} = 1; | ||||||
231 | } | ||||||
232 | else { | ||||||
233 | croak("content '$tag' outside of slide!"); | ||||||
234 | } | ||||||
235 | } | ||||||
236 | |||||||
237 | return($el); | ||||||
238 | } | ||||||
239 | |||||||
240 | =head2 do_code | ||||||
241 | |||||||
242 | $slidez->do_code($tag, $atts, $string); | ||||||
243 | |||||||
244 | =cut | ||||||
245 | |||||||
246 | sub do_code { | ||||||
247 | my $self = shift; | ||||||
248 | my ($tag, $atts, $string) = @_; | ||||||
249 | |||||||
250 | my %atts = $atts ? $atts->atts : (); | ||||||
251 | |||||||
252 | my $make = sub { | ||||||
253 | my $pre = $self->{ctx}->create_child(pre => [%atts]); | ||||||
254 | $pre->create_child('' => $_) for(@_); | ||||||
255 | }; | ||||||
256 | |||||||
257 | my $ft = delete($atts{type}); | ||||||
258 | |||||||
259 | require Text::VimColor; | ||||||
260 | my $cache; | ||||||
261 | if($string) { | ||||||
262 | # XXX how to do the caching? | ||||||
263 | # warn "string code is slow: $string\n"; | ||||||
264 | } | ||||||
265 | else { | ||||||
266 | my $src = delete $atts{src} or croak("must have src"); | ||||||
267 | my $input = File::Fu->file($src); | ||||||
268 | my $cache_dir = File::Fu->dir('.cache'); | ||||||
269 | if($cache_dir->d) { | ||||||
270 | $cache = $cache_dir + $input->file; | ||||||
271 | if($cache->e and $cache->stat->mtime >= $input->stat->mtime) { | ||||||
272 | warn "load $input from cache\n"; | ||||||
273 | return($make->(scalar $cache->read)); | ||||||
274 | } | ||||||
275 | } | ||||||
276 | my %ftmap = ( | ||||||
277 | html => 'html', | ||||||
278 | hbml => 'hbml', | ||||||
279 | pl => 'perl', | ||||||
280 | pm => 'perl', | ||||||
281 | ); | ||||||
282 | unless($ft) { | ||||||
283 | my ($ext) = $input =~ m/\.([^\.]+)$/; | ||||||
284 | $ft = $ftmap{$ext} if($ftmap{$ext}); | ||||||
285 | } | ||||||
286 | $string = $input->read; | ||||||
287 | } | ||||||
288 | my $html = Text::VimColor->new( | ||||||
289 | string => $string, | ||||||
290 | $ft ? (filetype => $ft) : (), | ||||||
291 | )->html; | ||||||
292 | |||||||
293 | # leading whitespace cleanup | ||||||
294 | $html =~ s{]*>(\s+)}{$1}g; | ||||||
295 | # pull whitespace out front | ||||||
296 | $html =~ s{^(]+>)(\s+)}{$2$1}mg; | ||||||
297 | $html =~ s/\n+$//; | ||||||
298 | $make->($html); | ||||||
299 | $cache->write($html) if($cache); | ||||||
300 | |||||||
301 | } # do_code ############################################################ | ||||||
302 | |||||||
303 | =head1 Shebangml Callbacks | ||||||
304 | |||||||
305 | These are really part of the parser class and not the API. | ||||||
306 | |||||||
307 | =head2 put_tag | ||||||
308 | |||||||
309 | $slidez->put_tag($tag, $atts, $string); | ||||||
310 | |||||||
311 | =cut | ||||||
312 | |||||||
313 | sub put_tag { | ||||||
314 | my $self = shift; | ||||||
315 | my ($tag, $atts, $string) = @_; | ||||||
316 | |||||||
317 | return $self->do_code(@_) if($tag eq 'code'); | ||||||
318 | return $self->do_include($atts) if($tag eq '.include'); | ||||||
319 | |||||||
320 | my $el = $self->_atag($tag, $atts); | ||||||
321 | |||||||
322 | $el->create_child('' => $self->escape_text($string)) | ||||||
323 | if(defined($string)); | ||||||
324 | |||||||
325 | $self->{ctx} = $el->parent; | ||||||
326 | |||||||
327 | } # put_tag ############################################################ | ||||||
328 | |||||||
329 | =head2 put_tag_start | ||||||
330 | |||||||
331 | $slidez->put_tag_start($tag, $atts); | ||||||
332 | |||||||
333 | =cut | ||||||
334 | |||||||
335 | sub put_tag_start { | ||||||
336 | my $self = shift; | ||||||
337 | my ($tag, $atts) = @_; | ||||||
338 | |||||||
339 | my $el = $self->_atag($tag, $atts); | ||||||
340 | |||||||
341 | } # put_tag_start ###################################################### | ||||||
342 | |||||||
343 | =head2 put_tag_end | ||||||
344 | |||||||
345 | $slidez->put_tag_end($tag); | ||||||
346 | |||||||
347 | =cut | ||||||
348 | |||||||
349 | sub put_tag_end { | ||||||
350 | my $self = shift; | ||||||
351 | my ($tag) = @_; | ||||||
352 | |||||||
353 | $tag = 'span' if($span_map{$tag}); | ||||||
354 | |||||||
355 | my $ctx = delete($self->{ctx}); | ||||||
356 | return() if($tag eq 'slides'); | ||||||
357 | ($ctx->tag eq $tag) or croak($ctx->tag, " is not a $tag!"); | ||||||
358 | croak("context fail $tag") | ||||||
359 | unless($self->{ctx} = $ctx->parent or $tag eq 'slide'); | ||||||
360 | |||||||
361 | } # put_tag_end ######################################################## | ||||||
362 | |||||||
363 | =head2 put_text | ||||||
364 | |||||||
365 | $slidez->put_text($text); | ||||||
366 | |||||||
367 | =cut | ||||||
368 | |||||||
369 | sub put_text { | ||||||
370 | my $self = shift; | ||||||
371 | my ($text) = @_; | ||||||
372 | |||||||
373 | my $ctx = $self->{ctx} or return; | ||||||
374 | $ctx->create_child('', | ||||||
375 | length($text) ? $self->escape_text($text) : ''); | ||||||
376 | # TODO escaped text might actually contain some certain tags :-/ | ||||||
377 | |||||||
378 | } # put_text ########################################################### | ||||||
379 | |||||||
380 | =head2 _part_slide | ||||||
381 | |||||||
382 | my @parts = $self->_part_slide($slide); | ||||||
383 | |||||||
384 | =cut | ||||||
385 | |||||||
386 | sub _part_slide { | ||||||
387 | my $self = shift; | ||||||
388 | my ($slide) = @_; | ||||||
389 | |||||||
390 | my @children = $slide->children; | ||||||
391 | pop(@children) if($children[-1] =~ m/^\s*$/); | ||||||
392 | my @parts = ([]); | ||||||
393 | my $sp; | ||||||
394 | # warn join(",", map({$_->type} @children)); | ||||||
395 | # if($children[0]->is_text) { # undenting :-/ | ||||||
396 | # $children[0]->{content} =~ s/^(\s+)//; | ||||||
397 | # $sp = $1; | ||||||
398 | # } | ||||||
399 | # warn "sp is >$sp<\n"; | ||||||
400 | while(@children) { | ||||||
401 | my $bit = shift(@children); | ||||||
402 | if($bit->is_text and $bit->{content} =~ s/\n$//) { | ||||||
403 | #$bit->{content} =~ s/^$sp// if(defined($sp)); | ||||||
404 | push(@{$parts[-1]}, $bit) if(length($bit)); | ||||||
405 | push(@parts, []); # start a new group | ||||||
406 | } | ||||||
407 | else { | ||||||
408 | #if($bit->is_text) { $bit->{content} =~ s/^$sp// if(defined($sp)); } | ||||||
409 | push(@{$parts[-1]}, $bit); | ||||||
410 | } | ||||||
411 | } | ||||||
412 | |||||||
413 | foreach my $part (@parts) { | ||||||
414 | next unless(@$part); | ||||||
415 | shift(@$part) | ||||||
416 | while($part->[0]->is_text and $part->[0] =~ m/^\s+$/); | ||||||
417 | } | ||||||
418 | |||||||
419 | # drop the trailing chunk | ||||||
420 | pop(@parts) if(@{$parts[-1]} == 0); | ||||||
421 | |||||||
422 | if(0) { | ||||||
423 | warn "slide:\n"; | ||||||
424 | warn join("\n---\n", map({join('|', @$_)} @parts)), "\n"; | ||||||
425 | warn "\n\n\n"; | ||||||
426 | } | ||||||
427 | |||||||
428 | return(@parts); | ||||||
429 | } # _part_slide ######################################################## | ||||||
430 | |||||||
431 | =head2 _calc_width | ||||||
432 | |||||||
433 | my $n = $self->_calc_width($text); | ||||||
434 | |||||||
435 | =cut | ||||||
436 | |||||||
437 | sub _calc_width { | ||||||
438 | my $self = shift; | ||||||
439 | my $text = shift; | ||||||
440 | |||||||
441 | my @lines = split(/\n| /, $text); |
||||||
442 | my ($width) = sort({$b <=> $a} | ||||||
443 | map({s/<[^>]+>//g; s/&[^;]+;/./g; length($_)} @lines)); | ||||||
444 | $width *= 0.625; # emperical em-width adjustment | ||||||
445 | } # _calc_width ######################################################## | ||||||
446 | |||||||
447 | =head2 _handle_parts | ||||||
448 | |||||||
449 | $self->_handle_parts($ctx, \@parts, %opts); | ||||||
450 | |||||||
451 | =cut | ||||||
452 | |||||||
453 | sub _handle_parts { | ||||||
454 | my $self = shift; | ||||||
455 | my ($ctx, $parts, %opts) = @_; | ||||||
456 | |||||||
457 | my @parts = @$parts; | ||||||
458 | my $calc_width = $opts{calc_width}; | ||||||
459 | |||||||
460 | if($parts[2] and @{$parts[1]} == 0) { | ||||||
461 | my $title_chunk = shift(@parts); | ||||||
462 | shift(@parts); # scrap | ||||||
463 | $ctx->create_child(div => [class => 'title'], @$title_chunk); | ||||||
464 | $ctx->create_child('br'); | ||||||
465 | } | ||||||
466 | else { | ||||||
467 | # center the whole thing vertically | ||||||
468 | $ctx = $ctx->create_child(div => [class => 'cell']); | ||||||
469 | } | ||||||
470 | |||||||
471 | while(@parts) { | ||||||
472 | my $part = shift(@parts); | ||||||
473 | next unless(@$part); | ||||||
474 | if(@$part == 1 and $part->[0] =~ m/^[^<]* [^<]*$/) { |
||||||
475 | $ctx->add_child($part->[0]); | ||||||
476 | next; | ||||||
477 | } | ||||||
478 | # pre fixup | ||||||
479 | if(@$part == 1 and $part->[0]->tag eq 'pre') { | ||||||
480 | my ($pre) = @$part; | ||||||
481 | my $text = join('', $pre->children); | ||||||
482 | $text =~ s/^\n//; | ||||||
483 | if($text =~ s/^(\s+)//) { | ||||||
484 | my $sp = $1; | ||||||
485 | $text =~ s/^$sp//mg; | ||||||
486 | } | ||||||
487 | my %atts = $pre->atts; | ||||||
488 | my $class = $atts{class} || ''; | ||||||
489 | $pre->{children} = []; | ||||||
490 | $pre->create_child('' => $text); | ||||||
491 | my $width = $calc_width->($text); | ||||||
492 | my $inner = $ctx->create_child( | ||||||
493 | div => [class => "auto left $class", | ||||||
494 | style => "width: $width"]); | ||||||
495 | $inner->add_child($pre); | ||||||
496 | next; | ||||||
497 | } | ||||||
498 | # bullet points | ||||||
499 | if($part->[0] =~ m/^(\s*)\* /) { | ||||||
500 | my $sp = $1; | ||||||
501 | my @points = $part; | ||||||
502 | # then go back to the well: | ||||||
503 | while(@parts and $parts[0][0] =~ m/^\s*\* /) { | ||||||
504 | push(@points, shift(@parts)); | ||||||
505 | } | ||||||
506 | foreach my $point (@points) { | ||||||
507 | $point->[0]->is_text or die; | ||||||
508 | $point->[0]->{content} =~ s/^$sp//; | ||||||
509 | } | ||||||
510 | |||||||
511 | my $width = $calc_width->(join("\n", map({@$_} @points))); | ||||||
512 | my $inner = $ctx->create_child( | ||||||
513 | div => [class => "auto left", style => "width: $width"]); | ||||||
514 | my $top = $inner->create_child(ul =>); | ||||||
515 | my @d = ($top); | ||||||
516 | foreach my $point (@points) { | ||||||
517 | $point->[0]->{content} =~ s/(\s*)\*\s+//; | ||||||
518 | my $ws = length($1)/2; | ||||||
519 | # warn "ws: $ws ($point->[0]->{content})\n"; | ||||||
520 | if($ws) { | ||||||
521 | $d[$ws] ||= $d[$ws-1]->child(-1)->create_child(ul =>); | ||||||
522 | } | ||||||
523 | else { | ||||||
524 | @d = ($top); | ||||||
525 | } | ||||||
526 | $d[$ws]->create_child(li => @$point); | ||||||
527 | } | ||||||
528 | # warn "yay: $top\n"; | ||||||
529 | next; | ||||||
530 | } | ||||||
531 | my $inner = $ctx->create_child(div =>); | ||||||
532 | $inner->add_child($_) for(@$part); | ||||||
533 | } | ||||||
534 | |||||||
535 | } # _handle_parts ###################################################### | ||||||
536 | |||||||
537 | =head2 _mk_script | ||||||
538 | |||||||
539 | $self->_mk_script(%opts); | ||||||
540 | |||||||
541 | =cut | ||||||
542 | |||||||
543 | sub _mk_script { | ||||||
544 | my $self = shift; | ||||||
545 | my (%opts) = @_; | ||||||
546 | |||||||
547 | my $script = | ||||||
548 | ($opts{next} ? qq(var next="$opts{next}"\n) . | ||||||
549 | "var down=0; document.onmousedown=function(e) { down=1 }\n". | ||||||
550 | " document.onmousemove=function(e) { down=0; }\n". | ||||||
551 | "document.onmouseup=function(e) {\n" . | ||||||
552 | "if(down == 1) {window.location = next;}; }\n" : '' | ||||||
553 | ) . | ||||||
554 | ($opts{prev} ? qq(var prev="$opts{prev}"\n) : '') . | ||||||
555 | ($opts{first} ? qq(var first="$opts{first}"\n) : '') . | ||||||
556 | ($opts{last} ? qq(var last="$opts{last}"\n) : ''); | ||||||
557 | my $func = <<' ---'; | ||||||
558 | document.onkeypress=function(e) { | ||||||
559 | var e=window.event || e | ||||||
560 | var n=e.keyCode || e.which | ||||||
561 | switch (n) { | ||||||
562 | -SWITCH- | ||||||
563 | } | ||||||
564 | } | ||||||
565 | --- | ||||||
566 | my $switch = join("\n", map({$_ . ' break;'} | ||||||
567 | ($opts{next} ? 'case 32 : window.location = next;' : ()), | ||||||
568 | ($opts{prev} ? 'case 8 : window.location = prev;' : ()), | ||||||
569 | ($opts{first} ? 'case 36 : window.location = first;' : ()), | ||||||
570 | ($opts{last} ? 'case 35 : window.location = last;' : ()), | ||||||
571 | )); | ||||||
572 | $func =~ s/-SWITCH-/$switch/; | ||||||
573 | |||||||
574 | return($script . $func); | ||||||
575 | } # _mk_script ######################################################### | ||||||
576 | |||||||
577 | =head1 AUTHOR | ||||||
578 | |||||||
579 | Eric Wilhelm @ |
||||||
580 | |||||||
581 | http://scratchcomputing.com/ | ||||||
582 | |||||||
583 | =head1 BUGS | ||||||
584 | |||||||
585 | If you found this module on CPAN, please report any bugs or feature | ||||||
586 | requests through the web interface at L |
||||||
587 | notified, and then you'll automatically be notified of progress on your | ||||||
588 | bug as I make changes. | ||||||
589 | |||||||
590 | If you pulled this development version from my /svn/, please contact me | ||||||
591 | directly. | ||||||
592 | |||||||
593 | =head1 COPYRIGHT | ||||||
594 | |||||||
595 | Copyright (C) 2009 Eric L. Wilhelm, All Rights Reserved. | ||||||
596 | |||||||
597 | =head1 NO WARRANTY | ||||||
598 | |||||||
599 | Absolutely, positively NO WARRANTY, neither express or implied, is | ||||||
600 | offered with this software. You use this software at your own risk. In | ||||||
601 | case of loss, no person or entity owes you anything whatsoever. You | ||||||
602 | have been warned. | ||||||
603 | |||||||
604 | =head1 LICENSE | ||||||
605 | |||||||
606 | This program is free software; you can redistribute it and/or modify it | ||||||
607 | under the same terms as Perl itself. | ||||||
608 | |||||||
609 | =cut | ||||||
610 | |||||||
611 | # vi:ts=2:sw=2:et:sta | ||||||
612 | 1; |