html_slicer 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +12 -0
- data/README.rdoc +14 -16
- data/html_slicer.gemspec +2 -1
- data/lib/html_slicer.rb +1 -2
- data/lib/html_slicer/document.rb +107 -0
- data/lib/html_slicer/helpers/smart_params.rb +0 -0
- data/lib/html_slicer/installer.rb +2 -3
- data/lib/html_slicer/interface.rb +15 -64
- data/lib/html_slicer/makers/resizing.rb +96 -0
- data/lib/html_slicer/makers/slicing.rb +103 -0
- data/lib/html_slicer/models/active_record_extension.rb +1 -2
- data/lib/html_slicer/processor.rb +1 -1
- data/lib/html_slicer/railtie.rb +2 -0
- data/lib/html_slicer/utilities.rb +0 -2
- data/lib/html_slicer/version.rb +1 -1
- metadata +30 -8
- data/lib/html_slicer/resizing.rb +0 -89
- data/lib/html_slicer/slicing.rb +0 -101
data/CHANGELOG
CHANGED
data/README.rdoc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
=
|
1
|
+
= html_slicer
|
2
2
|
|
3
3
|
A little gem for Rails 3 helps you implement a smart way to split textual content. This is a quick approach to create ‘pageable’ views for ActiveRecord Model’s attributes, just independent strings, or any other Ruby classes. Or course it can split HTML content. More over, it can ‘resize’ HTML tags through <tt>width=</tt> attribute*.
|
4
4
|
|
@@ -51,7 +51,7 @@ Then bundle:
|
|
51
51
|
slice <method_name>, <configuration>, [:config => <:style>]*
|
52
52
|
|
53
53
|
where:
|
54
|
-
* <method_name> - any method
|
54
|
+
* <method_name> - any method name which returns source String (can be called with .send()).
|
55
55
|
* <configuration> - Hash of configuration options and/or +:config+ parameter.
|
56
56
|
|
57
57
|
=== Basic example
|
@@ -73,20 +73,18 @@ Console:
|
|
73
73
|
@article = Article.find(1)
|
74
74
|
@article.content
|
75
75
|
# => "Words like violence break the silence\r\nCome crashing in into my little world\r\n<iframe width=\"560\" height=\"315\" src=\"http://www.youtube.com/embed/ms0bd_hCZsk\" frameborder=\"0\" allowfullscreen></iframe>\r\nPainful to me, pierce right through me\r\nCan't you understand, oh my little girl?"
|
76
|
-
|
76
|
+
|
77
77
|
@article_paged = @article.paged
|
78
78
|
# => "Words like violence bre"
|
79
|
-
|
80
|
-
* the +nil+ argument assumes it is number +1+.
|
81
79
|
|
82
80
|
@article_paged.slice!(2)
|
83
81
|
# => "ak the silence"
|
84
|
-
|
85
|
-
* the passed slice number is remembered.
|
86
|
-
|
82
|
+
|
87
83
|
@article_paged.slice!(4)
|
88
84
|
# => "rld
|
89
|
-
<iframe width="300" height="169" src="http://www.youtube.com/embed/ms0bd_hCZsk" frameborder="0" allowfullscreen></iframe>"
|
85
|
+
<iframe width="300" height="169" src="http://www.youtube.com/embed/ms0bd_hCZsk" frameborder="0" allowfullscreen></iframe>"
|
86
|
+
|
87
|
+
The <tt>.slice!()</tt> method accepts number of slice (page). No argument (or +nil+) assumes it is number +1+. Passed slice number is remembered.
|
90
88
|
|
91
89
|
=== Configuration options
|
92
90
|
|
@@ -109,7 +107,7 @@ All configuration keys:
|
|
109
107
|
|
110
108
|
* <tt>:unit</tt> is a +Regexp/String/Hash+ description of text units counted to split the text by slices.
|
111
109
|
When value is a +Hash+, it assumes the unit is a HTML tag (look at <tt>:only/:except</tt> options for details).
|
112
|
-
Undefined value or +nil+ assumes it by default
|
110
|
+
Undefined value or +nil+ assumes it by default regular expression <tt>/&#?\w+;|\S/</tt>. As you can see it counts any regular character or HTML special character as a unit.
|
113
111
|
* <tt>:maximum</tt> is a +Fixnum+ number of units to be a one slice.
|
114
112
|
|
115
113
|
If +:unit+ defined as Regexp or String, default value is 300.
|
@@ -119,7 +117,7 @@ If +:unit+ defined as Hash, default value is 10.
|
|
119
117
|
If +:unit+ is default, default value is 2000.
|
120
118
|
|
121
119
|
* <tt>:complete</tt> is a +Regexp+ description of a character used to complete the slice.
|
122
|
-
For example, if you want to end the slice with a complete word, using
|
120
|
+
For example, if you want to end the slice with a complete word, using <tt>:complete => /s+|z/</tt> the counter would continue the slice until the first whitespace character.
|
123
121
|
* <tt>:limit</tt> - a +Fixnum+ limit number of slices.
|
124
122
|
In many cases we just need the first slice to perform it as a partial.
|
125
123
|
* <tt>:text_break</tt> - a responsible <tt>.to_s</tt> value of text breaks between slices.
|
@@ -130,17 +128,17 @@ It can be an ellipsis or any other symbol.
|
|
130
128
|
* Actually the hash is an argument for HTML::Conditions class (the part of ActionPack's html_scanner code). Look at http://github.com/rails/rails/blob/master/actionpack/lib/action_controller/vendor/html-scanner/html/node.rb
|
131
129
|
This is a very flexible utility to navigate via HTML content. Read native documentation for details.
|
132
130
|
|
133
|
-
For example: ID for <tt><hr class="break"> tag
|
131
|
+
For example: ID for <tt><hr class="break"></tt> tag is a hash: <tt>{:tag => "hr", :attributes => {:class => "break"}}</tt>
|
134
132
|
|
135
133
|
=== Resizing options
|
136
134
|
|
137
|
-
* <tt>:width</tt> is a Fixnum number of pixels as a target value to squeeze the HTML tag. It does the resize automatically proportional with the
|
135
|
+
* <tt>:width</tt> is a Fixnum number of pixels as a target value to squeeze the HTML tag. It does the resize automatically proportional with the 'height=' (if the tag has one). The percentage values are ignored.
|
138
136
|
* <tt>:only</tt> is a +Hash+ or +Array+ of hashes, describes which exactly nodes of HTML content to resize.
|
139
137
|
* <tt>:except</tt> is a +Hash+ or +Array+ of hashes, describes which exactly nodes of HTML content NOT to resize.
|
140
138
|
|
141
139
|
=== Processors
|
142
140
|
|
143
|
-
Processors are used to transform the source text before it is sliced. Many of us use various markup languages for dynamic contents. This is basically the same thing. Just create any class
|
141
|
+
Processors are used to transform the source text before it is sliced. Many of us use various markup languages for dynamic contents. This is basically the same thing. Just create any class and inherit it from HtmlSlicer::Processor, put it in +/lib/html_slicer_processors+ directory and define its name within the +:processors+ option.
|
144
142
|
|
145
143
|
Example:
|
146
144
|
|
@@ -310,14 +308,14 @@ Examples:
|
|
310
308
|
|
311
309
|
=== Slicing a general String or ActiveModel (or any other) object
|
312
310
|
|
313
|
-
There is no apecific approach to it. Just extend target class to
|
311
|
+
There is no apecific approach to it. Just extend target class to HtmlSlicer::Installer and call the method slice as described before:
|
314
312
|
|
315
313
|
String.extend HtmlSlicer::Installer
|
316
314
|
String.slice :to_s, :as => :page, :config => :for_string
|
317
315
|
|
318
316
|
== Questions, Feedback
|
319
317
|
|
320
|
-
Message me and I’ll do my best to help everybody. Github (addagger), no Twitter account, Facebook (http://www.facebook.com/
|
318
|
+
Message me and I’ll do my best to help everybody. Github (addagger), no Twitter account, Facebook (http://www.facebook.com/valery.kvon)
|
321
319
|
|
322
320
|
|
323
321
|
== Contributing to HtmlSlicer
|
data/html_slicer.gemspec
CHANGED
@@ -10,10 +10,11 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.authors = ["Valery Kvon"]
|
11
11
|
s.email = ["addagger@gmail.com"]
|
12
12
|
s.homepage = %q{http://vkvon.ru/projects/html_slicer}
|
13
|
-
s.summary = %q{HTML text
|
13
|
+
s.summary = %q{HTML text pagination for Ruby on Rails}
|
14
14
|
s.description = %q{HtmlSlicer is a smart way to cut an HTML text into pieces. It also provides on option to resize "width"/"height" attributes of HTML tags, such as <iframe>, <object>, <img> or any other.}
|
15
15
|
|
16
16
|
s.add_development_dependency "actionpack", ['>= 3.0.0']
|
17
|
+
s.add_development_dependency "activesupport", ['>= 3.0.0']
|
17
18
|
|
18
19
|
s.rubyforge_project = "html_slicer"
|
19
20
|
|
data/lib/html_slicer.rb
CHANGED
@@ -9,8 +9,7 @@ module HtmlSlicer
|
|
9
9
|
require 'html_slicer/config'
|
10
10
|
require 'html_slicer/options'
|
11
11
|
require 'html_slicer/processor'
|
12
|
-
require 'html_slicer/
|
13
|
-
require 'html_slicer/resizing'
|
12
|
+
require 'html_slicer/document'
|
14
13
|
require 'html_slicer/interface'
|
15
14
|
require 'html_slicer/engine'
|
16
15
|
require 'html_slicer/helpers/action_view_extension'
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'html_slicer/makers/slicing'
|
2
|
+
require 'html_slicer/makers/resizing'
|
3
|
+
|
4
|
+
module HtmlSlicer
|
5
|
+
|
6
|
+
class Document # Framework
|
7
|
+
include HtmlSlicer::Makers
|
8
|
+
|
9
|
+
attr_reader :options, :document, :slicing, :resizing
|
10
|
+
|
11
|
+
delegate :root, :to => :document
|
12
|
+
|
13
|
+
def initialize(env, method_name, options = {})
|
14
|
+
@options = options
|
15
|
+
@source = Proc.new do
|
16
|
+
if options[:processors].present?
|
17
|
+
HtmlSlicer::Process.iterate(env.send(method_name), options[:processors])
|
18
|
+
else
|
19
|
+
env.send(method_name)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
prepare!
|
23
|
+
end
|
24
|
+
|
25
|
+
# Resturn number of slices.
|
26
|
+
def slice_number
|
27
|
+
sliced? ? @slicing.slice_number : 1
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s(slice = 1)
|
31
|
+
prepare! if changed?
|
32
|
+
if sliced? && map = slicing.map[slice-1]
|
33
|
+
view(root, map, slicing.options.text_break)
|
34
|
+
else
|
35
|
+
root
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def inspect
|
40
|
+
to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
def method_missing(*args, &block)
|
44
|
+
to_s.send(*args, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def resized?
|
48
|
+
resizing.try(:did?)||false
|
49
|
+
end
|
50
|
+
|
51
|
+
def sliced?
|
52
|
+
slicing.present?
|
53
|
+
end
|
54
|
+
|
55
|
+
def changed?
|
56
|
+
@source_hash != @source.call.hash
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# Return a textual representation of the node including all children assigned to a +map+.
|
62
|
+
def view(node, map = {}, text_break = nil)
|
63
|
+
case node
|
64
|
+
when HTML::Tag then
|
65
|
+
children_view = node.children.collect {|child| view(child, map, text_break)}.compact.join
|
66
|
+
if map[node.object_id] || children_view.present?
|
67
|
+
if node.closing == :close
|
68
|
+
"</#{node.name}>"
|
69
|
+
else
|
70
|
+
s = "<#{node.name}"
|
71
|
+
node.attributes.each do |k,v|
|
72
|
+
s << " #{k}"
|
73
|
+
s << "=\"#{v}\"" if String === v
|
74
|
+
end
|
75
|
+
s << " /" if node.closing == :self
|
76
|
+
s << ">"
|
77
|
+
s += children_view
|
78
|
+
s << "</#{node.name}>" if node.closing != :self && !node.children.empty?
|
79
|
+
s
|
80
|
+
end
|
81
|
+
end
|
82
|
+
when HTML::Text then
|
83
|
+
if range = map[node.object_id]
|
84
|
+
"#{node.content[range]}#{text_break unless range.last == -1}"
|
85
|
+
end
|
86
|
+
when HTML::CDATA then
|
87
|
+
node.to_s
|
88
|
+
when HTML::Node then
|
89
|
+
node.children.collect {|child| view(child, map, text_break)}.compact.join
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Mapping the original source.
|
94
|
+
def prepare!
|
95
|
+
@source_hash = @source.call.hash
|
96
|
+
@document = HTML::Document.new(@source.call)
|
97
|
+
if options[:resize]
|
98
|
+
@resizing = Resizing.new(document, options[:resize])
|
99
|
+
end
|
100
|
+
if options[:slice]
|
101
|
+
@slicing = Slicing.new(document, options[:slice])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
File without changes
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module HtmlSlicer
|
2
|
-
|
3
2
|
module Installer
|
4
3
|
|
5
4
|
# The basic implementation method.
|
@@ -109,10 +108,10 @@ module HtmlSlicer
|
|
109
108
|
class_exec do
|
110
109
|
define_method method_name do
|
111
110
|
var_name = "@_#{method_name}"
|
112
|
-
instance_variable_get(var_name)||instance_variable_set(var_name, HtmlSlicer::Interface.new(
|
111
|
+
instance_variable_get(var_name)||instance_variable_set(var_name, HtmlSlicer::Interface.new(self, attr_name, config.config))
|
113
112
|
end
|
114
113
|
end
|
115
114
|
end
|
115
|
+
|
116
116
|
end
|
117
|
-
|
118
117
|
end
|
@@ -1,26 +1,23 @@
|
|
1
1
|
module HtmlSlicer
|
2
2
|
|
3
|
+
# Interface code.
|
4
|
+
# Accepts slice number, store it into instance variable and provides resulted String.
|
5
|
+
#
|
6
|
+
# === Example:
|
7
|
+
#
|
8
|
+
# @article = Article.find(1)
|
9
|
+
# @article_paged = @article.paged.slice!(params[:slice])
|
10
|
+
#
|
11
|
+
|
3
12
|
class Interface # General accessor instance
|
4
|
-
attr_reader :
|
5
|
-
|
6
|
-
delegate :
|
13
|
+
attr_reader :options, :current_slice, :document
|
14
|
+
|
15
|
+
delegate :sliced?, :resized?, :slice_number, :to => :document
|
7
16
|
|
8
|
-
def initialize(
|
9
|
-
raise(TypeError, "String object expected, '#{content.class}' passed") unless content.is_a?(String)
|
17
|
+
def initialize(env, method_name, options = {})
|
10
18
|
@options = options
|
19
|
+
@document = Document.new(env, method_name, options)
|
11
20
|
@current_slice = 1
|
12
|
-
@document = HTML::Document.new(HtmlSlicer::Process.iterate(content, options[:processors]))
|
13
|
-
if @options[:slice]
|
14
|
-
@slicing = Slicing.new(document, @options[:slice])
|
15
|
-
end
|
16
|
-
if @options[:resize]
|
17
|
-
@resizing = Resizing.new(document, @options[:resize])
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# Resturn number of slices.
|
22
|
-
def slice_number
|
23
|
-
sliced? ? @slicing.slice_number : 1
|
24
21
|
end
|
25
22
|
|
26
23
|
# General slicing method. Passing the argument changes the slice.
|
@@ -38,11 +35,7 @@ module HtmlSlicer
|
|
38
35
|
|
39
36
|
# Textual representation according to a current slice.
|
40
37
|
def to_s
|
41
|
-
|
42
|
-
view(root, map, @slicing.options.text_break)
|
43
|
-
else
|
44
|
-
root
|
45
|
-
end
|
38
|
+
document.to_s(current_slice)
|
46
39
|
end
|
47
40
|
|
48
41
|
def inspect
|
@@ -53,52 +46,10 @@ module HtmlSlicer
|
|
53
46
|
to_s.send(*args, &block)
|
54
47
|
end
|
55
48
|
|
56
|
-
def sliced?
|
57
|
-
@slicing.present?
|
58
|
-
end
|
59
|
-
|
60
|
-
def resized?
|
61
|
-
@resizing.present?
|
62
|
-
end
|
63
|
-
|
64
49
|
# Return the current slice is a last or not?
|
65
50
|
def last_slice?
|
66
51
|
current_slice == slice_number
|
67
52
|
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
# Return a textual representation of the node including all children assigned to a +map+.
|
72
|
-
def view(node, map = {}, text_break = nil)
|
73
|
-
case node
|
74
|
-
when HTML::Tag then
|
75
|
-
children_view = node.children.collect {|child| view(child, map, text_break)}.compact.join
|
76
|
-
if map[node.object_id] || children_view.present?
|
77
|
-
if node.closing == :close
|
78
|
-
"</#{node.name}>"
|
79
|
-
else
|
80
|
-
s = "<#{node.name}"
|
81
|
-
node.attributes.each do |k,v|
|
82
|
-
s << " #{k}"
|
83
|
-
s << "=\"#{v}\"" if String === v
|
84
|
-
end
|
85
|
-
s << " /" if node.closing == :self
|
86
|
-
s << ">"
|
87
|
-
s += children_view
|
88
|
-
s << "</#{node.name}>" if node.closing != :self && !node.children.empty?
|
89
|
-
s
|
90
|
-
end
|
91
|
-
end
|
92
|
-
when HTML::Text then
|
93
|
-
if range = map[node.object_id]
|
94
|
-
"#{node.content[range]}#{text_break unless range.last == -1}"
|
95
|
-
end
|
96
|
-
when HTML::CDATA then
|
97
|
-
node.to_s
|
98
|
-
when HTML::Node then
|
99
|
-
node.children.collect {|child| view(child, map, text_break)}.compact.join
|
100
|
-
end
|
101
|
-
end
|
102
53
|
|
103
54
|
end
|
104
55
|
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module HtmlSlicer
|
2
|
+
module Makers
|
3
|
+
|
4
|
+
class Resizing # Resizing engine
|
5
|
+
attr_reader :options
|
6
|
+
|
7
|
+
def initialize(document, options = {})
|
8
|
+
raise(TypeError, "HTML::Document expected, '#{document.class}' passed") unless document.is_a?(HTML::Document)
|
9
|
+
@options = ResizeOptions.new(options)
|
10
|
+
resize_document!(document.root)
|
11
|
+
end
|
12
|
+
|
13
|
+
def did?
|
14
|
+
@did||false
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
include HtmlSlicer::Utilities::ParseNode
|
20
|
+
include HtmlSlicer::Utilities::NodeMatchExtension
|
21
|
+
|
22
|
+
def resize_document!(root)
|
23
|
+
parse(root) do |node|
|
24
|
+
resize!(node) if node.is_a?(HTML::Tag) && resizeable?(node)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def resizeable?(node)
|
29
|
+
able_to?(node, @options)
|
30
|
+
end
|
31
|
+
|
32
|
+
def width(node)
|
33
|
+
values = []
|
34
|
+
if block_given?
|
35
|
+
node.attributes["width"] = yield
|
36
|
+
else
|
37
|
+
values << absolute_resolution(node.attributes["width"])
|
38
|
+
end
|
39
|
+
if style = node.attributes["style"]
|
40
|
+
style.gsub!(/width:\s+\d+px;/) do |t|
|
41
|
+
t.gsub(/\d+/) do |w|
|
42
|
+
if block_given?
|
43
|
+
yield
|
44
|
+
else
|
45
|
+
values << w.to_i
|
46
|
+
w
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
values.compact.min
|
52
|
+
end
|
53
|
+
|
54
|
+
def height(node)
|
55
|
+
values = []
|
56
|
+
if block_given?
|
57
|
+
node.attributes["height"] = yield
|
58
|
+
else
|
59
|
+
values << absolute_resolution(node.attributes["height"])
|
60
|
+
end
|
61
|
+
if style = node.attributes["style"]
|
62
|
+
style.gsub!(/height:\s+\d+px;/) do |t|
|
63
|
+
t.gsub(/\d+/) do |h|
|
64
|
+
if block_given?
|
65
|
+
yield
|
66
|
+
else
|
67
|
+
values << h.to_i
|
68
|
+
h
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
values.compact.min
|
74
|
+
end
|
75
|
+
|
76
|
+
def resize!(node)
|
77
|
+
target_width = node.parent.is_a?(HTML::Tag) ? width(node.parent)||@options.width : nil
|
78
|
+
if target_width.present? && node_width = width(node)
|
79
|
+
node_height = height(node)
|
80
|
+
if node_width > target_width
|
81
|
+
ratio = node_width.to_f/target_width
|
82
|
+
width(node) { target_width.to_s }
|
83
|
+
height(node) { (node_height/ratio).round.to_s } if node_height
|
84
|
+
@did = true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def absolute_resolution(value)
|
90
|
+
(value.present? && value.last != "%") ? value.to_i : nil
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module HtmlSlicer
|
2
|
+
module Makers
|
3
|
+
|
4
|
+
class Slicing # Slicing engine
|
5
|
+
attr_reader :options, :map
|
6
|
+
|
7
|
+
def initialize(document, options = {})
|
8
|
+
raise(TypeError, "HTML::Document expected, '#{document.class}' passed") unless document.is_a?(HTML::Document)
|
9
|
+
@options = SliceOptions.new(options)
|
10
|
+
@map = [Hash.new]
|
11
|
+
@options.unit.is_a?(Hash) ? slice_document_by_node!(document.root) : slice_document_by_text!(document.root)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Resturn number of slices.
|
15
|
+
def slice_number
|
16
|
+
@map.size
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
include HtmlSlicer::Utilities::ParseNode
|
22
|
+
include HtmlSlicer::Utilities::NodeMatchExtension
|
23
|
+
|
24
|
+
def slice_document_by_text!(root)
|
25
|
+
units_count = 0
|
26
|
+
parse(root) do |node|
|
27
|
+
if node.is_a?(HTML::Text)
|
28
|
+
if sliceable?(node)
|
29
|
+
sanitize_content!(node)
|
30
|
+
content = node.to_s
|
31
|
+
index = 0
|
32
|
+
begin
|
33
|
+
while (match = content.match(@options.unit, index)) && index < content.size
|
34
|
+
units_count += 1
|
35
|
+
last_index ||= 0
|
36
|
+
if units_count == @options.maximum
|
37
|
+
units_count = 0
|
38
|
+
index = complete!(content, match.end(0))
|
39
|
+
@map.last[node.object_id] = Range.new(last_index, index-1)
|
40
|
+
last_index = index
|
41
|
+
limited? ? raise(Exception) : @map << Hash.new
|
42
|
+
else
|
43
|
+
index = match.end(0)
|
44
|
+
end
|
45
|
+
if units_count > 0
|
46
|
+
@map.last[node.object_id] = Range.new(last_index, -1)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
rescue Exception
|
50
|
+
break
|
51
|
+
end
|
52
|
+
else
|
53
|
+
@map.last[node.object_id] = Range.new(0, -1)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
@map.last[node.object_id] = true
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def slice_document_by_node!(root)
|
62
|
+
units_count = 0
|
63
|
+
parse(root) do |node|
|
64
|
+
if node.is_a?(HTML::Text)
|
65
|
+
@map.last[node.object_id] = Range.new(0, -1)
|
66
|
+
else
|
67
|
+
@map.last[node.object_id] = true
|
68
|
+
end
|
69
|
+
if node.match(@options.unit) && sliceable?(node)
|
70
|
+
units_count += 1
|
71
|
+
if units_count == @options.maximum
|
72
|
+
units_count = 0
|
73
|
+
limited? ? break : @map << Hash.new
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def limited?
|
80
|
+
@options.limit && slice_number >= @options.limit
|
81
|
+
end
|
82
|
+
|
83
|
+
def sanitize_content!(node)
|
84
|
+
content = HTML::FullSanitizer.new.sanitize(node.to_s)
|
85
|
+
node.instance_variable_set(:@content, content)
|
86
|
+
end
|
87
|
+
|
88
|
+
def complete!(content, index)
|
89
|
+
if regexp = @options.complete
|
90
|
+
content.match(regexp, index).try(:begin, 0)||index
|
91
|
+
else
|
92
|
+
index
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def sliceable?(node)
|
97
|
+
able_to?(node, @options)
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
data/lib/html_slicer/railtie.rb
CHANGED
data/lib/html_slicer/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: html_slicer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
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: 2012-
|
12
|
+
date: 2012-06-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: actionpack
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,28 @@ dependencies:
|
|
21
21
|
version: 3.0.0
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.0.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activesupport
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 3.0.0
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 3.0.0
|
25
46
|
description: HtmlSlicer is a smart way to cut an HTML text into pieces. It also provides
|
26
47
|
on option to resize "width"/"height" attributes of HTML tags, such as <iframe>,
|
27
48
|
<object>, <img> or any other.
|
@@ -62,6 +83,7 @@ files:
|
|
62
83
|
- html_slicer.gemspec
|
63
84
|
- lib/html_slicer.rb
|
64
85
|
- lib/html_slicer/config.rb
|
86
|
+
- lib/html_slicer/document.rb
|
65
87
|
- lib/html_slicer/engine.rb
|
66
88
|
- lib/html_slicer/helpers/action_view_extension.rb
|
67
89
|
- lib/html_slicer/helpers/slicer.rb
|
@@ -69,12 +91,12 @@ files:
|
|
69
91
|
- lib/html_slicer/helpers/tags.rb
|
70
92
|
- lib/html_slicer/installer.rb
|
71
93
|
- lib/html_slicer/interface.rb
|
94
|
+
- lib/html_slicer/makers/resizing.rb
|
95
|
+
- lib/html_slicer/makers/slicing.rb
|
72
96
|
- lib/html_slicer/models/active_record_extension.rb
|
73
97
|
- lib/html_slicer/options.rb
|
74
98
|
- lib/html_slicer/processor.rb
|
75
99
|
- lib/html_slicer/railtie.rb
|
76
|
-
- lib/html_slicer/resizing.rb
|
77
|
-
- lib/html_slicer/slicing.rb
|
78
100
|
- lib/html_slicer/utilities.rb
|
79
101
|
- lib/html_slicer/version.rb
|
80
102
|
homepage: http://vkvon.ru/projects/html_slicer
|
@@ -98,8 +120,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
120
|
version: '0'
|
99
121
|
requirements: []
|
100
122
|
rubyforge_project: html_slicer
|
101
|
-
rubygems_version: 1.8.
|
123
|
+
rubygems_version: 1.8.24
|
102
124
|
signing_key:
|
103
125
|
specification_version: 3
|
104
|
-
summary: HTML text
|
126
|
+
summary: HTML text pagination for Ruby on Rails
|
105
127
|
test_files: []
|
data/lib/html_slicer/resizing.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
module HtmlSlicer
|
2
|
-
|
3
|
-
class Resizing # Resizing engine
|
4
|
-
attr_reader :options
|
5
|
-
|
6
|
-
def initialize(document, options = {})
|
7
|
-
raise(TypeError, "HTML::Document expected, '#{document.class}' passed") unless document.is_a?(HTML::Document)
|
8
|
-
@options = ResizeOptions.new(options)
|
9
|
-
resize_document!(document.root)
|
10
|
-
end
|
11
|
-
|
12
|
-
private
|
13
|
-
|
14
|
-
include HtmlSlicer::Utilities::ParseNode
|
15
|
-
include HtmlSlicer::Utilities::NodeMatchExtension
|
16
|
-
|
17
|
-
def resize_document!(root)
|
18
|
-
parse(root) do |node|
|
19
|
-
resize!(node) if node.is_a?(HTML::Tag) && resizeable?(node)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def resizeable?(node)
|
24
|
-
able_to?(node, @options)
|
25
|
-
end
|
26
|
-
|
27
|
-
def width(node)
|
28
|
-
values = []
|
29
|
-
if block_given?
|
30
|
-
node.attributes["width"] = yield
|
31
|
-
else
|
32
|
-
values << absolute_resolution(node.attributes["width"])
|
33
|
-
end
|
34
|
-
if style = node.attributes["style"]
|
35
|
-
style.gsub!(/width:\s+\d+px;/) do |t|
|
36
|
-
t.gsub(/\d+/) do |w|
|
37
|
-
if block_given?
|
38
|
-
yield
|
39
|
-
else
|
40
|
-
values << w.to_i
|
41
|
-
w
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
values.compact.min
|
47
|
-
end
|
48
|
-
|
49
|
-
def height(node)
|
50
|
-
values = []
|
51
|
-
if block_given?
|
52
|
-
node.attributes["height"] = yield
|
53
|
-
else
|
54
|
-
values << absolute_resolution(node.attributes["height"])
|
55
|
-
end
|
56
|
-
if style = node.attributes["style"]
|
57
|
-
style.gsub!(/height:\s+\d+px;/) do |t|
|
58
|
-
t.gsub(/\d+/) do |h|
|
59
|
-
if block_given?
|
60
|
-
yield
|
61
|
-
else
|
62
|
-
values << h.to_i
|
63
|
-
h
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
values.compact.min
|
69
|
-
end
|
70
|
-
|
71
|
-
def resize!(node)
|
72
|
-
target_width = node.parent.is_a?(HTML::Tag) ? width(node.parent)||@options.width : nil
|
73
|
-
if target_width.present? && node_width = width(node)
|
74
|
-
node_height = height(node)
|
75
|
-
if node_width > target_width
|
76
|
-
ratio = node_width.to_f/target_width
|
77
|
-
width(node) { target_width.to_s }
|
78
|
-
height(node) { (node_height/ratio).round.to_s } if node_height
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def absolute_resolution(value)
|
84
|
-
(value.present? && value.last != "%") ? value.to_i : nil
|
85
|
-
end
|
86
|
-
|
87
|
-
end
|
88
|
-
|
89
|
-
end
|
data/lib/html_slicer/slicing.rb
DELETED
@@ -1,101 +0,0 @@
|
|
1
|
-
module HtmlSlicer
|
2
|
-
|
3
|
-
class Slicing # Slicing engine
|
4
|
-
attr_reader :options, :map
|
5
|
-
|
6
|
-
def initialize(document, options = {})
|
7
|
-
raise(TypeError, "HTML::Document expected, '#{document.class}' passed") unless document.is_a?(HTML::Document)
|
8
|
-
@options = SliceOptions.new(options)
|
9
|
-
@map = [Hash.new]
|
10
|
-
@options.unit.is_a?(Hash) ? slice_document_by_node!(document.root) : slice_document_by_text!(document.root)
|
11
|
-
end
|
12
|
-
|
13
|
-
# Resturn number of slices.
|
14
|
-
def slice_number
|
15
|
-
@map.size
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
include HtmlSlicer::Utilities::ParseNode
|
21
|
-
include HtmlSlicer::Utilities::NodeMatchExtension
|
22
|
-
|
23
|
-
def slice_document_by_text!(root)
|
24
|
-
units_count = 0
|
25
|
-
parse(root) do |node|
|
26
|
-
if node.is_a?(HTML::Text)
|
27
|
-
if sliceable?(node)
|
28
|
-
sanitize_content!(node)
|
29
|
-
content = node.to_s
|
30
|
-
index = 0
|
31
|
-
begin
|
32
|
-
while (match = content.match(@options.unit, index)) && index < content.size
|
33
|
-
units_count += 1
|
34
|
-
last_index ||= 0
|
35
|
-
if units_count == @options.maximum
|
36
|
-
units_count = 0
|
37
|
-
index = complete!(content, match.end(0))
|
38
|
-
@map.last[node.object_id] = Range.new(last_index, index-1)
|
39
|
-
last_index = index
|
40
|
-
limited? ? raise(Exception) : @map << Hash.new
|
41
|
-
else
|
42
|
-
index = match.end(0)
|
43
|
-
end
|
44
|
-
if units_count > 0
|
45
|
-
@map.last[node.object_id] = Range.new(last_index, -1)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
rescue Exception
|
49
|
-
break
|
50
|
-
end
|
51
|
-
else
|
52
|
-
@map.last[node.object_id] = Range.new(0, -1)
|
53
|
-
end
|
54
|
-
else
|
55
|
-
@map.last[node.object_id] = true
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def slice_document_by_node!(root)
|
61
|
-
units_count = 0
|
62
|
-
parse(root) do |node|
|
63
|
-
if node.is_a?(HTML::Text)
|
64
|
-
@map.last[node.object_id] = Range.new(0, -1)
|
65
|
-
else
|
66
|
-
@map.last[node.object_id] = true
|
67
|
-
end
|
68
|
-
if node.match(@options.unit) && sliceable?(node)
|
69
|
-
units_count += 1
|
70
|
-
if units_count == @options.maximum
|
71
|
-
units_count = 0
|
72
|
-
limited? ? break : @map << Hash.new
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def limited?
|
79
|
-
@options.limit && slice_number >= @options.limit
|
80
|
-
end
|
81
|
-
|
82
|
-
def sanitize_content!(node)
|
83
|
-
content = HTML::FullSanitizer.new.sanitize(node.to_s)
|
84
|
-
node.instance_variable_set(:@content, content)
|
85
|
-
end
|
86
|
-
|
87
|
-
def complete!(content, index)
|
88
|
-
if regexp = @options.complete
|
89
|
-
content.match(regexp, index).try(:begin, 0)||index
|
90
|
-
else
|
91
|
-
index
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def sliceable?(node)
|
96
|
-
able_to?(node, @options)
|
97
|
-
end
|
98
|
-
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|