unpoly-rails 0.22.1 → 0.23.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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/design/positioning.txt +28 -0
  4. data/dist/unpoly.css +27 -20
  5. data/dist/unpoly.js +171 -59
  6. data/dist/unpoly.min.css +1 -1
  7. data/dist/unpoly.min.js +3 -3
  8. data/lib/assets/javascripts/unpoly/browser.js.coffee +12 -0
  9. data/lib/assets/javascripts/unpoly/bus.js.coffee +21 -22
  10. data/lib/assets/javascripts/unpoly/form.js.coffee +9 -5
  11. data/lib/assets/javascripts/unpoly/layout.js.coffee +3 -2
  12. data/lib/assets/javascripts/unpoly/link.js.coffee +3 -2
  13. data/lib/assets/javascripts/unpoly/navigation.js.coffee +2 -2
  14. data/lib/assets/javascripts/unpoly/proxy.js.coffee +11 -9
  15. data/lib/assets/javascripts/unpoly/tooltip.js.coffee +9 -2
  16. data/lib/assets/javascripts/unpoly/util.js.coffee +79 -11
  17. data/lib/assets/stylesheets/unpoly/tooltip.css.sass +32 -22
  18. data/lib/unpoly/rails/version.rb +1 -1
  19. data/spec_app/Gemfile.lock +1 -1
  20. data/spec_app/app/assets/images/grid.png +0 -0
  21. data/spec_app/app/assets/javascripts/integration_test.coffee +2 -0
  22. data/spec_app/app/assets/javascripts/jasmine_specs.coffee +7 -0
  23. data/spec_app/app/assets/stylesheets/integration_test.sass +24 -0
  24. data/spec_app/app/assets/stylesheets/jasmine_specs.sass +1 -0
  25. data/spec_app/app/controllers/{test_controller.rb → binding_test_controller.rb} +1 -1
  26. data/spec_app/app/controllers/css_test_controller.rb +5 -0
  27. data/spec_app/app/controllers/form_test/basics_controller.rb +14 -0
  28. data/spec_app/app/controllers/form_test/uploads_controller.rb +15 -0
  29. data/spec_app/app/controllers/pages_controller.rb +5 -0
  30. data/spec_app/app/views/css_test/tooltip.erb +15 -0
  31. data/spec_app/app/views/form_test/basics/new.erb +33 -0
  32. data/spec_app/app/views/form_test/submission_result.erb +30 -0
  33. data/spec_app/app/views/form_test/uploads/new.erb +27 -0
  34. data/spec_app/app/views/layouts/integration_test.erb +14 -0
  35. data/spec_app/app/views/pages/start.erb +25 -0
  36. data/spec_app/config/initializers/assets.rb +4 -1
  37. data/spec_app/config/routes.rb +8 -2
  38. data/spec_app/spec/controllers/{test_controller_spec.rb → binding_test_controller_spec.rb} +1 -1
  39. data/spec_app/spec/javascripts/helpers/parse_form_data.js.coffee +9 -0
  40. data/spec_app/spec/javascripts/support/jasmine.yml +2 -2
  41. data/spec_app/spec/javascripts/up/form_spec.js.coffee +21 -1
  42. data/spec_app/spec/javascripts/up/tooltip_spec.js.coffee +54 -17
  43. metadata +21 -13
  44. data/spec_app/app/assets/javascripts/application.js +0 -20
  45. data/spec_app/app/assets/stylesheets/application.css +0 -17
  46. data/spec_app/app/assets/stylesheets/blocks/card.css.sass +0 -11
  47. data/spec_app/app/assets/stylesheets/blocks/controls.css.sass +0 -7
  48. data/spec_app/app/assets/stylesheets/blocks/menu.css.sass +0 -13
  49. data/spec_app/app/assets/stylesheets/blocks/panel.css.sass +0 -8
  50. data/spec_app/app/assets/stylesheets/jasmine_specs.css +0 -5
  51. data/spec_app/app/controllers/concerns/.keep +0 -0
  52. data/spec_app/app/views/layouts/application.html.erb +0 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6109418137600ed7280a7f3ecb2adb7ab5da2b4f
4
- data.tar.gz: 118d634ab654710610a010e42d0d55223cd65a6b
3
+ metadata.gz: ec9d0678d3c0fa042de8cb5e10f94014dfbe7f36
4
+ data.tar.gz: 28e851c819c201c8e65fd1e1945a3b44f4310e56
5
5
  SHA512:
