html_truncator 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +19 -8
- data/lib/html_truncator.rb +32 -17
- metadata +3 -3
data/README.md
CHANGED
@@ -14,19 +14,19 @@ It's very simple. Install it with rubygems:
|
|
14
14
|
|
15
15
|
Or, if you use bundler, add it to your `Gemfile`:
|
16
16
|
|
17
|
-
gem "html_truncator", :version => "~>0.
|
17
|
+
gem "html_truncator", :version => "~>0.2"
|
18
18
|
|
19
19
|
Then you can use it in your code:
|
20
20
|
|
21
21
|
require "html_truncator"
|
22
22
|
HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 3)
|
23
|
-
# => "<p>Lorem ipsum dolor
|
23
|
+
# => "<p>Lorem ipsum dolor…</p>"
|
24
24
|
|
25
25
|
The HTML_Truncator class has only one method, `truncate`, with 3 arguments:
|
26
26
|
|
27
27
|
* the HTML-formatted string to truncate
|
28
28
|
* the number of words to keep (real words, tags and attributes aren't count)
|
29
|
-
* the ellipsis (optional, '
|
29
|
+
* some options like the ellipsis (optional, '…' by default).
|
30
30
|
|
31
31
|
And an attribute, `ellipsable_tags`, which lists the tags that can contain the ellipsis
|
32
32
|
(by default: p ol ul li div header article nav section footer aside dd dt dl).
|
@@ -38,33 +38,43 @@ Examples
|
|
38
38
|
A simple example:
|
39
39
|
|
40
40
|
HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 3)
|
41
|
-
# => "<p>Lorem ipsum dolor
|
41
|
+
# => "<p>Lorem ipsum dolor…</p>"
|
42
42
|
|
43
43
|
If the text is too short to be truncated, it won't be modified:
|
44
44
|
|
45
45
|
HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 5)
|
46
46
|
# => "<p>Lorem ipsum dolor sit amet.</p>"
|
47
47
|
|
48
|
+
If you prefer, you can have the length in characters instead of words:
|
49
|
+
|
50
|
+
HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 12, :length_in_chars => true)
|
51
|
+
# => "<p>Lorem ipsum …</p>"
|
52
|
+
|
48
53
|
You can customize the ellipsis:
|
49
54
|
|
50
|
-
HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 3, " (truncated)")
|
55
|
+
HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 3, :ellipsis => " (truncated)")
|
51
56
|
# => "<p>Lorem ipsum dolor (truncated)</p>"
|
52
57
|
|
53
58
|
And even have HTML in the ellipsis:
|
54
59
|
|
55
|
-
HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 3, '<a href="/more-to-read">...</a>')
|
60
|
+
HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 3, :ellipsis => '<a href="/more-to-read">...</a>')
|
56
61
|
# => "<p>Lorem ipsum dolor<a href="/more-to-read">...</a></p>"
|
57
62
|
|
58
63
|
The ellipsis is put at the right place, inside `<p>`, but not `<i>`:
|
59
64
|
|
60
65
|
HTML_Truncator.truncate("<p><i>Lorem ipsum dolor sit amet.</i></p>", 3)
|
61
|
-
# => "<p><i>Lorem ipsum dolor</i
|
66
|
+
# => "<p><i>Lorem ipsum dolor</i>…</p>"
|
62
67
|
|
63
68
|
You can indicate that a tag can contain the ellipsis but adding it to the ellipsable_tags:
|
64
69
|
|
65
70
|
HTML_Truncator.ellipsable_tags << "blockquote"
|
66
71
|
HTML_Truncator.truncate("<blockquote>Lorem ipsum dolor sit amet.</blockquote>", 3)
|
67
|
-
# => "<blockquote>Lorem ipsum dolor
|
72
|
+
# => "<blockquote>Lorem ipsum dolor…</blockquote>"
|
73
|
+
|
74
|
+
You can know if a string was truncated with the `html_truncated?` method:
|
75
|
+
|
76
|
+
HTML_Truncator.truncate("<p>Lorem ipsum dolor sit amet.</p>", 3).html_truncated?
|
77
|
+
# => true
|
68
78
|
|
69
79
|
|
70
80
|
Alternatives
|
@@ -102,5 +112,6 @@ Credits
|
|
102
112
|
-------
|
103
113
|
|
104
114
|
Thanks to François de Metz for his awesome help!
|
115
|
+
Thanks to [kuroir](https://github.com/kuroir) and [benhutton](https://github.com/benhutton) for their suggestions.
|
105
116
|
|
106
117
|
Copyright (c) 2011 Bruno Michel <bmichel@menfin.info>, released under the MIT license
|
data/lib/html_truncator.rb
CHANGED
@@ -1,11 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require "nokogiri"
|
2
4
|
require "set"
|
3
5
|
|
4
6
|
|
5
7
|
class HTML_Truncator
|
6
|
-
|
8
|
+
DEFAULT_OPTIONS = { :ellipsis => "…", :length_in_chars => false }
|
9
|
+
|
10
|
+
def self.truncate(text, max, opts={})
|
11
|
+
return truncate(text, max, :ellipsis => opts) if String === opts
|
12
|
+
opts = DEFAULT_OPTIONS.merge(opts)
|
7
13
|
doc = Nokogiri::HTML::DocumentFragment.parse(text)
|
8
|
-
doc.truncate(
|
14
|
+
str, _, opts = doc.truncate(max, opts)
|
15
|
+
eval "class <<str; def html_truncated?; #{opts[:was_truncated]} end end"
|
16
|
+
str
|
9
17
|
end
|
10
18
|
|
11
19
|
class <<self
|
@@ -22,28 +30,29 @@ class Nokogiri::HTML::DocumentFragment
|
|
22
30
|
end
|
23
31
|
|
24
32
|
class Nokogiri::XML::Node
|
25
|
-
def truncate(
|
26
|
-
return ["", 1,
|
27
|
-
inner, remaining,
|
33
|
+
def truncate(max, opts)
|
34
|
+
return ["", 1, opts] if max == 0 && !ellipsable?
|
35
|
+
inner, remaining, opts = inner_truncate(max, opts)
|
28
36
|
children.remove
|
29
37
|
add_child Nokogiri::HTML::DocumentFragment.parse(inner)
|
30
|
-
[
|
38
|
+
[to_html(:indent => 0), max - remaining, opts]
|
31
39
|
end
|
32
40
|
|
33
|
-
def inner_truncate(
|
34
|
-
inner, remaining = "",
|
41
|
+
def inner_truncate(max, opts)
|
42
|
+
inner, remaining = "", max
|
35
43
|
self.children.each do |node|
|
36
|
-
txt, nb,
|
44
|
+
txt, nb, opts = node.truncate(remaining, opts)
|
37
45
|
remaining -= nb
|
38
46
|
inner += txt
|
39
47
|
next if remaining >= 0
|
40
48
|
if ellipsable?
|
41
|
-
inner += ellipsis
|
42
|
-
ellipsis = ""
|
49
|
+
inner += opts[:ellipsis]
|
50
|
+
opts[:ellipsis] = ""
|
51
|
+
opts[:was_truncated] = true
|
43
52
|
end
|
44
53
|
break
|
45
54
|
end
|
46
|
-
[inner, remaining,
|
55
|
+
[inner, remaining, opts]
|
47
56
|
end
|
48
57
|
|
49
58
|
def ellipsable?
|
@@ -52,10 +61,16 @@ class Nokogiri::XML::Node
|
|
52
61
|
end
|
53
62
|
|
54
63
|
class Nokogiri::XML::Text
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
64
|
+
def truncate(max, opts)
|
65
|
+
if opts[:length_in_chars]
|
66
|
+
count = content.length
|
67
|
+
return [to_xhtml, count, opts] if count <= max && max > 0
|
68
|
+
[content.slice(0, max), count, opts]
|
69
|
+
else
|
70
|
+
words = content.split
|
71
|
+
count = words.length
|
72
|
+
return [to_xhtml, count, opts] if count <= max && max > 0
|
73
|
+
[words.slice(0, max).join(' '), count, opts]
|
74
|
+
end
|
60
75
|
end
|
61
76
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
- 1
|
8
7
|
- 2
|
9
|
-
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Bruno Michel
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-01-
|
17
|
+
date: 2011-01-28 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|