upjs-rails 0.15.1 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1a81edd09a48591324d04f37a58207623cca49ba
4
- data.tar.gz: 13dca17380e69e2b6401677119bd812393cb5b40
3
+ metadata.gz: 005f274cf3a1aeaff81a079b615681027441316b
4
+ data.tar.gz: 3d124a91a4883ee03fc07e5f9d0c32dcd1d5fedd
5
5
  SHA512:
6
- metadata.gz: 3a768370269c498f793ae009dca9a7c3cfa623a37810e02fa34099221b1174a7464b9fe793c06d8ca2718f6d6c787f7ef2f808994845f9e4911e2150fe39b553
7
- data.tar.gz: 4d821a21623420319f9eb77b4c1c6108bc85f66585cb0ab951a19dc54d83c64c57d534c72a787d7f2dc49168720dd3ad28ecfb2d2524548af32aa13d3f58fadf
6
+ metadata.gz: 8b195df6de1a0189651515dffb9bf486bfdf71c9ba9b9784e3f6d6b6c9899cda0cd53c84504b69e9eb4a624cdc74d35a4448d3fa03487e59689b43a5069c186b
7
+ data.tar.gz: 782852940c5b82fb15fe995a8f45a1b174b582d0814e1f7b8b2e5b0d735416065e9962bac2a63f0bc12aec72988165f46cc507da77b3677c03fff0ca155389a6
data/CHANGELOG.md CHANGED
@@ -5,6 +5,35 @@ All notable changes to this project will be documented in this file.
5
5
  This project mostly adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
7
 
8
+ Unreleased
9
+ -----------
10
+
11
+ ### Compatible changes
12
+
13
+ - You can now configure [`up.proxy.config.maxRequests`](/up.proxy.config) to limit
14
+ the maximum number of concurrent requests. Additional
15
+ requests are queued. This currently ignores preloading requests.
16
+
17
+ You might find it useful to set this to `1` in full-stack integration
18
+ tests (e.g. Selenium).
19
+ - Allow to disable animations globally with `up.motion.enabled = false`.
20
+ This can be useful in full-stack integration tests like a Selenium test suite.
21
+ - New function [`up.motion.isEnabled`](/up.motion.isEnabled) to check if animations will be performed.
22
+ - [`up.popup.attach`](/up.popup.attach) now throws a helpful error when trying to attach a popup to a non-existing element
23
+ - New option [`up.modal.config.history`](/up.modal.config) to configure if modals change the browser URL (defaults to `true`)
24
+ - New option [`up.popup.config.history`](/up.popup.config) to configure if popup change the browser URL (defaults to `false`).
25
+ - Fix CSS for popups with a position of `"bottom-left"`.
26
+
27
+ ### Breaking changes
28
+
29
+ - Popups and modals used to close automatically whenever an element behind the overlay was replaced.
30
+ This behavior is still in effect, but only if the replacement was triggered by a link or element from
31
+ within the popup or modal.
32
+ - Popups and modals no longer raise an error if their (hidden) overlay was closed before the
33
+ response was received.
34
+ - Popups and modals are now compiled before they are animated.
35
+
36
+
8
37
  0.15.1
9
38
  ------
10
39
 
data/dist/up.js CHANGED
@@ -1077,39 +1077,34 @@ that might save you from loading something like [Underscore.js](http://underscor
1077
1077
  cssAnimate = function(elementOrSelector, lastFrame, opts) {
1078
1078
  var $element, deferred, endTimeout, transition, withoutCompositing, withoutTransition;
1079
1079
  $element = $(elementOrSelector);
1080
- if (up.browser.canCssTransition()) {
1081
- opts = options(opts, {
1082
- duration: 300,
1083
- delay: 0,
1084
- easing: 'ease'
1085
- });
1086
- deferred = $.Deferred();
1087
- transition = {
1088
- 'transition-property': Object.keys(lastFrame).join(', '),
1089
- 'transition-duration': opts.duration + "ms",
1090
- 'transition-delay': opts.delay + "ms",
1091
- 'transition-timing-function': opts.easing
1092
- };
1093
- withoutCompositing = forceCompositing($element);
1094
- withoutTransition = temporaryCss($element, transition);
1095
- $element.css(lastFrame);
1096
- deferred.then(withoutCompositing);
1097
- deferred.then(withoutTransition);
1098
- $element.data(ANIMATION_PROMISE_KEY, deferred);
1099
- deferred.then(function() {
1100
- return $element.removeData(ANIMATION_PROMISE_KEY);
1101
- });
1102
- endTimeout = setTimeout((function() {
1103
- return deferred.resolve();
1104
- }), opts.duration + opts.delay);
1105
- deferred.then(function() {
1106
- return clearTimeout(endTimeout);
1107
- });
1108
- return deferred;
1109
- } else {
1110
- $element.css(lastFrame);
1111
- return resolvedDeferred();
1112
- }
1080
+ opts = options(opts, {
1081
+ duration: 300,
1082
+ delay: 0,
1083
+ easing: 'ease'
1084
+ });
1085
+ deferred = $.Deferred();
1086
+ transition = {
1087
+ 'transition-property': Object.keys(lastFrame).join(', '),
1088
+ 'transition-duration': opts.duration + "ms",
1089
+ 'transition-delay': opts.delay + "ms",
1090
+ 'transition-timing-function': opts.easing
1091
+ };
1092
+ withoutCompositing = forceCompositing($element);
1093
+ withoutTransition = temporaryCss($element, transition);
1094
+ $element.css(lastFrame);
1095
+ deferred.then(withoutCompositing);
1096
+ deferred.then(withoutTransition);
1097
+ $element.data(ANIMATION_PROMISE_KEY, deferred);
1098
+ deferred.then(function() {
1099
+ return $element.removeData(ANIMATION_PROMISE_KEY);
1100
+ });
1101
+ endTimeout = setTimeout((function() {
1102
+ return deferred.resolve();
1103
+ }), opts.duration + opts.delay);
1104
+ deferred.then(function() {
1105
+ return clearTimeout(endTimeout);
1106
+ });
1107
+ return deferred;
1113
1108
  };
1114
1109
  ANIMATION_PROMISE_KEY = 'up-animation-promise';
1115
1110
 
@@ -2664,16 +2659,18 @@ later.
2664
2659
 
2665
2660
  @function up.hello
2666
2661
  @param {String|Element|jQuery} selectorOrElement
2662
+ @param {String|Element|jQuery} [options.origin]
2667
2663
  @return {jQuery}
2668
2664
  The compiled element
2669
2665
  @stable
2670
2666
  */
2671
- hello = function(selectorOrElement) {
2672
- var $element;
2667
+ hello = function(selectorOrElement, options) {
2668
+ var $element, eventAttrs;
2673
2669
  $element = $(selectorOrElement);
2674
- up.emit('up:fragment:inserted', {
2670
+ eventAttrs = u.options(options, {
2675
2671
  $element: $element
2676
2672
  });
2673
+ up.emit('up:fragment:inserted', eventAttrs);
2677
2674
  return $element;
2678
2675
  };
2679
2676
 
@@ -3564,7 +3561,7 @@ are based on this module.
3564
3561
 
3565
3562
  (function() {
3566
3563
  up.flow = (function($) {
3567
- var autofocus, destroy, elementsInserted, findOldFragment, first, fragmentNotFound, implant, isRealElement, parseImplantSteps, parseResponse, reload, replace, resolveSelector, setSource, source, swapElements, u;
3564
+ var autofocus, destroy, elementsInserted, findOldFragment, first, implant, isRealElement, oldFragmentNotFound, parseImplantSteps, parseResponse, reload, replace, resolveSelector, setSource, source, swapElements, u;
3568
3565
  u = up.util;
3569
3566
  setSource = function(element, sourceUrl) {
3570
3567
  var $element;
@@ -3708,6 +3705,9 @@ are based on this module.
3708
3705
  @param {Object} [options.headers={}]
3709
3706
  An object of additional header key/value pairs to send along
3710
3707
  with the request.
3708
+ @param {Boolean} [options.requireMatch=true]
3709
+ Whether to raise an error if the given selector is missing in
3710
+ either the current page or in the response.
3711
3711
  @return {Promise}
3712
3712
  A promise that will be resolved when the page has been updated.
3713
3713
  @stable
@@ -3795,13 +3795,14 @@ are based on this module.
3795
3795
  @experimental
3796
3796
  */
3797
3797
  implant = function(selectorOrElement, html, options) {
3798
- var $new, $old, j, len, ref, response, results, selector, step;
3798
+ var $new, $old, j, len, ref, ref1, response, results, selector, step;
3799
3799
  selector = resolveSelector(selectorOrElement, options);
3800
3800
  options = u.options(options, {
3801
- historyMethod: 'push'
3801
+ historyMethod: 'push',
3802
+ requireMatch: true
3802
3803
  });
3803
3804
  options.source = u.option(options.source, options.history);
3804
- response = parseResponse(html);
3805
+ response = parseResponse(html, options);
3805
3806
  options.title || (options.title = response.title());
3806
3807
  if (options.saveScroll !== false) {
3807
3808
  up.layout.saveScroll();
@@ -3810,24 +3811,30 @@ are based on this module.
3810
3811
  results = [];
3811
3812
  for (j = 0, len = ref.length; j < len; j++) {
3812
3813
  step = ref[j];
3813
- $old = findOldFragment(step.selector);
3814
- $new = response.find(step.selector).first();
3815
- results.push(swapElements($old, $new, step.pseudoClass, step.transition, options));
3814
+ $old = findOldFragment(step.selector, options);
3815
+ $new = (ref1 = response.find(step.selector)) != null ? ref1.first() : void 0;
3816
+ if ($old && $new) {
3817
+ results.push(swapElements($old, $new, step.pseudoClass, step.transition, options));
3818
+ } else {
3819
+ results.push(void 0);
3820
+ }
3816
3821
  }
3817
3822
  return results;
3818
3823
  };
3819
- findOldFragment = function(selector) {
3820
- return first(".up-popup " + selector) || first(".up-modal " + selector) || first(selector) || fragmentNotFound(selector);
3824
+ findOldFragment = function(selector, options) {
3825
+ return first(".up-popup " + selector) || first(".up-modal " + selector) || first(selector) || oldFragmentNotFound(selector, options);
3821
3826
  };
3822
- fragmentNotFound = function(selector) {
3827
+ oldFragmentNotFound = function(selector, options) {
3823
3828
  var message;
3824
- message = 'Could not find selector %o in current body HTML';
3825
- if (message[0] === '#') {
3826
- message += ' (avoid using IDs)';
3829
+ if (options.requireMatch) {
3830
+ message = 'Could not find selector %o in current body HTML';
3831
+ if (message[0] === '#') {
3832
+ message += ' (avoid using IDs)';
3833
+ }
3834
+ return u.error(message, selector);
3827
3835
  }
3828
- return u.error(message, selector);
3829
3836
  };
3830
- parseResponse = function(html) {
3837
+ parseResponse = function(html, options) {
3831
3838
  var htmlElement;
3832
3839
  htmlElement = u.createElementFromHtml(html);
3833
3840
  return {
@@ -3839,16 +3846,13 @@ are based on this module.
3839
3846
  var child;
3840
3847
  if (child = $.find(selector, htmlElement)[0]) {
3841
3848
  return $(child);
3842
- } else {
3849
+ } else if (options.requireMatch) {
3843
3850
  return u.error("Could not find selector %o in response %o", selector, html);
3844
3851
  }
3845
3852
  }
3846
3853
  };
3847
3854
  };
3848
3855
  elementsInserted = function($new, options) {
3849
- if (typeof options.insert === "function") {
3850
- options.insert($new);
3851
- }
3852
3856
  if (options.history) {
3853
3857
  if (options.title) {
3854
3858
  document.title = options.title;
@@ -3859,7 +3863,9 @@ are based on this module.
3859
3863
  setSource($new, options.source);
3860
3864
  }
3861
3865
  autofocus($new);
3862
- return up.hello($new);
3866
+ return up.hello($new, {
3867
+ origin: options.origin
3868
+ });
3863
3869
  };
3864
3870
  swapElements = function($old, $new, pseudoClass, transition, options) {
3865
3871
  var $wrapper, insertionMethod;
@@ -4138,7 +4144,7 @@ or [transitions](/up.transition) using Javascript or CSS.
4138
4144
 
4139
4145
  (function() {
4140
4146
  up.motion = (function($) {
4141
- var GHOSTING_PROMISE_KEY, animate, animateOptions, animation, animations, assertIsDeferred, config, defaultAnimations, defaultTransitions, findAnimation, finish, finishGhosting, morph, none, prependCopy, reset, resolvableWhen, skipMorph, snapshot, transition, transitions, u, withGhosts;
4147
+ var GHOSTING_PROMISE_KEY, animate, animateOptions, animation, animations, assertIsDeferred, config, defaultAnimations, defaultTransitions, findAnimation, finish, finishGhosting, isEnabled, morph, none, prependCopy, reset, resolvableWhen, skipMorph, snapshot, transition, transitions, u, withGhosts;
4142
4148
  u = up.util;
4143
4149
  animations = {};
4144
4150
  defaultAnimations = {};
@@ -4152,12 +4158,21 @@ or [transitions](/up.transition) using Javascript or CSS.
4152
4158
  @param {Number} [config.duration=300]
4153
4159
  @param {Number} [config.delay=0]
4154
4160
  @param {String} [config.easing='ease']
4161
+ @param {Boolean} [config.enabled=true]
4162
+ Whether animation is enabled.
4163
+
4164
+ Set this to `false` to disable animation globally.
4165
+ This can be useful in full-stack integration tests like a Selenium test suite.
4166
+
4167
+ Regardless of this setting, all animations will be skipped on browsers
4168
+ that do not support [CSS transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions).
4155
4169
  @stable
4156
4170
  */
4157
4171
  config = u.config({
4158
4172
  duration: 300,
4159
4173
  delay: 0,
4160
- easing: 'ease'
4174
+ easing: 'ease',
4175
+ enabled: true
4161
4176
  });
4162
4177
  reset = function() {
4163
4178
  animations = u.copy(defaultAnimations);
@@ -4165,6 +4180,21 @@ or [transitions](/up.transition) using Javascript or CSS.
4165
4180
  return config.reset();
4166
4181
  };
4167
4182
 
4183
+ /**
4184
+ Returns whether Up.js will perform animations.
4185
+
4186
+ Animations will be performed if the browser supports
4187
+ [CSS transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions)
4188
+ and if [`up.motion.config.enabled`](/up.motion.config) is set to `true` (which is the default).
4189
+
4190
+ @function up.motion.isEnabled
4191
+ @return {Boolean}
4192
+ @stable
4193
+ */
4194
+ isEnabled = function() {
4195
+ return config.enabled && up.browser.canCssTransition();
4196
+ };
4197
+
4168
4198
  /**
4169
4199
  Applies the given animation to the given element.
4170
4200
 
@@ -4249,7 +4279,12 @@ or [transitions](/up.transition) using Javascript or CSS.
4249
4279
  } else if (u.isString(animation)) {
4250
4280
  return animate($element, findAnimation(animation), options);
4251
4281
  } else if (u.isHash(animation)) {
4252
- return u.cssAnimate($element, animation, options);
4282
+ if (isEnabled()) {
4283
+ return u.cssAnimate($element, animation, options);
4284
+ } else {
4285
+ $element.css(animation);
4286
+ return u.resolvedDeferred();
4287
+ }
4253
4288
  } else {
4254
4289
  return u.error("Unknown animation type %o", animation);
4255
4290
  }
@@ -4424,7 +4459,7 @@ or [transitions](/up.transition) using Javascript or CSS.
4424
4459
  $new = $(target);
4425
4460
  parsedOptions = u.only(options, 'reveal', 'restoreScroll', 'source');
4426
4461
  parsedOptions = u.extend(parsedOptions, animateOptions(options));
4427
- if (up.browser.canCssTransition()) {
4462
+ if (isEnabled()) {
4428
4463
  finish($old);
4429
4464
  finish($new);
4430
4465
  if (transitionOrName === 'none' || transitionOrName === false || (animation = animations[transitionOrName])) {
@@ -4756,6 +4791,7 @@ or [transitions](/up.transition) using Javascript or CSS.
4756
4791
  transition: transition,
4757
4792
  animation: animation,
4758
4793
  config: config,
4794
+ isEnabled: isEnabled,
4759
4795
  defaults: function() {
4760
4796
  return u.error('up.motion.defaults(...) no longer exists. Set values on he up.motion.config property instead.');
4761
4797
  },
@@ -4832,14 +4868,17 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
4832
4868
  */
4833
4869
 
4834
4870
  (function() {
4871
+ var slice = [].slice;
4872
+
4835
4873
  up.proxy = (function($) {
4836
- var $waitingLink, SAFE_HTTP_METHODS, ajax, alias, busy, busyDelayTimer, busyEventEmitted, cache, cacheKey, cancelBusyDelay, cancelPreloadDelay, checkPreload, clear, config, get, idle, isIdempotent, load, loadEnded, loadStarted, normalizeRequest, pendingCount, preload, preloadDelayTimer, remove, reset, set, startPreloadDelay, u;
4874
+ var $waitingLink, SAFE_HTTP_METHODS, ajax, alias, busy, busyDelayTimer, busyEventEmitted, cache, cacheKey, cancelBusyDelay, cancelPreloadDelay, checkPreload, clear, config, get, idle, isIdempotent, load, loadEnded, loadOrQueue, loadStarted, normalizeRequest, pendingCount, pokeQueue, preload, preloadDelayTimer, queue, queuedRequests, remove, reset, set, startPreloadDelay, u;
4837
4875
  u = up.util;
4838
4876
  $waitingLink = void 0;
4839
4877
  preloadDelayTimer = void 0;
4840
4878
  busyDelayTimer = void 0;
4841
4879
  pendingCount = void 0;
4842
4880
  busyEventEmitted = void 0;
4881
+ queuedRequests = [];
4843
4882
 
4844
4883
  /**
4845
4884
  @property up.proxy.config
@@ -4855,13 +4894,23 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
4855
4894
  @param {Number} [config.busyDelay=300]
4856
4895
  How long the proxy waits until emitting the [`up:proxy:busy` event](/up:proxy:busy).
4857
4896
  Use this to prevent flickering of spinners.
4897
+ @param {Number} [config.maxRequests=4]
4898
+ The maximum number of concurrent requests to allow before additional
4899
+ requests are queued. This currently ignores preloading requests.
4900
+
4901
+ You might find it useful to set this to `1` in full-stack integration
4902
+ tests (e.g. Selenium).
4903
+
4904
+ Note that your browser might [impose its own request limit](http://www.browserscope.org/?category=network)
4905
+ regardless of what you configure here.
4858
4906
  @stable
4859
4907
  */
4860
4908
  config = u.config({
4861
4909
  busyDelay: 300,
4862
4910
  preloadDelay: 75,
4863
4911
  cacheSize: 70,
4864
- cacheExpiry: 1000 * 60 * 5
4912
+ cacheExpiry: 1000 * 60 * 5,
4913
+ maxRequests: 4
4865
4914
  });
4866
4915
  cacheKey = function(request) {
4867
4916
  normalizeRequest(request);
@@ -4966,7 +5015,8 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
4966
5015
  pendingCount = 0;
4967
5016
  config.reset();
4968
5017
  busyEventEmitted = false;
4969
- return cache.clear();
5018
+ cache.clear();
5019
+ return queuedRequests = [];
4970
5020
  };
4971
5021
  reset();
4972
5022
  alias = cache.alias;
@@ -5019,11 +5069,11 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5019
5069
  pending = true;
5020
5070
  if (!isIdempotent(request) && !forceCache) {
5021
5071
  clear();
5022
- promise = load(request);
5072
+ promise = loadOrQueue(request);
5023
5073
  } else if ((promise = get(request)) && !ignoreCache) {
5024
5074
  pending = promise.state() === 'pending';
5025
5075
  } else {
5026
- promise = load(request);
5076
+ promise = loadOrQueue(request);
5027
5077
  set(request, promise);
5028
5078
  promise.fail(function() {
5029
5079
  return remove(request);
@@ -5120,16 +5170,51 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5120
5170
  @event up:proxy:idle
5121
5171
  @stable
5122
5172
  */
5173
+ loadOrQueue = function(request) {
5174
+ if (pendingCount < config.maxRequests) {
5175
+ return load(request);
5176
+ } else {
5177
+ return queue(request);
5178
+ }
5179
+ };
5180
+ queue = function(request) {
5181
+ var deferred, entry;
5182
+ u.debug('Queuing URL %o', request.url);
5183
+ deferred = $.Deferred();
5184
+ entry = {
5185
+ deferred: deferred,
5186
+ request: request
5187
+ };
5188
+ queuedRequests.push(entry);
5189
+ return deferred.promise();
5190
+ };
5123
5191
  load = function(request) {
5124
5192
  var promise;
5125
5193
  u.debug('Loading URL %o', request.url);
5126
5194
  up.emit('up:proxy:load', request);
5127
5195
  promise = u.ajax(request);
5128
5196
  promise.always(function() {
5129
- return up.emit('up:proxy:received', request);
5197
+ up.emit('up:proxy:received', request);
5198
+ return pokeQueue();
5130
5199
  });
5131
5200
  return promise;
5132
5201
  };
5202
+ pokeQueue = function() {
5203
+ var entry, promise;
5204
+ if (entry = queuedRequests.shift()) {
5205
+ promise = load(entry.request);
5206
+ promise.done(function() {
5207
+ var args, ref;
5208
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
5209
+ return (ref = entry.deferred).resolve.apply(ref, args);
5210
+ });
5211
+ return promise.fail(function() {
5212
+ var args, ref;
5213
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
5214
+ return (ref = entry.deferred).reject.apply(ref, args);
5215
+ });
5216
+ }
5217
+ };
5133
5218
 
5134
5219
  /**
5135
5220
  This event is [emitted]/(up.emit) before an [AJAX request](/up.proxy.ajax)
@@ -6331,7 +6416,7 @@ open dialogs with sub-forms, etc. all without losing form state.
6331
6416
  You can change this default behavior by setting `up.config.validateTargets`:
6332
6417
 
6333
6418
  // Always update the entire form containing the current field ("&")
6334
- up.config.validateTargets = ['form &']
6419
+ up.form.config.validateTargets = ['form &']
6335
6420
 
6336
6421
  You can also individually override what to update by setting the `up-validate`
6337
6422
  attribute to a CSS selector:
@@ -6488,7 +6573,7 @@ By default the popup uses the following DOM structure:
6488
6573
  The popup closes when the user clicks anywhere outside the popup area.
6489
6574
 
6490
6575
  By default the popup also closes
6491
- *whenever a page fragment below the popup is updated*.
6576
+ *whenever a page fragment behind the popup is updated*.
6492
6577
  This is useful to have the popup interact with the page that
6493
6578
  opened it, e.g. by updating parts of a larger form or by signing in a user
6494
6579
  and revealing additional information.
@@ -6517,7 +6602,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
6517
6602
  currentUrl = void 0;
6518
6603
 
6519
6604
  /**
6520
- Returns the URL of the page or modal below the popup.
6605
+ Returns the URL of the page or modal behind the popup.
6521
6606
 
6522
6607
  @function up.popup.coveredUrl
6523
6608
  @return {String}
@@ -6541,12 +6626,15 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
6541
6626
  Defines where the popup is attached to the opening element.
6542
6627
 
6543
6628
  Valid values are `bottom-right`, `bottom-left`, `top-right` and `top-left`.
6629
+ @param {String} [config.history=false]
6630
+ Whether opening a popup will add a browser history entry.
6544
6631
  @stable
6545
6632
  */
6546
6633
  config = u.config({
6547
6634
  openAnimation: 'fade-in',
6548
6635
  closeAnimation: 'fade-out',
6549
- position: 'bottom-right'
6636
+ position: 'bottom-right',
6637
+ history: false
6550
6638
  });
6551
6639
  reset = function() {
6552
6640
  close();
@@ -6567,7 +6655,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
6567
6655
  case "bottom-left":
6568
6656
  return {
6569
6657
  left: linkBox.left,
6570
- top: linkBox.bottom + linkBox.height
6658
+ top: linkBox.top + linkBox.height
6571
6659
  };
6572
6660
  case "top-right":
6573
6661
  return {
@@ -6646,15 +6734,17 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
6646
6734
  $popup.hide();
6647
6735
  return $popup;
6648
6736
  };
6649
- updated = function($link, $popup, position, animation, animateOptions) {
6650
- var deferred;
6651
- $popup.show();
6652
- setPosition($link, $popup, position);
6653
- deferred = up.animate($popup, animation, animateOptions);
6654
- deferred.then(function() {
6655
- return up.emit('up:popup:opened');
6656
- });
6657
- return deferred;
6737
+ updated = function($link, position, animation, animateOptions) {
6738
+ var $popup, deferred;
6739
+ $popup = $('.up-popup');
6740
+ if ($popup.is(':hidden')) {
6741
+ $popup.show();
6742
+ setPosition($link, $popup, position);
6743
+ deferred = up.animate($popup, animation, animateOptions);
6744
+ return deferred.then(function() {
6745
+ return up.emit('up:popup:opened');
6746
+ });
6747
+ }
6658
6748
  };
6659
6749
 
6660
6750
  /**
@@ -6666,6 +6756,9 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
6666
6756
  @param {Element|jQuery|String} elementOrSelector
6667
6757
  @param {String} [options.url]
6668
6758
  @param {String} [options.position='bottom-right']
6759
+ Defines where the popup is attached to the opening element.
6760
+
6761
+ Valid values are `bottom-right`, `bottom-left`, `top-right` and `top-left`.
6669
6762
  @param {String} [options.animation]
6670
6763
  The animation to use when opening the popup.
6671
6764
  @param {Number} [options.duration]
@@ -6683,27 +6776,30 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
6683
6776
  @stable
6684
6777
  */
6685
6778
  attach = function(linkOrSelector, options) {
6686
- var $link, $popup, animateOptions, animation, history, position, selector, sticky, url;
6779
+ var $link, animateOptions, animation, history, position, promise, selector, sticky, url;
6687
6780
  $link = $(linkOrSelector);
6781
+ $link.length || u.error('Cannot attach popup to non-existing element %o', linkOrSelector);
6688
6782
  options = u.options(options);
6689
6783
  url = u.option(options.url, $link.attr('href'));
6690
6784
  selector = u.option(options.target, $link.attr('up-popup'), 'body');
6691
6785
  position = u.option(options.position, $link.attr('up-position'), config.position);
6692
6786
  animation = u.option(options.animation, $link.attr('up-animation'), config.openAnimation);
6693
6787
  sticky = u.option(options.sticky, u.castedAttr($link, 'up-sticky'));
6694
- history = up.browser.canPushState() ? u.option(options.history, u.castedAttr($link, 'up-history'), false) : false;
6788
+ history = up.browser.canPushState() ? u.option(options.history, u.castedAttr($link, 'up-history'), config.history) : false;
6695
6789
  animateOptions = up.motion.animateOptions(options, $link);
6696
6790
  close();
6697
6791
  if (up.bus.nobodyPrevents('up:popup:open', {
6698
6792
  url: url
6699
6793
  })) {
6700
- $popup = createHiddenPopup($link, selector, sticky);
6701
- return up.replace(selector, url, {
6794
+ createHiddenPopup($link, selector, sticky);
6795
+ promise = up.replace(selector, url, {
6702
6796
  history: history,
6703
- insert: function() {
6704
- return updated($link, $popup, position, animation, animateOptions);
6705
- }
6797
+ requireMatch: false
6706
6798
  });
6799
+ promise.then(function() {
6800
+ return updated($link, position, animation, animateOptions);
6801
+ });
6802
+ return promise;
6707
6803
  } else {
6708
6804
  return u.unresolvableDeferred();
6709
6805
  }
@@ -6810,14 +6906,19 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
6810
6906
  <a href="/decks" up-popup=".deck_list">Switch deck</a>
6811
6907
 
6812
6908
  If the `up-sticky` attribute is set, the dialog does not auto-close
6813
- if a page fragment below the popup overlay updates:
6909
+ if a page fragment behind the popup overlay updates:
6814
6910
 
6815
6911
  <a href="/decks" up-popup=".deck_list">Switch deck</a>
6816
6912
  <a href="/settings" up-popup=".options" up-sticky>Settings</a>
6817
6913
 
6818
6914
  @selector a[up-popup]
6819
- @param [up-sticky]
6820
6915
  @param [up-position]
6916
+ Defines where the popup is attached to the opening element.
6917
+
6918
+ Valid values are `bottom-right`, `bottom-left`, `top-right` and `top-left`.
6919
+ @param [up-sticky]
6920
+ If set to `true`, the popup remains
6921
+ open even if the page changes in the background.
6821
6922
  @stable
6822
6923
  */
6823
6924
  up.on('click', 'a[up-popup]', function(event, $link) {
@@ -6841,7 +6942,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
6841
6942
  if (newSource = $fragment.attr('up-source')) {
6842
6943
  return currentUrl = newSource;
6843
6944
  }
6844
- } else {
6945
+ } else if (contains(event.origin)) {
6845
6946
  return autoclose();
6846
6947
  }
6847
6948
  });
@@ -6938,7 +7039,7 @@ configure Up.js to [use a different HTML structure](/up.modal.config).
6938
7039
  \#\#\#\# Closing behavior
6939
7040
 
6940
7041
  By default the dialog automatically closes
6941
- *whenever a page fragment below the dialog is updated*.
7042
+ *whenever a page fragment behind the dialog is updated*.
6942
7043
  This is useful to have the dialog interact with the page that
6943
7044
  opened it, e.g. by updating parts of a larger form or by signing in a user
6944
7045
  and revealing additional information.
@@ -6991,6 +7092,8 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
6991
7092
  @param {String} [config.closeAnimation='fade-out']
6992
7093
  The animation used to close the modal. The animation will be applied
6993
7094
  to both the dialog box and the overlay dimming the page.
7095
+ @param {String} [config.history=true]
7096
+ Whether opening a modal will add a browser history entry.
6994
7097
  @stable
6995
7098
  */
6996
7099
  config = u.config({
@@ -6998,6 +7101,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
6998
7101
  minWidth: null,
6999
7102
  width: null,
7000
7103
  height: null,
7104
+ history: true,
7001
7105
  openAnimation: 'fade-in',
7002
7106
  closeAnimation: 'fade-out',
7003
7107
  closeLabel: '×',
@@ -7018,7 +7122,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7018
7122
  currentUrl = void 0;
7019
7123
 
7020
7124
  /**
7021
- Returns the URL of the page below the modal overlay.
7125
+ Returns the URL of the page behind the modal overlay.
7022
7126
 
7023
7127
  @function up.modal.coveredUrl
7024
7128
  @return {String}
@@ -7103,14 +7207,17 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7103
7207
  return unshiftElements.push(unshiftElement);
7104
7208
  });
7105
7209
  };
7106
- updated = function($modal, animation, animateOptions) {
7107
- var deferred;
7108
- shiftElements();
7109
- $modal.show();
7110
- deferred = up.animate($modal, animation, animateOptions);
7111
- return deferred.then(function() {
7112
- return up.emit('up:modal:opened');
7113
- });
7210
+ updated = function(animation, animateOptions) {
7211
+ var $modal, deferred;
7212
+ $modal = $('.up-modal');
7213
+ if ($modal.is(':hidden')) {
7214
+ shiftElements();
7215
+ $modal.show();
7216
+ deferred = up.animate($modal, animation, animateOptions);
7217
+ return deferred.then(function() {
7218
+ return up.emit('up:modal:opened');
7219
+ });
7220
+ }
7114
7221
  };
7115
7222
 
7116
7223
  /**
@@ -7176,7 +7283,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7176
7283
  The CSS selector to extract from the response.
7177
7284
  The extracted content will be placed into the dialog window.
7178
7285
  @param {Object} options
7179
- See options for [previous `up.modal.open` variant](/up.modal.open).
7286
+ See options for [`up.modal.follow`](/up.modal.follow).
7180
7287
  @return {Promise}
7181
7288
  A promise that will be resolved when the popup has been loaded and rendered.
7182
7289
  @stable
@@ -7192,7 +7299,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7192
7299
  @internal
7193
7300
  */
7194
7301
  open = function(options) {
7195
- var $link, $modal, animateOptions, animation, height, history, maxWidth, selector, sticky, url, width;
7302
+ var $link, animateOptions, animation, height, history, maxWidth, promise, selector, sticky, url, width;
7196
7303
  options = u.options(options);
7197
7304
  $link = u.option(options.$link, u.nullJQuery());
7198
7305
  url = u.option(options.url, $link.attr('up-href'), $link.attr('href'));
@@ -7202,25 +7309,27 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7202
7309
  height = u.option(options.height, $link.attr('up-height'), config.height);
7203
7310
  animation = u.option(options.animation, $link.attr('up-animation'), config.openAnimation);
7204
7311
  sticky = u.option(options.sticky, u.castedAttr($link, 'up-sticky'));
7205
- history = up.browser.canPushState() ? u.option(options.history, u.castedAttr($link, 'up-history'), true) : false;
7312
+ history = up.browser.canPushState() ? u.option(options.history, u.castedAttr($link, 'up-history'), config.history) : false;
7206
7313
  animateOptions = up.motion.animateOptions(options, $link);
7207
7314
  close();
7208
7315
  if (up.bus.nobodyPrevents('up:modal:open', {
7209
7316
  url: url
7210
7317
  })) {
7211
- $modal = createHiddenModal({
7318
+ createHiddenModal({
7212
7319
  selector: selector,
7213
7320
  width: width,
7214
7321
  maxWidth: maxWidth,
7215
7322
  height: height,
7216
7323
  sticky: sticky
7217
7324
  });
7218
- return up.replace(selector, url, {
7325
+ promise = up.replace(selector, url, {
7219
7326
  history: history,
7220
- insert: function() {
7221
- return updated($modal, animation, animateOptions);
7222
- }
7327
+ requireMatch: false
7328
+ });
7329
+ promise.then(function() {
7330
+ return updated(animation, animateOptions);
7223
7331
  });
7332
+ return promise;
7224
7333
  } else {
7225
7334
  return u.unresolvableDeferred();
7226
7335
  }
@@ -7367,7 +7476,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7367
7476
  if (newSource = $fragment.attr('up-source')) {
7368
7477
  return currentUrl = newSource;
7369
7478
  }
7370
- } else if (!up.popup.contains($fragment)) {
7479
+ } else if (!up.popup.contains($fragment) && contains(event.origin)) {
7371
7480
  return autoclose();
7372
7481
  }
7373
7482
  });
@@ -7597,7 +7706,7 @@ The tooltip element is appended to the end of `<body>`.
7597
7706
  /**
7598
7707
  Displays a tooltip with HTML content when hovering the mouse over this element:
7599
7708
 
7600
- <a href="/decks" up-tooltip="Show &lt;b&gt;all&lt;/b&gt; decks">Decks</a>
7709
+ <a href="/decks" up-tooltip-html="Show &lt;b&gt;all&lt;/b&gt; decks">Decks</a>
7601
7710
 
7602
7711
  @selector [up-tooltip-html]
7603
7712
  @stable