unpoly-rails 0.32.0 → 0.33.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 (232) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +106 -76
  3. data/README.md +8 -5
  4. data/README_RAILS.md +1 -1
  5. data/design/test_rejected_promise.txt +5 -0
  6. data/dist/unpoly-bootstrap3.js +1 -1
  7. data/dist/unpoly-bootstrap3.min.js +1 -1
  8. data/dist/unpoly.js +814 -417
  9. data/dist/unpoly.min.js +3 -3
  10. data/lib/assets/javascripts/unpoly/{browser.js.coffee → browser.coffee} +15 -6
  11. data/lib/assets/javascripts/unpoly/{bus.js.coffee → bus.coffee} +13 -13
  12. data/lib/assets/javascripts/unpoly/dom/extract_cascade.coffee +73 -0
  13. data/lib/assets/javascripts/unpoly/dom/extract_plan.coffee +65 -0
  14. data/lib/assets/javascripts/unpoly/{flow.js.coffee → dom.coffee} +109 -114
  15. data/lib/assets/javascripts/unpoly/{navigation.js.coffee → feedback.coffee} +11 -11
  16. data/lib/assets/javascripts/unpoly/{form.js.coffee → form.coffee} +35 -24
  17. data/lib/assets/javascripts/unpoly/{history.js.coffee → history.coffee} +9 -10
  18. data/lib/assets/javascripts/unpoly/{layout.js.coffee → layout.coffee} +53 -21
  19. data/lib/assets/javascripts/unpoly/{link.js.coffee → link.coffee} +46 -40
  20. data/lib/assets/javascripts/unpoly/{log.js.coffee → log.coffee} +2 -2
  21. data/lib/assets/javascripts/unpoly/{modal.js.coffee → modal.coffee} +17 -14
  22. data/lib/assets/javascripts/unpoly/{motion.js.coffee → motion.coffee} +28 -31
  23. data/lib/assets/javascripts/unpoly/namespace.coffee.erb +10 -0
  24. data/lib/assets/javascripts/unpoly/{popup.js.coffee → popup.coffee} +22 -10
  25. data/lib/assets/javascripts/unpoly/{proxy.js.coffee → proxy.coffee} +34 -12
  26. data/lib/assets/javascripts/unpoly/{rails.js.coffee → rails.coffee} +0 -0
  27. data/lib/assets/javascripts/unpoly/{syntax.js.coffee → syntax.coffee} +32 -21
  28. data/lib/assets/javascripts/unpoly/{toast.js.coffee → toast.coffee} +0 -0
  29. data/lib/assets/javascripts/unpoly/{tooltip.js.coffee → tooltip.coffee} +2 -2
  30. data/lib/assets/javascripts/unpoly/{util.js.coffee → util.coffee} +122 -35
  31. data/lib/assets/javascripts/unpoly-bootstrap3/{form-ext.js.coffee → form-ext.coffee} +0 -0
  32. data/lib/assets/javascripts/unpoly-bootstrap3/{layout-ext.js.coffee → layout-ext.coffee} +0 -0
  33. data/lib/assets/javascripts/unpoly-bootstrap3/{modal-ext.js.coffee → modal-ext.coffee} +0 -0
  34. data/lib/assets/javascripts/unpoly-bootstrap3/{navigation-ext.js.coffee → navigation-ext.coffee} +1 -1
  35. data/lib/assets/javascripts/{unpoly-bootstrap3.js.coffee → unpoly-bootstrap3.coffee} +0 -0
  36. data/lib/assets/javascripts/unpoly.coffee +22 -0
  37. data/lib/assets/stylesheets/unpoly/{close.css.sass → close.sass} +0 -0
  38. data/lib/assets/stylesheets/unpoly/{flow.css.sass → flow.sass} +0 -0
  39. data/lib/assets/stylesheets/unpoly/{link.css.sass → link.sass} +0 -0
  40. data/lib/assets/stylesheets/unpoly/{modal.css.sass → modal.sass} +0 -0
  41. data/lib/assets/stylesheets/unpoly/{popup.css.sass → popup.sass} +0 -0
  42. data/lib/assets/stylesheets/unpoly/{toast.css.sass → toast.sass} +0 -0
  43. data/lib/assets/stylesheets/unpoly/{tooltip.css.sass → tooltip.sass} +0 -0
  44. data/lib/assets/stylesheets/unpoly-bootstrap3/{modal-ext.css.sass → modal-ext.sass} +0 -0
  45. data/lib/assets/stylesheets/{unpoly-bootstrap3.css.sass → unpoly-bootstrap3.sass} +0 -0
  46. data/lib/assets/stylesheets/{unpoly.css.sass → unpoly.sass} +0 -0
  47. data/lib/unpoly/rails/version.rb +1 -1
  48. data/package.json +1 -1
  49. data/spec_app/Gemfile.lock +11 -13
  50. data/spec_app/app/assets/javascripts/jasmine_specs.coffee +1 -1
  51. data/spec_app/app/assets/stylesheets/_helpers.sass +1 -1
  52. data/spec_app/config/initializers/assets.rb +1 -5
  53. data/spec_app/spec/javascripts/up/{flow_spec.js.coffee → dom_spec.js.coffee} +294 -44
  54. data/spec_app/spec/javascripts/up/{navigation_spec.js.coffee → feedback_spec.js.coffee} +2 -2
  55. data/spec_app/spec/javascripts/up/form_spec.js.coffee +1 -0
  56. data/spec_app/spec/javascripts/up/layout_spec.js.coffee +10 -0
  57. data/spec_app/spec/javascripts/up/link_spec.js.coffee +28 -0
  58. data/spec_app/spec/javascripts/up/modal_spec.js.coffee +46 -9
  59. data/spec_app/spec/javascripts/up/motion_spec.js.coffee +32 -2
  60. data/spec_app/spec/javascripts/up/popup_spec.js.coffee +5 -4
  61. data/spec_app/spec/javascripts/up/util_spec.js.coffee +75 -0
  62. data/spec_app/vendor/{assets/bower_components/jasmine-ajax → asset-libs/jasmine-ajax-3.3.1}/.bower.json +0 -0
  63. data/spec_app/vendor/asset-libs/jasmine-ajax-3.3.1/.gitignore +6 -0
  64. data/spec_app/vendor/asset-libs/jasmine-ajax-3.3.1/.npmignore +10 -0
  65. data/spec_app/vendor/asset-libs/jasmine-ajax-3.3.1/.pairs +6 -0
  66. data/spec_app/vendor/asset-libs/jasmine-ajax-3.3.1/.travis.yml +56 -0
  67. data/spec_app/vendor/{assets/bower_components/jasmine-ajax/lib/mock-ajax.js → asset-libs/jasmine-ajax-3.3.1/jasmine-ajax.js} +83 -26
  68. data/spec_app/vendor/{assets/bower_components/jasmine-fixture/dist → asset-libs/jasmine-fixture-1.3.4}/jasmine-fixture.js +13 -13
  69. data/spec_app/vendor/{assets/bower_components/jasmine-jquery → asset-libs/jasmine-jquery-2.1.1}/.bower.json +0 -0
  70. data/spec_app/vendor/{assets/bower_components/jasmine-jquery/lib → asset-libs/jasmine-jquery-2.1.1}/jasmine-jquery.js +0 -0
  71. data/spec_app/vendor/assets/{javascripts/.keep → .keep} +0 -0
  72. metadata +52 -203
  73. data/lib/assets/javascripts/unpoly/module.js.coffee.erb +0 -8
  74. data/lib/assets/javascripts/unpoly.js.coffee +0 -21
  75. data/spec_app/Bowerfile +0 -3
  76. data/spec_app/vendor/assets/.bowerrc +0 -3
  77. data/spec_app/vendor/assets/bower.json +0 -8
  78. data/spec_app/vendor/assets/bower_components/jasmine/.bower.json +0 -50
  79. data/spec_app/vendor/assets/bower_components/jasmine/CONTRIBUTING.md +0 -130
  80. data/spec_app/vendor/assets/bower_components/jasmine/GOALS_2.0.md +0 -64
  81. data/spec_app/vendor/assets/bower_components/jasmine/MANIFEST.in +0 -5
  82. data/spec_app/vendor/assets/bower_components/jasmine/MIT.LICENSE +0 -20
  83. data/spec_app/vendor/assets/bower_components/jasmine/README.md +0 -73
  84. data/spec_app/vendor/assets/bower_components/jasmine/RELEASE.md +0 -73
  85. data/spec_app/vendor/assets/bower_components/jasmine/bower.json +0 -41
  86. data/spec_app/vendor/assets/bower_components/jasmine/images/jasmine-horizontal.png +0 -0
  87. data/spec_app/vendor/assets/bower_components/jasmine/images/jasmine-horizontal.svg +0 -102
  88. data/spec_app/vendor/assets/bower_components/jasmine/images/jasmine_favicon.png +0 -0
  89. data/spec_app/vendor/assets/bower_components/jasmine/lib/console/console.js +0 -190
  90. data/spec_app/vendor/assets/bower_components/jasmine/lib/jasmine-core/boot.js +0 -143
  91. data/spec_app/vendor/assets/bower_components/jasmine/lib/jasmine-core/example/node_example/lib/jasmine_examples/Player.js +0 -24
  92. data/spec_app/vendor/assets/bower_components/jasmine/lib/jasmine-core/example/node_example/lib/jasmine_examples/Song.js +0 -9
  93. data/spec_app/vendor/assets/bower_components/jasmine/lib/jasmine-core/jasmine-html.js +0 -446
  94. data/spec_app/vendor/assets/bower_components/jasmine/lib/jasmine-core/jasmine.css +0 -58
  95. data/spec_app/vendor/assets/bower_components/jasmine/lib/jasmine-core/jasmine.js +0 -3298
  96. data/spec_app/vendor/assets/bower_components/jasmine/lib/jasmine-core/json2.js +0 -489
  97. data/spec_app/vendor/assets/bower_components/jasmine/lib/jasmine-core/node_boot.js +0 -41
  98. data/spec_app/vendor/assets/bower_components/jasmine/lib/jasmine-core.js +0 -37
  99. data/spec_app/vendor/assets/bower_components/jasmine/package.json +0 -34
  100. data/spec_app/vendor/assets/bower_components/jasmine/requirements.txt +0 -1
  101. data/spec_app/vendor/assets/bower_components/jasmine-ajax/MIT.LICENSE +0 -20
  102. data/spec_app/vendor/assets/bower_components/jasmine-ajax/README.markdown +0 -289
  103. data/spec_app/vendor/assets/bower_components/jasmine-ajax/bower.json +0 -35
  104. data/spec_app/vendor/assets/bower_components/jasmine-ajax/package.json +0 -26
  105. data/spec_app/vendor/assets/bower_components/jasmine-ajax/release_notes/2.0.2.md +0 -50
  106. data/spec_app/vendor/assets/bower_components/jasmine-ajax/release_notes/2.99.md +0 -14
  107. data/spec_app/vendor/assets/bower_components/jasmine-ajax/release_notes/3.0.md +0 -28
  108. data/spec_app/vendor/assets/bower_components/jasmine-ajax/release_notes/3.1.0.md +0 -24
  109. data/spec_app/vendor/assets/bower_components/jasmine-ajax/release_notes/3.1.1.md +0 -23
  110. data/spec_app/vendor/assets/bower_components/jasmine-ajax/release_notes/3.2.0.md +0 -20
  111. data/spec_app/vendor/assets/bower_components/jasmine-fixture/.bower.json +0 -27
  112. data/spec_app/vendor/assets/bower_components/jasmine-fixture/.gitignore +0 -8
  113. data/spec_app/vendor/assets/bower_components/jasmine-fixture/.npmignore +0 -8
  114. data/spec_app/vendor/assets/bower_components/jasmine-fixture/LICENSE.txt +0 -24
  115. data/spec_app/vendor/assets/bower_components/jasmine-fixture/README.md +0 -118
  116. data/spec_app/vendor/assets/bower_components/jasmine-fixture/bower.json +0 -17
  117. data/spec_app/vendor/assets/bower_components/jasmine-fixture/dist/jasmine-fixture.min.js +0 -5
  118. data/spec_app/vendor/assets/bower_components/jasmine-fixture/spec-e2e/basic-usage-spec.coffee +0 -14
  119. data/spec_app/vendor/assets/bower_components/jasmine-fixture/spec-e2e/helpers/invariants.coffee +0 -17
  120. data/spec_app/vendor/assets/bower_components/jasmine-fixture/spec-e2e/helpers/spec-within-a-spec.coffee +0 -24
  121. data/spec_app/vendor/assets/bower_components/jasmine-fixture/spec-e2e/helpers/tmp-files.coffee +0 -8
  122. data/spec_app/vendor/assets/bower_components/jasmine-fixture/spec-e2e/support/jasmine1-testem-config.json +0 -11
  123. data/spec_app/vendor/assets/bower_components/jasmine-fixture/spec-e2e/support/jasmine2-testem-config.json +0 -11
  124. data/spec_app/vendor/assets/bower_components/jasmine-fixture/vendor/js/jquery-1.11.0.js +0 -10337
  125. data/spec_app/vendor/assets/bower_components/jasmine-fixture/vendor/js/jquery-1.8.3.js +0 -9472
  126. data/spec_app/vendor/assets/bower_components/jasmine-fixture/vendor/js/jquery-2.1.0.js +0 -9111
  127. data/spec_app/vendor/assets/bower_components/jasmine-jquery/CONTRIBUTING.md +0 -28
  128. data/spec_app/vendor/assets/bower_components/jasmine-jquery/Gruntfile.js +0 -49
  129. data/spec_app/vendor/assets/bower_components/jasmine-jquery/LICENSE +0 -20
  130. data/spec_app/vendor/assets/bower_components/jasmine-jquery/README.md +0 -367
  131. data/spec_app/vendor/assets/bower_components/jasmine-jquery/bower.json +0 -15
  132. data/spec_app/vendor/assets/bower_components/jasmine-jquery/package.json +0 -35
  133. data/spec_app/vendor/assets/bower_components/jasmine-jquery/spec/fixtures/fixture_with_checkbox_with_checked.html +0 -6
  134. data/spec_app/vendor/assets/bower_components/jasmine-jquery/spec/fixtures/fixture_with_javascript.html +0 -1
  135. data/spec_app/vendor/assets/bower_components/jasmine-jquery/spec/fixtures/fixture_with_javascript_block.html +0 -1
  136. data/spec_app/vendor/assets/bower_components/jasmine-jquery/spec/fixtures/javascripts/jasmine_javascript_click.js +0 -1
  137. data/spec_app/vendor/assets/bower_components/jasmine-jquery/spec/fixtures/javascripts/jasmine_javascript_hover.js +0 -1
  138. data/spec_app/vendor/assets/bower_components/jasmine-jquery/spec/fixtures/json/jasmine_json_test.json +0 -1
  139. data/spec_app/vendor/assets/bower_components/jasmine-jquery/spec/fixtures/real_non_mocked_fixture.html +0 -1
  140. data/spec_app/vendor/assets/bower_components/jasmine-jquery/spec/fixtures/real_non_mocked_fixture_style.css +0 -1
  141. data/spec_app/vendor/assets/bower_components/jasmine-jquery/spec/suites/jasmine-jquery-spec.js +0 -1842
  142. data/spec_app/vendor/assets/bower_components/jquery/.bower.json +0 -38
  143. data/spec_app/vendor/assets/bower_components/jquery/MIT-LICENSE.txt +0 -21
  144. data/spec_app/vendor/assets/bower_components/jquery/bower.json +0 -28
  145. data/spec_app/vendor/assets/bower_components/jquery/dist/jquery.js +0 -9210
  146. data/spec_app/vendor/assets/bower_components/jquery/dist/jquery.min.js +0 -5
  147. data/spec_app/vendor/assets/bower_components/jquery/dist/jquery.min.map +0 -1
  148. data/spec_app/vendor/assets/bower_components/jquery/src/ajax/jsonp.js +0 -89
  149. data/spec_app/vendor/assets/bower_components/jquery/src/ajax/load.js +0 -75
  150. data/spec_app/vendor/assets/bower_components/jquery/src/ajax/parseJSON.js +0 -13
  151. data/spec_app/vendor/assets/bower_components/jquery/src/ajax/parseXML.js +0 -28
  152. data/spec_app/vendor/assets/bower_components/jquery/src/ajax/script.js +0 -64
  153. data/spec_app/vendor/assets/bower_components/jquery/src/ajax/var/nonce.js +0 -5
  154. data/spec_app/vendor/assets/bower_components/jquery/src/ajax/var/rquery.js +0 -3
  155. data/spec_app/vendor/assets/bower_components/jquery/src/ajax/xhr.js +0 -136
  156. data/spec_app/vendor/assets/bower_components/jquery/src/ajax.js +0 -786
  157. data/spec_app/vendor/assets/bower_components/jquery/src/attributes/attr.js +0 -141
  158. data/spec_app/vendor/assets/bower_components/jquery/src/attributes/classes.js +0 -158
  159. data/spec_app/vendor/assets/bower_components/jquery/src/attributes/prop.js +0 -94
  160. data/spec_app/vendor/assets/bower_components/jquery/src/attributes/support.js +0 -35
  161. data/spec_app/vendor/assets/bower_components/jquery/src/attributes/val.js +0 -161
  162. data/spec_app/vendor/assets/bower_components/jquery/src/attributes.js +0 -11
  163. data/spec_app/vendor/assets/bower_components/jquery/src/callbacks.js +0 -205
  164. data/spec_app/vendor/assets/bower_components/jquery/src/core/access.js +0 -60
  165. data/spec_app/vendor/assets/bower_components/jquery/src/core/init.js +0 -123
  166. data/spec_app/vendor/assets/bower_components/jquery/src/core/parseHTML.js +0 -39
  167. data/spec_app/vendor/assets/bower_components/jquery/src/core/ready.js +0 -97
  168. data/spec_app/vendor/assets/bower_components/jquery/src/core/var/rsingleTag.js +0 -4
  169. data/spec_app/vendor/assets/bower_components/jquery/src/core.js +0 -502
  170. data/spec_app/vendor/assets/bower_components/jquery/src/css/addGetHookIf.js +0 -22
  171. data/spec_app/vendor/assets/bower_components/jquery/src/css/curCSS.js +0 -57
  172. data/spec_app/vendor/assets/bower_components/jquery/src/css/defaultDisplay.js +0 -70
  173. data/spec_app/vendor/assets/bower_components/jquery/src/css/hiddenVisibleSelectors.js +0 -15
  174. data/spec_app/vendor/assets/bower_components/jquery/src/css/support.js +0 -96
  175. data/spec_app/vendor/assets/bower_components/jquery/src/css/swap.js +0 -28
  176. data/spec_app/vendor/assets/bower_components/jquery/src/css/var/cssExpand.js +0 -3
  177. data/spec_app/vendor/assets/bower_components/jquery/src/css/var/getStyles.js +0 -12
  178. data/spec_app/vendor/assets/bower_components/jquery/src/css/var/isHidden.js +0 -13
  179. data/spec_app/vendor/assets/bower_components/jquery/src/css/var/rmargin.js +0 -3
  180. data/spec_app/vendor/assets/bower_components/jquery/src/css/var/rnumnonpx.js +0 -5
  181. data/spec_app/vendor/assets/bower_components/jquery/src/css.js +0 -450
  182. data/spec_app/vendor/assets/bower_components/jquery/src/data/Data.js +0 -181
  183. data/spec_app/vendor/assets/bower_components/jquery/src/data/accepts.js +0 -20
  184. data/spec_app/vendor/assets/bower_components/jquery/src/data/var/data_priv.js +0 -5
  185. data/spec_app/vendor/assets/bower_components/jquery/src/data/var/data_user.js +0 -5
  186. data/spec_app/vendor/assets/bower_components/jquery/src/data.js +0 -178
  187. data/spec_app/vendor/assets/bower_components/jquery/src/deferred.js +0 -149
  188. data/spec_app/vendor/assets/bower_components/jquery/src/deprecated.js +0 -13
  189. data/spec_app/vendor/assets/bower_components/jquery/src/dimensions.js +0 -50
  190. data/spec_app/vendor/assets/bower_components/jquery/src/effects/Tween.js +0 -114
  191. data/spec_app/vendor/assets/bower_components/jquery/src/effects/animatedSelector.js +0 -13
  192. data/spec_app/vendor/assets/bower_components/jquery/src/effects.js +0 -648
  193. data/spec_app/vendor/assets/bower_components/jquery/src/event/ajax.js +0 -13
  194. data/spec_app/vendor/assets/bower_components/jquery/src/event/alias.js +0 -39
  195. data/spec_app/vendor/assets/bower_components/jquery/src/event/support.js +0 -9
  196. data/spec_app/vendor/assets/bower_components/jquery/src/event.js +0 -868
  197. data/spec_app/vendor/assets/bower_components/jquery/src/exports/amd.js +0 -24
  198. data/spec_app/vendor/assets/bower_components/jquery/src/exports/global.js +0 -32
  199. data/spec_app/vendor/assets/bower_components/jquery/src/intro.js +0 -44
  200. data/spec_app/vendor/assets/bower_components/jquery/src/jquery.js +0 -37
  201. data/spec_app/vendor/assets/bower_components/jquery/src/manipulation/_evalUrl.js +0 -18
  202. data/spec_app/vendor/assets/bower_components/jquery/src/manipulation/support.js +0 -32
  203. data/spec_app/vendor/assets/bower_components/jquery/src/manipulation/var/rcheckableType.js +0 -3
  204. data/spec_app/vendor/assets/bower_components/jquery/src/manipulation.js +0 -580
  205. data/spec_app/vendor/assets/bower_components/jquery/src/offset.js +0 -207
  206. data/spec_app/vendor/assets/bower_components/jquery/src/outro.js +0 -1
  207. data/spec_app/vendor/assets/bower_components/jquery/src/queue/delay.js +0 -22
  208. data/spec_app/vendor/assets/bower_components/jquery/src/queue.js +0 -142
  209. data/spec_app/vendor/assets/bower_components/jquery/src/selector-native.js +0 -172
  210. data/spec_app/vendor/assets/bower_components/jquery/src/selector-sizzle.js +0 -14
  211. data/spec_app/vendor/assets/bower_components/jquery/src/selector.js +0 -1
  212. data/spec_app/vendor/assets/bower_components/jquery/src/serialize.js +0 -111
  213. data/spec_app/vendor/assets/bower_components/jquery/src/sizzle/dist/sizzle.js +0 -2067
  214. data/spec_app/vendor/assets/bower_components/jquery/src/sizzle/dist/sizzle.min.js +0 -3
  215. data/spec_app/vendor/assets/bower_components/jquery/src/sizzle/dist/sizzle.min.map +0 -1
  216. data/spec_app/vendor/assets/bower_components/jquery/src/traversing/findFilter.js +0 -100
  217. data/spec_app/vendor/assets/bower_components/jquery/src/traversing/var/rneedsContext.js +0 -6
  218. data/spec_app/vendor/assets/bower_components/jquery/src/traversing.js +0 -199
  219. data/spec_app/vendor/assets/bower_components/jquery/src/var/arr.js +0 -3
  220. data/spec_app/vendor/assets/bower_components/jquery/src/var/class2type.js +0 -4
  221. data/spec_app/vendor/assets/bower_components/jquery/src/var/concat.js +0 -5
  222. data/spec_app/vendor/assets/bower_components/jquery/src/var/hasOwn.js +0 -5
  223. data/spec_app/vendor/assets/bower_components/jquery/src/var/indexOf.js +0 -5
  224. data/spec_app/vendor/assets/bower_components/jquery/src/var/pnum.js +0 -3
  225. data/spec_app/vendor/assets/bower_components/jquery/src/var/push.js +0 -5
  226. data/spec_app/vendor/assets/bower_components/jquery/src/var/rnotwhite.js +0 -3
  227. data/spec_app/vendor/assets/bower_components/jquery/src/var/slice.js +0 -5
  228. data/spec_app/vendor/assets/bower_components/jquery/src/var/strundefined.js +0 -3
  229. data/spec_app/vendor/assets/bower_components/jquery/src/var/support.js +0 -4
  230. data/spec_app/vendor/assets/bower_components/jquery/src/var/toString.js +0 -5
  231. data/spec_app/vendor/assets/bower_components/jquery/src/wrap.js +0 -79
  232. data/spec_app/vendor/assets/stylesheets/.keep +0 -0
