File Coverage

blib/lib/Mojolicious/Plugin/Bootstrap3.pm
Criterion Covered Total %
statement 54 103 52.4
branch 11 42 26.1
condition 6 17 35.2
subroutine 10 16 62.5
pod 2 2 100.0
total 83 180 46.1


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::Bootstrap3;
2              
3             =head1 NAME
4              
5             Mojolicious::Plugin::Bootstrap3 - Mojolicious + http://getbootstrap.com/
6              
7             =head1 VERSION
8              
9             3.3505
10              
11             =head1 DESCRIPTION
12              
13             L is used to include L
14             CSS and JavaScript files into your project.
15              
16             This is done with the help of L and
17             L.
18              
19             See L on how to
20             intall Sass.
21              
22             =head1 SYNOPSIS
23              
24             =head2 Mojolicious application with embedded template
25              
26             use Mojolicious::Lite;
27             plugin "bootstrap3";
28             get "/" => "index";
29             app->start;
30              
31             __DATA__
32             @@ index.html.ep
33            
34            
35            
36             %= asset "bootstrap.css"
37             %= asset "bootstrap.js"
38            
39            
40            
41            
42            
43             %= form_for "index", begin
44            
45            
46            
47            
48            
49             % end
50            
51            
52            

Alarm!

53            
54            
55            
56            
57            
58              
59             This basic application will make the C and C
60             assets available, which again is loaded into the "index.html.ep" template in the
61             data section.
62              
63             Note: If this is all you're going to do, you can rather use
64             L directly:
65              
66             use Mojolicious::Lite;
67             plugin "AssetPack";
68             app->asset("bootstrap.css" => "http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css");
69             app->asset("bootstrap.js" => "http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js");
70              
71             =head2 Custom stylesheet
72              
73             The reason for using this plugin is that it's very easy to customize Bootstrap,
74             and make a smaller package for the user to download.
75              
76             use Mojolicious::Lite;
77             plugin "bootstrap3", {custom => 1};
78             get "/" => "index";
79             app->start;
80              
81             Setting C to a true value will copy C to your
82             C directory. You can then edit the file and remove the parts
83             you don't need.
84              
85             =head2 Custom javascript
86              
87             Custom list of which javascript to include can be done directly in the
88             configuration:
89              
90             plugin "bootstrap3", jquery => 0, js => [qw( transition.js tooltip.js )];
91              
92             The config above will I include jQuery, and only include "transition.js"
93             and "tooltip.js" in the output C bundle. Complete list of
94             possible javascripts can be found under L.
95              
96             =head2 Themes
97              
98             It is very simple to use a custom
99             L<_variables.scss|https://github.com/twbs/bootstrap-sass/blob/master/assets/stylesheets/bootstrap/_variables.scss>
100             file with your project. This file contains the variables controlling colors,
101             fonts and styling rules in general.
102              
103             Example:
104              
105             # application code
106             $app->plugin(bootstrap3 => (
107             theme => {xyz => "http://example.com/_variables.scss"}
108             ));
109              
110             # template code
111             %= asset "xyz.css"
112             %= asset "bootstrap.js"
113              
114             There is also built in support for themes from L. To
115             use one of the themes from bootswatch, simply specify the URL to the
116             C<_bootswatch.scss> file instead of C<_variables.scss>:
117              
118             # application code
119             $app->plugin(bootstrap3 => (
120             theme => {paper => "https://bootswatch.com/paper/_bootswatch.scss"}
121             ));
122              
123             # template code
124             %= asset "paper.css"
125             %= asset "bootstrap.js"
126              
127             =head1 STATIC FILE STRUCTURE
128              
129             You can replace any of these static files in your own project.
130              
131             L
132             and
133             L
134             are probably the files that you want to replace, to make the generated
135             bootstrap file smaller and more personal.
136              
137             font/glyphicons-halflings-regular.eot
138             font/glyphicons-halflings-regular.svg
139             font/glyphicons-halflings-regular.ttf
140             font/glyphicons-halflings-regular.woff
141             js/bootstrap/affix.js
142             js/bootstrap/alert.js
143             js/bootstrap/button.js
144             js/bootstrap/carousel.js
145             js/bootstrap/collapse.js
146             js/bootstrap/dropdown.js
147             js/bootstrap/modal.js
148             js/bootstrap/popover.js
149             js/bootstrap/scrollspy.js
150             js/bootstrap/tab.js
151             js/bootstrap/tooltip.js
152             js/bootstrap/transition.js
153             js/jquery-1.11.0.min.js
154             sass/bootstrap.scss
155             sass/bootstrap/_alerts.scss
156             sass/bootstrap/_badges.scss
157             sass/bootstrap/_breadcrumbs.scss
158             sass/bootstrap/_button-groups.scss
159             sass/bootstrap/_buttons.scss
160             sass/bootstrap/_carousel.scss
161             sass/bootstrap/_close.scss
162             sass/bootstrap/_code.scss
163             sass/bootstrap/_component-animations.scss
164             sass/bootstrap/_dropdowns.scss
165             sass/bootstrap/_field-with-error.scss
166             sass/bootstrap/_forms.scss
167             sass/bootstrap/_glyphicons.scss
168             sass/bootstrap/_grid.scss
169             sass/bootstrap/_input-groups.scss
170             sass/bootstrap/_jumbotron.scss
171             sass/bootstrap/_labels.scss
172             sass/bootstrap/_list-group.scss
173             sass/bootstrap/_media.scss
174             sass/bootstrap/_mixins.scss
175             sass/bootstrap/_modals.scss
176             sass/bootstrap/_navbar.scss
177             sass/bootstrap/_navs.scss
178             sass/bootstrap/_normalize.scss
179             sass/bootstrap/_pager.scss
180             sass/bootstrap/_pagination.scss
181             sass/bootstrap/_panels.scss
182             sass/bootstrap/_popovers.scss
183             sass/bootstrap/_print.scss
184             sass/bootstrap/_progress-bars.scss
185             sass/bootstrap/_responsive-utilities.scss
186             sass/bootstrap/_scaffolding.scss
187             sass/bootstrap/_tables.scss
188             sass/bootstrap/_theme.scss
189             sass/bootstrap/_thumbnails.scss
190             sass/bootstrap/_tooltip.scss
191             sass/bootstrap/_type.scss
192             sass/bootstrap/_utilities.scss
193             sass/bootstrap/_variables.scss
194             sass/bootstrap/_wells.scss
195              
196             =head2 Non-standard files
197              
198             Some of the L are not bundled with the
199             original Bootstrap distribution.
200              
201             =over 4
202              
203             =item * js/jquery-1.11.0.min.js
204              
205             The jQuery bundled with this distribution will always be compatible with
206             the Bootstrap javascript files. It might change minor version, but it is
207             very unlikely that it will change much. Exceptions from this rule is if
208             the Bootstrap javascripts should require a newer version to function
209             properly.
210              
211             =item * sass/bootstrap/_field-with-error.scss
212              
213             This SASS file need to be included manually. It is used to style
214             L<.field-with-error|Mojolicious::Plugin::TagHelpers/DESCRIPTION>
215             tags, the same way as L<.has-error|http://getbootstrap.com/css/#forms-control-validation>.
216              
217             Example of markup that will be styled on
218             L:
219              
220            
221             %= label_for "username", "Username", class => "col-sm-2 control-label"
222            
223             %= text_field "username", class => "form-control"
224            
225            
226              
227             This is EXPERIMENTAL and subject to change.
228              
229             =back
230              
231             =cut
232              
233 2     2   359666 use Mojo::Base 'Mojolicious::Plugin';
  2         6  
  2         12  
