unpoly-rails 0.22.0 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of unpoly-rails might be problematic. Click here for more details.

@@ -5,7 +5,7 @@ Caching and preloading
5
5
  All HTTP requests go through the Unpoly proxy.
6
6
  It caches a [limited](/up.proxy.config) number of server responses
7
7
  for a [limited](/up.proxy.config) amount of time,
8
- making requests to these URLs return insantly.
8
+ making requests to these URLs return instantly.
9
9
 
10
10
  The cache is cleared whenever the user makes a non-`GET` request
11
11
  (like `POST`, `PUT` or `DELETE`).
@@ -15,42 +15,6 @@ links when the user hovers over the click area](/up-preload) (or puts the mouse/
15
15
  down before releasing). This way the response will already be cached when
16
16
  the user performs the click.
17
17
 
18
- Spinners
19
- --------
20
-
21
- You can [listen](/up.on) to the [`up:proxy:slow`](/up:proxy:slow)
22
- and [`up:proxy:recover`](/up:proxy:recover) events to implement a spinner
23
- that appears during a long-running request,
24
- and disappears once the response has been received:
25
-
26
- <div class="spinner">Please wait!</div>
27
-
28
- Here is the Javascript to make it alive:
29
-
30
- up.compiler('.spinner', function($element) {
31
-
32
- show = function() { $element.show() };
33
- hide = function() { $element.hide() };
34
-
35
- showOff = up.on('up:proxy:slow', show);
36
- hideOff = up.on('up:proxy:recover', hide);
37
-
38
- hide();
39
-
40
- // Clean up when the element is removed from the DOM
41
- return function() {
42
- showOff();
43
- hideOff();
44
- };
45
-
46
- });
47
-
48
- The `up:proxy:slow` event will be emitted after a delay of 300 ms
49
- to prevent the spinner from flickering on and off.
50
- You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.config) like this:
51
-
52
- up.proxy.config.slowDelay = 150;
53
-
54
18
  @class up.proxy
55
19
  ###
