upjs-rails 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
data/dist/up.js CHANGED
@@ -22,10 +22,10 @@ If you use them in your own code, you will get hurt.
22
22
  */
23
23
 
24
24
  (function() {
25
- var __slice = [].slice;
25
+ var slice = [].slice;
26
26
 
27
27
  up.util = (function() {
28
- var $createElementFromSelector, ANIMATION_PROMISE_KEY, CONSOLE_PLACEHOLDERS, ajax, castsToFalse, castsToTrue, clientSize, contains, copy, copyAttributes, createElement, createElementFromHtml, createSelectorFromElement, cssAnimate, debug, detect, each, error, escapePressed, extend, findWithSelf, finishCssAnimate, forceCompositing, get, ifGiven, isArray, isBlank, isDeferred, isDefined, isFunction, isGiven, isHash, isJQuery, isMissing, isNull, isObject, isPresent, isPromise, isStandardPort, isString, isUndefined, keys, last, locationFromXhr, measure, merge, methodFromXhr, nextFrame, normalizeMethod, normalizeUrl, only, option, options, prependGhost, presence, presentAttr, resolvableWhen, resolvedDeferred, resolvedPromise, select, setMissingAttrs, stringSet, stringifyConsoleArgs, temporaryCss, toArray, trim, unwrap;
28
+ var $createElementFromSelector, ANIMATION_PROMISE_KEY, CONSOLE_PLACEHOLDERS, ajax, castsToFalse, castsToTrue, clientSize, contains, copy, copyAttributes, createElement, createElementFromHtml, createSelectorFromElement, cssAnimate, debug, detect, each, error, escapePressed, extend, findWithSelf, finishCssAnimate, forceCompositing, get, ifGiven, isArray, isBlank, isDeferred, isDefined, isFunction, isGiven, isHash, isJQuery, isMissing, isNull, isObject, isPresent, isPromise, isStandardPort, isString, isUndefined, isUnmodifiedKeyEvent, isUnmodifiedMouseEvent, keys, last, locationFromXhr, measure, merge, methodFromXhr, nextFrame, normalizeMethod, normalizeUrl, only, option, options, prependGhost, presence, presentAttr, resolvableWhen, resolvedDeferred, resolvedPromise, select, setMissingAttrs, stringSet, stringifyConsoleArgs, temporaryCss, toArray, trim, unwrap;
29
29
  get = function(url, options) {
30
30
  options = options || {};
31
31
  options.url = url;
@@ -82,7 +82,7 @@ If you use them in your own code, you will get hurt.
82
82
  return normalized;
83
83
  };
84
84
 
85
- /*
85
+ /**
86
86
  @method up.util.normalizeMethod
87
87
  @protected
88
88
  */
@@ -94,17 +94,17 @@ If you use them in your own code, you will get hurt.
94
94
  }
95
95
  };
96
96
  $createElementFromSelector = function(selector) {
97
- var $element, $parent, $root, classes, conjunction, depthSelector, expression, html, id, iteration, path, tag, _i, _j, _len, _len1;
97
+ var $element, $parent, $root, classes, conjunction, depthSelector, expression, html, id, iteration, j, k, len, len1, path, tag;
98
98
  path = selector.split(/[ >]/);
99
99
  $root = null;
100
- for (iteration = _i = 0, _len = path.length; _i < _len; iteration = ++_i) {
100
+ for (iteration = j = 0, len = path.length; j < len; iteration = ++j) {
101
101
  depthSelector = path[iteration];
102
102
  conjunction = depthSelector.match(/(^|\.|\#)[A-Za-z0-9\-_]+/g);
103
103
  tag = "div";
104
104
  classes = [];
105
105
  id = null;
106
- for (_j = 0, _len1 = conjunction.length; _j < _len1; _j++) {
107
- expression = conjunction[_j];
106
+ for (k = 0, len1 = conjunction.length; k < len1; k++) {
107
+ expression = conjunction[k];
108
108
  switch (expression[0]) {
109
109
  case ".":
110
110
  classes.push(expression.substr(1));
@@ -144,16 +144,16 @@ If you use them in your own code, you will get hurt.
144
144
  return element;
145
145
  };
146
146
  debug = function() {
147
- var args, group, message, placeHolderCount, value, _ref;
148
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
147
+ var args, group, message, placeHolderCount, ref, value;
148
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
149
149
  args = toArray(args);
150
150
  message = args.shift();
151
151
  message = "[UP] " + message;
152
- placeHolderCount = ((_ref = message.match(CONSOLE_PLACEHOLDERS)) != null ? _ref.length : void 0) || 0;
152
+ placeHolderCount = ((ref = message.match(CONSOLE_PLACEHOLDERS)) != null ? ref.length : void 0) || 0;
153
153
  if (isFunction(last(args)) && placeHolderCount < args.length) {
154
154
  group = args.pop();
155
155
  }
156
- value = console.debug.apply(console, [message].concat(__slice.call(args)));
156
+ value = console.debug.apply(console, [message].concat(slice.call(args)));
157
157
  if (group) {
158
158
  console.groupCollapsed();
159
159
  try {
@@ -166,7 +166,7 @@ If you use them in your own code, you will get hurt.
166
166
  };
167
167
  error = function() {
168
168
  var $error, args, asString;
169
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
169
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
170
170
  args[0] = "[UP] " + args[0];
171
171
  console.error.apply(console, args);
172
172
  asString = stringifyConsoleArgs(args);
@@ -200,7 +200,7 @@ If you use them in your own code, you will get hurt.
200
200
  });
201
201
  };
202
202
  createSelectorFromElement = function($element) {
203
- var classString, classes, id, klass, selector, _i, _len;
203
+ var classString, classes, id, j, klass, len, selector;
204
204
  debug("Creating selector from element %o", $element);
205
205
  classes = (classString = $element.attr("class")) ? classString.split(" ") : [];
206
206
  id = $element.attr("id");
@@ -208,8 +208,8 @@ If you use them in your own code, you will get hurt.
208
208
  if (id) {
209
209
  selector += "#" + id;
210
210
  }
211
- for (_i = 0, _len = classes.length; _i < _len; _i++) {
212
- klass = classes[_i];
211
+ for (j = 0, len = classes.length; j < len; j++) {
212
+ klass = classes[j];
213
213
  selector += "." + klass;
214
214
  }
215
215
  return selector;
@@ -246,10 +246,10 @@ If you use them in your own code, you will get hurt.
246
246
  extend = $.extend;
247
247
  trim = $.trim;
248
248
  keys = Object.keys || function(object) {
249
- var key, result, _i, _len;
249
+ var j, key, len, result;
250
250
  result = [];
251
- for (_i = 0, _len = object.length; _i < _len; _i++) {
252
- key = object[_i];
251
+ for (j = 0, len = object.length; j < len; j++) {
252
+ key = object[j];
253
253
  if (object.hasOwnProperty(key)) {
254
254
  result.push(key);
255
255
  }
@@ -257,13 +257,13 @@ If you use them in your own code, you will get hurt.
257
257
  return result;
258
258
  };
259
259
  each = function(collection, block) {
260
- var index, item, _i, _len, _results;
261
- _results = [];
262
- for (index = _i = 0, _len = collection.length; _i < _len; index = ++_i) {
260
+ var index, item, j, len, results;
261
+ results = [];
262
+ for (index = j = 0, len = collection.length; j < len; index = ++j) {
263
263
  item = collection[index];
264
- _results.push(block(item, index));
264
+ results.push(block(item, index));
265
265
  }
266
- return _results;
266
+ return results;
267
267
  };
268
268
  isNull = function(object) {
269
269
  return object === null;
@@ -374,11 +374,11 @@ If you use them in your own code, you will get hurt.
374
374
  @param {Array} args...
375
375
  */
376
376
  option = function() {
377
- var arg, args, match, value, _i, _len;
378
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
377
+ var arg, args, j, len, match, value;
378
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
379
379
  match = null;
380
- for (_i = 0, _len = args.length; _i < _len; _i++) {
381
- arg = args[_i];
380
+ for (j = 0, len = args.length; j < len; j++) {
381
+ arg = args[j];
382
382
  value = arg;
383
383
  if (isFunction(value)) {
384
384
  value = value();
@@ -391,10 +391,10 @@ If you use them in your own code, you will get hurt.
391
391
  return match;
392
392
  };
393
393
  detect = function(array, tester) {
394
- var element, match, _i, _len;
394
+ var element, j, len, match;
395
395
  match = null;
396
- for (_i = 0, _len = array.length; _i < _len; _i++) {
397
- element = array[_i];
396
+ for (j = 0, len = array.length; j < len; j++) {
397
+ element = array[j];
398
398
  if (tester(element)) {
399
399
  match = element;
400
400
  break;
@@ -414,15 +414,15 @@ If you use them in your own code, you will get hurt.
414
414
  };
415
415
  presentAttr = function() {
416
416
  var $element, attrName, attrNames, values;
417
- $element = arguments[0], attrNames = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
417
+ $element = arguments[0], attrNames = 2 <= arguments.length ? slice.call(arguments, 1) : [];
418
418
  values = (function() {
419
- var _i, _len, _results;
420
- _results = [];
421
- for (_i = 0, _len = attrNames.length; _i < _len; _i++) {
422
- attrName = attrNames[_i];
423
- _results.push($element.attr(attrName));
419
+ var j, len, results;
420
+ results = [];
421
+ for (j = 0, len = attrNames.length; j < len; j++) {
422
+ attrName = attrNames[j];
423
+ results.push($element.attr(attrName));
424
424
  }
425
- return _results;
425
+ return results;
426
426
  })();
427
427
  return detect(values, isPresent);
428
428
  };
@@ -535,13 +535,17 @@ If you use them in your own code, you will get hurt.
535
535
  };
536
536
  ANIMATION_PROMISE_KEY = 'up-animation-promise';
537
537
 
538
- /*
538
+ /**
539
539
  Completes the animation for the given element by jumping
540
540
  to the last frame instantly. All callbacks chained to
541
541
  the original animation's promise will be called.
542
542
 
543
543
  Does nothing if the given element is not currently animating.
544
544
 
545
+ Also see [`up.motion.finish`](/up.motion#up.motion.finish).
546
+
547
+ @method up.util.finishCssAnimate
548
+ @protected
545
549
  @param {Element|jQuery|String} elementOrSelector
546
550
  */
547
551
  finishCssAnimate = function(elementOrSelector) {
@@ -574,18 +578,18 @@ If you use them in your own code, you will get hurt.
574
578
  return box;
575
579
  };
576
580
  copyAttributes = function($source, $target) {
577
- var attr, _i, _len, _ref, _results;
578
- _ref = $source.get(0).attributes;
579
- _results = [];
580
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
581
- attr = _ref[_i];
581
+ var attr, j, len, ref, results;
582
+ ref = $source.get(0).attributes;
583
+ results = [];
584
+ for (j = 0, len = ref.length; j < len; j++) {
585
+ attr = ref[j];
582
586
  if (attr.specified) {
583
- _results.push($target.attr(attr.name, attr.value));
587
+ results.push($target.attr(attr.name, attr.value));
584
588
  } else {
585
- _results.push(void 0);
589
+ results.push(void 0);
586
590
  }
587
591
  }
588
- return _results;
592
+ return results;
589
593
  };
590
594
  prependGhost = function($element) {
591
595
  var $ghost, dimensions;
@@ -626,17 +630,23 @@ If you use them in your own code, you will get hurt.
626
630
  return xhr.getResponseHeader('X-Up-Method');
627
631
  };
628
632
  only = function() {
629
- var filtered, key, keys, object, _i, _len;
630
- object = arguments[0], keys = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
633
+ var filtered, j, key, keys, len, object;
634
+ object = arguments[0], keys = 2 <= arguments.length ? slice.call(arguments, 1) : [];
631
635
  filtered = {};
632
- for (_i = 0, _len = keys.length; _i < _len; _i++) {
633
- key = keys[_i];
636
+ for (j = 0, len = keys.length; j < len; j++) {
637
+ key = keys[j];
634
638
  if (object.hasOwnProperty(key)) {
635
639
  filtered[key] = object[key];
636
640
  }
637
641
  }
638
642
  return filtered;
639
643
  };
644
+ isUnmodifiedKeyEvent = function(event) {
645
+ return !(event.metaKey || event.shiftKey || event.ctrlKey);
646
+ };
647
+ isUnmodifiedMouseEvent = function(event) {
648
+ return event.button === 0 && isUnmodifiedKeyEvent(event);
649
+ };
640
650
  resolvedDeferred = function() {
641
651
  var deferred;
642
652
  deferred = $.Deferred();
@@ -648,7 +658,7 @@ If you use them in your own code, you will get hurt.
648
658
  };
649
659
  resolvableWhen = function() {
650
660
  var deferreds, joined;
651
- deferreds = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
661
+ deferreds = 1 <= arguments.length ? slice.call(arguments, 0) : [];
652
662
  joined = $.when.apply($, deferreds);
653
663
  joined.resolve = function() {
654
664
  return each(deferreds, function(deferred) {
@@ -658,20 +668,20 @@ If you use them in your own code, you will get hurt.
658
668
  return joined;
659
669
  };
660
670
  setMissingAttrs = function($element, attrs) {
661
- var key, value, _results;
662
- _results = [];
671
+ var key, results, value;
672
+ results = [];
663
673
  for (key in attrs) {
664
674
  value = attrs[key];
665
675
  if (isMissing($element.attr(key))) {
666
- _results.push($element.attr(key, value));
676
+ results.push($element.attr(key, value));
667
677
  } else {
668
- _results.push(void 0);
678
+ results.push(void 0);
669
679
  }
670
680
  }
671
- return _results;
681
+ return results;
672
682
  };
673
683
  stringSet = function(array) {
674
- var includes, includesAny, key, put, set, string, _i, _len;
684
+ var includes, includesAny, j, key, len, put, set, string;
675
685
  set = {};
676
686
  includes = function(string) {
677
687
  return set[key(string)];
@@ -685,8 +695,8 @@ If you use them in your own code, you will get hurt.
685
695
  key = function(string) {
686
696
  return "_" + string;
687
697
  };
688
- for (_i = 0, _len = array.length; _i < _len; _i++) {
689
- string = array[_i];
698
+ for (j = 0, len = array.length; j < len; j++) {
699
+ string = array[j];
690
700
  put(string);
691
701
  }
692
702
  return {
@@ -732,6 +742,8 @@ If you use them in your own code, you will get hurt.
732
742
  isDeferred: isDeferred,
733
743
  isHash: isHash,
734
744
  ifGiven: ifGiven,
745
+ isUnmodifiedKeyEvent: isUnmodifiedKeyEvent,
746
+ isUnmodifiedMouseEvent: isUnmodifiedMouseEvent,
735
747
  unwrap: unwrap,
736
748
  nextFrame: nextFrame,
737
749
  measure: measure,
@@ -772,7 +784,7 @@ Browser interface
772
784
  */
773
785
 
774
786
  (function() {
775
- var __slice = [].slice;
787
+ var slice = [].slice;
776
788
 
777
789
  up.browser = (function() {
778
790
  var canCssAnimation, canInputEvent, canPushState, ensureConsoleExists, ensureRecentJquery, isSupported, loadPage, memoize, u, url;
@@ -807,16 +819,16 @@ Browser interface
807
819
  return location.href;
808
820
  };
809
821
  ensureConsoleExists = function() {
810
- var noop, _base, _base1, _base2, _base3, _base4, _base5, _base6;
822
+ var base, base1, base2, base3, base4, base5, base6, noop;
811
823
  window.console || (window.console = {});
812
824
  noop = function() {};
813
- (_base = window.console).log || (_base.log = noop);
814
- (_base1 = window.console).info || (_base1.info = noop);
815
- (_base2 = window.console).error || (_base2.error = noop);
816
- (_base3 = window.console).debug || (_base3.debug = noop);
817
- (_base4 = window.console).group || (_base4.group = noop);
818
- (_base5 = window.console).groupCollapsed || (_base5.groupCollapsed = noop);
819
- return (_base6 = window.console).groupEnd || (_base6.groupEnd = noop);
825
+ (base = window.console).log || (base.log = noop);
826
+ (base1 = window.console).info || (base1.info = noop);
827
+ (base2 = window.console).error || (base2.error = noop);
828
+ (base3 = window.console).debug || (base3.debug = noop);
829
+ (base4 = window.console).group || (base4.group = noop);
830
+ (base5 = window.console).groupCollapsed || (base5.groupCollapsed = noop);
831
+ return (base6 = window.console).groupEnd || (base6.groupEnd = noop);
820
832
  };
821
833
  memoize = function(func) {
822
834
  var cache, cached;
@@ -824,7 +836,7 @@ Browser interface
824
836
  cached = false;
825
837
  return function() {
826
838
  var args;
827
- args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
839
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
828
840
  if (cached) {
829
841
  return cache;
830
842
  } else {
@@ -895,7 +907,7 @@ We need to work on this page:
895
907
  */
896
908
 
897
909
  (function() {
898
- var __slice = [].slice;
910
+ var slice = [].slice;
899
911
 
900
912
  up.bus = (function() {
901
913
  var callbacksByEvent, callbacksFor, defaultCallbacksByEvent, emit, listen, reset, snapshot, u;
@@ -914,14 +926,14 @@ We need to work on this page:
914
926
  @method up.bus.snapshot
915
927
  */
916
928
  snapshot = function() {
917
- var callbacks, event, _results;
929
+ var callbacks, event, results;
918
930
  defaultCallbacksByEvent = {};
919
- _results = [];
931
+ results = [];
920
932
  for (event in callbacksByEvent) {
921
933
  callbacks = callbacksByEvent[event];
922
- _results.push(defaultCallbacksByEvent[event] = u.copy(callbacks));
934
+ results.push(defaultCallbacksByEvent[event] = u.copy(callbacks));
923
935
  }
924
- return _results;
936
+ return results;
925
937
  };
926
938
 
927
939
  /**
@@ -960,7 +972,7 @@ We need to work on this page:
960
972
  */
961
973
  emit = function() {
962
974
  var args, callbacks, eventName;
963
- eventName = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
975
+ eventName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
964
976
  u.debug("Emitting event %o with args %o", eventName, args);
965
977
  callbacks = callbacksFor(eventName);
966
978
  return u.each(callbacks, function(callback) {
@@ -977,6 +989,139 @@ We need to work on this page:
977
989
 
978
990
  }).call(this);
979
991
 
992
+ /**
993
+ Viewport scrolling
994
+ ==================
995
+
996
+ This modules contains functions to scroll the viewport and reveal contained elements.
997
+
998
+ By default Up.js will always scroll to an element before updating it.
999
+
1000
+ @class up.viewport
1001
+ */
1002
+
1003
+ (function() {
1004
+ up.viewport = (function() {
1005
+ var SCROLL_PROMISE_KEY, config, defaults, finishScrolling, reveal, scroll, u;
1006
+ u = up.util;
1007
+ config = {
1008
+ duration: 0,
1009
+ view: 'body',
1010
+ easing: 'swing'
1011
+ };
1012
+
1013
+ /**
1014
+ @method up.viewport.defaults
1015
+ @param {Number} [options.duration]
1016
+ @param {String} [options.easing]
1017
+ @param {Number} [options.padding]
1018
+ @param {String|Element|jQuery} [options.view]
1019
+ */
1020
+ defaults = function(options) {
1021
+ return u.extend(config, options);
1022
+ };
1023
+ SCROLL_PROMISE_KEY = 'up-scroll-promise';
1024
+
1025
+ /**
1026
+ @method up.scroll
1027
+ @param {String|Element|jQuery} viewOrSelector
1028
+ @param {Number} scrollPos
1029
+ @param {String}[options.duration]
1030
+ @param {String}[options.easing]
1031
+ @returns {Deferred}
1032
+ @protected
1033
+ */
1034
+ scroll = function(viewOrSelector, scrollPos, options) {
1035
+ var $view, deferred, duration, easing, targetProps;
1036
+ $view = $(viewOrSelector);
1037
+ options = u.options(options);
1038
+ duration = u.option(options.duration, config.duration);
1039
+ easing = u.option(options.easing, config.easing);
1040
+ finishScrolling($view);
1041
+ if (duration > 0) {
1042
+ deferred = $.Deferred();
1043
+ $view.data(SCROLL_PROMISE_KEY, deferred);
1044
+ deferred.then(function() {
1045
+ $view.removeData(SCROLL_PROMISE_KEY);
1046
+ return $view.finish();
1047
+ });
1048
+ targetProps = {
1049
+ scrollTop: scrollPos
1050
+ };
1051
+ $view.animate(targetProps, {
1052
+ duration: duration,
1053
+ easing: easing,
1054
+ complete: function() {
1055
+ return deferred.resolve();
1056
+ }
1057
+ });
1058
+ return deferred;
1059
+ } else {
1060
+ $view.scrollTop(scrollPos);
1061
+ return u.resolvedDeferred();
1062
+ }
1063
+ };
1064
+
1065
+ /**
1066
+ @method up.viewport.finishScrolling
1067
+ @private
1068
+ */
1069
+ finishScrolling = function(elementOrSelector) {
1070
+ return $(elementOrSelector).each(function() {
1071
+ var existingScrolling;
1072
+ if (existingScrolling = $(this).data(SCROLL_PROMISE_KEY)) {
1073
+ return existingScrolling.resolve();
1074
+ }
1075
+ });
1076
+ };
1077
+
1078
+ /**
1079
+ @method up.reveal
1080
+ @param {String|Element|jQuery} element
1081
+ @param {String|Element|jQuery} [options.view]
1082
+ @param {Number} [options.duration]
1083
+ @param {String} [options.easing]
1084
+ @param {Number} [options.padding]
1085
+ @returns {Deferred}
1086
+ @protected
1087
+ */
1088
+ reveal = function(elementOrSelector, options) {
1089
+ var $element, $view, elementTooHigh, elementTooLow, elementTop, firstVisibleRow, lastVisibleRow, padding, scrollPos, view, viewHeight;
1090
+ options = u.options(options);
1091
+ view = u.option(options.view, config.view);
1092
+ padding = u.option(options.padding, config.padding);
1093
+ $element = $(elementOrSelector);
1094
+ $view = $(view);
1095
+ viewHeight = $view.height();
1096
+ scrollPos = $view.scrollTop();
1097
+ firstVisibleRow = scrollPos;
1098
+ lastVisibleRow = scrollPos + viewHeight;
1099
+ elementTop = $element.position().top;
1100
+ elementTooHigh = elementTop - padding < firstVisibleRow;
1101
+ elementTooLow = elementTop > lastVisibleRow - padding;
1102
+ if (elementTooHigh || elementTooLow) {
1103
+ scrollPos = elementTop - padding;
1104
+ scrollPos = Math.max(scrollPos, 0);
1105
+ scrollPos = Math.min(scrollPos, viewHeight - 1);
1106
+ return scroll($view, scrollPos, options);
1107
+ } else {
1108
+ return u.resolvedDeferred();
1109
+ }
1110
+ };
1111
+ return {
1112
+ reveal: reveal,
1113
+ scroll: scroll,
1114
+ finishScrolling: finishScrolling,
1115
+ defaults: defaults
1116
+ };
1117
+ })();
1118
+
1119
+ up.scroll = up.viewport.scroll;
1120
+
1121
+ up.reveal = up.viewport.reveal;
1122
+
1123
+ }).call(this);
1124
+
980
1125
  /**
981
1126
  Changing page fragments programmatically
982
1127
  ========================================
@@ -997,7 +1142,7 @@ We need to work on this page:
997
1142
 
998
1143
  (function() {
999
1144
  up.flow = (function() {
1000
- var autofocus, destroy, elementsInserted, implant, implantSteps, reload, replace, reset, setSource, source, swapElements, u;
1145
+ var autofocus, destroy, elementsInserted, findOldFragment, implant, parseImplantSteps, parseResponse, prepareForReplacement, reload, replace, reset, reveal, setSource, source, swapElements, u;
1001
1146
  u = up.util;
1002
1147
  setSource = function(element, sourceUrl) {
1003
1148
  var $element;
@@ -1033,6 +1178,7 @@ We need to work on this page:
1033
1178
  If set to `false`, the history will remain unchanged.
1034
1179
  @param {String|Boolean} [options.source=true]
1035
1180
  @param {String} [options.transition]
1181
+ @param {String} [options.scroll='body']
1036
1182
  @param {String} [options.historyMethod='push']
1037
1183
  */
1038
1184
  replace = function(selectorOrElement, url, options) {
@@ -1087,34 +1233,69 @@ We need to work on this page:
1087
1233
  @param {String} [options.title]
1088
1234
  @param {String} [options.source]
1089
1235
  @param {Object} [options.transition]
1236
+ @param {String} [options.scroll='body']
1090
1237
  @param {String} [options.history]
1091
1238
  @param {String} [options.historyMethod='push']
1092
1239
  */
1093
1240
  implant = function(selector, html, options) {
1094
- var $new, $old, fragment, htmlElement, step, _i, _len, _ref, _ref1, _results;
1241
+ var $new, $old, j, len, ref, response, results, step;
1095
1242
  options = u.options(options, {
1096
1243
  historyMethod: 'push'
1097
1244
  });
1098
- if (options.history === 'false') {
1245
+ if (u.castsToFalse(options.history)) {
1099
1246
  options.history = null;
1100
1247
  }
1248
+ if (u.castsToFalse(options.scroll)) {
1249
+ options.scroll = null;
1250
+ }
1101
1251
  options.source = u.option(options.source, options.history);
1252
+ response = parseResponse(html);
1253
+ options.title || (options.title = response.title());
1254
+ ref = parseImplantSteps(selector, options);
1255
+ results = [];
1256
+ for (j = 0, len = ref.length; j < len; j++) {
1257
+ step = ref[j];
1258
+ $old = findOldFragment(step.selector);
1259
+ $new = response.find(step.selector);
1260
+ results.push(prepareForReplacement($old, options).then(function() {
1261
+ return swapElements($old, $new, step.pseudoClass, step.transition, options);
1262
+ }));
1263
+ }
1264
+ return results;
1265
+ };
1266
+ findOldFragment = function(selector) {
1267
+ return u.presence($(".up-popup " + selector)) || u.presence($(".up-modal " + selector)) || u.presence($(selector)) || u.error('Could not find selector %o in current body HTML', selector);
1268
+ };
1269
+ parseResponse = function(html) {
1270
+ var htmlElement;
1102
1271
  htmlElement = u.createElementFromHtml(html);
1103
- options.title || (options.title = (_ref = htmlElement.querySelector("title")) != null ? _ref.textContent : void 0);
1104
- _ref1 = implantSteps(selector, options);
1105
- _results = [];
1106
- for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
1107
- step = _ref1[_i];
1108
- up.motion.finish(step.selector);
1109
- $old = u.presence($(".up-popup " + step.selector)) || u.presence($(".up-modal " + step.selector)) || u.presence($(step.selector)) || u.error('Could not find selector %o in current body HTML', step.selector);
1110
- if (fragment = htmlElement.querySelector(step.selector)) {
1111
- $new = $(fragment);
1112
- _results.push(swapElements($old, $new, step.pseudoClass, step.transition, options));
1113
- } else {
1114
- _results.push(u.error("Could not find selector %o in response %o", step.selector, html));
1272
+ return {
1273
+ title: function() {
1274
+ var ref;
1275
+ return (ref = htmlElement.querySelector("title")) != null ? ref.textContent : void 0;
1276
+ },
1277
+ find: function(selector) {
1278
+ var child;
1279
+ if (child = htmlElement.querySelector(selector)) {
1280
+ return $(child);
1281
+ } else {
1282
+ return u.error("Could not find selector %o in response %o", selector, html);
1283
+ }
1115
1284
  }
1285
+ };
1286
+ };
1287
+ prepareForReplacement = function($element, options) {
1288
+ up.motion.finish($element);
1289
+ return reveal($element, options.scroll);
1290
+ };
1291
+ reveal = function($element, view) {
1292
+ if (view) {
1293
+ return up.reveal($element, {
1294
+ view: view
1295
+ });
1296
+ } else {
1297
+ return u.resolvedDeferred();
1116
1298
  }
1117
- return _results;
1118
1299
  };
1119
1300
  elementsInserted = function($new, options) {
1120
1301
  if (typeof options.insert === "function") {
@@ -1143,7 +1324,7 @@ We need to work on this page:
1143
1324
  } else {
1144
1325
  return destroy($old, {
1145
1326
  animation: function() {
1146
- $new.insertAfter($old);
1327
+ $new.insertBefore($old);
1147
1328
  elementsInserted($new, options);
1148
1329
  if ($old.is('body') && transition !== 'none') {
1149
1330
  u.error('Cannot apply transitions to body-elements (%o)', transition);
@@ -1153,26 +1334,26 @@ We need to work on this page:
1153
1334
  });
1154
1335
  }
1155
1336
  };
1156
- implantSteps = function(selector, options) {
1157
- var comma, disjunction, i, selectorAtom, selectorParts, transition, transitionString, transitions, _i, _len, _results;
1337
+ parseImplantSteps = function(selector, options) {
1338
+ var comma, disjunction, i, j, len, results, selectorAtom, selectorParts, transition, transitionString, transitions;
1158
1339
  transitionString = options.transition || options.animation || 'none';
1159
1340
  comma = /\ *,\ */;
1160
1341
  disjunction = selector.split(comma);
1161
1342
  if (u.isPresent(transitionString)) {
1162
1343
  transitions = transitionString.split(comma);
1163
1344
  }
1164
- _results = [];
1165
- for (i = _i = 0, _len = disjunction.length; _i < _len; i = ++_i) {
1345
+ results = [];
1346
+ for (i = j = 0, len = disjunction.length; j < len; i = ++j) {
1166
1347
  selectorAtom = disjunction[i];
1167
1348
  selectorParts = selectorAtom.match(/^(.+?)(?:\:(before|after))?$/);
1168
1349
  transition = transitions[i] || u.last(transitions);
1169
- _results.push({
1350
+ results.push({
1170
1351
  selector: selectorParts[1],
1171
1352
  pseudoClass: selectorParts[2],
1172
1353
  transition: transition
1173
1354
  });
1174
1355
  }
1175
- return _results;
1356
+ return results;
1176
1357
  };
1177
1358
  autofocus = function($element) {
1178
1359
  var $control, selector;
@@ -1284,7 +1465,7 @@ We need to work on this page:
1284
1465
  */
1285
1466
 
1286
1467
  (function() {
1287
- var __slice = [].slice;
1468
+ var slice = [].slice;
1288
1469
 
1289
1470
  up.magic = (function() {
1290
1471
  var DESTROYABLE_CLASS, DESTROYER_KEY, applyAwakener, awaken, awakeners, compile, data, defaultAwakeners, defaultLiveDescriptions, destroy, live, liveDescriptions, onEscape, ready, reset, snapshot, u;
@@ -1311,7 +1492,7 @@ We need to work on this page:
1311
1492
  liveDescriptions = [];
1312
1493
  defaultLiveDescriptions = null;
1313
1494
  live = function(events, selector, behavior) {
1314
- var description, _ref;
1495
+ var description, ref;
1315
1496
  if (!up.browser.isSupported()) {
1316
1497
  return;
1317
1498
  }
@@ -1321,7 +1502,7 @@ We need to work on this page:
1321
1502
  }
1322
1503
  ];
1323
1504
  liveDescriptions.push(description);
1324
- return (_ref = $(document)).on.apply(_ref, description);
1505
+ return (ref = $(document)).on.apply(ref, description);
1325
1506
  };
1326
1507
 
1327
1508
  /**
@@ -1349,7 +1530,7 @@ We need to work on this page:
1349
1530
  defaultAwakeners = null;
1350
1531
  awaken = function() {
1351
1532
  var args, awakener, options, selector;
1352
- selector = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
1533
+ selector = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
1353
1534
  if (!up.browser.isSupported()) {
1354
1535
  return;
1355
1536
  }
@@ -1373,25 +1554,25 @@ We need to work on this page:
1373
1554
  }
1374
1555
  };
1375
1556
  compile = function($fragment) {
1376
- var $matches, awakener, _i, _len, _results;
1557
+ var $matches, awakener, i, len, results;
1377
1558
  u.debug("Compiling fragment %o", $fragment);
1378
- _results = [];
1379
- for (_i = 0, _len = awakeners.length; _i < _len; _i++) {
1380
- awakener = awakeners[_i];
1559
+ results = [];
1560
+ for (i = 0, len = awakeners.length; i < len; i++) {
1561
+ awakener = awakeners[i];
1381
1562
  $matches = u.findWithSelf($fragment, awakener.selector);
1382
1563
  if ($matches.length) {
1383
1564
  if (awakener.batch) {
1384
- _results.push(applyAwakener(awakener, $matches, $matches.get()));
1565
+ results.push(applyAwakener(awakener, $matches, $matches.get()));
1385
1566
  } else {
1386
- _results.push($matches.each(function() {
1567
+ results.push($matches.each(function() {
1387
1568
  return applyAwakener(awakener, $(this), this);
1388
1569
  }));
1389
1570
  }
1390
1571
  } else {
1391
- _results.push(void 0);
1572
+ results.push(void 0);
1392
1573
  }
1393
1574
  }
1394
- return _results;
1575
+ return results;
1395
1576
  };
1396
1577
  destroy = function($fragment) {
1397
1578
  return u.findWithSelf($fragment, "." + DESTROYABLE_CLASS).each(function() {
@@ -1402,7 +1583,7 @@ We need to work on this page:
1402
1583
  });
1403
1584
  };
1404
1585
 
1405
- /*
1586
+ /**
1406
1587
  Checks if the given element has an `up-data` attribute.
1407
1588
  If yes, parses the attribute value as JSON and returns the parsed object.
1408
1589
 
@@ -1415,6 +1596,22 @@ We need to work on this page:
1415
1596
  @method up.magic.data
1416
1597
  @param {String|Element|jQuery} elementOrSelector
1417
1598
  */
1599
+
1600
+ /*
1601
+ Stores a JSON-string with the element.
1602
+
1603
+ If an element annotated with [`up-data`] is inserted into the DOM,
1604
+ Up will parse the JSON and pass the resulting object to any matching
1605
+ [`up.awaken`](/up.magic#up.magic.awaken) handlers.
1606
+
1607
+ Similarly, when an event is triggered on an element annotated with
1608
+ [`up-data`], the parsed object will be passed to any matching
1609
+ [`up.on`](/up.magic#up.on) handlers.
1610
+
1611
+ @ujs
1612
+ @method [up-data]
1613
+ @param {JSON} [up-data]
1614
+ */
1418
1615
  data = function(elementOrSelector) {
1419
1616
  var $element, json;
1420
1617
  $element = $(elementOrSelector);
@@ -1446,11 +1643,11 @@ We need to work on this page:
1446
1643
  @method up.magic.reset
1447
1644
  */
1448
1645
  reset = function() {
1449
- var description, _i, _len, _ref;
1450
- for (_i = 0, _len = liveDescriptions.length; _i < _len; _i++) {
1451
- description = liveDescriptions[_i];
1646
+ var description, i, len, ref;
1647
+ for (i = 0, len = liveDescriptions.length; i < len; i++) {
1648
+ description = liveDescriptions[i];
1452
1649
  if (!u.contains(defaultLiveDescriptions, description)) {
1453
- (_ref = $(document)).off.apply(_ref, description);
1650
+ (ref = $(document)).off.apply(ref, description);
1454
1651
  }
1455
1652
  }
1456
1653
  liveDescriptions = u.copy(defaultLiveDescriptions);
@@ -1622,21 +1819,21 @@ We need to work on this page:
1622
1819
  up.motion = (function() {
1623
1820
  var GHOSTING_PROMISE_KEY, animate, animation, animations, assertIsDeferred, config, defaultAnimations, defaultTransitions, defaults, findAnimation, finish, finishGhosting, morph, none, reset, resolvableWhen, snapshot, transition, transitions, u, withGhosts;
1624
1821
  u = up.util;
1822
+ animations = {};
1823
+ defaultAnimations = {};
1824
+ transitions = {};
1825
+ defaultTransitions = {};
1625
1826
  config = {
1626
1827
  duration: 300,
1627
1828
  delay: 0,
1628
1829
  easing: 'ease'
1629
1830
  };
1630
- animations = {};
1631
- defaultAnimations = {};
1632
- transitions = {};
1633
- defaultTransitions = {};
1634
1831
 
1635
1832
  /**
1636
1833
  @method up.modal.defaults
1637
- @param {Number} options.duration
1638
- @param {Number} options.delay
1639
- @param {String} options.easing
1834
+ @param {Number} [options.duration]
1835
+ @param {Number} [options.delay]
1836
+ @param {String} [options.easing]
1640
1837
  */
1641
1838
  defaults = function(options) {
1642
1839
  return u.extend(config, options);
@@ -1726,13 +1923,14 @@ We need to work on this page:
1726
1923
  return promise;
1727
1924
  };
1728
1925
 
1729
- /*
1926
+ /**
1730
1927
  Completes all animations and transitions for the given element
1731
1928
  by jumping to the last animation frame instantly. All callbacks chained to
1732
1929
  the original animation's promise will be called.
1733
1930
 
1734
1931
  Does nothing if the given element is not currently animating.
1735
1932
 
1933
+ @method up.motion.finish
1736
1934
  @param {Element|jQuery|String} elementOrSelector
1737
1935
  */
1738
1936
  finish = function(elementOrSelector) {
@@ -2026,10 +2224,12 @@ Caching and preloading
2026
2224
  ======================
2027
2225
 
2028
2226
  All HTTP requests go through the Up.js proxy.
2029
- It caches a limited number
2227
+ It caches a [limited](/up.proxy#up.proxy.defaults) number of server responses
2228
+ for a [limited](/up.proxy#up.proxy.defaults) amount of time,
2229
+ making requests to these URLs return insantly.
2030
2230
 
2031
- The cache is cleared whenever the user makes a nonGET` request
2032
- (like `POST`, `PUT`, `DELETE`).
2231
+ The cache is cleared whenever the user makes a non-`GET` request
2232
+ (like `POST`, `PUT` or `DELETE`).
2033
2233
 
2034
2234
  The proxy can also used to speed up reaction times by preloading
2035
2235
  links when the user hovers over the click area (or puts the mouse/finger
@@ -2043,16 +2243,16 @@ response will already be cached when the user performs the click.
2043
2243
  up.proxy = (function() {
2044
2244
  var $waitingLink, SAFE_HTTP_METHODS, ajax, alias, cache, cacheKey, cancelDelay, checkPreload, clear, config, defaults, delayTimer, ensureIsIdempotent, get, isFresh, isIdempotent, normalizeRequest, preload, remove, reset, set, startDelay, timestamp, touch, trim, u;
2045
2245
  config = {
2046
- preloadDelay: 50,
2246
+ preloadDelay: 75,
2047
2247
  cacheSize: 70,
2048
2248
  cacheExpiry: 1000 * 60 * 5
2049
2249
  };
2050
2250
 
2051
2251
  /**
2052
2252
  @method up.proxy.defaults
2053
- @param {Number} [preloadDelay]
2054
- @param {Number} [cacheSize]
2055
- @param {Number} [cacheExpiry]
2253
+ @param {Number} [options.preloadDelay]
2254
+ @param {Number} [options.cacheSize]
2255
+ @param {Number} [options.cacheExpiry]
2056
2256
  The number of milliseconds until a cache entry expires.
2057
2257
  */
2058
2258
  defaults = function(options) {
@@ -2111,11 +2311,19 @@ response will already be cached when the user performs the click.
2111
2311
  }
2112
2312
  };
2113
2313
 
2114
- /*
2314
+ /**
2315
+ Makes a request to the given URL and caches the response.
2316
+ If the response was already cached, returns the HTML instantly.
2317
+
2318
+ If requesting a URL that is not read-only, the response will
2319
+ not be cached and the entire cache will be cleared.
2320
+ Only requests with a method of `GET`, `OPTIONS` and `HEAD`
2321
+ are considered to be read-only.
2322
+
2115
2323
  @method up.proxy.ajax
2116
- @param {String} options.url
2117
- @param {String} [options.method='GET']
2118
- @param {String} [options.selector]
2324
+ @param {String} request.url
2325
+ @param {String} [request.method='GET']
2326
+ @param {String} [request.selector]
2119
2327
  */
2120
2328
  ajax = function(request) {
2121
2329
  var promise;
@@ -2211,7 +2419,7 @@ response will already be cached when the user performs the click.
2211
2419
  };
2212
2420
  up.bus.on('framework:reset', reset);
2213
2421
 
2214
- /*
2422
+ /**
2215
2423
  Links with an `up-preload` attribute will silently fetch their target
2216
2424
  when the user hovers over the click area, or when the user puts her
2217
2425
  mouse/finger down (before releasing). This way the
@@ -2219,6 +2427,10 @@ response will already be cached when the user performs the click.
2219
2427
  making the interaction feel instant.
2220
2428
 
2221
2429
  @method [up-preload]
2430
+ @param [[up-delay]=50]
2431
+ The number of milliseconds to wait between hovering
2432
+ and preloading. Increasing this will lower the load in your server,
2433
+ but will also make the interaction feel less instant.
2222
2434
  @ujs
2223
2435
  */
2224
2436
  up.on('mouseover mousedown touchstart', '[up-preload]', function(event, $element) {
@@ -2316,7 +2528,7 @@ Read on
2316
2528
 
2317
2529
  (function() {
2318
2530
  up.link = (function() {
2319
- var childClicked, follow, resolve, u, visit;
2531
+ var activeInstantLink, childClicked, follow, resolve, u, visit;
2320
2532
  u = up.util;
2321
2533
 
2322
2534
  /**
@@ -2351,6 +2563,9 @@ Read on
2351
2563
  or to `body` if such an attribute does not exist.
2352
2564
  @param {Function|String} [options.transition]
2353
2565
  A transition function or name.
2566
+ @param {Element|jQuery|String} scroll
2567
+ An element or selector that will be scrolled to the top in
2568
+ case the replaced element is not visible in the viewport.
2354
2569
  */
2355
2570
  follow = function(link, options) {
2356
2571
  var $link, selector, url;
@@ -2360,6 +2575,7 @@ Read on
2360
2575
  selector = u.option(options.target, $link.attr('up-target'), 'body');
2361
2576
  options.transition = u.option(options.transition, $link.attr('up-transition'), $link.attr('up-animation'));
2362
2577
  options.history = u.option(options.history, $link.attr('up-history'));
2578
+ options.scroll = u.option(options.history, $link.attr('up-scroll'), 'body');
2363
2579
  return up.replace(selector, url, options);
2364
2580
  };
2365
2581
  resolve = function(element) {
@@ -2404,13 +2620,13 @@ Read on
2404
2620
  }
2405
2621
  });
2406
2622
  up.on('mousedown', 'a[up-target][up-instant]', function(event, $link) {
2407
- if (event.which === 1) {
2623
+ if (activeInstantLink(event, $link)) {
2408
2624
  event.preventDefault();
2409
- return follow($link);
2625
+ return up.follow($link);
2410
2626
  }
2411
2627
  });
2412
2628
 
2413
- /*
2629
+ /**
2414
2630
  @method up.link.childClicked
2415
2631
  @private
2416
2632
  */
@@ -2420,6 +2636,9 @@ Read on
2420
2636
  $targetLink = $target.closest('a, [up-follow]');
2421
2637
  return $targetLink.length && $link.find($targetLink).length;
2422
2638
  };
2639
+ activeInstantLink = function(event, $link) {
2640
+ return u.isUnmodifiedMouseEvent(event) && !childClicked(event, $link);
2641
+ };
2423
2642
 
2424
2643
  /**
2425
2644
  If applied on a link, Follows this link via AJAX and replaces the
@@ -2454,22 +2673,22 @@ Read on
2454
2673
  @param up-instant
2455
2674
  If set, fetches the element on `mousedown` instead of `click`.
2456
2675
  */
2457
- up.on('click', '[up-follow]', function(event, $element) {
2458
- if (!childClicked(event, $element)) {
2676
+ up.on('click', '[up-follow]', function(event, $link) {
2677
+ if (!childClicked(event, $link)) {
2459
2678
  event.preventDefault();
2460
- if (!$element.is('[up-instant]')) {
2461
- return follow(resolve($element));
2679
+ if (!$link.is('[up-instant]')) {
2680
+ return follow(resolve($link));
2462
2681
  }
2463
2682
  }
2464
2683
  });
2465
- up.on('mousedown', '[up-follow][up-instant]', function(event, $element) {
2466
- if (!childClicked(event, $element) && event.which === 1) {
2684
+ up.on('mousedown', '[up-follow][up-instant]', function(event, $link) {
2685
+ if (activeInstantLink(event, $link)) {
2467
2686
  event.preventDefault();
2468
- return follow(resolve($element));
2687
+ return up.follow(resolve($link));
2469
2688
  }
2470
2689
  });
2471
2690
 
2472
- /*
2691
+ /**
2473
2692
  Marks up the current link to be followed *as fast as possible*.
2474
2693
  This is done by:
2475
2694
 
@@ -2483,7 +2702,7 @@ Read on
2483
2702
 
2484
2703
  Note that this is shorthand for:
2485
2704
 
2486
- <a href="/users" up-target=".main" up-instant up-preload>User list</a>
2705
+ <a href="/users" up-target=".main" up-instant up-preload>User list</a>
2487
2706
 
2488
2707
  You can also apply `[up-dash]` to any element that contains a link
2489
2708
  in order to enlarge the link's click area:
@@ -2609,7 +2828,7 @@ We need to work on this page:
2609
2828
  };
2610
2829
  successUrl = function(xhr) {
2611
2830
  var currentLocation;
2612
- url = historyOption ? historyOption === 'false' ? false : u.isString(historyOption) ? historyOption : (currentLocation = u.locationFromXhr(xhr)) ? currentLocation : request.type === 'GET' ? request.url + '?' + request.data : void 0 : void 0;
2831
+ url = historyOption ? u.castsToFalse(historyOption) ? false : u.isString(historyOption) ? historyOption : (currentLocation = u.locationFromXhr(xhr)) ? currentLocation : request.type === 'GET' ? request.url + '?' + request.data : void 0 : void 0;
2613
2832
  return u.option(url, false);
2614
2833
  };
2615
2834
  return u.ajax(request).always(function() {
@@ -2682,7 +2901,7 @@ We need to work on this page:
2682
2901
  check = function() {
2683
2902
  var skipCallback, value;
2684
2903
  value = $field.val();
2685
- skipCallback = _.isNull(knownValue);
2904
+ skipCallback = u.isNull(knownValue);
2686
2905
  if (knownValue !== value) {
2687
2906
  knownValue = value;
2688
2907
  if (!skipCallback) {
@@ -2796,7 +3015,7 @@ We need to work on this page:
2796
3015
 
2797
3016
  (function() {
2798
3017
  up.popup = (function() {
2799
- var autoclose, close, config, createHiddenPopup, defaults, ensureInViewport, open, position, source, u, updated;
3018
+ var autoclose, close, config, createHiddenPopup, defaults, discardHistory, ensureInViewport, open, position, rememberHistory, source, u, updated;
2800
3019
  u = up.util;
2801
3020
  config = {
2802
3021
  openAnimation: 'fade-in',
@@ -2881,17 +3100,28 @@ We need to work on this page:
2881
3100
  }
2882
3101
  }
2883
3102
  };
3103
+ rememberHistory = function() {
3104
+ var $popup;
3105
+ $popup = $('.up-popup');
3106
+ $popup.attr('up-previous-url', up.browser.url());
3107
+ return $popup.attr('up-previous-title', document.title);
3108
+ };
3109
+ discardHistory = function() {
3110
+ var $popup;
3111
+ $popup = $('.up-popup');
3112
+ $popup.removeAttr('up-previous-url');
3113
+ return $popup.removeAttr('up-previous-title');
3114
+ };
2884
3115
  createHiddenPopup = function($link, selector, sticky) {
2885
3116
  var $placeholder, $popup;
2886
3117
  $popup = u.$createElementFromSelector('.up-popup');
2887
3118
  if (sticky) {
2888
3119
  $popup.attr('up-sticky', '');
2889
3120
  }
2890
- $popup.attr('up-previous-url', up.browser.url());
2891
- $popup.attr('up-previous-title', document.title);
2892
3121
  $placeholder = u.$createElementFromSelector(selector);
2893
3122
  $placeholder.appendTo($popup);
2894
3123
  $popup.appendTo(document.body);
3124
+ rememberHistory();
2895
3125
  $popup.hide();
2896
3126
  return $popup;
2897
3127
  };
@@ -3009,6 +3239,7 @@ We need to work on this page:
3009
3239
  });
3010
3240
  up.bus.on('fragment:ready', function($fragment) {
3011
3241
  if (!$fragment.closest('.up-popup').length) {
3242
+ discardHistory();
3012
3243
  return autoclose();
3013
3244
  }
3014
3245
  });
@@ -3061,7 +3292,7 @@ We need to work on this page:
3061
3292
 
3062
3293
  (function() {
3063
3294
  up.modal = (function() {
3064
- var autoclose, close, config, createHiddenModal, defaults, open, source, templateHtml, u, updated;
3295
+ var autoclose, close, config, createHiddenModal, defaults, discardHistory, open, rememberHistory, source, templateHtml, u, updated;
3065
3296
  u = up.util;
3066
3297
  config = {
3067
3298
  width: 'auto',
@@ -3095,6 +3326,18 @@ We need to work on this page:
3095
3326
  return template;
3096
3327
  }
3097
3328
  };
3329
+ rememberHistory = function() {
3330
+ var $popup;
3331
+ $popup = $('.up-modal');
3332
+ $popup.attr('up-previous-url', up.browser.url());
3333
+ return $popup.attr('up-previous-title', document.title);
3334
+ };
3335
+ discardHistory = function() {
3336
+ var $popup;
3337
+ $popup = $('.up-modal');
3338
+ $popup.removeAttr('up-previous-url');
3339
+ return $popup.removeAttr('up-previous-title');
3340
+ };
3098
3341
  createHiddenModal = function(selector, width, height, sticky) {
3099
3342
  var $content, $dialog, $modal, $placeholder;
3100
3343
  $modal = $(templateHtml());
@@ -3114,6 +3357,7 @@ We need to work on this page:
3114
3357
  $placeholder = u.$createElementFromSelector(selector);
3115
3358
  $placeholder.appendTo($content);
3116
3359
  $modal.appendTo(document.body);
3360
+ rememberHistory();
3117
3361
  $modal.hide();
3118
3362
  return $modal;
3119
3363
  };
@@ -3196,6 +3440,7 @@ We need to work on this page:
3196
3440
  };
3197
3441
  autoclose = function() {
3198
3442
  if (!$('.up-modal').is('[up-sticky]')) {
3443
+ discardHistory();
3199
3444
  return close();
3200
3445
  }
3201
3446
  };
@@ -3416,11 +3661,21 @@ From Up's point of view the "current" location is either:
3416
3661
 
3417
3662
  (function() {
3418
3663
  up.navigation = (function() {
3419
- var CLASS_ACTIVE, CLASS_CURRENT, SELECTOR_ACTIVE, SELECTOR_SECTION, enlargeClickArea, locationChanged, normalizeUrl, sectionClicked, sectionUrls, u, unmarkActive;
3664
+ var CLASS_ACTIVE, CLASS_CURRENT, SELECTORS_SECTION, SELECTOR_ACTIVE, SELECTOR_SECTION, SELECTOR_SECTION_INSTANT, enlargeClickArea, locationChanged, normalizeUrl, sectionClicked, sectionUrls, selector, u, unmarkActive;
3420
3665
  u = up.util;
3421
3666
  CLASS_ACTIVE = 'up-active';
3422
3667
  CLASS_CURRENT = 'up-current';
3423
- SELECTOR_SECTION = 'a[href], a[up-target], [up-follow], [up-modal], [up-popup], [up-source]';
3668
+ SELECTORS_SECTION = ['a[href]', 'a[up-target]', '[up-follow]', '[up-modal]', '[up-popup]', '[up-href]'];
3669
+ SELECTOR_SECTION = SELECTORS_SECTION.join(', ');
3670
+ SELECTOR_SECTION_INSTANT = ((function() {
3671
+ var i, len, results;
3672
+ results = [];
3673
+ for (i = 0, len = SELECTORS_SECTION.length; i < len; i++) {
3674
+ selector = SELECTORS_SECTION[i];
3675
+ results.push(selector + "[up-instant]");
3676
+ }
3677
+ return results;
3678
+ })()).join(', ');
3424
3679
  SELECTOR_ACTIVE = "." + CLASS_ACTIVE;
3425
3680
  normalizeUrl = function(url) {
3426
3681
  if (u.isPresent(url)) {
@@ -3431,12 +3686,12 @@ From Up's point of view the "current" location is either:
3431
3686
  }
3432
3687
  };
3433
3688
  sectionUrls = function($section) {
3434
- var $link, attr, url, urls, _i, _len, _ref;
3689
+ var $link, attr, i, len, ref, url, urls;
3435
3690
  urls = [];
3436
3691
  if ($link = up.link.resolve($section)) {
3437
- _ref = ['href', 'up-follow', 'up-source'];
3438
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
3439
- attr = _ref[_i];
3692
+ ref = ['href', 'up-follow', 'up-href'];
3693
+ for (i = 0, len = ref.length; i < len; i++) {
3694
+ attr = ref[i];
3440
3695
  if (url = u.presentAttr($link, attr)) {
3441
3696
  url = normalizeUrl(url);
3442
3697
  urls.push(url);
@@ -3471,7 +3726,14 @@ From Up's point of view the "current" location is either:
3471
3726
  return $(SELECTOR_ACTIVE).removeClass(CLASS_ACTIVE);
3472
3727
  };
3473
3728
  up.on('click', SELECTOR_SECTION, function(event, $section) {
3474
- return sectionClicked($section);
3729
+ if (!$section.is('[up-instant]')) {
3730
+ return sectionClicked($section);
3731
+ }
3732
+ });
3733
+ up.on('mousedown', SELECTOR_SECTION_INSTANT, function(event, $section) {
3734
+ if (u.isUnmodifiedMouseEvent(event)) {
3735
+ return sectionClicked($section);
3736
+ }
3475
3737
  });
3476
3738
  up.bus.on('fragment:ready', function() {
3477
3739
  unmarkActive();