upjs-rails 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-version +2 -0
- data/LICENSE.txt +22 -0
- data/README.md +47 -0
- data/Rakefile +1 -0
- data/bin/doc-server +3 -0
- data/bin/install-ydoc +4 -0
- data/design/animation-ghosting.txt +72 -0
- data/design/design.txt +34 -0
- data/design/draft.html.erb +48 -0
- data/design/draft.rb +9 -0
- data/lib/assets/javascripts/up/browser.js.coffee +20 -0
- data/lib/assets/javascripts/up/bus.js.coffee +54 -0
- data/lib/assets/javascripts/up/flow.js.coffee +160 -0
- data/lib/assets/javascripts/up/form.js.coffee +162 -0
- data/lib/assets/javascripts/up/history.js.coffee +33 -0
- data/lib/assets/javascripts/up/index.js +13 -0
- data/lib/assets/javascripts/up/link.js.coffee +95 -0
- data/lib/assets/javascripts/up/magic.js.coffee +79 -0
- data/lib/assets/javascripts/up/modal.js.coffee +51 -0
- data/lib/assets/javascripts/up/module.js.coffee +4 -0
- data/lib/assets/javascripts/up/motion.js.coffee +276 -0
- data/lib/assets/javascripts/up/navigation.js.coffee +63 -0
- data/lib/assets/javascripts/up/popup.js.coffee +143 -0
- data/lib/assets/javascripts/up/util.js.coffee +287 -0
- data/lib/assets/stylesheets/up/follow.css.sass +2 -0
- data/lib/assets/stylesheets/up/index.css +3 -0
- data/lib/assets/stylesheets/up/modal.css.sass +54 -0
- data/lib/assets/stylesheets/up/popup.css.sass +9 -0
- data/lib/upjs/rails/engine.rb +6 -0
- data/lib/upjs/rails/redirection.rb +26 -0
- data/lib/upjs/rails/request.rb +13 -0
- data/lib/upjs/rails/version.rb +5 -0
- data/lib/upjs-rails.rb +7 -0
- data/spec_app/.firefox-version +1 -0
- data/spec_app/.gitignore +17 -0
- data/spec_app/Gemfile +24 -0
- data/spec_app/Gemfile.lock +239 -0
- data/spec_app/README.rdoc +28 -0
- data/spec_app/Rakefile +6 -0
- data/spec_app/app/assets/images/.keep +0 -0
- data/spec_app/app/assets/javascripts/application.js +16 -0
- data/spec_app/app/assets/stylesheets/application.css +15 -0
- data/spec_app/app/assets/stylesheets/blocks/card.css.sass +11 -0
- data/spec_app/app/assets/stylesheets/blocks/controls.css.sass +7 -0
- data/spec_app/app/assets/stylesheets/blocks/field_with_errors.css.sass +5 -0
- data/spec_app/app/assets/stylesheets/blocks/menu.css.sass +13 -0
- data/spec_app/app/assets/stylesheets/blocks/panel.css.sass +8 -0
- data/spec_app/app/controllers/application_controller.rb +14 -0
- data/spec_app/app/controllers/cards_controller.rb +51 -0
- data/spec_app/app/controllers/concerns/.keep +0 -0
- data/spec_app/app/controllers/pages_controller.rb +6 -0
- data/spec_app/app/helpers/application_helper.rb +2 -0
- data/spec_app/app/mailers/.keep +0 -0
- data/spec_app/app/models/card.rb +6 -0
- data/spec_app/app/models/concerns/.keep +0 -0
- data/spec_app/app/models/tests.rb +27 -0
- data/spec_app/app/views/cards/_side.html.haml +4 -0
- data/spec_app/app/views/cards/index.html.haml +10 -0
- data/spec_app/app/views/cards/new.html.haml +15 -0
- data/spec_app/app/views/cards/show.html.haml +11 -0
- data/spec_app/app/views/layouts/application.html.erb +12 -0
- data/spec_app/app/views/pages/home.html.haml +5 -0
- data/spec_app/bin/bundle +3 -0
- data/spec_app/bin/rails +8 -0
- data/spec_app/bin/rake +8 -0
- data/spec_app/bin/setup +29 -0
- data/spec_app/bin/spring +18 -0
- data/spec_app/config/application.rb +26 -0
- data/spec_app/config/boot.rb +3 -0
- data/spec_app/config/cucumber.yml +8 -0
- data/spec_app/config/database.yml +25 -0
- data/spec_app/config/environment.rb +5 -0
- data/spec_app/config/environments/development.rb +41 -0
- data/spec_app/config/environments/production.rb +79 -0
- data/spec_app/config/environments/test.rb +42 -0
- data/spec_app/config/initializers/assets.rb +11 -0
- data/spec_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec_app/config/initializers/cookies_serializer.rb +3 -0
- data/spec_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec_app/config/initializers/inflections.rb +16 -0
- data/spec_app/config/initializers/mime_types.rb +4 -0
- data/spec_app/config/initializers/session_store.rb +3 -0
- data/spec_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec_app/config/locales/en.yml +23 -0
- data/spec_app/config/routes.rb +6 -0
- data/spec_app/config/secrets.yml +22 -0
- data/spec_app/config.ru +4 -0
- data/spec_app/db/migrate/20141225125143_create_card.rb +9 -0
- data/spec_app/db/schema.rb +23 -0
- data/spec_app/db/seeds.rb +7 -0
- data/spec_app/features/history.feature +30 -0
- data/spec_app/features/navigation.feature +9 -0
- data/spec_app/features/step_definitions/factory_steps.rb +5 -0
- data/spec_app/features/step_definitions/navigation_steps.rb +29 -0
- data/spec_app/features/step_definitions/utility_steps.rb +15 -0
- data/spec_app/features/support/env.rb +73 -0
- data/spec_app/features/support/find_by_anything.rb +19 -0
- data/spec_app/features/support/paths.rb +51 -0
- data/spec_app/lib/assets/.keep +0 -0
- data/spec_app/lib/tasks/.keep +0 -0
- data/spec_app/lib/tasks/cucumber.rake +65 -0
- data/spec_app/log/.keep +0 -0
- data/spec_app/public/404.html +67 -0
- data/spec_app/public/422.html +67 -0
- data/spec_app/public/500.html +66 -0
- data/spec_app/public/favicon.ico +0 -0
- data/spec_app/public/robots.txt +5 -0
- data/spec_app/script/cucumber +10 -0
- data/spec_app/test/controllers/.keep +0 -0
- data/spec_app/test/fixtures/.keep +0 -0
- data/spec_app/test/helpers/.keep +0 -0
- data/spec_app/test/integration/.keep +0 -0
- data/spec_app/test/mailers/.keep +0 -0
- data/spec_app/test/models/.keep +0 -0
- data/spec_app/test/test_helper.rb +10 -0
- data/spec_app/vendor/assets/javascripts/.keep +0 -0
- data/spec_app/vendor/assets/stylesheets/.keep +0 -0
- data/upjs-rails.gemspec +24 -0
- metadata +207 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
up.history = (->
|
2
|
+
|
3
|
+
replace = (url) ->
|
4
|
+
manipulate "replace", url
|
5
|
+
|
6
|
+
push = (url) ->
|
7
|
+
manipulate "push", url
|
8
|
+
|
9
|
+
manipulate = (method, url) ->
|
10
|
+
method += "State" # resulting in either pushState or replaceState
|
11
|
+
window.history[method]({ fromUp: true }, '', url)
|
12
|
+
|
13
|
+
pop = (event) ->
|
14
|
+
state = event.originalEvent.state
|
15
|
+
console.log "popping state", state
|
16
|
+
console.log "current href", currentUrl()
|
17
|
+
if state?.fromUp
|
18
|
+
up.visit currentUrl(), history: { method: 'replace' }
|
19
|
+
else
|
20
|
+
console.log "null state"
|
21
|
+
|
22
|
+
currentUrl = ->
|
23
|
+
location.href
|
24
|
+
|
25
|
+
setTimeout (->
|
26
|
+
$(window).on "popstate", pop
|
27
|
+
replace(currentUrl())
|
28
|
+
), 200
|
29
|
+
|
30
|
+
push: push
|
31
|
+
replace: replace
|
32
|
+
|
33
|
+
)()
|
@@ -0,0 +1,13 @@
|
|
1
|
+
//= require up/module
|
2
|
+
//= require up/util
|
3
|
+
//= require up/browser
|
4
|
+
//= require up/bus
|
5
|
+
//= require up/flow
|
6
|
+
//= require up/magic
|
7
|
+
//= require up/history
|
8
|
+
//= require up/motion
|
9
|
+
//= require up/link
|
10
|
+
//= require up/form
|
11
|
+
//= require up/popup
|
12
|
+
//= require up/modal
|
13
|
+
//= require up/navigation
|
@@ -0,0 +1,95 @@
|
|
1
|
+
###*
|
2
|
+
Links.
|
3
|
+
|
4
|
+
@class up.link
|
5
|
+
###
|
6
|
+
|
7
|
+
up.link = (->
|
8
|
+
|
9
|
+
###*
|
10
|
+
Visits the given URL without a full page load.
|
11
|
+
This is done by fetching `url` through an AJAX request
|
12
|
+
and replaceing the current `<body>` tag with the response's `<body>` tag..
|
13
|
+
|
14
|
+
@method up.visit
|
15
|
+
@param {String} url
|
16
|
+
The URL to visit.
|
17
|
+
@param {Object} options
|
18
|
+
See options for {{#crossLink "up.flow/up.replace"}}{{/crossLink}}.
|
19
|
+
@example
|
20
|
+
<a href="/users" up-follow>User list</a>
|
21
|
+
###
|
22
|
+
visit = (url, options) ->
|
23
|
+
console.log("up.visit", url)
|
24
|
+
# options = up.util.options(options, )
|
25
|
+
up.replace('body', url, options)
|
26
|
+
|
27
|
+
###*
|
28
|
+
Follows the given link and replaces a selector in the current page
|
29
|
+
with corresponding elements from a new page fetched from the server.
|
30
|
+
|
31
|
+
@method up.follow
|
32
|
+
@param {Element|jQuery|String} link
|
33
|
+
An element or selector which resolves to an `<a>` tag
|
34
|
+
or any element that is marked up with an `up-follow` attribute.
|
35
|
+
@param {String} [options.target]
|
36
|
+
The selector to replace.
|
37
|
+
Defaults to the `up-target` attribute on `link`,
|
38
|
+
or to `body` if such an attribute does not exist.
|
39
|
+
@param {Function|String} [options.transition]
|
40
|
+
A transition function or name.
|
41
|
+
@example
|
42
|
+
<a href="/users" up-target=".main">User list</a>
|
43
|
+
###
|
44
|
+
follow = (link, options) ->
|
45
|
+
$link = $(link)
|
46
|
+
options = up.util.options(options)
|
47
|
+
url = up.util.presentAttr($link, 'href', 'up-follow')
|
48
|
+
selector = options.target || $link.attr("up-target") || 'body'
|
49
|
+
options.transition ||= $link.attr('up-transition')
|
50
|
+
up.replace(selector, url, options)
|
51
|
+
|
52
|
+
resolve = (element) ->
|
53
|
+
$element = $(element)
|
54
|
+
if $element.is('a') || up.util.presentAttr($element, 'up-follow')
|
55
|
+
$element
|
56
|
+
else
|
57
|
+
$element.find('a:first')
|
58
|
+
|
59
|
+
resolveUrl = (element) ->
|
60
|
+
if link = resolve(element)
|
61
|
+
up.util.presentAttr(link, 'href', 'up-follow')
|
62
|
+
|
63
|
+
markActive = (element) ->
|
64
|
+
markUnactive()
|
65
|
+
$element = $(element)
|
66
|
+
$clickArea = $element.ancestors('up-follow')
|
67
|
+
$clickArea = $element unless $clickArea.length
|
68
|
+
$clickArea.addClass('up-active')
|
69
|
+
|
70
|
+
markUnactive = ->
|
71
|
+
$('[up-active]').removeClass('up-active')
|
72
|
+
|
73
|
+
up.on 'click', 'a[up-target]', (event, $link) ->
|
74
|
+
event.preventDefault()
|
75
|
+
follow($link)
|
76
|
+
|
77
|
+
up.on 'click', '[up-follow]', (event, $element) ->
|
78
|
+
|
79
|
+
childLinkClicked = ->
|
80
|
+
$target = $(event.target)
|
81
|
+
$target.closest('a').length && $element.has($target).length
|
82
|
+
|
83
|
+
unless childLinkClicked()
|
84
|
+
event.preventDefault()
|
85
|
+
follow(resolve($element))
|
86
|
+
|
87
|
+
visit: visit
|
88
|
+
follow: follow
|
89
|
+
resolve: resolve
|
90
|
+
resolveUrl: resolveUrl
|
91
|
+
|
92
|
+
)()
|
93
|
+
|
94
|
+
up.visit = up.link.visit
|
95
|
+
up.follow = up.link.follow
|
@@ -0,0 +1,79 @@
|
|
1
|
+
###*
|
2
|
+
Event handling.
|
3
|
+
|
4
|
+
@class up.magic
|
5
|
+
###
|
6
|
+
up.magic = (->
|
7
|
+
|
8
|
+
AWAKENED_CLASS = 'up-awakened'
|
9
|
+
DESTROYER_KEY = 'up-destroyer'
|
10
|
+
|
11
|
+
###*
|
12
|
+
Binds an event handler to the document,
|
13
|
+
which will be executed whenever the given event
|
14
|
+
is triggered on the given selector.
|
15
|
+
|
16
|
+
@method up.on
|
17
|
+
@param {String} events
|
18
|
+
A space-separated list of event names to bind.
|
19
|
+
@param {String} selector
|
20
|
+
The selector an on which the event must be triggered.
|
21
|
+
@param {Function} behavior
|
22
|
+
The handler that should be called.
|
23
|
+
###
|
24
|
+
live = (events, selector, behavior) ->
|
25
|
+
$(document).on events, selector, (event) ->
|
26
|
+
behavior.apply(this, [event, $(this)])
|
27
|
+
|
28
|
+
awakeners = []
|
29
|
+
|
30
|
+
###*
|
31
|
+
Registers a function to be called whenever an element with
|
32
|
+
the given selector is inserted into the DOM through Up.js.
|
33
|
+
|
34
|
+
@method up.awaken
|
35
|
+
@param {String} selector
|
36
|
+
The selector to match.
|
37
|
+
@param {Function} awakener
|
38
|
+
The function to call when a matching element is inserted.
|
39
|
+
The function takes the new element as the first argument (as a jQuery object).
|
40
|
+
It may return another function that destroys the awakened
|
41
|
+
object when it is removed from the DOM, by clearing global state such as
|
42
|
+
time-outs and event handlers bound to the document.
|
43
|
+
###
|
44
|
+
awaken = (selector, awakener) ->
|
45
|
+
awakeners.push
|
46
|
+
selector: selector
|
47
|
+
behavior: awakener
|
48
|
+
|
49
|
+
$deepFilter = ($element, selector) ->
|
50
|
+
$element.find(selector).addBack(selector)
|
51
|
+
|
52
|
+
compile = ($fragment) ->
|
53
|
+
for awakener in awakeners
|
54
|
+
$deepFilter($fragment, awakener.selector).each ->
|
55
|
+
$element = $(this)
|
56
|
+
destroyer = awakener.behavior.apply(this, [$element])
|
57
|
+
if up.util.isFunction(destroyer)
|
58
|
+
$element.prop(AWAKENED_CLASS, true)
|
59
|
+
$element.data(DESTROYER_KEY, destroyer)
|
60
|
+
|
61
|
+
destroy = ($fragment) ->
|
62
|
+
$deepFilter($fragment, "[#{AWAKENED_CLASS}]").each ->
|
63
|
+
$element = $(this)
|
64
|
+
destroyer = $element.data(DESTROYER_KEY)
|
65
|
+
destroyer()
|
66
|
+
|
67
|
+
up.bus.on 'app:ready', (-> up.bus.emit 'fragment:ready', $(document.body))
|
68
|
+
up.bus.on 'fragment:ready', compile
|
69
|
+
up.bus.on 'fragment:destroy', destroy
|
70
|
+
$(document).on 'ready', -> up.bus.emit('app:ready')
|
71
|
+
|
72
|
+
awaken: awaken
|
73
|
+
on: live
|
74
|
+
|
75
|
+
)()
|
76
|
+
|
77
|
+
up.awaken = up.magic.awaken
|
78
|
+
up.on = up.magic.on
|
79
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
###*
|
2
|
+
Modal dialogs (WIP).
|
3
|
+
|
4
|
+
@class up.modal
|
5
|
+
###
|
6
|
+
up.modal = (->
|
7
|
+
|
8
|
+
# configuration =
|
9
|
+
# width: 600
|
10
|
+
# height: 400
|
11
|
+
# template:
|
12
|
+
# """
|
13
|
+
# <div class="up-modal">
|
14
|
+
# <div class="up-modal-overlay"></div>
|
15
|
+
# <div class="up-modal-dialog">
|
16
|
+
# <a href="#" class="up-modal-close">
|
17
|
+
# <span class="up-modal-close-label">Close</span>
|
18
|
+
# <span class="up-modal-close-key">ESC</span>
|
19
|
+
# </a>
|
20
|
+
# <div class="up-modal-content"></div>
|
21
|
+
# </div>
|
22
|
+
# </div>
|
23
|
+
# """
|
24
|
+
#
|
25
|
+
# defaults = (defaults) ->
|
26
|
+
# up.util.extend(configuration, defaults)
|
27
|
+
#
|
28
|
+
# open = (link, options) ->
|
29
|
+
# $link = $(link)
|
30
|
+
# url = $link.attr("href")
|
31
|
+
# selector = $link.attr("up-modal") || $link.attr("up-target") || 'body'
|
32
|
+
# options.source = true
|
33
|
+
# replace(selector, url, options)
|
34
|
+
# options = up.util.options(options, configuration)
|
35
|
+
# createElements()
|
36
|
+
# update(options)
|
37
|
+
#
|
38
|
+
# close = ->
|
39
|
+
# if $container
|
40
|
+
# $container.remove()
|
41
|
+
# $container = null
|
42
|
+
|
43
|
+
source = ->
|
44
|
+
$('.up-modal').find('[up-source]').attr('up-source')
|
45
|
+
|
46
|
+
# defaults: defaults
|
47
|
+
# open: open
|
48
|
+
# close: close
|
49
|
+
source: source
|
50
|
+
|
51
|
+
)()
|
@@ -0,0 +1,276 @@
|
|
1
|
+
###*
|
2
|
+
Animation and transition effects.
|
3
|
+
|
4
|
+
@class up.motion
|
5
|
+
###
|
6
|
+
up.motion = (->
|
7
|
+
|
8
|
+
defaultOptions =
|
9
|
+
duration: 300
|
10
|
+
easing: 'ease'
|
11
|
+
|
12
|
+
animations = {}
|
13
|
+
transitions = {}
|
14
|
+
|
15
|
+
cssAnimate = up.util.cssAnimate
|
16
|
+
|
17
|
+
###*
|
18
|
+
Animates an element.
|
19
|
+
|
20
|
+
The following animations are pre-registered:
|
21
|
+
|
22
|
+
- `fade-in`
|
23
|
+
- `fade-out`
|
24
|
+
- `move-to-top`
|
25
|
+
- `move-from-top`
|
26
|
+
- `move-to-bottom`
|
27
|
+
- `move-from-bottom`
|
28
|
+
- `move-to-left`
|
29
|
+
- `move-from-left`
|
30
|
+
- `move-to-right`
|
31
|
+
- `move-from-right`
|
32
|
+
- `none`
|
33
|
+
|
34
|
+
@method up.animate
|
35
|
+
@param {Element|jQuery|String} elementOrSelector
|
36
|
+
@param {String|Function} animationOrName
|
37
|
+
@param {Number} [options.duration]
|
38
|
+
@param {String} [options.easing]
|
39
|
+
@return {Promise}
|
40
|
+
A promise for the animation's end.
|
41
|
+
###
|
42
|
+
animate = (elementOrSelector, animationOrName, options) ->
|
43
|
+
$element = $(elementOrSelector)
|
44
|
+
console.log("animating with", animationOrName)
|
45
|
+
options = up.util.options(options, defaultOptions)
|
46
|
+
anim = if up.util.isFunction(animationOrName)
|
47
|
+
animationOrName
|
48
|
+
else
|
49
|
+
animations[animationOrName] or up.util.error("Unknown animation", animationName)
|
50
|
+
assertIsPromise(
|
51
|
+
anim($element, options),
|
52
|
+
["Animation did not return a Promise", animationOrName]
|
53
|
+
)
|
54
|
+
|
55
|
+
withGhosts = ($old, $new, block) ->
|
56
|
+
$oldGhost = null
|
57
|
+
$newGhost = null
|
58
|
+
up.util.temporaryCss $new, display: 'none', ->
|
59
|
+
$oldGhost = up.util.prependGhost($old)
|
60
|
+
up.util.temporaryCss $old, display: 'none', ->
|
61
|
+
$newGhost = up.util.prependGhost($new)
|
62
|
+
# $old should take up space in the page flow until the transition ends
|
63
|
+
$old.css(visibility: 'hidden')
|
64
|
+
newCssMemo = up.util.temporaryCss($new, display: 'none')
|
65
|
+
promise = block($oldGhost, $newGhost)
|
66
|
+
promise.then ->
|
67
|
+
$oldGhost.remove()
|
68
|
+
$newGhost.remove()
|
69
|
+
# Now that the transition is over we show $new again.
|
70
|
+
# Since we expect $old to be removed in a heartblink,
|
71
|
+
# $new should take up space
|
72
|
+
$old.css(display: 'none')
|
73
|
+
newCssMemo()
|
74
|
+
|
75
|
+
assertIsPromise = (object, messageParts) ->
|
76
|
+
up.util.isPromise(object) or up.util.error(messageParts...)
|
77
|
+
object
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
###*
|
83
|
+
Performs a transition between two elements.
|
84
|
+
|
85
|
+
The following transitions are pre-registered:
|
86
|
+
|
87
|
+
- `cross-fade`
|
88
|
+
- `move-top`
|
89
|
+
- `move-bottom`
|
90
|
+
- `move-left`
|
91
|
+
- `move-right`
|
92
|
+
- `none`
|
93
|
+
|
94
|
+
You can also compose a transition from two animation names
|
95
|
+
separated by a slash character (`/`):
|
96
|
+
|
97
|
+
- `move-to-bottom/fade-in`
|
98
|
+
- `move-to-left/move-from-top`
|
99
|
+
|
100
|
+
@method up.morph
|
101
|
+
@param {Element|jQuery|String} source
|
102
|
+
@param {Element|jQuery|String} target
|
103
|
+
@param {Function|String} transitionOrName
|
104
|
+
@param {Number} [options.duration]
|
105
|
+
@param {String} [options.easing]
|
106
|
+
@return {Promise}
|
107
|
+
A promise for the transition's end.
|
108
|
+
###
|
109
|
+
morph = (source, target, transitionOrName, options) ->
|
110
|
+
options = up.util.options(defaultOptions)
|
111
|
+
$old = $(source)
|
112
|
+
$new = $(target)
|
113
|
+
transition = up.util.presence(transitionOrName, up.util.isFunction) || transitions[transitionOrName]
|
114
|
+
if transition
|
115
|
+
withGhosts $old, $new, ($oldGhost, $newGhost) ->
|
116
|
+
assertIsPromise(
|
117
|
+
transition($oldGhost, $newGhost, options),
|
118
|
+
["Transition did not return a promise", transitionOrName]
|
119
|
+
)
|
120
|
+
else if animation = animations[transitionOrName]
|
121
|
+
$old.hide()
|
122
|
+
animate($new, animation, options)
|
123
|
+
else if up.util.isString(transitionOrName) && transitionOrName.indexOf('/') >= 0
|
124
|
+
parts = transitionOrName.split('/')
|
125
|
+
transition = ($old, $new, options) ->
|
126
|
+
$.when(
|
127
|
+
animate($old, parts[0], options),
|
128
|
+
animate($new, parts[1], options)
|
129
|
+
)
|
130
|
+
morph($old, $new, transition, options)
|
131
|
+
else
|
132
|
+
up.util.error("Unknown transition: #{transitionOrName}")
|
133
|
+
|
134
|
+
###*
|
135
|
+
Defines a named transition.
|
136
|
+
|
137
|
+
@method up.transition
|
138
|
+
@param {String} name
|
139
|
+
@param {Function} transition
|
140
|
+
###
|
141
|
+
transition = (name, transition) ->
|
142
|
+
transitions[name] = transition
|
143
|
+
|
144
|
+
###*
|
145
|
+
Defines a named animation.
|
146
|
+
|
147
|
+
@method up.animation
|
148
|
+
@param {String} name
|
149
|
+
@param {Function} animation
|
150
|
+
###
|
151
|
+
animation = (name, animation) ->
|
152
|
+
animations[name] = animation
|
153
|
+
|
154
|
+
###*
|
155
|
+
Returns a no-op animation or transition which has no visual effects
|
156
|
+
and completes instantly.
|
157
|
+
|
158
|
+
@method up.motion.none
|
159
|
+
@return {Promise}
|
160
|
+
A resolved promise
|
161
|
+
###
|
162
|
+
none = ->
|
163
|
+
deferred = $.Deferred()
|
164
|
+
deferred.resolve()
|
165
|
+
deferred.promise()
|
166
|
+
|
167
|
+
animation('none', none)
|
168
|
+
|
169
|
+
animation('fade-in', ($ghost, options) ->
|
170
|
+
$ghost.css(opacity: 0)
|
171
|
+
cssAnimate($ghost, { opacity: 1 }, options)
|
172
|
+
)
|
173
|
+
|
174
|
+
animation('fade-out', ($ghost, options) ->
|
175
|
+
$ghost.css(opacity: 1)
|
176
|
+
cssAnimate($ghost, { opacity: 0 }, options)
|
177
|
+
)
|
178
|
+
|
179
|
+
animation('move-to-top', ($ghost, options) ->
|
180
|
+
$ghost.css('margin-top': '0%')
|
181
|
+
cssAnimate($ghost, { 'margin-top': '-100%' }, options)
|
182
|
+
)
|
183
|
+
|
184
|
+
animation('move-from-top', ($ghost, options) ->
|
185
|
+
$ghost.css('margin-top': '-100%')
|
186
|
+
cssAnimate($ghost, { 'margin-top': '0%' }, options)
|
187
|
+
)
|
188
|
+
|
189
|
+
animation('move-to-bottom', ($ghost, options) ->
|
190
|
+
$ghost.css('margin-top': '0%')
|
191
|
+
cssAnimate($ghost, { 'margin-top': '100%' }, options)
|
192
|
+
)
|
193
|
+
|
194
|
+
animation('move-from-bottom', ($ghost, options) ->
|
195
|
+
$ghost.css('margin-top': '100%')
|
196
|
+
cssAnimate($ghost, { 'margin-top': '0%' }, options)
|
197
|
+
)
|
198
|
+
|
199
|
+
animation('move-to-left', ($ghost, options) ->
|
200
|
+
$ghost.css('margin-left': '0%')
|
201
|
+
cssAnimate($ghost, { 'margin-left': '-100%' }, options)
|
202
|
+
)
|
203
|
+
|
204
|
+
animation('move-from-left', ($ghost, options) ->
|
205
|
+
$ghost.css('margin-left': '-100%')
|
206
|
+
cssAnimate($ghost, { 'margin-left': '0%' }, options)
|
207
|
+
)
|
208
|
+
|
209
|
+
animation('move-to-right', ($ghost, options) ->
|
210
|
+
$ghost.css('margin-left': '0%')
|
211
|
+
cssAnimate($ghost, { 'margin-left': '100%' }, options)
|
212
|
+
)
|
213
|
+
|
214
|
+
animation('move-from-right', ($ghost, options) ->
|
215
|
+
$ghost.css('margin-left': '100%')
|
216
|
+
cssAnimate($ghost, { 'margin-left': '0%' }, options)
|
217
|
+
)
|
218
|
+
|
219
|
+
animation('roll-down', ($ghost, options) ->
|
220
|
+
fullHeight = $ghost.height()
|
221
|
+
styleMemo = up.util.temporaryCss($ghost,
|
222
|
+
height: '0px'
|
223
|
+
overflow: 'hidden'
|
224
|
+
)
|
225
|
+
cssAnimate($ghost, { height: "#{fullHeight}px" }, options).then(styleMemo)
|
226
|
+
)
|
227
|
+
|
228
|
+
transition('none', none)
|
229
|
+
|
230
|
+
transition('move-left', ($old, $new, options) ->
|
231
|
+
$.when(
|
232
|
+
animate($old, 'move-to-left', options),
|
233
|
+
animate($new, 'move-from-right', options)
|
234
|
+
)
|
235
|
+
)
|
236
|
+
|
237
|
+
transition('move-right', ($old, $new, options) ->
|
238
|
+
$.when(
|
239
|
+
animate($old, 'move-to-right', options),
|
240
|
+
animate($new, 'move-from-left', options)
|
241
|
+
)
|
242
|
+
)
|
243
|
+
|
244
|
+
transition('move-top', ($old, $new, options) ->
|
245
|
+
$.when(
|
246
|
+
animate($old, 'move-to-top', options),
|
247
|
+
animate($new, 'move-from-bottom', options)
|
248
|
+
)
|
249
|
+
)
|
250
|
+
|
251
|
+
transition('move-bottom', ($old, $new, options) ->
|
252
|
+
$.when(
|
253
|
+
animate($old, 'move-to-bottom', options),
|
254
|
+
animate($new, 'move-from-top', options)
|
255
|
+
)
|
256
|
+
)
|
257
|
+
|
258
|
+
transition('cross-fade', ($old, $new, options) ->
|
259
|
+
$.when(
|
260
|
+
animate($old, 'fade-out', options),
|
261
|
+
animate($new, 'fade-in', options)
|
262
|
+
)
|
263
|
+
)
|
264
|
+
|
265
|
+
morph: morph
|
266
|
+
animate: animate
|
267
|
+
transition: transition
|
268
|
+
animation: animation
|
269
|
+
none: none
|
270
|
+
|
271
|
+
)()
|
272
|
+
|
273
|
+
up.transition = up.motion.transition
|
274
|
+
up.animation = up.motion.animation
|
275
|
+
up.morph = up.motion.morph
|
276
|
+
up.animate = up.motion.animate
|
@@ -0,0 +1,63 @@
|
|
1
|
+
###*
|
2
|
+
This module marks up link elements with classes indicating that
|
3
|
+
they are currently loading (class `up-active`) or linking
|
4
|
+
to the current location (class `up-current`).
|
5
|
+
|
6
|
+
The current location is either:
|
7
|
+
|
8
|
+
- the URL displayed in the browser window's location bar
|
9
|
+
- the source URL of a currently opened {{#crossLink "up.modal"}}modal dialog{{/crossLink}}
|
10
|
+
- the source URL of a currently opened {{#crossLink "up.popup"}}popup overlay{{/crossLink}}
|
11
|
+
|
12
|
+
@class up.navigation
|
13
|
+
###
|
14
|
+
up.navigation = (->
|
15
|
+
|
16
|
+
CLASS_ACTIVE = 'up-active'
|
17
|
+
CLASS_CURRENT = 'up-current'
|
18
|
+
SELECTOR_SECTION = 'a[href], a[up-target], [up-follow], [up-modal], [up-popup]'
|
19
|
+
SELECTOR_ACTIVE = ".#{CLASS_ACTIVE}"
|
20
|
+
|
21
|
+
locationChanged = ->
|
22
|
+
windowLocation = up.util.normalizeUrl(location.href, search: false)
|
23
|
+
modalLocation = up.modal.source()
|
24
|
+
popupLocation = up.popup.source()
|
25
|
+
|
26
|
+
up.util.each $(SELECTOR_SECTION), (section) ->
|
27
|
+
$section = $(section)
|
28
|
+
# if $section is marked up with up-follow,
|
29
|
+
# the actual link might be a child element.
|
30
|
+
url = up.link.resolveUrl($section)
|
31
|
+
url = up.util.normalizeUrl(url, search: false)
|
32
|
+
if url == windowLocation || url == modalLocation || url == popupLocation
|
33
|
+
$section.addClass(CLASS_CURRENT)
|
34
|
+
else
|
35
|
+
$section.removeClass(CLASS_CURRENT)
|
36
|
+
|
37
|
+
sectionClicked = ($section) ->
|
38
|
+
unmarkActive()
|
39
|
+
$section = enlargeClickArea($section)
|
40
|
+
$section.addClass(CLASS_ACTIVE)
|
41
|
+
|
42
|
+
enlargeClickArea = ($section) ->
|
43
|
+
up.util.presence($section.parents(SELECTOR_SECTION)) || $section
|
44
|
+
|
45
|
+
unmarkActive = ->
|
46
|
+
$(SELECTOR_ACTIVE).removeClass(CLASS_ACTIVE)
|
47
|
+
|
48
|
+
up.on 'click', SELECTOR_SECTION, (event, $section) ->
|
49
|
+
sectionClicked($section)
|
50
|
+
|
51
|
+
# If a new fragment is inserted, it's likely to be the result
|
52
|
+
# to the active action. So we can remove the active marker.
|
53
|
+
up.bus.on 'fragment:ready', ->
|
54
|
+
unmarkActive()
|
55
|
+
locationChanged()
|
56
|
+
|
57
|
+
# If the destroyed fragment is a modal or popup container
|
58
|
+
# this changes which URLs we consider currents.
|
59
|
+
up.bus.on 'fragment:destroy', ($fragment) ->
|
60
|
+
if $fragment.is('.up-modal, .up-popup')
|
61
|
+
locationChanged()
|
62
|
+
|
63
|
+
)()
|