56
20
  up.proxy = (($) ->
@@ -349,6 +313,43 @@ up.proxy = (($) ->
349
313
  Note that if additional requests are made while Unpoly is already busy
350
314
  waiting, **no** additional `up:proxy:slow` events will be triggered.
351
315
 
316
+
317
+ \#\#\#\# Spinners
318
+
319
+ You can [listen](/up.on) to the `up:proxy:slow`
320
+ and [`up:proxy:recover`](/up:proxy:recover) events to implement a spinner
321
+ that appears during a long-running request,
322
+ and disappears once the response has been received:
323
+
324
+ <div class="spinner">Please wait!</div>
325
+
326
+ Here is the Javascript to make it alive:
327
+
328
+ up.compiler('.spinner', function($element) {
329
+
330
+ show = function() { $element.show() };
331
+ hide = function() { $element.hide() };
332
+
333
+ showOff = up.on('up:proxy:slow', show);
334
+ hideOff = up.on('up:proxy:recover', hide);
335
+
336
+ hide();
337
+
338
+ // Clean up when the element is removed from the DOM
339
+ return function() {
340
+ showOff();
341
+ hideOff();
342
+ };
343
+
344
+ });
345
+
346
+ The `up:proxy:slow` event will be emitted after a delay of 300 ms
347
+ to prevent the spinner from flickering on and off.
348
+ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.config) like this:
349
+
350
+ up.proxy.config.slowDelay = 150;
351
+
352
+
352
353
  @event up:proxy:slow
353
354
  @stable
354
355
  ###
@@ -363,6 +364,10 @@ up.proxy = (($) ->
363
364
  This event is [emitted]/(up.emit) when [AJAX requests](/up.ajax)
364
365
  have [taken long to finish](/up:proxy:slow), but have finished now.
365
366
 
367
+ See [`up:proxy:slow`](/up:proxy:slow) for more documentation on
368
+ how to use this event for implementing a spinner that shows during
369
+ long-running requests.
370
+
366
371
  @event up:proxy:recover
367
372
  @stable
368
373
  ###
@@ -46,11 +46,11 @@ up.syntax = (($) ->
46
46
  Registers a function to be called whenever an element with
47
47
  the given selector is inserted into the DOM.
48
48
 
49
- $('.action').compiler(function($element) {
49
+ up.compiler('.action', function($element) {
50
50
  // your code here
51
51
  });
52
52
 
53
- Compiler functions will be called on matching elements when
53
+ The functions will be called on elements maching `.action` when
54
54
  the page loads, or whenever a matching fragment is [updated through Unpoly](/up.replace)
55
55
  later.
56
56
 
@@ -135,7 +135,7 @@ up.syntax = (($) ->
135
135
  { lat: 48.75, lng: 11.45, title: 'Ingolstadt' }
136
136
  ]"></div>
137
137
 
138
- The JSON will parsed and handed to your event handler as a second argument:
138
+ The JSON will parsed and handed to your compiler as a second argument:
139
139
 
140
140
  up.compiler('.google-map', function($element, pins) {
141
141
 
@@ -195,7 +195,7 @@ up.syntax = (($) ->
195
195
  @param {Function($element, data)} compiler
196
196
  The function to call when a matching element is inserted.
197
197
  The function takes the new element as the first argument (as a jQuery object).
198
- If the element has an `up-data` attribute, its value is parsed as JSON
198
+ If the element has an [`up-data`](/up-data) attribute, its value is parsed as JSON
199
199
  and passed as a second argument.
200
200
 
201
201
  The function may return a destructor function that destroys the compiled
@@ -324,11 +324,21 @@ up.syntax = (($) ->
324
324
  destroyer()
325
325
 
326
326
  ###*
327
- Checks if the given element has an `up-data` attribute.
327
+ Checks if the given element has an [`up-data`](/up-data) attribute.
328
328
  If yes, parses the attribute value as JSON and returns the parsed object.
329
329
 
330
330
  Returns an empty object if the element has no `up-data` attribute.
331
331
 
332
+ \#\#\#\# Example
333
+
334
+ You have an element with JSON data serialized into an `up-data` attribute:
335
+
336
+ <span class="person" up-data="{ age: 18, name: 'Bob' }">Bob</span>
337
+
338
+ Calling `up.syntax.data` will deserialize the JSON string into a Javascript object:
339
+
340
+ up.syntax.data('.person') // returns { age: 18, name: 'Bob' }
341
+
332
342
  @function up.syntax.data
333
343
  @param {String|Element|jQuery} elementOrSelector
334
344
  @return
@@ -338,15 +348,44 @@ up.syntax = (($) ->
338
348
  @experimental
339
349
  ###
340
350
 
341
- ###
351
+ ###*
342
352
  If an element annotated with [`up-data`] is inserted into the DOM,
343
353
  Up will parse the JSON and pass the resulting object to any matching
344
- [`up.compiler`](/up.syntax.compiler) handlers.
354
+ [`up.compiler`](/up.compiler) handlers.
355
+
356
+ For instance, a container for a [Google Map](https://developers.google.com/maps/documentation/javascript/tutorial)
357
+ might attach the location and names of its marker pins:
358
+
359
+ <div class="google-map" up-data="[
360
+ { lat: 48.36, lng: 10.99, title: 'Friedberg' },
361
+ { lat: 48.75, lng: 11.45, title: 'Ingolstadt' }
362
+ ]"></div>
363
+
364
+ The JSON will parsed and handed to your compiler as a second argument:
365
+
366
+ up.compiler('.google-map', function($element, pins) {
367
+
368
+ var map = new google.maps.Map($element);
369
+
370
+ pins.forEach(function(pin) {
371
+ var position = new google.maps.LatLng(pin.lat, pin.lng);
372
+ new google.maps.Marker({
373
+ position: position,
374
+ map: map,
375
+ title: pin.title
376
+ });
377
+ });
378
+
379
+ });
345
380
 
346
381
  Similarly, when an event is triggered on an element annotated with
347
382
  [`up-data`], the parsed object will be passed to any matching
348
383
  [`up.on`](/up.on) handlers.
349
384
 
385
+ up.on('click', '.google-map', function(event, $element, pins) {
386
+ console.log("There are %d pins on the clicked map", pins.length);
387
+ });
388
+
350
389
  @selector [up-data]
351
390
  @param {JSON} up-data
352
391
  A serialized JSON string
@@ -943,6 +943,7 @@ up.util = (($) ->
943
943
  if opts.relative == true
944
944
  coordinates = $element.position()
945
945
  else
946
+ # A relative context element is given
946
947
  $context = $(opts.relative)
947
948
  elementCoords = $element.offset()
948
949
  if $context.is(document)
@@ -968,9 +969,9 @@ up.util = (($) ->
968
969
  box.height = $element.outerHeight()
969
970
 
970
971
  if opts.full
971
- viewport = clientSize()
972
- box.right = viewport.width - (box.left + box.width)
973
- box.bottom = viewport.height - (box.top + box.height)
972
+ $viewport = up.layout.viewportOf($element)
973
+ box.right = $viewport.width() - (box.left + box.width)
974
+ box.bottom = $viewport.height() - (box.top + box.height)
974
975
  box
975
976
 
976
977
  ###*
@@ -4,6 +4,6 @@ module Unpoly
4
4
  # The current version of the unpoly-rails gem.
5
5
  # This version number is also used for releases of the Unpoly
6
6
  # frontend code.
7
- VERSION = '0.22.0'
7
+ VERSION = '0.22.1'
8
8
  end
9
9
  end
@@ -49,15 +49,16 @@ describe 'up.link', ->
49
49
  # so we don't lose the Jasmine runner interface.
50
50
  up.history.config.popTargets = ['.container']
51
51
 
52
- respondWith = (html) =>
52
+ respondWith = (html, title) =>
53
53
  @lastRequest().respondWith
54
54
  status: 200
55
55
  contentType: 'text/html'
56
56
  responseText: "<div class='container'><div class='target'>#{html}</div></div>"
57
+ responseHeaders: { 'X-Up-Title': title }
57
58
 
58
- followAndRespond = ($link, html) ->
59
+ followAndRespond = ($link, html, title) ->
59
60
  promise = up.follow($link)
60
- respondWith(html)
61
+ respondWith(html, title)
61
62
  promise
62
63
 
63
64
  $link1 = affix('a[href="/one"][up-target=".target"]')
@@ -66,35 +67,41 @@ describe 'up.link', ->
66
67
  $container = affix('.container')
67
68
  $target = affix('.target').appendTo($container).text('original text')
68
69
 
69
- followAndRespond($link1, 'text from one').then =>
70
+ followAndRespond($link1, 'text from one', 'title from one').then =>
70
71
  expect($('.target')).toHaveText('text from one')
71
72
  expect(location.pathname).toEqual('/one')
73
+ expect(document.title).toEqual('title from one')
72
74
 
73
- followAndRespond($link2, 'text from two').then =>
75
+ followAndRespond($link2, 'text from two', 'title from two').then =>
74
76
  expect($('.target')).toHaveText('text from two')
75
77
  expect(location.pathname).toEqual('/two')
78
+ expect(document.title).toEqual('title from two')
76
79
 
77
- followAndRespond($link3, 'text from three').then =>
80
+ followAndRespond($link3, 'text from three', 'title from three').then =>
78
81
  expect($('.target')).toHaveText('text from three')
79
82
  expect(location.pathname).toEqual('/three')
83
+ expect(document.title).toEqual('title from three')
80
84
 
81
85
  history.back()
82
86
  @setTimer 50, =>
83
- respondWith('restored text from two')
87
+ respondWith('restored text from two', 'restored title from two')
84
88
  expect($('.target')).toHaveText('restored text from two')
85
89
  expect(location.pathname).toEqual('/two')
90
+ expect(document.title).toEqual('restored title from two')
86
91
 
87
92
  history.back()
88
93
  @setTimer 50, =>
89
- respondWith('restored text from one')
94
+ respondWith('restored text from one', 'restored title from one')
90
95
  expect($('.target')).toHaveText('restored text from one')
91
96
  expect(location.pathname).toEqual('/one')
97
+ expect(document.title).toEqual('restored title from one')
92
98
 
93
99
  history.forward()
94
100
  @setTimer 50, =>
95
101
  # Since the response is cached, we don't have to respond
96
- expect($('.target')).toHaveText('restored text from two')
102
+ expect($('.target')).toHaveText('restored text from two', 'restored title from two')
97
103
  expect(location.pathname).toEqual('/two')
104
+ expect(document.title).toEqual('restored title from two')
98
105
 
99
106
  done()
100
107
 
@@ -190,6 +197,27 @@ describe 'up.link', ->
190
197
  up.follow($link)
191
198
  expect(up.browser.loadPage).toHaveBeenCalledWith('/path', { method: 'PUT' })
192
199
 
200
+ describe 'up.link.makeFollowable', ->
201
+
202
+ it "adds [up-follow] to a link that wouldn't otherwise be handled by Unpoly", ->
203
+ $link = affix('a[href="/path"]').text('label')
204
+ up.link.makeFollowable($link)
205
+ expect($link.attr('up-follow')).toEqual('')
206
+
207
+ it "does not add [up-follow] to a link that is already [up-target]", ->
208
+ $link = affix('a[href="/path"][up-target=".target"]').text('label')
209
+ up.link.makeFollowable($link)
210
+ expect($link.attr('up-follow')).toBeMissing()
211
+
212
+ it "does not add [up-follow] to a link that is already [up-modal]", ->
213
+ $link = affix('a[href="/path"][up-modal=".target"]').text('label')
214
+ up.link.makeFollowable($link)
215
+ expect($link.attr('up-follow')).toBeMissing()
216
+
217
+ it "does not add [up-follow] to a link that is already [up-popup]", ->
218
+ $link = affix('a[href="/path"][up-popup=".target"]').text('label')
219
+ up.link.makeFollowable($link)
220
+ expect($link.attr('up-follow')).toBeMissing()
193
221
 
194
222
  describe 'up.visit', ->
195
223
 
@@ -301,6 +329,48 @@ describe 'up.link', ->
301
329
  Trigger.mousedown(@$link, metaKey: true)
302
330
  expect(@followSpy).not.toHaveBeenCalled()
303
331
 
332
+ describe '[up-dash]', ->
333
+
334
+ it "is a shortcut for [up-preload], [up-instant] and [up-target], using [up-dash]'s value as [up-target]", ->
335
+ $link = affix('a[href="/path"][up-dash=".target"]').text('label')
336
+ up.hello($link)
337
+ expect($link.attr('up-preload')).toEqual('')
338
+ expect($link.attr('up-instant')).toEqual('')
339
+ expect($link.attr('up-target')).toEqual('.target')
340
+
341
+ it "adds [up-follow] attribute if [up-dash]'s value is 'true'", ->
342
+ $link = affix('a[href="/path"][up-dash="true"]').text('label')
343
+ up.hello($link)
344
+ expect($link.attr('up-follow')).toEqual('')
345
+
346
+ it "adds [up-follow] attribute if [up-dash] is present, but has no value", ->
347
+ $link = affix('a[href="/path"][up-dash]').text('label')
348
+ up.hello($link)
349
+ expect($link.attr('up-follow')).toEqual('')
350
+
351
+ it "does not add an [up-follow] attribute if [up-dash] is 'true', but [up-target] is present", ->
352
+ $link = affix('a[href="/path"][up-dash="true"][up-target=".target"]').text('label')
353
+ up.hello($link)
354
+ expect($link.attr('up-follow')).toBeMissing()
355
+ expect($link.attr('up-target')).toEqual('.target')
356
+
357
+ it "does not add an [up-follow] attribute if [up-dash] is 'true', but [up-modal] is present", ->
358
+ $link = affix('a[href="/path"][up-dash="true"][up-modal=".target"]').text('label')
359
+ up.hello($link)
360
+ expect($link.attr('up-follow')).toBeMissing()
361
+ expect($link.attr('up-modal')).toEqual('.target')
362
+
363
+ it "does not add an [up-follow] attribute if [up-dash] is 'true', but [up-popup] is present", ->
364
+ $link = affix('a[href="/path"][up-dash="true"][up-popup=".target"]').text('label')
365
+ up.hello($link)
366
+ expect($link.attr('up-follow')).toBeMissing()
367
+ expect($link.attr('up-popup')).toEqual('.target')
368
+
369
+ it "removes the [up-dash] attribute when it's done", ->
370
+ $link = affix('a[href="/path"]').text('label')
371
+ up.hello($link)
372
+ expect($link.attr('up-dash')).toBeMissing()
373
+
304
374
  describe '[up-expand]', ->
305
375
 
306
376
  it 'copies up-related attributes of a contained link', ->
@@ -332,6 +402,31 @@ describe 'up.link', ->
332
402
  up.hello($area)
333
403
  expect($area.attr('up-follow')).toEqual('')
334
404
 
405
+ it 'can be used to enlarge the click area of a link', ->
406
+ $area = affix('div[up-expand] a[href="/path"]')
407
+ up.hello($area)
408
+ spyOn(up, 'replace')
409
+ $area.get(0).click()
410
+ expect(up.replace).toHaveBeenCalled()
411
+
412
+ it 'does not trigger multiple replaces when the user clicks on the expanded area of an up-instant link (bugfix)', ->
413
+ $area = affix('div[up-expand] a[href="/path"][up-instant]')
414
+ up.hello($area)
415
+ spyOn(up, 'replace')
416
+ Trigger.mousedown($area)
417
+ Trigger.click($area)
418
+ expect(up.replace.calls.count()).toEqual(1)
419
+
420
+ it 'does not add an up-follow attribute if the expanded link is [up-dash] with a selector (bugfix)', ->
421
+ $area = affix('div[up-expand] a[href="/path"][up-dash=".element"]')
422
+ up.hello($area)
423
+ expect($area.attr('up-follow')).toBeMissing()
424
+
425
+ it 'does not an up-follow attribute if the expanded link is [up-dash] without a selector (bugfix)', ->
426
+ $area = affix('div[up-expand] a[href="/path"][up-dash]')
427
+ up.hello($area)
428
+ expect($area.attr('up-follow')).toEqual('')
429
+
335
430
  describe 'with a CSS selector in the property value', ->
336
431
 
337
432
  it "expands the contained link that matches the selector", ->
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unpoly-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.22.0
4
+ version: 0.22.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henning Koch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-14 00:00:00.000000000 Z
11
+ date: 2016-03-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails