unpoly-rails 0.28.1 → 0.29.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 (30) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -1
  3. data/dist/unpoly.js +376 -259
  4. data/dist/unpoly.min.js +3 -3
  5. data/lib/assets/javascripts/unpoly/browser.js.coffee +2 -2
  6. data/lib/assets/javascripts/unpoly/bus.js.coffee +40 -13
  7. data/lib/assets/javascripts/unpoly/flow.js.coffee +9 -9
  8. data/lib/assets/javascripts/unpoly/form.js.coffee +18 -18
  9. data/lib/assets/javascripts/unpoly/history.js.coffee +1 -1
  10. data/lib/assets/javascripts/unpoly/layout.js.coffee +9 -9
  11. data/lib/assets/javascripts/unpoly/link.js.coffee +34 -24
  12. data/lib/assets/javascripts/unpoly/modal.js.coffee +38 -37
  13. data/lib/assets/javascripts/unpoly/motion.js.coffee +20 -23
  14. data/lib/assets/javascripts/unpoly/navigation.js.coffee +101 -37
  15. data/lib/assets/javascripts/unpoly/popup.js.coffee +24 -16
  16. data/lib/assets/javascripts/unpoly/proxy.js.coffee +3 -3
  17. data/lib/assets/javascripts/unpoly/syntax.js.coffee +29 -37
  18. data/lib/assets/javascripts/unpoly/tooltip.js.coffee +18 -9
  19. data/lib/assets/javascripts/unpoly/util.js.coffee +15 -7
  20. data/lib/unpoly/rails/version.rb +1 -1
  21. data/spec_app/Gemfile.lock +1 -1
  22. data/spec_app/spec/javascripts/helpers/trigger.js.coffee +6 -0
  23. data/spec_app/spec/javascripts/up/bus_spec.js.coffee +9 -8
  24. data/spec_app/spec/javascripts/up/form_spec.js.coffee +10 -10
  25. data/spec_app/spec/javascripts/up/link_spec.js.coffee +25 -20
  26. data/spec_app/spec/javascripts/up/modal_spec.js.coffee +53 -44
  27. data/spec_app/spec/javascripts/up/navigation_spec.js.coffee +8 -8
  28. data/spec_app/spec/javascripts/up/popup_spec.js.coffee +92 -44
  29. data/spec_app/spec/javascripts/up/tooltip_spec.js.coffee +46 -4
  30. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fb021075a234456674e91bb9efa8ed7297d97688
4
- data.tar.gz: 56d23d3e15181b6eafe6948bc7d14722fdf1259c
3
+ metadata.gz: 5c3dd39115176a2678dd711465e699abf2a6075e
4
+ data.tar.gz: 3aa54c6a3322d1744049d08e28d8951a0202937a
5
5
  SHA512:
6
- metadata.gz: e1f587d724ab510fd1e358e9caa23ee6e165ddf3a8519b4314f7ecd58140eaca652dfbda63aabad102963d284d66e6ed196db0ed3b216cbdfbff5dc93464d29b
7
- data.tar.gz: 337d17a07a9ab3dc488b4449af391740c3815cbcf84b1b68611c7621a661016124d59eb0f2f1fc9b167f1668138a6e0cc9a78642ac33509b95300b8f458d9835
6
+ metadata.gz: c35a16fbcff7161a323a017fcc4fcaa05987d70e4fd0af46de864b4b19b6d626478c69aa72deaf3fdb032b8db516e31ee7545178e8f381e4ae676224fd06f7ca
7
+ data.tar.gz: f2bb1070125d3cb2a774d19efccd6e3d03b6ff20d6aa70d5683907a041e108a760a2067a55c7d7a0e9a3425ef5767306656b21e4e8e56927d2cc27416653a8ee
data/CHANGELOG.md CHANGED
@@ -10,8 +10,26 @@ Unreleased
10
10
 
11
11
  ### Compatible changes
12
12
 
13
+
14
+ ### Breaking changes
15
+
16
+
17
+
18
+ 0.29.0
19
+ ------
20
+
21
+ ### Compatible changes
22
+
23
+ - [`up.popup.attach`](/up.popup.attach) now has a `{ html }` option. This allows you to extract popup contents
24
+ from a HTML string without making a network request.
25
+ - [`up.tooltip.attach`](/up.tooltip.attach) now has a `{ text }` option which automatically escapes the given string.
26
+ - Fix a bug on Firefox where the page width would jump by the scrollbar width when opening a modal.
27
+ - Fix a bug where modals would close when following a link to a cached destination.
28
+
13
29
  ### Breaking changes
14
30
 
31
+ - Events handled by Unpoly selectors will now longer bubble up the DOM.
32
+
15
33
 
16
34
  0.28.1
17
35
  ------
@@ -414,7 +432,7 @@ Unreleased
414
432
  request and response.
415
433
  - [`up.follow`](/up.follow) and [`up.replace`](/up.replace) now have an option `{ failTarget }`.
416
434
  Use it to define the selector to replace if the server responds with a non-200 status code.
417
- - [`[up-target]`](/up-target) and [`up-follow`](/up.replace) now have a modifying attribute `up-fail-target`.
435
+ - [`[up-target]`](/a-up-target) and [`up-follow`](/a-up-follow) now have a modifying attribute `up-fail-target`.
418
436
  Use it to define the selector to replace if the server responds with a non-200 status code.
419
437
  - New utility method [`up.util.reject`](/up.util.reject)
420
438
  - New utility method [`up.util.only`](/up.util.only)
data/dist/unpoly.js CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  (function() {
7
7
  window.up = {
8
- version: "0.28.1"
8
+ version: "0.29.0"
9
9
  };
10
10
 
11
11
  }).call(this);
