upjs-rails 0.8.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 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) : [];