unpoly-rails 0.31.0 → 0.31.1

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f141062c454db36ff9fa469178c4980587858770
4
- data.tar.gz: cd9474a9ab62e41572b56f731822ef1483f8543a
3
+ metadata.gz: 8b2c54e030dfc8082214f4fdf1109b3e497f949e
4
+ data.tar.gz: 18108425585be7e38444f0bf0d2513745a1f0853
5
5
  SHA512:
6
- metadata.gz: 81d7cf8973a69e968ca7063cc058fbef25403027638d504c2b8fb3919b87e24ea11d1b0f7ca219c8a2a8ca340d13a8cd45474ecab50a6275d1fbae86c8d1def5
7
- data.tar.gz: eadfbdd2d046e641e8a93462d2bfb8cdb274086afedff58aa21681d1641a4d501ebc26722195f4d068f7a717e8ec2777ebb316cfda911264775f6e0f57a2d8d1
6
+ metadata.gz: 3598cb4d1f466fd2482d6135ed16ef34a9176141821f1762901b8ce199696a1ae039e77cd791f618ecb0fde550c0fa9b0d5f5d8c2a85a3b074d037c7a5dcce72
7
+ data.tar.gz: ffb33e6cd4003884e7671c8233159c1aa7be858ab78190c40633fc29b298cefae7a4e023e16512591e65e2c7315cd307dfa5580e961b6230aa80c6f4a04717f5
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  tmp
8
8
  /dist/manifest.json
9
9
  /doc
10
+ npm-debug.log
data/CHANGELOG.md CHANGED
@@ -10,7 +10,7 @@ Unreleased
10
10
 
11
11
  ### Compatible changes
12
12
 
13
- - Drawers are now a built-in modal flavor! Use the `[up-drawer]` attribute to open page fragements
13
+ - Drawers are now a built-in modal flavor! Use the [`[up-drawer]`](/up-drawer] attribute to open page fragements
14
14
  in a modal drawer that slides in from the edge of the screen.
15
15
 
16
16
 
data/Rakefile CHANGED
@@ -2,19 +2,23 @@ require "bundler/gem_tasks"
2
2
  require 'sass/util'
3
3
  require 'sass/script'
4
4
  require 'sprockets/standalone'
5
+ require 'unpoly/rails/version'
6
+ require 'json'
5
7
 
6
8
  module Unpoly
7
- module Assets
8
- MANIFESTS = %w(unpoly.js unpoly-bootstrap3.js unpoly.css unpoly-bootstrap3.css)
9
- SOURCES = %w(lib/assets/javascripts lib/assets/stylesheets)
10
- OUTPUT = 'dist'
9
+ module Tasks
10
+ SPROCKETS_MANIFESTS = %w(unpoly.js unpoly-bootstrap3.js unpoly.css unpoly-bootstrap3.css)
11
+ SPROCKETS_SOURCES = %w(lib/assets/javascripts lib/assets/stylesheets)
12
+ SPROCKETS_OUTPUT_FOLDER = 'dist'
13
+ NPM_MANIFEST = 'package.json'
14
+ VISIBLE_TASKS = %w(publish:build publish:commit publish:release)
11
15
  end
12
16
  end
13
17
 
14
18
  Sprockets::Standalone::RakeTask.new(:source_assets) do |task, sprockets|
15
- task.assets = Unpoly::Assets::MANIFESTS
16
- task.sources = Unpoly::Assets::SOURCES
17
- task.output = Unpoly::Assets::OUTPUT
19
+ task.assets = Unpoly::Tasks::SPROCKETS_MANIFESTS
20
+ task.sources = Unpoly::Tasks::SPROCKETS_SOURCES
21
+ task.output = Unpoly::Tasks::SPROCKETS_OUTPUT_FOLDER
18
22
  task.compress = false
19
23
  task.digest = false
20
24
  sprockets.js_compressor = nil
@@ -22,24 +26,97 @@ Sprockets::Standalone::RakeTask.new(:source_assets) do |task, sprockets|
22
26
  end
23
27
 
24
28
  Sprockets::Standalone::RakeTask.new(:minified_assets) do |task, sprockets|
25
- task.assets = Unpoly::Assets::MANIFESTS
26
- task.sources = Unpoly::Assets::SOURCES
27
- task.output = Unpoly::Assets::OUTPUT
29
+ task.assets = Unpoly::Tasks::SPROCKETS_MANIFESTS
30
+ task.sources = Unpoly::Tasks::SPROCKETS_SOURCES
31
+ task.output = Unpoly::Tasks::SPROCKETS_OUTPUT_FOLDER
28
32
  task.compress = false
29
33
  task.digest = false
30
34
  sprockets.js_compressor = :uglifier
31
35
  sprockets.css_compressor = :sass
32
36
  end
33
37
 
34
- namespace :assets do
35
- desc 'Compile assets for Bower and manual download'
36
- task :compile do
38
+ namespace :publish do
39
+ desc 'Build release artifacts'
40
+ task :build do
37
41
  Rake::Task['minified_assets:compile'].invoke