data/dist/unpoly.js CHANGED
@@ -1,15 +1,19 @@
1
- (function() {
2
- var world;
3
-
4
- world = typeof global !== 'undefined' ? global : this;
5
-
6
1
 
7
- /**
8
- @module up
9
- */
2
+ /**
3
+ @module up
4
+ */
10
5
 
11
- world.up = {
12
- version: "0.32.0"
6
+ (function() {
7
+ this.up = {
8
+ version: "0.33.0",
9
+ renamedModule: function(oldName, newName) {
10
+ return typeof Object.defineProperty === "function" ? Object.defineProperty(up, oldName, {
11
+ get: function() {
12
+ up.log.warn("up." + oldName + " has been renamed to up." + newName);
13
+ return up[newName];
14
+ }
15
+ }) : void 0;
16
+ }
13
17
  };
14
18
 
15
19
  }).call(this);
@@ -26,6 +30,7 @@ that might save you from loading something like [Underscore.js](http://underscor
26
30
 
27
31
  (function() {
28
32
  var slice = [].slice,
33
+ hasProp = {}.hasOwnProperty,
29
34
  bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
30
35
 
31
36
  up.util = (function($) {
@@ -36,10 +41,16 @@ that might save you from loading something like [Underscore.js](http://underscor
36
41
  @function up.util.noop
37
42
  @experimental
38
43
  */
39
- var $createElementFromSelector, $createPlaceholder, ANIMATION_DEFERRED_KEY, DivertibleChain, ESCAPE_HTML_ENTITY_MAP, all, any, appendRequestData, cache, castedAttr, clientSize, compact, config, contains, copy, copyAttributes, createElement, createElementFromHtml, cssAnimate, detachWith, detect, documentHasVerticalScrollbar, each, escapeHtml, escapePressed, evalOption, except, extend, extractOptions, fail, findWithSelf, finishCssAnimate, fixedToAbsolute, forceCompositing, forceRepaint, horizontalScreenHalf, identity, intersect, isArray, isBlank, isDeferred, isDefined, isDetached, isElement, isFixed, isFormData, isFunction, isGiven, isHash, isJQuery, isMissing, isNull, isNumber, isObject, isPresent, isPromise, isStandardPort, isString, isUndefined, isUnmodifiedKeyEvent, isUnmodifiedMouseEvent, last, locationFromXhr, map, measure, memoize, merge, methodFromXhr, multiSelector, nextFrame, nonUpClasses, noop, normalizeMethod, normalizeUrl, nullJQuery, offsetParent, once, only, opacity, openConfig, option, options, parseUrl, pluckData, pluckKey, presence, presentAttr, previewable, promiseTimer, reject, remove, requestDataAsArray, requestDataAsQuery, requestDataFromForm, resolvableWhen, resolvedDeferred, resolvedPromise, scrollbarWidth, select, selectorForElement, sequence, setMissingAttrs, setTimer, submittedValue, temporaryCss, times, titleFromXhr, toArray, trim, unJQuery, uniq, unresolvableDeferred, unresolvablePromise, unwrapElement, whenReady;
44
+ var $createElementFromSelector, $createPlaceholder, ANIMATION_DEFERRED_KEY, DivertibleChain, ESCAPE_HTML_ENTITY_MAP, all, any, appendRequestData, assign, assignPolyfill, cache, castedAttr, clientSize, compact, config, contains, copy, copyAttributes, createElement, createElementFromHtml, cssAnimate, detachWith, detect, documentHasVerticalScrollbar, each, escapeHtml, escapePressed, evalOption, except, extractOptions, fail, findWithSelf, finishCssAnimate, fixedToAbsolute, flatten, forceCompositing, forceRepaint, horizontalScreenHalf, identity, intersect, isArray, isBlank, isDeferred, isDefined, isDetached, isElement, isFixed, isFormData, isFunction, isGiven, isHash, isJQuery, isMissing, isNull, isNumber, isObject, isPresent, isPromise, isResolvedPromise, isStandardPort, isString, isTruthy, isUndefined, isUnmodifiedKeyEvent, isUnmodifiedMouseEvent, last, locationFromXhr, map, margins, measure, memoize, merge, methodFromXhr, multiSelector, nextFrame, nonUpClasses, noop, normalizeMethod, normalizeUrl, nullJQuery, offsetParent, once, only, opacity, openConfig, option, options, parseUrl, pluckData, pluckKey, presence, presentAttr, previewable, promiseTimer, reject, rejectedPromise, remove, requestDataAsArray, requestDataAsQuery, requestDataFromForm, resolvableWhen, resolvedDeferred, resolvedPromise, scrollbarWidth, select, selectorForElement, sequence, setMissingAttrs, setTimer, submittedValue, temporaryCss, times, titleFromXhr, toArray, trim, unJQuery, uniq, unresolvableDeferred, unresolvablePromise, unwrapElement, whenReady;
40
45
  noop = $.noop;
41
46
 
42
47
  /**
48
+ Ensures that the given function can only be called a single time.
49
+ Subsequent calls will return the return value of the first call.
50
+
51
+ Note that this is a simple implementation that
52
+ doesn't distinguish between argument lists.
53
+
43
54
  @function up.util.memoize
44
55
  @internal
45
56
  */
@@ -294,16 +305,29 @@ that might save you from loading something like [Underscore.js](http://underscor
294
305
  return createElement('div', html);
295
306
  }
296
307
  };
308
+ assignPolyfill = function() {
309
+ var i, key, len, source, sources, target, value;
310
+ target = arguments[0], sources = 2 <= arguments.length ? slice.call(arguments, 1) : [];
311
+ for (i = 0, len = sources.length; i < len; i++) {
312
+ source = sources[i];
313
+ for (key in source) {
314
+ if (!hasProp.call(source, key)) continue;
315
+ value = source[key];
316
+ target[key] = value;
317
+ }
318
+ }
319
+ return target;
320
+ };
297
321
 
298
322
  /**
299
- Merge the contents of two or more objects together into the first object.
323
+ Merge the own properties of one or more `sources` into the `target` object.
300
324
 
301
- @function up.util.extend
325
+ @function up.util.assign
302
326
  @param {Object} target
303
327
  @param {Array<Object>} sources...
304
328
  @stable
305
329
  */
306
- extend = $.extend;
330
+ assign = Object.assign || assignPolyfill;
307
331
 
308
332
  /**
309
333
  Returns a new string with whitespace removed from the beginning
@@ -408,7 +432,7 @@ that might save you from loading something like [Underscore.js](http://underscor
408
432
 
409
433
  Note that empty strings or zero are *not* considered to be "missing".
410
434
 
411
- For the opposite of `up.util.isMissing` see [`up.util.isGiven`](/up.util.isGiven).
435
+ For the opposite of `up.util.isMissing()` see [`up.util.isGiven()`](/up.util.isGiven).
412
436
 
413
437
  @function up.util.isMissing
414
438
  @param object
@@ -424,7 +448,7 @@ that might save you from loading something like [Underscore.js](http://underscor
424
448
 
425
449
  Note that empty strings or zero *are* considered to be "given".
426
450
 
427
- For the opposite of `up.util.isGiven` see [`up.util.isMissing`](/up.util.isMissing).
451
+ For the opposite of `up.util.isGiven()` see [`up.util.isMissing()`](/up.util.isMissing).
428
452
 
429
453
  @function up.util.isGiven
430
454
  @param object
@@ -546,7 +570,7 @@ that might save you from loading something like [Underscore.js](http://underscor
546
570
  Returns whether the given argument is an object.
547
571
 
548
572
  This also returns `true` for functions, which may behave like objects in JavaScript.
549
- For an alternative that returns `false` for functions, see [`up.util.isHash`](/up.util.isHash).
573
+ For an alternative that returns `false` for functions, see [`up.util.isHash()`](/up.util.isHash).
550
574
 
551
575
  @function up.util.isObject
552
576
  @param object
@@ -659,7 +683,7 @@ that might save you from loading something like [Underscore.js](http://underscor
659
683
  if (isArray(object)) {
660
684
  return object.slice();
661
685
  } else if (isHash(object)) {
662
- return extend({}, object);
686
+ return assign({}, object);
663
687
  }
664
688
  };
665
689
 
@@ -690,7 +714,7 @@ that might save you from loading something like [Underscore.js](http://underscor
690
714
  merge = function() {
691
715
  var sources;
692
716
  sources = 1 <= arguments.length ? slice.call(arguments, 0) : [];
693
- return extend.apply(null, [{}].concat(slice.call(sources)));
717
+ return assign.apply(null, [{}].concat(slice.call(sources)));
694
718
  };
695
719
 
696
720
  /**
@@ -918,7 +942,7 @@ that might save you from loading something like [Underscore.js](http://underscor
918
942
  Waits for the given number of milliseconds, the nruns the given callback.
919
943
 
920
944
  If the number of milliseconds is zero, the callback is run in the current execution frame.
921
- See [`up.util.nextFrame`] for running a function in the next executation frame.
945
+ See [`up.util.nextFrame()`] for running a function in the next executation frame.
922
946
 
923
947
  @function up.util.setTimer
924
948
  @param {Number} millis
@@ -1128,7 +1152,7 @@ that might save you from loading something like [Underscore.js](http://underscor
1128
1152
  @internal
1129
1153
  */
1130
1154
  cssAnimate = function(elementOrSelector, lastFrame, opts) {
1131
- var $element, deferred, oldTransition, onTransitionEnd, transition, transitionFinished, transitionProperties, withoutCompositing;
1155
+ var $element, deferred, oldTransition, onTransitionEnd, transition, transitionProperties, withoutCompositing;
1132
1156
  $element = $(elementOrSelector);
1133
1157
  opts = options(opts, {
1134
1158
  duration: 300,
@@ -1148,27 +1172,18 @@ that might save you from loading something like [Underscore.js](http://underscor
1148
1172
  'transition-timing-function': opts.easing
1149
1173
  };
1150
1174
  oldTransition = $element.css(Object.keys(transition));
1151
- $element.addClass('up-animating');
1152
- transitionFinished = function() {
1153
- $element.removeClass('up-animating');
1154
- return $element.off('transitionend', onTransitionEnd);
1155
- };
1156
1175
  onTransitionEnd = function(event) {
1157
1176
  var completedProperty;
1158
1177
  completedProperty = event.originalEvent.propertyName;
1159
1178
  if (contains(transitionProperties, completedProperty)) {
1160
- deferred.resolve();
1161
- return transitionFinished();
1179
+ return deferred.resolve();
1162
1180
  }
1163
1181
  };
1164
1182
  $element.on('transitionend', onTransitionEnd);
1165
- deferred.then(transitionFinished);
1166
- withoutCompositing = forceCompositing($element);
1167
- $element.css(transition);
1168
- $element.css(lastFrame);
1169
- $element.data(ANIMATION_DEFERRED_KEY, deferred);
1170
1183
  deferred.then(function() {
1171
1184
  var hadTransitionBefore;
1185
+ $element.removeClass('up-animating');
1186
+ $element.off('transitionend', onTransitionEnd);
1172
1187
  $element.removeData(ANIMATION_DEFERRED_KEY);
1173
1188
  withoutCompositing();
1174
1189
  $element.css({
@@ -1180,6 +1195,11 @@ that might save you from loading something like [Underscore.js](http://underscor
1180
1195
  return $element.css(oldTransition);
1181
1196
  }
1182
1197
  });
1198
+ $element.addClass('up-animating');
1199
+ withoutCompositing = forceCompositing($element);
1200
+ $element.css(transition);
1201
+ $element.data(ANIMATION_DEFERRED_KEY, deferred);
1202
+ $element.css(lastFrame);
1183
1203
  return deferred;
1184
1204
  };
1185
1205
  ANIMATION_DEFERRED_KEY = 'up-animation-deferred';
@@ -1191,7 +1211,7 @@ that might save you from loading something like [Underscore.js](http://underscor
1191
1211
 
1192
1212
  Does nothing if the given element is not currently animating.
1193
1213
 
1194
- Also see [`up.motion.finish`](/up.motion.finish).
1214
+ Also see [`up.motion.finish()`](/up.motion.finish).
1195
1215
 
1196
1216
  @function up.util.finishCssAnimate
1197
1217
  @param {Element|jQuery|String} elementOrSelector
@@ -1206,6 +1226,21 @@ that might save you from loading something like [Underscore.js](http://underscor
1206
1226
  });
1207
1227
  };
1208
1228
 
1229
+ /**
1230
+ @internal
1231
+ */
1232
+ margins = function(selectorOrElement) {
1233
+ var $element, withUnits;
1234
+ $element = $(selectorOrElement);
1235
+ withUnits = $element.css(['margin-top', 'margin-right', 'margin-bottom', 'margin-left']);
1236
+ return {
1237
+ top: parseFloat(withUnits['margin-top']),
1238
+ right: parseFloat(withUnits['margin-right']),
1239
+ bottom: parseFloat(withUnits['margin-bottom']),
1240
+ left: parseFloat(withUnits['margin-left'])
1241
+ };
1242
+ };
1243
+
1209
1244
  /**
1210
1245
  Measures the given element.
1211
1246
 
@@ -1213,10 +1248,11 @@ that might save you from loading something like [Underscore.js](http://underscor
1213
1248
  @internal
1214
1249
  */
1215
1250
  measure = function($element, opts) {
1216
- var $context, box, contextCoords, coordinates, elementCoords;
1251
+ var $context, box, contextCoords, coordinates, elementCoords, mgs;
1217
1252
  opts = options(opts, {
1218
1253
  relative: false,
1219
- inner: false
1254
+ inner: false,
1255
+ includeMargin: false
1220
1256
  });
1221
1257
  if (opts.relative) {
1222
1258
  if (opts.relative === true) {
@@ -1248,6 +1284,13 @@ that might save you from loading something like [Underscore.js](http://underscor
1248
1284
  box.width = $element.outerWidth();
1249
1285
  box.height = $element.outerHeight();
1250
1286
  }
1287
+ if (opts.includeMargin) {
1288
+ mgs = margins($element);
1289
+ box.left -= mgs.left;
1290
+ box.top -= mgs.top;
1291
+ box.height += mgs.top + mgs.bottom;
1292
+ box.width += mgs.left + mgs.right;
1293
+ }
1251
1294
  return box;
1252
1295
  };
1253
1296
 
@@ -1412,13 +1455,16 @@ that might save you from loading something like [Underscore.js](http://underscor
1412
1455
  already resolved.
1413
1456
 
1414
1457
  @function up.util.resolvedDeferred
1458
+ @param {Array<Object>} [args...]
1459
+ The resolution values that will be passed to callbacks
1415
1460
  @return {Deferred}
1416
1461
  @stable
1417
1462
  */
1418
1463
  resolvedDeferred = function() {
1419
- var deferred;
1464
+ var args, deferred;
1465
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
1420
1466
  deferred = $.Deferred();
1421
- deferred.resolve();
1467
+ deferred.resolve.apply(deferred, args);
1422
1468
  return deferred;
1423
1469
  };
1424
1470
 
@@ -1426,11 +1472,52 @@ that might save you from loading something like [Underscore.js](http://underscor
1426
1472
  Returns a promise that is already resolved.
1427
1473
 
1428
1474
  @function up.util.resolvedPromise
1475
+ @param {Array<Object>} [args...]
1476
+ The resolution values that will be passed to callbacks
1429
1477
  @return {Promise}
1430
1478
  @stable
1431
1479
  */
1432
1480
  resolvedPromise = function() {
1433
- return resolvedDeferred().promise();
1481
+ var args;
1482
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
1483
+ return resolvedDeferred.apply(null, args).promise();
1484
+ };
1485
+
1486
+ /**
1487
+ Returns a promise that is already rejected.
1488
+
1489
+ @function up.util.rejectedPromise
1490
+ @param {Array<Object>} [args...]
1491
+ The rejection values that will be passed to callbacks
1492
+ @return {Promise}
1493
+ @stable
1494
+ */
1495
+ rejectedPromise = function() {
1496
+ var args, deferred;
1497
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
1498
+ deferred = $.Deferred();
1499
+ deferred.reject.apply(deferred, args);
1500
+ return deferred.promise();
1501
+ };
1502
+
1503
+ /**
1504
+ Returns whether the given argument is a resolved jQuery promise.
1505
+
1506
+ @return {Boolean}
1507
+ @internal
1508
+ */
1509
+ isResolvedPromise = function(promise) {
1510
+ return isPromise(promise) && (typeof promise.state === "function" ? promise.state() : void 0) === 'resolved';
1511
+ };
1512
+
1513
+ /**
1514
+ Returns whether the given argument is a resolved jQuery promise.
1515
+
1516
+ @return {Boolean}
1517
+ @internal
1518
+ */
1519
+ isResolvedPromise = function(promise) {
1520
+ return isPromise(promise) && (typeof promise.state === "function" ? promise.state() : void 0) === 'resolved';
1434
1521
  };
1435
1522
 
1436
1523
  /**
@@ -1789,7 +1876,7 @@ that might save you from loading something like [Underscore.js](http://underscor
1789
1876
  if (isFunction(newOptions)) {
1790
1877
  newOptions = newOptions();
1791
1878
  }
1792
- return extend(hash, newOptions);
1879
+ return assign(hash, newOptions);
1793
1880
  };
1794
1881
  hash.reset();
1795
1882
  return hash;
@@ -2274,6 +2361,33 @@ that might save you from loading something like [Underscore.js](http://underscor
2274
2361
  $insertion.replaceWith($new);
2275
2362
  return $old;
2276
2363
  };
2364
+
2365
+ /**
2366
+ Flattens the given `array` a single level deep.
2367
+
2368
+ @function up.util.flatten
2369
+ @param {Array} array
2370
+ An array which might contain other arrays
2371
+ @return {Array}
2372
+ The flattened array
2373
+ @internal
2374
+ */
2375
+ flatten = function(array) {
2376
+ var flattened, i, len, object;
2377
+ flattened = [];
2378
+ for (i = 0, len = array.length; i < len; i++) {
2379
+ object = array[i];
2380
+ if (isArray(object)) {
2381
+ flattened = flattened.concat(object);
2382
+ } else {
2383
+ flattened.push(object);
2384
+ }
2385
+ }
2386
+ return flattened;
2387
+ };
2388
+ isTruthy = function(object) {
2389
+ return !!object;
2390
+ };
2277
2391
  return {
2278
2392
  isDetached: isDetached,
2279
2393
  requestDataAsArray: requestDataAsArray,
@@ -2292,7 +2406,8 @@ that might save you from loading something like [Underscore.js](http://underscor
2292
2406
  $createElementFromSelector: $createElementFromSelector,
2293
2407
  $createPlaceholder: $createPlaceholder,
2294
2408
  selectorForElement: selectorForElement,
2295
- extend: extend,
2409
+ assign: assign,
2410
+ assignPolyfill: assignPolyfill,
2296
2411
  copy: copy,
2297
2412
  merge: merge,
2298
2413
  options: options,
@@ -2325,6 +2440,7 @@ that might save you from loading something like [Underscore.js](http://underscor
2325
2440
  isElement: isElement,
2326
2441
  isJQuery: isJQuery,
2327
2442
  isPromise: isPromise,
2443
+ isResolvedPromise: isResolvedPromise,
2328
2444
  isDeferred: isDeferred,
2329
2445
  isHash: isHash,
2330
2446
  isArray: isArray,
@@ -2357,6 +2473,7 @@ that might save you from loading something like [Underscore.js](http://underscor
2357
2473
  unresolvableDeferred: unresolvableDeferred,
2358
2474
  unresolvablePromise: unresolvablePromise,
2359
2475
  resolvedPromise: resolvedPromise,
2476
+ rejectedPromise: rejectedPromise,
2360
2477
  resolvedDeferred: resolvedDeferred,
2361
2478
  resolvableWhen: resolvableWhen,
2362
2479
  setMissingAttrs: setMissingAttrs,
@@ -2386,7 +2503,9 @@ that might save you from loading something like [Underscore.js](http://underscor
2386
2503
  previewable: previewable,
2387
2504
  evalOption: evalOption,
2388
2505
  horizontalScreenHalf: horizontalScreenHalf,
2389
- detachWith: detachWith
2506
+ detachWith: detachWith,
2507
+ flatten: flatten,
2508
+ isTruthy: isTruthy
2390
2509
  };
2391
2510
  })($);
2392
2511
 
@@ -2395,11 +2514,20 @@ that might save you from loading something like [Underscore.js](http://underscor
2395
2514
  }).call(this);
2396
2515
 
2397
2516
  /**
2398
- Browser interface
2399
- =================
2517
+ Browser support
2518
+ ===============
2519
+
2520
+ Unpoly supports all modern browsers. It degrades gracefully with old versions of Internet Explorer:
2521
+
2522
+ IE 10, IE11, Edge
2523
+ : Full support
2524
+
2525
+ IE 9
2526
+ : Page updates that change browser history fall back to a classic page load.
2527
+
2528
+ IE 8
2529
+ : Unpoly prevents itself from booting itself, leaving you with a classic server-side application.
2400
2530
 
2401
- Some browser-interfacing methods and switches that
2402
- we can't currently get rid off.
2403
2531
 
2404
2532
  @class up.browser
2405
2533
  */
@@ -2583,7 +2711,7 @@ we can't currently get rid off.
2583
2711
  via [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState).
2584
2712
 
2585
2713
  When Unpoly is asked to change history on a browser that doesn't support
2586
- `pushState` (e.g. through [`up.follow`](/up.follow)), it will gracefully
2714
+ `pushState` (e.g. through [`up.follow()`](/up.follow)), it will gracefully
2587
2715
  fall back to a full page load.
2588
2716
 
2589
2717
  @function up.browser.canPushState
@@ -2599,7 +2727,7 @@ we can't currently get rid off.
2599
2727
  [CSS transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions).
2600
2728
 
2601
2729
  When Unpoly is asked to animate history on a browser that doesn't support
2602
- CSS transitions (e.g. through [`up.animate`](/up.animate)), it will skip the
2730
+ CSS transitions (e.g. through [`up.animate()`](/up.animate)), it will skip the
2603
2731
  animation by instantly jumping to the last frame.
2604
2732
 
2605
2733
  @function up.browser.canCssTransition
@@ -2785,7 +2913,7 @@ A better way to bind event listeners
2785
2913
  ------------------------------------
2786
2914
 
2787
2915
  Instead of using jQuery to bind an event handler to `document`, you can also
2788
- use the more convenient [`up.on`](/up.on):
2916
+ use the more convenient [`up.on()`](/up.on):
2789
2917
 
2790
2918
  up.on('click', 'button', function(event, $button) {
2791
2919
  // $button is a jQuery collection containing
@@ -2830,7 +2958,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2830
2958
  };
2831
2959
 
2832
2960
  /**
2833
- Converts an argument list for `up.on` to an argument list for `jQuery.on`.
2961
+ Converts an argument list for `up.on()` to an argument list for `jQuery.on`.
2834
2962
  This involves rewriting the listener signature in the last argument slot.
2835
2963
 
2836
2964
  @function upDescriptionToJqueryDescription
@@ -2888,7 +3016,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2888
3016
 
2889
3017
  \#\#\# Unbinding an event listener
2890
3018
 
2891
- `up.on` returns a function that unbinds the event listeners when called:
3019
+ `up.on()` returns a function that unbinds the event listeners when called:
2892
3020
 
2893
3021
  // Define the listener
2894
3022
  var listener = function() { ... };
@@ -2899,7 +3027,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2899
3027
  // Unbind the listener
2900
3028
  unbind()
2901
3029
 
2902
- There is also a function [`up.off`](/up.off) which you can use for the same purpose:
3030
+ There is also a function [`up.off()`](/up.off) which you can use for the same purpose:
2903
3031
 
2904
3032
  // Define the listener
2905
3033
  var listener = function() { ... };
@@ -2910,7 +3038,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2910
3038
  // Unbind the listener
2911
3039
  up.off('click', listener)
2912
3040
 
2913
- \#\#\# Migrating jQuery event handlers to `up.on`
3041
+ \#\#\# Migrating jQuery event handlers to `up.on()`
2914
3042
 
2915
3043
  Within the event handler, Unpoly will bind `this` to the
2916
3044
  native DOM element to help you migrate your existing jQuery code to
@@ -2922,7 +3050,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2922
3050
  $(this).something();
2923
3051
  });
2924
3052
 
2925
- ... you can simply copy the event handler to `up.on`:
3053
+ ... you can simply copy the event handler to `up.on()`:
2926
3054
 
2927
3055
  up.on('click', '.button', function() {
2928
3056
  $(this).something();
@@ -2959,7 +3087,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2959
3087
  };
2960
3088
 
2961
3089
  /**
2962
- Unbinds an event listener previously bound with [`up.on`](/up.on).
3090
+ Unbinds an event listener previously bound with [`up.on()`](/up.on).
2963
3091
 
2964
3092
  \#\#\# Example
2965
3093
 
@@ -2972,8 +3100,8 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2972
3100
 
2973
3101
  up.off('click', '.button', listener);
2974
3102
 
2975
- Note that you need to pass `up.off` a reference to the same listener function
2976
- that was passed to `up.on` earlier.
3103
+ Note that you need to pass `up.off()` a reference to the same listener function
3104
+ that was passed to `up.on()` earlier.
2977
3105
 
2978
3106
  @function up.off
2979
3107
  @stable
@@ -3005,7 +3133,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
3005
3133
  The event will be triggered as a jQuery event on `document`.
3006
3134
 
3007
3135
  Other code can subscribe to events with that name using
3008
- [`up.on`](/up.on) or by [binding a jQuery event listener](http://api.jquery.com/on/) to `document`.
3136
+ [`up.on()`](/up.on) or by [binding a jQuery event listener](http://api.jquery.com/on/) to `document`.
3009
3137
 
3010
3138
  \#\#\# Example
3011
3139
 
@@ -3111,7 +3239,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
3111
3239
  @param {Object} eventProps
3112
3240
  @param {String|Array} [eventProps.message]
3113
3241
  @return {Promise}
3114
- @experimental
3242
+ @internal
3115
3243
  */
3116
3244
  whenEmitted = function() {
3117
3245
  var args, deferred;
@@ -3170,7 +3298,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
3170
3298
 
3171
3299
  /**
3172
3300
  Makes a snapshot of the currently registered event listeners,
3173
- to later be restored through [`up.bus.reset`](/up.bus.reset).
3301
+ to later be restored through [`up.bus.reset()`](/up.bus.reset).
3174
3302
 
3175
3303
  @internal
3176
3304
  */
@@ -3358,7 +3486,7 @@ The output can be configured using the [`up.log.config`](/up.log.config) propert
3358
3486
  /**
3359
3487
  Prints a debugging message to the browser console.
3360
3488
 
3361
- @function up.debug
3489
+ @function up.log.debug
3362
3490
  @param {String} message
3363
3491
  @param {Array} args...
3364
3492
  @internal
@@ -3394,7 +3522,7 @@ The output can be configured using the [`up.log.config`](/up.log.config) propert
3394
3522
  warn = function() {
3395
3523
  var args, message;
3396
3524
  message = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
3397
- if (config.enabled && message) {
3525
+ if (message) {
3398
3526
  return b.puts.apply(b, ['warn', prefix(message)].concat(slice.call(args)));
3399
3527
  }
3400
3528
  };
@@ -3606,21 +3734,32 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
3606
3734
  Registers a function to be called whenever an element with
3607
3735
  the given selector is inserted into the DOM.
3608
3736
 
3737
+ Use compilers to activate your custom Javascript behavior on matching
3738
+ elements.
3739
+
3740
+ You should migrate your [jQuery ready callbacks](https://api.jquery.com/ready/)
3741
+ to compilers.
3742
+
3743
+
3744
+ \#\#\# Example
3745
+
3746
+ Let's say that any element with the `action` class should alert a message when clicked.
3747
+ We can implement this behavior as a compiler function that is called on all elements matching
3748
+ the `.action` selector:
3749
+
3609
3750
  up.compiler('.action', function($element) {
3610
- // your code here
3751
+ $element.on('click', function() {
3752
+ alert('Action was clicked!');
3753
+ });
3611
3754
  });
3612
3755
 
3613
- The functions will be called on elements matching `.action` when
3614
- the page loads, or whenever a matching fragment is [updated through Unpoly](/up.replace)
3615
- later.
3616
-
3617
- If you have used Angular.js before, this resembles
3618
- [Angular directives](https://docs.angularjs.org/guide/directive).
3756
+ The compiler function will be called once for each matching element when
3757
+ the page loads, or when a matching fragment is [inserted](/up.replace) later.
3619
3758
 
3620
3759
 
3621
3760
  \#\#\# Integrating jQuery plugins
3622
3761
 
3623
- `up.compiler` is a great way to integrate jQuery plugins.
3762
+ `up.compiler()` is a great way to integrate jQuery plugins.
3624
3763
  Let's say your JavaScript plugin wants you to call `lightboxify()`
3625
3764
  on links that should open a lightbox. You decide to
3626
3765
  do this for all links with an `lightbox` class:
@@ -3637,7 +3776,7 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
3637
3776
 
3638
3777
  \#\#\# Custom elements
3639
3778
 
3640
- You can use `up.compiler` to implement custom elements like this:
3779
+ You can use `up.compiler()` to implement custom elements like this:
3641
3780
 
3642
3781
  <clock></clock>
3643
3782
 
@@ -3714,7 +3853,7 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
3714
3853
  });
3715
3854
 
3716
3855
 
3717
- \#\#\# Migrating jQuery event handlers to `up.compiler`
3856
+ \#\#\# Migrating jQuery event handlers to `up.compiler()`
3718
3857
 
3719
3858
  Within the compiler, Unpoly will bind `this` to the
3720
3859
  native DOM element to help you migrate your existing jQuery code to
@@ -3728,9 +3867,9 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
3728
3867
  });
3729
3868
  });
3730
3869
 
3731
- ... you can reuse the event handler like this:
3870
+ ... you can reuse the callback function like this:
3732
3871
 
3733
- $('.action').compiler(function($element) {
3872
+ up.compiler('.action', function($element) {
3734
3873
  $element.on('click', function() {
3735
3874
  $(this).something();
3736
3875
  });
@@ -3764,7 +3903,7 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
3764
3903
  [clear global state](/up.compiler#cleaning-up-after-yourself)
3765
3904
  such as timeouts and event handlers bound to the document.
3766
3905
  The destructor is *not* expected to remove the element from the DOM, which
3767
- is already handled by [`up.destroy`](/up.destroy).
3906
+ is already handled by [`up.destroy()`](/up.destroy).
3768
3907
 
3769
3908
  The function may also return an array of destructor functions.
3770
3909
  @stable
@@ -3778,7 +3917,7 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
3778
3917
  /**
3779
3918
  Registers a [compiler](/up.compiler) that is run before all other compilers.
3780
3919
 
3781
- You can use `up.macro` to register a compiler that sets other UJS attributes.
3920
+ You can use `up.macro()` to register a compiler that sets other UJS attributes.
3782
3921
 
3783
3922
  \#\#\# Example
3784
3923
 
@@ -3810,10 +3949,10 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
3810
3949
  @param {String} selector
3811
3950
  The selector to match.
3812
3951
  @param {Object} options
3813
- See options for [`up.compiler`](/up.compiler).
3952
+ See options for [`up.compiler()`](/up.compiler).
3814
3953
  @param {Function($element, data)} compiler
3815
3954
  The function to call when a matching element is inserted.
3816
- See [`up.compiler`](/up.compiler) for details.
3955
+ See [`up.compiler()`](/up.compiler) for details.
3817
3956
  @stable
3818
3957
  */
3819
3958
  macro = function() {
@@ -3889,7 +4028,7 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
3889
4028
 
3890
4029
  /**
3891
4030
  Applies all compilers on the given element and its descendants.
3892
- Unlike [`up.hello`](/up.hello), this doesn't emit any events.
4031
+ Unlike [`up.hello()`](/up.hello), this doesn't emit any events.
3893
4032
 
3894
4033
  @function up.syntax.compile
3895
4034
  @param {Array<Element>} [options.skip]
@@ -3942,7 +4081,7 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
3942
4081
 
3943
4082
  /**
3944
4083
  Runs any destroyers on the given fragment and its descendants.
3945
- Unlike [`up.destroy`](/up.destroy), this doesn't emit any events
4084
+ Unlike [`up.destroy()`](/up.destroy), this doesn't emit any events
3946
4085
  and does not remove the element from the DOM.
3947
4086
 
3948
4087
  @function up.syntax.clean
@@ -3976,7 +4115,7 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
3976
4115
 
3977
4116
  <span class="person" up-data="{ age: 18, name: 'Bob' }">Bob</span>
3978
4117
 
3979
- Calling `up.syntax.data` will deserialize the JSON string into a JavaScript object:
4118
+ Calling `up.syntax.data()` will deserialize the JSON string into a JavaScript object:
3980
4119
 
3981
4120
  up.syntax.data('.person') // returns { age: 18, name: 'Bob' }
3982
4121
 
@@ -3992,7 +4131,7 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
3992
4131
  /**
3993
4132
  If an element annotated with [`up-data`] is inserted into the DOM,
3994
4133
  Up will parse the JSON and pass the resulting object to any matching
3995
- [`up.compiler`](/up.compiler) handlers.
4134
+ [`up.compiler()`](/up.compiler) handlers.
3996
4135
 
3997
4136
  For instance, a container for a [Google Map](https://developers.google.com/maps/documentation/javascript/tutorial)
3998
4137
  might attach the location and names of its marker pins:
@@ -4021,7 +4160,7 @@ or when a matching fragment is [inserted via AJAX](/up.link) later.
4021
4160
 
4022
4161
  Similarly, when an event is triggered on an element annotated with
4023
4162
  [`up-data`], the parsed object will be passed to any matching
4024
- [`up.on`](/up.on) handlers.
4163
+ [`up.on()`](/up.on) handlers.
4025
4164
 
4026
4165
  up.on('click', '.google-map', function(event, $element, pins) {
4027
4166
  console.log("There are %d pins on the clicked map", pins.length);
@@ -4128,8 +4267,8 @@ We need to work on this page:
4128
4267
  Returns the previous URL in the browser history.
4129
4268
 
4130
4269
  Note that this will only work reliably for history changes that
4131
- were applied by [`up.history.push`](/up.history.replace) or
4132
- [`up.history.replace`](/up.history.replace).
4270
+ were applied by [`up.history.push()`](/up.history.replace) or
4271
+ [`up.history.replace()`](/up.history.replace).
4133
4272
 
4134
4273
  @function up.history.previousUrl
4135
4274
  @internal
@@ -4175,8 +4314,8 @@ We need to work on this page:
4175
4314
  Unpoly will [`replace`](/up.replace) the document body with
4176
4315
  the body from that URL.
4177
4316
 
4178
- Note that functions like [`up.replace`](/up.replace) or
4179
- [`up.submit`](/up.submit) will automatically update the
4317
+ Note that functions like [`up.replace()`](/up.replace) or
4318
+ [`up.submit()`](/up.submit) will automatically update the
4180
4319
  browser's location bar for you.
4181
4320
 
4182
4321
  @function up.history.replace
@@ -4195,8 +4334,8 @@ We need to work on this page:
4195
4334
  Unpoly will [`replace`](/up.replace) the document body with
4196
4335
  the body from that URL.
4197
4336
 
4198
- Note that functions like [`up.replace`](/up.replace) or
4199
- [`up.submit`](/up.submit) will automatically update the
4337
+ Note that functions like [`up.replace()`](/up.replace) or
4338
+ [`up.submit()`](/up.submit) will automatically update the
4200
4339
  browser's location bar for you.
4201
4340
 
4202
4341
  Emits events [`up:history:push`](/up:history:push) and [`up:history:pushed`](/up:history:pushed).
@@ -4352,9 +4491,6 @@ We need to work on this page:
4352
4491
  up.on('up:framework:reset', reset);
4353
4492
  return {
4354
4493
  config: config,
4355
- defaults: function() {
4356
- return up.fail('up.history.defaults(...) no longer exists. Set values on he up.history.config property instead.');
4357
- },
4358
4494
  push: push,
4359
4495
  replace: replace,
4360
4496
  url: currentUrl,
@@ -4405,12 +4541,15 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4405
4541
  @param {Array} [config.fixedTop]
4406
4542
  An array of CSS selectors that find elements fixed to the
4407
4543
  top edge of the screen (using `position: fixed`).
4544
+ See [`[up-fixed="top"]`](/up-fixed-top) for details.
4408
4545
  @param {Array} [config.fixedBottom]
4409
4546
  An array of CSS selectors that find elements fixed to the
4410
4547
  bottom edge of the screen (using `position: fixed`).
4548
+ See [`[up-fixed="bottom"]`](/up-fixed-bottom) for details.
4411
4549
  @param {Array} [config.anchoredRight]
4412
4550
  An array of CSS selectors that find elements anchored to the
4413
- right edge of the screen (using `position: fixed` or `position: absolute`).
4551
+ right edge of the screen (using `right:0` with `position: fixed` or `position: absolute`).
4552
+ See [`[up-anchored="right"]`](/up-anchored-right) for details.
4414
4553
  @param {Number} [config.duration=0]
4415
4554
  The duration of the scrolling animation in milliseconds.
4416
4555
  Setting this to `0` will disable scrolling animations.
@@ -4466,7 +4605,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4466
4605
  duration: 250
4467
4606
  });
4468
4607
 
4469
- If the given viewport is already in a scroll animation when `up.scroll`
4608
+ If the given viewport is already in a scroll animation when `up.scroll()`
4470
4609
  is called a second time, the previous animation will instantly jump to the
4471
4610
  last frame before the next animation is started.
4472
4611
 
@@ -4548,7 +4687,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4548
4687
  if (!u.isPresent(anchorPosition)) {
4549
4688
  up.fail("Fixed element %o must have a CSS attribute %s", $obstructor.get(0), cssAttr);
4550
4689
  }
4551
- return parseInt(anchorPosition) + $obstructor.height();
4690
+ return parseFloat(anchorPosition) + $obstructor.height();
4552
4691
  };
4553
4692
  fixedTopBottoms = (function() {
4554
4693
  var i, len, ref, results;
@@ -4581,7 +4720,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4581
4720
  element are visible for the user.
4582
4721
 
4583
4722
  By default Unpoly will always reveal an element before
4584
- updating it with JavaScript functions like [`up.replace`](/up.replace)
4723
+ updating it with JavaScript functions like [`up.replace()`](/up.replace)
4585
4724
  or UJS behavior like [`[up-target]`](/a-up-target).
4586
4725
 
4587
4726
  \#\#\# How Unpoly finds the viewport
@@ -4599,9 +4738,9 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4599
4738
  Many applications have a navigation bar fixed to the top or bottom,
4600
4739
  obstructing the view on an element.
4601
4740
 
4602
- You can make `up.reveal` aware of these fixed elements
4741
+ You can make `up.reveal()` aware of these fixed elements
4603
4742
  so it can scroll the viewport far enough so the revealed element is fully visible.
4604
- To make `up.reveal` aware fixed elements you can either:
4743
+ To make `up.reveal()` aware fixed elements you can either:
4605
4744
 
4606
4745
  - give the element an attribute [`up-fixed="top"`](/up-fixed-top) or [`up-fixed="bottom"`](up-fixed-bottom)
4607
4746
  - [configure default options](/up.layout.config) for `fixedTop` or `fixedBottom`
@@ -4649,7 +4788,8 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4649
4788
  return newScrollPos + viewportHeight - obstruction.bottom - 1;
4650
4789
  };
4651
4790
  elementDims = u.measure($element, {
4652
- relative: $viewport
4791
+ relative: $viewport,
4792
+ includeMargin: true
4653
4793
  });
4654
4794
  firstElementRow = elementDims.top + offsetShift;
4655
4795
  lastElementRow = firstElementRow + Math.min(elementDims.height, config.substance) - 1;
@@ -4878,7 +5018,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4878
5018
  instead of scrolling `<body>`. As an alternative you can also push a selector
4879
5019
  matching your custom viewport to the [`up.layout.config.viewports`](/up.layout.config) array.
4880
5020
 
4881
- [`up.reveal`](/up.reveal) will always try to scroll the viewport closest
5021
+ [`up.reveal()`](/up.reveal) will always try to scroll the viewport closest
4882
5022
  to the element that is being revealed. By default this is the `<body>` element.
4883
5023
 
4884
5024
  \#\#\# Example
@@ -4925,11 +5065,16 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4925
5065
  */
4926
5066
 
4927
5067
  /**
4928
- Marks this element as a navigation fixed to the top edge of the screen
5068
+ Marks this element as being fixed to the top edge of the screen
4929
5069
  using `position: fixed`.
4930
5070
 
4931
- [`up.reveal`](/up.reveal) is aware of fixed elements and will scroll
4932
- the viewport far enough so the revealed element is fully visible.
5071
+ When [following a fragment link](/a-up-target), the viewport is scrolled
5072
+ so the targeted element becomes visible. By using this attribute you can make
5073
+ Unpoly aware of fixed elements that are obstructing the viewport contents.
5074
+ Unpoly will then scroll the viewport far enough that the revealed element is fully visible.
5075
+
5076
+ Instead of using this attribute,
5077
+ you can also configure a selector in [`up.layout.config.fixedTop`](/up.layout.config#fixedTop).
4933
5078
 
4934
5079
  \#\#\# Example
4935
5080
 
@@ -4940,11 +5085,16 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4940
5085
  */
4941
5086
 
4942
5087
  /**
4943
- Marks this element as a navigation fixed to the bottom edge of the screen
5088
+ Marks this element as being fixed to the bottom edge of the screen
4944
5089
  using `position: fixed`.
4945
5090
 
4946
- [`up.reveal`](/up.reveal) is aware of fixed elements and will scroll
4947
- the viewport far enough so the revealed element is fully visible.
5091
+ When [following a fragment link](/a-up-target), the viewport is scrolled
5092
+ so the targeted element becomes visible. By using this attribute you can make
5093
+ Unpoly aware of fixed elements that are obstructing the viewport contents.
5094
+ Unpoly will then scroll the viewport far enough that the revealed element is fully visible.
5095
+
5096
+ Instead of using this attribute,
5097
+ you can also configure a selector in [`up.layout.config.fixedBottom`](/up.layout.config#fixedBottom).
4948
5098
 
4949
5099
  \#\#\# Example
4950
5100
 
@@ -4955,15 +5105,35 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4955
5105
  */
4956
5106
 
4957
5107
  /**
4958
- Marks this element as a navigation anchored to the right edge of the screen
4959
- using `position: fixed` or `position:absolute`.
5108
+ Marks this element as being anchored to the right edge of the screen,
5109
+ typically fixed navigation bars.
5110
+
5111
+ Since [modal dialogs](/up.modal) hide the document scroll bar,
5112
+ elements anchored to the right appear to jump when the dialog opens or
5113
+ closes. Applying this attribute to anchored elements will make Unpoly
5114
+ aware of the issue and adjust the `right` property accordingly.
4960
5115
 
4961
- [`up.modal`](/up.modal) will move anchored elements to the left so they
4962
- don't appear to move when a modal dialog is opened or closed.
5116
+ You should give this attribute to layout elements
5117
+ with a CSS of `right: 0` with `position: fixed` or `position:absolute`.
5118
+
5119
+ Instead of giving this attribute to any affected element,
5120
+ you can also configure a selector in [`up.layout.config.anchoredRight`](/up.layout.config#anchoredRight).
4963
5121
 
4964
5122
  \#\#\# Example
4965
5123
 
4966
- <div class="bottom-nav" up-fixed="bottom">...</div>
5124
+ Here is the CSS for a navigation bar that is anchored to the top edge of the screen:
5125
+
5126
+ .top-nav {
5127
+ position: fixed;
5128
+ top: 0;
5129
+ left: 0;
5130
+ right: 0;
5131
+ }
5132
+
5133
+ By adding an `up-anchored="right"` attribute to the element, we can prevent the
5134
+ `right` edge from jumping when a [modal dialog](/up.modal) opens or closes:
5135
+
5136
+ <div class="top-nav" up-anchored="right">...</div>
4967
5137
 
4968
5138
  @selector [up-anchored=right]
4969
5139
  @stable
@@ -4975,9 +5145,6 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4975
5145
  scroll: scroll,
4976
5146
  finishScrolling: finishScrolling,
4977
5147
  config: config,
4978
- defaults: function() {
4979
- return up.fail('up.layout.defaults(...) no longer exists. Set values on he up.layout.config property instead.');
4980
- },
4981
5148
  viewportOf: viewportOf,
4982
5149
  viewportsWithin: viewportsWithin,
4983
5150
  viewports: viewports,
@@ -5000,32 +5167,40 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
5000
5167
  Fragment update API
5001
5168
  ===================
5002
5169
 
5003
- This module contains Unpoly's core functions to [change](/up.replace) or
5004
- [destroy](/up.destroy) page fragments via JavaScript.
5170
+ This module exposes a low-level Javascript API to [change](/up.replace) or
5171
+ [destroy](/up.destroy) page fragments.
5005
5172
 
5006
- Other Unpoly modules (like [`up.link`](/up.link) or [`up.modal`](/up.modal))
5007
- build upon this module to offer higher level API functions.
5008
-
5009
- @class up.flow
5173
+ Most of Unpoly's functionality (like [fragment links](/up.link) or [modals](/up.modal))
5174
+ is built from these functions. You can use them to extend Unpoly from your
5175
+ [custom Javascript](/up.syntax).
5176
+
5177
+ @class up.dom
5010
5178
  */
5011
5179
 
5012
5180
  (function() {
5013
- up.flow = (function($) {
5014
- var autofocus, config, destroy, emitFragmentInserted, emitFragmentKept, extract, filterScripts, findKeepPlan, findOldFragment, first, firstInLayer, firstInPriority, hello, isRealElement, layerOf, matchesLayer, oldFragmentNotFound, parseImplantSteps, parseResponse, processResponse, reload, replace, reset, resolveSelector, setSource, shouldExtractTitle, source, swapElements, transferKeepableElements, u, updateHistory;
5181
+ up.dom = (function($) {
5182
+ var autofocus, bestMatchingSteps, bestPreflightSelector, config, destroy, emitFragmentInserted, emitFragmentKept, extract, filterScripts, findKeepPlan, first, firstInLayer, firstInPriority, hello, isRealElement, layerOf, matchesLayer, parseResponse, processResponse, reload, replace, reset, resolveSelector, setSource, shouldExtractTitle, source, swapBody, swapElements, transferKeepableElements, u, updateHistoryAndTitle;
5015
5183
  u = up.util;
5016
5184
 
5017
5185
  /**
5018
5186
  Configures defaults for fragment insertion.
5019
5187
 
5020
- @property up.flow.config
5188
+ @property up.dom.config
5021
5189
  @param {Boolean} [options.runInlineScripts=true]
5022
5190
  Whether inline `<script>` tags inside inserted HTML fragments will be executed.
5023
5191
  @param {Boolean} [options.runLinkedScripts=false]
5024
5192
  Whether `<script src='...'>` tags inside inserted HTML fragments will fetch and execute
5025
5193
  the linked JavaScript file.
5194
+ @param {String} [options.fallbacks=['body']]
5195
+ When a fragment updates cannot find the requested element, Unpoly will try this list of alternative selectors.
5196
+ The first selector that matches an element in the current page (or response) will be used.
5197
+ @param {String} [options.fallbackTransition='none']
5198
+ The transition to use when using a fallback target.
5026
5199
  @stable
5027
5200
  */
5028
5201
  config = u.config({
5202
+ fallbacks: ['body'],
5203
+ fallbackTransition: 'none',
5029
5204
  runInlineScripts: true,
5030
5205
  runLinkedScripts: false
5031
5206
  });
@@ -5044,7 +5219,7 @@ build upon this module to offer higher level API functions.
5044
5219
  /**
5045
5220
  Returns the URL the given element was retrieved from.
5046
5221
 
5047
- @method up.flow.source
5222
+ @method up.dom.source
5048
5223
  @param {String|Element|jQuery} selectorOrElement
5049
5224
  @experimental
5050
5225
  */
@@ -5058,7 +5233,7 @@ build upon this module to offer higher level API functions.
5058
5233
  Resolves the given selector (which might contain `&` references)
5059
5234
  to an absolute selector.
5060
5235
 
5061
- @function up.flow.resolveSelector
5236
+ @function up.dom.resolveSelector
5062
5237
  @param {String|Element|jQuery} selectorOrElement
5063
5238
  @param {String|Element|jQuery} origin
5064
5239
  The element that this selector resolution is relative to.
@@ -5070,11 +5245,11 @@ build upon this module to offer higher level API functions.
5070
5245
  if (u.isString(selectorOrElement)) {
5071
5246
  selector = selectorOrElement;
5072
5247
  if (u.contains(selector, '&')) {
5073
- if (origin) {
5248
+ if (u.isPresent(origin)) {
5074
5249
  originSelector = u.selectorForElement(origin);
5075
5250
  selector = selector.replace(/\&/, originSelector);
5076
5251
  } else {
5077
- up.fail("Found origin reference (%s) in selector %s, but options.origin is missing", '&', selector);
5252
+ up.fail("Found origin reference (%s) in selector %s, but no origin was given", '&', selector);
5078
5253
  }
5079
5254
  }
5080
5255
  } else {
@@ -5168,6 +5343,8 @@ build upon this module to offer higher level API functions.
5168
5343
  The URL to fetch from the server.
5169
5344
  @param {String} [options.failTarget='body']
5170
5345
  The CSS selector to update if the server sends a non-200 status code.
5346
+ @param {String} [options.fallback]
5347
+ The selector to update when the original target was not found in the page.
5171
5348
  @param {String} [options.title]
5172
5349
  The document title after the replacement.
5173
5350
 
@@ -5217,23 +5394,32 @@ build upon this module to offer higher level API functions.
5217
5394
  same layer as the element that triggered the replacement (see `options.origin`).
5218
5395
  If that element is not known, or no match was found in that layer,
5219
5396
  Unpoly will search in other layers, starting from the topmost layer.
5397
+
5220
5398
  @return {Promise}
5221
5399
  A promise that will be resolved when the page has been updated.
5222
5400
  @stable
5223
5401
  */
5224
5402
  replace = function(selectorOrElement, url, options) {
5225
- var failTarget, onFailure, onSuccess, promise, request, target;
5226
- up.puts("Replacing %s from %s (%o)", selectorOrElement, url, options);
5403
+ var failTarget, failureOptions, onFailure, onSuccess, promise, request, successOptions, target;
5227
5404
  options = u.options(options);
5228
- target = resolveSelector(selectorOrElement, options.origin);
5229
- failTarget = u.option(options.failTarget, 'body');
5230
- failTarget = resolveSelector(failTarget, options.origin);
5231
5405
  if (!up.browser.canPushState() && options.history !== false) {
5232
5406
  if (!options.preload) {
5233
5407
  up.browser.loadPage(url, u.only(options, 'method', 'data'));
5234
5408
  }
5235
5409
  return u.unresolvablePromise();
5236
5410
  }
5411
+ options.inspectResponse = function() {
5412
+ return up.browser.loadPage(url, u.only(options, 'method', 'data'));
5413
+ };
5414
+ successOptions = u.merge(options, {
5415
+ humanizedTarget: 'target'
5416
+ });
5417
+ failureOptions = u.merge(options, {
5418
+ humanizedTarget: 'failure target',
5419
+ provideTarget: void 0
5420
+ });
5421
+ target = bestPreflightSelector(selectorOrElement, successOptions);
5422
+ failTarget = bestPreflightSelector(options.failTarget, failureOptions);
5237
5423
  request = {
5238
5424
  url: url,
5239
5425
  method: options.method,
@@ -5242,18 +5428,25 @@ build upon this module to offer higher level API functions.
5242
5428
  failTarget: failTarget,
5243
5429
  cache: options.cache,
5244
5430
  preload: options.preload,
5245
- headers: options.headers
5431
+ headers: options.headers,
5432
+ timeout: options.timeout
5246
5433
  };
5247
- options.inspectResponse = function() {
5248
- return up.browser.loadPage(url, u.only(options, 'method', 'data'));
5249
- };
5250
- promise = up.ajax(request);
5251
5434
  onSuccess = function(html, textStatus, xhr) {
5252
- return processResponse(true, target, url, request, xhr, options);
5435
+ return processResponse(true, target, url, request, xhr, successOptions);
5253
5436
  };
5254
5437
  onFailure = function(xhr, textStatus, errorThrown) {
5255
- return processResponse(false, failTarget, url, request, xhr, options);
5438
+ var promise, rejection;
5439
+ rejection = function() {
5440
+ return u.rejectedPromise(xhr, textStatus, errorThrown);
5441
+ };
5442
+ if (xhr.responseText) {
5443
+ promise = processResponse(false, failTarget, url, request, xhr, failureOptions);
5444
+ return promise.then(rejection, rejection);
5445
+ } else {
5446
+ return rejection();
5447
+ }
5256
5448
  };
5449
+ promise = up.ajax(request);
5257
5450
  promise = promise.then(onSuccess, onFailure);
5258
5451
  return promise;
5259
5452
  };
@@ -5262,7 +5455,7 @@ build upon this module to offer higher level API functions.
5262
5455
  @internal
5263
5456
  */
5264
5457
  processResponse = function(isSuccess, selector, url, request, xhr, options) {
5265
- var isReloadable, newRequest, query, urlFromServer;
5458
+ var isReloadable, newRequest, query, titleFromXhr, urlFromServer;
5266
5459
  options.method = u.normalizeMethod(u.option(u.methodFromXhr(xhr), options.method));
5267
5460
  isReloadable = options.method === 'GET';
5268
5461
  if (urlFromServer = u.locationFromXhr(xhr)) {
@@ -5311,8 +5504,8 @@ build upon this module to offer higher level API functions.
5311
5504
  options.history = false;
5312
5505
  }
5313
5506
  }
5314
- if (shouldExtractTitle(options)) {
5315
- options.title = u.titleFromXhr(xhr);
5507
+ if (shouldExtractTitle(options) && (titleFromXhr = u.titleFromXhr(xhr))) {
5508
+ options.title = titleFromXhr;
5316
5509
  }
5317
5510
  if (options.preload) {
5318
5511
  return u.resolvedPromise();
@@ -5356,7 +5549,7 @@ build upon this module to offer higher level API functions.
5356
5549
  @param {String|Element|jQuery} selectorOrElement
5357
5550
  @param {String} html
5358
5551
  @param {Object} [options]
5359
- See options for [`up.replace`](/up.replace).
5552
+ See options for [`up.replace()`](/up.replace).
5360
5553
  @return {Promise}
5361
5554
  A promise that will be resolved then the selector was updated
5362
5555
  and all animation has finished.
@@ -5364,79 +5557,60 @@ build upon this module to offer higher level API functions.
5364
5557
  */
5365
5558
  extract = function(selectorOrElement, html, options) {
5366
5559
  return up.log.group('Extracting %s from %d bytes of HTML', selectorOrElement, html != null ? html.length : void 0, function() {
5367
- var promise, response, selector;
5560
+ var i, implantSteps, len, response, responseTitle, step, swapPromises;
5368
5561
  options = u.options(options, {
5369
5562
  historyMethod: 'push',
5370
5563
  requireMatch: true,
5371
5564
  keep: true,
5372
5565
  layer: 'auto'
5373
5566
  });
5374
- selector = resolveSelector(selectorOrElement, options.origin);
5375
- response = parseResponse(html, options);
5376
- if (shouldExtractTitle(options)) {
5377
- options.title = response.title();
5378
- }
5379
5567
  if (options.saveScroll !== false) {
5380
5568
  up.layout.saveScroll();
5381
5569
  }
5382
- promise = u.resolvedPromise();
5383
- if (options.beforeSwap) {
5384
- promise = promise.then(options.beforeSwap);
5570
+ if (typeof options.provideTarget === "function") {
5571
+ options.provideTarget();
5385
5572
  }
5386
- promise = promise.then(function() {
5387
- return updateHistory(options);
5388
- });
5389
- promise = promise.then(function() {
5390
- var j, len, ref, step, swapPromises;
5391
- swapPromises = [];
5392
- ref = parseImplantSteps(selector, options);
5393
- for (j = 0, len = ref.length; j < len; j++) {
5394
- step = ref[j];
5395
- up.log.group('Updating %s', step.selector, function() {
5396
- var $new, $old, swapPromise;
5397
- $old = findOldFragment(step.selector, options);
5398
- $new = response.first(step.selector);
5399
- if ($old && $new) {
5400
- filterScripts($new, options);
5401
- swapPromise = swapElements($old, $new, step.pseudoClass, step.transition, options);
5402
- swapPromises.push(swapPromise);
5403
- return options.reveal = false;
5404
- }
5405
- });
5406
- }
5407
- return $.when.apply($, swapPromises);
5408
- });
5409
- if (options.afterSwap) {
5410
- promise = promise.then(options.afterSwap);
5573
+ response = parseResponse(html);
5574
+ implantSteps = bestMatchingSteps(selectorOrElement, response, options);
5575
+ if (shouldExtractTitle(options) && (responseTitle = response.title())) {
5576
+ options.title = responseTitle;
5411
5577
  }
5412
- return promise;
5578
+ updateHistoryAndTitle(options);
5579
+ swapPromises = [];
5580
+ for (i = 0, len = implantSteps.length; i < len; i++) {
5581
+ step = implantSteps[i];
5582
+ up.log.group('Updating %s', step.selector, function() {
5583
+ var swapPromise;
5584
+ filterScripts(step.$new, options);
5585
+ swapPromise = swapElements(step.$old, step.$new, step.pseudoClass, step.transition, options);
5586
+ swapPromises.push(swapPromise);
5587
+ return options.reveal = false;
5588
+ });
5589
+ }
5590
+ return $.when.apply($, swapPromises);
5413
5591
  });
5414
5592
  };
5415
- findOldFragment = function(selector, options) {
5416
- return first(selector, options) || oldFragmentNotFound(selector, options);
5593
+ bestPreflightSelector = function(selector, options) {
5594
+ var cascade;
5595
+ cascade = new up.dom.ExtractCascade(selector, options);
5596
+ return cascade.bestPreflightSelector();
5417
5597
  };
5418
- oldFragmentNotFound = function(selector, options) {
5419
- var layerProse, message;
5420
- if (options.requireMatch) {
5421
- layerProse = options.layer;
5422
- if (layerProse === 'auto') {
5423
- layerProse = 'page, modal or popup';
5424
- }
5425
- message = "Could not find selector %s in the current " + layerProse;
5426
- if (message[0] === '#') {
5427
- message += ' (avoid using IDs)';
5428
- }
5429
- return up.fail(message, selector);
5430
- }
5598
+ bestMatchingSteps = function(selector, response, options) {
5599
+ var cascade;
5600
+ options = u.merge(options, {
5601
+ response: response
5602
+ });
5603
+ cascade = new up.dom.ExtractCascade(selector, options);
5604
+ return cascade.bestMatchingSteps();
5431
5605
  };
5432
5606
  filterScripts = function($element, options) {
5433
- var $script, $scripts, isInline, isLinked, j, len, results, runInlineScripts, runLinkedScripts, script;
5607
+ var $script, $scripts, i, isInline, isLinked, len, results, runInlineScripts, runLinkedScripts, script;
5434
5608
  runInlineScripts = u.option(options.runInlineScripts, config.runInlineScripts);
5435
5609
  runLinkedScripts = u.option(options.runLinkedScripts, config.runLinkedScripts);
5436
5610
  $scripts = u.findWithSelf($element, 'script');
5437
5611
  results = [];
5438
- for (j = 0, len = $scripts.length; j < len; j++) {
5439
- script = $scripts[j];
5612
+ for (i = 0, len = $scripts.length; i < len; i++) {
5613
+ script = $scripts[i];
5440
5614
  $script = $(script);
5441
5615
  isLinked = u.isPresent($script.attr('src'));
5442
5616
  isInline = !isLinked;
@@ -5448,7 +5622,7 @@ build upon this module to offer higher level API functions.
5448
5622
  }
5449
5623
  return results;
5450
5624
  };
5451
- parseResponse = function(html, options) {
5625
+ parseResponse = function(html) {
5452
5626
  var htmlElement;
5453
5627
  htmlElement = u.createElementFromHtml(html);
5454
5628
  return {
@@ -5457,29 +5631,21 @@ build upon this module to offer higher level API functions.
5457
5631
  return (ref = htmlElement.querySelector("title")) != null ? ref.textContent : void 0;
5458
5632
  },
5459
5633
  first: function(selector) {
5460
- var child, inspectAction;
5634
+ var child;
5461
5635
  if (child = $.find(selector, htmlElement)[0]) {
5462
5636
  return $(child);
5463
- } else if (options.requireMatch) {
5464
- inspectAction = {
5465
- label: 'Open response',
5466
- callback: options.inspectResponse
5467
- };
5468
- return up.fail(["Could not find selector %s in response %o", selector, html], {
5469
- action: inspectAction
5470
- });
5471
5637
  }
5472
5638
  }
5473
5639
  };
5474
5640
  };
5475
- updateHistory = function(options) {
5641
+ updateHistoryAndTitle = function(options) {
5476
5642
  options = u.options(options, {
5477
5643
  historyMethod: 'push'
5478
5644
  });
5479
5645
  if (options.history) {
5480
5646
  up.history[options.historyMethod](options.history);
5481
5647
  }
5482
- if (options.title) {
5648
+ if (u.isString(options.title)) {
5483
5649
  return document.title = options.title;
5484
5650
  }
5485
5651
  };
@@ -5514,8 +5680,8 @@ build upon this module to offer higher level API functions.
5514
5680
  replacement = function() {
5515
5681
  options.keepPlans = transferKeepableElements($old, $new, options);
5516
5682
  if ($old.is('body')) {
5517
- up.syntax.clean($old);
5518
- $old.replaceWith($new);
5683
+ swapBody($old, $new);
5684
+ transition = false;
5519
5685
  } else {
5520
5686
  $new.insertBefore($old);
5521
5687
  }
@@ -5532,13 +5698,16 @@ build upon this module to offer higher level API functions.
5532
5698
  }
5533
5699
  return promise;
5534
5700
  };
5701
+ swapBody = function($oldBody, $newBody) {
5702
+ return $oldBody.replaceWith($newBody);
5703
+ };
5535
5704
  transferKeepableElements = function($old, $new, options) {
5536
- var $keepable, $keepableClone, j, keepPlans, keepable, len, plan, ref;
5705
+ var $keepable, $keepableClone, i, keepPlans, keepable, len, plan, ref;
5537
5706
  keepPlans = [];
5538
5707
  if (options.keep) {
5539
5708
  ref = $old.find('[up-keep]');
5540
- for (j = 0, len = ref.length; j < len; j++) {
5541
- keepable = ref[j];
5709
+ for (i = 0, len = ref.length; i < len; i++) {
5710
+ keepable = ref[i];
5542
5711
  $keepable = $(keepable);
5543
5712
  if (plan = findKeepPlan($keepable, $new, u.merge(options, {
5544
5713
  descendantsOnly: true
@@ -5670,42 +5839,13 @@ build upon this module to offer higher level API functions.
5670
5839
  parsed as a JSON object.
5671
5840
  @stable
5672
5841
  */
5673
- parseImplantSteps = function(selector, options) {
5674
- var comma, disjunction, i, j, len, pseudoClass, results, selectorAtom, selectorParts, transition, transitionArg, transitions;
5675
- transitionArg = options.transition || options.animation || 'none';
5676
- comma = /\ *,\ */;
5677
- disjunction = selector.split(comma);
5678
- if (u.isString(transitions)) {
5679
- transitions = transitionArg.split(comma);
5680
- } else {
5681
- transitions = [transitionArg];
5682
- }
5683
- results = [];
5684
- for (i = j = 0, len = disjunction.length; j < len; i = ++j) {
5685
- selectorAtom = disjunction[i];
5686
- selectorParts = selectorAtom.match(/^(.+?)(?:\:(before|after))?$/);
5687
- selectorParts || up.fail('Could not parse selector atom "%s"', selectorAtom);
5688
- selector = selectorParts[1];
5689
- if (selector === 'html') {
5690
- selector = 'body';
5691
- }
5692
- pseudoClass = selectorParts[2];
5693
- transition = transitions[i] || u.last(transitions);
5694
- results.push({
5695
- selector: selector,
5696
- pseudoClass: pseudoClass,
5697
- transition: transition
5698
- });
5699
- }
5700
- return results;
5701
- };
5702
5842
 
5703
5843
  /**
5704
5844
  Compiles a page fragment that has been inserted into the DOM
5705
5845
  by external code.
5706
5846
 
5707
5847
  **As long as you manipulate the DOM using Unpoly, you will never
5708
- need to call this method.** You only need to use `up.hello` if the
5848
+ need to call this method.** You only need to use `up.hello()` if the
5709
5849
  DOM is manipulated without Unpoly' involvement, e.g. by setting
5710
5850
  the `innerHTML` property or calling jQuery methods like
5711
5851
  `html`, `insertAfter` or `appendTo`:
@@ -5726,15 +5866,15 @@ build upon this module to offer higher level API functions.
5726
5866
  @stable
5727
5867
  */
5728
5868
  hello = function(selectorOrElement, options) {
5729
- var $element, j, keptElements, len, plan, ref;
5869
+ var $element, i, keptElements, len, plan, ref;
5730
5870
  $element = $(selectorOrElement);
5731
5871
  options = u.options(options, {
5732
5872
  keepPlans: []
5733
5873
  });
5734
5874
  keptElements = [];
5735
5875
  ref = options.keepPlans;
5736
- for (j = 0, len = ref.length; j < len; j++) {
5737
- plan = ref[j];
5876
+ for (i = 0, len = ref.length; i < len; i++) {
5877
+ plan = ref[i];
5738
5878
  emitFragmentKept(plan);
5739
5879
  keptElements.push(plan.$element);
5740
5880
  }
@@ -5805,24 +5945,30 @@ build upon this module to offer higher level API functions.
5805
5945
  @param {String} options.layer
5806
5946
  The name of the layer in which to find the element. Valid values are
5807
5947
  `auto`, `page`, `modal` and `popup`.
5808
- @param {}
5948
+ @param {String|Element|jQuery} [options.origin]
5949
+ An second element or selector that can be referenced as `&` in the first selector:
5950
+
5951
+ $input = $('input.email');
5952
+ up.first('.field:has(&)', $input); // returns the .field containing $input
5809
5953
  @return {jQuery|Undefined}
5810
5954
  The first element that is neither a ghost or being destroyed,
5811
5955
  or `undefined` if no such element was given.
5812
5956
  @experimental
5813
5957
  */
5814
5958
  first = function(selectorOrElement, options) {
5959
+ var resolved;
5815
5960
  options = u.options(options, {
5816
5961
  layer: 'auto'
5817
5962
  });
5963
+ resolved = resolveSelector(selectorOrElement, options.origin);
5818
5964
  if (options.layer === 'auto') {
5819
- return firstInPriority(selectorOrElement, options.origin);
5965
+ return firstInPriority(resolved, options.origin);
5820
5966
  } else {
5821
- return firstInLayer(selectorOrElement, options.layer);
5967
+ return firstInLayer(resolved, options.layer);
5822
5968
  }
5823
5969
  };
5824
5970
  firstInPriority = function(selectorOrElement, origin) {
5825
- var $match, j, layer, layers, len, originLayer;
5971
+ var $match, i, layer, layers, len, originLayer;
5826
5972
  layers = ['popup', 'modal', 'page'];
5827
5973
  $match = void 0;
5828
5974
  if (u.isPresent(origin)) {
@@ -5830,8 +5976,8 @@ build upon this module to offer higher level API functions.
5830
5976
  u.remove(layers, originLayer);
5831
5977
  layers.unshift(originLayer);
5832
5978
  }
5833
- for (j = 0, len = layers.length; j < len; j++) {
5834
- layer = layers[j];
5979
+ for (i = 0, len = layers.length; i < len; i++) {
5980
+ layer = layers[i];
5835
5981
  if ($match = firstInLayer(selectorOrElement, layer)) {
5836
5982
  break;
5837
5983
  }
@@ -5839,11 +5985,11 @@ build upon this module to offer higher level API functions.
5839
5985
  return $match;
5840
5986
  };
5841
5987
  firstInLayer = function(selectorOrElement, layer) {
5842
- var $element, $elements, $match, element, j, len;
5988
+ var $element, $elements, $match, element, i, len;
5843
5989
  $elements = $(selectorOrElement);
5844
5990
  $match = void 0;
5845
- for (j = 0, len = $elements.length; j < len; j++) {
5846
- element = $elements[j];
5991
+ for (i = 0, len = $elements.length; i < len; i++) {
5992
+ element = $elements[i];
5847
5993
  $element = $(element);
5848
5994
  if (isRealElement($element) && matchesLayer($element, layer)) {
5849
5995
  $match = $element;
@@ -5870,7 +6016,7 @@ build upon this module to offer higher level API functions.
5870
6016
  /**
5871
6017
  Destroys the given element or selector.
5872
6018
 
5873
- Takes care that all [`up.compiler`](/up.compiler) destructors, if any, are called.
6019
+ Takes care that all [`up.compiler()`](/up.compiler) destructors, if any, are called.
5874
6020
 
5875
6021
  The element is removed from the DOM.
5876
6022
  Note that if you choose to animate the element removal using `options.animate`,
@@ -5887,11 +6033,11 @@ build upon this module to offer higher level API functions.
5887
6033
  @param {String|Function} [options.animation='none']
5888
6034
  The animation to use before the element is removed from the DOM.
5889
6035
  @param {Number} [options.duration]
5890
- The duration of the animation. See [`up.animate`](/up.animate).
6036
+ The duration of the animation. See [`up.animate()`](/up.animate).
5891
6037
  @param {Number} [options.delay]
5892
- The delay before the animation starts. See [`up.animate`](/up.animate).
6038
+ The delay before the animation starts. See [`up.animate()`](/up.animate).
5893
6039
  @param {String} [options.easing]
5894
- The timing function that controls the animation's acceleration. [`up.animate`](/up.animate).
6040
+ The timing function that controls the animation's acceleration. [`up.animate()`](/up.animate).
5895
6041
  @return {Deferred}
5896
6042
  A promise that will be resolved once the element has been removed from the DOM.
5897
6043
  @stable
@@ -5914,7 +6060,7 @@ build upon this module to offer higher level API functions.
5914
6060
  });
5915
6061
  animateOptions = up.motion.animateOptions(options);
5916
6062
  $element.addClass('up-destroying');
5917
- updateHistory(options);
6063
+ updateHistoryAndTitle(options);
5918
6064
  animationDeferred = u.presence(options.animation, u.isDeferred) || up.motion.animate($element, options.animation, animateOptions);
5919
6065
  animationDeferred.then(function() {
5920
6066
  up.syntax.clean($element);
@@ -5973,7 +6119,7 @@ build upon this module to offer higher level API functions.
5973
6119
  @function up.reload
5974
6120
  @param {String|Element|jQuery} selectorOrElement
5975
6121
  @param {Object} [options]
5976
- See options for [`up.replace`](/up.replace)
6122
+ See options for [`up.replace()`](/up.replace)
5977
6123
  @param {String} [options.url]
5978
6124
  The URL from which to reload the fragment.
5979
6125
  This defaults to the URL from which the fragment was originally loaded.
@@ -6008,17 +6154,234 @@ build upon this module to offer higher level API functions.
6008
6154
  };
6009
6155
  })(jQuery);
6010
6156
 
6011
- up.replace = up.flow.replace;
6157
+ up.replace = up.dom.replace;
6158
+
6159
+ up.extract = up.dom.extract;
6160
+
6161
+ up.reload = up.dom.reload;
6162
+
6163
+ up.destroy = up.dom.destroy;
6164
+
6165
+ up.first = up.dom.first;
6166
+
6167
+ up.hello = up.dom.hello;
6168
+
6169
+ up.renamedModule('flow', 'dom');
6170
+
6171
+ }).call(this);
6172
+ (function() {
6173
+ var u,
6174
+ bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
6175
+
6176
+ u = up.util;
6177
+
6178
+ up.dom.ExtractCascade = (function() {
6179
+ function ExtractCascade(selector, options) {
6180
+ this.oldPlanNotFound = bind(this.oldPlanNotFound, this);
6181
+ this.matchingPlanNotFound = bind(this.matchingPlanNotFound, this);
6182
+ this.bestMatchingSteps = bind(this.bestMatchingSteps, this);
6183
+ this.bestPreflightSelector = bind(this.bestPreflightSelector, this);
6184
+ this.detectPlan = bind(this.detectPlan, this);
6185
+ this.matchingPlan = bind(this.matchingPlan, this);
6186
+ this.newPlan = bind(this.newPlan, this);
6187
+ this.oldPlan = bind(this.oldPlan, this);
6188
+ this.options = u.options(options, {
6189
+ humanizedTarget: 'selector',
6190
+ layer: 'auto'
6191
+ });
6192
+ this.candidates = this.buildCandidates(selector);
6193
+ this.plans = u.map(this.candidates, (function(_this) {
6194
+ return function(candidate, i) {
6195
+ var planOptions;
6196
+ planOptions = u.copy(_this.options);
6197
+ if (i > 0) {
6198
+ planOptions.transition = up.dom.config.fallbackTransition;
6199
+ }
6200
+ return new up.dom.ExtractPlan(candidate, planOptions);
6201
+ };
6202
+ })(this));
6203
+ }
6204
+
6205
+ ExtractCascade.prototype.buildCandidates = function(selector) {
6206
+ var candidates;
6207
+ candidates = [selector, this.options.fallback, up.dom.config.fallbacks];
6208
+ candidates = u.flatten(candidates);
6209
+ candidates = u.select(candidates, u.isTruthy);
6210
+ if (this.options.fallback === false || this.options.provideTarget) {
6211
+ candidates = [candidates[0]];
6212
+ }
6213
+ return candidates;
6214
+ };
6215
+
6216
+ ExtractCascade.prototype.oldPlan = function() {
6217
+ return this.detectPlan('oldExists');
6218
+ };
6219
+
6220
+ ExtractCascade.prototype.newPlan = function() {
6221
+ return this.detectPlan('newExists');
6222
+ };
6223
+
6224
+ ExtractCascade.prototype.matchingPlan = function() {
6225
+ return this.detectPlan('matchExists');
6226
+ };
6227
+
6228
+ ExtractCascade.prototype.detectPlan = function(checker) {
6229
+ return u.detect(this.plans, function(plan) {
6230
+ return plan[checker]();
6231
+ });
6232
+ };
6012
6233
 
6013
- up.extract = up.flow.extract;
6234
+ ExtractCascade.prototype.bestPreflightSelector = function() {
6235
+ var plan;
6236
+ if (this.options.provideTarget) {
6237
+ return this.plans[0].selector;
6238
+ } else if (plan = this.oldPlan()) {
6239
+ return plan.selector;
6240
+ } else {
6241
+ return this.oldPlanNotFound();
6242
+ }
6243
+ };
6014
6244
 
6015
- up.reload = up.flow.reload;
6245
+ ExtractCascade.prototype.bestMatchingSteps = function() {
6246
+ var plan;
6247
+ if (plan = this.matchingPlan()) {
6248
+ return plan.steps;
6249
+ } else {
6250
+ return this.matchingPlanNotFound();
6251
+ }
6252
+ };
6253
+
6254
+ ExtractCascade.prototype.matchingPlanNotFound = function() {
6255
+ var inspectAction, message;
6256
+ if (this.newPlan()) {
6257
+ return this.oldPlanNotFound();
6258
+ } else {
6259
+ if (this.oldPlan()) {
6260
+ message = "Could not find " + this.options.humanizedTarget + " in response";
6261
+ } else {
6262
+ message = "Could not match " + this.options.humanizedTarget + " in current page and response";
6263
+ }
6264
+ if (this.response && this.options.inspectResponse) {
6265
+ inspectAction = {
6266
+ label: 'Open response',
6267
+ callback: this.options.inspectResponse
6268
+ };
6269
+ }
6270
+ return up.fail([message + " (tried %o)", this.candidates], {
6271
+ action: inspectAction
6272
+ });
6273
+ }
6274
+ };
6275
+
6276
+ ExtractCascade.prototype.oldPlanNotFound = function() {
6277
+ var layerProse;
6278
+ layerProse = this.options.layer;
6279
+ if (layerProse === 'auto') {
6280
+ layerProse = 'page, modal or popup';
6281
+ }
6282
+ return up.fail("Could not find " + this.options.humanizedTarget + " in current " + layerProse + " (tried %o)", this.candidates);
6283
+ };
6284
+
6285
+ return ExtractCascade;
6286
+
6287
+ })();
6288
+
6289
+ }).call(this);
6290
+ (function() {
6291
+ var u,
6292
+ bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
6293
+
6294
+ u = up.util;
6295
+
6296
+ up.dom.ExtractPlan = (function() {
6297
+ function ExtractPlan(selector, options) {
6298
+ this.parseSteps = bind(this.parseSteps, this);
6299
+ this.matchExists = bind(this.matchExists, this);
6300
+ this.newExists = bind(this.newExists, this);
6301
+ this.oldExists = bind(this.oldExists, this);
6302
+ this.findNew = bind(this.findNew, this);
6303
+ this.findOld = bind(this.findOld, this);
6304
+ this.origin = options.origin;
6305
+ this.selector = up.dom.resolveSelector(selector, options.origin);
6306
+ this.transition = options.transition || options.animation || 'none';
6307
+ this.response = options.response;
6308
+ this.steps = this.parseSteps();
6309
+ }
6310
+
6311
+ ExtractPlan.prototype.findOld = function() {
6312
+ return u.each(this.steps, function(step) {
6313
+ return step.$old = up.dom.first(step.selector, this.options);
6314
+ });
6315
+ };
6316
+
6317
+ ExtractPlan.prototype.findNew = function() {
6318
+ return u.each(this.steps, (function(_this) {
6319
+ return function(step) {
6320
+ return step.$new = _this.response.first(step.selector);
6321
+ };
6322
+ })(this));
6323
+ };
6324
+
6325
+ ExtractPlan.prototype.oldExists = function() {
6326
+ this.findOld();
6327
+ return u.all(this.steps, function(step) {
6328
+ return step.$old;
6329
+ });
6330
+ };
6331
+
6332
+ ExtractPlan.prototype.newExists = function() {
6333
+ this.findNew();
6334
+ return u.all(this.steps, function(step) {
6335
+ return step.$new;
6336
+ });
6337
+ };
6338
+
6339
+ ExtractPlan.prototype.matchExists = function() {
6340
+ return this.oldExists() && this.newExists();
6341
+ };
6342
+
6343
+
6344
+ /**
6345
+ Example:
6346
+
6347
+ parseSelector('foo, bar:before', transition: 'cross-fade')
6348
+
6349
+ [
6350
+ { selector: 'foo', pseudoClass: undefined, transition: 'cross-fade' },
6351
+ { selector: 'bar', pseudoClass: 'before', transition: 'cross-fade' }
6352
+ ]
6353
+ */
6016
6354
 
6017
- up.destroy = up.flow.destroy;
6355
+ ExtractPlan.prototype.parseSteps = function() {
6356
+ var comma, disjunction, transitions;
6357
+ if (u.isString(this.transition)) {
6358
+ transitions = this.transition.split(comma);
6359
+ } else {
6360
+ transitions = [this.transition];
6361
+ }
6362
+ comma = /\ *,\ */;
6363
+ disjunction = this.selector.split(comma);
6364
+ return u.map(disjunction, function(literal, i) {
6365
+ var literalParts, pseudoClass, selector, transition;
6366
+ literalParts = literal.match(/^(.+?)(?:\:(before|after))?$/);
6367
+ literalParts || up.fail('Could not parse selector literal "%s"', literal);
6368
+ selector = literalParts[1];
6369
+ if (selector === 'html') {
6370
+ selector = 'body';
6371
+ }
6372
+ pseudoClass = literalParts[2];
6373
+ transition = transitions[i] || u.last(transitions);
6374
+ return {
6375
+ selector: selector,
6376
+ pseudoClass: pseudoClass,
6377
+ transition: transition
6378
+ };
6379
+ });
6380
+ };
6018
6381
 
6019
- up.first = up.flow.first;
6382
+ return ExtractPlan;
6020
6383
 
6021
- up.hello = up.flow.hello;
6384
+ })();
6022
6385
 
6023
6386
  }).call(this);
6024
6387
 
@@ -6050,8 +6413,8 @@ of the dialog by adding an [`up-animation`](/up-modal#up-animation) attribute to
6050
6413
  Unpoly ships with a number of [predefined transitions](/up.morph#named-transitions)
6051
6414
  and [predefined animations](/up.animate#named-animations).
6052
6415
 
6053
- You can define custom animations using [`up.transition`](/up.transition) and
6054
- [`up.animation`](/up.animation).
6416
+ You can define custom animations using [`up.transition()`](/up.transition) and
6417
+ [`up.animation()`](/up.animation).
6055
6418
 
6056
6419
  @class up.motion
6057
6420
  */
@@ -6149,7 +6512,7 @@ You can define custom animations using [`up.transition`](/up.transition) and
6149
6512
  | `move-from-right` | Moves the element leftwards from beyond the right edge of the screen until it reaches its current position |
6150
6513
  | `none` | An animation that has no visible effect. Sounds useless at first, but can save you a lot of `if` statements. |
6151
6514
 
6152
- You can define additional named animations using [`up.animation`](/up.animation).
6515
+ You can define additional named animations using [`up.animation()`](/up.animation).
6153
6516
 
6154
6517
  \#\#\# Animating CSS properties directly
6155
6518
 
@@ -6195,7 +6558,7 @@ You can define custom animations using [`up.transition`](/up.transition) and
6195
6558
  $element = $(elementOrSelector);
6196
6559
  finish($element);
6197
6560
  options = animateOptions(options);
6198
- if (animation === 'none' || animation === false || u.isMissing(animation)) {
6561
+ if (isNone(animation)) {
6199
6562
  return none();
6200
6563
  } else if (u.isFunction(animation)) {
6201
6564
  return assertIsDeferred(animation($element, options), animation);
@@ -6300,6 +6663,9 @@ You can define custom animations using [`up.transition`](/up.transition) and
6300
6663
  if (elementOrSelector == null) {
6301
6664
  elementOrSelector = '.up-animating';
6302
6665
  }
6666
+ if (!isEnabled()) {
6667
+ return;
6668
+ }
6303
6669
  $element = $(elementOrSelector);
6304
6670
  $animatingSubtree = u.findWithSelf($element, '.up-animating');
6305
6671
  u.finishCssAnimate($animatingSubtree);
@@ -6342,7 +6708,7 @@ You can define custom animations using [`up.transition`](/up.transition) and
6342
6708
  | `move-right` | Moves the first element rightwards until it exists the screen at the right edge. Simultaneously moves the second element rightwards from beyond the left edge of the screen until it reaches its current position. |
6343
6709
  | `none` | A transition that has no visible effect. Sounds useless at first, but can save you a lot of `if` statements. |
6344
6710
 
6345
- You can define additional named transitions using [`up.transition`](/up.transition).
6711
+ You can define additional named transitions using [`up.transition()`](/up.transition).
6346
6712
 
6347
6713
  You can also compose a transition from two [named animations](/named-animations).
6348
6714
  separated by a slash character (`/`):
@@ -6388,25 +6754,21 @@ You can define custom animations using [`up.transition`](/up.transition) and
6388
6754
  @stable
6389
6755
  */
6390
6756
  morph = function(source, target, transitionOrName, options) {
6391
- var $new, $old;
6392
- if (transitionOrName === 'none') {
6393
- transitionOrName = false;
6394
- }
6757
+ var $new, $old, willMorph;
6395
6758
  options = u.options(options);
6759
+ willMorph = isEnabled() && !isNone(transitionOrName);
6396
6760
  $old = $(source);
6397
6761
  $new = $(target);
6398
- ensureMorphable($old, transitionOrName);
6399
- ensureMorphable($new, transitionOrName);
6400
- return up.log.group((transitionOrName ? 'Morphing %o to %o (using %s, %o)' : void 0), $old.get(0), $new.get(0), transitionOrName, options, function() {
6762
+ return up.log.group((willMorph ? 'Morphing %o to %o (using %s, %o)' : void 0), $old.get(0), $new.get(0), transitionOrName, options, function() {
6401
6763
  var animation, parsedOptions, parts, transition;
6402
6764
  parsedOptions = u.only(options, 'reveal', 'restoreScroll', 'source');
6403
- parsedOptions = u.extend(parsedOptions, animateOptions(options));
6404
- if (isEnabled()) {
6405
- finish($old);
6406
- finish($new);
6407
- if (!transitionOrName) {
6408
- return skipMorph($old, $new, parsedOptions);
6409
- } else if (animation = animations[transitionOrName]) {
6765
+ parsedOptions = u.assign(parsedOptions, animateOptions(options));
6766
+ finish($old);
6767
+ finish($new);
6768
+ if (willMorph) {
6769
+ ensureMorphable($old);
6770
+ ensureMorphable($new);
6771
+ if (animation = animations[transitionOrName]) {
6410
6772
  skipMorph($old, $new, parsedOptions);
6411
6773
  return animate($new, animation, parsedOptions);
6412
6774
  } else if (transition = u.presence(transitionOrName, u.isFunction) || transitions[transitionOrName]) {
@@ -6429,9 +6791,9 @@ You can define custom animations using [`up.transition`](/up.transition) and
6429
6791
  }
6430
6792
  });
6431
6793
  };
6432
- ensureMorphable = function($element, transition) {
6794
+ ensureMorphable = function($element) {
6433
6795
  var element;
6434
- if (transition && $element.parents('body').length === 0) {
6796
+ if ($element.parents('body').length === 0) {
6435
6797
  element = $element.get(0);
6436
6798
  return up.fail("Can't morph a <%s> element (%o)", element.tagName, element);
6437
6799
  }
@@ -6511,10 +6873,10 @@ You can define custom animations using [`up.transition`](/up.transition) and
6511
6873
  )
6512
6874
  )
6513
6875
 
6514
- It is recommended that your transitions use [`up.animate`](/up.animate),
6876
+ It is recommended that your transitions use [`up.animate()`](/up.animate),
6515
6877
  passing along the `options` that were passed to you.
6516
6878
 
6517
- If you choose to *not* use `up.animate` and roll your own
6879
+ If you choose to *not* use `up.animate()` and roll your own
6518
6880
  logic instead, your code must honor the following contract:
6519
6881
 
6520
6882
  1. It must honor the passed options `{ delay, duration, easing }` if present
@@ -6523,7 +6885,7 @@ You can define custom animations using [`up.transition`](/up.transition) and
6523
6885
  4. The returned promise responds to a `resolve()` function that
6524
6886
  instantly jumps to the last transition frame and resolves the promise.
6525
6887
 
6526
- Calling [`up.animate`](/up.animate) with an object argument
6888
+ Calling [`up.animate()`](/up.animate) with an object argument
6527
6889
  will take care of all these points.
6528
6890
 
6529
6891
  @function up.transition
@@ -6546,10 +6908,10 @@ You can define custom animations using [`up.transition`](/up.transition) and
6546
6908
  })
6547
6909
 
6548
6910
  It is recommended that your definitions always end by calling
6549
- calling [`up.animate`](/up.animate) with an object argument, passing along
6911
+ calling [`up.animate()`](/up.animate) with an object argument, passing along
6550
6912
  the `options` that were passed to you.
6551
6913
 
6552
- If you choose to *not* use `up.animate` and roll your own
6914
+ If you choose to *not* use `up.animate()` and roll your own
6553
6915
  animation code instead, your code must honor the following contract:
6554
6916
 
6555
6917
  1. It must honor the passed options `{ delay, duration, easing }` if present
@@ -6558,7 +6920,7 @@ You can define custom animations using [`up.transition`](/up.transition) and
6558
6920
  4. The returned promise responds to a `resolve()` function that
6559
6921
  instantly jumps to the last animation frame and resolves the promise.
6560
6922
 
6561
- Calling [`up.animate`](/up.animate) with an object argument
6923
+ Calling [`up.animate()`](/up.animate) with an object argument
6562
6924
  will take care of all these points.
6563
6925
 
6564
6926
  @function up.animation
@@ -6612,7 +6974,7 @@ You can define custom animations using [`up.transition`](/up.transition) and
6612
6974
  @internal
6613
6975
  */
6614
6976
  isNone = function(animation) {
6615
- return animation === false || animation === 'none' || animation === none;
6977
+ return animation === false || animation === 'none' || u.isMissing(animation) || u.isResolvedPromise(animation);
6616
6978
  };
6617
6979
  animation('none', none);
6618
6980
  animation('fade-in', function($ghost, options) {
@@ -6732,9 +7094,6 @@ You can define custom animations using [`up.transition`](/up.transition) and
6732
7094
  animation: animation,
6733
7095
  config: config,
6734
7096
  isEnabled: isEnabled,
6735
- defaults: function() {
6736
- return up.fail('up.motion.defaults(...) no longer exists. Set values on he up.motion.config property instead.');
6737
- },
6738
7097
  none: none,
6739
7098
  when: resolvableWhen,
6740
7099
  prependCopy: prependCopy,
@@ -6753,24 +7112,27 @@ You can define custom animations using [`up.transition`](/up.transition) and
6753
7112
  }).call(this);
6754
7113
 
6755
7114
  /**
6756
- Caching and preloading
6757
- ======================
7115
+ AJAX acceleration
7116
+ =================
6758
7117
 
6759
- Unpoly caches server responses for a few minutes,
6760
- making requests to these URLs return instantly.
7118
+ Unpoly comes with a number of tricks to shorten the latency between browser and server.
6761
7119
 
6762
- All Unpoly functions and selectors go through this cache.
6763
- If you need to make cache-aware requests from your [custom JavaScript](/up.syntax),
6764
- use [`up.ajax`](/up.ajax).
7120
+ \#\#\# Server responses are cached by default
6765
7121
 
6766
- \#\#\# How the cache is cleared
7122
+ Unpoly caches server responses for a few minutes,
7123
+ making requests to these URLs return instantly.
7124
+ All Unpoly functions and selectors go through this cache, unless
7125
+ you explicitly pass a `{ cache: false }` option or set an `up-cache="false"` attribute.
6767
7126
 
6768
7127
  The cache holds up to 70 responses for 5 minutes. You can configure the cache size and expiry using
6769
- [`up.proxy.config`](/up.proxy.config), or clear the cache manually using [`up.proxy.clear`](/up.proxy.clear).
7128
+ [`up.proxy.config`](/up.proxy.config), or clear the cache manually using [`up.proxy.clear()`](/up.proxy.clear).
6770
7129
 
6771
7130
  Also the entire cache is cleared with every non-`GET` request (like `POST` or `PUT`).
6772
7131
 
6773
- \#\#\# Preloading
7132
+ If you need to make cache-aware requests from your [custom JavaScript](/up.syntax),
7133
+ use [`up.ajax()`](/up.ajax).
7134
+
7135
+ \#\#\# Preloading links
6774
7136
 
6775
7137
  Unpoly also lets you speed up reaction times by [preloading
6776
7138
  links](/up-preload) when the user hovers over the click area (or puts the mouse/finger
@@ -6782,6 +7144,13 @@ the user releases the mouse/finger.
6782
7144
  You can listen to the [`up:proxy:slow`](/up:proxy:slow) event to implement a spinner
6783
7145
  that appears during a long-running request.
6784
7146
 
7147
+ \#\#\# More acceleration
7148
+
7149
+ Other Unpoly modules contain even more tricks to outsmart network latency:
7150
+
7151
+ - [Instantaneous feedback for links that are currently loading](/up-active)
7152
+ - [Follow links on `mousedown` instead of `click`](/up-instant)
7153
+
6785
7154
  @class up.proxy
6786
7155
  */
6787
7156
 
@@ -6963,6 +7332,11 @@ that appears during a long-running request.
6963
7332
  @param {String} [request.url]
6964
7333
  You can omit the first string argument and pass the URL as
6965
7334
  a `request` property instead.
7335
+ @param {String} [request.timeout]
7336
+ A timeout in milliseconds for the request.
7337
+
7338
+ If [`up.proxy.config.maxRequests`](/up.proxy.config#maxRequests) is set, the timeout
7339
+ will not include the time spent waiting in the queue.
6966
7340
  @return
6967
7341
  A promise for the response that is API-compatible with the
6968
7342
  promise returned by [`jQuery.ajax`](http://api.jquery.com/jquery.ajax/).
@@ -6977,7 +7351,7 @@ that appears during a long-running request.
6977
7351
  }
6978
7352
  forceCache = options.cache === true;
6979
7353
  ignoreCache = options.cache === false;
6980
- request = u.only(options, 'url', 'method', 'data', 'target', 'headers', '_normalized');
7354
+ request = u.only(options, 'url', 'method', 'data', 'target', 'headers', 'timeout', '_normalized');
6981
7355
  request = normalizeRequest(request);
6982
7356
  pending = true;
6983
7357
  if (!isIdempotent(request) && !forceCache) {
@@ -7344,10 +7718,7 @@ that appears during a long-running request.
7344
7718
  isIdle: isIdle,
7345
7719
  isBusy: isBusy,
7346
7720
  isCachable: isCachable,
7347
- config: config,
7348
- defaults: function() {
7349
- return up.fail('up.proxy.defaults(...) no longer exists. Set values on he up.proxy.config property instead.');
7350
- }
7721
+ config: config
7351
7722
  };
7352
7723
  })(jQuery);
7353
7724
 
@@ -7356,10 +7727,15 @@ that appears during a long-running request.
7356
7727
  }).call(this);
7357
7728
 
7358
7729
  /**
7359
- Linking to page fragments
7360
- =========================
7730
+ Linking to fragments
7731
+ ====================
7732
+
7733
+ In a traditional web application, the entire page is destroyed and re-created when the
7734
+ user follows a link:
7735
+
7736
+ ![Traditional page flow](/images/tutorial/fragment_flow_vanilla.svg){:width="620px" class="picture has_border is_sepia has_padding"}
7361
7737
 
7362
- Standard HTML links are a poor fit for modern applications:
7738
+ This makes for an unfriendly experience:
7363
7739
 
7364
7740
  - State changes caused by AJAX updates get lost during the page transition.
7365
7741
  - Unsaved form changes get lost during the page transition.
@@ -7369,27 +7745,21 @@ Standard HTML links are a poor fit for modern applications:
7369
7745
  - The user sees a "flash" as the browser loads and renders the new page,
7370
7746
  even if large portions of the old and new page are the same (navigation, layout, etc.).
7371
7747
 
7372
- Unpoly fixes this by letting you annotate links with an [`up-target`](/a-up-target)
7748
+ Unpoly fixes this by letting you annotate links with an [`up-target`](/a-up-target)
7373
7749
  attribute. The value of this attribute is a CSS selector that indicates which page
7374
- fragment to update. The rest of the page will remain unchanged.
7750
+ fragment to update. The server **still renders full HTML pages**, but we only use
7751
+ the targeted ragments and discard the rest:
7375
7752
 
7753
+ ![Unpoly page flow](/images/tutorial/fragment_flow_unpoly.svg){:width="620px" class="picture has_border is_sepia has_padding"}
7376
7754
 
7377
- \#\#\# Example
7755
+ With this model, following links feel smooth. All transient DOM changes outside the updated fragment are preserved.
7756
+ Pages also load much faster since the DOM, CSS and Javascript environments do not need to be
7757
+ destroyed and recreated for every request.
7378
7758
 
7379
- Let's say we are rendering three pages with a tabbed navigation to switch between screens:
7380
7759
 
7760
+ ## Example
7381
7761
 
7382
- ```
7383
- /pages/a /pages/b /pages/c
7384
-
7385
- +---+---+---+ +---+---+---+ +---+---+---+
7386
- | A | B | C | | A | B | C | | A | B | C |
7387
- | +-------- (click) +---+ +---- (click) +---+---+ |
7388
- | | ======> | | ======> | |
7389
- | Page A | | Page B | | Page C |
7390
- | | | | | |
7391
- +-----------| +-----------| +-----------|
7392
- ```
7762
+ Let's say we are rendering three pages with a tabbed navigation to switch between screens:
7393
7763
 
7394
7764
  Your HTML could look like this:
7395
7765
 
@@ -7422,18 +7792,6 @@ With these [`up-target`](/a-up-target) annotations Unpoly only updates the targe
7422
7792
  The JavaScript environment will persist and the user will not see a white flash while the
7423
7793
  new page is loading.
7424
7794
 
7425
-
7426
- \#\#\# Read on
7427
-
7428
- - You can [animate page transitions](/up.motion) by definining animations for fragments as they enter or leave the screen.
7429
- - The `up-target` mechanism also works with [forms](/up.form).
7430
- - As you switch through pages, Unpoly will [update your browser's location bar and history](/up.history)
7431
- - You can [open fragments in popups or modal dialogs](/up.modal).
7432
- - You can give users [immediate feedback](/up.navigation) when a link is clicked or becomes current, without waiting for the server.
7433
- - [Controlling Unpoly pragmatically through JavaScript](/up.flow)
7434
- - [Defining custom tags](/up.syntax)
7435
-
7436
-
7437
7795
  @class up.link
7438
7796
  */
7439
7797
 
@@ -7457,7 +7815,7 @@ new page is loading.
7457
7815
  @param {String} [options.target='body']
7458
7816
  The selector to replace.
7459
7817
  @param {Object} [options]
7460
- See options for [`up.replace`](/up.replace)
7818
+ See options for [`up.replace()`](/up.replace)
7461
7819
  @stable
7462
7820
  */
7463
7821
  visit = function(url, options) {
@@ -7492,6 +7850,8 @@ new page is loading.
7492
7850
  @param {String} [options.failTarget]
7493
7851
  The selector to replace if the server responds with a non-200 status code.
7494
7852
  Defaults to the `up-fail-target` attribute on `link`, or to `body` if such an attribute does not exist.
7853
+ @param {String} [options.fallback]
7854
+ The selector to update when the original target was not found in the page.
7495
7855
  @param {String} [options.method='get']
7496
7856
  The HTTP method to use for the request.
7497
7857
  @param {String} [options.confirm]
@@ -7499,12 +7859,14 @@ new page is loading.
7499
7859
  before the link is followed.
7500
7860
  @param {Function|String} [options.transition]
7501
7861
  A transition function or name.
7862
+ @param {Function|String} [options.failTransition]
7863
+ The transition to use if the server responds with a non-200 status code.
7502
7864
  @param {Number} [options.duration]
7503
- The duration of the transition. See [`up.morph`](/up.morph).
7865
+ The duration of the transition. See [`up.morph()`](/up.morph).
7504
7866
  @param {Number} [options.delay]
7505
- The delay before the transition starts. See [`up.morph`](/up.morph).
7867
+ The delay before the transition starts. See [`up.morph()`](/up.morph).
7506
7868
  @param {String} [options.easing]
7507
- The timing function that controls the transition's acceleration. [`up.morph`](/up.morph).
7869
+ The timing function that controls the transition's acceleration. [`up.morph()`](/up.morph).
7508
7870
  @param {Element|jQuery|String} [options.reveal]
7509
7871
  Whether to reveal the target element within its viewport before updating.
7510
7872
  @param {Boolean} [options.restoreScroll]
@@ -7517,6 +7879,8 @@ new page is loading.
7517
7879
  @param {Object} [options.headers={}]
7518
7880
  An object of additional header key/value pairs to send along
7519
7881
  with the request.
7882
+ @param {Object} [options.timeout={}]
7883
+ A timeout in milliseconds for the request.
7520
7884
  @param {String} [options.layer='auto']
7521
7885
  The name of the layer that ought to be updated. Valid values are
7522
7886
  `auto`, `page`, `modal` and `popup`.
@@ -7534,8 +7898,9 @@ new page is loading.
7534
7898
  $link = $(linkOrSelector);
7535
7899
  options = u.options(options);
7536
7900
  url = u.option($link.attr('up-href'), $link.attr('href'));
7537
- target = u.option(options.target, $link.attr('up-target'), 'body');
7538
- options.failTarget = u.option(options.failTarget, $link.attr('up-fail-target'), 'body');
7901
+ target = u.option(options.target, $link.attr('up-target'));
7902
+ options.failTarget = u.option(options.failTarget, $link.attr('up-fail-target'));
7903
+ options.fallback = u.option(options.fallback, $link.attr('up-fallback'));
7539
7904
  options.transition = u.option(options.transition, u.castedAttr($link, 'up-transition'), 'none');
7540
7905
  options.failTransition = u.option(options.failTransition, u.castedAttr($link, 'up-fail-transition'), 'none');
7541
7906
  options.history = u.option(options.history, u.castedAttr($link, 'up-history'));
@@ -7597,7 +7962,7 @@ new page is loading.
7597
7962
  var handlerWithActiveMark;
7598
7963
  followVariantSelectors.push(selector);
7599
7964
  handlerWithActiveMark = function($link) {
7600
- return up.navigation.start($link, function() {
7965
+ return up.feedback.start($link, function() {
7601
7966
  return handler($link);
7602
7967
  });
7603
7968
  };
@@ -7674,7 +8039,7 @@ new page is loading.
7674
8039
 
7675
8040
  <a href="/posts/5" up-target=".main, .unread-count">Read post</a>
7676
8041
 
7677
- \#\#\# Appending or prepending instead of replacing
8042
+ \#\#\# Appending or prepending content
7678
8043
 
7679
8044
  By default Unpoly will replace the given selector with the same
7680
8045
  selector from a freshly fetched page. Instead of replacing you
@@ -7718,6 +8083,8 @@ new page is loading.
7718
8083
  @param {String} [up-fail-transition='none']
7719
8084
  The [transition](/up.motion) to use for morphing between the old and new elements
7720
8085
  when the server responds with a non-200 status code.
8086
+ @param {String} [up-fallback]
8087
+ The selector to update when the original target was not found in the page.
7721
8088
  @param {String} [up-href]
7722
8089
  The destination URL to follow.
7723
8090
  If omitted, the the link's `href` attribute will be used.
@@ -7798,10 +8165,12 @@ new page is loading.
7798
8165
 
7799
8166
  @param {String} [up-method='get']
7800
8167
  The HTTP method to use for the request.
7801
- @param {String} [up-transition='none']
7802
- The [transition](/up.motion) to use for morphing between the old and new elements.
7803
8168
  @param [up-fail-target='body']
7804
8169
  The selector to replace if the server responds with a non-200 status code.
8170
+ @param {String} [up-fallback]
8171
+ The selector to update when the original target was not found in the page.
8172
+ @param {String} [up-transition='none']
8173
+ The [transition](/up.motion) to use for morphing between the old and new elements.
7805
8174
  @param {String} [up-fail-transition='none']
7806
8175
  The [transition](/up.motion) to use for morphing between the old and new elements
7807
8176
  when the server responds with a non-200 status code.
@@ -7893,6 +8262,14 @@ new page is loading.
7893
8262
  <a class="close" href="/records">Close</a>
7894
8263
  </div>
7895
8264
 
8265
+ \#\#\# Limitations
8266
+
8267
+ Users will not be able to use the expanded area to open a context menu by right clicking,
8268
+ or to open the link in a new tab.
8269
+ To enable this, make the entire clickable area an actual `<a>` tag.
8270
+ [It's OK to put block elements inside an anchor tag](https://makandracards.com/makandra/43549-it-s-ok-to-put-block-elements-inside-an-a-tag).
8271
+
8272
+
7896
8273
  @selector [up-expand]
7897
8274
  @param {String} [up-expand]
7898
8275
  A CSS selector that defines which containing link should be expanded.
@@ -7967,7 +8344,7 @@ open dialogs with sub-forms, etc. all without losing form state.
7967
8344
 
7968
8345
  @property up.form.config
7969
8346
  @param {Number} [config.observeDelay=0]
7970
- The number of miliseconds to wait before [`up.observe`](/up.observe) runs the callback
8347
+ The number of miliseconds to wait before [`up.observe()`](/up.observe) runs the callback
7971
8348
  after the input value changes. Use this to limit how often the callback
7972
8349
  will be invoked for a fast typist.
7973
8350
  @param {Array} [config.validateTargets=['[up-fieldset]:has(&)', 'fieldset:has(&)', 'label:has(&)', 'form:has(&)']]
@@ -8018,11 +8395,14 @@ open dialogs with sub-forms, etc. all without losing form state.
8018
8395
  if none of these attributes are given.
8019
8396
  @param {String} [options.target]
8020
8397
  The selector to update when the form submission succeeds (server responds with status 200).
8021
- Defaults to the form's `up-target` attribute, or to `'body'`.
8398
+ Defaults to the form's `up-target` attribute.
8022
8399
  @param {String} [options.failTarget]
8023
8400
  The selector to update when the form submission fails (server responds with non-200 status).
8024
8401
  Defaults to the form's `up-fail-target` attribute, or to an auto-generated
8025
8402
  selector that matches the form itself.
8403
+ @param {String} [options.fallback]
8404
+ The selector to update when the original target was not found in the page.
8405
+ Defaults to the form's `up-fallback` attribute.
8026
8406
  @param {Boolean|String} [options.history=true]
8027
8407
  Successful form submissions will add a history entry and change the browser's
8028
8408
  location bar if the form either uses the `GET` method or the response redirected
@@ -8036,11 +8416,11 @@ open dialogs with sub-forms, etc. all without losing form state.
8036
8416
  The transition to use when a failed form submission updates the `options.failTarget` selector.
8037
8417
  Defaults to the form's `up-fail-transition` attribute, or to `options.transition`, or to `'none'`.
8038
8418
  @param {Number} [options.duration]
8039
- The duration of the transition. See [`up.morph`](/up.morph).
8419
+ The duration of the transition. See [`up.morph()`](/up.morph).
8040
8420
  @param {Number} [options.delay]
8041
- The delay before the transition starts. See [`up.morph`](/up.morph).
8421
+ The delay before the transition starts. See [`up.morph()`](/up.morph).
8042
8422
  @param {String} [options.easing]
8043
- The timing function that controls the transition's acceleration. [`up.morph`](/up.morph).
8423
+ The timing function that controls the transition's acceleration. [`up.morph()`](/up.morph).
8044
8424
  @param {Element|jQuery|String} [options.reveal]
8045
8425
  Whether to reveal the target element within its viewport.
8046
8426
  @param {Boolean} [options.restoreScroll]
@@ -8067,6 +8447,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8067
8447
  target = u.option(options.target, $form.attr('up-target'), 'body');
8068
8448
  url = u.option(options.url, $form.attr('action'), up.browser.url());
8069
8449
  options.failTarget = u.option(options.failTarget, $form.attr('up-fail-target')) || u.selectorForElement($form);
8450
+ options.fallback = u.option(options.fallback, $form.attr('up-fallback'));
8070
8451
  options.history = u.option(options.history, u.castedAttr($form, 'up-history'), true);
8071
8452
  options.transition = u.option(options.transition, u.castedAttr($form, 'up-transition'), 'none');
8072
8453
  options.failTransition = u.option(options.failTransition, u.castedAttr($form, 'up-fail-transition'), 'none');
@@ -8091,14 +8472,14 @@ open dialogs with sub-forms, etc. all without losing form state.
8091
8472
  return u.unresolvablePromise();
8092
8473
  }
8093
8474
  }
8094
- up.navigation.start($form);
8475
+ up.feedback.start($form);
8095
8476
  if (!(canAjaxSubmit && canHistoryOption)) {
8096
8477
  $form.get(0).submit();
8097
8478
  return u.unresolvablePromise();
8098
8479
  }
8099
8480
  promise = up.replace(target, url, options);
8100
8481
  promise.always(function() {
8101
- return up.navigation.stop($form);
8482
+ return up.feedback.stop($form);
8102
8483
  });
8103
8484
  return promise;
8104
8485
  };
@@ -8126,10 +8507,10 @@ open dialogs with sub-forms, etc. all without losing form state.
8126
8507
 
8127
8508
  Making network requests whenever a form field changes can cause
8128
8509
  [concurrency issues](https://makandracards.com/makandra/961-concurrency-issues-with-find-as-you-type-boxes).
8129
- Since `up.observe` can trigger many requests in a short period of time,
8510
+ Since `up.observe()` can trigger many requests in a short period of time,
8130
8511
  the responses might not arrive in the same order.
8131
8512
 
8132
- To mitigate this, `up.observe` will try to never run a callback
8513
+ To mitigate this, `up.observe()` will try to never run a callback
8133
8514
  before the previous callback has completed.
8134
8515
  For this your callback code must return a promise that resolves
8135
8516
  when your request completes.
@@ -8142,8 +8523,8 @@ open dialogs with sub-forms, etc. all without losing form state.
8142
8523
  return submitDone;
8143
8524
  });
8144
8525
 
8145
- Note that many Unpoly functions like [`up.submit`](/up.submit) or
8146
- [`up.replace`](/up.replace) return promises.
8526
+ Note that many Unpoly functions like [`up.submit()`](/up.submit) or
8527
+ [`up.replace()`](/up.replace) return promises.
8147
8528
 
8148
8529
  \#\#\# Debouncing
8149
8530
 
@@ -8190,6 +8571,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8190
8571
  callback = null;
8191
8572
  rawCallback = u.option(callbackArg, u.presentAttr($fields, 'up-observe'));
8192
8573
  if (u.isString(rawCallback)) {
8574
+ console.debug("**** RAW CALLBACK IS %o", rawCallback);
8193
8575
  callback = function(value, $field) {
8194
8576
  return eval(rawCallback);
8195
8577
  };
@@ -8255,7 +8637,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8255
8637
  @param {String|Element|jQuery} selectorOrElement
8256
8638
  The field or form to observe.
8257
8639
  @param {Object} [options]
8258
- See options for [`up.observe`](/up.observe)
8640
+ See options for [`up.observe()`](/up.observe)
8259
8641
  @return {Function}
8260
8642
  A destructor function that removes the observe watch when called.
8261
8643
  @stable
@@ -8264,7 +8646,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8264
8646
  return observe(selectorOrElement, options, function(value, $field) {
8265
8647
  var $form;
8266
8648
  $form = $field.closest('form');
8267
- return up.navigation.start($field, function() {
8649
+ return up.feedback.start($field, function() {
8268
8650
  return submit($form);
8269
8651
  });
8270
8652
  });
@@ -8275,7 +8657,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8275
8657
  if (u.isBlank(target)) {
8276
8658
  target || (target = u.detect(config.validateTargets, function(defaultTarget) {
8277
8659
  var resolvedDefault;
8278
- resolvedDefault = up.flow.resolveSelector(defaultTarget, options.origin);
8660
+ resolvedDefault = up.dom.resolveSelector(defaultTarget, options.origin);
8279
8661
  return $field.closest(resolvedDefault).length;
8280
8662
  }));
8281
8663
  }
@@ -8292,7 +8674,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8292
8674
  Performs a server-side validation of a form and update the form
8293
8675
  with validation messages.
8294
8676
 
8295
- `up.validate` submits the given field's form with an additional `X-Up-Validate`
8677
+ `up.validate()` submits the given field's form with an additional `X-Up-Validate`
8296
8678
  HTTP header. Upon seeing this header, the server is expected to validate (but not save)
8297
8679
  the form submission and render a new copy of the form with validation errors.
8298
8680
 
@@ -8438,7 +8820,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8438
8820
  The server response is searched for the selector given in `up-target`.
8439
8821
  The selector content is then [replaced](/up.replace) in the current page.
8440
8822
 
8441
- The programmatic variant of this is the [`up.submit`](/up.submit) function.
8823
+ The programmatic variant of this is the [`up.submit()`](/up.submit) function.
8442
8824
 
8443
8825
  \#\#\# Failed submission
8444
8826
 
@@ -8501,6 +8883,8 @@ open dialogs with sub-forms, etc. all without losing form state.
8501
8883
  The selector to [replace](/up.replace) if the form submission is not successful (non-200 status code).
8502
8884
  If omitted, Unpoly will replace the `<form>` tag itself, assuming that the
8503
8885
  server has echoed the form with validation errors.
8886
+ @param [up-fallback]
8887
+ The selector to replace if the server responds with a non-200 status code.
8504
8888
  @param {String} [up-transition]
8505
8889
  The animation to use when the form is replaced after a successful submission.
8506
8890
  @param {String} [up-fail-transition]
@@ -8537,11 +8921,14 @@ open dialogs with sub-forms, etc. all without losing form state.
8537
8921
  });
8538
8922
 
8539
8923
  /**
8540
- When a form field with this attribute is changed,
8541
- the form is validated on the server and is updated with
8542
- validation messages.
8924
+ When a form field with this attribute is changed, the form is validated on the server
8925
+ and is updated with validation messages.
8543
8926
 
8544
- The programmatic variant of this is the [`up.validate`](/up.validate) function.
8927
+ To validate the form, Unpoly will submit the form with an additional `X-Up-Validate` HTTP header.
8928
+ When seeing this header, the server is expected to validate (but not save)
8929
+ the form submission and render a new copy of the form with validation errors.
8930
+
8931
+ The programmatic variant of this is the [`up.validate()`](/up.validate) function.
8545
8932
 
8546
8933
  \#\#\# Example
8547
8934
 
@@ -8582,7 +8969,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8582
8969
 
8583
8970
  Whenever a field with `up-validate` changes, the form is POSTed to
8584
8971
  `/users` with an additional `X-Up-Validate` HTTP header.
8585
- Upon seeing this header, the server is expected to validate (but not save)
8972
+ When seeing this header, the server is expected to validate (but not save)
8586
8973
  the form submission and render a new copy of the form with validation errors.
8587
8974
 
8588
8975
  In Ruby on Rails the processing action should behave like this:
@@ -8637,7 +9024,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8637
9024
  With the Bootstrap bindings, Unpoly will also look
8638
9025
  for a container with the `form-group` class.
8639
9026
 
8640
- You can change this default behavior by setting `up.config.validateTargets`:
9027
+ You can change this default behavior by setting [`up.form.config.validateTargets`](/up.form.config#validateTargets):
8641
9028
 
8642
9029
  // Always update the entire form containing the current field ("&")
8643
9030
  up.form.config.validateTargets = ['form &']
@@ -8763,7 +9150,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8763
9150
 
8764
9151
  This is useful for observing text fields while the user is typing.
8765
9152
 
8766
- The programmatic variant of this is the [`up.observe`](/up.observe) function.
9153
+ The programmatic variant of this is the [`up.observe()`](/up.observe) function.
8767
9154
 
8768
9155
  \#\#\# Example
8769
9156
 
@@ -8801,7 +9188,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8801
9188
  The form field will be assigned a CSS class [`up-active`](/up-active)
8802
9189
  while the autosubmitted form is processing.
8803
9190
 
8804
- The programmatic variant of this is the [`up.autosubmit`](/up.autosubmit) function.
9191
+ The programmatic variant of this is the [`up.autosubmit()`](/up.autosubmit) function.
8805
9192
 
8806
9193
  \#\#\# Example
8807
9194
 
@@ -8942,8 +9329,9 @@ The HTML of a popup element is simply this:
8942
9329
  });
8943
9330
 
8944
9331
  /**
8945
- Returns the source URL for the fragment displayed
8946
- in the current popup, or `undefined` if no popup is open.
9332
+ Returns the URL from which the current popup's contents were loaded.
9333
+
9334
+ Returns `undefined` if no popup is open.
8947
9335
 
8948
9336
  @function up.popup.url
8949
9337
  @return {String}
@@ -9027,6 +9415,7 @@ The HTML of a popup element is simply this:
9027
9415
  Returns whether popup modal is currently open.
9028
9416
 
9029
9417
  @function up.popup.isOpen
9418
+ @return {Boolean}
9030
9419
  @stable
9031
9420
  */
9032
9421
  isOpen = function() {
@@ -9061,11 +9450,11 @@ The HTML of a popup element is simply this:
9061
9450
  @param {String} [options.animation]
9062
9451
  The animation to use when opening the popup.
9063
9452
  @param {Number} [options.duration]
9064
- The duration of the animation. See [`up.animate`](/up.animate).
9453
+ The duration of the animation. See [`up.animate()`](/up.animate).
9065
9454
  @param {Number} [options.delay]
9066
- The delay before the animation starts. See [`up.animate`](/up.animate).
9455
+ The delay before the animation starts. See [`up.animate()`](/up.animate).
9067
9456
  @param {String} [options.easing]
9068
- The timing function that controls the animation's acceleration. [`up.animate`](/up.animate).
9457
+ The timing function that controls the animation's acceleration. [`up.animate()`](/up.animate).
9069
9458
  @param {String} [options.method="GET"]
9070
9459
  Override the request method.
9071
9460
  @param {Boolean} [options.sticky=false]
@@ -9122,7 +9511,7 @@ The HTML of a popup element is simply this:
9122
9511
  state.coveredTitle = document.title;
9123
9512
  }
9124
9513
  state.sticky = options.sticky;
9125
- options.beforeSwap = function() {
9514
+ options.provideTarget = function() {
9126
9515
  return createFrame(target);
9127
9516
  };
9128
9517
  extractOptions = u.merge(options, {
@@ -9173,7 +9562,7 @@ The HTML of a popup element is simply this:
9173
9562
 
9174
9563
  @function up.popup.close
9175
9564
  @param {Object} options
9176
- See options for [`up.animate`](/up.animate).
9565
+ See options for [`up.animate()`](/up.animate).
9177
9566
  @return {Promise}
9178
9567
  A promise that will be resolved once the modal's close
9179
9568
  animation has finished.
@@ -9201,7 +9590,7 @@ The HTML of a popup element is simply this:
9201
9590
  duration: config.closeDuration,
9202
9591
  easing: config.closeEasing
9203
9592
  });
9204
- u.extend(options, animateOptions);
9593
+ u.assign(options, animateOptions);
9205
9594
  return up.bus.whenEmitted('up:popup:close', {
9206
9595
  message: 'Closing popup',
9207
9596
  $element: state.$popup
@@ -9252,6 +9641,8 @@ The HTML of a popup element is simply this:
9252
9641
 
9253
9642
  @methods up.popup.contains
9254
9643
  @param {String} elementOrSelector
9644
+ The element to test
9645
+ @return {Boolean}
9255
9646
  @stable
9256
9647
  */
9257
9648
  contains = function(elementOrSelector) {
@@ -9322,11 +9713,19 @@ The HTML of a popup element is simply this:
9322
9713
  up.bus.onEscape(closeAsap);
9323
9714
 
9324
9715
  /**
9325
- When an element with this attribute is clicked,
9326
- a currently open popup is closed.
9716
+ When this element is clicked, a currently open [popup](/up.popup) is closed.
9327
9717
 
9328
9718
  Does nothing if no popup is currently open.
9329
9719
 
9720
+ \#\#\# Example
9721
+
9722
+ Clickin on this `<span>` will close a currently open popup:
9723
+
9724
+ <span class='up-close'>Close this popup</span>
9725
+
9726
+ When a popup changes the current URL, you might need to deal with content being displayed
9727
+ as either a popup or a full page.
9728
+
9330
9729
  To make a link that closes the current popup, but follows to
9331
9730
  a fallback destination if no popup is open:
9332
9731
 
@@ -9632,7 +10031,7 @@ or function.
9632
10031
  if (u.documentHasVerticalScrollbar()) {
9633
10032
  $body = $('body');
9634
10033
  scrollbarWidth = u.scrollbarWidth();
9635
- bodyRightPadding = parseInt($body.css('padding-right'));
10034
+ bodyRightPadding = parseFloat($body.css('padding-right'));
9636
10035
  bodyRightShift = scrollbarWidth + bodyRightPadding;
9637
10036
  unshiftBody = u.temporaryCss($body, {
9638
10037
  'padding-right': bodyRightShift + "px",
@@ -9642,7 +10041,7 @@ or function.
9642
10041
  return up.layout.anchoredRight().each(function() {
9643
10042
  var $element, elementRight, elementRightShift, unshifter;
9644
10043
  $element = $(this);
9645
- elementRight = parseInt($element.css('right'));
10044
+ elementRight = parseFloat($element.css('right'));
9646
10045
  elementRightShift = scrollbarWidth + elementRight;
9647
10046
  unshifter = u.temporaryCss($element, {
9648
10047
  'right': elementRightShift
@@ -9666,6 +10065,7 @@ or function.
9666
10065
  This also returns `true` if the modal is in an opening or closing animation.
9667
10066
 
9668
10067
  @function up.modal.isOpen
10068
+ @return {Boolean}
9669
10069
  @stable
9670
10070
  */
9671
10071
  isOpen = function() {
@@ -9712,11 +10112,11 @@ or function.
9712
10112
  @param {String} [options.animation]
9713
10113
  The animation to use when opening the modal.
9714
10114
  @param {Number} [options.duration]
9715
- The duration of the animation. See [`up.animate`](/up.animate).
10115
+ The duration of the animation. See [`up.animate()`](/up.animate).
9716
10116
  @param {Number} [options.delay]
9717
- The delay before the animation starts. See [`up.animate`](/up.animate).
10117
+ The delay before the animation starts. See [`up.animate()`](/up.animate).
9718
10118
  @param {String} [options.easing]
9719
- The timing function that controls the animation's acceleration. [`up.animate`](/up.animate).
10119
+ The timing function that controls the animation's acceleration. [`up.animate()`](/up.animate).
9720
10120
  @return {Promise}
9721
10121
  A promise that will be resolved when the modal has been loaded and
9722
10122
  the opening animation has completed.
@@ -9731,7 +10131,7 @@ or function.
9731
10131
  /**
9732
10132
  Opens a modal for the given URL.
9733
10133
 
9734
- Example:
10134
+ \#\#\# Example
9735
10135
 
9736
10136
  up.modal.visit('/foo', { target: '.list' });
9737
10137
 
@@ -9747,7 +10147,7 @@ or function.
9747
10147
  The CSS selector to extract from the response.
9748
10148
  The extracted content will be placed into the dialog window.
9749
10149
  @param {Object} options
9750
- See options for [`up.modal.follow`](/up.modal.follow).
10150
+ See options for [`up.modal.follow()`](/up.modal.follow).
9751
10151
  @return {Promise}
9752
10152
  A promise that will be resolved when the modal has been loaded and the opening
9753
10153
  animation has completed.
@@ -9763,7 +10163,7 @@ or function.
9763
10163
  [Extracts](/up.extract) the given CSS selector from the given HTML string and
9764
10164
  opens the results in a modal.
9765
10165
 
9766
- Example:
10166
+ \#\#\# Example
9767
10167
 
9768
10168
  var html = 'before <div class="content">inner</div> after';
9769
10169
  up.modal.extract('.content', html);
@@ -9780,7 +10180,7 @@ or function.
9780
10180
  @param {String} html
9781
10181
  The HTML containing the modal content.
9782
10182
  @param {Object} options
9783
- See options for [`up.modal.follow`](/up.modal.follow).
10183
+ See options for [`up.modal.follow()`](/up.modal.follow).
9784
10184
  @return {Promise}
9785
10185
  A promise that will be resolved when the modal has been opened and the opening
9786
10186
  animation has completed.
@@ -9856,7 +10256,7 @@ or function.
9856
10256
  state.coveredUrl = up.browser.url();
9857
10257
  state.coveredTitle = document.title;
9858
10258
  }
9859
- options.beforeSwap = function() {
10259
+ options.provideTarget = function() {
9860
10260
  return createFrame(target, options);
9861
10261
  };
9862
10262
  extractOptions = u.merge(options, {
@@ -9907,7 +10307,7 @@ or function.
9907
10307
 
9908
10308
  @function up.modal.close
9909
10309
  @param {Object} options
9910
- See options for [`up.animate`](/up.animate)
10310
+ See options for [`up.animate()`](/up.animate)
9911
10311
  @return {Promise}
9912
10312
  A promise that will be resolved once the modal's close
9913
10313
  animation has finished.
@@ -10021,6 +10421,8 @@ or function.
10021
10421
 
10022
10422
  @function up.modal.contains
10023
10423
  @param {String} elementOrSelector
10424
+ The element to test
10425
+ @return {Boolean}
10024
10426
  @stable
10025
10427
  */
10026
10428
  contains = function(elementOrSelector) {
@@ -10033,7 +10435,7 @@ or function.
10033
10435
  overrideConfig = {};
10034
10436
  }
10035
10437
  up.log.warn('The up.modal.flavor function is deprecated. Use the up.modal.flavors property instead.');
10036
- return u.extend(flavorOverrides(name), overrideConfig);
10438
+ return u.assign(flavorOverrides(name), overrideConfig);
10037
10439
  };
10038
10440
 
10039
10441
  /**
@@ -10459,7 +10861,7 @@ The tooltip element is appended to the end of `<body>`.
10459
10861
 
10460
10862
  @function up.tooltip.close
10461
10863
  @param {Object} options
10462
- See options for [`up.animate`](/up.animate).
10864
+ See options for [`up.animate()`](/up.animate).
10463
10865
  @return {Promise}
10464
10866
  A promise for the end of the closing animation.
10465
10867
  @stable
@@ -10484,7 +10886,7 @@ The tooltip element is appended to the end of `<body>`.
10484
10886
  duration: config.closeDuration,
10485
10887
  easing: config.closeEasing
10486
10888
  });
10487
- u.extend(options, animateOptions);
10889
+ u.assign(options, animateOptions);
10488
10890
  state.phase = 'closing';
10489
10891
  return up.destroy(state.$tooltip, options).then(function() {
10490
10892
  state.phase = 'closed';
@@ -10592,18 +10994,18 @@ Once the response is received the URL will change to `/bar` and the `up-active`
10592
10994
  <a href="/bar" up-follow class="up-current">Bar</a>
10593
10995
 
10594
10996
 
10595
- @class up.navigation
10997
+ @class up.feedback
10596
10998
  */
10597
10999
 
10598
11000
  (function() {
10599
- up.navigation = (function($) {
11001
+ up.feedback = (function($) {
10600
11002
  var CLASS_ACTIVE, SELECTOR_SECTION, config, currentClass, findActionableArea, locationChanged, normalizeUrl, reset, sectionUrls, start, stop, u, urlSet;
10601
11003
  u = up.util;
10602
11004
 
10603
11005
  /**
10604
11006
  Sets default options for this module.
10605
11007
 
10606
- @property up.navigation.config
11008
+ @property up.feedback.config
10607
11009
  @param {Number} [config.currentClasses]
10608
11010
  An array of classes to set on [links that point the current location](/up-current).
10609
11011
  @stable
@@ -10715,9 +11117,9 @@ Once the response is received the URL will change to `/bar` and the `up-active`
10715
11117
 
10716
11118
  var $button = $('button');
10717
11119
  $button.on('click', function() {
10718
- up.navigation.start($button);
11120
+ up.feedback.start($button);
10719
11121
  up.ajax(...).always(function() {
10720
- up.navigation.stop($button);
11122
+ up.feedback.stop($button);
10721
11123
  });
10722
11124
  });
10723
11125
 
@@ -10725,18 +11127,18 @@ Once the response is received the URL will change to `/bar` and the `up-active`
10725
11127
 
10726
11128
  var $button = $('button');
10727
11129
  $button.on('click', function() {
10728
- up.navigation.start($button, function() {
11130
+ up.feedback.start($button, function() {
10729
11131
  up.ajax(...);
10730
11132
  });
10731
11133
  });
10732
11134
 
10733
- @method up.navigation.start
11135
+ @method up.feedback.start
10734
11136
  @param {Element|jQuery|String} elementOrSelector
10735
11137
  The element to mark as active
10736
11138
  @param {Function} [action]
10737
11139
  An optional function to run while the element is marked as loading.
10738
11140
  The function must return a promise.
10739
- Once the promise resolves, the element will be [marked as no longer loading](/up.navigation.stop).
11141
+ Once the promise resolves, the element will be [marked as no longer loading](/up.feedback.stop).
10740
11142
  @internal
10741
11143
  */
10742
11144
  start = function(elementOrSelector, action) {
@@ -10790,7 +11192,7 @@ Once the response is received the URL will change to `/bar` and the `up-active`
10790
11192
  This happens automatically when network requests initiated by the Unpoly API have completed.
10791
11193
  Use this function if you make custom network calls from your own JavaScript code.
10792
11194
 
10793
- @function up.navigation.stop
11195
+ @function up.feedback.stop
10794
11196
  @param {jQuery} event.$element
10795
11197
  The link or form that has finished loading.
10796
11198
  @internal
@@ -10798,10 +11200,6 @@ Once the response is received the URL will change to `/bar` and the `up-active`
10798
11200
  stop = function(elementOrSelector) {
10799
11201
  var $element;
10800
11202
  $element = findActionableArea(elementOrSelector);
10801
- up.emit('up:navigated', {
10802
- $element: $element,
10803
- message: false
10804
- });
10805
11203
  return $element.removeClass(CLASS_ACTIVE);
10806
11204
  };
10807
11205
 
@@ -10860,14 +11258,13 @@ Once the response is received the URL will change to `/bar` and the `up-active`
10860
11258
  up.on('up:framework:reset', reset);
10861
11259
  return {
10862
11260
  config: config,
10863
- defaults: function() {
10864
- return up.fail('up.navigation.defaults(...) no longer exists. Set values on he up.navigation.config property instead.');
10865
- },
10866
11261
  start: start,
10867
11262
  stop: stop
10868
11263
  };
10869
11264
  })(jQuery);
10870
11265
 
11266
+ up.renamedModule('navigation', 'feedback');
11267
+
10871
11268
  }).call(this);
10872
11269
 
10873
11270
  /**