ballonizer 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/examples/ballonizer_app/config.ru +59 -0
- data/examples/ballonizer_app/index.html +159 -0
- data/examples/ballonizer_js_module/index.html +196 -0
- data/lib/assets/javascripts/ballonizer.js +482 -0
- data/lib/assets/stylesheets/ballonizer.css +78 -0
- data/lib/ballonizer.rb +201 -36
- data/spec/ballonizer_spec.rb +153 -2
- data/spec/javascripts/ballonizer_spec.js +568 -0
- data/spec/javascripts/fixtures/ballonized-xkcd-with-anchor-in-image.html +163 -0
- data/spec/javascripts/fixtures/ballonized-xkcd-with-ballons.html +163 -0
- data/spec/javascripts/fixtures/ballonized-xkcd-without-ballons.html +163 -0
- data/spec/javascripts/fixtures/xkcd.css +191 -0
- data/spec/javascripts/helpers/jasmine-jquery.js +660 -0
- data/spec/javascripts/helpers/jquery.simulate-ext.js +32 -0
- data/spec/javascripts/helpers/jquery.simulate.drag-n-drop.js +583 -0
- data/spec/javascripts/helpers/jquery.simulate.js +328 -0
- data/spec/javascripts/support/jasmine.yml +99 -0
- data/vendor/assets/javascripts/jquery-2.0.1.js +8837 -0
- data/vendor/assets/javascripts/jquery-ui-1.10.3.custom.min.js +6 -0
- data/vendor/assets/javascripts/jquery.json-2.4.min.js +24 -0
- data/vendor/assets/stylesheets/ui-lightness/images/animated-overlay.gif +0 -0
- data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
- data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
- data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_flat_10_000000_40x100.png +0 -0
- data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
- data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- data/vendor/assets/stylesheets/ui-lightness/images/ui-icons_222222_256x240.png +0 -0
- data/vendor/assets/stylesheets/ui-lightness/images/ui-icons_228ef1_256x240.png +0 -0
- data/vendor/assets/stylesheets/ui-lightness/images/ui-icons_ef8c08_256x240.png +0 -0
- data/vendor/assets/stylesheets/ui-lightness/images/ui-icons_ffd27a_256x240.png +0 -0
- data/vendor/assets/stylesheets/ui-lightness/images/ui-icons_ffffff_256x240.png +0 -0
- data/vendor/assets/stylesheets/ui-lightness/jquery-ui-1.10.3.custom.min.css +5 -0
- metadata +51 -3
data/lib/ballonizer.rb
CHANGED
@@ -4,6 +4,7 @@ require 'sequel'
|
|
4
4
|
require 'json'
|
5
5
|
require 'htmlentities'
|
6
6
|
require 'rack'
|
7
|
+
require 'sprockets'
|
7
8
|
|
8
9
|
# This gem provides mechanisms to allow ballons (or speech bubbles) to be
|
9
10
|
# added/removed/edited over images of a HTML or XHTML document and to be
|
@@ -16,7 +17,7 @@ require 'rack'
|
|
16
17
|
#
|
17
18
|
# This class lacks a lot of features like: access to an abstraction of the
|
18
19
|
# ballons, images and their relationship; control over users who edit the
|
19
|
-
# ballons; access to the old versions of the ballon set of a image (
|
20
|
+
# ballons; access to the old versions of the ballon set of a image (that
|
20
21
|
# are stored in the database, but only can be accessed directly by the
|
21
22
|
# Sequel::Database object). It's a work in progress, be warned to use
|
22
23
|
# carefully and motivated to contribute.
|
@@ -40,12 +41,10 @@ require 'rack'
|
|
40
41
|
# To use this class with your (rack isn't?) app you need to: create the
|
41
42
|
# necessary tables in a Sequel::Database object with Ballonizer.create_tables;
|
42
43
|
# create a ballonizer instance with the url where you gonna handle the ballon
|
43
|
-
# change requests. Handle the ballon changes request
|
44
|
-
# process_submit. Call instance.ballonize_page over the html
|
45
|
-
# have the images to be ballonized.
|
46
|
-
#
|
47
|
-
# the ui-lightness and ballonizer css in the page (provided by the gem).
|
48
|
-
# Check if the image match the css selector :img_to_ballonize_css_selector.
|
44
|
+
# change requests and where provide the assets. Handle the ballon changes request
|
45
|
+
# in that url with process_submit. Call instance.ballonize_page over the html
|
46
|
+
# documents that can have the images to be ballonized. Check if the image match
|
47
|
+
# the css selector :img_to_ballonize_css_selector.
|
49
48
|
#
|
50
49
|
# What's explained above is basically the example you can access with
|
51
50
|
# 'rake example' and is in the examples/ballonizer_app/config.ru file.
|
@@ -64,23 +63,93 @@ class Ballonizer
|
|
64
63
|
|
65
64
|
attr_accessor :db, :settings
|
66
65
|
|
66
|
+
# @api private Don't use the methods of this module. They are for internal use only.
|
67
|
+
module Workaround
|
68
|
+
def self.join_uris(base, relative)
|
69
|
+
base = base.end_with?('/') ? base : base + '/'
|
70
|
+
Addressable::URI.parse(base).join(relative).to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.deep_freeze(e)
|
74
|
+
e.each { | v | deep_freeze(v) } if e.is_a?(Enumerable)
|
75
|
+
e.freeze
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.parse_html_or_xhtml(doc)
|
79
|
+
# If you parse XHTML as HTML with Nokogiri and use to_s after the markup can be messed up
|
80
|
+
#
|
81
|
+
# Example: <meta name="description" content="not important" />
|
82
|
+
# becomes <meta name="description" content="not important" >
|
83
|
+
# To avoid this we parse a document that is XML valid as XML, and, otherwise as HTML
|
84
|
+
parsed_doc = nil
|
85
|
+
begin
|
86
|
+
# this also isn't a great way to do this
|
87
|
+
# the Nokogiri don't have exception classes, this way any StandardError will be silenced
|
88
|
+
options = Nokogiri::XML::ParseOptions::DEFAULT_XML &
|
89
|
+
Nokogiri::XML::ParseOptions::STRICT &
|
90
|
+
Nokogiri::XML::ParseOptions::NONET
|
91
|
+
parsed_doc = Nokogiri::XML::Document.parse(doc, nil, nil, options)
|
92
|
+
rescue
|
93
|
+
parsed_doc = Nokogiri::HTML(doc)
|
94
|
+
end
|
95
|
+
|
96
|
+
parsed_doc
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private_constant :Workaround
|
101
|
+
|
102
|
+
# The load paths of assets inside the gem and the files inside each path,
|
103
|
+
# in the order they need to be included (the files of the first path need
|
104
|
+
# to be included before the files in the second path, and the files in the
|
105
|
+
# same path need to be included in the specified order).
|
106
|
+
# Give preference to the asset(s)_* and *_html_links methods over this constant.
|
107
|
+
ASSETS = Workaround.deep_freeze([
|
108
|
+
['vendor/assets/javascripts', [
|
109
|
+
'jquery-2.0.1.js',
|
110
|
+
'jquery.json-2.4.min.js',
|
111
|
+
'jquery-ui-1.10.3.custom.min.js']],
|
112
|
+
['lib/assets/javascripts', [
|
113
|
+
'ballonizer.js']],
|
114
|
+
['vendor/assets/stylesheets', [
|
115
|
+
'ui-lightness/jquery-ui-1.10.3.custom.min.css']],
|
116
|
+
['lib/assets/stylesheets', [
|
117
|
+
'ballonizer.css']]
|
118
|
+
])
|
119
|
+
|
67
120
|
# The default #settings
|
68
121
|
DEFAULT_SETTINGS = {
|
69
122
|
# The css selector used to define the elements to ballonize.
|
70
123
|
img_to_ballonize_css_selector: 'img.to_ballonize',
|
71
124
|
# A url to be used in the client-side action attribute of the form for
|
72
|
-
# ballon submition. The value will be used in the javascript snippet
|
125
|
+
# ballon submition. The value will be used in the javascript snippet that
|
73
126
|
# initialize the ballonizer client javascript allowing ballon edition
|
74
127
|
# (and consequently creating the form).
|
75
128
|
form_handler_url: '#',
|
76
|
-
# Define if the javascript code
|
129
|
+
# Define if the javascript code that allow edition will be added to the page.
|
77
130
|
# (this don't refer to the jquery-* libs and the ballonizer.js only the
|
78
131
|
# snippet to execute when the page is ready)
|
79
|
-
add_js_for_edition: true
|
132
|
+
add_js_for_edition: true,
|
133
|
+
# A path string to prefix each href of the css stylesheet links generated
|
134
|
+
# by the js_libs_html_links, and, possibly, added by the ballonize_page
|
135
|
+
# object. Example: if you use Ballonizer.assets_app mapped to '/assets'
|
136
|
+
# then use '/assets' here. This is used with the :add_required_css setting.
|
137
|
+
css_asset_path_for_link: nil,
|
138
|
+
# If the ballonize_page method will add or not the html generated by
|
139
|
+
# #css_html_links (require the :css_asset_path_for_link to be defined).
|
140
|
+
add_required_css: false,
|
141
|
+
# A path string to prefix each js source src generated by the
|
142
|
+
# object. Example: if you use Ballonizer.assets_app mapped to '/assets'
|
143
|
+
# then use '/assets' here. This is used with the
|
144
|
+
# :add_required_js_libs_for_edition setting.
|
145
|
+
js_asset_path_for_link: nil,
|
146
|
+
# If the ballonize_page method will add or not the html generated by
|
147
|
+
# #js_libs_html_links (require the :js_asset_path_for_link to be defined).
|
148
|
+
add_required_js_libs_for_edition: false
|
80
149
|
}.freeze.each { | _, v| v.freeze }
|
81
150
|
|
82
151
|
# Create a new Ballonizer object from a Sequel Database (with the expected
|
83
|
-
# tables,
|
152
|
+
# tables, that can be created with Ballonizer.create_tables) and a optional
|
84
153
|
# hash of settings.
|
85
154
|
# @param db [Sequel::Database] A Sequel::Database with tables as described
|
86
155
|
# @param settings [Hash{Symbol => String}] A optional hash of settings. The
|
@@ -256,7 +325,9 @@ class Ballonizer
|
|
256
325
|
end
|
257
326
|
|
258
327
|
# Wrap each image to ballonize with a container, add its ballons to the
|
259
|
-
# container and add the js snippet for the
|
328
|
+
# container and, possibly, add the css and js libs and snippet for the
|
329
|
+
# edition initialization. Don't make any change if the page has no images
|
330
|
+
# to ballonize.
|
260
331
|
# @param page [String] The (X)HTML page.
|
261
332
|
# @param page_url [String] The url of the page to be ballonized, necessary
|
262
333
|
# to make absolute the src attribute of img (if it's relative).
|
@@ -284,9 +355,15 @@ class Ballonizer
|
|
284
355
|
end
|
285
356
|
end
|
286
357
|
|
358
|
+
head = parsed_page.at_css('head')
|
359
|
+
if settings[:add_required_css]
|
360
|
+
head.children.last.add_next_sibling(self.css_html_links)
|
361
|
+
end
|
362
|
+
if settings[:add_required_js_libs_for_edition]
|
363
|
+
head.children.last.add_next_sibling(self.js_libs_html_links)
|
364
|
+
end
|
287
365
|
if settings[:add_js_for_edition]
|
288
|
-
|
289
|
-
.add_next_sibling(self.js_load_snippet)
|
366
|
+
head.children.last.add_next_sibling(self.js_load_snippet)
|
290
367
|
end
|
291
368
|
end
|
292
369
|
|
@@ -310,7 +387,7 @@ class Ballonizer
|
|
310
387
|
# Don't use this method. It is for internal use only.
|
311
388
|
# @note This method don't make distinction between a image in the database
|
312
389
|
# without any ballons (removed in the last version, by example) or a image
|
313
|
-
#
|
390
|
+
# that isn't in the database (both return a empty array).
|
314
391
|
def last_ballon_set_of_image(img_src)
|
315
392
|
db_image = self.db[:images].first({img_src: img_src})
|
316
393
|
if db_image
|
@@ -372,30 +449,118 @@ class Ballonizer
|
|
372
449
|
end
|
373
450
|
end
|
374
451
|
|
375
|
-
#
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
Nokogiri::XML::ParseOptions::STRICT &
|
389
|
-
Nokogiri::XML::ParseOptions::NONET
|
390
|
-
parsed_doc = Nokogiri::XML::Document.parse(doc, nil, nil, options)
|
391
|
-
rescue
|
392
|
-
parsed_doc = Nokogiri::HTML(doc)
|
393
|
-
end
|
452
|
+
# The (X)HTML fragment with the link tags that are added to the page by
|
453
|
+
# ballonize_page if the :add_required_css setting is true (the default
|
454
|
+
# is false). If the :css_asset_path_for_link isn't set (what is the
|
455
|
+
# default) this method return nil.
|
456
|
+
# @return [String,NilClass] A frozen string.
|
457
|
+
def css_html_links
|
458
|
+
return nil unless settings[:css_asset_path_for_link]
|
459
|
+
return @css_html_links if @css_html_links
|
460
|
+
|
461
|
+
link_template = '<link rel="stylesheet" type="text/css" href="PATH" />'
|
462
|
+
css_paths = self.class.asset_logical_paths.select do | p |
|
463
|
+
/^.+\.css$/.match(p)
|
464
|
+
end
|
394
465
|
|
395
|
-
|
466
|
+
links = css_paths.map do | p |
|
467
|
+
p = Workaround.join_uris(settings[:css_asset_path_for_link], p)
|
468
|
+
link_template.sub('PATH', p)
|
396
469
|
end
|
470
|
+
|
471
|
+
@css_html_links = links.join('').freeze
|
397
472
|
end
|
398
473
|
|
399
|
-
|
474
|
+
# The (X)HTML fragment with the script tags that are added to the page by
|
475
|
+
# ballonize_page if the :add_required_js_libs_for_edition setting is true
|
476
|
+
# (the default is false). If the :js_asset_path_for_link isn't set (what
|
477
|
+
# is the default) this method return nil.
|
478
|
+
# @return [String,NilClass] A frozen string.
|
479
|
+
def js_libs_html_links
|
480
|
+
return nil unless settings[:js_asset_path_for_link]
|
481
|
+
return @js_libs_html_links if @js_libs_html_links
|
482
|
+
|
483
|
+
link_template = '<script type="text/javascript" src="PATH" />'
|
484
|
+
js_libs_paths = self.class.asset_logical_paths.select do | p |
|
485
|
+
/^.+\.js$/.match(p)
|
486
|
+
end
|
487
|
+
|
488
|
+
links = js_libs_paths.map do | p |
|
489
|
+
p = Workaround.join_uris(settings[:js_asset_path_for_link], p)
|
490
|
+
link_template.sub('PATH', p)
|
491
|
+
end
|
492
|
+
|
493
|
+
@js_libs_html_links = links.join('').freeze
|
494
|
+
end
|
495
|
+
|
496
|
+
# List of paths (relative to the gem root directory) to the directories with
|
497
|
+
# the css and js provided by the gem.
|
498
|
+
# @return [Array<String>] A frozen array of frozen strings.
|
499
|
+
def self.asset_load_paths
|
500
|
+
return @asset_load_paths if @asset_load_paths
|
501
|
+
|
502
|
+
absolute_lib_dir = File.dirname(File.realpath(__FILE__))
|
503
|
+
ballonizer_gem_root_dir = File.expand_path('../', absolute_lib_dir)
|
504
|
+
|
505
|
+
@asset_load_paths = ASSETS.map do | load_path_and_files |
|
506
|
+
load_path = load_path_and_files.first
|
507
|
+
File.expand_path(load_path, ballonizer_gem_root_dir)
|
508
|
+
end
|
509
|
+
|
510
|
+
@asset_load_paths.flatten!
|
511
|
+
@asset_load_paths.freeze
|
512
|
+
end
|
513
|
+
|
514
|
+
# List of logical paths to the css and js assets. The assets_app respond to
|
515
|
+
# any requisition to one of these paths.
|
516
|
+
# @return [Array<String>] A frozen array of frozen strings.
|
517
|
+
def self.asset_logical_paths
|
518
|
+
return @asset_logical_paths if @asset_logical_paths
|
519
|
+
|
520
|
+
@asset_logical_paths = ASSETS.map do | load_path_and_files |
|
521
|
+
load_path_and_files.last
|
522
|
+
end
|
523
|
+
|
524
|
+
@asset_logical_paths.flatten!
|
525
|
+
@asset_logical_paths.freeze
|
526
|
+
end
|
527
|
+
|
528
|
+
# List of absolute filepaths to the css and js files needed by the client
|
529
|
+
# counterpart and provided by the gem. To all who not want to use assets_app.
|
530
|
+
# @return [Array<String>] A frozen array of frozen strings.
|
531
|
+
# @see Ballonizer.assets_app
|
532
|
+
def self.asset_absolute_paths
|
533
|
+
return @asset_absolute_paths if @asset_absolute_paths
|
534
|
+
|
535
|
+
absolute_lib_dir = File.dirname(File.realpath(__FILE__))
|
536
|
+
ballonizer_gem_root_dir = File.expand_path('../', absolute_lib_dir)
|
537
|
+
|
538
|
+
@asset_absolute_paths = ASSETS.map do | load_path_and_files |
|
539
|
+
relative_load_path, filepaths = *load_path_and_files
|
540
|
+
absolute_load_path = File.expand_path(relative_load_path, ballonizer_gem_root_dir)
|
541
|
+
|
542
|
+
filepaths.map do | filepath |
|
543
|
+
File.expand_path(filepath, absolute_load_path)
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
@asset_absolute_paths.flatten!
|
548
|
+
@asset_absolute_paths.freeze
|
549
|
+
end
|
550
|
+
|
551
|
+
# A Rack app that provide the gem css and js. Each call to this method return
|
552
|
+
# a new object (clone). The Sprockets::Environment isn't frozen because it
|
553
|
+
# can't be used with 'run' in a rack app if frozen.
|
554
|
+
# @return [Sprockets::Environment]
|
555
|
+
# @see Ballonizer.assets_app
|
556
|
+
def self.assets_app
|
557
|
+
# dont freeze because run don't work in a frozen sprockets env
|
558
|
+
return @assets_app.clone if @assets_app
|
559
|
+
@assets_app = Sprockets::Environment.new
|
560
|
+
asset_load_paths.each do | load_path |
|
561
|
+
@assets_app.prepend_path load_path
|
562
|
+
end
|
563
|
+
@assets_app.clone
|
564
|
+
end
|
400
565
|
end
|
401
566
|
|
data/spec/ballonizer_spec.rb
CHANGED
@@ -3,6 +3,7 @@ require 'rspec-html-matchers'
|
|
3
3
|
# Avoid to use equivalent-xml, the specs break with cosmetic changes this way
|
4
4
|
require 'equivalent-xml'
|
5
5
|
require 'stringio'
|
6
|
+
require 'rexml/document'
|
6
7
|
|
7
8
|
# make the changes in the BD restricted to the example
|
8
9
|
RSpec.configure do |c|
|
@@ -11,6 +12,26 @@ RSpec.configure do |c|
|
|
11
12
|
end
|
12
13
|
end
|
13
14
|
|
15
|
+
RSpec::Matchers.define :exist_in_filesystem do
|
16
|
+
match do | actual |
|
17
|
+
if actual.respond_to? :all?
|
18
|
+
actual.all? { | filename | File.exist?(filename) }
|
19
|
+
else
|
20
|
+
File.exist? actual
|
21
|
+
end
|
22
|
+
end
|
23
|
+
failure_message_for_should do | actual |
|
24
|
+
if actual.respond_to? :all?
|
25
|
+
"expected #{actual} to be a list of absolute filepaths for existing files or directories"
|
26
|
+
else
|
27
|
+
"expected #{actual} to be a absolute filepath for an existing file or directory"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
description do
|
31
|
+
"be a list of absolute paths for existing files or directories"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
14
35
|
describe Ballonizer do
|
15
36
|
|
16
37
|
DB = Sequel.sqlite
|
@@ -63,8 +84,11 @@ describe Ballonizer do
|
|
63
84
|
# Definitions ending with '_example' are to be cloned and defined in a
|
64
85
|
# context without the sufix. Definitions without the sufix are used in the
|
65
86
|
# specs and may require the definition of some without '_example' counterparts.
|
87
|
+
let (:ballonizer_settings_example) do
|
88
|
+
{}
|
89
|
+
end
|
66
90
|
let (:ballonizer_new_args_example) do
|
67
|
-
[DB,
|
91
|
+
[DB, ballonizer_settings]
|
68
92
|
end
|
69
93
|
# TODO: This isn't a valid Rack env, to turn it in a valid env will be
|
70
94
|
# necessary to add all obrigatory 'rack.' variables described in:
|
@@ -123,6 +147,7 @@ describe Ballonizer do
|
|
123
147
|
|
124
148
|
# definitions to be overriden in specific contexts (by doing a clone of the
|
125
149
|
# '_example' counterpart and changing what is needed)
|
150
|
+
let (:ballonizer_settings) { ballonizer_settings_example }
|
126
151
|
let (:ballonizer_new_args) { ballonizer_new_args_example }
|
127
152
|
let (:env) { env_example }
|
128
153
|
let (:original_page) { original_page_example.to_s }
|
@@ -173,6 +198,35 @@ describe Ballonizer do
|
|
173
198
|
end)
|
174
199
|
end
|
175
200
|
end
|
201
|
+
# TODO: create this specs
|
202
|
+
context 'and the settings define to insert css' do
|
203
|
+
let (:ballonizer_settings) do
|
204
|
+
ballonizer_settings_example.merge({
|
205
|
+
add_required_css: true,
|
206
|
+
css_asset_path_for_link: 'assets/css'
|
207
|
+
})
|
208
|
+
end
|
209
|
+
|
210
|
+
it do
|
211
|
+
# the example html don't have any link tag, so if there one
|
212
|
+
# it was added by the method
|
213
|
+
should have_tag('link', :with => { type: 'text/css' })
|
214
|
+
end
|
215
|
+
end
|
216
|
+
context 'and the settings define to insert js' do
|
217
|
+
let (:ballonizer_settings) do
|
218
|
+
ballonizer_settings_example.merge({
|
219
|
+
# this option is added to avoid a false positive in the test
|
220
|
+
add_js_for_edition: false,
|
221
|
+
add_required_js_libs_for_edition: true,
|
222
|
+
js_asset_path_for_link: 'assets/js'
|
223
|
+
})
|
224
|
+
end
|
225
|
+
|
226
|
+
it do
|
227
|
+
should have_tag('script', :with => { type: 'text/javascript' })
|
228
|
+
end
|
229
|
+
end
|
176
230
|
end
|
177
231
|
context 'and more than one of them is to be ballonized' do
|
178
232
|
let (:original_page) do
|
@@ -488,7 +542,6 @@ describe Ballonizer do
|
|
488
542
|
end
|
489
543
|
|
490
544
|
describe '#process_submit' do
|
491
|
-
|
492
545
|
# As process_submit use the #valid_submit_json? and #process_submit_hash
|
493
546
|
# we only make the tests here for example and its not the ideia cover the
|
494
547
|
# cases already covered in the specs of the two methods
|
@@ -535,5 +588,103 @@ describe Ballonizer do
|
|
535
588
|
end
|
536
589
|
end
|
537
590
|
end
|
591
|
+
|
592
|
+
describe '#css_html_links' do
|
593
|
+
context "when the path for the css isn't configured" do
|
594
|
+
it 'returns nil' do
|
595
|
+
expect(instance.css_html_links).to eq nil
|
596
|
+
end
|
597
|
+
end
|
598
|
+
context 'when the path for the css is configured' do
|
599
|
+
let (:ballonizer_settings) do
|
600
|
+
ballonizer_settings_example.merge({
|
601
|
+
css_asset_path_for_link: 'assets/css'
|
602
|
+
})
|
603
|
+
end
|
604
|
+
|
605
|
+
it 'return a HTML string with links prefixed by the path' do
|
606
|
+
REXML::Document.new("<root>#{instance.css_html_links}</root>")
|
607
|
+
.root.children.each do | e |
|
608
|
+
expect(e.attributes['href']).to match(/^assets\/css/)
|
609
|
+
end
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
describe '#js_libs_html_links' do
|
615
|
+
context "when the path for the js libs isn't configured" do
|
616
|
+
it 'returns nil' do
|
617
|
+
expect(instance.js_libs_html_links).to eq nil
|
618
|
+
end
|
619
|
+
end
|
620
|
+
context 'when the path for the js libs is configured' do
|
621
|
+
let (:ballonizer_settings) do
|
622
|
+
ballonizer_settings_example.merge({
|
623
|
+
js_asset_path_for_link: 'assets/js'
|
624
|
+
})
|
625
|
+
end
|
626
|
+
|
627
|
+
it 'return a HTML string with links prefixed by the path' do
|
628
|
+
REXML::Document.new("<root>#{instance.js_libs_html_links}</root>")
|
629
|
+
.root.children.each do | e |
|
630
|
+
expect(e.attributes['src']).to match(/^assets\/js/)
|
631
|
+
end
|
632
|
+
end
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
describe '.asset_load_paths' do
|
637
|
+
it 'return an array of paths who exist in the gem root dir' do
|
638
|
+
# TODO: change to __dir__ when the 2.0 become widely adopted
|
639
|
+
spec_dir = File.dirname(File.realpath(__FILE__))
|
640
|
+
gem_root_dir = File.expand_path('../', spec_dir)
|
641
|
+
|
642
|
+
absolute_load_paths = described_class.asset_load_paths.map do | path |
|
643
|
+
File.expand_path(path, gem_root_dir)
|
644
|
+
end
|
645
|
+
|
646
|
+
expect(absolute_load_paths).to exist_in_filesystem
|
647
|
+
end
|
648
|
+
end
|
649
|
+
|
650
|
+
describe '.asset_absolute_paths' do
|
651
|
+
it 'return an array of absolute filepaths who exist' do
|
652
|
+
expect(described_class.asset_absolute_paths).to exist_in_filesystem
|
653
|
+
end
|
654
|
+
end
|
655
|
+
|
656
|
+
describe '.asset_logical_paths' do
|
657
|
+
it 'return the last part of the asset_absolute_paths' do
|
658
|
+
logical_paths = described_class.asset_logical_paths
|
659
|
+
absolute_paths = described_class.asset_absolute_paths
|
660
|
+
|
661
|
+
are_last_part_of_absolute = logical_paths.all? do | lp |
|
662
|
+
absolute_paths.any? { | ap | ap.end_with? lp }
|
663
|
+
end
|
664
|
+
|
665
|
+
expect(are_last_part_of_absolute).to be_true
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
describe '.assets_app' do
|
670
|
+
let (:envs) do
|
671
|
+
described_class.asset_logical_paths.map do | asset_logical_path |
|
672
|
+
env_example.merge({
|
673
|
+
'HTTP_HOST' => 'example.net',
|
674
|
+
'SERVER_NAME' => 'example.net',
|
675
|
+
'PATH_INFO' => asset_logical_path,
|
676
|
+
'REQUEST_METHOD' => 'GET',
|
677
|
+
'rack.input' => nil,
|
678
|
+
'CONTENT_TYPE' => nil,
|
679
|
+
'CONTENT_LENGTH' => nil
|
680
|
+
})
|
681
|
+
end
|
682
|
+
end
|
683
|
+
it 'provide the css and js libs required by the gem' do
|
684
|
+
envs.each do | env |
|
685
|
+
expect(described_class.assets_app.call(env)[0]).to eq 200
|
686
|
+
end
|
687
|
+
end
|
688
|
+
end
|
538
689
|
end
|
539
690
|
|