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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3f5272dedf0729c07b9d465df87c0849389a41f8
4
- data.tar.gz: 21aac3463e562b39caf7920e2a66c0e7611357af
3
+ metadata.gz: ea22c4f8c05c98c188200595aae81fda36affbc6
4
+ data.tar.gz: 7cccbe256055dcfefa5036d0ad83df85f32064a7
5
5
  SHA512:
6
- metadata.gz: c959fc30ab815300dd3f219bc48a69c904daba8d67b19a19bc5c3d2573825685e571a3926dba0b629ac84ebbb69cea9d81bcd54f3ea467361688529065bce7bc
7
- data.tar.gz: 55e7bb84f0c17798bdcba9add1fc3f84ea0d2ff35b871a482f82e657fd27498a4d76630387774e062ea587896c11b5e0052b26936d28911172c4388812475d45
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 == 'false'
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
- # TODO: extract title from HTTP header
124
- options.title ||= htmlElement.querySelector("title")?.textContent
125
-
126
- for step in implantSteps(selector, options)
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
- # Before we select a replacement target, ensure that all transitions
129
- # and animations have been run. Finishing a transition usually removes
130
- # the element that is being morphed, so it will affect further selections
131
- # using the same selector.
132
- up.motion.finish(step.selector)
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
- $new.insertAfter($old)
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
- implantSteps = (selector, options) ->
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 == 'false'
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 = _.isNull(knownValue)
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.which is 1
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, $element) ->
210
- unless childClicked(event, $element)
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 $element.is('[up-instant]')
214
- follow(resolve($element))
220
+ unless $link.is('[up-instant]')
221
+ follow(resolve($link))
215
222
 
216
- up.on 'mousedown', '[up-follow][up-instant]', (event, $element) ->
217
- if !childClicked(event, $element) && event.which == 1
223
+ up.on 'mousedown', '[up-follow][up-instant]', (event, $link) ->
224
+ if activeInstantLink(event, $link)
218
225
  event.preventDefault()
219
- follow(resolve($element))
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
- <a href="/users" up-target=".main" up-instant up-preload>User list</a>
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
- SELECTOR_SECTION = 'a[href], a[up-target], [up-follow], [up-modal], [up-popup], [up-source]'
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-source']
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
- sectionClicked($section)
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 nonGET` request
9
- (like `POST`, `PUT`, `DELETE`).
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: 50
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} options.url
82
- @param {String} [options.method='GET']
83
- @param {String} [options.selector]
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
@@ -2,6 +2,7 @@
2
2
  #= require up/util
3
3
  #= require up/browser
4
4
  #= require up/bus
5
+ #= require up/viewport
5
6
  #= require up/flow
6
7
  #= require up/magic
7
8
  #= require up/history
@@ -1,5 +1,5 @@
1
1
  module Upjs
2
2
  module Rails
3
- VERSION = "0.4.1"
3
+ VERSION = '0.4.2'
4
4
  end
5
5
  end
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- upjs-rails (0.3.3)
4
+ upjs-rails (0.4.1)
5
5
  rails (>= 3)
6
6
 
7
7
  GEM
@@ -0,0 +1,9 @@
1
+ # http://jasmine.github.io/2.0/custom_equality.html
2
+
3
+ u = up.util
4
+
5
+ beforeEach ->
6
+ jasmine.addCustomEqualityTester (first, second) ->
7
+ if u.isJQuery(first) && u.isJQuery(second)
8
+ first.is(second)
9
+
@@ -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')
@@ -104,8 +104,9 @@ describe 'up.form', ->
104
104
 
105
105
  describe 'form[up-target]', ->
106
106
 
107
- it 'should have tests'
108
-
107
+ it 'rigs the form to use up.submit instead of a standard submit'
108
+
109
+
109
110
  describe 'input[up-observe]', ->
110
111
 
111
112
  it 'should have tests'
@@ -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 linked as .up-active until the request finishes', ->
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.1
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-05-19 00:00:00.000000000 Z
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