38
- Unpoly::Assets::MANIFESTS.each do |manifest|
42
+ Unpoly::Tasks::SPROCKETS_MANIFESTS.each do |manifest|
39
43
  source = "dist/#{manifest}"
40
44
  target = "dist/#{manifest.sub(/\.([^\.]+)$/, '.min.\\1')}"
41
45
  File.rename(source, target)
42
46
  end
43
47
  Rake::Task['source_assets:compile'].invoke
48
+ Rake::Task['npm:bump_version'].invoke
44
49
  end
50
+
51
+ desc 'Commit and push build release artifacts'
52
+ task :commit do
53
+ commands = [
54
+ "git add #{Unpoly::Tasks::SPROCKETS_OUTPUT_FOLDER}",
55
+ "git add #{Unpoly::Tasks::NPM_MANIFEST}",
56
+ "git commit -m 'Release artifacts for version #{Unpoly::Rails::VERSION}'",
57
+ "git push"
58
+ ]
59
+ commands.each do |command|
60
+ system(command) or raise "Error running command: #{command}"
61
+ end
62
+ end
63
+
64
+ desc 'Release new version to all package managers'
65
+ task :release do
66
+ Rake::Task['release'].invoke
67
+ Rake::Task['npm:publish'].invoke
68
+ end
69
+
45
70
  end
71
+
72
+ namespace :npm do
73
+
74
+ task :bump_version do
75
+ data = File.read(Unpoly::Tasks::NPM_MANIFEST)
76
+ json = JSON.load(data)
77
+ # Sanity-check the parsed JSON
78
+ json['version'] or raise 'No "version" key found in package.json'
79
+ json['version'] = Unpoly::Rails::VERSION
80
+ data = JSON.pretty_generate(json)
81
+ File.open(Unpoly::Tasks::NPM_MANIFEST, 'w') do |file|
82
+ file.write data
83
+ end
84
+ end
85
+
86
+ task :publish do
87
+ system('npm publish') or raise 'Could not publish NPM module'
88
+ end
89
+
90
+ end
91
+
92
+
93
+
94
+ # Rake::Task["assets:compile"].clear_comments
95
+
96
+ Rake::Task.tasks.each do |task|
97
+ unless Unpoly::Tasks::VISIBLE_TASKS.include?(task.name)
98
+ task.clear_comments
99
+ end
100
+ end
101
+
102
+
103
+
104
+ # namespace :publish do
105
+ #
106
+ # task :rubygems_and_bower do
107
+ # # This pushes a tag for the current version (Bower),
108
+ # # then builds a .gem and pushes it to Rubygems
109
+ # Rake::Task['release'].invoke
110
+ # end
111
+ #
112
+ # task :npm do
113
+ #
114
+ # end
115
+ #
116
+ # desc ''
117
+ # task :all do
118
+ # Rake::Task['publish:rubygems_and_bower'].invoke
119
+ # Rake::Task['publish:npm'].invoke
120
+ # end
121
+ #
122
+ # end
@@ -1,2 +1,11 @@
1
1
  .up-modal-content {
2
2
  padding: 0; }
3
+
4
+ .up-modal[up-flavor='drawer'] .up-modal-content {
5
+ border-radius: 0;
6
+ border-top: none;
7
+ border-bottom: none; }
8
+ .up-modal[up-flavor='drawer'][up-position='left'] .up-modal-content {
9
+ border-left: none; }
10
+ .up-modal[up-flavor='drawer'][up-position='right'] .up-modal-content {
11
+ border-right: none; }
@@ -1 +1 @@
1
- .up-modal-content{padding:0}
1
+ .up-modal-content{padding:0}.up-modal[up-flavor='drawer'] .up-modal-content{border-radius:0;border-top:none;border-bottom:none}.up-modal[up-flavor='drawer'][up-position='left'] .up-modal-content{border-left:none}.up-modal[up-flavor='drawer'][up-position='right'] .up-modal-content{border-right:none}
data/dist/unpoly.css CHANGED
@@ -65,6 +65,17 @@
65
65
  font-size: 34px;
66
66
  color: #666;
67
67
  cursor: pointer; }
