upjs-rails 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -3
- data/lib/assets/javascripts/up/flow.js.coffee +49 -36
- data/lib/assets/javascripts/up/form.js.coffee +2 -2
- data/lib/assets/javascripts/up/link.js.coffee +19 -12
- data/lib/assets/javascripts/up/magic.js.coffee +17 -1
- data/lib/assets/javascripts/up/modal.js.coffee +12 -0
- data/lib/assets/javascripts/up/motion.js.coffee +10 -9
- data/lib/assets/javascripts/up/navigation.js.coffee +11 -4
- data/lib/assets/javascripts/up/popup.js.coffee +12 -3
- data/lib/assets/javascripts/up/proxy.js.coffee +26 -12
- data/lib/assets/javascripts/up/util.js.coffee +14 -2
- data/lib/assets/javascripts/up/viewport.js.coffee +125 -0
- data/lib/assets/javascripts/up.js.coffee +1 -0
- data/lib/upjs/rails/version.rb +1 -1
- data/spec_app/Gemfile.lock +1 -1
- data/spec_app/spec/javascripts/helpers/to_equal_jquery.js.coffee +9 -0
- data/spec_app/spec/javascripts/helpers/trigger.js.coffee +28 -0
- data/spec_app/spec/javascripts/up/flow_spec.js.coffee +1 -1
- data/spec_app/spec/javascripts/up/form_spec.js.coffee +3 -2
- data/spec_app/spec/javascripts/up/link_spec.js.coffee +37 -0
- data/spec_app/spec/javascripts/up/modal_spec.js.coffee +9 -1
- data/spec_app/spec/javascripts/up/navigation_spec.js.coffee +15 -1
- data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +27 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea22c4f8c05c98c188200595aae81fda36affbc6
|
4
|
+
data.tar.gz: 7cccbe256055dcfefa5036d0ad83df85f32064a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 927e77f26edab9252b32c4c32a04a7a94ba5efd3f1cb8f03fd7dc2920f7f2fca09ca06cdf5b5977d508af7b81aa56f1be67c621d218b77da368303e18df6a195
|
7
|
+
data.tar.gz: a42ec712bd4a7a68b19ec5a813a8e044dc19eeec71e5a9dca989ffde7e90e4e6cecefd9bde8b44cc07d1c4b63c86482f2e8ec9a7241fafd33df5522edf485dd7
|
data/README.md
CHANGED
@@ -20,6 +20,7 @@ To run Jasmine tests:
|
|
20
20
|
- Install Ruby 2.1.2
|
21
21
|
- `cd` into `spec_app`
|
22
22
|
- Install dependencies by running `bundle install`
|
23
|
+
- Migrate
|
23
24
|
- Start the Rails server
|
24
25
|
- Access `http://localhost:3000/specs`
|
25
26
|
|
@@ -44,6 +45,3 @@ Now make the release for manual download and bower:
|
|
44
45
|
- From the project root, type `rake assets:compile`
|
45
46
|
- This will output minified JS and CSS files to the `dist` folder
|
46
47
|
- Commit and push the generated files
|
47
|
-
|
48
|
-
|
49
|
-
|
@@ -48,6 +48,7 @@ up.flow = (->
|
|
48
48
|
If set to `false`, the history will remain unchanged.
|
49
49
|
@param {String|Boolean} [options.source=true]
|
50
50
|
@param {String} [options.transition]
|
51
|
+
@param {String} [options.scroll='body']
|
51
52
|
@param {String} [options.historyMethod='push']
|
52
53
|
###
|
53
54
|
replace = (selectorOrElement, url, options) ->
|
@@ -102,6 +103,7 @@ up.flow = (->
|
|
102
103
|
@param {String} [options.title]
|
103
104
|
@param {String} [options.source]
|
104
105
|
@param {Object} [options.transition]
|
106
|
+
@param {String} [options.scroll='body']
|
105
107
|
@param {String} [options.history]
|
106
108
|
@param {String} [options.historyMethod='push']
|
107
109
|
###
|
@@ -111,38 +113,55 @@ up.flow = (->
|
|
111
113
|
historyMethod: 'push'
|
112
114
|
)
|
113
115
|
|
114
|
-
if options.history
|
116
|
+
if u.castsToFalse(options.history)
|
115
117
|
options.history = null
|
116
|
-
|
118
|
+
|
119
|
+
if u.castsToFalse(options.scroll)
|
120
|
+
options.scroll = null
|
121
|
+
|
117
122
|
options.source = u.option(options.source, options.history)
|
118
|
-
|
123
|
+
|
124
|
+
response = parseResponse(html)
|
125
|
+
|
126
|
+
options.title ||= response.title()
|
127
|
+
|
128
|
+
for step in parseImplantSteps(selector, options)
|
129
|
+
$old = findOldFragment(step.selector)
|
130
|
+
$new = response.find(step.selector)
|
131
|
+
prepareForReplacement($old, options).then ->
|
132
|
+
swapElements($old, $new, step.pseudoClass, step.transition, options)
|
133
|
+
|
134
|
+
findOldFragment = (selector) ->
|
135
|
+
u.presence($(".up-popup " + selector)) ||
|
136
|
+
u.presence($(".up-modal " + selector)) ||
|
137
|
+
u.presence($(selector)) ||
|
138
|
+
u.error('Could not find selector %o in current body HTML', selector)
|
139
|
+
|
140
|
+
parseResponse = (html) ->
|
119
141
|
# jQuery cannot construct transient elements that contain <html> or <body> tags,
|
120
142
|
# so we're using the native browser API to grep through the HTML
|
121
143
|
htmlElement = u.createElementFromHtml(html)
|
144
|
+
title: -> htmlElement.querySelector("title")?.textContent
|
145
|
+
find: (selector) ->
|
146
|
+
if child = htmlElement.querySelector(selector)
|
147
|
+
$(child)
|
148
|
+
else
|
149
|
+
u.error("Could not find selector %o in response %o", selector, html)
|
122
150
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
151
|
+
prepareForReplacement = ($element, options) ->
|
152
|
+
# Before we select a replacement target, ensure that all transitions
|
153
|
+
# and animations have been run. Finishing a transition usually removes
|
154
|
+
# the element that is being morphed, so it will affect further selections
|
155
|
+
# using the same selector.
|
156
|
+
up.motion.finish($element)
|
157
|
+
reveal($element, options.scroll)
|
127
158
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
159
|
+
reveal = ($element, view) ->
|
160
|
+
if view
|
161
|
+
up.reveal($element, view: view)
|
162
|
+
else
|
163
|
+
u.resolvedDeferred()
|
133
164
|
|
134
|
-
$old =
|
135
|
-
# always prefer to replace content in popups or modals
|
136
|
-
u.presence($(".up-popup " + step.selector)) ||
|
137
|
-
u.presence($(".up-modal " + step.selector)) ||
|
138
|
-
u.presence($(step.selector)) ||
|
139
|
-
u.error('Could not find selector %o in current body HTML', step.selector)
|
140
|
-
if fragment = htmlElement.querySelector(step.selector)
|
141
|
-
$new = $(fragment)
|
142
|
-
swapElements $old, $new, step.pseudoClass, step.transition, options
|
143
|
-
else
|
144
|
-
u.error("Could not find selector %o in response %o", step.selector, html)
|
145
|
-
|
146
165
|
elementsInserted = ($new, options) ->
|
147
166
|
options.insert?($new)
|
148
167
|
if options.history
|
@@ -177,13 +196,16 @@ up.flow = (->
|
|
177
196
|
# Wrap the replacement as a destroy animation, so $old will
|
178
197
|
# get marked as .up-destroying right away.
|
179
198
|
destroy $old, animation: ->
|
180
|
-
|
199
|
+
# Don't insert the new element after the old element.
|
200
|
+
# For some reason this will make the browser scroll to the
|
201
|
+
# bottom of the new element.
|
202
|
+
$new.insertBefore($old)
|
181
203
|
elementsInserted($new, options)
|
182
204
|
if $old.is('body') && transition != 'none'
|
183
205
|
u.error('Cannot apply transitions to body-elements (%o)', transition)
|
184
206
|
up.morph($old, $new, transition)
|
185
207
|
|
186
|
-
|
208
|
+
parseImplantSteps = (selector, options) ->
|
187
209
|
transitionString = options.transition || options.animation || 'none'
|
188
210
|
comma = /\ *,\ */
|
189
211
|
disjunction = selector.split(comma)
|
@@ -201,16 +223,7 @@ up.flow = (->
|
|
201
223
|
$control = u.findWithSelf($element, selector)
|
202
224
|
if $control.length && $control.get(0) != document.activeElement
|
203
225
|
$control.focus()
|
204
|
-
|
205
|
-
# executeScripts = ($new) ->
|
206
|
-
# $new.find('script').each ->
|
207
|
-
# $script = $(this)
|
208
|
-
# type = $script.attr('type')
|
209
|
-
# if u.isBlank(type) || type.indexOf('text/javascript') == 0
|
210
|
-
# code = $script.text()
|
211
|
-
# console.log("Evaling javascript code", code)
|
212
|
-
# eval(code)
|
213
|
-
|
226
|
+
|
214
227
|
###*
|
215
228
|
Destroys the given element or selector.
|
216
229
|
Takes care that all destructors, if any, are called.
|
@@ -82,7 +82,7 @@ up.form = (->
|
|
82
82
|
|
83
83
|
successUrl = (xhr) ->
|
84
84
|
url = if historyOption
|
85
|
-
if historyOption
|
85
|
+
if u.castsToFalse(historyOption)
|
86
86
|
false
|
87
87
|
else if u.isString(historyOption)
|
88
88
|
historyOption
|
@@ -165,7 +165,7 @@ up.form = (->
|
|
165
165
|
check = ->
|
166
166
|
value = $field.val()
|
167
167
|
# don't run the callback for the check during initialization
|
168
|
-
skipCallback =
|
168
|
+
skipCallback = u.isNull(knownValue)
|
169
169
|
if knownValue != value
|
170
170
|
knownValue = value
|
171
171
|
unless skipCallback
|
@@ -109,6 +109,9 @@ up.link = (->
|
|
109
109
|
or to `body` if such an attribute does not exist.
|
110
110
|
@param {Function|String} [options.transition]
|
111
111
|
A transition function or name.
|
112
|
+
@param {Element|jQuery|String} scroll
|
113
|
+
An element or selector that will be scrolled to the top in
|
114
|
+
case the replaced element is not visible in the viewport.
|
112
115
|
###
|
113
116
|
follow = (link, options) ->
|
114
117
|
$link = $(link)
|
@@ -118,6 +121,7 @@ up.link = (->
|
|
118
121
|
selector = u.option(options.target, $link.attr('up-target'), 'body')
|
119
122
|
options.transition = u.option(options.transition, $link.attr('up-transition'), $link.attr('up-animation'))
|
120
123
|
options.history = u.option(options.history, $link.attr('up-history'))
|
124
|
+
options.scroll = u.option(options.history, $link.attr('up-scroll'), 'body')
|
121
125
|
|
122
126
|
up.replace(selector, url, options)
|
123
127
|
|
@@ -160,11 +164,11 @@ up.link = (->
|
|
160
164
|
follow($link)
|
161
165
|
|
162
166
|
up.on 'mousedown', 'a[up-target][up-instant]', (event, $link) ->
|
163
|
-
if event
|
167
|
+
if activeInstantLink(event, $link)
|
164
168
|
event.preventDefault()
|
165
|
-
follow($link)
|
169
|
+
up.follow($link)
|
166
170
|
|
167
|
-
|
171
|
+
###*
|
168
172
|
@method up.link.childClicked
|
169
173
|
@private
|
170
174
|
###
|
@@ -173,6 +177,9 @@ up.link = (->
|
|
173
177
|
$targetLink = $target.closest('a, [up-follow]')
|
174
178
|
$targetLink.length && $link.find($targetLink).length
|
175
179
|
|
180
|
+
activeInstantLink = (event, $link) ->
|
181
|
+
u.isUnmodifiedMouseEvent(event) && !childClicked(event, $link)
|
182
|
+
|
176
183
|
###*
|
177
184
|
If applied on a link, Follows this link via AJAX and replaces the
|
178
185
|
current `<body>` element with the response's `<body>` element
|
@@ -206,19 +213,19 @@ up.link = (->
|
|
206
213
|
@param up-instant
|
207
214
|
If set, fetches the element on `mousedown` instead of `click`.
|
208
215
|
###
|
209
|
-
up.on 'click', '[up-follow]', (event, $
|
210
|
-
unless childClicked(event, $
|
216
|
+
up.on 'click', '[up-follow]', (event, $link) ->
|
217
|
+
unless childClicked(event, $link)
|
211
218
|
event.preventDefault()
|
212
219
|
# Check if the event was already triggered by `mousedown`
|
213
|
-
unless $
|
214
|
-
follow(resolve($
|
220
|
+
unless $link.is('[up-instant]')
|
221
|
+
follow(resolve($link))
|
215
222
|
|
216
|
-
up.on 'mousedown', '[up-follow][up-instant]', (event, $
|
217
|
-
if
|
223
|
+
up.on 'mousedown', '[up-follow][up-instant]', (event, $link) ->
|
224
|
+
if activeInstantLink(event, $link)
|
218
225
|
event.preventDefault()
|
219
|
-
follow(resolve($
|
226
|
+
up.follow(resolve($link))
|
220
227
|
|
221
|
-
|
228
|
+
###*
|
222
229
|
Marks up the current link to be followed *as fast as possible*.
|
223
230
|
This is done by:
|
224
231
|
|
@@ -232,7 +239,7 @@ up.link = (->
|
|
232
239
|
|
233
240
|
Note that this is shorthand for:
|
234
241
|
|
235
|
-
|
242
|
+
<a href="/users" up-target=".main" up-instant up-preload>User list</a>
|
236
243
|
|
237
244
|
You can also apply `[up-dash]` to any element that contains a link
|
238
245
|
in order to enlarge the link's click area:
|
@@ -113,7 +113,7 @@ up.magic = (->
|
|
113
113
|
destroyer = $element.data(DESTROYER_KEY)
|
114
114
|
destroyer()
|
115
115
|
|
116
|
-
|
116
|
+
###*
|
117
117
|
Checks if the given element has an `up-data` attribute.
|
118
118
|
If yes, parses the attribute value as JSON and returns the parsed object.
|
119
119
|
|
@@ -126,6 +126,22 @@ up.magic = (->
|
|
126
126
|
@method up.magic.data
|
127
127
|
@param {String|Element|jQuery} elementOrSelector
|
128
128
|
###
|
129
|
+
|
130
|
+
###
|
131
|
+
Stores a JSON-string with the element.
|
132
|
+
|
133
|
+
If an element annotated with [`up-data`] is inserted into the DOM,
|
134
|
+
Up will parse the JSON and pass the resulting object to any matching
|
135
|
+
[`up.awaken`](/up.magic#up.magic.awaken) handlers.
|
136
|
+
|
137
|
+
Similarly, when an event is triggered on an element annotated with
|
138
|
+
[`up-data`], the parsed object will be passed to any matching
|
139
|
+
[`up.on`](/up.magic#up.on) handlers.
|
140
|
+
|
141
|
+
@ujs
|
142
|
+
@method [up-data]
|
143
|
+
@param {JSON} [up-data]
|
144
|
+
###
|
129
145
|
data = (elementOrSelector) ->
|
130
146
|
$element = $(elementOrSelector)
|
131
147
|
json = $element.attr('up-data')
|
@@ -56,6 +56,16 @@ up.modal = (->
|
|
56
56
|
else
|
57
57
|
template
|
58
58
|
|
59
|
+
rememberHistory = ->
|
60
|
+
$popup = $('.up-modal')
|
61
|
+
$popup.attr('up-previous-url', up.browser.url())
|
62
|
+
$popup.attr('up-previous-title', document.title)
|
63
|
+
|
64
|
+
discardHistory = ->
|
65
|
+
$popup = $('.up-modal')
|
66
|
+
$popup.removeAttr('up-previous-url')
|
67
|
+
$popup.removeAttr('up-previous-title')
|
68
|
+
|
59
69
|
createHiddenModal = (selector, width, height, sticky) ->
|
60
70
|
$modal = $(templateHtml())
|
61
71
|
$modal.attr('up-sticky', '') if sticky
|
@@ -68,6 +78,7 @@ up.modal = (->
|
|
68
78
|
$placeholder = u.$createElementFromSelector(selector)
|
69
79
|
$placeholder.appendTo($content)
|
70
80
|
$modal.appendTo(document.body)
|
81
|
+
rememberHistory()
|
71
82
|
$modal.hide()
|
72
83
|
$modal
|
73
84
|
|
@@ -143,6 +154,7 @@ up.modal = (->
|
|
143
154
|
|
144
155
|
autoclose = ->
|
145
156
|
unless $('.up-modal').is('[up-sticky]')
|
157
|
+
discardHistory()
|
146
158
|
close()
|
147
159
|
|
148
160
|
###*
|
@@ -22,22 +22,22 @@ We need to work on this page:
|
|
22
22
|
up.motion = (->
|
23
23
|
|
24
24
|
u = up.util
|
25
|
-
|
26
|
-
config =
|
27
|
-
duration: 300
|
28
|
-
delay: 0
|
29
|
-
easing: 'ease'
|
30
25
|
|
31
26
|
animations = {}
|
32
27
|
defaultAnimations = {}
|
33
28
|
transitions = {}
|
34
29
|
defaultTransitions = {}
|
35
30
|
|
31
|
+
config =
|
32
|
+
duration: 300
|
33
|
+
delay: 0
|
34
|
+
easing: 'ease'
|
35
|
+
|
36
36
|
###*
|
37
37
|
@method up.modal.defaults
|
38
|
-
@param {Number} options.duration
|
39
|
-
@param {Number} options.delay
|
40
|
-
@param {String} options.easing
|
38
|
+
@param {Number} [options.duration]
|
39
|
+
@param {Number} [options.delay]
|
40
|
+
@param {String} [options.easing]
|
41
41
|
###
|
42
42
|
defaults = (options) ->
|
43
43
|
u.extend(config, options)
|
@@ -117,13 +117,14 @@ up.motion = (->
|
|
117
117
|
|
118
118
|
promise
|
119
119
|
|
120
|
-
|
120
|
+
###*
|
121
121
|
Completes all animations and transitions for the given element
|
122
122
|
by jumping to the last animation frame instantly. All callbacks chained to
|
123
123
|
the original animation's promise will be called.
|
124
124
|
|
125
125
|
Does nothing if the given element is not currently animating.
|
126
126
|
|
127
|
+
@method up.motion.finish
|
127
128
|
@param {Element|jQuery|String} elementOrSelector
|
128
129
|
###
|
129
130
|
finish = (elementOrSelector) ->
|
@@ -29,7 +29,9 @@ up.navigation = (->
|
|
29
29
|
|
30
30
|
CLASS_ACTIVE = 'up-active'
|
31
31
|
CLASS_CURRENT = 'up-current'
|
32
|
-
|
32
|
+
SELECTORS_SECTION = ['a[href]', 'a[up-target]', '[up-follow]', '[up-modal]', '[up-popup]', '[up-href]']
|
33
|
+
SELECTOR_SECTION = SELECTORS_SECTION.join(', ')
|
34
|
+
SELECTOR_SECTION_INSTANT = ("#{selector}[up-instant]" for selector in SELECTORS_SECTION).join(', ')
|
33
35
|
SELECTOR_ACTIVE = ".#{CLASS_ACTIVE}"
|
34
36
|
|
35
37
|
normalizeUrl = (url) ->
|
@@ -42,7 +44,7 @@ up.navigation = (->
|
|
42
44
|
sectionUrls = ($section) ->
|
43
45
|
urls = []
|
44
46
|
if $link = up.link.resolve($section)
|
45
|
-
for attr in ['href', 'up-follow', 'up-
|
47
|
+
for attr in ['href', 'up-follow', 'up-href']
|
46
48
|
if url = u.presentAttr($link, attr)
|
47
49
|
url = normalizeUrl(url)
|
48
50
|
urls.push(url)
|
@@ -77,8 +79,13 @@ up.navigation = (->
|
|
77
79
|
$(SELECTOR_ACTIVE).removeClass(CLASS_ACTIVE)
|
78
80
|
|
79
81
|
up.on 'click', SELECTOR_SECTION, (event, $section) ->
|
80
|
-
|
81
|
-
|
82
|
+
unless $section.is('[up-instant]')
|
83
|
+
sectionClicked($section)
|
84
|
+
|
85
|
+
up.on 'mousedown', SELECTOR_SECTION_INSTANT, (event, $section) ->
|
86
|
+
if u.isUnmodifiedMouseEvent(event)
|
87
|
+
sectionClicked($section)
|
88
|
+
|
82
89
|
# When a fragment is ready it might either have brought a location change
|
83
90
|
# with it, or it might have opened a modal / popup which we consider
|
84
91
|
# to be secondary location sources (the primary being the browser's
|
@@ -84,16 +84,24 @@ up.popup = (->
|
|
84
84
|
$popup.css('top', top - errorY)
|
85
85
|
else if bottom = parseInt($popup.css('bottom'))
|
86
86
|
$popup.css('bottom', bottom + errorY)
|
87
|
-
|
87
|
+
|
88
|
+
rememberHistory = ->
|
89
|
+
$popup = $('.up-popup')
|
90
|
+
$popup.attr('up-previous-url', up.browser.url())
|
91
|
+
$popup.attr('up-previous-title', document.title)
|
92
|
+
|
93
|
+
discardHistory = ->
|
94
|
+
$popup = $('.up-popup')
|
95
|
+
$popup.removeAttr('up-previous-url')
|
96
|
+
$popup.removeAttr('up-previous-title')
|
88
97
|
|
89
98
|
createHiddenPopup = ($link, selector, sticky) ->
|
90
99
|
$popup = u.$createElementFromSelector('.up-popup')
|
91
100
|
$popup.attr('up-sticky', '') if sticky
|
92
|
-
$popup.attr('up-previous-url', up.browser.url())
|
93
|
-
$popup.attr('up-previous-title', document.title)
|
94
101
|
$placeholder = u.$createElementFromSelector(selector)
|
95
102
|
$placeholder.appendTo($popup)
|
96
103
|
$popup.appendTo(document.body)
|
104
|
+
rememberHistory()
|
97
105
|
$popup.hide()
|
98
106
|
$popup
|
99
107
|
|
@@ -204,6 +212,7 @@ up.popup = (->
|
|
204
212
|
|
205
213
|
up.bus.on('fragment:ready', ($fragment) ->
|
206
214
|
unless $fragment.closest('.up-popup').length
|
215
|
+
discardHistory()
|
207
216
|
autoclose()
|
208
217
|
)
|
209
218
|
|
@@ -3,10 +3,12 @@ Caching and preloading
|
|
3
3
|
======================
|
4
4
|
|
5
5
|
All HTTP requests go through the Up.js proxy.
|
6
|
-
It caches a limited number
|
6
|
+
It caches a [limited](/up.proxy#up.proxy.defaults) number of server responses
|
7
|
+
for a [limited](/up.proxy#up.proxy.defaults) amount of time,
|
8
|
+
making requests to these URLs return insantly.
|
7
9
|
|
8
|
-
The cache is cleared whenever the user makes a non
|
9
|
-
(like `POST`, `PUT
|
10
|
+
The cache is cleared whenever the user makes a non-`GET` request
|
11
|
+
(like `POST`, `PUT` or `DELETE`).
|
10
12
|
|
11
13
|
The proxy can also used to speed up reaction times by preloading
|
12
14
|
links when the user hovers over the click area (or puts the mouse/finger
|
@@ -18,15 +20,15 @@ response will already be cached when the user performs the click.
|
|
18
20
|
up.proxy = (->
|
19
21
|
|
20
22
|
config =
|
21
|
-
preloadDelay:
|
23
|
+
preloadDelay: 75
|
22
24
|
cacheSize: 70
|
23
25
|
cacheExpiry: 1000 * 60 * 5
|
24
26
|
|
25
27
|
###*
|
26
28
|
@method up.proxy.defaults
|
27
|
-
@param {Number} [preloadDelay]
|
28
|
-
@param {Number} [cacheSize]
|
29
|
-
@param {Number} [cacheExpiry]
|
29
|
+
@param {Number} [options.preloadDelay]
|
30
|
+
@param {Number} [options.cacheSize]
|
31
|
+
@param {Number} [options.cacheExpiry]
|
30
32
|
The number of milliseconds until a cache entry expires.
|
31
33
|
###
|
32
34
|
defaults = (options) ->
|
@@ -76,11 +78,19 @@ up.proxy = (->
|
|
76
78
|
if promise = get(oldRequest)
|
77
79
|
set(newRequest, promise)
|
78
80
|
|
79
|
-
|
81
|
+
###*
|
82
|
+
Makes a request to the given URL and caches the response.
|
83
|
+
If the response was already cached, returns the HTML instantly.
|
84
|
+
|
85
|
+
If requesting a URL that is not read-only, the response will
|
86
|
+
not be cached and the entire cache will be cleared.
|
87
|
+
Only requests with a method of `GET`, `OPTIONS` and `HEAD`
|
88
|
+
are considered to be read-only.
|
89
|
+
|
80
90
|
@method up.proxy.ajax
|
81
|
-
@param {String}
|
82
|
-
@param {String} [
|
83
|
-
@param {String} [
|
91
|
+
@param {String} request.url
|
92
|
+
@param {String} [request.method='GET']
|
93
|
+
@param {String} [request.selector]
|
84
94
|
###
|
85
95
|
ajax = (request) ->
|
86
96
|
if !isIdempotent(request)
|
@@ -168,7 +178,7 @@ up.proxy = (->
|
|
168
178
|
|
169
179
|
up.bus.on 'framework:reset', reset
|
170
180
|
|
171
|
-
|
181
|
+
###*
|
172
182
|
Links with an `up-preload` attribute will silently fetch their target
|
173
183
|
when the user hovers over the click area, or when the user puts her
|
174
184
|
mouse/finger down (before releasing). This way the
|
@@ -176,6 +186,10 @@ up.proxy = (->
|
|
176
186
|
making the interaction feel instant.
|
177
187
|
|
178
188
|
@method [up-preload]
|
189
|
+
@param [[up-delay]=50]
|
190
|
+
The number of milliseconds to wait between hovering
|
191
|
+
and preloading. Increasing this will lower the load in your server,
|
192
|
+
but will also make the interaction feel less instant.
|
179
193
|
@ujs
|
180
194
|
###
|
181
195
|
up.on 'mouseover mousedown touchstart', '[up-preload]', (event, $element) ->
|
@@ -58,7 +58,7 @@ up.util = (->
|
|
58
58
|
normalized += anchor.search unless options?.search == false
|
59
59
|
normalized
|
60
60
|
|
61
|
-
|
61
|
+
###*
|
62
62
|
@method up.util.normalizeMethod
|
63
63
|
@protected
|
64
64
|
###
|
@@ -436,13 +436,17 @@ up.util = (->
|
|
436
436
|
|
437
437
|
ANIMATION_PROMISE_KEY = 'up-animation-promise'
|
438
438
|
|
439
|
-
|
439
|
+
###*
|
440
440
|
Completes the animation for the given element by jumping
|
441
441
|
to the last frame instantly. All callbacks chained to
|
442
442
|
the original animation's promise will be called.
|
443
443
|
|
444
444
|
Does nothing if the given element is not currently animating.
|
445
445
|
|
446
|
+
Also see [`up.motion.finish`](/up.motion#up.motion.finish).
|
447
|
+
|
448
|
+
@method up.util.finishCssAnimate
|
449
|
+
@protected
|
446
450
|
@param {Element|jQuery|String} elementOrSelector
|
447
451
|
###
|
448
452
|
finishCssAnimate = (elementOrSelector) ->
|
@@ -523,6 +527,12 @@ up.util = (->
|
|
523
527
|
filtered[key] = object[key]
|
524
528
|
filtered
|
525
529
|
|
530
|
+
isUnmodifiedKeyEvent = (event) ->
|
531
|
+
not (event.metaKey or event.shiftKey or event.ctrlKey)
|
532
|
+
|
533
|
+
isUnmodifiedMouseEvent = (event) ->
|
534
|
+
event.button is 0 and isUnmodifiedKeyEvent(event)
|
535
|
+
|
526
536
|
resolvedDeferred = ->
|
527
537
|
deferred = $.Deferred()
|
528
538
|
deferred.resolve()
|
@@ -615,6 +625,8 @@ up.util = (->
|
|
615
625
|
isDeferred: isDeferred
|
616
626
|
isHash: isHash
|
617
627
|
ifGiven: ifGiven
|
628
|
+
isUnmodifiedKeyEvent: isUnmodifiedKeyEvent
|
629
|
+
isUnmodifiedMouseEvent: isUnmodifiedMouseEvent
|
618
630
|
unwrap: unwrap
|
619
631
|
nextFrame: nextFrame
|
620
632
|
measure: measure
|
@@ -0,0 +1,125 @@
|
|
1
|
+
###*
|
2
|
+
Viewport scrolling
|
3
|
+
==================
|
4
|
+
|
5
|
+
This modules contains functions to scroll the viewport and reveal contained elements.
|
6
|
+
|
7
|
+
By default Up.js will always scroll to an element before updating it.
|
8
|
+
|
9
|
+
@class up.viewport
|
10
|
+
###
|
11
|
+
up.viewport = (->
|
12
|
+
|
13
|
+
u = up.util
|
14
|
+
|
15
|
+
config =
|
16
|
+
duration: 0
|
17
|
+
view: 'body'
|
18
|
+
easing: 'swing'
|
19
|
+
|
20
|
+
###*
|
21
|
+
@method up.viewport.defaults
|
22
|
+
@param {Number} [options.duration]
|
23
|
+
@param {String} [options.easing]
|
24
|
+
@param {Number} [options.padding]
|
25
|
+
@param {String|Element|jQuery} [options.view]
|
26
|
+
###
|
27
|
+
defaults = (options) ->
|
28
|
+
u.extend(config, options)
|
29
|
+
|
30
|
+
SCROLL_PROMISE_KEY = 'up-scroll-promise'
|
31
|
+
|
32
|
+
###*
|
33
|
+
@method up.scroll
|
34
|
+
@param {String|Element|jQuery} viewOrSelector
|
35
|
+
@param {Number} scrollPos
|
36
|
+
@param {String}[options.duration]
|
37
|
+
@param {String}[options.easing]
|
38
|
+
@returns {Deferred}
|
39
|
+
@protected
|
40
|
+
###
|
41
|
+
scroll = (viewOrSelector, scrollPos, options) ->
|
42
|
+
$view = $(viewOrSelector)
|
43
|
+
options = u.options(options)
|
44
|
+
duration = u.option(options.duration, config.duration)
|
45
|
+
easing = u.option(options.easing, config.easing)
|
46
|
+
|
47
|
+
finishScrolling($view)
|
48
|
+
|
49
|
+
if duration > 0
|
50
|
+
deferred = $.Deferred()
|
51
|
+
|
52
|
+
$view.data(SCROLL_PROMISE_KEY, deferred)
|
53
|
+
deferred.then ->
|
54
|
+
$view.removeData(SCROLL_PROMISE_KEY)
|
55
|
+
$view.finish()
|
56
|
+
|
57
|
+
targetProps =
|
58
|
+
scrollTop: scrollPos
|
59
|
+
|
60
|
+
$view.animate targetProps,
|
61
|
+
duration: duration,
|
62
|
+
easing: easing,
|
63
|
+
complete: -> deferred.resolve()
|
64
|
+
|
65
|
+
deferred
|
66
|
+
else
|
67
|
+
$view.scrollTop(scrollPos)
|
68
|
+
u.resolvedDeferred()
|
69
|
+
|
70
|
+
###*
|
71
|
+
@method up.viewport.finishScrolling
|
72
|
+
@private
|
73
|
+
###
|
74
|
+
finishScrolling = (elementOrSelector) ->
|
75
|
+
$(elementOrSelector).each ->
|
76
|
+
if existingScrolling = $(this).data(SCROLL_PROMISE_KEY)
|
77
|
+
existingScrolling.resolve()
|
78
|
+
|
79
|
+
###*
|
80
|
+
@method up.reveal
|
81
|
+
@param {String|Element|jQuery} element
|
82
|
+
@param {String|Element|jQuery} [options.view]
|
83
|
+
@param {Number} [options.duration]
|
84
|
+
@param {String} [options.easing]
|
85
|
+
@param {Number} [options.padding]
|
86
|
+
@returns {Deferred}
|
87
|
+
@protected
|
88
|
+
###
|
89
|
+
reveal = (elementOrSelector, options) ->
|
90
|
+
|
91
|
+
options = u.options(options)
|
92
|
+
view = u.option(options.view, config.view)
|
93
|
+
padding = u.option(options.padding, config.padding)
|
94
|
+
|
95
|
+
$element = $(elementOrSelector)
|
96
|
+
$view = $(view)
|
97
|
+
|
98
|
+
viewHeight = $view.height()
|
99
|
+
scrollPos = $view.scrollTop()
|
100
|
+
|
101
|
+
firstVisibleRow = scrollPos
|
102
|
+
lastVisibleRow = scrollPos + viewHeight
|
103
|
+
|
104
|
+
elementTop = $element.position().top
|
105
|
+
|
106
|
+
elementTooHigh = elementTop - padding < firstVisibleRow
|
107
|
+
elementTooLow = elementTop > lastVisibleRow - padding
|
108
|
+
|
109
|
+
if elementTooHigh || elementTooLow
|
110
|
+
scrollPos = elementTop - padding
|
111
|
+
scrollPos = Math.max(scrollPos, 0)
|
112
|
+
scrollPos = Math.min(scrollPos, viewHeight - 1)
|
113
|
+
scroll($view, scrollPos, options)
|
114
|
+
else
|
115
|
+
u.resolvedDeferred()
|
116
|
+
|
117
|
+
reveal: reveal
|
118
|
+
scroll: scroll
|
119
|
+
finishScrolling: finishScrolling
|
120
|
+
defaults: defaults
|
121
|
+
|
122
|
+
)()
|
123
|
+
|
124
|
+
up.scroll = up.viewport.scroll
|
125
|
+
up.reveal = up.viewport.reveal
|
data/lib/upjs/rails/version.rb
CHANGED
data/spec_app/Gemfile.lock
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
@Trigger = (->
|
2
|
+
|
3
|
+
u = up.util
|
4
|
+
|
5
|
+
mousedown = ($element, options) ->
|
6
|
+
options = u.options(options, view: window, cancelable: true, bubbles: true)
|
7
|
+
event = new MouseEvent('mousedown', options)
|
8
|
+
dispatch($element, event)
|
9
|
+
|
10
|
+
mouseup = ($element, options) ->
|
11
|
+
options = u.options(options, view: window, cancelable: true, bubbles: true)
|
12
|
+
event = new MouseEvent('mouseup', options)
|
13
|
+
dispatch($element, event)
|
14
|
+
|
15
|
+
click = ($element, options) ->
|
16
|
+
options = u.options(options, view: window, cancelable: true, bubbles: true)
|
17
|
+
event = new MouseEvent('click', options)
|
18
|
+
dispatch($element, event)
|
19
|
+
|
20
|
+
dispatch = ($element, event) ->
|
21
|
+
$element.each ->
|
22
|
+
this.dispatchEvent(event)
|
23
|
+
|
24
|
+
mousedown: mousedown
|
25
|
+
mouseup: mouseup
|
26
|
+
click: click
|
27
|
+
|
28
|
+
)()
|
@@ -35,7 +35,7 @@ describe 'up.flow', ->
|
|
35
35
|
expect($('.before')).toHaveText('old-before')
|
36
36
|
expect($('.middle')).toHaveText('new-middle')
|
37
37
|
expect($('.after')).toHaveText('old-after')
|
38
|
-
done()
|
38
|
+
done()
|
39
39
|
|
40
40
|
it 'should set the browser location to the given URL', (done) ->
|
41
41
|
@request = up.replace('.middle', '/path')
|
@@ -55,4 +55,41 @@ describe 'up.link', ->
|
|
55
55
|
|
56
56
|
it 'should have tests'
|
57
57
|
|
58
|
+
describe '[up-instant]', ->
|
59
|
+
|
60
|
+
beforeEach ->
|
61
|
+
@$link = affix('a[href="/path"][up-follow][up-instant]')
|
62
|
+
spyOn(up, 'follow')
|
63
|
+
|
64
|
+
it 'follows an [up-follow] link on mousedown (instead of on click)', ->
|
65
|
+
Trigger.mousedown(@$link)
|
66
|
+
expect(up.follow.calls.mostRecent().args[0]).toEqual(@$link)
|
67
|
+
|
68
|
+
it 'follows an [up-target] link on mousedown (instead of on click)', ->
|
69
|
+
Trigger.mousedown(@$link)
|
70
|
+
expect(up.follow.calls.mostRecent().args[0]).toEqual(@$link)
|
71
|
+
|
72
|
+
it 'does nothing on mouseup', ->
|
73
|
+
Trigger.mouseup(@$link)
|
74
|
+
expect(up.follow).not.toHaveBeenCalled()
|
75
|
+
|
76
|
+
it 'does nothing on click', ->
|
77
|
+
Trigger.click(@$link)
|
78
|
+
expect(up.follow).not.toHaveBeenCalled()
|
79
|
+
|
80
|
+
it 'does nothing if the right mouse button is pressed down', ->
|
81
|
+
Trigger.mousedown(@$link, button: 2)
|
82
|
+
expect(up.follow).not.toHaveBeenCalled()
|
83
|
+
|
84
|
+
it 'does nothing if shift is pressed during mousedown', ->
|
85
|
+
Trigger.mousedown(@$link, shiftKey: true)
|
86
|
+
expect(up.follow).not.toHaveBeenCalled()
|
87
|
+
|
88
|
+
it 'does nothing if ctrl is pressed during mousedown', ->
|
89
|
+
Trigger.mousedown(@$link, ctrlKey: true)
|
90
|
+
expect(up.follow).not.toHaveBeenCalled()
|
91
|
+
|
92
|
+
it 'does nothing if meta is pressed during mousedown', ->
|
93
|
+
Trigger.mousedown(@$link, metaKey: true)
|
94
|
+
expect(up.follow).not.toHaveBeenCalled()
|
58
95
|
|
@@ -27,4 +27,12 @@ describe 'up.modal', ->
|
|
27
27
|
describe '[up-close]', ->
|
28
28
|
|
29
29
|
it 'should have tests'
|
30
|
-
|
30
|
+
|
31
|
+
describe 'when following links inside a modal', ->
|
32
|
+
|
33
|
+
it 'prefers to replace a selector within the modal'
|
34
|
+
|
35
|
+
it 'auto-closes the modal if a selector behind the modal gets replaced'
|
36
|
+
|
37
|
+
it "doesn't auto-close the modal if a selector behind the modal if the modal is sticky"
|
38
|
+
|
@@ -37,11 +37,25 @@ describe 'up.navigation', ->
|
|
37
37
|
|
38
38
|
it 'changes .up-current marks as the URL changes'
|
39
39
|
|
40
|
-
it 'marks clicked
|
40
|
+
it 'marks clicked links as .up-active until the request finishes', ->
|
41
41
|
$link = affix('a[href="/foo"][up-target=".main"]')
|
42
42
|
affix('.main')
|
43
43
|
jasmine.Ajax.install()
|
44
44
|
$link.click()
|
45
|
+
# console.log($link)
|
46
|
+
expect($link).toHaveClass('up-active')
|
47
|
+
jasmine.Ajax.requests.mostRecent().respondWith
|
48
|
+
status: 200
|
49
|
+
contentType: 'text/html'
|
50
|
+
responseText: '<div class="main">new-text</div>'
|
51
|
+
expect($link).not.toHaveClass('up-active')
|
52
|
+
expect($link).toHaveClass('up-current')
|
53
|
+
|
54
|
+
it 'marks links with [up-instant] on mousedown as .up-active until the request finishes', ->
|
55
|
+
$link = affix('a[href="/foo"][up-instant][up-target=".main"]')
|
56
|
+
affix('.main')
|
57
|
+
jasmine.Ajax.install()
|
58
|
+
Trigger.mousedown($link)
|
45
59
|
expect($link).toHaveClass('up-active')
|
46
60
|
jasmine.Ajax.requests.mostRecent().respondWith
|
47
61
|
status: 200
|
@@ -0,0 +1,27 @@
|
|
1
|
+
describe 'up.proxy', ->
|
2
|
+
|
3
|
+
describe 'Javascript functions', ->
|
4
|
+
|
5
|
+
describe 'up.proxy.preload', ->
|
6
|
+
|
7
|
+
it 'should have tests'
|
8
|
+
|
9
|
+
describe 'up.proxy.ajax', ->
|
10
|
+
|
11
|
+
it 'should have tests'
|
12
|
+
|
13
|
+
describe 'up.proxy.get', ->
|
14
|
+
|
15
|
+
it 'should have tests'
|
16
|
+
|
17
|
+
describe 'up.proxy.set', ->
|
18
|
+
|
19
|
+
it 'should have tests'
|
20
|
+
|
21
|
+
describe 'up.proxy.alias', ->
|
22
|
+
|
23
|
+
it 'should have tests'
|
24
|
+
|
25
|
+
describe 'up.proxy.clear', ->
|
26
|
+
|
27
|
+
it 'should have tests'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: upjs-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Henning Koch
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -134,6 +134,7 @@ files:
|
|
134
134
|
- lib/assets/javascripts/up/proxy.js.coffee
|
135
135
|
- lib/assets/javascripts/up/tooltip.js.coffee
|
136
136
|
- lib/assets/javascripts/up/util.js.coffee
|
137
|
+
- lib/assets/javascripts/up/viewport.js.coffee
|
137
138
|
- lib/assets/stylesheets/up.css
|
138
139
|
- lib/assets/stylesheets/up/close.css.sass
|
139
140
|
- lib/assets/stylesheets/up/error.css.sass
|
@@ -226,6 +227,8 @@ files:
|
|
226
227
|
- spec_app/spec/javascripts/helpers/index.js.coffee
|
227
228
|
- spec_app/spec/javascripts/helpers/reset_path.js.coffee
|
228
229
|
- spec_app/spec/javascripts/helpers/reset_up.js.coffee
|
230
|
+
- spec_app/spec/javascripts/helpers/to_equal_jquery.js.coffee
|
231
|
+
- spec_app/spec/javascripts/helpers/trigger.js.coffee
|
229
232
|
- spec_app/spec/javascripts/support/jasmine.yml
|
230
233
|
- spec_app/spec/javascripts/up/bus_spec.js.coffee
|
231
234
|
- spec_app/spec/javascripts/up/flow_spec.js.coffee
|
@@ -238,6 +241,7 @@ files:
|
|
238
241
|
- spec_app/spec/javascripts/up/motion_spec.js.coffee
|
239
242
|
- spec_app/spec/javascripts/up/navigation_spec.js.coffee
|
240
243
|
- spec_app/spec/javascripts/up/popup_spec.js.coffee
|
244
|
+
- spec_app/spec/javascripts/up/proxy_spec.js.coffee
|
241
245
|
- spec_app/spec/javascripts/up/tooltip_spec.js.coffee
|
242
246
|
- spec_app/spec/javascripts/up/util_spec.js.coffee
|
243
247
|
- spec_app/test/controllers/.keep
|