File Coverage

blib/lib/Mojolicious/Plugin/Bootstrap3.pm
Criterion Covered Total %
statement 51 102 50.0
branch 13 46 28.2
condition 6 19 31.5
subroutine 10 16 62.5
pod 2 2 100.0
total 82 185 44.3


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.3600
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             The config below on the other hand will only include jQuery and nothing else:
97              
98             plugin bootstrap3 => {jquery => 1, js => []};
99              
100             =head2 Themes
101              
102             It is very simple to use a custom
103             L<_variables.scss|https://github.com/twbs/bootstrap-sass/blob/master/assets/stylesheets/bootstrap/_variables.scss>
104             file with your project. This file contains the variables controlling colors,
105             fonts and styling rules in general.
106              
107             Example:
108              
109             # application code
110             plugin bootstrap3 => {theme => {xyz => "http://example.com/_variables.scss"}};
111              
112             # template code
113             %= asset "xyz.css"
114             %= asset "bootstrap.js"
115              
116             There is also built in support for themes from L. To
117             use one of the themes from bootswatch, simply specify the URL to the
118             C<_bootswatch.scss> file instead of C<_variables.scss>:
119              
120             # application code
121             plugin bootstrap3 => {theme => {paper => "https://bootswatch.com/paper/_bootswatch.scss"}};
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   435582 use Mojo::Base 'Mojolicious::Plugin';
  2         5  
  2         12  
234 2     2   1185 use Mojo::Util ();
  2         4  
  2         39  
235 2     2   10 use File::Basename 'dirname';
  2         4  
  2         96  
236 2     2   11 use File::Copy ();
  2         4  
  2         28  
237 2     2   11 use File::Path ();
  2         4  
  2         100  
238 2     2   9 use File::Spec ();
  2         5  
  2         28  
239 2     2   16 use Cwd ();
  2         5  
  2         61  
240 2   50 2   9 use constant DEBUG => $ENV{MOJO_ASSETPACK_DEBUG} || 0;
  2         4  
  2         3616  
241              
242             our $VERSION = '3.3600';
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 161 my ($self, $type) = @_;
269 2 50       8 my @path = ref $self ? @{$self->{sass_path}} : ();
  2         6  
270 2         3 my %PATH;
271              
272 2 50 66     26 return join ':', grep { -d $_ and !$PATH{$_}++ } split(/:/, $ENV{SASS_PATH}), @path,
  1 100       52  
273             File::Spec->catdir($ASSET_DIR, 'sass')
274             if $type and $type eq 'sass';
275 1         3 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 35 my ($self, $app, $config) = @_;
332 1         2 my (@css, @js);
333              
334 1 50       2 $app->plugin('AssetPack') unless eval { $app->asset };
  1         12  
335              
336 1         38118 $self->{sass_path} = [];
337 1 50       6 $config->{custom} = 0 if $config->{theme};
338              
339 1         3 push @{$app->asset->source_paths}, $self->asset_path;
  1         6  
340 1 50       14 push @css, $config->{css} ? @{$config->{css}} : @DEFAULT_CSS_FILES;
  0         0  
341 1 50       4 push @js, map {"/js/bootstrap/$_"} $config->{js} ? @{$config->{js}} : @DEFAULT_JS_FILES;
  12         28  
  0         0  