@@ -32,7 +32,7 @@ that might save you from loading something like [Underscore.js](http://underscor
32
32
  @function up.util.noop
33
33
  @experimental
34
34
  */
35
- 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, detect, documentHasVerticalScrollbar, each, escapeHtml, escapePressed, except, extend, extractOptions, fail, findWithSelf, finishCssAnimate, fixedToAbsolute, forceCompositing, forceRepaint, 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, option, options, parseUrl, pluckData, pluckKey, presence, presentAttr, previewable, reject, remove, requestDataAsArray, requestDataAsQuery, requestDataFromForm, resolvableWhen, resolvedDeferred, resolvedPromise, scrollbarWidth, select, selectorForElement, setMissingAttrs, setTimer, submittedValue, temporaryCss, times, titleFromXhr, toArray, trim, unJQuery, uniq, unresolvableDeferred, unresolvablePromise, unwrapElement, whenReady;
35
+ 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, detect, documentHasVerticalScrollbar, each, escapeHtml, escapePressed, except, extend, extractOptions, fail, findWithSelf, finishCssAnimate, fixedToAbsolute, forceCompositing, forceRepaint, 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, option, options, parseUrl, pluckData, pluckKey, presence, presentAttr, previewable, 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;
36
36
  noop = $.noop;
37
37
 
38
38
  /**
@@ -983,8 +983,8 @@ that might save you from loading something like [Underscore.js](http://underscor
983
983
  position: 'absolute',
984
984
  top: '0',
985
985
  left: '0',
986
- width: '50px',
987
- height: '50px',
986
+ width: '100px',
987
+ height: '100px',
988
988
  overflowY: 'scroll'
989
989
  });
990
990
  $outer.appendTo(document.body);
@@ -1949,19 +1949,26 @@ that might save you from loading something like [Underscore.js](http://underscor
1949
1949
  };
1950
1950
 
1951
1951
  /**
1952
- Throws an [exception](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
1952
+ Throws a [Javascript error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
1953
1953
  with the given message.
1954
1954
 
1955
- The message will also be printed to the [error log](/up.log.error).
1955
+ The message will also be printed to the [error log](/up.log.error). Also a notification will be shown at the bottom of the screen.
1956
1956
 
1957
- Also a notification will be shown at the bottom of the screen.
1957
+ The message may contain [substitution marks](https://developer.mozilla.org/en-US/docs/Web/API/console#Using_string_substitutions).
1958
1958
 
1959
- \#\#\#\# Examples
1959
+ \#\#\# Examples
1960
1960
 
1961
1961
  up.fail('Division by zero')
1962
1962
  up.fail('Unexpected result %o', result)
1963
1963
 
1964
1964
  @function up.fail
1965
+ @param {String} message
1966
+ A message with details about the error.
1967
+
1968
+ The message can contain [substitution marks](https://developer.mozilla.org/en-US/docs/Web/API/console#Using_string_substitutions)
1969
+ like `%s` or `%o`.
1970
+ @param {Array<String>} vars...
1971
+ A list of variables to replace any substitution marks in the error message.
1965
1972
  @experimental
1966
1973
  */
1967
1974
  fail = function() {
@@ -2163,21 +2170,21 @@ that might save you from loading something like [Underscore.js](http://underscor
2163
2170
  return $field.val();
2164
2171
  }
2165
2172
  };
2166
- return {
2167
2173
 
2168
- /**
2169
- @function up.util.sequence
2170
- @internal
2171
- */
2172
- sequence: function() {
2173
- var functions;
2174
- functions = 1 <= arguments.length ? slice.call(arguments, 0) : [];
2175
- return function() {
2176
- return map(functions, function(f) {
2177
- return f();
2178
- });
2179
- };
2180
- },
2174
+ /**
2175
+ @function up.util.sequence
2176
+ @internal
2177
+ */
2178
+ sequence = function() {
2179
+ var functions;
2180
+ functions = 1 <= arguments.length ? slice.call(arguments, 0) : [];
2181
+ return function() {
2182
+ return map(functions, function(f) {
2183
+ return f();
2184
+ });
2185
+ };
2186
+ };
2187
+ return {
2181
2188
  isDetached: isDetached,
2182
2189
  requestDataAsArray: requestDataAsArray,
2183
2190
  requestDataAsQuery: requestDataAsQuery,
@@ -2282,7 +2289,8 @@ that might save you from loading something like [Underscore.js](http://underscor
2282
2289
  identity: identity,
2283
2290
  escapeHtml: escapeHtml,
2284
2291
  DivertibleChain: DivertibleChain,
2285
- submittedValue: submittedValue
2292
+ submittedValue: submittedValue,
2293
+ sequence: sequence
2286
2294
  };
2287
2295
  })($);
2288
2296
 
@@ -2372,7 +2380,7 @@ we can't currently get rid off.
2372
2380
  It also prints substitution strings (e.g. `console.log("From %o to %o", "a", "b")`)
2373
2381
  as a single string if the browser console does not support substitution strings.
2374
2382
 
2375
- \#\#\#\# Example
2383
+ \#\#\# Example
2376
2384
 
2377
2385
  up.browser.puts('log', 'Hi world');
2378
2386
  up.browser.puts('error', 'There was an error in %o', obj);
@@ -2534,7 +2542,7 @@ we can't currently get rid off.
2534
2542
  [string substitution](https://developer.mozilla.org/en-US/docs/Web/API/console#Using_string_substitutions)
2535
2543
  in `console` functions.
2536
2544
 
2537
- \#\#\#\# Example for string substition
2545
+ \#\#\# Example for string substition
2538
2546
 
2539
2547
  console.log("Hello %o!", "Judy");
2540
2548
 
@@ -2705,7 +2713,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2705
2713
  var slice = [].slice;
2706
2714
 
2707
2715
  up.bus = (function($) {
2708
- var boot, emit, emitReset, forgetUpDescription, live, liveUpDescriptions, logEmission, nextUpDescriptionNumber, nobodyPrevents, onEscape, rememberUpDescription, restoreSnapshot, snapshot, u, unbind, upDescriptionNumber, upDescriptionToJqueryDescription, upListenerToJqueryListener, whenEmitted;
2716
+ var boot, consumeAction, emit, emitReset, forgetUpDescription, haltEvent, live, liveUpDescriptions, logEmission, nextUpDescriptionNumber, nobodyPrevents, onEscape, rememberUpDescription, restoreSnapshot, snapshot, u, unbind, upDescriptionNumber, upDescriptionToJqueryDescription, upListenerToJqueryListener, whenEmitted;
2709
2717
  u = up.util;
2710
2718
  liveUpDescriptions = {};
2711
2719
  nextUpDescriptionNumber = 0;
@@ -2768,7 +2776,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2768
2776
  Other than jQuery, Unpoly will silently discard event listeners
2769
2777
  on [unsupported browsers](/up.browser.isSupported).
2770
2778
 
2771
- \#\#\#\# Attaching structured data
2779
+ \#\#\# Attaching structured data
2772
2780
 
2773
2781
  In case you want to attach structured data to the event you're observing,
2774
2782
  you can serialize the data to JSON and put it into an `[up-data]` attribute:
@@ -2782,7 +2790,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2782
2790
  console.log("This is %o who is %o years old", data.name, data.age);
2783
2791
  });
2784
2792
 
2785
- \#\#\#\# Unbinding an event listener
2793
+ \#\#\# Unbinding an event listener
2786
2794
 
2787
2795
  `up.on` returns a function that unbinds the event listeners when called:
2788
2796
 
@@ -2806,7 +2814,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2806
2814
  // Unbind the listener
2807
2815
  up.off('click', listener)
2808
2816
 
2809
- \#\#\#\# Migrating jQuery event handlers to `up.on`
2817
+ \#\#\# Migrating jQuery event handlers to `up.on`
2810
2818
 
2811
2819
  Within the event handler, Unpoly will bind `this` to the
2812
2820
  native DOM element to help you migrate your existing jQuery code to
@@ -2857,7 +2865,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2857
2865
  /**
2858
2866
  Unbinds an event listener previously bound with [`up.on`](/up.on).
2859
2867
 
2860
- \#\#\#\# Example
2868
+ \#\#\# Example
2861
2869
 
2862
2870
  Let's say you are listing to clicks on `.button` elements:
2863
2871
 
@@ -2903,7 +2911,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2903
2911
  Other code can subscribe to events with that name using
2904
2912
  [`up.on`](/up.on) or by [binding a jQuery event listener](http://api.jquery.com/on/) to `document`.
2905
2913
 
2906
- \#\#\#\# Example
2914
+ \#\#\# Example
2907
2915
 
2908
2916
  up.on('my:event', function(event) {
2909
2917
  console.log(event.foo);
@@ -2948,16 +2956,18 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2948
2956
  if (eventProps.hasOwnProperty('message')) {
2949
2957
  niceMessage = eventProps.message;
2950
2958
  delete eventProps.message;
2951
- if (u.isArray(niceMessage)) {
2952
- ref = niceMessage, niceMessage = ref[0], niceMessageArgs = 2 <= ref.length ? slice.call(ref, 1) : [];
2953
- } else {
2954
- niceMessageArgs = [];
2955
- }
2956
- if (niceMessage) {
2957
- if (u.isPresent(eventProps)) {
2958
- return up.puts.apply(up, [niceMessage + " (%s (%o))"].concat(slice.call(niceMessageArgs), [eventName], [eventProps]));
2959
+ if (niceMessage !== false) {
2960
+ if (u.isArray(niceMessage)) {
2961
+ ref = niceMessage, niceMessage = ref[0], niceMessageArgs = 2 <= ref.length ? slice.call(ref, 1) : [];
2959
2962
  } else {
2960
- return up.puts.apply(up, [niceMessage + " (%s)"].concat(slice.call(niceMessageArgs), [eventName]));
2963
+ niceMessageArgs = [];
2964
+ }
2965
+ if (niceMessage) {
2966
+ if (u.isPresent(eventProps)) {
2967
+ return up.puts.apply(up, [niceMessage + " (%s (%o))"].concat(slice.call(niceMessageArgs), [eventName], [eventProps]));
2968
+ } else {
2969
+ return up.puts.apply(up, [niceMessage + " (%s)"].concat(slice.call(niceMessageArgs), [eventName]));
2970
+ }
2961
2971
  }
2962
2972
  }
2963
2973
  } else {
@@ -3036,6 +3046,32 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
3036
3046
  });
3037
3047
  };
3038
3048
 
3049
+ /**
3050
+ Stops the given event from propagating and prevents the default action.
3051
+
3052
+ @function up.bus.haltEvent
3053
+ @internal
3054
+ */
3055
+ haltEvent = function(event) {
3056
+ event.stopImmediatePropagation();
3057
+ event.stopPropagation();
3058
+ return event.preventDefault();
3059
+ };
3060
+
3061
+ /**
3062
+ @function up.bus.consumeAction
3063
+ @internal
3064
+ */
3065
+ consumeAction = function(event) {
3066
+ haltEvent(event);
3067
+ if (event.type !== 'up:action:consumed') {
3068
+ return emit('up:action:consumed', {
3069
+ $element: $(event.target),
3070
+ message: false
3071
+ });
3072
+ }
3073
+ };
3074
+
3039
3075
  /**
3040
3076
  Makes a snapshot of the currently registered event listeners,
3041
3077
  to later be restored through [`up.bus.reset`](/up.bus.reset).
@@ -3149,6 +3185,8 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
3149
3185
  whenEmitted: whenEmitted,
3150
3186
  onEscape: onEscape,
3151
3187
  emitReset: emitReset,
3188
+ haltEvent: haltEvent,
3189
+ consumeAction: consumeAction,
3152
3190
  boot: boot
3153
3191
  };
3154
3192
  })(jQuery);
@@ -3436,36 +3474,23 @@ Toast alerts
3436
3474
  }).call(this);
3437
3475
 
3438
3476
  /**
3439
- Enhancing elements
3440
- ==================
3441
-
3442
- Unpoly keeps a persistent Javascript environment during page transitions.
3443
- If you wire Javascript to run on `ready` or `onload` events, those scripts will
3444
- only run during the initial page load. Subsequently [inserted](/up.replace)
3445
- page fragments will not be compiled.
3446
-
3447
- Let's say your Javascript plugin wants you to call `lightboxify()`
3448
- on links that should open a lightbox. You decide to
3449
- do this for all links with an `lightbox` class:
3450
-
3451
- <a href="river.png" class="lightbox">River</a>
3452
- <a href="ocean.png" class="lightbox">Ocean</a>
3477
+ Custom Javascript
3478
+ =================
3453
3479
 
3454
- You should **avoid** doing this on page load:
3480
+ Every app needs a way to pair Javascript snippets with certain HTML elements,
3481
+ in order to integrate libraries or implement custom behavior.
3455
3482
 
3456
- $(document).on('ready', function() {
3457
- $('a.lightbox').lightboxify();
3458
- });
3483
+ Unpoly lets you organize your Javascript snippets using [compilers](/up.compiler).
3459
3484
 
3460
- Instead you should register a [`compiler`](/up.compiler) for the `a.lightbox` selector:
3485
+ For instance, to activate the [Masonry](http://masonry.desandro.com/) jQuery plugin for every element
3486
+ with a `grid` class, use this compiler:
3461
3487
 
3462
- up.compiler('a.lightbox', function($element) {
3463
- $element.lightboxify();
3488
+ up.compiler('.grid', function($element) {
3489
+ $element.masonry();
3464
3490
  });
3465
3491
 
3466
- The compiler function will be called on matching elements when
3467
- the page loads, or whenever a matching fragment is [updated through Unpoly](/up.replace)
3468
- later.
3492
+ The compiler function will be called on matching elements when the page loads
3493
+ or when a matching fragment is [inserted via AJAX](/up.link) later.
3469
3494
 
3470
3495
  @class up.syntax
3471
3496
  */
@@ -3474,7 +3499,7 @@ later.
3474
3499
  var slice = [].slice;
3475
3500
 
3476
3501
  up.syntax = (function($) {
3477
- var DESTRUCTABLE_CLASS, DESTRUCTORS_KEY, addDestructor, applyCompiler, buildCompiler, clean, compile, compiler, compilers, data, discoverDestructor, insertCompiler, macro, macros, reset, snapshot, u;
3502
+ var DESTRUCTABLE_CLASS, DESTRUCTORS_KEY, addDestructor, applyCompiler, buildCompiler, clean, compile, compiler, compilers, data, discoverDestructors, insertCompiler, macro, macros, reset, snapshot, u;
3478
3503
  u = up.util;
3479
3504
  DESTRUCTABLE_CLASS = 'up-destructable';
3480
3505
  DESTRUCTORS_KEY = 'up-destructors';
@@ -3497,7 +3522,7 @@ later.
3497
3522
  [Angular directives](https://docs.angularjs.org/guide/directive).
3498
3523
 
3499
3524
 
3500
- \#\#\#\# Integrating jQuery plugins
3525
+ \#\#\# Integrating jQuery plugins
3501
3526
 
3502
3527
  `up.compiler` is a great way to integrate jQuery plugins.
3503
3528
  Let's say your Javascript plugin wants you to call `lightboxify()`
@@ -3514,7 +3539,7 @@ later.
3514
3539
  });
3515
3540
 
3516
3541
 
3517
- \#\#\#\# Custom elements
3542
+ \#\#\# Custom elements
3518
3543
 
3519
3544
  You can use `up.compiler` to implement custom elements like this:
3520
3545
 
@@ -3528,7 +3553,7 @@ later.
3528
3553
  });
3529
3554
 
3530
3555
 
3531
- \#\#\#\# Cleaning up after yourself
3556
+ \#\#\# Cleaning up after yourself
3532
3557
 
3533
3558
  If your compiler returns a function, Unpoly will use this as a *destructor* to
3534
3559
  clean up if the element leaves the DOM. Note that in Unpoly the same DOM ad Javascript environment
@@ -3537,7 +3562,7 @@ later.
3537
3562
 
3538
3563
  You should clean up after yourself whenever your compilers have global
3539
3564
  side effects, like a [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval)
3540
- or event handlers bound to the document root.
3565
+ or [event handlers bound to the document root](/up.on).
3541
3566
 
3542
3567
  Here is a version of `<clock>` that updates
3543
3568
  the time every second, and cleans up once it's done. Note how it returns
@@ -3563,7 +3588,7 @@ later.
3563
3588
  of `<clock>` elements.
3564
3589
 
3565
3590
 
3566
- \#\#\#\# Attaching structured data
3591
+ \#\#\# Attaching structured data
3567
3592
 
3568
3593
  In case you want to attach structured data to the event you're observing,
3569
3594
  you can serialize the data to JSON and put it into an `[up-data]` attribute.
@@ -3593,7 +3618,7 @@ later.
3593
3618
  });
