2014-08-19 03:37:56 +02:00
/ * S o m e s c r i p t s a n d s t u f f
-- -- -- -- -- -- -- -- -- -- -- -- -- * /
2015-09-02 18:48:09 +02:00
2014-08-19 03:37:56 +02:00
/ * T a r g e t - B l a n k f o r C S S - C l a s s " e x t e r n a l "
-- -- -- -- -- -- -- -- -- -- -- -- -- * /
function externalLinks ( ) {
if ( ! document . getElementsByTagName ) { return ; }
var anchors = document . getElementsByTagName ( "a" ) ;
for ( var i = 0 ; i < anchors . length ; i ++ ) {
var anchor = anchors [ i ] ;
if ( anchor . getAttribute ( "href" ) && anchor . getAttribute ( "class" ) === "external" ) {
anchor . target = "_blank" ;
}
}
}
window . onload = externalLinks ;
// or in jQuery
/ *
$ ( 'a[rel="external"]' ) . attr ( 'target' , '_blank' ) ;
* /
/ *
HTML5 Shiv v3 . 7.0 | @ afarkas @ jdalton @ jon _neal @ rem | MIT / GPL2 Licensed
* /
( function ( l , f ) { function m ( ) { var a = e . elements ; return "string" == typeof a ? a . split ( " " ) : a } function i ( a ) { var b = n [ a [ o ] ] ; b || ( b = { } , h ++ , a [ o ] = h , n [ h ] = b ) ; return b } function p ( a , b , c ) { b || ( b = f ) ; if ( g ) return b . createElement ( a ) ; c || ( c = i ( b ) ) ; b = c . cache [ a ] ? c . cache [ a ] . cloneNode ( ) : r . test ( a ) ? ( c . cache [ a ] = c . createElem ( a ) ) . cloneNode ( ) : c . createElem ( a ) ; return b . canHaveChildren && ! s . test ( a ) ? c . frag . appendChild ( b ) : b } function t ( a , b ) { if ( ! b . cache ) b . cache = { } , b . createElem = a . createElement , b . createFrag = a . createDocumentFragment , b . frag = b . createFrag ( ) ;
a . createElement = function ( c ) { return ! e . shivMethods ? b . createElem ( c ) : p ( c , a , b ) } ; a . createDocumentFragment = Function ( "h,f" , "return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&(" + m ( ) . join ( ) . replace ( /[\w\-]+/g , function ( a ) { b . createElem ( a ) ; b . frag . createElement ( a ) ; return 'c("' + a + '")' } ) + ");return n}" ) ( e , b . frag ) } function q ( a ) { a || ( a = f ) ; var b = i ( a ) ; if ( e . shivCSS && ! j && ! b . hasCSS ) { var c , d = a ; c = d . createElement ( "p" ) ; d = d . getElementsByTagName ( "head" ) [ 0 ] || d . documentElement ; c . innerHTML = "x<style>article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}</style>" ;
c = d . insertBefore ( c . lastChild , d . firstChild ) ; b . hasCSS = ! ! c } g || t ( a , b ) ; return a } var k = l . html5 || { } , s = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i , r = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i , j , o = "_html5shiv" , h = 0 , n = { } , g ; ( function ( ) { try { var a = f . createElement ( "a" ) ; a . innerHTML = "<xyz></xyz>" ; j = "hidden" in a ; var b ; if ( ! ( b = 1 == a . childNodes . length ) ) { f . createElement ( "a" ) ; var c = f . createDocumentFragment ( ) ; b = "undefined" == typeof c . cloneNode ||
"undefined" == typeof c . createDocumentFragment || "undefined" == typeof c . createElement } g = b } catch ( d ) { g = j = ! 0 } } ) ( ) ; var e = { elements : k . elements || "abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video" , version : "3.7.0" , shivCSS : ! 1 !== k . shivCSS , supportsUnknownElements : g , shivMethods : ! 1 !== k . shivMethods , type : "default" , shivDocument : q , createElement : p , createDocumentFragment : function ( a , b ) { a || ( a = f ) ;
if ( g ) return a . createDocumentFragment ( ) ; for ( var b = b || i ( a ) , c = b . frag . cloneNode ( ) , d = 0 , e = m ( ) , h = e . length ; d < h ; d ++ ) c . createElement ( e [ d ] ) ; return c } } ; l . html5 = e ; q ( f ) } ) ( this , document ) ;
/* InstantClick 3.0.1 | (C) 2014 Alexandre Dieulot | http://instantclick.io/license.html */
var InstantClick = function ( document , location ) {
// Internal variables
var $ua = navigator . userAgent ,
$hasTouch = 'createTouch' in document ,
$currentLocationWithoutHash ,
$urlToPreload ,
$preloadTimer ,
// Preloading-related variables
$history = { } ,
$xhr ,
$url = false ,
$title = false ,
$mustRedirect = false ,
$body = false ,
$timing = { } ,
$isPreloading = false ,
$isWaitingForCompletion = false ,
$trackedAssets = [ ] ,
// Variables defined by public functions
$useWhitelist ,
$preloadOnMousedown ,
$delayBeforePreload ,
$eventsCallbacks = {
fetch : [ ] ,
receive : [ ] ,
wait : [ ] ,
change : [ ]
}
////////// HELPERS //////////
function removeHash ( url ) {
var index = url . indexOf ( '#' )
if ( index < 0 ) {
return url
}
return url . substr ( 0 , index )
}
function getLinkTarget ( target ) {
while ( target . nodeName != 'A' ) {
target = target . parentNode
}
return target
}
function isBlacklisted ( elem ) {
do {
if ( ! elem . hasAttribute ) { // Parent of <html>
break
}
if ( elem . hasAttribute ( 'data-instant' ) ) {
return false
}
if ( elem . hasAttribute ( 'data-no-instant' ) ) {
return true
}
}
while ( elem = elem . parentNode ) ;
return false
}
function isWhitelisted ( elem ) {
do {
if ( ! elem . hasAttribute ) { // Parent of <html>
break
}
if ( elem . hasAttribute ( 'data-no-instant' ) ) {
return false
}
if ( elem . hasAttribute ( 'data-instant' ) ) {
return true
}
}
while ( elem = elem . parentNode ) ;
return false
}
function triggerPageEvent ( eventType , arg1 ) {
for ( var i = 0 ; i < $eventsCallbacks [ eventType ] . length ; i ++ ) {
$eventsCallbacks [ eventType ] [ i ] ( arg1 )
}
/* The `change` event takes one boolean argument: "isInitialLoad" */
}
function changePage ( title , body , newUrl , scrollY ) {
document . title = title
document . documentElement . replaceChild ( body , document . body )
/ * W e c a n n o t j u s t u s e ` d o c u m e n t . b o d y = d o c . b o d y ` , i t c a u s e s S a f a r i ( t e s t e d
5.1 , 6.0 and Mobile 7.0 ) to execute script tags directly .
* /
if ( newUrl ) {
history . pushState ( null , null , newUrl )
var hashIndex = newUrl . indexOf ( '#' ) ,
hashElem = hashIndex > - 1
&& document . getElementById ( newUrl . substr ( hashIndex + 1 ) ) ,
offset = 0
if ( hashElem ) {
while ( hashElem . offsetParent ) {
offset += hashElem . offsetTop
hashElem = hashElem . offsetParent
}
}
scrollTo ( 0 , offset )
$currentLocationWithoutHash = removeHash ( newUrl )
}
else {
scrollTo ( 0 , scrollY )
}
instantanize ( )
bar . done ( )
triggerPageEvent ( 'change' , false )
}
function setPreloadingAsHalted ( ) {
$isPreloading = false
$isWaitingForCompletion = false
}
////////// EVENT HANDLERS //////////
function mousedown ( e ) {
preload ( getLinkTarget ( e . target ) . href )
}
function mouseover ( e ) {
var a = getLinkTarget ( e . target )
a . addEventListener ( 'mouseout' , mouseout )
if ( ! $delayBeforePreload ) {
preload ( a . href )
}
else {
$urlToPreload = a . href
$preloadTimer = setTimeout ( preload , $delayBeforePreload )
}
}
function touchstart ( e ) {
var a = getLinkTarget ( e . target )
if ( $preloadOnMousedown ) {
a . removeEventListener ( 'mousedown' , mousedown )
}
else {
a . removeEventListener ( 'mouseover' , mouseover )
}
preload ( a . href )
}
function click ( e ) {
if ( e . which > 1 || e . metaKey || e . ctrlKey ) { // Opening in new tab
return
}
e . preventDefault ( )
display ( getLinkTarget ( e . target ) . href )
}
function mouseout ( ) {
if ( $preloadTimer ) {
clearTimeout ( $preloadTimer )
$preloadTimer = false
return
}
if ( ! $isPreloading || $isWaitingForCompletion ) {
return
}
$xhr . abort ( )
setPreloadingAsHalted ( )
}
function readystatechange ( ) {
if ( $xhr . readyState < 4 ) {
return
}
if ( $xhr . status == 0 ) {
/* Request aborted */
return
}
$timing . ready = + new Date - $timing . start
triggerPageEvent ( 'receive' )
if ( $xhr . getResponseHeader ( 'Content-Type' ) . match ( /\/(x|ht|xht)ml/ ) ) {
var doc = document . implementation . createHTMLDocument ( '' )
doc . documentElement . innerHTML = $xhr . responseText
$title = doc . title
$body = doc . body
var urlWithoutHash = removeHash ( $url )
$history [ urlWithoutHash ] = {
body : $body ,
title : $title ,
scrollY : urlWithoutHash in $history ? $history [ urlWithoutHash ] . scrollY : 0
}
var elems = doc . head . children ,
found = 0 ,
elem ,
data
for ( var i = elems . length - 1 ; i >= 0 ; i -- ) {
elem = elems [ i ]
if ( elem . hasAttribute ( 'data-instant-track' ) ) {
data = elem . getAttribute ( 'href' ) || elem . getAttribute ( 'src' ) || elem . innerHTML
for ( var j = $trackedAssets . length - 1 ; j >= 0 ; j -- ) {
if ( $trackedAssets [ j ] == data ) {
found ++
}
}
}
}
if ( found != $trackedAssets . length ) {
$mustRedirect = true // Assets have changed
}
}
else {
$mustRedirect = true // Not an HTML document
}
if ( $isWaitingForCompletion ) {
$isWaitingForCompletion = false
display ( $url )
}
}
////////// MAIN FUNCTIONS //////////
function instantanize ( isInitializing ) {
var as = document . getElementsByTagName ( 'a' ) ,
a ,
domain = location . protocol + '//' + location . host
for ( var i = as . length - 1 ; i >= 0 ; i -- ) {
a = as [ i ]
if ( a . target // target="_blank" etc.
|| a . hasAttribute ( 'download' )
|| a . href . indexOf ( domain + '/' ) != 0 // Another domain, or no href attribute
|| ( a . href . indexOf ( '#' ) > - 1
&& removeHash ( a . href ) == $currentLocationWithoutHash ) // Anchor
|| ( $useWhitelist
? ! isWhitelisted ( a )
: isBlacklisted ( a ) )
) {
continue
}
a . addEventListener ( 'touchstart' , touchstart )
if ( $preloadOnMousedown ) {
a . addEventListener ( 'mousedown' , mousedown )
}
else {
a . addEventListener ( 'mouseover' , mouseover )
}
a . addEventListener ( 'click' , click )
}
if ( ! isInitializing ) {
var scripts = document . body . getElementsByTagName ( 'script' ) ,
script ,
copy ,
parentNode ,
nextSibling
for ( i = 0 , j = scripts . length ; i < j ; i ++ ) {
script = scripts [ i ]
if ( script . hasAttribute ( 'data-no-instant' ) ) {
continue
}
copy = document . createElement ( 'script' )
if ( script . src ) {
copy . src = script . src
}
if ( script . innerHTML ) {
copy . innerHTML = script . innerHTML
}
parentNode = script . parentNode
nextSibling = script . nextSibling
parentNode . removeChild ( script )
parentNode . insertBefore ( copy , nextSibling )
}
}
}
function preload ( url ) {
if ( ! $preloadOnMousedown
&& 'display' in $timing
&& + new Date - ( $timing . start + $timing . display ) < 100 ) {
/ * A f t e r a p a g e i s d i s p l a y e d , i f t h e u s e r ' s c u r s o r h a p p e n s t o b e a b o v e
a link a mouseover event will be in most browsers triggered
automatically , and in other browsers it will be triggered when the
user moves his mouse by 1 px .
Here are the behavior I noticed , all on Windows :
- Safari 5.1 : auto - triggers after 0 ms
- IE 11 : auto - triggers after 30 - 80 ms ( depends on page ' s size ? )
- Firefox : auto - triggers after 10 ms
- Opera 18 : auto - triggers after 10 ms
- Chrome : triggers when cursor moved
- Opera 12.16 : triggers when cursor moved
To remedy to this , we do not start preloading if last display
occurred less than 100 ms ago . If they happen to click on the link ,
they will be redirected .
* /
return
}
if ( $preloadTimer ) {
clearTimeout ( $preloadTimer )
$preloadTimer = false
}
if ( ! url ) {
url = $urlToPreload
}
if ( $isPreloading && ( url == $url || $isWaitingForCompletion ) ) {
return
}
$isPreloading = true
$isWaitingForCompletion = false
$url = url
$body = false
$mustRedirect = false
$timing = {
start : + new Date
}
triggerPageEvent ( 'fetch' )
$xhr . open ( 'GET' , url )
$xhr . send ( )
}
function display ( url ) {
if ( ! ( 'display' in $timing ) ) {
$timing . display = + new Date - $timing . start
}
if ( $preloadTimer ) {
/ * H a p p e n s w h e n t h e r e ’ s a d e l a y b e f o r e p r e l o a d i n g a n d t h a t d e l a y
hasn 't expired (preloading didn' t kick in ) .
* /
if ( $url && $url != url ) {
/ * H a p p e n s w h e n t h e u s e r c l i c k s o n a l i n k b e f o r e p r e l o a d i n g
kicks in while another link is already preloading .
* /
location . href = url
return
}
preload ( url )
bar . start ( 0 , true )
triggerPageEvent ( 'wait' )
$isWaitingForCompletion = true
return
}
if ( ! $isPreloading || $isWaitingForCompletion ) {
/ * I f t h e p a g e i s n ' t p r e l o a d e d , i t l i k e l y m e a n s t h e u s e r h a s f o c u s e d
on a link ( with his Tab key ) and then pressed Return , which
triggered a click .
Because very few people do this , it isn ' t worth handling this case
and preloading on focus ( also , focusing on a link doesn 't mean it' s
likely that you ' ll "click" on it ) , so we just redirect them when
they "click" .
It could also mean the user hovered over a link less than 100 ms
after a page display , thus we didn ' t start the preload ( see
comments in ` preload() ` for the rationale behind this . )
If the page is waiting for completion , the user clicked twice while
the page was preloading . Either on the same link or on another
link . If it ' s the same link something might have gone wrong ( or he
could have double clicked ) , so we send him to the page the old way .
If it 's another link, it hasn' t been preloaded , so we redirect the
user the old way .
* /
location . href = url
return
}
if ( $mustRedirect ) {
location . href = $url
return
}
if ( ! $body ) {
bar . start ( 0 , true )
triggerPageEvent ( 'wait' )
$isWaitingForCompletion = true
return
}
$history [ $currentLocationWithoutHash ] . scrollY = pageYOffset
setPreloadingAsHalted ( )
changePage ( $title , $body , $url )
}
////////// PROGRESS BAR FUNCTIONS //////////
var bar = function ( ) {
var $barContainer ,
$barElement ,
$barTransformProperty ,
$barProgress ,
$barTimer
function init ( ) {
$barContainer = document . createElement ( 'div' )
$barContainer . id = 'instantclick'
$barElement = document . createElement ( 'div' )
$barElement . id = 'instantclick-bar'
$barElement . className = 'instantclick-bar'
$barContainer . appendChild ( $barElement )
var vendors = [ 'Webkit' , 'Moz' , 'O' ]
$barTransformProperty = 'transform'
if ( ! ( $barTransformProperty in $barElement . style ) ) {
for ( var i = 0 ; i < 3 ; i ++ ) {
if ( vendors [ i ] + 'Transform' in $barElement . style ) {
$barTransformProperty = vendors [ i ] + 'Transform'
}
}
}
var transitionProperty = 'transition'
if ( ! ( transitionProperty in $barElement . style ) ) {
for ( var i = 0 ; i < 3 ; i ++ ) {
if ( vendors [ i ] + 'Transition' in $barElement . style ) {
transitionProperty = '-' + vendors [ i ] . toLowerCase ( ) + '-' + transitionProperty
}
}
}
var style = document . createElement ( 'style' )
style . innerHTML = '#instantclick{position:' + ( $hasTouch ? 'absolute' : 'fixed' ) + ';top:0;left:0;width:100%;pointer-events:none;z-index:2147483647;' + transitionProperty + ':opacity .25s .1s}'
+ '.instantclick-bar{background:#29d;width:100%;margin-left:-100%;height:2px;' + transitionProperty + ':all .25s}'
/ * W e s e t t h e b a r ' s b a c k g r o u n d i n ` . i n s t a n t c l i c k - b a r ` s o t h a t i t c a n b e
overriden in CSS with ` #instantclick-bar ` , as IDs have higher priority .
* /
document . head . appendChild ( style )
if ( $hasTouch ) {
updatePositionAndScale ( )
addEventListener ( 'resize' , updatePositionAndScale )
addEventListener ( 'scroll' , updatePositionAndScale )
}
}
function start ( at , jump ) {
$barProgress = at
if ( document . getElementById ( $barContainer . id ) ) {
document . body . removeChild ( $barContainer )
}
$barContainer . style . opacity = '1'
if ( document . getElementById ( $barContainer . id ) ) {
document . body . removeChild ( $barContainer )
/* So there's no CSS animation if already done once and it goes from 1 to 0 */
}
update ( )
if ( jump ) {
setTimeout ( jumpStart , 0 )
/* Must be done in a timer, otherwise the CSS animation doesn't happen. */
}
clearTimeout ( $barTimer )
$barTimer = setTimeout ( inc , 500 )
}
function jumpStart ( ) {
$barProgress = 10
update ( )
}
function inc ( ) {
$barProgress += 1 + ( Math . random ( ) * 2 )
if ( $barProgress >= 98 ) {
$barProgress = 98
}
else {
$barTimer = setTimeout ( inc , 500 )
}
update ( )
}
function update ( ) {
$barElement . style [ $barTransformProperty ] = 'translate(' + $barProgress + '%)'
if ( ! document . getElementById ( $barContainer . id ) ) {
document . body . appendChild ( $barContainer )
}
}
function done ( ) {
if ( document . getElementById ( $barContainer . id ) ) {
clearTimeout ( $barTimer )
$barProgress = 100
update ( )
$barContainer . style . opacity = '0'
/* If you're debugging, setting this to 0.5 is handy. */
return
}
/* The bar container hasn't been appended: It's a new page. */
start ( $barProgress == 100 ? 0 : $barProgress )
/* $barProgress is 100 on popstate, usually. */
setTimeout ( done , 0 )
/* Must be done in a timer, otherwise the CSS animation doesn't happen. */
}
function updatePositionAndScale ( ) {
/ * A d a p t e d f r o m c o d e b y S a m S t e p h e n s o n a n d M i s l a v M a r o h n i ć
http : //signalvnoise.com/posts/2407
* /
$barContainer . style . left = pageXOffset + 'px'
$barContainer . style . width = innerWidth + 'px'
$barContainer . style . top = pageYOffset + 'px'
var landscape = 'orientation' in window && Math . abs ( orientation ) == 90 ,
scaleY = innerWidth / screen [ landscape ? 'height' : 'width' ] * 2
/ * W e m u l t i p l y t h e s i z e b y 2 b e c a u s e t h e p r o g r e s s b a r i s h a r d e r
to notice on a mobile device .
* /
$barContainer . style [ $barTransformProperty ] = 'scaleY(' + scaleY + ')'
}
return {
init : init ,
start : start ,
done : done
}
} ( )
////////// PUBLIC VARIABLE AND FUNCTIONS //////////
var supported = 'pushState' in history
&& ( ! $ua . match ( 'Android' ) || $ua . match ( 'Chrome/' ) )
&& location . protocol != "file:"
/ * T h e s t a t e o f A n d r o i d ' s A O S P b r o w s e r s :
2.3 . 7 : pushState appears to work correctly , but
` doc.documentElement.innerHTML = body ` is buggy .
See details here : http : //stackoverflow.com/q/21918564
Note an issue anymore , but it may fail where 3.0 do , this needs
testing again .
3.0 : pushState appears to work correctly ( though the URL bar is only
updated on focus ) , but
` document.documentElement.replaceChild(doc.body, document.body) `
throws DOMException : WRONG _DOCUMENT _ERR .
4.0 . 2 : Doesn ' t support pushState .
4.0 . 4 ,
4.1 . 1 ,
4.2 ,
4.3 : pushState is here , but it doesn ' t update the URL bar .
( Great logic there . )
4.4 : Works correctly . Claims to be 'Chrome/30.0.0.0' .
All androids tested with Android SDK ' s Emulator .
Version numbers are from the browser ' s user agent .
Because of this mess , the only whitelisted browser on Android is Chrome .
* /
function init ( ) {
if ( $currentLocationWithoutHash ) {
/* Already initialized */
return
}
if ( ! supported ) {
triggerPageEvent ( 'change' , true )
return
}
for ( var i = arguments . length - 1 ; i >= 0 ; i -- ) {
var arg = arguments [ i ]
if ( arg === true ) {
$useWhitelist = true
}
else if ( arg == 'mousedown' ) {
$preloadOnMousedown = true
}
else if ( typeof arg == 'number' ) {
$delayBeforePreload = arg
}
}
$currentLocationWithoutHash = removeHash ( location . href )
$history [ $currentLocationWithoutHash ] = {
body : document . body ,
title : document . title ,
scrollY : pageYOffset
}
var elems = document . head . children ,
elem ,
data
for ( var i = elems . length - 1 ; i >= 0 ; i -- ) {
elem = elems [ i ]
if ( elem . hasAttribute ( 'data-instant-track' ) ) {
data = elem . getAttribute ( 'href' ) || elem . getAttribute ( 'src' ) || elem . innerHTML
/ * W e c a n ' t u s e j u s t ` e l e m . h r e f ` a n d ` e l e m . s r c ` b e c a u s e w e c a n ' t
retrieve ` href ` s and ` src ` s from the Ajax response .
* /
$trackedAssets . push ( data )
}
}
$xhr = new XMLHttpRequest ( )
$xhr . addEventListener ( 'readystatechange' , readystatechange )
instantanize ( true )
bar . init ( )
triggerPageEvent ( 'change' , true )
addEventListener ( 'popstate' , function ( ) {
var loc = removeHash ( location . href )
if ( loc == $currentLocationWithoutHash ) {
return
}
if ( ! ( loc in $history ) ) {
location . href = location . href
/ * R e l o a d s t h e p a g e w h i l e u s i n g c a c h e f o r s c r i p t s , s t y l e s a n d i m a g e s ,
unlike ` location.reload() ` * /
return
}
$history [ $currentLocationWithoutHash ] . scrollY = pageYOffset
$currentLocationWithoutHash = loc
changePage ( $history [ loc ] . title , $history [ loc ] . body , false , $history [ loc ] . scrollY )
} )
}
function on ( eventType , callback ) {
$eventsCallbacks [ eventType ] . push ( callback )
}
/ * T h e d e b u g f u n c t i o n i s n ' t i n c l u d e d b y d e f a u l t t o r e d u c e f i l e s i z e .
To enable it , add a slash at the beginning of the comment englobing
the debug function , and uncomment "debug: debug," in the return
statement below the function . * /
/ *
function debug ( ) {
return {
currentLocationWithoutHash : $currentLocationWithoutHash ,
history : $history ,
xhr : $xhr ,
url : $url ,
title : $title ,
mustRedirect : $mustRedirect ,
body : $body ,
timing : $timing ,
isPreloading : $isPreloading ,
isWaitingForCompletion : $isWaitingForCompletion
}
}
//*/
////////////////////
return {
// debug: debug,
supported : supported ,
init : init ,
on : on
}
} ( document , location ) ;