Merge pull request #232 from Retrospring/feature/sharing
Add manual share links to answerboxes
This commit is contained in:
commit
1ba99af4ce
|
@ -80,7 +80,7 @@
|
|||
}
|
||||
|
||||
body:not(.cap-web-share) {
|
||||
.answerbox__action[name="ab-share"] {
|
||||
[name="ab-share"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
module SocialHelper
|
||||
include SocialHelper::TwitterMethods
|
||||
include SocialHelper::TumblrMethods
|
||||
end
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 } }
|
||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue