-
Notifications
You must be signed in to change notification settings - Fork 7
/
transitioner.js
117 lines (94 loc) · 3.59 KB
/
transitioner.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// sits in front of the router and provides 'currentPage' and 'nextPage',
// whilst setting the correct classes on the body to allow transitions, namely:
//
// body.transitioning.from_X.to_Y
(function() {
var Transitioner = function() {
this._currentPage = null;
this._currentPageListeners = new Deps.Dependency();
this._nextPage = null;
this._nextPageListeners = new Deps.Dependency();
this._options = {}
}
Transitioner._TRANSITIONING_CLASS = 'transitioning';
Transitioner.prototype._transitionEvents = 'webkitTransitionEnd.transitioner oTransitionEnd.transitioner transitionEnd.transitioner msTransitionEnd.transitioner transitionend.transitioner';
Transitioner.prototype._transitionClasses = function() {
return "from_" + this._currentPage + " to_" + this._nextPage;
}
Transitioner.prototype.setOptions = function(options) {
_.extend(this._options, options);
}
Transitioner.prototype.currentPage = function() {
Deps.depend(this._currentPageListeners);
return this._currentPage;
}
Transitioner.prototype._setCurrentPage = function(page) {
this._currentPage = page;
this._currentPageListeners.changed();
}
Transitioner.prototype.nextPage = function() {
Deps.depend(this._nextPageListeners);
return this._nextPage;
}
Transitioner.prototype._setNextPage = function(page) {
this._nextPage = page;
this._nextPageListeners.changed();
}
Transitioner.prototype.listen = function() {
var self = this;
Deps.autorun(function() {
self.transition(Meteor.Router.page());
});
}
// do a transition to newPage, if we are already set and there already
//
// note: this is called inside an autorun, so we need to take care to not
// do anything reactive.
Transitioner.prototype.transition = function(newPage) {
var self = this;
// this is our first page? don't do a transition
if (!self._currentPage)
return self._setCurrentPage(newPage);
// if we are transitioning already, quickly finish that transition
if (self._nextPage)
self.endTransition();
// if we are transitioning to the page we are already on, no-op
if (self._currentPage === newPage)
return;
// Setup the transition -- first tell any listeners to re-draw themselves
// and set the informative class on the body.
self._setNextPage(newPage);
$('body').addClass(self._transitionClasses())
self._options.before && self._options.before();
// let the DOM re-draw, then start the transition
Meteor.defer(function() {
// add relevant classes to the body and wait for the body to finish
// transitioning (this is how we know the transition is done)
$('body')
.addClass(Transitioner._TRANSITIONING_CLASS)
.on(self._transitionEvents, function (e) {
$(e.target).is('body') && self.endTransition();
});
});
}
Transitioner.prototype.endTransition = function() {
var self = this;
var classes = self._transitionClasses();
// if nextPage isn't set, something weird is going on, bail
if (! self._nextPage)
return;
// switch
self._setCurrentPage(self._nextPage);
self._setNextPage(null);
// clean up our transitioning state
Deps.afterFlush(function() {
$('body').off('.transitioner')
.removeClass(classes).removeClass(Transitioner._TRANSITIONING_CLASS);
self._options.after && self._options.after();
});
}
Meteor.Transitioner = new Transitioner();
Meteor.startup(function() {
Meteor.Transitioner.listen();
});
}());