upjs-rails 0.18.1 → 0.19.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: 6d1b52fa522fbde804ecf3db0de54efa03a5efa5
4
- data.tar.gz: 2f8c0c4b0589ffb165a1237caa492a41922a3157
3
+ metadata.gz: 77dcd1a1f7e464a6f108d1fb3fafcc34c1c6c06e
4
+ data.tar.gz: 63001606276d007e811562e6c1e26d078a45fa63
5
5
  SHA512:
6
- metadata.gz: 688084094aeea1ae88a73f96d5243e632e82b089376e95d3ee0cf37e77b57ef5b10259bdc0ae3f1ddf25b3d005b7bd07ee43d1530f012b9f8c6dd51bcd5660ec
7
- data.tar.gz: af2131873f4c54165dc49780fb724b96bb4ab6b5ae0c830abb18d7469e3b01b9da6cf689066579089c0dd5325c33cd61a5b9f8f1d5b847b2629f6c0e61aef412
6
+ metadata.gz: 43e602670030b82cb89e564dfa223bfa3a602872ff55225f09915b066c3e0588e620affd0fbe670c6eb4f9a9648b0adc37c8f4186c244842e3ac37f7b9b8b175
7
+ data.tar.gz: 00c7bfc420e1f6397f18c9f7bb703a406e6ef3bfbf7d5881a72104514220e323cf47b0c6307de7c91123174eed84fc75516c4d5a12334c143cac914b559612c8
data/CHANGELOG.md CHANGED
@@ -10,9 +10,22 @@ Unreleased
10
10
 
11
11
  ### Compatible changes
12
12
 
13
+ ### Breaking changes
14
+
15
+
16
+ 0.19.0
17
+ ------
18
+
19
+ ### Compatible changes
20
+
21
+ - Elements can now be persisted during page updates using the [`up-keep`](/up-keep) attribute.
22
+ - `up.proxy.ajax` is now available as [`up.ajax`](/up.ajax).
23
+ - `up.ajax` can now handle nested objects as `{ data }` option (used to pass form parameters).
13
24
 
14
25
  ### Breaking changes
15
26
 
27
+ - `up.implant` has been renamed to [`up.extract`](/up.extract).
28
+
16
29
 
17
30
  0.18.1
18
31
  ------
