unpoly-rails 0.31.2 → 0.32.0

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.

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