package Mojolicious::Plugin::ShareHelpers;
use strict;
use warnings;
use Mojo::ByteStream 'b';
use Mojo::Base 'Mojolicious::Plugin';
our $VERSION = '0.6';
our $APP; # for app instance
has url => sub { +{
'twitter' => 'http://twitter.com/share',
'facebook' => 'http://facebook.com/sharer.php',
'vkontakte' => 'http://vk.com/share.php',
'mymailru' => 'http://connect.mail.ru/share',
'google+' => 'http://plus.google.com',
} };
sub register {
my($self, $app) = @_;
$APP = $app;
$app->helper( share_url => sub { $self->share_url ( @_ ) } );
$app->helper( share_button => sub { $self->share_button ( @_ ) } );
$app->helper( share_meta => sub { $self->share_meta ( @_ ) } );
$app->helper( is_share_agent => sub { $self->is_share_agent( @_ ) } );
}
sub share_url {
my($self, $c) = (shift, shift);
my $type = shift;
return '' unless $self->_check_type( $type );
my %args = @_;
my $param;
if ($type eq 'twitter') {
$param->{$_} = $args{$_} for qw(url via text related count lang counturl);
}
elsif ($type eq 'facebook') {
$param->{u} = $args{url };
$param->{t} = $args{text};
}
elsif ($type eq 'vkontakte') {
$param->{url} = $args{url};
}
elsif ($type eq 'mymailru') {
$param->{share_url} = $args{url};
}
elsif ($type eq 'google+') {
$APP->log->error("Google Plus doen't have share URL, use share_button");
return '';
}
my @p = grep { $param->{$_} } sort keys %$param;
return join '?', $self->url->{ $type },
@p ? join '&', map { $_ . '=' . b( $param->{$_} )->url_escape } @p : ()
;
}
sub share_button {
my($self, $c) = (shift, shift);
my $type = shift;
return '' unless $self->_check_type( $type );
my %args = @_;
my $button;
if ($type eq 'twitter') {
if ($args{iframe}) {
my $url = $c->share_url( $type, @_ );
my($param) = $url =~ /.*\?(.*)/;
$button =
qq(<iframe allowtransparency="true" frameborder="0" scrolling="no" style="width:130px; height:50px;" ) .
qq(src="http://platform.twitter.com/widgets/tweet_button.html?$param"></iframe>)
;
}
else {
my $attr; push @$attr, qq(data-$_="$args{$_}")
for grep { $args{$_} } qw(url via text related count lang counturl);
my $param = join ' ', @$attr;
$button =
qq(<a href="http://twitter.com/share" class="twitter-share-button" $param>Tweet</a>) .
qq(<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>)
;
}
}
elsif ($type eq 'facebook') {
if ($args{fb}) {
my $attr = { type => $args{type}, href => $args{url}, class => $args{class} };
my $param = join ' ', map { qq($_="$attr->{$_}") } grep { $attr->{$_} } keys %$attr;
$button =
qq(<fb:share-button $param></fb:share-button>)
;
}
else {
my $attr = { type => $args{type}, share_url => $args{url} };
my $param = join ' ', map { qq($_="$attr->{$_}") } grep { $attr->{$_} } keys %$attr;
$button =
qq(<a name="fb_share" $param>$args{title}</a>) .
qq(<script src="http://static.ak.fbcdn.net/connect.php/js/FB.Share" type="text/javascript"></script>)
;
}
}
elsif ($type eq 'vkontakte') {
my $url = $args{url} ? qq({url: "$args{url}"}) : 'false';
my $attr = { type => $args{type}, text => $args{title} };
my $param = join ', ', map { qq($_: "$attr->{$_}") } grep { $attr->{$_} } keys %$attr;
$button =
qq(<script type="text/javascript" src="http://vk.com/js/api/share.js?146" charset="windows-1251"></script>) .
qq(<script type="text/javascript">document.write(VK.Share.button($url, {$param}));</script>)
;
}
elsif ($type eq 'mymailru') {
use utf8;
my $url = $c->share_url( $type, @_ );
$args{type } ||= '';
$args{title} ||= 'В Мой Мир';
$button =
qq(<script src="http://cdn.connect.mail.ru/js/share/2/share.js" type="text/javascript"></script>) .
qq(<a class="mrc__share" type="$args{type}" href="$url">$args{title}</a>)
;
}
elsif ($type eq 'google+') {
my $attr = { size => $args{size}, href => $args{url}, count => $args{count}, callback => $args{callback} };
my $param = join ' ', 'class="g-plusone"', map { qq(data-$_="$attr->{$_}") } grep { $attr->{$_} } keys %$attr;
my $script = join ', ', map { qq($_: "$args{$_}") } grep { $args{$_} } qw(lang parsetags);
$button =
(
$args{noscript}
? ''
: qq(<script type="text/javascript" src="https://apis.google.com/js/plusone.js">) . ( $script ? "{$script}" : '' ) . qq(</script>\n)
) .
qq(<div $param></div>)
;
}
return $button;
}
sub share_meta {
my($self, $c) = (shift, shift);
my %args = @_;
$_ = b($_)->xml_escape->to_string for grep {$_} @args{qw(title description)};
return join "\n",
@_ ? qq(<meta name="medium" content="mult"/>) : '',
$args{og} ? (
$args{fb_app_id} ? qq(<meta property="fb:app_id" content="$args{fb_app_id}"/>) : (),
qq(<meta property="og:site_name" content="$args{site_name}" />),
qq(<meta property="og:type" content="website" />),
map { $args{$_} ? qq(<meta property="og:$_" content="$args{$_}"/>) : () }
qw(image title description)
) : (),
$args{title} ? qq(<meta name="title" content="$args{title}"/>) : (),
$args{description} ? qq(<meta name="description" content="$args{description}"/>) : (),
$args{image} ? qq(<link rel="image_src" href="$args{image}" />) : (),
$args{url} ? (
qq(<link rel="target_url" href="$args{url}"/>),
qq(<link rel="canonical" href="$args{url}"/>),
) : (),
;
}
sub is_share_agent {
my($self, $c) = (shift, shift);
my $ua = $c->req->headers->user_agent;
my $range = $c->req->headers->header('Range');
my $enc = $c->req->headers->header('Accept-Encoding');
my $agent =
$ua =~ /facebookexternalhit/ && $range && $enc eq 'gzip' ? 'facebook' :
$ua =~ /Mozilla/ && $range && $enc =~ /gzip/ ? 'vkontakte' : # XXX: add cp1251
''
;
$APP->log->debug(qq(Found the share agent "$agent")) if $agent;
return $agent;
}
sub _check_type {
my $self = shift;
my $type = shift || '';
if (!$type) {
$APP->log->debug('Missed the share type');
return;
}
elsif (! exists $self->url->{ $type }) {
my $types = join ', ', sort keys %{$self->url};
$APP->log->debug(qq(Bad share type "$type", support types of share: $types));
return;
}
else {
return $type;
}
}
1;
__END__
=encoding UTF-8
=head1 NAME
Mojolicious::Plugin::ShareHelpers - A Mojolicious Plugin for generate share urls, buttons and meta for Twitter, Facebook, VKontakte, MyMailRU and Google Plus
=head1 SYNOPSIS
# Mojolicious
$self->plugin('share_helpers');
# Mojolicious::Lite
plugin 'share_helpers';
# share urls:
<a href="<%== share_url 'twitter', url => $url, text => $text, via => 'sharifulin' %>">Share to Twitter</a>
<a href="<%== share_url 'facebook', url => $url, text => $text %>">Share to Facebook</a>
<a href="<%== share_url 'vkontakte', url => $url %>">Share to ВКонтакте</a>
<a href="<%== share_url 'mymailru', url => $url %>">Share to Мой Мир</a>
# share buttons:
%== share_button 'twitter', url => 'http://mojolicio.us', text => 'Viva la revolution!', via => 'sharifulin';
%== share_button 'facebook', url => 'http://mojolicio.us', type => 'button_count', title => 'Share it';
%== share_button 'vkontakte', url => 'http://mojolicio.us', type => 'round', title => 'Save';
%== share_button 'mymailru', url => 'http://mojolicio.us', type => 'button_count', title => 'Share to Мой Мир';
# google plus button +1:
%== share_button 'google+', lang => 'ru'
%== share_button 'google+', noscript => 1, size => 'tall', url => 'http://mojolicio.us'
# generate meta for share
%== share_meta title => 'Mojolicious', description => 'Viva la revolition!', url => 'http://mojolicio.us', image => 'http://mojolicious.org/webinabox.png'
%== share_meta title => 'Mojolicious', description => 'Viva la revolition!', url => 'http://mojolicio.us', image => 'http://mojolicious.org/webinabox.png', og => 1, fb_app_id => 1234567890, site_name => 'Site Name'
# check share agent, it may returns string such as 'facebook' or 'twitter' or 'vkontakte' or empty string
%= is_share_agent
=head1 DESCRIPTION
L<Mojolicous::Plugin::ShareHelpers> is a plugin for generate share url, share button and share meta (Twitter, Facebook, VKontakte).
Plugin adds a C<share_url>, C<share_button>, C<share_meta> and C<is_share_agent> helpers to L<Mojolicious>.
=head1 SHARE API
=over 5
=item * Twitter Share L<http://dev.twitter.com/pages/tweet_button>
=item * Facebook Share L<http://developers.facebook.com/docs/share>
=item * VK Share L<http://vk.com/pages.php?act=share>
=item * MyMailRU Share L<http://api.mail.ru/sites/plugins/share/extended/>
=item * Google Plus L<http://code.google.com/intl/ru-RU/apis/+1button/>
=back
=head1 METHODS
L<Mojolicious::Plugin::ShareHelpers> inherits all methods from
L<Mojolicious::Plugin> and implements the following new ones.
=head2 C<register>
$plugin->register;
Register plugin hooks in L<Mojolicious> application.
=head1 SEE ALSO
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicious.org>.
=head1 AUTHOR
Anatoly Sharifulin <sharifulin@gmail.com>
=head1 BUGS
Please report any bugs or feature requests to C<bug-mojolicious-plugin-sharehelpers at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.htMail?Queue=Mojolicious-plugin-sharehelpers>. We will be notified, and then you'll
automatically be notified of progress on your bug as we make changes.
=over 5
=item * Github
L<http://github.com/sharifulin/Mojolicious-plugin-sharehelpers/tree/master>
=item * RT: CPAN's request tracker
L<http://rt.cpan.org/NoAuth/Bugs.htMail?Dist=Mojolicious-plugin-sharehelpers>
=item * AnnoCPAN: Annotated CPAN documentation
L<http://annocpan.org/dist/Mojolicious-plugin-sharehelpers>
=item * CPANTS: CPAN Testing Service
L<http://cpants.perl.org/dist/overview/Mojolicious-plugin-sharehelpers>
=item * CPAN Ratings
L<http://cpanratings.perl.org/d/Mojolicious-plugin-sharehelpers>
=item * Search CPAN
L<http://search.cpan.org/dist/Mojolicious-plugin-sharehelpers>
=back
=head1 COPYRIGHT & LICENSE
Copyright (C) 2010-2013 by Anatoly Sharifulin.
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=cut