truncate_html 0.5.5 → 0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +0 -1
- data/Gemfile.lock +1 -1
- data/README.markdown +46 -15
- data/lib/truncate_html.rb +1 -1
- data/lib/truncate_html/configuration.rb +1 -1
- data/lib/truncate_html/html_string.rb +1 -2
- data/lib/truncate_html/html_truncator.rb +50 -38
- data/lib/truncate_html/version.rb +1 -1
- data/spec/truncate_html/html_truncator_spec.rb +64 -0
- metadata +8 -8
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
data/README.markdown
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
TruncateHtml
|
2
2
|
============
|
3
3
|
|
4
|
-
[![Build Status](https://secure.travis-ci.org/
|
4
|
+
[![Build Status](https://secure.travis-ci.org/hgmnz/truncate_html.png?branch=master)](http://travis-ci.org/hgmnz/truncate_html)
|
5
|
+
[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/hgmnz/truncate_html)
|
5
6
|
|
6
7
|
truncate_html is a Rails helper plugin that [cuts off](http://www.youtube.com/watch?v=6XG4DIOA7nU) a string of HTML and takes care of closing any lingering open tags. There are many possible solutions to this. This plugin does not have any dependencies, and does all it's work via [regular expressions](http://xkcd.com/208/).
|
7
8
|
|
@@ -11,9 +12,11 @@ The API is very similar to Rails' own <code>truncate()</code> method.
|
|
11
12
|
Example
|
12
13
|
-------
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
```ruby
|
16
|
+
some_html = '<ul><li><a href="http://whatever">This is a link</a></li></ul>'
|
17
|
+
truncate_html(some_html, :length => 15, :omission => '...(continued)')
|
18
|
+
=> <ul><li><a href="http://whatever">This...(continued)</a></li></ul>
|
19
|
+
```
|
17
20
|
|
18
21
|
A few notes:
|
19
22
|
|
@@ -22,21 +25,49 @@ A few notes:
|
|
22
25
|
* If the input HTML is nil, it will return an empty string.
|
23
26
|
* The omission text's length does count toward the resulting string's length.
|
24
27
|
* `<script>` tags will pass right through - they will not count toward the resulting string's length, or be truncated.
|
28
|
+
|
25
29
|
* The default options are:
|
26
30
|
* :length => 100
|
27
31
|
* :omission => '...'
|
28
32
|
* :word_boundary => true
|
29
33
|
|
30
34
|
You may also set global configuration options.
|
31
|
-
For example, place the following on
|
32
|
-
like `config/initializers/truncate_html.rb`
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
For example, place the following on application boot,
|
36
|
+
something like `config/initializers/truncate_html.rb`
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
TruncateHtml.configure do |config|
|
40
|
+
config.length = 50
|
41
|
+
config.omission = '...(continued)'
|
42
|
+
config.word_boundary = false
|
43
|
+
config.break_token = '<!-- break -->'
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
If you really want, you can even set a custom word boundary regexp.
|
48
|
+
For example, to truncate at the end of the nearest sentence:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
TruncateHtml.configure do |config|
|
52
|
+
config.length = 50
|
53
|
+
config.omission = ''
|
54
|
+
config.word_boundary = /\S[\.\?\!]/
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
You can also truncate the html at a specific point not based on length but content.
|
59
|
+
To do that, place the `:break_token` in your source. This allows the truncation to be
|
60
|
+
data driven, breaking after a leading paragraph or sentence. If the
|
61
|
+
`:break_token` is in your content before the specified :length, :length will be
|
62
|
+
ignored and the content truncated at :break_token
|
63
|
+
If the `:break_token` is in your content after the specified :length,
|
64
|
+
`:break_token` will be ignored and the content truncated at :length
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
TruncateHtml.configure do |config|
|
68
|
+
config.break_token = '<!-- truncate -->
|
69
|
+
end
|
70
|
+
```
|
40
71
|
Installation
|
41
72
|
------------
|
42
73
|
|
@@ -52,7 +83,7 @@ For Rails 3, use the latest truncate_html:
|
|
52
83
|
Issues or Suggestions
|
53
84
|
---------------------
|
54
85
|
|
55
|
-
Found an issue or have a suggestion? Please report it on [Github's issue tracker](http://github.com/
|
86
|
+
Found an issue or have a suggestion? Please report it on [Github's issue tracker](http://github.com/hgmnz/truncate_html/issues).
|
56
87
|
|
57
88
|
Testing
|
58
89
|
-------
|
@@ -64,4 +95,4 @@ All green? Go hack.
|
|
64
95
|
|
65
96
|
Copyright (c) 2009 - 2010 Harold A. Giménez, released under the MIT license
|
66
97
|
|
67
|
-
Thanks to all the [contributors](https://github.com/
|
98
|
+
Thanks to all the [contributors](https://github.com/hgmnz/truncate_html/contributors)!
|
data/lib/truncate_html.rb
CHANGED
@@ -7,7 +7,7 @@ require File.join(File.dirname(__FILE__), 'app', 'helpers', 'truncate_html_helpe
|
|
7
7
|
TruncateHtml.configure do |config|
|
8
8
|
config.length = 100
|
9
9
|
config.omission = '...'
|
10
|
-
config.word_boundary =
|
10
|
+
config.word_boundary = /\S/
|
11
11
|
end
|
12
12
|
|
13
13
|
ActionController::Base.helper(TruncateHtmlHelper)
|
@@ -34,8 +34,7 @@ module TruncateHtml
|
|
34
34
|
|
35
35
|
private
|
36
36
|
def regex
|
37
|
-
|
38
|
-
/(?:<script.*>.*<\/script>)+|<\/?[^>]+>|[#{"[[:alpha:]]" if RUBY_VERSION >= '1.9'}\w\|`~!@#\$%^&*\(\)\-_\+=\[\]{}:;'",\.\/?]+|\s+|#{punctuation}/
|
37
|
+
/(?:<script.*>.*<\/script>)+|<\/?[^>]+>|[[[:alpha:]]\w\|`~!@#\$%^&*\(\)\-_\+=\[\]{}:;'",\.\/?]+|\s+|[[:punct:]]/
|
39
38
|
end
|
40
39
|
|
41
40
|
end
|
@@ -6,67 +6,79 @@ module TruncateHtml
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def truncate(options = {})
|
9
|
-
length
|
10
|
-
@omission
|
11
|
-
@word_boundary
|
9
|
+
length = options[:length] || TruncateHtml.configuration.length
|
10
|
+
@omission = options[:omission] || TruncateHtml.configuration.omission
|
11
|
+
@word_boundary = (options.has_key?(:word_boundary) ? options[:word_boundary] : TruncateHtml.configuration.word_boundary)
|
12
|
+
@break_token = options[:break_token] || TruncateHtml.configuration.break_token || nil
|
12
13
|
@chars_remaining = length - @omission.length
|
13
14
|
@open_tags, @truncated_html = [], ['']
|
14
15
|
|
15
16
|
return @omission if @chars_remaining < 0
|
16
17
|
@original_html.html_tokens.each do |token|
|
17
|
-
|
18
|
-
if @chars_remaining > 0
|
19
|
-
process_token(token)
|
20
|
-
else
|
18
|
+
if @chars_remaining <= 0 || truncate_token?(token)
|
21
19
|
close_open_tags
|
22
20
|
break
|
21
|
+
else
|
22
|
+
process_token(token)
|
23
23
|
end
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
|
+
out = @truncated_html.join
|
27
|
+
|
28
|
+
if @word_boundary
|
29
|
+
term_regexp = Regexp.new("^.*#{@word_boundary.source}")
|
30
|
+
match = out.match(term_regexp)
|
31
|
+
match ? match[0] : out
|
32
|
+
else
|
33
|
+
out
|
34
|
+
end
|
26
35
|
end
|
27
36
|
|
28
37
|
private
|
29
38
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
else
|
36
|
-
remove_latest_open_tag(token)
|
37
|
-
end
|
39
|
+
def process_token(token)
|
40
|
+
append_to_result(token)
|
41
|
+
if token.html_tag?
|
42
|
+
if token.open_tag?
|
43
|
+
@open_tags << token
|
38
44
|
else
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
45
|
+
remove_latest_open_tag(token)
|
46
|
+
end
|
47
|
+
else
|
48
|
+
@chars_remaining -= (@word_boundary ? token.length : token[0, @chars_remaining].length)
|
49
|
+
if @chars_remaining <= 0
|
50
|
+
@truncated_html[-1] = @truncated_html[-1].rstrip + @omission
|
43
51
|
end
|
44
52
|
end
|
53
|
+
end
|
45
54
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
55
|
+
def append_to_result(token)
|
56
|
+
if token.html_tag?
|
57
|
+
@truncated_html << token
|
58
|
+
elsif @word_boundary
|
59
|
+
@truncated_html << token if (@chars_remaining - token.length) >= 0
|
60
|
+
else
|
61
|
+
@truncated_html << token[0, @chars_remaining]
|
54
62
|
end
|
63
|
+
end
|
55
64
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
65
|
+
def close_open_tags
|
66
|
+
@open_tags.reverse_each do |open_tag|
|
67
|
+
@truncated_html << open_tag.matching_close_tag
|
60
68
|
end
|
69
|
+
end
|
61
70
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
end
|
71
|
+
def remove_latest_open_tag(close_tag)
|
72
|
+
(0...@open_tags.length).to_a.reverse.each do |index|
|
73
|
+
if @open_tags[index].matching_close_tag == close_tag
|
74
|
+
@open_tags.delete_at(index)
|
75
|
+
break
|
68
76
|
end
|
69
77
|
end
|
78
|
+
end
|
70
79
|
|
80
|
+
def truncate_token?(token)
|
81
|
+
@break_token and token == @break_token
|
82
|
+
end
|
71
83
|
end
|
72
84
|
end
|
@@ -17,6 +17,22 @@ describe TruncateHtml::HtmlTruncator do
|
|
17
17
|
html = 'some text <span class="caps">CAPS</span> some text'
|
18
18
|
truncate(html, :length => 25, :word_boundary => false).should == 'some text <span class="caps">CAPS</span> some te...'
|
19
19
|
end
|
20
|
+
|
21
|
+
context 'and a custom omission value is passed' do
|
22
|
+
it 'retains the omission text' do
|
23
|
+
truncate_html("testtest", :length => 10, :omission => '..', :word_boundary => false).should == 'testtest..'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'handles multibyte characters' do
|
27
|
+
truncate_html("prüfenprüfen", :length => 8, :omission => '..', :word_boundary => false). should == 'prüfen..'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when the word_boundary option is a custom value (for splitting on sentences)' do
|
33
|
+
it 'truncates to the end of the nearest sentence' do
|
34
|
+
truncate_html('hello there. or maybe not?', :length => 16, :omission => '', :word_boundary => /\S[\.\?\!]/).should == 'hello there.'
|
35
|
+
end
|
20
36
|
end
|
21
37
|
|
22
38
|
it "includes the omission text's length in the returned truncated html" do
|
@@ -124,4 +140,52 @@ describe TruncateHtml::HtmlTruncator do
|
|
124
140
|
result.should include "<p>“我现在使用的是中文的拼音。”<br>"
|
125
141
|
end
|
126
142
|
|
143
|
+
context 'when the break_token option is set as <!-- truncate -->' do
|
144
|
+
it 'does not truncate abnormally if the break_token is not present' do
|
145
|
+
truncate('This is line one. This is line two.', :length => 30, :break_token => '<!-- truncate -->').should == 'This is line one. This is...'
|
146
|
+
end
|
147
|
+
it 'does not truncate abnormally if the break_token is present, but beyond the length param' do
|
148
|
+
truncate('This is line one. This is line <!-- truncate --> two.', :length => 30, :break_token => '<!-- truncate -->').should == 'This is line one. This is...'
|
149
|
+
end
|
150
|
+
it 'truncates before the length param if the break_token is before the token at "length"' do
|
151
|
+
truncate('This is line one. <!-- truncate --> This is line two.', :length => 30, :break_token => '<!-- truncate -->').should == 'This is line one.'
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when the break_token option is customized as a comment' do
|
156
|
+
it 'does not truncate abnormally if the break_token is not present' do
|
157
|
+
truncate('This is line one. This is line two.', :length => 30, :break_token => '<!-- break -->').should == 'This is line one. This is...'
|
158
|
+
end
|
159
|
+
it 'does not truncate abnormally if the break_token is present, but beyond the length param' do
|
160
|
+
truncate('This is line one. This is line <!-- break --> two.', :length => 30, :break_token => '<!-- break -->').should == 'This is line one. This is...'
|
161
|
+
end
|
162
|
+
it 'truncates before the length param if the break_token is before the token at "length"' do
|
163
|
+
truncate('This is line one. <!-- break --> This is line two.', :length => 30, :break_token => '<!-- break -->').should == 'This is line one.'
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'when the break_token option is customized as an html tag' do
|
168
|
+
it 'does not truncate abnormally if the break_token is not present' do
|
169
|
+
truncate('This is line one. This is line two.', :length => 30, :break_token => '<break />').should == 'This is line one. This is...'
|
170
|
+
end
|
171
|
+
it 'does not truncate abnormally if the break_token is present, but beyond the length param' do
|
172
|
+
truncate('This is line one. This is line <break /> two.', :length => 30, :break_token => '<break />').should == 'This is line one. This is...'
|
173
|
+
end
|
174
|
+
it 'truncates before the length param if the break_token is before the token at "length"' do
|
175
|
+
truncate('This is line one. <break /> This is line two.', :length => 30, :break_token => '<break />').should == 'This is line one.'
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
context 'when the break_token option is customized as a word' do
|
180
|
+
it 'does not truncate abnormally if the break_token is not present' do
|
181
|
+
truncate('This is line one. This is line two.', :length => 30, :break_token => 'foobar').should == 'This is line one. This is...'
|
182
|
+
end
|
183
|
+
it 'does not truncate abnormally if the break_token is present, but beyond the length param' do
|
184
|
+
truncate('This is line one. This is line foobar two.', :length => 30, :break_token => 'foobar').should == 'This is line one. This is...'
|
185
|
+
end
|
186
|
+
it 'truncates before the length param if the break_token is before the token at "length"' do
|
187
|
+
truncate('This is line one. foobar This is line two.', :length => 30, :break_token => 'foobar').should == 'This is line one.'
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
127
191
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: truncate_html
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.9'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec-rails
|
16
|
-
requirement: &
|
16
|
+
requirement: &70117859351640 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '2.9'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70117859351640
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rails
|
27
|
-
requirement: &
|
27
|
+
requirement: &70117859350560 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: 3.0.3
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70117859350560
|
36
36
|
description: Truncates html so you don't have to
|
37
37
|
email:
|
38
38
|
- harold.gimenez@gmail.com
|
@@ -99,7 +99,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
99
99
|
version: '0'
|
100
100
|
segments:
|
101
101
|
- 0
|
102
|
-
hash:
|
102
|
+
hash: 2344297215831564369
|
103
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
104
|
none: false
|
105
105
|
requirements:
|
@@ -108,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
108
|
version: '0'
|
109
109
|
segments:
|
110
110
|
- 0
|
111
|
-
hash:
|
111
|
+
hash: 2344297215831564369
|
112
112
|
requirements: []
|
113
113
|
rubyforge_project:
|
114
114
|
rubygems_version: 1.8.10
|