social_linker 0.1.1 → 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
[](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
|