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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5bf4f7c8da8c6850ded2132c67beebc4bb5306ff
|
4
|
+
data.tar.gz: 8238aea52c3812bdb5ef6113744d2c2f01d0e488
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7b614154da4bf1e78483c9266e067d33a425f57dd4d10f662732163316a5852b76aac86e59aba5e591ac9531d45d1829b1990b9e3b6d349d2f6ee2693b8d527
|
7
|
+
data.tar.gz: 4ebfcf50deafb861e2cce5f5e20120399e133748ece9865dec01c1def8cf936ff81b926d6e4f1fbca8aca39c8ff6754507a9743c2d1074813a7ef5e1150d31b8
|
@@ -13,6 +13,7 @@ html_name = 'index.html'
|
|
13
13
|
html = File.read("#{path_rake_to_app}#{html_name}")
|
14
14
|
|
15
15
|
ballonizer = Ballonizer.new(db_uri, {
|
16
|
+
img_to_ballonize_css_selector: '#comic img',
|
16
17
|
create_tables_if_none: true,
|
17
18
|
form_handler_url: '/request_handler',
|
18
19
|
add_required_css: true,
|
@@ -26,9 +27,10 @@ app = Rack::Builder.new do
|
|
26
27
|
run(lambda do | env |
|
27
28
|
# the url is needed to make relative paths to images absolute
|
28
29
|
request = Rack::Request.new(env)
|
29
|
-
|
30
|
+
mime_type = 'application/xhtml+xml'
|
31
|
+
ballonized_page = ballonizer.ballonize_page(html, request.url, mime_type)
|
30
32
|
|
31
|
-
[200, {}, [ballonized_page]]
|
33
|
+
[200, { 'content-type' => mime_type }, [ballonized_page]]
|
32
34
|
end)
|
33
35
|
end
|
34
36
|
|
@@ -1,159 +1,107 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
<a href="http://
|
86
|
-
|
87
|
-
|
88
|
-
<a
|
89
|
-
|
90
|
-
|
91
|
-
<a href="http://
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
<img src="http://imgs.xkcd.com/s/a899e84.jpg" width="520"
|
107
|
-
height="100" alt="Selected Comics" usemap="#comicmap" />
|
108
|
-
<map id="comicmap">
|
109
|
-
<!-- http://code.google.com/p/chromium/issues/detail?id=108489 Might be MIME dependant. -->
|
110
|
-
<area shape="rect" coords="0,0,100,100" href="http://xkcd.com/150/"
|
111
|
-
alt="Grownups" />
|
112
|
-
<area shape="rect" coords="104,0,204,100" href="http://xkcd.com/730/"
|
113
|
-
alt="Circuit Diagram" />
|
114
|
-
<area shape="rect" coords="208,0,308,100" href="http://xkcd.com/162/"
|
115
|
-
alt="Angular Momentum" />
|
116
|
-
<area shape="rect" coords="312,0,412,100" href="http://xkcd.com/688/"
|
117
|
-
alt="Self-Description" />
|
118
|
-
<area shape="rect" coords="416,0,520,100" href="http://xkcd.com/556/"
|
119
|
-
alt="Alternative Energy Revolution" />
|
120
|
-
</map>
|
121
|
-
<a href="http://xkcd.com/rss.xml">RSS Feed</a>-
|
122
|
-
<a href="http://xkcd.com/atom.xml">Atom Feed</a></div>
|
123
|
-
<br />
|
124
|
-
<div id="comicLinks">Comics I enjoy:
|
125
|
-
<br />
|
126
|
-
<a href="http://threewordphrase.com/">Three Word Phrase</a>,
|
127
|
-
<a href="http://oglaf.com/">Oglaf</a>(nsfw),
|
128
|
-
<a href="http://www.smbc-comics.com/">SMBC</a>,
|
129
|
-
<a href="http://www.qwantz.com">Dinosaur Comics</a>,
|
130
|
-
<a href="http://www.asofterworld.com">A Softer World</a>,
|
131
|
-
<a href="http://buttersafe.com/">Buttersafe</a>,
|
132
|
-
<a href="http://pbfcomics.com/">Perry Bible Fellowship</a>,
|
133
|
-
<a href="http://questionablecontent.net/">Questionable
|
134
|
-
Content</a>,
|
135
|
-
<a href="http://www.buttercupfestival.com/">Buttercup
|
136
|
-
Festival</a></div>
|
137
|
-
<p>Warning: this comic occasionally contains strong language
|
138
|
-
(which may be unsuitable for children), unusual humor (which
|
139
|
-
may be unsuitable for adults), and advanced mathematics
|
140
|
-
(which may be unsuitable for liberal-arts majors).</p>
|
141
|
-
<div id="footnote">BTC 1NEPgrUmed3VyXpqbYZom7YVJ8MozYrNWx
|
142
|
-
<br />We did not invent the algorithm. The algorithm
|
143
|
-
consistently finds Jesus. The algorithm killed Jeeves.
|
144
|
-
<br />The algorithm is banned in China. The algorithm is from
|
145
|
-
Jersey. The algorithm constantly finds Jesus.
|
146
|
-
<br />This is not the algorithm. This is close.</div>
|
147
|
-
<div id="licenseText">
|
148
|
-
<p>This work is licensed under a
|
149
|
-
<a href="http://creativecommons.org/licenses/by-nc/2.5/">
|
150
|
-
Creative Commons Attribution-NonCommercial 2.5
|
151
|
-
License</a>.</p>
|
152
|
-
<p>This means you're free to copy and share these comics
|
153
|
-
(but not to sell them).
|
154
|
-
<a rel="license" href="http://xkcd.com/license.html">More details</a>.</p>
|
155
|
-
</div>
|
156
|
-
</div>
|
157
|
-
</body>
|
1
|
+
<?xml version="1.0" encoding="UTF-8" ?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
4
|
+
<html version="-//W3C//DTD XHTML 1.1//EN" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
5
|
+
<head>
|
6
|
+
<link rel="stylesheet" type="text/css" href="http://xkcd.com/s/d16ebb.css" title="Default"/>
|
7
|
+
<title>xkcd: Cells</title>
|
8
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
9
|
+
<link rel="shortcut icon" href="http://xkcd.com/s/919f27.ico" type="image/x-icon"/>
|
10
|
+
<link rel="icon" href="http://xkcd.com/s/919f27.ico" type="image/x-icon"/>
|
11
|
+
<link rel="alternate" type="application/atom+xml" title="Atom 1.0" href="http://xkcd.com/atom.xml"/>
|
12
|
+
<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="http://xkcd.com/rss.xml"/>
|
13
|
+
<link rel="apple-touch-icon-precomposed" href="http://xkcd.com/s/d9522a.png" />
|
14
|
+
</head>
|
15
|
+
<body>
|
16
|
+
<div id="topContainer">
|
17
|
+
<div id="topLeft">
|
18
|
+
<ul>
|
19
|
+
<li><a href="http://xkcd.com/archive">Archive</a></li>
|
20
|
+
<li><a href="http://what-if.xkcd.com">What If?</a></li>
|
21
|
+
<li><a href="http://blag.xkcd.com">Blag</a></li>
|
22
|
+
<li><a href="http://store.xkcd.com/">Store</a></li>
|
23
|
+
<li><a rel="author" href="http://xkcd.com/about">About</a></li>
|
24
|
+
</ul>
|
25
|
+
</div>
|
26
|
+
<div id="topRight">
|
27
|
+
<div id="masthead">
|
28
|
+
<span><a href="/"><img src="http://imgs.xkcd.com/static/terrible_small_logo.png" alt="xkcd.com logo" height="83" width="185"/></a></span>
|
29
|
+
<span id="slogan">A webcomic of romance,<br/> sarcasm, math, and language.</span>
|
30
|
+
</div>
|
31
|
+
<div id="news">
|
32
|
+
You can get the Subways comic as a <a href="http://store-xkcd-com.myshopify.com/products/subways">poster</a>!
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
<div id="bgLeft" class="bg box"></div>
|
36
|
+
<div id="bgRight" class="bg box"></div>
|
37
|
+
</div>
|
38
|
+
<div id="middleContainer" class="box">
|
39
|
+
|
40
|
+
<div id="ctitle">Cells</div>
|
41
|
+
<ul class="comicNav">
|
42
|
+
<li><a href="http://xkcd.com/1/">|<</a></li>
|
43
|
+
<li><a rel="prev" href="http://xkcd.com/1216/" accesskey="p">< Prev</a></li>
|
44
|
+
<li><a href="http://dynamic.xkcd.com/random/comic/">Random</a></li>
|
45
|
+
<li><a rel="next" href="http://xkcd.com/1218/" accesskey="n">Next ></a></li>
|
46
|
+
<li><a href="/">>|</a></li>
|
47
|
+
</ul>
|
48
|
+
<div id="comic">
|
49
|
+
<img src="http://imgs.xkcd.com/comics/cells.png" title="Now, if it selectively kills cancer cells in a petri dish, you can be sure it's at least a great breakthrough for everyone suffering from petri dish cancer." alt="Cells" />
|
50
|
+
</div>
|
51
|
+
<ul class="comicNav">
|
52
|
+
<li><a href="http://xkcd.com/1/">|<</a></li>
|
53
|
+
<li><a rel="prev" href="http://xkcd.com/1216/" accesskey="p">< Prev</a></li>
|
54
|
+
<li><a href="http://dynamic.xkcd.com/random/comic/">Random</a></li>
|
55
|
+
<li><a rel="next" href="http://xkcd.com/1218/" accesskey="n">Next ></a></li>
|
56
|
+
<li><a href="http://xkcd.com/">>|</a></li>
|
57
|
+
</ul>
|
58
|
+
<br />
|
59
|
+
Permanent link to this comic: http://xkcd.com/1217/<br />
|
60
|
+
Image URL (for hotlinking/embedding): http://imgs.xkcd.com/comics/cells.png
|
61
|
+
<div id="transcript" style="display: none">When you see a claim that a common drug or vitamin "kills cancer cells in a petri dish," keep in mind:
|
62
|
+
[[A scientist stands on a chair next to a desk, pointing a gun at a petri dish. There is a microscope on the desk.]]
|
63
|
+
So does a handgun.
|
64
|
+
|
65
|
+
{{Title text: Now, if it selectively kills cancer cells in a petri dish, you can be sure it's at least a great breakthrough for everyone suffering from petri dish cancer.}}</div>
|
66
|
+
</div>
|
67
|
+
<div id="bottom" class="box">
|
68
|
+
<img src="http://imgs.xkcd.com/s/a899e84.jpg" width="520" height="100" alt="Selected Comics" usemap="#comicmap"/>
|
69
|
+
<map id="comicmap">
|
70
|
+
<!-- http://code.google.com/p/chromium/issues/detail?id=108489 Might be MIME dependent. -->
|
71
|
+
<area shape="rect" coords="0,0,100,100" href="http://xkcd.com/150/" alt="Grownups"/>
|
72
|
+
<area shape="rect" coords="104,0,204,100" href="http://xkcd.com/730/" alt="Circuit Diagram"/>
|
73
|
+
<area shape="rect" coords="208,0,308,100" href="http://xkcd.com/162/" alt="Angular Momentum"/>
|
74
|
+
<area shape="rect" coords="312,0,412,100" href="http://xkcd.com/688/" alt="Self-Description"/>
|
75
|
+
<area shape="rect" coords="416,0,520,100" href="http://xkcd.com/556/" alt="Alternative Energy Revolution"/>
|
76
|
+
</map>
|
77
|
+
<div>
|
78
|
+
Search comic titles and transcripts:
|
79
|
+
<a href="http://xkcd.com/rss.xml">RSS Feed</a> - <a href="/atom.xml">Atom Feed</a>
|
80
|
+
</div>
|
81
|
+
<br />
|
82
|
+
<div id="comicLinks">
|
83
|
+
Comics I enjoy:<br/>
|
84
|
+
<a href="http://threewordphrase.com/">Three Word Phrase</a>,
|
85
|
+
<a href="http://oglaf.com/">Oglaf</a> (nsfw),
|
86
|
+
<a href="http://www.smbc-comics.com/">SMBC</a>,
|
87
|
+
<a href="http://www.qwantz.com">Dinosaur Comics</a>,
|
88
|
+
<a href="http://www.asofterworld.com">A Softer World</a>,
|
89
|
+
<a href="http://buttersafe.com/">Buttersafe</a>,
|
90
|
+
<a href="http://pbfcomics.com/">Perry Bible Fellowship</a>,
|
91
|
+
<a href="http://questionablecontent.net/">Questionable Content</a>,
|
92
|
+
<a href="http://www.buttercupfestival.com/">Buttercup Festival</a>
|
93
|
+
</div>
|
94
|
+
<p>Warning: this comic occasionally contains strong language (which may be unsuitable for children), unusual humor (which may be unsuitable for adults), and advanced mathematics (which may be unsuitable for liberal-arts majors).</p>
|
95
|
+
<div id="footnote">BTC 1NfBXWqseXc9rCBc3Cbbu6HjxYssFUgkH6<br />We did not invent the algorithm. The algorithm consistently finds Jesus. The algorithm killed Jeeves. <br/>The algorithm is banned in China. The algorithm is from Jersey. The algorithm constantly finds Jesus.<br/>This is not the algorithm. This is close.</div>
|
96
|
+
<div id="licenseText">
|
97
|
+
<p>
|
98
|
+
This work is licensed under a
|
99
|
+
<a href="http://creativecommons.org/licenses/by-nc/2.5/">Creative Commons Attribution-NonCommercial 2.5 License</a>.
|
100
|
+
</p><p>
|
101
|
+
This means you're free to copy and share these comics (but not to sell them). <a rel="license" href="http://xkcd.com/license.html">More details</a>.</p>
|
102
|
+
</div>
|
103
|
+
</div>
|
104
|
+
</body>
|
105
|
+
<!-- Layout by Ian Clasbey, davean, and chromakode -->
|
158
106
|
</html>
|
159
107
|
|
Binary file
|
@@ -9,9 +9,9 @@
|
|
9
9
|
href="http://imgs.xkcd.com/static/styles_short_beta.css"
|
10
10
|
title="Default" />
|
11
11
|
<link rel="stylesheet" type="text/css"
|
12
|
-
href="../../
|
12
|
+
href="../../vendor/assets/stylesheets/ui-lightness/jquery-ui-1.10.3.custom.min.css" />
|
13
13
|
<link rel="stylesheet" type="text/css"
|
14
|
-
href="../../lib/
|
14
|
+
href="../../lib/assets/stylesheets/ballonizer.css" />
|
15
15
|
<script type="text/javascript"
|
16
16
|
src="../../vendor/assets/javascripts/jquery-2.0.1.js"></script>
|
17
17
|
<script type="text/javascript"
|
@@ -19,7 +19,7 @@
|
|
19
19
|
<script type="text/javascript"
|
20
20
|
src="../../vendor/assets/javascripts/jquery-ui-1.10.3.custom.min.js"></script>
|
21
21
|
<script type="text/javascript"
|
22
|
-
src="../../lib/
|
22
|
+
src="../../lib/assets/javascripts/ballonizer.js"></script>
|
23
23
|
<script type="text/javascript">
|
24
24
|
$(document).ready(function() {
|
25
25
|
Ballonizer('/path/to/form/submit',
|
@@ -87,7 +87,7 @@
|
|
87
87
|
</li>
|
88
88
|
</ul>
|
89
89
|
<div id="comic">
|
90
|
-
<div class="ballonizer_image_container"><p style="left: 0px; top: 0px; width: 218px; height: 82px;" class="ballonizer_ballon" >When you see a claim that a common drug or vitamin "kills cancer cells in a petri dish", keep in mind:</p><p style="top: 319px; left: 21px; width: 170px; height: 19px;" class="ballonizer_ballon">So does a handgun.</p><img src="http://imgs.xkcd.com/comics/cells.png"
|
90
|
+
<div class="ballonizer_image_container"><p style="left: 0px; top: 0px; width: 218px; height: 82px; font-size: 15px;" class="ballonizer_ballon" >When you see a claim that a common drug or vitamin "kills cancer cells in a petri dish", keep in mind:</p><p style="top: 319px; left: 21px; width: 170px; height: 19px; font-size: 14px;" class="ballonizer_ballon">So does a handgun.</p><img src="http://imgs.xkcd.com/comics/cells.png"
|
91
91
|
title="Now, if it selectively kills cancer cells in a petri dish, you can be sure it's at least a great breakthrough for everyone suffering from petri dish cancer."
|
92
92
|
width="218px"
|
93
93
|
height="339px"
|
@@ -117,10 +117,11 @@
|
|
117
117
|
|
118
118
|
Ballonizer.prototype.generateBallonizerFormNode = function () {
|
119
119
|
var form = $("<form class='ballonizer_page_form' method='post' >" +
|
120
|
-
"<input name='ballonizer_data' type='hidden'
|
121
|
-
"
|
122
|
-
"value='" +
|
123
|
-
|
120
|
+
"<div><input name='ballonizer_data' type='hidden'>" +
|
121
|
+
"</input><input name='ballonizer_submit'" +
|
122
|
+
" type='submit' value='" +
|
123
|
+
this.config.submitButtonValue +
|
124
|
+
"'></input></div></form>");
|
124
125
|
|
125
126
|
form.attr("action", this.actionFormURL);
|
126
127
|
|
@@ -161,17 +162,29 @@
|
|
161
162
|
containerNode);
|
162
163
|
}
|
163
164
|
|
165
|
+
// See notifyBallonChange for this flag explanation
|
166
|
+
this.userAlreadyInteracted = false;
|
167
|
+
|
164
168
|
this.ballonizerInstance = ballonizerInstance;
|
165
169
|
this.containerNode = containerNode;
|
166
170
|
this.ballons = [];
|
167
171
|
|
168
172
|
// Insert the form for the ballons in edit mode
|
169
|
-
|
170
|
-
|
173
|
+
this.form = $(
|
174
|
+
"<form class='ballonizer_image_form' action='#'></form>"
|
175
|
+
);
|
176
|
+
this.formInnerContainer = $(
|
177
|
+
"<div></div>"
|
171
178
|
);
|
179
|
+
this.form.prepend(this.formInnerContainer);
|
180
|
+
// The form is prepended in the beggining of the ballonizer
|
181
|
+
// context and not inside the ballonizer_image_container
|
182
|
+
// because not every element that can wrap a image (as an
|
183
|
+
// anchor for example) can wrap a form (or a block element).
|
184
|
+
// See more in: http://www.w3.org/TR/REC-html40/struct/global.html#block-inline, http://skypoetsworld.blogspot.com.br/2008/10/dont-ever-put-block-inside-inline.html, http://stackoverflow.com/questions/1091739/html-div-in-link-problem, stackoverflow.com/questions/1827965/is-putting-a-div-inside-an-anchor-ever-correcta
|
185
|
+
this.ballonizerInstance.getContext().prepend(this.form);
|
172
186
|
|
173
|
-
var ballons = $(".ballonizer_ballon",
|
174
|
-
this.ballonizerInstance.getContext());
|
187
|
+
var ballons = $(".ballonizer_ballon", this.containerNode);
|
175
188
|
|
176
189
|
ballons.each($.proxy(function (ix, element) {
|
177
190
|
this.ballons.push(new InterfaceBallon(this, $(element)));
|
@@ -186,6 +199,10 @@
|
|
186
199
|
}, this));
|
187
200
|
};
|
188
201
|
|
202
|
+
BallonizedImageContainer.prototype.getFormInnerContainer = function () {
|
203
|
+
return this.formInnerContainer;
|
204
|
+
};
|
205
|
+
|
189
206
|
BallonizedImageContainer.prototype.getContainerNode = function () {
|
190
207
|
return this.containerNode;
|
191
208
|
};
|
@@ -194,7 +211,33 @@
|
|
194
211
|
return this.ballonizerInstance;
|
195
212
|
};
|
196
213
|
|
214
|
+
// Avoid to call this method in methods that update the ballons
|
215
|
+
// data, call this method only in callbacks of events, after calling
|
216
|
+
// the methods that update the ballons data. This is intended to
|
217
|
+
// preserve the semantics of the ballon change be always from a user
|
218
|
+
// interaction.
|
197
219
|
BallonizedImageContainer.prototype.notifyBallonChange = function () {
|
220
|
+
// This flag is necessary to work around the load of the image.
|
221
|
+
// The ready callback don't wait for images to load and the
|
222
|
+
// load callback has several caveats with using images (see
|
223
|
+
// http://api.jquery.com/ready/ and http://api.jquery.com/load-event/).
|
224
|
+
// All the ballons are defined in percentages and probably won't
|
225
|
+
// be visible until the image is loaded (or will be over the alt
|
226
|
+
// text but is hard to think of an user edit a ballon in this
|
227
|
+
// case). So when the user interact with a ballon it will
|
228
|
+
// calculate and update the sizes in pixels of all ballons
|
229
|
+
// (the attributes used for the serialize), assuming that the
|
230
|
+
// user is already editing because the image is loaded.
|
231
|
+
// This fix a bug where all the ballons except the modified
|
232
|
+
// (who the bounds are recalculated) are serialized and
|
233
|
+
// submitted with the incorrect values (but are displayed
|
234
|
+
// corretly to the user before the submission).
|
235
|
+
if (!this.userAlreadyInteracted) {
|
236
|
+
jQuery.each(this.ballons, function (ix, ballon) {
|
237
|
+
ballon.updatePositionAndSize();
|
238
|
+
});
|
239
|
+
this.userAlreadyInteracted = true;
|
240
|
+
}
|
198
241
|
return this.ballonizerInstance.notifyBallonChange();
|
199
242
|
};
|
200
243
|
|
@@ -274,6 +317,7 @@
|
|
274
317
|
if (2 === arguments.length) {
|
275
318
|
this.node = xOrNode;
|
276
319
|
this.updatePositionAndSize();
|
320
|
+
this.fontSize = parseInt(this.node.css('font-size'), 10);
|
277
321
|
this.text = this.node.text();
|
278
322
|
} else {
|
279
323
|
this.left = xOrNode;
|
@@ -304,9 +348,8 @@
|
|
304
348
|
|
305
349
|
this.text = initialText;
|
306
350
|
this.node = this.generateBallonNode();
|
307
|
-
this.
|
308
|
-
|
309
|
-
);
|
351
|
+
this.imgContainer.getContainerNode().prepend(this.node);
|
352
|
+
this.changeFontSizeToBestFitBallon();
|
310
353
|
}
|
311
354
|
|
312
355
|
this.node.draggable({
|
@@ -316,6 +359,7 @@
|
|
316
359
|
stop: $.proxy(function (event, ui) {
|
317
360
|
/* jshint unused: false */
|
318
361
|
this.updatePositionAndSize();
|
362
|
+
this.imgContainer.notifyBallonChange();
|
319
363
|
}, this)
|
320
364
|
});
|
321
365
|
this.node.resizable({
|
@@ -327,13 +371,17 @@
|
|
327
371
|
stop: $.proxy(function (event, ui) {
|
328
372
|
/* jshint unused: false */
|
329
373
|
this.updatePositionAndSize();
|
374
|
+
this.changeFontSizeToBestFitBallon();
|
375
|
+
this.imgContainer.notifyBallonChange();
|
330
376
|
}, this)
|
331
377
|
});
|
332
378
|
|
333
|
-
var imageForm =
|
334
|
-
this.imgContainer.getContainerNode());
|
379
|
+
var imageForm = this.imgContainer.getFormInnerContainer();
|
335
380
|
var editionBallon = $(
|
336
|
-
|
381
|
+
// cols and rows are obrigatory attributes, the choosen
|
382
|
+
// values are magic numbers without a good reason
|
383
|
+
"<textarea cols='100' rows='40' " +
|
384
|
+
"class='ballonizer_edition_ballon'></textarea>"
|
337
385
|
).val(this.text);
|
338
386
|
|
339
387
|
this.editionNode = editionBallon;
|
@@ -358,7 +406,7 @@
|
|
358
406
|
var nodeStyle = ["left: ", this.left, "px; ", "top: ",
|
359
407
|
this.top, "px; ", "width: ", this.width, "px; ",
|
360
408
|
"height: ", this.height, "px;"].join("");
|
361
|
-
var node = $("<
|
409
|
+
var node = $("<span class='ballonizer_ballon' ></span>");
|
362
410
|
|
363
411
|
// The use of ".text" will escape '<', '>', and others
|
364
412
|
node.text(this.text).attr("style", nodeStyle);
|
@@ -377,6 +425,19 @@
|
|
377
425
|
height: this.height
|
378
426
|
};
|
379
427
|
};
|
428
|
+
InterfaceBallon.prototype.changeFontSizeToBestFitBallon = function () {
|
429
|
+
var old_height = this.node.css('height');
|
430
|
+
var desired_calc_height = this.node.height();
|
431
|
+
this.node.css('height', 'auto');
|
432
|
+
var actual_font_size = 1;
|
433
|
+
this.node.css('font-size', actual_font_size);
|
434
|
+
while (this.node.height() < desired_calc_height) {
|
435
|
+
this.node.css('font-size', ++actual_font_size + 'px');
|
436
|
+
}
|
437
|
+
this.node.css('font-size', --actual_font_size + 'px');
|
438
|
+
this.node.css('height', old_height);
|
439
|
+
this.fontSize = actual_font_size;
|
440
|
+
};
|
380
441
|
InterfaceBallon.prototype.updatePositionAndSize = function () {
|
381
442
|
var newX = this.node.position().left;
|
382
443
|
var newY = this.node.position().top;
|
@@ -390,7 +451,6 @@
|
|
390
451
|
this.top = newY;
|
391
452
|
this.width = newWidth;
|
392
453
|
this.height = newHeight;
|
393
|
-
this.imgContainer.notifyBallonChange();
|
394
454
|
}
|
395
455
|
};
|
396
456
|
InterfaceBallon.prototype.getState = function () {
|
@@ -445,6 +505,7 @@
|
|
445
505
|
this.node.removeClass("ballonizer_ballon_hidden_for_edition");
|
446
506
|
this.editionNode.removeClass("ballonizer_ballon_in_edition");
|
447
507
|
if (this.text !== oldText) {
|
508
|
+
this.changeFontSizeToBestFitBallon();
|
448
509
|
this.imgContainer.notifyBallonChange();
|
449
510
|
}
|
450
511
|
}
|
@@ -452,8 +513,48 @@
|
|
452
513
|
|
453
514
|
InterfaceBallon.prototype.dblclick = function () {
|
454
515
|
this.state = this.state.replace("initial", "edit");
|
516
|
+
|
517
|
+
var context = this.imgContainer.getBallonizerInstance().getContext();
|
518
|
+
|
519
|
+
// The add not only add this node to the set but sort the set
|
520
|
+
// (that is a array, not a set) in the order that the elements
|
521
|
+
// appears in the document. This way the most outer parent is
|
522
|
+
// the first element.
|
523
|
+
// This behaviour is documented in: http://api.jquery.com/add/
|
524
|
+
var els = this.node.parentsUntil(context).add(this.node);
|
525
|
+
var zIndexes = [];
|
526
|
+
els.each(function (ix, el) {
|
527
|
+
var zIndexCSS = $(el).css('z-index');
|
528
|
+
// the inherit is made numeric by the jQuery, we are
|
529
|
+
// filtering here only the "auto" string value
|
530
|
+
if (jQuery.isNumeric(zIndexCSS)) {
|
531
|
+
zIndexes.push(parseInt(zIndexCSS));
|
532
|
+
}
|
533
|
+
});
|
534
|
+
var zIndex = null;
|
535
|
+
if (zIndexes.length > 0) {
|
536
|
+
// The zIndex only need to be one greater than the
|
537
|
+
// zIndex of the most outer parent with a defined zIndex.
|
538
|
+
zIndex = zIndexes[0] + 1;
|
539
|
+
} else {
|
540
|
+
zIndex = 1;
|
541
|
+
}
|
542
|
+
|
543
|
+
// we subtract the offset of the imageform from the offset
|
544
|
+
// of the normal ballon because the left and top of the edition
|
545
|
+
// ballon is relative to this form (its the closest parent with
|
546
|
+
// position: relative defined)
|
547
|
+
var offset = this.node.offset();
|
548
|
+
var imageFormOffset = this.imgContainer.getFormInnerContainer().offset();
|
549
|
+
|
550
|
+
this.editionNode.css('top', offset.top - imageFormOffset.top);
|
551
|
+
this.editionNode.css('left', offset.left - imageFormOffset.left);
|
552
|
+
this.editionNode.css('width', this.node.css('width'));
|
553
|
+
this.editionNode.css('height', this.node.css('height'));
|
554
|
+
this.editionNode.css('z-index', zIndex);
|
555
|
+
|
556
|
+
// only make the ballon hidden after getting the offset
|
455
557
|
this.node.addClass("ballonizer_ballon_hidden_for_edition");
|
456
|
-
this.editionNode.attr("style", this.node.attr("style"));
|
457
558
|
this.editionNode.addClass("ballonizer_ballon_in_edition");
|
458
559
|
// focus after is visible, otherwise will crash in IE
|
459
560
|
// http://api.jquery.com/focus/#focus
|
@@ -474,6 +575,7 @@
|
|
474
575
|
top: this.top / containerHeight,
|
475
576
|
width: this.width / containerWidth,
|
476
577
|
height: this.height / containerHeight,
|
578
|
+
font_size: this.fontSize,
|
477
579
|
text: this.text
|
478
580
|
};
|
479
581
|
};
|