upjs-rails 0.8.2 → 0.9.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: 1a8cf11326d2f0ca81fbed53af3ffd3d43762bde
4
- data.tar.gz: 96caa5a3b6239a921f66c0d39fe237dc5bca2949
3
+ metadata.gz: dc09b20d83f04c7aab8c11e39ee0eb4f7eb6f9e3
4
+ data.tar.gz: 0f6e623d66e8d2bd8a5ec25aa906e3999eaf5cc3
5
5
  SHA512:
6
- metadata.gz: f3124e80cbab1474ac49621e5b127194316e7db2728b41ec1a453d88ec67242802c808abb70649feab5f4b626b9099c038913ae9fc062b424daa3073bb578136
7
- data.tar.gz: 25abfbe06ad4e1a0689038ab20b8f0862b1f05bf8526b2064618e13065d9f603aac44a968eb59ec666ef9ab4b7ba61a44f999264eb8135ffd111acfaf61796a6
6
+ metadata.gz: 0adae829accb44dd0fea004cd41bd27169a9c8cc33ea4cbb4ce9639bd81639506d617eb49206a11917b6e0851e9d2d9d1c2ff6b4ead30c987ea53d9aeaabfea6
7
+ data.tar.gz: 688bf765d4cf1dde1aeb9193f17f41c253c9788b66c8e54cdb73ea1027102f4356c551d46c1aab5b161bf407ba4f3b88ca9d185d3ad6f56d94f88f9c3b8a98d7
data/dist/up-bootstrap.js CHANGED
@@ -1,8 +1,21 @@
1
+ (function() {
2
+ var defaults;
3
+
4
+ defaults = up.layout.defaults();
5
+
6
+ up.layout.defaults({
7
+ fixedTop: defaults.fixedTop + ", .navbar-fixed-top",
8
+ fixedBottom: defaults.fixedBottom + ", .navbar-fixed-bottom"
9
+ });
10
+
11
+ }).call(this);
1
12
  (function() {
2
13
  up.modal.defaults({
3
14
  template: "<div class=\"up-modal\">\n <div class=\"up-modal-dialog modal-dialog\">\n <div class=\"up-modal-content modal-content\"></div>\n </div>\n</div>"
4
15
  });
5
16
 
17
+ }).call(this);
18
+ (function() {
6
19
  up.navigation.defaults({
7
20
  currentClass: 'active'
8
21
  });
@@ -1 +1 @@
1
- (function(){up.modal.defaults({template:'<div class="up-modal">\n <div class="up-modal-dialog modal-dialog">\n <div class="up-modal-content modal-content"></div>\n </div>\n</div>'}),up.navigation.defaults({currentClass:"active"})}).call(this),function(){}.call(this);
1
+ (function(){var a;a=up.layout.defaults(),up.layout.defaults({fixedTop:a.fixedTop+", .navbar-fixed-top",fixedBottom:a.fixedBottom+", .navbar-fixed-bottom"})}).call(this),function(){up.modal.defaults({template:'<div class="up-modal">\n <div class="up-modal-dialog modal-dialog">\n <div class="up-modal-content modal-content"></div>\n </div>\n</div>'})}.call(this),function(){up.navigation.defaults({currentClass:"active"})}.call(this),function(){}.call(this);
data/dist/up.js CHANGED
@@ -25,7 +25,7 @@ If you use them in your own code, you will get hurt.
25
25
  var slice = [].slice;
26
26
 
27
27
  up.util = (function() {
28
- var $createElementFromSelector, ANIMATION_PROMISE_KEY, CONSOLE_PLACEHOLDERS, ajax, castsToFalse, castsToTrue, clientSize, compact, config, contains, copy, copyAttributes, createElement, createElementFromHtml, createSelectorFromElement, cssAnimate, debug, detect, each, error, escapePressed, extend, findWithSelf, finishCssAnimate, forceCompositing, get, ifGiven, isArray, isBlank, isDeferred, isDefined, isElement, isFunction, isGiven, isHash, isJQuery, isMissing, isNull, isObject, isPresent, isPromise, isStandardPort, isString, isUndefined, isUnmodifiedKeyEvent, isUnmodifiedMouseEvent, keys, last, locationFromXhr, measure, memoize, merge, methodFromXhr, nextFrame, normalizeMethod, normalizeUrl, nullJquery, once, only, option, options, prependGhost, presence, presentAttr, remove, resolvableWhen, resolvedDeferred, resolvedPromise, scrollbarWidth, select, setMissingAttrs, stringifyConsoleArgs, temporaryCss, times, toArray, trim, uniq, unwrap, warn;
28
+ var $createElementFromSelector, ANIMATION_PROMISE_KEY, CONSOLE_PLACEHOLDERS, ajax, castsToFalse, castsToTrue, clientSize, compact, config, contains, copy, copyAttributes, createElement, createElementFromHtml, createSelectorFromElement, cssAnimate, debug, detect, each, endsWith, error, escapePressed, extend, findWithSelf, finishCssAnimate, forceCompositing, get, identity, ifGiven, isArray, isBlank, isDeferred, isDefined, isElement, isFunction, isGiven, isHash, isJQuery, isMissing, isNull, isObject, isPresent, isPromise, isStandardPort, isString, isUndefined, isUnmodifiedKeyEvent, isUnmodifiedMouseEvent, keys, last, locationFromXhr, map, measure, memoize, merge, methodFromXhr, nextFrame, normalizeMethod, normalizeUrl, nullJquery, once, only, option, options, prependGhost, presence, presentAttr, remove, resolvableWhen, resolvedDeferred, resolvedPromise, scrollbarWidth, select, setMissingAttrs, startsWith, stringifyConsoleArgs, temporaryCss, times, toArray, trim, unJquery, uniq, unwrapElement, warn;
29
29
  memoize = function(func) {
30
30
  var cache, cached;
31
31
  cache = void 0;
@@ -85,7 +85,7 @@ If you use them in your own code, you will get hurt.
85
85
  anchor.href = anchor.href;
86
86
  }
87
87
  } else {
88
- anchor = unwrap(urlOrAnchor);
88
+ anchor = unJquery(urlOrAnchor);
89
89
  }
90
90
  normalized = anchor.protocol + "//" + anchor.hostname;
91
91
  if (!isStandardPort(anchor.protocol, anchor.port)) {
@@ -197,7 +197,7 @@ If you use them in your own code, you will get hurt.
197
197
  var i, maxLength, message;
198
198
  message = args[0];
199
199
  i = 0;
200
- maxLength = 30;
200
+ maxLength = 50;
201
201
  return message.replace(CONSOLE_PLACEHOLDERS, function() {
202
202
  var arg, argType;
203
203
  i += 1;
@@ -208,12 +208,16 @@ If you use them in your own code, you will get hurt.
208
208
  if (arg.length > maxLength) {
209
209
  arg = (arg.substr(0, maxLength)) + "…";
210
210
  }
211
- return "\"" + arg + "\"";
211
+ arg = "\"" + arg + "\"";
212
212
  } else if (argType === 'number') {
213
- return arg.toString();
213
+ arg = arg.toString();
214
214
  } else {
215
- return "(" + argType + ")";
215
+ arg = JSON.stringify(arg);
216
+ if (arg.length > maxLength) {
217
+ arg = (arg.substr(0, maxLength)) + "…";
218
+ }
216
219
  }
220
+ return arg;
217
221
  });
218
222
  };
219
223
  createSelectorFromElement = function($element) {
@@ -282,6 +286,10 @@ If you use them in your own code, you will get hurt.
282
286
  }
283
287
  return results;
284
288
  };
289
+ map = each;
290
+ identity = function(x) {
291
+ return x;
292
+ };
285
293
  times = function(count, block) {
286
294
  var iteration, j, ref, results;
287
295
  results = [];
@@ -363,7 +371,7 @@ If you use them in your own code, you will get hurt.
363
371
  return extend({}, object);
364
372
  }
365
373
  };
