Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add manual share links to answerboxes #232

Merged
merged 12 commits into from
Dec 26, 2021
Merged
2 changes: 1 addition & 1 deletion app/assets/stylesheets/components/_answerbox.scss
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
}

body:not(.cap-web-share) {
.answerbox__action[name="ab-share"] {
[name="ab-share"] {
display: none;
}
}
4 changes: 4 additions & 0 deletions app/helpers/social_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module SocialHelper
include SocialHelper::TwitterMethods
include SocialHelper::TumblrMethods
end
35 changes: 35 additions & 0 deletions app/helpers/social_helper/tumblr_methods.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require 'cgi'

module SocialHelper::TumblrMethods
def tumblr_title(answer)
asker = if answer.question.author_is_anonymous?
APP_CONFIG['anonymous_name']
else
answer.question.user.profile.safe_name
end

"#{asker} asked: #{answer.question.content}"
end

def tumblr_body(answer)
answer_url = show_user_answer_url(
id: answer.id,
username: answer.user.screen_name,
host: APP_CONFIG['hostname'],
protocol: (APP_CONFIG['https'] ? :https : :http)
)

"#{answer.content}\n\n[Smile or comment on the answer here](#{answer_url})"
end

def tumblr_share_url(answer)
answer_url = show_user_answer_url(
id: answer.id,
username: answer.user.screen_name,
host: APP_CONFIG['hostname'],
protocol: (APP_CONFIG['https'] ? :https : :http)
)

"https://www.tumblr.com/widgets/share/tool?shareSource=legacy&posttype=text&title=#{CGI.escape(tumblr_title(answer))}&url=#{CGI.escape(answer_url)}&caption=&content=#{CGI.escape(tumblr_body(answer))}"
end
end
37 changes: 37 additions & 0 deletions app/helpers/social_helper/twitter_methods.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require 'cgi'

module SocialHelper::TwitterMethods
include MarkdownHelper

def prepare_tweet(answer)
question_content = twitter_markdown answer.question.content.gsub(/\@(\w+)/, '\1')
original_question_length = question_content.length
answer_content = twitter_markdown answer.content
original_answer_length = answer_content.length
answer_url = show_user_answer_url(
id: answer.id,
username: answer.user.screen_name,
host: APP_CONFIG['hostname'],
protocol: (APP_CONFIG['https'] ? :https : :http)
)

parsed_tweet = { :valid => false }
tweet_text = ""

until parsed_tweet[:valid]
tweet_text = "#{question_content[0..122]}#{'…' if original_question_length > [123, question_content.length].min}" \
" — #{answer_content[0..123]}#{'…' if original_answer_length > [124, answer_content.length].min} #{answer_url}"

parsed_tweet = Twitter::TwitterText::Validation::parse_tweet(tweet_text)

question_content = question_content[0..-2]
answer_content = answer_content[0..-2]
end

tweet_text
end

def twitter_share_url(answer)
"https://twitter.com/intent/tweet?text=#{CGI.escape(prepare_tweet(answer))}"
end
end
13 changes: 3 additions & 10 deletions app/javascript/retrospring/features/answerbox/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import registerEvents from 'utilities/registerEvents';
import { createShareEvent } from './share';
import { on } from 'retrospring/utilities/on';
import { shareEventHandler } from './share';

export default (): void => {
if ('share' in navigator) {
document.body.classList.add('cap-web-share');
const entries: NodeList = document.querySelectorAll('.answerbox:not(.js-initialized)');

entries.forEach((element: HTMLElement) => {
registerEvents([
{ type: 'click', target: element.querySelector('[name=ab-share]'), handler: createShareEvent(element) }
]);

element.classList.add('js-initialized');
});
on('click', '[name=ab-share]', shareEventHandler);
}
}
13 changes: 7 additions & 6 deletions app/javascript/retrospring/features/answerbox/share.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import noop from 'utilities/noop';

export function createShareEvent(answerbox: HTMLElement): () => void {
return function (): void {
navigator.share({
url: answerbox.querySelector<HTMLAnchorElement>('.answerbox__answer-date > a, a.answerbox__permalink').href
})
export function shareEventHandler(event: Event): void {
event.preventDefault();
const answerbox = (event.target as HTMLElement).closest('.answerbox');

navigator.share({
url: answerbox.querySelector<HTMLAnchorElement>('.answerbox__answer-date > a, a.answerbox__permalink').href
})
.then(noop)
.catch(noop)
}
}
18 changes: 3 additions & 15 deletions app/models/services/tumblr.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
class Services::Tumblr < Service
include Rails.application.routes.url_helpers
include MarkdownHelper
include SocialHelper::TumblrMethods

def provider
"tumblr"
Expand All @@ -23,21 +22,10 @@ def client
end

def create_post(answer)
answer_url = show_user_answer_url(
id: answer.id,
username: answer.user.screen_name,
host: APP_CONFIG['hostname'],
protocol: (APP_CONFIG['https'] ? :https : :http)
)
asker = if answer.question.author_is_anonymous?
APP_CONFIG['anonymous_name']
else
answer.question.user.profile.display_name.blank? ? answer.question.user.screen_name : answer.question.user.profile.display_name
end
client.text(
self.uid,
title: "#{asker} asked: #{answer.question.content}",
body: "#{answer.content}\n\n[Smile or comment on the answer here](#{answer_url})",
title: tumblr_title(answer),
body: tumblr_body(answer),
format: 'markdown',
tweet: 'off'
)
Expand Down
30 changes: 1 addition & 29 deletions app/models/services/twitter.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class Services::Twitter < Service
include Rails.application.routes.url_helpers
include MarkdownHelper
include SocialHelper::TwitterMethods

def provider
"twitter"
Expand All @@ -25,32 +25,4 @@ def client
def post_tweet(answer)
client.update! prepare_tweet(answer)
end

def prepare_tweet(answer)
question_content = twitter_markdown answer.question.content.gsub(/\@(\w+)/, '\1')
original_question_length = question_content.length
answer_content = twitter_markdown answer.content
original_answer_length = answer_content.length
answer_url = show_user_answer_url(
id: answer.id,
username: answer.user.screen_name,
host: APP_CONFIG['hostname'],
protocol: (APP_CONFIG['https'] ? :https : :http)
)

parsed_tweet = { :valid => false }
tweet_text = ""

until parsed_tweet[:valid]
tweet_text = "#{question_content[0..122]}#{'…' if original_question_length > [123, question_content.length].min}" \
" — #{answer_content[0..123]}#{'…' if original_answer_length > [124, answer_content.length].min} #{answer_url}"

parsed_tweet = Twitter::TwitterText::Validation::parse_tweet(tweet_text)

question_content = question_content[0..-2]
answer_content = answer_content[0..-2]
end

tweet_text
end
end
14 changes: 12 additions & 2 deletions app/views/answerbox/_actions.haml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,18 @@
%button.btn.btn-link.answerbox__action{ type: :button, name: 'ab-comments', data: { a_id: a.id, state: :hidden } }
%i.fa.fa-fw.fa-comments
%span{ id: "ab-comment-count-#{a.id}" }= a.comment_count
%button.btn.btn-link.answerbox__action{ type: :button, name: 'ab-share' }
%i.fa.fa-fw.fa-share-alt{ title: 'Share' }
.btn-group
%button.btn.btn-link.answerbox__action{ data: { toggle: :dropdown }, aria: { expanded: false } }
%i.fa.fa-fw.fa-share-alt{ title: 'Share' }
.dropdown-menu.dropdown-menu-right{ role: :menu }
%a.dropdown-item{ href: twitter_share_url(a), target: '_blank' }
%i.fa.fa-fw.fa-twitter
Share on Twitter
%a.dropdown-item{ href: tumblr_share_url(a), target: '_blank' }
%i.fa.fa-fw.fa-tumblr
Share on Tumblr
%a.dropdown-item{ href: '#', name: 'ab-share' }
Share on other apps...
- if user_signed_in?
.btn-group
%button.btn.btn-default.btn-sm.dropdown-toggle{ data: { toggle: :dropdown }, aria: { expanded: false } }
Expand Down
50 changes: 50 additions & 0 deletions spec/helpers/social_helper/tumblr_methods_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

require 'rails_helper'

describe SocialHelper::TumblrMethods, :type => :helper do
let(:user) { FactoryBot.create(:user) }
let(:answer) { FactoryBot.create(:answer, user: user,
content: 'aaaa',
question_content: 'q') }

describe '#tumblr_title' do
context 'Asker is anonymous' do
subject { tumblr_title(answer) }

it 'should return a proper title' do
expect(subject).to eq('Anonymous asked: q')
end
end

context 'Asker is known' do
before do
@user = FactoryBot.create(:user)
answer.question.user = @user
answer.question.author_is_anonymous = false
end

subject { tumblr_title(answer) }

it 'should return a proper title' do
expect(subject).to eq("#{answer.question.user.profile.display_name} asked: q")
end
end
end

describe '#tumblr_body' do
subject { tumblr_body(answer) }

it 'should return a proper body' do
expect(subject).to eq("aaaa\n\n[Smile or comment on the answer here](https://justask.rrerr.net/#{answer.user.screen_name}/a/#{answer.id})")
end
end

describe '#tumblr_share_url' do
subject { tumblr_share_url(answer) }

it 'should return a proper share link' do
expect(subject).to eq("https://www.tumblr.com/widgets/share/tool?shareSource=legacy&posttype=text&title=#{CGI.escape(tumblr_title(answer))}&url=#{CGI.escape("https://justask.rrerr.net/#{answer.user.screen_name}/a/#{answer.id}")}&caption=&content=#{CGI.escape(tumblr_body(answer))}")
end
end
end
43 changes: 43 additions & 0 deletions spec/helpers/social_helper/twitter_methods_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

require 'rails_helper'

describe SocialHelper::TwitterMethods, :type => :helper do
let(:user) { FactoryBot.create(:user) }
let(:answer) { FactoryBot.create(:answer, user: user,
content: 'a' * 255,
question_content: 'q' * 255) }

describe '#prepare_tweet' do
context 'when the question and answer need to be shortened' do
subject { prepare_tweet(answer) }

it 'should return a properly formatted tweet' do
expect(subject).to eq("#{'q' * 123}… — #{'a' * 124}… https://justask.rrerr.net/#{user.screen_name}/a/#{answer.id}")
end
end

context 'when the question and answer are short' do
before do
answer.question.content = 'Why are raccoons so good?'
answer.question.save!
answer.content = 'Because they are good cunes.'
answer.save!
end

subject { prepare_tweet(answer) }

it 'should return a properly formatted tweet' do
expect(subject).to eq("#{answer.question.content} — #{answer.content} https://justask.rrerr.net/#{user.screen_name}/a/#{answer.id}")
end
end
end

describe '#twitter_share_url' do
subject { twitter_share_url(answer) }

it 'should return a proper share link' do
expect(subject).to eq("https://twitter.com/intent/tweet?text=#{CGI.escape(prepare_tweet(answer))}")
end
end
end