ballonizer 0.2.4 → 0.4.0
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/examples/ballonizer_app/config.ru +4 -2
- data/examples/ballonizer_app/index.html +105 -157
- data/examples/ballonizer_app/test.db +0 -0
- data/examples/ballonizer_js_module/index.html +4 -4
- data/lib/assets/javascripts/ballonizer.js +119 -17
- data/lib/assets/stylesheets/ballonizer.css +17 -12
- data/lib/ballonizer.rb +81 -25
- data/spec/ballonizer_spec.rb +108 -45
- data/spec/javascripts/ballonizer_spec.js +186 -129
- data/spec/javascripts/fixtures/ballonized-xkcd-with-anchor-in-image.html +2 -2
- data/spec/javascripts/fixtures/ballonized-xkcd-with-ballons.html +2 -2
- data/spec/javascripts/fixtures/ballonized-xkcd-without-ballons.html +2 -2
- metadata +3 -2
@@ -14,7 +14,9 @@
|
|
14
14
|
background-color: white;
|
15
15
|
color: black;
|
16
16
|
text-align: center;
|
17
|
-
|
17
|
+
display: block;
|
18
|
+
word-wrap: break-word;
|
19
|
+
overflow: hidden;
|
18
20
|
}
|
19
21
|
|
20
22
|
.ballonizer_ballon_hidden_for_edition
|
@@ -31,44 +33,47 @@
|
|
31
33
|
* occupy space (no one). With this the form is "hidden" because don't occupy
|
32
34
|
* any space (the width AND height are equal zero).
|
33
35
|
*/
|
34
|
-
.ballonizer_image_form
|
36
|
+
.ballonizer_image_form, .ballonizer_image_form div
|
35
37
|
{
|
36
38
|
margin: 0;
|
37
39
|
padding: 0;
|
38
40
|
border: 0;
|
41
|
+
left: 0;
|
42
|
+
top: 0;
|
39
43
|
display: inline-block;
|
44
|
+
/* we must */
|
45
|
+
position: relative;
|
40
46
|
}
|
41
47
|
|
42
|
-
.ballonizer_image_form
|
48
|
+
.ballonizer_image_form .ballonizer_edition_ballon
|
43
49
|
{
|
44
50
|
position: absolute;
|
45
51
|
display: none;
|
52
|
+
border: 0;
|
46
53
|
margin: 0;
|
47
54
|
text-align: center;
|
48
55
|
}
|
49
56
|
|
50
|
-
.ballonizer_image_form
|
57
|
+
.ballonizer_image_form .ballonizer_edition_ballon.ballonizer_ballon_in_edition
|
51
58
|
{
|
52
59
|
display: block;
|
53
60
|
}
|
54
61
|
|
55
62
|
/* We use the same trick used in the image form in the page form */
|
56
|
-
.ballonizer_page_form
|
63
|
+
.ballonizer_page_form, .ballonizer_page_form div
|
57
64
|
{
|
58
65
|
display: inline-block;
|
59
|
-
padding: 0;
|
60
66
|
margin: 0;
|
61
|
-
|
67
|
+
padding: 0;
|
68
|
+
border: 0;
|
62
69
|
}
|
63
70
|
|
64
|
-
.ballonizer_page_form
|
71
|
+
.ballonizer_page_form input[type=submit]
|
65
72
|
{
|
66
|
-
|
67
|
-
margin: 0;
|
68
|
-
padding: 0;
|
73
|
+
display: none;
|
69
74
|
}
|
70
75
|
|
71
|
-
.ballonizer_page_form
|
76
|
+
.ballonizer_page_form input[type=submit].ballonizer_ballons_have_changes
|
72
77
|
{
|
73
78
|
display: block;
|
74
79
|
position: fixed;
|
data/lib/ballonizer.rb
CHANGED
@@ -54,6 +54,24 @@ require 'sprockets'
|
|
54
54
|
# The tables names are: images, ballons, ballonized_image_versions,
|
55
55
|
# ballonized_image_ballons.
|
56
56
|
#
|
57
|
+
# Changelog:
|
58
|
+
# v0.4.0:
|
59
|
+
# * Changed the way the Javascript module add containers in the page
|
60
|
+
# to avoid creating invalid HTML4.0.1/XHTML1.1/HTML5 documents.
|
61
|
+
# * Now the ballonize_page takes a mime-type argument to decide if
|
62
|
+
# the page has to be parsed as XML or HTML (trying to be in
|
63
|
+
# conformance with http://www.w3.org/TR/xhtml-media-types/).
|
64
|
+
# * The change in the ballon size now change the font-size of the
|
65
|
+
# ballon text.
|
66
|
+
# * Database schema change, as consequence of the font-size change,
|
67
|
+
# the database now stores the font-size. No migration provided for
|
68
|
+
# databases in the old format, but the font-size field can be null.
|
69
|
+
# The migration only require adding this column with null value to
|
70
|
+
# all records (see the create_tables code).
|
71
|
+
# * Fixed a bug in the Javascript module that give wrong position and
|
72
|
+
# size values to all ballons that aren't edited/added before submmiting
|
73
|
+
# (only if the image wasn't loaded before the javascript loading).
|
74
|
+
#
|
57
75
|
class Ballonizer
|
58
76
|
|
59
77
|
# The superclass of any error explicitly raised by the Ballonizer class.
|
@@ -75,22 +93,38 @@ class Ballonizer
|
|
75
93
|
e.freeze
|
76
94
|
end
|
77
95
|
|
78
|
-
def self.parse_html_or_xhtml(doc)
|
79
|
-
# If you parse XHTML as HTML with Nokogiri and use to_s after the markup
|
96
|
+
def self.parse_html_or_xhtml(doc, mime_type)
|
97
|
+
# If you parse XHTML as HTML with Nokogiri, and use to_s after, the markup
|
98
|
+
# can be messed up, breaking the structural integrity of the xml
|
80
99
|
#
|
81
100
|
# Example: <meta name="description" content="not important" />
|
82
101
|
# becomes <meta name="description" content="not important" >
|
83
|
-
#
|
102
|
+
#
|
103
|
+
# In the other side if you parse HTML as a XML, and use to_s after, the
|
104
|
+
# Nokogiri make empty content tags self-close
|
105
|
+
#
|
106
|
+
# Example: <script type="text/javascript" src="/ballonizer.js"></script>
|
107
|
+
# becomes: <script type="text/javascript" src="/ballonizer.js" />
|
108
|
+
#
|
109
|
+
# What's even worse than the contrary (xml as html)
|
84
110
|
parsed_doc = nil
|
85
|
-
|
86
|
-
|
87
|
-
|
111
|
+
|
112
|
+
case mime_type
|
113
|
+
when /text\/html/
|
114
|
+
parsed_doc = Nokogiri::HTML(doc)
|
115
|
+
when /application\/xhtml\+xml/
|
88
116
|
options = Nokogiri::XML::ParseOptions::DEFAULT_XML &
|
89
117
|
Nokogiri::XML::ParseOptions::STRICT &
|
90
118
|
Nokogiri::XML::ParseOptions::NONET
|
91
|
-
|
92
|
-
|
93
|
-
|
119
|
+
begin
|
120
|
+
parsed_doc = Nokogiri::XML::Document.parse(doc, nil, nil, options)
|
121
|
+
rescue
|
122
|
+
return nil
|
123
|
+
end
|
124
|
+
else
|
125
|
+
fail Error, "the only mime-types accepted are text/html and" +
|
126
|
+
" application/xhtml+xml, the passed argument was " +
|
127
|
+
"'#{mime_type}'"
|
94
128
|
end
|
95
129
|
|
96
130
|
parsed_doc
|
@@ -258,12 +292,16 @@ class Ballonizer
|
|
258
292
|
if ballon["text"].empty?
|
259
293
|
fail SubmitError, "the ballon text is empty"
|
260
294
|
end
|
295
|
+
[:top, :left, :width, :height, :font_size].each do | numeric_attr_name |
|
296
|
+
numeric_attr = ballon[numeric_attr_name.to_s]
|
297
|
+
unless numeric_attr.is_a?(Fixnum) || numeric_attr.is_a?(Float)
|
298
|
+
fail SubmitError, "the #{numeric_attr_name} " +
|
299
|
+
"(#{numeric_attr}) isn't a Fixnum or " +
|
300
|
+
"Float (is a '#{numeric_attr.class}')"
|
301
|
+
end
|
302
|
+
end
|
261
303
|
[:top, :left, :width, :height].each do | bound_name |
|
262
304
|
bound = ballon[bound_name.to_s]
|
263
|
-
unless bound.is_a?(Fixnum) || bound.is_a?(Float)
|
264
|
-
fail SubmitError, "the #{bound_name.to_s} (#{bound.to_s}) isn't" +
|
265
|
-
" a Fixnum or Float (is a '#{bound.class.to_s}')"
|
266
|
-
end
|
267
305
|
unless bound >= 0 && bound <= 1
|
268
306
|
fail SubmitError, "the #{bound_name.to_s} (#{bound.to_s}) isn't"
|
269
307
|
" between 0 and 1 (both inclusive)"
|
@@ -271,14 +309,14 @@ class Ballonizer
|
|
271
309
|
end
|
272
310
|
|
273
311
|
ballon_end = {}
|
274
|
-
ballon_end[:x] = ballon["
|
275
|
-
ballon_end[:y] = ballon["
|
312
|
+
ballon_end[:x] = ballon["left"] + ballon["width"]
|
313
|
+
ballon_end[:y] = ballon["top"] + ballon["height"]
|
276
314
|
|
277
315
|
[:x, :y].each do | axis |
|
278
316
|
if ballon_end[axis] > 1
|
279
|
-
|
280
|
-
|
281
|
-
" of the image"
|
317
|
+
side = { x: "right side", y: "bottom" }[axis]
|
318
|
+
fail SubmitError, "the ballon with text #{ballon["text"].to_s} " +
|
319
|
+
"is trespassing the #{side} of the image"
|
282
320
|
end
|
283
321
|
end
|
284
322
|
end
|
@@ -351,22 +389,35 @@ class Ballonizer
|
|
351
389
|
# Wrap each image to ballonize with a container, add its ballons to the
|
352
390
|
# container and, possibly, add the css and js libs and snippet for the
|
353
391
|
# edition initialization. Don't make any change if the page has no images
|
354
|
-
# to ballonize.
|
392
|
+
# to ballonize. If the page can't be parsed (as HTML or X(HT)ML, depending
|
393
|
+
# of the mime-type) return the page argument without throwing any exceptions.
|
394
|
+
# Throw an exception if the mime-type doesn't match with html or xhtml.
|
355
395
|
# @param page [String] The (X)HTML page.
|
356
396
|
# @param page_url [String] The url of the page to be ballonized, necessary
|
357
397
|
# to make absolute the src attribute of img (if it's relative).
|
358
398
|
# @param settings [Hash{Symbol => String}] Optional. If not provided the
|
359
399
|
# #settings will be used.
|
360
|
-
# @
|
361
|
-
|
400
|
+
# @param mime_type A string that have the substring 'text/html' or
|
401
|
+
# 'application/xhtml+xml'.
|
402
|
+
# @return [String] The ballonized page (new string), or the same string,
|
403
|
+
# if the parse has failed.
|
404
|
+
# @raise [Ballonizer::Error] If the mime-type don't match either 'text/html'
|
405
|
+
# or 'application/xhtml+xml'.
|
406
|
+
def ballonize_page(page, page_url, mime_type, settings = {})
|
362
407
|
settings = self.settings.merge(settings)
|
363
408
|
|
364
|
-
|
409
|
+
# can raise Ballonizer::Error if the mime-type is invalid
|
410
|
+
parsed_page = Workaround.parse_html_or_xhtml(page, mime_type)
|
411
|
+
# if can't parse return the page unaltered
|
412
|
+
if parsed_page.nil?
|
413
|
+
return page
|
414
|
+
end
|
415
|
+
|
365
416
|
selector = settings[:img_to_ballonize_css_selector]
|
366
417
|
imgs = parsed_page.css(selector)
|
367
418
|
|
368
419
|
unless imgs.empty?
|
369
|
-
imgs.wrap('<
|
420
|
+
imgs.wrap('<span class="ballonizer_image_container" ></span>')
|
370
421
|
|
371
422
|
imgs.each do | img |
|
372
423
|
img_src = img['src']
|
@@ -403,8 +454,9 @@ class Ballonizer
|
|
403
454
|
# transform ratio [0,1] to percent [0, 100]
|
404
455
|
style = style + "#{sym}: #{(ballon_data[sym] * 100)}%;"
|
405
456
|
end
|
457
|
+
style = style + "font-size: #{ballon_data[:font_size]}px;"
|
406
458
|
|
407
|
-
"<
|
459
|
+
"<span class='ballonizer_ballon' style='#{style}'>#{text}</span>"
|
408
460
|
end
|
409
461
|
|
410
462
|
# @api private
|
@@ -422,7 +474,8 @@ class Ballonizer
|
|
422
474
|
.join(:ballons, { ballonized_image_ballons__version: version,
|
423
475
|
ballonized_image_ballons__image_id: image_id,
|
424
476
|
ballonized_image_ballons__ballon_id: :ballons__id
|
425
|
-
}).select(:text, :top, :left, :width, :height
|
477
|
+
}).select(:text, :top, :left, :width, :height,
|
478
|
+
:font_size).all
|
426
479
|
else
|
427
480
|
[]
|
428
481
|
end
|
@@ -458,6 +511,9 @@ class Ballonizer
|
|
458
511
|
Float :left, :allow_null => false
|
459
512
|
Float :width, :allow_null => false
|
460
513
|
Float :height, :allow_null => false
|
514
|
+
# the font_size allow null to support databases migrated from old versions
|
515
|
+
# (that don't have this field)
|
516
|
+
Float :font_size, :allow_null => true
|
461
517
|
end
|
462
518
|
db.create_table(:ballonized_image_versions) do
|
463
519
|
Integer :version
|
data/spec/ballonizer_spec.rb
CHANGED
@@ -31,6 +31,24 @@ RSpec::Matchers.define :exist_in_filesystem do
|
|
31
31
|
"be a list of absolute paths for existing files or directories"
|
32
32
|
end
|
33
33
|
end
|
34
|
+
# TODO: check the font-size, the position and the size of the ballon
|
35
|
+
# TODO: check the src of the image inside the container (not so easy
|
36
|
+
# because the src is relative in the html but absolute in the database)
|
37
|
+
RSpec::Matchers.define :have_ballons_as_submitted_by do | expected |
|
38
|
+
match do | actual |
|
39
|
+
expected.each do | img_src, ballons |
|
40
|
+
expect(actual).to(have_tag('.ballonizer_image_container') do
|
41
|
+
with_tag('img')
|
42
|
+
ballons.each do | b |
|
43
|
+
with_tag('span', { text: b['text'], with: { class: 'ballonizer_ballon' }})
|
44
|
+
end
|
45
|
+
end)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
description do
|
49
|
+
'have ballons as the ones added by the last submit'
|
50
|
+
end
|
51
|
+
end
|
34
52
|
|
35
53
|
describe Ballonizer do
|
36
54
|
|
@@ -42,17 +60,23 @@ describe Ballonizer do
|
|
42
60
|
db[:images].insert({img_src: 'http://comic-translation.com/tr/pt-BR/a_comic/imgs/3.jpg'})
|
43
61
|
|
44
62
|
db[:ballons].insert({ text: 'first ballon of first image',
|
45
|
-
top: 0, left: 0, width: 0.5, height: 0.5
|
63
|
+
top: 0, left: 0, width: 0.5, height: 0.5,
|
64
|
+
font_size: 16 })
|
46
65
|
db[:ballons].insert({ text: 'second ballon of first image',
|
47
|
-
top: 0
|
66
|
+
top: 0, left: 0, width: 0.5, height: 0.5,
|
67
|
+
font_size: 16 })
|
48
68
|
db[:ballons].insert({ text: 'first ballon of second image',
|
49
|
-
top: 0, left: 0, width: 0.5, height: 0.5
|
69
|
+
top: 0, left: 0, width: 0.5, height: 0.5,
|
70
|
+
font_size: 16 })
|
50
71
|
db[:ballons].insert({ text: 'second ballon of second image',
|
51
|
-
top: 0
|
72
|
+
top: 0, left: 0, width: 0.5, height: 0.5,
|
73
|
+
font_size: 16 })
|
52
74
|
db[:ballons].insert({ text: 'first ballon of third image',
|
53
|
-
top: 0, left: 0, width: 0.5, height: 0.5
|
75
|
+
top: 0, left: 0, width: 0.5, height: 0.5,
|
76
|
+
font_size: 16 })
|
54
77
|
db[:ballons].insert({ text: 'second ballon of third image',
|
55
|
-
top: 0
|
78
|
+
top: 0, left: 0, width: 0.5, height: 0.5,
|
79
|
+
font_size: 16 })
|
56
80
|
|
57
81
|
# both ballons added in the first version
|
58
82
|
db[:ballonized_image_versions].insert({image_id: 1, version: 1, time: time})
|
@@ -81,6 +105,10 @@ describe Ballonizer do
|
|
81
105
|
JSON.parse(JSON.generate(v))
|
82
106
|
end
|
83
107
|
|
108
|
+
# definitions to be overriden in need, but who doesn't need a *_example
|
109
|
+
# counterpart (are so simple that clone and change isn't pratical)
|
110
|
+
let (:mime_type) { 'application/xhtml+xml' }
|
111
|
+
|
84
112
|
# Definitions ending with '_example' are to be cloned and defined in a
|
85
113
|
# context without the sufix. Definitions without the sufix are used in the
|
86
114
|
# specs and may require the definition of some without '_example' counterparts.
|
@@ -139,7 +167,7 @@ describe Ballonizer do
|
|
139
167
|
{}
|
140
168
|
end
|
141
169
|
let (:submit_json_example) do
|
142
|
-
'{"http://imgs.xkcd.com/comics/cells.png":[{"left":0,"top":0,"width":1,"height":0.23837209302325582,"text":"When you see a claim that a common drug or vitamin \"kills cancer cells in a petri dish\", keep in mind:"},{"left":0.0963302752293578,"top":0.9273255813953488,"width":0.7798165137614679,"height":0.055232558139534885,"text":"So does a handgun."}]}'
|
170
|
+
'{"http://imgs.xkcd.com/comics/cells.png":[{"left":0,"top":0,"width":1,"height":0.23837209302325582,"font_size":15,"text":"When you see a claim that a common drug or vitamin \"kills cancer cells in a petri dish\", keep in mind:"},{"left":0.0963302752293578,"top":0.9273255813953488,"width":0.7798165137614679,"height":0.055232558139534885,"font_size":16,"text":"So does a handgun."}]}'
|
143
171
|
end
|
144
172
|
let (:submit_hash_example) do
|
145
173
|
JSON.parse(submit_json_example)
|
@@ -158,14 +186,53 @@ describe Ballonizer do
|
|
158
186
|
|
159
187
|
# Definition who need others (no *_example)
|
160
188
|
let (:instance) { described_class.new(*ballonizer_new_args) }
|
189
|
+
let (:ballonize_page_call) do
|
190
|
+
lambda { instance.ballonize_page(original_page, page_url, mime_type, settings) }
|
191
|
+
end
|
161
192
|
let (:ballonized_page) do
|
162
|
-
|
193
|
+
ballonize_page_call.call
|
163
194
|
end
|
164
195
|
|
165
196
|
# TODO: verify if the style property has the correct values
|
166
197
|
describe '#ballonize_page' do
|
167
198
|
subject { ballonized_page }
|
168
199
|
|
200
|
+
context "when the mime-type isn't valid" do
|
201
|
+
let (:mime_type) { 'a invalid mime-type' }
|
202
|
+
it { expect(ballonize_page_call).to raise_error(Ballonizer::Error) }
|
203
|
+
end
|
204
|
+
context "when the mime-type is valid" do
|
205
|
+
context '(text/html)' do
|
206
|
+
let (:mime_type) { 'text/html; charset=utf8' }
|
207
|
+
it { expect(ballonize_page_call).to_not raise_error }
|
208
|
+
end
|
209
|
+
context '(application/xhtml+xml)' do
|
210
|
+
let (:mime_type) { 'application/xhtml+xml; charset=utf8' }
|
211
|
+
it { expect(ballonize_page_call).to_not raise_error }
|
212
|
+
end
|
213
|
+
end
|
214
|
+
context "when the mime-type is 'application/xhtml+xml'" do
|
215
|
+
context "but the page isn't a xml" do
|
216
|
+
let (:original_page) do
|
217
|
+
<<-END
|
218
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
219
|
+
"http://www.w3.org/TR/html4/strict.dtd">
|
220
|
+
<html>
|
221
|
+
<head>
|
222
|
+
<title>A title</title>
|
223
|
+
<!-- this isn't a valid xml because the meta tag isn't closed -->
|
224
|
+
<meta http-equiv="content-type" content="text/html" charset=UTF-8">
|
225
|
+
</head>
|
226
|
+
<body>
|
227
|
+
</body>
|
228
|
+
</html>
|
229
|
+
END
|
230
|
+
end
|
231
|
+
it 'return the original (not cloned) page argument, unmodified' do
|
232
|
+
expect(ballonized_page).to be(original_page)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
169
236
|
context 'when the page has no img elements to ballonize' do
|
170
237
|
it "don't make changes in the page" do
|
171
238
|
should be_equivalent_to(original_page)
|
@@ -181,7 +248,7 @@ describe Ballonizer do
|
|
181
248
|
page_with_images.to_s
|
182
249
|
end
|
183
250
|
it 'add a container around the img' do
|
184
|
-
should have_tag('
|
251
|
+
should have_tag('span', :with => { class: 'ballonizer_image_container' }) do
|
185
252
|
with_tag('img', :with => { alt: 'A test image' })
|
186
253
|
end
|
187
254
|
end
|
@@ -189,16 +256,15 @@ describe Ballonizer do
|
|
189
256
|
it 'add the ballons inside the container' do
|
190
257
|
# the parentheses of the 'should' are necessary, otherwise the
|
191
258
|
# conditions inside the block are silently not tested
|
192
|
-
should(have_tag('
|
259
|
+
should(have_tag('span', :with => { class: 'ballonizer_image_container' }) do
|
193
260
|
with_tag("img[alt='A test image']")
|
194
|
-
with_tag('
|
261
|
+
with_tag('span', { text: 'first ballon of first image',
|
195
262
|
with: { class: 'ballonizer_ballon' }})
|
196
|
-
with_tag('
|
263
|
+
with_tag('span', { text: 'second ballon of first image',
|
197
264
|
with: { class: 'ballonizer_ballon'}})
|
198
265
|
end)
|
199
266
|
end
|
200
267
|
end
|
201
|
-
# TODO: create this specs
|
202
268
|
context 'and the settings define to insert css' do
|
203
269
|
let (:ballonizer_settings) do
|
204
270
|
ballonizer_settings_example.merge({
|
@@ -241,10 +307,10 @@ describe Ballonizer do
|
|
241
307
|
end
|
242
308
|
it 'add a container around the imgs' do
|
243
309
|
# TODO: DRY this test
|
244
|
-
should(have_tag('
|
310
|
+
should(have_tag('span', :with => { class: 'ballonizer_image_container' }) do
|
245
311
|
with_tag('img', :with => { alt: 'the second test image' })
|
246
312
|
end)
|
247
|
-
should(have_tag('
|
313
|
+
should(have_tag('span', :with => { class: 'ballonizer_image_container' }) do
|
248
314
|
with_tag('img', :with => { alt: 'the third test image' })
|
249
315
|
end)
|
250
316
|
end
|
@@ -252,24 +318,24 @@ describe Ballonizer do
|
|
252
318
|
it 'add the ballons inside the containers' do
|
253
319
|
# TODO: break this spec in smaller parts, this specificate more
|
254
320
|
# than one thing
|
255
|
-
should(have_tag('
|
321
|
+
should(have_tag('span', :with => { class: 'ballonizer_image_container' }) do
|
256
322
|
# the second image have two versions, the second ballon is added
|
257
323
|
# in the second version, so here we verify if the ballonize_page
|
258
324
|
# recover the ballons of the last version
|
259
325
|
with_tag('img', :with => { alt: 'the second test image' })
|
260
|
-
with_tag('
|
326
|
+
with_tag('span', { text: 'first ballon of second image',
|
261
327
|
with: { class: 'ballonizer_ballon' }})
|
262
|
-
with_tag('
|
328
|
+
with_tag('span', { text: 'second ballon of second image',
|
263
329
|
with: { class: 'ballonizer_ballon' }})
|
264
330
|
end)
|
265
|
-
should(have_tag('
|
331
|
+
should(have_tag('span', :with => { class: 'ballonizer_image_container' }) do
|
266
332
|
# the third image have two versions, the second ballon is removed
|
267
333
|
# in the second version, so here we verify if the ballonize_page
|
268
334
|
# do not use a ballon of an old version in the image
|
269
335
|
with_tag('img', :with => { alt: 'the third test image' })
|
270
|
-
with_tag('
|
336
|
+
with_tag('span', { text: 'first ballon of third image',
|
271
337
|
with: { class: 'ballonizer_ballon' }})
|
272
|
-
without_tag('
|
338
|
+
without_tag('span', { text: 'second ballon of third image',
|
273
339
|
with: { class: 'ballonizer_ballon' }})
|
274
340
|
end)
|
275
341
|
end
|
@@ -283,7 +349,7 @@ describe Ballonizer do
|
|
283
349
|
page_with_images.to_s
|
284
350
|
end
|
285
351
|
it "don't add a container around the imgs" do
|
286
|
-
should_not have_tag('
|
352
|
+
should_not have_tag('span', :with => {
|
287
353
|
class: 'ballonizer_image_container'
|
288
354
|
})
|
289
355
|
end
|
@@ -437,6 +503,17 @@ describe Ballonizer do
|
|
437
503
|
end
|
438
504
|
end
|
439
505
|
|
506
|
+
context "when a ballon don't have font_size" do
|
507
|
+
let (:submit_hash) do
|
508
|
+
deep_copy(submit_hash_example)[submit_hash_example.keys.first]
|
509
|
+
.first.update({ font_size: nil })
|
510
|
+
end
|
511
|
+
|
512
|
+
it { should be_false }
|
513
|
+
|
514
|
+
include_examples 'and the second argument is true'
|
515
|
+
end
|
516
|
+
|
440
517
|
context 'when the submit contain a image without ballons' do
|
441
518
|
let (:submit_hash) do
|
442
519
|
{ submit_hash_example.keys.first => [] }
|
@@ -444,6 +521,7 @@ describe Ballonizer do
|
|
444
521
|
|
445
522
|
it { should be_true }
|
446
523
|
end
|
524
|
+
|
447
525
|
context 'when the hash is valid' do
|
448
526
|
it { should be_true }
|
449
527
|
|
@@ -480,14 +558,7 @@ describe Ballonizer do
|
|
480
558
|
|
481
559
|
it 'the ballonize_page add the ballons to the image' do
|
482
560
|
instance.process_submit_hash(submit_hash, Time.at(0))
|
483
|
-
expect(ballonized_page).to
|
484
|
-
{ text: 'the first ballon of the fourth image',
|
485
|
-
with: { class: 'ballonizer_ballon' } }
|
486
|
-
)
|
487
|
-
expect(ballonized_page).to have_tag('p',
|
488
|
-
{ text: 'the second ballon of the fourth image',
|
489
|
-
with: { class: 'ballonizer_ballon' } }
|
490
|
-
)
|
561
|
+
expect(ballonized_page).to have_ballons_as_submitted_by(submit_hash)
|
491
562
|
end
|
492
563
|
end
|
493
564
|
context 'when the submit refer to a image already with ballons' do
|
@@ -512,14 +583,7 @@ describe Ballonizer do
|
|
512
583
|
|
513
584
|
it 'the ballonize_page use the new ballons' do
|
514
585
|
instance.process_submit_hash(submit_hash, Time.at(0))
|
515
|
-
expect(ballonized_page).to
|
516
|
-
{ text: 'the first ballon (version 2) of the first image',
|
517
|
-
with: { class: 'ballonizer_ballon' } }
|
518
|
-
)
|
519
|
-
expect(ballonized_page).to have_tag('p',
|
520
|
-
{ text: 'the second ballon (version 2) of the first image',
|
521
|
-
with: { class: 'ballonizer_ballon' } }
|
522
|
-
)
|
586
|
+
expect(ballonized_page).to have_ballons_as_submitted_by(submit_hash)
|
523
587
|
end
|
524
588
|
end
|
525
589
|
end
|
@@ -549,9 +613,10 @@ describe Ballonizer do
|
|
549
613
|
# The submit hash is used to define the env_example
|
550
614
|
# (and in consequence the env)
|
551
615
|
let (:submit_hash) do
|
552
|
-
# this input is invalid because
|
616
|
+
# this input is invalid because have no font_size
|
553
617
|
{ 'http://comic-translation.com/tr/pt-BR/a_comic/imgs/4.jpg' => [
|
554
|
-
{ 'text' => '', 'left' => 0, 'top' => 0, 'width' => 0.5,
|
618
|
+
{ 'text' => 'test', 'left' => 0, 'top' => 0, 'width' => 0.5,
|
619
|
+
'height' => 0.5 }
|
555
620
|
]}
|
556
621
|
end
|
557
622
|
|
@@ -568,7 +633,8 @@ describe Ballonizer do
|
|
568
633
|
let(:submit_hash) do
|
569
634
|
{ 'http://comic-translation.com/tr/pt-BR/a_comic/imgs/4.jpg' => [
|
570
635
|
{ 'text' => 'the first ballon of the fourth image',
|
571
|
-
'left' => 0, 'top' => 0, 'width' => 0.5, 'height' => 0.5
|
636
|
+
'left' => 0, 'top' => 0, 'width' => 0.5, 'height' => 0.5,
|
637
|
+
'font_size' => 16 }
|
572
638
|
]}
|
573
639
|
end
|
574
640
|
|
@@ -581,10 +647,7 @@ describe Ballonizer do
|
|
581
647
|
|
582
648
|
it 'the ballonize_page add the ballons to the image' do
|
583
649
|
instance.process_submit(env)
|
584
|
-
expect(ballonized_page).to
|
585
|
-
{ text: 'the first ballon of the fourth image',
|
586
|
-
with: { class: 'ballonizer_ballon' } }
|
587
|
-
)
|
650
|
+
expect(ballonized_page).to have_ballons_as_submitted_by(submit_hash)
|
588
651
|
end
|
589
652
|
end
|
590
653
|
end
|