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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -1
- data/dist/unpoly.css +29 -21
- data/dist/unpoly.js +291 -134
- data/dist/unpoly.min.css +1 -1
- data/dist/unpoly.min.js +3 -3
- data/lib/assets/javascripts/unpoly.js.coffee +1 -0
- data/lib/assets/javascripts/unpoly/browser.js.coffee +22 -5
- data/lib/assets/javascripts/unpoly/bus.js.coffee +1 -1
- data/lib/assets/javascripts/unpoly/flow.js.coffee +9 -6
- data/lib/assets/javascripts/unpoly/form.js.coffee +46 -49
- data/lib/assets/javascripts/unpoly/history.js.coffee +2 -2
- data/lib/assets/javascripts/unpoly/layout.js.coffee +3 -3
- data/lib/assets/javascripts/unpoly/modal.js.coffee +30 -2
- data/lib/assets/javascripts/unpoly/motion.js.coffee +6 -6
- data/lib/assets/javascripts/unpoly/navigation.js.coffee +1 -1
- data/lib/assets/javascripts/unpoly/popup.js.coffee +2 -2
- data/lib/assets/javascripts/unpoly/proxy.js.coffee +5 -9
- data/lib/assets/javascripts/unpoly/syntax.js.coffee +10 -6
- data/lib/assets/javascripts/unpoly/toast.js.coffee +66 -0
- data/lib/assets/javascripts/unpoly/tooltip.js.coffee +1 -1
- data/lib/assets/javascripts/unpoly/util.js.coffee +47 -21
- data/lib/assets/stylesheets/unpoly/toast.css.sass +33 -0
- data/lib/unpoly/rails/version.rb +1 -1
- data/spec_app/Gemfile.lock +1 -1
- data/spec_app/app/assets/javascripts/integration_test.coffee +1 -0
- data/spec_app/app/assets/stylesheets/integration_test.sass +14 -0
- data/spec_app/app/controllers/application_controller.rb +8 -0
- data/spec_app/app/controllers/error_test_controller.rb +5 -0
- data/spec_app/app/views/error_test/trigger.erb +72 -0
- data/spec_app/app/views/error_test/unexpected_response.erb +3 -0
- data/spec_app/app/views/pages/start.erb +4 -0
- data/spec_app/config/routes.rb +2 -0
- data/spec_app/spec/javascripts/helpers/last_request.js.coffee +1 -1
- data/spec_app/spec/javascripts/up/browser_spec.js.coffee +62 -0
- data/spec_app/spec/javascripts/up/form_spec.js.coffee +116 -3
- data/spec_app/spec/javascripts/up/link_spec.js.coffee +2 -2
- data/spec_app/spec/javascripts/up/modal_spec.js.coffee +88 -4
- data/spec_app/spec/javascripts/up/syntax_spec.js.coffee +27 -1
- data/spec_app/spec/javascripts/up/util_spec.js.coffee +12 -0
- metadata +8 -3
- data/lib/assets/stylesheets/unpoly/error.css.sass +0 -21
@@ -182,7 +182,7 @@ up.motion = (($) ->
|
|
182
182
|
$element.css(animation)
|
183
183
|
u.resolvedDeferred()
|
184
184
|
else
|
185
|
-
|
185
|
+
up.fail("Unknown animation type for %o", animation)
|
186
186
|
|
187
187
|
###*
|
188
188
|
Extracts animation-related options from the given options hash.
|
@@ -203,7 +203,7 @@ up.motion = (($) ->
|
|
203
203
|
consolidatedOptions
|
204
204
|
|
205
205
|
findAnimation = (name) ->
|
206
|
-
animations[name] or
|
206
|
+
animations[name] or up.fail("Unknown animation %o", name)
|
207
207
|
|
208
208
|
GHOSTING_DEFERRED_KEY = 'up-ghosting-deferred'
|
209
209
|
GHOSTING_CLASS = 'up-ghosting'
|
@@ -302,7 +302,7 @@ up.motion = (($) ->
|
|
302
302
|
if u.isDeferred(object)
|
303
303
|
object
|
304
304
|
else
|
305
|
-
|
305
|
+
up.fail("Did not return a promise with .then and .resolve methods: %o", source)
|
306
306
|
|
307
307
|
###*
|
308
308
|
Performs an animated transition between two elements.
|
@@ -407,14 +407,14 @@ up.motion = (($) ->
|
|
407
407
|
)
|
408
408
|
return morph($old, $new, transition, parsedOptions)
|
409
409
|
else
|
410
|
-
|
410
|
+
up.fail("Unknown transition %o", transitionOrName)
|
411
411
|
else
|
412
412
|
return skipMorph($old, $new, parsedOptions)
|
413
413
|
|
414
414
|
ensureMorphable = ($element, transition) ->
|
415
415
|
if transition && $element.parents('body').length == 0
|
416
416
|
element = $element.get(0)
|
417
|
-
|
417
|
+
up.fail("Can't morph a <%s> element (%o)", element.tagName, element)
|
418
418
|
|
419
419
|
###*
|
420
420
|
This causes the side effects of a successful transition, but instantly.
|
@@ -724,7 +724,7 @@ up.motion = (($) ->
|
|
724
724
|
animation: animation
|
725
725
|
config: config
|
726
726
|
isEnabled: isEnabled
|
727
|
-
defaults: ->
|
727
|
+
defaults: -> up.fail('up.motion.defaults(...) no longer exists. Set values on he up.motion.config property instead.')
|
728
728
|
none: none
|
729
729
|
when: resolvableWhen
|
730
730
|
prependCopy: prependCopy
|
@@ -221,7 +221,7 @@ up.navigation = (($) ->
|
|
221
221
|
up.on 'up:framework:reset', reset
|
222
222
|
|
223
223
|
config: config
|
224
|
-
defaults: ->
|
224
|
+
defaults: -> up.fail('up.navigation.defaults(...) no longer exists. Set values on he up.navigation.config property instead.')
|
225
225
|
markActive: markActive
|
226
226
|
unmarkActive: unmarkActive
|
227
227
|
withActiveMark: withActiveMark
|
@@ -144,7 +144,7 @@ up.popup = (($) ->
|
|
144
144
|
css['top'] = linkBox.top - popupBox.height
|
145
145
|
css['left'] = linkBox.left
|
146
146
|
else
|
147
|
-
|
147
|
+
up.fail("Unknown position option '%s'", state.position)
|
148
148
|
|
149
149
|
state.$popup.attr('up-position', state.position)
|
150
150
|
state.$popup.css(css)
|
@@ -216,7 +216,7 @@ up.popup = (($) ->
|
|
216
216
|
|
217
217
|
attachNow = (elementOrSelector, options) ->
|
218
218
|
$anchor = $(elementOrSelector)
|
219
|
-
$anchor.length or
|
219
|
+
$anchor.length or up.fail('Cannot attach popup to non-existing element %o', elementOrSelector)
|
220
220
|
|
221
221
|
options = u.options(options)
|
222
222
|
url = u.option(u.pluckKey(options, 'url'), $anchor.attr('up-href'), $anchor.attr('href'))
|
@@ -312,16 +312,12 @@ up.proxy = (($) ->
|
|
312
312
|
show = function() { $element.show() };
|
313
313
|
hide = function() { $element.hide() };
|
314
314
|
|
315
|
-
up.on('up:proxy:slow', show);
|
316
|
-
up.on('up:proxy:recover', hide);
|
317
|
-
|
318
315
|
hide();
|
319
316
|
|
320
|
-
|
321
|
-
|
322
|
-
up.
|
323
|
-
|
324
|
-
};
|
317
|
+
return [
|
318
|
+
up.on('up:proxy:slow', show),
|
319
|
+
up.on('up:proxy:recover', hide)
|
320
|
+
];
|
325
321
|
|
326
322
|
});
|
327
323
|
|
@@ -552,7 +548,7 @@ up.proxy = (($) ->
|
|
552
548
|
isBusy: isBusy
|
553
549
|
isCachable: isCachable
|
554
550
|
config: config
|
555
|
-
defaults: ->
|
551
|
+
defaults: -> up.fail('up.proxy.defaults(...) no longer exists. Set values on he up.proxy.config property instead.')
|
556
552
|
|
557
553
|
)(jQuery)
|
558
554
|
|
@@ -101,7 +101,8 @@ up.syntax = (($) ->
|
|
101
101
|
or event handlers bound to the document root.
|
102
102
|
|
103
103
|
Here is a version of `<clock>` that updates
|
104
|
-
the time every second, and cleans up once it's done
|
104
|
+
the time every second, and cleans up once it's done. Note how it returns
|
105
|
+
a function that calls `clearInterval`:
|
105
106
|
|
106
107
|
up.compiler('clock', function($element) {
|
107
108
|
|
@@ -279,10 +280,16 @@ up.syntax = (($) ->
|
|
279
280
|
if compiler.keep
|
280
281
|
value = if u.isString(compiler.keep) then compiler.keep else ''
|
281
282
|
$jqueryElement.attr('up-keep', value)
|
282
|
-
|
283
|
-
if
|
283
|
+
returnValue = compiler.callback.apply(nativeElement, [$jqueryElement, data($jqueryElement)])
|
284
|
+
if destructor = discoverDestructor(returnValue)
|
284
285
|
addDestructor($jqueryElement, destructor)
|
285
286
|
|
287
|
+
discoverDestructor = (returnValue) ->
|
288
|
+
if u.isFunction(returnValue)
|
289
|
+
returnValue
|
290
|
+
else if u.isArray(returnValue) && u.all(returnValue, u.isFunction)
|
291
|
+
u.sequence(returnValue...)
|
292
|
+
|
286
293
|
addDestructor = ($jqueryElement, destructor) ->
|
287
294
|
$jqueryElement.addClass(DESTRUCTABLE_CLASS)
|
288
295
|
destructors = $jqueryElement.data(DESTRUCTORS_KEY) || []
|
@@ -446,6 +453,3 @@ up.syntax = (($) ->
|
|
446
453
|
|
447
454
|
up.compiler = up.syntax.compiler
|
448
455
|
up.macro = up.syntax.macro
|
449
|
-
|
450
|
-
up.ready = -> up.util.error('up.ready no longer exists. Please use up.hello instead.')
|
451
|
-
up.awaken = -> up.util.error('up.awaken no longer exists. Please use up.compiler instead.')
|
@@ -0,0 +1,66 @@
|
|
1
|
+
###*
|
2
|
+
Toast alerts
|
3
|
+
============
|
4
|
+
|
5
|
+
@class up.toast
|
6
|
+
###
|
7
|
+
up.toast = (($) ->
|
8
|
+
|
9
|
+
u = up.util
|
10
|
+
b = up.browser
|
11
|
+
|
12
|
+
VARIABLE_FORMATTER = (arg) -> "<span class='up-toast-variable'>#{u.escapeHtml(arg)}</span>"
|
13
|
+
|
14
|
+
state = u.config
|
15
|
+
$toast: null
|
16
|
+
|
17
|
+
reset = ->
|
18
|
+
close()
|
19
|
+
state.reset()
|
20
|
+
|
21
|
+
messageToHtml = (message) ->
|
22
|
+
if u.isArray(message)
|
23
|
+
message[0] = u.escapeHtml(message[0])
|
24
|
+
message = b.sprintfWithFormattedArgs(VARIABLE_FORMATTER, message...)
|
25
|
+
else
|
26
|
+
message = u.escapeHtml(message)
|
27
|
+
message
|
28
|
+
|
29
|
+
isOpen = ->
|
30
|
+
!!state.$toast
|
31
|
+
|
32
|
+
addAction = ($actions, label, callback) ->
|
33
|
+
$action = $('<span class="up-toast-action"></span>').text(label)
|
34
|
+
$action.on 'click', callback
|
35
|
+
$action.appendTo($actions)
|
36
|
+
|
37
|
+
open = (message, options = {}) ->
|
38
|
+
close()
|
39
|
+
$toast = $('<div class="up-toast"></div>').prependTo('body')
|
40
|
+
$message = $('<div class="up-toast-message"></div>').appendTo($toast)
|
41
|
+
$actions = $('<div class="up-toast-actions"></div>').appendTo($toast)
|
42
|
+
|
43
|
+
message = messageToHtml(message)
|
44
|
+
$message.html(message)
|
45
|
+
|
46
|
+
if action = (options.action || options.inspect)
|
47
|
+
addAction($actions, action.label, action.callback)
|
48
|
+
|
49
|
+
addAction($actions, 'Close', close)
|
50
|
+
|
51
|
+
state.$toast = $toast
|
52
|
+
|
53
|
+
close = ->
|
54
|
+
if isOpen()
|
55
|
+
state.$toast.remove()
|
56
|
+
state.$toast = null
|
57
|
+
|
58
|
+
# The framework is reset between tests
|
59
|
+
up.on 'up:framework:reset', reset
|
60
|
+
|
61
|
+
open: open
|
62
|
+
close: close
|
63
|
+
reset: reset
|
64
|
+
isOpen: isOpen
|
65
|
+
|
66
|
+
)(jQuery)
|
@@ -102,7 +102,7 @@ up.tooltip = (($) ->
|
|
102
102
|
css['top'] = linkBox.top + linkBox.height
|
103
103
|
css['left'] = linkBox.left + 0.5 * (linkBox.width - tooltipBox.width)
|
104
104
|
else
|
105
|
-
|
105
|
+
up.fail("Unknown position option '%s'", state.position)
|
106
106
|
|
107
107
|
state.$tooltip.attr('up-position', state.position)
|
108
108
|
state.$tooltip.css(css)
|
@@ -545,7 +545,7 @@ up.util = (($) ->
|
|
545
545
|
|
546
546
|
Returns the array.
|
547
547
|
|
548
|
-
@function up.util.
|
548
|
+
@function up.util.toArray
|
549
549
|
@param object
|
550
550
|
@return {Array}
|
551
551
|
@stable
|
@@ -1597,7 +1597,7 @@ up.util = (($) ->
|
|
1597
1597
|
if isFormData(data)
|
1598
1598
|
# Until FormData#entries is implemented in all major browsers
|
1599
1599
|
# we must give up here
|
1600
|
-
up.
|
1600
|
+
up.fail('Cannot convert FormData into an array')
|
1601
1601
|
else
|
1602
1602
|
query = requestDataAsQuery(data)
|
1603
1603
|
array = []
|
@@ -1620,7 +1620,7 @@ up.util = (($) ->
|
|
1620
1620
|
if isFormData(data)
|
1621
1621
|
# Until FormData#entries is implemented in all major browsers
|
1622
1622
|
# we must give up here
|
1623
|
-
up.
|
1623
|
+
up.fail('Cannot convert FormData into a query string')
|
1624
1624
|
else if isPresent(data)
|
1625
1625
|
query = $.param(data)
|
1626
1626
|
query = query.replace(/\+/g, '%20')
|
@@ -1672,28 +1672,34 @@ up.util = (($) ->
|
|
1672
1672
|
data
|
1673
1673
|
|
1674
1674
|
###*
|
1675
|
-
Throws
|
1675
|
+
Throws an [exception](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
|
1676
|
+
with the given message.
|
1677
|
+
|
1678
|
+
The message will also be printed to the [error log](/up.log.error).
|
1676
1679
|
|
1677
|
-
|
1678
|
-
- An [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) (exception) will be thrown, unwinding the current call stack
|
1679
|
-
- The error message will be printed in a corner of the screen
|
1680
|
+
Also a notification will be shown at the bottom of the screen.
|
1680
1681
|
|
1681
1682
|
\#\#\#\# Examples
|
1682
1683
|
|
1683
|
-
up.
|
1684
|
-
up.
|
1684
|
+
up.fail('Division by zero')
|
1685
|
+
up.fail('Unexpected result %o', result)
|
1685
1686
|
|
1687
|
+
@function up.fail
|
1686
1688
|
@experimental
|
1687
1689
|
###
|
1688
|
-
|
1689
|
-
|
1690
|
-
|
1691
|
-
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1690
|
+
fail = (args...) ->
|
1691
|
+
if isArray(args[0])
|
1692
|
+
messageArgs = args[0]
|
1693
|
+
toastOptions = args[1] || {}
|
1694
|
+
else
|
1695
|
+
messageArgs = args
|
1696
|
+
toastOptions = {}
|
1697
|
+
|
1698
|
+
up.log.error(messageArgs...)
|
1699
|
+
|
1700
|
+
whenReady().then -> up.toast.open(messageArgs, toastOptions)
|
1701
|
+
|
1702
|
+
asString = up.browser.sprintf(messageArgs...)
|
1697
1703
|
throw new Error(asString)
|
1698
1704
|
|
1699
1705
|
ESCAPE_HTML_ENTITY_MAP =
|
@@ -1816,6 +1822,25 @@ up.util = (($) ->
|
|
1816
1822
|
@queue = map(newTasks, previewable)
|
1817
1823
|
@poke()
|
1818
1824
|
|
1825
|
+
###*
|
1826
|
+
@function up.util.submittedValue
|
1827
|
+
@internal
|
1828
|
+
###
|
1829
|
+
submittedValue = (fieldOrSelector) ->
|
1830
|
+
$field = $(fieldOrSelector)
|
1831
|
+
if $field.is('[type=checkbox], [type=radio]') && !$field.is(':checked')
|
1832
|
+
undefined
|
1833
|
+
else
|
1834
|
+
$field.val()
|
1835
|
+
|
1836
|
+
###*
|
1837
|
+
@function up.util.sequence
|
1838
|
+
@internal
|
1839
|
+
###
|
1840
|
+
sequence: (functions...) ->
|
1841
|
+
->
|
1842
|
+
map functions, (f) -> f()
|
1843
|
+
|
1819
1844
|
isDetached: isDetached
|
1820
1845
|
requestDataAsArray: requestDataAsArray
|
1821
1846
|
requestDataAsQuery: requestDataAsQuery
|
@@ -1838,7 +1863,7 @@ up.util = (($) ->
|
|
1838
1863
|
merge: merge
|
1839
1864
|
options: options
|
1840
1865
|
option: option
|
1841
|
-
|
1866
|
+
fail: fail
|
1842
1867
|
each: each
|
1843
1868
|
map: map
|
1844
1869
|
times: times
|
@@ -1911,7 +1936,7 @@ up.util = (($) ->
|
|
1911
1936
|
cache: cache
|
1912
1937
|
unwrapElement: unwrapElement
|
1913
1938
|
multiSelector: multiSelector
|
1914
|
-
error:
|
1939
|
+
error: fail
|
1915
1940
|
pluckData: pluckData
|
1916
1941
|
pluckKey: pluckKey
|
1917
1942
|
extractOptions: extractOptions
|
@@ -1922,7 +1947,8 @@ up.util = (($) ->
|
|
1922
1947
|
identity: identity
|
1923
1948
|
escapeHtml: escapeHtml
|
1924
1949
|
DivertibleChain: DivertibleChain
|
1950
|
+
submittedValue: submittedValue
|
1925
1951
|
|
1926
1952
|
)($)
|
1927
1953
|
|
1928
|
-
up.
|
1954
|
+
up.fail = up.util.fail
|
@@ -0,0 +1,33 @@
|
|
1
|
+
$highlight-color: #28b
|
2
|
+
$text-color: #333
|
3
|
+
|
4
|
+
.up-toast
|
5
|
+
border-top: 3px solid $highlight-color
|
6
|
+
background-color: white
|
7
|
+
color: $text-color
|
8
|
+
padding: 10px
|
9
|
+
font-family: monospace
|
10
|
+
font-size: 14px
|
11
|
+
line-height: 15px
|
12
|
+
position: fixed
|
13
|
+
left: 0
|
14
|
+
bottom: 0
|
15
|
+
right: 0
|
16
|
+
z-index: 99999999
|
17
|
+
|
18
|
+
.up-toast-variable
|
19
|
+
font-weight: normal
|
20
|
+
color: $text-color + 80
|
21
|
+
|
22
|
+
.up-toast-actions
|
23
|
+
margin-top: 7px
|
24
|
+
|
25
|
+
.up-toast-action
|
26
|
+
display: inline-block
|
27
|
+
word-spacing: -4px
|
28
|
+
text-decoration: underline
|
29
|
+
color: $highlight-color
|
30
|
+
cursor: pointer
|
31
|
+
|
32
|
+
&+.up-toast-action
|
33
|
+
margin-left: 12px
|
data/lib/unpoly/rails/version.rb
CHANGED
data/spec_app/Gemfile.lock
CHANGED
@@ -1,10 +1,19 @@
|
|
1
1
|
//= require unpoly
|
2
2
|
|
3
|
+
$block-spacing: 25px
|
4
|
+
|
5
|
+
=block-spacing
|
6
|
+
margin-top: $block-spacing
|
7
|
+
margin-bottom: $block-spacing
|
8
|
+
|
3
9
|
body
|
4
10
|
margin: 0
|
5
11
|
background: image-url('grid.png') repeat
|
6
12
|
font-family: arial, sans-serif
|
7
13
|
|
14
|
+
h1, h2, h3, h4, p
|
15
|
+
+block-spacing
|
16
|
+
|
8
17
|
.page
|
9
18
|
min-height: 3000px
|
10
19
|
|
@@ -24,6 +33,11 @@ body
|
|
24
33
|
.example
|
25
34
|
margin: 50px
|
26
35
|
|
36
|
+
.area
|
37
|
+
+block-spacing
|
38
|
+
padding: 25px
|
39
|
+
border: 1px dashed #666
|
40
|
+
|
27
41
|
.button
|
28
42
|
display: inline-block
|
29
43
|
height: 50px
|
@@ -3,4 +3,12 @@ class ApplicationController < ActionController::Base
|
|
3
3
|
# For APIs, you may want to use :null_session instead.
|
4
4
|
protect_from_forgery with: :exception
|
5
5
|
|
6
|
+
before_action :print_authenticity_token
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def print_authenticity_token
|
11
|
+
Rails.logger.info "*** Real token is #{send(:real_csrf_token, session)}"
|
12
|
+
end
|
13
|
+
|
6
14
|
end
|