68
+
69
+ .up-modal[up-flavor='drawer'] .up-modal-viewport {
70
+ text-align: left; }
71
+ .up-modal[up-flavor='drawer'][up-position='right'] .up-modal-viewport {
72
+ text-align: right; }
73
+ .up-modal[up-flavor='drawer'] .up-modal-dialog {
74
+ margin: 0;
75
+ max-width: 350px; }
76
+ .up-modal[up-flavor='drawer'] .up-modal-content {
77
+ min-height: 100vh;
78
+ box-sizing: border-box; }
68
79
  .up-popup {
69
80
  z-index: 20000;
70
81
  position: absolute;
data/dist/unpoly.js CHANGED
@@ -1,11 +1,15 @@
1
+ (function() {
2
+ var world;
1
3
 
2
- /**
3
- @module up
4
- */
4
+ world = typeof global !== 'undefined' ? global : this;
5
5
 
6
- (function() {
7
- window.up = {
8
- version: "0.30.0"
6
+
7
+ /**
8
+ @module up
9
+ */
10
+
11
+ world.up = {
12
+ version: "0.31.1"
9
13
  };
10
14
 
11
15
  }).call(this);
@@ -32,7 +36,7 @@ that might save you from loading something like [Underscore.js](http://underscor
32
36
  @function up.util.noop
33
37
  @experimental
34
38
  */
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, sequence, setMissingAttrs, setTimer, submittedValue, temporaryCss, times, titleFromXhr, toArray, trim, unJQuery, uniq, unresolvableDeferred, unresolvablePromise, unwrapElement, whenReady;
39
+ 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, evalOption, except, extend, extractOptions, fail, findWithSelf, finishCssAnimate, fixedToAbsolute, forceCompositing, forceRepaint, horizontalScreenHalf, 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, openConfig, option, options, parseUrl, pluckData, pluckKey, presence, presentAttr, previewable, promiseTimer, reject, remove, requestDataAsArray, requestDataAsQuery, requestDataFromForm, resolvableWhen, resolvedDeferred, resolvedPromise, scrollbarWidth, select, selectorForElement, sequence, setMissingAttrs, setTimer, submittedValue, temporaryCss, times, titleFromXhr, toArray, trim, unJQuery, uniq, unresolvableDeferred, unresolvablePromise, unwrapElement, whenReady;
36
40
  noop = $.noop;
37
41
 
38
42
  /**
@@ -925,7 +929,8 @@ that might save you from loading something like [Underscore.js](http://underscor
925
929
  if (millis > 0) {
926
930
  return setTimeout(callback, millis);
927
931
  } else {
928
- return callback();
932
+ callback();
933
+ return void 0;
929
934
  }
930
935
  };
931
936
 
@@ -1588,6 +1593,23 @@ that might save you from loading something like [Underscore.js](http://underscor
1588
1593
  return obj;
1589
1594
  };
1590
1595
 
1596
+ /**
1597
+ If the given `value` is a function, calls the function with the given `args`.
1598
+ Otherwise it just returns `value`.
1599
+
1600
+ @function up.util.evalOption
1601
+ @internal
1602
+ */
1603
+ evalOption = function() {
1604
+ var args, value;
1605
+ value = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
1606
+ if (isFunction(value)) {
1607
+ return value.apply(null, args);
1608
+ } else {
1609
+ return value;
1610
+ }
1611
+ };
1612
+
1591
1613
  /**
1592
1614
  @function up.util.cache
1593
1615
  @param {Number|Function} [config.size]
@@ -1604,26 +1626,17 @@ that might save you from loading something like [Underscore.js](http://underscor
1604
1626
  @internal
1605
1627
  */
1606
1628
  cache = function(config) {
1607
- var alias, clear, expiryMillis, get, isEnabled, isFresh, keys, log, makeRoomForAnotherKey, maxKeys, normalizeStoreKey, optionEvaluator, set, store, timestamp;
1629
+ var alias, clear, expiryMillis, get, isEnabled, isFresh, keys, log, makeRoomForAnotherKey, maxKeys, normalizeStoreKey, set, store, timestamp;
1608
1630
  if (config == null) {
1609
1631
  config = {};
1610
1632
  }
1611
1633
  store = void 0;
1612
- optionEvaluator = function(name) {
1613
- return function() {
1614
- var value;
1615
- value = config[name];
1616
- if (isNumber(value)) {
1617
- return value;
1618
- } else if (isFunction(value)) {
1619
- return value();
1620
- } else {
1621
- return void 0;
1622
- }
1623
- };
1634
+ maxKeys = function() {
1635
+ return evalOption(config.size);
1636
+ };
1637
+ expiryMillis = function() {
1638
+ return evalOption(config.expiry);
1624
1639
  };
1625
- maxKeys = optionEvaluator('size');
1626
- expiryMillis = optionEvaluator('expiry');
1627
1640
  normalizeStoreKey = function(key) {
1628
1641
  if (config.key) {
1629
1642
  return config.key(key);
@@ -1746,9 +1759,25 @@ that might save you from loading something like [Underscore.js](http://underscor
1746
1759
 
1747
1760
  /**
1748
1761
  @function up.util.config
1762
+ @param {Object|Function} blueprint
1763
+ Default configuration options.
1764
+ Will be restored by calling `reset` on the returned object.
1765
+ @return {Object}
1766
+ An object with a `reset` function.
1749
1767
  @internal
1750
1768
  */
1751
1769
  config = function(blueprint) {
1770
+ var hash;
1771
+ hash = openConfig(blueprint);
1772
+ Object.preventExtensions(hash);
1773
+ return hash;
1774
+ };
1775
+
1776
+ /**
1777
+ @function up.util.openConfig
1778
+ @internal
1779
+ */
1780
+ openConfig = function(blueprint) {
1752
1781
  var hash;
1753
1782
  if (blueprint == null) {
1754
1783
  blueprint = {};
@@ -1763,7 +1792,6 @@ that might save you from loading something like [Underscore.js](http://underscor
1763
1792
  return extend(hash, newOptions);
1764
1793
  };
1765
1794
  hash.reset();
1766
- Object.preventExtensions(hash);
1767
1795
  return hash;
1768
1796
  };
1769
1797
 
@@ -2075,6 +2103,9 @@ that might save you from loading something like [Underscore.js](http://underscor
2075
2103
  The proxy's `.promise` attribute is available even before the function is called
2076
2104
  and will resolve when the inner function's returned promise resolves.
2077
2105
 
2106
+ If the inner function does not return a promise, the proxy's `.promise` attribute
2107
+ will resolve as soon as the inner function returns.
2108
+
2078
2109
  @function up.util.previewable
2079
2110
  @internal
2080
2111
  */
@@ -2082,11 +2113,17 @@ that might save you from loading something like [Underscore.js](http://underscor
2082
2113
  var deferred, preview;
2083
2114
  deferred = $.Deferred();
2084
2115
  preview = function() {
2085
- var args;
2116
+ var args, funValue;
2086
2117
  args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
2087
- return fun.apply(null, args).then(function() {
2088
- return deferred.resolve();
2089
- });
2118
+ funValue = fun.apply(null, args);
2119
+ if (isPromise(funValue)) {
2120
+ funValue.then(function() {
2121
+ return deferred.resolve(funValue);
2122
+ });
2123
+ } else {
2124
+ deferred.resolve(funValue);
2125
+ }
2126
+ return funValue;
2090
2127
  };
2091
2128
  preview.promise = deferred.promise();
2092
2129
  return preview;
@@ -2184,6 +2221,42 @@ that might save you from loading something like [Underscore.js](http://underscor
2184
2221
  });
2185
2222
  };
2186
2223
  };
2224
+
2225
+ /**
2226
+ @function up.util.promiseTimer
2227
+ @internal
2228
+ */
2229
+ promiseTimer = function(ms) {
2230
+ var deferred, timeout;
2231
+ deferred = $.Deferred();
2232
+ timeout = setTimer(ms, function() {
2233
+ return deferred.resolve();
2234
+ });
2235
+ deferred.cancel = function() {
2236
+ return clearTimeout(timeout);
2237
+ };
2238
+ return deferred;
2239
+ };
2240
+
2241
+ /**
2242
+ Returns `'left'` if the center of the given element is in the left 50% of the screen.
2243
+ Otherwise returns `'right'`.
2244
+
2245
+ @function up.util.horizontalScreenHalf
2246
+ @internal
2247
+ */
2248
+ horizontalScreenHalf = function($element) {
2249
+ var elementDims, elementMid, screenDims, screenMid;
2250
+ elementDims = measure($element);
2251
+ screenDims = clientSize();
2252
+ elementMid = elementDims.left + 0.5 * elementDims.width;
2253
+ screenMid = 0.5 * screenDims.width;
2254
+ if (elementMid < screenMid) {
2255
+ return 'left';
2256
+ } else {
2257
+ return 'right';
2258
+ }
2259
+ };
2187
2260
  return {
2188
2261
  isDetached: isDetached,
2189
2262
  requestDataAsArray: requestDataAsArray,
@@ -2275,6 +2348,7 @@ that might save you from loading something like [Underscore.js](http://underscor
2275
2348
  scrollbarWidth: scrollbarWidth,
2276
2349
  documentHasVerticalScrollbar: documentHasVerticalScrollbar,
2277
2350
  config: config,
2351
+ openConfig: openConfig,
2278
2352
  cache: cache,
2279
2353
  unwrapElement: unwrapElement,
2280
2354
  multiSelector: multiSelector,
@@ -2290,7 +2364,11 @@ that might save you from loading something like [Underscore.js](http://underscor
2290
2364
  escapeHtml: escapeHtml,
2291
2365
  DivertibleChain: DivertibleChain,
2292
2366
  submittedValue: submittedValue,
2293
- sequence: sequence
2367
+ sequence: sequence,
2368
+ promiseTimer: promiseTimer,
2369
+ previewable: previewable,
2370
+ evalOption: evalOption,
2371
+ horizontalScreenHalf: horizontalScreenHalf
2294
2372
  };
2295
2373
  })($);
2296
2374
 
@@ -6095,7 +6173,7 @@ You can define custom animations using [`up.transition`](/up.transition) and
6095
6173
  $element = $(elementOrSelector);
6096
6174
  finish($element);
6097
6175
  options = animateOptions(options);
6098
- if (animation === 'none' || animation === false) {
6176
+ if (animation === 'none' || animation === false || u.isMissing(animation)) {
6099
6177
  return none();
6100
6178
  } else if (u.isFunction(animation)) {
6101
6179
  return assertIsDeferred(animation($element, options), animation);
@@ -8082,62 +8160,47 @@ open dialogs with sub-forms, etc. all without losing form state.
8082
8160
  delay = u.option($fields.attr('up-delay'), options.delay, config.observeDelay);
8083
8161
  delay = parseInt(delay);
8084
8162
  destructors = u.map($fields, function(field) {
8085
- return observeField($(field), options, callback);
8163
+ return observeField($(field), delay, callback);
8086
8164
  });
8087
8165
  return u.sequence.apply(u, destructors);
8088
8166
  };
8089
8167
  observeField = function($field, delay, callback) {
8090
- var callbackPromise, callbackTimer, changeEvents, check, clearTimer, knownValue, nextCallback, runNextCallback;
8091
- knownValue = null;
8092
- callbackTimer = null;
8093
- callbackPromise = u.resolvedPromise();
8094
- nextCallback = null;
8095
- runNextCallback = function() {
8096
- var returnValue;
8097
- if (nextCallback) {
8098
- returnValue = nextCallback();
8099
- nextCallback = null;
8100
- return returnValue;
8168
+ var changeEvents, check, lastCallbackDone, processedValue, runCallback, timer;
8169
+ processedValue = u.submittedValue($field);
8170
+ timer = void 0;
8171
+ lastCallbackDone = u.resolvedPromise();
8172
+ runCallback = function(value) {
8173
+ var callbackReturnValue;
8174
+ processedValue = value;
8175
+ callbackReturnValue = callback.apply($field.get(0), [value, $field]);
8176
+ if (u.isPromise(callbackReturnValue)) {
8177
+ return lastCallbackDone = callbackReturnValue;
8178
+ } else {
8179
+ return lastCallbackDone = callbackReturnValue;
8101
8180
  }
8102
8181
  };
8103
8182
  check = function() {
8104
- var runAndChain, skipCallback, value;
8183
+ var nextCallback, value;
8105
8184
  value = u.submittedValue($field);
8106
- skipCallback = u.isNull(knownValue);
8107
- if (knownValue !== value) {
8108
- knownValue = value;
8109
- if (!skipCallback) {
8110
- clearTimer();
8111
- nextCallback = function() {
8112
- return callback.apply($field.get(0), [value, $field]);
8113
- };
8114
- runAndChain = function() {
8115
- return callbackPromise.then(function() {
8116
- var returnValue;
8117
- returnValue = runNextCallback();
8118
- if (u.isPromise(returnValue)) {
8119
- return callbackPromise = returnValue;
8120
- } else {
8121
- return callbackPromise = u.resolvedPromise();
8122
- }
8123
- });
8124
- };
8125
- return u.setTimer(delay, runAndChain);
8185
+ if (processedValue !== value) {
8186
+ nextCallback = function() {
8187
+ return runCallback(value);
8188
+ };
8189
+ if (timer != null) {
8190
+ timer.cancel();
8126
8191
  }
8192
+ timer = u.promiseTimer(delay);
8193
+ return $.when(timer, lastCallbackDone).then(nextCallback);
8127
8194
  }
8128
8195
  };
8129
- clearTimer = function() {
8130
- return clearTimeout(callbackTimer);
8131
- };
8132
8196
  changeEvents = 'input change';
8133
8197
  if (!up.browser.canInputEvent()) {
8134
8198
  changeEvents += ' keypress paste cut click propertychange';
8135
8199
  }
8136
8200
  $field.on(changeEvents, check);
8137
- check();
8138
8201
  return function() {
8139
8202
  $field.off(changeEvents, check);
8140
- return clearTimer();
8203
+ return timer != null ? timer.cancel() : void 0;
8141
8204
  };
8142
8205
  };
8143
8206
 
@@ -8714,7 +8777,7 @@ open dialogs with sub-forms, etc. all without losing form state.
8714
8777
  but not if the checkbox was changed:
8715
8778
 
8716
8779
  <form method="GET" action="/search">
8717
- <input type="search" name="query" autosubmit>
8780
+ <input type="search" name="query" up-autosubmit>
8718
8781
  <input type="checkbox"> Include archive
8719
8782
  </form>
8720
8783
 
@@ -9170,6 +9233,9 @@ The HTML of a popup element is simply this:
9170
9233
  <a href="/settings" up-popup=".options" up-sticky>Settings</a>
9171
9234
 
9172
9235
  @selector [up-popup]
9236
+ @param {String} up-popup
9237
+ The CSS selector that will be extracted from the response and
9238
+ displayed in a popup overlay.
9173
9239
  @param [up-position]
9174
9240
  Defines where the popup is attached to the opening element.
9175
9241
 
@@ -9316,7 +9382,7 @@ or function.
9316
9382
 
9317
9383
  (function() {
9318
9384
  up.modal = (function($) {
9319
- var animate, autoclose, chain, closeAsap, closeNow, config, contains, createFrame, discardHistory, extractAsap, flavor, flavorDefault, flavorOverrides, followAsap, isOpen, markAsAnimating, openAsap, openNow, reset, shiftElements, state, templateHtml, u, unshiftElements, visitAsap;
9385
+ var animate, autoclose, chain, closeAsap, closeNow, config, contains, createFrame, discardHistory, extractAsap, flavor, flavorDefault, flavorOverrides, flavors, followAsap, isOpen, markAsAnimating, openAsap, openNow, reset, shiftElements, state, templateHtml, u, unshiftElements, visitAsap;
9320
9386
  u = up.util;
9321
9387
 
9322
9388
  /**
@@ -9375,6 +9441,8 @@ or function.
9375
9441
  @param {Boolean} [options.sticky=false]
9376
9442
  If set to `true`, the modal remains
9377
9443
  open even it changes the page in the background.
9444
+ @param {String} [options.flavor='default']
9445
+ The default [flavor](/up.modal.flavors).
9378
9446
  @stable
9379
9447
  */
9380
9448
  config = u.config({
@@ -9394,14 +9462,55 @@ or function.
9394
9462
  closeLabel: '×',
9395
9463
  closable: true,
9396
9464
  sticky: false,
9397
- flavors: {
9398
- "default": {}
9399
- },
9400
- template: function(config) {
9401
- return "<div class=\"up-modal\">\n <div class=\"up-modal-backdrop\"></div>\n <div class=\"up-modal-viewport\">\n <div class=\"up-modal-dialog\">\n <div class=\"up-modal-content\"></div>\n <div class=\"up-modal-close\" up-close>" + (flavorDefault('closeLabel')) + "</div>\n </div>\n </div>\n</div>";
9465
+ flavor: 'default',
9466
+ position: null,
9467
+ template: function(options) {
9468
+ return "<div class=\"up-modal\">\n <div class=\"up-modal-backdrop\"></div>\n <div class=\"up-modal-viewport\">\n <div class=\"up-modal-dialog\">\n <div class=\"up-modal-content\"></div>\n <div class=\"up-modal-close\" up-close>" + options.closeLabel + "</div>\n </div>\n </div>\n</div>";
9402
9469
  }
9403
9470
  });
9404
9471
 
9472
+ /**
9473
+ Define modal variants with their own default configuration, CSS or HTML template.
9474
+
9475
+ \#\#\# Example
9476
+
9477
+ Unpoly's [`[up-drawer]`](/up-drawer) is implemented as a modal flavor:
9478
+
9479
+ up.modal.flavors.drawer = {
9480
+ openAnimation: 'move-from-right',
9481
+ closeAnimation: 'move-to-right'
9482
+ }
9483
+
9484
+ Modals with that flavor will have a container with an `up-flavor` attribute:
9485
+
9486
+ <div class='up-modal' up-flavor='drawer'>
9487
+ ...
9488
+ </div>
9489
+
9490
+ We can target the `up-flavor` attribute to override the default dialog styles:
9491
+
9492
+ .up-modal[up-flavor='drawer'] {
9493
+
9494
+ .up-modal-dialog {
9495
+ margin: 0; // Remove margin so drawer starts at the screen edge
9496
+ max-width: 350px; // Set drawer size
9497
+ }
9498
+
9499
+ .up-modal-content {
9500
+ min-height: 100vh; // Stretch background to full window height
9501
+ }
9502
+ }
9503
+
9504
+ @property up.modal.flavors
9505
+ @param {Object} flavors
9506
+ An object where the keys are flavor names (e.g. `'drawer') and
9507
+ the values are the respective default configurations.
9508
+ @experimental
9509
+ */
9510
+ flavors = u.openConfig({
9511
+ "default": {}
9512
+ });
9513
+
9405
9514
  /**
9406
9515
  Returns the source URL for the fragment displayed in the current modal overlay,
9407
9516
  or `undefined` if no modal is currently open.
@@ -9430,6 +9539,7 @@ or function.
9430
9539
  url: null,
9431
9540
  coveredUrl: null,
9432
9541
  coveredTitle: null,
9542
+ position: null,
9433
9543
  unshifters: []
9434
9544
  };
9435
9545
  });
@@ -9442,16 +9552,15 @@ or function.
9442
9552
  unshiftElements();
9443
9553
  state.reset();
9444
9554
  chain.reset();
9445
- return config.reset();
9555
+ config.reset();
9556
+ return flavors.reset();
9446
9557
  };
9447
9558
  templateHtml = function() {
9448
9559
  var template;
9449
9560
  template = flavorDefault('template');
9450
- if (u.isFunction(template)) {
9451
- return template(config);
9452
- } else {
9453
- return template;
9454
- }
9561
+ return u.evalOption(template, {
9562
+ closeLabel: flavorDefault('closeLabel')
9563
+ });
9455
9564
  };
9456
9565
  discardHistory = function() {
9457
9566
  state.coveredTitle = null;
@@ -9461,6 +9570,9 @@ or function.
9461
9570
  var $content, $dialog, $modal;
9462
9571
  $modal = $(templateHtml());
9463
9572
  $modal.attr('up-flavor', state.flavor);
9573
+ if (u.isPresent(state.position)) {
9574
+ $modal.attr('up-position', state.position);
9575
+ }
9464
9576
  $dialog = $modal.find('.up-modal-dialog');
9465
9577
  if (u.isPresent(options.width)) {
9466
9578
  $dialog.css('width', options.width);
@@ -9664,12 +9776,22 @@ or function.
9664
9776
  url = u.option(u.pluckKey(options, 'url'), $link.attr('up-href'), $link.attr('href'));
9665
9777
  html = u.option(u.pluckKey(options, 'html'));
9666
9778
  target = u.option(u.pluckKey(options, 'target'), $link.attr('up-modal'), 'body');
9667
- options.flavor = u.option(options.flavor, $link.attr('up-flavor'));
9779
+ options.flavor = u.option(options.flavor, $link.attr('up-flavor'), config.flavor);
9780
+ options.position = u.option(options.position, $link.attr('up-position'), flavorDefault('position', options.flavor));
9781
+ options.position = u.evalOption(options.position, {
9782
+ $link: $link
9783
+ });
9668
9784
  options.width = u.option(options.width, $link.attr('up-width'), flavorDefault('width', options.flavor));
9669
9785
  options.maxWidth = u.option(options.maxWidth, $link.attr('up-max-width'), flavorDefault('maxWidth', options.flavor));
9670
9786
  options.height = u.option(options.height, $link.attr('up-height'), flavorDefault('height'));
9671
9787
  options.animation = u.option(options.animation, $link.attr('up-animation'), flavorDefault('openAnimation', options.flavor));
9788
+ options.animation = u.evalOption(options.animation, {
9789
+ position: options.position
9790
+ });
9672
9791
  options.backdropAnimation = u.option(options.backdropAnimation, $link.attr('up-backdrop-animation'), flavorDefault('backdropOpenAnimation', options.flavor));
9792
+ options.backdropAnimation = u.evalOption(options.backdropAnimation, {
9793
+ position: options.position
9794
+ });
9673
9795
  options.sticky = u.option(options.sticky, u.castedAttr($link, 'up-sticky'), flavorDefault('sticky', options.flavor));
9674
9796
  options.closable = u.option(options.closable, u.castedAttr($link, 'up-closable'), flavorDefault('closable', options.flavor));
9675
9797
  options.confirm = u.option(options.confirm, $link.attr('up-confirm'));
@@ -9693,6 +9815,7 @@ or function.
9693
9815
  state.flavor = options.flavor;
9694
9816
  state.sticky = options.sticky;
9695
9817
  state.closable = options.closable;
9818
+ state.position = options.position;
9696
9819
  if (options.history) {
9697
9820
  state.coveredUrl = up.browser.url();
9698
9821
  state.coveredTitle = document.title;
@@ -9769,7 +9892,13 @@ or function.
9769
9892
  }
9770
9893
  options = u.options(options);
9771
9894
  viewportCloseAnimation = u.option(options.animation, flavorDefault('closeAnimation'));
9895
+ viewportCloseAnimation = u.evalOption(viewportCloseAnimation, {
9896
+ position: state.position
9897
+ });
9772
9898
  backdropCloseAnimation = u.option(options.backdropAnimation, flavorDefault('backdropCloseAnimation'));
9899
+ backdropCloseAnimation = u.evalOption(backdropCloseAnimation, {
9900
+ position: state.position
9901
+ });
9773
9902
  animateOptions = up.motion.animateOptions(options, {
9774
9903
  duration: flavorDefault('closeDuration'),
9775
9904
  easing: flavorDefault('closeEasing')
@@ -9798,6 +9927,7 @@ or function.
9798
9927
  state.flavor = null;
9799
9928
  state.sticky = null;
9800
9929
  state.closable = null;
9930
+ state.position = null;
9801
9931
  return up.emit('up:modal:closed', {
9802
9932
  message: 'Modal closed'
9803
9933
  });
@@ -9862,46 +9992,11 @@ or function.
9862
9992
  $element = $(elementOrSelector);
9863
9993
  return $element.closest('.up-modal').length > 0;
9864
9994
  };
9865
-
9866
- /**
9867
- Register a new modal variant with its own default configuration, CSS or HTML template.
9868
-
9869
- \#\#\# Example
9870
-
9871
- Let's implement a drawer that slides in from the right:
9872
-
9873
- up.modal.flavor('drawer', {
9874
- openAnimation: 'move-from-right',
9875
- closeAnimation: 'move-to-right',
9876
- maxWidth: 400
9877
- }
9878
-
9879
- Modals with that flavor will have a container `<div class='up-modal' up-flavor='drawer'>...</div>`.
9880
- We can target the `up-flavor` attribute override the default dialog styles:
9881
-
9882
- .up-modal[up-flavor='drawer'] {
9883
-
9884
- // Align drawer on the right
9885
- .up-modal-viewport { text-align: right; }
9886
-
9887
- // Remove margin so the drawer starts at the screen edge
9888
- .up-modal-dialog { margin: 0; }
9889
-
9890
- // Stretch drawer background to full window height
9891
- .up-modal-content { min-height: 100vh; }
9892
- }
9893
-
9894
- @function up.modal.flavor
9895
- @param {String} name
9896
- The name of the new flavor.
9897
- @param {Object} [overrideConfig]
9898
- An object whose properties override the defaults in [`/up.modal.config`](/up.modal.config).
9899
- @experimental
9900
- */
9901
9995
  flavor = function(name, overrideConfig) {
9902
9996
  if (overrideConfig == null) {
9903
9997
  overrideConfig = {};
9904
9998
  }
9999
+ up.log.warn('The up.modal.flavor function is deprecated. Use the up.modal.flavors property instead.');
9905
10000
  return u.extend(flavorOverrides(name), overrideConfig);
9906
10001
  };
9907
10002
 
@@ -9914,8 +10009,7 @@ or function.
9914
10009
  @internal
9915
10010
  */
9916
10011
  flavorOverrides = function(flavor) {
9917
- var base;
9918
- return (base = config.flavors)[flavor] || (base[flavor] = {});
10012
+ return flavors[flavor] || (flavors[flavor] = {});
9919
10013
  };
9920
10014
 
9921
10015
  /**
@@ -9942,16 +10036,18 @@ or function.
9942
10036
  Clicking this link will load the destination via AJAX and open
9943
10037
  the given selector in a modal dialog.
9944
10038
 
9945
- Example:
10039
+ \#\#\#\# Example
9946
10040
 
9947
10041
  <a href="/blogs" up-modal=".blog-list">Switch blog</a>
9948
10042
 
9949
10043
  Clicking would request the path `/blog` and select `.blog-list` from
9950
- the HTML response. Unpoly will dim the page with an overlay
10044
+ the HTML response. Unpoly will dim the page
9951
10045
  and place the matching `.blog-list` tag will be placed in
9952
10046
  a modal dialog.
9953
10047
 
9954
10048
  @selector [up-modal]
10049
+ @param {String} up-modal
10050
+ The CSS selector that will be extracted from the response and displayed in a modal dialog.
9955
10051
  @param {String} [up-confirm]
9956
10052
  A message that will be displayed in a cancelable confirmation dialog
9957
10053
  before the modal is opened.
@@ -10033,6 +10129,77 @@ or function.
10033
10129
  return up.bus.consumeAction(event);
10034
10130
  }
10035
10131
  });
10132
+
10133
+ /**
10134
+ Clicking this link will load the destination via AJAX and open
10135
+ the given selector in a modal drawer that slides in from the edge of the screen.
10136
+
10137
+ You can configure drawers using the [`up.modal.flavors.drawer`](/up.modal.flavors.drawer) property.
10138
+
10139
+ \#\#\#\# Example
10140
+
10141
+ <a href="/blogs" up-drawer=".blog-list">Switch blog</a>
10142
+
10143
+ Clicking would request the path `/blog` and select `.blog-list` from
10144
+ the HTML response. Unpoly will dim the page
10145
+ and place the matching `.blog-list` tag will be placed in
10146
+ a modal drawer.
10147
+
10148
+ @selector [up-drawer]
10149
+ @param {String} up-drawer
10150
+ The CSS selector to extract from the response and open in the drawer.
10151
+ @param {String} [up-position='auto']
10152
+ The side from which the drawer slides in.
10153
+
10154
+ Valid values are `'left'`, `'right'` and `'auto'`. If set to `'auto'`, the
10155
+ drawer will slide in from left if the opening link is on the left half of the screen.
10156
+ Otherwise it will slide in from the right.
10157
+ @experimental
10158
+ */
10159
+ up.macro('[up-drawer]', function($link) {
10160
+ var target;
10161
+ target = $link.attr('up-drawer');
10162
+ return $link.attr({
10163
+ 'up-modal': target,
10164
+ 'up-flavor': 'drawer'
10165
+ });
10166
+ });
10167
+
10168
+ /**
10169
+ Sets default options for future drawers.
10170
+
10171
+ @property up.modal.flavors.drawer
10172
+ @param {Object} config
10173
+ Default options for future drawers.
10174
+
10175
+ See [`up.modal.config`] for available options.
10176
+ @experimental
10177
+ */
10178
+ flavors.drawer = {
10179
+ openAnimation: function(options) {
10180
+ switch (options.position) {
10181
+ case 'left':
10182
+ return 'move-from-left';
10183
+ case 'right':
10184
+ return 'move-from-right';
10185
+ }
10186
+ },
10187
+ closeAnimation: function(options) {
10188
+ switch (options.position) {
10189
+ case 'left':
10190
+ return 'move-to-left';
10191
+ case 'right':
10192
+ return 'move-to-right';
10193
+ }
10194
+ },
10195
+ position: function(options) {
10196
+ if (u.isPresent(options.$link)) {
10197
+ return u.horizontalScreenHalf(options.$link);
10198
+ } else {
10199
+ return 'left';
10200
+ }
10201
+ }
10202
+ };
10036
10203
  up.on('up:framework:reset', reset);
10037
10204
  return {
10038
10205
  knife: eval(typeof Knife !== "undefined" && Knife !== null ? Knife.point : void 0),
@@ -10047,6 +10214,7 @@ or function.
10047
10214
  return state.coveredUrl;
10048
10215
  },
10049
10216
  config: config,
10217
+ flavors: flavors,
10050
10218
  contains: contains,
10051
10219
  isOpen: isOpen,
10052
10220
  flavor: flavor