upjs-rails 0.15.1 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
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