6
- metadata.gz: 4bd0e2d984e5c55654d201fd095eb4424105000d46f1d22273190f8fea325189a9727152a16d5bf549eb9a990f49f3ef9f5366ff06260b012ad81b7343629e87
7
- data.tar.gz: 4f8a3ba9acf52274f0a26a21a600e4d0092694366b935de0ba1e992283f43bbf7b2b6979ef844335ab9d7bf16e985362da3ae3a0c67848ee4ff2ef5425730698
6
+ metadata.gz: 8a70cad251b68e888be109193209eea3101aab04efb98a62abd0e2a282ef10977f64569c208cbd9041c4f7c9bc74ea5147e140341badf15b5f58c91eb1e4efc8
7
+ data.tar.gz: 6b13838de87ece08a23be26531c3bfa0258cffc958f3495d0a692288bba6bf3859c55e020cd63c15842c37227e5f618c3484415c9530e3dd19912797b6e001c3
data/CHANGELOG.md CHANGED
@@ -14,6 +14,21 @@ Unreleased
14
14
  ### Breaking changes
15
15
 
16
16
 
17
+ 0.23.0
18
+ ------
19
+
20
+ ### Compatible changes
21
+
22
+ - Unpoly forms can now [submit](/up.submit) file uploads via AJAX.
23
+ - You can now position [tooltips](/up-tooltip) on the left or right side of an element.
24
+
25
+
26
+ ### Breaking changes
27
+
28
+ - Tooltips have a darker background color.
29
+ - The tooltip CSS has been changed to be easier to override.
30
+
31
+
17
32
  0.22.1
18
33
  ------
19
34
 
@@ -0,0 +1,28 @@
1
+ Macht es jemals sinn von rechts oder von rechts zu positionieren?
2
+ Wenn dann Inhalt unten dran kommt verschiebt sich alles?
3
+
4
+
5
+
6
+ Tooltip
7
+ top { left, top
8
+ right
9
+ bottom
10
+ left
11
+
12
+ Popup
13
+ top-left then stretch rightwards
14
+ bottom-left then stretch rightwards
15
+ top-right then stretch leftwards
16
+ bottom-right then stretch leftwards
17
+
18
+
19
+ Popup
20
+ Menu?
21
+ Context?
22
+ Dropdown?
23
+ Popover?
24
+
25
+
26
+
27
+ up.positioning
28
+
data/dist/unpoly.css CHANGED
@@ -62,37 +62,44 @@
62
62
  padding: 15px;
63
63
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.3); }
64
64
  .up-tooltip {
65
- z-index: 30000;
66
65
  position: absolute;
67
- background-color: #666;
66
+ z-index: 30000;
67
+ background-color: #111;
68
68
  color: white;
69
69
  padding: 6px 9px;
70
70
  white-space: nowrap; }
71
+ .up-tooltip:after {
72
+ content: "";
73
+ position: absolute;
74
+ display: block;
75
+ width: 0;
76
+ height: 0;
77
+ border: 8px solid transparent; }
71
78
  .up-tooltip[up-position=top] {
72
79
  margin-top: -6px; }
73
80
  .up-tooltip[up-position=top]:after {
74
- content: "";
75
- position: absolute;
76
- border-style: solid;
77
- border-width: 8px 8px 0;
78
- border-color: #666 transparent;
79
- display: block;
80
- width: 0;
81
- z-index: 1;
82
- bottom: -8px;
81
+ border-top-color: #111;
82
+ bottom: -16px;
83
83
  left: 50%;
84
84
  margin-left: -8px; }
85
+ .up-tooltip[up-position=left] {
86
+ margin-left: -6px; }
87
+ .up-tooltip[up-position=left]:after {
88
+ border-left-color: #111;
89
+ right: -16px;
90
+ top: 50%;
91
+ margin-top: -8px; }
92
+ .up-tooltip[up-position=right] {
93
+ margin-left: 6px; }
94
+ .up-tooltip[up-position=right]:after {
95
+ border-right-color: #111;
96
+ left: -16px;
97
+ top: 50%;
98
+ margin-top: -8px; }
85
99
  .up-tooltip[up-position=bottom] {
86
100
  margin-top: 6px; }