342 1 50 50     54 unshift @js, '/js/jquery-1.11.0.min.js' if $config->{jquery} or (@js and $config->{jquery} // 1);
      33        
      33        
343              
344 1 50       5 if ($config->{custom}) {
345             $self->_copy_files($app,
346 0 0       0 map { [$_, $_] } ref $config->{custom} eq 'ARRAY' ? @{$config->{custom}} : @DEFAULT_CSS_FILES);
  0         0  
  0         0  
347             }
348              
349 1 50       5 if ($config->{theme}) {
    50          
350 0         0 $self->_generate_theme($app, $config->{theme});
351             }
352             elsif (@css) {
353 1         3 $ENV{SASS_PATH} = $self->asset_path('sass');
354 1         2 warn "[BOOTSTRAP] Defining asset 'bootstrap.css' SASS_PATH=$ENV{SASS_PATH}\n" if DEBUG;
355 1         3 $app->asset('bootstrap.css' => map {"/sass/$_"} @css);
  1         25  
356             }
357              
358 1 50       23990 if (@js) {
359 1         11 $app->asset('bootstrap.js' => @js);
360             }
361             }
362              
363             sub _copy_files {
364 0 0   0     my $modifier = ref $_[-1] eq 'CODE' ? pop : sub { };
        0      
365 0           my ($self, $app, @files) = @_;
366              
367 0           for (@files) {
368 0           my ($from, $to) = @$_;
369 0           my $source = File::Spec->catfile($ASSET_DIR, 'sass', split '/', $from);
370 0 0         my $destination = $self->_destination_file($app, $to) or next;
371 0 0         File::Path::make_path(dirname $destination) unless -d dirname($destination);
372 0           $app->log->info("[BOOTSTRAP] Copying $source to $destination");
373 0           local $_ = Mojo::Util::slurp($source);
374 0           $modifier->();
375 0           Mojo::Util::spurt($_, $destination);
376             }
377             }
378              
379             sub _destination_file {
380 0     0     my ($self, $app, $name) = @_;
381              
382 0           for my $path (@{$app->asset->source_paths}) {
  0            
383 0           my $destination_dir = File::Spec->catdir($path, 'sass');
384 0           my $destination = File::Spec->catfile($destination_dir, split '/', $name);
385 0           push @{$self->{sass_path}}, $destination_dir;
  0            
386 0 0         return '' if -e $destination; # already exists
387 0           warn "[BOOTSTRAP] Can write $destination\n" if DEBUG;
388 0 0         return $destination if -w dirname $destination_dir;
389             }
390              
391             # should never come to this, because of
392 0           $app->log->warn("Custom file $name does not exist in static directories!");
393 0           return '';
394             }
395              
396             sub _generate_theme {
397 0     0     my ($self, $app, $theme) = @_;
398              
399 0           for my $name (keys %$theme) {
400 0           my $url = $theme->{$name};
401              
402 0           warn "[BOOTSTRAP] Defining theme '$name' from $url\n" if DEBUG;
403              
404 0 0         if ($url =~ m!/_bootswatch\.scss!) {
405 0           my $destination = $self->_destination_file($app, "$name/_bootswatch.scss");
406 0 0 0       $self->_move($app->asset->fetch($url), $destination) if $destination and !-e $destination;
407 0           $url =~ s!/_bootswatch\.scss!/_variables.scss!;
408 0           local $OVERRIDE = 'bootswatch';
409 0           $self->_generate_theme($app, {$name => $url});
410             }
411             else {
412 0           my $destination = $self->_destination_file($app, "$name/_variables.scss");
413 0 0 0       if ($destination and !-e $destination) {
414             $self->_copy_files(
415             $app,
416             ["bootstrap.scss" => "$name.scss"],
417             sub {
418 0     0     s!(\@import.*bootstrap/variables.*)!\@import "$name/variables";\n$1!m;
419 0 0         s!(//.*\bUtility\b.*)!$1\n\@import "$name/$OVERRIDE";\n!mi if $OVERRIDE;
420             }
421 0           );
422 0           $self->_move($app->asset->fetch($url), $destination);
423             }
424 0           $ENV{SASS_PATH} = $self->asset_path('sass');
425 0           warn "[BOOTSTRAP] Defining asset '$name.css' SASS_PATH=$ENV{SASS_PATH}\n" if DEBUG;
426 0           $app->asset("$name.css" => "/sass/$name.scss");
427             }
428             }
429             }
430              
431             sub _move {
432 0     0     my ($self, $from, $to) = @_;
433 0           File::Path::make_path(dirname $to);
434 0 0         File::Copy::move($from, $to) or die "[BOOTSTRAP] move $from $to: $!";
435             }
436              
437             =head1 CREDITS
438              
439             L has a number of major
440             contributors:
441              
442             Thomas McDonald
443             Tristan Harward
444             Peter Gumeson
445             Gleb Mazovetskiy
446              
447             and a L
448              
449             =head1 LICENSE
450              
451             Bootstrap is licensed under L
452              
453             Mojolicious is licensed under Artistic License version 2.0 and so is this code.
454              
455             =head1 AUTHOR
456              
457             Jan Henning Thorsen - C
458              
459             =cut
460              
461             1;