234 2     2   1083 use Mojo::Util ();
  2         4  
  2         35  
235 2     2   10 use File::Basename 'dirname';
  2         4  
  2         86  
236 2     2   10 use File::Copy ();
  2         4  
  2         27  
237 2     2   10 use File::Path ();
  2         3  
  2         24  
238 2     2   9 use File::Spec ();
  2         4  
  2         25  
239 2     2   8 use Cwd ();
  2         3  
  2         63  
240 2   50 2   9 use constant DEBUG => $ENV{MOJO_ASSETPACK_DEBUG} || 0;
  2         2  
  2         3250  
241              
242             our $VERSION = '3.3505';
243             our $OVERRIDE; # ugly hack. might go away
244              
245             $ENV{SASS_PATH} ||= '';
246              
247             my $ASSET_DIR = do { local $_ = Cwd::abs_path(__FILE__); s!\.pm$!!; $_; };
248              
249             my @DEFAULT_CSS_FILES = qw( bootstrap.scss );
250             my @DEFAULT_JS_FILES
251             = qw( transition.js alert.js button.js carousel.js collapse.js dropdown.js modal.js tooltip.js popover.js scrollspy.js tab.js affix.js );
252              
253             =head1 METHODS
254              
255             =head2 asset_path
256              
257             $path = Mojolicious::Plugin::Bootstrap3->asset_path($type);
258             $path = $self->asset_path($type);
259              
260             Returns the base path to the assets bundled with this module.
261              
262             Set C<$type> to "sass" if you want a return value that is suitable for
263             the C environment variable.
264              
265             =cut
266              
267             sub asset_path {
268 2     2 1 311 my ($self, $type) = @_;
269 2 50       9 my @path = ref $self ? @{$self->{sass_path}} : ();
  2         6  
270 2         4 my %PATH;
271              
272 2 50 66     27 return join ':', grep { -d $_ and !$PATH{$_}++ } split(/:/, $ENV{SASS_PATH}), @path,
  1 100       50  
273             File::Spec->catdir($ASSET_DIR, 'sass')
274             if $type and $type eq 'sass';
275 1         6 return $ASSET_DIR;
276             }
277              
278             =head2 register
279              
280             $app->plugin(
281             bootstrap3 => {
282             css => [qw( bootstrap.scss )],
283             js => [qw( button.js collapse.js ... )],
284             custom => 0,
285             jquery => 1,
286             theme => undef,
287             },
288             );
289              
290             Default values:
291              
292             =over 4
293              
294             =item * css: C
295              
296             The name of the files to include in the asset named C.
297              
298             Specify an empty list to disable building C.
299              
300             =item * js
301              
302             C, C, C, C, C,
303             C, C, C, C, C,
304             C and C.
305              
306             The name of the files to include in the asset named C.
307              
308             Specify an empty list to disable building C.
309              
310             =item * custom
311              
312             Disabled by default. Will copy C to your project if
313             true and set C to the appropriate paths.
314              
315             =item * jquery
316              
317             This will include the bundled L version in the
318             L asset. Set this to 0 if you include your own jQuery.
319              
320             =item * theme
321              
322             Specifying a theme will override L and L.
323              
324             See L.
325              
326             =back
327              
328             =cut
329              
330             sub register {
331 1     1 1 34 my ($self, $app, $config) = @_;
332              
333 1 50       2 $app->plugin('AssetPack') unless eval { $app->asset };
  1         12  
334              
335 1         31827 $self->{sass_path} = [];
336 1   50     14 $config->{css} ||= [@DEFAULT_CSS_FILES];
337 1   50     9 $config->{js} ||= [@DEFAULT_JS_FILES];
338 1 50       4 $config->{custom} = 0 if $config->{theme};
339 1   50     11 $config->{jquery} //= 1;
340              
341 1         3 push @{$app->asset->source_paths}, $self->asset_path;
  1         7  
342              
343 1 50       14 if ($config->{custom}) {
344             $self->_copy_files($app,
345 0 0       0 map { [$_, $_] } ref $config->{custom} eq 'ARRAY' ? @{$config->{custom}} : @DEFAULT_CSS_FILES);
  0         0  
  0         0  
346             }
347              
348 1 50       4 if ($config->{theme}) {
    50          
349 0         0 $self->_generate_theme($app, $config->{theme});
350             }
351 1         6 elsif (@{$config->{css}}) {
352 1         4 $ENV{SASS_PATH} = $self->asset_path('sass');
353 1         2 warn "[BOOTSTRAP] Defining asset 'bootstrap.css' SASS_PATH=$ENV{SASS_PATH}\n" if DEBUG;
354 1         3 $app->asset('bootstrap.css' => map {"/sass/$_"} @{$config->{css}});
  1         29  
  1         2  
355             }
356              
357 1 50       22675 if (@{$config->{js}}) {
  1         9  
358             $app->asset(
359             'bootstrap.js' => $config->{jquery} ? ('/js/jquery-1.11.0.min.js') : (),
360 1 50       6 map {"/js/bootstrap/$_"} @{$config->{js}},
  12         33  
  1         4  
361             );
362             }
363             }
364              
365             sub _copy_files {
366 0 0   0     my $modifier = ref $_[-1] eq 'CODE' ? pop : sub { };
        0      
367 0           my ($self, $app, @files) = @_;
368              
369 0           for (@files) {
370 0           my ($from, $to) = @$_;
371 0           my $source = File::Spec->catfile($ASSET_DIR, 'sass', split '/', $from);
372 0 0         my $destination = $self->_destination_file($app, $to) or next;
373 0 0         File::Path::make_path(dirname $destination) unless -d dirname($destination);
374 0           $app->log->info("[BOOTSTRAP] Copying $source to $destination");
375 0           local $_ = Mojo::Util::slurp($source);
376 0           $modifier->();
377 0           Mojo::Util::spurt($_, $destination);
378             }
379             }
380              
381             sub _destination_file {
382 0     0     my ($self, $app, $name) = @_;
383              
384 0           for my $path (@{$app->asset->source_paths}) {
  0            
385 0           my $destination_dir = File::Spec->catdir($path, 'sass');
386 0           my $destination = File::Spec->catfile($destination_dir, split '/', $name);
387 0           push @{$self->{sass_path}}, $destination_dir;
  0            
388 0 0         return '' if -e $destination; # already exists
389 0           warn "[BOOTSTRAP] Can write $destination\n" if DEBUG;
390 0 0         return $destination if -w dirname $destination_dir;
391             }
392              
393             # should never come to this, because of
394 0           $app->log->warn("Custom file $name does not exist in static directories!");
395 0           return '';
396             }
397              
398             sub _generate_theme {
399 0     0     my ($self, $app, $theme) = @_;
400              
401 0           for my $name (keys %$theme) {
402 0           my $url = $theme->{$name};
403              
404 0           warn "[BOOTSTRAP] Defining theme '$name' from $url\n" if DEBUG;
405              
406 0 0         if ($url =~ m!/_bootswatch\.scss!) {
407 0           my $destination = $self->_destination_file($app, "$name/_bootswatch.scss");
408 0 0 0       $self->_move($app->asset->fetch($url), $destination) if $destination and !-e $destination;
409 0           $url =~ s!/_bootswatch\.scss!/_variables.scss!;
410 0           local $OVERRIDE = 'bootswatch';
411 0           $self->_generate_theme($app, {$name => $url});
412             }
413             else {
414 0           my $destination = $self->_destination_file($app, "$name/_variables.scss");
415 0 0 0       if ($destination and !-e $destination) {
416             $self->_copy_files(
417             $app,
418             ["bootstrap.scss" => "$name.scss"],
419             sub {
420 0     0     s!(\@import.*bootstrap/variables.*)!\@import "$name/variables";\n$1!m;
421 0 0         s!(//.*\bUtility\b.*)!$1\n\@import "$name/$OVERRIDE";\n!mi if $OVERRIDE;
422             }
423 0           );
424 0           $self->_move($app->asset->fetch($url), $destination);
425             }
426 0           $ENV{SASS_PATH} = $self->asset_path('sass');
427 0           warn "[BOOTSTRAP] Defining asset '$name.css' SASS_PATH=$ENV{SASS_PATH}\n" if DEBUG;
428 0           $app->asset("$name.css" => "/sass/$name.scss");
429             }
430             }
431             }
432              
433             sub _move {
434 0     0     my ($self, $from, $to) = @_;
435 0           File::Path::make_path(dirname $to);
436 0 0         File::Copy::move($from, $to) or die "[BOOTSTRAP] move $from $to: $!";
437             }
438              
439             =head1 CREDITS
440              
441             L has a number of major
442             contributors:
443              
444             Thomas McDonald
445             Tristan Harward
446             Peter Gumeson
447             Gleb Mazovetskiy
448              
449             and a L
450              
451             =head1 LICENSE
452              
453             Bootstrap is licensed under L
454              
455             Mojolicious is licensed under Artistic License version 2.0 and so is this code.
456              
457             =head1 AUTHOR
458              
459             Jan Henning Thorsen - C
460              
461             =cut
462              
463             1;