87
101
  .up-tooltip[up-position=bottom]:after {
88
- content: "";
89
- position: absolute;
90
- border-style: solid;
91
- border-width: 0 8px 8px;
92
- border-color: #666 transparent;
93
- display: block;
94
- width: 0;
95
- z-index: 1;
96
- top: -8px;
102
+ border-bottom-color: #111;
103
+ top: -16px;
97
104
  left: 50%;
98
105
  margin-left: -8px; }
data/dist/unpoly.js CHANGED
@@ -27,7 +27,7 @@ that might save you from loading something like [Underscore.js](http://underscor
27
27
  @function up.util.memoize
28
28
  @internal
29
29
  */
30
- var $createElementFromSelector, $createPlaceholder, ANIMATION_DEFERRED_KEY, all, any, cache, castedAttr, clientSize, compact, config, contains, copy, copyAttributes, createElement, createElementFromHtml, cssAnimate, detect, each, error, escapePressed, except, extend, findWithSelf, finishCssAnimate, fixedToAbsolute, forceCompositing, intersect, isArray, isBlank, isDeferred, isDefined, isElement, 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, normalizeMethod, normalizeUrl, nullJQuery, offsetParent, once, only, option, options, parseUrl, pluckData, presence, presentAttr, reject, remove, requestDataAsArray, requestDataAsQuery, resolvableWhen, resolvedDeferred, resolvedPromise, scrollbarWidth, select, selectorForElement, setMissingAttrs, temporaryCss, times, titleFromXhr, toArray, trim, unJQuery, uniq, unresolvableDeferred, unresolvablePromise, unwrapElement;
30
+ var $createElementFromSelector, $createPlaceholder, ANIMATION_DEFERRED_KEY, all, any, appendRequestData, cache, castedAttr, clientSize, compact, config, contains, copy, copyAttributes, createElement, createElementFromHtml, cssAnimate, detect, each, error, escapePressed, except, extend, findWithSelf, finishCssAnimate, fixedToAbsolute, forceCompositing, intersect, isArray, isBlank, isDeferred, isDefined, isElement, 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, normalizeMethod, normalizeUrl, nullJQuery, offsetParent, once, only, option, options, parseUrl, pluckData, presence, presentAttr, reject, remove, requestDataAsArray, requestDataAsQuery, requestDataFromForm, resolvableWhen, resolvedDeferred, resolvedPromise, scrollbarWidth, select, selectorForElement, setMissingAttrs, temporaryCss, times, titleFromXhr, toArray, trim, unJQuery, uniq, unresolvableDeferred, unresolvablePromise, unwrapElement;
31
31
  memoize = function(func) {
32
32
  var cache, cached;
33
33
  cache = void 0;
@@ -602,6 +602,20 @@ that might save you from loading something like [Underscore.js](http://underscor
602
602
  return Object.prototype.toString.call(object) === '[object Array]';
603
603
  };
604
604
 
605
+ /**
606
+ Returns whether the given argument is a `FormData` instance.
607
+
608
+ Always returns `false` in browsers that don't support `FormData`.
609
+
610
+ @function up.util.isFormData
611
+ @param object
612
+ @return {Boolean}
613
+ @internal
614
+ */
615
+ isFormData = function(object) {
616
+ return up.browser.canFormData() && object instanceof FormData;
617
+ };
618
+
605
619
  /**
606
620
  Converts the given array-like argument into an array.
607
621
 
@@ -1732,20 +1746,24 @@ that might save you from loading something like [Underscore.js](http://underscor
1732
1746
  */
1733
1747
  requestDataAsArray = function(data) {
1734
1748
  var array, i, len, pair, part, query, ref;
1735
- query = requestDataAsQuery(data);
1736
- array = [];
1737
- ref = query.split('&');
1738
- for (i = 0, len = ref.length; i < len; i++) {
1739
- part = ref[i];
1740
- if (isPresent(part)) {
1741
- pair = part.split('=');
1742
- array.push({
1743
- name: decodeURIComponent(pair[0]),
1744
- value: decodeURIComponent(pair[1])
1745
- });
1749
+ if (isFormData(data)) {
1750
+ return up.error('Cannot convert FormData into an array');
1751
+ } else {
1752
+ query = requestDataAsQuery(data);
1753
+ array = [];
1754
+ ref = query.split('&');
1755
+ for (i = 0, len = ref.length; i < len; i++) {
1756
+ part = ref[i];
1757
+ if (isPresent(part)) {
1758
+ pair = part.split('=');
1759
+ array.push({
1760
+ name: decodeURIComponent(pair[0]),
1761
+ value: decodeURIComponent(pair[1])
1762
+ });
1763
+ }
1746
1764
  }
1765
+ return array;
1747
1766
  }
1748
- return array;
1749
1767
  };
1750
1768
 
1751
1769
  /**
@@ -1757,7 +1775,9 @@ that might save you from loading something like [Underscore.js](http://underscor
1757
1775
  */
1758
1776
  requestDataAsQuery = function(data) {
1759
1777
  var query;
1760
- if (data) {
1778
+ if (isFormData(data)) {
1779
+ return up.error('Cannot convert FormData into a query string');
1780
+ } else if (isPresent(data)) {
1761
1781
  query = $.param(data);
1762
1782
  query = query.replace(/\+/g, '%20');
1763
1783
  return query;
@@ -1766,6 +1786,64 @@ that might save you from loading something like [Underscore.js](http://underscor
1766
1786
  }
1767
1787
  };
1768
1788
 
1789
+ /**
1790
+ Serializes the given form into a request data representation.
1791
+
1792
+ @function up.util.requestDataFromForm
1793
+ @return {Array|FormData}
1794
+ @internal
1795
+ */
1796
+ requestDataFromForm = function(form) {
1797
+ var $form, hasFileInputs;
1798
+ $form = $(form);
1799
+ hasFileInputs = $form.find('input[type=file]').length;
1800
+ if (hasFileInputs && up.browser.canFormData()) {
1801
+ return new FormData($form.get(0));
1802
+ } else {
1803
+ return $form.serializeArray();
1804
+ }
1805
+ };
1806
+
1807
+ /**
1808
+ Adds a key/value pair to the given request data representation.
1809
+
1810
+ This mutates the given `data` if `data` is a `FormData`, an object
1811
+ or an array. When `data` is `String` a new string with the appended key/value
1812
+ pair is returned.
1813
+
1814
+ @function up.util.appendRequestData
1815
+ @param {FormData|Object|Array|Undefined|Null} data
1816
+ @param {String} key
1817
+ @param {String|Blob|File} value
1818
+ @internal
1819
+ */
1820
+ appendRequestData = function(data, name, value) {
1821
+ var newPair;
1822
+ if (isFormData(data)) {
1823
+ data.append(name, value);
1824
+ } else if (isArray(data)) {
1825
+ data.push({
1826
+ name: name,
1827
+ value: value
1828
+ });
1829
+ } else if (isObject(data)) {
1830
+ data[name] = value;
1831
+ } else if (isString(data) || isMissing(data)) {
1832
+ newPair = requestDataAsQuery([
1833
+ {
1834
+ name: name,
1835
+ value: value
1836
+ }
1837
+ ]);
1838
+ if (isPresent(data)) {
1839
+ data = [data, newPair].join('&');
1840
+ } else {
1841
+ data = newPair;
1842
+ }
1843
+ }
1844
+ return data;
1845
+ };
1846
+
1769
1847
  /**
1770
1848
  Throws a fatal error with the given message.
1771
1849
 
@@ -1800,6 +1878,8 @@ that might save you from loading something like [Underscore.js](http://underscor
1800
1878
  return {
1801
1879
  requestDataAsArray: requestDataAsArray,
1802
1880
  requestDataAsQuery: requestDataAsQuery,
1881
+ appendRequestData: appendRequestData,
1882
+ requestDataFromForm: requestDataFromForm,
1803
1883
  offsetParent: offsetParent,
1804
1884
  fixedToAbsolute: fixedToAbsolute,
1805
1885
  presentAttr: presentAttr,
@@ -1845,6 +1925,8 @@ that might save you from loading something like [Underscore.js](http://underscor
1845
1925
  isPromise: isPromise,
1846
1926
  isDeferred: isDeferred,
1847
1927
  isHash: isHash,
1928
+ isArray: isArray,
1929
+ isFormData: isFormData,
1848
1930
  isUnmodifiedKeyEvent: isUnmodifiedKeyEvent,
1849
1931
  isUnmodifiedMouseEvent: isUnmodifiedMouseEvent,
1850
1932
  nullJQuery: nullJQuery,
@@ -1859,7 +1941,6 @@ that might save you from loading something like [Underscore.js](http://underscor
1859
1941
  copyAttributes: copyAttributes,
1860
1942
  findWithSelf: findWithSelf,
1861
1943
  contains: contains,
1862
- isArray: isArray,
1863
1944
  toArray: toArray,
1864
1945
  castedAttr: castedAttr,
1865
1946
  locationFromXhr: locationFromXhr,
@@ -2016,7 +2097,7 @@ we can't currently get rid off.
2016
2097
  var slice = [].slice;
2017
2098
 
2018
2099
  up.browser = (function($) {
2019
- var CONSOLE_PLACEHOLDERS, canCssTransition, canInputEvent, canLogSubstitution, canPushState, confirm, initialRequestMethod, installPolyfills, isIE8OrWorse, isIE9OrWorse, isRecentJQuery, isSupported, loadPage, popCookie, puts, sprintf, u, url;
2100
+ var CONSOLE_PLACEHOLDERS, canCssTransition, canFormData, canInputEvent, canLogSubstitution, canPushState, confirm, initialRequestMethod, installPolyfills, isIE8OrWorse, isIE9OrWorse, isRecentJQuery, isSupported, loadPage, popCookie, puts, sprintf, u, url;
2020
2101
  u = up.util;
2021
2102
 
2022
2103
  /**
@@ -2178,6 +2259,18 @@ we can't currently get rid off.
2178
2259
  return 'oninput' in document.createElement('input');
2179
2260
  });
2180
2261
 
2262
+ /**
2263
+ Returns whether this browser supports the [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData)
2264
+ interface.
2265
+
2266
+ @function up.browser.canFormData
2267
+ @return {Boolean}
2268
+ @experimental
2269
+ */
2270
+ canFormData = u.memoize(function() {
2271
+ return !!window.FormData;
2272
+ });
2273
+
2181
2274
  /**
2182
2275
  Returns whether this browser supports
2183
2276
  [string substitution](https://developer.mozilla.org/en-US/docs/Web/API/console#Using_string_substitutions)
@@ -2276,6 +2369,7 @@ we can't currently get rid off.
2276
2369
  canPushState: canPushState,
2277
2370
  canCssTransition: canCssTransition,
2278
2371
  canInputEvent: canInputEvent,
2372
+ canFormData: canFormData,
2279
2373
  canLogSubstitution: canLogSubstitution,
2280
2374
  isSupported: isSupported,
2281
2375
  installPolyfills: installPolyfills,
@@ -2321,14 +2415,13 @@ use the more convenient [`up.on`](/up.on):
2321
2415
  // the clicked <button> element
2322
2416
  });
2323
2417
 
2324
- This is roughly equivalent to binding an event listener to `document`
2325
- using jQuery's [`on`](http://api.jquery.com/on/).
2418
+ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2326
2419
 
2327
2420
  - Event listeners on [unsupported browsers](/up.browser.isSupported) are silently discarded,
2328
2421
  leaving you with an application without Javascript. This is typically preferable to
2329
2422
  a soup of randomly broken Javascript in ancient browsers.
2330
2423
  - A jQuery object with the target element is automatically passed to the event handler
2331
- as a second argument.
2424
+ as a second argument. You no longer need to write `$(this)` in the handler function.
2332
2425
  - You use an [`up-data`](/up-data) attribute to [attach structured data](/up.on#attaching-structured-data)
2333
2426
  to observed elements.
2334
2427
 
@@ -2416,25 +2509,7 @@ using jQuery's [`on`](http://api.jquery.com/on/).
2416
2509
  console.log("This is %o who is %o years old", data.name, data.age);
2417
2510
  });
2418
2511
 
2419
- \#\#\#\# Migrating jQuery event handlers to `up.on`
2420
-
2421
- Within the event handler, Unpoly will bind `this` to the
2422
- native DOM element to help you migrate your existing jQuery code to
2423
- this new syntax.
2424
-
2425
- So if you had this before:
2426
-
2427
- $(document).on('click', '.button', function() {
2428
- $(this).something();
2429
- });
2430
-
2431
- ... you can simply copy the event handler to `up.on`:
2432
-
2433
- up.on('click', '.button', function() {
2434
- $(this).something();
2435
- });
2436
-
2437
- \#\#\#\# Stopping to listen
2512
+ \#\#\#\# Unbinding an event listener
2438
2513
 
2439
2514
  `up.on` returns a function that unbinds the event listeners when called:
2440
2515
 
@@ -2458,6 +2533,24 @@ using jQuery's [`on`](http://api.jquery.com/on/).
2458
2533
  // Unbind the listener
2459
2534
  up.off('click', listener)
2460
2535
 
2536
+ \#\#\#\# Migrating jQuery event handlers to `up.on`
2537
+
2538
+ Within the event handler, Unpoly will bind `this` to the
2539
+ native DOM element to help you migrate your existing jQuery code to
2540
+ this new syntax.
2541
+
2542
+ So if you had this before:
2543
+
2544
+ $(document).on('click', '.button', function() {
2545
+ $(this).something();
2546
+ });
2547
+
2548
+ ... you can simply copy the event handler to `up.on`:
2549
+
2550
+ up.on('click', '.button', function() {
2551
+ $(this).something();
2552
+ });
2553
+
2461
2554
  @function up.on
2462
2555
  @param {String} events
2463
2556
  A space-separated list of event names to bind.
@@ -3810,11 +3903,16 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
3810
3903
  @param {String|Element|jQuery} selectorOrElement
3811
3904
  @internal
3812
3905
  */
3813
- viewportOf = function(selectorOrElement) {
3906
+ viewportOf = function(selectorOrElement, options) {
3814
3907
  var $element, $viewport;
3908
+ if (options == null) {
3909
+ options = {};
3910
+ }
3815
3911
  $element = $(selectorOrElement);
3816
3912
  $viewport = viewportSelector().seekUp($element);
3817
- $viewport.length || u.error("Could not find viewport for %o", $element);
3913
+ if ($viewport.length === 0 && options.strict !== false) {
3914
+ u.error("Could not find viewport for %o", $element);
3915
+ }
3818
3916
  return $viewport;
3819
3917
  };
3820
3918
 
@@ -6070,15 +6168,15 @@ the user performs the click.
6070
6168
  show = function() { $element.show() };
6071
6169
  hide = function() { $element.hide() };
6072
6170
 
6073
- showOff = up.on('up:proxy:slow', show);
6074
- hideOff = up.on('up:proxy:recover', hide);
6171
+ up.on('up:proxy:slow', show);
6172
+ up.on('up:proxy:recover', hide);
6075
6173
 
6076
6174
  hide();
6077
6175
 
6078
6176
  // Clean up when the element is removed from the DOM
6079
6177
  return function() {
6080
- showOff();
6081
- hideOff();
6178
+ up.off('up:proxy:slow', show);
6179
+ up.off('up:proxy:recover', hide);
6082
6180
  };
6083
6181
 
6084
6182
  });
@@ -6140,14 +6238,14 @@ the user performs the click.
6140
6238
  request = u.copy(request);
6141
6239
  request.headers || (request.headers = {});
6142
6240
  request.headers['X-Up-Target'] = request.target;
6143
- request.data = u.requestDataAsArray(request.data);
6144
6241
  if (u.contains(config.wrapMethods, request.method)) {
6145
- request.data.push({
6146
- name: config.wrapMethodParam,
6147
- value: request.method
6148
- });
6242
+ request.data = u.appendRequestData(request.data, config.wrapMethodParam, request.method);
6149
6243
  request.method = 'POST';
6150
6244
  }
6245
+ if (u.isFormData(request.data)) {
6246
+ request.contentType = false;
6247
+ request.processData = false;
6248
+ }
6151
6249
  promise = $.ajax(request);
6152
6250
  promise.done(function(data, textStatus, xhr) {
6153
6251
  return responseReceived(request, xhr);
@@ -6308,8 +6406,8 @@ attribute. The value of this attribute is a CSS selector that indicates which pa
6308
6406
  fragment to update. The rest of the page will remain unchanged.
6309
6407
 
6310
6408
 
6311
- Exammple
6312
- --------
6409
+ Example
6410
+ -------
6313
6411
 
6314
6412
  Let's say we are rendering three pages with a tabbed navigation to switch between screens:
6315
6413
 
@@ -6702,6 +6800,7 @@ Read on
6702
6800
 
6703
6801
  /**
6704
6802
  Marks up the current link to be followed *as fast as possible*.
6803
+
6705
6804
  This is done by:
6706
6805
 
6707
6806
  - [Following the link through AJAX](/up-target) instead of a full page load
@@ -6930,7 +7029,7 @@ open dialogs with sub-forms, etc. all without losing form state.
6930
7029
  @stable
6931
7030
  */
6932
7031
  submit = function(formOrSelector, options) {
6933
- var $form, hasFileInputs, promise, target, url;
7032
+ var $form, canAjaxSubmit, canHistoryOption, hasFileInputs, promise, target, url;
6934
7033
  $form = $(formOrSelector).closest('form');
6935
7034
  options = u.options(options);
6936
7035
  target = u.option(options.target, $form.attr('up-target'), 'body');
@@ -6945,18 +7044,20 @@ open dialogs with sub-forms, etc. all without losing form state.
6945
7044
  options.cache = u.option(options.cache, u.castedAttr($form, 'up-cache'));
6946
7045
  options.restoreScroll = u.option(options.restoreScroll, u.castedAttr($form, 'up-restore-scroll'));
6947
7046
  options.origin = u.option(options.origin, $form);
6948
- options.data = $form.serializeArray();
7047
+ options.data = up.util.requestDataFromForm($form);
6949
7048
  options = u.merge(options, up.motion.animateOptions(options, $form));
6950
7049
  hasFileInputs = $form.find('input[type=file]').length;
7050
+ canAjaxSubmit = !hasFileInputs || u.isFormData(options.data);
7051
+ canHistoryOption = up.browser.canPushState() || options.history === false;
6951
7052
  if (options.validate) {
6952
7053
  options.headers || (options.headers = {});
6953
7054
  options.headers['X-Up-Validate'] = options.validate;
6954
- if (hasFileInputs) {
7055
+ if (!canAjaxSubmit) {
6955
7056
  return u.unresolvablePromise();
6956
7057
  }
6957
7058
  }
6958
7059
  $form.addClass('up-active');
6959
- if (hasFileInputs || (!up.browser.canPushState() && options.history !== false)) {
7060
+ if (!(canAjaxSubmit && canHistoryOption)) {
6960
7061
  $form.get(0).submit();
6961
7062
  return u.unresolvablePromise();
6962
7063
  }
@@ -8802,7 +8903,7 @@ The tooltip element is appended to the end of `<body>`.
8802
8903
  @property up.tooltip.config
8803
8904
  @param {String} [config.position]
8804
8905
  The default position of tooltips relative to the element.
8805
- Can be either `"top"` or `"bottom"`.
8906
+ Can be `'top'`, `'right'`, `'bottom'` or `'left'`.
8806
8907
  @param {String} [config.openAnimation='fade-in']
8807
8908
  The animation used to open a tooltip.
8808
8909
  @param {String} [config.closeAnimation='fade-out']
@@ -8828,6 +8929,16 @@ The tooltip element is appended to the end of `<body>`.
8828
8929
  left: linkBox.left + 0.5 * (linkBox.width - tooltipBox.width),
8829
8930
  top: linkBox.top - tooltipBox.height
8830
8931
  };
8932
+ case "left":
8933
+ return {
8934
+ left: linkBox.left - tooltipBox.width,
8935
+ top: linkBox.top + 0.5 * (linkBox.height - tooltipBox.height)
8936
+ };
8937
+ case "right":
8938
+ return {
8939
+ left: linkBox.left + linkBox.width,
8940
+ top: linkBox.top + 0.5 * (linkBox.height - tooltipBox.height)
8941
+ };
8831
8942
  case "bottom":
8832
8943
  return {
8833
8944
  left: linkBox.left + 0.5 * (linkBox.width - tooltipBox.width),
@@ -8864,7 +8975,8 @@ The tooltip element is appended to the end of `<body>`.
8864
8975
  @param {String} [options.html]
8865
8976
  The HTML to display in the tooltip.
8866
8977
  @param {String} [options.position='top']
8867
- The position of the tooltip. Known values are `top` and `bottom`.
8978
+ The position of the tooltip.
8979
+ Can be `'top'`, `'right'`, `'bottom'` or `'left'`.
8868
8980
  @param {String} [options.animation]
8869
8981
  The animation to use when opening the tooltip.
8870
8982
  @return {Promise}
@@ -8969,8 +9081,8 @@ The tooltip element is appended to the end of `<body>`.
8969
9081
  }).call(this);
8970
9082
 
8971
9083
  /**
8972
- Fast interaction feedback
8973
- =========================
9084
+ Navigation bars
9085
+ ===============
8974
9086
 
8975
9087
  Unpoly automatically marks up link elements with classes indicating that
8976
9088
  they are currently loading (class `up-active`) or linking