data/dist/up.js CHANGED
@@ -27,7 +27,7 @@ that might save you from loading something like [Underscore.js](http://underscor
27
27
  @function up.util.memoize
28
28
  @internal
29
29
  */
30
- var $createElementFromSelector, ANIMATION_PROMISE_KEY, CONSOLE_PLACEHOLDERS, any, cache, castedAttr, clientSize, compact, config, contains, copy, copyAttributes, createElement, createElementFromHtml, cssAnimate, debug, detect, each, error, escapePressed, evalConsoleTemplate, except, extend, findWithSelf, finishCssAnimate, fixedToAbsolute, forceCompositing, intersect, isArray, isBlank, isDeferred, isDefined, isElement, isFunction, isGiven, isHash, isJQuery, isMissing, isNull, isNumber, isObject, isPresent, isPromise, isStandardPort, isString, isUndefined, isUnmodifiedKeyEvent, isUnmodifiedMouseEvent, last, locationFromXhr, map, measure, memoize, merge, methodFromXhr, multiSelector, nextFrame, nonUpClasses, normalizeMethod, normalizeUrl, nullJQuery, offsetParent, once, only, option, options, parseUrl, presence, presentAttr, reject, remove, requestDataAsArray, requestDataAsQueryString, resolvableWhen, resolvedDeferred, resolvedPromise, scrollbarWidth, select, selectorForElement, setMissingAttrs, temporaryCss, times, titleFromXhr, toArray, trim, unJQuery, uniq, unresolvableDeferred, unresolvablePromise, unwrapElement, warn;
30
+ var $createElementFromSelector, $createPlaceholder, ANIMATION_PROMISE_KEY, all, any, cache, castedAttr, clientSize, compact, config, contains, copy, copyAttributes, createElement, createElementFromHtml, cssAnimate, detect, each, error, escapePressed, except, extend, findWithSelf, finishCssAnimate, fixedToAbsolute, forceCompositing, intersect, isArray, isBlank, isDeferred, isDefined, isElement, isFunction, isGiven, isHash, isJQuery, isMissing, isNull, isNumber, isObject, isPresent, isPromise, isStandardPort, isString, isUndefined, isUnmodifiedKeyEvent, isUnmodifiedMouseEvent, last, locationFromXhr, map, measure, memoize, merge, methodFromXhr, multiSelector, nextFrame, nonUpClasses, normalizeMethod, normalizeUrl, nullJQuery, offsetParent, once, only, option, options, parseUrl, presence, presentAttr, reject, remove, requestDataAsArray, requestDataAsQuery, resolvableWhen, resolvedDeferred, resolvedPromise, scrollbarWidth, select, selectorForElement, setMissingAttrs, temporaryCss, times, titleFromXhr, toArray, trim, unJQuery, uniq, unresolvableDeferred, unresolvablePromise, unwrapElement;
31
31
  memoize = function(func) {
32
32
  var cache, cached;
33
33
  cache = void 0;
@@ -140,17 +140,17 @@ that might save you from loading something like [Underscore.js](http://underscor
140
140
  @internal
141
141
  */
142
142
  $createElementFromSelector = function(selector) {
143
- var $element, $parent, $root, classes, conjunction, depthSelector, expression, html, id, iteration, j, k, len, len1, path, tag;
143
+ var $element, $parent, $root, classes, conjunction, depthSelector, expression, html, i, id, iteration, j, len, len1, path, tag;
144
144
  path = selector.split(/[ >]/);
145
145
  $root = null;
146
- for (iteration = j = 0, len = path.length; j < len; iteration = ++j) {
146
+ for (iteration = i = 0, len = path.length; i < len; iteration = ++i) {
147
147
  depthSelector = path[iteration];
148
148
  conjunction = depthSelector.match(/(^|\.|\#)[A-Za-z0-9\-_]+/g);
149
149
  tag = "div";
150
150
  classes = [];
151
151
  id = null;
152
- for (k = 0, len1 = conjunction.length; k < len1; k++) {
153
- expression = conjunction[k];
152
+ for (j = 0, len1 = conjunction.length; j < len1; j++) {
153
+ expression = conjunction[j];
154
154
  switch (expression[0]) {
155
155
  case ".":
156
156
  classes.push(expression.substr(1));
@@ -191,90 +191,17 @@ that might save you from loading something like [Underscore.js](http://underscor
191
191
  };
192
192
 
193
193
  /**
194
- Prints a debugging message to the browser console.
195
-
196
- @function up.debug
197
- @param {String} message
198
- @param {Array} args...
199
- @internal
200
- */
201
- debug = function() {
202
- var args, message, ref;
203
- message = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
204
- message = "[UP] " + message;
205
- return (ref = up.browser).puts.apply(ref, ['debug', message].concat(slice.call(args)));
206
- };
207
-
208
- /**
209
- @function up.warn
210
- @internal
211
- */
212
- warn = function() {
213
- var args, message, ref;
214
- message = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
215
- message = "[UP] " + message;
216
- return (ref = up.browser).puts.apply(ref, ['warn', message].concat(slice.call(args)));
217
- };
218
-
219
- /**
220
- Throws a fatal error with the given message.
221
-
222
- - The error will be printed to the [error console](https://developer.mozilla.org/en-US/docs/Web/API/Console/error)
223
- - An [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) (exception) will be thrown, unwinding the current call stack
224
- - The error message will be printed in a corner of the screen
225
-
226
- \#\#\#\# Examples
227
-
228
- up.error('Division by zero')
229
- up.error('Unexpected result %o', result)
230
-
231
- @function up.error
232
- @internal
194
+ @function $create
233
195
  */
234
- error = function() {
235
- var $error, args, asString, ref;
236
- args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
237
- args[0] = "[UP] " + args[0];
238
- (ref = up.browser).puts.apply(ref, ['error'].concat(slice.call(args)));
239
- asString = evalConsoleTemplate.apply(null, args);
240
- $error = presence($('.up-error')) || $('<div class="up-error"></div>').prependTo('body');
241
- $error.addClass('up-error');
242
- $error.text(asString);
243
- throw new Error(asString);
244
- };
245
- CONSOLE_PLACEHOLDERS = /\%[odisf]/g;
246
- evalConsoleTemplate = function() {
247
- var args, i, maxLength, message;
248
- args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
249
- message = args[0];
250
- i = 0;
251
- maxLength = 80;
252
- return message.replace(CONSOLE_PLACEHOLDERS, function() {
253
- var arg, argType;
254
- i += 1;
255
- arg = args[i];
256
- argType = typeof arg;
257
- if (argType === 'string') {
258
- arg = arg.replace(/\s+/g, ' ');
259
- if (arg.length > maxLength) {
260
- arg = (arg.substr(0, maxLength)) + "…";
261
- }
262
- arg = "\"" + arg + "\"";
263
- } else if (argType === 'undefined') {
264
- arg = 'undefined';
265
- } else if (argType === 'number' || argType === 'function') {
266
- arg = arg.toString();
267
- } else {
268
- arg = JSON.stringify(arg);
269
- }
270
- if (arg.length > maxLength) {
271
- arg = (arg.substr(0, maxLength)) + " …";
272
- if (argType === 'object' || argType === 'function') {
273
- arg += " }";
274
- }
275
- }
276
- return arg;
277
- });
196
+ $createPlaceholder = function(selector, container) {
197
+ var $placeholder;
198
+ if (container == null) {
199
+ container = document.body;
200
+ }
201
+ $placeholder = $createElementFromSelector(selector);
202
+ $placeholder.addClass('up-placeholder');
203
+ $placeholder.appendTo(container);
204
+ return $placeholder;
278
205
  };
279
206
 
280
207
  /**
@@ -294,10 +221,10 @@ that might save you from loading something like [Underscore.js](http://underscor
294
221
  @experimental
295
222
  */
296
223
  selectorForElement = function(element) {
297
- var $element, classes, id, j, klass, len, name, selector, upId;
224
+ var $element, classes, i, id, klass, len, name, selector, upId;
298
225
  $element = $(element);
299
226
  selector = void 0;
300
- debug("Creating selector from element %o", $element.get(0));
227
+ up.puts("Creating selector from element %o", $element.get(0));
301
228
  if (upId = presence($element.attr("up-id"))) {
302
229
  selector = "[up-id='" + upId + "']";
303
230
  } else if (id = presence($element.attr("id"))) {
@@ -305,10 +232,9 @@ that might save you from loading something like [Underscore.js](http://underscor
305
232
  } else if (name = presence($element.attr("name"))) {
306
233
  selector = "[name='" + name + "']";
307
234
  } else if (classes = presence(nonUpClasses($element))) {
308
- console.log("using klass!", classes);
309
235
  selector = '';
310
- for (j = 0, len = classes.length; j < len; j++) {
311
- klass = classes[j];
236
+ for (i = 0, len = classes.length; i < len; i++) {
237
+ klass = classes[i];
312
238
  selector += "." + klass;
313
239
  }
314
240
  } else {
@@ -387,9 +313,9 @@ that might save you from loading something like [Underscore.js](http://underscor
387
313
  @stable
388
314
  */
389
315
  each = function(array, block) {
390
- var index, item, j, len, results;
316
+ var i, index, item, len, results;
391
317
  results = [];
392
- for (index = j = 0, len = array.length; j < len; index = ++j) {
318
+ for (index = i = 0, len = array.length; i < len; index = ++i) {
393
319
  item = array[index];
394
320
  results.push(block(item, index));
395
321
  }
@@ -418,9 +344,9 @@ that might save you from loading something like [Underscore.js](http://underscor
418
344
  @stable
419
345
  */
420
346
  times = function(count, block) {
421
- var iteration, j, ref, results;
347
+ var i, iteration, ref, results;
422
348
  results = [];
423
- for (iteration = j = 0, ref = count - 1; 0 <= ref ? j <= ref : j >= ref; iteration = 0 <= ref ? ++j : --j) {
349
+ for (iteration = i = 0, ref = count - 1; 0 <= ref ? i <= ref : i >= ref; iteration = 0 <= ref ? ++i : --i) {
424
350
  results.push(block(iteration));
425
351
  }
426
352
  return results;
@@ -797,10 +723,10 @@ that might save you from loading something like [Underscore.js](http://underscor
797
723
  @stable
798
724
  */
799
725
  detect = function(array, tester) {
800
- var element, j, len, match;
726
+ var element, i, len, match;
801
727
  match = void 0;
802
- for (j = 0, len = array.length; j < len; j++) {
803
- element = array[j];
728
+ for (i = 0, len = array.length; i < len; i++) {
729
+ element = array[i];
804
730
  if (tester(element)) {
805
731
  match = element;
806
732
  break;
@@ -820,10 +746,10 @@ that might save you from loading something like [Underscore.js](http://underscor
820
746
  @experimental
821
747
  */
822
748
  any = function(array, tester) {
823
- var element, j, len, match;
749
+ var element, i, len, match;
824
750
  match = false;
825
- for (j = 0, len = array.length; j < len; j++) {
826
- element = array[j];
751
+ for (i = 0, len = array.length; i < len; i++) {
752
+ element = array[i];
827
753
  if (tester(element)) {
828
754
  match = true;
829
755
  break;
@@ -832,6 +758,29 @@ that might save you from loading something like [Underscore.js](http://underscor
832
758
  return match;
833
759
  };
834
760
 
761
+ /**
762
+ Returns whether the given function returns a truthy value
763
+ for all elements in the given array.
764
+
765
+ @function up.util.all
766
+ @param {Array<T>} array
767
+ @param {Function<T>} tester
768
+ @return {Boolean}
769
+ @experimental
770
+ */
771
+ all = function(array, tester) {
772
+ var element, i, len, match;
773
+ match = true;
774
+ for (i = 0, len = array.length; i < len; i++) {
775
+ element = array[i];
776
+ if (!tester(element)) {
777
+ match = false;
778
+ break;
779
+ }
780
+ }
781
+ return match;
782
+ };
783
+
835
784
  /**
836
785
  Returns all elements from the given array that are
837
786
  neither `null` or `undefined`.
@@ -925,10 +874,10 @@ that might save you from loading something like [Underscore.js](http://underscor
925
874
  var $element, attrName, attrNames, values;
926
875
  $element = arguments[0], attrNames = 2 <= arguments.length ? slice.call(arguments, 1) : [];
927
876
  values = (function() {
928
- var j, len, results;
877
+ var i, len, results;
929
878
  results = [];
930
- for (j = 0, len = attrNames.length; j < len; j++) {
931
- attrName = attrNames[j];
879
+ for (i = 0, len = attrNames.length; i < len; i++) {
880
+ attrName = attrNames[i];
932
881
  results.push($element.attr(attrName));
933
882
  }
934
883
  return results;
@@ -1212,11 +1161,11 @@ that might save you from loading something like [Underscore.js](http://underscor
1212
1161
  @internal
1213
1162
  */
1214
1163
  copyAttributes = function($source, $target) {
1215
- var attr, j, len, ref, results;
1164
+ var attr, i, len, ref, results;
1216
1165
  ref = $source.get(0).attributes;
1217
1166
  results = [];
1218
- for (j = 0, len = ref.length; j < len; j++) {
1219
- attr = ref[j];
1167
+ for (i = 0, len = ref.length; i < len; i++) {
1168
+ attr = ref[i];
1220
1169
  if (attr.specified) {
1221
1170
  results.push($target.attr(attr.name, attr.value));
1222
1171
  } else {
@@ -1311,11 +1260,11 @@ that might save you from loading something like [Underscore.js](http://underscor
1311
1260
  @stable
1312
1261
  */
1313
1262
  only = function() {
1314
- var filtered, j, len, object, properties, property;
1263
+ var filtered, i, len, object, properties, property;
1315
1264
  object = arguments[0], properties = 2 <= arguments.length ? slice.call(arguments, 1) : [];
1316
1265
  filtered = {};
1317
- for (j = 0, len = properties.length; j < len; j++) {
1318
- property = properties[j];
1266
+ for (i = 0, len = properties.length; i < len; i++) {
1267
+ property = properties[i];
1319
1268
  if (object.hasOwnProperty(property)) {
1320
1269
  filtered[property] = object[property];
1321
1270
  }
@@ -1333,11 +1282,11 @@ that might save you from loading something like [Underscore.js](http://underscor
1333
1282
  @stable
1334
1283
  */
1335
1284
  except = function() {
1336
- var filtered, j, len, object, properties, property;
1285
+ var filtered, i, len, object, properties, property;
1337
1286
  object = arguments[0], properties = 2 <= arguments.length ? slice.call(arguments, 1) : [];
1338
1287
  filtered = copy(object);
1339
- for (j = 0, len = properties.length; j < len; j++) {
1340
- property = properties[j];
1288
+ for (i = 0, len = properties.length; i < len; i++) {
1289
+ property = properties[i];
1341
1290
  delete filtered[property];
1342
1291
  }
1343
1292
  return filtered;
@@ -1484,12 +1433,12 @@ that might save you from loading something like [Underscore.js](http://underscor
1484
1433
  @internal
1485
1434
  */
1486
1435
  multiSelector = function(parts) {
1487
- var combinedSelector, elements, j, len, obj, part, selectors;
1436
+ var combinedSelector, elements, i, len, obj, part, selectors;
1488
1437
  obj = {};
1489
1438
  selectors = [];
1490
1439
  elements = [];
1491
- for (j = 0, len = parts.length; j < len; j++) {
1492
- part = parts[j];
1440
+ for (i = 0, len = parts.length; i < len; i++) {
1441
+ part = parts[i];
1493
1442
  if (isString(part)) {
1494
1443
  selectors.push(part);
1495
1444
  } else {
@@ -1505,11 +1454,11 @@ that might save you from loading something like [Underscore.js](http://underscor
1505
1454
  return obj.find(void 0);
1506
1455
  };
1507
1456
  obj.find = function($root) {
1508
- var $matches, $result, k, len1, ref, selector;
1457
+ var $matches, $result, j, len1, ref, selector;
1509
1458
  $result = nullJQuery();
1510
1459
  ref = obj.parsed;
1511
- for (k = 0, len1 = ref.length; k < len1; k++) {
1512
- selector = ref[k];
1460
+ for (j = 0, len1 = ref.length; j < len1; j++) {
1461
+ selector = ref[j];
1513
1462
  $matches = $root ? $root.find(selector) : $(selector);
1514
1463
  $result = $result.add($matches);
1515
1464
  }
@@ -1577,7 +1526,7 @@ that might save you from loading something like [Underscore.js](http://underscor
1577
1526
  args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
1578
1527
  if (config.log) {
1579
1528
  args[0] = "[" + config.log + "] " + args[0];
1580
- return debug.apply(null, args);
1529
+ return up.puts.apply(up, args);
1581
1530
  }
1582
1531
  };
1583
1532
  keys = function() {
@@ -1635,7 +1584,9 @@ that might save you from loading something like [Underscore.js](http://underscor
1635
1584
  };
1636
1585
  alias = function(oldKey, newKey) {
1637
1586
  var value;
1638
- value = get(oldKey);
1587
+ value = get(oldKey, {
1588
+ silent: true
1589
+ });
1639
1590
  if (isDefined(value)) {
1640
1591
  return set(newKey, value);
1641
1592
  }
@@ -1666,24 +1617,30 @@ that might save you from loading something like [Underscore.js](http://underscor
1666
1617
  return true;
1667
1618
  }
1668
1619
  };
1669
- get = function(key, fallback) {
1620
+ get = function(key, options) {
1670
1621
  var entry, storeKey;
1671
- if (fallback == null) {
1672
- fallback = void 0;
1622
+ if (options == null) {
1623
+ options = {};
1673
1624
  }
1674
1625
  storeKey = normalizeStoreKey(key);
1675
1626
  if (entry = store[storeKey]) {
1676
1627
  if (isFresh(entry)) {
1677
- log("Cache hit for %o", key);
1628
+ if (!options.silent) {
1629
+ log("Cache hit for '%s'", key);
1630
+ }
1678
1631
  return entry.value;
1679
1632
  } else {
1680
- log("Discarding stale cache entry for %o", key);
1633
+ if (!options.silent) {
1634
+ log("Discarding stale cache entry for '%s'", key);
1635
+ }
1681
1636
  remove(key);
1682
- return fallback;
1637
+ return void 0;
1683
1638
  }
1684
1639
  } else {
1685
- log("Cache miss for %o", key);
1686
- return fallback;
1640
+ if (!options.silent) {
1641
+ log("Cache miss for '%s'", key);
1642
+ }
1643
+ return void 0;
1687
1644
  }
1688
1645
  };
1689
1646
  return {
@@ -1774,51 +1731,68 @@ that might save you from loading something like [Underscore.js](http://underscor
1774
1731
  @internal
1775
1732
  */
1776
1733
  requestDataAsArray = function(data) {
1777
- var name, results, value;
1778
- if (isMissing(data)) {
1779
- return [];
1780
- } else if (isArray(data)) {
1781
- return data;
1782
- } else if (isObject(data)) {
1783
- results = [];
1784
- for (name in data) {
1785
- value = data[name];
1786
- results.push({
1787
- name: name,
1788
- value: value
1734
+ var array, i, len, pair, part, query, ref;
1735
+ query = requestDataAsQuery(data);
1736
+ array = [];
1737
+ ref = query.split('&');
1738
+ for (i = 0, len = ref.length; i < len; i++) {
1739
+ part = ref[i];
1740
+ if (isPresent(part)) {
1741
+ pair = part.split('=');
1742
+ array.push({
1743
+ name: decodeURIComponent(pair[0]),
1744
+ value: decodeURIComponent(pair[1])
1789
1745
  });
1790
1746
  }
1791
- return results;
1792
- } else {
1793
- return error('Unknown options.data type for %o', data);
1794
1747
  }
1748
+ return array;
1795
1749
  };
1796
1750
 
1797
1751
  /**
1798
1752
  Returns an URL-encoded query string for the given params object.
1799
1753
 
1800
- @function up.util.requestDataAsQueryString
1754
+ @function up.util.requestDataAsQuery
1801
1755
  @param {Object|Array|Undefined|Null} data
1802
1756
  @internal
1803
1757
  */
1804
- requestDataAsQueryString = function(data) {
1805
- var array, query;
1806
- array = requestDataAsArray(data);
1807
- query = '';
1808
- if (isPresent(array)) {
1809
- query += '?';
1810
- each(array, function(field, index) {
1811
- if (index !== 0) {
1812
- query += '&';
1813
- }
1814
- return query += encodeURIComponent(field.name) + '=' + encodeURIComponent(field.value);
1815
- });
1758
+ requestDataAsQuery = function(data) {
1759
+ var query;
1760
+ if (data) {
1761
+ query = $.param(data);
1762
+ query = query.replace(/\+/g, '%20');
1763
+ return query;
1764
+ } else {
1765
+ return "";
1816
1766
  }
1817
- return query;
1767
+ };
1768
+
1769
+ /**
1770
+ Throws a fatal error with the given message.
1771
+
1772
+ - The error will be printed to the [error console](https://developer.mozilla.org/en-US/docs/Web/API/Console/error)
1773
+ - An [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) (exception) will be thrown, unwinding the current call stack
1774
+ - The error message will be printed in a corner of the screen
1775
+
1776
+ \#\#\#\# Examples
1777
+
1778
+ up.error('Division by zero')
1779
+ up.error('Unexpected result %o', result)
1780
+
1781
+ @experimental
1782
+ */
1783
+ error = function() {
1784
+ var $error, args, asString, ref, ref1;
1785
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
1786
+ (ref = up.log).error.apply(ref, args);
1787
+ asString = (ref1 = up.browser).sprintf.apply(ref1, args);
1788
+ $error = presence($('.up-error')) || $('<div class="up-error"></div>').prependTo('body');
1789
+ $error.addClass('up-error');
1790
+ $error.text(asString);
1791
+ throw new Error(asString);
1818
1792
  };
1819
1793
  return {
1820
1794
  requestDataAsArray: requestDataAsArray,
1821
- requestDataAsQueryString: requestDataAsQueryString,
1795
+ requestDataAsQuery: requestDataAsQuery,
1822
1796
  offsetParent: offsetParent,
1823
1797
  fixedToAbsolute: fixedToAbsolute,
1824
1798
  presentAttr: presentAttr,
@@ -1828,6 +1802,7 @@ that might save you from loading something like [Underscore.js](http://underscor
1828
1802
  normalizeMethod: normalizeMethod,
1829
1803
  createElementFromHtml: createElementFromHtml,
1830
1804
  $createElementFromSelector: $createElementFromSelector,
1805
+ $createPlaceholder: $createPlaceholder,
1831
1806
  selectorForElement: selectorForElement,
1832
1807
  extend: extend,
1833
1808
  copy: copy,
@@ -1835,12 +1810,11 @@ that might save you from loading something like [Underscore.js](http://underscor
1835
1810
  options: options,
1836
1811
  option: option,
1837
1812
  error: error,
1838
- debug: debug,
1839
- warn: warn,
1840
1813
  each: each,
1841
1814
  map: map,
1842
1815
  times: times,
1843
1816
  any: any,
1817
+ all: all,
1844
1818
  detect: detect,
1845
1819
  select: select,
1846
1820
  reject: reject,
@@ -1901,15 +1875,112 @@ that might save you from loading something like [Underscore.js](http://underscor
1901
1875
  cache: cache,
1902
1876
  unwrapElement: unwrapElement,
1903
1877
  multiSelector: multiSelector,
1904
- evalConsoleTemplate: evalConsoleTemplate
1878
+ error: error
1905
1879
  };
1906
1880
  })($);
1907
1881
 
1908
1882
  up.error = up.util.error;
1909
1883
 
1910
- up.warn = up.util.warn;
1884
+ }).call(this);
1885
+ (function() {
1886
+ var slice = [].slice;
1887
+
1888
+ up.log = (function($) {
1889
+ var debug, error, group, prefix, puts, warn;
1890
+ prefix = function(message) {
1891
+ return "ᴜᴘ " + message;
1892
+ };
1893
+
1894
+ /**
1895
+ Prints a debugging message to the browser console.
1896
+
1897
+ @function up.debug
1898
+ @param {String} message
1899
+ @param {Array} args...
1900
+ @internal
1901
+ */
1902
+ debug = function() {
1903
+ var args, message, ref;
1904
+ message = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
1905
+ if (message) {
1906
+ return (ref = up.browser).puts.apply(ref, ['debug', prefix(message)].concat(slice.call(args)));
1907
+ }
1908
+ };
1909
+
1910
+ /**
1911
+ Prints a logging message to the browser console.
1912
+
1913
+ @function up.puts
1914
+ @param {String} message
1915
+ @param {Array} args...
1916
+ @internal
1917
+ */
1918
+ puts = function() {
1919
+ var args, message, ref;
1920
+ message = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
1921
+ if (message) {
1922
+ return (ref = up.browser).puts.apply(ref, ['log', prefix(message)].concat(slice.call(args)));
1923
+ }
1924
+ };
1911
1925
 
1912
- up.debug = up.util.debug;
1926
+ /**
1927
+ @function up.log.warn
1928
+ @internal
1929
+ */
1930
+ warn = function() {
1931
+ var args, message, ref;
1932
+ message = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
1933
+ if (message) {
1934
+ return (ref = up.browser).puts.apply(ref, ['warn', prefix(message)].concat(slice.call(args)));
1935
+ }
1936
+ };
1937
+
1938
+ /**
1939
+ - Makes sure the group always closes
1940
+ - Does not make a group if the message is nil
1941
+
1942
+ @function up.log.group
1943
+ @internal
1944
+ */
1945
+ group = function() {
1946
+ var args, block, message, ref;
1947
+ message = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
1948
+ block = args.pop();
1949
+ if (message) {
1950
+ (ref = up.browser).puts.apply(ref, ['groupCollapsed', prefix(message)].concat(slice.call(args)));
1951
+ try {
1952
+ return block();
1953
+ } finally {
1954
+ if (message) {
1955
+ console.groupEnd();
1956
+ }
1957
+ }
1958
+ } else {
1959
+ return block();
1960
+ }
1961
+ };
1962
+
1963
+ /**
1964
+ @function up.log.error
1965
+ @internal
1966
+ */
1967
+ error = function() {
1968
+ var args, message, ref;
1969
+ message = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
1970
+ if (message) {
1971
+ return (ref = up.browser).puts.apply(ref, ['error', prefix(message)].concat(slice.call(args)));
1972
+ }
1973
+ };
1974
+ return {
1975
+ puts: puts,
1976
+ debug: debug,
1977
+ error: error,
1978
+ warn: warn,
1979
+ group: group
1980
+ };
1981
+ })(jQuery);
1982
+
1983
+ up.puts = up.log.puts;
1913
1984
 
1914
1985
  }).call(this);
1915
1986
 
@@ -1927,7 +1998,7 @@ we can't currently get rid off.
1927
1998
  var slice = [].slice;
1928
1999
 
1929
2000
  up.browser = (function($) {
1930
- var canCssTransition, canInputEvent, canLogSubstitution, canPushState, confirm, initialRequestMethod, isIE8OrWorse, isIE9OrWorse, isRecentJQuery, isSupported, loadPage, popCookie, puts, u, url;
2001
+ var CONSOLE_PLACEHOLDERS, canCssTransition, canInputEvent, canLogSubstitution, canPushState, confirm, initialRequestMethod, installPolyfills, isIE8OrWorse, isIE9OrWorse, isRecentJQuery, isSupported, loadPage, popCookie, puts, sprintf, u, url;
1931
2002
  u = up.util;
1932
2003
 
1933
2004
  /**
@@ -1938,13 +2009,17 @@ we can't currently get rid off.
1938
2009
  @internal
1939
2010
  */
1940
2011
  loadPage = function(url, options) {
1941
- var $form, addField, csrfField, method;
2012
+ var $form, addField, csrfField, method, query;
1942
2013
  if (options == null) {
1943
2014
  options = {};
1944
2015
  }
1945
2016
  method = u.option(options.method, 'get').toLowerCase();
1946
2017
  if (method === 'get') {
1947
- return location.href = url + u.requestDataAsQueryString(options.data);
2018
+ query = u.requestDataAsQuery(options.data);
2019
+ if (query) {
2020
+ url = url + "?" + query;
2021
+ }
2022
+ return location.href = url;
1948
2023
  } else {
1949
2024
  $form = $("<form method='post' action='" + url + "'></form>");
1950
2025
  addField = function(field) {
@@ -1988,10 +2063,50 @@ we can't currently get rid off.
1988
2063
  if (canLogSubstitution()) {
1989
2064
  return console[stream].apply(console, args);
1990
2065
  } else {
1991
- message = u.evalConsoleTemplate.apply(u, args);
2066
+ message = sprintf.apply(null, args);
1992
2067
  return console[stream](message);
1993
2068
  }
1994
2069
  };
2070
+ CONSOLE_PLACEHOLDERS = /\%[odisf]/g;
2071
+
2072
+ /**
2073
+ See https://developer.mozilla.org/en-US/docs/Web/API/Console#Using_string_substitutions
2074
+
2075
+ @function up.browser.sprintf
2076
+ @internal
2077
+ */
2078
+ sprintf = function() {
2079
+ var args, i, maxLength, message;
2080
+ message = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
2081
+ i = 0;
2082
+ maxLength = 80;
2083
+ return message.replace(CONSOLE_PLACEHOLDERS, function() {
2084
+ var arg, argType;
2085
+ arg = args[i];
2086
+ argType = typeof arg;
2087
+ if (argType === 'string') {
2088
+ arg = arg.replace(/\s+/g, ' ');
2089
+ if (arg.length > maxLength) {
2090
+ arg = (arg.substr(0, maxLength)) + "…";
2091
+ }
2092
+ arg = "\"" + arg + "\"";
2093
+ } else if (argType === 'undefined') {
2094
+ arg = 'undefined';
2095
+ } else if (argType === 'number' || argType === 'function') {
2096
+ arg = arg.toString();
2097
+ } else {
2098
+ arg = JSON.stringify(arg);
2099
+ }
2100
+ if (arg.length > maxLength) {
2101
+ arg = (arg.substr(0, maxLength)) + " …";
2102
+ if (argType === 'object' || argType === 'function') {
2103
+ arg += " }";
2104
+ }
2105
+ }
2106
+ i += 1;
2107
+ return arg;
2108
+ });
2109
+ };
1995
2110
  url = function() {
1996
2111
  return location.href;
1997
2112
  };
@@ -2113,6 +2228,27 @@ we can't currently get rid off.
2113
2228
  isSupported = function() {
2114
2229
  return (!isIE8OrWorse()) && isRecentJQuery();
2115
2230
  };
2231
+
2232
+ /**
2233
+ @internal
2234
+ */
2235
+ installPolyfills = function() {
2236
+ console.group || (console.group = function() {
2237
+ var args;
2238
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
2239
+ return puts.apply(null, ['group'].concat(slice.call(args)));
2240
+ });
2241
+ console.groupCollapsed || (console.groupCollapsed = function() {
2242
+ var args;
2243
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
2244
+ return puts.apply(null, ['groupCollapsed'].concat(slice.call(args)));
2245
+ });
2246
+ return console.groupEnd || (console.groupEnd = function() {
2247
+ var args;
2248
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
2249
+ return puts.apply(null, ['groupEnd'].concat(slice.call(args)));
2250
+ });
2251
+ };
2116
2252
  return {
2117
2253
  url: url,
2118
2254
  loadPage: loadPage,
@@ -2122,7 +2258,9 @@ we can't currently get rid off.
2122
2258
  canInputEvent: canInputEvent,
2123
2259
  canLogSubstitution: canLogSubstitution,
2124
2260
  isSupported: isSupported,
2125
- puts: puts
2261
+ installPolyfills: installPolyfills,
2262
+ puts: puts,
2263
+ sprintf: sprintf
2126
2264
  };
2127
2265
  })(jQuery);
2128
2266
 
@@ -2173,7 +2311,7 @@ and call `preventDefault()` on the `event` object:
2173
2311
  var slice = [].slice;
2174
2312
 
2175
2313
  up.bus = (function($) {
2176
- var boot, emit, emitReset, forgetUpDescription, live, liveUpDescriptions, nextUpDescriptionNumber, nobodyPrevents, onEscape, rememberUpDescription, restoreSnapshot, snapshot, u, unbind, upDescriptionNumber, upDescriptionToJqueryDescription, upListenerToJqueryListener;
2314
+ var boot, emit, emitReset, forgetUpDescription, live, liveUpDescriptions, logEmission, nextUpDescriptionNumber, nobodyPrevents, onEscape, rememberUpDescription, restoreSnapshot, snapshot, u, unbind, upDescriptionNumber, upDescriptionToJqueryDescription, upListenerToJqueryListener;
2177
2315
  u = up.util;
2178
2316
  liveUpDescriptions = {};
2179
2317
  nextUpDescriptionNumber = 0;
@@ -2372,6 +2510,10 @@ and call `preventDefault()` on the `event` object:
2372
2510
  or `stopPropagation()`.
2373
2511
  @param {jQuery} [eventProps.$element=$(document)]
2374
2512
  The element on which the event is triggered.
2513
+ @param {String|Array} [eventProps.message]
2514
+ A message to print to the console when the event is emitted.
2515
+ If omitted, a default message is printed.
2516
+ Set this to `false` to prevent any console output.
2375
2517
  @experimental
2376
2518
  */
2377
2519
  emit = function(eventName, eventProps) {
@@ -2380,11 +2522,40 @@ and call `preventDefault()` on the `event` object:
2380
2522
  eventProps = {};
2381
2523
  }
2382
2524
  event = $.Event(eventName, eventProps);
2383
- $target = eventProps.$element || $(document);
2384
- u.debug("Emitting %o on %o with props %o", eventName, $target, eventProps);
2525
+ if ($target = eventProps.$element) {
2526
+ delete eventProps.$element;
2527
+ } else {
2528
+ $target = $(document);
2529
+ }
2530
+ logEmission(eventName, eventProps);
2385
2531
  $target.trigger(event);
2386
2532
  return event;
2387
2533
  };
2534
+ logEmission = function(eventName, eventProps) {
2535
+ var niceMessage, niceMessageArgs, ref;
2536
+ if (eventProps.hasOwnProperty('message')) {
2537
+ niceMessage = eventProps.message;
2538
+ delete eventProps.message;
2539
+ if (u.isArray(niceMessage)) {
2540
+ ref = niceMessage, niceMessage = ref[0], niceMessageArgs = 2 <= ref.length ? slice.call(ref, 1) : [];
2541
+ } else {
2542
+ niceMessageArgs = [];
2543
+ }
2544
+ if (niceMessage) {
2545
+ if (u.isPresent(eventProps)) {
2546
+ return up.puts.apply(up, [niceMessage + " (%s (%o))"].concat(slice.call(niceMessageArgs), [eventName], [eventProps]));
2547
+ } else {
2548
+ return up.puts.apply(up, [niceMessage + " (%s)"].concat(slice.call(niceMessageArgs), [eventName]));
2549
+ }
2550
+ }
2551
+ } else {
2552
+ if (u.isPresent(eventProps)) {
2553
+ return up.puts('Emitted event %s (%o)', eventName, eventProps);
2554
+ } else {
2555
+ return up.puts('Emitted event %s', eventName);
2556
+ }
2557
+ }
2558
+ };
2388
2559
 
2389
2560
  /**
2390
2561
  [Emits an event](/up.emit) and returns whether any listener
@@ -2393,13 +2564,19 @@ and call `preventDefault()` on the `event` object:
2393
2564
  @function up.bus.nobodyPrevents
2394
2565
  @param {String} eventName
2395
2566
  @param {Object} eventProps
2567
+ @param {String|Array} [eventProps.message]
2396
2568
  @experimental
2397
2569
  */
2398
2570
  nobodyPrevents = function() {
2399
2571
  var args, event;
2400
2572
  args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
2401
2573
  event = emit.apply(null, args);
2402
- return !event.isDefaultPrevented();
2574
+ if (event.isDefaultPrevented()) {
2575
+ up.puts("An observer prevented the event %s", args[0]);
2576
+ return false;
2577
+ } else {
2578
+ return true;
2579
+ }
2403
2580
  };
2404
2581
 
2405
2582
  /**
@@ -2432,7 +2609,7 @@ and call `preventDefault()` on the `event` object:
2432
2609
  results = [];
2433
2610
  for (i = 0, len = liveUpDescriptions.length; i < len; i++) {
2434
2611
  description = liveUpDescriptions[i];
2435
- results.push(description._isDefault = true);
2612
+ results.push(description.isDefault = true);
2436
2613
  }
2437
2614
  return results;
2438
2615
  };
@@ -2446,7 +2623,7 @@ and call `preventDefault()` on the `event` object:
2446
2623
  restoreSnapshot = function() {
2447
2624
  var description, doomedDescriptions, i, len, results;
2448
2625
  doomedDescriptions = u.reject(liveUpDescriptions, function(description) {
2449
- return description._isDefault;
2626
+ return description.isDefault;
2450
2627
  });
2451
2628
  results = [];
2452
2629
  for (i = 0, len = doomedDescriptions.length; i < len; i++) {
@@ -2468,7 +2645,9 @@ and call `preventDefault()` on the `event` object:
2468
2645
  @experimental
2469
2646
  */
2470
2647
  emitReset = function() {
2471
- return up.emit('up:framework:reset');
2648
+ return up.emit('up:framework:reset', {
2649
+ message: 'Resetting framework'
2650
+ });
2472
2651
  };
2473
2652
 
2474
2653
  /**
@@ -2493,7 +2672,10 @@ and call `preventDefault()` on the `event` object:
2493
2672
  */
2494
2673
  boot = function() {
2495
2674
  if (up.browser.isSupported()) {
2496
- return up.emit('up:framework:boot');
2675
+ up.browser.installPolyfills();
2676
+ return up.emit('up:framework:boot', {
2677
+ message: 'Booting framework'
2678
+ });
2497
2679
  }
2498
2680
  };
2499
2681
 
@@ -2568,7 +2750,7 @@ later.
2568
2750
  var slice = [].slice;
2569
2751
 
2570
2752
  up.syntax = (function($) {
2571
- var DESTROYABLE_CLASS, DESTROYER_KEY, applyCompiler, compile, compiler, compilers, data, defaultCompilers, hello, reset, runDestroyers, snapshot, u;
2753
+ var DESTROYABLE_CLASS, DESTROYER_KEY, applyCompiler, clean, compile, compiler, compilers, data, reset, snapshot, u;
2572
2754
  u = up.util;
2573
2755
  DESTROYABLE_CLASS = 'up-destroyable';
2574
2756
  DESTROYER_KEY = 'up-destroyer';
@@ -2714,6 +2896,11 @@ later.
2714
2896
  If set to `true` and a fragment insertion contains multiple
2715
2897
  elements matching the selector, `compiler` is only called once
2716
2898
  with a jQuery collection containing all matching elements.
2899
+ @param {Boolean} [options.keep=false]
2900
+ If set to `true` compiled fragment will be [persisted](/up-keep) during
2901
+ [page updates](/a-up-target).
2902
+
2903
+ This has the same effect as setting an `up-keep` attribute on the element.
2717
2904
  @param {Function($element, data)} compiler
2718
2905
  The function to call when a matching element is inserted.
2719
2906
  The function takes the new element as the first argument (as a jQuery object).
@@ -2728,7 +2915,6 @@ later.
2728
2915
  @stable
2729
2916
  */
2730
2917
  compilers = [];
2731
- defaultCompilers = null;
2732
2918
  compiler = function() {
2733
2919
  var args, options, selector;
2734
2920
  selector = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
@@ -2736,46 +2922,81 @@ later.
2736
2922
  return;
2737
2923
  }
2738
2924
  compiler = args.pop();
2739
- options = u.options(args[0], {
2740
- batch: false
2741
- });
2925
+ options = u.options(args[0]);
2742
2926
  return compilers.push({
2743
2927
  selector: selector,
2744
2928
  callback: compiler,
2745
- batch: options.batch
2929
+ batch: options.batch,
2930
+ keep: options.keep
2746
2931
  });
2747
2932
  };
2748
2933
  applyCompiler = function(compiler, $jqueryElement, nativeElement) {
2749
- var destroyer;
2750
- u.debug("Applying compiler %o on %o", compiler.selector, nativeElement);
2934
+ var destroyer, value;
2935
+ up.puts((!compiler.isDefault ? "Compiling '%s' on %o" : void 0), compiler.selector, nativeElement);
2936
+ if (compiler.keep) {
2937
+ value = u.isString(compiler.keep) ? compiler.keep : '';
2938
+ $jqueryElement.attr('up-keep', value);
2939
+ }
2751
2940
  destroyer = compiler.callback.apply(nativeElement, [$jqueryElement, data($jqueryElement)]);
2752
2941
  if (u.isFunction(destroyer)) {
2753
2942
  $jqueryElement.addClass(DESTROYABLE_CLASS);
2754
2943
  return $jqueryElement.data(DESTROYER_KEY, destroyer);
2755
- }
2756
- };
2757
- compile = function($fragment) {
2758
- var $matches, i, len, results;
2759
- u.debug("Compiling fragment %o", $fragment);
2760
- results = [];
2761
- for (i = 0, len = compilers.length; i < len; i++) {
2762
- compiler = compilers[i];
2763
- $matches = u.findWithSelf($fragment, compiler.selector);
2764
- if ($matches.length) {
2765
- if (compiler.batch) {
2766
- results.push(applyCompiler(compiler, $matches, $matches.get()));
2767
- } else {
2768
- results.push($matches.each(function() {
2769
- return applyCompiler(compiler, $(this), this);
2944
+ }
2945
+ };
2946
+
2947
+ /**
2948
+ Applies all compilers on the given element and its descendants.
2949
+ Unlike [`up.hello`](/up.hello), this doesn't emit any events.
2950
+
2951
+ @function up.syntax.compile
2952
+ @param {Array<Element>} [options.skip]
2953
+ A list of elements whose subtrees should not be compiled.
2954
+ @internal
2955
+ */
2956
+ compile = function($fragment, options) {
2957
+ var $skipSubtrees;
2958
+ options = u.options(options);
2959
+ $skipSubtrees = $(options.skip);
2960
+ return up.log.group("Compiling fragment %o", $fragment.get(0), function() {
2961
+ var $matches, i, len, results;
2962
+ results = [];
2963
+ for (i = 0, len = compilers.length; i < len; i++) {
2964
+ compiler = compilers[i];
2965
+ $matches = u.findWithSelf($fragment, compiler.selector);
2966
+ $matches = $matches.filter(function() {
2967
+ var $match;
2968
+ $match = $(this);
2969
+ return u.all($skipSubtrees, function(element) {
2970
+ return $match.closest(element).length === 0;
2971
+ });
2972
+ });
2973
+ if ($matches.length) {
2974
+ results.push(up.log.group((!compiler.isDefault ? "Compiling '%s' on %d element(s)" : void 0), compiler.selector, $matches.length, function() {
2975
+ if (compiler.batch) {
2976
+ return applyCompiler(compiler, $matches, $matches.get());
2977
+ } else {
2978
+ return $matches.each(function() {
2979
+ return applyCompiler(compiler, $(this), this);
2980
+ });
2981
+ }
2770
2982
  }));
2983
+ } else {
2984
+ results.push(void 0);
2771
2985
  }
2772
- } else {
2773
- results.push(void 0);
2774
2986
  }
2775
- }
2776
- return results;
2987
+ return results;
2988
+ });
2777
2989
  };
2778
- runDestroyers = function($fragment) {
2990
+
2991
+ /**
2992
+ Runs any destroyers on the given fragment and its descendants.
2993
+ Unlike [`up.destroy`](/up.destroy), this doesn't emit any events
2994
+ and does not remove the element from the DOM.
2995
+
2996
+ @function up.syntax.clean
2997
+ @internal
2998
+ */
2999
+ clean = function($fragment) {
2779
3000
  return u.findWithSelf($fragment, "." + DESTROYABLE_CLASS).each(function() {
2780
3001
  var $element, destroyer;
2781
3002
  $element = $(this);
@@ -2831,7 +3052,13 @@ later.
2831
3052
  @internal
2832
3053
  */
2833
3054
  snapshot = function() {
2834
- return defaultCompilers = u.copy(compilers);
3055
+ var i, len, results;
3056
+ results = [];
3057
+ for (i = 0, len = compilers.length; i < len; i++) {
3058
+ compiler = compilers[i];
3059
+ results.push(compiler.isDefault = true);
3060
+ }
3061
+ return results;
2835
3062
  };
2836
3063
 
2837
3064
  /**
@@ -2841,80 +3068,22 @@ later.
2841
3068
  @internal
2842
3069
  */
2843
3070
  reset = function() {
2844
- return compilers = u.copy(defaultCompilers);
2845
- };
2846
-
2847
- /**
2848
- Compiles a page fragment that has been inserted into the DOM
2849
- without Up.js.
2850
-
2851
- **As long as you manipulate the DOM using Up.js, you will never
2852
- need to call this method.** You only need to use `up.hello` if the
2853
- DOM is manipulated without Up.js' involvement, e.g. by setting
2854
- the `innerHTML` property or calling jQuery methods like
2855
- `html`, `insertAfter` or `appendTo`:
2856
-
2857
- $element = $('.element');
2858
- $element.html('<div>...</div>');
2859
- up.hello($element);
2860
-
2861
- This function emits the [`up:fragment:inserted`](/up:fragment:inserted)
2862
- event.
2863
-
2864
- @function up.hello
2865
- @param {String|Element|jQuery} selectorOrElement
2866
- @param {String|Element|jQuery} [options.origin]
2867
- @return {jQuery}
2868
- The compiled element
2869
- @stable
2870
- */
2871
- hello = function(selectorOrElement, options) {
2872
- var $element, eventAttrs;
2873
- $element = $(selectorOrElement);
2874
- eventAttrs = u.options(options, {
2875
- $element: $element
3071
+ return compilers = u.select(compilers, function(compiler) {
3072
+ return compiler.isDefault;
2876
3073
  });
2877
- up.emit('up:fragment:inserted', eventAttrs);
2878
- return $element;
2879
3074
  };
2880
-
2881
- /**
2882
- When a page fragment has been [inserted or updated](/up.replace),
2883
- this event is [emitted](/up.emit) on the fragment.
2884
-
2885
- \#\#\#\# Example
2886
-
2887
- up.on('up:fragment:inserted', function(event, $fragment) {
2888
- console.log("Looks like we have a new %o!", $fragment);
2889
- });
2890
-
2891
- @event up:fragment:inserted
2892
- @param {jQuery} event.$element
2893
- The fragment that has been inserted or updated.
2894
- @stable
2895
- */
2896
- up.on('ready', (function() {
2897
- return hello(document.body);
2898
- }));
2899
- up.on('up:fragment:inserted', function(event, $element) {
2900
- return compile($element);
2901
- });
2902
- up.on('up:fragment:destroy', function(event, $element) {
2903
- return runDestroyers($element);
2904
- });
2905
3075
  up.on('up:framework:boot', snapshot);
2906
3076
  up.on('up:framework:reset', reset);
2907
3077
  return {
2908
3078
  compiler: compiler,
2909
- hello: hello,
3079
+ compile: compile,
3080
+ clean: clean,
2910
3081
  data: data
2911
3082
  };
2912
3083
  })(jQuery);
2913
3084
 
2914
3085
  up.compiler = up.syntax.compiler;
2915
3086
 
2916
- up.hello = up.syntax.hello;
2917
-
2918
3087
  up.ready = function() {
2919
3088
  return up.util.error('up.ready no longer exists. Please use up.hello instead.');
2920
3089
  };
@@ -3041,6 +3210,7 @@ We need to work on this page:
3041
3210
  @experimental
3042
3211
  */
3043
3212
  push = function(url, options) {
3213
+ up.puts("Current location is now %s", url);
3044
3214
  return manipulate('push', url, options);
3045
3215
  };
3046
3216
  manipulate = function(method, url, options) {
@@ -3052,7 +3222,6 @@ We need to work on this page:
3052
3222
  if (up.browser.canPushState()) {
3053
3223
  fullMethod = method + "State";
3054
3224
  state = buildState();
3055
- u.debug("Changing history to URL %o (%o)", url, method);
3056
3225
  window.history[fullMethod](state, '', url);
3057
3226
  return observeNewUrl(currentUrl());
3058
3227
  } else {
@@ -3066,32 +3235,35 @@ We need to work on this page:
3066
3235
  };
3067
3236
  };
3068
3237
  restoreStateOnPop = function(state) {
3069
- var popSelector, url;
3070
- url = currentUrl();
3071
- u.debug("Restoring state %o (now on " + url + ")", state);
3072
- popSelector = config.popTargets.join(', ');
3073
- return up.replace(popSelector, url, {
3074
- history: false,
3075
- reveal: false,
3076
- transition: 'none',
3077
- saveScroll: false,
3078
- restoreScroll: config.restoreScroll
3079
- });
3080
- };
3081
- pop = function(event) {
3082
- var state;
3083
- u.debug("History state popped to URL %o", currentUrl());
3084
- observeNewUrl(currentUrl());
3085
- up.layout.saveScroll({
3086
- url: previousUrl
3087
- });
3088
- state = event.originalEvent.state;
3238
+ var url;
3089
3239
  if (state != null ? state.fromUp : void 0) {
3090
- return restoreStateOnPop(state);
3240
+ url = currentUrl();
3241
+ return up.log.group("Restoring URL %s", url, function() {
3242
+ var popSelector;
3243
+ popSelector = config.popTargets.join(', ');
3244
+ return up.replace(popSelector, url, {
3245
+ history: false,
3246
+ reveal: false,
3247
+ transition: 'none',
3248
+ saveScroll: false,
3249
+ restoreScroll: config.restoreScroll
3250
+ });
3251
+ });
3091
3252
  } else {
3092
- return u.debug('Discarding unknown state %o', state);
3253
+ return up.puts('Ignoring a state not pushed by Up.js (%o)', state);
3093
3254
  }
3094
3255
  };
3256
+ pop = function(event) {
3257
+ return up.log.group("History state popped to URL %s", currentUrl(), function() {
3258
+ var state;
3259
+ observeNewUrl(currentUrl());
3260
+ up.layout.saveScroll({
3261
+ url: previousUrl
3262
+ });
3263
+ state = event.originalEvent.state;
3264
+ return restoreStateOnPop(state);
3265
+ });
3266
+ };
3095
3267
  if (up.browser.canPushState()) {
3096
3268
  register = function() {
3097
3269
  $(window).on("popstate", pop);
@@ -3324,7 +3496,7 @@ This modules contains functions to scroll the viewport and reveal contained elem
3324
3496
  $obstructor = $(obstructor);
3325
3497
  anchorPosition = $obstructor.css(cssAttr);
3326
3498
  if (!u.isPresent(anchorPosition)) {
3327
- u.error("Fixed element %o must have a CSS attribute %o", $obstructor, cssAttr);
3499
+ u.error("Fixed element %o must have a CSS attribute %s", $obstructor.get(0), cssAttr);
3328
3500
  }
3329
3501
  return parseInt(anchorPosition) + $obstructor.height();
3330
3502
  };
@@ -3399,9 +3571,9 @@ This modules contains functions to scroll the viewport and reveal contained elem
3399
3571
  */
3400
3572
  reveal = function(elementOrSelector, options) {
3401
3573
  var $element, $viewport, elementDims, firstElementRow, lastElementRow, newScrollPos, obstruction, offsetShift, originalScrollPos, predictFirstVisibleRow, predictLastVisibleRow, snap, viewportHeight, viewportIsDocument;
3402
- u.debug('Revealing %o', elementOrSelector);
3403
- options = u.options(options);
3404
3574
  $element = $(elementOrSelector);
3575
+ up.puts('Revealing fragment %o', elementOrSelector.get(0));
3576
+ options = u.options(options);
3405
3577
  $viewport = options.viewport ? $(options.viewport) : viewportOf($element);
3406
3578
  snap = u.option(options.snap, config.snap);
3407
3579
  viewportIsDocument = $viewport.is(document);
@@ -3566,7 +3738,7 @@ This modules contains functions to scroll the viewport and reveal contained elem
3566
3738
  }
3567
3739
  url = u.option(options.url, up.history.url());
3568
3740
  tops = u.option(options.tops, scrollTops());
3569
- u.debug('Saving scroll positions for URL %o: %o', url, tops);
3741
+ up.puts('Saving scroll positions for URL %s (%o)', url, tops);
3570
3742
  return lastScrollTops.set(url, tops);
3571
3743
  };
3572
3744
 
@@ -3584,7 +3756,7 @@ This modules contains functions to scroll the viewport and reveal contained elem
3584
3756
  @experimental
3585
3757
  */
3586
3758
  restoreScroll = function(options) {
3587
- var $ancestorViewports, $descendantViewports, $matchingViewport, $viewports, key, right, scrollTop, tops, url;
3759
+ var $ancestorViewports, $descendantViewports, $viewports, tops, url;
3588
3760
  if (options == null) {
3589
3761
  options = {};
3590
3762
  }
@@ -3598,16 +3770,18 @@ This modules contains functions to scroll the viewport and reveal contained elem
3598
3770
  $viewports = viewports();
3599
3771
  }
3600
3772
  tops = lastScrollTops.get(url);
3601
- u.debug('Restoring scroll positions for URL %o (viewports are %o, saved tops are %o)', url, $viewports, tops);
3602
- for (key in tops) {
3603
- scrollTop = tops[key];
3604
- right = key === 'document' ? document : key;
3605
- $matchingViewport = $viewports.filter(right);
3606
- scroll($matchingViewport, scrollTop, {
3607
- duration: 0
3608
- });
3609
- }
3610
- return u.resolvedDeferred();
3773
+ return up.log.group('Restoring scroll positions for URL %s to %o', url, tops, function() {
3774
+ var $matchingViewport, key, right, scrollTop;
3775
+ for (key in tops) {
3776
+ scrollTop = tops[key];
3777
+ right = key === 'document' ? document : key;
3778
+ $matchingViewport = $viewports.filter(right);
3779
+ scroll($matchingViewport, scrollTop, {
3780
+ duration: 0
3781
+ });
3782
+ }
3783
+ return u.resolvedDeferred();
3784
+ });
3611
3785
  };
3612
3786
 
3613
3787
  /**
@@ -3765,7 +3939,7 @@ are based on this module.
3765
3939
 
3766
3940
  (function() {
3767
3941
  up.flow = (function($) {
3768
- var autofocus, destroy, elementsInserted, findOldFragment, first, implant, isRealElement, oldFragmentNotFound, parseImplantSteps, parseResponse, processResponse, reload, replace, resolveSelector, setSource, source, swapElements, u;
3942
+ var autofocus, destroy, emitFragmentInserted, emitFragmentKept, extract, findKeepPlan, findOldFragment, first, hello, isRealElement, oldFragmentNotFound, parseImplantSteps, parseResponse, processResponse, reload, replace, resolveSelector, setSource, source, swapElements, transferKeepableElements, u, updateHistory;
3769
3943
  u = up.util;
3770
3944
  setSource = function(element, sourceUrl) {
3771
3945
  var $element;
@@ -3809,7 +3983,7 @@ are based on this module.
3809
3983
  originSelector = u.selectorForElement(origin);
3810
3984
  selector = selector.replace(/\&/, originSelector);
3811
3985
  } else {
3812
- u.error("Found origin reference %o in selector %o, but options.origin is missing", '&', selector);
3986
+ u.error("Found origin reference (%s) in selector %s, but options.origin is missing", '&', selector);
3813
3987
  }
3814
3988
  }
3815
3989
  } else {
@@ -3822,7 +3996,9 @@ are based on this module.
3822
3996
  Replaces elements on the current page with corresponding elements
3823
3997
  from a new page fetched from the server.
3824
3998
 
3825
- The current and new elements must have the same CSS selector.
3999
+ The current and new elements must both match the given CSS selector.
4000
+
4001
+ The UJS variant of this is the [`a[up-target]`](/a-up-target) selector.
3826
4002
 
3827
4003
  \#\#\#\# Example
3828
4004
 
@@ -3840,7 +4016,7 @@ are based on this module.
3840
4016
  <div class="one">new one</div>
3841
4017
  <div class="two">new two</div>
3842
4018
 
3843
- Up.js looks for the selector `.two` in the response and [implants](/up.implant) it into
4019
+ Up.js looks for the selector `.two` in the response and [implants](/up.extract) it into
3844
4020
  the current page. The current page now looks like this:
3845
4021
 
3846
4022
  <div class="one">old one</div>
@@ -3942,7 +4118,7 @@ are based on this module.
3942
4118
  */
3943
4119
  replace = function(selectorOrElement, url, options) {
3944
4120
  var failTarget, promise, request, target;
3945
- u.debug("Replace %o with %o (options %o)", selectorOrElement, url, options);
4121
+ up.puts("Replacing %s from %s (%o)", selectorOrElement, url, options);
3946
4122
  options = u.options(options);
3947
4123
  target = resolveSelector(selectorOrElement, options.origin);
3948
4124
  failTarget = u.option(options.failTarget, 'body');
@@ -3963,7 +4139,7 @@ are based on this module.
3963
4139
  preload: options.preload,
3964
4140
  headers: options.headers
3965
4141
  };
3966
- promise = up.proxy.ajax(request);
4142
+ promise = up.ajax(request);
3967
4143
  promise.done(function(html, textStatus, xhr) {
3968
4144
  return processResponse(true, target, url, request, xhr, options);
3969
4145
  });
@@ -3977,7 +4153,7 @@ are based on this module.
3977
4153
  @internal
3978
4154
  */
3979
4155
  processResponse = function(isSuccess, selector, url, request, xhr, options) {
3980
- var isReloadable, newRequest, urlFromServer;
4156
+ var isReloadable, newRequest, query, urlFromServer;
3981
4157
  options.method = u.normalizeMethod(u.option(u.methodFromXhr(xhr), options.method));
3982
4158
  options.title = u.option(u.titleFromXhr(xhr), options.title);
3983
4159
  isReloadable = options.method === 'GET';
@@ -3992,7 +4168,9 @@ are based on this module.
3992
4168
  up.proxy.alias(request, newRequest);
3993
4169
  }
3994
4170
  } else if (isReloadable) {
3995
- url = url + u.requestDataAsQueryString(options.data);
4171
+ if (query = u.requestDataAsQuery(options.data)) {
4172
+ url = url + "?" + query;
4173
+ }
3996
4174
  }
3997
4175
  if (isSuccess) {
3998
4176
  if (isReloadable) {
@@ -4028,7 +4206,7 @@ are based on this module.
4028
4206
  if (options.preload) {
4029
4207
  return u.resolvedPromise();
4030
4208
  } else {
4031
- return implant(selector, xhr.responseText, options);
4209
+ return extract(selector, xhr.responseText, options);
4032
4210
  }
4033
4211
  };
4034
4212
 
@@ -4049,7 +4227,7 @@ are based on this module.
4049
4227
  html = '<div class="one">new one</div>' +
4050
4228
  '<div class="two">new two</div>';
4051
4229
 
4052
- up.flow.implant('.two', html);
4230
+ up.extract('.two', html);
4053
4231
 
4054
4232
  Up.js looks for the selector `.two` in the strings and updates its
4055
4233
  contents in the current page. The current page now looks like this:
@@ -4060,7 +4238,7 @@ are based on this module.
4060
4238
  Note how only `.two` has changed. The update for `.one` was
4061
4239
  discarded, since it didn't match the selector.
4062
4240
 
4063
- @function up.implant
4241
+ @function up.extract
4064
4242
  @param {String|Element|jQuery} selectorOrElement
4065
4243
  @param {String} html
4066
4244
  @param {Object} [options]
@@ -4070,36 +4248,43 @@ are based on this module.
4070
4248
  and all animation has finished.
4071
4249
  @experimental
4072
4250
  */
4073
- implant = function(selectorOrElement, html, options) {
4074
- var $new, $old, deferred, deferreds, j, len, ref, ref1, ref2, response, selector, step;
4075
- options = u.options(options, {
4076
- historyMethod: 'push',
4077
- requireMatch: true
4078
- });
4079
- selector = resolveSelector(selectorOrElement, options.origin);
4080
- response = parseResponse(html, options);
4081
- options.title || (options.title = response.title());
4082
- if (options.saveScroll !== false) {
4083
- up.layout.saveScroll();
4084
- }
4085
- if (typeof options.beforeSwap === "function") {
4086
- options.beforeSwap($old, $new);
4087
- }
4088
- deferreds = [];
4089
- ref = parseImplantSteps(selector, options);
4090
- for (j = 0, len = ref.length; j < len; j++) {
4091
- step = ref[j];
4092
- $old = findOldFragment(step.selector, options);
4093
- $new = (ref1 = response.find(step.selector)) != null ? ref1.first() : void 0;
4094
- if ($old && $new) {
4095
- deferred = swapElements($old, $new, step.pseudoClass, step.transition, options);
4096
- deferreds.push(deferred);
4251
+ extract = function(selectorOrElement, html, options) {
4252
+ return up.log.group('Extracting %s from %d bytes of HTML', selectorOrElement, html != null ? html.length : void 0, function() {
4253
+ var deferreds, j, len, ref, ref1, response, selector, step;
4254
+ options = u.options(options, {
4255
+ historyMethod: 'push',
4256
+ requireMatch: true,
4257
+ keep: true
4258
+ });
4259
+ selector = resolveSelector(selectorOrElement, options.origin);
4260
+ response = parseResponse(html, options);
4261
+ options.title || (options.title = response.title());
4262
+ if (options.saveScroll !== false) {
4263
+ up.layout.saveScroll();
4097
4264
  }
4098
- }
4099
- if (typeof options.afterSwap === "function") {
4100
- options.afterSwap($old, $new);
4101
- }
4102
- return (ref2 = up.motion).when.apply(ref2, deferreds);
4265
+ if (typeof options.beforeSwap === "function") {
4266
+ options.beforeSwap();
4267
+ }
4268
+ deferreds = [];
4269
+ updateHistory(options);
4270
+ ref = parseImplantSteps(selector, options);
4271
+ for (j = 0, len = ref.length; j < len; j++) {
4272
+ step = ref[j];
4273
+ up.log.group('Updating %s', step.selector, function() {
4274
+ var $new, $old, deferred, ref1;
4275
+ $old = findOldFragment(step.selector, options);
4276
+ $new = (ref1 = response.find(step.selector)) != null ? ref1.first() : void 0;
4277
+ if ($old && $new) {
4278
+ deferred = swapElements($old, $new, step.pseudoClass, step.transition, options);
4279
+ return deferreds.push(deferred);
4280
+ }
4281
+ });
4282
+ }
4283
+ if (typeof options.afterSwap === "function") {
4284
+ options.afterSwap();
4285
+ }
4286
+ return (ref1 = up.motion).when.apply(ref1, deferreds);
4287
+ });
4103
4288
  };
4104
4289
  findOldFragment = function(selector, options) {
4105
4290
  return first(".up-popup " + selector) || first(".up-modal " + selector) || first(selector) || oldFragmentNotFound(selector, options);
@@ -4107,7 +4292,7 @@ are based on this module.
4107
4292
  oldFragmentNotFound = function(selector, options) {
4108
4293
  var message;
4109
4294
  if (options.requireMatch) {
4110
- message = 'Could not find selector %o in current body HTML';
4295
+ message = 'Could not find selector %s in current body HTML';
4111
4296
  if (message[0] === '#') {
4112
4297
  message += ' (avoid using IDs)';
4113
4298
  }
@@ -4127,28 +4312,21 @@ are based on this module.
4127
4312
  if (child = $.find(selector, htmlElement)[0]) {
4128
4313
  return $(child);
4129
4314
  } else if (options.requireMatch) {
4130
- return u.error("Could not find selector %o in response %o", selector, html);
4315
+ return u.error("Could not find selector %s in response %o", selector, html);
4131
4316
  }
4132
4317
  }
4133
4318
  };
4134
4319
  };
4135
- elementsInserted = function($new, options) {
4320
+ updateHistory = function(options) {
4136
4321
  if (options.history) {
4137
4322
  if (options.title) {
4138
4323
  document.title = options.title;
4139
4324
  }
4140
- up.history[options.historyMethod](options.history);
4325
+ return up.history[options.historyMethod](options.history);
4141
4326
  }
4142
- if (options.source !== false) {
4143
- setSource($new, options.source);
4144
- }
4145
- autofocus($new);
4146
- return up.hello($new, {
4147
- origin: options.origin
4148
- });
4149
4327
  };
4150
4328
  swapElements = function($old, $new, pseudoClass, transition, options) {
4151
- var $wrapper, insertionMethod, promise, replacement;
4329
+ var $wrapper, keepPlan, promise, replacement;
4152
4330
  transition || (transition = 'none');
4153
4331
  if (options.source === 'keep') {
4154
4332
  options = u.merge(options, {
@@ -4157,11 +4335,13 @@ are based on this module.
4157
4335
  }
4158
4336
  up.motion.finish($old);
4159
4337
  if (pseudoClass) {
4160
- insertionMethod = pseudoClass === 'before' ? 'prepend' : 'append';
4161
4338
  $wrapper = $new.contents().wrap('<span class="up-insertion"></span>').parent();
4162
- $old[insertionMethod]($wrapper);
4163
- u.copyAttributes($new, $old);
4164
- elementsInserted($wrapper.children(), options);
4339
+ if (pseudoClass === 'before') {
4340
+ $old.prepend($wrapper);
4341
+ } else {
4342
+ $old.append($wrapper);
4343
+ }
4344
+ hello($wrapper.children(), options);
4165
4345
  promise = up.layout.revealOrRestoreScroll($wrapper, options);
4166
4346
  promise = promise.then(function() {
4167
4347
  return up.animate($wrapper, transition, options);
@@ -4169,34 +4349,179 @@ are based on this module.
4169
4349
  promise = promise.then(function() {
4170
4350
  return u.unwrapElement($wrapper);
4171
4351
  });
4172
- return promise;
4352
+ } else if (keepPlan = findKeepPlan($old, $new, options)) {
4353
+ emitFragmentKept(keepPlan);
4354
+ promise = u.resolvedPromise();
4173
4355
  } else {
4174
4356
  replacement = function() {
4357
+ options.keepPlans = transferKeepableElements($old, $new, options);
4175
4358
  $new.insertBefore($old);
4176
- elementsInserted($new, options);
4177
- if ($old.is('body') && transition !== 'none') {
4178
- u.error('Cannot apply transitions to body-elements (%o)', transition);
4359
+ if (options.source !== false) {
4360
+ setSource($new, options.source);
4179
4361
  }
4362
+ autofocus($new);
4363
+ hello($new, options);
4180
4364
  return up.morph($old, $new, transition, options);
4181
4365
  };
4182
- return destroy($old, {
4366
+ promise = destroy($old, {
4183
4367
  animation: replacement
4184
4368
  });
4185
4369
  }
4370
+ return promise;
4371
+ };
4372
+ transferKeepableElements = function($old, $new, options) {
4373
+ var $keepable, $keepableClone, j, keepPlans, keepable, len, plan, ref;
4374
+ keepPlans = [];
4375
+ if (options.keep) {
4376
+ ref = $old.find('[up-keep]');
4377
+ for (j = 0, len = ref.length; j < len; j++) {
4378
+ keepable = ref[j];
4379
+ $keepable = $(keepable);
4380
+ if (plan = findKeepPlan($keepable, $new, u.merge(options, {
4381
+ descendantsOnly: true
4382
+ }))) {
4383
+ $keepableClone = $keepable.clone();
4384
+ $keepable.replaceWith($keepableClone);
4385
+ plan.$newElement.replaceWith($keepable);
4386
+ keepPlans.push(plan);
4387
+ }
4388
+ }
4389
+ }
4390
+ return keepPlans;
4391
+ };
4392
+ findKeepPlan = function($element, $new, options) {
4393
+ var $keepable, $partner, description, keepEventArgs, partnerSelector;
4394
+ if (options.keep) {
4395
+ $keepable = $element;
4396
+ if (partnerSelector = u.castedAttr($keepable, 'up-keep')) {
4397
+ u.isString(partnerSelector) || (partnerSelector = '&');
4398
+ partnerSelector = resolveSelector(partnerSelector, $keepable);
4399
+ if (options.descendantsOnly) {
4400
+ $partner = $new.find(partnerSelector);
4401
+ } else {
4402
+ $partner = u.findWithSelf($new, partnerSelector);
4403
+ }
4404
+ $partner = $partner.first();
4405
+ if ($partner.length && $partner.is('[up-keep]')) {
4406
+ description = {
4407
+ $element: $keepable,
4408
+ $newElement: $partner,
4409
+ newData: up.syntax.data($partner)
4410
+ };
4411
+ keepEventArgs = u.merge(description, {
4412
+ message: ['Keeping element %o', $keepable.get(0)]
4413
+ });
4414
+ if (up.bus.nobodyPrevents('up:fragment:keep', keepEventArgs)) {
4415
+ return description;
4416
+ }
4417
+ }
4418
+ }
4419
+ }
4186
4420
  };
4421
+
4422
+ /**
4423
+ Elements with an `up-keep` attribute will be persisted during
4424
+ [fragment updates](/a-up-target).
4425
+
4426
+ For example:
4427
+
4428
+ <audio up-keep src="song.mp3"></audio>
4429
+
4430
+ The element you're keeping should have an umambiguous class name, ID or `up-id`
4431
+ attribute so Up.js can find its new position within the page update.
4432
+
4433
+ Emits events [`up:fragment:keep`](/up:fragment:keep) and [`up:fragment:kept`](/up:fragment:kept).
4434
+
4435
+ \#\#\#\# Controlling if an element will be kept
4436
+
4437
+ Up.js will **only** keep an existing element if:
4438
+
4439
+ - The existing element has an `up-keep` attribute
4440
+ - The response contains an element matching the CSS selector of the existing element
4441
+ - The matching element *also* has an `up-keep` attribute
4442
+ - The [`up:fragment:keep`](/up:fragment:keep) event that is [emitted](/up.emit) on the existing element
4443
+ is not prevented by a event listener.
4444
+
4445
+ Let's say we want only keep an `<audio>` element as long as it plays
4446
+ the same song (as identified by the tag's `src` attribute).
4447
+
4448
+ On the client we can achieve this by listening to an `up:keep:fragment` event
4449
+ and preventing it if the `src` attribute of the old and new element differ:
4450
+
4451
+ up.compiler('audio', function($element) {
4452
+ $element.on('up:fragment:keep', function(event) {
4453
+ if $element.attr('src') !== event.$newElement.attr('src') {
4454
+ event.preventDefault();
4455
+ }
4456
+ });
4457
+ });
4458
+
4459
+ If we don't want to solve this on the client, we can achieve the same effect
4460
+ on the server. By setting the value of the `up-keep` attribute we can
4461
+ define the CSS selector used for matching elements.
4462
+
4463
+ <audio up-keep="audio[src='song.mp3']" src="song.mp3"></audio>
4464
+
4465
+ Now, if a response no longer contains an `<audio src="song.mp3">` tag, the existing
4466
+ element will be destroyed and replaced by a fragment from the response.
4467
+
4468
+ @selector [up-keep]
4469
+ @stable
4470
+ */
4471
+
4472
+ /**
4473
+ This event is [emitted](/up.emit) before an existing element is [kept](/up-keep) during
4474
+ a page update.
4475
+
4476
+ Event listeners can call `event.preventDefault()` on an `up:fragment:keep` event
4477
+ to prevent the element from being persisted. If the event is prevented, the element
4478
+ will be replaced by a fragment from the response.
4479
+
4480
+ @event up:fragment:keep
4481
+ @param event.preventDefault()
4482
+ Event listeners may call this method to prevent the element from being preserved.
4483
+ @param {jQuery} event.$element
4484
+ The fragment that will be kept.
4485
+ @param {jqQuery} event.$newElement
4486
+ The discarded element.
4487
+ @param {jQuery} event.newData
4488
+ The value of the [`up-data`](/up-data) attribute of the discarded element,
4489
+ parsed as a JSON object.
4490
+ @stable
4491
+ */
4492
+
4493
+ /**
4494
+ This event is [emitted](/up.emit) when an existing element has been [kept](/up-keep)
4495
+ during a page update.
4496
+
4497
+ Event listeners can inspect the discarded update through `event.$newElement`
4498
+ and `event.newData` and then modify the preserved element when necessary.
4499
+
4500
+ @event up:fragment:kept
4501
+ @param {jQuery} event.$element
4502
+ The fragment that has been kept.
4503
+ @param {jqQuery} event.$newElement
4504
+ The discarded element.
4505
+ @param {jQuery} event.newData
4506
+ The value of the [`up-data`](/up-data) attribute of the discarded element,
4507
+ parsed as a JSON object.
4508
+ @stable
4509
+ */
4187
4510
  parseImplantSteps = function(selector, options) {
4188
- var comma, disjunction, i, j, len, pseudoClass, results, selectorAtom, selectorParts, transition, transitionString, transitions;
4189
- transitionString = options.transition || options.animation || 'none';
4511
+ var comma, disjunction, i, j, len, pseudoClass, results, selectorAtom, selectorParts, transition, transitionArg, transitions;
4512
+ transitionArg = options.transition || options.animation || 'none';
4190
4513
  comma = /\ *,\ */;
4191
4514
  disjunction = selector.split(comma);
4192
- if (u.isPresent(transitionString)) {
4193
- transitions = transitionString.split(comma);
4515
+ if (u.isString(transitions)) {
4516
+ transitions = transitionArg.split(comma);
4517
+ } else {
4518
+ transitions = [transitionArg];
4194
4519
  }
4195
4520
  results = [];
4196
4521
  for (i = j = 0, len = disjunction.length; j < len; i = ++j) {
4197
4522
  selectorAtom = disjunction[i];
4198
4523
  selectorParts = selectorAtom.match(/^(.+?)(?:\:(before|after))?$/);
4199
- selectorParts || u.error('Could not parse selector atom %o', selectorAtom);
4524
+ selectorParts || u.error('Could not parse selector atom "%s"', selectorAtom);
4200
4525
  selector = selectorParts[1];
4201
4526
  if (selector === 'html') {
4202
4527
  selector = 'body';
@@ -4211,6 +4536,83 @@ are based on this module.
4211
4536
  }
4212
4537
  return results;
4213
4538
  };
4539
+
4540
+ /**
4541
+ Compiles a page fragment that has been inserted into the DOM
4542
+ without Up.js.
4543
+
4544
+ **As long as you manipulate the DOM using Up.js, you will never
4545
+ need to call this method.** You only need to use `up.hello` if the
4546
+ DOM is manipulated without Up.js' involvement, e.g. by setting
4547
+ the `innerHTML` property or calling jQuery methods like
4548
+ `html`, `insertAfter` or `appendTo`:
4549
+
4550
+ $element = $('.element');
4551
+ $element.html('<div>...</div>');
4552
+ up.hello($element);
4553
+
4554
+ This function emits the [`up:fragment:inserted`](/up:fragment:inserted)
4555
+ event.
4556
+
4557
+ @function up.hello
4558
+ @param {String|Element|jQuery} selectorOrElement
4559
+ @param {String|Element|jQuery} [options.origin]
4560
+ @param {String|Element|jQuery} [options.kept]
4561
+ @return {jQuery}
4562
+ The compiled element
4563
+ @stable
4564
+ */
4565
+ hello = function(selectorOrElement, options) {
4566
+ var $element, j, keptElements, len, plan, ref;
4567
+ $element = $(selectorOrElement);
4568
+ options = u.options(options, {
4569
+ keepPlans: []
4570
+ });
4571
+ keptElements = [];
4572
+ ref = options.keepPlans;
4573
+ for (j = 0, len = ref.length; j < len; j++) {
4574
+ plan = ref[j];
4575
+ emitFragmentKept(plan);
4576
+ keptElements.push(plan.$element);
4577
+ }
4578
+ up.syntax.compile($element, {
4579
+ skip: keptElements
4580
+ });
4581
+ emitFragmentInserted($element, options);
4582
+ return $element;
4583
+ };
4584
+
4585
+ /**
4586
+ When a page fragment has been [inserted or updated](/up.replace),
4587
+ this event is [emitted](/up.emit) on the fragment.
4588
+
4589
+ \#\#\#\# Example
4590
+
4591
+ up.on('up:fragment:inserted', function(event, $fragment) {
4592
+ console.log("Looks like we have a new %o!", $fragment);
4593
+ });
4594
+
4595
+ @event up:fragment:inserted
4596
+ @param {jQuery} event.$element
4597
+ The fragment that has been inserted or updated.
4598
+ @stable
4599
+ */
4600
+ emitFragmentInserted = function(fragment, options) {
4601
+ var $fragment;
4602
+ $fragment = $(fragment);
4603
+ return up.emit('up:fragment:inserted', {
4604
+ $element: $fragment,
4605
+ message: ['Inserted fragment %o', $fragment.get(0)],
4606
+ origin: options.origin
4607
+ });
4608
+ };
4609
+ emitFragmentKept = function(keepPlan) {
4610
+ var eventAttrs;
4611
+ eventAttrs = u.merge(keepPlan, {
4612
+ message: ['Kept fragment %o', keepPlan.$element.get(0)]
4613
+ });
4614
+ return up.emit('up:fragment:kept', eventAttrs);
4615
+ };
4214
4616
  autofocus = function($element) {
4215
4617
  var $control, selector;
4216
4618
  selector = '[autofocus]:last';
@@ -4290,10 +4692,15 @@ are based on this module.
4290
4692
  @stable
4291
4693
  */
4292
4694
  destroy = function(selectorOrElement, options) {
4293
- var $element, animateOptions, animationDeferred;
4695
+ var $element, animateOptions, animationDeferred, destroyMessage, destroyedMessage;
4294
4696
  $element = $(selectorOrElement);
4697
+ if (!$element.is('.up-placeholder, .up-tooltip, .up-modal, .up-popup')) {
4698
+ destroyMessage = ['Destroying fragment %o', $element.get(0)];
4699
+ destroyedMessage = ['Destroyed fragment %o', $element.get(0)];
4700
+ }
4295
4701
  if (up.bus.nobodyPrevents('up:fragment:destroy', {
4296
- $element: $element
4702
+ $element: $element,
4703
+ message: destroyMessage
4297
4704
  })) {
4298
4705
  options = u.options(options, {
4299
4706
  animation: false
@@ -4308,8 +4715,10 @@ are based on this module.
4308
4715
  }
4309
4716
  animationDeferred = u.presence(options.animation, u.isDeferred) || up.motion.animate($element, options.animation, animateOptions);
4310
4717
  animationDeferred.then(function() {
4718
+ up.syntax.clean($element);
4311
4719
  up.emit('up:fragment:destroyed', {
4312
- $element: $element
4720
+ $element: $element,
4721
+ message: destroyedMessage
4313
4722
  });
4314
4723
  return $element.remove();
4315
4724
  });
@@ -4377,23 +4786,27 @@ are based on this module.
4377
4786
  return replace(selectorOrElement, sourceUrl, options);
4378
4787
  };
4379
4788
  up.on('ready', function() {
4380
- return setSource(document.body, up.browser.url());
4789
+ var $body;
4790
+ $body = $(document.body);
4791
+ setSource($body, up.browser.url());
4792
+ return hello($body);
4381
4793
  });
4382
4794
  return {
4383
4795
  knife: eval(typeof Knife !== "undefined" && Knife !== null ? Knife.point : void 0),
4384
4796
  replace: replace,
4385
4797
  reload: reload,
4386
4798
  destroy: destroy,
4387
- implant: implant,
4799
+ extract: extract,
4388
4800
  first: first,
4389
4801
  source: source,
4390
- resolveSelector: resolveSelector
4802
+ resolveSelector: resolveSelector,
4803
+ hello: hello
4391
4804
  };
4392
4805
  })(jQuery);
4393
4806
 
4394
4807
  up.replace = up.flow.replace;
4395
4808
 
4396
- up.implant = up.flow.implant;
4809
+ up.extract = up.flow.extract;
4397
4810
 
4398
4811
  up.reload = up.flow.reload;
4399
4812
 
@@ -4401,6 +4814,8 @@ are based on this module.
4401
4814
 
4402
4815
  up.first = up.flow.first;
4403
4816
 
4817
+ up.hello = up.flow.hello;
4818
+
4404
4819
  }).call(this);
4405
4820
 
4406
4821
  /**
@@ -4436,7 +4851,7 @@ or [transitions](/up.transition) using Javascript or CSS.
4436
4851
 
4437
4852
  (function() {
4438
4853
  up.motion = (function($) {
4439
- var GHOSTING_PROMISE_KEY, animate, animateOptions, animation, animations, assertIsDeferred, config, defaultAnimations, defaultTransitions, findAnimation, finish, finishGhosting, isEnabled, morph, none, prependCopy, reset, resolvableWhen, skipMorph, snapshot, transition, transitions, u, withGhosts;
4854
+ var GHOSTING_PROMISE_KEY, animate, animateOptions, animation, animations, assertIsDeferred, config, defaultAnimations, defaultTransitions, ensureMorphable, findAnimation, finish, finishGhosting, isEnabled, morph, none, prependCopy, reset, resolvableWhen, skipMorph, snapshot, transition, transitions, u, withGhosts;
4440
4855
  u = up.util;
4441
4856
  animations = {};
4442
4857
  defaultAnimations = {};
@@ -4668,7 +5083,7 @@ or [transitions](/up.transition) using Javascript or CSS.
4668
5083
  finishGhosting = function($element) {
4669
5084
  var existingGhosting;
4670
5085
  if (existingGhosting = $element.data(GHOSTING_PROMISE_KEY)) {
4671
- u.debug('Canceling existing ghosting on %o', $element);
5086
+ up.puts('Canceling existing ghosting on %o', $element);
4672
5087
  return typeof existingGhosting.resolve === "function" ? existingGhosting.resolve() : void 0;
4673
5088
  }
4674
5089
  };
@@ -4744,37 +5159,51 @@ or [transitions](/up.transition) using Javascript or CSS.
4744
5159
  @stable
4745
5160
  */
4746
5161
  morph = function(source, target, transitionOrName, options) {
4747
- var $new, $old, animation, parsedOptions, parts, transition;
4748
- u.debug('Morphing %o to %o (using %o)', source, target, transitionOrName);
5162
+ var $new, $old;
5163
+ if (transitionOrName === 'none') {
5164
+ transitionOrName = false;
5165
+ }
4749
5166
  $old = $(source);
4750
5167
  $new = $(target);
4751
- parsedOptions = u.only(options, 'reveal', 'restoreScroll', 'source');
4752
- parsedOptions = u.extend(parsedOptions, animateOptions(options));
4753
- if (isEnabled()) {
4754
- finish($old);
4755
- finish($new);
4756
- if (transitionOrName === 'none' || transitionOrName === false) {
4757
- return skipMorph($old, $new, parsedOptions);
4758
- } else if (animation = animations[transitionOrName]) {
4759
- skipMorph($old, $new, parsedOptions);
4760
- return animate($new, animation, parsedOptions);
4761
- } else if (transition = u.presence(transitionOrName, u.isFunction) || transitions[transitionOrName]) {
4762
- return withGhosts($old, $new, parsedOptions, function($oldGhost, $newGhost) {
4763
- var transitionPromise;
4764
- transitionPromise = transition($oldGhost, $newGhost, parsedOptions);
4765
- return assertIsDeferred(transitionPromise, transitionOrName);
4766
- });
4767
- } else if (u.isString(transitionOrName) && transitionOrName.indexOf('/') >= 0) {
4768
- parts = transitionOrName.split('/');
4769
- transition = function($old, $new, options) {
4770
- return resolvableWhen(animate($old, parts[0], options), animate($new, parts[1], options));
4771
- };
4772
- return morph($old, $new, transition, parsedOptions);
5168
+ ensureMorphable($old, transitionOrName);
5169
+ ensureMorphable($new, transitionOrName);
5170
+ return up.log.group((transitionOrName ? 'Morphing %o to %o (using %o)' : void 0), source, target, transitionOrName, function() {
5171
+ var animation, parsedOptions, parts, transition;
5172
+ parsedOptions = u.only(options, 'reveal', 'restoreScroll', 'source');
5173
+ parsedOptions = u.extend(parsedOptions, animateOptions(options));
5174
+ if (isEnabled()) {
5175
+ finish($old);
5176
+ finish($new);
5177
+ if (!transitionOrName) {
5178
+ return skipMorph($old, $new, parsedOptions);
5179
+ } else if (animation = animations[transitionOrName]) {
5180
+ skipMorph($old, $new, parsedOptions);
5181
+ return animate($new, animation, parsedOptions);
5182
+ } else if (transition = u.presence(transitionOrName, u.isFunction) || transitions[transitionOrName]) {
5183
+ return withGhosts($old, $new, parsedOptions, function($oldGhost, $newGhost) {
5184
+ var transitionPromise;
5185
+ transitionPromise = transition($oldGhost, $newGhost, parsedOptions);
5186
+ return assertIsDeferred(transitionPromise, transitionOrName);
5187
+ });
5188
+ } else if (u.isString(transitionOrName) && transitionOrName.indexOf('/') >= 0) {
5189
+ parts = transitionOrName.split('/');
5190
+ transition = function($old, $new, options) {
5191
+ return resolvableWhen(animate($old, parts[0], options), animate($new, parts[1], options));
5192
+ };
5193
+ return morph($old, $new, transition, parsedOptions);
5194
+ } else {
5195
+ return u.error("Unknown transition %o", transitionOrName);
5196
+ }
4773
5197
  } else {
4774
- return u.error("Unknown transition %o", transitionOrName);
5198
+ return skipMorph($old, $new, parsedOptions);
4775
5199
  }
4776
- } else {
4777
- return skipMorph($old, $new, parsedOptions);
5200
+ });
5201
+ };
5202
+ ensureMorphable = function($element, transition) {
5203
+ var element;
5204
+ if (transition && $element.parents('body').length === 0) {
5205
+ element = $element.get(0);
5206
+ return u.error("Can't morph a <%s> element (%o)", element.tagName, element);
4778
5207
  }
4779
5208
  };
4780
5209
 
@@ -5161,7 +5590,7 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5161
5590
  var slice = [].slice;
5162
5591
 
5163
5592
  up.proxy = (function($) {
5164
- var $waitingLink, ajax, alias, busy, busyDelayTimer, busyEventEmitted, cache, cacheKey, cancelBusyDelay, cancelPreloadDelay, checkPreload, clear, config, get, idle, isIdempotent, load, loadEnded, loadOrQueue, loadStarted, normalizeRequest, pendingCount, pokeQueue, preload, preloadDelayTimer, queue, queuedRequests, remove, reset, set, startPreloadDelay, u;
5593
+ var $waitingLink, ajax, alias, busy, busyDelayTimer, busyEventEmitted, cache, cacheKey, cancelBusyDelay, cancelPreloadDelay, checkPreload, clear, config, get, idle, isIdempotent, load, loadEnded, loadOrQueue, loadStarted, normalizeRequest, pendingCount, pokeQueue, preload, preloadDelayTimer, queue, queuedRequests, remove, reset, responseReceived, set, startPreloadDelay, u;
5165
5594
  u = up.util;
5166
5595
  $waitingLink = void 0;
5167
5596
  preloadDelayTimer = void 0;
@@ -5226,8 +5655,7 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5226
5655
  expiry: function() {
5227
5656
  return config.cacheExpiry;
5228
5657
  },
5229
- key: cacheKey,
5230
- log: 'up.proxy'
5658
+ key: cacheKey
5231
5659
  });
5232
5660
 
5233
5661
  /**
@@ -5349,7 +5777,7 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5349
5777
  Once the response is received, a `up:proxy:receive` event will
5350
5778
  be emitted.
5351
5779
 
5352
- @function up.proxy.ajax
5780
+ @function up.ajax
5353
5781
  @param {String} request.url
5354
5782
  @param {String} [request.method='GET']
5355
5783
  @param {String} [request.target='body']
@@ -5371,11 +5799,13 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5371
5799
  forceCache = options.cache === true;
5372
5800
  ignoreCache = options.cache === false;
5373
5801
  request = u.only(options, 'url', 'method', 'data', 'target', 'headers', '_normalized');
5802
+ request = normalizeRequest(request);
5374
5803
  pending = true;
5375
5804
  if (!isIdempotent(request) && !forceCache) {
5376
5805
  clear();
5377
5806
  promise = loadOrQueue(request);
5378
5807
  } else if ((promise = get(request)) && !ignoreCache) {
5808
+ up.puts('Re-using cached response for %s %s', request.method, request.url);
5379
5809
  pending = promise.state() === 'pending';
5380
5810
  } else {
5381
5811
  promise = loadOrQueue(request);
@@ -5388,6 +5818,7 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5388
5818
  loadStarted();
5389
5819
  promise.always(loadEnded);
5390
5820
  }
5821
+ console.groupEnd();
5391
5822
  return promise;
5392
5823
  };
5393
5824
 
@@ -5429,7 +5860,9 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5429
5860
  if (wasIdle) {
5430
5861
  emission = function() {
5431
5862
  if (busy()) {
5432
- up.emit('up:proxy:busy');
5863
+ up.emit('up:proxy:busy', {
5864
+ message: 'Proxy is busy'
5865
+ });
5433
5866
  return busyEventEmitted = true;
5434
5867
  }
5435
5868
  };
@@ -5442,7 +5875,7 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5442
5875
  };
5443
5876
 
5444
5877
  /**
5445
- This event is [emitted]/(up.emit) when [AJAX requests](/up.proxy.ajax)
5878
+ This event is [emitted]/(up.emit) when [AJAX requests](/up.ajax)
5446
5879
  are taking long to finish.
5447
5880
 
5448
5881
  By default Up.js will wait 300 ms for an AJAX request to finish
@@ -5462,13 +5895,15 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5462
5895
  loadEnded = function() {
5463
5896
  pendingCount -= 1;
5464
5897
  if (idle() && busyEventEmitted) {
5465
- up.emit('up:proxy:idle');
5898
+ up.emit('up:proxy:idle', {
5899
+ message: 'Proxy is idle'
5900
+ });
5466
5901
  return busyEventEmitted = false;
5467
5902
  }
5468
5903
  };
5469
5904
 
5470
5905
  /**
5471
- This event is [emitted]/(up.emit) when [AJAX requests](/up.proxy.ajax)
5906
+ This event is [emitted]/(up.emit) when [AJAX requests](/up.ajax)
5472
5907
  have [taken long to finish](/up:proxy:busy), but have finished now.
5473
5908
 
5474
5909
  @event up:proxy:idle
@@ -5483,7 +5918,7 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5483
5918
  };
5484
5919
  queue = function(request) {
5485
5920
  var deferred, entry;
5486
- u.debug('Queuing URL %o', request.url);
5921
+ up.puts('Queuing request for %s %s', request.method, request.url);
5487
5922
  deferred = $.Deferred();
5488
5923
  entry = {
5489
5924
  deferred: deferred,
@@ -5494,8 +5929,9 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5494
5929
  };
5495
5930
  load = function(request) {
5496
5931
  var promise;
5497
- u.debug('Fetching %o via %o', request.url, request.method);
5498
- up.emit('up:proxy:load', request);
5932
+ up.emit('up:proxy:load', u.merge(request, {
5933
+ message: ['Loading %s %s', request.method, request.url]
5934
+ }));
5499
5935
  request = u.copy(request);
5500
5936
  request.headers || (request.headers = {});
5501
5937
  request.headers['X-Up-Target'] = request.target;
@@ -5508,12 +5944,21 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5508
5944
  request.method = 'POST';
5509
5945
  }
5510
5946
  promise = $.ajax(request);
5511
- promise.always(function() {
5512
- up.emit('up:proxy:received', request);
5513
- return pokeQueue();
5947
+ promise.done(function(data, textStatus, xhr) {
5948
+ return responseReceived(request, xhr);
5949
+ });
5950
+ promise.fail(function(xhr, textStatus, errorThrown) {
5951
+ return responseReceived(request, xhr);
5514
5952
  });
5515
5953
  return promise;
5516
5954
  };
5955
+ responseReceived = function(request, xhr) {
5956
+ var ref;
5957
+ up.emit('up:proxy:received', u.merge(request, {
5958
+ message: ['Server responded with %s %s (%d bytes)', xhr.status, xhr.statusText, (ref = xhr.responseText) != null ? ref.length : void 0]
5959
+ }));
5960
+ return pokeQueue();
5961
+ };
5517
5962
  pokeQueue = function() {
5518
5963
  var entry, promise;
5519
5964
  if (entry = queuedRequests.shift()) {
@@ -5532,7 +5977,7 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5532
5977
  };
5533
5978
 
5534
5979
  /**
5535
- This event is [emitted]/(up.emit) before an [AJAX request](/up.proxy.ajax)
5980
+ This event is [emitted]/(up.emit) before an [AJAX request](/up.ajax)
5536
5981
  is starting to load.
5537
5982
 
5538
5983
  @event up:proxy:load
@@ -5543,7 +5988,7 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5543
5988
  */
5544
5989
 
5545
5990
  /**
5546
- This event is [emitted]/(up.emit) when the response to an [AJAX request](/up.proxy.ajax)
5991
+ This event is [emitted]/(up.emit) when the response to an [AJAX request](/up.ajax)
5547
5992
  has been received.
5548
5993
 
5549
5994
  @event up:proxy:received
@@ -5589,11 +6034,12 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5589
6034
  if (isIdempotent({
5590
6035
  method: method
5591
6036
  })) {
5592
- u.debug("Preloading %o", $link);
5593
- options.preload = true;
5594
- return up.follow($link, options);
6037
+ return up.log.group("Preloading link %o", $link, function() {
6038
+ options.preload = true;
6039
+ return up.follow($link, options);
6040
+ });
5595
6041
  } else {
5596
- u.debug("Won't preload %o due to unsafe method %o", $link, method);
6042
+ up.puts("Won't preload %o due to unsafe method %s", $link, method);
5597
6043
  return u.resolvedPromise();
5598
6044
  }
5599
6045
  };
@@ -5634,6 +6080,8 @@ You can change (or remove) this delay by [configuring `up.proxy`](/up.proxy.conf
5634
6080
  };
5635
6081
  })(jQuery);
5636
6082
 
6083
+ up.ajax = up.proxy.ajax;
6084
+
5637
6085
  }).call(this);
5638
6086
 
5639
6087
  /**
@@ -6384,7 +6832,7 @@ open dialogs with sub-forms, etc. all without losing form state.
6384
6832
  delay = parseInt(delay);
6385
6833
  callback = null;
6386
6834
  if (u.isGiven(options.change)) {
6387
- up.error('up.observe now takes the change callback as the last argument');
6835
+ u.error('up.observe now takes the change callback as the last argument');
6388
6836
  }
6389
6837
  rawCallback = u.option(u.presentAttr($element, 'op-observe'), callbackArg);
6390
6838
  if (u.isString(rawCallback)) {
@@ -6510,7 +6958,7 @@ open dialogs with sub-forms, etc. all without losing form state.
6510
6958
  }));
6511
6959
  }
6512
6960
  if (u.isBlank(target)) {
6513
- error('Could not find default validation target for %o (tried ancestors %o)', $field, config.validateTargets);
6961
+ u.error('Could not find default validation target for %o (tried ancestors %o)', $field.get(0), config.validateTargets);
6514
6962
  }
6515
6963
  if (!u.isString(target)) {
6516
6964
  target = u.selectorForElement(target);
@@ -6567,17 +7015,13 @@ open dialogs with sub-forms, etc. all without losing form state.
6567
7015
  values = [':unchecked', ':blank'];
6568
7016
  }
6569
7017
  } else if ($field.is('input[type=radio]')) {
6570
- console.log('-- it is a radio button --');
6571
7018
  $checkedButton = $field.closest('form, body').find("input[type='radio'][name='" + ($field.attr('name')) + "']:checked");
6572
- console.log('checked button is %o', $checkedButton);
6573
- console.log('checked button val is %o', $checkedButton.val());
6574
7019
  if ($checkedButton.length) {
6575
7020
  values = [':checked', ':present', $checkedButton.val()];
6576
7021
  } else {
6577
7022
  values = [':unchecked', ':blank'];
6578
7023
  }
6579
7024
  } else {
6580
- console.log('-- else -- for %o', $field);
6581
7025
  value = $field.val();
6582
7026
  if (u.isPresent(value)) {
6583
7027
  values = [':present', value];
@@ -6641,7 +7085,7 @@ open dialogs with sub-forms, etc. all without losing form state.
6641
7085
  $field = $(fieldOrSelector);
6642
7086
  options = u.options(options);
6643
7087
  targets = u.option(options.target, $field.attr('up-toggle'));
6644
- u.isPresent(targets) || u.error("No toggle target given for %o", $field);
7088
+ u.isPresent(targets) || u.error("No toggle target given for %o", $field.get(0));
6645
7089
  fieldValues = currentValuesForToggle($field);
6646
7090
  return $(targets).each(function() {
6647
7091
  var $target, hideValues, show, showValues;
@@ -6976,7 +7420,7 @@ open dialogs with sub-forms, etc. all without losing form state.
6976
7420
 
6977
7421
  @selector [up-hide-for]
6978
7422
  @param up-hide-for
6979
- A space-separated list of values for which to show this element.
7423
+ A space-separated list of values for which to hide this element.
6980
7424
  @stable
6981
7425
  */
6982
7426
  up.on('change', '[up-toggle]', function(event, $field) {
@@ -7198,7 +7642,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7198
7642
  bottom: linkBox.top
7199
7643
  };
7200
7644
  default:
7201
- return u.error("Unknown position %o", position);
7645
+ return u.error("Unknown position option '%s'", position);
7202
7646
  }
7203
7647
  })();
7204
7648
  $popup = $('.up-popup');
@@ -7247,15 +7691,14 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7247
7691
  return $popup.removeAttr('up-covered-title');
7248
7692
  };
7249
7693
  createFrame = function(target, options) {
7250
- var $placeholder, $popup;
7694
+ var $popup;
7251
7695
  $popup = u.$createElementFromSelector('.up-popup');
7252
7696
  if (options.sticky) {
7253
7697
  $popup.attr('up-sticky', '');
7254
7698
  }
7255
7699
  $popup.attr('up-covered-url', up.browser.url());
7256
7700
  $popup.attr('up-covered-title', document.title);
7257
- $placeholder = u.$createElementFromSelector(target);
7258
- $placeholder.appendTo($popup);
7701
+ u.$createPlaceholder(target, $popup);
7259
7702
  $popup.appendTo(document.body);
7260
7703
  return $popup;
7261
7704
  };
@@ -7318,7 +7761,8 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7318
7761
  return up.browser.confirm(options.confirm).then(function() {
7319
7762
  var promise, wasOpen;
7320
7763
  if (up.bus.nobodyPrevents('up:popup:open', {
7321
- url: url
7764
+ url: url,
7765
+ message: 'Opening popup'
7322
7766
  })) {
7323
7767
  wasOpen = isOpen();
7324
7768
  if (wasOpen) {
@@ -7341,7 +7785,9 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7341
7785
  });
7342
7786
  }
7343
7787
  promise = promise.then(function() {
7344
- return up.emit('up:popup:opened');
7788
+ return up.emit('up:popup:opened', {
7789
+ message: 'Popup opened'
7790
+ });
7345
7791
  });
7346
7792
  return promise;
7347
7793
  } else {
@@ -7396,7 +7842,9 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7396
7842
  currentUrl = void 0;
7397
7843
  deferred = up.destroy($popup, options);
7398
7844
  deferred.then(function() {
7399
- return up.emit('up:popup:closed');
7845
+ return up.emit('up:popup:closed', {
7846
+ message: 'Popup closed'
7847
+ });
7400
7848
  });
7401
7849
  return deferred;
7402
7850
  } else {
@@ -7703,7 +8151,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7703
8151
  return $modal.removeAttr('up-covered-title');
7704
8152
  };
7705
8153
  createFrame = function(target, options) {
7706
- var $content, $dialog, $modal, $placeholder;
8154
+ var $content, $dialog, $modal;
7707
8155
  shiftElements();
7708
8156
  $modal = $(templateHtml());
7709
8157
  if (options.sticky) {
@@ -7722,8 +8170,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7722
8170
  $dialog.css('height', options.height);
7723
8171
  }
7724
8172
  $content = $modal.find('.up-modal-content');
7725
- $placeholder = u.$createElementFromSelector(target);
7726
- $placeholder.appendTo($content);
8173
+ u.$createPlaceholder(target, $content);
7727
8174
  $modal.appendTo(document.body);
7728
8175
  return $modal;
7729
8176
  };
@@ -7868,7 +8315,8 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7868
8315
  return up.browser.confirm(options.confirm).then(function() {
7869
8316
  var promise, wasOpen;
7870
8317
  if (up.bus.nobodyPrevents('up:modal:open', {
7871
- url: url
8318
+ url: url,
8319
+ message: 'Opening modal'
7872
8320
  })) {
7873
8321
  wasOpen = isOpen();
7874
8322
  if (wasOpen) {
@@ -7888,7 +8336,9 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7888
8336
  });
7889
8337
  }
7890
8338
  promise = promise.then(function() {
7891
- return up.emit('up:modal:opened');
8339
+ return up.emit('up:modal:opened', {
8340
+ message: 'Modal opened'
8341
+ });
7892
8342
  });
7893
8343
  return promise;
7894
8344
  } else {
@@ -7933,7 +8383,8 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7933
8383
  $modal = $('.up-modal');
7934
8384
  if ($modal.length) {
7935
8385
  if (up.bus.nobodyPrevents('up:modal:close', {
7936
- $element: $modal
8386
+ $element: $modal,
8387
+ message: 'Closing modal'
7937
8388
  })) {
7938
8389
  options = u.options(options, {
7939
8390
  animation: config.closeAnimation,
@@ -7944,7 +8395,9 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
7944
8395
  promise = up.destroy($modal, options);
7945
8396
  promise = promise.then(function() {
7946
8397
  unshiftElements();
7947
- return up.emit('up:modal:closed');
8398
+ return up.emit('up:modal:closed', {
8399
+ message: 'Modal closed'
8400
+ });
7948
8401
  });
7949
8402
  return promise;
7950
8403
  } else {
@@ -8170,7 +8623,7 @@ The tooltip element is appended to the end of `<body>`.
8170
8623
  top: linkBox.top + linkBox.height
8171
8624
  };
8172
8625
  default:
8173
- return u.error("Unknown position %o", position);
8626
+ return u.error("Unknown position option '%s'", position);
8174
8627
  }
8175
8628
  })();
8176
8629
  $tooltip.attr('up-position', position);