diff --git a/Gemfile b/Gemfile index e624a1f7..1aed033a 100644 --- a/Gemfile +++ b/Gemfile @@ -209,6 +209,9 @@ gem 'sprockets-rails' # for multiple speakers select on proposal/event forms gem 'selectize-rails' +# event social sharing bootstrap buttons +gem 'bootstrap-social-rails' + # Nokogiri < 1.8.1 is subject to: # CVE-2017-0663, CVE-2017-7375, CVE-2017-7376, CVE-2017-9047, CVE-2017-9048, # CVE-2017-9049, CVE-2017-9050 diff --git a/Gemfile.lock b/Gemfile.lock index 0f64b0e8..13cf7aa7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -86,6 +86,8 @@ GEM bootstrap-sass (3.3.4.1) autoprefixer-rails (>= 5.0.0.1) sass (>= 3.2.19) + bootstrap-social-rails (4.12.0) + railties (>= 3.1) bootstrap-switch-rails (3.0.2) bootstrap3-datetimepicker-rails (3.0.3) momentjs-rails (>= 2.8.1) @@ -584,6 +586,7 @@ DEPENDENCIES axlsx! axlsx_rails bootstrap-sass (~> 3.3.4.1) + bootstrap-social-rails bootstrap-switch-rails (~> 3.0.0) bootstrap3-datetimepicker-rails (~> 3.0.2) byebug diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index b347821b..9ca2cfb4 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -25,6 +25,7 @@ //= require osem-dashboard //= require ahoy //= require jquery-smooth-scroll +//= require jquery.prettySocial //= require trianglify //= require tinycolor //= require bootstrap-markdown diff --git a/app/assets/javascripts/jquery.prettySocial.js b/app/assets/javascripts/jquery.prettySocial.js new file mode 100644 index 00000000..68d31bde --- /dev/null +++ b/app/assets/javascripts/jquery.prettySocial.js @@ -0,0 +1,148 @@ +/** + * jQuery prettySocial: Use custom social share buttons + * Author: Sonny T. , sonnyt.com + */ + +(function ($) { + 'use strict'; + + $.fn.prettySocial = function () { + /** + * Supported social sites + * @type {Object} + */ + var _sites = { + pinterest: { + url: 'http://pinterest.com/pin/create/button/?url={{url}}&media={{media}}&description={{description}}', + popup: { + width: 685, + height: 500 + } + }, + facebook: { + url: 'https://www.facebook.com/sharer/sharer.php?s=100&p[title]={{title}}&p[summary]={{description}}&p[url]={{url}}&p[images][0]={{media}}', + popup: { + width: 626, + height: 436 + } + }, + twitter: { + url: 'https://twitter.com/share?url={{url}}&via={{via}}&text={{description}}', + popup: { + width: 685, + height: 500 + } + }, + googleplus: { + url: 'https://plus.google.com/share?url={{url}}', + popup: { + width: 600, + height: 600 + } + }, + linkedin: { + url: 'https://www.linkedin.com/shareArticle?mini=true&url={{url}}&title={{title}}&summary={{description}}+&source={{via}}', + popup: { + width: 600, + height: 600 + } + } + }, + + /** + * Pop-up window + * This method is only used on desktop browsers + * @param {Object} site Selected social site + * @param {String} url Fixed URL to open + */ + _popup = function (site, url) { + // center window + var left = (window.innerWidth/2) - (site.popup.width/2), + top = (window.innerHeight/2) - (site.popup.height/2); + + return window.open(url, '', 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=' + site.popup.width + ', height=' + site.popup.height + ', top=' + top + ', left=' + left); + }, + + /** + * Prepare link based on social sites + * @param {Object} site Selected social site + * @param {Object} link Link with variables + * @return {String} Polished link based on the social site template + */ + _linkFix = function (site, link) { + // replace template url + var url = site.url.replace(/{{url}}/g, encodeURIComponent(link.url)) + .replace(/{{title}}/g, encodeURIComponent(link.title)) + .replace(/{{description}}/g, encodeURIComponent(link.description)) + .replace(/{{media}}/g, encodeURIComponent(link.media)) + .replace(/{{via}}/g, encodeURIComponent(link.via)); + + return url; + }; + + return this.each(function() { + + // declare $(this) as variable + var $this = $(this); + + // link type + var type = $this.data('type'), + + // set site + site = _sites[type] || null; + + // check if social site is selected + if (!site) { + $.error('Social site is not set.'); + } + + // gather link info + var link = { + url: $this.data('url') || '', + title: $this.data('title') || '', + description: $this.data('description') || '', + media: $this.data('media') || '', + via: $this.data('via') || '' + }; + + // prepare link + var url = _linkFix(site, link); + + // if not, set click trigger + if (navigator.userAgent.match(/Android|IEMobile|BlackBerry|iPhone|iPad|iPod|Opera Mini/i)) { + $this + .bind('touchstart', function (e) { + if(e.originalEvent.touches.length > 1) { + return; + } + + $this.data('touchWithoutScroll', true); + }) + .bind('touchmove', function () { + $this.data('touchWithoutScroll', false); + + return; + }).bind('touchend', function (e) { + e.preventDefault(); + + var touchWithoutScroll = $this.data('touchWithoutScroll'); + + if (e.originalEvent.touches.length > 1 || !touchWithoutScroll) { + return; + } + + // call popup window + _popup(site, url); + }); + } else { + $this.bind('click', function (e) { + e.preventDefault(); + + // call popup window + _popup(site, url); + }); + } + }); + }; + +})(jQuery); diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index c95bbb87..1ddd1329 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -18,4 +18,5 @@ *= require osem-navbar *= require selectize *= require selectize.bootstrap3 + *= require bootstrap-social */ diff --git a/app/assets/stylesheets/osem.css.scss b/app/assets/stylesheets/osem.css.scss index bbcabc44..44cf0dad 100644 --- a/app/assets/stylesheets/osem.css.scss +++ b/app/assets/stylesheets/osem.css.scss @@ -115,3 +115,29 @@ p.comment-body { float: right; } } + +// social share menu items +.social-share ul { + float: right; + list-style: none outside none; + margin: 0; + min-width: 20px; + padding: 0; +} + +.social-share { + min-width: 50px; +} + +.social-share li { + display: block; + font-size: 18px; + list-style: none outside none; + margin-bottom: 2px; + margin-left: 3px; + margin-top: 2px; +} + +.social-share > li > a { + color: white +} diff --git a/app/helpers/shareable_helper.rb b/app/helpers/shareable_helper.rb new file mode 100644 index 00000000..b5109cb5 --- /dev/null +++ b/app/helpers/shareable_helper.rb @@ -0,0 +1,15 @@ +module ShareableHelper + def get_shareable_title(event) + "Watching #{event.title} by #{event.speaker_names}" + end + + def get_shareable_url(event, conference) + url_for(conference_program_proposal_path(conference.short_title, event.id)) + end + + HANDLE_REGEX=/((https?:\/\/)?(www\.)?twitter\.com\/)?(@|#!\/)?([A-Za-z0-9_]{1,15})(\/([-a-z]{1,20}))?/ + def get_twitter_handle(event) + twitter = event.program.conference.contact.twitter + return HANDLE_REGEX.match(twitter)[5] unless twitter.blank? + end +end diff --git a/app/views/proposals/_share_menu.haml b/app/views/proposals/_share_menu.haml new file mode 100644 index 00000000..dfb3da99 --- /dev/null +++ b/app/views/proposals/_share_menu.haml @@ -0,0 +1,17 @@ +.btn-group + %button.btn.btn-info.dropdown-toggle.share{href: '#', data: {toggle: 'dropdown'}} + %i.fa.fa-share-alt + %span.caret + %ul.dropdown-menu.social-share + %li + = link_to "#", class: "btn btn-social-icon btn-twitter prettySocial", data: {type: 'twitter', url: request.original_url, description: get_shareable_title(@event).truncate(120), via: get_twitter_handle(@event)} do + %i.fa.fa-twitter + %li + = link_to "#", class: "btn btn-social-icon btn-facebook prettySocial", data: {type: 'facebook', url: request.original_url, description: @event.description, title: get_shareable_title(@event) } do + %i.fa.fa-facebook + %li + = link_to "#", class: "btn btn-social-icon btn-google prettySocial", data: {type: 'googleplus', url: request.original_url, description: get_shareable_title(@event), media: nil} do + %i.fa.fa-google + %li + = link_to "#", class: "btn btn-social-icon btn-linkedin prettySocial", data: {type: 'linkedin', url: request.original_url, description: @event.description} do + %i.fa.fa-linkedin \ No newline at end of file diff --git a/app/views/proposals/show.html.haml b/app/views/proposals/show.html.haml index 99f2d49e..bd7e9b6e 100644 --- a/app/views/proposals/show.html.haml +++ b/app/views/proposals/show.html.haml @@ -16,7 +16,27 @@ %br %small = @event.subtitle - .btn-group.pull-right + + .row.pull-right + - if @event.scheduled? + .btn-group + %button.btn.btn-info.dropdown-toggle.share{href: '#', data: {toggle: 'dropdown'}} + %i.fa.fa-share-alt + %span.caret + %ul.dropdown-menu.social-share + %li + = link_to "#", class: "btn btn-social-icon btn-twitter prettySocial", data: {type: 'twitter', url: request.original_url, description: get_shareable_title(@event).truncate(120), via: get_twitter_handle(@event)} do + %i.fa.fa-twitter + %li + = link_to "#", class: "btn btn-social-icon btn-facebook prettySocial", data: {type: 'facebook', url: request.original_url, description: @event.description, title: get_shareable_title(@event) } do + %i.fa.fa-facebook + %li + = link_to "#", class: "btn btn-social-icon btn-google prettySocial", data: {type: 'googleplus', url: request.original_url, description: get_shareable_title(@event), media: nil} do + %i.fa.fa-google + %li + = link_to "#", class: "btn btn-social-icon btn-linkedin prettySocial", data: {type: 'linkedin', url: request.original_url, description: @event.description} do + %i.fa.fa-linkedin + .btn-group - if can? :update, @event = link_to 'Registrations', registrations_conference_program_proposal_path(@conference.short_title, @event), class: 'btn btn-mini btn-success' - if can? :edit, @event @@ -105,6 +125,7 @@ %dt Requires Registration: %dd = link_to "Yes (#{registered_text(@event)})", new_conference_conference_registration_path(@conference.short_title), class: 'btn btn-xs btn-danger', disabled: !@event.registration_possible? + - if concurrent_events(@event).present? .col-md-12 %hr @@ -122,3 +143,8 @@ %dt Room: %dd = event.room.name + +:javascript + $(function () { + $('.prettySocial').prettySocial(); + })