unpoly-rails 0.23.0 → 0.24.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 +68 -0
- data/dist/unpoly-bootstrap3.js +1 -1
- data/dist/unpoly-bootstrap3.min.js +1 -1
- data/dist/unpoly.css +18 -8
- data/dist/unpoly.js +498 -265
- data/dist/unpoly.min.css +1 -1
- data/dist/unpoly.min.js +3 -3
- data/lib/assets/javascripts/unpoly-bootstrap3/modal-ext.js.coffee +5 -2
- data/lib/assets/javascripts/unpoly/flow.js.coffee +3 -1
- data/lib/assets/javascripts/unpoly/form.js.coffee +3 -6
- data/lib/assets/javascripts/unpoly/layout.js.coffee +1 -1
- data/lib/assets/javascripts/unpoly/link.js.coffee +4 -2
- data/lib/assets/javascripts/unpoly/log.js.coffee +2 -2
- data/lib/assets/javascripts/unpoly/modal.js.coffee +125 -36
- data/lib/assets/javascripts/unpoly/motion.js.coffee +75 -37
- data/lib/assets/javascripts/unpoly/navigation.js.coffee +38 -26
- data/lib/assets/javascripts/unpoly/proxy.js.coffee +77 -52
- data/lib/assets/javascripts/unpoly/syntax.js.coffee +1 -0
- data/lib/assets/javascripts/unpoly/tooltip.js.coffee +2 -0
- data/lib/assets/javascripts/unpoly/util.js.coffee +138 -46
- data/lib/assets/stylesheets/unpoly/link.css.sass +1 -1
- data/lib/assets/stylesheets/unpoly/modal.css.sass +28 -15
- data/lib/unpoly/rails/version.rb +1 -1
- data/spec_app/Gemfile.lock +7 -7
- data/spec_app/spec/javascripts/helpers/reset_up.js.coffee +2 -0
- data/spec_app/spec/javascripts/helpers/to_contain.js.coffee +5 -0
- data/spec_app/spec/javascripts/up/flow_spec.js.coffee +2 -2
- data/spec_app/spec/javascripts/up/history_spec.js.coffee +6 -4
- data/spec_app/spec/javascripts/up/link_spec.js.coffee +114 -5
- data/spec_app/spec/javascripts/up/modal_spec.js.coffee +28 -18
- data/spec_app/spec/javascripts/up/motion_spec.js.coffee +112 -7
- data/spec_app/spec/javascripts/up/navigation_spec.js.coffee +157 -121
- data/spec_app/spec/javascripts/up/popup_spec.js.coffee +1 -1
- data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +42 -3
- data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +1 -2
- data/spec_app/spec/javascripts/up/util_spec.js.coffee +26 -1
- data/spec_app/vendor/assets/bower_components/jquery/.bower.json +1 -1
- metadata +3 -3
- data/spec_app/spec/javascripts/helpers/set_timer.js.coffee +0 -3
@@ -36,11 +36,8 @@ up.navigation = (($) ->
|
|
36
36
|
classes.join(' ')
|
37
37
|
|
38
38
|
CLASS_ACTIVE = 'up-active'
|
39
|
-
|
40
|
-
|
41
|
-
SELECTOR_SECTION_INSTANT = ("#{selector}[up-instant]" for selector in SELECTORS_SECTION).join(', ')
|
42
|
-
SELECTOR_ACTIVE = ".#{CLASS_ACTIVE}"
|
43
|
-
|
39
|
+
SELECTOR_SECTION = 'a, [up-href]'
|
40
|
+
|
44
41
|
normalizeUrl = (url) ->
|
45
42
|
if u.isPresent(url)
|
46
43
|
u.normalizeUrl(url,
|
@@ -102,6 +99,22 @@ up.navigation = (($) ->
|
|
102
99
|
else if $section.hasClass(klass) && $section.closest('.up-destroying').length == 0
|
103
100
|
$section.removeClass(klass)
|
104
101
|
|
102
|
+
###*
|
103
|
+
@function findClickArea
|
104
|
+
@param {String|Element|jQuery} elementOrSelector
|
105
|
+
@param {Boolean} options.enlarge
|
106
|
+
If `true`, tries to find a containing link that has expanded the link's click area.
|
107
|
+
If we find one, we prefer to mark the larger area as active.
|
108
|
+
@internal
|
109
|
+
###
|
110
|
+
findClickArea = (elementOrSelector, options) ->
|
111
|
+
$area = $(elementOrSelector)
|
112
|
+
options = u.options(options, enlarge: false)
|
113
|
+
if options.enlarge
|
114
|
+
u.presence($area.parent(SELECTOR_SECTION)) || $area
|
115
|
+
else
|
116
|
+
$area
|
117
|
+
|
105
118
|
###*
|
106
119
|
Links that are currently loading are assigned the `up-active`
|
107
120
|
class automatically. Style `.up-active` in your CSS to improve the
|
@@ -129,24 +142,23 @@ up.navigation = (($) ->
|
|
129
142
|
@selector .up-active
|
130
143
|
@stable
|
131
144
|
###
|
132
|
-
|
133
|
-
|
134
|
-
$
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
$(
|
142
|
-
|
143
|
-
|
144
|
-
if u.
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
sectionClicked($section)
|
145
|
+
markActive = (elementOrSelector, options) ->
|
146
|
+
$element = findClickArea(elementOrSelector, options)
|
147
|
+
$element.addClass(CLASS_ACTIVE)
|
148
|
+
|
149
|
+
unmarkActive = (elementOrSelector, options) ->
|
150
|
+
$element = findClickArea(elementOrSelector, options)
|
151
|
+
$element.removeClass(CLASS_ACTIVE)
|
152
|
+
|
153
|
+
withActiveMark = (elementOrSelector, options, block) ->
|
154
|
+
$element = $(elementOrSelector)
|
155
|
+
markActive($element, options)
|
156
|
+
promise = block()
|
157
|
+
if u.isPromise(promise)
|
158
|
+
promise.always -> unmarkActive($element, options)
|
159
|
+
else
|
160
|
+
up.warn('Expected block to return a promise, but got %o', promise)
|
161
|
+
promise
|
150
162
|
|
151
163
|
###*
|
152
164
|
Links that point to the current location are assigned
|
@@ -193,9 +205,6 @@ up.navigation = (($) ->
|
|
193
205
|
@stable
|
194
206
|
###
|
195
207
|
up.on 'up:fragment:inserted', ->
|
196
|
-
# If a new fragment is inserted, it's likely to be the result
|
197
|
-
# of the active action. So we can remove the active marker.
|
198
|
-
unmarkActive()
|
199
208
|
# When a fragment is inserted it might either have brought a location change
|
200
209
|
# with it, or it might have opened a modal / popup which we consider
|
201
210
|
# to be secondary location sources (the primary being the browser's
|
@@ -215,5 +224,8 @@ up.navigation = (($) ->
|
|
215
224
|
|
216
225
|
config: config
|
217
226
|
defaults: -> u.error('up.navigation.defaults(...) no longer exists. Set values on he up.navigation.config property instead.')
|
227
|
+
markActive: markActive
|
228
|
+
unmarkActive: unmarkActive
|
229
|
+
withActiveMark: withActiveMark
|
218
230
|
|
219
231
|
)(jQuery)
|
@@ -112,67 +112,26 @@ up.proxy = (($) ->
|
|
112
112
|
if response = cache.get(candidate)
|
113
113
|
return response
|
114
114
|
|
115
|
-
###*
|
116
|
-
Manually stores a promise for the response to the given request.
|
117
|
-
|
118
|
-
@function up.proxy.set
|
119
|
-
@param {String} request.url
|
120
|
-
@param {String} [request.method='GET']
|
121
|
-
@param {String} [request.target='body']
|
122
|
-
@param {Promise} response
|
123
|
-
A promise for the response that is API-compatible with the
|
124
|
-
promise returned by [`jQuery.ajax`](http://api.jquery.com/jquery.ajax/).
|
125
|
-
@experimental
|
126
|
-
###
|
127
|
-
set = cache.set
|
128
|
-
|
129
|
-
###*
|
130
|
-
Manually removes the given request from the cache.
|
131
|
-
|
132
|
-
You can also [configure](/up.proxy.config) when the proxy
|
133
|
-
automatically removes cache entries.
|
134
|
-
|
135
|
-
@function up.proxy.remove
|
136
|
-
@param {String} request.url
|
137
|
-
@param {String} [request.method='GET']
|
138
|
-
@param {String} [request.target='body']
|
139
|
-
@experimental
|
140
|
-
###
|
141
|
-
remove = cache.remove
|
142
|
-
|
143
|
-
###*
|
144
|
-
Removes all cache entries.
|
145
|
-
|
146
|
-
Unpoly also automatically clears the cache whenever it processes
|
147
|
-
a request with a non-GET HTTP method.
|
148
|
-
|
149
|
-
@function up.proxy.clear
|
150
|
-
@stable
|
151
|
-
###
|
152
|
-
clear = cache.clear
|
153
|
-
|
154
115
|
cancelPreloadDelay = ->
|
155
116
|
clearTimeout(preloadDelayTimer)
|
156
117
|
preloadDelayTimer = null
|
157
118
|
|
158
|
-
|
119
|
+
cancelSlowDelay = ->
|
159
120
|
clearTimeout(slowDelayTimer)
|
160
121
|
slowDelayTimer = null
|
161
122
|
|
162
123
|
reset = ->
|
163
124
|
$waitingLink = null
|
164
125
|
cancelPreloadDelay()
|
165
|
-
|
126
|
+
cancelSlowDelay()
|
166
127
|
pendingCount = 0
|
167
128
|
config.reset()
|
168
|
-
slowEventEmitted = false
|
169
129
|
cache.clear()
|
130
|
+
slowEventEmitted = false
|
170
131
|
queuedRequests = []
|
171
132
|
|
172
133
|
reset()
|
173
134
|
|
174
|
-
alias = cache.alias
|
175
|
-
|
176
135
|
normalizeRequest = (request) ->
|
177
136
|
unless request._normalized
|
178
137
|
request.method = u.normalizeMethod(request.method)
|
@@ -190,13 +149,23 @@ up.proxy = (($) ->
|
|
190
149
|
Only requests with a method of `GET`, `OPTIONS` and `HEAD`
|
191
150
|
are considered to be read-only.
|
192
151
|
|
152
|
+
\#\#\#\# Example
|
153
|
+
|
154
|
+
up.ajax('/search', data: { query: 'sunshine' }).then(function(data, status, xhr) {
|
155
|
+
console.log('The response body is %o', data);
|
156
|
+
}).fail(function(xhr, status, error) {
|
157
|
+
console.error('The request failed');
|
158
|
+
});
|
159
|
+
|
160
|
+
\#\#\#\# Events
|
161
|
+
|
193
162
|
If a network connection is attempted, the proxy will emit
|
194
|
-
a `up:proxy:load` event with the `request` as its argument.
|
195
|
-
Once the response is received, a `up:proxy:receive` event will
|
163
|
+
a [`up:proxy:load`](/up:proxy:load) event with the `request` as its argument.
|
164
|
+
Once the response is received, a [`up:proxy:receive`](/up:proxy:receive) event will
|
196
165
|
be emitted.
|
197
166
|
|
198
167
|
@function up.ajax
|
199
|
-
@param {String}
|
168
|
+
@param {String} url
|
200
169
|
@param {String} [request.method='GET']
|
201
170
|
@param {String} [request.target='body']
|
202
171
|
@param {Boolean} [request.cache]
|
@@ -207,12 +176,18 @@ up.proxy = (($) ->
|
|
207
176
|
with the request.
|
208
177
|
@param {Object} [request.data={}]
|
209
178
|
An object of request parameters.
|
179
|
+
@param {String} [request.url]
|
180
|
+
You can omit the first string argument and pass the URL as
|
181
|
+
a `request` property instead.
|
210
182
|
@return
|
211
183
|
A promise for the response that is API-compatible with the
|
212
184
|
promise returned by [`jQuery.ajax`](http://api.jquery.com/jquery.ajax/).
|
213
185
|
@stable
|
214
186
|
###
|
215
|
-
ajax = (
|
187
|
+
ajax = (args...) ->
|
188
|
+
|
189
|
+
options = u.extractOptions(args)
|
190
|
+
options.url = args[0] if u.isGiven(args[0])
|
216
191
|
|
217
192
|
forceCache = (options.cache == true)
|
218
193
|
ignoreCache = (options.cache == false)
|
@@ -293,10 +268,7 @@ up.proxy = (($) ->
|
|
293
268
|
if isBusy() # a fast response might have beaten the delay
|
294
269
|
up.emit('up:proxy:slow', message: 'Proxy is busy')
|
295
270
|
slowEventEmitted = true
|
296
|
-
|
297
|
-
slowDelayTimer = setTimeout(emission, config.slowDelay)
|
298
|
-
else
|
299
|
-
emission()
|
271
|
+
slowDelayTimer = u.setTimer(config.slowDelay, emission)
|
300
272
|
|
301
273
|
###*
|
302
274
|
This event is [emitted]/(up.emit) when [AJAX requests](/up.ajax)
|
@@ -423,6 +395,59 @@ up.proxy = (($) ->
|
|
423
395
|
promise.done (args...) -> entry.deferred.resolve(args...)
|
424
396
|
promise.fail (args...) -> entry.deferred.reject(args...)
|
425
397
|
|
398
|
+
###*
|
399
|
+
Makes the proxy assume that `newRequest` has the same response as the
|
400
|
+
already cached `oldRequest`.
|
401
|
+
|
402
|
+
Unpoly uses this internally when the user redirects from `/old` to `/new`.
|
403
|
+
In that case, both `/old` and `/new` will cache the same response from `/new`.
|
404
|
+
|
405
|
+
@function up.proxy.alias
|
406
|
+
@param {Object} oldRequest
|
407
|
+
@param {Object} newRequest
|
408
|
+
@experimental
|
409
|
+
###
|
410
|
+
alias = cache.alias
|
411
|
+
|
412
|
+
###*
|
413
|
+
Manually stores a promise for the response to the given request.
|
414
|
+
|
415
|
+
@function up.proxy.set
|
416
|
+
@param {String} request.url
|
417
|
+
@param {String} [request.method='GET']
|
418
|
+
@param {String} [request.target='body']
|
419
|
+
@param {Promise} response
|
420
|
+
A promise for the response that is API-compatible with the
|
421
|
+
promise returned by [`jQuery.ajax`](http://api.jquery.com/jquery.ajax/).
|
422
|
+
@experimental
|
423
|
+
###
|
424
|
+
set = cache.set
|
425
|
+
|
426
|
+
###*
|
427
|
+
Manually removes the given request from the cache.
|
428
|
+
|
429
|
+
You can also [configure](/up.proxy.config) when the proxy
|
430
|
+
automatically removes cache entries.
|
431
|
+
|
432
|
+
@function up.proxy.remove
|
433
|
+
@param {String} request.url
|
434
|
+
@param {String} [request.method='GET']
|
435
|
+
@param {String} [request.target='body']
|
436
|
+
@experimental
|
437
|
+
###
|
438
|
+
remove = cache.remove
|
439
|
+
|
440
|
+
###*
|
441
|
+
Removes all cache entries.
|
442
|
+
|
443
|
+
Unpoly also automatically clears the cache whenever it processes
|
444
|
+
a request with a non-GET HTTP method.
|
445
|
+
|
446
|
+
@function up.proxy.clear
|
447
|
+
@stable
|
448
|
+
###
|
449
|
+
clear = cache.clear
|
450
|
+
|
426
451
|
###*
|
427
452
|
This event is [emitted]/(up.emit) before an [AJAX request](/up.ajax)
|
428
453
|
is starting to load.
|
@@ -9,6 +9,14 @@ that might save you from loading something like [Underscore.js](http://underscor
|
|
9
9
|
###
|
10
10
|
up.util = (($) ->
|
11
11
|
|
12
|
+
###*
|
13
|
+
A function that does nothing.
|
14
|
+
|
15
|
+
@function up.util.noop
|
16
|
+
@experimental
|
17
|
+
###
|
18
|
+
noop = $.noop
|
19
|
+
|
12
20
|
###*
|
13
21
|
@function up.util.memoize
|
14
22
|
@internal
|
@@ -755,6 +763,24 @@ up.util = (($) ->
|
|
755
763
|
values = ($element.attr(attrName) for attrName in attrNames)
|
756
764
|
detect(values, isPresent)
|
757
765
|
|
766
|
+
###*
|
767
|
+
Waits for the given number of milliseconds, the nruns the given callback.
|
768
|
+
|
769
|
+
If the number of milliseconds is zero, the callback is run in the current execution frame.
|
770
|
+
See [`up.util.nextFrame`] for running a function in the next executation frame.
|
771
|
+
|
772
|
+
@function up.util.setTimer
|
773
|
+
@param {Number} millis
|
774
|
+
@param {Function} callback
|
775
|
+
@experimental
|
776
|
+
###
|
777
|
+
setTimer = (millis, callback) ->
|
778
|
+
if millis > 0
|
779
|
+
setTimeout(callback, millis)
|
780
|
+
else
|
781
|
+
callback()
|
782
|
+
|
783
|
+
|
758
784
|
###*
|
759
785
|
Schedules the given function to be called in the
|
760
786
|
next Javascript execution frame.
|
@@ -868,6 +894,16 @@ up.util = (($) ->
|
|
868
894
|
memo = ->
|
869
895
|
memo
|
870
896
|
|
897
|
+
###*
|
898
|
+
Forces a repaint of the given element.
|
899
|
+
|
900
|
+
@function up.util.forceRepaint
|
901
|
+
@internal
|
902
|
+
###
|
903
|
+
forceRepaint = (element) ->
|
904
|
+
element = unJQuery(element)
|
905
|
+
element.offsetHeight
|
906
|
+
|
871
907
|
###*
|
872
908
|
Animates the given element's CSS properties using CSS transitions.
|
873
909
|
|
@@ -901,23 +937,49 @@ up.util = (($) ->
|
|
901
937
|
delay: 0,
|
902
938
|
easing: 'ease'
|
903
939
|
)
|
904
|
-
|
905
|
-
#
|
940
|
+
|
941
|
+
# We don't finish an existing animation here, since the public API
|
942
|
+
# we expose as `up.motion.animate` already does this.
|
906
943
|
deferred = $.Deferred()
|
907
944
|
transition =
|
908
945
|
'transition-property': Object.keys(lastFrame).join(', ')
|
909
946
|
'transition-duration': "#{opts.duration}ms"
|
910
947
|
'transition-delay': "#{opts.delay}ms"
|
911
948
|
'transition-timing-function': opts.easing
|
949
|
+
oldTransition = $element.css(Object.keys(transition))
|
950
|
+
|
951
|
+
$element.addClass('up-animating')
|
912
952
|
withoutCompositing = forceCompositing($element)
|
913
|
-
|
953
|
+
$element.css(transition)
|
914
954
|
$element.css(lastFrame)
|
915
|
-
deferred.then(withoutCompositing)
|
916
|
-
deferred.then(withoutTransition)
|
917
955
|
$element.data(ANIMATION_DEFERRED_KEY, deferred)
|
918
|
-
|
919
|
-
|
920
|
-
|
956
|
+
|
957
|
+
deferred.then ->
|
958
|
+
$element.removeData(ANIMATION_DEFERRED_KEY)
|
959
|
+
withoutCompositing()
|
960
|
+
|
961
|
+
# To interrupt the running transition we *must* set it to 'none' exactly.
|
962
|
+
# We cannot simply restore the old transition properties because browsers
|
963
|
+
# would simply keep transitioning the old properties.
|
964
|
+
$element.css('transition': 'none')
|
965
|
+
|
966
|
+
# Restoring a previous transition involves some work, so we only do it if
|
967
|
+
# we know the element was transitioning before.
|
968
|
+
hadTransitionBefore = !(oldTransition['transition-property'] == 'none' || (oldTransition['transition-property'] == 'all' && oldTransition['transition-duration'][0] == '0'))
|
969
|
+
if hadTransitionBefore
|
970
|
+
forceRepaint($element) # :(
|
971
|
+
$element.css(oldTransition)
|
972
|
+
|
973
|
+
# Since listening to transitionEnd events is painful, we wait for a timeout
|
974
|
+
# and then resolve our deferred. Maybe revisit that decision some day.
|
975
|
+
animationEnd = opts.duration + opts.delay
|
976
|
+
endTimeout = setTimer animationEnd, ->
|
977
|
+
$element.removeClass('up-animating')
|
978
|
+
deferred.resolve() unless isDetached($element)
|
979
|
+
# Clean up in case we're canceled through some other code that
|
980
|
+
# resolves our deferred.
|
981
|
+
deferred.then(-> clearTimeout(endTimeout))
|
982
|
+
|
921
983
|
# Return the whole deferred and not just return a thenable.
|
922
984
|
# Other code will need the possibility to cancel the animation
|
923
985
|
# by resolving the deferred.
|
@@ -1299,49 +1361,46 @@ up.util = (($) ->
|
|
1299
1361
|
|
1300
1362
|
store = undefined
|
1301
1363
|
|
1364
|
+
optionEvaluator = (name) ->
|
1365
|
+
->
|
1366
|
+
value = config[name]
|
1367
|
+
if isNumber(value)
|
1368
|
+
value
|
1369
|
+
else if isFunction(value)
|
1370
|
+
value()
|
1371
|
+
else
|
1372
|
+
undefined
|
1373
|
+
|
1374
|
+
maxKeys = optionEvaluator('size')
|
1375
|
+
|
1376
|
+
expiryMillis = optionEvaluator('expiry')
|
1377
|
+
|
1378
|
+
normalizeStoreKey = (key) ->
|
1379
|
+
if config.key
|
1380
|
+
config.key(key)
|
1381
|
+
else
|
1382
|
+
key.toString()
|
1383
|
+
|
1384
|
+
isEnabled = ->
|
1385
|
+
maxKeys() isnt 0 && expiryMillis() isnt 0
|
1386
|
+
|
1302
1387
|
clear = ->
|
1303
1388
|
store = {}
|
1304
1389
|
|
1305
1390
|
clear()
|
1306
1391
|
|
1307
1392
|
log = (args...) ->
|
1308
|
-
if config.
|
1309
|
-
args[0] = "[#{config.
|
1393
|
+
if config.logPrefix
|
1394
|
+
args[0] = "[#{config.logPrefix}] #{args[0]}"
|
1310
1395
|
up.puts(args...)
|
1311
1396
|
|
1312
1397
|
keys = ->
|
1313
1398
|
Object.keys(store)
|
1314
1399
|
|
1315
|
-
|
1316
|
-
if isMissing(config.size)
|
1317
|
-
undefined
|
1318
|
-
else if isFunction(config.size)
|
1319
|
-
config.size()
|
1320
|
-
else if isNumber(config.size)
|
1321
|
-
config.size
|
1322
|
-
else
|
1323
|
-
error("Invalid size config: %o", config.size)
|
1324
|
-
|
1325
|
-
expiryMilis = ->
|
1326
|
-
if isMissing(config.expiry)
|
1327
|
-
undefined
|
1328
|
-
else if isFunction(config.expiry)
|
1329
|
-
config.expiry()
|
1330
|
-
else if isNumber(config.expiry)
|
1331
|
-
config.expiry
|
1332
|
-
else
|
1333
|
-
error("Invalid expiry config: %o", config.expiry)
|
1334
|
-
|
1335
|
-
normalizeStoreKey = (key) ->
|
1336
|
-
if config.key
|
1337
|
-
config.key(key)
|
1338
|
-
else
|
1339
|
-
key.toString()
|
1340
|
-
|
1341
|
-
trim = ->
|
1400
|
+
makeRoomForAnotherKey = ->
|
1342
1401
|
storeKeys = copy(keys())
|
1343
|
-
|
1344
|
-
if
|
1402
|
+
max = maxKeys()
|
1403
|
+
if max && storeKeys.length >= max
|
1345
1404
|
oldestKey = null
|
1346
1405
|
oldestTimestamp = null
|
1347
1406
|
each storeKeys, (key) ->
|
@@ -1361,20 +1420,22 @@ up.util = (($) ->
|
|
1361
1420
|
(new Date()).valueOf()
|
1362
1421
|
|
1363
1422
|
set = (key, value) ->
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1423
|
+
if isEnabled()
|
1424
|
+
makeRoomForAnotherKey()
|
1425
|
+
storeKey = normalizeStoreKey(key)
|
1426
|
+
store[storeKey] =
|
1427
|
+
timestamp: timestamp()
|
1428
|
+
value: value
|
1368
1429
|
|
1369
1430
|
remove = (key) ->
|
1370
1431
|
storeKey = normalizeStoreKey(key)
|
1371
1432
|
delete store[storeKey]
|
1372
1433
|
|
1373
1434
|
isFresh = (entry) ->
|
1374
|
-
|
1375
|
-
if
|
1435
|
+
millis = expiryMillis()
|
1436
|
+
if millis
|
1376
1437
|
timeSinceTouch = timestamp() - entry.timestamp
|
1377
|
-
timeSinceTouch <
|
1438
|
+
timeSinceTouch < millis
|
1378
1439
|
else
|
1379
1440
|
true
|
1380
1441
|
|
@@ -1570,12 +1631,37 @@ up.util = (($) ->
|
|
1570
1631
|
$error.text(asString)
|
1571
1632
|
throw new Error(asString)
|
1572
1633
|
|
1634
|
+
pluckKey = (object, key) ->
|
1635
|
+
value = object[key]
|
1636
|
+
delete object[key]
|
1637
|
+
value
|
1638
|
+
|
1573
1639
|
pluckData = (elementOrSelector, key) ->
|
1574
1640
|
$element = $(elementOrSelector)
|
1575
1641
|
value = $element.data(key)
|
1576
1642
|
$element.removeData(key)
|
1577
1643
|
value
|
1578
1644
|
|
1645
|
+
extractOptions = (args) ->
|
1646
|
+
lastArg = last(args)
|
1647
|
+
if isObject(lastArg)
|
1648
|
+
args.pop()
|
1649
|
+
else
|
1650
|
+
{}
|
1651
|
+
|
1652
|
+
###*
|
1653
|
+
Returns whether the given element has been detached from the DOM
|
1654
|
+
(or whether it was never attached).
|
1655
|
+
|
1656
|
+
@function up.util.isDetached
|
1657
|
+
@internal
|
1658
|
+
###
|
1659
|
+
isDetached = (element) ->
|
1660
|
+
element = unJQuery(element)
|
1661
|
+
# This is by far the fastest way to do this
|
1662
|
+
not jQuery.contains(document.documentElement, element)
|
1663
|
+
|
1664
|
+
isDetached: isDetached
|
1579
1665
|
requestDataAsArray: requestDataAsArray
|
1580
1666
|
requestDataAsQuery: requestDataAsQuery
|
1581
1667
|
appendRequestData: appendRequestData
|
@@ -1631,12 +1717,14 @@ up.util = (($) ->
|
|
1631
1717
|
isUnmodifiedMouseEvent: isUnmodifiedMouseEvent
|
1632
1718
|
nullJQuery: nullJQuery
|
1633
1719
|
unJQuery: unJQuery
|
1720
|
+
setTimer: setTimer
|
1634
1721
|
nextFrame: nextFrame
|
1635
1722
|
measure: measure
|
1636
1723
|
temporaryCss: temporaryCss
|
1637
1724
|
cssAnimate: cssAnimate
|
1638
1725
|
finishCssAnimate: finishCssAnimate
|
1639
1726
|
forceCompositing: forceCompositing
|
1727
|
+
forceRepaint: forceRepaint
|
1640
1728
|
escapePressed: escapePressed
|
1641
1729
|
copyAttributes: copyAttributes
|
1642
1730
|
findWithSelf: findWithSelf
|
@@ -1667,6 +1755,10 @@ up.util = (($) ->
|
|
1667
1755
|
multiSelector: multiSelector
|
1668
1756
|
error: error
|
1669
1757
|
pluckData: pluckData
|
1758
|
+
pluckKey: pluckKey
|
1759
|
+
extractOptions: extractOptions
|
1760
|
+
isDetached: isDetached
|
1761
|
+
noop: noop
|
1670
1762
|
|
1671
1763
|
)($)
|
1672
1764
|
|