Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable animation based on navigation transitions. #310

Merged
merged 1 commit into from
Mar 10, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/client/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,19 +193,21 @@ spf.ResponseFragment;
/**
* Type definition for a single SPF response object.
* - attr: Map of Element IDs to maps of attibute names to attribute values
* to set on the Elements.
* to set on the Elements.
* - body: Map of Element IDs to HTML strings containing content with which
* to update the Elements.
* to update the Elements.
* - cacheKey: Key used to cache this response.
* - cacheType: String of the type of caching to use for this response.
* - foot: HTML string containing <script> tags of JS to execute.
* - head: HTML string containing <link> and <style> tags of CSS to install.
* - name: String of the general name of this type of response. This will be
* used to generate "from" and "to" CSS classes for animation.
* - redirect: String of a URL to request instead.
* - reload: Boolean to indicate the page should be reloaded.
* - timing: Map of timing attributes to timestamp numbers.
* - title: String of the new Document title.
* - url: String of the correct URL for the current request. This will replace
* the current URL in history.
* the current URL in history.
*
* @typedef {{
* attr: (Object.<string, Object.<string, string>>|undefined),
Expand All @@ -214,6 +216,7 @@ spf.ResponseFragment;
* cacheType: (string|undefined),
* foot: (spf.ResponseFragment|undefined),
* head: (spf.ResponseFragment|undefined),
* name: (string|undefined),
* redirect: (string|undefined),
* reload: (boolean|undefined),
* timing: (Object.<string, number>|undefined),
Expand Down
10 changes: 10 additions & 0 deletions src/client/nav/nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ goog.require('spf.config');
goog.require('spf.debug');
goog.require('spf.dom');
goog.require('spf.dom.classlist');
goog.require('spf.dom.dataset');
goog.require('spf.history');
goog.require('spf.nav.request');
goog.require('spf.nav.response');
Expand Down Expand Up @@ -750,6 +751,15 @@ spf.nav.handleNavigateSuccess_ = function(options, info, url, response) {
// queued after existing ones from any ongoing part prcoessing.
var r = /** @type {spf.SingleResponse} */ (multipart ? {} : response);
spf.nav.response.process(url, r, info, function() {
// After processing is complete, save the name for future use.
var name = response['name'] || '';
if (multipart) {
var parts = response['parts'];
for (var i = 0; i < parts.length; i++) {
name = parts[i]['name'] || name;
}
}
spf.dom.dataset.set(document.body, 'spfName', name);
// If this navigation was from history, attempt to scroll to the previous
// position after all processing is complete. This should not be done
// earlier because the prevous position might rely on page width/height
Expand Down
17 changes: 16 additions & 1 deletion src/client/nav/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ goog.require('spf.config');
goog.require('spf.debug');
goog.require('spf.dom');
goog.require('spf.dom.classlist');
goog.require('spf.dom.dataset');
goog.require('spf.history');
goog.require('spf.net.connect');
goog.require('spf.net.script');
Expand Down Expand Up @@ -137,6 +138,8 @@ spf.nav.response.process = function(url, response, opt_info, opt_callback) {
var hasPosition = opt_info && !!opt_info.position;
var hasScrolled = opt_info && opt_info.scrolled;

var name = response['name'] || '';

// Convert the URL to absolute, to be used for finding the task queue.
var key = 'process ' + spf.url.absolute(url);
var sync = !spf.config.get('experimental-process-async');
Expand Down Expand Up @@ -272,6 +275,7 @@ spf.nav.response.process = function(url, response, opt_info, opt_callback) {
el,
extracted.html,
animationClass,
name,
parseInt(spf.config.get('animation-duration'), 10),
!!isReverse);
// Suspend main queue while the animation is running.
Expand Down Expand Up @@ -445,6 +449,8 @@ spf.nav.response.preprocess = function(url, response, opt_info, opt_callback) {
spf.nav.response.prepareAnimation_ = function(data) {
// Add the start class to put elements in their beginning states.
spf.dom.classlist.add(data.element, data.dirClass);
spf.dom.classlist.add(data.element, data.fromClass);
spf.dom.classlist.add(data.element, data.toClass);
spf.dom.classlist.add(data.element, data.startClass);
spf.dom.classlist.add(data.element, data.startClassDeprecated);
// Pack the existing content into a temporary container.
Expand Down Expand Up @@ -489,6 +495,8 @@ spf.nav.response.completeAnimation_ = function(data) {
// Remove the end class to put elements back in normal state.
spf.dom.classlist.remove(data.element, data.endClass);
spf.dom.classlist.remove(data.element, data.endClassDeprecated);
spf.dom.classlist.remove(data.element, data.fromClass);
spf.dom.classlist.remove(data.element, data.toClass);
spf.dom.classlist.remove(data.element, data.dirClass);
spf.debug.debug(' process done complete animation', data.element.id);
};
Expand Down Expand Up @@ -796,13 +804,14 @@ spf.nav.response.getCurrentUrl_ = function() {
* @param {!Element} el The element being updated.
* @param {string} html The new content for the element.
* @param {string} cls The animation class name.
* @param {string} name The page name.
* @param {number} duration The animation duration.
* @param {boolean} reverse Whether this is a "back" animation.
* @constructor
* @struct
* @private
*/
spf.nav.response.Animation_ = function(el, html, cls, duration, reverse) {
spf.nav.response.Animation_ = function(el, html, cls, name, duration, reverse) {
/** @type {!Element} */
this.element = el;
/** @type {string} */
Expand All @@ -812,8 +821,14 @@ spf.nav.response.Animation_ = function(el, html, cls, duration, reverse) {
/** @type {boolean} */
this.reverse = reverse;

var prevName = spf.dom.dataset.get(document.body, 'spfName') || '';

/** @type {string} */
this.key = spf.tasks.key(el);
/** @type {string} */
this.fromClass = prevName && (cls + '-from-' + prevName);
/** @type {string} */
this.toClass = name && (cls + '-to-' + name);
/** @type {Element} */
this.oldEl = null;
/** @type {string} */
Expand Down
6 changes: 6 additions & 0 deletions src/server/demo/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ def create_spf_response(self, content, fragments=None):
title = str(getattr(content, 'title', ''))
if title:
response[spf.ResponseKey.TITLE] = title
name = str(getattr(content, 'name', ''))
if name:
response[spf.ResponseKey.NAME] = name
attr = json.loads(str(getattr(content, 'attributes', '{}')))
if attr:
response[spf.ResponseKey.ATTR] = attr
Expand Down Expand Up @@ -167,6 +170,9 @@ def chunked_render_spf(self, content, fragments=None, truncate=False):
early[spf.ResponseKey.HEAD] = resp.pop(spf.ResponseKey.HEAD)
if spf.ResponseKey.TITLE in resp:
early[spf.ResponseKey.TITLE] = resp.pop(spf.ResponseKey.TITLE)
if spf.ResponseKey.NAME in resp:
# Don't pop the name so that it is present in both parts.
early[spf.ResponseKey.NAME] = resp[spf.ResponseKey.NAME]
# Begin the multipart response.
yield spf.MultipartToken.BEGIN
# Send part 1.
Expand Down
37 changes: 30 additions & 7 deletions src/server/demo/static/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -109,31 +109,54 @@ html, body {
left: 0;
width: 100%;
height: 100%;
-webkit-transition: -webkit-transform 400ms ease, opacity 400ms linear;
transition: transform 400ms ease, opacity 400ms linear;
-webkit-transition: -webkit-transform 400ms ease, opacity 200ms linear;
transition: transform 400ms ease, opacity 200ms linear;
will-change: transform, opacity;
}
/* Transitions fade-out old and fade-in new */
.spf-animate-start .spf-animate-old,
.spf-animate-end .spf-animate-new {
opacity: 1;
-webkit-transition-delay: 200ms;
transition-delay: 200ms;
}
.spf-animate-start .spf-animate-new,
.spf-animate-end .spf-animate-old {
opacity: 0;
}
/* transitions slide-out old and slide-in new */
/* By default, no movement, just fade */
.spf-animate-start .spf-animate-old,
.spf-animate-end .spf-animate-new {
-webkit-transform: translate(0%, 0%);
transform: translate(0%, 0%);
}
.spf-animate-start.spf-animate-forward .spf-animate-new,
.spf-animate-end.spf-animate-reverse .spf-animate-old {
/* Home/Spec -> Demo, slide in from right */
.spf-animate-from-home.spf-animate-to-demo.spf-animate-start .spf-animate-new,
.spf-animate-from-spec.spf-animate-to-demo.spf-animate-start .spf-animate-new {
-webkit-transform: translate(150%, 0%);
transform: translate(150%, 0%);
-webkit-transition-delay: 0ms;
transition-delay: 0ms;
}
.spf-animate-end.spf-animate-forward .spf-animate-old,
.spf-animate-start.spf-animate-reverse .spf-animate-new {
.spf-animate-from-home.spf-animate-to-demo.spf-animate-end .spf-animate-old,
.spf-animate-from-spec.spf-animate-to-demo.spf-animate-end .spf-animate-old {
-webkit-transform: translate(-150%, 0%);
transform: translate(-150%, 0%);
-webkit-transition-delay: 0ms;
transition-delay: 0ms;
}
/* Demo -> Home/Spec, slide in from left */
.spf-animate-from-demo.spf-animate-to-home.spf-animate-start .spf-animate-new,
.spf-animate-from-demo.spf-animate-to-spec.spf-animate-start .spf-animate-new {
-webkit-transform: translate(-150%, 0%);
transform: translate(-150%, 0%);
-webkit-transition-delay: 0ms;
transition-delay: 0ms;
}
.spf-animate-from-demo.spf-animate-to-home.spf-animate-end .spf-animate-old,
.spf-animate-from-demo.spf-animate-to-spec.spf-animate-end .spf-animate-old {
-webkit-transform: translate(150%, 0%);
transform: translate(150%, 0%);
-webkit-transition-delay: 0ms;
transition-delay: 0ms;
}
2 changes: 1 addition & 1 deletion src/server/demo/templates/base.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ See the LICENSE file for details.
<link rel="stylesheet" href="/static/app.css" name="app">
$:content.stylesheet
</head>
<body>
<body data-spf-name="$content.name">
<div id="masthead">
<strong>S</strong>tructured <strong>P</strong>age <strong>F</strong>ragments
<span class="info">
Expand Down
1 change: 1 addition & 0 deletions src/server/demo/templates/chunked.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ $def _javascript():


$var title: Chunked Test
$var name: chunked
$var stylesheet: $:_stylesheet()
$var javascript: $:_javascript()
$var attributes: $:_attributes()
Expand Down
1 change: 1 addition & 0 deletions src/server/demo/templates/demo.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ $def _attributes():
{ "nav": { "class": "demo$page_num" } }

$var title: Demo Page $page_num
$var name: demo
$var stylesheet: $:_stylesheet()
$var javascript:
$var attributes: $:_attributes()
Expand Down
1 change: 1 addition & 0 deletions src/server/demo/templates/index.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ $def _attributes():
{ "nav": { "class": "home" } }

$var title: Home
$var name: home
$var stylesheet: $:_stylesheet()
$var javascript: $:_javascript()
$var attributes: $:_attributes()
Expand Down
1 change: 1 addition & 0 deletions src/server/demo/templates/missing.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ $def _attributes():
{ "nav": { "class": "missing" } }

$var title: Missing
$var name: missing
$var stylesheet:
$var javascript:
$var attributes: $:_attributes()
Expand Down
1 change: 1 addition & 0 deletions src/server/demo/templates/other.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ $def _attributes():
{ "nav": { "class": "other" } }

$var title: Other
$var name: other
$var stylesheet:
$var javascript:
$var attributes: $:_attributes()
Expand Down
1 change: 1 addition & 0 deletions src/server/demo/templates/spec.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ $def _attributes():
{ "nav": { "class": "spec" } }

$var title: Spec
$var name: spec
$var stylesheet: $:_stylesheet()
$var javascript: $:_javascript()
$var attributes: $:_attributes()
Expand Down
1 change: 1 addition & 0 deletions src/server/demo/templates/truncated.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ $def _attributes():
{ "nav": { "class": "truncated" } }

$var title: Truncated
$var name: truncated
$var stylesheet:
$var javascript:
$var attributes: $:_attributes()
Expand Down
1 change: 1 addition & 0 deletions src/server/python/spf.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class ResponseKey(object):
FOOT = 'foot'
ATTR = 'attr'
BODY = 'body'
NAME = 'name'
REDIRECT = 'redirect'


Expand Down