From: stephen@cubedesigners.com Date: Wed, 17 Aug 2016 17:59:50 +0000 (+0000) Subject: Major home page updates to handle full page scrolling and responsiveness. WIP #4 X-Git-Url: http://git.cubedesigners.com/?a=commitdiff_plain;h=73fda694d247cfbde1fea5dbb37d2388c560c1f1;p=fluidbook-v3.git Major home page updates to handle full page scrolling and responsiveness. WIP #4 --- diff --git a/framework/application/views/helpers/ContactFooter.php b/framework/application/views/helpers/ContactFooter.php index c56e975..37e6a60 100644 --- a/framework/application/views/helpers/ContactFooter.php +++ b/framework/application/views/helpers/ContactFooter.php @@ -21,6 +21,9 @@ class Fluidbook_View_Helper_ContactFooter extends CubeIT_View_Helper_Abstract { $res = $this->htmlElement($res, 'div', array('class' => 'grid')); $res = $this->backgroundBlock($res, $cf, array('content-wrapper')); - return $this->htmlElement($res, 'section', array('class' => 'contactFooter section')); + return $this->htmlElement($res, 'section', array( + 'class' => 'contactFooter section', + 'data-themecolor' => '#8aab41', // Todo: possibly set this via the admin? + 'data-section-name' => 'contact')); } } \ No newline at end of file diff --git a/framework/application/views/helpers/HomeFeatures.php b/framework/application/views/helpers/HomeFeatures.php index d6340c7..a7d5ef8 100644 --- a/framework/application/views/helpers/HomeFeatures.php +++ b/framework/application/views/helpers/HomeFeatures.php @@ -6,6 +6,8 @@ class Fluidbook_View_Helper_HomeFeatures extends Fluidbook_View_Helper_HomeLayer */ public function homeFeatures($data) { + $this->headScript()->addScriptAndStyle('212-home-features'); + $this->data = $data; $res .= $this->_leftText(); diff --git a/framework/application/views/helpers/HomeIntro.php b/framework/application/views/helpers/HomeIntro.php index 467c25b..209053b 100644 --- a/framework/application/views/helpers/HomeIntro.php +++ b/framework/application/views/helpers/HomeIntro.php @@ -10,9 +10,11 @@ class Fluidbook_View_Helper_HomeIntro extends Fluidbook_View_Helper_HomeLayer { $this->data = $data; - $res=$this->_leftText(); + $res = $this->_leftText(); - return $this->_layer($res, 'intro'); + $arrow = $this->link(null, '#', ['class' => 'scroll-arrow']); + + return $this->_layer($res, 'intro', [], $arrow); } diff --git a/framework/application/views/helpers/HomeLayer.php b/framework/application/views/helpers/HomeLayer.php index 782de74..c72a972 100644 --- a/framework/application/views/helpers/HomeLayer.php +++ b/framework/application/views/helpers/HomeLayer.php @@ -5,9 +5,14 @@ class Fluidbook_View_Helper_HomeLayer extends CubeIT_View_Helper_Abstract { protected function _layer($content, $class, $attributes = array(), $outerContent = '') { + $section = $class; + $class .= ' section ' . $this->data['headerstyle']; - $defaultAttributes = array('class' => $class, 'data-headerstyle' => $this->data['headerstyle']); + $defaultAttributes = array('class' => $class, + 'data-headerstyle' => $this->data['headerstyle'], + 'data-themecolor' => $this->data['themecolor'], + 'data-section-name' => $section); $attributes = $this->_mergeAttributes($attributes, $defaultAttributes); $content = $this->htmlElement($content, 'div', array('class' => 'content-inner')); diff --git a/framework/application/views/scripts/common/footer.phtml b/framework/application/views/scripts/common/footer.phtml index 2e06d82..5ab031f 100644 --- a/framework/application/views/scripts/common/footer.phtml +++ b/framework/application/views/scripts/common/footer.phtml @@ -86,4 +86,4 @@ $res .= ''; // .footer-inner $res .= ''; // footer.legal // Output footer with Organization microdata wrapper -echo $this->microdata($res, ['class' => 'section fp-auto-height'], 'Organization'); \ No newline at end of file +echo $this->microdata($res, ['class' => 'auto-height'], 'Organization'); \ No newline at end of file diff --git a/framework/application/views/scripts/templates/home.phtml b/framework/application/views/scripts/templates/home.phtml index 9c510a8..896849c 100644 --- a/framework/application/views/scripts/templates/home.phtml +++ b/framework/application/views/scripts/templates/home.phtml @@ -1,6 +1,6 @@ headScript()->addFullPage(); +$this->headScript()->addScriptAndStyle('209-scrollify'); // Patched version of Scrollify script $this->headScript()->addScriptAndStyle('210-home'); echo $this->home(); \ No newline at end of file diff --git a/js/002-common.js b/js/002-common.js index 217de63..0a277e9 100644 --- a/js/002-common.js +++ b/js/002-common.js @@ -1,5 +1,6 @@ registerLoader(load_common, true); var zoom = 1; +var maxContentWidth = 1680; var _mobile = null; function load_common() { @@ -69,7 +70,7 @@ function resize() { $('main').css('min-height', mainHeight); // Handle divs with background images that must have a proportional min-height - $('[data-bg-ratio]:not(.fullheight)').each(function () { + $('body:not(.home) [data-bg-ratio]').each(function () { $(this).css('min-height', Math.round($(this).outerWidth() * $(this).data('bg-ratio'))); }); @@ -83,11 +84,22 @@ function resize() { $(window).trigger('fluidbookresize'); } -function setZoom(ww) { +function calculateZoom(ww) { + + if (typeof ww === 'undefined') { + ww = $(window).outerWidth(); + } + zoom = 1; - if (ww >= 1680) { - zoom = ww / 1680; + if (ww >= maxContentWidth) { + zoom = ww / maxContentWidth; } +} + +function setZoom(ww) { + + calculateZoom(ww); + var transform = ''; if (zoom > 1) { transform = 'scale(' + zoom + ')'; diff --git a/js/101-header.js b/js/101-header.js index 16a17fc..2ed187b 100644 --- a/js/101-header.js +++ b/js/101-header.js @@ -5,6 +5,7 @@ var scrolledDistance = 0; var headerPos = 0; var htl; var home = false; +var fullPages = false; registerLoader(load_header, true); @@ -26,13 +27,13 @@ function resizeHeader() { } function setHeaderAnimation() { - fb('set header information'); var h = $('#h'); - home = $("body").hasClass('home'); + home = $('body').hasClass('home'); + fullPages = $('body').hasClass('fullpages'); // Are we in full page mode? var bgcolor = "#fff"; var boxshadow = '0 0 120px rgba(0,0,0,0.3)'; - if (home && !isMobile()) { + if (fullPages && !isMobile()) { bgcolor = 'transparent'; boxshadow = '0 0 0 rgba(0,0,0,0)'; } @@ -45,7 +46,7 @@ function setHeaderAnimation() { // Background-color & height htl.add(TweenMax.fromTo(h, 1.5, {height: 90}, {height: 75}), 0); htl.add(TweenMax.fromTo(h, 1, {backgroundColor: 'transparent', boxShadow: '0 0 0 rgba(0,0,0,0)'}, {backgroundColor: bgcolor, boxShadow: boxshadow}), 1); - if (home && isMobile()) { + if (home && (isMobile() || !fullPages)) { htl.add(TweenMax.fromTo($("#h,#nav-icon"), 1, {className: $("main section:first").data('headerstyle')}, {className: "-=light"}), 1); } htl.add(TweenMax.fromTo($(h).find('#header'), 1.5, {height: 90}, {height: 56}), 0); @@ -113,7 +114,7 @@ function headerScroll() { } // Normalize top value var top = Math.max(-headerHeight, Math.min(adminHeight, htop + adminHeight)); - if (home && !isMobile()) { + if (home && !isMobile() && fullPages) { top = adminHeight; } $(h).css('top', top); @@ -124,15 +125,13 @@ function headerScroll() { formerScroll = s; scrollUp = goingUp; - if (home && !isMobile()) { + if (fullPages && !isMobile()) { changeHeaderStyle(); } } function changeHeaderStyle() { - // Todo: rework all this to be compatible with FullPage.js - see callbacks... - var scrollTop = $(window).scrollTop(); var wh = $(window).height(); var section; diff --git a/js/209-scrollify.js b/js/209-scrollify.js new file mode 100644 index 0000000..4019b47 --- /dev/null +++ b/js/209-scrollify.js @@ -0,0 +1,808 @@ +//### PATCHED VERSION TO SUPPORT CONTENT SCALING - see ~line 632 for changes ###// + +/*! + * jQuery Scrollify + * Version 1.0.4 + * + * Requires: + * - jQuery 1.6 or higher + * + * https://github.com/lukehaas/Scrollify + * + * Copyright 2016, Luke Haas + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + + If section being scrolled to is an interstitialSection and the last section on page + + then value to scroll to is current position plus height of interstitialSection + + */ +(function (global,factory) { + "use strict"; + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], function($) { + return factory($, global, global.document); + }); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + factory(jQuery, global, global.document); + return jQuery; + }; + } else { + // Browser globals + factory(jQuery, global, global.document); + } +}(typeof window !== 'undefined' ? window : this, function ($, window, document, undefined) { + "use strict"; + var heights = [], + names = [], + elements = [], + overflow = [], + index = 0, + currentIndex = 0, + interstitialIndex = 1, + hasLocation = false, + timeoutId, + timeoutId2, + $window = $(window), + top = $window.scrollTop(), + scrollable = false, + locked = false, + scrolled = false, + manualScroll, + swipeScroll, + util, + disabled = false, + scrollSamples = [], + scrollTime = new Date().getTime(), + firstLoad = true, + initialised = false, + wheelEvent = 'onwheel' in document ? 'wheel' : document.onmousewheel !== undefined ? 'mousewheel' : 'DOMMouseScroll', + settings = { + //section should be an identifier that is the same for each section + section: ".section", + sectionName: "section-name", + interstitialSection: "", + easing: "easeOutExpo", + scrollSpeed: 1100, + offset : 0, + scrollbars: true, + axis:"y", + target:"html,body", + standardScrollElements: false, + setHeights: true, + overflowScroll:true, + before:function() {}, + after:function() {}, + afterResize:function() {}, + afterRender:function() {} + }; + function animateScroll(index,instant,callbacks) { + if(currentIndex===index) { + callbacks = false; + } + if(disabled===true) { + return true; + } + if(names[index]) { + scrollable = false; + if(callbacks) { + settings.before(index,elements); + } + interstitialIndex = 1; + if(settings.sectionName && !(firstLoad===true && index===0)) { + if(history.pushState) { + try { + history.replaceState(null, null, names[index]); + } catch (e) { + if(window.console) { + console.warn("Scrollify warning: This needs to be hosted on a server to manipulate the hash value."); + } + } + + } else { + window.location.hash = names[index]; + } + } + if(instant) { + $(settings.target).stop().scrollTop(heights[index]); + if(callbacks) { + settings.after(index,elements); + } + } else { + locked = true; + if( $().velocity ) { + $(settings.target).stop().velocity('scroll', { + duration: settings.scrollSpeed, + easing: settings.easing, + offset: heights[index], + mobileHA: false + }); + } else { + + //console.info(index + ' -- Scrolling to: ' + heights[index] + ' | ' + settings.scrollSpeed + ' | ' + settings.easing); + + $(settings.target).stop().animate({ + scrollTop: heights[index] + }, settings.scrollSpeed,settings.easing); + } + + if(window.location.hash.length && settings.sectionName && window.console) { + try { + if($(window.location.hash).length) { + console.warn("Scrollify warning: There are IDs on the page that match the hash value - this will cause the page to anchor."); + } + } catch (e) { + console.warn("Scrollify warning:", window.location.hash, "is not a valid jQuery expression."); + } + } + $(settings.target).promise().done(function(){ + currentIndex = index; + locked = false; + firstLoad = false; + if(callbacks) { + settings.after(index,elements); + } + }); + } + + } + } + + function isAccelerating(samples) { + function average(num) { + var sum = 0; + + var lastElements = samples.slice(Math.max(samples.length - num, 1)); + + for(var i = 0; i < lastElements.length; i++){ + sum += lastElements[i]; + } + + return Math.ceil(sum/num); + } + + var avEnd = average(10); + var avMiddle = average(70); + + if(avEnd >= avMiddle) { + return true; + } else { + return false; + } + } + $.scrollify = function(options) { + initialised = true; + + $.easing['easeOutExpo'] = function(x, t, b, c, d) { + return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; + }; + + manualScroll = { + handleMousedown:function() { + if(disabled===true) { + return true; + } + scrollable = false; + scrolled = false; + }, + handleMouseup:function() { + if(disabled===true) { + return true; + } + scrollable = true; + if(scrolled) { + manualScroll.calculateNearest(); + } + }, + handleScroll:function() { + if(disabled===true) { + return true; + } + if(timeoutId){ + clearTimeout(timeoutId); + } + timeoutId = setTimeout(function(){ + + scrolled = true; + if(scrollable===false) { + return false; + } + scrollable = false; + manualScroll.calculateNearest(); + + }, 200); + }, + calculateNearest:function() { + top = $window.scrollTop(); + var i =1, + max = heights.length, + closest = 0, + prev = Math.abs(heights[0] - top), + diff; + for(;i 149){ + scrollSamples.shift(); + } + //scrollSamples.push(Math.abs(delta*10)); + scrollSamples.push(Math.abs(value)); + + if((currentScrollTime-scrollTime) > 200){ + scrollSamples = []; + } + scrollTime = currentScrollTime; + + + if(locked) { + return false; + } + + if(delta<0) { + if(index0) { + if(index>0) { + if(atTop()) { + if(isAccelerating(scrollSamples)) { + e.preventDefault(); + index--; + locked = true; + animateScroll(index,false,true); + } else { + return false + } + } + } + } + + }, + keyHandler:function(e) { + if(disabled===true) { + return true; + } + if(locked===true) { + return false; + } + if(e.keyCode==38) { + if(index>0) { + if(atTop()) { + e.preventDefault(); + index--; + animateScroll(index,false,true); + } + } + } else if(e.keyCode==40) { + if(indexMath.abs(swipeScroll.touches.touchstart.x-swipeScroll.touches.touchmove.x))) { + //if(!overflow[index]) { + event.preventDefault(); + //} + swipeScroll.touches.direction = "y"; + if((swipeScroll.options.timeStamp+swipeScroll.options.timeGap)<(new Date().getTime()) && swipeScroll.touches.touchend == false) { + + swipeScroll.touches.touchend = true; + if (swipeScroll.touches.touchstart.y > -1) { + + if(Math.abs(swipeScroll.touches.touchmove.y-swipeScroll.touches.touchstart.y)>swipeScroll.options.distance) { + if(swipeScroll.touches.touchstart.y < swipeScroll.touches.touchmove.y) { + + swipeScroll.up(); + + } else { + swipeScroll.down(); + + } + } + } + } + } + break; + case 'touchend': + if(swipeScroll.touches[event.type]===false) { + swipeScroll.touches[event.type] = true; + if (swipeScroll.touches.touchstart.y > -1 && swipeScroll.touches.touchmove.y > -1 && swipeScroll.touches.direction==="y") { + + if(Math.abs(swipeScroll.touches.touchmove.y-swipeScroll.touches.touchstart.y)>swipeScroll.options.distance) { + if(swipeScroll.touches.touchstart.y < swipeScroll.touches.touchmove.y) { + swipeScroll.up(); + + } else { + swipeScroll.down(); + + } + } + swipeScroll.touches.touchstart.y = -1; + swipeScroll.touches.touchstart.x = -1; + swipeScroll.touches.direction = "undetermined"; + } + } + default: + break; + } + } + } + }, + down: function() { + if(index<=heights.length-1) { + + if(atBottom() && indexinterstitialIndex) { + + // interstitialScroll(parseInt(heights[index])+($window.height()*interstitialIndex)); + interstitialScroll(Math.round(heights[index])+($window.height()*interstitialIndex)); + interstitialIndex += 1; + + } else { + // interstitialScroll(parseInt(heights[index])+(elements[index].height()-$window.height())); + interstitialScroll(Math.round(heights[index])+(elements[index].height()-$window.height())); + } + + } + } + }, + up: function() { + if(index>=0) { + if(atTop() && index>0) { + + index--; + animateScroll(index,false,true); + } else { + + if(interstitialIndex>2) { + + interstitialIndex -= 1; + // interstitialScroll(parseInt(heights[index])+($window.height()*interstitialIndex)); + interstitialScroll(Math.round(heights[index])+($window.height()*interstitialIndex)); + + } else { + + interstitialIndex = 1; + // interstitialScroll(parseInt(heights[index])); + interstitialScroll(Math.round(heights[index])); + } + } + + } + }, + init: function() { + if (document.addEventListener) { + document.addEventListener('touchstart', swipeScroll.touchHandler, false); + document.addEventListener('touchmove', swipeScroll.touchHandler, false); + document.addEventListener('touchend', swipeScroll.touchHandler, false); + } + } + }; + + + util = { + refresh:function(withCallback) { + clearTimeout(timeoutId2); + timeoutId2 = setTimeout(function() { + sizePanels(); + calculatePositions(true); + if(withCallback) { + settings.afterResize(); + } + },400); + }, + handleUpdate:function() { + util.refresh(false); + }, + handleResize:function() { + util.refresh(true); + } + }; + settings = $.extend(settings, options); + + sizePanels(); + + calculatePositions(false); + + if(true===hasLocation) { + animateScroll(index,false,true); + } else { + setTimeout(function() { + animateScroll(0,false,true); + },200); + } + if(heights.length) { + manualScroll.init(); + swipeScroll.init(); + + $window.bind("resize",util.handleResize); + if (document.addEventListener) { + window.addEventListener("orientationchange", util.handleResize, false); + } + } + function interstitialScroll(pos) { + if( $().velocity ) { + $(settings.target).stop().velocity('scroll', { + duration: settings.scrollSpeed, + easing: settings.easing, + offset: pos, + mobileHA: false + }); + } else { + $(settings.target).stop().animate({ + scrollTop: pos + }, settings.scrollSpeed,settings.easing); + } + } + + function sizePanels() { + var selector = settings.section; + overflow = []; + if(settings.interstitialSection.length) { + selector += "," + settings.interstitialSection; + } + $(selector).each(function(i) { + + if(settings.setHeights) { + if($(this).is(settings.interstitialSection)) { + overflow[i] = false; + } else { + + if(($(this).css("height","auto").outerHeight()<$window.height()) || $(this).css("overflow")==="hidden") { + $(this).css({"height":$window.height()}); + + overflow[i] = false; + } else { + + $(this).css({"height":$(this).height()}); + + if(settings.overflowScroll) { + overflow[i] = true; + } else { + overflow[i] = false; + } + } + + } + + } else { + + if(($(this).outerHeight()<$window.height()) || (settings.overflowScroll===false)) { + overflow[i] = false; + } else { + overflow[i] = true; + } + } + }); + } + function calculatePositions(resize) { + var selector = settings.section; + if(settings.interstitialSection.length) { + selector += "," + settings.interstitialSection; + } + heights = []; + names = []; + elements = []; + $(selector).each(function(i){ + if(i>0) { + // heights[i] = parseInt($(this).offset().top) + settings.offset; + heights[i] = Math.round($(this).offset().top) + settings.offset; + } else { + // heights[i] = parseInt($(this).offset().top); + heights[i] = Math.round($(this).offset().top); + } + if(settings.sectionName && $(this).data(settings.sectionName)) { + names[i] = "#" + $(this).data(settings.sectionName).replace(/ /g,"-"); + } else { + if($(this).is(settings.interstitialSection)===false) { + names[i] = "#" + (i + 1); + } else { + names[i] = "#"; + if(i===$(selector).length-1 && i>1) { // If it's the last element, we will add its height so scroll goes right to the bottom + + //--------- + // ## PATCHED by Stephen to take into account the CSS scaled size of the element... + //heights[i] = heights[i-1]+parseInt($(this).height()); // Original code + heights[i] = heights[i-1] + Math.round($(this)[0].getBoundingClientRect().height); + //--------- + } + } + } + elements[i] = $(this); + try { + if($(names[i]).length && window.console) { + console.warn("Scrollify warning: Section names can't match IDs on the page - this will cause the browser to anchor."); + } + } catch (e) {} + + if(window.location.hash===names[i]) { + index = i; + hasLocation = true; + } + + }); + + if(true===resize) { + animateScroll(index,false,false); + } else { + settings.afterRender(); + } + } + + function atTop() { + if(!overflow[index]) { + return true; + } + top = $window.scrollTop(); + if(top>parseInt(heights[index])) { + return false; + } else { + return true; + } + } + function atBottom() { + if(!overflow[index]) { + return true; + } + top = $window.scrollTop(); + + if(top=0;z--) { + if(typeof panel === 'string') { + if (names[z]===panel) { + index = z; + animateScroll(z,instant,true); + } + } else { + if(z===panel) { + index = z; + animateScroll(z,instant,true); + } + } + } + } + $.scrollify.move = function(panel) { + if(panel===undefined) { + return false; + } + if(panel.originalEvent) { + panel = $(this).attr("href"); + } + move(panel,false); + }; + $.scrollify.instantMove = function(panel) { + if(panel===undefined) { + return false; + } + move(panel,true); + }; + $.scrollify.next = function() { + if(index0) { + index -= 1; + animateScroll(index,false,true); + } + }; + $.scrollify.instantNext = function() { + if(index0) { + index -= 1; + animateScroll(index,true,true); + } + }; + $.scrollify.destroy = function() { + if(!initialised) { + return false; + } + if(settings.setHeights) { + $(settings.section).each(function() { + $(this).css("height","auto"); + }); + } + $window.unbind("resize",util.handleResize); + if(settings.scrollbars) { + $window.unbind('mousedown', manualScroll.handleMousedown); + $window.unbind('mouseup', manualScroll.handleMouseup); + $window.unbind('scroll', manualScroll.handleScroll); + } + $(document).unbind(wheelEvent,manualScroll.wheelHandler); + $(document).unbind('keydown', manualScroll.keyHandler); + + if (document.addEventListener) { + document.removeEventListener('touchstart', swipeScroll.touchHandler, false); + document.removeEventListener('touchmove', swipeScroll.touchHandler, false); + document.removeEventListener('touchend', swipeScroll.touchHandler, false); + } + heights = []; + names = []; + elements = []; + overflow = []; + }; + $.scrollify.update = function() { + if(!initialised) { + return false; + } + util.handleUpdate(); + }; + $.scrollify.current = function() { + return elements[index]; + }; + $.scrollify.disable = function() { + disabled = true; + }; + $.scrollify.enable = function() { + disabled = false; + if (typeof manualScroll !== 'undefined') { + manualScroll.calculateNearest(); + } + }; + $.scrollify.isDisabled = function() { + return disabled; + }; + $.scrollify.setOptions = function(updatedOptions) { + if(!initialised) { + return false; + } + if(typeof updatedOptions === "object") { + settings = $.extend(settings, updatedOptions); + util.handleUpdate(); + } else if(window.console) { + console.warn("Scrollify warning: Options need to be in an object."); + } + }; +})); \ No newline at end of file diff --git a/js/210-home.js b/js/210-home.js index 2205854..bb1ffbf 100644 --- a/js/210-home.js +++ b/js/210-home.js @@ -2,55 +2,194 @@ registerLoader(load_home, true); function load_home() { $(window).on('fluidbookresize', resizeHome); resizeHome(); + initScrollify(); - // // FullPage.js setup - // $('#contentWrapper').fullpage({ - // navigation: true, - // navigationPosition: 'left', - // verticalCentered: false, - // afterRender: function() { - // console.log('FullPage rendered.'); - // }, - // afterLoad: function(anchorLink, index) { - // console.log('Loaded section #' + index); - // updateHeaderStyle(); - // }, - // onSlideLeave: function(anchorLink, index, slideIndex, direction, nextSlideIndex) { - // updateHeaderStyle(); - // } - // - // }); + // Bouncing scroll down arrow + // Show scroll-down arrow after a small delay + setTimeout(function() { + $('.scroll-arrow').fadeIn(1000); + // Animate arrow + TweenMax.to($('.scroll-arrow'), 1, {bottom: "+=15px", yoyo: true, repeat: -1, ease: Linear.easeNone}); + }, 2500); -} + $(document).on('click', '.scroll-arrow', function(e) { + $('html,body').animate({ + scrollTop: $('#contentWrapper section:nth-of-type(2)').offset().top + }, 1100, 'easeOutExpo'); + e.preventDefault(); + }); + + // Handle clicks on pagination dots + $(".pagination li").on("click",function() { + $.scrollify.move($(this).data('section')); + }); -// function updateHeaderStyle() { -// var headerClass = $('.fp-section.active').data('headerstyle'); -// console.info(headerClass); -// if (headerClass == 'light') { -// if (!$("header").hasClass('light')) { -// console.log('adding light...'); -// $("header").addClass('light').removeClass('dark'); -// } -// } else { -// if (!$("header").hasClass('dark')) { -// $("header").addClass('dark').removeClass('light'); -// } -// } -// } + // Handle clicks to AJAX popups and disable scrollify when they open + // because it interferes with internal popup scrolling + $(document).on('click', '.popup', function() { + disableScrollify(); + }); + $(document).on('click', '.closePopup', function() { + resizeHome(); // Update layout and re-enable scrollify if space requirements are met + }); +} function resizeHome() { - // Resize sections - var wh = $(window).outerHeight() / zoom; - var ww = $(window).outerWidth() / zoom; - if (ww > 900) { - $('#contentWrapper > section').css('height', wh); - } else { - $('#contentWrapper > section').css('height', 'auto'); - } + var sections = $('#contentWrapper > section'); + + // Since we have 100% height sections and the scroller, the standard zoom handling causes + // problems so we temporarily reset it and apply it after the sections have been sized + setZoom(0); + + // Recalculate zoom value but don't apply scaling yet + calculateZoom(); + + // Resize sections, allowing for scale factor that will be applied to parent element + var wh = Math.ceil($(window).outerHeight() / zoom); + var ww = Math.ceil($(window).outerWidth() / zoom); resizeHomeContact(ww, wh); resizeHomeReferences(ww, wh); + + if (isMobile()) { + sections.css('height', 'auto'); + disableScrollify(); + } else if (!isTallEnough()) { + // Size each section according to its content and background image ratio + sections.each(function() { + + var bgHolder = $(this).find('[data-bg-ratio]'), + bgHeight = 0, + contentHeight = $(this).find('.content-inner').outerHeight() + 100; // + extra padding height for content + + if (bgHolder.length > 0) { + bgHeight = Math.round(bgHolder.outerWidth() * bgHolder.data('bg-ratio')) + 50; // + extra space for background + } + + $(this).css('height', Math.max(bgHeight, contentHeight)); + }); + + disableScrollify(); + + } else { + sections.css('height', wh); + enableScrollify(); + } + + setZoom(); // Finally set scaling again +} + +// Check if the window height is tall enough to contain the content of each section +function isTallEnough() { + + // Get available height for contents + var wh = $(window).height() - $('#h').outerHeight() - $('#adminBar').outerHeight() - 30; // 30px extra breathing space around content + var ok = true; + var bgHeight = 0; + var contentHeight; + var sectionHeight; + + $('section .content-wrapper').each(function() { + + // First, check if the section has a background image that forces a minimum ratio for the size + if ($(this).data('bg-ratio')) { + bgHeight = $(this).data('bg-ratio') * $(this).outerWidth(); + } + + // Get height of actual content + contentHeight = $(this).find('.content-inner').outerHeight(); + + // Largest dimension of the two wins + sectionHeight = Math.max(bgHeight, contentHeight); + + + //console.info(sectionHeight + ' > ' + wh + '? ' + $(this).parent().attr('class')); + if (sectionHeight > wh) { + //console.error($(this).parent().attr('class') + ' is too tall...'); + ok = false; + return false; + } + }); + + return ok; +} + +function initScrollify() { + $.scrollify({ + scrollbars: true, + interstitialSection: '.auto-height', + setHeights: false, + before: function(index, sections) { + //fb("before: #" + index, sections.length); + + // Handle scrolling to last (footer) section + // This block is shorter so the header will end up over the middle of the content + // We add the background and shadow in to give it separation + if (index + 1 == sections.length) { + + $('#h').css({ + 'background-color': '#fff', + 'box-shadow': '0 0 120px rgba(0,0,0,0.3)' + }); + + $('.pagination').css('opacity', 0); + + } else { + + setTimeout(function() { + $('#h').css({ + 'background-color': 'transparent', + 'box-shadow': '0 0 0 rgba(0,0,0,0)' + }); + + $('.pagination').css('opacity', 1); + + }, 300); + + } + + // Pagination update + var ref = sections[index].attr('data-section-name'); + var color = sections[index].attr('data-themecolor'); + $(".pagination .active").css('color', '').removeClass('active'); + $(".pagination").find('[data-section="#' + ref + '"]').css('color', color).addClass('active'); + }, + afterRender:function() { + var pagination = '
    '; + + $('[data-section-name]').each(function(i) { + pagination += '
  • ' + $(this).attr('data-section-name').charAt(0).toUpperCase() + $(this).attr('data-section-name').slice(1) + '
  • '; + }); + + pagination += "