366
- unwrap = function(object) {
374
+ unJquery = function(object) {
367
375
  if (isJQuery(object)) {
368
376
  return object.get(0);
369
377
  } else {
@@ -691,6 +699,12 @@ If you use them in your own code, you will get hurt.
691
699
  escapePressed = function(event) {
692
700
  return event.keyCode === 27;
693
701
  };
702
+ startsWith = function(string, element) {
703
+ return string.indexOf(element) === 0;
704
+ };
705
+ endsWith = function(string, element) {
706
+ return string.indexOf(element) === string.length - element.length;
707
+ };
694
708
  contains = function(stringOrArray, element) {
695
709
  return stringOrArray.indexOf(element) >= 0;
696
710
  };
@@ -796,23 +810,35 @@ If you use them in your own code, you will get hurt.
796
810
  return hash.update(copy(factoryOptions));
797
811
  },
798
812
  update: function(options) {
799
- var key, results, value;
800
- results = [];
813
+ var key, value;
814
+ if (options == null) {
815
+ options = {};
816
+ }
801
817
  for (key in options) {
802
818
  value = options[key];
803
819
  if (factoryOptions.hasOwnProperty(key)) {
804
- results.push(hash[key] = value);
820
+ hash[key] = value;
805
821
  } else {
806
- results.push(error("Unknown setting %o", key));
822
+ error("Unknown setting %o", key);
807
823
  }
808
824
  }
809
- return results;
825
+ return hash;
810
826
  }
811
827
  };
812
828
  apiKeys = Object.getOwnPropertyNames(hash);
813
829
  hash.reset();
814
830
  return hash;
815
831
  };
