social_linker 0.1.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +56 -2
- data/lib/social_linker.rb +10 -178
- data/lib/social_linker/railtie.rb +9 -0
- data/lib/social_linker/subject.rb +248 -0
- data/lib/social_linker/version.rb +1 -1
- data/lib/social_linker/view_helpers.rb +65 -0
- data/social_linker.gemspec +3 -3
- metadata +12 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8d3e93ca4d88de3fdd12f5d738a9af7e7a68627
|
4
|
+
data.tar.gz: 43d0897a189edf1e5ebf1ac4d41d199ef067759a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4e08bec4223c51baa898f72185818a62139d29d57847624ca0dd7ee4112ba92fee5269be271e751eeee40188d45f04f139c19d06e5cf97a6ae99f7fc05a6fe3
|
7
|
+
data.tar.gz: 762b1cf66474bdb86821c514564c9ad2b584d28fb3676faf58b29a61a414c35ed2d6c9faed05df16afa94d26532e76d5837799ee49ce6c7424ab0cfbb43ea6ab
|
data/README.md
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
# SocialLinker
|
2
2
|
|
3
|
-
|
3
|
+
[![Build Status](https://travis-ci.org/murb/social_linker.svg?branch=master)](https://travis-ci.org/murb/social_linker)
|
4
|
+
|
5
|
+
SocialLinker is able to generate the most common share links for you, without depending on JavaScript.
|
6
|
+
You should use generated links, instead of the share buttons provided by the platforms themselves, to
|
7
|
+
protect your user's privacy, and this gem makes it easy for you to do so.
|
8
|
+
|
9
|
+
And when using Rails, SocialLinker also solves the tedious job of getting the meta tags right.
|
10
|
+
Because once you've set the SocialLinker::Subject correctly, you've also got the right ingredients
|
11
|
+
for the perfect meta keywords & description, open graph variables etc.
|
4
12
|
|
5
13
|
## Installation
|
6
14
|
|
@@ -38,6 +46,18 @@ Which will deliver you the following url:
|
|
38
46
|
|
39
47
|
mailto:emailaddress?subject=Example%20website&body=Example.com%20is%20the%20typical%20URL%20you%20would%20want%20to%20use%20in%20explanations%20anyway.%0A%0Ahttp%3A%2F%2Fexample.com%2F
|
40
48
|
|
49
|
+
Currently support is available for the following ways of sharing:
|
50
|
+
|
51
|
+
:email
|
52
|
+
:facebook
|
53
|
+
:facebook_native
|
54
|
+
:twitter
|
55
|
+
:twitter_native
|
56
|
+
:pinterest
|
57
|
+
:google
|
58
|
+
:linkedin
|
59
|
+
:whatsapp
|
60
|
+
|
41
61
|
Or to save you the copy-paste:
|
42
62
|
|
43
63
|
[TestMailLink](mailto:emailaddress?subject=Example%20website&body=Example.com%20is%20the%20typical%20URL%20you%20would%20want%20to%20use%20in%20explanations%20anyway.%0A%0Ahttp%3A%2F%2Fexample.com%2F)
|
@@ -51,7 +71,41 @@ The supported options are:
|
|
51
71
|
* title
|
52
72
|
* tags
|
53
73
|
|
54
|
-
I've tried to map them as good as possible to the different share tools. Sometimes by combining several values. You may also pass along link-specific parameters such as `:
|
74
|
+
I've tried to map them as good as possible to the different share tools. Sometimes by combining several values. You may also pass along link-specific parameters such as `:hashtags`, so no 2-tag long string is generated from the list of tags.
|
75
|
+
|
76
|
+
To conclude: a very complete instantiation:
|
77
|
+
|
78
|
+
@subject = SocialLinker::Subject.new(
|
79
|
+
title: "title",
|
80
|
+
url: "https://murb.nl/blog",
|
81
|
+
image_url: "https://murb.nl/image.jpg",
|
82
|
+
image_type: 'image/jpeg',
|
83
|
+
summary: "short summary",
|
84
|
+
tags: ["key1", "key2", "key3"],
|
85
|
+
twitter_username: 'murb'
|
86
|
+
)
|
87
|
+
|
88
|
+
## UTM Campaign parameters
|
89
|
+
|
90
|
+
By default [utm campaign parameters](https://support.google.com/analytics/answer/1033863?hl=en) are added when they are not present. You can turn this off by passing the option: `utm_parameters: false`.
|
91
|
+
|
92
|
+
## Rails helpers
|
93
|
+
|
94
|
+
When using Ruby on Rails a few helpers have been created.
|
95
|
+
|
96
|
+
### OpenGraph, Twitter, and HTML meta-data:
|
97
|
+
|
98
|
+
Just set the following, which should give you a reasonable default.
|
99
|
+
|
100
|
+
header_meta_tags(@subject, {
|
101
|
+
site_title_postfix: "your sitename" # optional
|
102
|
+
})
|
103
|
+
|
104
|
+
## TODO
|
105
|
+
|
106
|
+
* Render sharelink helpers (including SVG icons)
|
107
|
+
* [Further improvement] include even [javascript timeout workarounds](http://stackoverflow.com/questions/7231085/how-to-fall-back-to-marketplace-when-android-custom-url-scheme-not-handled)
|
108
|
+
* More share methods!
|
55
109
|
|
56
110
|
## Development
|
57
111
|
|
data/lib/social_linker.rb
CHANGED
@@ -1,179 +1,11 @@
|
|
1
1
|
require "social_linker/version"
|
2
|
-
require "
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
# generic options
|
13
|
-
SHARE_TEMPLATES = {
|
14
|
-
email: {
|
15
|
-
base: "mailto:emailaddress?",
|
16
|
-
params: [:subject,:body,:cc,:bcc]
|
17
|
-
},
|
18
|
-
pinterest: {
|
19
|
-
base: "https://pinterest.com/pin/create/button/?",
|
20
|
-
params: [:url, :media, :description]
|
21
|
-
},
|
22
|
-
linkedin: {
|
23
|
-
base: "https://www.linkedin.com/shareArticle?mini=true&",
|
24
|
-
params: [:url, :title, :summary, :source]
|
25
|
-
},
|
26
|
-
google: {
|
27
|
-
base: "https://plus.google.com/share?",
|
28
|
-
params: [:url]
|
29
|
-
},
|
30
|
-
twitter: {
|
31
|
-
base: "https://twitter.com/home?",
|
32
|
-
params: [:status]
|
33
|
-
},
|
34
|
-
facebook: {
|
35
|
-
base: "https://www.facebook.com/sharer/sharer.php?",
|
36
|
-
params: [:u]
|
37
|
-
}
|
38
|
-
|
39
|
-
}
|
40
|
-
|
41
|
-
# convert an array of strings to a Twitter-like hashtag-string
|
42
|
-
#
|
43
|
-
# @param [Array] tags to be converted to string
|
44
|
-
# @return [String] containing a Twitter-style tag-list
|
45
|
-
def hashtag_string(tags)
|
46
|
-
string = (tags and tags.count > 0) ? "##{tags.collect{|a| a.to_s.strip.gsub('#','')}.join(" #")}" : nil
|
47
|
-
if string and string.length > 60
|
48
|
-
puts "WARNING: string of tags longer than adviced lenght of 60 characters: #{string}"
|
49
|
-
end
|
50
|
-
string
|
51
|
-
end
|
52
|
-
|
53
|
-
# default url accessor
|
54
|
-
#
|
55
|
-
# @return String with url
|
56
|
-
def url
|
57
|
-
@options[:url]
|
58
|
-
end
|
59
|
-
|
60
|
-
# default title accessor
|
61
|
-
# @return String with title
|
62
|
-
def title
|
63
|
-
@options[:title]
|
64
|
-
end
|
65
|
-
|
66
|
-
# default summary accessor
|
67
|
-
# @return String with summary
|
68
|
-
def summary
|
69
|
-
@options[:summary]
|
70
|
-
end
|
71
|
-
|
72
|
-
# default media accessor
|
73
|
-
# @return String with media-url
|
74
|
-
def media
|
75
|
-
@options[:media]
|
76
|
-
end
|
77
|
-
|
78
|
-
# default tags accessor
|
79
|
-
# @return Array<String> with tags
|
80
|
-
def tags
|
81
|
-
@options[:media]
|
82
|
-
end
|
83
|
-
|
84
|
-
# puts quotes around a string
|
85
|
-
# @return [String] now with quotes.
|
86
|
-
def quote_string(string)
|
87
|
-
"“#{string}”" if string and string.to_s.strip != ""
|
88
|
-
end
|
89
|
-
|
90
|
-
# strips a string to the max length taking into account quoting
|
91
|
-
# @param [String] string that is about to be shortened
|
92
|
-
# @param [Integer] max_length of the string to be shortened (default 100)
|
93
|
-
# @return [String] shortened to the max lenght
|
94
|
-
def strip_string(string, max_length=100)
|
95
|
-
if string and string.length > max_length
|
96
|
-
elipsis = "…"
|
97
|
-
if string[-1] == "”"
|
98
|
-
elipsis = "#{elipsis}”"
|
99
|
-
end
|
100
|
-
max_char = max_length-1-elipsis.length
|
101
|
-
string = string[0..max_char]+elipsis
|
102
|
-
end
|
103
|
-
string
|
104
|
-
end
|
105
|
-
|
106
|
-
# Initialize the SocialLinker::Subject
|
107
|
-
#
|
108
|
-
# options accepts:
|
109
|
-
# * tags
|
110
|
-
# * url
|
111
|
-
# * title
|
112
|
-
# * image_url
|
113
|
-
#
|
114
|
-
# @params [hash] options as defined above
|
115
|
-
def initialize(options={})
|
116
|
-
@options = options
|
117
|
-
@options[:u] = @options[:url] unless options[:u]
|
118
|
-
@options[:description] = @options[:summary] unless options[:description]
|
119
|
-
@options[:summary] = @options[:description] unless options[:summary]
|
120
|
-
@options[:title] = "#{ strip_string(@options[:summary], 120) }" unless options[:title]
|
121
|
-
@options[:description] = @options[:title] unless @options[:description]
|
122
|
-
@options[:subject] = @options[:title] unless @options[:subject]
|
123
|
-
@options[:url] = @options[:media] unless @options[:url]
|
124
|
-
|
125
|
-
unless @options[:status]
|
126
|
-
hash_string = @options[:tags] ? hashtag_string(@options[:tags][0..2]) : ""
|
127
|
-
max_length = 140 - ((hash_string ? hash_string.length : 0) + 12 + 4) #hashstring + url length (shortened) + spaces
|
128
|
-
@options[:status] = "#{quote_string(strip_string(@options[:title],max_length))} #{@options[:url]} #{hash_string}"
|
129
|
-
end
|
130
|
-
|
131
|
-
unless @options[:body]
|
132
|
-
@options[:body] = ""
|
133
|
-
@options[:body] += "#{@options[:summary]}\n" if @options[:summary]
|
134
|
-
@options[:body] += "\n#{@options[:url]}\n" if @options[:url]
|
135
|
-
@options[:body] += "\n#{@options[:description]}\n" if @options[:summary] != @options[:description] and @options[:description]
|
136
|
-
@options[:body] += "\n#{@options[:media]}\n" if @options[:media] != @options[:url] and @options[:media]
|
137
|
-
@options[:body] += "\n\n#{hashtag_string(@options[:tags])}" if @options[:tags]
|
138
|
-
@options[:body] = nil if @options[:body].strip == ""
|
139
|
-
end
|
140
|
-
|
141
|
-
@options.each do |k,v|
|
142
|
-
@options[k] = v.strip if v and v.is_a? String
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
# Returns the given options, extended with the (derived) defaults
|
147
|
-
#
|
148
|
-
# @return Hash with the options
|
149
|
-
def options
|
150
|
-
@options
|
151
|
-
end
|
152
|
-
|
153
|
-
# Generates a share link for each of the predefined platforms in the `SHARE_TEMPLATES` constant
|
154
|
-
#
|
155
|
-
# @param [Symbol] platform to generate the link for
|
156
|
-
def share_link(platform)
|
157
|
-
share_options = SHARE_TEMPLATES[platform]
|
158
|
-
raise "No share template defined" unless share_options
|
159
|
-
params = options.keys & share_options[:params]
|
160
|
-
if params.include?(:description) and !params.include?(:title)
|
161
|
-
@options[:description] = @options[:title]
|
162
|
-
end
|
163
|
-
|
164
|
-
return share_options[:base]+params.collect{|k| "#{k}=#{url_encode(options[k])}"}.join('&')
|
165
|
-
end
|
166
|
-
|
167
|
-
# Catches method missing and tries to resolve them in either an appropriate share link or option value
|
168
|
-
def method_missing(m,*args)
|
169
|
-
share_link_matcher = m.to_s.match(/([a-z]*)_share_link/)
|
170
|
-
if share_link_matcher
|
171
|
-
return share_link(share_link_matcher[1].to_sym)
|
172
|
-
elsif options[m]
|
173
|
-
return options[m]
|
174
|
-
else
|
175
|
-
super
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
2
|
+
require "social_linker/subject"
|
3
|
+
require 'social_linker/railtie' if defined?(Rails)
|
4
|
+
# require "ERB"
|
5
|
+
# include ERB::Util
|
6
|
+
#
|
7
|
+
# module SocialLinker
|
8
|
+
#
|
9
|
+
# # The main class of SocialLinker is the `SocialLinker::Subject`-class.
|
10
|
+
#
|
11
|
+
# end
|
@@ -0,0 +1,248 @@
|
|
1
|
+
module SocialLinker
|
2
|
+
class Subject
|
3
|
+
|
4
|
+
# Constant defining how the different share-url's look like and their parameters;
|
5
|
+
# the parameters can be set in the options directly, or will be derived from more
|
6
|
+
# generic options
|
7
|
+
SHARE_TEMPLATES = {
|
8
|
+
email: {
|
9
|
+
base: "mailto:emailaddress?",
|
10
|
+
params: [:subject,:body,:cc,:bcc]
|
11
|
+
},
|
12
|
+
pinterest: {
|
13
|
+
base: "https://pinterest.com/pin/create/button/?",
|
14
|
+
params: {url: :url, media: :media, description: :title}
|
15
|
+
},
|
16
|
+
linkedin: {
|
17
|
+
base: "https://www.linkedin.com/shareArticle?mini=true&",
|
18
|
+
params: [:url, :title, :summary, :source]
|
19
|
+
},
|
20
|
+
google: {
|
21
|
+
base: "https://plus.google.com/share?",
|
22
|
+
params: [:url]
|
23
|
+
},
|
24
|
+
twitter: {
|
25
|
+
base: "https://twitter.com/intent/tweet?",
|
26
|
+
params: {text: :tweet_text, via: :via, url: :url, hashtags: :hashtags}
|
27
|
+
},
|
28
|
+
twitter_native: {
|
29
|
+
base: "twitter://post?",
|
30
|
+
params: [:message]
|
31
|
+
},
|
32
|
+
facebook: {
|
33
|
+
base: "https://www.facebook.com/sharer/sharer.php?",
|
34
|
+
params: [:u]
|
35
|
+
},
|
36
|
+
facebook_native: {
|
37
|
+
base: "fb://publish/profile/me?",
|
38
|
+
params: [:text]
|
39
|
+
},
|
40
|
+
whatsapp: {
|
41
|
+
base: "whatsapp://send?",
|
42
|
+
params: [:text]
|
43
|
+
}
|
44
|
+
|
45
|
+
}
|
46
|
+
|
47
|
+
# convert an array of strings to a Twitter-like hashtag-string
|
48
|
+
#
|
49
|
+
# @param [Array] tags to be converted to string
|
50
|
+
# @return [String] containing a Twitter-style tag-list
|
51
|
+
def hashtag_string(tags)
|
52
|
+
if tags and tags.count > 0
|
53
|
+
tags = tags.collect{|a| camelize_tag_when_needed(a) }
|
54
|
+
string = "##{tags.collect{|a| a.to_s.strip.gsub('#','')}.join(" #")}"
|
55
|
+
if string and string.length > 60
|
56
|
+
puts "WARNING: string of tags longer than adviced lenght of 60 characters: #{string}"
|
57
|
+
end
|
58
|
+
string
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# single world tags don't need any processing, but tags consisting of different words do (before they can use in hashtags following convention)
|
63
|
+
#
|
64
|
+
# @param [String] tag to might need conversion
|
65
|
+
# @return [String] fixed tag
|
66
|
+
def camelize_tag_when_needed(tag)
|
67
|
+
tag = tag.to_s
|
68
|
+
tag.match(/\s/) ? tag.split(/\s/).collect{|a| a.capitalize}.join("") : tag
|
69
|
+
end
|
70
|
+
|
71
|
+
# default url accessor
|
72
|
+
#
|
73
|
+
# @return String with url
|
74
|
+
def url
|
75
|
+
@options[:url]
|
76
|
+
end
|
77
|
+
|
78
|
+
def utm_parameters
|
79
|
+
[nil, true].include?(@options[:utm_parameters]) ? true : false
|
80
|
+
end
|
81
|
+
|
82
|
+
def canonical_url
|
83
|
+
@options[:canonical_url]
|
84
|
+
end
|
85
|
+
|
86
|
+
# default title accessor
|
87
|
+
# @return String with title
|
88
|
+
def title
|
89
|
+
@options[:title]
|
90
|
+
end
|
91
|
+
|
92
|
+
# default summary accessor
|
93
|
+
# @return String with summary
|
94
|
+
def summary
|
95
|
+
@options[:summary]
|
96
|
+
end
|
97
|
+
|
98
|
+
# default media accessor
|
99
|
+
# @return String with media-url
|
100
|
+
def media
|
101
|
+
@options[:media]
|
102
|
+
end
|
103
|
+
|
104
|
+
# default tags accessor
|
105
|
+
# @return Array<String> with tags
|
106
|
+
def tags
|
107
|
+
@options[:tags] ? @options[:tags] : []
|
108
|
+
end
|
109
|
+
|
110
|
+
def hashtags
|
111
|
+
@options[:hashtags]
|
112
|
+
end
|
113
|
+
|
114
|
+
# puts quotes around a string
|
115
|
+
# @return [String] now with quotes.
|
116
|
+
def quote_string(string)
|
117
|
+
"“#{string}”" if string and string.to_s.strip != ""
|
118
|
+
end
|
119
|
+
|
120
|
+
# strips a string to the max length taking into account quoting
|
121
|
+
# @param [String] string that is about to be shortened
|
122
|
+
# @param [Integer] max_length of the string to be shortened (default 100)
|
123
|
+
# @return [String] shortened to the max lenght
|
124
|
+
def strip_string(string, max_length=100)
|
125
|
+
if string and string.length > max_length
|
126
|
+
elipsis = "…"
|
127
|
+
if string[-1] == "”"
|
128
|
+
elipsis = "#{elipsis}”"
|
129
|
+
end
|
130
|
+
max_char = max_length-1-elipsis.length
|
131
|
+
string = string[0..max_char]+elipsis
|
132
|
+
end
|
133
|
+
string
|
134
|
+
end
|
135
|
+
|
136
|
+
# Initialize the SocialLinker::Subject
|
137
|
+
#
|
138
|
+
# options accepts:
|
139
|
+
# * tags
|
140
|
+
# * url
|
141
|
+
# * title
|
142
|
+
# * image_url & image_type(image/jpeg, image/png)
|
143
|
+
# * ... and more often medium specific attributes...
|
144
|
+
#
|
145
|
+
# Note by default tracking parameters are added, turn this off by passing
|
146
|
+
# `utm_parameters: false`
|
147
|
+
#
|
148
|
+
# @params [Hash] options as defined above
|
149
|
+
def initialize(options={})
|
150
|
+
# basic option syncing
|
151
|
+
@options = options
|
152
|
+
@options[:u] = @options[:url] unless options[:u]
|
153
|
+
@options[:media] = @options[:image_url] unless options[:media]
|
154
|
+
@options[:description] = @options[:summary] unless options[:description]
|
155
|
+
@options[:summary] = @options[:description] unless options[:summary]
|
156
|
+
@options[:title] = "#{ strip_string(@options[:summary], 120) }" unless options[:title]
|
157
|
+
@options[:description] = @options[:title] unless @options[:description]
|
158
|
+
@options[:subject] = @options[:title] unless @options[:subject]
|
159
|
+
@options[:via] = @options[:twitter_username] unless @options[:via]
|
160
|
+
@options[:url] = @options[:media] unless @options[:url]
|
161
|
+
@options[:text] = "#{@options[:title]} #{@options[:url]}" unless @options[:text] #facebook & whatsapp native
|
162
|
+
@options[:canonical_url] = @options[:url]
|
163
|
+
if @options[:url] and utm_parameters
|
164
|
+
unless @options[:url].match /utm_source/
|
165
|
+
combine_with = @options[:url].match(/\?/) ? "&" : "?"
|
166
|
+
@options[:url] = "#{@options[:url]}#{combine_with}utm_source=<%=share_source%>"
|
167
|
+
end
|
168
|
+
unless @options[:url].match /utm_medium/
|
169
|
+
combine_with = "&"
|
170
|
+
@options[:url] = "#{@options[:url]}#{combine_with}utm_medium=share_link"
|
171
|
+
end
|
172
|
+
unless @options[:url].match /utm_campaign/
|
173
|
+
combine_with = "&"
|
174
|
+
@options[:url] = "#{@options[:url]}#{combine_with}utm_campaign=social"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
if @options[:tags]
|
178
|
+
@options[:tags].compact!
|
179
|
+
@options[:hashtags] = @options[:tags][0..1].collect{|a| camelize_tag_when_needed(a) }.join(",") if @options[:tags] and !@options[:hashtags]
|
180
|
+
@options[:hash_string] = @options[:tags] ? hashtag_string(@options[:tags][0..1]) : ""
|
181
|
+
end
|
182
|
+
unless @options[:tweet_text]
|
183
|
+
max_length = 140 - ((@options[:hash_string] ? @options[:hash_string].length : 0) + 12 + 4) #hashstring + url length (shortened) + spaces
|
184
|
+
@options[:tweet_text] = "#{quote_string(strip_string(@options[:title],max_length))}"
|
185
|
+
end
|
186
|
+
@options[:message] = [@options[:tweet_text],@options[:url],@options[:hash_string]].compact.join(" ") unless @options[:message]
|
187
|
+
@options[:status] = @options[:message] unless @options[:status]
|
188
|
+
unless @options[:body]
|
189
|
+
@options[:body] = ""
|
190
|
+
@options[:body] += "#{@options[:summary]}\n" if @options[:summary]
|
191
|
+
@options[:body] += "\n#{@options[:url]}\n" if @options[:url]
|
192
|
+
@options[:body] += "\n#{@options[:description]}\n" if @options[:summary] != @options[:description] and @options[:description]
|
193
|
+
@options[:body] += "\n#{@options[:media]}\n" if @options[:media] != @options[:url] and @options[:media]
|
194
|
+
@options[:body] += "\n\n#{hashtag_string(@options[:tags])}" if @options[:tags]
|
195
|
+
@options[:body] = nil if @options[:body].strip == ""
|
196
|
+
end
|
197
|
+
@options[:domain] = @options[:url].split(/\//)[0..2].join("/") if @options[:url] and !@options[:domain]
|
198
|
+
|
199
|
+
@options.each do |k,v|
|
200
|
+
@options[k] = v.strip if v and v.is_a? String
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# Returns the given options, extended with the (derived) defaults
|
205
|
+
#
|
206
|
+
# @return Hash with the options
|
207
|
+
def options
|
208
|
+
@options
|
209
|
+
end
|
210
|
+
|
211
|
+
# Generates a share link for each of the predefined platforms in the `SHARE_TEMPLATES` constant
|
212
|
+
#
|
213
|
+
# @param [Symbol] platform to generate the link for
|
214
|
+
def share_link(platform)
|
215
|
+
share_options = SHARE_TEMPLATES[platform]
|
216
|
+
raise "No share template defined" unless share_options
|
217
|
+
|
218
|
+
url_params = {}
|
219
|
+
share_options[:params].each do |k,v|
|
220
|
+
value_key = v||k #smartassery; v = nil for arrays
|
221
|
+
value = options[value_key]
|
222
|
+
if value and value.to_s.strip != ""
|
223
|
+
value = value.gsub('<%=share_source%>', platform.to_s)
|
224
|
+
url_params[k] = value
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
return share_options[:base]+url_params.collect{|k,v| "#{k}=#{url_encode(v)}"}.join('&')
|
229
|
+
end
|
230
|
+
|
231
|
+
def url_encode(v)
|
232
|
+
ERB::Util.url_encode(v)
|
233
|
+
end
|
234
|
+
|
235
|
+
# Catches method missing and tries to resolve them in either an appropriate share link or option value
|
236
|
+
def method_missing(m,*args)
|
237
|
+
share_link_matcher = m.to_s.match(/([a-z]*)_share_link/)
|
238
|
+
if share_link_matcher
|
239
|
+
return share_link(share_link_matcher[1].to_sym)
|
240
|
+
elsif options[m]
|
241
|
+
return options[m]
|
242
|
+
else
|
243
|
+
super
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module SocialLinker
|
2
|
+
module ViewHelpers
|
3
|
+
# renders a metatag
|
4
|
+
# param [String, Symbol] name (or property) (defaults to name, values starting with 'og:' (opengraph) will be using the property attribute)
|
5
|
+
# param [String, Symbol] content (the value for the name or the property)
|
6
|
+
# @returns [String, nil] nil is returned when the content is empty
|
7
|
+
def meta_tag(name, content)
|
8
|
+
name_or_property_section = name.start_with?("og:") ? "property=\"#{erb_sanitized(name)}\"" : "name=\"#{erb_sanitized(name)}\""
|
9
|
+
"<meta #{name_or_property_section} content=\"#{erb_sanitized(content)}\" />" if content and content != ""
|
10
|
+
end
|
11
|
+
|
12
|
+
def erb_sanitized(value)
|
13
|
+
if defined? Rails
|
14
|
+
h(value)
|
15
|
+
else
|
16
|
+
ERB::Util.h(value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# header_meta_tags renders the most important metatags based on the SocialLinker::Subject
|
21
|
+
# param [SocialLinker::Subject] the SocialLinker::Subject initialized as complete as possible
|
22
|
+
# param [Hash] options with site-defaults for `:site_title_postfix`, (e.g. article title - {site title postfix here}), `:domain` (the main url), `
|
23
|
+
def header_meta_tags subject, options={}
|
24
|
+
site_title_postfix = options[:site_title_postfix]
|
25
|
+
header_html = []
|
26
|
+
if subject
|
27
|
+
domain = options[:domain] || subject.options[:domain]
|
28
|
+
|
29
|
+
header_html << meta_tag("twitter:card", subject.media ? :summary_large_image : :summary)
|
30
|
+
header_html << meta_tag("twitter:site", subject.options[:twitter_username])
|
31
|
+
header_html << meta_tag("twitter:creator", subject.options[:twitter_username])
|
32
|
+
header_html << meta_tag("twitter:domain", domain)
|
33
|
+
|
34
|
+
if subject.url
|
35
|
+
header_html << meta_tag("og:url", subject.canonical_url)
|
36
|
+
header_html << "<link rel=\"canonical\" content=\"#{erb_sanitized(subject.canonical_url)}\" />"
|
37
|
+
end
|
38
|
+
|
39
|
+
header_html << meta_tag("keywords", subject.tags.join(" "))
|
40
|
+
header_html << meta_tag("description", subject.summary)
|
41
|
+
|
42
|
+
header_html << meta_tag("twitter:description", subject.summary)
|
43
|
+
header_html << meta_tag("og:description", subject.summary)
|
44
|
+
|
45
|
+
if subject.media
|
46
|
+
header_html << meta_tag("twitter:image:src", subject.media)
|
47
|
+
header_html << meta_tag("og:image", subject.media)
|
48
|
+
header_html << meta_tag("og:image:type", subject.options[:image_type])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
title = @title
|
53
|
+
title = subject.title if subject
|
54
|
+
site_title = [title, site_title_postfix].uniq.compact.join(" - ")
|
55
|
+
header_html << "<title>#{site_title}</title>"
|
56
|
+
header_html << meta_tag("twitter:title", title)
|
57
|
+
header_html << meta_tag("og:title", title)
|
58
|
+
|
59
|
+
header_html.compact!
|
60
|
+
header_html.join("\n") if header_html
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
data/social_linker.gemspec
CHANGED
@@ -20,7 +20,7 @@ Supported networks are: Twitter, Facebook, LinkedIn, Google+, Pinterest, and ema
|
|
20
20
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
21
21
|
spec.require_paths = ["lib"]
|
22
22
|
|
23
|
-
spec.add_development_dependency "bundler", "~> 1
|
24
|
-
spec.add_development_dependency "rake", "~>
|
25
|
-
spec.add_development_dependency "rspec", "~> 3
|
23
|
+
spec.add_development_dependency "bundler", "~> 1"
|
24
|
+
spec.add_development_dependency "rake", "~> 11 "
|
25
|
+
spec.add_development_dependency "rspec", "~> 3"
|
26
26
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: social_linker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.2'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- murb
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-09-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,42 +16,42 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1
|
19
|
+
version: '1'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1
|
26
|
+
version: '1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '11'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '11'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '3
|
47
|
+
version: '3'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '3
|
54
|
+
version: '3'
|
55
55
|
description: |-
|
56
56
|
Social linker generates share-links for the different social networks from a simple SocialLinker::Subject class.
|
57
57
|
|
@@ -73,7 +73,10 @@ files:
|
|
73
73
|
- bin/console
|
74
74
|
- bin/setup
|
75
75
|
- lib/social_linker.rb
|
76
|
+
- lib/social_linker/railtie.rb
|
77
|
+
- lib/social_linker/subject.rb
|
76
78
|
- lib/social_linker/version.rb
|
79
|
+
- lib/social_linker/view_helpers.rb
|
77
80
|
- social_linker.gemspec
|
78
81
|
homepage: https://murb.nl/blog?tags=social_linker
|
79
82
|
licenses:
|
@@ -95,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
98
|
version: '0'
|
96
99
|
requirements: []
|
97
100
|
rubyforge_project:
|
98
|
-
rubygems_version: 2.
|
101
|
+
rubygems_version: 2.5.1
|
99
102
|
signing_key:
|
100
103
|
specification_version: 4
|
101
104
|
summary: Social linker generates share-links for the different social networks from
|