diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5455e0c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +.sass-cache diff --git a/Checklist.md b/Checklist.md new file mode 100644 index 0000000..c315488 --- /dev/null +++ b/Checklist.md @@ -0,0 +1,4 @@ +#Design-Checklist + +- Responsive Design – Mobile: 320, 360, 400px +- Create Favicons (ICO!) with multiple sizes (16, 32, 48, 64px) diff --git a/css/main.css b/css/main.css index f1f8bfa..29440a4 100644 --- a/css/main.css +++ b/css/main.css @@ -152,7 +152,8 @@ figure { * Address differences between Firefox and other browsers. */ hr { - box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box; height: 0; } /** @@ -244,7 +245,8 @@ input { * 2. Remove excess padding in IE 8/9/10. */ input[type="checkbox"], input[type="radio"] { - box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } @@ -265,6 +267,7 @@ input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-o input[type="search"] { -webkit-appearance: textfield; /* 1 */ + -webkit-box-sizing: content-box; /* 2 */ box-sizing: content-box; } @@ -324,13 +327,15 @@ td, th { /* Reset --------------------------*/ *, *:before, *:after { - box-sizing: inherit; + -webkit-box-sizing: inherit; + box-sizing: inherit; padding: 0; margin: 0; } html { height: 100%; - box-sizing: border-box; } + -webkit-box-sizing: border-box; + box-sizing: border-box; } /* Ideal Viewport-Fix for IE */ @-ms-viewport { @@ -448,7 +453,7 @@ ul li { a { color: #660000; -webkit-transition: color 0.2s ease; - transition: color 0.2s ease; } + transition: color 0.2s ease; } a:hover, a:active, a:focus { color: #b30000; } a:active { diff --git a/css/main.min.css b/css/main.min.css index 6b213e4..a1db701 100644 --- a/css/main.min.css +++ b/css/main.min.css @@ -1 +1 @@ -html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}*,:after,:before{box-sizing:inherit;padding:0;margin:0}html{height:100%;box-sizing:border-box}@-ms-viewport{width:device-width}.clearfix::after,.clearfix::before{content:" ";display:table}.clearfix::after{clear:both}canvas,iframe,img,svg,video{max-width:100%}.video{position:relative;height:0;padding-bottom:56.25%}.video>*{position:absolute;top:0;left:0;height:100%;width:100%}.container{margin:0 auto}.row{overflow:hidden;max-width:960px;margin:0 auto}.fullrow{max-width:100%}.column{float:left;margin-left:5%}.column:first-child{margin-left:0}.column.full{width:100%}.column.three-fourth{width:63.75%}.column.two-thirds{width:65%}.column.half{width:47.5%}.column.one-third{width:30%}.column.one-fourth{width:21.25%}body{color:#000;font-family:Open Sans,Helvetica,Arial,sans-serif;font-size:12pt;-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto}h1,h2,h3{font-family:Open Sans,Helvetica,Arial,sans-serif;font-weight:700;line-height:1.2em;margin:.4em 0}h1{font-size:2em;word-break:break-all}h2{font-size:1.5em}h3{font-size:1.25em}p{line-height:1.45em;padding:.5em 0}ul li{margin:.3em 0 .3em .5em;list-style-position:inside;list-style-type:square;font-size:1em}ul li p{padding-left:1em}a{color:#600;-webkit-transition:color .2s ease;transition:color .2s ease}a:active,a:focus,a:hover{color:#b30000}a:active{position:relative;top:1px}a.notdown:active{position:inherit}@media screen{a.external:after{content:"\00A0" "[" "\2197" "]"}}@media print{a[href]:after{content:" (" attr(href) ")"}}#instantclick-bar{background:red}.fa{margin-right:.3em;speak:none}.button{text-overflow:ellipsis}@media screen and (max-width:768px){.column.full,.column.half,.column.three-fourth,.column.two-thirds{float:none;margin:0;width:100%}.column.one-fourth,.column.one-third{float:left;margin:0;width:50%;padding:.4em}}@media screen and (max-width:568px){.column.one-third,.column.two-third{float:none;margin:0;width:100%}}@media screen and (max-width:480px){.column.full,.column.half,.column.one-fourth,.column.one-third,.column.three-fourth,.column.two-thirds{float:left;margin:0;width:100%}} \ No newline at end of file +html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}*,:after,:before{-webkit-box-sizing:inherit;box-sizing:inherit;padding:0;margin:0}html{height:100%;-webkit-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.clearfix::after,.clearfix::before{content:" ";display:table}.clearfix::after{clear:both}canvas,iframe,img,svg,video{max-width:100%}.video{position:relative;height:0;padding-bottom:56.25%}.video>*{position:absolute;top:0;left:0;height:100%;width:100%}.container{margin:0 auto}.row{overflow:hidden;max-width:960px;margin:0 auto}.fullrow{max-width:100%}.column{float:left;margin-left:5%}.column:first-child{margin-left:0}.column.full{width:100%}.column.three-fourth{width:63.75%}.column.two-thirds{width:65%}.column.half{width:47.5%}.column.one-third{width:30%}.column.one-fourth{width:21.25%}body{color:#000;font-family:Open Sans,Helvetica,Arial,sans-serif;font-size:12pt;-webkit-font-smoothing:subpixel-antialiased;-moz-osx-font-smoothing:auto}h1,h2,h3{font-family:Open Sans,Helvetica,Arial,sans-serif;font-weight:700;line-height:1.2em;margin:.4em 0}h1{font-size:2em;word-break:break-all}h2{font-size:1.5em}h3{font-size:1.25em}p{line-height:1.45em;padding:.5em 0}ul li{margin:.3em 0 .3em .5em;list-style-position:inside;list-style-type:square;font-size:1em}ul li p{padding-left:1em}a{color:#600;-webkit-transition:color .2s ease;transition:color .2s ease}a:active,a:focus,a:hover{color:#b30000}a:active{position:relative;top:1px}a.notdown:active{position:inherit}@media screen{a.external:after{content:"\00A0" "[" "\2197" "]"}}@media print{a[href]:after{content:" (" attr(href) ")"}}#instantclick-bar{background:red}.fa{margin-right:.3em;speak:none}.button{text-overflow:ellipsis}@media screen and (max-width:768px){.column.full,.column.half,.column.three-fourth,.column.two-thirds{float:none;margin:0;width:100%}.column.one-fourth,.column.one-third{float:left;margin:0;width:50%;padding:.4em}}@media screen and (max-width:568px){.column.one-third,.column.two-third{float:none;margin:0;width:100%}}@media screen and (max-width:480px){.column.full,.column.half,.column.one-fourth,.column.one-third,.column.three-fourth,.column.two-thirds{float:left;margin:0;width:100%}} \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index b74494c..472d8f6 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,24 +1,79 @@ -// include gulp -var gulp = require('gulp'); +// Require all those npm-modules -// include plug-ins -var jshint = require('gulp-jshint'); -var sass = require('gulp-sass'); -var prefix = require('gulp-autoprefixer'); -var rename = require('gulp-rename'); -var cssmin = require('gulp-cssmin'); -var watch = require('gulp-watch'); -var imagemin = require('gulp-imagemin'); -var pngcrush = require('imagemin-pngcrush'); +var gulp = require('gulp'), + sass = require('gulp-sass'), + autoprefixer = require('gulp-autoprefixer'), + cssmin = require('gulp-cssmin'), + jshint = require('gulp-jshint'), + uglify = require('gulp-uglify'), + imagemin = require('gulp-imagemin'), + pngcrush = require('imagemin-pngcrush'), + rename = require('gulp-rename'), + clean = require('gulp-rimraf'), + concat = require('gulp-concat'), + notify = require('gulp-notify'), + cache = require('gulp-cache'), + livereload = require('gulp-livereload'); - -// JS hint task -gulp.task('jshint', function() { - gulp.src('./scripts/*.js') - .pipe(jshint()) - .pipe(jshint.reporter('default')); +// render scss +gulp.task('styles', function() { + gulp.src('./src/scss/main.scss') + .pipe(sass({ style: 'expanded' })) + .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 9', 'opera 12.1', 'ios 6', 'android 4')) + .pipe(gulp.dest('./css')) + .pipe(rename({suffix: '.min'})) + .pipe(cssmin()) + .pipe(gulp.dest('./css')) + .pipe(notify({ message: 'Styles task complete' })); }); +// compress images +gulp.task('images', function() { + gulp.src('./src/img/*') + .pipe(cache(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true }))) + .pipe(gulp.dest('./img/')) + .pipe(notify({ message: 'Images task complete' })); +}); + +// clean the folders +gulp.task('clean', function() { + gulp.src(['./css/*', './js/*', './img/*'], {read: false}) + .pipe(clean()); +}); + +// do the javascript-dance +gulp.task('scripts', function() { + gulp.src('./src/js/**/*.js') + .pipe(concat('main.js')) + .pipe(gulp.dest('./js')) + .pipe(rename({suffix: '.min'})) + .pipe(uglify()) + .pipe(gulp.dest('./js')) + .pipe(notify({ message: 'Scripts task complete' })); +}); + +gulp.task('watch', function() { + // Watch .scss files + gulp.watch('src/scss/**/*.scss', ['styles']); + + // Watch .js files + gulp.watch('src/js/**/*.js', ['scripts']); + + // Watch image files + gulp.watch('src/img/**/*', ['images']); +}); + +// default: +gulp.task('default', ['clean'], function() { + gulp.start('styles', 'scripts', 'images'); +}); + + + +/* +// +// OLD STUFF +// ---------------------- // sass + watch gulp.task('sass', function() { gulp.src('./scss/*.scss') @@ -58,3 +113,12 @@ gulp.task('final', function() { })) .pipe(gulp.dest('./img/')) }); + +// JS hint task +gulp.task('jshint', function() { + gulp.src('./scripts/*.js') + .pipe(jshint()) + .pipe(jshint.reporter('default')); +}); + +*/ diff --git a/js/instantclick3.min.js b/js/instantclick3.min.js deleted file mode 100644 index 3403327..0000000 --- a/js/instantclick3.min.js +++ /dev/null @@ -1,12 +0,0 @@ -/* InstantClick 3.0 | (C) 2014 Alexandre Dieulot | http://instantclick.io/license.html */ -var InstantClick=function(e,g){function v(a){var c=a.indexOf("#");return 0>c?a:a.substr(0,c)}function y(a){for(;"A"!=a.nodeName;)a=a.parentNode;return a}function t(a,c){for(var b=0;bp.readyState)&&0!=p.status){q.ready=+new Date-q.start;t("receive");if(p.getResponseHeader("Content-Type").match(/\/(x|ht|xht)ml/)){var a= -e.implementation.createHTMLDocument("");a.documentElement.innerHTML=p.responseText;F=a.title;x=a.body;var c=v(s);f[c]={body:x,title:F,scrollY:c in f?f[c].scrollY:0};for(var a=a.head.children,c=0,b,l=a.length-1;0<=l;l--)if(b=a[l],b.hasAttribute("data-instant-track")){b=b.getAttribute("href")||b.getAttribute("src")||b.innerHTML;for(var n=B.length-1;0<=n;n--)B[n]==b&&c++}c!=B.length&&(C=!0)}else C=!0;h&&(h=!1,L(s))}}function H(a){for(var c=e.getElementsByTagName("a"),b,l=g.protocol+"//"+g.host,n=c.length- -1;0<=n;n--){b=c[n];var d;if(!((d=b.target)||(d=b.hasAttribute("download"))||(d=0!=b.href.indexOf(l+"/"))||(d=-1+new Date-(q.start+q.display)))if(r&&(clearTimeout(r),r=!1),a||(a=K),!u||a!=s&&!h)u= -!0,h=!1,s=a,C=x=!1,q={start:+new Date},t("fetch"),p.open("GET",a),p.send()}function L(a){"display"in q||(q.display=+new Date-q.start);r?s&&s!=a?g.href=a:(w(a),z.start(0,!0),t("wait"),h=!0):!u||h?g.href=a:C?g.href=s:x?(f[m].scrollY=pageYOffset,h=u=!1,G(F,x,s)):(z.start(0,!0),t("wait"),h=!0)}var N=navigator.userAgent,O="createTouch"in e,m,K,r,f={},p,s=!1,F=!1,C=!1,x=!1,q={},u=!1,h=!1,B=[],M,A,E,D={fetch:[],receive:[],wait:[],change:[]},z=function(){function a(a,d){f=a;e.getElementById(k.id)&&e.body.removeChild(k); -k.style.opacity="1";e.getElementById(k.id)&&e.body.removeChild(k);l();d&&setTimeout(c,0);clearTimeout(m);m=setTimeout(b,500)}function c(){f=10;l()}function b(){f+=1+2*Math.random();98<=f?f=98:m=setTimeout(b,500);l()}function l(){g.style[h]="translate("+f+"%)";e.getElementById(k.id)||e.body.appendChild(k)}function n(){e.getElementById(k.id)?(clearTimeout(m),f=100,l(),k.style.opacity="0"):(a(100==f?0:f),setTimeout(n,0))}function d(){k.style.left=pageXOffset+"px";k.style.width=innerWidth+"px";k.style.top= -pageYOffset+"px";var a=innerWidth/screen[90==Math.abs(orientation)?"height":"width"]*2;k.style[h]="scaleY("+a+")"}var k,g,h,f,m;return{init:function(){k=e.createElement("div");k.id="instantclick";g=e.createElement("div");g.id="instantclick-bar";g.className="instantclick-bar";k.appendChild(g);var a=["Webkit","Moz","O"];h="transform";if(!(h in g.style))for(var b=0;3>b;b++)a[b]+"Transform"in g.style&&(h=a[b]+"Transform");var c="transition";if(!(c in g.style))for(b=0;3>b;b++)a[b]+"Transition"in g.style&& -(c="-"+a[b].toLowerCase()+"-"+c);a=e.createElement("style");a.innerHTML="#instantclick{position:"+(O?"absolute":"fixed")+";top:0;left:0;width:100%;pointer-events:none;z-index:2147483647;"+c+":opacity .25s .1s}.instantclick-bar{background:#29d;width:100%;margin-left:-100%;height:2px;"+c+":all .25s}";e.head.appendChild(a);O&&(d(),addEventListener("resize",d),addEventListener("scroll",d))},start:a,done:n}}(),P="pushState"in history&&(!N.match("Android")||N.match("Chrome/"))&&"file:"!=g.protocol;return{supported:P, -init:function(){if(!m)if(P){for(var a=arguments.length-1;0<=a;a--){var c=arguments[a];!0===c?M=!0:"mousedown"==c?A=!0:"number"==typeof c&&(E=c)}m=v(g.href);f[m]={body:e.body,title:e.title,scrollY:pageYOffset};for(var c=e.head.children,b,a=c.length-1;0<=a;a--)b=c[a],b.hasAttribute("data-instant-track")&&(b=b.getAttribute("href")||b.getAttribute("src")||b.innerHTML,B.push(b));p=new XMLHttpRequest;p.addEventListener("readystatechange",T);H(!0);z.init();t("change",!0);addEventListener("popstate",function(){var a= -v(g.href);a!=m&&(a in f?(f[m].scrollY=pageYOffset,m=a,G(f[a].title,f[a].body,!1,f[a].scrollY)):g.href=g.href)})}else t("change",!0)},on:function(a,c){D[a].push(c)}}}(document,location); \ No newline at end of file diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..c1fab2f --- /dev/null +++ b/js/main.js @@ -0,0 +1,725 @@ +/* Some scripts and stuff +--------------------------*/ + + +/* Target-Blank for CSS-Class "external" +--------------------------*/ +function externalLinks() { + if (!document.getElementsByTagName) {return;} + var anchors = document.getElementsByTagName("a"); + for (var i=0; i + 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 + 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) + /* We cannot just use `document.body = doc.body`, it causes Safari (tested + 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) { + /* After a page is displayed, if the user's cursor happens to be above + 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 1px. + + 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) { + /* Happens when there’s a delay before preloading and that delay + hasn't expired (preloading didn't kick in). + */ + + if ($url && $url != url) { + /* Happens when the user clicks on a link before preloading + 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) { + /* If the page isn't preloaded, it likely means the user has focused + 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}' + /* We set the bar's background in `.instantclick-bar` so that it can be + 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() { + /* Adapted from code by Sam Stephenson and Mislav Marohnić + 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 + /* We multiply the size by 2 because the progress bar is harder + 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:" + + /* The state of Android's AOSP browsers: + + 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 + /* We can't use just `elem.href` and `elem.src` because we can'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 + /* Reloads the page while using cache for scripts, styles and images, + 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) + } + + + /* The debug function isn't included by default to reduce file size. + 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); + +/* + 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"; +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="";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;dt?e:e.substr(0,t)}function r(e){for(;"A"!=e.nodeName;)e=e.parentNode;return e}function a(e){do{if(!e.hasAttribute)break;if(e.hasAttribute("data-instant"))return!1;if(e.hasAttribute("data-no-instant"))return!0}while(e=e.parentNode);return!1}function i(e){do{if(!e.hasAttribute)break;if(e.hasAttribute("data-no-instant"))return!1;if(e.hasAttribute("data-instant"))return!0}while(e=e.parentNode);return!1}function o(e,t){for(var n=0;n-1&&e.getElementById(a.substr(s+1)),l=0;if(c)for(;c.offsetParent;)l+=c.offsetTop,c=c.offsetParent;scrollTo(0,l),E=n(a)}else scrollTo(0,i);v(),W.done(),o("change",!1)}function c(){Y=!1,O=!1}function l(e){g(r(e.target).href)}function d(e){var t=r(e.target);t.addEventListener("mouseout",h),C?(T=t.href,w=setTimeout(g,C)):g(t.href)}function f(e){var t=r(e.target);x?t.removeEventListener("mousedown",l):t.removeEventListener("mouseover",d),g(t.href)}function u(e){e.which>1||e.metaKey||e.ctrlKey||(e.preventDefault(),p(r(e.target).href))}function h(){return w?(clearTimeout(w),void(w=!1)):void(Y&&!O&&(L.abort(),c()))}function m(){if(!(L.readyState<4)&&0!=L.status){if(F.ready=+new Date-F.start,o("receive"),L.getResponseHeader("Content-Type").match(/\/(x|ht|xht)ml/)){var t=e.implementation.createHTMLDocument("");t.documentElement.innerHTML=L.responseText,D=t.title,B=t.body;var r=n(S);N[r]={body:B,title:D,scrollY:r in N?N[r].scrollY:0};for(var a,i,s=t.head.children,c=0,l=s.length-1;l>=0;l--)if(a=s[l],a.hasAttribute("data-instant-track")){i=a.getAttribute("href")||a.getAttribute("src")||a.innerHTML;for(var d=I.length-1;d>=0;d--)I[d]==i&&c++}c!=I.length&&(H=!0)}else H=!0;O&&(O=!1,p(S))}}function v(r){for(var o,s=e.getElementsByTagName("a"),c=t.protocol+"//"+t.host,h=s.length-1;h>=0;h--)o=s[h],o.target||o.hasAttribute("download")||0!=o.href.indexOf(c+"/")||o.href.indexOf("#")>-1&&n(o.href)==E||(k?!i(o):a(o))||(o.addEventListener("touchstart",f),x?o.addEventListener("mousedown",l):o.addEventListener("mouseover",d),o.addEventListener("click",u));if(!r){var m,v,g,p,y=e.body.getElementsByTagName("script");for(h=0,j=y.length;j>h;h++)m=y[h],m.hasAttribute("data-no-instant")||(v=e.createElement("script"),m.src&&(v.src=m.src),m.innerHTML&&(v.innerHTML=m.innerHTML),g=m.parentNode,p=m.nextSibling,g.removeChild(m),g.insertBefore(v,p))}}function g(e){!x&&"display"in F&&+new Date-(F.start+F.display)<100||(w&&(clearTimeout(w),w=!1),e||(e=T),(!Y||e!=S&&!O)&&(Y=!0,O=!1,S=e,B=!1,H=!1,F={start:+new Date},o("fetch"),L.open("GET",e),L.send()))}function p(e){return"display"in F||(F.display=+new Date-F.start),w?S&&S!=e?void(t.href=e):(g(e),W.start(0,!0),o("wait"),void(O=!0)):!Y||O?void(t.href=e):H?void(t.href=S):B?(N[E].scrollY=pageYOffset,c(),void s(D,B,S)):(W.start(0,!0),o("wait"),void(O=!0))}function y(){if(!E){if(!q)return void o("change",!0);for(var r=arguments.length-1;r>=0;r--){var a=arguments[r];a===!0?k=!0:"mousedown"==a?x=!0:"number"==typeof a&&(C=a)}E=n(t.href),N[E]={body:e.body,title:e.title,scrollY:pageYOffset};for(var i,c,l=e.head.children,r=l.length-1;r>=0;r--)i=l[r],i.hasAttribute("data-instant-track")&&(c=i.getAttribute("href")||i.getAttribute("src")||i.innerHTML,I.push(c));L=new XMLHttpRequest,L.addEventListener("readystatechange",m),v(!0),W.init(),o("change",!0),addEventListener("popstate",function(){var e=n(t.href);if(e!=E){if(!(e in N))return void(t.href=t.href);N[E].scrollY=pageYOffset,E=e,s(N[e].title,N[e].body,!1,N[e].scrollY)}})}}function b(e,t){z[e].push(t)}var E,T,w,L,k,x,C,A=navigator.userAgent,M="createTouch"in e,N={},S=!1,D=!1,H=!1,B=!1,F={},Y=!1,O=!1,I=[],z={fetch:[],receive:[],wait:[],change:[]},W=function(){function t(){c=e.createElement("div"),c.id="instantclick",l=e.createElement("div"),l.id="instantclick-bar",l.className="instantclick-bar",c.appendChild(l);var t=["Webkit","Moz","O"];if(d="transform",!(d in l.style))for(var n=0;3>n;n++)t[n]+"Transform"in l.style&&(d=t[n]+"Transform");var r="transition";if(!(r in l.style))for(var n=0;3>n;n++)t[n]+"Transition"in l.style&&(r="-"+t[n].toLowerCase()+"-"+r);var a=e.createElement("style");a.innerHTML="#instantclick{position:"+(M?"absolute":"fixed")+";top:0;left:0;width:100%;pointer-events:none;z-index:2147483647;"+r+":opacity .25s .1s}.instantclick-bar{background:#29d;width:100%;margin-left:-100%;height:2px;"+r+":all .25s}",e.head.appendChild(a),M&&(s(),addEventListener("resize",s),addEventListener("scroll",s))}function n(t,n){f=t,e.getElementById(c.id)&&e.body.removeChild(c),c.style.opacity="1",e.getElementById(c.id)&&e.body.removeChild(c),i(),n&&setTimeout(r,0),clearTimeout(u),u=setTimeout(a,500)}function r(){f=10,i()}function a(){f+=1+2*Math.random(),f>=98?f=98:u=setTimeout(a,500),i()}function i(){l.style[d]="translate("+f+"%)",e.getElementById(c.id)||e.body.appendChild(c)}function o(){return e.getElementById(c.id)?(clearTimeout(u),f=100,i(),void(c.style.opacity="0")):(n(100==f?0:f),void setTimeout(o,0))}function s(){c.style.left=pageXOffset+"px",c.style.width=innerWidth+"px",c.style.top=pageYOffset+"px";var e="orientation"in window&&90==Math.abs(orientation),t=innerWidth/screen[e?"height":"width"]*2;c.style[d]="scaleY("+t+")"}var c,l,d,f,u;return{init:t,start:n,done:o}}(),q="pushState"in history&&(!A.match("Android")||A.match("Chrome/"))&&"file:"!=t.protocol;return{supported:q,init:y,on:b}}(document,location);!function(e,t){function n(){var e=v.elements;return"string"==typeof e?e.split(" "):e}function r(e){var t=m[e[u]];return t||(t={},h++,e[u]=h,m[h]=t),t}function a(e,n,a){return n||(n=t),c?n.createElement(e):(a||(a=r(n)),n=a.cache[e]?a.cache[e].cloneNode():f.test(e)?(a.cache[e]=a.createElem(e)).cloneNode():a.createElem(e),n.canHaveChildren&&!d.test(e)?a.frag.appendChild(n):n)}function i(e,t){t.cache||(t.cache={},t.createElem=e.createElement,t.createFrag=e.createDocumentFragment,t.frag=t.createFrag()),e.createElement=function(n){return v.shivMethods?a(n,e,t):t.createElem(n)},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+n().join().replace(/[\w\-]+/g,function(e){return t.createElem(e),t.frag.createElement(e),'c("'+e+'")'})+");return n}")(v,t.frag)}function o(e){e||(e=t);var n=r(e);if(v.shivCSS&&!s&&!n.hasCSS){var a,o=e;a=o.createElement("p"),o=o.getElementsByTagName("head")[0]||o.documentElement,a.innerHTML="x",a=o.insertBefore(a.lastChild,o.firstChild),n.hasCSS=!!a}return c||i(e,n),e}var s,c,l=e.html5||{},d=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,f=/^(?: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,u="_html5shiv",h=0,m={};!function(){try{var e=t.createElement("a");e.innerHTML="",s="hidden"in e;var n;if(!(n=1==e.childNodes.length)){t.createElement("a");var r=t.createDocumentFragment();n="undefined"==typeof r.cloneNode||"undefined"==typeof r.createDocumentFragment||"undefined"==typeof r.createElement}c=n}catch(a){c=s=!0}}();var v={elements:l.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!==l.shivCSS,supportsUnknownElements:c,shivMethods:!1!==l.shivMethods,type:"default",shivDocument:o,createElement:a,createDocumentFragment:function(e,a){if(e||(e=t),c)return e.createDocumentFragment();for(var a=a||r(e),i=a.frag.cloneNode(),o=0,s=n(),l=s.length;l>o;o++)i.createElement(s[o]);return i}};e.html5=v,o(t)}(this,document); \ No newline at end of file diff --git a/js/scripts-min.js b/js/scripts-min.js deleted file mode 100644 index 3cf9448..0000000 --- a/js/scripts-min.js +++ /dev/null @@ -1 +0,0 @@ -function externalLinks(){if(document.getElementsByTagName)for(var e=document.getElementsByTagName("a"),t=0;t + 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 + 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) + /* We cannot just use `document.body = doc.body`, it causes Safari (tested + 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) { + /* After a page is displayed, if the user's cursor happens to be above + 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 1px. + + 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) { + /* Happens when there’s a delay before preloading and that delay + hasn't expired (preloading didn't kick in). + */ + + if ($url && $url != url) { + /* Happens when the user clicks on a link before preloading + 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) { + /* If the page isn't preloaded, it likely means the user has focused + 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}' + /* We set the bar's background in `.instantclick-bar` so that it can be + 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() { + /* Adapted from code by Sam Stephenson and Mislav Marohnić + 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 + /* We multiply the size by 2 because the progress bar is harder + 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:" + + /* The state of Android's AOSP browsers: + + 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 + /* We can't use just `elem.href` and `elem.src` because we can'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 + /* Reloads the page while using cache for scripts, styles and images, + 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) + } + + + /* The debug function isn't included by default to reduce file size. + 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); diff --git a/js/scripts.js b/src/js/scripts.js similarity index 100% rename from js/scripts.js rename to src/js/scripts.js diff --git a/scss/_defaults.scss b/src/scss/_defaults.scss similarity index 100% rename from scss/_defaults.scss rename to src/scss/_defaults.scss diff --git a/scss/_font-awesome.scss b/src/scss/_font-awesome.scss similarity index 100% rename from scss/_font-awesome.scss rename to src/scss/_font-awesome.scss diff --git a/scss/_mixins.scss b/src/scss/_mixins.scss similarity index 100% rename from scss/_mixins.scss rename to src/scss/_mixins.scss diff --git a/scss/_normalize.scss b/src/scss/_normalize.scss similarity index 100% rename from scss/_normalize.scss rename to src/scss/_normalize.scss diff --git a/scss/main.scss b/src/scss/main.scss similarity index 98% rename from scss/main.scss rename to src/scss/main.scss index 8133a2d..17a4e88 100644 --- a/scss/main.scss +++ b/src/scss/main.scss @@ -6,8 +6,8 @@ --------------------------*/ @import 'normalize'; -@import 'mixins'; @import 'defaults'; +@import 'mixins'; /* @import 'font-awesome'; */ /* Content @@ -55,7 +55,7 @@ ul { } a { color: $linkcolor; - @include transition(color 0.2s ease); + transition: color 0.2s ease; &:hover, &:active, &:focus{ color: lighten($linkcolor, 15%); }