832
+ unwrapElement = function(wrapper) {
833
+ var parent, wrappedNodes;
834
+ wrapper = unJquery(wrapper);
835
+ parent = wrapper.parentNode;
836
+ wrappedNodes = toArray(wrapper.childNodes);
837
+ each(wrappedNodes, function(wrappedNode) {
838
+ return parent.insertBefore(wrappedNode, wrapper);
839
+ });
840
+ return parent.removeChild(wrapper);
841
+ };
816
842
  return {
817
843
  presentAttr: presentAttr,
818
844
  createElement: createElement,
@@ -832,6 +858,8 @@ If you use them in your own code, you will get hurt.
832
858
  debug: debug,
833
859
  warn: warn,
834
860
  each: each,
861
+ map: map,
862
+ identity: identity,
835
863
  times: times,
836
864
  detect: detect,
837
865
  select: select,
@@ -858,7 +886,7 @@ If you use them in your own code, you will get hurt.
858
886
  isUnmodifiedKeyEvent: isUnmodifiedKeyEvent,
859
887
  isUnmodifiedMouseEvent: isUnmodifiedMouseEvent,
860
888
  nullJquery: nullJquery,
861
- unwrap: unwrap,
889
+ unJquery: unJquery,
862
890
  nextFrame: nextFrame,
863
891
  measure: measure,
864
892
  temporaryCss: temporaryCss,
@@ -870,6 +898,8 @@ If you use them in your own code, you will get hurt.
870
898
  copyAttributes: copyAttributes,
871
899
  findWithSelf: findWithSelf,
872
900
  contains: contains,
901
+ startsWith: startsWith,
902
+ endsWith: endsWith,
873
903
  isArray: isArray,
874
904
  toArray: toArray,
875
905
  castsToTrue: castsToTrue,
@@ -887,7 +917,8 @@ If you use them in your own code, you will get hurt.
887
917
  remove: remove,
888
918
  memoize: memoize,
889
919
  scrollbarWidth: scrollbarWidth,
890
- config: config
920
+ config: config,
921
+ unwrapElement: unwrapElement
891
922
  };
892
923
  })();
893
924
 
@@ -1164,32 +1195,33 @@ Viewport scrolling
1164
1195
 
1165
1196
  This modules contains functions to scroll the viewport and reveal contained elements.
1166
1197
 
1167
- By default Up.js will always scroll to an element before updating it.
1168
-
1169
- The container that will be scrolled is the closest parent of the element that is either:
1170
-
1171
- - The currently open [modal](/up.modal)
1172
- - An element with the attribute `[up-viewport]`
1173
- - The `<body>` element
1174
- - An element matching the selector you have configured using `up.viewport.defaults({ viewSelector: 'my-custom-selector' })`.
1175
-
1176
- @class up.viewport
1198
+ @class up.layout
1177
1199
  */
1178
1200
 