"; + + $('body').append(pagination); + + // Highlight first dot + $('.pagination li:first-of-type').css('color', $('[data-section-name]:first-of-type').data('themecolor')).addClass('active'); + } + }); +} + +function enableScrollify() { + if (typeof $.scrollify !== 'undefined') { + $('body').addClass('fullpages'); + fullPages = true; + setHeaderAnimation(); // Ensure header animation settings are correct after changing modes + $.scrollify.enable(); + $.scrollify.update(); + } +} + +function disableScrollify() { + if (typeof $.scrollify !== 'undefined') { + $('body').removeClass('fullpages'); + fullPages = false; + $.scrollify.disable(); + setHeaderAnimation(); // Update header animation settings for normal scrolling + $('html,body').animate({scrollTop: $(window).scrollTop() + 1 }, 0); // Scroll down 1px to trigger header animation update + } } function resizeHomeContact(ww, wh) { diff --git a/less/002-common.less b/less/002-common.less index a33b3cc..e4fdb0f 100644 --- a/less/002-common.less +++ b/less/002-common.less @@ -33,6 +33,7 @@ main { background-color: #fff; max-width: @content-max-width; margin: 0 auto; + position: relative; } #z { diff --git a/less/210-home.less b/less/210-home.less index 1183084..85f87e4 100644 --- a/less/210-home.less +++ b/less/210-home.less @@ -11,12 +11,12 @@ } .content-inner { - position: absolute; - padding: 0 5%; - top: 50%; - left: 0; - width: 100%; - transform: translateY(-50%); + position: absolute; + padding: 0 5%; + top: 50%; + left: 0; + width: 100%; + transform: translateY(-50%); @media @m900 { position: static; @@ -62,4 +62,30 @@ } } } +} + +.pagination { + color: rgba(128,128,128,0.5); + position: fixed; + top: 50%; + left: 15px; + transform: translateY(-50%); + font-size: 30px; + line-height: 1; + transition: opacity 0.3s; + cursor: pointer; + z-index: 10; + display: none; // Displayed only when in pagination mode + + .fullpages & { + display: block; + } + + //li:hover span { + // display: inline-block; + //} + + span { + display: none; + } } \ No newline at end of file diff --git a/less/211-home-intro.less b/less/211-home-intro.less index 0c5e119..bddf643 100644 --- a/less/211-home-intro.less +++ b/less/211-home-intro.less @@ -2,6 +2,23 @@ section.intro { + a.scroll-arrow { + display: none; + position: absolute; + bottom: 10px; + left: 50%; + transform: translateX(-50%); + + &:after { + .icon('f'); + font-size: 40px; + color: #fff; + transform: rotate(90deg); + display: inline-block; + .font-thinning-off(); + } + } + @media @m900 { .content-wrapper.fullheight { background-size: 100%; diff --git a/less/212-home-features.less b/less/212-home-features.less new file mode 100644 index 0000000..f4e35ce --- /dev/null +++ b/less/212-home-features.less @@ -0,0 +1,13 @@ +@import "000-imports"; + +.features { + + .title { + max-width: 50%; + + @media @m900 { + max-width: none; + } + } + +} \ No newline at end of file