unpoly-rails 0.26.2 → 0.27.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of unpoly-rails might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -1
- data/dist/unpoly.js +704 -446
- data/dist/unpoly.min.js +3 -3
- data/lib/assets/javascripts/unpoly/browser.js.coffee +18 -9
- data/lib/assets/javascripts/unpoly/bus.js.coffee +28 -1
- data/lib/assets/javascripts/unpoly/flow.js.coffee +1 -1
- data/lib/assets/javascripts/unpoly/history.js.coffee +54 -22
- data/lib/assets/javascripts/unpoly/link.js.coffee +1 -1
- data/lib/assets/javascripts/unpoly/log.js.coffee +19 -12
- data/lib/assets/javascripts/unpoly/modal.js.coffee +119 -124
- data/lib/assets/javascripts/unpoly/motion.js.coffee +1 -0
- data/lib/assets/javascripts/unpoly/navigation.js.coffee +2 -6
- data/lib/assets/javascripts/unpoly/popup.js.coffee +136 -126
- data/lib/assets/javascripts/unpoly/proxy.js.coffee +0 -2
- data/lib/assets/javascripts/unpoly/syntax.js.coffee +1 -1
- data/lib/assets/javascripts/unpoly/tooltip.js.coffee +101 -46
- data/lib/assets/javascripts/unpoly/util.js.coffee +76 -7
- data/lib/unpoly/rails/version.rb +1 -1
- data/spec_app/Gemfile.lock +1 -1
- data/spec_app/app/assets/stylesheets/integration_test.sass +4 -0
- data/spec_app/app/assets/stylesheets/jasmine_specs.sass +5 -0
- data/spec_app/app/views/css_test/modal.erb +3 -0
- data/spec_app/app/views/css_test/modal_contents.erb +5 -0
- data/spec_app/app/views/css_test/popup.erb +11 -11
- data/spec_app/app/views/css_test/tooltip.erb +12 -5
- data/spec_app/app/views/pages/start.erb +4 -0
- data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +2 -3
- data/spec_app/spec/javascripts/up/flow_spec.js.coffee +97 -88
- data/spec_app/spec/javascripts/up/history_spec.js.coffee +100 -1
- data/spec_app/spec/javascripts/up/link_spec.js.coffee +18 -16
- data/spec_app/spec/javascripts/up/modal_spec.js.coffee +102 -97
- data/spec_app/spec/javascripts/up/motion_spec.js.coffee +89 -75
- data/spec_app/spec/javascripts/up/navigation_spec.js.coffee +17 -5
- data/spec_app/spec/javascripts/up/popup_spec.js.coffee +89 -70
- data/spec_app/spec/javascripts/up/util_spec.js.coffee +23 -0
- metadata +4 -2
@@ -39,12 +39,8 @@ up.navigation = (($) ->
|
|
39
39
|
SELECTOR_SECTION = 'a, [up-href]'
|
40
40
|
|
41
41
|
normalizeUrl = (url) ->
|
42
|
-
if u.isPresent(url)
|
43
|
-
|
44
|
-
search: false
|
45
|
-
stripTrailingSlash: true
|
46
|
-
)
|
47
|
-
|
42
|
+
u.normalizeUrl(url) if u.isPresent(url)
|
43
|
+
|
48
44
|
sectionUrls = ($section) ->
|
49
45
|
urls = []
|
50
46
|
for attr in ['href', 'up-href', 'up-alias']
|
@@ -46,27 +46,6 @@ up.popup = (($) ->
|
|
46
46
|
|
47
47
|
u = up.util
|
48
48
|
|
49
|
-
###*
|
50
|
-
Returns the source URL for the fragment displayed
|
51
|
-
in the current popup, or `undefined` if no popup is open.
|
52
|
-
|
53
|
-
@function up.popup.url
|
54
|
-
@return {String}
|
55
|
-
the source URL
|
56
|
-
@stable
|
57
|
-
###
|
58
|
-
currentUrl = undefined
|
59
|
-
|
60
|
-
###*
|
61
|
-
Returns the URL of the page or modal behind the popup.
|
62
|
-
|
63
|
-
@function up.popup.coveredUrl
|
64
|
-
@return {String}
|
65
|
-
@experimental
|
66
|
-
###
|
67
|
-
coveredUrl = ->
|
68
|
-
$('.up-popup').attr('up-covered-url')
|
69
|
-
|
70
49
|
###*
|
71
50
|
Sets default options for future popups.
|
72
51
|
|
@@ -97,68 +76,86 @@ up.popup = (($) ->
|
|
97
76
|
config = u.config
|
98
77
|
openAnimation: 'fade-in'
|
99
78
|
closeAnimation: 'fade-out'
|
100
|
-
openDuration:
|
101
|
-
closeDuration:
|
79
|
+
openDuration: 150
|
80
|
+
closeDuration: 100
|
102
81
|
openEasing: null
|
103
82
|
closeEasing: null
|
104
83
|
position: 'bottom-right'
|
105
84
|
history: false
|
106
85
|
|
86
|
+
###*
|
87
|
+
Returns the source URL for the fragment displayed
|
88
|
+
in the current popup, or `undefined` if no popup is open.
|
89
|
+
|
90
|
+
@function up.popup.url
|
91
|
+
@return {String}
|
92
|
+
the source URL
|
93
|
+
@stable
|
94
|
+
###
|
95
|
+
|
96
|
+
###*
|
97
|
+
Returns the URL of the page or modal behind the popup.
|
98
|
+
|
99
|
+
@function up.popup.coveredUrl
|
100
|
+
@return {String}
|
101
|
+
@experimental
|
102
|
+
###
|
103
|
+
|
104
|
+
state = u.config
|
105
|
+
phase: 'closed' # can be 'opening', 'opened', 'closing' and 'closed'
|
106
|
+
$anchor: null # the element to which the tooltip is anchored
|
107
|
+
$popup: null # the popup container
|
108
|
+
position: null # the position of the popup container element relative to its anchor
|
109
|
+
sticky: null
|
110
|
+
url: null
|
111
|
+
coveredUrl: null
|
112
|
+
coveredTitle: null
|
113
|
+
|
114
|
+
chain = new u.DivertibleChain()
|
115
|
+
|
107
116
|
reset = ->
|
108
|
-
|
117
|
+
state.$popup?.remove()
|
118
|
+
state.reset()
|
119
|
+
chain.reset()
|
109
120
|
config.reset()
|
110
121
|
|
111
|
-
|
122
|
+
align = ->
|
112
123
|
css = {}
|
113
124
|
|
114
|
-
|
115
|
-
popupBox = u.measure($popup)
|
125
|
+
popupBox = u.measure(state.$popup)
|
116
126
|
|
117
|
-
if u.isFixed(
|
118
|
-
linkBox =
|
127
|
+
if u.isFixed(state.$anchor)
|
128
|
+
linkBox = state.$anchor.get(0).getBoundingClientRect()
|
119
129
|
css['position'] = 'fixed'
|
120
130
|
else
|
121
|
-
linkBox = u.measure(
|
131
|
+
linkBox = u.measure(state.$anchor)
|
122
132
|
|
123
|
-
switch position
|
124
|
-
when
|
133
|
+
switch state.position
|
134
|
+
when 'bottom-right' # anchored to bottom-right of link, opens towards bottom-left
|
125
135
|
css['top'] = linkBox.top + linkBox.height
|
126
136
|
css['left'] = linkBox.left + linkBox.width - popupBox.width
|
127
|
-
when
|
137
|
+
when 'bottom-left' # anchored to bottom-left of link, opens towards bottom-right
|
128
138
|
css['top'] = linkBox.top + linkBox.height
|
129
139
|
css['left'] = linkBox.left
|
130
|
-
when
|
140
|
+
when 'top-right' # anchored to top-right of link, opens to top-left
|
131
141
|
css['top'] = linkBox.top - popupBox.height
|
132
142
|
css['left'] = linkBox.left + linkBox.width - popupBox.width
|
133
|
-
when
|
143
|
+
when 'top-left' # anchored to top-left of link, opens to top-right
|
134
144
|
css['top'] = linkBox.top - popupBox.height
|
135
145
|
css['left'] = linkBox.left
|
136
146
|
else
|
137
|
-
u.error("Unknown position option '%s'", position)
|
147
|
+
u.error("Unknown position option '%s'", state.position)
|
138
148
|
|
139
|
-
|
140
|
-
|
149
|
+
state.$popup.attr('up-position', state.position)
|
150
|
+
state.$popup.css(css)
|
141
151
|
|
142
|
-
|
143
|
-
$popup =
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
if isOpen()
|
150
|
-
promise = promise.then -> close()
|
151
|
-
promise = promise.then ->
|
152
|
-
$popup = u.$createElementFromSelector('.up-popup')
|
153
|
-
$popup.attr('up-sticky', '') if options.sticky
|
154
|
-
$popup.attr('up-covered-url', up.browser.url())
|
155
|
-
$popup.attr('up-covered-title', document.title)
|
156
|
-
# Create an empty element that will match the
|
157
|
-
# selector that is being replaced.
|
158
|
-
u.$createPlaceholder(target, $popup)
|
159
|
-
$popup.appendTo(document.body)
|
160
|
-
$popup
|
161
|
-
return promise
|
152
|
+
createFrame = (target) ->
|
153
|
+
$popup = u.$createElementFromSelector('.up-popup')
|
154
|
+
# Create an empty element that will match the
|
155
|
+
# selector that is being replaced.
|
156
|
+
u.$createPlaceholder(target, $popup)
|
157
|
+
$popup.appendTo(document.body)
|
158
|
+
state.$popup = $popup
|
162
159
|
|
163
160
|
###*
|
164
161
|
Returns whether popup modal is currently open.
|
@@ -167,13 +164,13 @@ up.popup = (($) ->
|
|
167
164
|
@stable
|
168
165
|
###
|
169
166
|
isOpen = ->
|
170
|
-
|
167
|
+
state.phase == 'opened' || state.phase == 'opening'
|
171
168
|
|
172
169
|
###*
|
173
170
|
Attaches a popup overlay to the given element or selector.
|
174
171
|
|
175
172
|
Emits events [`up:popup:open`](/up:popup:open) and [`up:popup:opened`](/up:popup:opened).
|
176
|
-
|
173
|
+
|
177
174
|
@function up.popup.attach
|
178
175
|
@param {Element|jQuery|String} elementOrSelector
|
179
176
|
@param {String} [options.url]
|
@@ -205,41 +202,51 @@ up.popup = (($) ->
|
|
205
202
|
the opening animation has completed.
|
206
203
|
@stable
|
207
204
|
###
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
205
|
+
attachAsap = (elementOrSelector, options) ->
|
206
|
+
curriedAttachNow = -> attachNow(elementOrSelector, options)
|
207
|
+
if isOpen()
|
208
|
+
chain.asap(closeNow, curriedAttachNow)
|
209
|
+
else
|
210
|
+
chain.asap(curriedAttachNow)
|
211
|
+
chain.promise()
|
212
|
+
|
213
|
+
attachNow = (elementOrSelector, options) ->
|
214
|
+
$anchor = $(elementOrSelector)
|
215
|
+
$anchor.length or u.error('Cannot attach popup to non-existing element %o', elementOrSelector)
|
216
|
+
|
212
217
|
options = u.options(options)
|
213
|
-
url = u.option(u.pluckKey(options, 'url'), $
|
218
|
+
url = u.option(u.pluckKey(options, 'url'), $anchor.attr('up-href'), $anchor.attr('href'))
|
214
219
|
html = u.option(u.pluckKey(options, 'html'))
|
215
|
-
target = u.option(u.pluckKey(options, 'target'), $
|
216
|
-
|
217
|
-
options.animation = u.option(options.animation, $
|
218
|
-
options.sticky = u.option(options.sticky, u.castedAttr($
|
219
|
-
options.history = if up.browser.canPushState() then u.option(options.history, u.castedAttr($
|
220
|
-
options.confirm = u.option(options.confirm, $
|
221
|
-
options.method = up.link.followMethod($
|
222
|
-
animateOptions = up.motion.animateOptions(options, $
|
223
|
-
|
224
|
-
up.browser.
|
225
|
-
|
226
|
-
|
220
|
+
target = u.option(u.pluckKey(options, 'target'), $anchor.attr('up-popup'), 'body')
|
221
|
+
position = u.option(options.position, $anchor.attr('up-position'), config.position)
|
222
|
+
options.animation = u.option(options.animation, $anchor.attr('up-animation'), config.openAnimation)
|
223
|
+
options.sticky = u.option(options.sticky, u.castedAttr($anchor, 'up-sticky'), config.sticky)
|
224
|
+
options.history = if up.browser.canPushState() then u.option(options.history, u.castedAttr($anchor, 'up-history'), config.history) else false
|
225
|
+
options.confirm = u.option(options.confirm, $anchor.attr('up-confirm'))
|
226
|
+
options.method = up.link.followMethod($anchor, options)
|
227
|
+
animateOptions = up.motion.animateOptions(options, $anchor, duration: config.openDuration, easing: config.openEasing)
|
228
|
+
|
229
|
+
up.browser.whenConfirmed(options).then ->
|
230
|
+
up.bus.whenEmitted('up:popup:open', url: url, message: 'Opening popup').then ->
|
231
|
+
state.phase = 'opening'
|
232
|
+
state.$anchor = $anchor
|
233
|
+
state.position = position
|
234
|
+
state.coveredUrl = up.browser.url()
|
235
|
+
state.coveredTitle = document.title
|
236
|
+
state.sticky = options.sticky
|
237
|
+
options.beforeSwap = -> createFrame(target)
|
227
238
|
extractOptions = u.merge(options, animation: false)
|
228
239
|
if html
|
229
240
|
promise = up.extract(target, html, extractOptions)
|
230
241
|
else
|
231
242
|
promise = up.replace(target, url, extractOptions)
|
232
243
|
promise = promise.then ->
|
233
|
-
|
244
|
+
align()
|
245
|
+
up.animate(state.$popup, options.animation, animateOptions)
|
234
246
|
promise = promise.then ->
|
235
|
-
|
236
|
-
|
237
|
-
up.emit('up:popup:opened', message: 'Popup opened')
|
247
|
+
state.phase = 'opened'
|
248
|
+
up.emit('up:popup:opened', message: 'Popup opened')#
|
238
249
|
promise
|
239
|
-
else
|
240
|
-
# Although someone prevented the destruction, keep a uniform API for
|
241
|
-
# callers by returning a promise that will never be resolved.
|
242
|
-
u.unresolvablePromise()
|
243
250
|
|
244
251
|
###*
|
245
252
|
This event is [emitted](/up.emit) when a popup is starting to open.
|
@@ -256,7 +263,7 @@ up.popup = (($) ->
|
|
256
263
|
@event up:popup:opened
|
257
264
|
@stable
|
258
265
|
###
|
259
|
-
|
266
|
+
|
260
267
|
###*
|
261
268
|
Closes a currently opened popup overlay.
|
262
269
|
|
@@ -272,27 +279,35 @@ up.popup = (($) ->
|
|
272
279
|
animation has finished.
|
273
280
|
@stable
|
274
281
|
###
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
282
|
+
closeAsap = (options) ->
|
283
|
+
if isOpen()
|
284
|
+
chain.asap -> closeNow(options)
|
285
|
+
chain.promise()
|
286
|
+
|
287
|
+
closeNow = (options) ->
|
288
|
+
unless isOpen() # this can happen when a request fails and the chain proceeds to the next task
|
289
|
+
return u.resolvedPromise()
|
290
|
+
|
291
|
+
options = u.options(options,
|
292
|
+
animation: config.closeAnimation
|
293
|
+
url: state.coveredUrl,
|
294
|
+
title: state.coveredTitle
|
295
|
+
)
|
296
|
+
animateOptions = up.motion.animateOptions(options, duration: config.closeDuration, easing: config.closeEasing)
|
297
|
+
u.extend(options, animateOptions)
|
298
|
+
|
299
|
+
up.bus.whenEmitted('up:popup:close', message: 'Closing popup', $element: state.$popup).then ->
|
300
|
+
state.phase = 'closing'
|
301
|
+
state.url = null
|
302
|
+
state.coveredUrl = null
|
303
|
+
state.coveredTitle = null
|
304
|
+
|
305
|
+
up.destroy(state.$popup, options).then ->
|
306
|
+
state.phase = 'closed'
|
307
|
+
state.$popup = null
|
308
|
+
state.$anchor = null
|
309
|
+
state.sticky = null
|
310
|
+
up.emit('up:popup:closed', message: 'Popup closed')
|
296
311
|
|
297
312
|
###*
|
298
313
|
This event is [emitted](/up.emit) when a popup dialog
|
@@ -313,9 +328,7 @@ up.popup = (($) ->
|
|
313
328
|
###
|
314
329
|
|
315
330
|
autoclose = ->
|
316
|
-
unless
|
317
|
-
discardHistory()
|
318
|
-
close()
|
331
|
+
closeAsap() unless state.sticky
|
319
332
|
|
320
333
|
###*
|
321
334
|
Returns whether the given element or selector is contained
|
@@ -363,29 +376,29 @@ up.popup = (($) ->
|
|
363
376
|
###
|
364
377
|
up.link.onAction('[up-popup]', ($link) ->
|
365
378
|
if $link.is('.up-current')
|
366
|
-
|
379
|
+
closeAsap()
|
367
380
|
else
|
368
|
-
|
381
|
+
attachAsap($link)
|
369
382
|
)
|
370
383
|
|
371
384
|
# Close the popup when someone clicks outside the popup
|
372
385
|
# (but not on a popup opener).
|
373
|
-
up.on('
|
386
|
+
up.on('mousedown', 'body', (event, $body) ->
|
374
387
|
$target = $(event.target)
|
375
|
-
unless $target.closest('.up-popup
|
376
|
-
|
388
|
+
unless $target.closest('.up-popup, [up-popup]').length
|
389
|
+
closeAsap()
|
377
390
|
)
|
378
391
|
|
379
392
|
up.on('up:fragment:inserted', (event, $fragment) ->
|
380
393
|
if contains($fragment)
|
381
394
|
if newSource = $fragment.attr('up-source')
|
382
|
-
|
395
|
+
state.url = newSource
|
383
396
|
else if contains(event.origin)
|
384
397
|
autoclose()
|
385
398
|
)
|
386
399
|
|
387
400
|
# Close the pop-up overlay when the user presses ESC.
|
388
|
-
up.bus.onEscape(
|
401
|
+
up.bus.onEscape(closeAsap)
|
389
402
|
|
390
403
|
###*
|
391
404
|
When an element with this attribute is clicked,
|
@@ -402,8 +415,8 @@ up.popup = (($) ->
|
|
402
415
|
@stable
|
403
416
|
###
|
404
417
|
up.on('click', '[up-close]', (event, $element) ->
|
405
|
-
if $element
|
406
|
-
|
418
|
+
if contains($element)
|
419
|
+
closeAsap()
|
407
420
|
# Only prevent the default when we actually closed a popup.
|
408
421
|
# This way we can have buttons that close a popup when within a popup,
|
409
422
|
# but link to a destination if not.
|
@@ -414,15 +427,12 @@ up.popup = (($) ->
|
|
414
427
|
up.on 'up:framework:reset', reset
|
415
428
|
|
416
429
|
knife: eval(Knife?.point)
|
417
|
-
attach:
|
418
|
-
close:
|
419
|
-
url: ->
|
420
|
-
coveredUrl: coveredUrl
|
430
|
+
attach: attachAsap
|
431
|
+
close: closeAsap
|
432
|
+
url: -> state.url
|
433
|
+
coveredUrl: -> state.coveredUrl
|
421
434
|
config: config
|
422
|
-
defaults: -> u.error('up.popup.defaults(...) no longer exists. Set values on he up.popup.config property instead.')
|
423
435
|
contains: contains
|
424
|
-
open: -> up.error('up.popup.open no longer exists. Please use up.popup.attach instead.')
|
425
|
-
source: -> up.error('up.popup.source no longer exists. Please use up.popup.url instead.')
|
426
436
|
isOpen: isOpen
|
427
437
|
|
428
438
|
)(jQuery)
|
@@ -50,7 +50,7 @@ up.syntax = (($) ->
|
|
50
50
|
// your code here
|
51
51
|
});
|
52
52
|
|
53
|
-
The functions will be called on elements
|
53
|
+
The functions will be called on elements matching `.action` when
|
54
54
|
the page loads, or whenever a matching fragment is [updated through Unpoly](/up.replace)
|
55
55
|
later.
|
56
56
|
|
@@ -44,46 +44,68 @@ up.tooltip = (($) ->
|
|
44
44
|
The animation used to open a tooltip.
|
45
45
|
@param {String} [config.closeAnimation='fade-out']
|
46
46
|
The animation used to close a tooltip.
|
47
|
+
@param {Number} [config.openDuration]
|
48
|
+
The duration of the open animation (in milliseconds).
|
49
|
+
@param {Number} [config.closeDuration]
|
50
|
+
The duration of the close animation (in milliseconds).
|
51
|
+
@param {String} [config.openEasing]
|
52
|
+
The timing function controlling the acceleration of the opening animation.
|
53
|
+
@param {String} [config.closeEasing]
|
54
|
+
The timing function controlling the acceleration of the closing animation.
|
47
55
|
@stable
|
48
56
|
###
|
49
57
|
config = u.config
|
50
58
|
position: 'top'
|
51
59
|
openAnimation: 'fade-in'
|
52
60
|
closeAnimation: 'fade-out'
|
61
|
+
openDuration: 100
|
62
|
+
closeDuration: 50
|
63
|
+
openEasing: null
|
64
|
+
closeEasing: null
|
65
|
+
|
66
|
+
state = u.config
|
67
|
+
phase: 'closed' # can be 'opening', 'opened', 'closing' and 'closed'
|
68
|
+
$anchor: null # the element to which the tooltip is anchored
|
69
|
+
$tooltip: null # the tooltiop element
|
70
|
+
position: null # the position of the tooltip element relative to its anchor
|
71
|
+
|
72
|
+
chain = new u.DivertibleChain()
|
53
73
|
|
54
74
|
reset = ->
|
55
75
|
# Destroy the tooltip container regardless whether it's currently in a closing animation
|
56
|
-
|
76
|
+
state.$tooltip?.remove()
|
77
|
+
state.reset()
|
78
|
+
chain.reset()
|
57
79
|
config.reset()
|
58
80
|
|
59
|
-
|
81
|
+
align = ->
|
60
82
|
css = {}
|
61
|
-
tooltipBox = u.measure(
|
83
|
+
tooltipBox = u.measure(state.$tooltip)
|
62
84
|
|
63
|
-
if u.isFixed(
|
64
|
-
linkBox =
|
85
|
+
if u.isFixed(state.$anchor)
|
86
|
+
linkBox = state.$anchor.get(0).getBoundingClientRect()
|
65
87
|
css['position'] = 'fixed'
|
66
88
|
else
|
67
|
-
linkBox = u.measure(
|
89
|
+
linkBox = u.measure(state.$anchor)
|
68
90
|
|
69
|
-
switch position
|
70
|
-
when
|
91
|
+
switch state.position
|
92
|
+
when 'top'
|
71
93
|
css['top'] = linkBox.top - tooltipBox.height
|
72
94
|
css['left'] = linkBox.left + 0.5 * (linkBox.width - tooltipBox.width)
|
73
|
-
when
|
95
|
+
when 'left'
|
74
96
|
css['top'] = linkBox.top + 0.5 * (linkBox.height - tooltipBox.height)
|
75
97
|
css['left'] = linkBox.left - tooltipBox.width
|
76
|
-
when
|
98
|
+
when 'right'
|
77
99
|
css['top'] = linkBox.top + 0.5 * (linkBox.height - tooltipBox.height)
|
78
100
|
css['left'] = linkBox.left + linkBox.width
|
79
|
-
when
|
101
|
+
when 'bottom'
|
80
102
|
css['top'] = linkBox.top + linkBox.height
|
81
103
|
css['left'] = linkBox.left + 0.5 * (linkBox.width - tooltipBox.width)
|
82
104
|
else
|
83
|
-
u.error("Unknown position option '%s'", position)
|
105
|
+
u.error("Unknown position option '%s'", state.position)
|
84
106
|
|
85
|
-
|
86
|
-
|
107
|
+
state.$tooltip.attr('up-position', state.position)
|
108
|
+
state.$tooltip.css(css)
|
87
109
|
|
88
110
|
createElement = (options) ->
|
89
111
|
$element = u.$createElementFromSelector('.up-tooltip')
|
@@ -92,7 +114,7 @@ up.tooltip = (($) ->
|
|
92
114
|
else
|
93
115
|
$element.html(options.html)
|
94
116
|
$element.appendTo(document.body)
|
95
|
-
$element
|
117
|
+
state.$tooltip = $element
|
96
118
|
|
97
119
|
###*
|
98
120
|
Opens a tooltip over the given element.
|
@@ -100,7 +122,7 @@ up.tooltip = (($) ->
|
|
100
122
|
up.tooltip.attach('.help', {
|
101
123
|
html: 'Enter multiple words or phrases'
|
102
124
|
});
|
103
|
-
|
125
|
+
|
104
126
|
@function up.tooltip.attach
|
105
127
|
@param {Element|jQuery|String} elementOrSelector
|
106
128
|
@param {String} [options.html]
|
@@ -114,33 +136,68 @@ up.tooltip = (($) ->
|
|
114
136
|
A promise that will be resolved when the tooltip's opening animation has finished.
|
115
137
|
@stable
|
116
138
|
###
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
139
|
+
attachAsap = (elementOrSelector, options = {}) ->
|
140
|
+
curriedAttachNow = -> attachNow(elementOrSelector, options)
|
141
|
+
if isOpen()
|
142
|
+
chain.asap(closeNow, curriedAttachNow)
|
143
|
+
else
|
144
|
+
chain.asap(curriedAttachNow)
|
145
|
+
chain.promise()
|
146
|
+
|
147
|
+
attachNow = (elementOrSelector, options) ->
|
148
|
+
$anchor = $(elementOrSelector)
|
149
|
+
options = u.options(options)
|
150
|
+
html = u.option(options.html, $anchor.attr('up-tooltip-html'))
|
151
|
+
text = u.option(options.text, $anchor.attr('up-tooltip'))
|
152
|
+
position = u.option(options.position, $anchor.attr('up-position'), config.position)
|
153
|
+
animation = u.option(options.animation, u.castedAttr($anchor, 'up-animation'), config.openAnimation)
|
154
|
+
animateOptions = up.motion.animateOptions(options, $anchor, duration: config.openDuration, easing: config.openEasing)
|
155
|
+
|
156
|
+
state.phase = 'opening'
|
157
|
+
state.$anchor = $anchor
|
158
|
+
createElement(text: text, html: html)
|
159
|
+
state.position = position
|
160
|
+
align()
|
161
|
+
up.animate(state.$tooltip, animation, animateOptions).then ->
|
162
|
+
state.phase = 'opened'
|
128
163
|
|
129
164
|
###*
|
130
165
|
Closes a currently shown tooltip.
|
131
166
|
Does nothing if no tooltip is currently shown.
|
132
|
-
|
167
|
+
|
133
168
|
@function up.tooltip.close
|
134
169
|
@param {Object} options
|
135
170
|
See options for [`up.animate`](/up.animate).
|
171
|
+
@return {Promise}
|
172
|
+
A promise for the end of the closing animation.
|
136
173
|
@stable
|
137
174
|
###
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
175
|
+
closeAsap = (options) ->
|
176
|
+
if isOpen()
|
177
|
+
chain.asap -> closeNow(options)
|
178
|
+
chain.promise()
|
179
|
+
|
180
|
+
closeNow = (options) ->
|
181
|
+
unless isOpen() # this can happen when a request fails and the chain proceeds to the next task
|
182
|
+
return u.resolvedPromise()
|
183
|
+
|
184
|
+
options = u.options(options, animation: config.closeAnimation)
|
185
|
+
animateOptions = up.motion.animateOptions(options, duration: config.closeDuration, easing: config.closeEasing)
|
186
|
+
u.extend(options, animateOptions)
|
187
|
+
state.phase = 'closing'
|
188
|
+
up.destroy(state.$tooltip, options).then ->
|
189
|
+
state.phase = 'closed'
|
190
|
+
state.$tooltip = null
|
191
|
+
state.$anchor = null
|
192
|
+
|
193
|
+
###*
|
194
|
+
Returns whether a tooltip is currently showing.
|
195
|
+
|
196
|
+
@function up.tooltip.isOpen
|
197
|
+
@stable
|
198
|
+
###
|
199
|
+
isOpen = ->
|
200
|
+
state.phase == 'opening' || state.phase == 'opened'
|
144
201
|
|
145
202
|
###*
|
146
203
|
Displays a tooltip with text content when hovering the mouse over this element:
|
@@ -171,30 +228,28 @@ up.tooltip = (($) ->
|
|
171
228
|
@selector [up-tooltip-html]
|
172
229
|
@stable
|
173
230
|
###
|
174
|
-
up.compiler('[up-tooltip], [up-tooltip-html]', ($
|
231
|
+
up.compiler('[up-tooltip], [up-tooltip-html]', ($opener) ->
|
175
232
|
# Don't register these events on document since *every*
|
176
233
|
# mouse move interaction bubbles up to the document.
|
177
|
-
$
|
178
|
-
$
|
234
|
+
$opener.on('mouseenter', -> attachAsap($opener))
|
235
|
+
$opener.on('mouseleave', -> closeAsap())
|
179
236
|
)
|
180
237
|
|
181
238
|
# Close the tooltip when someone clicks anywhere.
|
182
239
|
up.on('click', 'body', (event, $body) ->
|
183
|
-
|
240
|
+
closeAsap()
|
184
241
|
)
|
185
242
|
|
186
243
|
# The framework is reset between tests, so also close
|
187
244
|
# a currently open tooltip.
|
188
|
-
up.on 'up:framework:reset',
|
245
|
+
up.on 'up:framework:reset', reset
|
189
246
|
|
190
247
|
# Close the tooltip when the user presses ESC.
|
191
|
-
up.bus.onEscape(->
|
192
|
-
|
193
|
-
# The framework is reset between tests
|
194
|
-
up.on 'up:framework:reset', reset
|
248
|
+
up.bus.onEscape(-> closeAsap())
|
195
249
|
|
196
|
-
|
197
|
-
|
198
|
-
|
250
|
+
config: config
|
251
|
+
attach: attachAsap
|
252
|
+
isOpen: isOpen
|
253
|
+
close: closeAsap
|
199
254
|
|
200
255
|
)(jQuery)
|