unpoly-rails 0.31.2 → 0.32.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -5
  3. data/README.md +21 -15
  4. data/README_RAILS.md +2 -2
  5. data/Rakefile +1 -1
  6. data/bower.json +4 -3
  7. data/design/homepage.txt +2 -2
  8. data/dist/unpoly-bootstrap3.css +3 -0
  9. data/dist/unpoly-bootstrap3.min.css +1 -1
  10. data/dist/unpoly.css +4 -4
  11. data/dist/unpoly.js +114 -80
  12. data/dist/unpoly.min.css +1 -1
  13. data/dist/unpoly.min.js +3 -3
  14. data/lib/assets/javascripts/unpoly/browser.js.coffee +1 -1
  15. data/lib/assets/javascripts/unpoly/bus.js.coffee +3 -3
  16. data/lib/assets/javascripts/unpoly/flow.js.coffee +15 -11
  17. data/lib/assets/javascripts/unpoly/form.js.coffee +1 -1
  18. data/lib/assets/javascripts/unpoly/layout.js.coffee +12 -9
  19. data/lib/assets/javascripts/unpoly/link.js.coffee +22 -7
  20. data/lib/assets/javascripts/unpoly/log.js.coffee +3 -2
  21. data/lib/assets/javascripts/unpoly/modal.js.coffee +11 -13
  22. data/lib/assets/javascripts/unpoly/motion.js.coffee +1 -1
  23. data/lib/assets/javascripts/unpoly/navigation.js.coffee +5 -5
  24. data/lib/assets/javascripts/unpoly/popup.js.coffee +8 -9
  25. data/lib/assets/javascripts/unpoly/proxy.js.coffee +2 -2
  26. data/lib/assets/javascripts/unpoly/syntax.js.coffee +19 -15
  27. data/lib/assets/javascripts/unpoly/util.js.coffee +19 -3
  28. data/lib/assets/stylesheets/unpoly-bootstrap3/modal-ext.css.sass +6 -1
  29. data/lib/assets/stylesheets/unpoly/modal.css.sass +7 -2
  30. data/lib/unpoly/rails/version.rb +1 -1
  31. data/package.json +2 -2
  32. data/spec_app/Gemfile.lock +1 -1
  33. data/spec_app/app/assets/javascripts/bootstrap_manifest.coffee +2 -2
  34. data/spec_app/app/views/css_test/modal.erb +4 -0
  35. data/spec_app/app/views/css_test/modal_contents_wide.erb +5 -0
  36. data/spec_app/app/views/layouts/integration_test.erb +1 -0
  37. data/spec_app/spec/javascripts/helpers/knife.js.coffee +1 -1
  38. data/spec_app/spec/javascripts/up/browser_spec.js.coffee +1 -1
  39. data/spec_app/spec/javascripts/up/bus_spec.js.coffee +1 -1
  40. data/spec_app/spec/javascripts/up/flow_spec.js.coffee +63 -5
  41. data/spec_app/spec/javascripts/up/form_spec.js.coffee +2 -2
  42. data/spec_app/spec/javascripts/up/history_spec.js.coffee +1 -1
  43. data/spec_app/spec/javascripts/up/layout_spec.js.coffee +27 -1
  44. data/spec_app/spec/javascripts/up/link_spec.js.coffee +3 -3
  45. data/spec_app/spec/javascripts/up/log_spec.js.coffee +1 -1
  46. data/spec_app/spec/javascripts/up/modal_spec.js.coffee +3 -3
  47. data/spec_app/spec/javascripts/up/motion_spec.js.coffee +1 -1
  48. data/spec_app/spec/javascripts/up/popup_spec.js.coffee +21 -3
  49. data/spec_app/spec/javascripts/up/proxy_spec.js.coffee +1 -1
  50. data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +1 -1
  51. data/spec_app/spec/javascripts/up/tooltip_spec.js.coffee +1 -1
  52. data/spec_app/spec/javascripts/up/util_spec.js.coffee +2 -2
  53. data/spec_app/vendor/assets/bower_components/jasmine-jquery/README.md +2 -2
  54. data/unpoly-rails.gemspec +1 -1
  55. metadata +5 -4