3594
3619
 
3595
3620
 
3596
- \#\#\#\# Migrating jQuery event handlers to `up.compiler`
3621
+ \#\#\# Migrating jQuery event handlers to `up.compiler`
3597
3622
 
3598
3623
  Within the compiler, Unpoly will bind `this` to the
3599
3624
  native DOM element to help you migrate your existing jQuery code to
@@ -3640,9 +3665,12 @@ later.
3640
3665
 
3641
3666
  The function may return a destructor function that destroys the compiled
3642
3667
  object before it is removed from the DOM. The destructor is supposed to
3643
- clear global state such as time-outs and event handlers bound to the document.
3668
+ [clear global state](/up.compiler#cleaning-up-after-yourself)
3669
+ such as timeouts and event handlers bound to the document.
3644
3670
  The destructor is *not* expected to remove the element from the DOM, which
3645
3671
  is already handled by [`up.destroy`](/up.destroy).
3672
+
3673
+ The function may also return an array of destructor functions.
3646
3674
  @stable
3647
3675
  */
3648
3676
  compiler = function() {
@@ -3656,7 +3684,7 @@ later.
3656
3684
 
3657
3685
  You can use `up.macro` to register a compiler that sets other UJS attributes.
3658
3686
 
3659
- \#\#\#\# Example
3687
+ \#\#\# Example
3660
3688
 
3661
3689
  You will sometimes find yourself setting the same combination of UJS attributes again and again:
3662
3690
 
@@ -3731,22 +3759,28 @@ later.
3731
3759
  return queue.splice(index, 0, newCompiler);
3732
3760
  };
3733
3761
  applyCompiler = function(compiler, $jqueryElement, nativeElement) {
3734
- var destructor, returnValue, value;
3762
+ var destructor, i, len, ref, results, returnValue, value;
3735
3763
  up.puts((!compiler.isDefault ? "Compiling '%s' on %o" : void 0), compiler.selector, nativeElement);
3736
3764
  if (compiler.keep) {
3737
3765
  value = u.isString(compiler.keep) ? compiler.keep : '';
3738
3766
  $jqueryElement.attr('up-keep', value);
3739
3767
  }
3740
3768
  returnValue = compiler.callback.apply(nativeElement, [$jqueryElement, data($jqueryElement)]);
3741
- if (destructor = discoverDestructor(returnValue)) {
3742
- return addDestructor($jqueryElement, destructor);
3769
+ ref = discoverDestructors(returnValue);
3770
+ results = [];
3771
+ for (i = 0, len = ref.length; i < len; i++) {
3772
+ destructor = ref[i];
3773
+ results.push(addDestructor($jqueryElement, destructor));
3743
3774
  }
3775
+ return results;
3744
3776
  };
3745
- discoverDestructor = function(returnValue) {
3777
+ discoverDestructors = function(returnValue) {
3746
3778
  if (u.isFunction(returnValue)) {
3747
- return returnValue;
3779
+ return [returnValue];
3748
3780
  } else if (u.isArray(returnValue) && u.all(returnValue, u.isFunction)) {
3749
- return u.sequence.apply(u, returnValue);
3781
+ return returnValue;
3782
+ } else {
3783
+ return [];
3750
3784
  }
3751
3785
  };
3752
3786
  addDestructor = function($jqueryElement, destructor) {
@@ -3838,7 +3872,7 @@ later.
3838
3872
 
3839
3873
  Returns an empty object if the element has no `up-data` attribute.
3840
3874
 
3841
- \#\#\#\# Example
3875
+ \#\#\# Example
3842
3876
 
3843
3877
  You have an element with JSON data serialized into an `up-data` attribute:
3844
3878
 
@@ -4190,7 +4224,7 @@ We need to work on this page:
4190
4224
  Note that this will *not* call `location.back()`, but will set
4191
4225
  the link's `up-href` attribute to the actual, previous URL.
4192
4226
 
4193
- \#\#\#\# Under the hood
4227
+ \#\#\# Under the hood
4194
4228
 
4195
4229
  This link ...
4196
4230
 
@@ -4319,13 +4353,13 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4319
4353
  A "viewport" is an element that has scrollbars, e.g. `<body>` or
4320
4354
  a container with `overflow-x: scroll`.
4321
4355
 
4322
- \#\#\#\# Example
4356
+ \#\#\# Example
4323
4357
 
4324
4358
  This will scroll a `<div class="main">...</div>` to a Y-position of 100 pixels:
4325
4359
 
4326
4360
  up.scroll('.main', 100);
4327
4361
 
4328
- \#\#\#\# Animating the scrolling motion
4362
+ \#\#\# Animating the scrolling motion
4329
4363
 
4330
4364
  The scrolling can (optionally) be animated.
4331
4365
 
@@ -4450,9 +4484,9 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4450
4484
 
4451
4485
  By default Unpoly will always reveal an element before
4452
4486
  updating it with Javascript functions like [`up.replace`](/up.replace)
4453
- or UJS behavior like [`[up-target]`](/up-target).
4487
+ or UJS behavior like [`[up-target]`](/a-up-target).
4454
4488
 
4455
- \#\#\#\# How Unpoly finds the viewport
4489
+ \#\#\# How Unpoly finds the viewport
4456
4490
 
4457
4491
  The viewport (the container that is going to be scrolled)
4458
4492
  is the closest parent of the element that is either:
@@ -4462,7 +4496,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4462
4496
  - the `<body>` element
4463
4497
  - an element matching the selector you have configured using `up.layout.config.viewports.push('my-custom-selector')`
4464
4498
 
4465
- \#\#\#\# Fixed elements obstruction the viewport
4499
+ \#\#\# Fixed elements obstruction the viewport
4466
4500
 
4467
4501
  Many applications have a navigation bar fixed to the top or bottom,
4468
4502
  obstructing the view on an element.
@@ -4747,7 +4781,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4747
4781
  [`up.reveal`](/up.reveal) will always try to scroll the viewport closest
4748
4782
  to the element that is being revealed. By default this is the `<body>` element.
4749
4783
 
4750
- \#\#\#\# Example
4784
+ \#\#\# Example
4751
4785
 
4752
4786
  Here is an example for a layout for an e-mail client, showing a list of e-mails
4753
4787
  on the left side and the e-mail text on the right side:
@@ -4797,7 +4831,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4797
4831
  [`up.reveal`](/up.reveal) is aware of fixed elements and will scroll
4798
4832
  the viewport far enough so the revealed element is fully visible.
4799
4833
 
4800
- \#\#\#\# Example
4834
+ \#\#\# Example
4801
4835
 
4802
4836
  <div class="top-nav" up-fixed="top">...</div>
4803
4837
 
@@ -4812,7 +4846,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4812
4846
  [`up.reveal`](/up.reveal) is aware of fixed elements and will scroll
4813
4847
  the viewport far enough so the revealed element is fully visible.
4814
4848
 
4815
- \#\#\#\# Example
4849
+ \#\#\# Example
4816
4850
 
4817
4851
  <div class="bottom-nav" up-fixed="bottom">...</div>
4818
4852
 
@@ -4827,7 +4861,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4827
4861
  [`up.modal`](/up.modal) will move anchored elements to the left so they
4828
4862
  don't appear to move when a modal dialog is opened or closed.
4829
4863
 
4830
- \#\#\#\# Example
4864
+ \#\#\# Example
4831
4865
 
4832
4866
  <div class="bottom-nav" up-fixed="bottom">...</div>
4833
4867
 
@@ -4957,7 +4991,7 @@ are based on this module.
4957
4991
 
4958
4992
  The UJS variant of this is the [`a[up-target]`](/a-up-target) selector.
4959
4993
 
4960
- \#\#\#\# Example
4994
+ \#\#\# Example
4961
4995
 
4962
4996
  Let's say your curent HTML looks like this:
4963
4997
 
@@ -4982,7 +5016,7 @@ are based on this module.
4982
5016
  Note how only `.two` has changed. The update for `.one` was
4983
5017
  discarded, since it didn't match the selector.
4984
5018
 
4985
- \#\#\#\# Appending or prepending instead of replacing
5019
+ \#\#\# Appending or prepending instead of replacing
4986
5020
 
4987
5021
  By default Unpoly will replace the given selector with the same
4988
5022
  selector from a freshly fetched page. Instead of replacing you
@@ -5003,7 +5037,7 @@ are based on this module.
5003
5037
 
5004
5038
  up.replace('.tasks:after', '/page/2')
5005
5039
 
5006
- \#\#\#\# Setting the window title from the server
5040
+ \#\#\# Setting the window title from the server
5007
5041
 
5008
5042
  If the `replace` call changes history, the document title will be set
5009
5043
  to the contents of a `<title>` tag in the response.
@@ -5011,7 +5045,7 @@ are based on this module.
5011
5045
  The server can also change the document title by setting
5012
5046
  an `X-Up-Title` header in the response.
5013
5047
 
5014
- \#\#\#\# Optimizing response rendering
5048
+ \#\#\# Optimizing response rendering
5015
5049
 
5016
5050
  The server is free to optimize Unpoly requests by only rendering the HTML fragment
5017
5051
  that is being updated. The request's `X-Up-Target` header will contain
@@ -5020,7 +5054,7 @@ are based on this module.
5020
5054
  If you are using the `unpoly-rails` gem you can also access the selector via
5021
5055
  `up.target` in all controllers, views and helpers.
5022
5056
 
5023
- \#\#\#\# Events
5057
+ \#\#\# Events
5024
5058
 
5025
5059
  Unpoly will emit [`up:fragment:destroyed`](/up:fragment:destroyed) on the element
5026
5060
  that was replaced and [`up:fragment:inserted`](/up:fragment:inserted) on the new
@@ -5194,7 +5228,7 @@ are based on this module.
5194
5228
  Updates a selector on the current page with the
5195
5229
  same selector from the given HTML string.
5196
5230
 
5197
- \#\#\#\# Example
5231
+ \#\#\# Example
5198
5232
 
5199
5233
  Let's say your curent HTML looks like this:
5200
5234
 
@@ -5461,7 +5495,7 @@ are based on this module.
5461
5495
 
5462
5496
  Emits events [`up:fragment:keep`](/up:fragment:keep) and [`up:fragment:kept`](/up:fragment:kept).
5463
5497
 
5464
- \#\#\#\# Controlling if an element will be kept
5498
+ \#\#\# Controlling if an element will be kept
5465
5499
 
5466
5500
  Unpoly will **only** keep an existing element if:
5467
5501
 
@@ -5615,7 +5649,7 @@ are based on this module.
5615
5649
  When a page fragment has been [inserted or updated](/up.replace),
5616
5650
  this event is [emitted](/up.emit) on the fragment.
5617
5651
 
5618
- \#\#\#\# Example
5652
+ \#\#\# Example
5619
5653
 
5620
5654
  up.on('up:fragment:inserted', function(event, $fragment) {
5621
5655
  console.log("Looks like we have a new %o!", $fragment);
@@ -5827,7 +5861,7 @@ are based on this module.
5827
5861
  /**
5828
5862
  Replaces the given element with a fresh copy fetched from the server.
5829
5863
 
5830
- \#\#\#\# Example
5864
+ \#\#\# Example
5831
5865
 
5832
5866
  up.on('new-mail', function() {
5833
5867
  up.reload('.inbox');
@@ -5892,35 +5926,32 @@ are based on this module.
5892
5926
  Animation
5893
5927
  =========
5894
5928
 
5895
- Whenever you update a page fragment (through methods like
5896
- [`up.replace`](/up.replace) or UJS attributes like [`up-target`](/up-target))
5897
- you can animate the change.
5929
+ Whenever you [update a page fragment](/up-link) you can animate the change.
5898
5930
 
5899
- For instance, when you replace a selector `.list` with a new `.list`
5900
- from the server, you can add an `up-transition="cross-fade"` attribute
5901
- to smoothly fade out the old `.list` while fading in the new `.list`:
5931
+ Let's say you are using an [`up-target`](/a-up-target) link to update an element
5932
+ with content from the server. You can add an attribute [`up-transition`](/a-up-target#up-transition)
5933
+ to smoothly fade out the old element while fading in the new element:
5902
5934
 
5903
5935
  <a href="/users" up-target=".list" up-transition="cross-fade">Show users</a>
5904
5936
 
5905
- Transitions vs. animations
5906
- --------------------------
5937
+ \#\#\# Transitions vs. animations
5907
5938
 
5908
- When we morph between an old an new element, we call it a *transition*.
5939
+ When we morph between an old and a new element, we call it a *transition*.
5909
5940
  In contrast, when we animate a new element without simultaneously removing an
5910
5941
  old element, we call it an *animation*.
5911
5942
 
5912
- An example for an animation is opening a new dialog, which we can animate
5913
- using the `up-animation` attribute:
5943
+ An example for an animation is opening a new dialog. We can animate the appearance
5944
+ of the dialog by adding an [`up-animation`](/up-modal#up-animation) attribute to the opening link:
5914
5945
 
5915
5946
  <a href="/users" up-modal=".list" up-animation="move-from-top">Show users</a>
5916
5947
 
5917
- Predefined animations and transitions
5918
- -------------------------------------
5948
+ \#\#\# Which animations are available?
5919
5949
 
5920
- Unpoly ships with a number of predefined [animations](/up.animate#named-animation)
5921
- and [transitions](/up.morph#named-animation).
5922
- You can also easily [define your own animations](/up.animation)
5923
- or [transitions](/up.transition) using Javascript or CSS.
5950
+ Unpoly ships with a number of [predefined transitions](/up.morph#named-transitions)
5951
+ and [predefined animations](/up.animate#named-animations).
5952
+
5953
+ You can define custom animations using [`up.transition`](/up.transition) and
5954
+ [`up.animation`](/up.animation).
5924
5955
 
5925
5956
  @class up.motion
5926
5957
  */
@@ -5990,7 +6021,7 @@ or [transitions](/up.transition) using Javascript or CSS.
5990
6021
  /**
5991
6022
  Applies the given animation to the given element.
5992
6023
 
5993
- \#\#\#\# Example
6024
+ \#\#\# Example
5994
6025
 
5995
6026
  up.animate('.warning', 'fade-in');
5996
6027
 
@@ -6002,7 +6033,7 @@ or [transitions](/up.transition) using Javascript or CSS.
6002
6033
  easing: 'linear'
6003
6034
  });
6004
6035
 
6005
- \#\#\#\# Named animations
6036
+ \#\#\# Named animations
6006
6037
 
6007
6038
  The following animations are pre-defined:
6008
6039
 
@@ -6020,7 +6051,7 @@ or [transitions](/up.transition) using Javascript or CSS.
6020
6051
 
6021
6052
  You can define additional named animations using [`up.animation`](/up.animation).
6022
6053
 
6023
- \#\#\#\# Animating CSS properties directly
6054
+ \#\#\# Animating CSS properties directly
6024
6055
 
6025
6056
  By passing an object instead of an animation name, you can animate
6026
6057
  the CSS properties of the given element:
@@ -6029,7 +6060,7 @@ or [transitions](/up.transition) using Javascript or CSS.
6029
6060
  $warning.css({ opacity: 0 });
6030
6061
  up.animate($warning, { opacity: 1 });
6031
6062
 
6032
- \#\#\#\# Multiple animations on the same element
6063
+ \#\#\# Multiple animations on the same element
6033
6064
 
6034
6065
  Unpoly doesn't allow more than one concurrent animation on the same element.
6035
6066
 
@@ -6200,7 +6231,7 @@ or [transitions](/up.transition) using Javascript or CSS.
6200
6231
  Note that the transition does not remove any elements from the DOM.
6201
6232
  The first element will remain in the DOM, albeit hidden using `display: none`.
6202
6233
 
6203
- \#\#\#\# Named transitions
6234
+ \#\#\# Named transitions
6204
6235
 
6205
6236
  The following transitions are pre-defined:
6206
6237
 
@@ -6219,7 +6250,7 @@ or [transitions](/up.transition) using Javascript or CSS.
6219
6250
  - `move-to-bottom/fade-in`
6220
6251
  - `move-to-left/move-from-top`
6221
6252
 
6222
- \#\#\#\# Implementation details
6253
+ \#\#\# Implementation details
6223
6254
 
6224
6255
  During a transition both the old and new element occupy
6225
6256
  the same position on the screen.
@@ -6789,7 +6820,7 @@ the user performs the click.
6789
6820
  Only requests with a method of `GET`, `OPTIONS` and `HEAD`
6790
6821
  are considered to be read-only.
6791
6822
 
6792
- \#\#\#\# Example
6823
+ \#\#\# Example
6793
6824
 
6794
6825
  up.ajax('/search', data: { query: 'sunshine' }).then(function(data, status, xhr) {
6795
6826
  console.log('The response body is %o', data);
@@ -6797,7 +6828,7 @@ the user performs the click.
6797
6828
  console.error('The request failed');
6798
6829
  });
6799
6830
 
6800
- \#\#\#\# Events
6831
+ \#\#\# Events
6801
6832
 
6802
6833
  If a network connection is attempted, the proxy will emit
6803
6834
  a [`up:proxy:load`](/up:proxy:load) event with the `request` as its argument.
@@ -6926,7 +6957,7 @@ the user performs the click.
6926
6957
  waiting, **no** additional `up:proxy:slow` events will be triggered.
6927
6958
 
6928
6959
 
6929
- \#\#\#\# Spinners
6960
+ \#\#\# Spinners
6930
6961
 
6931
6962
  You can [listen](/up.on) to the `up:proxy:slow`
6932
6963
  and [`up:proxy:recover`](/up:proxy:recover) events to implement a spinner
@@ -7225,13 +7256,12 @@ Standard HTML links are a poor fit for modern applications:
7225
7256
  - The user sees a "flash" as the browser loads and renders the new page,
7226
7257
  even if large portions of the old and new page are the same (navigation, layout, etc.).
7227
7258
 
7228
- Unpoly fixes this by letting you annotate links with an [`up-target`](/up-target)
7259
+ Unpoly fixes this by letting you annotate links with an [`up-target`](/a-up-target)
7229
7260
  attribute. The value of this attribute is a CSS selector that indicates which page
7230
7261
  fragment to update. The rest of the page will remain unchanged.
7231
7262
 
7232
7263
 
7233
- Example
7234
- -------
7264
+ \#\#\# Example
7235
7265
 
7236
7266
  Let's say we are rendering three pages with a tabbed navigation to switch between screens:
7237
7267
 
@@ -7275,13 +7305,13 @@ with an `up-target` attribute:
7275
7305
 
7276
7306
  Note that instead of `article` you can use any other CSS selector like `#main .article`.
7277
7307
 
7278
- With these [`up-target`](/up-target) annotations Unpoly only updates the targeted part of the screen.
7308
+ With these [`up-target`](/a-up-target) annotations Unpoly only updates the targeted part of the screen.
7279
7309
  The Javascript environment will persist and the user will not see a white flash while the
7280
7310
  new page is loading.
7281
7311
 
7282
7312
 
7283
- Read on
7284
- -------
7313
+ \#\#\# Read on
7314
+
7285
7315
  - You can [animate page transitions](/up.motion) by definining animations for fragments as they enter or leave the screen.
7286
7316
  - The `up-target` mechanism also works with [forms](/up.form).
7287
7317
  - As you switch through pages, Unpoly will [update your browser's location bar and history](/up.history)
@@ -7454,18 +7484,16 @@ Read on
7454
7484
  var handlerWithActiveMark;
7455
7485
  followVariantSelectors.push(selector);
7456
7486
  handlerWithActiveMark = function($link) {
7457
- return up.navigation.withActiveMark($link, {
7458
- enlarge: true
7459
- }, function() {
7487
+ return up.navigation.start($link, function() {
7460
7488
  return handler($link);
7461
7489
  });
7462
7490
  };
7463
7491
  up.on('click', "a" + selector + ", [up-href]" + selector, function(event, $link) {
7464
7492
  if (shouldProcessLinkEvent(event, $link)) {
7465
7493
  if ($link.is('[up-instant]')) {
7466
- return event.preventDefault();
7494
+ return up.bus.haltEvent(event);
7467
7495
  } else {
7468
- event.preventDefault();
7496
+ up.bus.consumeAction(event);
7469
7497
  return handlerWithActiveMark($link);
7470
7498
  }
7471
7499
  } else {
@@ -7474,7 +7502,7 @@ Read on
7474
7502
  });
7475
7503
  return up.on('mousedown', "a" + selector + "[up-instant], [up-href]" + selector + "[up-instant]", function(event, $link) {
7476
7504
  if (shouldProcessLinkEvent(event, $link)) {
7477
- event.preventDefault();
7505
+ up.bus.consumeAction(event);
7478
7506
  return handlerWithActiveMark($link);
7479
7507
  }
7480
7508
  });
@@ -7508,7 +7536,7 @@ Read on
7508
7536
 
7509
7537
  <a href="/posts/5" up-target=".main">Read post</a>
7510
7538
 
7511
- \#\#\#\# Updating multiple fragments
7539
+ \#\#\# Updating multiple fragments
7512
7540
 
7513
7541
  You can update multiple fragments from a single request by separating
7514
7542
  separators with a comma (like in CSS). E.g. if opening a post should
@@ -7517,7 +7545,7 @@ Read on
7517
7545
 
7518
7546
  <a href="/posts/5" up-target=".main, .unread-count">Read post</a>
7519
7547
 
7520
- \#\#\#\# Appending or prepending instead of replacing
7548
+ \#\#\# Appending or prepending instead of replacing
7521
7549
 
7522
7550
  By default Unpoly will replace the given selector with the same
7523
7551
  selector from a freshly fetched page. Instead of replacing you
@@ -7539,7 +7567,7 @@ Read on
7539
7567
  Load more tasks
7540
7568
  </a>
7541
7569
 
7542
- \#\#\#\# Following elements that are no links
7570
+ \#\#\# Following elements that are no links
7543
7571
 
7544
7572
  You can also use `[up-target]` to turn an arbitrary element into a link.
7545
7573
  In this case, put the link's destination into the `up-href` attribute:
@@ -7552,13 +7580,18 @@ Read on
7552
7580
  @selector a[up-target]
7553
7581
  @param {String} up-target
7554
7582
  The CSS selector to replace
7583
+ @param {String} [up-method='get']
7584
+ The HTTP method to use for the request.
7585
+ @param {String} [up-transition='none']
7586
+ The [transition](/up.motion) to use for morphing between the old and new elements.
7555
7587
  @param [up-fail-target='body']
7556
7588
  The selector to replace if the server responds with a non-200 status code.
7589
+ @param {String} [up-fail-transition='none']
7590
+ The [transition](/up.motion) to use for morphing between the old and new elements
7591
+ when the server responds with a non-200 status code.
7557
7592
  @param {String} [up-href]
7558
7593
  The destination URL to follow.
7559
7594
  If omitted, the the link's `href` attribute will be used.
7560
- @param {String} [up-method='get']
7561
- The HTTP method to use for the request.
7562
7595
  @param {String} [up-confirm]
7563
7596
  A message that will be displayed in a cancelable confirmation dialog
7564
7597
  before the link is followed.
@@ -7618,11 +7651,11 @@ Read on
7618
7651
  To only update a fragment instead of the entire page, see
7619
7652
  [`a[up-target]`](/a-up-target).
7620
7653
 
7621
- \#\#\#\# Example
7654
+ \#\#\# Example
7622
7655
 
7623
7656
  <a href="/users" up-follow>User list</a>
7624
7657
 
7625
- \#\#\#\# Turn any element into a link
7658
+ \#\#\# Turn any element into a link
7626
7659
 
7627
7660
  You can also use `[up-follow]` to turn an arbitrary element into a link.
7628
7661
  In this case, put the link's destination into the `up-href` attribute:
@@ -7633,13 +7666,19 @@ Read on
7633
7666
  opening the destination in a new tab.
7634
7667
 
7635
7668
  @selector a[up-follow]
7669
+
7670
+ @param {String} [up-method='get']
7671
+ The HTTP method to use for the request.
7672
+ @param {String} [up-transition='none']
7673
+ The [transition](/up.motion) to use for morphing between the old and new elements.
7636
7674
  @param [up-fail-target='body']
7637
7675
  The selector to replace if the server responds with a non-200 status code.
7676
+ @param {String} [up-fail-transition='none']
7677
+ The [transition](/up.motion) to use for morphing between the old and new elements
7678
+ when the server responds with a non-200 status code.
7638
7679
  @param [up-href]
7639
7680
  The destination URL to follow.
7640
7681
  If omitted, the the link's `href` attribute will be used.
7641
- @param {String} [up-method='get']
7642
- The HTTP method to use for the request.
7643
7682
  @param {String} [up-confirm]
7644
7683
  A message that will be displayed in a cancelable confirmation dialog
7645
7684
  before the link is followed.
@@ -7662,7 +7701,7 @@ Read on
7662
7701
 
7663
7702
  This is done by:
7664
7703
 
7665
- - [Following the link through AJAX](/up-target) instead of a full page load
7704
+ - [Following the link through AJAX](/a-up-target) instead of a full page load
7666
7705
  - [Preloading the link's destination URL](/up-preload)
7667
7706
  - [Triggering the link on `mousedown`](/up-instant) instead of on `click`
7668
7707
 
@@ -7700,9 +7739,9 @@ Read on
7700
7739
  in order to enlarge the link's click area.
7701
7740
 
7702
7741
  `up-expand` honors all the UJS behavior in expanded links
7703
- ([`up-target`](/up-target), [`up-instant`](/up-instant), [`up-preload`](/up-preload), etc.).
7742
+ ([`up-target`](/a-up-target), [`up-instant`](/up-instant), [`up-preload`](/up-preload), etc.).
7704
7743
 
7705
- \#\#\#\# Example
7744
+ \#\#\# Example
7706
7745
 
7707
7746
  <div class="notification" up-expand>
7708
7747
  Record was saved!
@@ -7714,7 +7753,7 @@ Read on
7714
7753
 
7715
7754
  `up-expand` also expands links that open [modals](/up.modal) or [popups](/up.popup).
7716
7755
 
7717
- \#\#\#\# Elements with multiple contained links
7756
+ \#\#\# Elements with multiple contained links
7718
7757
 
7719
7758
  If a container contains more than one link, you can set the value of the
7720
7759
  `up-expand` attribute to a CSS selector to define which link should be expanded:
@@ -7922,14 +7961,14 @@ open dialogs with sub-forms, etc. all without losing form state.
7922
7961
  return u.unresolvablePromise();
7923
7962
  }
7924
7963
  }
7925
- up.navigation.markActive($form);
7964
+ up.navigation.start($form);
7926
7965
  if (!(canAjaxSubmit && canHistoryOption)) {
7927
7966
  $form.get(0).submit();
7928
7967
  return u.unresolvablePromise();
7929
7968
  }
7930
7969
  promise = up.replace(target, url, options);
7931
7970
  promise.always(function() {
7932
- return up.navigation.unmarkActive($form);
7971
+ return up.navigation.stop($form);
7933
7972
  });
7934
7973
  return promise;
7935
7974
  };
@@ -7941,7 +7980,7 @@ open dialogs with sub-forms, etc. all without losing form state.
7941
7980
 
7942
7981
  The UJS variant of this is the [`up-observe`](/up-observe) attribute.
7943
7982
 
7944
- \#\#\#\# Example
7983
+ \#\#\# Example
7945
7984
 
7946
7985
  The following would submit the form whenever the
7947
7986
  text field value changes:
@@ -7954,7 +7993,7 @@ open dialogs with sub-forms, etc. all without losing form state.
7954
7993
  pass, a `<form>` or any container that contains form fields.
7955
7994
  The callback will be run if any of the given fields change.
7956
7995
 
7957
- \#\#\#\# Preventing concurrency
7996
+ \#\#\# Preventing concurrency
7958
7997
 
7959
7998
  Firing asynchronous code after a form field can cause
7960
7999
  [concurrency issues](https://makandracards.com/makandra/961-concurrency-issues-with-find-as-you-type-boxes).
@@ -7964,7 +8003,7 @@ open dialogs with sub-forms, etc. all without losing form state.
7964
8003
  To take advantage of this, your callback code must return a promise.
7965
8004
  Note that all asynchronous Unpoly functions return promises.
7966
8005
 
7967
- \#\#\#\# Throttling
8006
+ \#\#\# Throttling
7968
8007
 
7969
8008
  If you are concerned about fast typists causing too much
7970
8009
  load on your server, you can use a `delay` option to wait
@@ -8098,7 +8137,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8098
8137
  return observe(selectorOrElement, options, function(value, $field) {
8099
8138
  var $form;
8100
8139
  $form = $field.closest('form');
8101
- return up.navigation.withActiveMark($field, function() {
8140
+ return up.navigation.start($field, function() {
8102
8141
  return submit($form);
8103
8142
  });
8104
8143
  });
@@ -8134,7 +8173,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8134
8173
  See the documentation for [`[up-validate]`](/up-validate) for more information
8135
8174
  on how server-side validation works in Unpoly.
8136
8175
 
8137
- \#\#\#\# Example
8176
+ \#\#\# Example
8138
8177
 
8139
8178
  up.validate('input[name=email]', { target: '.email-errors' })
8140
8179
 
@@ -8274,7 +8313,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8274
8313
 
8275
8314
  The programmatic variant of this is the [`up.submit`](/up.submit) function.
8276
8315
 
8277
- \#\#\#\# Failed submission
8316
+ \#\#\# Failed submission
8278
8317
 
8279
8318
  When the server was unable to save the form due to invalid data,
8280
8319
  it will usually re-render an updated copy of the form with
@@ -8307,7 +8346,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8307
8346
  [`up-validate`](/up-validate) attribute to perform server-side
8308
8347
  validations while the user is completing fields.
8309
8348
 
8310
- \#\#\#\# Redirects
8349
+ \#\#\# Redirects
8311
8350
 
8312
8351
  Unpoly requires two additional response headers to detect redirects,
8313
8352
  which are otherwise undetectable for an AJAX client.
@@ -8319,7 +8358,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8319
8358
  If you are using Unpoly via the `unpoly-rails` gem, these headers
8320
8359
  are set automatically for every request.
8321
8360
 
8322
- \#\#\#\# Giving feedback while the form is processing
8361
+ \#\#\# Giving feedback while the form is processing
8323
8362
 
8324
8363
  The `<form>` element will be assigned a CSS class `up-active` while
8325
8364
  the submission is loading.
@@ -8366,7 +8405,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8366
8405
  @stable
8367
8406
  */
8368
8407
  up.on('submit', 'form[up-target]', function(event, $form) {
8369
- event.preventDefault();
8408
+ up.bus.consumeAction(event);
8370
8409
  return submit($form);
8371
8410
  });
8372
8411
 
@@ -8377,7 +8416,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8377
8416
 
8378
8417
  The programmatic variant of this is the [`up.validate`](/up.validate) function.
8379
8418
 
8380
- \#\#\#\# Example
8419
+ \#\#\# Example
8381
8420
 
8382
8421
  Let's look at a standard registration form that asks for an e-mail and password:
8383
8422
 
@@ -8458,7 +8497,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8458
8497
  The `<label>` around the e-mail field is now updated to have the `has-error`
8459
8498
  class and display the validation message.
8460
8499
 
8461
- \#\#\#\# How validation results are displayed
8500
+ \#\#\# How validation results are displayed
8462
8501
 
8463
8502
  Although the server will usually respond to a validation with a complete,
8464
8503
  fresh copy of the form, Unpoly will by default not update the entire form.
@@ -8482,7 +8521,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8482
8521
  <input type="text" name="email" up-validate=".email-errors">
8483
8522
  <span class="email-errors"></span>
8484
8523
 
8485
- \#\#\#\# Updating dependent fields
8524
+ \#\#\# Updating dependent fields
8486
8525
 
8487
8526
  The `[up-validate]` behavior is also a great way to partially update a form
8488
8527
  when one fields depends on the value of another field.
@@ -8519,7 +8558,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8519
8558
  /**
8520
8559
  Show or hide part of a form if certain options are selected or boxes are checked.
8521
8560
 
8522
- \#\#\#\# Example
8561
+ \#\#\# Example
8523
8562
 
8524
8563
  The triggering input gets an `up-switch` attribute with a selector for the elements to show or hide:
8525
8564
 
@@ -8599,7 +8638,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8599
8638
 
8600
8639
  The programmatic variant of this is the [`up.observe`](/up.observe) function.
8601
8640
 
8602
- \#\#\#\# Example
8641
+ \#\#\# Example
8603
8642
 
8604
8643
  The following would run a global `showSuggestions(value)` function
8605
8644
  whenever the `<input>` changes:
@@ -8608,7 +8647,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8608
8647
  <input type="query" up-observe="showSuggestions(value)">
8609
8648
  </form>
8610
8649
 
8611
- \#\#\#\# Callback context
8650
+ \#\#\# Callback context
8612
8651
 
8613
8652
  The script given to `up-observe` runs with the following context:
8614
8653
 
@@ -8637,7 +8676,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8637
8676
 
8638
8677
  The programmatic variant of this is the [`up.autosubmit`](/up.autosubmit) function.
8639
8678
 
8640
- \#\#\#\# Example
8679
+ \#\#\# Example
8641
8680
 
8642
8681
  The following would submit the form whenever the
8643
8682
  text field value changes:
@@ -8696,7 +8735,7 @@ or call the Javascript function [`up.popup.attach`](/up.popup.attach).
8696
8735
 
8697
8736
  For modal dialogs see [up.modal](/up.modal) instead.
8698
8737
 
8699
- \#\#\#\# Customizing the popup design
8738
+ \#\#\# Customizing the popup design
8700
8739
 
8701
8740
  Loading the Unpoly stylesheet will give you a minimal popup design:
8702
8741
 
@@ -8712,7 +8751,7 @@ By default the popup uses the following DOM structure:
8712
8751
  ...
8713
8752
  </div>
8714
8753
 
8715
- \#\#\#\# Closing behavior
8754
+ \#\#\# Closing behavior
8716
8755
 
8717
8756
  The popup closes when the user clicks anywhere outside the popup area.
8718
8757
 
@@ -8870,14 +8909,22 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
8870
8909
  Emits events [`up:popup:open`](/up:popup:open) and [`up:popup:opened`](/up:popup:opened).
8871
8910
 
8872
8911
  @function up.popup.attach
8873
- @param {Element|jQuery|String} elementOrSelector
8912
+ @param {Element|jQuery|String} anchor
8913
+ The element to which the popup will be attached.
8874
8914
  @param {String} [options.url]
8915
+ The URL from which to fetch the popup contents.
8916
+
8917
+ If omitted, the `href` or `up-href` attribute of the anchor element will be used.
8918
+
8919
+ Will be ignored if `options.html` is given.
8875
8920
  @param {String} [options.target]
8876
8921
  A CSS selector that will be extracted from the response and placed into the popup.
8877
8922
  @param {String} [options.position='bottom-right']
8878
8923
  Defines where the popup is attached to the opening element.
8879
8924
 
8880
8925
  Valid values are `bottom-right`, `bottom-left`, `top-right` and `top-left`.
8926
+ @param {String} [options.html]
8927
+ A string of HTML from which to extract the popup contents. No network request will be made.
8881
8928
  @param {String} [options.confirm]
8882
8929
  A message that will be displayed in a cancelable confirmation dialog
8883
8930
  before the modal is being opened.
@@ -9122,7 +9169,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9122
9169
  return attachAsap($link);
9123
9170
  }
9124
9171
  });
9125
- up.on('mousedown', 'body', function(event, $body) {
9172
+ up.on('click up:action:consumed', function(event) {
9126
9173
  var $target;
9127
9174
  $target = $(event.target);
9128
9175
  if (!$target.closest('.up-popup, [up-popup]').length) {
@@ -9158,7 +9205,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9158
9205
  up.on('click', '[up-close]', function(event, $element) {
9159
9206
  if (contains($element)) {
9160
9207
  closeAsap();
9161
- return event.preventDefault();
9208
+ return up.bus.consumeAction(event);
9162
9209
  }
9163
9210
  });
9164
9211
  up.on('up:framework:reset', reset);
@@ -9184,28 +9231,40 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9184
9231
  Modal dialogs
9185
9232
  =============
9186
9233
 
9187
- Instead of [linking to a page fragment](/up.link), you can choose
9188
- to show a fragment in a modal dialog. The existing page will remain
9189
- open in the background and reappear once the modal is closed.
9234
+ Instead of [linking to a page fragment](/up.link), you can choose to show a fragment
9235
+ in a modal dialog. The existing page will remain open in the background.
9190
9236
 
9191
- To open a modal, add an [`up-modal` attribute](/up-modal) to a link,
9192
- or call the Javascript functions [`up.modal.follow`](/up.modal.follow)
9193
- and [`up.modal.visit`](/up.modal.visit).
9194
-
9195
- For smaller popup overlays ("dropdowns") see [up.popup](/up.popup) instead.
9237
+ To open a modal, add an [`up-modal`](/up-modal) attribute to a link:
9238
+
9239
+ <a href="/blogs" up-modal=".blog-list">Switch blog</a>
9240
+
9241
+ When this link is clicked, Unpoly will request the path `/blogs` and extract
9242
+ an element matching the selector `.blog-list` from the response. The matching element
9243
+ will then be placed in a modal dialog.
9244
+
9245
+
9246
+ \#\#\# Closing behavior
9247
+
9248
+ By default the dialog automatically closes
9249
+ *when a link inside a modal changes a fragment behind the modal*.
9250
+ This is useful to have the dialog interact with the page that
9251
+ opened it, e.g. by updating parts of a larger form or by signing in a user
9252
+ and revealing additional information.
9253
+
9254
+ To disable this behavior, give the opening link an [`up-sticky`](/up-modal#up-sticky) attribute:
9196
9255
 
9197
9256
 
9198
- \#\#\#\# Customizing the dialog design
9257
+ \#\#\# Customizing the dialog design
9199
9258
 
9200
- Loading the Unpoly stylesheet will give you a minimal dialog design:
9259
+ Dialogs have a minimal default design:
9201
9260
 
9202
- - Dialog contents are displayed in a white box that is centered vertically and horizontally.
9203
- - There is a a subtle box shadow around the dialog
9261
+ - Contents are displayed in a white box with a subtle box shadow
9204
9262
  - The box will grow to fit the dialog contents, but never grow larger than the screen
9205
- - The box is placed over a semi-transparent background to dim the rest of the page
9263
+ - The box is placed over a semi-transparent backdrop to dim the rest of the page
9206
9264
  - There is a button to close the dialog in the top-right corner
9207
9265
 
9208
- The easiest way to change how the dialog looks is by overriding the [default CSS styles](https://github.com/unpoly/unpoly/blob/master/lib/assets/stylesheets/up/modal.css.sass).
9266
+ The easiest way to change how the dialog looks is by overriding the
9267
+ [default CSS styles](https://github.com/unpoly/unpoly/blob/master/lib/assets/stylesheets/up/modal.css.sass).
9209
9268
 
9210
9269
  By default the dialog uses the following DOM structure:
9211
9270
 
@@ -9214,28 +9273,15 @@ By default the dialog uses the following DOM structure:
9214
9273
  <div class="up-modal-viewport">
9215
9274
  <div class="up-modal-dialog">
9216
9275
  <div class="up-modal-content">
9217
- ...
9276
+ <!-- the matching element will be placed here -->
9218
9277
  </div>
9219
9278
  <div class="up-modal-close" up-close>X</div>
9220
9279
  </div>
9221
9280
  </div>
9222
9281
  </div>
9223
9282
 
9224
- If you want to change the design beyond CSS, you can
9225
- configure Unpoly to [use a different HTML structure](/up.modal.config).
9226
-
9227
-
9228
- \#\#\#\# Closing behavior
9229
-
9230
- By default the dialog automatically closes
9231
- *when a link inside a modal changes a fragment behind the modal*.
9232
- This is useful to have the dialog interact with the page that
9233
- opened it, e.g. by updating parts of a larger form or by signing in a user
9234
- and revealing additional information.
9235
-
9236
- To disable this behavior, give the opening link an `up-sticky` attribute:
9237
-
9238
- <a href="/settings" up-modal=".options" up-sticky>Settings</a>
9283
+ You can change this structure by setting [`up.modal.config.template`](/up.modal.config#config.template) to a new template string
9284
+ or function.
9239
9285
 
9240
9286
 
9241
9287
  @class up.modal
@@ -9253,7 +9299,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9253
9299
  @param {String} [config.history=true]
9254
9300
  Whether opening a modal will add a browser history entry.
9255
9301
  @param {Number} [config.width]
9256
- The width of the dialog as a CSS value like `'400px'` or `50%`.
9302
+ The width of the dialog as a CSS value like `'400px'` or `'50%'`.
9257
9303
 
9258
9304
  Defaults to `undefined`, meaning that the dialog will grow to fit its contents
9259
9305
  until it reaches `config.maxWidth`. Leaving this as `undefined` will
@@ -9793,7 +9839,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9793
9839
  /**
9794
9840
  Register a new modal variant with its own default configuration, CSS or HTML template.
9795
9841
 
9796
- \#\#\#\# Example
9842
+ \#\#\# Example
9797
9843
 
9798
9844
  Let's implement a drawer that slides in from the right:
9799
9845
 
@@ -9914,13 +9960,14 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9914
9960
  up.link.onAction('[up-modal]', function($link) {
9915
9961
  return followAsap($link);
9916
9962
  });
9917
- up.on('click', 'body', function(event, $body) {
9963
+ up.on('click', function(event) {
9918
9964
  var $target;
9919
9965
  if (!state.closable) {
9920
9966
  return;
9921
9967
  }
9922
9968
  $target = $(event.target);
9923
9969
  if (!($target.closest('.up-modal-dialog').length || $target.closest('[up-modal]').length)) {
9970
+ up.bus.consumeAction(event);
9924
9971
  return closeAsap();
9925
9972
  }
9926
9973
  });
@@ -9956,7 +10003,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9956
10003
  up.on('click', '[up-close]', function(event, $element) {
9957
10004
  if (contains($element)) {
9958
10005
  closeAsap();
9959
- return event.preventDefault();
10006
+ return up.bus.consumeAction(event);
9960
10007
  }
9961
10008
  });
9962
10009
  up.on('up:framework:reset', reset);
@@ -9993,7 +10040,7 @@ You can an [`up-tooltip`](/up-tooltip) attribute to any HTML tag to show a toolt
9993
10040
  <a href="/decks" up-tooltip="Show all decks">Decks</a>
9994
10041
 
9995
10042
 
9996
- \#\#\#\# Styling
10043
+ \#\#\# Styling
9997
10044
 
9998
10045
  The [default styles](https://github.com/unpoly/unpoly/blob/master/lib/assets/stylesheets/up/tooltip.css.sass)
9999
10046
  show a simple tooltip with white text on a gray background.
@@ -10118,8 +10165,16 @@ The tooltip element is appended to the end of `<body>`.
10118
10165
 
10119
10166
  @function up.tooltip.attach
10120
10167
  @param {Element|jQuery|String} elementOrSelector
10168
+ @param {String} [options.text]
10169
+ The text to display in the tooltip.
10170
+
10171
+ Any HTML control characters will be escaped.
10172
+ If you need to use HTML formatting in the tooltip, use `options.html` instead.
10121
10173
  @param {String} [options.html]
10122
- The HTML to display in the tooltip.
10174
+ The HTML to display in the tooltip unescaped.
10175
+
10176
+ Make sure to escape any user-provided text before passing it as this option,
10177
+ or use `options.text` (which automatically escapes).
10123
10178
  @param {String} [options.position='top']
10124
10179
  The position of the tooltip.
10125
10180
  Can be `'top'`, `'right'`, `'bottom'` or `'left'`.
@@ -10256,7 +10311,7 @@ The tooltip element is appended to the end of `<body>`.
10256
10311
  return closeAsap();
10257
10312
  });
10258
10313
  });
10259
- up.on('click', 'body', function(event, $body) {
10314
+ up.on('click up:action:consumed', function(event) {
10260
10315
  return closeAsap();
10261
10316
  });
10262
10317
  up.on('up:framework:reset', reset);
@@ -10277,21 +10332,43 @@ The tooltip element is appended to the end of `<body>`.
10277
10332
  Navigation bars
10278
10333
  ===============
10279
10334
 
10280
- Unpoly automatically marks up link elements with classes indicating that
10281
- they are currently loading (class `up-active`) or linking
10282
- to the current location (class `up-current`).
10335
+ Unpoly automatically adds CSS classes to links while they are
10336
+ currently loading ([`.up-active`](/up-active)) or
10337
+ pointing to the current location ([`.up-current`](/up-current)).
10338
+
10339
+ By styling these classes with CSS you can provide instant feedback to user interactions.
10340
+ This improves the perceived speed of your interface.
10341
+
10342
+ \#\#\# Example
10343
+
10344
+ Let's say we have an navigation bar with two links, pointing to `/foo` and `/bar` respectively:
10345
+
10346
+ <a href="/foo" up-follow>Foo</a>
10347
+ <a href="/bar" up-follow>Bar</a>
10348
+
10349
+ If the current URL is `/foo`, the first link is automatically marked with an [`up-current`](/up-current) class:
10350
+
10351
+ <a href="/foo" up-follow class="up-current">Foo</a>
10352
+ <a href="/bar" up-follow>Bar</a>
10353
+
10354
+ When the user clicks on the `/bar` link, the link will receive the [`up-active`](/up-active) class while it is waiting
10355
+ for the server to respond:
10356
+
10357
+ <a href="/foo" up-follow class="up-current">Foo</a>
10358
+ <a href="/bar" up-follow class="up-active">Bar</a>
10359
+
10360
+ Once the response is received the URL will change to `/bar` and the `up-active` class is removed:
10361
+
10362
+ <a href="/foo" up-follow>Foo</a>
10363
+ <a href="/bar" up-follow class="up-current">Bar</a>
10283
10364
 
10284
- This dramatically improves the perceived speed of your user interface
10285
- by providing instant feedback for user interactions.
10286
10365
 
10287
10366
  @class up.navigation
10288
10367
  */
10289
10368
 
10290
10369
  (function() {
10291
- var slice = [].slice;
10292
-
10293
10370
  up.navigation = (function($) {
10294
- var CLASS_ACTIVE, SELECTOR_SECTION, config, currentClass, findClickArea, locationChanged, markActive, normalizeUrl, reset, sectionUrls, u, unmarkActive, urlSet, withActiveMark;
10371
+ var CLASS_ACTIVE, SELECTOR_SECTION, config, currentClass, findActionableArea, locationChanged, normalizeUrl, reset, sectionUrls, start, stop, u, urlSet;
10295
10372
  u = up.util;
10296
10373
 
10297
10374
  /**
@@ -10383,23 +10460,70 @@ by providing instant feedback for user interactions.
10383
10460
  };
10384
10461
 
10385
10462
  /**
10386
- @function findClickArea
10463
+ @function findActionableArea
10387
10464
  @param {String|Element|jQuery} elementOrSelector
10388
- @param {Boolean} options.enlarge
10389
- If `true`, tries to find a containing link that has expanded the link's click area.
10390
- If we find one, we prefer to mark the larger area as active.
10391
10465
  @internal
10392
10466
  */
10393
- findClickArea = function(elementOrSelector, options) {
10467
+ findActionableArea = function(elementOrSelector) {
10394
10468
  var $area;
10395
10469
  $area = $(elementOrSelector);
10396
- options = u.options(options, {
10397
- enlarge: false
10398
- });
10399
- if (options.enlarge) {
10400
- return u.presence($area.parent(SELECTOR_SECTION)) || $area;
10401
- } else {
10402
- return $area;
10470
+ if ($area.is(SELECTOR_SECTION)) {
10471
+ $area = u.presence($area.parent(SELECTOR_SECTION)) || $area;
10472
+ }
10473
+ return $area;
10474
+ };
10475
+
10476
+ /**
10477
+ Marks the given element as currently loading, by assigning the CSS class [`up-active`](/up-active).
10478
+
10479
+ This happens automatically when following links or submitting forms through the Unpoly API.
10480
+ Use this function if you make custom network calls from your own Javascript code.
10481
+
10482
+ If the given element is a link within an [expanded click area](/up-expand),
10483
+ the class will be assigned to the expanded area.
10484
+
10485
+ \#\#\# Example
10486
+
10487
+ var $button = $('button');
10488
+ $button.on('click', function() {
10489
+ up.navigation.start($button);
10490
+ up.ajax(...).always(function() {
10491
+ up.navigation.stop($button);
10492
+ });
10493
+ });
10494
+
10495
+ Or shorter:
10496
+
10497
+ var $button = $('button');
10498
+ $button.on('click', function() {
10499
+ up.navigation.start($button, function() {
10500
+ up.ajax(...);
10501
+ });
10502
+ });
10503
+
10504
+ @method up.navigation.start
10505
+ @param {Element|jQuery|String} elementOrSelector
10506
+ The element to mark as active
10507
+ @param {Function} [action]
10508
+ An optional function to run while the element is marked as loading.
10509
+ The function must return a promise.
10510
+ Once the promise resolves, the element will be [marked as no longer loading](/up.navigation.stop).
10511
+ @internal
10512
+ */
10513
+ start = function(elementOrSelector, action) {
10514
+ var $element, promise;
10515
+ $element = findActionableArea(elementOrSelector);
10516
+ $element.addClass(CLASS_ACTIVE);
10517
+ if (action) {
10518
+ promise = action();
10519
+ if (u.isPromise(promise)) {
10520
+ promise.always(function() {
10521
+ return stop($element);
10522
+ });
10523
+ } else {
10524
+ up.warn('Expected block to return a promise, but got %o', promise);
10525
+ }
10526
+ return promise;
10403
10527
  }
10404
10528
  };
10405
10529
 
@@ -10411,7 +10535,7 @@ by providing instant feedback for user interactions.
10411
10535
  The `up-active` class will be removed as soon as another
10412
10536
  page fragment is added or updated through Unpoly.
10413
10537
 
10414
- \#\#\#\# Example
10538
+ \#\#\# Example
10415
10539
 
10416
10540
  We have a link:
10417
10541
 
@@ -10430,33 +10554,27 @@ by providing instant feedback for user interactions.
10430
10554
  @selector .up-active
10431
10555
  @stable
10432
10556
  */
10433
- markActive = function(elementOrSelector, options) {
10434
- var $element;
10435
- $element = findClickArea(elementOrSelector, options);
10436
- return $element.addClass(CLASS_ACTIVE);
10437
- };
10438
- unmarkActive = function(elementOrSelector, options) {
10557
+
10558
+ /**
10559
+ Marks the given element as no longer loading, by removing the CSS class [`up-active`](/up-active).
10560
+
10561
+ This happens automatically when network requests initiated by the Unpoly API have completed.
10562
+ Use this function if you make custom network calls from your own Javascript code.
10563
+
10564
+ @function up.navigation.stop
10565
+ @param {jQuery} event.$element
10566
+ The link or form that has finished loading.
10567
+ @internal
10568
+ */
10569
+ stop = function(elementOrSelector) {
10439
10570
  var $element;
10440
- $element = findClickArea(elementOrSelector, options);
10571
+ $element = findActionableArea(elementOrSelector);
10572
+ up.emit('up:navigated', {
10573
+ $element: $element,
10574
+ message: false
10575
+ });
10441
10576
  return $element.removeClass(CLASS_ACTIVE);
10442
10577
  };
10443
- withActiveMark = function() {
10444
- var $element, args, block, elementOrSelector, options, promise;
10445
- elementOrSelector = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
10446
- block = args.pop();
10447
- options = u.options(args.pop());
10448
- $element = $(elementOrSelector);
10449
- markActive($element, options);
10450
- promise = block();
10451
- if (u.isPromise(promise)) {
10452
- promise.always(function() {
10453
- return unmarkActive($element, options);
10454
- });
10455
- } else {
10456
- up.warn('Expected block to return a promise, but got %o', promise);
10457
- }
10458
- return promise;
10459
- };
10460
10578
 
10461
10579
  /**
10462
10580
  Links that point to the current location are assigned
@@ -10476,7 +10594,7 @@ by providing instant feedback for user interactions.
10476
10594
  <a href="/bar">Bar</a>
10477
10595
  </nav>
10478
10596
 
10479
- \#\#\#\# What's considered to be "current"?
10597
+ \#\#\# What's considered to be "current"?
10480
10598
 
10481
10599
  The current location is considered to be either:
10482
10600
 
@@ -10516,9 +10634,8 @@ by providing instant feedback for user interactions.
10516
10634
  defaults: function() {
10517
10635
  return up.fail('up.navigation.defaults(...) no longer exists. Set values on he up.navigation.config property instead.');
10518
10636
  },
10519
- markActive: markActive,
10520
- unmarkActive: unmarkActive,
10521
- withActiveMark: withActiveMark
10637
+ start: start,
10638
+ stop: stop
10522
10639
  };
10523
10640
  })(jQuery);
10524
10641