upjs-rails 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -98,13 +98,16 @@ up.link = (->
98
98
  @method up.visit
99
99
  @param {String} url
100
100
  The URL to visit.
101
+ @param {String} [options.target='body']
102
+ The selector to replace.
103
+ See options for [`up.replace`](/up.flow#up.replace)
101
104
  @param {Object} options
102
105
  See options for [`up.replace`](/up.flow#up.replace)
103
106
  ###
104
107
  visit = (url, options) ->
105
- u.debug "Visiting #{url}"
106
- # options = util.options(options, )
107
- up.replace('body', url, options)
108
+ options = u.options(options)
109
+ selector = u.option(options.target, 'body')
110
+ up.replace(selector, url, options)
108
111
 
109
112
  ###*
110
113
  Follows the given link via AJAX and replaces a CSS selector in the current page
@@ -138,13 +138,6 @@ up.modal = (->
138
138
 
139
139
  Any option attributes for [`a[up-modal]`](#a.up-modal) will be honored.
140
140
 
141
- You can also open a URL directly like this:
142
-
143
- up.modal.open({ url: '/foo', target: '.list' })
144
-
145
- This will request `/foo`, extract the `.list` selector from the response
146
- and open the selected container in a modal dialog.
147
-
148
141
  \#\#\#\# Events
149
142
 
150
143
  - Emits an [event](/up.bus) `modal:open` when the modal
@@ -153,12 +146,8 @@ up.modal = (->
153
146
  animation has finished and the modal contents are fully visible.
154
147
 
155
148
  @method up.modal.open
156
- @param {Element|jQuery|String} [elementOrSelector]
149
+ @param {Element|jQuery|String} elementOrSelector
157
150
  The link to follow.
158
- Can be omitted if you give `options.url` instead.
159
- @param {String} [options.url]
160
- The URL to open.
161
- Can be omitted if you give `elementOrSelector` instead.
162
151
  @param {String} [options.target]
163
152
  The selector to extract from the response and open in a modal dialog.
164
153
  @param {Number} [options.width]
@@ -183,6 +172,26 @@ up.modal = (->
183
172
  @return {Promise}
184
173
  A promise that will be resolved when the modal has finished loading.
185
174
  ###
175
+
176
+ ###*
177
+ Opens a modal for the given URL.
178
+
179
+ Example:
180
+
181
+ up.modal.open({ url: '/foo', target: '.list' })
182
+
183
+ This will request `/foo`, extract the `.list` selector from the response
184
+ and open the selected container in a modal dialog.
185
+
186
+ @method up.modal.open
187
+ @param {String} options.url
188
+ The URL to load.
189
+ @param {String} options.target
190
+ The CSS selector to extract from the response.
191
+ The extracted content will be placed into the dialog window.
192
+ @param {Object} options
193
+ See options for [previous `up.modal.open` variant](#up.modal.open).
194
+ ###
186
195
  open = (args...) ->
187
196
  if u.isObject(args[0]) && !u.isElement(args[0]) && !u.isJQuery(args[0])
188
197
  $link = u.nullJquery()
@@ -63,7 +63,7 @@ up.util = (->
63
63
  # https://gist.github.com/jlong/2428561#comment-1461205
64
64
  anchor.href = anchor.href if isBlank(anchor.hostname)
65
65
  else
66
- anchor = unwrap(urlOrAnchor)
66
+ anchor = unJquery(urlOrAnchor)
67
67
  normalized = anchor.protocol + "//" + anchor.hostname
68
68
  normalized += ":#{anchor.port}" unless isStandardPort(anchor.protocol, anchor.port)
69
69
  pathname = anchor.pathname
@@ -142,7 +142,7 @@ up.util = (->
142
142
  stringifyConsoleArgs = (args) ->
143
143
  message = args[0]
144
144
  i = 0
145
- maxLength = 30
145
+ maxLength = 50
146
146
  message.replace CONSOLE_PLACEHOLDERS, ->
147
147
  i += 1
148
148
  arg = args[i]
@@ -150,11 +150,13 @@ up.util = (->
150
150
  if argType == 'string'
151
151
  arg = arg.replace(/\s+/g, ' ')
152
152
  arg = "#{arg.substr(0, maxLength)}…" if arg.length > maxLength
153
- "\"#{arg}\""
153
+ arg = "\"#{arg}\""
154
154
  else if argType == 'number'
155
- arg.toString()
155
+ arg = arg.toString()
156
156
  else
157
- "(#{argType})"
157
+ arg = JSON.stringify(arg)
158
+ arg = "#{arg.substr(0, maxLength)}…" if arg.length > maxLength
159
+ arg
158
160
 
159
161
  createSelectorFromElement = ($element) ->
160
162
  debug("Creating selector from element %o", $element)
@@ -225,6 +227,10 @@ up.util = (->
225
227
  each = (collection, block) ->
226
228
  block(item, index) for item, index in collection
227
229
 
230
+ map = each
231
+
232
+ identity = (x) -> x
233
+
228
234
  times = (count, block) ->
229
235
  block(iteration) for iteration in [0..(count - 1)]
230
236
 
@@ -294,7 +300,7 @@ up.util = (->
294
300
  else
295
301
  extend({}, object)
296
302
 
297
- unwrap = (object) ->
303
+ unJquery = (object) ->
298
304
  if isJQuery(object)
299
305
  object.get(0)
300
306
  else
@@ -557,7 +563,13 @@ up.util = (->
557
563
 
558
564
  escapePressed = (event) ->
559
565
  event.keyCode == 27
560
-
566
+
567
+ startsWith = (string, element) ->
568
+ string.indexOf(element) == 0
569
+
570
+ endsWith = (string, element) ->
571
+ string.indexOf(element) == string.length - element.length
572
+
561
573
  contains = (stringOrArray, element) ->
562
574
  stringOrArray.indexOf(element) >= 0
563
575
 
@@ -627,16 +639,25 @@ up.util = (->
627
639
  for key in ownKeys
628
640
  delete hash[key] unless contains(apiKeys, key)
629
641
  hash.update copy(factoryOptions)
630
- update: (options) ->
642
+ update: (options = {}) ->
631
643
  for key, value of options
632
644
  if factoryOptions.hasOwnProperty(key)
633
645
  hash[key] = value
634
646
  else
635
647
  error("Unknown setting %o", key)
648
+ hash
636
649
  apiKeys = Object.getOwnPropertyNames(hash)
637
650
  hash.reset()
638
651
  hash
639
652
 
653
+ unwrapElement = (wrapper) ->
654
+ wrapper = unJquery(wrapper)
655
+ parent = wrapper.parentNode;
656
+ wrappedNodes = toArray(wrapper.childNodes)
657
+ each wrappedNodes, (wrappedNode) ->
658
+ parent.insertBefore(wrappedNode, wrapper)
659
+ parent.removeChild(wrapper)
660
+
640
661
  presentAttr: presentAttr
641
662
  createElement: createElement
642
663
  normalizeUrl: normalizeUrl
@@ -655,6 +676,8 @@ up.util = (->
655
676
  debug: debug
656
677
  warn: warn
657
678
  each: each
679
+ map: map
680
+ identity: identity
658
681
  times: times
659
682
  detect: detect
660
683
  select: select
@@ -681,7 +704,7 @@ up.util = (->
681
704
  isUnmodifiedKeyEvent: isUnmodifiedKeyEvent
682
705
  isUnmodifiedMouseEvent: isUnmodifiedMouseEvent
683
706
  nullJquery: nullJquery
684
- unwrap: unwrap
707
+ unJquery: unJquery
685
708
  nextFrame: nextFrame
686
709
  measure: measure
687
710
  temporaryCss: temporaryCss
@@ -693,6 +716,8 @@ up.util = (->
693
716
  copyAttributes: copyAttributes
694
717
  findWithSelf: findWithSelf
695
718
  contains: contains
719
+ startsWith: startsWith
720
+ endsWith: endsWith
696
721
  isArray: isArray
697
722
  toArray: toArray
698
723
  castsToTrue: castsToTrue
@@ -711,5 +736,6 @@ up.util = (->
711
736
  memoize: memoize
712
737
  scrollbarWidth: scrollbarWidth
713
738
  config: config
739
+ unwrapElement: unwrapElement
714
740
 
715
741
  )()
@@ -1,5 +1,5 @@
1
1
  module Upjs
2
2
  module Rails
3
- VERSION = '0.8.2'
3
+ VERSION = '0.9.0'
4
4
  end
5
5
  end
@@ -1,4 +1,6 @@
1
1
  describe 'up.flow', ->
2
+
3
+ u = up.util
2
4
 
3
5
  describe 'Javascript functions', ->
4
6
 
@@ -8,9 +10,9 @@ describe 'up.flow', ->
8
10
 
9
11
  beforeEach ->
10
12
 
11
- affix('.before').text('old-before')
12
- affix('.middle').text('old-middle')
13
- affix('.after').text('old-after')
13
+ @oldBefore = affix('.before').text('old-before')
14
+ @oldMiddle = affix('.middle').text('old-middle')
15
+ @oldAfter = affix('.after').text('old-after')
14
16
 
15
17
  @responseText =
16
18
  """
@@ -62,6 +64,7 @@ describe 'up.flow', ->
62
64
  @respond()
63
65
  @request.then ->
64
66
  expect($('.before')).toHaveText('old-before')
67
+ console.log("foooo", $('.middle').text())
65
68
  expect($('.middle')).toHaveText('new-middleold-middle')
66
69
  expect($('.after')).toHaveText('old-after')
67
70
  done()
@@ -111,6 +114,47 @@ describe 'up.flow', ->
111
114
  expect(window.scriptTagExecuted).toHaveBeenCalledWith('middle')
112
115
  done()
113
116
 
117
+ describe 'automatic scrolling', ->
118
+
119
+ beforeEach ->
120
+ @revealedHTML = ''
121
+ spyOn(up, 'reveal').and.callFake ($revealedElement) =>
122
+ @revealedHTML = $revealedElement.get(0).outerHTML
123
+ u.resolvedPromise()
124
+
125
+ it 'reveals an old element before it is being replaced', (done) ->
126
+ @request = up.replace('.middle', '/path')
127
+ @respond()
128
+ @request.then =>
129
+ expect(up.reveal).toHaveBeenCalledWith(@oldMiddle, jasmine.any(Object))
130
+ done()
131
+
132
+ it 'reveals a new element that is being appended', (done) ->
133
+ @request = up.replace('.middle:after', '/path')
134
+ @respond()
135
+ @request.then =>
136
+ expect(up.reveal).not.toHaveBeenCalledWith(@oldMiddle, jasmine.any(Object))
137
+ # Text nodes are wrapped in a .up-insertion container so we can
138
+ # animate them and measure their position/size for scrolling.
139
+ # This is not possible for container-less text nodes.
140
+ expect(@revealedHTML).toEqual('<span class="up-insertion">new-middle</span>')
141
+ # Show that the wrapper is done after the insertion.
142
+ expect($('.up-insertion')).not.toExist()
143
+ done()
144
+
145
+ it 'reveals a new element that is being prepended', (done) ->
146
+ @request = up.replace('.middle:before', '/path')
147
+ @respond()
148
+ @request.then =>
149
+ expect(up.reveal).not.toHaveBeenCalledWith(@oldMiddle, jasmine.any(Object))
150
+ # Text nodes are wrapped in a .up-insertion container so we can
151
+ # animate them and measure their position/size for scrolling.
152
+ # This is not possible for container-less text nodes.
153
+ expect(@revealedHTML).toEqual('<span class="up-insertion">new-middle</span>')
154
+ # Show that the wrapper is done after the insertion.
155
+ expect($('.up-insertion')).not.toExist()
156
+ done()
157
+
114
158
  else
115
159
 
116
160
  it 'makes a full page load', ->
@@ -0,0 +1,240 @@
1
+ describe 'up.layout', ->
2
+
3
+ u = up.util
4
+
5
+ describe 'Javascript functions', ->
6
+
7
+ describe 'up.reveal', ->
8
+
9
+ beforeEach ->
10
+ up.layout.defaults(snap: 0)
11
+
12
+ describe 'when the container is body', ->
13
+
14
+ beforeEach ->
15
+ @$viewport = $('body')
16
+ @restoreMargin = u.temporaryCss(@$viewport, 'margin-top': 0)
17
+ @$viewport.scrollTop(0)
18
+
19
+ @$elements = []
20
+ @$container = $('<div class="container">').prependTo(@$viewport)
21
+
22
+ @clientHeight = u.clientSize().height
23
+
24
+ for height in [@clientHeight, '50px', '5000px']
25
+ $element = $('<div>').css(height: height)
26
+ $element.appendTo(@$container)
27
+ @$elements.push($element)
28
+
29
+ afterEach ->
30
+ @$container.remove()
31
+ @restoreMargin()
32
+
33
+ it 'reveals the given element', ->
34
+ up.reveal(@$elements[0], viewport: @$viewport)
35
+ # ---------------------
36
+ # [0] 0 .......... ch-1
37
+ # ---------------------
38
+ # [1] ch+0 ...... ch+49
39
+ # [2] ch+50 ... ch+5049
40
+ expect(@$viewport.scrollTop()).toBe(0)
41
+
42
+ up.reveal(@$elements[1], viewport: @$viewport)
43
+ # ---------------------
44
+ # [0] 0 .......... ch-1
45
+ # [1] ch+0 ...... ch+49
46
+ # ---------------------
47
+ # [2] ch+50 ... ch+5049
48
+ expect(@$viewport.scrollTop()).toBe(50)
49
+
50
+ up.reveal(@$elements[2], viewport: @$viewport)
51
+ # [0] 0 .......... ch-1
52
+ # [1] ch+0 ...... ch+49
53
+ # ---------------------
54
+ # [2] ch+50 ... ch+5049
55
+ # ---------------------
56
+ expect(@$viewport.scrollTop()).toBe(@clientHeight + 50)
57
+
58
+ it 'snaps to the top if the space above the future-visible area is smaller than the value of config.snap', ->
59
+
60
+ up.layout.defaults(snap: 30)
61
+
62
+ @$elements[0].css(height: '20px')
63
+
64
+ up.reveal(@$elements[2], viewport: @$viewport)
65
+ # [0] 0 ............ 19
66
+ # [1] 20 ........... 69
67
+ # ---------------------
68
+ # [2] 70 ......... 5069
69
+ # ---------------------
70
+ expect(@$viewport.scrollTop()).toBe(70)
71
+
72
+ # Even though we're revealing the second element, the viewport
73
+ # snaps to the top edge.
74
+ up.reveal(@$elements[1], viewport: @$viewport)
75
+ # ---------------------
76
+ # [0] 0 ............ 19
77
+ # [1] 20 ........... 69
78
+ # ---------------------
79
+ # [2] 70 ......... 5069
80
+ expect(@$viewport.scrollTop()).toBe(0)
81
+
82
+ it 'scrolls far enough so the element is not obstructed by an element fixed to the top', ->
83
+ $topNav = affix('[up-fixed=top]').css(
84
+ position: 'fixed',
85
+ top: '0',
86
+ left: '0',
87
+ right: '0'
88
+ height: '100px'
89
+ )
90
+
91
+ up.reveal(@$elements[0], viewport: @viewport)
92
+ # ---------------------
93
+ # [F] 0 ............ 99
94
+ # [0] 0 .......... ch-1
95
+ # ---------------------
96
+ # [1] ch+0 ...... ch+49
97
+ # [2] ch+50 ... ch+5049
98
+ expect(@$viewport.scrollTop()).toBe(0) # would need to be -100
99
+
100
+ up.reveal(@$elements[1], viewport: @$viewport)
101
+ # ---------------------
102
+ # [F] 0 ............ 99
103
+ # [0] 00000 ...... ch-1
104
+ # [1] ch+0 ...... ch+49
105
+ # ---------------------
106
+ # [2] ch+50 ... ch+5049
107
+
108
+ expect(@$viewport.scrollTop()).toBe(50)
109
+
110
+ up.reveal(@$elements[2], viewport: @$viewport)
111
+ # [0] 00000 ...... ch-1
112
+ # [1] ch+0 ...... ch+49
113
+ # ---------------------
114
+ # [F] 0 ............ 99
115
+ # [2] ch+50 ... ch+5049
116
+ # ----------------
117
+ expect(@$viewport.scrollTop()).toBe(@clientHeight + 50 - 100)
118
+
119
+ up.reveal(@$elements[1], viewport: @$viewport)
120
+ # [0] 00000 ...... ch-1
121
+ # ---------------------
122
+ # [F] 0 ............ 99
123
+ # [1] ch+0 ...... ch+49
124
+ # [2] ch+50 ... ch+5049
125
+ # ----------------
126
+ expect(@$viewport.scrollTop()).toBe(@clientHeight + 50 - 100 - 50)
127
+
128
+
129
+ it 'scrolls far enough so the element is not obstructed by an element fixed to the bottom', ->
130
+ $bottomNav = affix('[up-fixed=bottom]').css(
131
+ position: 'fixed',
132
+ bottom: '0',
133
+ left: '0',
134
+ right: '0'
135
+ height: '100px'
136
+ )
137
+
138
+ up.reveal(@$elements[0], viewport: @$viewport)
139
+ # ---------------------
140
+ # [0] 0 .......... ch-1
141
+ # [F] 0 ............ 99
142
+ # ---------------------
143
+ # [1] ch+0 ...... ch+49
144
+ # [2] ch+50 ... ch+5049
145
+ expect(@$viewport.scrollTop()).toBe(0)
146
+
147
+ up.reveal(@$elements[1], viewport: @$viewport)
148
+ # ---------------------
149
+ # [0] 0 .......... ch-1
150
+ # [1] ch+0 ...... ch+49
151
+ # [F] 0 ............ 99
152
+ # ---------------------
153
+ # [2] ch+50 ... ch+5049
154
+ expect(@$viewport.scrollTop()).toBe(150)
155
+
156
+ up.reveal(@$elements[2], viewport: @$viewport)
157
+ # ---------------------
158
+ # [0] 0 .......... ch-1
159
+ # [1] ch+0 ...... ch+49
160
+ # ---------------------
161
+ # [2] ch+50 ... ch+5049
162
+ # [F] 0 ............ 99
163
+ expect(@$viewport.scrollTop()).toBe(@clientHeight + 50)
164
+
165
+
166
+
167
+
168
+ describe 'when the viewport is a container with overflow-y: scroll', ->
169
+
170
+ it 'reveals the given element', ->
171
+ $viewport = affix('div').css
172
+ 'position': 'absolute'
173
+ 'top': '50px'
174
+ 'left': '50px'
175
+ 'width': '100px'
176
+ 'height': '100px'
177
+ 'overflow-y': 'scroll'
178
+ $elements = []
179
+ u.each [0..5], ->
180
+ $element = $('<div>').css(height: '50px')
181
+ $element.appendTo($viewport)
182
+ $elements.push($element)
183
+
184
+ # ------------
185
+ # [0] 000..049
186
+ # [1] 050..099
187
+ # ------------
188
+ # [2] 100..149
189
+ # [3] 150..199
190
+ # [4] 200..249
191
+ # [5] 250..399
192
+ expect($viewport.scrollTop()).toBe(0)
193
+
194
+ # See that the view only scrolls down as little as possible
195
+ # in order to reveal the element
196
+ up.reveal($elements[3], viewport: $viewport)
197
+ # [0] 000..049
198
+ # [1] 050..099
199
+ # ------------
200
+ # [2] 100..149
201
+ # [3] 150..199
202
+ # ------------
203
+ # [4] 200..249
204
+ # [5] 250..399
205
+ expect($viewport.scrollTop()).toBe(100)
206
+
207
+ # See that the view doesn't move if the element
208
+ # is already revealed
209
+ up.reveal($elements[2], viewport: $viewport)
210
+ expect($viewport.scrollTop()).toBe(100)
211
+
212
+ # See that the view scrolls as far down as it cans
213
+ # to show the bottom element
214
+ up.reveal($elements[5], viewport: $viewport)
215
+ # [0] 000..049
216
+ # [1] 050..099
217
+ # [2] 100..149
218
+ # [3] 150..199
219
+ # ------------
220
+ # [4] 200..249
221
+ # [5] 250..399
222
+ # ------------
223
+ expect($viewport.scrollTop()).toBe(200)
224
+
225
+ # See that the view only scrolls up as little as possible
226
+ # in order to reveal the element
227
+ up.reveal($elements[1], viewport: $viewport)
228
+ # [0] 000..049
229
+ # ------------
230
+ # [1] 050..099
231
+ # [2] 100..149
232
+ # ------------
233
+ # [3] 150..199
234
+ # [4] 200..249
235
+ # [5] 250..399
236
+ expect($viewport.scrollTop()).toBe(50)
237
+
238
+ describe 'up.scroll', ->
239
+
240
+ it 'should have tests'