├── README.md ├── assets ├── jquery.alton.js └── jquery.alton.min.js ├── bower.json └── package.json /README.md: -------------------------------------------------------------------------------- 1 | # README # 2 | 3 | ## What is Alton? ## 4 | Alton is a jQuery-powered scrolling plugin that utilizes custom vertical scrolling effects in order to present and navigate through web content in a unique manner. It utilizes the whole scrolljacking idea, but greatly improves upon the often-poorly-implemented scrolljacking experiences you might be used to. 5 | 6 | ## What makes Alton unique? ## 7 | Good question. Here's why Alton rules: 8 | 9 | 1. The **Standard** functionality. Standard brings you the full page scrolling you're used to by making the "featured area of projects" in the middle section 100% height, and each scroll directs you to the next one (scroll down) or previous (scroll up). [Here's a demo of Standard.](http://demo.paper-leaf.com/alton/standard) 10 | 11 | 2. The **Bookend** functionality. This allows you to create a bookend experience which allows you to seamlessly introduce your full height section, and summarize or even conclude it. [Here's a demo of Bookend.](http://demo.paper-leaf.com/alton/bookend) 12 | 13 | 3. The **Hero Scroll** functionality. This allows you to scrolljack *only* the "Hero Section", wherein the page will scoll to the top of the section that immediately follows the Hero Section, then re-enable native scrolling for the rest of the page. [Here's a demo of Hero Scroll.](http://demo.paper-leaf.com/alton/heroscroll) 14 | 15 | 4. The plugin uses **100% height** containers for full-screen presentation; it's great for impactful presentation. 16 | 17 | 5. You have options for a **couple of different layouts** right out of the box. 18 | 19 | 6. It's **lightweight, easy to implement,** and **not CPU intensive.** 20 | 21 | ## What is "ScrollJacking"? ## 22 | Scrolljacking basically means we replace native scrolling (what you're used to) with targeted scrolling: when the user initiates a scroll, either with their mouse or keyboard, scrolljacking takes them to an exact vertical point on the screen (for example, the top of the next content container). When done properly, scrolljacking can be a part of a unique, enjoyable online experience. 23 | 24 | ## Compatibility ## 25 | This plugin has been tested on IE9+ and with jQuery 1.7+. Anything less and you're on your own for now – sorry! 26 | 27 | ## Demos ## 28 | In case you missed the links above, here are a few demos showing the different ways Alton can be used. You can also take a quick peek under the hood there to see exactly how we're implementing it. 29 | 30 | [Demo 1 (Standard Implementation)](http://demo.paper-leaf.com/alton/standard) 31 | 32 | [Demo 2 (with Bookend functionality)](http://demo.paper-leaf.com/alton/bookend) 33 | 34 | [Demo 3 (with Hero Scroll functionality)](http://demo.paper-leaf.com/alton/heroscroll) 35 | 36 | ## Quick start ## 37 | ### Standard Functionality ### 38 | *Standard* functionality brings you the full page scrolling you're used to. The "featured area of projects" in the middle section are all 100% height, and each scroll directs you to the next one (scroll down) or previous (scroll up). [Here's a demo of Standard.](http://demo.paper-leaf.com/alton/standard) 39 | 40 | Here is an example for all the options needed for *Standard*: 41 | 42 | First ensure you have the proper HTML structure: 43 | ```html 44 | 45 |
46 |
47 |
48 |
49 |
50 | 51 | ``` 52 | 53 | Next add the following JavaScript where you want to call it. Note: **If you don't want errors to occur, only run the script on the page where scrolling occurs** 54 | 55 | ```js 56 | $(document).alton({ 57 | fullSlideContainer: 'full', // Tell Alton the full height container 58 | singleSlideClass: 'slide', // Tell Alton the full height slide class 59 | useSlideNumbers: true, // Set to false if you don't want to use pagination 60 | slideNumbersBorderColor: '#fff', // Set the outside color of the pagination items (also used for active) 61 | slideNumbersColor: 'transparent', // Set the inner color of the pagination items (not active) 62 | bodyContainer: 'pageWrapper', // Tell Alton the body class 63 | }); 64 | ``` 65 | 66 | ### Bookend Functionality ### 67 | The Idea behind *Bookend* functionality is that you have a header and footer sections ("bookends"), with a featured area of projects or something in the middle. The "featured area of projects" in the middle section are all 100% height, whereas the bookends can be whatever height you'd like them to be. [Here's a demo of Bookend.](http://demo.paper-leaf.com/alton/bookend) 68 | 69 | Here is an example for all the options needed for *Bookend*: 70 | 71 | First ensure you have the proper HTML structure: 72 | 73 | ```html 74 | 75 | 76 |
77 |
78 |
79 |
80 |
81 |
82 | 83 | 84 | ``` 85 | 86 | Next add the following JavaScript where you want to call it. Note: **If you don't want errors to occur, only run the script on the page where scrolling occurs** 87 | 88 | ```js 89 | $(document).alton({ 90 | fullSlideContainer: 'full', // Tell Alton the full height container 91 | singleSlideClass: 'slide', // Tell Alton the full height slide class 92 | useSlideNumbers: true, // Set to false if you don't want to use pagination 93 | slideNumbersBorderColor: '#fff', // Set the outside color of the pagination items (also used for active) 94 | slideNumbersColor: 'transparent', // Set the inner color of the pagination items (not active) 95 | bodyContainer: 'pageWrapper', // Tell Alton the body class 96 | }); 97 | ``` 98 | 99 | ### Hero Scroll ### 100 | The Idea behind *Hero Scroll* is that we only apply scrolljacking to the topmost "Hero" container; one scroll movement takes the user to the top of the next section of content and native scrolling is enabled. [Here's a demo of Hero Scroll.](http://demo.paper-leaf.com/alton/heroscroll) 101 | 102 | Here is an example for all the options needed for *Hero Scroll*: 103 | 104 | First ensure you have the proper HTML structure: 105 | 106 | ```html 107 |
108 | 109 |
110 |
111 | 112 |
113 | ``` 114 | 115 | Next add the following JavaScript where you want to call it. Note: **If you don't want errors to occur, only run the script on the page where scrolling occurs** 116 | 117 | ```js 118 | $(document).alton({ 119 | firstClass : 'header', // Set the first container class 120 | bodyContainer: 'pageWrapper', // Set the body container 121 | scrollMode: 'headerScroll', // Set the scroll mode 122 | }); 123 | ``` 124 | 125 | ### All Available Options ### 126 | 127 | Here's a list of all the options that come built in to Alton, along with their default values. 128 | 129 | ```js 130 | firstClass : 'header', // classname of the first element in your page content 131 | fullSlideContainer : 'full', // full page elements container for 132 | singleSlideClass : 'slide', // class for each individual slide 133 | nextElement : 'div', // set the first element in the first page series. 134 | previousClass : null, // null when starting at the top. Will be updated based on current postion 135 | lastClass: 'footer', // last block to scroll to 136 | slideNumbersContainer: 'slide-numbers', // ID of Slide Numbers 137 | bodyContainer: 'pageWrapper', // ID of content container 138 | scrollMode: 'featuredScroll', // Choose scroll mode 139 | useSlideNumbers: false, // Enable or disable slider 140 | slideNumbersBorderColor: '#fff', // outside color for slide numbers 141 | slideNumbersColor: '#000', // interior color when slide numbers inactive 142 | ``` 143 | ## What's included ## 144 | 145 | ## Bugs and feature requests ## 146 | 147 | Have a bug or a feature request? Please first read the issue guidelines and search for existing and closed issues. If your problem or idea is not addressed yet, please open a new issue. 148 | 149 | ### Currently Working On ### 150 | * Custom Animations 151 | * More Customization for slide number indicators (pagination) 152 | 153 | ## Keep track of our progress. ## 154 | 155 | Follow [@paper_leaf](https://twitter.com/paper_leaf) on Twitter. 156 | 157 | ## Copyright and License ## 158 | *Copyright 2014 Paper Leaf Design* 159 | 160 | License: GPL v3 161 | 162 | ## Frequently Asked Questions ## 163 | #### Does this work on touchscreens? #### 164 | No. 165 | #### Why not? #### 166 | Touch events are a different beast, and considering the amount of people on cheaper, less powerful devices, or even the majority still stuck in contracts, the usability is usually non-existent. That being said, we are continuing to explore ways of implementing this for mobile devices. 167 | #### So you are looking at adding mobile functionality? #### 168 | Possibly! 169 | #### What currently happens on mobile devices, then, if Alton doesn't work? #### 170 | It falls back to regular scrolling on mobile. It's the best of both worlds, like pizza made out of candy. 171 | #### Scrolling appears unresponsive at times. What's going on? #### 172 | After every scroll there's a delay in effect to help get rid of Inertia Scroll on Macs. If you try to scroll within this delay it will prevent you from scrolling, until the barrage of mousewheel events has ended. 173 | #### Why did you name this plugin Alton? #### 174 | We're playing off the idea of height, in that this plugin uses 100% height containers. That led us to the discovery of [Robert Wadlow](http://en.wikipedia.org/wiki/Robert_Wadlow), the world's tallest man – also known as the Alton Giant. *mic drop* 175 | -------------------------------------------------------------------------------- /assets/jquery.alton.js: -------------------------------------------------------------------------------- 1 | /* =============================================================================== 2 | * alton.js v1.2.1 3 | * =============================================================================== 4 | * Copyright 2014 Paper Leaf Design 5 | * http://www.paper-leaf.com 6 | * 7 | * Author: Paper Leaf 8 | * 9 | * A full featured scrolling plugin for creating 10 | * immersive featured sections or headers. 11 | * 12 | * Credit: 13 | * is_mobile() based off these helpful posts 14 | * - http://stackoverflow.com/questions/3514784/what-is-the-best-way-to-detect-a-handheld-device-in-jquery 15 | * 16 | * Getting stable scroll events was helped hugely by Huge Inc's insights 17 | * - http://www.hugeinc.com/ideas/perspective/scroll-jacking-on-hugeinc 18 | * 19 | * Stabilizing keypress events was helped in large part by jQuery OnePage Scroll 20 | * - https://github.com/peachananr/onepage-scroll 21 | * 22 | * License: GPL v3 23 | * =============================================================================== */ 24 | 25 | (function($) { 26 | /* =============================================================================== 27 | * Table of Contents 28 | * ------------------- 29 | * 30 | * 1. Default Options 31 | * 2. Global Variables 32 | * 3. Initiate Layout 33 | * 4. Mobile Device Check 34 | * 5. Click to Navigate 35 | * 6. Update Position 36 | * 7. Move Up 37 | * 8. Move Down 38 | * 9. Prevent Default Animations 39 | * 10. Scroll To 40 | * 11. Featured Scroll 41 | * 12. Header Scroll 42 | * 43 | * =============================================================================== */ 44 | 45 | /* ============================================================================= 46 | * Default Options 47 | * ------------------- 48 | * Creating defaults in case the user doesn't feel like adding their own 49 | * ============================================================================= */ 50 | "use strict"; 51 | var defaults = { 52 | firstClass: 'header', // classname of the first element in your page content 53 | fullSlideContainer: 'full', // full page elements container for 54 | singleSlideClass: 'slide', // class for each individual slide 55 | nextElement: 'div', // set the first element in the first page series. 56 | previousClass: null, // null when starting at the top. Will be updated based on current postion 57 | lastClass: 'footer', // last block to scroll to 58 | slideNumbersContainer: 'slide-numbers', // ID of Slide Numbers 59 | bodyContainer: 'pageWrapper', // ID of content container 60 | scrollMode: 'featuredScroll', // Choose scroll mode 61 | useSlideNumbers: false, // Enable or disable slider 62 | slideNumbersBorderColor: '#fff', // outside color for slide numbers 63 | slideNumbersColor: '#000', // interior color when slide numbers inactive 64 | animationType: 'slow', // animation type: currently doesn't do anything 65 | callback: false, // default is no callback 66 | }; 67 | 68 | $.fn.alton = function(options) { 69 | /* ============================================================================= 70 | * User Settings 71 | * ------------------- 72 | * Update the default settings with user selected options 73 | * ============================================================================= */ 74 | var settings = $.extend(true, {}, defaults, options), 75 | 76 | /* ============================================================================= 77 | * Global Variables 78 | * ------------------- 79 | * Setting up variables that will be used throught the plugin 80 | * ============================================================================= */ 81 | singleSlideClass = settings.singleSlideClass, 82 | singleSlide, 83 | bodyScroll, 84 | down = false, 85 | up = false, 86 | current = $('.' + settings.firstClass), 87 | next = $('.' + singleSlideClass + ':first'), 88 | previous = null, 89 | last = $('.' + settings.lastClass), 90 | projectCount = $('.' + settings.fullSlideContainer).children().length, 91 | slideNumbers, 92 | top = true, 93 | upCount = 0, 94 | downCount = 0, 95 | windowHeight = $(window).outerHeight(), 96 | animating = false, 97 | docElem = window.document.documentElement, 98 | scrollOffset, 99 | offsetTest, 100 | i; 101 | 102 | // IE8 Support for getElementsByClassname 103 | if ('getElementsByClassName' in document) { 104 | singleSlide = document.getElementsByClassName(singleSlideClass); 105 | } else { 106 | singleSlide = document.querySelectorAll('.' + singleSlideClass); 107 | } 108 | 109 | if (!current.length) { 110 | current = next; 111 | next = current.next(); 112 | } 113 | if (!last.length) { 114 | last = $('.' + singleSlideClass + ':last'); 115 | } 116 | last = last[0]; 117 | 118 | /* ============================================================================= 119 | * Position Variables 120 | * ------------------- 121 | * Update postion variable if headerScroll 122 | * ============================================================================= */ 123 | if (settings.scrollMode === 'headerScroll') { 124 | current = $('.' + settings.firstClass); // current element is the topmost element 125 | next = $('.' + settings.bodyContainer + ':first'); 126 | } 127 | 128 | /* ============================================================================ 129 | * Initiate Layout 130 | * ------------------- 131 | * Get the slides to 100% height, and add pagination 132 | * ============================================================================ */ 133 | function initiateLayout(style) { 134 | if (style === 'featuredScroll') { 135 | for (i = singleSlide.length - 1; i >= 0; i -= 1) { 136 | if (is_mobile()) { 137 | if ($(singleSlide[i]).height() > windowHeight) { 138 | $(singleSlide[i]).css('height', $(singleSlide[i]).height()); 139 | } else { 140 | $(singleSlide[i]).css('height', windowHeight); 141 | $(singleSlide[i]).outerHeight(windowHeight); 142 | } 143 | } else { 144 | $(singleSlide[i]).css('height', windowHeight); 145 | $(singleSlide[i]).outerHeight(windowHeight); 146 | 147 | } 148 | } 149 | if (settings.useSlideNumbers && !is_mobile()) { 150 | // Create Slider Buttons 151 | $('.' + settings.bodyContainer).append('
'); 152 | $('#' + settings.slideNumbersContainer).css({ 153 | 'height': '100%', 154 | 'position': 'fixed', 155 | 'top': 0, 156 | 'right': '0px', 157 | 'bottom': '0px', 158 | 'width': '86px', 159 | 'z-index': 999 160 | }); 161 | if (is_mobile()) { 162 | $('#' + settings.slideNumbersContainer).css({ 163 | 'height': 'auto', 164 | 'min-height': '100%' 165 | }); 166 | } 167 | $('.' + settings.bodyContainer + ' #' + settings.slideNumbersContainer).append(''); 168 | $('.' + settings.bodyContainer + ' #' + settings.slideNumbersContainer + ' ul').css({ 169 | 'transform': 'translateY(-50%)', 170 | '-moz-transform': 'translateY(-50%)', 171 | '-ms-transform': 'translateY(-50%)', 172 | '-o-transform': 'translateY(-50%)', 173 | '-webkit-transform': 'translateY(-50%)', 174 | 'top': '50%', 175 | 'position': 'fixed' 176 | }); 177 | 178 | var testCount = 0; 179 | 180 | while (testCount < projectCount) { 181 | $('.' + settings.bodyContainer + ' #' + settings.slideNumbersContainer + ' ul').append('
  • '); 182 | if (msieversion()) { 183 | $('.paginate').css({ 184 | 'cursor': 'pointer', 185 | 'border-radius': '50%', 186 | 'list-style': 'none', 187 | 'background': settings.slideNumbersBorderColor, 188 | 'border-color': settings.slideNumbersBorderColor, 189 | 'border-width': '2px', 190 | 'border-style': 'solid', 191 | 'height': '11px', 192 | 'width': '11px', 193 | 'margin': '5px 0' 194 | }); 195 | } else { 196 | $('.paginate').css({ 197 | 'cursor': 'pointer', 198 | 'border-radius': '50%', 199 | 'list-style': 'none', 200 | 'background': settings.slideNumbersBorderColor, 201 | 'border-color': settings.slideNumbersBorderColor, 202 | 'border-width': '2px', 203 | 'border-style': 'solid', 204 | 'height': '10px', 205 | 'width': '10px', 206 | 'margin': '5px 0' 207 | }); 208 | } 209 | 210 | testCount += 1; 211 | } 212 | // Store the slidenumbers 213 | // IE8 Support for getElementsByClassname 214 | if (('getElementsByClassName' in document)) { 215 | slideNumbers = document.getElementsByClassName('paginate'); 216 | } else { 217 | slideNumbers = document.querySelectorAll('.paginate'); 218 | } 219 | } 220 | } else { 221 | $('.' + settings.firstClass).css('height', windowHeight + 10); 222 | if (!$('.' + settings.firstClass).hasClass('active')) { 223 | $('.' + settings.firstClass).toggleClass('active'); 224 | if (msieversion()) { 225 | $('.paginate.active').css({ 226 | 'margin-left': '-1px', 227 | 'border-color': '#' + settings.slideNumbersBorderColor, 228 | 'border-style': 'solid', 229 | 'border-width': '2px', 230 | 'height': '8px', 231 | 'width': '8px' 232 | }); 233 | } 234 | } 235 | } 236 | } 237 | 238 | function msieversion() { 239 | var ua = window.navigator.userAgent; 240 | var msie = ua.indexOf("MSIE "); 241 | 242 | if (msie > 0 || navigator.userAgent.match(/Trident.*rv\:11\./)) { // If Internet Explorer, return version number 243 | return true; 244 | } else { 245 | return false; 246 | } 247 | } 248 | 249 | /* ============================================================================ 250 | * Mobile device check 251 | * ------------------- 252 | * Check if mobile device 253 | * ============================================================================ */ 254 | function is_mobile() { 255 | return navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|BB10|Windows Phone|Tizen|Bada)/); 256 | } 257 | 258 | /* ============================================================================ 259 | * Update pagination 260 | * ------------------- 261 | * Updates pagination on scroll down or up when called etc. 262 | * ============================================================================ */ 263 | function slideIndex(element, toggle) { 264 | if (toggle && $(slideNumbers[$(element).parent().children().index(element)]).hasClass('active')) { 265 | $(slideNumbers[$(element).parent().children().index(element)]).toggleClass('active'); 266 | $(slideNumbers[$(element).parent().children().index(element)]).css('background', settings.slideNumbersBorderColor); 267 | } else if (!$(slideNumbers[$(element).parent().children().index(element)]).hasClass('active')) { 268 | $(slideNumbers[$(element).parent().children().index(element)]).toggleClass('active'); 269 | $(slideNumbers[$(element).parent().children().index(element)]).css('background', settings.slideNumbersColor); 270 | } 271 | } 272 | 273 | /* ============================================================================ 274 | * Slide Numbers Fade 275 | * ------------------- 276 | * Fades out the slide numbers 277 | * ============================================================================ */ 278 | function slideNumbersFade(fadeInOut) { 279 | if (settings.useSlideNumbers) { 280 | if (fadeInOut) { 281 | $('#' + settings.slideNumbersContainer).fadeIn(); 282 | } else { 283 | $('#' + settings.slideNumbersContainer).fadeOut(); 284 | } 285 | } 286 | } 287 | 288 | /* ============================================================================ 289 | * Click to Navigate 290 | * ------------------- 291 | * Adds click to navigate functionality to pagination 292 | * ============================================================================ */ 293 | function clickToNavigate(elementIndex) { 294 | var elementContainer = document.getElementsByClassName(singleSlideClass); 295 | $(document).scrollTo($(elementContainer[elementIndex])); 296 | current = elementContainer[elementIndex]; 297 | if ($(current).prev().hasClass(singleSlideClass)) { 298 | previous = $(current).prev(); 299 | } else { 300 | previous = $('.' + settings.firstClass); 301 | } 302 | if ($(current).next().hasClass(singleSlideClass)) { 303 | next = $(current).next(); 304 | } else { 305 | next = $('.' + settings.lastClass); 306 | } 307 | 308 | slideIndex($('#' + settings.slideNumbersContainer + ' li.active'), true); 309 | slideIndex(elementContainer[elementIndex], false); 310 | 311 | // Callback function 312 | if ( typeof settings.callback == 'function' ) { 313 | settings.callback(); 314 | } 315 | } 316 | 317 | /* ============================================================================ 318 | * Update Position 319 | * ------------------- 320 | * Update current, previous and next, based on window position on load. 321 | * ============================================================================ */ 322 | function getCurrentPosition() { 323 | if ($(next).length > 0 || $(previous).length > 0) { 324 | if ($(window).scrollTop() >= $('.' + singleSlideClass + ':first').offset().top && $(window).scrollTop() + $(window).outerHeight() !== $(document).outerHeight()) { 325 | if (settings.useSlideNumbers) { 326 | slideIndex(current, true); 327 | } 328 | $('.' + singleSlideClass).each(function() { 329 | offsetTest = $(this).offset().top; 330 | if (offsetTest <= $(window).scrollTop()) { 331 | if ($(this).prev().hasClass(singleSlideClass)) { 332 | previous = $(this).prev(); 333 | } else { 334 | previous = $('.' + settings.firstClass); 335 | } 336 | current = $(this); 337 | if (current.next().hasClass(singleSlideClass)) { 338 | next = $(this).next(); 339 | } else { 340 | next = $('.' + settings.lastClass); 341 | } 342 | top = false; 343 | } 344 | }); 345 | if (settings.useSlideNumbers) { 346 | slideIndex(current, false); 347 | } 348 | $(document).scrollTo(current); 349 | } else { 350 | if (settings.useSlideNumbers) { 351 | if (last !== $('.' + singleSlideClass + ':last-child')[0]) { 352 | slideNumbersFade(false); 353 | } else { 354 | slideNumbersFade(true); 355 | slideIndex(current, false); 356 | } 357 | } 358 | $(document).scrollTo(current); 359 | } 360 | } 361 | } 362 | 363 | /* ============================================================================ 364 | * Prevent Default Animations 365 | * ------------------- 366 | * Stops default scroll animations when called 367 | * ============================================================================ */ 368 | function preventDefault(e) { 369 | if(e !== undefined) { 370 | e = e || window.event; 371 | if (e.preventDefault) { 372 | e.stopPropagation(); 373 | e.returnValue = false; 374 | } 375 | } 376 | } 377 | 378 | function stopDefaultAnimate(event) { 379 | return preventDefault(event); 380 | } 381 | 382 | /* ============================================================================ 383 | * Move Down 384 | * ------------------- 385 | * All the code to move the page down 386 | * ============================================================================ */ 387 | $.fn.moveDown = function() { 388 | scrollOffset = scrollY(); 389 | if (scrollOffset >= 0 && (scrollOffset <= $(current).scrollTop()) && top === true) { 390 | // Check if top of page 391 | // Update the selectors 392 | previous = current; 393 | current = next; 394 | next = current.next(); 395 | 396 | // Set Slide Indexes and Fade Slide Numbers 397 | if (settings.useSlideNumbers) { 398 | if (last === $('.' + singleSlideClass + ':last-child')[0]) { 399 | slideIndex(previous, true); 400 | slideIndex(current, false); 401 | } else { 402 | slideIndex(current, false); 403 | slideNumbersFade(true); 404 | } 405 | } 406 | 407 | // Update top variable 408 | top = false; 409 | $(document).scrollTo(current); // Scroll to selected element 410 | } else if (!bodyScroll && next && $(current).offset().top < scrollOffset + 1) { 411 | // Check if slide 412 | if (next.hasClass(singleSlideClass)) { 413 | // Update the selectors 414 | previous = current; 415 | current = next; 416 | next = $(current).next(); 417 | // Set Slide Indexes and Fade Slide Numbers 418 | if (settings.useSlideNumbers) { 419 | slideIndex(previous, true); 420 | slideIndex(current, false); 421 | } 422 | $(document).scrollTo(current); // Scroll to selected element 423 | } else if (last !== $('.' + singleSlideClass + ':last-child')[0]) { 424 | // Update the selectors 425 | previous = $('.' + singleSlideClass + ':last-child')[0]; 426 | current = last; 427 | next = null; 428 | if ($(window).scrollTop() + windowHeight + 10 >= $(document).outerHeight() - $(last).outerHeight()) { 429 | // Check for bottom 430 | // Set Slide Indexes and Fade Slide Numbers 431 | if (settings.useSlideNumbers) { 432 | slideIndex(previous, false); 433 | slideNumbersFade(false); 434 | } 435 | } 436 | $(document).scrollTo(current); // Scroll to selected element 437 | $.event.trigger({ 438 | type: "lastSlide", 439 | slide: last, 440 | time: new Date() 441 | }); 442 | } 443 | } 444 | 445 | // Callback function 446 | if ( typeof settings.callback == 'function' ) { 447 | settings.callback(); 448 | } 449 | }; 450 | 451 | /* ============================================================================ 452 | * Move Up 453 | * ------------------- 454 | * All the code to move the page up 455 | * ============================================================================ */ 456 | $.fn.moveUp = function() { 457 | scrollOffset = scrollY(); 458 | if ($('.' + settings.fullSlideContainer).offset().top + 1 > scrollOffset && previous && scrollOffset > 0) { 459 | // Check if not scrolling to top of page 460 | if ($(current).offset().top >= scrollOffset) { 461 | // Update the selectors 462 | current = $('.' + settings.firstClass); 463 | previous = null; 464 | next = $('.' + singleSlideClass); 465 | 466 | // Update and fade slideNumbers 467 | if (settings.useSlideNumbers) { 468 | slideNumbersFade(false); 469 | slideIndex(next, false); 470 | } 471 | // Update top variable as we are at the top of the page 472 | top = true; 473 | } else { 474 | // Update the selectors 475 | current = previous; 476 | previous = null; 477 | next = $('.' + singleSlideClass); 478 | 479 | // Update and fade slideNumbers 480 | if (settings.useSlideNumbers) { 481 | slideIndex(current, true); 482 | slideIndex(previous, true); 483 | } 484 | } 485 | $(document).scrollTo(current); // Scroll to proper element 486 | } else if (!bodyScroll && $('.' + settings.fullSlideContainer).offset().top < scrollOffset) { 487 | // Update the selectors 488 | current = previous; 489 | previous = $(current).prev(); 490 | next = $(current).next(); 491 | 492 | // Update and fade slideNumbers 493 | if (settings.useSlideNumbers) { 494 | slideIndex(current, false); 495 | slideIndex(next, true); 496 | slideNumbersFade(true); 497 | } 498 | 499 | // Scroll to proper element 500 | $(document).scrollTo(current); 501 | 502 | // Stop default scrolling 503 | } 504 | 505 | // Update movement variables 506 | up = true; 507 | down = false; 508 | 509 | // Callback function 510 | if ( typeof settings.callback == 'function' ) { 511 | settings.callback(); 512 | } 513 | 514 | // Stop default scrolling animations 515 | }; 516 | 517 | /* ============================================================================ 518 | * Scroll To 519 | * ------------------- 520 | * Scroll to element. This is a public function and can be used in an JS file 521 | * ============================================================================ */ 522 | $.fn.scrollTo = function(element) { 523 | if (element !== last) { 524 | $("body,html").stop(true, true).animate({ 525 | scrollTop: $(element).offset().top 526 | }, { 527 | duration: 375 528 | }); 529 | } else { 530 | $("body,html").stop(true, true).animate({ 531 | scrollTop: $(document).outerHeight() - windowHeight 532 | }, { 533 | duration: 375 534 | }); 535 | } 536 | }; 537 | 538 | /* ============================================================================ 539 | * ScrollY 540 | * ------------------- 541 | * Replacing default scrollY with IE8 Compat 542 | * ============================================================================ */ 543 | function scrollY() { 544 | return window.pageYOffset || docElem.scrollTop; 545 | } 546 | 547 | /* ============================================================================ 548 | * Featured Scroll 549 | * ------------------- 550 | * Scroll based on the idea of having a header, a full screen featured projects 551 | * area, and then a footer after 552 | * ============================================================================ */ 553 | function featuredScroll(e) { 554 | bodyScroll = $('body,html').is(':animated') || $('body').is(':animated') || $('html').is(':animated'); // Check if body is currently animated 555 | 556 | if (e.type == 'mousewheel' || e.type == "DOMMouseScroll") { // <-- fix for firefox 557 | clearTimeout($.data(this, 'scrollTimer')); // jshint ignore:line 558 | $(document).unbind({ 559 | 'scroll' : featuredScroll 560 | }); 561 | $.data(this, 'scrollTimer', setTimeout(function() { // jshint ignore:line 562 | animating = false; 563 | $(document).bind({ 564 | 'scroll' : featuredScroll 565 | }); 566 | }, 35)); 567 | 568 | if (e.originalEvent.detail > 1 && !animating || e.originalEvent.wheelDelta < -1 && !animating) { 569 | // Check if scrolling down 570 | downCount += 1; 571 | $(document).moveDown(); 572 | animating = true; 573 | preventDefault(); 574 | } else if (e.originalEvent.detail < -1 && !animating || e.originalEvent.wheelDelta > 1 && !animating) { 575 | // Check if not scrolling up 576 | upCount += 1; 577 | $(document).moveUp(); 578 | animating = true; 579 | preventDefault(); 580 | } 581 | } else if (e.type == 'scroll') { 582 | preventDefault(); 583 | animating = false; 584 | clearTimeout($.data(this, 'scrollTimer')); // jshint ignore:line 585 | $.data(this, 'scrollTimer', setTimeout(function() { // jshint ignore:line 586 | getCurrentPosition(); 587 | }, 500)); 588 | } 589 | return false; 590 | } 591 | 592 | /* ============================================================================ 593 | * Header Scroll 594 | * ------------------- 595 | * Scroll jacking for full size header image, then re-enables native scrolling 596 | * 597 | * ============================================================================ */ 598 | function headerScroll(e) { 599 | scrollOffset = scrollY(); 600 | if (e.originalEvent.detail > 0 || e.originalEvent.wheelDelta < 0) { 601 | if ($(next).offset().top > 0 && scrollOffset < $('.' + settings.firstClass).outerHeight()) { 602 | if ($('.' + settings.firstClass).hasClass('active')) { 603 | $('.' + settings.firstClass).toggleClass('active'); 604 | $(document).scrollTo(next); 605 | previous = current; 606 | current = next; 607 | return stopDefaultAnimate(e); 608 | } else if (!$('html, body').is(':animated')) { 609 | return true; 610 | } 611 | } else { 612 | return true; 613 | } 614 | } else { 615 | if (!$('.' + settings.firstClass).hasClass('active') && $(window).scrollTop() <= $('.' + settings.firstClass).outerHeight()) { 616 | $('.' + settings.firstClass).toggleClass('active'); 617 | $(document).scrollTo(previous); 618 | next = current; 619 | current = previous; 620 | } else if (!$('html, body').is(':animated')) { 621 | return true; 622 | } 623 | } 624 | return false; 625 | } 626 | 627 | /* ============================================================================ 628 | * Function Calls and Ordering 629 | * ------------------- 630 | * Calling all the functions on document load to make sure nothing breaks 631 | * ============================================================================ */ 632 | $(document).ready(function() { 633 | initiateLayout(settings.scrollMode); 634 | if (settings.scrollMode === 'featuredScroll' && !is_mobile()) { 635 | getCurrentPosition(); 636 | } 637 | if (settings.scrollMode === 'featuredScroll' && !is_mobile()) { 638 | $('#' + settings.slideNumbersContainer + ' li').on("click", function() { 639 | clickToNavigate($(this).parent().children().index(this)); 640 | }); 641 | 642 | var map = []; 643 | onkeydown = onkeyup = function(e) { 644 | e = e || event; // to deal with IE 645 | map[e.which] = e.type == 'keyup'; 646 | switch (e.which) { 647 | case 40: // arrowDown 648 | e.preventDefault(); 649 | $(document).moveDown(e); 650 | break; 651 | case 32: // pageUp 652 | e.preventDefault(); 653 | if (map['16'] === true) { 654 | $(document).moveUp(e); 655 | } else { 656 | $(document).moveDown(e); 657 | } 658 | break; 659 | case 33: // pageUp 660 | $(document).moveDown(e); 661 | e.preventDefault(); 662 | break; 663 | case 34: // pageUp 664 | e.preventDefault(); 665 | $(document).moveUp(e); 666 | break; 667 | case 38: // arrowUp 668 | e.preventDefault(); 669 | $(document).moveUp(e); 670 | break; 671 | case 36: // home 672 | e.preventDefault(); 673 | if ($('.' + settings.firstClass).length !== 0) { 674 | if (settings.useSlideNumbers) { 675 | slideIndex(current, true); 676 | } 677 | previous = null; 678 | current = '.' + settings.firstClass; 679 | next = $('.' + singleSlideClass + ':first'); 680 | 681 | if (settings.useSlideNumbers) { 682 | slideIndex(current, false); 683 | } 684 | $(document).scrollTo('.' + settings.firstClass); 685 | } else { 686 | if (settings.useSlideNumbers) { 687 | slideIndex(current, true); 688 | } 689 | previous = null; 690 | current = $('.pane:first'); 691 | next = current.next(); 692 | $(document).scrollTo($('.pane')[0]); 693 | if (settings.useSlideNumbers) { 694 | slideIndex(current, false); 695 | } 696 | } 697 | break; 698 | case 35: // end 699 | if ($('.' + settings.firstClass).length !== 0) { 700 | if (settings.useSlideNumbers) { 701 | slideIndex($(current), true); 702 | slideIndex($('.pane:last'), false); 703 | } 704 | previous = $('.pane:last'); 705 | } else { 706 | if (settings.useSlideNumbers) { 707 | slideIndex($(current), true); 708 | slideIndex($(last), false); 709 | } 710 | previous = $(last).prev(); 711 | } 712 | current = $(last); 713 | next = null; 714 | e.preventDefault(); 715 | $(document).scrollTo(last); 716 | } 717 | }; 718 | } 719 | 720 | if (!is_mobile()) { 721 | if (settings.scrollMode === 'featuredScroll') { 722 | $(document).bind({ 723 | 'DOMMouseScroll mousewheel scroll': featuredScroll 724 | }); 725 | } else if (settings.scrollMode === 'headerScroll') { 726 | $(document).bind({ 727 | 'DOMMouseScroll mousewheel': headerScroll 728 | }); 729 | } 730 | $(window).resize(function() { 731 | $(singleSlide).each(function() { 732 | $(this).css('height', $(window).outerHeight()); 733 | $(this).outerHeight($(window).outerHeight()); 734 | }); 735 | }); 736 | } 737 | }); 738 | }; 739 | })(jQuery); -------------------------------------------------------------------------------- /assets/jquery.alton.min.js: -------------------------------------------------------------------------------- 1 | !function(e){"use strict";var t={firstClass:"header",fullSlideContainer:"full",singleSlideClass:"slide",nextElement:"div",previousClass:null,lastClass:"footer",slideNumbersContainer:"slide-numbers",bodyContainer:"pageWrapper",scrollMode:"featuredScroll",useSlideNumbers:!1,slideNumbersBorderColor:"#fff",slideNumbersColor:"#000",animationType:"slow",callback:!1};e.fn.alton=function(s){function l(t){if("featuredScroll"===t){for(w=p.length-1;w>=0;w-=1)r()&&e(p[w]).height()>O?e(p[w]).css("height",e(p[w]).height()):(e(p[w]).css("height",O),e(p[w]).outerHeight(O));if(N.useSlideNumbers&&!r()){e("."+N.bodyContainer).append('
    '),e("#"+N.slideNumbersContainer).css({height:"100%",position:"fixed",top:0,right:"0px",bottom:"0px",width:"86px","z-index":999}),r()&&e("#"+N.slideNumbersContainer).css({height:"auto","min-height":"100%"}),e("."+N.bodyContainer+" #"+N.slideNumbersContainer).append(""),e("."+N.bodyContainer+" #"+N.slideNumbersContainer+" ul").css({transform:"translateY(-50%)","-moz-transform":"translateY(-50%)","-ms-transform":"translateY(-50%)","-o-transform":"translateY(-50%)","-webkit-transform":"translateY(-50%)",top:"50%",position:"fixed"});for(var s=0;E>s;)e("."+N.bodyContainer+" #"+N.slideNumbersContainer+" ul").append('
  • '),o()?e(".paginate").css({cursor:"pointer","border-radius":"50%","list-style":"none",background:N.slideNumbersBorderColor,"border-color":N.slideNumbersBorderColor,"border-width":"2px","border-style":"solid",height:"11px",width:"11px",margin:"5px 0"}):e(".paginate").css({cursor:"pointer","border-radius":"50%","list-style":"none",background:N.slideNumbersBorderColor,"border-color":N.slideNumbersBorderColor,"border-width":"2px","border-style":"solid",height:"10px",width:"10px",margin:"5px 0"}),s+=1;g="getElementsByClassName"in document?document.getElementsByClassName("paginate"):document.querySelectorAll(".paginate")}}else e("."+N.firstClass).css("height",O+10),e("."+N.firstClass).hasClass("active")||(e("."+N.firstClass).toggleClass("active"),o()&&e(".paginate.active").css({"margin-left":"-1px","border-color":"#"+N.slideNumbersBorderColor,"border-style":"solid","border-width":"2px",height:"8px",width:"8px"}))}function o(){var e=window.navigator.userAgent,t=e.indexOf("MSIE ");return t>0||navigator.userAgent.match(/Trident.*rv\:11\./)?!0:!1}function r(){return navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|BB10|Windows Phone|Tizen|Bada)/)}function n(t,s){s&&e(g[e(t).parent().children().index(t)]).hasClass("active")?(e(g[e(t).parent().children().index(t)]).toggleClass("active"),e(g[e(t).parent().children().index(t)]).css("background",N.slideNumbersBorderColor)):e(g[e(t).parent().children().index(t)]).hasClass("active")||(e(g[e(t).parent().children().index(t)]).toggleClass("active"),e(g[e(t).parent().children().index(t)]).css("background",N.slideNumbersColor))}function i(t){N.useSlideNumbers&&(t?e("#"+N.slideNumbersContainer).fadeIn():e("#"+N.slideNumbersContainer).fadeOut())}function a(t){var s=document.getElementsByClassName(y);e(document).scrollTo(e(s[t])),T=s[t],D=e(T).prev().hasClass(y)?e(T).prev():e("."+N.firstClass),k=e(T).next().hasClass(y)?e(T).next():e("."+N.lastClass),n(e("#"+N.slideNumbersContainer+" li.active"),!0),n(s[t],!1),"function"==typeof N.callback&&N.callback()}function d(){(e(k).length>0||e(D).length>0)&&(e(window).scrollTop()>=e("."+y+":first").offset().top&&e(window).scrollTop()+e(window).outerHeight()!==e(document).outerHeight()?(N.useSlideNumbers&&n(T,!0),e("."+y).each(function(){v=e(this).offset().top,v<=e(window).scrollTop()&&(D=e(this).prev().hasClass(y)?e(this).prev():e("."+N.firstClass),T=e(this),k=T.next().hasClass(y)?e(this).next():e("."+N.lastClass),M=!1)}),N.useSlideNumbers&&n(T,!1),e(document).scrollTo(T)):(N.useSlideNumbers&&(B!==e("."+y+":last-child")[0]?i(!1):(i(!0),n(T,!1))),e(document).scrollTo(T)))}function u(e){void 0!==e&&(e=e||window.event,e.preventDefault&&(e.stopPropagation(),e.returnValue=!1))}function c(e){return u(e)}function m(){return window.pageYOffset||P.scrollTop}function f(t){return b=e("body,html").is(":animated")||e("body").is(":animated")||e("html").is(":animated"),"mousewheel"==t.type||"DOMMouseScroll"==t.type?(clearTimeout(e.data(this,"scrollTimer")),e(document).unbind({scroll:f}),e.data(this,"scrollTimer",setTimeout(function(){Y=!1,e(document).bind({scroll:f})},35)),t.originalEvent.detail>1&&!Y||t.originalEvent.wheelDelta<-1&&!Y?(A+=1,e(document).moveDown(),Y=!0,u()):(t.originalEvent.detail<-1&&!Y||t.originalEvent.wheelDelta>1&&!Y)&&(H+=1,e(document).moveUp(),Y=!0,u())):"scroll"==t.type&&(u(),Y=!1,clearTimeout(e.data(this,"scrollTimer")),e.data(this,"scrollTimer",setTimeout(function(){d()},500))),!1}function h(t){if(C=m(),t.originalEvent.detail>0||t.originalEvent.wheelDelta<0){if(!(e(k).offset().top>0&&C=0&&C<=e(T).scrollTop()&&M===!0?(D=T,T=k,k=T.next(),N.useSlideNumbers&&(B===e("."+y+":last-child")[0]?(n(D,!0),n(T,!1)):(n(T,!1),i(!0))),M=!1,e(document).scrollTo(T)):!b&&k&&e(T).offset().top=e(document).outerHeight()-e(B).outerHeight()&&N.useSlideNumbers&&(n(D,!1),i(!1)),e(document).scrollTo(T),e.event.trigger({type:"lastSlide",slide:B,time:new Date}))),"function"==typeof N.callback&&N.callback()},e.fn.moveUp=function(){C=m(),e("."+N.fullSlideContainer).offset().top+1>C&&D&&C>0?(e(T).offset().top>=C?(T=e("."+N.firstClass),D=null,k=e("."+y),N.useSlideNumbers&&(i(!1),n(k,!1)),M=!0):(T=D,D=null,k=e("."+y),N.useSlideNumbers&&(n(T,!0),n(D,!0))),e(document).scrollTo(T)):!b&&e("."+N.fullSlideContainer).offset().top" 17 | ], 18 | "license": "GPL-3.0", 19 | "ignore": [ 20 | "package.json" 21 | ], 22 | "private": false 23 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alton", 3 | "version": "1.2.1", 4 | "description": "Alton is a jQuery-powered scrolling plugin, with a twist.", 5 | "main": "jquery.alton.min.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/paper-leaf/alton.git" 9 | }, 10 | "keywords": [ 11 | "jQuery", 12 | "scroll", 13 | "twist" 14 | ], 15 | "author": "Paper Leaf Design", 16 | "license": "GPL-3.0", 17 | "bugs": { 18 | "url": "https://github.com/paper-leaf/alton/issues" 19 | }, 20 | "homepage": "https://github.com/paper-leaf/alton#readme" 21 | 22 | } 23 | --------------------------------------------------------------------------------