1179
1201
  (function() {
1180
- up.viewport = (function() {
1181
- var SCROLL_PROMISE_KEY, config, findView, finishScrolling, reset, reveal, scroll, u;
1202
+ var slice = [].slice;
1203
+
1204
+ up.layout = (function() {
1205
+ var SCROLL_PROMISE_KEY, config, findViewport, finishScrolling, measureObstruction, reset, reveal, scroll, u;
1182
1206
  u = up.util;
1183
1207
 
1184
1208
  /**
1185
- @method up.viewport.defaults
1209
+
1210
+
1211
+ @method up.layout.defaults
1212
+ @param {String} [options.viewport]
1213
+ @param {String} [options.fixedTop]
1214
+ @param {String} [options.fixedBottom]
1186
1215
  @param {Number} [options.duration]
1187
1216
  @param {String} [options.easing]
1188
- @param {String} [options.viewSelector]
1217
+ @param {Number} [options.snap]
1189
1218
  */
1190
1219
  config = u.config({
1191
1220
  duration: 0,
1192
- viewSelector: 'body, .up-modal, [up-viewport]',
1221
+ viewport: 'body, .up-modal, [up-viewport]',
1222
+ fixedTop: '[up-fixed~=top]',
1223
+ fixedBottom: '[up-fixed~=bottom]',
1224
+ snap: 50,
1193
1225
  easing: 'swing'
1194
1226
  });
1195
1227
  reset = function() {
@@ -1198,17 +1230,46 @@ The container that will be scrolled is the closest parent of the element that is
1198
1230
  SCROLL_PROMISE_KEY = 'up-scroll-promise';
1199
1231
 
1200
1232
  /**
1233
+ Scrolls the given viewport to the given Y-position.
1234
+
1235
+ A "viewport" is an element that has scrollbars, e.g. `<body>` or
1236
+ a container with `overflow-x: scroll`.
1237
+
1238
+ \#\#\#\# Example
1239
+
1240
+ This will scroll a `<div class="main">...</div>` to a Y-position of 100 pixels:
1241
+
1242
+ up.scoll('.main', 100);
1243
+
1244
+ \#\#\#\# Animating the scrolling motion
1245
+
1246
+ The scrolling can (optionally) be animated.
1247
+
1248
+ up.scoll('.main', 100, {
1249
+ easing: 'swing',
1250
+ duration: 250
1251
+ });
1252
+
1253
+ If the given viewport is already in a scroll animation when `up.scroll`
1254
+ is called a second time, the previous animation will instantly jump to the
1255
+ last frame before the next animation is started.
1256
+
1257
+ @protected
1201
1258
  @method up.scroll
1202
- @param {String|Element|jQuery} viewOrSelector
1259
+ @param {String|Element|jQuery} viewport
1260
+ The container element to scroll.
1203
1261
  @param {Number} scrollPos
1204
- @param {String}[options.duration]
1262
+ The absolute number of pixels to set the scroll position to.
1263
+ @param {Number}[options.duration]
1264
+ The number of miliseconds for the scrolling's animation.
1205
1265
  @param {String}[options.easing]
1266
+ The timing function that controls the acceleration for the scrolling's animation.
1206
1267
  @return {Deferred}
1207
- @protected
1268
+ A promise that will be resolved when the scrolling ends.
1208
1269
  */
1209
- scroll = function(viewOrSelector, scrollTop, options) {
1270
+ scroll = function(viewport, scrollTop, options) {
1210
1271
  var $view, deferred, duration, easing, targetProps;
1211
- $view = $(viewOrSelector);
1272
+ $view = $(viewport);
1212
1273
  options = u.options(options);
1213
1274
  duration = u.option(options.duration, config.duration);
1214
1275
  easing = u.option(options.easing, config.easing);
@@ -1249,45 +1310,124 @@ The container that will be scrolled is the closest parent of the element that is
1249
1310
  }
1250
1311
  });
1251
1312
  };
1313
+ measureObstruction = function() {
1314
+ var fixedBottomTops, fixedTopBottoms, measurePosition, obstructor;
1315
+ measurePosition = function(obstructor, cssAttr) {
1316
+ var $obstructor, anchorPosition;
1317
+ $obstructor = $(obstructor);
1318
+ anchorPosition = $obstructor.css(cssAttr);
1319
+ if (!(anchorPosition === '0' || u.endsWith(anchorPosition, 'px'))) {
1320
+ u.error("Fixed element must have an anchor position in px, but was %o", anchorPosition);
1321
+ }
1322
+ return parseInt(anchorPosition) + $obstructor.height();
1323
+ };
1324
+ fixedTopBottoms = (function() {
1325
+ var i, len, ref, results;
1326
+ ref = $(config.fixedTop);
1327
+ results = [];
1328
+ for (i = 0, len = ref.length; i < len; i++) {
1329
+ obstructor = ref[i];
1330
+ results.push(measurePosition(obstructor, 'top'));
1331
+ }
1332
+ return results;
1333
+ })();
1334
+ fixedBottomTops = (function() {
1335
+ var i, len, ref, results;
1336
+ ref = $(config.fixedBottom);
1337
+ results = [];
1338
+ for (i = 0, len = ref.length; i < len; i++) {
1339
+ obstructor = ref[i];
1340
+ results.push(measurePosition(obstructor, 'bottom'));
1341
+ }
1342
+ return results;
1343
+ })();
1344
+ return {
1345
+ top: Math.max.apply(Math, [0].concat(slice.call(fixedTopBottoms))),
1346
+ bottom: Math.max.apply(Math, [0].concat(slice.call(fixedBottomTops)))
1347
+ };
1348
+ };
1252
1349
 
1253
1350
  /**
1351
+ Scroll's the given element's viewport so the element
1352
+ is visible for the user.
1353
+
1354
+ By default Up.js will always reveal an element before
1355
+ updating it with Javascript functions like [`up.replace`](/up.flow#up.replace)
1356
+ or UJS behavior like [`[up-target]`](/up.link#up-target).
1357
+
1358
+ \#\#\#\# How Up.js finds the viewport
1359
+
1360
+ The viewport (the container that is going to be scrolled)
1361
+ is the closest parent of the element that is either:
1362
+
1363
+ - the currently open [modal](/up.modal)
1364
+ - an element with the attribute `[up-viewport]`
1365
+ - the `<body>` element
1366
+ - an element matching the selector you have configured using `up.viewport.defaults({ viewSelector: 'my-custom-selector' })`
1367
+
1368
+ \#\#\#\# Fixed elements obstruction the viewport
1369
+
1370
+ Many applications have a navigation bar fixed to the top or bottom,
1371
+ obstructing the view on an element.
1372
+
1373
+ To make `up.aware` of these fixed elements you can either:
1374
+
1375
+ - give the element an attribute [`up-fixed="top"`](#up-fixed-top) or [`up-fixed="bottom"`](up-fixed-bottom)
1376
+ - [configure default options](#up.layout.defaults) for `fixedTop` or `fixedBottom`
1377
+
1254
1378
  @method up.reveal
1255
1379
  @param {String|Element|jQuery} element
1256
- @param {String|Element|jQuery} [options.view]
1380
+ @param {String|Element|jQuery} [options.viewport]
1257
1381
  @param {Number} [options.duration]
1258
1382
  @param {String} [options.easing]
1383
+ @param {String} [options.snap]
1259
1384
  @return {Deferred}
1260
- @protected
1385
+ A promise that will be resolved when the element is revealed.
1261
1386
  */
1262
1387
  reveal = function(elementOrSelector, options) {
1263
- var $element, $view, elementDims, firstElementRow, firstVisibleRow, lastElementRow, lastVisibleRow, newScrollPos, offsetShift, originalScrollPos, viewHeight, viewIsBody;
1388
+ var $element, $viewport, elementDims, firstElementRow, lastElementRow, newScrollPos, obstruction, offsetShift, originalScrollPos, predictFirstVisibleRow, predictLastVisibleRow, snap, viewportHeight, viewportIsBody;
1264
1389
  options = u.options(options);
1265
1390
  $element = $(elementOrSelector);
1266
- $view = findView($element, options.view);
1267
- viewIsBody = $view.is('body');
1268
- viewHeight = viewIsBody ? u.clientSize().height : $view.height();
1269
- originalScrollPos = $view.scrollTop();
1391
+ $viewport = findViewport($element, options.viewport);
1392
+ snap = u.option(options.snap, config.snap);
1393
+ viewportIsBody = $viewport.is('body');
1394
+ viewportHeight = viewportIsBody ? u.clientSize().height : $viewport.height();
1395
+ originalScrollPos = $viewport.scrollTop();
1270
1396
  newScrollPos = originalScrollPos;
1271
- offsetShift = viewIsBody ? 0 : originalScrollPos;
1272
- firstVisibleRow = function() {
1273
- return newScrollPos;
1397
+ offsetShift = void 0;
1398
+ obstruction = void 0;
1399
+ if (viewportIsBody) {
1400
+ obstruction = measureObstruction();
1401
+ offsetShift = 0;
1402
+ } else {
1403
+ obstruction = {
1404
+ top: 0,
1405
+ bottom: 0
1406
+ };
1407
+ offsetShift = originalScrollPos;
1408
+ }
1409
+ predictFirstVisibleRow = function() {
1410
+ return newScrollPos + obstruction.top;
1274
1411
  };
1275
- lastVisibleRow = function() {
1276
- return newScrollPos + viewHeight - 1;
1412
+ predictLastVisibleRow = function() {
1413
+ return newScrollPos + viewportHeight - obstruction.bottom - 1;
1277
1414
  };
1278
1415
  elementDims = u.measure($element, {
1279
1416
  relative: true
1280
1417
  });
1281
1418
  firstElementRow = elementDims.top + offsetShift;
1282
1419
  lastElementRow = firstElementRow + elementDims.height - 1;
1283
- if (lastElementRow > lastVisibleRow()) {
1284
- newScrollPos += lastElementRow - lastVisibleRow();
1420
+ if (lastElementRow > predictLastVisibleRow()) {
1421
+ newScrollPos += lastElementRow - predictLastVisibleRow();
1285
1422
  }
1286
- if (firstElementRow < firstVisibleRow()) {
1287
- newScrollPos = firstElementRow;
1423
+ if (firstElementRow < predictFirstVisibleRow()) {
1424
+ newScrollPos = firstElementRow - obstruction.top;
1425
+ }
1426
+ if (newScrollPos < snap) {
1427
+ newScrollPos = 0;
1288
1428
  }
1289
1429
  if (newScrollPos !== originalScrollPos) {
1290
- return scroll($view, newScrollPos, options);
1430
+ return scroll($viewport, newScrollPos, options);
1291
1431
  } else {
1292
1432
  return u.resolvedDeferred();
1293
1433
  }
@@ -1295,27 +1435,99 @@ The container that will be scrolled is the closest parent of the element that is
1295
1435
 
1296
1436
  /**
1297
1437
  @private
1298
- @method up.viewport.findView
1438
+ @method up.viewport.findViewport
1299
1439
  */
1300
- findView = function($element, viewSelectorOrElement) {
1301
- var $view, viewSelector;
1302
- $view = void 0;
1303
- if (u.isJQuery(viewSelectorOrElement)) {
1304
- $view = viewSelectorOrElement;
1440
+ findViewport = function($element, viewportSelectorOrElement) {
1441
+ var $viewport, vieportSelector;
1442
+ $viewport = void 0;
1443
+ if (u.isJQuery(viewportSelectorOrElement)) {
1444
+ $viewport = viewportSelectorOrElement;
1305
1445
  } else {
1306
- viewSelector = u.presence(viewSelectorOrElement) || config.viewSelector;
1307
- $view = $element.closest(viewSelector);
1446
+ vieportSelector = u.presence(viewportSelectorOrElement) || config.viewport;
1447
+ $viewport = $element.closest(vieportSelector);
1308
1448
  }
1309
- $view.length || u.error("Could not find view to scroll for %o (tried selectors %o)", $element, viewSelectors);
1310
- return $view;
1449
+ $viewport.length || u.error("Could not find viewport for %o", $element);
1450
+ return $viewport;
1311
1451
  };
1312
1452
 
1313
1453
  /**
1314
- Marks this element as a scrolling container.
1315
- Use this e.g. if your app uses a custom panel layout with fixed positioning
1316
- instead of scrolling `<body>`.
1454
+ Marks this element as a scrolling container. Apply this ttribute if your app uses
1455
+ a custom panel layout with fixed positioning instead of scrolling `<body>`.
1456
+
1457
+ [`up.reveal`](/up.reveal) will always try to scroll the viewport closest
1458
+ to the element that is being revealed. By default this is the `<body>` element.
1459
+
1460
+ \#\#\#\# Example
1461
+
1462
+ Here is an example for a layout for an e-mail client, showing a list of e-mails
1463
+ on the left side and the e-mail text on the right side:
1464
+
1465
+ .side {
1466
+ position: fixed;
1467
+ top: 0;
1468
+ bottom: 0;
1469
+ left: 0;
1470
+ width: 100px;
1471
+ overflow-y: scroll;
1472
+ }
1473
+
1474
+ .main {
1475
+ position: fixed;
1476
+ top: 0;
1477
+ bottom: 0;
1478
+ left: 100px;
1479
+ right: 0;
1480
+ overflow-y: scroll;
1481
+ }
1482
+
1483
+ This would be the HTML (notice the `up-viewport` attribute):
1484
+
1485
+ <div class=".side" up-viewport>
1486
+ <a href="/emails/5001" up-target=".main">Re: Your invoice</a>
1487
+ <a href="/emails/2023" up-target=".main">Quote for services</a>
1488
+ <a href="/emails/9002" up-target=".main">Fwd: Room reservation</a>
1489
+ </div>
1490
+
1491
+ <div class="main" up-viewport>
1492
+ <h1>Re: Your Invoice</h1>
1493
+ <p>
1494
+ Lorem ipsum dolor sit amet, consetetur sadipscing elitr.
1495
+ Stet clita kasd gubergren, no sea takimata sanctus est.
1496
+ </p>
1497
+ </div>
1317
1498
 
1318
1499
  @method [up-viewport]
1500
+ @ujs
1501
+ */
1502
+
1503
+ /**
1504
+ Marks this element as a navigation fixed to the top edge of the screen
1505
+ using `position: fixed`.
1506
+
1507
+ [`up.reveal`](/up.reveal) is aware of fixed elements and will scroll
1508
+ the viewport far enough so the revealed element is fully visible.
1509
+
1510
+ Example:
1511
+
1512
+ <div class="top-nav" up-fixed="top">...</div>
1513
+
1514
+ @method [up-fixed=top]
1515
+ @ujs
1516
+ */
1517
+
1518
+ /**
1519
+ Marks this element as a navigation fixed to the bottom edge of the screen
1520
+ using `position: fixed`.
1521
+
1522
+ [`up.reveal`](/up.reveal) is aware of fixed elements and will scroll
1523
+ the viewport far enough so the revealed element is fully visible.
1524
+
1525
+ Example:
1526
+
1527
+ <div class="bottom-nav" up-fixed="bottom">...</div>
1528
+
1529
+ @method [up-fixed=bottom]
1530
+ @ujs
1319
1531
  */
1320
1532
  up.bus.on('framework:reset', reset);
1321
1533
  return {
@@ -1326,9 +1538,9 @@ The container that will be scrolled is the closest parent of the element that is
1326
1538
  };
1327
1539
  })();
1328
1540
 
1329
- up.scroll = up.viewport.scroll;
1541
+ up.scroll = up.layout.scroll;
1330
1542
 
1331
- up.reveal = up.viewport.reveal;
1543
+ up.reveal = up.layout.reveal;
1332
1544
 
1333
1545
  }).call(this);
1334
1546
 
@@ -1352,7 +1564,7 @@ We need to work on this page:
1352
1564
 
1353
1565
  (function() {
1354
1566
  up.flow = (function() {
1355
- var autofocus, destroy, elementsInserted, findOldFragment, first, fragmentNotFound, implant, isRealElement, parseImplantSteps, parseResponse, prepareForReplacement, reload, replace, reset, reveal, setSource, source, swapElements, u;
1567
+ var autofocus, destroy, elementsInserted, findOldFragment, first, fragmentNotFound, implant, isRealElement, parseImplantSteps, parseResponse, reload, replace, reset, reveal, setSource, source, swapElements, u;
1356
1568
  u = up.util;
1357
1569
  setSource = function(element, sourceUrl) {
1358
1570
  var $element;
@@ -1388,7 +1600,11 @@ We need to work on this page:
1388
1600
  If omitted or true, the `url` argument will be used.
1389
1601
  If set to `false`, the history will remain unchanged.
1390
1602
  @param {String|Boolean} [options.source=true]
1391
- @param {String} [options.scroll='body']
1603
+ @param {String} [options.scroll]
1604
+ Up.js will try to [reveal](/up.layout#up.reveal) the element being updated, by
1605
+ scrolling its containing viewport. Set this option to `false` to prevent any scrolling.
1606
+
1607
+ If omitted, this will use the [default from `up.layout`](/up.layout#up.layout.defaults).
1392
1608
  @param {Boolean} [options.cache]
1393
1609
  Whether to use a [cached response](/up.proxy) if available.
1394
1610
  @param {String} [options.historyMethod='push']
@@ -1471,7 +1687,7 @@ We need to work on this page:
1471
1687
  options.history = null;
1472
1688
  }
1473
1689
  if (u.castsToFalse(options.scroll)) {
1474
- options.scroll = null;
1690
+ options.scroll = false;
1475
1691
  }
1476
1692
  options.source = u.option(options.source, options.history);
1477
1693
  response = parseResponse(html);
@@ -1481,10 +1697,8 @@ We need to work on this page:
1481
1697
  for (j = 0, len = ref.length; j < len; j++) {
1482
1698
  step = ref[j];
1483
1699
  $old = findOldFragment(step.selector);
1484
- $new = response.find(step.selector);
1485
- results.push(prepareForReplacement($old, options).then(function() {
1486
- return swapElements($old, $new, step.pseudoClass, step.transition, options);
1487
- }));
1700
+ $new = response.find(step.selector).first();
1701
+ results.push(swapElements($old, $new, step.pseudoClass, step.transition, options));
1488
1702
  }
1489
1703
  return results;
1490
1704
  };
@@ -1517,14 +1731,12 @@ We need to work on this page:
1517
1731
  }
1518
1732
  };
1519
1733
  };
1520
- prepareForReplacement = function($element, options) {
1521
- up.motion.finish($element);
1522
- return reveal($element, options.scroll);
1523
- };
1524
- reveal = function($element, view) {
1525
- if (view) {
1734
+ reveal = function($element, options) {
1735
+ var viewport;
1736
+ viewport = options.scroll;
1737
+ if (viewport !== false) {
1526
1738
  return up.reveal($element, {
1527
- view: view
1739
+ viewport: viewport
1528
1740
  });
1529
1741
  } else {
1530
1742
  return u.resolvedDeferred();
@@ -1545,25 +1757,32 @@ We need to work on this page:
1545
1757
  return up.ready($new);
1546
1758
  };
1547
1759
  swapElements = function($old, $new, pseudoClass, transition, options) {
1548
- var $addedChildren, insertionMethod;
1760
+ var $wrapper, insertionMethod;
1549
1761
  transition || (transition = 'none');
1762
+ up.motion.finish($old);
1550
1763
  if (pseudoClass) {
1551
1764
  insertionMethod = pseudoClass === 'before' ? 'prepend' : 'append';
1552
- $addedChildren = $new.children();
1553
- $old[insertionMethod]($new.contents());
1765
+ $wrapper = $new.contents().wrap('<span class="up-insertion"></span>').parent();
1766
+ $old[insertionMethod]($wrapper);
1554
1767
  u.copyAttributes($new, $old);
1555
- elementsInserted($addedChildren, options);
1556
- return up.animate($new, transition, options);
1768
+ elementsInserted($wrapper.children(), options);
1769
+ return reveal($wrapper, options).then(function() {
1770
+ return up.animate($wrapper, transition, options);
1771
+ }).then(function() {
1772
+ u.unwrapElement($wrapper);
1773
+ });
1557
1774
  } else {
1558
- return destroy($old, {
1559
- animation: function() {
1560
- $new.insertBefore($old);
1561
- elementsInserted($new, options);
1562
- if ($old.is('body') && transition !== 'none') {
1563
- u.error('Cannot apply transitions to body-elements (%o)', transition);
1775
+ return reveal($old, options).then(function() {
1776
+ return destroy($old, {
1777
+ animation: function() {
1778
+ $new.insertBefore($old);
1779
+ elementsInserted($new, options);
1780
+ if ($old.is('body') && transition !== 'none') {
1781
+ u.error('Cannot apply transitions to body-elements (%o)', transition);
1782
+ }
1783
+ return up.morph($old, $new, transition, options);
1564
1784
  }
1565
- return up.morph($old, $new, transition, options);
1566
- }
1785
+ });
1567
1786
  });
1568
1787
  }
1569
1788
  };
@@ -1662,9 +1881,10 @@ We need to work on this page:
1662
1881
  }
1663
1882
  up.bus.emit('fragment:destroy', $element);
1664
1883
  animationPromise = u.presence(options.animation, u.isPromise) || up.motion.animate($element, options.animation, animateOptions);
1665
- return animationPromise.then(function() {
1884
+ animationPromise.then(function() {
1666
1885
  return $element.remove();
1667
1886
  });
1887
+ return animationPromise;
1668
1888
  };
1669
1889
 
1670
1890
  /**
@@ -3273,12 +3493,17 @@ Read on
3273
3493
  @method up.visit
3274
3494
  @param {String} url
3275
3495
  The URL to visit.
3496
+ @param {String} [options.target='body']
3497
+ The selector to replace.
3498
+ See options for [`up.replace`](/up.flow#up.replace)
3276
3499
  @param {Object} options
3277
3500
  See options for [`up.replace`](/up.flow#up.replace)
3278
3501
  */
3279
3502
  visit = function(url, options) {
3280
- u.debug("Visiting " + url);
3281
- return up.replace('body', url, options);
3503
+ var selector;
3504
+ options = u.options(options);
3505
+ selector = u.option(options.target, 'body');
3506
+ return up.replace(selector, url, options);
3282
3507
  };
3283
3508
 
3284
3509
  /**
@@ -4338,13 +4563,6 @@ For small popup overlays ("dropdowns") see [up.popup](/up.popup) instead.
4338
4563
 
4339
4564
  Any option attributes for [`a[up-modal]`](#a.up-modal) will be honored.
4340
4565
 
4341
- You can also open a URL directly like this:
4342
-
4343
- up.modal.open({ url: '/foo', target: '.list' })
4344
-
4345
- This will request `/foo`, extract the `.list` selector from the response
4346
- and open the selected container in a modal dialog.
4347
-
4348
4566
  \#\#\#\# Events
4349
4567
 
4350
4568
  - Emits an [event](/up.bus) `modal:open` when the modal
@@ -4353,12 +4571,8 @@ For small popup overlays ("dropdowns") see [up.popup](/up.popup) instead.
4353
4571
  animation has finished and the modal contents are fully visible.
4354
4572
 
4355
4573
  @method up.modal.open
4356
- @param {Element|jQuery|String} [elementOrSelector]
4574
+ @param {Element|jQuery|String} elementOrSelector
4357
4575
  The link to follow.
4358
- Can be omitted if you give `options.url` instead.
4359
- @param {String} [options.url]
4360
- The URL to open.
4361
- Can be omitted if you give `elementOrSelector` instead.
4362
4576
  @param {String} [options.target]
4363
4577
  The selector to extract from the response and open in a modal dialog.
4364
4578
  @param {Number} [options.width]
@@ -4383,6 +4597,26 @@ For small popup overlays ("dropdowns") see [up.popup](/up.popup) instead.
4383
4597
  @return {Promise}
4384
4598
  A promise that will be resolved when the modal has finished loading.
4385
4599
  */
4600
+
4601
+ /**
4602
+ Opens a modal for the given URL.
4603
+
4604
+ Example:
4605
+
4606
+ up.modal.open({ url: '/foo', target: '.list' })
4607
+
4608
+ This will request `/foo`, extract the `.list` selector from the response
4609
+ and open the selected container in a modal dialog.
4610
+
4611
+ @method up.modal.open
4612
+ @param {String} options.url
4613
+ The URL to load.
4614
+ @param {String} options.target
4615
+ The CSS selector to extract from the response.
4616
+ The extracted content will be placed into the dialog window.
4617
+ @param {Object} options
4618
+ See options for [previous `up.modal.open` variant](#up.modal.open).
4619
+ */
4386
4620
  open = function() {
4387
4621
  var $link, $modal, animateOptions, animation, args, height, history, maxWidth, options, selector, sticky, url, width;
4388
4622
  args = 1 <= arguments.length ? slice.call(arguments, 0) : [];