Initial Commit
This commit is contained in:
176
database/perl/vendor/lib/Mojolicious/Plugin/Config.pm
vendored
Normal file
176
database/perl/vendor/lib/Mojolicious/Plugin/Config.pm
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
package Mojolicious::Plugin::Config;
|
||||
use Mojo::Base 'Mojolicious::Plugin';
|
||||
|
||||
use Mojo::File qw(path);
|
||||
use Mojo::Util qw(decode);
|
||||
|
||||
sub load { $_[0]->parse(decode('UTF-8', path($_[1])->slurp), @_[1, 2, 3]) }
|
||||
|
||||
sub parse {
|
||||
my ($self, $content, $file, $conf, $app) = @_;
|
||||
|
||||
# Run Perl code in sandbox
|
||||
my $config = eval 'package Mojolicious::Plugin::Config::Sandbox; no warnings;'
|
||||
. "sub app; local *app = sub { \$app }; use Mojo::Base -strict; $content";
|
||||
die qq{Can't load configuration from file "$file": $@} if $@;
|
||||
die qq{Configuration file "$file" did not return a hash reference.\n} unless ref $config eq 'HASH';
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
sub register {
|
||||
my ($self, $app, $conf) = @_;
|
||||
|
||||
# DEPRECATED!
|
||||
$app->defaults(config => $app->config);
|
||||
|
||||
# Override
|
||||
return $app->config if $app->config->{config_override};
|
||||
|
||||
# Config file
|
||||
my $file = $conf->{file} || $ENV{MOJO_CONFIG};
|
||||
$file ||= $app->moniker . '.' . ($conf->{ext} || 'conf');
|
||||
|
||||
# Mode specific config file
|
||||
my $mode = $file =~ /^(.*)\.([^.]+)$/ ? join('.', $1, $app->mode, $2) : '';
|
||||
|
||||
my $home = $app->home;
|
||||
$file = $home->child($file) unless path($file)->is_abs;
|
||||
$mode = $home->child($mode) if $mode && !path($mode)->is_abs;
|
||||
$mode = undef unless $mode && -e $mode;
|
||||
|
||||
# Read config file
|
||||
my $config = {};
|
||||
if (-e $file) { $config = $self->load($file, $conf, $app) }
|
||||
|
||||
# Check for default and mode specific config file
|
||||
elsif (!$conf->{default} && !$mode) { die qq{Configuration file "$file" missing, maybe you need to create it?\n} }
|
||||
|
||||
# Merge everything
|
||||
$config = {%$config, %{$self->load($mode, $conf, $app)}} if $mode;
|
||||
$config = {%{$conf->{default}}, %$config} if $conf->{default};
|
||||
return $app->config($config)->config;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojolicious::Plugin::Config - Perl-ish configuration plugin
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# myapp.conf (it's just Perl returning a hash)
|
||||
{
|
||||
# Just a value
|
||||
foo => "bar",
|
||||
|
||||
# Nested data structures are fine too
|
||||
baz => ['♥'],
|
||||
|
||||
# You have full access to the application
|
||||
music_dir => app->home->child('music')
|
||||
};
|
||||
|
||||
# Mojolicious
|
||||
my $config = $app->plugin('Config');
|
||||
say $config->{foo};
|
||||
|
||||
# Mojolicious::Lite
|
||||
my $config = plugin 'Config';
|
||||
say $config->{foo};
|
||||
|
||||
# foo.html.ep
|
||||
%= config->{foo}
|
||||
|
||||
# The configuration is available application-wide
|
||||
my $config = app->config;
|
||||
say $config->{foo};
|
||||
|
||||
# Everything can be customized with options
|
||||
my $config = plugin Config => {file => '/etc/myapp.stuff'};
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojolicious::Plugin::Config> is a Perl-ish configuration plugin.
|
||||
|
||||
The application object can be accessed via C<$app> or the C<app> function, L<strict>, L<warnings>, L<utf8> and Perl
|
||||
5.16 L<features|feature> are automatically enabled. A default configuration filename in the application home directory
|
||||
will be generated from the value of L<Mojolicious/"moniker"> (C<$moniker.conf>). You can extend the normal
|
||||
configuration file C<$moniker.conf> with C<mode> specific ones like C<$moniker.$mode.conf>, which will be detected
|
||||
automatically.
|
||||
|
||||
If the configuration value C<config_override> has been set in L<Mojolicious/"config"> when this plugin is loaded, it
|
||||
will not do anything.
|
||||
|
||||
The code of this plugin is a good example for learning to build new plugins, you're welcome to fork it.
|
||||
|
||||
See L<Mojolicious::Plugins/"PLUGINS"> for a list of plugins that are available by default.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
L<Mojolicious::Plugin::Config> supports the following options.
|
||||
|
||||
=head2 default
|
||||
|
||||
# Mojolicious::Lite
|
||||
plugin Config => {default => {foo => 'bar'}};
|
||||
|
||||
Default configuration, making configuration files optional.
|
||||
|
||||
=head2 ext
|
||||
|
||||
# Mojolicious::Lite
|
||||
plugin Config => {ext => 'stuff'};
|
||||
|
||||
File extension for generated configuration filenames, defaults to C<conf>.
|
||||
|
||||
=head2 file
|
||||
|
||||
# Mojolicious::Lite
|
||||
plugin Config => {file => 'myapp.conf'};
|
||||
plugin Config => {file => '/etc/foo.stuff'};
|
||||
|
||||
Path to configuration file, absolute or relative to the application home directory, defaults to the value of the
|
||||
C<MOJO_CONFIG> environment variable or C<$moniker.conf> in the application home directory.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojolicious::Plugin::Config> inherits all methods from L<Mojolicious::Plugin> and implements the following new ones.
|
||||
|
||||
=head2 load
|
||||
|
||||
$plugin->load($file, $conf, $app);
|
||||
|
||||
Loads configuration file and passes the content to L</"parse">.
|
||||
|
||||
sub load ($self, $file, $conf, $app) {
|
||||
...
|
||||
return $self->parse($content, $file, $conf, $app);
|
||||
}
|
||||
|
||||
=head2 parse
|
||||
|
||||
$plugin->parse($content, $file, $conf, $app);
|
||||
|
||||
Parse configuration file.
|
||||
|
||||
sub parse ($self, $content, $file, $conf, $app) {
|
||||
...
|
||||
return $hash;
|
||||
}
|
||||
|
||||
=head2 register
|
||||
|
||||
my $config = $plugin->register(Mojolicious->new);
|
||||
my $config = $plugin->register(Mojolicious->new, {file => '/etc/app.conf'});
|
||||
|
||||
Register plugin in L<Mojolicious> application and merge configuration.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
805
database/perl/vendor/lib/Mojolicious/Plugin/DefaultHelpers.pm
vendored
Normal file
805
database/perl/vendor/lib/Mojolicious/Plugin/DefaultHelpers.pm
vendored
Normal file
@@ -0,0 +1,805 @@
|
||||
package Mojolicious::Plugin::DefaultHelpers;
|
||||
use Mojo::Base 'Mojolicious::Plugin';
|
||||
|
||||
use Mojo::Asset::File;
|
||||
use Mojo::ByteStream;
|
||||
use Mojo::Collection;
|
||||
use Mojo::Exception;
|
||||
use Mojo::IOLoop;
|
||||
use Mojo::Promise;
|
||||
use Mojo::Util qw(dumper hmac_sha1_sum steady_time);
|
||||
use Time::HiRes qw(gettimeofday tv_interval);
|
||||
use Scalar::Util qw(blessed weaken);
|
||||
|
||||
sub register {
|
||||
my ($self, $app) = @_;
|
||||
|
||||
# Controller alias helpers
|
||||
for my $name (qw(app param stash session url_for)) {
|
||||
$app->helper($name => sub { shift->$name(@_) });
|
||||
}
|
||||
|
||||
# Stash key shortcuts (should not generate log messages)
|
||||
for my $name (qw(extends layout title)) {
|
||||
$app->helper($name => sub { shift->stash($name, @_) });
|
||||
}
|
||||
|
||||
$app->helper(accepts => sub { $_[0]->app->renderer->accepts(@_) });
|
||||
$app->helper(b => sub { shift; Mojo::ByteStream->new(@_) });
|
||||
$app->helper(c => sub { shift; Mojo::Collection->new(@_) });
|
||||
$app->helper(config => sub { shift->app->config(@_) });
|
||||
|
||||
$app->helper(content => sub { _content(0, 0, @_) });
|
||||
$app->helper(content_for => sub { _content(1, 0, @_) });
|
||||
$app->helper(content_with => sub { _content(0, 1, @_) });
|
||||
|
||||
$app->helper($_ => $self->can("_$_"))
|
||||
for qw(csrf_token current_route flash inactivity_timeout is_fresh), qw(redirect_to respond_to url_with validation);
|
||||
|
||||
$app->helper(dumper => sub { shift; dumper @_ });
|
||||
$app->helper(include => sub { shift->render_to_string(@_) });
|
||||
|
||||
$app->helper(log => \&_log);
|
||||
|
||||
$app->helper('proxy.get_p' => sub { _proxy_method_p('GET', @_) });
|
||||
$app->helper('proxy.post_p' => sub { _proxy_method_p('POST', @_) });
|
||||
$app->helper('proxy.start_p' => \&_proxy_start_p);
|
||||
|
||||
$app->helper("reply.$_" => $self->can("_$_")) for qw(asset file static);
|
||||
|
||||
$app->helper('reply.exception' => sub { _development('exception', @_) });
|
||||
$app->helper('reply.not_found' => sub { _development('not_found', @_) });
|
||||
|
||||
$app->helper('timing.begin' => \&_timing_begin);
|
||||
$app->helper('timing.elapsed' => \&_timing_elapsed);
|
||||
$app->helper('timing.rps' => \&_timing_rps);
|
||||
$app->helper('timing.server_timing' => \&_timing_server_timing);
|
||||
|
||||
$app->helper(ua => sub { shift->app->ua });
|
||||
}
|
||||
|
||||
sub _asset {
|
||||
my $c = shift;
|
||||
$c->app->static->serve_asset($c, @_);
|
||||
$c->rendered;
|
||||
}
|
||||
|
||||
sub _block { ref $_[0] eq 'CODE' ? $_[0]() : $_[0] }
|
||||
|
||||
sub _content {
|
||||
my ($append, $replace, $c, $name, $content) = @_;
|
||||
$name ||= 'content';
|
||||
|
||||
my $hash = $c->stash->{'mojo.content'} //= {};
|
||||
if (defined $content) {
|
||||
if ($append) { $hash->{$name} .= _block($content) }
|
||||
if ($replace) { $hash->{$name} = _block($content) }
|
||||
else { $hash->{$name} //= _block($content) }
|
||||
}
|
||||
|
||||
return Mojo::ByteStream->new($hash->{$name} // '');
|
||||
}
|
||||
|
||||
sub _csrf_token { $_[0]->session->{csrf_token} ||= hmac_sha1_sum($$ . steady_time . rand, $_[0]->app->secrets->[0]) }
|
||||
|
||||
sub _current_route {
|
||||
return '' unless my $route = shift->match->endpoint;
|
||||
return @_ ? $route->name eq shift : $route->name;
|
||||
}
|
||||
|
||||
sub _development {
|
||||
my ($page, $c, $e) = @_;
|
||||
|
||||
$c->helpers->log->error(($e = _is_e($e) ? $e : Mojo::Exception->new($e))->inspect) if $page eq 'exception';
|
||||
|
||||
# Filtered stash snapshot
|
||||
my $stash = $c->stash;
|
||||
%{$stash->{snapshot} = {}} = map { $_ => $stash->{$_} } grep { !/^mojo\./ and defined $stash->{$_} } keys %$stash;
|
||||
$stash->{exception} = $page eq 'exception' ? $e : undef;
|
||||
|
||||
# Render with fallbacks
|
||||
my $app = $c->app;
|
||||
my $mode = $app->mode;
|
||||
my $options = {
|
||||
format => $stash->{format} || $app->renderer->default_format,
|
||||
handler => undef,
|
||||
status => $page eq 'exception' ? 500 : 404,
|
||||
template => "$page.$mode"
|
||||
};
|
||||
my $bundled = 'mojo/' . ($mode eq 'development' ? 'debug' : $page);
|
||||
return $c if _fallbacks($c, $options, $page, $bundled);
|
||||
_fallbacks($c, {%$options, format => 'html'}, $page, $bundled);
|
||||
return $c;
|
||||
}
|
||||
|
||||
|
||||
sub _fallbacks {
|
||||
my ($c, $options, $template, $bundled) = @_;
|
||||
|
||||
# Mode specific template
|
||||
return 1 if $c->render_maybe(%$options);
|
||||
|
||||
# Normal template
|
||||
return 1 if $c->render_maybe(%$options, template => $template);
|
||||
|
||||
# Inline template
|
||||
my $stash = $c->stash;
|
||||
return undef unless $options->{format} eq 'html';
|
||||
delete @$stash{qw(extends layout)};
|
||||
return $c->render_maybe($bundled, %$options, handler => 'ep');
|
||||
}
|
||||
|
||||
sub _file { _asset(shift, Mojo::Asset::File->new(path => shift)) }
|
||||
|
||||
sub _flash {
|
||||
my $c = shift;
|
||||
|
||||
# Check old flash
|
||||
my $session = $c->session;
|
||||
return $session->{flash} ? $session->{flash}{$_[0]} : undef if @_ == 1 && !ref $_[0];
|
||||
|
||||
# Initialize new flash and merge values
|
||||
my $values = ref $_[0] ? $_[0] : {@_};
|
||||
@{$session->{new_flash} //= {}}{keys %$values} = values %$values;
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
sub _inactivity_timeout {
|
||||
my ($c, $timeout) = @_;
|
||||
my $stream = Mojo::IOLoop->stream($c->tx->connection // '');
|
||||
$stream->timeout($timeout) if $stream;
|
||||
return $c;
|
||||
}
|
||||
|
||||
sub _is_e { blessed $_[0] && $_[0]->isa('Mojo::Exception') }
|
||||
|
||||
sub _is_fresh {
|
||||
my ($c, %options) = @_;
|
||||
return $c->app->static->is_fresh($c, \%options);
|
||||
}
|
||||
|
||||
sub _log { $_[0]->stash->{'mojo.log'} ||= $_[0]->app->log->context('[' . $_[0]->req->request_id . ']') }
|
||||
|
||||
sub _proxy_method_p {
|
||||
my ($method, $c) = (shift, shift);
|
||||
return _proxy_start_p($c, $c->ua->build_tx($method, @_));
|
||||
}
|
||||
|
||||
sub _proxy_start_p {
|
||||
my ($c, $source_tx) = @_;
|
||||
my $tx = $c->render_later->tx;
|
||||
|
||||
my $promise = Mojo::Promise->new;
|
||||
$source_tx->res->content->auto_upgrade(0)->auto_decompress(0)->once(
|
||||
body => sub {
|
||||
my $source_content = shift;
|
||||
|
||||
my $source_res = $source_tx->res;
|
||||
my $res = $tx->res;
|
||||
my $content = $res->content;
|
||||
$res->code($source_res->code)->message($source_res->message);
|
||||
my $headers = $source_res->headers->clone->dehop;
|
||||
$content->headers($headers);
|
||||
$promise->resolve;
|
||||
|
||||
my $source_stream = Mojo::IOLoop->stream($source_tx->connection);
|
||||
return unless my $stream = Mojo::IOLoop->stream($tx->connection);
|
||||
|
||||
my $write = $source_content->is_chunked ? 'write_chunk' : 'write';
|
||||
$source_content->unsubscribe('read')->on(
|
||||
read => sub {
|
||||
my $data = pop;
|
||||
$content->$write(length $data ? $data : ()) and $tx->resume;
|
||||
|
||||
# Throttle transparently when backpressure rises
|
||||
return if $stream->can_write;
|
||||
$source_stream->stop;
|
||||
$stream->once(drain => sub { $source_stream->start });
|
||||
}
|
||||
);
|
||||
|
||||
# Unknown length (fall back to connection close)
|
||||
$source_res->once(finish => sub { $content->$write('') and $tx->resume })
|
||||
unless length($headers->content_length // '');
|
||||
}
|
||||
);
|
||||
weaken $source_tx;
|
||||
$source_tx->once(finish => sub { $promise->reject(_tx_error(@_)) });
|
||||
|
||||
$c->ua->start_p($source_tx)->catch(sub { });
|
||||
|
||||
return $promise;
|
||||
}
|
||||
|
||||
sub _redirect_to {
|
||||
my $c = shift;
|
||||
|
||||
# Don't override 3xx status
|
||||
my $res = $c->res;
|
||||
$res->headers->location($c->url_for(@_));
|
||||
return $c->rendered($res->is_redirect ? () : 302);
|
||||
}
|
||||
|
||||
sub _respond_to {
|
||||
my ($c, $args) = (shift, ref $_[0] ? $_[0] : {@_});
|
||||
|
||||
# Find target
|
||||
my $target;
|
||||
my $renderer = $c->app->renderer;
|
||||
my @formats = @{$renderer->accepts($c)};
|
||||
for my $format (@formats ? @formats : ($renderer->default_format)) {
|
||||
next unless $target = $args->{$format};
|
||||
$c->stash->{format} = $format;
|
||||
last;
|
||||
}
|
||||
|
||||
# Fallback
|
||||
unless ($target) {
|
||||
return $c->rendered(204) unless $target = $args->{any};
|
||||
delete $c->stash->{format};
|
||||
}
|
||||
|
||||
# Dispatch
|
||||
ref $target eq 'CODE' ? $target->($c) : $c->render(%$target);
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
sub _static {
|
||||
my ($c, $file) = @_;
|
||||
return !!$c->rendered if $c->app->static->serve($c, $file);
|
||||
$c->helpers->log->debug(qq{Static file "$file" not found});
|
||||
return !$c->helpers->reply->not_found;
|
||||
}
|
||||
|
||||
sub _timing_begin { shift->stash->{'mojo.timing'}{shift()} = [gettimeofday] }
|
||||
|
||||
sub _timing_elapsed {
|
||||
my ($c, $name) = @_;
|
||||
return undef unless my $started = $c->stash->{'mojo.timing'}{$name};
|
||||
return tv_interval($started, [gettimeofday()]);
|
||||
}
|
||||
|
||||
sub _timing_rps { $_[1] == 0 ? undef : sprintf '%.3f', 1 / $_[1] }
|
||||
|
||||
sub _timing_server_timing {
|
||||
my ($c, $metric, $desc, $dur) = @_;
|
||||
my $value = $metric;
|
||||
$value .= qq{;desc="$desc"} if defined $desc;
|
||||
$value .= ";dur=$dur" if defined $dur;
|
||||
$c->res->headers->append('Server-Timing' => $value);
|
||||
}
|
||||
|
||||
sub _tx_error { (shift->error // {})->{message} // 'Unknown error' }
|
||||
|
||||
sub _url_with {
|
||||
my $c = shift;
|
||||
return $c->url_for(@_)->query($c->req->url->query->clone);
|
||||
}
|
||||
|
||||
sub _validation {
|
||||
my $c = shift;
|
||||
|
||||
my $stash = $c->stash;
|
||||
return $stash->{'mojo.validation'} if $stash->{'mojo.validation'};
|
||||
|
||||
my $req = $c->req;
|
||||
my $token = $c->session->{csrf_token};
|
||||
my $header = $req->headers->header('X-CSRF-Token');
|
||||
my $hash = $req->params->to_hash;
|
||||
$hash->{csrf_token} //= $header if $token && $header;
|
||||
$hash->{$_} = $req->every_upload($_) for map { $_->name } @{$req->uploads};
|
||||
my $v = $c->app->validator->validation->input($hash);
|
||||
return $stash->{'mojo.validation'} = $v->csrf_token($token);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojolicious::Plugin::DefaultHelpers - Default helpers plugin
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# Mojolicious
|
||||
$app->plugin('DefaultHelpers');
|
||||
|
||||
# Mojolicious::Lite
|
||||
plugin 'DefaultHelpers';
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojolicious::Plugin::DefaultHelpers> is a collection of helpers for L<Mojolicious>.
|
||||
|
||||
This is a core plugin, that means it is always enabled and its code a good example for learning to build new plugins,
|
||||
you're welcome to fork it.
|
||||
|
||||
See L<Mojolicious::Plugins/"PLUGINS"> for a list of plugins that are available by default.
|
||||
|
||||
=head1 HELPERS
|
||||
|
||||
L<Mojolicious::Plugin::DefaultHelpers> implements the following helpers.
|
||||
|
||||
=head2 accepts
|
||||
|
||||
my $formats = $c->accepts;
|
||||
my $format = $c->accepts('html', 'json', 'txt');
|
||||
|
||||
Select best possible representation for resource from C<format> C<GET>/C<POST> parameter, C<format> stash value or
|
||||
C<Accept> request header with L<Mojolicious::Renderer/"accepts">, defaults to returning the first extension if no
|
||||
preference could be detected.
|
||||
|
||||
# Check if JSON is acceptable
|
||||
$c->render(json => {hello => 'world'}) if $c->accepts('json');
|
||||
|
||||
# Check if JSON was specifically requested
|
||||
$c->render(json => {hello => 'world'}) if $c->accepts('', 'json');
|
||||
|
||||
# Unsupported representation
|
||||
$c->render(data => '', status => 204)
|
||||
unless my $format = $c->accepts('html', 'json');
|
||||
|
||||
# Detected representations to select from
|
||||
my @formats = @{$c->accepts};
|
||||
|
||||
=head2 app
|
||||
|
||||
%= app->secrets->[0]
|
||||
|
||||
Alias for L<Mojolicious::Controller/"app">.
|
||||
|
||||
=head2 b
|
||||
|
||||
%= b('Joel is a slug')->slugify
|
||||
|
||||
Turn string into a L<Mojo::ByteStream> object.
|
||||
|
||||
=head2 c
|
||||
|
||||
%= c('a', 'b', 'c')->shuffle->join
|
||||
|
||||
Turn list into a L<Mojo::Collection> object.
|
||||
|
||||
=head2 config
|
||||
|
||||
%= config 'something'
|
||||
|
||||
Alias for L<Mojolicious/"config">.
|
||||
|
||||
=head2 content
|
||||
|
||||
%= content foo => begin
|
||||
test
|
||||
% end
|
||||
%= content bar => 'Hello World!'
|
||||
%= content 'foo'
|
||||
%= content 'bar'
|
||||
%= content
|
||||
|
||||
Store partial rendered content in a named buffer and retrieve it later, defaults to retrieving the named buffer
|
||||
C<content>, which is used by the renderer for the C<layout> and C<extends> features. New content will be ignored if the
|
||||
named buffer is already in use.
|
||||
|
||||
=head2 content_for
|
||||
|
||||
% content_for foo => begin
|
||||
test
|
||||
% end
|
||||
%= content_for 'foo'
|
||||
|
||||
Same as L</"content">, but appends content to named buffers if they are already in use.
|
||||
|
||||
% content_for message => begin
|
||||
Hello
|
||||
% end
|
||||
% content_for message => begin
|
||||
world!
|
||||
% end
|
||||
%= content 'message'
|
||||
|
||||
=head2 content_with
|
||||
|
||||
% content_with foo => begin
|
||||
test
|
||||
% end
|
||||
%= content_with 'foo'
|
||||
|
||||
Same as L</"content">, but replaces content of named buffers if they are already in use.
|
||||
|
||||
% content message => begin
|
||||
world!
|
||||
% end
|
||||
% content_with message => begin
|
||||
Hello <%= content 'message' %>
|
||||
% end
|
||||
%= content 'message'
|
||||
|
||||
=head2 csrf_token
|
||||
|
||||
%= csrf_token
|
||||
|
||||
Get CSRF token from L</"session">, and generate one if none exists.
|
||||
|
||||
=head2 current_route
|
||||
|
||||
% if (current_route 'login') {
|
||||
Welcome to Mojolicious!
|
||||
% }
|
||||
%= current_route
|
||||
|
||||
Check or get name of current route.
|
||||
|
||||
=head2 dumper
|
||||
|
||||
%= dumper {some => 'data'}
|
||||
|
||||
Dump a Perl data structure with L<Mojo::Util/"dumper">, very useful for debugging.
|
||||
|
||||
=head2 extends
|
||||
|
||||
% extends 'blue';
|
||||
% extends 'blue', title => 'Blue!';
|
||||
|
||||
Set C<extends> stash value, all additional key/value pairs get merged into the L</"stash">.
|
||||
|
||||
=head2 flash
|
||||
|
||||
my $foo = $c->flash('foo');
|
||||
$c = $c->flash({foo => 'bar'});
|
||||
$c = $c->flash(foo => 'bar');
|
||||
%= flash 'foo'
|
||||
|
||||
Data storage persistent only for the next request, stored in the L</"session">.
|
||||
|
||||
# Show message after redirect
|
||||
$c->flash(message => 'User created successfully!');
|
||||
$c->redirect_to('show_user', id => 23);
|
||||
|
||||
=head2 inactivity_timeout
|
||||
|
||||
$c = $c->inactivity_timeout(3600);
|
||||
|
||||
Use L<Mojo::IOLoop/"stream"> to find the current connection and increase timeout if possible.
|
||||
|
||||
# Longer version
|
||||
Mojo::IOLoop->stream($c->tx->connection)->timeout(3600);
|
||||
|
||||
=head2 include
|
||||
|
||||
%= include 'menubar'
|
||||
%= include 'menubar', format => 'txt'
|
||||
|
||||
Alias for L<Mojolicious::Controller/"render_to_string">.
|
||||
|
||||
=head2 is_fresh
|
||||
|
||||
my $bool = $c->is_fresh;
|
||||
my $bool = $c->is_fresh(etag => 'abc');
|
||||
my $bool = $c->is_fresh(etag => 'W/"def"');
|
||||
my $bool = $c->is_fresh(last_modified => $epoch);
|
||||
|
||||
Check freshness of request by comparing the C<If-None-Match> and C<If-Modified-Since> request headers to the C<ETag>
|
||||
and C<Last-Modified> response headers with L<Mojolicious::Static/"is_fresh">.
|
||||
|
||||
# Add ETag/Last-Modified headers and check freshness before rendering
|
||||
$c->is_fresh(etag => 'abc', last_modified => 1424985708)
|
||||
? $c->rendered(304)
|
||||
: $c->render(text => 'I ♥ Mojolicious!');
|
||||
|
||||
=head2 layout
|
||||
|
||||
% layout 'green';
|
||||
% layout 'green', title => 'Green!';
|
||||
|
||||
Set C<layout> stash value, all additional key/value pairs get merged into the L</"stash">.
|
||||
|
||||
=head2 log
|
||||
|
||||
my $log = $c->log;
|
||||
|
||||
Alternative to L<Mojolicious/"log"> that includes L<Mojo::Message::Request/"request_id"> with every log message.
|
||||
|
||||
# Log message with context
|
||||
$c->log->debug('This is a log message with request id');
|
||||
|
||||
# Pass logger with context to model
|
||||
my $log = $c->log;
|
||||
$c->some_model->create({foo => $foo}, $log);
|
||||
|
||||
=head2 param
|
||||
|
||||
%= param 'foo'
|
||||
|
||||
Alias for L<Mojolicious::Controller/"param">.
|
||||
|
||||
=head2 proxy->get_p
|
||||
|
||||
my $promise = $c->proxy->get_p('http://example.com' => {Accept => '*/*'});
|
||||
|
||||
Perform non-blocking C<GET> request and forward response as efficiently as possible, takes the same arguments as
|
||||
L<Mojo::UserAgent/"get"> and returns a L<Mojo::Promise> object.
|
||||
|
||||
# Forward with exception handling
|
||||
$c->proxy->get_p('http://mojolicious.org')->catch(sub ($err) {
|
||||
$c->log->debug("Proxy error: $err");
|
||||
$c->render(text => 'Something went wrong!', status => 400);
|
||||
});
|
||||
|
||||
=head2 proxy->post_p
|
||||
|
||||
my $promise = $c->proxy->post_p('http://example.com' => {Accept => '*/*'});
|
||||
|
||||
Perform non-blocking C<POST> request and forward response as efficiently as possible, takes the same arguments as
|
||||
L<Mojo::UserAgent/"post"> and returns a L<Mojo::Promise> object.
|
||||
|
||||
# Forward with exception handling
|
||||
$c->proxy->post_p('example.com' => form => {test => 'pass'})->catch(sub ($err) {
|
||||
$c->log->debug("Proxy error: $err");
|
||||
$c->render(text => 'Something went wrong!', status => 400);
|
||||
});
|
||||
|
||||
=head2 proxy->start_p
|
||||
|
||||
my $promise = $c->proxy->start_p(Mojo::Transaction::HTTP->new);
|
||||
|
||||
Perform non-blocking request for a custom L<Mojo::Transaction::HTTP> object and forward response as efficiently as
|
||||
possible, returns a L<Mojo::Promise> object.
|
||||
|
||||
# Forward with exception handling
|
||||
my $tx = $c->ua->build_tx(GET => 'http://mojolicious.org');
|
||||
$c->proxy->start_p($tx)->catch(sub ($err) {
|
||||
$c->log->debug("Proxy error: $err");
|
||||
$c->render(text => 'Something went wrong!', status => 400);
|
||||
});
|
||||
|
||||
# Forward with custom request and response headers
|
||||
my $headers = $c->req->headers->clone->dehop;
|
||||
$headers->header('X-Proxy' => 'Mojo');
|
||||
my $tx = $c->ua->build_tx(GET => 'http://example.com' => $headers->to_hash);
|
||||
$c->proxy->start_p($tx);
|
||||
$tx->res->content->once(body => sub ($content) { $c->res->headers->header('X-Proxy' => 'Mojo') });
|
||||
|
||||
=head2 redirect_to
|
||||
|
||||
$c = $c->redirect_to('named', foo => 'bar');
|
||||
$c = $c->redirect_to('named', {foo => 'bar'});
|
||||
$c = $c->redirect_to('/index.html');
|
||||
$c = $c->redirect_to('http://example.com/index.html');
|
||||
|
||||
Prepare a C<302> (if the status code is not already C<3xx>) redirect response with C<Location> header, takes the same
|
||||
arguments as L</"url_for">.
|
||||
|
||||
# Moved Permanently
|
||||
$c->res->code(301);
|
||||
$c->redirect_to('some_route');
|
||||
|
||||
# Temporary Redirect
|
||||
$c->res->code(307);
|
||||
$c->redirect_to('some_route');
|
||||
|
||||
=head2 reply->asset
|
||||
|
||||
$c->reply->asset(Mojo::Asset::File->new);
|
||||
|
||||
Reply with a L<Mojo::Asset::File> or L<Mojo::Asset::Memory> object using L<Mojolicious::Static/"serve_asset">, and
|
||||
perform content negotiation with C<Range>, C<If-Modified-Since> and C<If-None-Match> headers.
|
||||
|
||||
# Serve asset with custom modification time
|
||||
my $asset = Mojo::Asset::Memory->new;
|
||||
$asset->add_chunk('Hello World!')->mtime(784111777);
|
||||
$c->res->headers->content_type('text/plain');
|
||||
$c->reply->asset($asset);
|
||||
|
||||
# Serve static file if it exists
|
||||
if (my $asset = $c->app->static->file('images/logo.png')) {
|
||||
$c->res->headers->content_type('image/png');
|
||||
$c->reply->asset($asset);
|
||||
}
|
||||
|
||||
=head2 reply->exception
|
||||
|
||||
$c = $c->reply->exception('Oops!');
|
||||
$c = $c->reply->exception(Mojo::Exception->new);
|
||||
|
||||
Render the exception template C<exception.$mode.$format.*> or C<exception.$format.*> and set the response status code
|
||||
to C<500>. Also sets the stash values C<exception> to a L<Mojo::Exception> object and C<snapshot> to a copy of the
|
||||
L</"stash"> for use in the templates.
|
||||
|
||||
=head2 reply->file
|
||||
|
||||
$c->reply->file('/etc/passwd');
|
||||
|
||||
Reply with a static file from an absolute path anywhere on the file system using L<Mojolicious/"static">.
|
||||
|
||||
# Longer version
|
||||
$c->reply->asset(Mojo::Asset::File->new(path => '/etc/passwd'));
|
||||
|
||||
# Serve file from an absolute path with a custom content type
|
||||
$c->res->headers->content_type('application/myapp');
|
||||
$c->reply->file('/home/sri/foo.txt');
|
||||
|
||||
# Serve file from a secret application directory
|
||||
$c->reply->file($c->app->home->child('secret', 'file.txt'));
|
||||
|
||||
=head2 reply->not_found
|
||||
|
||||
$c = $c->reply->not_found;
|
||||
|
||||
Render the not found template C<not_found.$mode.$format.*> or C<not_found.$format.*> and set the response status code
|
||||
to C<404>. Also sets the stash value C<snapshot> to a copy of the L</"stash"> for use in the templates.
|
||||
|
||||
=head2 reply->static
|
||||
|
||||
my $bool = $c->reply->static('images/logo.png');
|
||||
my $bool = $c->reply->static('../lib/MyApp.pm');
|
||||
|
||||
Reply with a static file using L<Mojolicious/"static">, usually from the C<public> directories or C<DATA> sections of
|
||||
your application. Note that this helper uses a relative path, but does not protect from traversing to parent
|
||||
directories.
|
||||
|
||||
# Serve file from a relative path with a custom content type
|
||||
$c->res->headers->content_type('application/myapp');
|
||||
$c->reply->static('foo.txt');
|
||||
|
||||
=head2 respond_to
|
||||
|
||||
$c = $c->respond_to(
|
||||
json => {json => {message => 'Welcome!'}},
|
||||
html => {template => 'welcome'},
|
||||
any => sub {...}
|
||||
);
|
||||
|
||||
Automatically select best possible representation for resource from C<format> C<GET>/C<POST> parameter, C<format> stash
|
||||
value or C<Accept> request header, defaults to L<Mojolicious::Renderer/"default_format"> or rendering an empty C<204>
|
||||
response. Each representation can be handled with a callback or a hash reference containing arguments to be passed to
|
||||
L<Mojolicious::Controller/"render">.
|
||||
|
||||
# Everything else than "json" and "xml" gets a 204 response
|
||||
$c->respond_to(
|
||||
json => sub { $c->render(json => {just => 'works'}) },
|
||||
xml => {text => '<just>works</just>'},
|
||||
any => {data => '', status => 204}
|
||||
);
|
||||
|
||||
For more advanced negotiation logic you can also use L</"accepts">.
|
||||
|
||||
=head2 session
|
||||
|
||||
%= session 'foo'
|
||||
|
||||
Alias for L<Mojolicious::Controller/"session">.
|
||||
|
||||
=head2 stash
|
||||
|
||||
%= stash 'foo'
|
||||
% stash foo => 'bar';
|
||||
|
||||
Alias for L<Mojolicious::Controller/"stash">.
|
||||
|
||||
%= stash('name') // 'Somebody'
|
||||
|
||||
=head2 timing->begin
|
||||
|
||||
$c->timing->begin('foo');
|
||||
|
||||
Create named timestamp for L<"timing-E<gt>elapsed">.
|
||||
|
||||
=head2 timing->elapsed
|
||||
|
||||
my $elapsed = $c->timing->elapsed('foo');
|
||||
|
||||
Return fractional amount of time in seconds since named timstamp has been created with L</"timing-E<gt>begin"> or
|
||||
C<undef> if no such timestamp exists.
|
||||
|
||||
# Log timing information
|
||||
$c->timing->begin('database_stuff');
|
||||
...
|
||||
my $elapsed = $c->timing->elapsed('database_stuff');
|
||||
$c->app->log->debug("Database stuff took $elapsed seconds");
|
||||
|
||||
=head2 timing->rps
|
||||
|
||||
my $rps = $c->timing->rps('0.001');
|
||||
|
||||
Return fractional number of requests that could be performed in one second if every singe one took the given amount of
|
||||
time in seconds or C<undef> if the number is too low.
|
||||
|
||||
# Log more timing information
|
||||
$c->timing->begin('web_stuff');
|
||||
...
|
||||
my $elapsed = $c->timing->elapsed('web_stuff');
|
||||
my $rps = $c->timing->rps($elapsed);
|
||||
$c->app->log->debug("Web stuff took $elapsed seconds ($rps per second)");
|
||||
|
||||
=head2 timing->server_timing
|
||||
|
||||
$c->timing->server_timing('metric');
|
||||
$c->timing->server_timing('metric', 'Some Description');
|
||||
$c->timing->server_timing('metric', 'Some Description', '0.001');
|
||||
|
||||
Create C<Server-Timing> header with optional description and duration.
|
||||
|
||||
# "Server-Timing: miss"
|
||||
$c->timing->server_timing('miss');
|
||||
|
||||
# "Server-Timing: dc;desc=atl"
|
||||
$c->timing->server_timing('dc', 'atl');
|
||||
|
||||
# "Server-Timing: db;desc=Database;dur=0.0001"
|
||||
$c->timing->begin('database_stuff');
|
||||
...
|
||||
my $elapsed = $c->timing->elapsed('database_stuff');
|
||||
$c->timing->server_timing('db', 'Database', $elapsed);
|
||||
|
||||
# "Server-Timing: miss, dc;desc=atl"
|
||||
$c->timing->server_timing('miss');
|
||||
$c->timing->server_timing('dc', 'atl');
|
||||
|
||||
=head2 title
|
||||
|
||||
%= title
|
||||
% title 'Welcome!';
|
||||
% title 'Welcome!', foo => 'bar';
|
||||
|
||||
Get or set C<title> stash value, all additional key/value pairs get merged into the L</"stash">.
|
||||
|
||||
=head2 ua
|
||||
|
||||
%= ua->get('mojolicious.org')->result->dom->at('title')->text
|
||||
|
||||
Alias for L<Mojolicious/"ua">.
|
||||
|
||||
=head2 url_for
|
||||
|
||||
%= url_for 'named', controller => 'bar', action => 'baz'
|
||||
|
||||
Alias for L<Mojolicious::Controller/"url_for">.
|
||||
|
||||
%= url_for('/index.html')->query(foo => 'bar')
|
||||
|
||||
=head2 url_with
|
||||
|
||||
%= url_with 'named', controller => 'bar', action => 'baz'
|
||||
|
||||
Does the same as L</"url_for">, but inherits query parameters from the current request.
|
||||
|
||||
%= url_with->query({page => 2})
|
||||
|
||||
=head2 validation
|
||||
|
||||
my $v = $c->validation;
|
||||
|
||||
Get L<Mojolicious::Validator::Validation> object for current request to validate file uploads as well as C<GET> and
|
||||
C<POST> parameters extracted from the query string and C<application/x-www-form-urlencoded> or C<multipart/form-data>
|
||||
message body. Parts of the request body need to be loaded into memory to parse C<POST> parameters, so you have to make
|
||||
sure it is not excessively large. There's a 16MiB limit for requests by default.
|
||||
|
||||
# Validate GET/POST parameter
|
||||
my $v = $c->validation;
|
||||
$v->required('title', 'trim')->size(3, 50);
|
||||
my $title = $v->param('title');
|
||||
|
||||
# Validate file upload
|
||||
my $v = $c->validation;
|
||||
$v->required('tarball')->upload->size(1, 1048576);
|
||||
my $tarball = $v->param('tarball');
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojolicious::Plugin::DefaultHelpers> inherits all methods from L<Mojolicious::Plugin> and implements the following
|
||||
new ones.
|
||||
|
||||
=head2 register
|
||||
|
||||
$plugin->register(Mojolicious->new);
|
||||
|
||||
Register helpers in L<Mojolicious> application.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
99
database/perl/vendor/lib/Mojolicious/Plugin/EPLRenderer.pm
vendored
Normal file
99
database/perl/vendor/lib/Mojolicious/Plugin/EPLRenderer.pm
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
package Mojolicious::Plugin::EPLRenderer;
|
||||
use Mojo::Base 'Mojolicious::Plugin';
|
||||
|
||||
use Mojo::Template;
|
||||
use Mojo::Util qw(encode md5_sum);
|
||||
|
||||
sub register {
|
||||
my ($self, $app) = @_;
|
||||
$app->renderer->add_handler(epl => sub { _render(@_, Mojo::Template->new, $_[1]) });
|
||||
}
|
||||
|
||||
sub _render {
|
||||
my ($renderer, $c, $output, $options, $mt, @args) = @_;
|
||||
|
||||
# Cached
|
||||
if ($mt->compiled) {
|
||||
$c->helpers->log->debug("Rendering cached @{[$mt->name]}");
|
||||
$$output = $mt->process(@args);
|
||||
}
|
||||
|
||||
# Not cached
|
||||
else {
|
||||
my $inline = $options->{inline};
|
||||
my $name = defined $inline ? md5_sum encode('UTF-8', $inline) : undef;
|
||||
return unless defined($name //= $renderer->template_name($options));
|
||||
|
||||
# Inline
|
||||
if (defined $inline) {
|
||||
$c->helpers->log->debug(qq{Rendering inline template "$name"});
|
||||
$$output = $mt->name(qq{inline template "$name"})->render($inline, @args);
|
||||
}
|
||||
|
||||
# File
|
||||
else {
|
||||
if (my $encoding = $renderer->encoding) { $mt->encoding($encoding) }
|
||||
|
||||
# Try template
|
||||
if (defined(my $path = $renderer->template_path($options))) {
|
||||
$c->helpers->log->debug(qq{Rendering template "$name"});
|
||||
$$output = $mt->name(qq{template "$name"})->render_file($path, @args);
|
||||
}
|
||||
|
||||
# Try DATA section
|
||||
elsif (defined(my $d = $renderer->get_data_template($options))) {
|
||||
$c->helpers->log->debug(qq{Rendering template "$name" from DATA section});
|
||||
$$output = $mt->name(qq{template "$name" from DATA section})->render($d, @args);
|
||||
}
|
||||
|
||||
# No template
|
||||
else { $c->helpers->log->debug(qq{Template "$name" not found}) }
|
||||
}
|
||||
}
|
||||
|
||||
# Exception
|
||||
die $$output if ref $$output;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojolicious::Plugin::EPLRenderer - Embedded Perl Lite renderer plugin
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# Mojolicious
|
||||
$app->plugin('EPLRenderer');
|
||||
|
||||
# Mojolicious::Lite
|
||||
plugin 'EPLRenderer';
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojolicious::Plugin::EPLRenderer> is a renderer for C<epl> templates, which are pretty much just raw
|
||||
L<Mojo::Template>.
|
||||
|
||||
This is a core plugin, that means it is always enabled and its code a good example for learning to build new plugins,
|
||||
you're welcome to fork it.
|
||||
|
||||
See L<Mojolicious::Plugins/"PLUGINS"> for a list of plugins that are available by default.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojolicious::Plugin::EPLRenderer> inherits all methods from L<Mojolicious::Plugin> and implements the following new
|
||||
ones.
|
||||
|
||||
=head2 register
|
||||
|
||||
$plugin->register(Mojolicious->new);
|
||||
|
||||
Register renderer in L<Mojolicious> application.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
116
database/perl/vendor/lib/Mojolicious/Plugin/EPRenderer.pm
vendored
Normal file
116
database/perl/vendor/lib/Mojolicious/Plugin/EPRenderer.pm
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
package Mojolicious::Plugin::EPRenderer;
|
||||
use Mojo::Base 'Mojolicious::Plugin::EPLRenderer';
|
||||
|
||||
use Mojo::Template;
|
||||
use Mojo::Util qw(encode md5_sum monkey_patch);
|
||||
|
||||
sub DESTROY { Mojo::Util::_teardown(shift->{namespace}) }
|
||||
|
||||
sub register {
|
||||
my ($self, $app, $conf) = @_;
|
||||
|
||||
# Auto escape by default to prevent XSS attacks
|
||||
my $ep = {auto_escape => 1, %{$conf->{template} // {}}, vars => 1};
|
||||
my $ns = $self->{namespace} = $ep->{namespace} //= 'Mojo::Template::Sandbox::' . md5_sum "$self";
|
||||
|
||||
# Make "$self" and "$c" available in templates
|
||||
$ep->{prepend} = 'my $self = my $c = _C;' . ($ep->{prepend} // '');
|
||||
|
||||
# Add "ep" handler and make it the default
|
||||
$app->renderer->default_handler('ep')->add_handler(
|
||||
$conf->{name} || 'ep' => sub {
|
||||
my ($renderer, $c, $output, $options) = @_;
|
||||
|
||||
my $name = $options->{inline} // $renderer->template_name($options);
|
||||
return unless defined $name;
|
||||
my $key = md5_sum encode 'UTF-8', $name;
|
||||
|
||||
my $cache = $renderer->cache;
|
||||
my $mt = $cache->get($key);
|
||||
$cache->set($key => $mt = Mojo::Template->new($ep)) unless $mt;
|
||||
|
||||
# Export helpers only once
|
||||
++$self->{helpers} and _helpers($ns, $renderer->helpers) unless $self->{helpers};
|
||||
|
||||
# Make current controller available and render with "epl" handler
|
||||
no strict 'refs';
|
||||
no warnings 'redefine';
|
||||
local *{"${ns}::_C"} = sub {$c};
|
||||
Mojolicious::Plugin::EPLRenderer::_render($renderer, $c, $output, $options, $mt, $c->stash);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
sub _helpers {
|
||||
my ($class, $helpers) = @_;
|
||||
for my $method (grep {/^\w+$/} keys %$helpers) {
|
||||
my $sub = $helpers->{$method};
|
||||
monkey_patch $class, $method, sub { $class->_C->$sub(@_) };
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojolicious::Plugin::EPRenderer - Embedded Perl renderer plugin
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# Mojolicious
|
||||
$app->plugin('EPRenderer');
|
||||
$app->plugin(EPRenderer => {name => 'foo'});
|
||||
$app->plugin(EPRenderer => {name => 'bar', template => {line_start => '.'}});
|
||||
|
||||
# Mojolicious::Lite
|
||||
plugin 'EPRenderer';
|
||||
plugin EPRenderer => {name => 'foo'};
|
||||
plugin EPRenderer => {name => 'bar', template => {line_start => '.'}};
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojolicious::Plugin::EPRenderer> is a renderer for Embedded Perl templates. For more information see
|
||||
L<Mojolicious::Guides::Rendering/"Embedded Perl">.
|
||||
|
||||
This is a core plugin, that means it is always enabled and its code a good example for learning to build new plugins,
|
||||
you're welcome to fork it.
|
||||
|
||||
See L<Mojolicious::Plugins/"PLUGINS"> for a list of plugins that are available by default.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
L<Mojolicious::Plugin::EPRenderer> supports the following options.
|
||||
|
||||
=head2 name
|
||||
|
||||
# Mojolicious::Lite
|
||||
plugin EPRenderer => {name => 'foo'};
|
||||
|
||||
Handler name, defaults to C<ep>.
|
||||
|
||||
=head2 template
|
||||
|
||||
# Mojolicious::Lite
|
||||
plugin EPRenderer => {template => {line_start => '.'}};
|
||||
|
||||
Attribute values passed to L<Mojo::Template> objects used to render templates.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojolicious::Plugin::EPRenderer> inherits all methods from L<Mojolicious::Plugin::EPLRenderer> and implements the
|
||||
following new ones.
|
||||
|
||||
=head2 register
|
||||
|
||||
$plugin->register(Mojolicious->new);
|
||||
$plugin->register(Mojolicious->new, {name => 'foo'});
|
||||
|
||||
Register renderer in L<Mojolicious> application.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
85
database/perl/vendor/lib/Mojolicious/Plugin/HeaderCondition.pm
vendored
Normal file
85
database/perl/vendor/lib/Mojolicious/Plugin/HeaderCondition.pm
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
package Mojolicious::Plugin::HeaderCondition;
|
||||
use Mojo::Base 'Mojolicious::Plugin';
|
||||
|
||||
use re qw(is_regexp);
|
||||
|
||||
sub register {
|
||||
my ($self, $app) = @_;
|
||||
|
||||
$app->routes->add_condition(headers => \&_headers);
|
||||
$app->routes->add_condition(agent => sub { _headers(@_[0 .. 2], {'User-Agent' => $_[3]}) });
|
||||
$app->routes->add_condition(host => sub { _check($_[1]->req->url->to_abs->host, $_[3]) });
|
||||
}
|
||||
|
||||
sub _check {
|
||||
my ($value, $pattern) = @_;
|
||||
return 1 if $value && $pattern && is_regexp($pattern) && $value =~ $pattern;
|
||||
return $value && defined $pattern && $pattern eq $value;
|
||||
}
|
||||
|
||||
sub _headers {
|
||||
my ($route, $c, $captures, $patterns) = @_;
|
||||
return undef unless $patterns && ref $patterns eq 'HASH' && keys %$patterns;
|
||||
|
||||
# All headers need to match
|
||||
my $headers = $c->req->headers;
|
||||
_check($headers->header($_), $patterns->{$_}) || return undef for keys %$patterns;
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojolicious::Plugin::HeaderCondition - Header condition plugin
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# Mojolicious
|
||||
$app->plugin('HeaderCondition');
|
||||
$app->routes->get('/:controller/:action')
|
||||
->requires(headers => {Referer => qr/example\.com/});
|
||||
|
||||
# Mojolicious::Lite
|
||||
plugin 'HeaderCondition';
|
||||
get '/' => (headers => {Referer => qr/example\.com/}) => sub {...};
|
||||
|
||||
# All headers need to match
|
||||
$app->routes->get('/:controller/:action')->requires(headers => {
|
||||
'X-Secret-Header' => 'Foo',
|
||||
Referer => qr/example\.com/
|
||||
});
|
||||
|
||||
# The "agent" condition is a shortcut for the "User-Agent" header
|
||||
get '/' => (agent => qr/Firefox/) => sub {...};
|
||||
|
||||
# The "host" condition is a shortcut for the detected host
|
||||
get '/' => (host => qr/mojolicious\.org/) => sub {...};
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojolicious::Plugin::HeaderCondition> is a route condition for header-based routes.
|
||||
|
||||
This is a core plugin, that means it is always enabled and its code a good example for learning to build new plugins,
|
||||
you're welcome to fork it.
|
||||
|
||||
See L<Mojolicious::Plugins/"PLUGINS"> for a list of plugins that are available by default.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojolicious::Plugin::HeaderCondition> inherits all methods from L<Mojolicious::Plugin> and implements the following
|
||||
new ones.
|
||||
|
||||
=head2 register
|
||||
|
||||
$plugin->register(Mojolicious->new);
|
||||
|
||||
Register conditions in L<Mojolicious> application.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
140
database/perl/vendor/lib/Mojolicious/Plugin/JSONConfig.pm
vendored
Normal file
140
database/perl/vendor/lib/Mojolicious/Plugin/JSONConfig.pm
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
package Mojolicious::Plugin::JSONConfig;
|
||||
use Mojo::Base 'Mojolicious::Plugin::Config';
|
||||
|
||||
use Mojo::JSON qw(from_json);
|
||||
use Mojo::Template;
|
||||
|
||||
sub parse {
|
||||
my ($self, $content, $file, $conf, $app) = @_;
|
||||
|
||||
my $config = eval { from_json $self->render($content, $file, $conf, $app) };
|
||||
die qq{Can't parse config "$file": $@} if $@;
|
||||
die qq{Invalid config "$file"} unless ref $config eq 'HASH';
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
sub register { shift->SUPER::register(shift, {ext => 'json', %{shift()}}) }
|
||||
|
||||
sub render {
|
||||
my ($self, $content, $file, $conf, $app) = @_;
|
||||
|
||||
# Application instance and helper
|
||||
my $prepend = q[no strict 'refs'; no warnings 'redefine';];
|
||||
$prepend .= q[my $app = shift; sub app; local *app = sub { $app };];
|
||||
$prepend .= q[use Mojo::Base -strict; no warnings 'ambiguous';];
|
||||
|
||||
my $mt = Mojo::Template->new($conf->{template} // {})->name($file);
|
||||
my $output = $mt->prepend($prepend . $mt->prepend)->render($content, $app);
|
||||
return ref $output ? die $output : $output;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojolicious::Plugin::JSONConfig - JSON configuration plugin
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# myapp.json (it's just JSON with embedded Perl)
|
||||
{
|
||||
%# Just a value
|
||||
"foo": "bar",
|
||||
|
||||
%# Nested data structures are fine too
|
||||
"baz": ["♥"],
|
||||
|
||||
%# You have full access to the application
|
||||
"music_dir": "<%= app->home->child('music') %>"
|
||||
}
|
||||
|
||||
# Mojolicious
|
||||
my $config = $app->plugin('JSONConfig');
|
||||
say $config->{foo};
|
||||
|
||||
# Mojolicious::Lite
|
||||
my $config = plugin 'JSONConfig';
|
||||
say $config->{foo};
|
||||
|
||||
# foo.html.ep
|
||||
%= config->{foo}
|
||||
|
||||
# The configuration is available application-wide
|
||||
my $config = app->config;
|
||||
say $config->{foo};
|
||||
|
||||
# Everything can be customized with options
|
||||
my $config = plugin JSONConfig => {file => '/etc/myapp.conf'};
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojolicious::Plugin::JSONConfig> is a JSON configuration plugin that preprocesses its input with L<Mojo::Template>.
|
||||
|
||||
The application object can be accessed via C<$app> or the C<app> function. A default configuration filename in the
|
||||
application home directory will be generated from the value of L<Mojolicious/"moniker"> (C<$moniker.json>). You can
|
||||
extend the normal configuration file C<$moniker.json> with C<mode> specific ones like C<$moniker.$mode.json>, which
|
||||
will be detected automatically.
|
||||
|
||||
If the configuration value C<config_override> has been set in L<Mojolicious/"config"> when this plugin is loaded, it
|
||||
will not do anything.
|
||||
|
||||
The code of this plugin is a good example for learning to build new plugins, you're welcome to fork it.
|
||||
|
||||
See L<Mojolicious::Plugins/"PLUGINS"> for a list of plugins that are available by default.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
L<Mojolicious::Plugin::JSONConfig> inherits all options from L<Mojolicious::Plugin::Config> and supports the following
|
||||
new ones.
|
||||
|
||||
=head2 template
|
||||
|
||||
# Mojolicious::Lite
|
||||
plugin JSONConfig => {template => {line_start => '.'}};
|
||||
|
||||
Attribute values passed to L<Mojo::Template> object used to preprocess configuration files.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojolicious::Plugin::JSONConfig> inherits all methods from L<Mojolicious::Plugin::Config> and implements the
|
||||
following new ones.
|
||||
|
||||
=head2 parse
|
||||
|
||||
$plugin->parse($content, $file, $conf, $app);
|
||||
|
||||
Process content with L</"render"> and parse it with L<Mojo::JSON>.
|
||||
|
||||
sub parse ($self, $content, $file, $conf, $app) {
|
||||
...
|
||||
$content = $self->render($content, $file, $conf, $app);
|
||||
...
|
||||
return $hash;
|
||||
}
|
||||
|
||||
=head2 register
|
||||
|
||||
my $config = $plugin->register(Mojolicious->new);
|
||||
my $config = $plugin->register(Mojolicious->new, {file => '/etc/foo.conf'});
|
||||
|
||||
Register plugin in L<Mojolicious> application and merge configuration.
|
||||
|
||||
=head2 render
|
||||
|
||||
$plugin->render($content, $file, $conf, $app);
|
||||
|
||||
Process configuration file with L<Mojo::Template>.
|
||||
|
||||
sub render ($self, $content, $file, $conf, $app) {
|
||||
...
|
||||
return $content;
|
||||
}
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
76
database/perl/vendor/lib/Mojolicious/Plugin/Mount.pm
vendored
Normal file
76
database/perl/vendor/lib/Mojolicious/Plugin/Mount.pm
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package Mojolicious::Plugin::Mount;
|
||||
use Mojo::Base 'Mojolicious::Plugin';
|
||||
|
||||
use Mojo::Server;
|
||||
|
||||
sub register {
|
||||
my ($self, $app, $conf) = @_;
|
||||
|
||||
my $path = (keys %$conf)[0];
|
||||
my $embed = Mojo::Server->new->load_app($conf->{$path});
|
||||
$embed->secrets($app->secrets);
|
||||
|
||||
# Extract host
|
||||
my $host;
|
||||
($host, $path) = ($1 ? qr/^(?:.*\.)?\Q$2\E$/i : qr/^\Q$2\E$/i, $3) if $path =~ m!^(\*\.)?([^/]+)(/.*)?$!;
|
||||
|
||||
my $route = $app->routes->any($path)->partial(1)->to(app => $embed);
|
||||
return $host ? $route->requires(host => $host) : $route;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojolicious::Plugin::Mount - Application mount plugin
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# Mojolicious
|
||||
my $route = $app->plugin(Mount => {'/prefix' => '/home/sri/foo/script/foo'});
|
||||
|
||||
# Mojolicious::Lite
|
||||
my $route = plugin Mount => {'/prefix' => '/home/sri/myapp.pl'};
|
||||
|
||||
# Adjust the generated route and mounted application
|
||||
my $example = plugin Mount => {'/example' => '/home/sri/example.pl'};
|
||||
$example->to(message => 'It works great!');
|
||||
my $app = $example->pattern->defaults->{app};
|
||||
$app->config(foo => 'bar');
|
||||
$app->log(app->log);
|
||||
|
||||
# Mount application with host
|
||||
plugin Mount => {'example.com' => '/home/sri/myapp.pl'};
|
||||
|
||||
# Host and path
|
||||
plugin Mount => {'example.com/myapp' => '/home/sri/myapp.pl'};
|
||||
|
||||
# Or even hosts with wildcard subdomains
|
||||
plugin Mount => {'*.example.com/myapp' => '/home/sri/myapp.pl'};
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojolicious::Plugin::Mount> is a plugin that allows you to mount whole L<Mojolicious> applications.
|
||||
|
||||
The code of this plugin is a good example for learning to build new plugins, you're welcome to fork it.
|
||||
|
||||
See L<Mojolicious::Plugins/"PLUGINS"> for a list of plugins that are available by default.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojolicious::Plugin::Mount> inherits all methods from L<Mojolicious::Plugin> and implements the following new ones.
|
||||
|
||||
=head2 register
|
||||
|
||||
my $route = $plugin->register(Mojolicious->new, {'/foo' => '/some/app.pl'});
|
||||
|
||||
Mount L<Mojolicious> application and return the generated route, which is usually a L<Mojolicious::Routes::Route>
|
||||
object.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
122
database/perl/vendor/lib/Mojolicious/Plugin/NotYAMLConfig.pm
vendored
Normal file
122
database/perl/vendor/lib/Mojolicious/Plugin/NotYAMLConfig.pm
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
package Mojolicious::Plugin::NotYAMLConfig;
|
||||
use Mojo::Base 'Mojolicious::Plugin::JSONConfig';
|
||||
|
||||
use CPAN::Meta::YAML;
|
||||
use Mojo::Util qw(decode encode);
|
||||
|
||||
sub register {
|
||||
my ($self, $app, $conf) = @_;
|
||||
|
||||
$conf->{ext} //= 'yml';
|
||||
$self->{yaml} = sub { CPAN::Meta::YAML::Load(decode 'UTF-8', shift) };
|
||||
if (my $mod = $conf->{module}) {
|
||||
die qq{YAML module $mod has no Load function} unless $self->{yaml} = $mod->can('Load');
|
||||
}
|
||||
|
||||
return $self->SUPER::register($app, $conf);
|
||||
}
|
||||
|
||||
sub parse {
|
||||
my ($self, $content, $file, $conf, $app) = @_;
|
||||
my $config = eval { $self->{yaml}->(encode('UTF-8', $self->render($content, $file, $conf, $app))) };
|
||||
die qq{Can't parse config "$file": $@} if $@;
|
||||
die qq{Invalid config "$file"} unless ref $config eq 'HASH';
|
||||
return $config;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojolicious::Plugin::NotYAMLConfig - Not quite YAML configuration plugin
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# myapp.yml (it's just YAML with embedded Perl)
|
||||
---
|
||||
foo: bar
|
||||
baz:
|
||||
- ♥
|
||||
music_dir: <%= app->home->child('music') %>
|
||||
|
||||
# Mojolicious
|
||||
my $config = $app->plugin('NotYAMLConfig');
|
||||
say $config->{foo};
|
||||
|
||||
# Mojolicious::Lite
|
||||
my $config = plugin 'NotYAMLConfig';
|
||||
say $config->{foo};
|
||||
|
||||
# foo.html.ep
|
||||
%= config->{foo}
|
||||
|
||||
# The configuration is available application-wide
|
||||
my $config = app->config;
|
||||
say $config->{foo};
|
||||
|
||||
# Everything can be customized with options
|
||||
my $config = plugin NotYAMLConfig => {file => '/etc/myapp.conf'};
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojolicious::Plugin::NotYAMLConfig> is a YAML configuration plugin that preprocesses its input with L<Mojo::Template>.
|
||||
By default it uses L<CPAN::Meta::YAML> for parsing, which is not the best YAML module available, but good enough for
|
||||
most config files. If you need something more correct you can use a different module like L<YAML::XS> with the
|
||||
L</"module"> option.
|
||||
|
||||
The application object can be accessed via C<$app> or the C<app> function. A default configuration filename in the
|
||||
application home directory will be generated from the value of L<Mojolicious/"moniker"> (C<$moniker.yml>). You can
|
||||
extend the normal configuration file C<$moniker.yml> with C<mode> specific ones like C<$moniker.$mode.yml>, which will
|
||||
be detected automatically.
|
||||
|
||||
If the configuration value C<config_override> has been set in L<Mojolicious/"config"> when this plugin is loaded, it
|
||||
will not do anything.
|
||||
|
||||
The code of this plugin is a good example for learning to build new plugins, you're welcome to fork it.
|
||||
|
||||
See L<Mojolicious::Plugins/"PLUGINS"> for a list of plugins that are available by default.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
L<Mojolicious::Plugin::NotYAMLConfig> inherits all options from L<Mojolicious::Plugin::JSONConfig> and supports the
|
||||
following new ones.
|
||||
|
||||
=head2 module
|
||||
|
||||
# Mojolicious::Lite
|
||||
plugin NotYAMLConfig => {module => 'YAML::PP'};
|
||||
|
||||
Alternative YAML module to use for parsing.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojolicious::Plugin::NotYAMLConfig> inherits all methods from L<Mojolicious::Plugin::JSONConfig> and implements the
|
||||
following new ones.
|
||||
|
||||
=head2 parse
|
||||
|
||||
$plugin->parse($content, $file, $conf, $app);
|
||||
|
||||
Process content with L<Mojolicious::Plugin::JSONConfig/"render"> and parse it with L<CPAN::Meta::YAML>.
|
||||
|
||||
sub parse ($self, $content, $file, $conf, $app) {
|
||||
...
|
||||
$content = $self->render($content, $file, $conf, $app);
|
||||
...
|
||||
return $hash;
|
||||
}
|
||||
|
||||
=head2 register
|
||||
|
||||
my $config = $plugin->register(Mojolicious->new);
|
||||
my $config = $plugin->register(Mojolicious->new, {file => '/etc/foo.conf'});
|
||||
|
||||
Register plugin in L<Mojolicious> application and merge configuration.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
772
database/perl/vendor/lib/Mojolicious/Plugin/TagHelpers.pm
vendored
Normal file
772
database/perl/vendor/lib/Mojolicious/Plugin/TagHelpers.pm
vendored
Normal file
@@ -0,0 +1,772 @@
|
||||
package Mojolicious::Plugin::TagHelpers;
|
||||
use Mojo::Base 'Mojolicious::Plugin';
|
||||
|
||||
use Mojo::ByteStream;
|
||||
use Mojo::DOM::HTML qw(tag_to_html);
|
||||
use Scalar::Util qw(blessed);
|
||||
|
||||
sub register {
|
||||
my ($self, $app) = @_;
|
||||
|
||||
# Text field variations
|
||||
my @time = qw(date month time week);
|
||||
for my $name (@time, qw(color email number range search tel text url)) {
|
||||
$app->helper("${name}_field" => sub { _input(@_, type => $name) });
|
||||
}
|
||||
$app->helper(datetime_field => sub { _input(@_, type => 'datetime-local') });
|
||||
|
||||
my @helpers = (
|
||||
qw(csrf_field form_for hidden_field javascript label_for link_to select_field stylesheet submit_button),
|
||||
qw(tag_with_error text_area)
|
||||
);
|
||||
$app->helper($_ => __PACKAGE__->can("_$_")) for @helpers;
|
||||
|
||||
$app->helper(button_to => sub { _button_to(0, @_) });
|
||||
$app->helper(check_box => sub { _input(@_, type => 'checkbox') });
|
||||
$app->helper(csrf_button_to => sub { _button_to(1, @_) });
|
||||
$app->helper(file_field => sub { _empty_field('file', @_) });
|
||||
$app->helper(image => sub { _tag('img', src => shift->url_for(shift), @_) });
|
||||
$app->helper(input_tag => sub { _input(@_) });
|
||||
$app->helper(password_field => sub { _empty_field('password', @_) });
|
||||
$app->helper(radio_button => sub { _input(@_, type => 'radio') });
|
||||
|
||||
# "t" is just a shortcut for the "tag" helper
|
||||
$app->helper($_ => sub { shift; _tag(@_) }) for qw(t tag);
|
||||
}
|
||||
|
||||
sub _button_to {
|
||||
my ($csrf, $c, $text) = (shift, shift, shift);
|
||||
my $prefix = $csrf ? _csrf_field($c) : '';
|
||||
return _form_for($c, @_, sub { $prefix . _submit_button($c, $text) });
|
||||
}
|
||||
|
||||
sub _csrf_field {
|
||||
my $c = shift;
|
||||
return _hidden_field($c, csrf_token => $c->helpers->csrf_token, @_);
|
||||
}
|
||||
|
||||
sub _empty_field {
|
||||
my ($type, $c, $name) = (shift, shift, shift);
|
||||
return _validation($c, $name, 'input', name => $name, @_, type => $type);
|
||||
}
|
||||
|
||||
sub _form_for {
|
||||
my ($c, @url) = (shift, shift);
|
||||
push @url, shift if ref $_[0] eq 'HASH';
|
||||
|
||||
# Method detection
|
||||
my $r = $c->app->routes->lookup($url[0]);
|
||||
my $method = $r ? $r->suggested_method : 'GET';
|
||||
my @post = $method ne 'GET' ? (method => 'POST') : ();
|
||||
|
||||
my $url = $c->url_for(@url);
|
||||
$url->query({_method => $method}) if @post && $method ne 'POST';
|
||||
return _tag('form', action => $url, @post, @_);
|
||||
}
|
||||
|
||||
sub _hidden_field {
|
||||
my ($c, $name, $value) = (shift, shift, shift);
|
||||
return _tag('input', name => $name, value => $value, @_, type => 'hidden');
|
||||
}
|
||||
|
||||
sub _input {
|
||||
my ($c, $name) = (shift, shift);
|
||||
my %attrs = @_ % 2 ? (value => shift, @_) : @_;
|
||||
|
||||
if (my @values = @{$c->every_param($name)}) {
|
||||
|
||||
# Checkbox or radiobutton
|
||||
my $type = $attrs{type} || '';
|
||||
if ($type eq 'checkbox' || $type eq 'radio') {
|
||||
my $value = $attrs{value} // 'on';
|
||||
delete $attrs{checked};
|
||||
$attrs{checked} = undef if grep { $_ eq $value } @values;
|
||||
}
|
||||
|
||||
# Others
|
||||
else { $attrs{value} = $values[-1] }
|
||||
}
|
||||
|
||||
return _validation($c, $name, 'input', name => $name, %attrs);
|
||||
}
|
||||
|
||||
sub _javascript {
|
||||
my $c = shift;
|
||||
my $content = ref $_[-1] eq 'CODE' ? "//<![CDATA[\n" . pop->() . "\n//]]>" : '';
|
||||
my @src = @_ % 2 ? (src => $c->url_for(shift)) : ();
|
||||
return _tag('script', @src, @_, sub {$content});
|
||||
}
|
||||
|
||||
sub _label_for {
|
||||
my ($c, $name) = (shift, shift);
|
||||
my $content = ref $_[-1] eq 'CODE' ? pop : shift;
|
||||
return _validation($c, $name, 'label', for => $name, @_, $content);
|
||||
}
|
||||
|
||||
sub _link_to {
|
||||
my ($c, $content) = (shift, shift);
|
||||
my @url = ($content);
|
||||
|
||||
# Content
|
||||
unless (ref $_[-1] eq 'CODE') {
|
||||
@url = (shift);
|
||||
push @_, $content;
|
||||
}
|
||||
|
||||
# Captures
|
||||
push @url, shift if ref $_[0] eq 'HASH';
|
||||
|
||||
return _tag('a', href => $c->url_for(@url), @_);
|
||||
}
|
||||
|
||||
sub _option {
|
||||
my ($values, $pair) = @_;
|
||||
|
||||
$pair = [$pair => $pair] unless ref $pair eq 'ARRAY';
|
||||
my %attrs = (value => $pair->[1], @$pair[2 .. $#$pair]);
|
||||
delete $attrs{selected} if keys %$values;
|
||||
$attrs{selected} = undef if $values->{$pair->[1]};
|
||||
|
||||
return _tag('option', %attrs, $pair->[0]);
|
||||
}
|
||||
|
||||
sub _select_field {
|
||||
my ($c, $name, $options, %attrs) = (shift, shift, shift, @_);
|
||||
|
||||
my %values = map { $_ => 1 } grep {defined} @{$c->every_param($name)};
|
||||
|
||||
my $groups = '';
|
||||
for my $group (@$options) {
|
||||
|
||||
# "optgroup" tag
|
||||
if (blessed $group && $group->isa('Mojo::Collection')) {
|
||||
my ($label, $values, %attrs) = @$group;
|
||||
my $content = join '', map { _option(\%values, $_) } @$values;
|
||||
$groups .= _tag('optgroup', label => $label, %attrs, sub {$content});
|
||||
}
|
||||
|
||||
# "option" tag
|
||||
else { $groups .= _option(\%values, $group) }
|
||||
}
|
||||
|
||||
return _validation($c, $name, 'select', name => $name, %attrs, sub {$groups});
|
||||
}
|
||||
|
||||
sub _stylesheet {
|
||||
my $c = shift;
|
||||
my $content = ref $_[-1] eq 'CODE' ? "/*<![CDATA[*/\n" . pop->() . "\n/*]]>*/" : '';
|
||||
return _tag('style', @_, sub {$content}) unless @_ % 2;
|
||||
return _tag('link', rel => 'stylesheet', href => $c->url_for(shift), @_);
|
||||
}
|
||||
|
||||
sub _submit_button {
|
||||
my ($c, $value) = (shift, shift // 'Ok');
|
||||
return _tag('input', value => $value, @_, type => 'submit');
|
||||
}
|
||||
|
||||
sub _tag { Mojo::ByteStream->new(tag_to_html(@_)) }
|
||||
|
||||
sub _tag_with_error {
|
||||
my ($c, $tag) = (shift, shift);
|
||||
my ($content, %attrs) = (@_ % 2 ? pop : undef, @_);
|
||||
$attrs{class} .= $attrs{class} ? ' field-with-error' : 'field-with-error';
|
||||
return _tag($tag, %attrs, defined $content ? $content : ());
|
||||
}
|
||||
|
||||
sub _text_area {
|
||||
my ($c, $name) = (shift, shift);
|
||||
|
||||
my $cb = ref $_[-1] eq 'CODE' ? pop : undef;
|
||||
my $content = @_ % 2 ? shift : undef;
|
||||
$content = $c->param($name) // $content // $cb // '';
|
||||
|
||||
return _validation($c, $name, 'textarea', name => $name, @_, $content);
|
||||
}
|
||||
|
||||
sub _validation {
|
||||
my ($c, $name) = (shift, shift);
|
||||
return _tag(@_) unless $c->helpers->validation->has_error($name);
|
||||
return $c->helpers->tag_with_error(@_);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojolicious::Plugin::TagHelpers - Tag helpers plugin
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# Mojolicious
|
||||
$app->plugin('TagHelpers');
|
||||
|
||||
# Mojolicious::Lite
|
||||
plugin 'TagHelpers';
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojolicious::Plugin::TagHelpers> is a collection of HTML tag helpers for L<Mojolicious>, based on the L<HTML Living
|
||||
Standard|https://html.spec.whatwg.org>.
|
||||
|
||||
Most form helpers can automatically pick up previous input values and will show them as default. You can also use
|
||||
L<Mojolicious::Plugin::DefaultHelpers/"param"> to set them manually and let necessary attributes always be generated
|
||||
automatically.
|
||||
|
||||
% param country => 'germany' unless param 'country';
|
||||
<%= radio_button country => 'germany' %> Germany
|
||||
<%= radio_button country => 'france' %> France
|
||||
<%= radio_button country => 'uk' %> UK
|
||||
|
||||
For fields that failed validation with L<Mojolicious::Plugin::DefaultHelpers/"validation"> the C<field-with-error>
|
||||
class will be automatically added through L</"tag_with_error">, to make styling with CSS easier.
|
||||
|
||||
<input class="field-with-error" name="age" type="text" value="250">
|
||||
|
||||
This is a core plugin, that means it is always enabled and its code a good example for learning how to build new
|
||||
plugins, you're welcome to fork it.
|
||||
|
||||
See L<Mojolicious::Plugins/"PLUGINS"> for a list of plugins that are available by default.
|
||||
|
||||
=head1 HELPERS
|
||||
|
||||
L<Mojolicious::Plugin::TagHelpers> implements the following helpers.
|
||||
|
||||
=head2 button_to
|
||||
|
||||
%= button_to Test => 'some_get_route'
|
||||
%= button_to Test => some_get_route => {id => 23} => (class => 'menu')
|
||||
%= button_to Test => 'http://example.com/test' => (class => 'menu')
|
||||
%= button_to Remove => 'some_delete_route'
|
||||
|
||||
Generate portable C<form> tag with L</"form_for">, containing a single button.
|
||||
|
||||
<form action="/path/to/get/route">
|
||||
<input type="submit" value="Test">
|
||||
</form>
|
||||
<form action="/path/to/get/route/23" class="menu">
|
||||
<input type="submit" value="Test">
|
||||
</form>
|
||||
<form action="http://example.com/test" class="menu">
|
||||
<input type="submit" value="Test">
|
||||
</form>
|
||||
<form action="/path/to/delete/route?_method=DELETE" method="POST">
|
||||
<input type="submit" value="Remove">
|
||||
</form>
|
||||
|
||||
=head2 check_box
|
||||
|
||||
%= check_box 'employed'
|
||||
%= check_box employed => 1
|
||||
%= check_box employed => 1, checked => undef, id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<checkbox>. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="employed" type="checkbox">
|
||||
<input name="employed" type="checkbox" value="1">
|
||||
<input checked id="foo" name="employed" type="checkbox" value="1">
|
||||
|
||||
=head2 color_field
|
||||
|
||||
%= color_field 'background'
|
||||
%= color_field background => '#ffffff'
|
||||
%= color_field background => '#ffffff', id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<color>. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="background" type="color">
|
||||
<input name="background" type="color" value="#ffffff">
|
||||
<input id="foo" name="background" type="color" value="#ffffff">
|
||||
|
||||
=head2 csrf_button_to
|
||||
|
||||
%= csrf_button_to Remove => 'some_delete_route'
|
||||
|
||||
Same as L</"button_to">, but also includes a L</"csrf_field">.
|
||||
|
||||
<form action="/path/to/delete/route?_method=DELETE" method="POST">
|
||||
<input name="csrf_token" type="hidden" value="fa6a08...">
|
||||
<input type="submit" value="Remove">
|
||||
</form>
|
||||
|
||||
=head2 csrf_field
|
||||
|
||||
%= csrf_field
|
||||
|
||||
Generate C<input> tag of type C<hidden> with L<Mojolicious::Plugin::DefaultHelpers/"csrf_token">.
|
||||
|
||||
<input name="csrf_token" type="hidden" value="fa6a08...">
|
||||
|
||||
=head2 date_field
|
||||
|
||||
%= date_field 'end'
|
||||
%= date_field end => '2012-12-21'
|
||||
%= date_field end => '2012-12-21', id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<date>. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="end" type="date">
|
||||
<input name="end" type="date" value="2012-12-21">
|
||||
<input id="foo" name="end" type="date" value="2012-12-21">
|
||||
|
||||
=head2 datetime_field
|
||||
|
||||
%= datetime_field 'end'
|
||||
%= datetime_field end => '2012-12-21T23:59:59'
|
||||
%= datetime_field end => '2012-12-21T23:59:59', id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<datetime-local>. Previous input values will automatically get picked up and shown as
|
||||
default.
|
||||
|
||||
<input name="end" type="datetime-local">
|
||||
<input name="end" type="datetime-local" value="2012-12-21T23:59:59">
|
||||
<input id="foo" name="end" type="datetime-local" value="2012-12-21T23:59:59">
|
||||
|
||||
=head2 email_field
|
||||
|
||||
%= email_field 'notify'
|
||||
%= email_field notify => 'nospam@example.com'
|
||||
%= email_field notify => 'nospam@example.com', id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<email>. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="notify" type="email">
|
||||
<input name="notify" type="email" value="nospam@example.com">
|
||||
<input id="foo" name="notify" type="email" value="nospam@example.com">
|
||||
|
||||
=head2 file_field
|
||||
|
||||
%= file_field 'avatar'
|
||||
%= file_field 'avatar', id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<file>.
|
||||
|
||||
<input name="avatar" type="file">
|
||||
<input id="foo" name="avatar" type="file">
|
||||
|
||||
=head2 form_for
|
||||
|
||||
%= form_for login => begin
|
||||
%= text_field 'first_name'
|
||||
%= submit_button
|
||||
% end
|
||||
%= form_for login => {format => 'txt'} => (method => 'POST') => begin
|
||||
%= text_field 'first_name'
|
||||
%= submit_button
|
||||
% end
|
||||
%= form_for '/login' => (enctype => 'multipart/form-data') => begin
|
||||
%= text_field 'first_name', disabled => 'disabled'
|
||||
%= submit_button
|
||||
% end
|
||||
%= form_for 'http://example.com/login' => (method => 'POST') => begin
|
||||
%= text_field 'first_name'
|
||||
%= submit_button
|
||||
% end
|
||||
%= form_for some_delete_route => begin
|
||||
%= submit_button 'Remove'
|
||||
% end
|
||||
|
||||
Generate portable C<form> tag with L<Mojolicious::Controller/"url_for">. For routes that do not allow C<GET>, a
|
||||
C<method> attribute with the value C<POST> will be automatically added. And for methods other than C<GET> or C<POST>,
|
||||
an C<_method> query parameter will be added as well.
|
||||
|
||||
<form action="/path/to/login">
|
||||
<input name="first_name" type="text">
|
||||
<input type="submit" value="Ok">
|
||||
</form>
|
||||
<form action="/path/to/login.txt" method="POST">
|
||||
<input name="first_name" type="text">
|
||||
<input type="submit" value="Ok">
|
||||
</form>
|
||||
<form action="/path/to/login" enctype="multipart/form-data">
|
||||
<input disabled="disabled" name="first_name" type="text">
|
||||
<input type="submit" value="Ok">
|
||||
</form>
|
||||
<form action="http://example.com/login" method="POST">
|
||||
<input name="first_name" type="text">
|
||||
<input type="submit" value="Ok">
|
||||
</form>
|
||||
<form action="/path/to/delete/route?_method=DELETE" method="POST">
|
||||
<input type="submit" value="Remove">
|
||||
</form>
|
||||
|
||||
=head2 hidden_field
|
||||
|
||||
%= hidden_field foo => 'bar'
|
||||
%= hidden_field foo => 'bar', id => 'bar'
|
||||
|
||||
Generate C<input> tag of type C<hidden>.
|
||||
|
||||
<input name="foo" type="hidden" value="bar">
|
||||
<input id="bar" name="foo" type="hidden" value="bar">
|
||||
|
||||
=head2 image
|
||||
|
||||
%= image '/images/foo.png'
|
||||
%= image '/images/foo.png', alt => 'Foo'
|
||||
|
||||
Generate portable C<img> tag.
|
||||
|
||||
<img src="/path/to/images/foo.png">
|
||||
<img alt="Foo" src="/path/to/images/foo.png">
|
||||
|
||||
=head2 input_tag
|
||||
|
||||
%= input_tag 'first_name'
|
||||
%= input_tag first_name => 'Default'
|
||||
%= input_tag 'employed', type => 'checkbox'
|
||||
|
||||
Generate C<input> tag. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="first_name">
|
||||
<input name="first_name" value="Default">
|
||||
<input name="employed" type="checkbox">
|
||||
|
||||
=head2 javascript
|
||||
|
||||
%= javascript '/script.js'
|
||||
%= javascript '/script.js', defer => undef
|
||||
%= javascript begin
|
||||
var a = 'b';
|
||||
% end
|
||||
|
||||
Generate portable C<script> tag for JavaScript asset.
|
||||
|
||||
<script src="/path/to/script.js"></script>
|
||||
<script defer src="/path/to/script.js"></script>
|
||||
<script><![CDATA[
|
||||
var a = 'b';
|
||||
]]></script>
|
||||
|
||||
=head2 label_for
|
||||
|
||||
%= label_for first_name => 'First name'
|
||||
%= label_for first_name => 'First name', class => 'user'
|
||||
%= label_for first_name => begin
|
||||
First name
|
||||
% end
|
||||
%= label_for first_name => (class => 'user') => begin
|
||||
First name
|
||||
% end
|
||||
|
||||
Generate C<label> tag.
|
||||
|
||||
<label for="first_name">First name</label>
|
||||
<label class="user" for="first_name">First name</label>
|
||||
<label for="first_name">
|
||||
First name
|
||||
</label>
|
||||
<label class="user" for="first_name">
|
||||
First name
|
||||
</label>
|
||||
|
||||
=head2 link_to
|
||||
|
||||
%= link_to Home => 'index'
|
||||
%= link_to Home => 'index' => {format => 'txt'} => (class => 'menu')
|
||||
%= link_to index => {format => 'txt'} => (class => 'menu') => begin
|
||||
Home
|
||||
% end
|
||||
%= link_to Contact => 'mailto:sri@example.com'
|
||||
<%= link_to index => begin %>Home<% end %>
|
||||
<%= link_to '/file.txt' => begin %>File<% end %>
|
||||
<%= link_to 'https://mojolicious.org' => begin %>Mojolicious<% end %>
|
||||
<%= link_to url_for->query(foo => 'bar')->to_abs => begin %>Retry<% end %>
|
||||
|
||||
Generate portable C<a> tag with L<Mojolicious::Controller/"url_for">, defaults to using the capitalized link target as
|
||||
content.
|
||||
|
||||
<a href="/path/to/index">Home</a>
|
||||
<a class="menu" href="/path/to/index.txt">Home</a>
|
||||
<a class="menu" href="/path/to/index.txt">
|
||||
Home
|
||||
</a>
|
||||
<a href="mailto:sri@example.com">Contact</a>
|
||||
<a href="/path/to/index">Home</a>
|
||||
<a href="/path/to/file.txt">File</a>
|
||||
<a href="https://mojolicious.org">Mojolicious</a>
|
||||
<a href="http://127.0.0.1:3000/current/path?foo=bar">Retry</a>
|
||||
|
||||
=head2 month_field
|
||||
|
||||
%= month_field 'vacation'
|
||||
%= month_field vacation => '2012-12'
|
||||
%= month_field vacation => '2012-12', id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<month>. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="vacation" type="month">
|
||||
<input name="vacation" type="month" value="2012-12">
|
||||
<input id="foo" name="vacation" type="month" value="2012-12">
|
||||
|
||||
=head2 number_field
|
||||
|
||||
%= number_field 'age'
|
||||
%= number_field age => 25
|
||||
%= number_field age => 25, id => 'foo', min => 0, max => 200
|
||||
|
||||
Generate C<input> tag of type C<number>. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="age" type="number">
|
||||
<input name="age" type="number" value="25">
|
||||
<input id="foo" max="200" min="0" name="age" type="number" value="25">
|
||||
|
||||
=head2 password_field
|
||||
|
||||
%= password_field 'pass'
|
||||
%= password_field 'pass', id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<password>.
|
||||
|
||||
<input name="pass" type="password">
|
||||
<input id="foo" name="pass" type="password">
|
||||
|
||||
=head2 radio_button
|
||||
|
||||
%= radio_button 'test'
|
||||
%= radio_button country => 'germany'
|
||||
%= radio_button country => 'germany', checked => undef, id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<radio>. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="test" type="radio">
|
||||
<input name="country" type="radio" value="germany">
|
||||
<input checked id="foo" name="country" type="radio" value="germany">
|
||||
|
||||
=head2 range_field
|
||||
|
||||
%= range_field 'age'
|
||||
%= range_field age => 25
|
||||
%= range_field age => 25, id => 'foo', min => 0, max => 200
|
||||
|
||||
Generate C<input> tag of type C<range>. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="age" type="range">
|
||||
<input name="age" type="range" value="25">
|
||||
<input id="foo" max="200" min="200" name="age" type="range" value="25">
|
||||
|
||||
=head2 search_field
|
||||
|
||||
%= search_field 'q'
|
||||
%= search_field q => 'perl'
|
||||
%= search_field q => 'perl', id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<search>. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="q" type="search">
|
||||
<input name="q" type="search" value="perl">
|
||||
<input id="foo" name="q" type="search" value="perl">
|
||||
|
||||
=head2 select_field
|
||||
|
||||
%= select_field country => ['de', 'en']
|
||||
%= select_field country => [[Germany => 'de'], 'en'], id => 'eu'
|
||||
%= select_field country => [[Germany => 'de', selected => 'selected'], 'en']
|
||||
%= select_field country => [c(EU => [[Germany => 'de'], 'en'], id => 'eu')]
|
||||
%= select_field country => [c(EU => ['de', 'en']), c(Asia => ['cn', 'jp'])]
|
||||
|
||||
Generate C<select> and C<option> tags from array references and C<optgroup> tags from L<Mojo::Collection> objects.
|
||||
Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<select name="country">
|
||||
<option value="de">de</option>
|
||||
<option value="en">en</option>
|
||||
</select>
|
||||
<select id="eu" name="country">
|
||||
<option value="de">Germany</option>
|
||||
<option value="en">en</option>
|
||||
</select>
|
||||
<select name="country">
|
||||
<option selected="selected" value="de">Germany</option>
|
||||
<option value="en">en</option>
|
||||
</select>
|
||||
<select name="country">
|
||||
<optgroup id="eu" label="EU">
|
||||
<option value="de">Germany</option>
|
||||
<option value="en">en</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
<select name="country">
|
||||
<optgroup label="EU">
|
||||
<option value="de">de</option>
|
||||
<option value="en">en</option>
|
||||
</optgroup>
|
||||
<optgroup label="Asia">
|
||||
<option value="cn">cn</option>
|
||||
<option value="jp">jp</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
|
||||
=head2 stylesheet
|
||||
|
||||
%= stylesheet '/foo.css'
|
||||
%= stylesheet '/foo.css', title => 'Foo style'
|
||||
%= stylesheet begin
|
||||
body {color: #000}
|
||||
% end
|
||||
|
||||
Generate portable C<style> or C<link> tag for CSS asset.
|
||||
|
||||
<link href="/path/to/foo.css" rel="stylesheet">
|
||||
<link href="/path/to/foo.css" rel="stylesheet" title="Foo style">
|
||||
<style><![CDATA[
|
||||
body {color: #000}
|
||||
]]></style>
|
||||
|
||||
=head2 submit_button
|
||||
|
||||
%= submit_button
|
||||
%= submit_button 'Ok!', id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<submit>.
|
||||
|
||||
<input type="submit" value="Ok">
|
||||
<input id="foo" type="submit" value="Ok!">
|
||||
|
||||
=head2 t
|
||||
|
||||
%= t div => 'test & 123'
|
||||
|
||||
Alias for L</"tag">.
|
||||
|
||||
<div>test & 123</div>
|
||||
|
||||
=head2 tag
|
||||
|
||||
%= tag 'br'
|
||||
%= tag 'div'
|
||||
%= tag 'div', id => 'foo', hidden => undef
|
||||
%= tag 'div', 'test & 123'
|
||||
%= tag 'div', id => 'foo', 'test & 123'
|
||||
%= tag 'div', data => {my_id => 1, Name => 'test'}, 'test & 123'
|
||||
%= tag div => begin
|
||||
test & 123
|
||||
% end
|
||||
<%= tag div => (id => 'foo') => begin %>test & 123<% end %>
|
||||
|
||||
Alias for L<Mojo::DOM/"new_tag">.
|
||||
|
||||
<br>
|
||||
<div></div>
|
||||
<div id="foo" hidden></div>
|
||||
<div>test & 123</div>
|
||||
<div id="foo">test & 123</div>
|
||||
<div data-my-id="1" data-name="test">test & 123</div>
|
||||
<div>
|
||||
test & 123
|
||||
</div>
|
||||
<div id="foo">test & 123</div>
|
||||
|
||||
Very useful for reuse in more specific tag helpers.
|
||||
|
||||
my $output = $c->tag('meta');
|
||||
my $output = $c->tag('meta', charset => 'UTF-8');
|
||||
my $output = $c->tag('div', '<p>This will be escaped</p>');
|
||||
my $output = $c->tag('div', sub { '<p>This will not be escaped</p>' });
|
||||
|
||||
Results are automatically wrapped in L<Mojo::ByteStream> objects to prevent accidental double escaping in C<ep>
|
||||
templates.
|
||||
|
||||
=head2 tag_with_error
|
||||
|
||||
%= tag_with_error 'input', class => 'foo'
|
||||
|
||||
Same as L</"tag">, but adds the class C<field-with-error>.
|
||||
|
||||
<input class="foo field-with-error">
|
||||
|
||||
=head2 tel_field
|
||||
|
||||
%= tel_field 'work'
|
||||
%= tel_field work => '123456789'
|
||||
%= tel_field work => '123456789', id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<tel>. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="work" type="tel">
|
||||
<input name="work" type="tel" value="123456789">
|
||||
<input id="foo" name="work" type="tel" value="123456789">
|
||||
|
||||
=head2 text_area
|
||||
|
||||
%= text_area 'story'
|
||||
%= text_area 'story', cols => 40
|
||||
%= text_area story => 'Default', cols => 40
|
||||
%= text_area story => (cols => 40) => begin
|
||||
Default
|
||||
% end
|
||||
|
||||
Generate C<textarea> tag. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<textarea name="story"></textarea>
|
||||
<textarea cols="40" name="story"></textarea>
|
||||
<textarea cols="40" name="story">Default</textarea>
|
||||
<textarea cols="40" name="story">
|
||||
Default
|
||||
</textarea>
|
||||
|
||||
=head2 text_field
|
||||
|
||||
%= text_field 'first_name'
|
||||
%= text_field first_name => 'Default'
|
||||
%= text_field first_name => 'Default', class => 'user'
|
||||
|
||||
Generate C<input> tag of type C<text>. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="first_name" type="text">
|
||||
<input name="first_name" type="text" value="Default">
|
||||
<input class="user" name="first_name" type="text" value="Default">
|
||||
|
||||
=head2 time_field
|
||||
|
||||
%= time_field 'start'
|
||||
%= time_field start => '23:59:59'
|
||||
%= time_field start => '23:59:59', id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<time>. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="start" type="time">
|
||||
<input name="start" type="time" value="23:59:59">
|
||||
<input id="foo" name="start" type="time" value="23:59:59">
|
||||
|
||||
=head2 url_field
|
||||
|
||||
%= url_field 'address'
|
||||
%= url_field address => 'https://mojolicious.org'
|
||||
%= url_field address => 'https://mojolicious.org', id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<url>. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="address" type="url">
|
||||
<input name="address" type="url" value="https://mojolicious.org">
|
||||
<input id="foo" name="address" type="url" value="https://mojolicious.org">
|
||||
|
||||
=head2 week_field
|
||||
|
||||
%= week_field 'vacation'
|
||||
%= week_field vacation => '2012-W17'
|
||||
%= week_field vacation => '2012-W17', id => 'foo'
|
||||
|
||||
Generate C<input> tag of type C<week>. Previous input values will automatically get picked up and shown as default.
|
||||
|
||||
<input name="vacation" type="week">
|
||||
<input name="vacation" type="week" value="2012-W17">
|
||||
<input id="foo" name="vacation" type="week" value="2012-W17">
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojolicious::Plugin::TagHelpers> inherits all methods from L<Mojolicious::Plugin> and implements the following new
|
||||
ones.
|
||||
|
||||
=head2 register
|
||||
|
||||
$plugin->register(Mojolicious->new);
|
||||
|
||||
Register helpers in L<Mojolicious> application.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user