Merge pull request #232 from Retrospring/feature/sharing

Add manual share links to answerboxes
This commit is contained in:
Karina Kwiatek 2021-12-26 23:53:02 +01:00 committed by GitHub
commit 1ba99af4ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 196 additions and 63 deletions

View File

@ -80,7 +80,7 @@
}
body:not(.cap-web-share) {
.answerbox__action[name="ab-share"] {
[name="ab-share"] {
display: none;
}
}

View File

@ -0,0 +1,4 @@
module SocialHelper
include SocialHelper::TwitterMethods
include SocialHelper::TumblrMethods
end

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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)
}
}

View File

@ -1,6 +1,5 @@
class Services::Tumblr < Service
include Rails.application.routes.url_helpers
include MarkdownHelper
include SocialHelper::TumblrMethods
def provider
"tumblr"
@ -23,21 +22,10 @@ class Services::Tumblr < Service
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'
)

View File

@ -1,6 +1,6 @@
class Services::Twitter < Service
include Rails.application.routes.url_helpers
include MarkdownHelper
include SocialHelper::TwitterMethods
def provider
"twitter"
@ -25,32 +25,4 @@ class Services::Twitter < Service
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

View File

@ -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 } }

View File

@ -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

View File

@ -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