unpoly-rails 0.27.3 → 0.28.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of unpoly-rails might be problematic. Click here for more details.

Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -1
  3. data/dist/unpoly.css +29 -21
  4. data/dist/unpoly.js +291 -134
  5. data/dist/unpoly.min.css +1 -1
  6. data/dist/unpoly.min.js +3 -3
  7. data/lib/assets/javascripts/unpoly.js.coffee +1 -0
  8. data/lib/assets/javascripts/unpoly/browser.js.coffee +22 -5
  9. data/lib/assets/javascripts/unpoly/bus.js.coffee +1 -1
  10. data/lib/assets/javascripts/unpoly/flow.js.coffee +9 -6
  11. data/lib/assets/javascripts/unpoly/form.js.coffee +46 -49
  12. data/lib/assets/javascripts/unpoly/history.js.coffee +2 -2
  13. data/lib/assets/javascripts/unpoly/layout.js.coffee +3 -3
  14. data/lib/assets/javascripts/unpoly/modal.js.coffee +30 -2
  15. data/lib/assets/javascripts/unpoly/motion.js.coffee +6 -6
  16. data/lib/assets/javascripts/unpoly/navigation.js.coffee +1 -1
  17. data/lib/assets/javascripts/unpoly/popup.js.coffee +2 -2
  18. data/lib/assets/javascripts/unpoly/proxy.js.coffee +5 -9
  19. data/lib/assets/javascripts/unpoly/syntax.js.coffee +10 -6
  20. data/lib/assets/javascripts/unpoly/toast.js.coffee +66 -0
  21. data/lib/assets/javascripts/unpoly/tooltip.js.coffee +1 -1
  22. data/lib/assets/javascripts/unpoly/util.js.coffee +47 -21
  23. data/lib/assets/stylesheets/unpoly/toast.css.sass +33 -0
  24. data/lib/unpoly/rails/version.rb +1 -1
  25. data/spec_app/Gemfile.lock +1 -1
  26. data/spec_app/app/assets/javascripts/integration_test.coffee +1 -0
  27. data/spec_app/app/assets/stylesheets/integration_test.sass +14 -0
  28. data/spec_app/app/controllers/application_controller.rb +8 -0
  29. data/spec_app/app/controllers/error_test_controller.rb +5 -0
  30. data/spec_app/app/views/error_test/trigger.erb +72 -0
  31. data/spec_app/app/views/error_test/unexpected_response.erb +3 -0
  32. data/spec_app/app/views/pages/start.erb +4 -0
  33. data/spec_app/config/routes.rb +2 -0
  34. data/spec_app/spec/javascripts/helpers/last_request.js.coffee +1 -1
  35. data/spec_app/spec/javascripts/up/browser_spec.js.coffee +62 -0
  36. data/spec_app/spec/javascripts/up/form_spec.js.coffee +116 -3
  37. data/spec_app/spec/javascripts/up/link_spec.js.coffee +2 -2
  38. data/spec_app/spec/javascripts/up/modal_spec.js.coffee +88 -4
  39. data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +27 -1
  40. data/spec_app/spec/javascripts/up/util_spec.js.coffee +12 -0
  41. metadata +8 -3
  42. data/lib/assets/stylesheets/unpoly/error.css.sass +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d404629719d453d5e2aca5dc42043b8f2eb2edee
4
- data.tar.gz: ee1e3c7da3506f74134521a0e34004274d0cd9d4
3
+ metadata.gz: 9486ab6b2931b851c74e76e8b3e84d80f3942e34
4
+ data.tar.gz: 6052d81a38db40d33cf31ebb55b21a6a358e3f2b
5
5
  SHA512:
6
- metadata.gz: 03ded9fb08965c29e3965754ff96a1e95d384aa15da31661ee9079bfe837511332d6534aa7b6db258a5b34f8b510a9395bd560ba3cfb15abe3e8b7651e2f6c19
7
- data.tar.gz: 5b5c82abc2089e9ea3a5ee765c8128540cd25c16f73410617b663aaa6438a5406f9669bab61056e357274d31051387306a869dbb5685cc6e2cb04c33ac83d10d
6
+ metadata.gz: ad27fbb580b56ed3c66b8955c5856aa676642b791233305e97e817e37e9da9c0e30994463cbabfe123102a7d8d4b56c613b9d6f8043bba565146a2917302a537
7
+ data.tar.gz: ea8131ad33ce5608f32d51f2db8e194246e77241e91e47179259940c2735c850ded1ed87951bfe411999854c1068351b8fcd17219e9c6fa2bda1fa84329b8178
data/CHANGELOG.md CHANGED
@@ -10,9 +10,30 @@ Unreleased
10
10
 
11
11
  ### Compatible changes
12
12
 
13
+ ### Breaking changes
14
+
15
+
16
+ 0.28.0
17
+ ------
18
+
19
+ ### Compatible changes
20
+
21
+ - The error notification is now easier to read and can be closed.
22
+ - When a target selector was not found in the response, the error notification now offers a link to re-request the response for inspection.
23
+ - [Compilers](/up.compiler) can now return an array of functions that will *all* be called when the element is destroyed.
24
+ - [`up.observe`](/up.observe) now works on checkboxes and radio buttons.
25
+ - [`up.observe`](/up.observe) can now be called with multiple form fields, or any container that contains form fields.
26
+ - When opening a [modal](/up.modal) you can now pass an option `{ closable: false }` or set an `up-closable='false'` attribute
27
+ This lets you disable the default methods to close a modal (close button, clicking on the backdrop, pressing ESC).
28
+ You can also configure this globally by setting [`up.modal.config.closable`](/up.modal.config).
29
+ - Fix a bug where [`up.observe(form, options)`](/up.observe) would not respect options.
30
+ - Fix a bug where [`up.autosubmit(form)`](/up.autosubmit) was not published.
31
+ - Fix a bug where falling back to non-AJAX page loads on old browsers would not work
13
32
 
14
33
  ### Breaking changes
15
34
 
35
+ - `up.error` has been renamed to [`up.fail`](/up.fail) in order to prevent confusion with [`up.log.error`](/up.log.error).
36
+
16
37
 
17
38
  0.27.3
18
39
  ------
@@ -22,7 +43,7 @@ Unreleased
22
43
  - [Popups](/up.popup) and [modals](/up.modal) will no longer try to restore a covered document title
23
44
  and URL if they were opened without pushing a history entry.
24
45
  - When fragments are [replaced](/up.replace) without pushing a new history entry,
25
- the document title will no longer by changed by default.
46
+ the document title will no longer be changed by default.
26
47
 
27
48
 
28
49
  ### Breaking changes
data/dist/unpoly.css CHANGED
@@ -1,26 +1,5 @@
1
1
  [up-close] {
2
2
  cursor: pointer; }
3
- .up-error {
4
- background-color: #c30;
5
- color: white;
6
- padding: 10px;
7
- font-family: arial, helvetica, sans-serif;
8
- font-size: 14px;
9
- line-height: 18px;
10
- position: fixed;
11
- left: 0;
12
- bottom: 0;
13
- max-width: 100%;
14
- box-sizing: border-box;
15
- z-index: 99999999; }
16
-
17
- .up-error-variable {
18
- background-color: rgba(0, 0, 0, 0.3);
19
- padding: 1px 3px;
20
- border-radius: 2px;
21
- font-weight: normal;
22
- max-width: 100px;
23
- overflow: hidden; }
24
3
  .up-insertion {
25
4
  display: inline-block; }