@@ -456,7 +456,7 @@ up.util = (($) ->
456
456
  ###*
457
457
  Returns whether the given argument is an object.
458
458
 
459
- This also returns `true` for functions, which may behave like objects in Javascript.
459
+ This also returns `true` for functions, which may behave like objects in JavaScript.
460
460
  For an alternative that returns `false` for functions, see [`up.util.isHash`](/up.util.isHash).
461
461
 
462
462
  @function up.util.isObject
@@ -783,7 +783,7 @@ up.util = (($) ->
783
783
 
784
784
  ###*
785
785
  Schedules the given function to be called in the
786
- next Javascript execution frame.
786
+ next JavaScript execution frame.
787
787
 
788
788
  @function up.util.nextFrame
789
789
  @param {Function} block
@@ -1684,7 +1684,7 @@ up.util = (($) ->
1684
1684
  data
1685
1685
 
1686
1686
  ###*
1687
- Throws a [Javascript error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
1687
+ Throws a [JavaScript error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
1688
1688
  with the given message.
1689
1689
 
1690
1690
  The message will also be printed to the [error log](/up.log.error). Also a notification will be shown at the bottom of the screen.
@@ -1905,6 +1905,21 @@ up.util = (($) ->
1905
1905
  else
1906
1906
  'right'
1907
1907
 
1908
+ ###*
1909
+ Like `$old.replaceWith($new)`, but keeps event handlers bound to `$old`.
1910
+
1911
+ Note that this is a memory leak unless you re-attach `$new` to the DOM aferwards.
1912
+
1913
+ @function up.util.detachWith
1914
+ @internal
1915
+ ###
1916
+ detachWith = ($old, $new) ->
1917
+ $insertion = $('<div></div>')
1918
+ $insertion.insertAfter($old)
1919
+ $old.detach()
1920
+ $insertion.replaceWith($new)
1921
+ $old
1922
+
1908
1923
  isDetached: isDetached
1909
1924
  requestDataAsArray: requestDataAsArray
1910
1925
  requestDataAsQuery: requestDataAsQuery
@@ -2018,6 +2033,7 @@ up.util = (($) ->
2018
2033
  previewable: previewable
2019
2034
  evalOption: evalOption
2020
2035
  horizontalScreenHalf: horizontalScreenHalf
2036
+ detachWith: detachWith
2021
2037
 
2022
2038
  )($)
2023
2039
 
@@ -1,8 +1,13 @@
1
1
  .up-modal-content
2
2
  // Unpoly: Gives some default padding
3
- // BS: Expects content to set the padding
3
+ // Bootstrap: Expects content to set the padding
4
4
  padding: 0
5
5
 
6
+ .up-modal-dialog
7
+ // Unpoly: Dialog margin is a padding of .up-modal-viewport so we can give .up-modal-dialog a max-width of 100%
8
+ // Bootstrap: Dialog margin is a margin of .modal-dialog
9
+ margin: 0
10
+
6
11
  .up-modal[up-flavor='drawer']
7
12
 
8
13
  .up-modal-content
@@ -50,6 +50,12 @@ $close-font-size: 34px
50
50
  // contents of `.up-modal-content`.
51
51
  text-align: center
52
52
 
53
+ // Implement the margin around the dialog box with a padding of the viewport.
54
+ // This way we can give .up-modal-dialog a max-width of 100%, (1) preventing people
55
+ // from setting withs larger than the viewport, and (2) sizing approproately
56
+ // if the modal contents are very wide and cannot wrap (e.g. code blocks).
57
+ padding: 30px 10px
58
+
53
59
  .up-modal.up-modal-animating
54
60
  // During opening/closing animations we let the .up-modal container take over
55
61
  // the scrollbars that would usually be owned by .up-modal-viewport.
@@ -68,7 +74,6 @@ $close-font-size: 34px
68
74
  // the width and height attributes set by up.modal
69
75
  // should be honored exactly.
70
76
  box-sizing: border-box
71
- margin: 30px 10px
72
77
 
73
78
  // In case someone sets a huge width on the dialog.
74
79
  max-width: 100%
@@ -99,10 +104,10 @@ $close-font-size: 34px
99
104
  .up-modal[up-flavor='drawer']
100
105
  .up-modal-viewport
101
106
  text-align: left
107
+ padding: 0
102
108
  &[up-position='right'] .up-modal-viewport
103
109
  text-align: right
104
110
  .up-modal-dialog
105
- margin: 0
106
111
  max-width: 350px
107
112
  .up-modal-content
108
113
  min-height: 100vh
@@ -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.31.2'
7
+ VERSION = '0.32.0'
8
8
  end
9
9
  end
data/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "unpoly",
3
- "version": "0.31.2",
4
- "description": "Progressive enhancement Javascript framework",
3
+ "version": "0.32.0",
4
+ "description": "Unobtrusive JavaScript framework",
5
5
  "main": "dist/unpoly.js",
6
6
  "files": [
7
7
  "dist/unpoly.js",
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- unpoly-rails (0.31.0)
4
+ unpoly-rails (0.31.2)
5
5
  rails (>= 3)
6
6
 
7
7
  GEM
@@ -2,5 +2,5 @@
2
2
 
3
3
  # From the docs (https://github.com/twbs/bootstrap-sass):
4
4
  # bootstrap-sprockets and bootstrap should not both be included in application.js.
5
- # bootstrap-sprockets provides individual Bootstrap Javascript files (alert.js or dropdown.js, for example),
6
- # while bootstrap provides a concatenated file containing all Bootstrap Javascripts.
5
+ # bootstrap-sprockets provides individual Bootstrap JavaScript files (alert.js or dropdown.js, for example),
6
+ # while bootstrap provides a concatenated file containing all Bootstrap JavaScripts.
@@ -2,6 +2,10 @@
2
2
  <a class="button" href="/css_test/modal_contents" up-modal=".contents">Modal</a>
3
3
  </div>
4
4
 
5
+ <div class="example">
6
+ <a class="button" href="/css_test/modal_contents_wide" up-modal=".contents">Modal (wide contents)</a>
7
+ </div>
8
+
5
9
  <div class="example">
6
10
  <a class="button" href="/css_test/modal_contents" up-drawer=".contents" style="float: left">Drawer (auto)</a>
7
11
  <a class="button" href="/css_test/modal_contents" up-drawer=".contents" style="float: right">Drawer (auto)</a>
@@ -0,0 +1,5 @@
1
+ <div class="contents">
2
+ <% (1..100).each do |i| %>
3
+ Line<%= i %>:This_content_wont_wrap_because_it_contains_no_spaces<br>
4
+ <% end %>
5
+ </div>
@@ -11,6 +11,7 @@
11
11
  <%= javascript_include_tag 'unpoly-bootstrap3' %>
12
12
  <% end %>
13
13
  <%= csrf_meta_tags %>
14
+ <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'>
14
15
  </head>
15
16
  <body>
16
17
  <div class="page">
@@ -1,5 +1,5 @@
1
1
  ##
2
- # Knife: Get, set or mock inaccessible variables in a Javascript closure
2
+ # Knife: Get, set or mock inaccessible variables in a JavaScript closure
3
3
  # ======================================================================
4
4
  #
5
5
  # Requires [Jasmine](http://jasmine.github.io/) 2+.
@@ -2,7 +2,7 @@ describe 'up.browser', ->
2
2
 
3
3
  u = up.util
4
4
 
5
- describe 'Javascript functions', ->
5
+ describe 'JavaScript functions', ->
6
6
 
7
7
  describe 'up.browser.loadPage', ->
8
8
 
@@ -1,6 +1,6 @@
1
1
  describe 'up.bus', ->
2
2
 
3
- describe 'Javascript functions', ->
3
+ describe 'JavaScript functions', ->
4
4
 
5
5
  describe 'up.on', ->
6
6
 
@@ -2,7 +2,7 @@ describe 'up.flow', ->
2
2
 
3
3
  u = up.util
4
4
 
5
- describe 'Javascript functions', ->
5
+ describe 'JavaScript functions', ->
6
6
 
7
7
  describe 'up.replace', ->
8
8
 
@@ -493,10 +493,12 @@ describe 'up.flow', ->
493
493
  beforeEach ->
494
494
  @revealedHTML = []
495
495
  @revealedText = []
496
+ @revealOptions = {}
496
497
 
497
- @revealMock = up.layout.knife.mock('reveal').and.callFake ($revealedElement) =>
498
- @revealedHTML.push $revealedElement.get(0).outerHTML
499
- @revealedText.push $revealedElement.text().trim()
498
+ @revealMock = up.layout.knife.mock('reveal').and.callFake ($element, options) =>
499
+ @revealedHTML.push $element.get(0).outerHTML
500
+ @revealedText.push $element.text().trim()
501
+ @revealOptions = options
500
502
  u.resolvedDeferred()
501
503
 
502
504
  it 'reveals a new element before it is being replaced', (done) ->
@@ -519,7 +521,7 @@ describe 'up.flow', ->
519
521
 
520
522
  describe 'when there is an anchor #hash in the URL', ->
521
523
 
522
- it 'reveals a child with the ID of that #hash', (done) ->
524
+ it 'scrolls to the top of a child with the ID of that #hash', (done) ->
523
525
  promise = up.replace('.middle', '/path#three', reveal: true)
524
526
  @responseText =
525
527
  """
@@ -532,6 +534,7 @@ describe 'up.flow', ->
532
534
  @respond()
533
535
  promise.then =>
534
536
  expect(@revealedHTML).toEqual ['<div id="three">three</div>']
537
+ expect(@revealOptions).toEqual { top: true }
535
538
  done()
536
539
 
537
540
  it "reveals the entire element if it has no child with the ID of that #hash", (done) ->
@@ -794,34 +797,67 @@ describe 'up.flow', ->
794
797
  expect(keptListener).toHaveBeenCalledWith(jasmine.anything(), $('.keeper'), jasmine.anything())
795
798
 
796
799
  it "removes an [up-keep] element if no matching element is found in the response", ->
800
+ barCompiler = jasmine.createSpy()
801
+ barDestructor = jasmine.createSpy()
802
+ up.compiler '.bar', ($bar) ->
803
+ text = $bar.text()
804
+ barCompiler(text)
805
+ return -> barDestructor(text)
806
+
797
807
  $container = affix('.container')
798
808
  $container.html """
799
809
  <div class='foo'>old-foo</div>
800
810
  <div class='bar' up-keep>old-bar</div>
801
811
  """
812
+ up.hello($container)
813
+
814
+ expect(barCompiler.calls.allArgs()).toEqual [['old-bar']]
815
+ expect(barDestructor.calls.allArgs()).toEqual []
816
+
802
817
  up.extract '.container', """
803
818
  <div class='container'>
804
819
  <div class='foo'>new-foo</div>
805
820
  </div>
806
821
  """
822
+
807
823
  expect($('.container .foo')).toExist()
808
824
  expect($('.container .bar')).not.toExist()
809
825
 
826
+ expect(barCompiler.calls.allArgs()).toEqual [['old-bar']]
827
+ expect(barDestructor.calls.allArgs()).toEqual [['old-bar']]
828
+
810
829
  it "updates an element if a matching element is found in the response, but that other element is no longer [up-keep]", ->
830
+ barCompiler = jasmine.createSpy()
831
+ barDestructor = jasmine.createSpy()
832
+ up.compiler '.bar', ($bar) ->
833
+ text = $bar.text()
834
+ console.info('Compiling %o', text)
835
+ barCompiler(text)
836
+ return -> barDestructor(text)
837
+
811
838
  $container = affix('.container')
812
839
  $container.html """
813
840
  <div class='foo'>old-foo</div>
814
841
  <div class='bar' up-keep>old-bar</div>
815
842
  """
843
+ up.hello($container)
844
+
845
+ expect(barCompiler.calls.allArgs()).toEqual [['old-bar']]
846
+ expect(barDestructor.calls.allArgs()).toEqual []
847
+
816
848
  up.extract '.container', """
817
849
  <div class='container'>
818
850
  <div class='foo'>new-foo</div>
819
851
  <div class='bar'>new-bar</div>
820
852
  </div>
821
853
  """
854
+
822
855
  expect($('.container .foo')).toHaveText('new-foo')
823
856
  expect($('.container .bar')).toHaveText('new-bar')
824
857
 
858
+ expect(barCompiler.calls.allArgs()).toEqual [['old-bar'], ['new-bar']]
859
+ expect(barDestructor.calls.allArgs()).toEqual [['old-bar']]
860
+
825
861
  it 'moves a kept element to the ancestry position of the matching element in the response', ->
826
862
  $container = affix('.container')
827
863
  $container.html """
@@ -874,6 +910,28 @@ describe 'up.flow', ->
874
910
  expect(compiler.calls.count()).toEqual(1)
875
911
  expect('.keeper').toExist()
876
912
 
913
+ it 'does not lose jQuery event handlers on a kept element (bugfix)', ->
914
+ handler = jasmine.createSpy('event handler')
915
+ up.compiler '.keeper', ($keeper) ->
916
+ $keeper.on 'click', handler
917
+
918
+ $container = affix('.container')
919
+ $container.html """
920
+ <div class="keeper" up-keep>old-text</div>
921
+ """
922
+ up.hello($container)
923
+
924
+ up.extract '.container', """
925
+ <div class='container'>
926
+ <div class="keeper" up-keep>new-text</div>
927
+ </div>
928
+ """
929
+
930
+ $keeper = $('.keeper')
931
+ expect($keeper).toHaveText('old-text')
932
+ Trigger.click($keeper)
933
+ expect(handler).toHaveBeenCalled()
934
+
877
935
  it 'lets listeners cancel the keeping by preventing default on an up:fragment:keep event', ->
878
936
  $keeper = affix('.keeper[up-keep]').text('old-inside')
879
937
  $keeper.on 'up:fragment:keep', (event) -> event.preventDefault()
@@ -2,7 +2,7 @@ describe 'up.form', ->
2
2
 
3
3
  u = up.util
4
4
 
5
- describe 'Javascript functions', ->
5
+ describe 'JavaScript functions', ->
6
6
 
7
7
  describe 'up.observe', ->
8
8
 
@@ -419,7 +419,7 @@ describe 'up.form', ->
419
419
  afterEach ->
420
420
  window.observeCallbackSpy = undefined
421
421
 
422
- it 'runs the Javascript code in the attribute value when a change is observed in the field', (done) ->
422
+ it 'runs the JavaScript code in the attribute value when a change is observed in the field', (done) ->
423
423
  $form = affix('form')
424
424
  window.observeCallbackSpy = jasmine.createSpy('observe callback')
425
425
  $field = $form.affix('input[val="old-value"][up-observe="window.observeCallbackSpy(value, $field.get(0))"]')
@@ -2,7 +2,7 @@ describe 'up.history', ->
2
2
 
3
3
  u = up.util
4
4
 
5
- describe 'Javascript functions', ->
5
+ describe 'JavaScript functions', ->
6
6
 
7
7
  describe 'up.history.replace', ->
8
8
 
@@ -2,7 +2,7 @@ describe 'up.layout', ->
2
2
 
3
3
  u = up.util
4
4
 
5
- describe 'Javascript functions', ->
5
+ describe 'JavaScript functions', ->
6
6
 
7
7
  describe 'up.reveal', ->
8
8
 
@@ -78,6 +78,18 @@ describe 'up.layout', ->
78
78
  # [2] 70 ......... 5069
79
79
  expect($(document).scrollTop()).toBe(0)
80
80
 
81
+ it 'does not snap to the top if it would un-reveal an element at the bottom edge of the screen (bugfix)', ->
82
+ up.layout.config.snap = 100
83
+
84
+ up.reveal(@$elements[1])
85
+ # ---------------------
86
+ # [0] 0 .......... ch-1
87
+ # [1] ch+0 ...... ch+49
88
+ # ---------------------
89
+ # [2] ch+50 ... ch+5049
90
+ expect($(document).scrollTop()).toBe(50)
91
+
92
+
81
93
  it 'scrolls far enough so the element is not obstructed by an element fixed to the top', ->
82
94
  $topNav = affix('[up-fixed=top]').css(
83
95
  position: 'fixed',
@@ -161,6 +173,20 @@ describe 'up.layout', ->
161
173
  # [F] 0 ............ 99
162
174
  expect($(document).scrollTop()).toBe(@clientHeight + 50)
163
175
 
176
+ describe 'with { top: true } option', ->
177
+
178
+ it 'scrolls the viewport to the first row of the element, even if that element is already fully revealed', ->
179
+
180
+ @$elements[0].css(height: '20px')
181
+
182
+ up.reveal(@$elements[1], { top: true })
183
+ # [0] 0 ............ 19
184
+ # [1] 20 ........... 69
185
+ # ---------------------
186
+ # [2] 70 ......... 5069
187
+ # ---------------------
188
+ expect($(document).scrollTop()).toBe(20)
189
+
164
190
 
165
191
  describe 'when the viewport is a container with overflow-y: scroll', ->
166
192
 
@@ -2,7 +2,7 @@ describe 'up.link', ->
2
2
 
3
3
  u = up.util
4
4
 
5
- describe 'Javascript functions', ->
5
+ describe 'JavaScript functions', ->
6
6
 
7
7
  describe 'up.follow', ->
8
8
 
@@ -462,7 +462,7 @@ describe 'up.link', ->
462
462
  Trigger.click(@$link)
463
463
  expect(@followSpy).toHaveBeenCalledWith(@$link)
464
464
 
465
- # IE does not call Javascript and always performs the default action on right clicks
465
+ # IE does not call JavaScript and always performs the default action on right clicks
466
466
  unless navigator.userAgent.match(/Trident/)
467
467
  it 'does nothing if the right mouse button is used', ->
468
468
  Trigger.click(@$link, button: 2)
@@ -497,7 +497,7 @@ describe 'up.link', ->
497
497
  Trigger.click(@$link)
498
498
  expect(@followSpy).not.toHaveBeenCalled()
499
499
 
500
- # IE does not call Javascript and always performs the default action on right clicks
500
+ # IE does not call JavaScript and always performs the default action on right clicks
501
501
  unless navigator.userAgent.match(/Trident/)
502
502
  it 'does nothing if the right mouse button is pressed down', ->
503
503
  Trigger.mousedown(@$link, button: 2)
@@ -1,6 +1,6 @@
1
1
  describe 'up.log', ->
2
2
 
3
- describe 'Javascript functions', ->
3
+ describe 'JavaScript functions', ->
4
4
 
5
5
  describe 'up.log.puts', ->
6
6