Merge pull request #1660 from hnakamur/turbolinks

Add turbolinks.js 1.3.0.
This commit is contained in:
Thomas Davis
2013-09-02 22:48:37 -07:00
4 changed files with 466 additions and 0 deletions
+423
View File
@@ -0,0 +1,423 @@
// Generated by CoffeeScript 1.6.3
(function() {
var CSRFToken, anchoredLink, browserCompatibleDocumentParser, browserIsntBuggy, browserSupportsPushState, cacheCurrentPage, cacheSize, changePage, constrainPageCacheTo, createDocument, crossOriginLink, currentState, executeScriptTags, extractLink, extractTitleAndBody, fetchHistory, fetchReplacement, handleClick, ignoreClick, initializeTurbolinks, installClickHandlerLast, loadedAssets, noTurbolink, nonHtmlLink, nonStandardClick, pageCache, pageChangePrevented, pagesCached, processResponse, recallScrollPosition, referer, reflectNewUrl, reflectRedirectedUrl, rememberCurrentState, rememberCurrentUrl, removeHash, removeNoscriptTags, requestMethod, requestMethodIsSafe, resetScrollPosition, targetLink, triggerEvent, visit, xhr, _ref,
__hasProp = {}.hasOwnProperty,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
cacheSize = 10;
currentState = null;
referer = null;
loadedAssets = null;
pageCache = {};
createDocument = null;
requestMethod = ((_ref = document.cookie.match(/request_method=(\w+)/)) != null ? _ref[1].toUpperCase() : void 0) || '';
xhr = null;
fetchReplacement = function(url) {
var safeUrl;
triggerEvent('page:fetch');
safeUrl = removeHash(url);
if (xhr != null) {
xhr.abort();
}
xhr = new XMLHttpRequest;
xhr.open('GET', safeUrl, true);
xhr.setRequestHeader('Accept', 'text/html, application/xhtml+xml, application/xml');
xhr.setRequestHeader('X-XHR-Referer', referer);
xhr.onload = function() {
var doc;
triggerEvent('page:receive');
if (doc = processResponse()) {
reflectNewUrl(url);
changePage.apply(null, extractTitleAndBody(doc));
reflectRedirectedUrl();
if (document.location.hash) {
document.location.href = document.location.href;
} else {
resetScrollPosition();
}
return triggerEvent('page:load');
} else {
return document.location.href = url;
}
};
xhr.onloadend = function() {
return xhr = null;
};
xhr.onabort = function() {
return rememberCurrentUrl();
};
xhr.onerror = function() {
return document.location.href = url;
};
return xhr.send();
};
fetchHistory = function(position) {
var page;
cacheCurrentPage();
page = pageCache[position];
if (xhr != null) {
xhr.abort();
}
changePage(page.title, page.body);
recallScrollPosition(page);
return triggerEvent('page:restore');
};
cacheCurrentPage = function() {
pageCache[currentState.position] = {
url: document.location.href,
body: document.body,
title: document.title,
positionY: window.pageYOffset,
positionX: window.pageXOffset
};
return constrainPageCacheTo(cacheSize);
};
pagesCached = function(size) {
if (size == null) {
size = cacheSize;
}
if (/^[\d]+$/.test(size)) {
return cacheSize = parseInt(size);
}
};
constrainPageCacheTo = function(limit) {
var key, value;
for (key in pageCache) {
if (!__hasProp.call(pageCache, key)) continue;
value = pageCache[key];
if (key <= currentState.position - limit) {
pageCache[key] = null;
}
}
};
changePage = function(title, body, csrfToken, runScripts) {
document.title = title;
document.documentElement.replaceChild(body, document.body);
if (csrfToken != null) {
CSRFToken.update(csrfToken);
}
removeNoscriptTags();
if (runScripts) {
executeScriptTags();
}
currentState = window.history.state;
return triggerEvent('page:change');
};
executeScriptTags = function() {
var attr, copy, nextSibling, parentNode, script, scripts, _i, _j, _len, _len1, _ref1, _ref2;
scripts = Array.prototype.slice.call(document.body.querySelectorAll('script:not([data-turbolinks-eval="false"])'));
for (_i = 0, _len = scripts.length; _i < _len; _i++) {
script = scripts[_i];
if (!((_ref1 = script.type) === '' || _ref1 === 'text/javascript')) {
continue;
}
copy = document.createElement('script');
_ref2 = script.attributes;
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
attr = _ref2[_j];
copy.setAttribute(attr.name, attr.value);
}
copy.appendChild(document.createTextNode(script.innerHTML));
parentNode = script.parentNode, nextSibling = script.nextSibling;
parentNode.removeChild(script);
parentNode.insertBefore(copy, nextSibling);
}
};
removeNoscriptTags = function() {
var noscript, noscriptTags, _i, _len;
noscriptTags = Array.prototype.slice.call(document.body.getElementsByTagName('noscript'));
for (_i = 0, _len = noscriptTags.length; _i < _len; _i++) {
noscript = noscriptTags[_i];
noscript.parentNode.removeChild(noscript);
}
};
reflectNewUrl = function(url) {
if (url !== referer) {
return window.history.pushState({
turbolinks: true,
position: currentState.position + 1
}, '', url);
}
};
reflectRedirectedUrl = function() {
var location, preservedHash;
if (location = xhr.getResponseHeader('X-XHR-Redirected-To')) {
preservedHash = removeHash(location) === location ? document.location.hash : '';
return window.history.replaceState(currentState, '', location + preservedHash);
}
};
rememberCurrentUrl = function() {
return window.history.replaceState({
turbolinks: true,
position: Date.now()
}, '', document.location.href);
};
rememberCurrentState = function() {
return currentState = window.history.state;
};
recallScrollPosition = function(page) {
return window.scrollTo(page.positionX, page.positionY);
};
resetScrollPosition = function() {
return window.scrollTo(0, 0);
};
removeHash = function(url) {
var link;
link = url;
if (url.href == null) {
link = document.createElement('A');
link.href = url;
}
return link.href.replace(link.hash, '');
};
triggerEvent = function(name) {
var event;
event = document.createEvent('Events');
event.initEvent(name, true, true);
return document.dispatchEvent(event);
};
pageChangePrevented = function() {
return !triggerEvent('page:before-change');
};
processResponse = function() {
var assetsChanged, clientOrServerError, doc, extractTrackAssets, intersection, validContent;
clientOrServerError = function() {
var _ref1;
return (400 <= (_ref1 = xhr.status) && _ref1 < 600);
};
validContent = function() {
return xhr.getResponseHeader('Content-Type').match(/^(?:text\/html|application\/xhtml\+xml|application\/xml)(?:;|$)/);
};
extractTrackAssets = function(doc) {
var node, _i, _len, _ref1, _results;
_ref1 = doc.head.childNodes;
_results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
node = _ref1[_i];
if ((typeof node.getAttribute === "function" ? node.getAttribute('data-turbolinks-track') : void 0) != null) {
_results.push(node.src || node.href);
}
}
return _results;
};
assetsChanged = function(doc) {
var fetchedAssets;
loadedAssets || (loadedAssets = extractTrackAssets(document));
fetchedAssets = extractTrackAssets(doc);
return fetchedAssets.length !== loadedAssets.length || intersection(fetchedAssets, loadedAssets).length !== loadedAssets.length;
};
intersection = function(a, b) {
var value, _i, _len, _ref1, _results;
if (a.length > b.length) {
_ref1 = [b, a], a = _ref1[0], b = _ref1[1];
}
_results = [];
for (_i = 0, _len = a.length; _i < _len; _i++) {
value = a[_i];
if (__indexOf.call(b, value) >= 0) {
_results.push(value);
}
}
return _results;
};
if (!clientOrServerError() && validContent()) {
doc = createDocument(xhr.responseText);
if (doc && !assetsChanged(doc)) {
return doc;
}
}
};
extractTitleAndBody = function(doc) {
var title;
title = doc.querySelector('title');
return [title != null ? title.textContent : void 0, doc.body, CSRFToken.get(doc).token, 'runScripts'];
};
CSRFToken = {
get: function(doc) {
var tag;
if (doc == null) {
doc = document;
}
return {
node: tag = doc.querySelector('meta[name="csrf-token"]'),
token: tag != null ? typeof tag.getAttribute === "function" ? tag.getAttribute('content') : void 0 : void 0
};
},
update: function(latest) {
var current;
current = this.get();
if ((current.token != null) && (latest != null) && current.token !== latest) {
return current.node.setAttribute('content', latest);
}
}
};
browserCompatibleDocumentParser = function() {
var createDocumentUsingDOM, createDocumentUsingParser, createDocumentUsingWrite, e, testDoc, _ref1;
createDocumentUsingParser = function(html) {
return (new DOMParser).parseFromString(html, 'text/html');
};
createDocumentUsingDOM = function(html) {
var doc;
doc = document.implementation.createHTMLDocument('');
doc.documentElement.innerHTML = html;
return doc;
};
createDocumentUsingWrite = function(html) {
var doc;
doc = document.implementation.createHTMLDocument('');
doc.open('replace');
doc.write(html);
doc.close();
return doc;
};
try {
if (window.DOMParser) {
testDoc = createDocumentUsingParser('<html><body><p>test');
return createDocumentUsingParser;
}
} catch (_error) {
e = _error;
testDoc = createDocumentUsingDOM('<html><body><p>test');
return createDocumentUsingDOM;
} finally {
if ((testDoc != null ? (_ref1 = testDoc.body) != null ? _ref1.childNodes.length : void 0 : void 0) !== 1) {
return createDocumentUsingWrite;
}
}
};
installClickHandlerLast = function(event) {
if (!event.defaultPrevented) {
document.removeEventListener('click', handleClick, false);
return document.addEventListener('click', handleClick, false);
}
};
handleClick = function(event) {
var link;
if (!event.defaultPrevented) {
link = extractLink(event);
if (link.nodeName === 'A' && !ignoreClick(event, link)) {
if (!pageChangePrevented()) {
visit(link.href);
}
return event.preventDefault();
}
}
};
extractLink = function(event) {
var link;
link = event.target;
while (!(!link.parentNode || link.nodeName === 'A')) {
link = link.parentNode;
}
return link;
};
crossOriginLink = function(link) {
return location.protocol !== link.protocol || location.host !== link.host;
};
anchoredLink = function(link) {
return ((link.hash && removeHash(link)) === removeHash(location)) || (link.href === location.href + '#');
};
nonHtmlLink = function(link) {
var url;
url = removeHash(link);
return url.match(/\.[a-z]+(\?.*)?$/g) && !url.match(/\.html?(\?.*)?$/g);
};
noTurbolink = function(link) {
var ignore;
while (!(ignore || link === document)) {
ignore = link.getAttribute('data-no-turbolink') != null;
link = link.parentNode;
}
return ignore;
};
targetLink = function(link) {
return link.target.length !== 0;
};
nonStandardClick = function(event) {
return event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
};
ignoreClick = function(event, link) {
return crossOriginLink(link) || anchoredLink(link) || nonHtmlLink(link) || noTurbolink(link) || targetLink(link) || nonStandardClick(event);
};
initializeTurbolinks = function() {
rememberCurrentUrl();
rememberCurrentState();
createDocument = browserCompatibleDocumentParser();
document.addEventListener('click', installClickHandlerLast, true);
return window.addEventListener('popstate', function(event) {
var state;
state = event.state;
if (state != null ? state.turbolinks : void 0) {
if (pageCache[state.position]) {
return fetchHistory(state.position);
} else {
return visit(event.target.location.href);
}
}
}, false);
};
browserSupportsPushState = window.history && window.history.pushState && window.history.replaceState && window.history.state !== void 0;
browserIsntBuggy = !navigator.userAgent.match(/CriOS\//);
requestMethodIsSafe = requestMethod === 'GET' || requestMethod === '';
if (browserSupportsPushState && browserIsntBuggy && requestMethodIsSafe) {
visit = function(url) {
referer = document.location.href;
cacheCurrentPage();
return fetchReplacement(url);
};
initializeTurbolinks();
} else {
visit = function(url) {
return document.location.href = url;
};
}
this.Turbolinks = {
visit: visit,
pagesCached: pagesCached
};
}).call(this);
+13
View File
@@ -0,0 +1,13 @@
(function(){var s,A,B,p,C,t,q,u,D,v,E,f,F,G,H,I,J,w,K,L,M,k,N,O,P,g,Q,R,S,r,T,U,V,x,l,W,y,X,Y,h,n,c,aa={}.hasOwnProperty,ba=[].indexOf||function(a){for(var b=0,e=this.length;b<e;b++)if(b in this&&this[b]===a)return b;return-1};q=10;k=r=f=null;g={};v=null;y=(null!=(p=document.cookie.match(/request_method=(\w+)/))?p[1].toUpperCase():void 0)||"";c=null;J=function(a){var b;h("page:fetch");b=l(a);null!=c&&c.abort();c=new XMLHttpRequest;c.open("GET",b,!0);c.setRequestHeader("Accept","text/html, application/xhtml+xml, application/xml");
c.setRequestHeader("X-XHR-Referer",r);c.onload=function(){var b;h("page:receive");return(b=R())?(T(a),u.apply(null,H(b)),U(),document.location.hash?document.location.href=document.location.href:X(),h("page:load")):document.location.href=a};c.onloadend=function(){return c=null};c.onabort=function(){return x()};c.onerror=function(){return document.location.href=a};return c.send()};I=function(a){t();a=g[a];null!=c&&c.abort();u(a.title,a.body);S(a);return h("page:restore")};t=function(){g[f.position]=
{url:document.location.href,body:document.body,title:document.title,positionY:window.pageYOffset,positionX:window.pageXOffset};return D(q)};D=function(a){for(var b in g)aa.call(g,b)&&b<=f.position-a&&(g[b]=null)};u=function(a,b,e,d){document.title=a;document.documentElement.replaceChild(b,document.body);null!=e&&s.update(e);W();d&&F();f=window.history.state;return h("page:change")};F=function(){var a,b,e,d,z,c,Z,m,$,f;z=Array.prototype.slice.call(document.body.querySelectorAll('script:not([data-turbolinks-eval="false"])'));
c=0;for(Z=z.length;c<Z;c++)if(d=z[c],""===($=d.type)||"text/javascript"===$){b=document.createElement("script");f=d.attributes;e=0;for(m=f.length;e<m;e++)a=f[e],b.setAttribute(a.name,a.value);b.appendChild(document.createTextNode(d.innerHTML));e=d.parentNode;a=d.nextSibling;e.removeChild(d);e.insertBefore(b,a)}};W=function(){var a,b,c,d;b=Array.prototype.slice.call(document.body.getElementsByTagName("noscript"));c=0;for(d=b.length;c<d;c++)a=b[c],a.parentNode.removeChild(a)};T=function(a){if(a!==r)return window.history.pushState({turbolinks:!0,
position:f.position+1},"",a)};U=function(){var a,b;if(a=c.getResponseHeader("X-XHR-Redirected-To"))return b=l(a)===a?document.location.hash:"",window.history.replaceState(f,"",a+b)};x=function(){return window.history.replaceState({turbolinks:!0,position:Date.now()},"",document.location.href)};V=function(){return f=window.history.state};S=function(a){return window.scrollTo(a.positionX,a.positionY)};X=function(){return window.scrollTo(0,0)};l=function(a){var b;b=a;null==a.href&&(b=document.createElement("A"),
b.href=a);return b.href.replace(b.hash,"")};h=function(a){var b;b=document.createEvent("Events");b.initEvent(a,!0,!0);return document.dispatchEvent(b)};Q=function(){return!h("page:before-change")};R=function(){var a,b,e,d;b=function(){return c.getResponseHeader("Content-Type").match(/^(?:text\/html|application\/xhtml\+xml|application\/xml)(?:;|$)/)};e=function(a){var b,c,m,d;m=a.head.childNodes;d=[];b=0;for(c=m.length;b<c;b++)a=m[b],null!=("function"===typeof a.getAttribute?a.getAttribute("data-turbolinks-track"):
void 0)&&d.push(a.src||a.href);return d};a=function(a){k||(k=e(document));a=e(a);return a.length!==k.length||d(a,k).length!==k.length};d=function(a,b){var c,d,e,f;a.length>b.length&&(c=[b,a],a=c[0],b=c[1]);f=[];d=0;for(e=a.length;d<e;d++)c=a[d],0<=ba.call(b,c)&&f.push(c);return f};if(!function(){var a;return 400<=(a=c.status)&&600>a}()&&b()&&(b=v(c.responseText))&&!a(b))return b};H=function(a){var b;b=a.querySelector("title");return[null!=b?b.textContent:void 0,a.body,s.get(a).token,"runScripts"]};
s={get:function(a){var b;null==a&&(a=document);return{node:b=a.querySelector('meta[name="csrf-token"]'),token:null!=b?"function"===typeof b.getAttribute?b.getAttribute("content"):void 0:void 0}},update:function(a){var b;b=this.get();if(null!=b.token&&null!=a&&b.token!==a)return b.node.setAttribute("content",a)}};B=function(){var a,b,c,d,f;b=function(a){return(new DOMParser).parseFromString(a,"text/html")};a=function(a){var b;b=document.implementation.createHTMLDocument("");b.documentElement.innerHTML=
a;return b};c=function(a){var b;b=document.implementation.createHTMLDocument("");b.open("replace");b.write(a);b.close();return b};try{if(window.DOMParser)return d=b("<html><body><p>test"),b}catch(g){return d=a("<html><body><p>test"),a}finally{if(1!==(null!=d?null!=(f=d.body)?f.childNodes.length:void 0:void 0))return c}};M=function(a){if(!a.defaultPrevented)return document.removeEventListener("click",w,!1),document.addEventListener("click",w,!1)};w=function(a){var b;if(!a.defaultPrevented&&(b=G(a),
"A"===b.nodeName&&!K(a,b)))return Q()||n(b.href),a.preventDefault()};G=function(a){for(a=a.target;a.parentNode&&"A"!==a.nodeName;)a=a.parentNode;return a};E=function(a){return location.protocol!==a.protocol||location.host!==a.host};A=function(a){return(a.hash&&l(a))===l(location)||a.href===location.href+"#"};O=function(a){a=l(a);return a.match(/\.[a-z]+(\?.*)?$/g)&&!a.match(/\.html?(\?.*)?$/g)};N=function(a){for(var b;!b&&a!==document;)b=null!=a.getAttribute("data-no-turbolink"),a=a.parentNode;return b};
Y=function(a){return 0!==a.target.length};P=function(a){return 1<a.which||a.metaKey||a.ctrlKey||a.shiftKey||a.altKey};K=function(a,b){return E(b)||A(b)||O(b)||N(b)||Y(b)||P(a)};L=function(){x();V();v=B();document.addEventListener("click",M,!0);return window.addEventListener("popstate",function(a){var b;b=a.state;if(null!=b&&b.turbolinks)return g[b.position]?I(b.position):n(a.target.location.href)},!1)};C=window.history&&window.history.pushState&&window.history.replaceState&&void 0!==window.history.state;
p=!navigator.userAgent.match(/CriOS\//);C&&p&&("GET"===y||""===y)?(n=function(a){r=document.location.href;t();return J(a)},L()):n=function(a){return document.location.href=a};this.Turbolinks={visit:n,pagesCached:function(a){null==a&&(a=q);if(/^[\d]+$/.test(a))return q=parseInt(a)}}}).call(this);
//# sourceMappingURL=turbolinks.min.map
File diff suppressed because one or more lines are too long
+22
View File
@@ -0,0 +1,22 @@
{
"name": "turbolinks",
"filename": "turbolinks.min.js",
"version": "1.3.0",
"description": "Turbolinks makes following links in your web application faster. Instead of letting the browser recompile the JavaScript and CSS between each page change, it keeps the current page instance alive and replaces only the body and the title in the head. Think CGI vs persistent process.",
"homepage": "https://github.com/rails/turbolinks/",
"keywords": [
"rails",
"popular"
],
"maintainers": [
{
"name": "The Ruby on Rails Project"
}
],
"repositories": [
{
"type": "git",
"url": "https://github.com/rails/turbolinks.git"
}
]
}