26
5
  [up-href] {
@@ -92,6 +71,35 @@
92
71
  background-color: #fff;
93
72
  padding: 15px;
94
73
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.3); }
74
+ .up-toast {
75
+ border-top: 3px solid #28b;
76
+ background-color: white;
77
+ color: #333;
78
+ padding: 10px;
79
+ font-family: monospace;
80
+ font-size: 14px;
81
+ line-height: 15px;
82
+ position: fixed;
83
+ left: 0;
84
+ bottom: 0;
85
+ right: 0;
86
+ z-index: 99999999; }
87
+
88
+ .up-toast-variable {
89
+ font-weight: normal;
90
+ color: #838383; }
91
+
92
+ .up-toast-actions {
93
+ margin-top: 7px; }
94
+
95
+ .up-toast-action {
96
+ display: inline-block;
97
+ word-spacing: -4px;
98
+ text-decoration: underline;
99
+ color: #28b;
100
+ cursor: pointer; }
101
+ .up-toast-action + .up-toast-action {
102
+ margin-left: 12px; }
95
103
  .up-tooltip {
96
104
  position: absolute;
97
105
  z-index: 30000;
data/dist/unpoly.js CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  (function() {
7
7
  window.up = {
8
- version: "0.27.3"
8
+ version: "0.28.0"
9
9
  };
10
10
 
11
11
  }).call(this);
@@ -32,7 +32,7 @@ that might save you from loading something like [Underscore.js](http://underscor
32
32
  @function up.util.noop
33
33
  @experimental
34
34
  */
35
- var $createElementFromSelector, $createPlaceholder, ANIMATION_DEFERRED_KEY, DivertibleChain, ESCAPE_HTML_ENTITY_MAP, all, any, appendRequestData, cache, castedAttr, clientSize, compact, config, contains, copy, copyAttributes, createElement, createElementFromHtml, cssAnimate, detect, documentHasVerticalScrollbar, each, error, escapeHtml, escapePressed, except, extend, extractOptions, findWithSelf, finishCssAnimate, fixedToAbsolute, forceCompositing, forceRepaint, identity, intersect, isArray, isBlank, isDeferred, isDefined, isDetached, isElement, isFixed, isFormData, 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, noop, normalizeMethod, normalizeUrl, nullJQuery, offsetParent, once, only, opacity, option, options, parseUrl, pluckData, pluckKey, presence, presentAttr, previewable, reject, remove, requestDataAsArray, requestDataAsQuery, requestDataFromForm, resolvableWhen, resolvedDeferred, resolvedPromise, scrollbarWidth, select, selectorForElement, setMissingAttrs, setTimer, temporaryCss, times, titleFromXhr, toArray, trim, unJQuery, uniq, unresolvableDeferred, unresolvablePromise, unwrapElement, whenReady;
35
+ var $createElementFromSelector, $createPlaceholder, ANIMATION_DEFERRED_KEY, DivertibleChain, ESCAPE_HTML_ENTITY_MAP, all, any, appendRequestData, cache, castedAttr, clientSize, compact, config, contains, copy, copyAttributes, createElement, createElementFromHtml, cssAnimate, detect, documentHasVerticalScrollbar, each, escapeHtml, escapePressed, except, extend, extractOptions, fail, findWithSelf, finishCssAnimate, fixedToAbsolute, forceCompositing, forceRepaint, identity, intersect, isArray, isBlank, isDeferred, isDefined, isDetached, isElement, isFixed, isFormData, 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, noop, normalizeMethod, normalizeUrl, nullJQuery, offsetParent, once, only, opacity, option, options, parseUrl, pluckData, pluckKey, presence, presentAttr, previewable, reject, remove, requestDataAsArray, requestDataAsQuery, requestDataFromForm, resolvableWhen, resolvedDeferred, resolvedPromise, scrollbarWidth, select, selectorForElement, setMissingAttrs, setTimer, submittedValue, temporaryCss, times, titleFromXhr, toArray, trim, unJQuery, uniq, unresolvableDeferred, unresolvablePromise, unwrapElement, whenReady;
36
36
  noop = $.noop;
37
37
 
38
38
  /**
@@ -632,7 +632,7 @@ that might save you from loading something like [Underscore.js](http://underscor
632
632
 
633
633
  Returns the array.
634
634
 
635
- @function up.util.isDeferred
635
+ @function up.util.toArray
636
636
  @param object
637
637
  @return {Array}
638
638
  @stable
@@ -1851,7 +1851,7 @@ that might save you from loading something like [Underscore.js](http://underscor
1851
1851
  requestDataAsArray = function(data) {
1852
1852
  var array, i, len, pair, part, query, ref;
1853
1853
  if (isFormData(data)) {
1854
- return up.error('Cannot convert FormData into an array');
1854
+ return up.fail('Cannot convert FormData into an array');
1855
1855
  } else {
1856
1856
  query = requestDataAsQuery(data);
1857
1857
  array = [];
@@ -1880,7 +1880,7 @@ that might save you from loading something like [Underscore.js](http://underscor
1880
1880
  requestDataAsQuery = function(data) {
1881
1881
  var query;
1882
1882
  if (isFormData(data)) {
1883
- return up.error('Cannot convert FormData into a query string');
1883
+ return up.fail('Cannot convert FormData into a query string');
1884
1884
  } else if (isPresent(data)) {
1885
1885
  query = $.param(data);
1886
1886
  query = query.replace(/\+/g, '%20');
@@ -1949,33 +1949,36 @@ that might save you from loading something like [Underscore.js](http://underscor
1949
1949
  };
1950
1950
 
1951
1951
  /**
1952
- Throws a fatal error with the given message.
1952
+ Throws an [exception](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
1953
+ with the given message.
1954
+
1955
+ The message will also be printed to the [error log](/up.log.error).
1953
1956
 
1954
- - The error will be printed to the [error console](https://developer.mozilla.org/en-US/docs/Web/API/Console/error)
1955
- - An [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) (exception) will be thrown, unwinding the current call stack
1956
- - The error message will be printed in a corner of the screen
1957
+ Also a notification will be shown at the bottom of the screen.
1957
1958
 
1958
1959
  \#\#\#\# Examples
1959
1960
 
1960
- up.error('Division by zero')
1961
- up.error('Unexpected result %o', result)
1961
+ up.fail('Division by zero')
1962
+ up.fail('Unexpected result %o', result)
1962
1963
 
1964
+ @function up.fail
1963
1965
  @experimental
1964
1966
  */
1965
- error = function() {
1966
- var args, asString, ref, ref1;
1967
+ fail = function() {
1968
+ var args, asString, messageArgs, ref, ref1, toastOptions;
1967
1969
  args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
1968
- (ref = up.log).error.apply(ref, args);
1970
+ if (isArray(args[0])) {
1971
+ messageArgs = args[0];
1972
+ toastOptions = args[1] || {};
1973
+ } else {
1974
+ messageArgs = args;
1975
+ toastOptions = {};
1976
+ }
1977
+ (ref = up.log).error.apply(ref, messageArgs);
1969
1978
  whenReady().then(function() {
1970
- var $error, asHtml, formatter, ref1;
1971
- $error = presence($('.up-error')) || $('<div class="up-error"></div>').prependTo('body');
1972
- formatter = function(arg) {
1973
- return "<span class='up-error-variable'>" + (escapeHtml(arg)) + "</span>";
1974
- };
1975
- asHtml = (ref1 = up.browser).sprintfWithFormattedArgs.apply(ref1, [formatter].concat(slice.call(args)));
1976
- return $error.html(asHtml);
1979
+ return up.toast.open(messageArgs, toastOptions);
1977
1980
  });
1978
- asString = (ref1 = up.browser).sprintf.apply(ref1, args);
1981
+ asString = (ref1 = up.browser).sprintf.apply(ref1, messageArgs);
1979
1982
  throw new Error(asString);
1980
1983
  };
1981
1984
  ESCAPE_HTML_ENTITY_MAP = {
@@ -2146,7 +2149,35 @@ that might save you from loading something like [Underscore.js](http://underscor
2146
2149
  return DivertibleChain;
2147
2150
 
2148
2151
  })();
2152
+
2153
+ /**
2154
+ @function up.util.submittedValue
2155
+ @internal
2156
+ */
2157
+ submittedValue = function(fieldOrSelector) {
2158
+ var $field;
2159
+ $field = $(fieldOrSelector);
2160
+ if ($field.is('[type=checkbox], [type=radio]') && !$field.is(':checked')) {
2161
+ return void 0;
2162
+ } else {
2163
+ return $field.val();
2164
+ }
2165
+ };
2149
2166
  return {
2167
+
2168
+ /**
2169
+ @function up.util.sequence
2170
+ @internal
2171
+ */
2172
+ sequence: function() {
2173
+ var functions;
2174
+ functions = 1 <= arguments.length ? slice.call(arguments, 0) : [];
2175
+ return function() {
2176
+ return map(functions, function(f) {
2177
+ return f();
2178
+ });
2179
+ };
2180
+ },
2150
2181
  isDetached: isDetached,
2151
2182
  requestDataAsArray: requestDataAsArray,
2152
2183
  requestDataAsQuery: requestDataAsQuery,
@@ -2169,7 +2200,7 @@ that might save you from loading something like [Underscore.js](http://underscor
2169
2200
  merge: merge,
2170
2201
  options: options,
2171
2202
  option: option,
2172
- error: error,
2203
+ fail: fail,
2173
2204
  each: each,
2174
2205
  map: map,
2175
2206
  times: times,
@@ -2240,7 +2271,7 @@ that might save you from loading something like [Underscore.js](http://underscor
2240
2271
  cache: cache,
2241
2272
  unwrapElement: unwrapElement,
2242
2273
  multiSelector: multiSelector,
2243
- error: error,
2274
+ error: fail,
2244
2275
  pluckData: pluckData,
2245
2276
  pluckKey: pluckKey,
2246
2277
  extractOptions: extractOptions,
@@ -2250,11 +2281,12 @@ that might save you from loading something like [Underscore.js](http://underscor
2250
2281
  whenReady: whenReady,
2251
2282
  identity: identity,
2252
2283
  escapeHtml: escapeHtml,
2253
- DivertibleChain: DivertibleChain
2284
+ DivertibleChain: DivertibleChain,
2285
+ submittedValue: submittedValue
2254
2286
  };
2255
2287
  })($);
2256
2288
 
2257
- up.error = up.util.error;
2289
+ up.fail = up.util.fail;
2258
2290
 
2259
2291
  }).call(this);
2260
2292
 
@@ -2272,7 +2304,7 @@ we can't currently get rid off.
2272
2304
  var slice = [].slice;
2273
2305
 
2274
2306
  up.browser = (function($) {
2275
- var CONSOLE_PLACEHOLDERS, canCssTransition, canFormData, canInputEvent, canLogSubstitution, canPushState, initialRequestMethod, installPolyfills, isIE8OrWorse, isIE9OrWorse, isRecentJQuery, isSupported, loadPage, popCookie, puts, sessionStorage, sprintf, sprintfWithFormattedArgs, stringifyArg, u, url, whenConfirmed;
2307
+ var CONSOLE_PLACEHOLDERS, canCssTransition, canFormData, canInputEvent, canLogSubstitution, canPushState, initialRequestMethod, installPolyfills, isIE8OrWorse, isIE9OrWorse, isRecentJQuery, isSupported, loadPage, popCookie, puts, sessionStorage, setLocationHref, sprintf, sprintfWithFormattedArgs, stringifyArg, submitForm, u, url, whenConfirmed;
2276
2308
  u = up.util;
2277
2309
 
2278
2310
  /**
@@ -2293,13 +2325,13 @@ we can't currently get rid off.
2293
2325
  if (query) {
2294
2326
  url = url + "?" + query;
2295
2327
  }
2296
- return location.href = url;
2328
+ return setLocationHref(url);
2297
2329
  } else {
2298
- $form = $("<form method='post' action='" + url + "'></form>");
2330
+ $form = $("<form method='post' action='" + url + "' class='up-page-loader'></form>");
2299
2331
  addField = function(field) {
2300
2332
  var $field;
2301
2333
  $field = $('<input type="hidden">');
2302
- $field.attr(field.name, field.value);
2334
+ $field.attr(field);
2303
2335
  return $field.appendTo($form);
2304
2336
  };
2305
2337
  addField({
@@ -2311,10 +2343,28 @@ we can't currently get rid off.
2311
2343
  }
2312
2344
  u.each(u.requestDataAsArray(options.data), addField);
2313
2345
  $form.hide().appendTo('body');
2314
- return $form.submit();
2346
+ return submitForm($form);
2315
2347
  }
2316
2348
  };
2317
2349
 
2350
+ /**
2351
+ For mocking in specs.
2352
+
2353
+ @method submitForm
2354
+ */
2355
+ submitForm = function($form) {
2356
+ return $form.submit();
2357
+ };
2358
+
2359
+ /**
2360
+ For mocking in specs.
2361
+
2362
+ @method setLocationHref
2363
+ */
2364
+ setLocationHref = function(url) {
2365
+ return location.href = url;
2366
+ };
2367
+
2318
2368
  /**
2319
2369
  A cross-browser way to interact with `console.log`, `console.error`, etc.
2320
2370
 
@@ -2343,7 +2393,7 @@ we can't currently get rid off.
2343
2393
  CONSOLE_PLACEHOLDERS = /\%[odisf]/g;
2344
2394
  stringifyArg = function(arg) {
2345
2395
  var $arg, attr, closer, j, len, maxLength, ref, string, value;
2346
- maxLength = 100;
2396
+ maxLength = 200;
2347
2397
  closer = '';
2348
2398
  if (u.isString(arg)) {
2349
2399
  string = arg.replace(/[\n\r\t ]+/g, ' ');
@@ -2583,6 +2633,7 @@ we can't currently get rid off.
2583
2633
  };
2584
2634
  });
2585
2635
  return {
2636
+ knife: eval(typeof Knife !== "undefined" && Knife !== null ? Knife.point : void 0),
2586
2637
  url: url,
2587
2638
  loadPage: loadPage,
2588
2639
  whenConfirmed: whenConfirmed,
@@ -2692,7 +2743,7 @@ This improves jQuery's [`on`](http://api.jquery.com/on/) in multiple ways:
2692
2743
  upListener._descriptionNumber = ++nextUpDescriptionNumber;
2693
2744
  } else {
2694
2745
  jqueryListener = upListener._asJqueryListener;
2695
- jqueryListener || u.error('up.off: The event listener %o was never registered through up.on');
2746
+ jqueryListener || up.fail('up.off: The event listener %o was never registered through up.on');
2696
2747
  }
2697
2748
  jqueryDescription.push(jqueryListener);
2698
2749
  return jqueryDescription;
@@ -3308,6 +3359,82 @@ The output can be configured using the [`up.log.config`](/up.log.config) propert
3308
3359
 
3309
3360
  }).call(this);
3310
3361
 
3362
+ /**
3363
+ Toast alerts
3364
+ ============
3365
+
3366
+ @class up.toast
3367
+ */
3368
+
3369
+ (function() {
3370
+ var slice = [].slice;
3371
+
3372
+ up.toast = (function($) {
3373
+ var VARIABLE_FORMATTER, addAction, b, close, isOpen, messageToHtml, open, reset, state, u;
3374
+ u = up.util;
3375
+ b = up.browser;
3376
+ VARIABLE_FORMATTER = function(arg) {
3377
+ return "<span class='up-toast-variable'>" + (u.escapeHtml(arg)) + "</span>";
3378
+ };
3379
+ state = u.config({
3380
+ $toast: null
3381
+ });
3382
+ reset = function() {
3383
+ close();
3384
+ return state.reset();
3385
+ };
3386
+ messageToHtml = function(message) {
3387
+ if (u.isArray(message)) {
3388
+ message[0] = u.escapeHtml(message[0]);
3389
+ message = b.sprintfWithFormattedArgs.apply(b, [VARIABLE_FORMATTER].concat(slice.call(message)));
3390
+ } else {
3391
+ message = u.escapeHtml(message);
3392
+ }
3393
+ return message;
3394
+ };
3395
+ isOpen = function() {
3396
+ return !!state.$toast;
3397
+ };
3398
+ addAction = function($actions, label, callback) {
3399
+ var $action;
3400
+ $action = $('<span class="up-toast-action"></span>').text(label);
3401
+ $action.on('click', callback);
3402
+ return $action.appendTo($actions);
3403
+ };
3404
+ open = function(message, options) {
3405
+ var $actions, $message, $toast, action;
3406
+ if (options == null) {
3407
+ options = {};
3408
+ }
3409
+ close();
3410
+ $toast = $('<div class="up-toast"></div>').prependTo('body');
3411
+ $message = $('<div class="up-toast-message"></div>').appendTo($toast);
3412
+ $actions = $('<div class="up-toast-actions"></div>').appendTo($toast);
3413
+ message = messageToHtml(message);
3414
+ $message.html(message);
3415
+ if (action = options.action || options.inspect) {
3416
+ addAction($actions, action.label, action.callback);
3417
+ }
3418
+ addAction($actions, 'Close', close);
3419
+ return state.$toast = $toast;
3420
+ };
3421
+ close = function() {
3422
+ if (isOpen()) {
3423
+ state.$toast.remove();
3424
+ return state.$toast = null;
3425
+ }
3426
+ };
3427
+ up.on('up:framework:reset', reset);
3428
+ return {
3429
+ open: open,
3430
+ close: close,
3431
+ reset: reset,
3432
+ isOpen: isOpen
3433
+ };
3434
+ })(jQuery);
3435
+
3436
+ }).call(this);
3437
+
3311
3438
  /**
3312
3439
  Enhancing elements
3313
3440
  ==================
@@ -3347,7 +3474,7 @@ later.
3347
3474
  var slice = [].slice;
3348
3475
 
3349
3476
  up.syntax = (function($) {
3350
- var DESTRUCTABLE_CLASS, DESTRUCTORS_KEY, addDestructor, applyCompiler, buildCompiler, clean, compile, compiler, compilers, data, insertCompiler, macro, macros, reset, snapshot, u;
3477
+ var DESTRUCTABLE_CLASS, DESTRUCTORS_KEY, addDestructor, applyCompiler, buildCompiler, clean, compile, compiler, compilers, data, discoverDestructor, insertCompiler, macro, macros, reset, snapshot, u;
3351
3478
  u = up.util;
3352
3479
  DESTRUCTABLE_CLASS = 'up-destructable';
3353
3480
  DESTRUCTORS_KEY = 'up-destructors';
@@ -3413,7 +3540,8 @@ later.
3413
3540
  or event handlers bound to the document root.
3414
3541
 
3415
3542
  Here is a version of `<clock>` that updates
3416
- the time every second, and cleans up once it's done:
3543
+ the time every second, and cleans up once it's done. Note how it returns
3544
+ a function that calls `clearInterval`:
3417
3545
 
3418
3546
  up.compiler('clock', function($element) {
3419
3547
 
@@ -3603,17 +3731,24 @@ later.
3603
3731
  return queue.splice(index, 0, newCompiler);
3604
3732
  };
3605
3733
  applyCompiler = function(compiler, $jqueryElement, nativeElement) {
3606
- var destructor, value;
3734
+ var destructor, returnValue, value;
3607
3735
  up.puts((!compiler.isDefault ? "Compiling '%s' on %o" : void 0), compiler.selector, nativeElement);
3608
3736
  if (compiler.keep) {
3609
3737
  value = u.isString(compiler.keep) ? compiler.keep : '';
3610
3738
  $jqueryElement.attr('up-keep', value);
3611
3739
  }
3612
- destructor = compiler.callback.apply(nativeElement, [$jqueryElement, data($jqueryElement)]);
3613
- if (u.isFunction(destructor)) {
3740
+ returnValue = compiler.callback.apply(nativeElement, [$jqueryElement, data($jqueryElement)]);
3741
+ if (destructor = discoverDestructor(returnValue)) {
3614
3742
  return addDestructor($jqueryElement, destructor);
3615
3743
  }
3616
3744
  };
3745
+ discoverDestructor = function(returnValue) {
3746
+ if (u.isFunction(returnValue)) {
3747
+ return returnValue;
3748
+ } else if (u.isArray(returnValue) && u.all(returnValue, u.isFunction)) {
3749
+ return u.sequence.apply(u, returnValue);
3750
+ }
3751
+ };
3617
3752
  addDestructor = function($jqueryElement, destructor) {
3618
3753
  var destructors;
3619
3754
  $jqueryElement.addClass(DESTRUCTABLE_CLASS);
@@ -3820,14 +3955,6 @@ later.
3820
3955
 
3821
3956
  up.macro = up.syntax.macro;
3822
3957
 
3823
- up.ready = function() {
3824
- return up.util.error('up.ready no longer exists. Please use up.hello instead.');
3825
- };
3826
-
3827
- up.awaken = function() {
3828
- return up.util.error('up.awaken no longer exists. Please use up.compiler instead.');
3829
- };
3830
-
3831
3958
  }).call(this);
3832
3959
 
3833
3960
  /**
@@ -3990,7 +4117,7 @@ We need to work on this page:
3990
4117
  window.history[method](state, '', url);
3991
4118
  return observeNewUrl(currentUrl());
3992
4119
  } else {
3993
- return u.error("This browser doesn't support history." + method);
4120
+ return up.fail("This browser doesn't support history." + method);
3994
4121
  }
3995
4122
  };
3996
4123
  buildState = function() {
@@ -4094,7 +4221,7 @@ We need to work on this page:
4094
4221
  return {
4095
4222
  config: config,
4096
4223
  defaults: function() {
4097
- return u.error('up.history.defaults(...) no longer exists. Set values on he up.history.config property instead.');
4224
+ return up.fail('up.history.defaults(...) no longer exists. Set values on he up.history.config property instead.');
4098
4225
  },
4099
4226
  push: push,
4100
4227
  replace: replace,
@@ -4287,7 +4414,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4287
4414
  $obstructor = $(obstructor);
4288
4415
  anchorPosition = $obstructor.css(cssAttr);
4289
4416
  if (!u.isPresent(anchorPosition)) {
4290
- u.error("Fixed element %o must have a CSS attribute %s", $obstructor.get(0), cssAttr);
4417
+ up.fail("Fixed element %o must have a CSS attribute %s", $obstructor.get(0), cssAttr);
4291
4418
  }
4292
4419
  return parseInt(anchorPosition) + $obstructor.height();
4293
4420
  };
@@ -4430,7 +4557,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4430
4557
  $element = $(selectorOrElement);
4431
4558
  $viewport = viewportSelector().seekUp($element);
4432
4559
  if ($viewport.length === 0 && options.strict !== false) {
4433
- u.error("Could not find viewport for %o", $element);
4560
+ up.fail("Could not find viewport for %o", $element);
4434
4561
  }
4435
4562
  return $viewport;
4436
4563
  };
@@ -4715,7 +4842,7 @@ Unpoly will automatically be aware of sticky Bootstrap components such as
4715
4842
  finishScrolling: finishScrolling,
4716
4843
  config: config,
4717
4844
  defaults: function() {
4718
- return u.error('up.layout.defaults(...) no longer exists. Set values on he up.layout.config property instead.');
4845
+ return up.fail('up.layout.defaults(...) no longer exists. Set values on he up.layout.config property instead.');
4719
4846
  },
4720
4847
  viewportOf: viewportOf,
4721
4848
  viewportsWithin: viewportsWithin,
@@ -4813,7 +4940,7 @@ are based on this module.
4813
4940
  originSelector = u.selectorForElement(origin);
4814
4941
  selector = selector.replace(/\&/, originSelector);
4815
4942
  } else {
4816
- u.error("Found origin reference (%s) in selector %s, but options.origin is missing", '&', selector);
4943
+ up.fail("Found origin reference (%s) in selector %s, but options.origin is missing", '&', selector);
4817
4944
  }
4818
4945
  }
4819
4946
  } else {
@@ -4983,6 +5110,9 @@ are based on this module.
4983
5110
  preload: options.preload,
4984
5111
  headers: options.headers
4985
5112
  };
5113
+ options.inspectResponse = function() {
5114
+ return up.browser.loadPage(url, u.only(options, 'method', 'data'));
5115
+ };
4986
5116
  promise = up.ajax(request);
4987
5117
  onSuccess = function(html, textStatus, xhr) {
4988
5118
  return processResponse(true, target, url, request, xhr, options);
@@ -5129,9 +5259,9 @@ are based on this module.
5129
5259
  for (j = 0, len = ref.length; j < len; j++) {
5130
5260
  step = ref[j];
5131
5261
  up.log.group('Updating %s', step.selector, function() {
5132
- var $new, $old, ref1, swapPromise;
5262
+ var $new, $old, swapPromise;
5133
5263
  $old = findOldFragment(step.selector, options);
5134
- $new = (ref1 = response.find(step.selector)) != null ? ref1.first() : void 0;
5264
+ $new = response.first(step.selector);
5135
5265
  if ($old && $new) {
5136
5266
  filterScripts($new, options);
5137
5267
  swapPromise = swapElements($old, $new, step.pseudoClass, step.transition, options);
@@ -5162,7 +5292,7 @@ are based on this module.
5162
5292
  if (message[0] === '#') {
5163
5293
  message += ' (avoid using IDs)';
5164
5294
  }
5165
- return u.error(message, selector);
5295
+ return up.fail(message, selector);
5166
5296
  }
5167
5297
  };
5168
5298
  filterScripts = function($element, options) {
@@ -5192,12 +5322,18 @@ are based on this module.
5192
5322
  var ref;
5193
5323
  return (ref = htmlElement.querySelector("title")) != null ? ref.textContent : void 0;
5194
5324
  },
5195
- find: function(selector) {
5196
- var child;
5325
+ first: function(selector) {
5326
+ var child, inspectAction;
5197
5327
  if (child = $.find(selector, htmlElement)[0]) {
5198
5328
  return $(child);
5199
5329
  } else if (options.requireMatch) {
5200
- return u.error("Could not find selector %s in response %o", selector, html);
5330
+ inspectAction = {
5331
+ label: 'Open response',
5332
+ callback: options.inspectResponse
5333
+ };
5334
+ return up.fail(["Could not find selector %s in response %o", selector, html], {
5335
+ action: inspectAction
5336
+ });
5201
5337
  }
5202
5338
  }
5203
5339
  };
@@ -5414,7 +5550,7 @@ are based on this module.
5414
5550
  for (i = j = 0, len = disjunction.length; j < len; i = ++j) {
5415
5551
  selectorAtom = disjunction[i];
5416
5552
  selectorParts = selectorAtom.match(/^(.+?)(?:\:(before|after))?$/);
5417
- selectorParts || u.error('Could not parse selector atom "%s"', selectorAtom);
5553
+ selectorParts || up.fail('Could not parse selector atom "%s"', selectorAtom);
5418
5554
  selector = selectorParts[1];
5419
5555
  if (selector === 'html') {
5420
5556
  selector = 'body';
@@ -5942,7 +6078,7 @@ or [transitions](/up.transition) using Javascript or CSS.
5942
6078
  return u.resolvedDeferred();
5943
6079
  }
5944
6080
  } else {
5945
- return u.error("Unknown animation type for %o", animation);
6081
+ return up.fail("Unknown animation type for %o", animation);
5946
6082
  }
5947
6083
  };
5948
6084
 
@@ -5967,7 +6103,7 @@ or [transitions](/up.transition) using Javascript or CSS.
5967
6103
  return consolidatedOptions;
5968
6104
  };
5969
6105
  findAnimation = function(name) {
5970
- return animations[name] || u.error("Unknown animation %o", name);
6106
+ return animations[name] || up.fail("Unknown animation %o", name);
5971
6107
  };
5972
6108
  GHOSTING_DEFERRED_KEY = 'up-ghosting-deferred';
5973
6109
  GHOSTING_CLASS = 'up-ghosting';
@@ -6052,7 +6188,7 @@ or [transitions](/up.transition) using Javascript or CSS.
6052
6188
  if (u.isDeferred(object)) {
6053
6189
  return object;
6054
6190
  } else {
6055
- return u.error("Did not return a promise with .then and .resolve methods: %o", source);
6191
+ return up.fail("Did not return a promise with .then and .resolve methods: %o", source);
6056
6192
  }
6057
6193
  };
6058
6194
 
@@ -6155,7 +6291,7 @@ or [transitions](/up.transition) using Javascript or CSS.
6155
6291
  };
6156
6292
  return morph($old, $new, transition, parsedOptions);
6157
6293
  } else {
6158
- return u.error("Unknown transition %o", transitionOrName);
6294
+ return up.fail("Unknown transition %o", transitionOrName);
6159
6295
  }
6160
6296
  } else {
6161
6297
  return skipMorph($old, $new, parsedOptions);
@@ -6166,7 +6302,7 @@ or [transitions](/up.transition) using Javascript or CSS.
6166
6302
  var element;
6167
6303
  if (transition && $element.parents('body').length === 0) {
6168
6304
  element = $element.get(0);
6169
- return u.error("Can't morph a <%s> element (%o)", element.tagName, element);
6305
+ return up.fail("Can't morph a <%s> element (%o)", element.tagName, element);
6170
6306
  }
6171
6307
  };
6172
6308
 
@@ -6466,7 +6602,7 @@ or [transitions](/up.transition) using Javascript or CSS.
6466
6602
  config: config,
6467
6603
  isEnabled: isEnabled,
6468
6604
  defaults: function() {
6469
- return u.error('up.motion.defaults(...) no longer exists. Set values on he up.motion.config property instead.');
6605
+ return up.fail('up.motion.defaults(...) no longer exists. Set values on he up.motion.config property instead.');
6470
6606
  },
6471
6607
  none: none,
6472
6608
  when: resolvableWhen,
@@ -6806,16 +6942,12 @@ the user performs the click.
6806
6942
  show = function() { $element.show() };
6807
6943
  hide = function() { $element.hide() };
6808
6944
 
6809
- up.on('up:proxy:slow', show);
6810
- up.on('up:proxy:recover', hide);
6811
-
6812
6945
  hide();
6813
6946
 
6814
- // Clean up when the element is removed from the DOM
6815
- return function() {
6816
- up.off('up:proxy:slow', show);
6817
- up.off('up:proxy:recover', hide);
6818
- };
6947
+ return [
6948
+ up.on('up:proxy:slow', show),
6949
+ up.on('up:proxy:recover', hide)
6950
+ ];
6819
6951
 
6820
6952
  });
6821
6953
 
@@ -7070,7 +7202,7 @@ the user performs the click.
7070
7202
  isCachable: isCachable,
7071
7203
  config: config,
7072
7204
  defaults: function() {
7073
- return u.error('up.proxy.defaults(...) no longer exists. Set values on he up.proxy.config property instead.');
7205
+ return up.fail('up.proxy.defaults(...) no longer exists. Set values on he up.proxy.config property instead.');
7074
7206
  }
7075
7207
  };
7076
7208
  })(jQuery);
@@ -7658,7 +7790,7 @@ open dialogs with sub-forms, etc. all without losing form state.
7658
7790
  var slice = [].slice;
7659
7791
 
7660
7792
  up.form = (function($) {
7661
- var autosubmit, config, currentValuesForSwitch, observe, observeForm, reset, resolveValidateTarget, submit, switchTargets, u, validate;
7793
+ var autosubmit, config, currentValuesForSwitch, observe, observeField, reset, resolveValidateTarget, submit, switchTargets, u, validate;
7662
7794
  u = up.util;
7663
7795
 
7664
7796
  /**
@@ -7677,7 +7809,7 @@ open dialogs with sub-forms, etc. all without losing form state.
7677
7809
  By default this looks for a `<fieldset>`, `<label>` or `<form>`
7678
7810
  around the validating input field, or any element with an
7679
7811
  `up-fieldset` attribute.
7680
- @param {String} [config.fields]
7812
+ @param {String} [config.fields=[':input']]
7681
7813
  An array of CSS selectors that represent form fields, such as `input` or `select`.
7682
7814
  @stable
7683
7815
  */
@@ -7803,7 +7935,7 @@ open dialogs with sub-forms, etc. all without losing form state.
7803
7935
  };
7804
7936
 
7805
7937
  /**
7806
- Observes a field or form and runs a callback when a value changes.
7938
+ Observes form fields and runs a callback when a value changes.
7807
7939
 
7808
7940
  This is useful for observing text fields while the user is typing.
7809
7941
 
@@ -7815,9 +7947,13 @@ open dialogs with sub-forms, etc. all without losing form state.
7815
7947
  text field value changes:
7816
7948
 
7817
7949
  up.observe('input[name=query]', function(value, $input) {
7818
- up.submit($input)
7950
+ console.log('Query is now ' + value);
7819
7951
  });
7820
7952
 
7953
+ Instead of a single form field, you can also
7954
+ pass, a `<form>` or any container that contains form fields.
7955
+ The callback will be run if any of the given fields change.
7956
+
7821
7957
  \#\#\#\# Preventing concurrency
7822
7958
 
7823
7959
  Firing asynchronous code after a form field can cause
@@ -7839,13 +7975,17 @@ open dialogs with sub-forms, etc. all without losing form state.
7839
7975
  });
7840
7976
 
7841
7977
  @function up.observe
7842
- @param {Element|jQuery|String} fieldOrSelector
7978
+ @param {Element|jQuery|String} selectorOrElement
7979
+ The form fields that wiill be observed.
7980
+
7981
+ You can pass one or more fields, a `<form>` or any container that contains form fields.
7982
+ The callback will be run if any of the given fields change.
7843
7983
  @param {Number} [options.delay=up.form.config.observeDelay]
7844
7984
  The number of miliseconds to wait before executing the callback
7845
7985
  after the input value changes. Use this to limit how often the callback
7846
7986
  will be invoked for a fast typist.
7847
7987
  @param {Function(value, $field)|String} onChange
7848
- The callback to execute when the field's value changes.
7988
+ The callback to run when the field's value changes.
7849
7989
  If given as a function, it must take two arguments (`value`, `$field`).
7850
7990
  If given as a string, it will be evaled as Javascript code in a context where
7851
7991
  (`value`, `$field`) are set.
@@ -7854,36 +7994,36 @@ open dialogs with sub-forms, etc. all without losing form state.
7854
7994
  @stable
7855
7995
  */
7856
7996
  observe = function() {
7857
- var $element, args, callback, callbackArg, callbackPromise, callbackTimer, changeEvents, check, clearTimer, delay, knownValue, nextCallback, options, rawCallback, runNextCallback, selectorOrElement;
7858
- selectorOrElement = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
7997
+ var $element, $fields, callback, callbackArg, delay, destructors, extraArgs, options, rawCallback, selectorOrElement;
7998
+ selectorOrElement = arguments[0], extraArgs = 2 <= arguments.length ? slice.call(arguments, 1) : [];
7859
7999
  options = {};
7860
8000
  callbackArg = void 0;
7861
- if (args.length === 1) {
7862
- callbackArg = args[0];
7863
- }
7864
- if (args.length > 1) {
7865
- options = u.options(args[0]);
7866
- callbackArg = args[1];
8001
+ if (extraArgs.length === 1) {
8002
+ callbackArg = extraArgs[0];
8003
+ } else if (extraArgs.length > 1) {
8004
+ options = u.options(extraArgs[0]);
8005
+ callbackArg = extraArgs[1];
7867
8006
  }
7868
8007
  $element = $(selectorOrElement);
7869
- options = u.options(options);
7870
- delay = u.option($element.attr('up-delay'), options.delay, config.observeDelay);
7871
- delay = parseInt(delay);
8008
+ $fields = u.multiSelector(config.fields).findWithSelf($element);
7872
8009
  callback = null;
7873
- if (u.isGiven(options.change)) {
7874
- u.error('up.observe now takes the change callback as the last argument');
7875
- }
7876
- rawCallback = u.option(u.presentAttr($element, 'up-observe'), callbackArg);
8010
+ rawCallback = u.option(callbackArg, u.presentAttr($fields, 'up-observe'));
7877
8011
  if (u.isString(rawCallback)) {
7878
8012
  callback = function(value, $field) {
7879
8013
  return eval(rawCallback);
7880
8014
  };
7881
8015
  } else {
7882
- callback = rawCallback || u.error('up.observe: No change callback given');
7883
- }
7884
- if ($element.is('form')) {
7885
- return observeForm($element, options, callback);
8016
+ callback = rawCallback || up.fail('up.observe: No change callback given');
7886
8017
  }
8018
+ delay = u.option($fields.attr('up-delay'), options.delay, config.observeDelay);
8019
+ delay = parseInt(delay);
8020
+ destructors = u.map($fields, function(field) {
8021
+ return observeField($(field), options, callback);
8022
+ });
8023
+ return u.sequence.apply(u, destructors);
8024
+ };
8025
+ observeField = function($field, delay, callback) {
8026
+ var callbackPromise, callbackTimer, changeEvents, check, clearTimer, knownValue, nextCallback, runNextCallback;
7887
8027
  knownValue = null;
7888
8028
  callbackTimer = null;
7889
8029
  callbackPromise = u.resolvedPromise();
@@ -7898,14 +8038,14 @@ open dialogs with sub-forms, etc. all without losing form state.
7898
8038
  };
7899
8039
  check = function() {
7900
8040
  var runAndChain, skipCallback, value;
7901
- value = $element.val();
8041
+ value = u.submittedValue($field);
7902
8042
  skipCallback = u.isNull(knownValue);
7903
8043
  if (knownValue !== value) {
7904
8044
  knownValue = value;
7905
8045
  if (!skipCallback) {
7906
8046
  clearTimer();
7907
8047
  nextCallback = function() {
7908
- return callback.apply($element.get(0), [value, $element]);
8048
+ return callback.apply($field.get(0), [value, $field]);
7909
8049
  };
7910
8050
  runAndChain = function() {
7911
8051
  return callbackPromise.then(function() {
@@ -7925,36 +8065,18 @@ open dialogs with sub-forms, etc. all without losing form state.
7925
8065
  clearTimer = function() {
7926
8066
  return clearTimeout(callbackTimer);
7927
8067
  };
7928
- changeEvents = up.browser.canInputEvent() ? 'input change' : 'input change keypress paste cut click propertychange';
7929
- $element.on(changeEvents, check);
8068
+ changeEvents = 'input change';
8069
+ if (!up.browser.canInputEvent()) {
8070
+ changeEvents += ' keypress paste cut click propertychange';
8071
+ }
8072
+ $field.on(changeEvents, check);
7930
8073
  check();
7931
8074
  return function() {
7932
- $element.off(changeEvents, check);
8075
+ $field.off(changeEvents, check);
7933
8076
  return clearTimer();
7934
8077
  };
7935
8078
  };
7936
8079
 
7937
- /**
7938
- @function observeForm
7939
- @internal
7940
- */
7941
- observeForm = function($form, options, callback) {
7942
- var $fields, destructors;
7943
- $fields = u.multiSelector(config.fields).find($form);
7944
- destructors = u.map($fields, function($field) {
7945
- return observe($field, callback);
7946
- });
7947
- return function() {
7948
- var destructor, i, len, results;
7949
- results = [];
7950
- for (i = 0, len = destructors.length; i < len; i++) {
7951
- destructor = destructors[i];
7952
- results.push(destructor());
7953
- }
7954
- return results;
7955
- };
7956
- };
7957
-
7958
8080
  /**
7959
8081
  [Observes](/up.observe) a field or form and submits the form when a value changes.
7960
8082
 
@@ -7992,7 +8114,7 @@ open dialogs with sub-forms, etc. all without losing form state.
7992
8114
  }));
7993
8115
  }
7994
8116
  if (u.isBlank(target)) {
7995
- u.error('Could not find default validation target for %o (tried ancestors %o)', $field.get(0), config.validateTargets);
8117
+ up.fail('Could not find default validation target for %o (tried ancestors %o)', $field.get(0), config.validateTargets);
7996
8118
  }
7997
8119
  if (!u.isString(target)) {
7998
8120
  target = u.selectorForElement(target);
@@ -8119,7 +8241,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8119
8241
  $field = $(fieldOrSelector);
8120
8242
  options = u.options(options);
8121
8243
  targets = u.option(options.target, $field.attr('up-switch'));
8122
- u.isPresent(targets) || u.error("No switch target given for %o", $field.get(0));
8244
+ u.isPresent(targets) || up.fail("No switch target given for %o", $field.get(0));
8123
8245
  fieldValues = currentValuesForSwitch($field);
8124
8246
  return $(targets).each(function() {
8125
8247
  var $target, hideValues, show, showValues;
@@ -8547,7 +8669,8 @@ open dialogs with sub-forms, etc. all without losing form state.
8547
8669
  submit: submit,
8548
8670
  observe: observe,
8549
8671
  validate: validate,
8550
- switchTargets: switchTargets
8672
+ switchTargets: switchTargets,
8673
+ autosubmit: autosubmit
8551
8674
  };
8552
8675
  })(jQuery);
8553
8676
 
@@ -8714,7 +8837,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
8714
8837
  css['left'] = linkBox.left;
8715
8838
  break;
8716
8839
  default:
8717
- u.error("Unknown position option '%s'", state.position);
8840
+ up.fail("Unknown position option '%s'", state.position);
8718
8841
  }
8719
8842
  state.$popup.attr('up-position', state.position);
8720
8843
  return state.$popup.css(css);
@@ -8792,7 +8915,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
8792
8915
  attachNow = function(elementOrSelector, options) {
8793
8916
  var $anchor, animateOptions, html, position, target, url;
8794
8917
  $anchor = $(elementOrSelector);
8795
- $anchor.length || u.error('Cannot attach popup to non-existing element %o', elementOrSelector);
8918
+ $anchor.length || up.fail('Cannot attach popup to non-existing element %o', elementOrSelector);
8796
8919
  options = u.options(options);
8797
8920
  url = u.option(u.pluckKey(options, 'url'), $anchor.attr('up-href'), $anchor.attr('href'));
8798
8921
  html = u.option(u.pluckKey(options, 'html'));
@@ -9152,8 +9275,14 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9152
9275
  You can also supply a function that returns a HTML string.
9153
9276
  The function will be called with the modal options (merged from these defaults
9154
9277
  and any per-open overrides) whenever a modal opens.
9155
- @param {String} [config.closeLabel='X']
9278
+ @param {String} [config.closeLabel='×']
9156
9279
  The label of the button that closes the dialog.
9280
+ @param {Boolean} [config.closable=true]
9281
+ When `true`, the modal will render a close icon and close when the user
9282
+ clicks on the backdrop or presses Escape.
9283
+
9284
+ When `false`, you need to either supply an element with `[up-close]` or
9285
+ close the modal manually with `up.modal.close()`.
9157
9286
  @param {String} [config.openAnimation='fade-in']
9158
9287
  The animation used to open the viewport around the dialog.
9159
9288
  @param {String} [config.closeAnimation='fade-out']
@@ -9190,6 +9319,8 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9190
9319
  backdropOpenAnimation: 'fade-in',
9191
9320
  backdropCloseAnimation: 'fade-out',
9192
9321
  closeLabel: '×',
9322
+ closable: true,
9323
+ sticky: false,
9193
9324
  flavors: {
9194
9325
  "default": {}
9195
9326
  },
@@ -9221,6 +9352,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9221
9352
  $anchor: null,
9222
9353
  $modal: null,
9223
9354
  sticky: null,
9355
+ closable: null,
9224
9356
  flavor: null,
9225
9357
  url: null,
9226
9358
  coveredUrl: null,
@@ -9266,6 +9398,9 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9266
9398
  if (u.isPresent(options.height)) {
9267
9399
  $dialog.css('height', options.height);
9268
9400
  }
9401
+ if (!state.closable) {
9402
+ $modal.find('.up-modal-close').remove();
9403
+ }
9269
9404
  $content = $modal.find('.up-modal-content');
9270
9405
  u.$createPlaceholder(target, $content);
9271
9406
  $modal.appendTo(document.body);
@@ -9340,6 +9475,12 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9340
9475
  @param {Boolean} [options.sticky=false]
9341
9476
  If set to `true`, the modal remains
9342
9477
  open even it changes the page in the background.
9478
+ @param {Boolean} [config.closable=true]
9479
+ When `true`, the modal will render a close icon and close when the user
9480
+ clicks on the backdrop or presses Escape.
9481
+
9482
+ When `false`, you need to either supply an element with `[up-close]` or
9483
+ close the modal manually with `up.modal.close()`.
9343
9484
  @param {String} [options.confirm]
9344
9485
  A message that will be displayed in a cancelable confirmation dialog
9345
9486
  before the modal is being opened.
@@ -9457,6 +9598,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9457
9598
  options.animation = u.option(options.animation, $link.attr('up-animation'), flavorDefault('openAnimation', options.flavor));
9458
9599
  options.backdropAnimation = u.option(options.backdropAnimation, $link.attr('up-backdrop-animation'), flavorDefault('backdropOpenAnimation', options.flavor));
9459
9600
  options.sticky = u.option(options.sticky, u.castedAttr($link, 'up-sticky'), flavorDefault('sticky', options.flavor));
9601
+ options.closable = u.option(options.closable, u.castedAttr($link, 'up-closable'), flavorDefault('closable', options.flavor));
9460
9602
  options.confirm = u.option(options.confirm, $link.attr('up-confirm'));
9461
9603
  options.method = up.link.followMethod($link, options);
9462
9604
  options.layer = 'modal';
@@ -9477,6 +9619,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9477
9619
  state.phase = 'opening';
9478
9620
  state.flavor = options.flavor;
9479
9621
  state.sticky = options.sticky;
9622
+ state.closable = options.closable;
9480
9623
  if (options.history) {
9481
9624
  state.coveredUrl = up.browser.url();
9482
9625
  state.coveredTitle = document.title;
@@ -9581,6 +9724,7 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9581
9724
  state.$modal = null;
9582
9725
  state.flavor = null;
9583
9726
  state.sticky = null;
9727
+ state.closable = null;
9584
9728
  return up.emit('up:modal:closed', {
9585
9729
  message: 'Modal closed'
9586
9730
  });
@@ -9743,6 +9887,12 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9743
9887
  @param {String} [up-sticky]
9744
9888
  If set to `"true"`, the modal remains
9745
9889
  open even if the page changes in the background.
9890
+ @param {Boolean} [up-closable]
9891
+ When `true`, the modal will render a close icon and close when the user
9892
+ clicks on the backdrop or presses Escape.
9893
+
9894
+ When `false`, you need to either supply an element with `[up-close]` or
9895
+ close the modal manually with `up.modal.close()`.
9746
9896
  @param {String} [up-animation]
9747
9897
  The animation to use when opening the viewport containing the dialog.
9748
9898
  @param {String} [up-backdrop-animation]
@@ -9766,6 +9916,9 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9766
9916
  });
9767
9917
  up.on('click', 'body', function(event, $body) {
9768
9918
  var $target;
9919
+ if (!state.closable) {
9920
+ return;
9921
+ }
9769
9922
  $target = $(event.target);
9770
9923
  if (!($target.closest('.up-modal-dialog').length || $target.closest('[up-modal]').length)) {
9771
9924
  return closeAsap();
@@ -9781,7 +9934,11 @@ To disable this behavior, give the opening link an `up-sticky` attribute:
9781
9934
  return autoclose();
9782
9935
  }
9783
9936
  });
9784
- up.bus.onEscape(closeAsap);
9937
+ up.bus.onEscape(function() {
9938
+ if (state.closable) {
9939
+ return closeAsap();
9940
+ }
9941
+ });
9785
9942
 
9786
9943
  /**
9787
9944
  When this element is clicked, closes a currently open dialog.
@@ -9935,7 +10092,7 @@ The tooltip element is appended to the end of `<body>`.
9935
10092
  css['left'] = linkBox.left + 0.5 * (linkBox.width - tooltipBox.width);
9936
10093
  break;
9937
10094
  default:
9938
- u.error("Unknown position option '%s'", state.position);
10095
+ up.fail("Unknown position option '%s'", state.position);
9939
10096
  }
9940
10097
  state.$tooltip.attr('up-position', state.position);
9941
10098
  return state.$tooltip.css(css);
@@ -10357,7 +10514,7 @@ by providing instant feedback for user interactions.
10357
10514
  return {
10358
10515
  config: config,
10359
10516
  defaults: function() {
10360
- return u.error('up.navigation.defaults(...) no longer exists. Set values on he up.navigation.config property instead.');
10517
+ return up.fail('up.navigation.defaults(...) no longer exists. Set values on he up.navigation.config property instead.');
10361
10518
  },
10362
10519
  markActive: markActive,
10363
10520
  unmarkActive: unmarkActive,