unpoly-rails 0.31.0 → 0.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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