├── .gitignore ├── gg-close-read.Rproj ├── custom.scss ├── README.md ├── practice ├── second.css ├── lib │ ├── shortcuts │ │ ├── sticky.min.js │ │ ├── infinite.min.js │ │ ├── inview.min.js │ │ ├── sticky.js │ │ ├── infinite.js │ │ └── inview.js │ ├── waypoints.debug.js │ ├── jquery.waypoints.min.js │ ├── zepto.waypoints.min.js │ ├── noframework.waypoints.min.js │ ├── jquery.waypoints.js │ ├── zepto.waypoints.js │ └── noframework.waypoints.js ├── style.css ├── layouts.qmd ├── sticky-side-original.qmd ├── scrollama.qmd ├── sticky-side.qmd └── waypoints.qmd ├── gg-close-read-dream-syntax-1.qmd └── gg-close-read.qmd /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | .DS_Store 6 | 7 | *.html 8 | *_files 9 | _publish.yml -------------------------------------------------------------------------------- /gg-close-read.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | -------------------------------------------------------------------------------- /custom.scss: -------------------------------------------------------------------------------- 1 | /*-- scss:defaults --*/ 2 | 3 | // Google fonts 4 | @import url('https://fonts.googleapis.com/css2?family=Nanum+Myeongjo&display=swap'); 5 | 6 | // Fonts 7 | 8 | $font-family-sans-serif: 'Nanum Myeongjo', serif; 9 | 10 | /*-- scss:rules --*/ 11 | 12 | p { 13 | margin-bottom: 85vh; /* between paragraphs */ 14 | } 15 | 16 | h3 { 17 | margin-top: 15vh; /* for new sections */ 18 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## GG Close Read 2 | 3 | A test to see how close we can get to creating a scrollytelling html document from a Quarto document. The inspiration for this is the Close Read series from the New York Times, specifically: 4 | 5 | [*A Poem (and a Painting) About the Suffering That Hides in Plain Sight*](https://www.nytimes.com/interactive/2022/03/06/books/auden-musee-des-beaux-arts.html) by Elisa Gabbert. 6 | 7 | The result can be viewed on Quarto pubs: 8 | 9 | [*A Grammar of Graphics: A close read of a scatterplot*](https://andrew.quarto.pub/gg-close-read/) 10 | 11 | -------------------------------------------------------------------------------- /practice/second.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | } 4 | 5 | .wrapper { 6 | height: 100%; 7 | font-family: Helvetica, sans-serif; 8 | line-height: 1.5; 9 | word-spacing: 2px; 10 | letter-spacing: 0.5px; 11 | } 12 | 13 | .fixed { 14 | background-attachment: fixed; 15 | background-repeat: no-repeat; 16 | background-size: cover; 17 | background-position: center center; 18 | height: 100%; 19 | width: 100%; 20 | color: #eeeeee; 21 | text-align: center; 22 | display: table; 23 | } 24 | 25 | .fixed h2 { 26 | display: table-cell; 27 | vertical-align: middle; 28 | } 29 | 30 | .scroll { 31 | background-color: #ffe0f6; 32 | padding: 10px 70px; 33 | color: #666666; 34 | } 35 | 36 | .one { 37 | background-image: "pic1.png"; 38 | } 39 | 40 | .two { 41 | background-image: pic2.png; 42 | } 43 | 44 | .three { 45 | background-image: pic3.png; 46 | } -------------------------------------------------------------------------------- /practice/lib/shortcuts/sticky.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints Sticky Element Shortcut - 4.0.1 3 | Copyright © 2011-2016 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6 | */ 7 | !function(){"use strict";function t(s){this.options=e.extend({},i.defaults,t.defaults,s),this.element=this.options.element,this.$element=e(this.element),this.createWrapper(),this.createWaypoint()}var e=window.jQuery,i=window.Waypoint;t.prototype.createWaypoint=function(){var t=this.options.handler;this.waypoint=new i(e.extend({},this.options,{element:this.wrapper,handler:e.proxy(function(e){var i=this.options.direction.indexOf(e)>-1,s=i?this.$element.outerHeight(!0):"";this.$wrapper.height(s),this.$element.toggleClass(this.options.stuckClass,i),t&&t.call(this,e)},this)}))},t.prototype.createWrapper=function(){this.options.wrapper&&this.$element.wrap(this.options.wrapper),this.$wrapper=this.$element.parent(),this.wrapper=this.$wrapper[0]},t.prototype.destroy=function(){this.$element.parent()[0]===this.wrapper&&(this.waypoint.destroy(),this.$element.removeClass(this.options.stuckClass),this.options.wrapper&&this.$element.unwrap())},t.defaults={wrapper:'
',stuckClass:"stuck",direction:"down right"},i.Sticky=t}(); -------------------------------------------------------------------------------- /practice/lib/shortcuts/infinite.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints Infinite Scroll Shortcut - 4.0.1 3 | Copyright © 2011-2016 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6 | */ 7 | !function(){"use strict";function t(n){this.options=i.extend({},t.defaults,n),this.container=this.options.element,"auto"!==this.options.container&&(this.container=this.options.container),this.$container=i(this.container),this.$more=i(this.options.more),this.$more.length&&(this.setupHandler(),this.waypoint=new o(this.options))}var i=window.jQuery,o=window.Waypoint;t.prototype.setupHandler=function(){this.options.handler=i.proxy(function(){this.options.onBeforePageLoad(),this.destroy(),this.$container.addClass(this.options.loadingClass),i.get(i(this.options.more).attr("href"),i.proxy(function(t){var n=i(i.parseHTML(t)),e=n.find(this.options.more),s=n.find(this.options.items);s.length||(s=n.filter(this.options.items)),this.$container.append(s),this.$container.removeClass(this.options.loadingClass),e.length||(e=n.filter(this.options.more)),e.length?(this.$more.replaceWith(e),this.$more=e,this.waypoint=new o(this.options)):this.$more.remove(),this.options.onAfterPageLoad(s)},this))},this)},t.prototype.destroy=function(){this.waypoint&&this.waypoint.destroy()},t.defaults={container:"auto",items:".infinite-item",more:".infinite-more-link",offset:"bottom-in-view",loadingClass:"infinite-loading",onBeforePageLoad:i.noop,onAfterPageLoad:i.noop},o.Infinite=t}(); -------------------------------------------------------------------------------- /practice/lib/waypoints.debug.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints Debug - 4.0.1 3 | Copyright © 2011-2016 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6 | */ 7 | (function() { 8 | 'use strict' 9 | 10 | var displayNoneMessage = [ 11 | 'You have a Waypoint element with display none. For more information on ', 12 | 'why this is a bad idea read ', 13 | 'http://imakewebthings.com/waypoints/guides/debugging/#display-none' 14 | ].join('') 15 | var fixedMessage = [ 16 | 'You have a Waypoint element with fixed positioning. For more ', 17 | 'information on why this is a bad idea read ', 18 | 'http://imakewebthings.com/waypoints/guides/debugging/#fixed-position' 19 | ].join('') 20 | 21 | function checkWaypointStyles() { 22 | var originalRefresh = window.Waypoint.Context.prototype.refresh 23 | 24 | window.Waypoint.Context.prototype.refresh = function() { 25 | for (var axis in this.waypoints) { 26 | for (var key in this.waypoints[axis]) { 27 | var waypoint = this.waypoints[axis][key] 28 | var style = window.getComputedStyle(waypoint.element) 29 | if (!waypoint.enabled) { 30 | continue 31 | } 32 | if (style && style.display === 'none') { 33 | console.error(displayNoneMessage) 34 | } 35 | if (style && style.position === 'fixed') { 36 | console.error(fixedMessage) 37 | } 38 | } 39 | } 40 | return originalRefresh.call(this) 41 | } 42 | } 43 | 44 | checkWaypointStyles() 45 | }()) 46 | ; -------------------------------------------------------------------------------- /practice/lib/shortcuts/inview.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints Inview Shortcut - 4.0.1 3 | Copyright © 2011-2016 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6 | */ 7 | !function(){"use strict";function t(){}function e(t){this.options=i.Adapter.extend({},e.defaults,t),this.axis=this.options.horizontal?"horizontal":"vertical",this.waypoints=[],this.element=this.options.element,this.createWaypoints()}var i=window.Waypoint;e.prototype.createWaypoints=function(){for(var t={vertical:[{down:"enter",up:"exited",offset:"100%"},{down:"entered",up:"exit",offset:"bottom-in-view"},{down:"exit",up:"entered",offset:0},{down:"exited",up:"enter",offset:function(){return-this.adapter.outerHeight()}}],horizontal:[{right:"enter",left:"exited",offset:"100%"},{right:"entered",left:"exit",offset:"right-in-view"},{right:"exit",left:"entered",offset:0},{right:"exited",left:"enter",offset:function(){return-this.adapter.outerWidth()}}]},e=0,i=t[this.axis].length;i>e;e++){var n=t[this.axis][e];this.createWaypoint(n)}},e.prototype.createWaypoint=function(t){var e=this;this.waypoints.push(new i({context:this.options.context,element:this.options.element,enabled:this.options.enabled,handler:function(t){return function(i){e.options[t[i]].call(e,i)}}(t),offset:t.offset,horizontal:this.options.horizontal}))},e.prototype.destroy=function(){for(var t=0,e=this.waypoints.length;e>t;t++)this.waypoints[t].destroy();this.waypoints=[]},e.prototype.disable=function(){for(var t=0,e=this.waypoints.length;e>t;t++)this.waypoints[t].disable()},e.prototype.enable=function(){for(var t=0,e=this.waypoints.length;e>t;t++)this.waypoints[t].enable()},e.defaults={context:window,enabled:!0,enter:t,entered:t,exit:t,exited:t},i.Inview=e}(); -------------------------------------------------------------------------------- /practice/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | html, 6 | body { 7 | margin: 0; 8 | padding: 0; 9 | } 10 | 11 | body { 12 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, 13 | Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; 14 | min-height: 1280px; 15 | color: #3b3b3b; 16 | font-size: 24px; 17 | } 18 | 19 | p, 20 | h1, 21 | h2, 22 | h3, 23 | h4, 24 | a { 25 | margin: 0; 26 | font-weight: 400; 27 | } 28 | 29 | a, 30 | a:visited, 31 | a:hover { 32 | color: teal; 33 | text-decoration: none; 34 | border-bottom: 2px solid currentColor; 35 | } 36 | 37 | nav { 38 | display: -webkit-box; 39 | display: -ms-flexbox; 40 | display: flex; 41 | -webkit-box-align: baseline; 42 | -ms-flex-align: baseline; 43 | align-items: baseline; 44 | -webkit-box-pack: justify; 45 | -ms-flex-pack: justify; 46 | justify-content: space-between; 47 | background: #f3f3f3; 48 | padding: 1rem; 49 | padding-right: 5rem; 50 | -ms-flex-wrap: wrap; 51 | flex-wrap: wrap; 52 | } 53 | 54 | .nav__examples { 55 | display: -webkit-box; 56 | display: -ms-flexbox; 57 | display: flex; 58 | -webkit-box-align: baseline; 59 | -ms-flex-align: baseline; 60 | align-items: baseline; 61 | -ms-flex-wrap: wrap; 62 | flex-wrap: wrap; 63 | margin-top: 1rem; 64 | } 65 | 66 | .nav__examples > * { 67 | margin-right: 0.5rem; 68 | } 69 | 70 | #intro { 71 | max-width: 40rem; 72 | margin: 1rem auto; 73 | text-align: center; 74 | } 75 | 76 | .intro__hed { 77 | font-size: 2em; 78 | margin: 2rem auto 0.5rem auto; 79 | } 80 | 81 | .intro__dek { 82 | color: #8a8a8a; 83 | } 84 | 85 | #intro { 86 | margin-bottom: 320px; 87 | } 88 | 89 | #outro { 90 | height: 640px; 91 | } 92 | 93 | @media (min-width: 840px) { 94 | .nav__examples { 95 | margin-top: 0; 96 | margin-left: 2rem; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /practice/lib/shortcuts/sticky.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints Sticky Element Shortcut - 4.0.1 3 | Copyright © 2011-2016 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6 | */ 7 | (function() { 8 | 'use strict' 9 | 10 | var $ = window.jQuery 11 | var Waypoint = window.Waypoint 12 | 13 | /* http://imakewebthings.com/waypoints/shortcuts/sticky-elements */ 14 | function Sticky(options) { 15 | this.options = $.extend({}, Waypoint.defaults, Sticky.defaults, options) 16 | this.element = this.options.element 17 | this.$element = $(this.element) 18 | this.createWrapper() 19 | this.createWaypoint() 20 | } 21 | 22 | /* Private */ 23 | Sticky.prototype.createWaypoint = function() { 24 | var originalHandler = this.options.handler 25 | 26 | this.waypoint = new Waypoint($.extend({}, this.options, { 27 | element: this.wrapper, 28 | handler: $.proxy(function(direction) { 29 | var shouldBeStuck = this.options.direction.indexOf(direction) > -1 30 | var wrapperHeight = shouldBeStuck ? this.$element.outerHeight(true) : '' 31 | 32 | this.$wrapper.height(wrapperHeight) 33 | this.$element.toggleClass(this.options.stuckClass, shouldBeStuck) 34 | 35 | if (originalHandler) { 36 | originalHandler.call(this, direction) 37 | } 38 | }, this) 39 | })) 40 | } 41 | 42 | /* Private */ 43 | Sticky.prototype.createWrapper = function() { 44 | if (this.options.wrapper) { 45 | this.$element.wrap(this.options.wrapper) 46 | } 47 | this.$wrapper = this.$element.parent() 48 | this.wrapper = this.$wrapper[0] 49 | } 50 | 51 | /* Public */ 52 | Sticky.prototype.destroy = function() { 53 | if (this.$element.parent()[0] === this.wrapper) { 54 | this.waypoint.destroy() 55 | this.$element.removeClass(this.options.stuckClass) 56 | if (this.options.wrapper) { 57 | this.$element.unwrap() 58 | } 59 | } 60 | } 61 | 62 | Sticky.defaults = { 63 | wrapper: '
', 64 | stuckClass: 'stuck', 65 | direction: 'down right' 66 | } 67 | 68 | Waypoint.Sticky = Sticky 69 | }()) 70 | ; -------------------------------------------------------------------------------- /practice/lib/shortcuts/infinite.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints Infinite Scroll Shortcut - 4.0.1 3 | Copyright © 2011-2016 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6 | */ 7 | (function() { 8 | 'use strict' 9 | 10 | var $ = window.jQuery 11 | var Waypoint = window.Waypoint 12 | 13 | /* http://imakewebthings.com/waypoints/shortcuts/infinite-scroll */ 14 | function Infinite(options) { 15 | this.options = $.extend({}, Infinite.defaults, options) 16 | this.container = this.options.element 17 | if (this.options.container !== 'auto') { 18 | this.container = this.options.container 19 | } 20 | this.$container = $(this.container) 21 | this.$more = $(this.options.more) 22 | 23 | if (this.$more.length) { 24 | this.setupHandler() 25 | this.waypoint = new Waypoint(this.options) 26 | } 27 | } 28 | 29 | /* Private */ 30 | Infinite.prototype.setupHandler = function() { 31 | this.options.handler = $.proxy(function() { 32 | this.options.onBeforePageLoad() 33 | this.destroy() 34 | this.$container.addClass(this.options.loadingClass) 35 | 36 | $.get($(this.options.more).attr('href'), $.proxy(function(data) { 37 | var $data = $($.parseHTML(data)) 38 | var $newMore = $data.find(this.options.more) 39 | 40 | var $items = $data.find(this.options.items) 41 | if (!$items.length) { 42 | $items = $data.filter(this.options.items) 43 | } 44 | 45 | this.$container.append($items) 46 | this.$container.removeClass(this.options.loadingClass) 47 | 48 | if (!$newMore.length) { 49 | $newMore = $data.filter(this.options.more) 50 | } 51 | if ($newMore.length) { 52 | this.$more.replaceWith($newMore) 53 | this.$more = $newMore 54 | this.waypoint = new Waypoint(this.options) 55 | } 56 | else { 57 | this.$more.remove() 58 | } 59 | 60 | this.options.onAfterPageLoad($items) 61 | }, this)) 62 | }, this) 63 | } 64 | 65 | /* Public */ 66 | Infinite.prototype.destroy = function() { 67 | if (this.waypoint) { 68 | this.waypoint.destroy() 69 | } 70 | } 71 | 72 | Infinite.defaults = { 73 | container: 'auto', 74 | items: '.infinite-item', 75 | more: '.infinite-more-link', 76 | offset: 'bottom-in-view', 77 | loadingClass: 'infinite-loading', 78 | onBeforePageLoad: $.noop, 79 | onAfterPageLoad: $.noop 80 | } 81 | 82 | Waypoint.Infinite = Infinite 83 | }()) 84 | ; -------------------------------------------------------------------------------- /practice/layouts.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "layouts" 3 | format: html 4 | --- 5 | 6 | ::::: {.columns .column-page} 7 | :::{.sidebar} 8 | hello there good frriend! 9 | ::: 10 | :::{.column-screen-right} 11 | Quarto supports a variety of page layout options that enable you to author content that: 12 | 13 | Fills the main content region 14 | Overflows the content region 15 | Spans the entire page 16 | Occupies the document margin 17 | Quarto uses the concept of columns to describe page layout (e.g. the “body” column, the “margin” column, etc.). Below we’ll describe how to arrange content into these columns. 18 | 19 | All of the layout capabilities described in this document work for HTML output and many work for PDF and LaTeX output. For details about the PDF / LaTeX output, see PDF/LaTeX Layout. 20 | Quarto supports a variety of page layout options that enable you to author content that: 21 | 22 | Fills the main content region 23 | Overflows the content region 24 | Spans the entire page 25 | Occupies the document margin 26 | Quarto uses the concept of columns to describe page layout (e.g. the “body” column, the “margin” column, etc.). Below we’ll describe how to arrange content into these columns. 27 | 28 | All of the layout capabilities described in this document work for HTML output and many work for PDF and LaTeX output. For details about the PDF / LaTeX output, see PDF/LaTeX Layout. 29 | Quarto supports a variety of page layout options that enable you to author content that: 30 | 31 | Fills the main content region 32 | Overflows the content region 33 | Spans the entire page 34 | Occupies the document margin 35 | Quarto uses the concept of columns to describe page layout (e.g. the “body” column, the “margin” column, etc.). Below we’ll describe how to arrange content into these columns. 36 | 37 | All of the layout capabilities described in this document work for HTML output and many work for PDF and LaTeX output. For details about the PDF / LaTeX output, see PDF/LaTeX Layout. 38 | Quarto supports a variety of page layout options that enable you to author content that: 39 | 40 | Fills the main content region 41 | Overflows the content region 42 | Spans the entire page 43 | Occupies the document margin 44 | Quarto uses the concept of columns to describe page layout (e.g. the “body” column, the “margin” column, etc.). Below we’ll describe how to arrange content into these columns. 45 | 46 | All of the layout capabilities described in this document work for HTML output and many work for PDF and LaTeX output. For details about the PDF / LaTeX output, see PDF/LaTeX Layout. 47 | ::: 48 | ::: 49 | 50 | ```{=html} 51 | 68 | ``` 69 | 70 | -------------------------------------------------------------------------------- /practice/lib/shortcuts/inview.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints Inview Shortcut - 4.0.1 3 | Copyright © 2011-2016 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6 | */ 7 | (function() { 8 | 'use strict' 9 | 10 | function noop() {} 11 | 12 | var Waypoint = window.Waypoint 13 | 14 | /* http://imakewebthings.com/waypoints/shortcuts/inview */ 15 | function Inview(options) { 16 | this.options = Waypoint.Adapter.extend({}, Inview.defaults, options) 17 | this.axis = this.options.horizontal ? 'horizontal' : 'vertical' 18 | this.waypoints = [] 19 | this.element = this.options.element 20 | this.createWaypoints() 21 | } 22 | 23 | /* Private */ 24 | Inview.prototype.createWaypoints = function() { 25 | var configs = { 26 | vertical: [{ 27 | down: 'enter', 28 | up: 'exited', 29 | offset: '100%' 30 | }, { 31 | down: 'entered', 32 | up: 'exit', 33 | offset: 'bottom-in-view' 34 | }, { 35 | down: 'exit', 36 | up: 'entered', 37 | offset: 0 38 | }, { 39 | down: 'exited', 40 | up: 'enter', 41 | offset: function() { 42 | return -this.adapter.outerHeight() 43 | } 44 | }], 45 | horizontal: [{ 46 | right: 'enter', 47 | left: 'exited', 48 | offset: '100%' 49 | }, { 50 | right: 'entered', 51 | left: 'exit', 52 | offset: 'right-in-view' 53 | }, { 54 | right: 'exit', 55 | left: 'entered', 56 | offset: 0 57 | }, { 58 | right: 'exited', 59 | left: 'enter', 60 | offset: function() { 61 | return -this.adapter.outerWidth() 62 | } 63 | }] 64 | } 65 | 66 | for (var i = 0, end = configs[this.axis].length; i < end; i++) { 67 | var config = configs[this.axis][i] 68 | this.createWaypoint(config) 69 | } 70 | } 71 | 72 | /* Private */ 73 | Inview.prototype.createWaypoint = function(config) { 74 | var self = this 75 | this.waypoints.push(new Waypoint({ 76 | context: this.options.context, 77 | element: this.options.element, 78 | enabled: this.options.enabled, 79 | handler: (function(config) { 80 | return function(direction) { 81 | self.options[config[direction]].call(self, direction) 82 | } 83 | }(config)), 84 | offset: config.offset, 85 | horizontal: this.options.horizontal 86 | })) 87 | } 88 | 89 | /* Public */ 90 | Inview.prototype.destroy = function() { 91 | for (var i = 0, end = this.waypoints.length; i < end; i++) { 92 | this.waypoints[i].destroy() 93 | } 94 | this.waypoints = [] 95 | } 96 | 97 | Inview.prototype.disable = function() { 98 | for (var i = 0, end = this.waypoints.length; i < end; i++) { 99 | this.waypoints[i].disable() 100 | } 101 | } 102 | 103 | Inview.prototype.enable = function() { 104 | for (var i = 0, end = this.waypoints.length; i < end; i++) { 105 | this.waypoints[i].enable() 106 | } 107 | } 108 | 109 | Inview.defaults = { 110 | context: window, 111 | enabled: true, 112 | enter: noop, 113 | entered: noop, 114 | exit: noop, 115 | exited: noop 116 | } 117 | 118 | Waypoint.Inview = Inview 119 | }()) 120 | ; -------------------------------------------------------------------------------- /gg-close-read-dream-syntax-1.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | format: 3 | close-read-html: 4 | sticky-sidebar: 5 | sidebar-background: black 6 | body-background: white 7 | execute: 8 | echo: false 9 | --- 10 | 11 | :::{.sticky-sidebar} 12 | 13 | # A Grammar of Graphics 14 | 15 | ## A close read of a scatterplot 16 | 17 | By Andrew Bray 18 | 19 | What a lovely graphic this is, 20 | 21 | with its three colors 22 | 23 | and dots all over the place. 24 | 25 | I wonder: how was this made? Let's walk through this step by step, starting with the data. 26 | 27 | ```{r} 28 | #| echo: false 29 | #| eval: true 30 | #| warning: false 31 | #| label: cr-plot1 32 | 33 | ggplot(penguins, aes(x = bill_length_mm, 34 | y = flipper_length_mm, 35 | color = species)) + 36 | geom_point() + 37 | labs(x = "Bill Length", 38 | y = "Flipper Length", 39 | Species = "Species") + 40 | theme_bw() 41 | ``` 42 | 43 | ### The Data {.step label="cr-tab1" transition="scrolloff-then-scrollon"} 44 | 45 | At the foundation of any data visualization is the data itself. Here our data come from Dr. Kristen Gorman, who recorded measurements on 344 penguins near Palmer Station, Antarctica. The three variables at hand are the length of the bill (a numerical variable), the length of the flipper (a numerical variable), and the species of the bird (a categorical variable). 46 | 47 | We can see that we have a bump in the road ahead! At least one of these rows has some missing values, as indicated by *NA*. [show highlight of NA row]. 48 | 49 | ```{r} 50 | #| echo: false 51 | #| eval: true 52 | #| warning: false 53 | #| label: cr-tab1 54 | 55 | select(penguins, species, bill_length_mm, flipper_length_mm) 56 | ``` 57 | 58 | 59 | ### The Canvas {.step label="cr-plot2"} 60 | 61 | You can lay down a blank sheet of paper by calling the `ggplot()` function in the `ggplot2` package in R. Right now, there's nothing to see here, just a blank canvas, waiting to be designed. 62 | 63 | ```{r} 64 | #| echo: true 65 | #| eval: true 66 | #| warning: false 67 | #| label: cr-plot2 68 | #| transition: "fade 69 | 70 | ggplot() 71 | ``` 72 | 73 | ### Aesthetic mappings {.step label="cr-plot3" transition="fadeout-then-fadein"} 74 | 75 | The first and most important decision in the design of a graphic is the *aesthetic mapping*. This is a dynamic link that ties the variability found in a column of your data frame to variability in an aesthetic attribute of the plot. 76 | 77 | For a colored scatter plot, we use the following aesthetic mappings:\ 78 | - Map bill length to the x-axis\ 79 | - Map flipper length to the y-axis\ 80 | - Map the species to a color palette\ 81 | 82 | This plot still looks quite bare. Where is the data? 83 | 84 | ```{r} 85 | #| echo: true 86 | #| eval: true 87 | #| warning: false 88 | #| label: cr-plot3 89 | #| cr-transition: " 90 | 91 | ggplot(penguins, aes(x = bill_length_mm, 92 | y = flipper_length_mm, 93 | color = species)) 94 | ``` 95 | 96 | ### Geometry 97 | 98 | The plot comes alive once we've assigned a **geometry**. The geometry describes the manner in which the observations show up in the graphic. In the *point* geometry, every observation is represented by a single circle. Now that our observation are plotted according to their aesthetic mapping, our plot is almost complete. 99 | 100 | What's lacking is some polish. 101 | 102 | ```{r} 103 | #| echo: true 104 | #| eval: true 105 | #| warning: false 106 | 107 | ggplot(penguins, aes(x = bill_length_mm, 108 | y = flipper_length_mm, 109 | color = species)) + 110 | geom_point() 111 | ``` 112 | 113 | ### Theme 114 | 115 | To polish up the look of our plot, we'll focus on two things. The most apparent is the *theme*, which encompasses several small design decisions: the color of the background, the number and color of guidelines, the font, etc. `ggplot2` defaults to a gray background but I prefer the more minimal look of the white background in the black-and-white theme. 116 | 117 | The last piece to fix up was those labels. By default, the column names will show up. Those are written so that R can understand them: they lack spaces or punctuation. Here I've rewritten the labels to be ones that can be better understood by a human. 118 | 119 | ```{r} 120 | #| echo: true 121 | #| eval: true 122 | #| warning: false 123 | 124 | ggplot(penguins, aes(x = bill_length_mm, 125 | y = flipper_length_mm, 126 | color = species)) + 127 | geom_point() + 128 | labs(x = "Bill Length", 129 | y = "Flipper Length", 130 | Species = "Species") + 131 | theme_bw() 132 | ``` 133 | 134 | # El Fin 135 | 136 | ::: 137 | -------------------------------------------------------------------------------- /practice/sticky-side-original.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Untitled" 3 | format: html 4 | --- 5 | 6 | 7 | ```{=html} 8 | 9 | 10 | 11 | 12 | Scrollama: Sticky Overlay Example 13 | 14 | 15 | 16 | 74 | 75 | 76 | 77 |
78 | 88 |
89 |

Sticky Overlay Example

90 |

91 | Start scrolling to see how it works. 92 |

93 |
94 | 95 |
96 |
97 |

0

98 |
99 | 100 |
101 |
102 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

103 |
104 |
105 |

ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

106 |
107 |
108 |

dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

109 |
110 |
111 |

sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

112 |
113 |
114 |
115 | 116 |
117 |
118 | 119 | 120 | 121 | 122 | 166 | 167 | 168 | ``` -------------------------------------------------------------------------------- /gg-close-read.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | format: 3 | html: 4 | theme: 5 | - custom.scss 6 | fontcolor: black 7 | backgroundcolor: white 8 | page-layout: full 9 | self-contained: true 10 | df-print: paged 11 | execute: 12 | echo: false 13 | --- 14 | 15 | ::::: {.columns .column-page} 16 | 17 | :::: {.column width=35%} 18 | 19 | # A Grammar of Graphics 20 | 21 | ## A close read of a scatterplot 22 | 23 | [By Andrew Bray]{style="font-size: .7em"} 24 | 25 | :::{} 26 | \ 27 | ::: 28 | 29 | What a lovely graphic this is, 30 | 31 | with its three colors 32 | 33 | and dots all over the place. 34 | 35 | I wonder: how was this made? Let's walk through this step by step, starting with the data. 36 | 37 | :::: 38 | 39 | :::: {.column width="10%"} 40 | :::: 41 | 42 | :::: {.column width="55%" style="padding:20px; position:sticky;top:30vh;"} 43 | 44 | ```{r} 45 | #| echo: false 46 | #| eval: true 47 | #| warning: false 48 | 49 | library(ggplot2) 50 | library(palmerpenguins) 51 | library(dplyr) 52 | ggplot(penguins, aes(x = bill_length_mm, 53 | y = flipper_length_mm, 54 | color = species)) + 55 | geom_point() + 56 | labs(x = "Bill Length", 57 | y = "Flipper Length", 58 | Species = "Species") + 59 | theme_bw() 60 | ``` 61 | ::::: 62 | ::::: 63 | 64 | ::::: {.columns .column-page} 65 | :::: {.column width="35%"} 66 | 67 | ### The Data 68 | 69 | At the foundation of any data visualization is the data itself. Here our data come from Dr. Kristen Gorman, who recorded measurements on 344 penguins near Palmer Station, Antarctica. The three variables at hand are the length of the bill (a numerical variable), the length of the flipper (a numerical variable), and the species of the bird (a categorical variable). 70 | 71 | We can see that we have a bump in the road ahead! At least one of these rows has some missing values, as indicated by *NA*. [show highlight of NA row]. 72 | 73 | 74 | \ 75 | 76 | :::: 77 | 78 | :::: {.column width="10%"} 79 | :::: 80 | 81 | :::: {.column width="55%" style="padding:20px; position:sticky;top:20vh;"} 82 | 83 | ```{r} 84 | #| echo: false 85 | #| eval: true 86 | #| warning: false 87 | 88 | select(penguins, species, bill_length_mm, flipper_length_mm) 89 | ``` 90 | 91 | :::: 92 | ::::: 93 | 94 | ::::: {.columns .column-page} 95 | :::: {.column width="35%"} 96 | 97 | ### The Canvas 98 | 99 | You can lay down a blank sheet of paper by calling the `ggplot()` function in the `ggplot2` package in R. Right now, there's nothing to see here, just a blank canvas, waiting to be designed. 100 | 101 | \ 102 | 103 | :::: 104 | 105 | :::: {.column width="10%"} 106 | :::: 107 | 108 | :::: {.column width="55%" style="padding:20px; position:sticky;top:20vh;"} 109 | 110 | ```{r} 111 | #| echo: true 112 | #| eval: true 113 | #| warning: false 114 | 115 | ggplot() 116 | ``` 117 | 118 | :::: 119 | ::::: 120 | 121 | 122 | ::::: {.columns .column-page} 123 | :::: {.column width="35%"} 124 | 125 | ### Aesthetic mappings 126 | 127 | The first and most important decision in the design of a graphic is the *aesthetic mapping*. This is a dynamic link that ties the variability found in a column of your data frame to variability in an aesthetic attribute of the plot. 128 | 129 | For a colored scatter plot, we use the following aesthetic mappings:\ 130 | - Map bill length to the x-axis\ 131 | - Map flipper length to the y-axis\ 132 | - Map the species to a color palette\ 133 | 134 | This plot still looks quite bare. Where is the data? 135 | 136 | :::: 137 | 138 | :::: {.column width="10%"} 139 | :::: 140 | 141 | :::: {.column width="55%" style="padding:20px; position:sticky;top:10vh;"} 142 | 143 | ```{r} 144 | #| echo: true 145 | #| eval: true 146 | #| warning: false 147 | 148 | ggplot(penguins, aes(x = bill_length_mm, 149 | y = flipper_length_mm, 150 | color = species)) 151 | ``` 152 | 153 | :::: 154 | ::::: 155 | 156 | ::::: {.columns .column-page} 157 | :::: {.column width="35%"} 158 | 159 | ### Geometry 160 | 161 | The plot comes alive once we've assigned a **geometry**. The geometry describes the manner in which the observations show up in the graphic. In the *point* geometry, every observation is represented by a single circle. Now that our observation are plotted according to their aesthetic mapping, our plot is almost complete. 162 | 163 | What's lacking is some polish. 164 | 165 | :::: 166 | 167 | :::: {.column width="10%"} 168 | :::: 169 | 170 | :::: {.column width="55%" style="padding:20px; position:sticky;top:10vh;"} 171 | 172 | ```{r} 173 | #| echo: true 174 | #| eval: true 175 | #| warning: false 176 | 177 | ggplot(penguins, aes(x = bill_length_mm, 178 | y = flipper_length_mm, 179 | color = species)) + 180 | geom_point() 181 | ``` 182 | 183 | :::: 184 | ::::: 185 | 186 | 187 | ::::: {.columns .column-page} 188 | :::: {.column width="35%"} 189 | 190 | ### Theme 191 | 192 | To polish up the look of our plot, we'll focus on two things. The most apparent is the *theme*, which encompasses several small design decisions: the color of the background, the number and color of guidelines, the font, etc. `ggplot2` defaults to a gray background but I prefer the more minimal look of the white background in the black-and-white theme. 193 | 194 | :::{} 195 | The last piece to fix up was those labels. By default, the column names will show up. Those are written so that R can understand them: they lack spaces or punctuation. Here I've rewritten the labels to be ones that can be better understood by a human. 196 | 197 | \ 198 | 199 | :::: 200 | 201 | :::: {.column width="10%"} 202 | :::: 203 | 204 | :::: {.column width="55%" style="padding:20px; position:sticky;top:7vh;"} 205 | 206 | ```{r} 207 | #| echo: true 208 | #| eval: true 209 | #| warning: false 210 | 211 | ggplot(penguins, aes(x = bill_length_mm, 212 | y = flipper_length_mm, 213 | color = species)) + 214 | geom_point() + 215 | labs(x = "Bill Length", 216 | y = "Flipper Length", 217 | Species = "Species") + 218 | theme_bw() 219 | ``` 220 | 221 | :::: 222 | ::::: 223 | 224 | 225 | # El Fin 226 | -------------------------------------------------------------------------------- /practice/scrollama.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | format: html 3 | --- 4 | 5 | ```{=html} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Scrollama: Sticky Side Example 14 | 15 | 16 | 17 | 86 | 87 | 88 | 89 | 100 |
101 |
102 |

Sticky Side Example

103 |

104 | Start scrolling to see how it works. 105 |

106 |
107 | 108 |
109 |
110 |
111 |

STEP 1

112 |
113 |
114 |

STEP 2

115 |
116 |
117 |

STEP 3

118 |
119 |
120 |

STEP 4

121 |
122 |
123 | 124 |
125 |

0

126 |
127 |
128 | 129 |
130 |
131 | 132 | 133 | 134 | 135 | 197 | 198 | 199 | 200 | ``` -------------------------------------------------------------------------------- /practice/sticky-side.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | format: 3 | html: 4 | theme: 5 | - sandstone 6 | - custom.scss 7 | fontcolor: black 8 | backgroundcolor: white 9 | page-layout: full 10 | execute: 11 | echo: false 12 | --- 13 | 14 | ::::: {.columns .column-page} 15 | 16 | :::: {.column width=35%} 17 | 18 | # A Grammar of Graphics 19 | 20 | ## A close read of a scatterplot 21 | 22 | [By Andrew Bray]{style="font-size: .7em"} 23 | 24 | :::{} 25 | \ 26 | ::: 27 | 28 | What a lovely graphics this is, 29 | 30 | :::{.step data-img="url(pic2.png)" data-color="blue" data-src="https://rstudio-conf-2022.github.io/rmd-to-quarto/materials/3-computation/slides/computation.html#/generalizing-the-code-chunk-2"} 31 | with its three colors 32 | ::: 33 | 34 | :::{.step data-img="url(pic2.png)" data-color="green"} 35 | and dots all over the place. 36 | ::: 37 | 38 | I wonder: how was this made? 39 | 40 | :::: 41 | 42 | :::: {.column width="10%"} 43 | :::: 44 | 45 | :::: {.column .sticky-thing width="55%"} 46 | 47 | 48 | 49 | 50 | ```{r} 51 | #| echo: false 52 | #| eval: false 53 | #| warning: false 54 | 55 | library(tidyverse) 56 | library(palmerpenguins) 57 | 58 | ggplot(penguins, aes(x = bill_length_mm, 59 | y = flipper_length_mm, 60 | color = species)) + 61 | geom_point() + 62 | labs(x = "Bill Length", 63 | y = "Flipper Length", 64 | Species = "Species") 65 | ``` 66 | :::: 67 | ::::: 68 | 69 | ```{=html} 70 | 71 | 72 | 73 | 74 | Scrollama: Sticky Overlay Example 75 | 76 | 77 | 113 | 114 | 115 | 116 |
117 |
118 |

Sticky Overlay Example

119 |

120 | Start scrolling to see how it works. 121 |

122 |
123 | 124 |
125 |
126 |

0

127 |
128 | 129 |
130 |
131 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

132 |
133 |
134 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

135 |
136 |
137 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

138 |
139 |
140 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

141 |
142 |
143 |
144 | 145 |
146 |
147 | 148 | 149 | 150 | 151 | 191 | 192 | 193 | ``` -------------------------------------------------------------------------------- /practice/waypoints.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | format: html 3 | --- 4 | 5 | ```{=html} 6 | 7 | 8 | 22 | 23 | 31 | ``` 32 | 33 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 34 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 35 | 36 | :::{#basic-waypoint} 37 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 38 | ::: 39 | 40 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 41 | 42 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 43 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter.v 44 | 45 | 46 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 47 | 48 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 49 | 50 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 51 | 52 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 53 | 54 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 55 | 56 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 57 | 58 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 59 | 60 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 61 | 62 | v 63 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 64 | 65 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 66 | 67 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 68 | 69 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 70 | 71 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 72 | 73 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. 74 | 75 | You may notice the basic example above triggers when we scroll through the waypoint both downwards and upwards. What if we want to perform different actions when scrolling up, or limit our handler to one direction? When a waypoint is triggered, the handler function is passed a direction parameter. -------------------------------------------------------------------------------- /practice/lib/jquery.waypoints.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints - 4.0.1 3 | Copyright © 2011-2016 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6 | */ 7 | !function(){"use strict";function t(o){if(!o)throw new Error("No options passed to Waypoint constructor");if(!o.element)throw new Error("No element option passed to Waypoint constructor");if(!o.handler)throw new Error("No handler option passed to Waypoint constructor");this.key="waypoint-"+e,this.options=t.Adapter.extend({},t.defaults,o),this.element=this.options.element,this.adapter=new t.Adapter(this.element),this.callback=o.handler,this.axis=this.options.horizontal?"horizontal":"vertical",this.enabled=this.options.enabled,this.triggerPoint=null,this.group=t.Group.findOrCreate({name:this.options.group,axis:this.axis}),this.context=t.Context.findOrCreateByElement(this.options.context),t.offsetAliases[this.options.offset]&&(this.options.offset=t.offsetAliases[this.options.offset]),this.group.add(this),this.context.add(this),i[this.key]=this,e+=1}var e=0,i={};t.prototype.queueTrigger=function(t){this.group.queueTrigger(this,t)},t.prototype.trigger=function(t){this.enabled&&this.callback&&this.callback.apply(this,t)},t.prototype.destroy=function(){this.context.remove(this),this.group.remove(this),delete i[this.key]},t.prototype.disable=function(){return this.enabled=!1,this},t.prototype.enable=function(){return this.context.refresh(),this.enabled=!0,this},t.prototype.next=function(){return this.group.next(this)},t.prototype.previous=function(){return this.group.previous(this)},t.invokeAll=function(t){var e=[];for(var o in i)e.push(i[o]);for(var n=0,r=e.length;r>n;n++)e[n][t]()},t.destroyAll=function(){t.invokeAll("destroy")},t.disableAll=function(){t.invokeAll("disable")},t.enableAll=function(){t.Context.refreshAll();for(var e in i)i[e].enabled=!0;return this},t.refreshAll=function(){t.Context.refreshAll()},t.viewportHeight=function(){return window.innerHeight||document.documentElement.clientHeight},t.viewportWidth=function(){return document.documentElement.clientWidth},t.adapters=[],t.defaults={context:window,continuous:!0,enabled:!0,group:"default",horizontal:!1,offset:0},t.offsetAliases={"bottom-in-view":function(){return this.context.innerHeight()-this.adapter.outerHeight()},"right-in-view":function(){return this.context.innerWidth()-this.adapter.outerWidth()}},window.Waypoint=t}(),function(){"use strict";function t(t){window.setTimeout(t,1e3/60)}function e(t){this.element=t,this.Adapter=n.Adapter,this.adapter=new this.Adapter(t),this.key="waypoint-context-"+i,this.didScroll=!1,this.didResize=!1,this.oldScroll={x:this.adapter.scrollLeft(),y:this.adapter.scrollTop()},this.waypoints={vertical:{},horizontal:{}},t.waypointContextKey=this.key,o[t.waypointContextKey]=this,i+=1,n.windowContext||(n.windowContext=!0,n.windowContext=new e(window)),this.createThrottledScrollHandler(),this.createThrottledResizeHandler()}var i=0,o={},n=window.Waypoint,r=window.onload;e.prototype.add=function(t){var e=t.options.horizontal?"horizontal":"vertical";this.waypoints[e][t.key]=t,this.refresh()},e.prototype.checkEmpty=function(){var t=this.Adapter.isEmptyObject(this.waypoints.horizontal),e=this.Adapter.isEmptyObject(this.waypoints.vertical),i=this.element==this.element.window;t&&e&&!i&&(this.adapter.off(".waypoints"),delete o[this.key])},e.prototype.createThrottledResizeHandler=function(){function t(){e.handleResize(),e.didResize=!1}var e=this;this.adapter.on("resize.waypoints",function(){e.didResize||(e.didResize=!0,n.requestAnimationFrame(t))})},e.prototype.createThrottledScrollHandler=function(){function t(){e.handleScroll(),e.didScroll=!1}var e=this;this.adapter.on("scroll.waypoints",function(){(!e.didScroll||n.isTouch)&&(e.didScroll=!0,n.requestAnimationFrame(t))})},e.prototype.handleResize=function(){n.Context.refreshAll()},e.prototype.handleScroll=function(){var t={},e={horizontal:{newScroll:this.adapter.scrollLeft(),oldScroll:this.oldScroll.x,forward:"right",backward:"left"},vertical:{newScroll:this.adapter.scrollTop(),oldScroll:this.oldScroll.y,forward:"down",backward:"up"}};for(var i in e){var o=e[i],n=o.newScroll>o.oldScroll,r=n?o.forward:o.backward;for(var s in this.waypoints[i]){var a=this.waypoints[i][s];if(null!==a.triggerPoint){var l=o.oldScroll=a.triggerPoint,p=l&&h,u=!l&&!h;(p||u)&&(a.queueTrigger(r),t[a.group.id]=a.group)}}}for(var c in t)t[c].flushTriggers();this.oldScroll={x:e.horizontal.newScroll,y:e.vertical.newScroll}},e.prototype.innerHeight=function(){return this.element==this.element.window?n.viewportHeight():this.adapter.innerHeight()},e.prototype.remove=function(t){delete this.waypoints[t.axis][t.key],this.checkEmpty()},e.prototype.innerWidth=function(){return this.element==this.element.window?n.viewportWidth():this.adapter.innerWidth()},e.prototype.destroy=function(){var t=[];for(var e in this.waypoints)for(var i in this.waypoints[e])t.push(this.waypoints[e][i]);for(var o=0,n=t.length;n>o;o++)t[o].destroy()},e.prototype.refresh=function(){var t,e=this.element==this.element.window,i=e?void 0:this.adapter.offset(),o={};this.handleScroll(),t={horizontal:{contextOffset:e?0:i.left,contextScroll:e?0:this.oldScroll.x,contextDimension:this.innerWidth(),oldScroll:this.oldScroll.x,forward:"right",backward:"left",offsetProp:"left"},vertical:{contextOffset:e?0:i.top,contextScroll:e?0:this.oldScroll.y,contextDimension:this.innerHeight(),oldScroll:this.oldScroll.y,forward:"down",backward:"up",offsetProp:"top"}};for(var r in t){var s=t[r];for(var a in this.waypoints[r]){var l,h,p,u,c,d=this.waypoints[r][a],f=d.options.offset,w=d.triggerPoint,y=0,g=null==w;d.element!==d.element.window&&(y=d.adapter.offset()[s.offsetProp]),"function"==typeof f?f=f.apply(d):"string"==typeof f&&(f=parseFloat(f),d.options.offset.indexOf("%")>-1&&(f=Math.ceil(s.contextDimension*f/100))),l=s.contextScroll-s.contextOffset,d.triggerPoint=Math.floor(y+l-f),h=w=s.oldScroll,u=h&&p,c=!h&&!p,!g&&u?(d.queueTrigger(s.backward),o[d.group.id]=d.group):!g&&c?(d.queueTrigger(s.forward),o[d.group.id]=d.group):g&&s.oldScroll>=d.triggerPoint&&(d.queueTrigger(s.forward),o[d.group.id]=d.group)}}return n.requestAnimationFrame(function(){for(var t in o)o[t].flushTriggers()}),this},e.findOrCreateByElement=function(t){return e.findByElement(t)||new e(t)},e.refreshAll=function(){for(var t in o)o[t].refresh()},e.findByElement=function(t){return o[t.waypointContextKey]},window.onload=function(){r&&r(),e.refreshAll()},n.requestAnimationFrame=function(e){var i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||t;i.call(window,e)},n.Context=e}(),function(){"use strict";function t(t,e){return t.triggerPoint-e.triggerPoint}function e(t,e){return e.triggerPoint-t.triggerPoint}function i(t){this.name=t.name,this.axis=t.axis,this.id=this.name+"-"+this.axis,this.waypoints=[],this.clearTriggerQueues(),o[this.axis][this.name]=this}var o={vertical:{},horizontal:{}},n=window.Waypoint;i.prototype.add=function(t){this.waypoints.push(t)},i.prototype.clearTriggerQueues=function(){this.triggerQueues={up:[],down:[],left:[],right:[]}},i.prototype.flushTriggers=function(){for(var i in this.triggerQueues){var o=this.triggerQueues[i],n="up"===i||"left"===i;o.sort(n?e:t);for(var r=0,s=o.length;s>r;r+=1){var a=o[r];(a.options.continuous||r===o.length-1)&&a.trigger([i])}}this.clearTriggerQueues()},i.prototype.next=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints),o=i===this.waypoints.length-1;return o?null:this.waypoints[i+1]},i.prototype.previous=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints);return i?this.waypoints[i-1]:null},i.prototype.queueTrigger=function(t,e){this.triggerQueues[e].push(t)},i.prototype.remove=function(t){var e=n.Adapter.inArray(t,this.waypoints);e>-1&&this.waypoints.splice(e,1)},i.prototype.first=function(){return this.waypoints[0]},i.prototype.last=function(){return this.waypoints[this.waypoints.length-1]},i.findOrCreate=function(t){return o[t.axis][t.name]||new i(t)},n.Group=i}(),function(){"use strict";function t(t){this.$element=e(t)}var e=window.jQuery,i=window.Waypoint;e.each(["innerHeight","innerWidth","off","offset","on","outerHeight","outerWidth","scrollLeft","scrollTop"],function(e,i){t.prototype[i]=function(){var t=Array.prototype.slice.call(arguments);return this.$element[i].apply(this.$element,t)}}),e.each(["extend","inArray","isEmptyObject"],function(i,o){t[o]=e[o]}),i.adapters.push({name:"jquery",Adapter:t}),i.Adapter=t}(),function(){"use strict";function t(t){return function(){var i=[],o=arguments[0];return t.isFunction(arguments[0])&&(o=t.extend({},arguments[1]),o.handler=arguments[0]),this.each(function(){var n=t.extend({},o,{element:this});"string"==typeof n.context&&(n.context=t(this).closest(n.context)[0]),i.push(new e(n))}),i}}var e=window.Waypoint;window.jQuery&&(window.jQuery.fn.waypoint=t(window.jQuery)),window.Zepto&&(window.Zepto.fn.waypoint=t(window.Zepto))}(); -------------------------------------------------------------------------------- /practice/lib/zepto.waypoints.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints - 4.0.1 3 | Copyright © 2011-2016 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6 | */ 7 | !function(){"use strict";function t(o){if(!o)throw new Error("No options passed to Waypoint constructor");if(!o.element)throw new Error("No element option passed to Waypoint constructor");if(!o.handler)throw new Error("No handler option passed to Waypoint constructor");this.key="waypoint-"+e,this.options=t.Adapter.extend({},t.defaults,o),this.element=this.options.element,this.adapter=new t.Adapter(this.element),this.callback=o.handler,this.axis=this.options.horizontal?"horizontal":"vertical",this.enabled=this.options.enabled,this.triggerPoint=null,this.group=t.Group.findOrCreate({name:this.options.group,axis:this.axis}),this.context=t.Context.findOrCreateByElement(this.options.context),t.offsetAliases[this.options.offset]&&(this.options.offset=t.offsetAliases[this.options.offset]),this.group.add(this),this.context.add(this),i[this.key]=this,e+=1}var e=0,i={};t.prototype.queueTrigger=function(t){this.group.queueTrigger(this,t)},t.prototype.trigger=function(t){this.enabled&&this.callback&&this.callback.apply(this,t)},t.prototype.destroy=function(){this.context.remove(this),this.group.remove(this),delete i[this.key]},t.prototype.disable=function(){return this.enabled=!1,this},t.prototype.enable=function(){return this.context.refresh(),this.enabled=!0,this},t.prototype.next=function(){return this.group.next(this)},t.prototype.previous=function(){return this.group.previous(this)},t.invokeAll=function(t){var e=[];for(var o in i)e.push(i[o]);for(var n=0,r=e.length;r>n;n++)e[n][t]()},t.destroyAll=function(){t.invokeAll("destroy")},t.disableAll=function(){t.invokeAll("disable")},t.enableAll=function(){t.Context.refreshAll();for(var e in i)i[e].enabled=!0;return this},t.refreshAll=function(){t.Context.refreshAll()},t.viewportHeight=function(){return window.innerHeight||document.documentElement.clientHeight},t.viewportWidth=function(){return document.documentElement.clientWidth},t.adapters=[],t.defaults={context:window,continuous:!0,enabled:!0,group:"default",horizontal:!1,offset:0},t.offsetAliases={"bottom-in-view":function(){return this.context.innerHeight()-this.adapter.outerHeight()},"right-in-view":function(){return this.context.innerWidth()-this.adapter.outerWidth()}},window.Waypoint=t}(),function(){"use strict";function t(t){window.setTimeout(t,1e3/60)}function e(t){this.element=t,this.Adapter=n.Adapter,this.adapter=new this.Adapter(t),this.key="waypoint-context-"+i,this.didScroll=!1,this.didResize=!1,this.oldScroll={x:this.adapter.scrollLeft(),y:this.adapter.scrollTop()},this.waypoints={vertical:{},horizontal:{}},t.waypointContextKey=this.key,o[t.waypointContextKey]=this,i+=1,n.windowContext||(n.windowContext=!0,n.windowContext=new e(window)),this.createThrottledScrollHandler(),this.createThrottledResizeHandler()}var i=0,o={},n=window.Waypoint,r=window.onload;e.prototype.add=function(t){var e=t.options.horizontal?"horizontal":"vertical";this.waypoints[e][t.key]=t,this.refresh()},e.prototype.checkEmpty=function(){var t=this.Adapter.isEmptyObject(this.waypoints.horizontal),e=this.Adapter.isEmptyObject(this.waypoints.vertical),i=this.element==this.element.window;t&&e&&!i&&(this.adapter.off(".waypoints"),delete o[this.key])},e.prototype.createThrottledResizeHandler=function(){function t(){e.handleResize(),e.didResize=!1}var e=this;this.adapter.on("resize.waypoints",function(){e.didResize||(e.didResize=!0,n.requestAnimationFrame(t))})},e.prototype.createThrottledScrollHandler=function(){function t(){e.handleScroll(),e.didScroll=!1}var e=this;this.adapter.on("scroll.waypoints",function(){(!e.didScroll||n.isTouch)&&(e.didScroll=!0,n.requestAnimationFrame(t))})},e.prototype.handleResize=function(){n.Context.refreshAll()},e.prototype.handleScroll=function(){var t={},e={horizontal:{newScroll:this.adapter.scrollLeft(),oldScroll:this.oldScroll.x,forward:"right",backward:"left"},vertical:{newScroll:this.adapter.scrollTop(),oldScroll:this.oldScroll.y,forward:"down",backward:"up"}};for(var i in e){var o=e[i],n=o.newScroll>o.oldScroll,r=n?o.forward:o.backward;for(var s in this.waypoints[i]){var a=this.waypoints[i][s];if(null!==a.triggerPoint){var l=o.oldScroll=a.triggerPoint,p=l&&h,u=!l&&!h;(p||u)&&(a.queueTrigger(r),t[a.group.id]=a.group)}}}for(var c in t)t[c].flushTriggers();this.oldScroll={x:e.horizontal.newScroll,y:e.vertical.newScroll}},e.prototype.innerHeight=function(){return this.element==this.element.window?n.viewportHeight():this.adapter.innerHeight()},e.prototype.remove=function(t){delete this.waypoints[t.axis][t.key],this.checkEmpty()},e.prototype.innerWidth=function(){return this.element==this.element.window?n.viewportWidth():this.adapter.innerWidth()},e.prototype.destroy=function(){var t=[];for(var e in this.waypoints)for(var i in this.waypoints[e])t.push(this.waypoints[e][i]);for(var o=0,n=t.length;n>o;o++)t[o].destroy()},e.prototype.refresh=function(){var t,e=this.element==this.element.window,i=e?void 0:this.adapter.offset(),o={};this.handleScroll(),t={horizontal:{contextOffset:e?0:i.left,contextScroll:e?0:this.oldScroll.x,contextDimension:this.innerWidth(),oldScroll:this.oldScroll.x,forward:"right",backward:"left",offsetProp:"left"},vertical:{contextOffset:e?0:i.top,contextScroll:e?0:this.oldScroll.y,contextDimension:this.innerHeight(),oldScroll:this.oldScroll.y,forward:"down",backward:"up",offsetProp:"top"}};for(var r in t){var s=t[r];for(var a in this.waypoints[r]){var l,h,p,u,c,d=this.waypoints[r][a],f=d.options.offset,w=d.triggerPoint,y=0,g=null==w;d.element!==d.element.window&&(y=d.adapter.offset()[s.offsetProp]),"function"==typeof f?f=f.apply(d):"string"==typeof f&&(f=parseFloat(f),d.options.offset.indexOf("%")>-1&&(f=Math.ceil(s.contextDimension*f/100))),l=s.contextScroll-s.contextOffset,d.triggerPoint=Math.floor(y+l-f),h=w=s.oldScroll,u=h&&p,c=!h&&!p,!g&&u?(d.queueTrigger(s.backward),o[d.group.id]=d.group):!g&&c?(d.queueTrigger(s.forward),o[d.group.id]=d.group):g&&s.oldScroll>=d.triggerPoint&&(d.queueTrigger(s.forward),o[d.group.id]=d.group)}}return n.requestAnimationFrame(function(){for(var t in o)o[t].flushTriggers()}),this},e.findOrCreateByElement=function(t){return e.findByElement(t)||new e(t)},e.refreshAll=function(){for(var t in o)o[t].refresh()},e.findByElement=function(t){return o[t.waypointContextKey]},window.onload=function(){r&&r(),e.refreshAll()},n.requestAnimationFrame=function(e){var i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||t;i.call(window,e)},n.Context=e}(),function(){"use strict";function t(t,e){return t.triggerPoint-e.triggerPoint}function e(t,e){return e.triggerPoint-t.triggerPoint}function i(t){this.name=t.name,this.axis=t.axis,this.id=this.name+"-"+this.axis,this.waypoints=[],this.clearTriggerQueues(),o[this.axis][this.name]=this}var o={vertical:{},horizontal:{}},n=window.Waypoint;i.prototype.add=function(t){this.waypoints.push(t)},i.prototype.clearTriggerQueues=function(){this.triggerQueues={up:[],down:[],left:[],right:[]}},i.prototype.flushTriggers=function(){for(var i in this.triggerQueues){var o=this.triggerQueues[i],n="up"===i||"left"===i;o.sort(n?e:t);for(var r=0,s=o.length;s>r;r+=1){var a=o[r];(a.options.continuous||r===o.length-1)&&a.trigger([i])}}this.clearTriggerQueues()},i.prototype.next=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints),o=i===this.waypoints.length-1;return o?null:this.waypoints[i+1]},i.prototype.previous=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints);return i?this.waypoints[i-1]:null},i.prototype.queueTrigger=function(t,e){this.triggerQueues[e].push(t)},i.prototype.remove=function(t){var e=n.Adapter.inArray(t,this.waypoints);e>-1&&this.waypoints.splice(e,1)},i.prototype.first=function(){return this.waypoints[0]},i.prototype.last=function(){return this.waypoints[this.waypoints.length-1]},i.findOrCreate=function(t){return o[t.axis][t.name]||new i(t)},n.Group=i}(),function(){"use strict";function t(t){this.element=t,this.$element=e(t)}var e=window.Zepto,i=window.Waypoint;e.each(["off","on","scrollLeft","scrollTop"],function(e,i){t.prototype[i]=function(){var t=Array.prototype.slice.call(arguments);return this.$element[i].apply(this.$element,t)}}),t.prototype.offset=function(){return this.element!==this.element.window?this.$element.offset():void 0},e.each(["width","height"],function(i,o){function n(t,i){return function(t){var n=this.$element,r=n[o](),s={width:["left","right"],height:["top","bottom"]};return e.each(s[o],function(e,o){r+=parseInt(n.css("padding-"+o),10),i&&(r+=parseInt(n.css("border-"+o+"-width"),10)),t&&(r+=parseInt(n.css("margin-"+o),10))}),r}}var r=e.camelCase("inner-"+o),s=e.camelCase("outer-"+o);t.prototype[r]=n(!1),t.prototype[s]=n(!0)}),e.each(["extend","inArray"],function(i,o){t[o]=e[o]}),t.isEmptyObject=function(t){for(var e in t)return!1;return!0},i.adapters.push({name:"zepto",Adapter:t}),i.Adapter=t}(),function(){"use strict";function t(t){return function(){var i=[],o=arguments[0];return t.isFunction(arguments[0])&&(o=t.extend({},arguments[1]),o.handler=arguments[0]),this.each(function(){var n=t.extend({},o,{element:this});"string"==typeof n.context&&(n.context=t(this).closest(n.context)[0]),i.push(new e(n))}),i}}var e=window.Waypoint;window.jQuery&&(window.jQuery.fn.waypoint=t(window.jQuery)),window.Zepto&&(window.Zepto.fn.waypoint=t(window.Zepto))}(); -------------------------------------------------------------------------------- /practice/lib/noframework.waypoints.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints - 4.0.1 3 | Copyright © 2011-2016 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6 | */ 7 | !function(){"use strict";function t(n){if(!n)throw new Error("No options passed to Waypoint constructor");if(!n.element)throw new Error("No element option passed to Waypoint constructor");if(!n.handler)throw new Error("No handler option passed to Waypoint constructor");this.key="waypoint-"+e,this.options=t.Adapter.extend({},t.defaults,n),this.element=this.options.element,this.adapter=new t.Adapter(this.element),this.callback=n.handler,this.axis=this.options.horizontal?"horizontal":"vertical",this.enabled=this.options.enabled,this.triggerPoint=null,this.group=t.Group.findOrCreate({name:this.options.group,axis:this.axis}),this.context=t.Context.findOrCreateByElement(this.options.context),t.offsetAliases[this.options.offset]&&(this.options.offset=t.offsetAliases[this.options.offset]),this.group.add(this),this.context.add(this),i[this.key]=this,e+=1}var e=0,i={};t.prototype.queueTrigger=function(t){this.group.queueTrigger(this,t)},t.prototype.trigger=function(t){this.enabled&&this.callback&&this.callback.apply(this,t)},t.prototype.destroy=function(){this.context.remove(this),this.group.remove(this),delete i[this.key]},t.prototype.disable=function(){return this.enabled=!1,this},t.prototype.enable=function(){return this.context.refresh(),this.enabled=!0,this},t.prototype.next=function(){return this.group.next(this)},t.prototype.previous=function(){return this.group.previous(this)},t.invokeAll=function(t){var e=[];for(var n in i)e.push(i[n]);for(var o=0,r=e.length;r>o;o++)e[o][t]()},t.destroyAll=function(){t.invokeAll("destroy")},t.disableAll=function(){t.invokeAll("disable")},t.enableAll=function(){t.Context.refreshAll();for(var e in i)i[e].enabled=!0;return this},t.refreshAll=function(){t.Context.refreshAll()},t.viewportHeight=function(){return window.innerHeight||document.documentElement.clientHeight},t.viewportWidth=function(){return document.documentElement.clientWidth},t.adapters=[],t.defaults={context:window,continuous:!0,enabled:!0,group:"default",horizontal:!1,offset:0},t.offsetAliases={"bottom-in-view":function(){return this.context.innerHeight()-this.adapter.outerHeight()},"right-in-view":function(){return this.context.innerWidth()-this.adapter.outerWidth()}},window.Waypoint=t}(),function(){"use strict";function t(t){window.setTimeout(t,1e3/60)}function e(t){this.element=t,this.Adapter=o.Adapter,this.adapter=new this.Adapter(t),this.key="waypoint-context-"+i,this.didScroll=!1,this.didResize=!1,this.oldScroll={x:this.adapter.scrollLeft(),y:this.adapter.scrollTop()},this.waypoints={vertical:{},horizontal:{}},t.waypointContextKey=this.key,n[t.waypointContextKey]=this,i+=1,o.windowContext||(o.windowContext=!0,o.windowContext=new e(window)),this.createThrottledScrollHandler(),this.createThrottledResizeHandler()}var i=0,n={},o=window.Waypoint,r=window.onload;e.prototype.add=function(t){var e=t.options.horizontal?"horizontal":"vertical";this.waypoints[e][t.key]=t,this.refresh()},e.prototype.checkEmpty=function(){var t=this.Adapter.isEmptyObject(this.waypoints.horizontal),e=this.Adapter.isEmptyObject(this.waypoints.vertical),i=this.element==this.element.window;t&&e&&!i&&(this.adapter.off(".waypoints"),delete n[this.key])},e.prototype.createThrottledResizeHandler=function(){function t(){e.handleResize(),e.didResize=!1}var e=this;this.adapter.on("resize.waypoints",function(){e.didResize||(e.didResize=!0,o.requestAnimationFrame(t))})},e.prototype.createThrottledScrollHandler=function(){function t(){e.handleScroll(),e.didScroll=!1}var e=this;this.adapter.on("scroll.waypoints",function(){(!e.didScroll||o.isTouch)&&(e.didScroll=!0,o.requestAnimationFrame(t))})},e.prototype.handleResize=function(){o.Context.refreshAll()},e.prototype.handleScroll=function(){var t={},e={horizontal:{newScroll:this.adapter.scrollLeft(),oldScroll:this.oldScroll.x,forward:"right",backward:"left"},vertical:{newScroll:this.adapter.scrollTop(),oldScroll:this.oldScroll.y,forward:"down",backward:"up"}};for(var i in e){var n=e[i],o=n.newScroll>n.oldScroll,r=o?n.forward:n.backward;for(var s in this.waypoints[i]){var l=this.waypoints[i][s];if(null!==l.triggerPoint){var a=n.oldScroll=l.triggerPoint,p=a&&h,u=!a&&!h;(p||u)&&(l.queueTrigger(r),t[l.group.id]=l.group)}}}for(var d in t)t[d].flushTriggers();this.oldScroll={x:e.horizontal.newScroll,y:e.vertical.newScroll}},e.prototype.innerHeight=function(){return this.element==this.element.window?o.viewportHeight():this.adapter.innerHeight()},e.prototype.remove=function(t){delete this.waypoints[t.axis][t.key],this.checkEmpty()},e.prototype.innerWidth=function(){return this.element==this.element.window?o.viewportWidth():this.adapter.innerWidth()},e.prototype.destroy=function(){var t=[];for(var e in this.waypoints)for(var i in this.waypoints[e])t.push(this.waypoints[e][i]);for(var n=0,o=t.length;o>n;n++)t[n].destroy()},e.prototype.refresh=function(){var t,e=this.element==this.element.window,i=e?void 0:this.adapter.offset(),n={};this.handleScroll(),t={horizontal:{contextOffset:e?0:i.left,contextScroll:e?0:this.oldScroll.x,contextDimension:this.innerWidth(),oldScroll:this.oldScroll.x,forward:"right",backward:"left",offsetProp:"left"},vertical:{contextOffset:e?0:i.top,contextScroll:e?0:this.oldScroll.y,contextDimension:this.innerHeight(),oldScroll:this.oldScroll.y,forward:"down",backward:"up",offsetProp:"top"}};for(var r in t){var s=t[r];for(var l in this.waypoints[r]){var a,h,p,u,d,f=this.waypoints[r][l],c=f.options.offset,w=f.triggerPoint,y=0,g=null==w;f.element!==f.element.window&&(y=f.adapter.offset()[s.offsetProp]),"function"==typeof c?c=c.apply(f):"string"==typeof c&&(c=parseFloat(c),f.options.offset.indexOf("%")>-1&&(c=Math.ceil(s.contextDimension*c/100))),a=s.contextScroll-s.contextOffset,f.triggerPoint=Math.floor(y+a-c),h=w=s.oldScroll,u=h&&p,d=!h&&!p,!g&&u?(f.queueTrigger(s.backward),n[f.group.id]=f.group):!g&&d?(f.queueTrigger(s.forward),n[f.group.id]=f.group):g&&s.oldScroll>=f.triggerPoint&&(f.queueTrigger(s.forward),n[f.group.id]=f.group)}}return o.requestAnimationFrame(function(){for(var t in n)n[t].flushTriggers()}),this},e.findOrCreateByElement=function(t){return e.findByElement(t)||new e(t)},e.refreshAll=function(){for(var t in n)n[t].refresh()},e.findByElement=function(t){return n[t.waypointContextKey]},window.onload=function(){r&&r(),e.refreshAll()},o.requestAnimationFrame=function(e){var i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||t;i.call(window,e)},o.Context=e}(),function(){"use strict";function t(t,e){return t.triggerPoint-e.triggerPoint}function e(t,e){return e.triggerPoint-t.triggerPoint}function i(t){this.name=t.name,this.axis=t.axis,this.id=this.name+"-"+this.axis,this.waypoints=[],this.clearTriggerQueues(),n[this.axis][this.name]=this}var n={vertical:{},horizontal:{}},o=window.Waypoint;i.prototype.add=function(t){this.waypoints.push(t)},i.prototype.clearTriggerQueues=function(){this.triggerQueues={up:[],down:[],left:[],right:[]}},i.prototype.flushTriggers=function(){for(var i in this.triggerQueues){var n=this.triggerQueues[i],o="up"===i||"left"===i;n.sort(o?e:t);for(var r=0,s=n.length;s>r;r+=1){var l=n[r];(l.options.continuous||r===n.length-1)&&l.trigger([i])}}this.clearTriggerQueues()},i.prototype.next=function(e){this.waypoints.sort(t);var i=o.Adapter.inArray(e,this.waypoints),n=i===this.waypoints.length-1;return n?null:this.waypoints[i+1]},i.prototype.previous=function(e){this.waypoints.sort(t);var i=o.Adapter.inArray(e,this.waypoints);return i?this.waypoints[i-1]:null},i.prototype.queueTrigger=function(t,e){this.triggerQueues[e].push(t)},i.prototype.remove=function(t){var e=o.Adapter.inArray(t,this.waypoints);e>-1&&this.waypoints.splice(e,1)},i.prototype.first=function(){return this.waypoints[0]},i.prototype.last=function(){return this.waypoints[this.waypoints.length-1]},i.findOrCreate=function(t){return n[t.axis][t.name]||new i(t)},o.Group=i}(),function(){"use strict";function t(t){return t===t.window}function e(e){return t(e)?e:e.defaultView}function i(t){this.element=t,this.handlers={}}var n=window.Waypoint;i.prototype.innerHeight=function(){var e=t(this.element);return e?this.element.innerHeight:this.element.clientHeight},i.prototype.innerWidth=function(){var e=t(this.element);return e?this.element.innerWidth:this.element.clientWidth},i.prototype.off=function(t,e){function i(t,e,i){for(var n=0,o=e.length-1;o>n;n++){var r=e[n];i&&i!==r||t.removeEventListener(r)}}var n=t.split("."),o=n[0],r=n[1],s=this.element;if(r&&this.handlers[r]&&o)i(s,this.handlers[r][o],e),this.handlers[r][o]=[];else if(o)for(var l in this.handlers)i(s,this.handlers[l][o]||[],e),this.handlers[l][o]=[];else if(r&&this.handlers[r]){for(var a in this.handlers[r])i(s,this.handlers[r][a],e);this.handlers[r]={}}},i.prototype.offset=function(){if(!this.element.ownerDocument)return null;var t=this.element.ownerDocument.documentElement,i=e(this.element.ownerDocument),n={top:0,left:0};return this.element.getBoundingClientRect&&(n=this.element.getBoundingClientRect()),{top:n.top+i.pageYOffset-t.clientTop,left:n.left+i.pageXOffset-t.clientLeft}},i.prototype.on=function(t,e){var i=t.split("."),n=i[0],o=i[1]||"__default",r=this.handlers[o]=this.handlers[o]||{},s=r[n]=r[n]||[];s.push(e),this.element.addEventListener(n,e)},i.prototype.outerHeight=function(e){var i,n=this.innerHeight();return e&&!t(this.element)&&(i=window.getComputedStyle(this.element),n+=parseInt(i.marginTop,10),n+=parseInt(i.marginBottom,10)),n},i.prototype.outerWidth=function(e){var i,n=this.innerWidth();return e&&!t(this.element)&&(i=window.getComputedStyle(this.element),n+=parseInt(i.marginLeft,10),n+=parseInt(i.marginRight,10)),n},i.prototype.scrollLeft=function(){var t=e(this.element);return t?t.pageXOffset:this.element.scrollLeft},i.prototype.scrollTop=function(){var t=e(this.element);return t?t.pageYOffset:this.element.scrollTop},i.extend=function(){function t(t,e){if("object"==typeof t&&"object"==typeof e)for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}for(var e=Array.prototype.slice.call(arguments),i=1,n=e.length;n>i;i++)t(e[0],e[i]);return e[0]},i.inArray=function(t,e,i){return null==e?-1:e.indexOf(t,i)},i.isEmptyObject=function(t){for(var e in t)return!1;return!0},n.adapters.push({name:"noframework",Adapter:i}),n.Adapter=i}(); -------------------------------------------------------------------------------- /practice/lib/jquery.waypoints.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints - 4.0.1 3 | Copyright © 2011-2016 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6 | */ 7 | (function() { 8 | 'use strict' 9 | 10 | var keyCounter = 0 11 | var allWaypoints = {} 12 | 13 | /* http://imakewebthings.com/waypoints/api/waypoint */ 14 | function Waypoint(options) { 15 | if (!options) { 16 | throw new Error('No options passed to Waypoint constructor') 17 | } 18 | if (!options.element) { 19 | throw new Error('No element option passed to Waypoint constructor') 20 | } 21 | if (!options.handler) { 22 | throw new Error('No handler option passed to Waypoint constructor') 23 | } 24 | 25 | this.key = 'waypoint-' + keyCounter 26 | this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options) 27 | this.element = this.options.element 28 | this.adapter = new Waypoint.Adapter(this.element) 29 | this.callback = options.handler 30 | this.axis = this.options.horizontal ? 'horizontal' : 'vertical' 31 | this.enabled = this.options.enabled 32 | this.triggerPoint = null 33 | this.group = Waypoint.Group.findOrCreate({ 34 | name: this.options.group, 35 | axis: this.axis 36 | }) 37 | this.context = Waypoint.Context.findOrCreateByElement(this.options.context) 38 | 39 | if (Waypoint.offsetAliases[this.options.offset]) { 40 | this.options.offset = Waypoint.offsetAliases[this.options.offset] 41 | } 42 | this.group.add(this) 43 | this.context.add(this) 44 | allWaypoints[this.key] = this 45 | keyCounter += 1 46 | } 47 | 48 | /* Private */ 49 | Waypoint.prototype.queueTrigger = function(direction) { 50 | this.group.queueTrigger(this, direction) 51 | } 52 | 53 | /* Private */ 54 | Waypoint.prototype.trigger = function(args) { 55 | if (!this.enabled) { 56 | return 57 | } 58 | if (this.callback) { 59 | this.callback.apply(this, args) 60 | } 61 | } 62 | 63 | /* Public */ 64 | /* http://imakewebthings.com/waypoints/api/destroy */ 65 | Waypoint.prototype.destroy = function() { 66 | this.context.remove(this) 67 | this.group.remove(this) 68 | delete allWaypoints[this.key] 69 | } 70 | 71 | /* Public */ 72 | /* http://imakewebthings.com/waypoints/api/disable */ 73 | Waypoint.prototype.disable = function() { 74 | this.enabled = false 75 | return this 76 | } 77 | 78 | /* Public */ 79 | /* http://imakewebthings.com/waypoints/api/enable */ 80 | Waypoint.prototype.enable = function() { 81 | this.context.refresh() 82 | this.enabled = true 83 | return this 84 | } 85 | 86 | /* Public */ 87 | /* http://imakewebthings.com/waypoints/api/next */ 88 | Waypoint.prototype.next = function() { 89 | return this.group.next(this) 90 | } 91 | 92 | /* Public */ 93 | /* http://imakewebthings.com/waypoints/api/previous */ 94 | Waypoint.prototype.previous = function() { 95 | return this.group.previous(this) 96 | } 97 | 98 | /* Private */ 99 | Waypoint.invokeAll = function(method) { 100 | var allWaypointsArray = [] 101 | for (var waypointKey in allWaypoints) { 102 | allWaypointsArray.push(allWaypoints[waypointKey]) 103 | } 104 | for (var i = 0, end = allWaypointsArray.length; i < end; i++) { 105 | allWaypointsArray[i][method]() 106 | } 107 | } 108 | 109 | /* Public */ 110 | /* http://imakewebthings.com/waypoints/api/destroy-all */ 111 | Waypoint.destroyAll = function() { 112 | Waypoint.invokeAll('destroy') 113 | } 114 | 115 | /* Public */ 116 | /* http://imakewebthings.com/waypoints/api/disable-all */ 117 | Waypoint.disableAll = function() { 118 | Waypoint.invokeAll('disable') 119 | } 120 | 121 | /* Public */ 122 | /* http://imakewebthings.com/waypoints/api/enable-all */ 123 | Waypoint.enableAll = function() { 124 | Waypoint.Context.refreshAll() 125 | for (var waypointKey in allWaypoints) { 126 | allWaypoints[waypointKey].enabled = true 127 | } 128 | return this 129 | } 130 | 131 | /* Public */ 132 | /* http://imakewebthings.com/waypoints/api/refresh-all */ 133 | Waypoint.refreshAll = function() { 134 | Waypoint.Context.refreshAll() 135 | } 136 | 137 | /* Public */ 138 | /* http://imakewebthings.com/waypoints/api/viewport-height */ 139 | Waypoint.viewportHeight = function() { 140 | return window.innerHeight || document.documentElement.clientHeight 141 | } 142 | 143 | /* Public */ 144 | /* http://imakewebthings.com/waypoints/api/viewport-width */ 145 | Waypoint.viewportWidth = function() { 146 | return document.documentElement.clientWidth 147 | } 148 | 149 | Waypoint.adapters = [] 150 | 151 | Waypoint.defaults = { 152 | context: window, 153 | continuous: true, 154 | enabled: true, 155 | group: 'default', 156 | horizontal: false, 157 | offset: 0 158 | } 159 | 160 | Waypoint.offsetAliases = { 161 | 'bottom-in-view': function() { 162 | return this.context.innerHeight() - this.adapter.outerHeight() 163 | }, 164 | 'right-in-view': function() { 165 | return this.context.innerWidth() - this.adapter.outerWidth() 166 | } 167 | } 168 | 169 | window.Waypoint = Waypoint 170 | }()) 171 | ;(function() { 172 | 'use strict' 173 | 174 | function requestAnimationFrameShim(callback) { 175 | window.setTimeout(callback, 1000 / 60) 176 | } 177 | 178 | var keyCounter = 0 179 | var contexts = {} 180 | var Waypoint = window.Waypoint 181 | var oldWindowLoad = window.onload 182 | 183 | /* http://imakewebthings.com/waypoints/api/context */ 184 | function Context(element) { 185 | this.element = element 186 | this.Adapter = Waypoint.Adapter 187 | this.adapter = new this.Adapter(element) 188 | this.key = 'waypoint-context-' + keyCounter 189 | this.didScroll = false 190 | this.didResize = false 191 | this.oldScroll = { 192 | x: this.adapter.scrollLeft(), 193 | y: this.adapter.scrollTop() 194 | } 195 | this.waypoints = { 196 | vertical: {}, 197 | horizontal: {} 198 | } 199 | 200 | element.waypointContextKey = this.key 201 | contexts[element.waypointContextKey] = this 202 | keyCounter += 1 203 | if (!Waypoint.windowContext) { 204 | Waypoint.windowContext = true 205 | Waypoint.windowContext = new Context(window) 206 | } 207 | 208 | this.createThrottledScrollHandler() 209 | this.createThrottledResizeHandler() 210 | } 211 | 212 | /* Private */ 213 | Context.prototype.add = function(waypoint) { 214 | var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical' 215 | this.waypoints[axis][waypoint.key] = waypoint 216 | this.refresh() 217 | } 218 | 219 | /* Private */ 220 | Context.prototype.checkEmpty = function() { 221 | var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal) 222 | var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical) 223 | var isWindow = this.element == this.element.window 224 | if (horizontalEmpty && verticalEmpty && !isWindow) { 225 | this.adapter.off('.waypoints') 226 | delete contexts[this.key] 227 | } 228 | } 229 | 230 | /* Private */ 231 | Context.prototype.createThrottledResizeHandler = function() { 232 | var self = this 233 | 234 | function resizeHandler() { 235 | self.handleResize() 236 | self.didResize = false 237 | } 238 | 239 | this.adapter.on('resize.waypoints', function() { 240 | if (!self.didResize) { 241 | self.didResize = true 242 | Waypoint.requestAnimationFrame(resizeHandler) 243 | } 244 | }) 245 | } 246 | 247 | /* Private */ 248 | Context.prototype.createThrottledScrollHandler = function() { 249 | var self = this 250 | function scrollHandler() { 251 | self.handleScroll() 252 | self.didScroll = false 253 | } 254 | 255 | this.adapter.on('scroll.waypoints', function() { 256 | if (!self.didScroll || Waypoint.isTouch) { 257 | self.didScroll = true 258 | Waypoint.requestAnimationFrame(scrollHandler) 259 | } 260 | }) 261 | } 262 | 263 | /* Private */ 264 | Context.prototype.handleResize = function() { 265 | Waypoint.Context.refreshAll() 266 | } 267 | 268 | /* Private */ 269 | Context.prototype.handleScroll = function() { 270 | var triggeredGroups = {} 271 | var axes = { 272 | horizontal: { 273 | newScroll: this.adapter.scrollLeft(), 274 | oldScroll: this.oldScroll.x, 275 | forward: 'right', 276 | backward: 'left' 277 | }, 278 | vertical: { 279 | newScroll: this.adapter.scrollTop(), 280 | oldScroll: this.oldScroll.y, 281 | forward: 'down', 282 | backward: 'up' 283 | } 284 | } 285 | 286 | for (var axisKey in axes) { 287 | var axis = axes[axisKey] 288 | var isForward = axis.newScroll > axis.oldScroll 289 | var direction = isForward ? axis.forward : axis.backward 290 | 291 | for (var waypointKey in this.waypoints[axisKey]) { 292 | var waypoint = this.waypoints[axisKey][waypointKey] 293 | if (waypoint.triggerPoint === null) { 294 | continue 295 | } 296 | var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint 297 | var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint 298 | var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint 299 | var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint 300 | if (crossedForward || crossedBackward) { 301 | waypoint.queueTrigger(direction) 302 | triggeredGroups[waypoint.group.id] = waypoint.group 303 | } 304 | } 305 | } 306 | 307 | for (var groupKey in triggeredGroups) { 308 | triggeredGroups[groupKey].flushTriggers() 309 | } 310 | 311 | this.oldScroll = { 312 | x: axes.horizontal.newScroll, 313 | y: axes.vertical.newScroll 314 | } 315 | } 316 | 317 | /* Private */ 318 | Context.prototype.innerHeight = function() { 319 | /*eslint-disable eqeqeq */ 320 | if (this.element == this.element.window) { 321 | return Waypoint.viewportHeight() 322 | } 323 | /*eslint-enable eqeqeq */ 324 | return this.adapter.innerHeight() 325 | } 326 | 327 | /* Private */ 328 | Context.prototype.remove = function(waypoint) { 329 | delete this.waypoints[waypoint.axis][waypoint.key] 330 | this.checkEmpty() 331 | } 332 | 333 | /* Private */ 334 | Context.prototype.innerWidth = function() { 335 | /*eslint-disable eqeqeq */ 336 | if (this.element == this.element.window) { 337 | return Waypoint.viewportWidth() 338 | } 339 | /*eslint-enable eqeqeq */ 340 | return this.adapter.innerWidth() 341 | } 342 | 343 | /* Public */ 344 | /* http://imakewebthings.com/waypoints/api/context-destroy */ 345 | Context.prototype.destroy = function() { 346 | var allWaypoints = [] 347 | for (var axis in this.waypoints) { 348 | for (var waypointKey in this.waypoints[axis]) { 349 | allWaypoints.push(this.waypoints[axis][waypointKey]) 350 | } 351 | } 352 | for (var i = 0, end = allWaypoints.length; i < end; i++) { 353 | allWaypoints[i].destroy() 354 | } 355 | } 356 | 357 | /* Public */ 358 | /* http://imakewebthings.com/waypoints/api/context-refresh */ 359 | Context.prototype.refresh = function() { 360 | /*eslint-disable eqeqeq */ 361 | var isWindow = this.element == this.element.window 362 | /*eslint-enable eqeqeq */ 363 | var contextOffset = isWindow ? undefined : this.adapter.offset() 364 | var triggeredGroups = {} 365 | var axes 366 | 367 | this.handleScroll() 368 | axes = { 369 | horizontal: { 370 | contextOffset: isWindow ? 0 : contextOffset.left, 371 | contextScroll: isWindow ? 0 : this.oldScroll.x, 372 | contextDimension: this.innerWidth(), 373 | oldScroll: this.oldScroll.x, 374 | forward: 'right', 375 | backward: 'left', 376 | offsetProp: 'left' 377 | }, 378 | vertical: { 379 | contextOffset: isWindow ? 0 : contextOffset.top, 380 | contextScroll: isWindow ? 0 : this.oldScroll.y, 381 | contextDimension: this.innerHeight(), 382 | oldScroll: this.oldScroll.y, 383 | forward: 'down', 384 | backward: 'up', 385 | offsetProp: 'top' 386 | } 387 | } 388 | 389 | for (var axisKey in axes) { 390 | var axis = axes[axisKey] 391 | for (var waypointKey in this.waypoints[axisKey]) { 392 | var waypoint = this.waypoints[axisKey][waypointKey] 393 | var adjustment = waypoint.options.offset 394 | var oldTriggerPoint = waypoint.triggerPoint 395 | var elementOffset = 0 396 | var freshWaypoint = oldTriggerPoint == null 397 | var contextModifier, wasBeforeScroll, nowAfterScroll 398 | var triggeredBackward, triggeredForward 399 | 400 | if (waypoint.element !== waypoint.element.window) { 401 | elementOffset = waypoint.adapter.offset()[axis.offsetProp] 402 | } 403 | 404 | if (typeof adjustment === 'function') { 405 | adjustment = adjustment.apply(waypoint) 406 | } 407 | else if (typeof adjustment === 'string') { 408 | adjustment = parseFloat(adjustment) 409 | if (waypoint.options.offset.indexOf('%') > - 1) { 410 | adjustment = Math.ceil(axis.contextDimension * adjustment / 100) 411 | } 412 | } 413 | 414 | contextModifier = axis.contextScroll - axis.contextOffset 415 | waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment) 416 | wasBeforeScroll = oldTriggerPoint < axis.oldScroll 417 | nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll 418 | triggeredBackward = wasBeforeScroll && nowAfterScroll 419 | triggeredForward = !wasBeforeScroll && !nowAfterScroll 420 | 421 | if (!freshWaypoint && triggeredBackward) { 422 | waypoint.queueTrigger(axis.backward) 423 | triggeredGroups[waypoint.group.id] = waypoint.group 424 | } 425 | else if (!freshWaypoint && triggeredForward) { 426 | waypoint.queueTrigger(axis.forward) 427 | triggeredGroups[waypoint.group.id] = waypoint.group 428 | } 429 | else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) { 430 | waypoint.queueTrigger(axis.forward) 431 | triggeredGroups[waypoint.group.id] = waypoint.group 432 | } 433 | } 434 | } 435 | 436 | Waypoint.requestAnimationFrame(function() { 437 | for (var groupKey in triggeredGroups) { 438 | triggeredGroups[groupKey].flushTriggers() 439 | } 440 | }) 441 | 442 | return this 443 | } 444 | 445 | /* Private */ 446 | Context.findOrCreateByElement = function(element) { 447 | return Context.findByElement(element) || new Context(element) 448 | } 449 | 450 | /* Private */ 451 | Context.refreshAll = function() { 452 | for (var contextId in contexts) { 453 | contexts[contextId].refresh() 454 | } 455 | } 456 | 457 | /* Public */ 458 | /* http://imakewebthings.com/waypoints/api/context-find-by-element */ 459 | Context.findByElement = function(element) { 460 | return contexts[element.waypointContextKey] 461 | } 462 | 463 | window.onload = function() { 464 | if (oldWindowLoad) { 465 | oldWindowLoad() 466 | } 467 | Context.refreshAll() 468 | } 469 | 470 | 471 | Waypoint.requestAnimationFrame = function(callback) { 472 | var requestFn = window.requestAnimationFrame || 473 | window.mozRequestAnimationFrame || 474 | window.webkitRequestAnimationFrame || 475 | requestAnimationFrameShim 476 | requestFn.call(window, callback) 477 | } 478 | Waypoint.Context = Context 479 | }()) 480 | ;(function() { 481 | 'use strict' 482 | 483 | function byTriggerPoint(a, b) { 484 | return a.triggerPoint - b.triggerPoint 485 | } 486 | 487 | function byReverseTriggerPoint(a, b) { 488 | return b.triggerPoint - a.triggerPoint 489 | } 490 | 491 | var groups = { 492 | vertical: {}, 493 | horizontal: {} 494 | } 495 | var Waypoint = window.Waypoint 496 | 497 | /* http://imakewebthings.com/waypoints/api/group */ 498 | function Group(options) { 499 | this.name = options.name 500 | this.axis = options.axis 501 | this.id = this.name + '-' + this.axis 502 | this.waypoints = [] 503 | this.clearTriggerQueues() 504 | groups[this.axis][this.name] = this 505 | } 506 | 507 | /* Private */ 508 | Group.prototype.add = function(waypoint) { 509 | this.waypoints.push(waypoint) 510 | } 511 | 512 | /* Private */ 513 | Group.prototype.clearTriggerQueues = function() { 514 | this.triggerQueues = { 515 | up: [], 516 | down: [], 517 | left: [], 518 | right: [] 519 | } 520 | } 521 | 522 | /* Private */ 523 | Group.prototype.flushTriggers = function() { 524 | for (var direction in this.triggerQueues) { 525 | var waypoints = this.triggerQueues[direction] 526 | var reverse = direction === 'up' || direction === 'left' 527 | waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint) 528 | for (var i = 0, end = waypoints.length; i < end; i += 1) { 529 | var waypoint = waypoints[i] 530 | if (waypoint.options.continuous || i === waypoints.length - 1) { 531 | waypoint.trigger([direction]) 532 | } 533 | } 534 | } 535 | this.clearTriggerQueues() 536 | } 537 | 538 | /* Private */ 539 | Group.prototype.next = function(waypoint) { 540 | this.waypoints.sort(byTriggerPoint) 541 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 542 | var isLast = index === this.waypoints.length - 1 543 | return isLast ? null : this.waypoints[index + 1] 544 | } 545 | 546 | /* Private */ 547 | Group.prototype.previous = function(waypoint) { 548 | this.waypoints.sort(byTriggerPoint) 549 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 550 | return index ? this.waypoints[index - 1] : null 551 | } 552 | 553 | /* Private */ 554 | Group.prototype.queueTrigger = function(waypoint, direction) { 555 | this.triggerQueues[direction].push(waypoint) 556 | } 557 | 558 | /* Private */ 559 | Group.prototype.remove = function(waypoint) { 560 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 561 | if (index > -1) { 562 | this.waypoints.splice(index, 1) 563 | } 564 | } 565 | 566 | /* Public */ 567 | /* http://imakewebthings.com/waypoints/api/first */ 568 | Group.prototype.first = function() { 569 | return this.waypoints[0] 570 | } 571 | 572 | /* Public */ 573 | /* http://imakewebthings.com/waypoints/api/last */ 574 | Group.prototype.last = function() { 575 | return this.waypoints[this.waypoints.length - 1] 576 | } 577 | 578 | /* Private */ 579 | Group.findOrCreate = function(options) { 580 | return groups[options.axis][options.name] || new Group(options) 581 | } 582 | 583 | Waypoint.Group = Group 584 | }()) 585 | ;(function() { 586 | 'use strict' 587 | 588 | var $ = window.jQuery 589 | var Waypoint = window.Waypoint 590 | 591 | function JQueryAdapter(element) { 592 | this.$element = $(element) 593 | } 594 | 595 | $.each([ 596 | 'innerHeight', 597 | 'innerWidth', 598 | 'off', 599 | 'offset', 600 | 'on', 601 | 'outerHeight', 602 | 'outerWidth', 603 | 'scrollLeft', 604 | 'scrollTop' 605 | ], function(i, method) { 606 | JQueryAdapter.prototype[method] = function() { 607 | var args = Array.prototype.slice.call(arguments) 608 | return this.$element[method].apply(this.$element, args) 609 | } 610 | }) 611 | 612 | $.each([ 613 | 'extend', 614 | 'inArray', 615 | 'isEmptyObject' 616 | ], function(i, method) { 617 | JQueryAdapter[method] = $[method] 618 | }) 619 | 620 | Waypoint.adapters.push({ 621 | name: 'jquery', 622 | Adapter: JQueryAdapter 623 | }) 624 | Waypoint.Adapter = JQueryAdapter 625 | }()) 626 | ;(function() { 627 | 'use strict' 628 | 629 | var Waypoint = window.Waypoint 630 | 631 | function createExtension(framework) { 632 | return function() { 633 | var waypoints = [] 634 | var overrides = arguments[0] 635 | 636 | if (framework.isFunction(arguments[0])) { 637 | overrides = framework.extend({}, arguments[1]) 638 | overrides.handler = arguments[0] 639 | } 640 | 641 | this.each(function() { 642 | var options = framework.extend({}, overrides, { 643 | element: this 644 | }) 645 | if (typeof options.context === 'string') { 646 | options.context = framework(this).closest(options.context)[0] 647 | } 648 | waypoints.push(new Waypoint(options)) 649 | }) 650 | 651 | return waypoints 652 | } 653 | } 654 | 655 | if (window.jQuery) { 656 | window.jQuery.fn.waypoint = createExtension(window.jQuery) 657 | } 658 | if (window.Zepto) { 659 | window.Zepto.fn.waypoint = createExtension(window.Zepto) 660 | } 661 | }()) 662 | ; -------------------------------------------------------------------------------- /practice/lib/zepto.waypoints.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints - 4.0.1 3 | Copyright © 2011-2016 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6 | */ 7 | (function() { 8 | 'use strict' 9 | 10 | var keyCounter = 0 11 | var allWaypoints = {} 12 | 13 | /* http://imakewebthings.com/waypoints/api/waypoint */ 14 | function Waypoint(options) { 15 | if (!options) { 16 | throw new Error('No options passed to Waypoint constructor') 17 | } 18 | if (!options.element) { 19 | throw new Error('No element option passed to Waypoint constructor') 20 | } 21 | if (!options.handler) { 22 | throw new Error('No handler option passed to Waypoint constructor') 23 | } 24 | 25 | this.key = 'waypoint-' + keyCounter 26 | this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options) 27 | this.element = this.options.element 28 | this.adapter = new Waypoint.Adapter(this.element) 29 | this.callback = options.handler 30 | this.axis = this.options.horizontal ? 'horizontal' : 'vertical' 31 | this.enabled = this.options.enabled 32 | this.triggerPoint = null 33 | this.group = Waypoint.Group.findOrCreate({ 34 | name: this.options.group, 35 | axis: this.axis 36 | }) 37 | this.context = Waypoint.Context.findOrCreateByElement(this.options.context) 38 | 39 | if (Waypoint.offsetAliases[this.options.offset]) { 40 | this.options.offset = Waypoint.offsetAliases[this.options.offset] 41 | } 42 | this.group.add(this) 43 | this.context.add(this) 44 | allWaypoints[this.key] = this 45 | keyCounter += 1 46 | } 47 | 48 | /* Private */ 49 | Waypoint.prototype.queueTrigger = function(direction) { 50 | this.group.queueTrigger(this, direction) 51 | } 52 | 53 | /* Private */ 54 | Waypoint.prototype.trigger = function(args) { 55 | if (!this.enabled) { 56 | return 57 | } 58 | if (this.callback) { 59 | this.callback.apply(this, args) 60 | } 61 | } 62 | 63 | /* Public */ 64 | /* http://imakewebthings.com/waypoints/api/destroy */ 65 | Waypoint.prototype.destroy = function() { 66 | this.context.remove(this) 67 | this.group.remove(this) 68 | delete allWaypoints[this.key] 69 | } 70 | 71 | /* Public */ 72 | /* http://imakewebthings.com/waypoints/api/disable */ 73 | Waypoint.prototype.disable = function() { 74 | this.enabled = false 75 | return this 76 | } 77 | 78 | /* Public */ 79 | /* http://imakewebthings.com/waypoints/api/enable */ 80 | Waypoint.prototype.enable = function() { 81 | this.context.refresh() 82 | this.enabled = true 83 | return this 84 | } 85 | 86 | /* Public */ 87 | /* http://imakewebthings.com/waypoints/api/next */ 88 | Waypoint.prototype.next = function() { 89 | return this.group.next(this) 90 | } 91 | 92 | /* Public */ 93 | /* http://imakewebthings.com/waypoints/api/previous */ 94 | Waypoint.prototype.previous = function() { 95 | return this.group.previous(this) 96 | } 97 | 98 | /* Private */ 99 | Waypoint.invokeAll = function(method) { 100 | var allWaypointsArray = [] 101 | for (var waypointKey in allWaypoints) { 102 | allWaypointsArray.push(allWaypoints[waypointKey]) 103 | } 104 | for (var i = 0, end = allWaypointsArray.length; i < end; i++) { 105 | allWaypointsArray[i][method]() 106 | } 107 | } 108 | 109 | /* Public */ 110 | /* http://imakewebthings.com/waypoints/api/destroy-all */ 111 | Waypoint.destroyAll = function() { 112 | Waypoint.invokeAll('destroy') 113 | } 114 | 115 | /* Public */ 116 | /* http://imakewebthings.com/waypoints/api/disable-all */ 117 | Waypoint.disableAll = function() { 118 | Waypoint.invokeAll('disable') 119 | } 120 | 121 | /* Public */ 122 | /* http://imakewebthings.com/waypoints/api/enable-all */ 123 | Waypoint.enableAll = function() { 124 | Waypoint.Context.refreshAll() 125 | for (var waypointKey in allWaypoints) { 126 | allWaypoints[waypointKey].enabled = true 127 | } 128 | return this 129 | } 130 | 131 | /* Public */ 132 | /* http://imakewebthings.com/waypoints/api/refresh-all */ 133 | Waypoint.refreshAll = function() { 134 | Waypoint.Context.refreshAll() 135 | } 136 | 137 | /* Public */ 138 | /* http://imakewebthings.com/waypoints/api/viewport-height */ 139 | Waypoint.viewportHeight = function() { 140 | return window.innerHeight || document.documentElement.clientHeight 141 | } 142 | 143 | /* Public */ 144 | /* http://imakewebthings.com/waypoints/api/viewport-width */ 145 | Waypoint.viewportWidth = function() { 146 | return document.documentElement.clientWidth 147 | } 148 | 149 | Waypoint.adapters = [] 150 | 151 | Waypoint.defaults = { 152 | context: window, 153 | continuous: true, 154 | enabled: true, 155 | group: 'default', 156 | horizontal: false, 157 | offset: 0 158 | } 159 | 160 | Waypoint.offsetAliases = { 161 | 'bottom-in-view': function() { 162 | return this.context.innerHeight() - this.adapter.outerHeight() 163 | }, 164 | 'right-in-view': function() { 165 | return this.context.innerWidth() - this.adapter.outerWidth() 166 | } 167 | } 168 | 169 | window.Waypoint = Waypoint 170 | }()) 171 | ;(function() { 172 | 'use strict' 173 | 174 | function requestAnimationFrameShim(callback) { 175 | window.setTimeout(callback, 1000 / 60) 176 | } 177 | 178 | var keyCounter = 0 179 | var contexts = {} 180 | var Waypoint = window.Waypoint 181 | var oldWindowLoad = window.onload 182 | 183 | /* http://imakewebthings.com/waypoints/api/context */ 184 | function Context(element) { 185 | this.element = element 186 | this.Adapter = Waypoint.Adapter 187 | this.adapter = new this.Adapter(element) 188 | this.key = 'waypoint-context-' + keyCounter 189 | this.didScroll = false 190 | this.didResize = false 191 | this.oldScroll = { 192 | x: this.adapter.scrollLeft(), 193 | y: this.adapter.scrollTop() 194 | } 195 | this.waypoints = { 196 | vertical: {}, 197 | horizontal: {} 198 | } 199 | 200 | element.waypointContextKey = this.key 201 | contexts[element.waypointContextKey] = this 202 | keyCounter += 1 203 | if (!Waypoint.windowContext) { 204 | Waypoint.windowContext = true 205 | Waypoint.windowContext = new Context(window) 206 | } 207 | 208 | this.createThrottledScrollHandler() 209 | this.createThrottledResizeHandler() 210 | } 211 | 212 | /* Private */ 213 | Context.prototype.add = function(waypoint) { 214 | var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical' 215 | this.waypoints[axis][waypoint.key] = waypoint 216 | this.refresh() 217 | } 218 | 219 | /* Private */ 220 | Context.prototype.checkEmpty = function() { 221 | var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal) 222 | var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical) 223 | var isWindow = this.element == this.element.window 224 | if (horizontalEmpty && verticalEmpty && !isWindow) { 225 | this.adapter.off('.waypoints') 226 | delete contexts[this.key] 227 | } 228 | } 229 | 230 | /* Private */ 231 | Context.prototype.createThrottledResizeHandler = function() { 232 | var self = this 233 | 234 | function resizeHandler() { 235 | self.handleResize() 236 | self.didResize = false 237 | } 238 | 239 | this.adapter.on('resize.waypoints', function() { 240 | if (!self.didResize) { 241 | self.didResize = true 242 | Waypoint.requestAnimationFrame(resizeHandler) 243 | } 244 | }) 245 | } 246 | 247 | /* Private */ 248 | Context.prototype.createThrottledScrollHandler = function() { 249 | var self = this 250 | function scrollHandler() { 251 | self.handleScroll() 252 | self.didScroll = false 253 | } 254 | 255 | this.adapter.on('scroll.waypoints', function() { 256 | if (!self.didScroll || Waypoint.isTouch) { 257 | self.didScroll = true 258 | Waypoint.requestAnimationFrame(scrollHandler) 259 | } 260 | }) 261 | } 262 | 263 | /* Private */ 264 | Context.prototype.handleResize = function() { 265 | Waypoint.Context.refreshAll() 266 | } 267 | 268 | /* Private */ 269 | Context.prototype.handleScroll = function() { 270 | var triggeredGroups = {} 271 | var axes = { 272 | horizontal: { 273 | newScroll: this.adapter.scrollLeft(), 274 | oldScroll: this.oldScroll.x, 275 | forward: 'right', 276 | backward: 'left' 277 | }, 278 | vertical: { 279 | newScroll: this.adapter.scrollTop(), 280 | oldScroll: this.oldScroll.y, 281 | forward: 'down', 282 | backward: 'up' 283 | } 284 | } 285 | 286 | for (var axisKey in axes) { 287 | var axis = axes[axisKey] 288 | var isForward = axis.newScroll > axis.oldScroll 289 | var direction = isForward ? axis.forward : axis.backward 290 | 291 | for (var waypointKey in this.waypoints[axisKey]) { 292 | var waypoint = this.waypoints[axisKey][waypointKey] 293 | if (waypoint.triggerPoint === null) { 294 | continue 295 | } 296 | var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint 297 | var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint 298 | var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint 299 | var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint 300 | if (crossedForward || crossedBackward) { 301 | waypoint.queueTrigger(direction) 302 | triggeredGroups[waypoint.group.id] = waypoint.group 303 | } 304 | } 305 | } 306 | 307 | for (var groupKey in triggeredGroups) { 308 | triggeredGroups[groupKey].flushTriggers() 309 | } 310 | 311 | this.oldScroll = { 312 | x: axes.horizontal.newScroll, 313 | y: axes.vertical.newScroll 314 | } 315 | } 316 | 317 | /* Private */ 318 | Context.prototype.innerHeight = function() { 319 | /*eslint-disable eqeqeq */ 320 | if (this.element == this.element.window) { 321 | return Waypoint.viewportHeight() 322 | } 323 | /*eslint-enable eqeqeq */ 324 | return this.adapter.innerHeight() 325 | } 326 | 327 | /* Private */ 328 | Context.prototype.remove = function(waypoint) { 329 | delete this.waypoints[waypoint.axis][waypoint.key] 330 | this.checkEmpty() 331 | } 332 | 333 | /* Private */ 334 | Context.prototype.innerWidth = function() { 335 | /*eslint-disable eqeqeq */ 336 | if (this.element == this.element.window) { 337 | return Waypoint.viewportWidth() 338 | } 339 | /*eslint-enable eqeqeq */ 340 | return this.adapter.innerWidth() 341 | } 342 | 343 | /* Public */ 344 | /* http://imakewebthings.com/waypoints/api/context-destroy */ 345 | Context.prototype.destroy = function() { 346 | var allWaypoints = [] 347 | for (var axis in this.waypoints) { 348 | for (var waypointKey in this.waypoints[axis]) { 349 | allWaypoints.push(this.waypoints[axis][waypointKey]) 350 | } 351 | } 352 | for (var i = 0, end = allWaypoints.length; i < end; i++) { 353 | allWaypoints[i].destroy() 354 | } 355 | } 356 | 357 | /* Public */ 358 | /* http://imakewebthings.com/waypoints/api/context-refresh */ 359 | Context.prototype.refresh = function() { 360 | /*eslint-disable eqeqeq */ 361 | var isWindow = this.element == this.element.window 362 | /*eslint-enable eqeqeq */ 363 | var contextOffset = isWindow ? undefined : this.adapter.offset() 364 | var triggeredGroups = {} 365 | var axes 366 | 367 | this.handleScroll() 368 | axes = { 369 | horizontal: { 370 | contextOffset: isWindow ? 0 : contextOffset.left, 371 | contextScroll: isWindow ? 0 : this.oldScroll.x, 372 | contextDimension: this.innerWidth(), 373 | oldScroll: this.oldScroll.x, 374 | forward: 'right', 375 | backward: 'left', 376 | offsetProp: 'left' 377 | }, 378 | vertical: { 379 | contextOffset: isWindow ? 0 : contextOffset.top, 380 | contextScroll: isWindow ? 0 : this.oldScroll.y, 381 | contextDimension: this.innerHeight(), 382 | oldScroll: this.oldScroll.y, 383 | forward: 'down', 384 | backward: 'up', 385 | offsetProp: 'top' 386 | } 387 | } 388 | 389 | for (var axisKey in axes) { 390 | var axis = axes[axisKey] 391 | for (var waypointKey in this.waypoints[axisKey]) { 392 | var waypoint = this.waypoints[axisKey][waypointKey] 393 | var adjustment = waypoint.options.offset 394 | var oldTriggerPoint = waypoint.triggerPoint 395 | var elementOffset = 0 396 | var freshWaypoint = oldTriggerPoint == null 397 | var contextModifier, wasBeforeScroll, nowAfterScroll 398 | var triggeredBackward, triggeredForward 399 | 400 | if (waypoint.element !== waypoint.element.window) { 401 | elementOffset = waypoint.adapter.offset()[axis.offsetProp] 402 | } 403 | 404 | if (typeof adjustment === 'function') { 405 | adjustment = adjustment.apply(waypoint) 406 | } 407 | else if (typeof adjustment === 'string') { 408 | adjustment = parseFloat(adjustment) 409 | if (waypoint.options.offset.indexOf('%') > - 1) { 410 | adjustment = Math.ceil(axis.contextDimension * adjustment / 100) 411 | } 412 | } 413 | 414 | contextModifier = axis.contextScroll - axis.contextOffset 415 | waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment) 416 | wasBeforeScroll = oldTriggerPoint < axis.oldScroll 417 | nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll 418 | triggeredBackward = wasBeforeScroll && nowAfterScroll 419 | triggeredForward = !wasBeforeScroll && !nowAfterScroll 420 | 421 | if (!freshWaypoint && triggeredBackward) { 422 | waypoint.queueTrigger(axis.backward) 423 | triggeredGroups[waypoint.group.id] = waypoint.group 424 | } 425 | else if (!freshWaypoint && triggeredForward) { 426 | waypoint.queueTrigger(axis.forward) 427 | triggeredGroups[waypoint.group.id] = waypoint.group 428 | } 429 | else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) { 430 | waypoint.queueTrigger(axis.forward) 431 | triggeredGroups[waypoint.group.id] = waypoint.group 432 | } 433 | } 434 | } 435 | 436 | Waypoint.requestAnimationFrame(function() { 437 | for (var groupKey in triggeredGroups) { 438 | triggeredGroups[groupKey].flushTriggers() 439 | } 440 | }) 441 | 442 | return this 443 | } 444 | 445 | /* Private */ 446 | Context.findOrCreateByElement = function(element) { 447 | return Context.findByElement(element) || new Context(element) 448 | } 449 | 450 | /* Private */ 451 | Context.refreshAll = function() { 452 | for (var contextId in contexts) { 453 | contexts[contextId].refresh() 454 | } 455 | } 456 | 457 | /* Public */ 458 | /* http://imakewebthings.com/waypoints/api/context-find-by-element */ 459 | Context.findByElement = function(element) { 460 | return contexts[element.waypointContextKey] 461 | } 462 | 463 | window.onload = function() { 464 | if (oldWindowLoad) { 465 | oldWindowLoad() 466 | } 467 | Context.refreshAll() 468 | } 469 | 470 | 471 | Waypoint.requestAnimationFrame = function(callback) { 472 | var requestFn = window.requestAnimationFrame || 473 | window.mozRequestAnimationFrame || 474 | window.webkitRequestAnimationFrame || 475 | requestAnimationFrameShim 476 | requestFn.call(window, callback) 477 | } 478 | Waypoint.Context = Context 479 | }()) 480 | ;(function() { 481 | 'use strict' 482 | 483 | function byTriggerPoint(a, b) { 484 | return a.triggerPoint - b.triggerPoint 485 | } 486 | 487 | function byReverseTriggerPoint(a, b) { 488 | return b.triggerPoint - a.triggerPoint 489 | } 490 | 491 | var groups = { 492 | vertical: {}, 493 | horizontal: {} 494 | } 495 | var Waypoint = window.Waypoint 496 | 497 | /* http://imakewebthings.com/waypoints/api/group */ 498 | function Group(options) { 499 | this.name = options.name 500 | this.axis = options.axis 501 | this.id = this.name + '-' + this.axis 502 | this.waypoints = [] 503 | this.clearTriggerQueues() 504 | groups[this.axis][this.name] = this 505 | } 506 | 507 | /* Private */ 508 | Group.prototype.add = function(waypoint) { 509 | this.waypoints.push(waypoint) 510 | } 511 | 512 | /* Private */ 513 | Group.prototype.clearTriggerQueues = function() { 514 | this.triggerQueues = { 515 | up: [], 516 | down: [], 517 | left: [], 518 | right: [] 519 | } 520 | } 521 | 522 | /* Private */ 523 | Group.prototype.flushTriggers = function() { 524 | for (var direction in this.triggerQueues) { 525 | var waypoints = this.triggerQueues[direction] 526 | var reverse = direction === 'up' || direction === 'left' 527 | waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint) 528 | for (var i = 0, end = waypoints.length; i < end; i += 1) { 529 | var waypoint = waypoints[i] 530 | if (waypoint.options.continuous || i === waypoints.length - 1) { 531 | waypoint.trigger([direction]) 532 | } 533 | } 534 | } 535 | this.clearTriggerQueues() 536 | } 537 | 538 | /* Private */ 539 | Group.prototype.next = function(waypoint) { 540 | this.waypoints.sort(byTriggerPoint) 541 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 542 | var isLast = index === this.waypoints.length - 1 543 | return isLast ? null : this.waypoints[index + 1] 544 | } 545 | 546 | /* Private */ 547 | Group.prototype.previous = function(waypoint) { 548 | this.waypoints.sort(byTriggerPoint) 549 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 550 | return index ? this.waypoints[index - 1] : null 551 | } 552 | 553 | /* Private */ 554 | Group.prototype.queueTrigger = function(waypoint, direction) { 555 | this.triggerQueues[direction].push(waypoint) 556 | } 557 | 558 | /* Private */ 559 | Group.prototype.remove = function(waypoint) { 560 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 561 | if (index > -1) { 562 | this.waypoints.splice(index, 1) 563 | } 564 | } 565 | 566 | /* Public */ 567 | /* http://imakewebthings.com/waypoints/api/first */ 568 | Group.prototype.first = function() { 569 | return this.waypoints[0] 570 | } 571 | 572 | /* Public */ 573 | /* http://imakewebthings.com/waypoints/api/last */ 574 | Group.prototype.last = function() { 575 | return this.waypoints[this.waypoints.length - 1] 576 | } 577 | 578 | /* Private */ 579 | Group.findOrCreate = function(options) { 580 | return groups[options.axis][options.name] || new Group(options) 581 | } 582 | 583 | Waypoint.Group = Group 584 | }()) 585 | ;(function() { 586 | 'use strict' 587 | 588 | var $ = window.Zepto 589 | var Waypoint = window.Waypoint 590 | 591 | function ZeptoAdapter(element) { 592 | this.element = element 593 | this.$element = $(element) 594 | } 595 | 596 | $.each([ 597 | 'off', 598 | 'on', 599 | 'scrollLeft', 600 | 'scrollTop' 601 | ], function(i, method) { 602 | ZeptoAdapter.prototype[method] = function() { 603 | var args = Array.prototype.slice.call(arguments) 604 | return this.$element[method].apply(this.$element, args) 605 | } 606 | }) 607 | 608 | ZeptoAdapter.prototype.offset = function() { 609 | if (this.element !== this.element.window) { 610 | return this.$element.offset() 611 | } 612 | } 613 | 614 | // Adapted from https://gist.github.com/wheresrhys/5823198 615 | $.each([ 616 | 'width', 617 | 'height' 618 | ], function(i, dimension) { 619 | function createDimensionMethod($element, includeBorder) { 620 | return function(includeMargin) { 621 | var $element = this.$element 622 | var size = $element[dimension]() 623 | var sides = { 624 | width: ['left', 'right'], 625 | height: ['top', 'bottom'] 626 | } 627 | 628 | $.each(sides[dimension], function(i, side) { 629 | size += parseInt($element.css('padding-' + side), 10) 630 | if (includeBorder) { 631 | size += parseInt($element.css('border-' + side + '-width'), 10) 632 | } 633 | if (includeMargin) { 634 | size += parseInt($element.css('margin-' + side), 10) 635 | } 636 | }) 637 | return size 638 | } 639 | } 640 | 641 | var innerMethod = $.camelCase('inner-' + dimension) 642 | var outerMethod = $.camelCase('outer-' + dimension) 643 | 644 | ZeptoAdapter.prototype[innerMethod] = createDimensionMethod(false) 645 | ZeptoAdapter.prototype[outerMethod] = createDimensionMethod(true) 646 | }) 647 | 648 | $.each([ 649 | 'extend', 650 | 'inArray' 651 | ], function(i, method) { 652 | ZeptoAdapter[method] = $[method] 653 | }) 654 | 655 | ZeptoAdapter.isEmptyObject = function(obj) { 656 | /* eslint no-unused-vars: 0 */ 657 | for (var name in obj) { 658 | return false 659 | } 660 | return true 661 | } 662 | 663 | Waypoint.adapters.push({ 664 | name: 'zepto', 665 | Adapter: ZeptoAdapter 666 | }) 667 | Waypoint.Adapter = ZeptoAdapter 668 | }()) 669 | ;(function() { 670 | 'use strict' 671 | 672 | var Waypoint = window.Waypoint 673 | 674 | function createExtension(framework) { 675 | return function() { 676 | var waypoints = [] 677 | var overrides = arguments[0] 678 | 679 | if (framework.isFunction(arguments[0])) { 680 | overrides = framework.extend({}, arguments[1]) 681 | overrides.handler = arguments[0] 682 | } 683 | 684 | this.each(function() { 685 | var options = framework.extend({}, overrides, { 686 | element: this 687 | }) 688 | if (typeof options.context === 'string') { 689 | options.context = framework(this).closest(options.context)[0] 690 | } 691 | waypoints.push(new Waypoint(options)) 692 | }) 693 | 694 | return waypoints 695 | } 696 | } 697 | 698 | if (window.jQuery) { 699 | window.jQuery.fn.waypoint = createExtension(window.jQuery) 700 | } 701 | if (window.Zepto) { 702 | window.Zepto.fn.waypoint = createExtension(window.Zepto) 703 | } 704 | }()) 705 | ; -------------------------------------------------------------------------------- /practice/lib/noframework.waypoints.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints - 4.0.1 3 | Copyright © 2011-2016 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blob/master/licenses.txt 6 | */ 7 | (function() { 8 | 'use strict' 9 | 10 | var keyCounter = 0 11 | var allWaypoints = {} 12 | 13 | /* http://imakewebthings.com/waypoints/api/waypoint */ 14 | function Waypoint(options) { 15 | if (!options) { 16 | throw new Error('No options passed to Waypoint constructor') 17 | } 18 | if (!options.element) { 19 | throw new Error('No element option passed to Waypoint constructor') 20 | } 21 | if (!options.handler) { 22 | throw new Error('No handler option passed to Waypoint constructor') 23 | } 24 | 25 | this.key = 'waypoint-' + keyCounter 26 | this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options) 27 | this.element = this.options.element 28 | this.adapter = new Waypoint.Adapter(this.element) 29 | this.callback = options.handler 30 | this.axis = this.options.horizontal ? 'horizontal' : 'vertical' 31 | this.enabled = this.options.enabled 32 | this.triggerPoint = null 33 | this.group = Waypoint.Group.findOrCreate({ 34 | name: this.options.group, 35 | axis: this.axis 36 | }) 37 | this.context = Waypoint.Context.findOrCreateByElement(this.options.context) 38 | 39 | if (Waypoint.offsetAliases[this.options.offset]) { 40 | this.options.offset = Waypoint.offsetAliases[this.options.offset] 41 | } 42 | this.group.add(this) 43 | this.context.add(this) 44 | allWaypoints[this.key] = this 45 | keyCounter += 1 46 | } 47 | 48 | /* Private */ 49 | Waypoint.prototype.queueTrigger = function(direction) { 50 | this.group.queueTrigger(this, direction) 51 | } 52 | 53 | /* Private */ 54 | Waypoint.prototype.trigger = function(args) { 55 | if (!this.enabled) { 56 | return 57 | } 58 | if (this.callback) { 59 | this.callback.apply(this, args) 60 | } 61 | } 62 | 63 | /* Public */ 64 | /* http://imakewebthings.com/waypoints/api/destroy */ 65 | Waypoint.prototype.destroy = function() { 66 | this.context.remove(this) 67 | this.group.remove(this) 68 | delete allWaypoints[this.key] 69 | } 70 | 71 | /* Public */ 72 | /* http://imakewebthings.com/waypoints/api/disable */ 73 | Waypoint.prototype.disable = function() { 74 | this.enabled = false 75 | return this 76 | } 77 | 78 | /* Public */ 79 | /* http://imakewebthings.com/waypoints/api/enable */ 80 | Waypoint.prototype.enable = function() { 81 | this.context.refresh() 82 | this.enabled = true 83 | return this 84 | } 85 | 86 | /* Public */ 87 | /* http://imakewebthings.com/waypoints/api/next */ 88 | Waypoint.prototype.next = function() { 89 | return this.group.next(this) 90 | } 91 | 92 | /* Public */ 93 | /* http://imakewebthings.com/waypoints/api/previous */ 94 | Waypoint.prototype.previous = function() { 95 | return this.group.previous(this) 96 | } 97 | 98 | /* Private */ 99 | Waypoint.invokeAll = function(method) { 100 | var allWaypointsArray = [] 101 | for (var waypointKey in allWaypoints) { 102 | allWaypointsArray.push(allWaypoints[waypointKey]) 103 | } 104 | for (var i = 0, end = allWaypointsArray.length; i < end; i++) { 105 | allWaypointsArray[i][method]() 106 | } 107 | } 108 | 109 | /* Public */ 110 | /* http://imakewebthings.com/waypoints/api/destroy-all */ 111 | Waypoint.destroyAll = function() { 112 | Waypoint.invokeAll('destroy') 113 | } 114 | 115 | /* Public */ 116 | /* http://imakewebthings.com/waypoints/api/disable-all */ 117 | Waypoint.disableAll = function() { 118 | Waypoint.invokeAll('disable') 119 | } 120 | 121 | /* Public */ 122 | /* http://imakewebthings.com/waypoints/api/enable-all */ 123 | Waypoint.enableAll = function() { 124 | Waypoint.Context.refreshAll() 125 | for (var waypointKey in allWaypoints) { 126 | allWaypoints[waypointKey].enabled = true 127 | } 128 | return this 129 | } 130 | 131 | /* Public */ 132 | /* http://imakewebthings.com/waypoints/api/refresh-all */ 133 | Waypoint.refreshAll = function() { 134 | Waypoint.Context.refreshAll() 135 | } 136 | 137 | /* Public */ 138 | /* http://imakewebthings.com/waypoints/api/viewport-height */ 139 | Waypoint.viewportHeight = function() { 140 | return window.innerHeight || document.documentElement.clientHeight 141 | } 142 | 143 | /* Public */ 144 | /* http://imakewebthings.com/waypoints/api/viewport-width */ 145 | Waypoint.viewportWidth = function() { 146 | return document.documentElement.clientWidth 147 | } 148 | 149 | Waypoint.adapters = [] 150 | 151 | Waypoint.defaults = { 152 | context: window, 153 | continuous: true, 154 | enabled: true, 155 | group: 'default', 156 | horizontal: false, 157 | offset: 0 158 | } 159 | 160 | Waypoint.offsetAliases = { 161 | 'bottom-in-view': function() { 162 | return this.context.innerHeight() - this.adapter.outerHeight() 163 | }, 164 | 'right-in-view': function() { 165 | return this.context.innerWidth() - this.adapter.outerWidth() 166 | } 167 | } 168 | 169 | window.Waypoint = Waypoint 170 | }()) 171 | ;(function() { 172 | 'use strict' 173 | 174 | function requestAnimationFrameShim(callback) { 175 | window.setTimeout(callback, 1000 / 60) 176 | } 177 | 178 | var keyCounter = 0 179 | var contexts = {} 180 | var Waypoint = window.Waypoint 181 | var oldWindowLoad = window.onload 182 | 183 | /* http://imakewebthings.com/waypoints/api/context */ 184 | function Context(element) { 185 | this.element = element 186 | this.Adapter = Waypoint.Adapter 187 | this.adapter = new this.Adapter(element) 188 | this.key = 'waypoint-context-' + keyCounter 189 | this.didScroll = false 190 | this.didResize = false 191 | this.oldScroll = { 192 | x: this.adapter.scrollLeft(), 193 | y: this.adapter.scrollTop() 194 | } 195 | this.waypoints = { 196 | vertical: {}, 197 | horizontal: {} 198 | } 199 | 200 | element.waypointContextKey = this.key 201 | contexts[element.waypointContextKey] = this 202 | keyCounter += 1 203 | if (!Waypoint.windowContext) { 204 | Waypoint.windowContext = true 205 | Waypoint.windowContext = new Context(window) 206 | } 207 | 208 | this.createThrottledScrollHandler() 209 | this.createThrottledResizeHandler() 210 | } 211 | 212 | /* Private */ 213 | Context.prototype.add = function(waypoint) { 214 | var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical' 215 | this.waypoints[axis][waypoint.key] = waypoint 216 | this.refresh() 217 | } 218 | 219 | /* Private */ 220 | Context.prototype.checkEmpty = function() { 221 | var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal) 222 | var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical) 223 | var isWindow = this.element == this.element.window 224 | if (horizontalEmpty && verticalEmpty && !isWindow) { 225 | this.adapter.off('.waypoints') 226 | delete contexts[this.key] 227 | } 228 | } 229 | 230 | /* Private */ 231 | Context.prototype.createThrottledResizeHandler = function() { 232 | var self = this 233 | 234 | function resizeHandler() { 235 | self.handleResize() 236 | self.didResize = false 237 | } 238 | 239 | this.adapter.on('resize.waypoints', function() { 240 | if (!self.didResize) { 241 | self.didResize = true 242 | Waypoint.requestAnimationFrame(resizeHandler) 243 | } 244 | }) 245 | } 246 | 247 | /* Private */ 248 | Context.prototype.createThrottledScrollHandler = function() { 249 | var self = this 250 | function scrollHandler() { 251 | self.handleScroll() 252 | self.didScroll = false 253 | } 254 | 255 | this.adapter.on('scroll.waypoints', function() { 256 | if (!self.didScroll || Waypoint.isTouch) { 257 | self.didScroll = true 258 | Waypoint.requestAnimationFrame(scrollHandler) 259 | } 260 | }) 261 | } 262 | 263 | /* Private */ 264 | Context.prototype.handleResize = function() { 265 | Waypoint.Context.refreshAll() 266 | } 267 | 268 | /* Private */ 269 | Context.prototype.handleScroll = function() { 270 | var triggeredGroups = {} 271 | var axes = { 272 | horizontal: { 273 | newScroll: this.adapter.scrollLeft(), 274 | oldScroll: this.oldScroll.x, 275 | forward: 'right', 276 | backward: 'left' 277 | }, 278 | vertical: { 279 | newScroll: this.adapter.scrollTop(), 280 | oldScroll: this.oldScroll.y, 281 | forward: 'down', 282 | backward: 'up' 283 | } 284 | } 285 | 286 | for (var axisKey in axes) { 287 | var axis = axes[axisKey] 288 | var isForward = axis.newScroll > axis.oldScroll 289 | var direction = isForward ? axis.forward : axis.backward 290 | 291 | for (var waypointKey in this.waypoints[axisKey]) { 292 | var waypoint = this.waypoints[axisKey][waypointKey] 293 | if (waypoint.triggerPoint === null) { 294 | continue 295 | } 296 | var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint 297 | var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint 298 | var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint 299 | var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint 300 | if (crossedForward || crossedBackward) { 301 | waypoint.queueTrigger(direction) 302 | triggeredGroups[waypoint.group.id] = waypoint.group 303 | } 304 | } 305 | } 306 | 307 | for (var groupKey in triggeredGroups) { 308 | triggeredGroups[groupKey].flushTriggers() 309 | } 310 | 311 | this.oldScroll = { 312 | x: axes.horizontal.newScroll, 313 | y: axes.vertical.newScroll 314 | } 315 | } 316 | 317 | /* Private */ 318 | Context.prototype.innerHeight = function() { 319 | /*eslint-disable eqeqeq */ 320 | if (this.element == this.element.window) { 321 | return Waypoint.viewportHeight() 322 | } 323 | /*eslint-enable eqeqeq */ 324 | return this.adapter.innerHeight() 325 | } 326 | 327 | /* Private */ 328 | Context.prototype.remove = function(waypoint) { 329 | delete this.waypoints[waypoint.axis][waypoint.key] 330 | this.checkEmpty() 331 | } 332 | 333 | /* Private */ 334 | Context.prototype.innerWidth = function() { 335 | /*eslint-disable eqeqeq */ 336 | if (this.element == this.element.window) { 337 | return Waypoint.viewportWidth() 338 | } 339 | /*eslint-enable eqeqeq */ 340 | return this.adapter.innerWidth() 341 | } 342 | 343 | /* Public */ 344 | /* http://imakewebthings.com/waypoints/api/context-destroy */ 345 | Context.prototype.destroy = function() { 346 | var allWaypoints = [] 347 | for (var axis in this.waypoints) { 348 | for (var waypointKey in this.waypoints[axis]) { 349 | allWaypoints.push(this.waypoints[axis][waypointKey]) 350 | } 351 | } 352 | for (var i = 0, end = allWaypoints.length; i < end; i++) { 353 | allWaypoints[i].destroy() 354 | } 355 | } 356 | 357 | /* Public */ 358 | /* http://imakewebthings.com/waypoints/api/context-refresh */ 359 | Context.prototype.refresh = function() { 360 | /*eslint-disable eqeqeq */ 361 | var isWindow = this.element == this.element.window 362 | /*eslint-enable eqeqeq */ 363 | var contextOffset = isWindow ? undefined : this.adapter.offset() 364 | var triggeredGroups = {} 365 | var axes 366 | 367 | this.handleScroll() 368 | axes = { 369 | horizontal: { 370 | contextOffset: isWindow ? 0 : contextOffset.left, 371 | contextScroll: isWindow ? 0 : this.oldScroll.x, 372 | contextDimension: this.innerWidth(), 373 | oldScroll: this.oldScroll.x, 374 | forward: 'right', 375 | backward: 'left', 376 | offsetProp: 'left' 377 | }, 378 | vertical: { 379 | contextOffset: isWindow ? 0 : contextOffset.top, 380 | contextScroll: isWindow ? 0 : this.oldScroll.y, 381 | contextDimension: this.innerHeight(), 382 | oldScroll: this.oldScroll.y, 383 | forward: 'down', 384 | backward: 'up', 385 | offsetProp: 'top' 386 | } 387 | } 388 | 389 | for (var axisKey in axes) { 390 | var axis = axes[axisKey] 391 | for (var waypointKey in this.waypoints[axisKey]) { 392 | var waypoint = this.waypoints[axisKey][waypointKey] 393 | var adjustment = waypoint.options.offset 394 | var oldTriggerPoint = waypoint.triggerPoint 395 | var elementOffset = 0 396 | var freshWaypoint = oldTriggerPoint == null 397 | var contextModifier, wasBeforeScroll, nowAfterScroll 398 | var triggeredBackward, triggeredForward 399 | 400 | if (waypoint.element !== waypoint.element.window) { 401 | elementOffset = waypoint.adapter.offset()[axis.offsetProp] 402 | } 403 | 404 | if (typeof adjustment === 'function') { 405 | adjustment = adjustment.apply(waypoint) 406 | } 407 | else if (typeof adjustment === 'string') { 408 | adjustment = parseFloat(adjustment) 409 | if (waypoint.options.offset.indexOf('%') > - 1) { 410 | adjustment = Math.ceil(axis.contextDimension * adjustment / 100) 411 | } 412 | } 413 | 414 | contextModifier = axis.contextScroll - axis.contextOffset 415 | waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment) 416 | wasBeforeScroll = oldTriggerPoint < axis.oldScroll 417 | nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll 418 | triggeredBackward = wasBeforeScroll && nowAfterScroll 419 | triggeredForward = !wasBeforeScroll && !nowAfterScroll 420 | 421 | if (!freshWaypoint && triggeredBackward) { 422 | waypoint.queueTrigger(axis.backward) 423 | triggeredGroups[waypoint.group.id] = waypoint.group 424 | } 425 | else if (!freshWaypoint && triggeredForward) { 426 | waypoint.queueTrigger(axis.forward) 427 | triggeredGroups[waypoint.group.id] = waypoint.group 428 | } 429 | else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) { 430 | waypoint.queueTrigger(axis.forward) 431 | triggeredGroups[waypoint.group.id] = waypoint.group 432 | } 433 | } 434 | } 435 | 436 | Waypoint.requestAnimationFrame(function() { 437 | for (var groupKey in triggeredGroups) { 438 | triggeredGroups[groupKey].flushTriggers() 439 | } 440 | }) 441 | 442 | return this 443 | } 444 | 445 | /* Private */ 446 | Context.findOrCreateByElement = function(element) { 447 | return Context.findByElement(element) || new Context(element) 448 | } 449 | 450 | /* Private */ 451 | Context.refreshAll = function() { 452 | for (var contextId in contexts) { 453 | contexts[contextId].refresh() 454 | } 455 | } 456 | 457 | /* Public */ 458 | /* http://imakewebthings.com/waypoints/api/context-find-by-element */ 459 | Context.findByElement = function(element) { 460 | return contexts[element.waypointContextKey] 461 | } 462 | 463 | window.onload = function() { 464 | if (oldWindowLoad) { 465 | oldWindowLoad() 466 | } 467 | Context.refreshAll() 468 | } 469 | 470 | 471 | Waypoint.requestAnimationFrame = function(callback) { 472 | var requestFn = window.requestAnimationFrame || 473 | window.mozRequestAnimationFrame || 474 | window.webkitRequestAnimationFrame || 475 | requestAnimationFrameShim 476 | requestFn.call(window, callback) 477 | } 478 | Waypoint.Context = Context 479 | }()) 480 | ;(function() { 481 | 'use strict' 482 | 483 | function byTriggerPoint(a, b) { 484 | return a.triggerPoint - b.triggerPoint 485 | } 486 | 487 | function byReverseTriggerPoint(a, b) { 488 | return b.triggerPoint - a.triggerPoint 489 | } 490 | 491 | var groups = { 492 | vertical: {}, 493 | horizontal: {} 494 | } 495 | var Waypoint = window.Waypoint 496 | 497 | /* http://imakewebthings.com/waypoints/api/group */ 498 | function Group(options) { 499 | this.name = options.name 500 | this.axis = options.axis 501 | this.id = this.name + '-' + this.axis 502 | this.waypoints = [] 503 | this.clearTriggerQueues() 504 | groups[this.axis][this.name] = this 505 | } 506 | 507 | /* Private */ 508 | Group.prototype.add = function(waypoint) { 509 | this.waypoints.push(waypoint) 510 | } 511 | 512 | /* Private */ 513 | Group.prototype.clearTriggerQueues = function() { 514 | this.triggerQueues = { 515 | up: [], 516 | down: [], 517 | left: [], 518 | right: [] 519 | } 520 | } 521 | 522 | /* Private */ 523 | Group.prototype.flushTriggers = function() { 524 | for (var direction in this.triggerQueues) { 525 | var waypoints = this.triggerQueues[direction] 526 | var reverse = direction === 'up' || direction === 'left' 527 | waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint) 528 | for (var i = 0, end = waypoints.length; i < end; i += 1) { 529 | var waypoint = waypoints[i] 530 | if (waypoint.options.continuous || i === waypoints.length - 1) { 531 | waypoint.trigger([direction]) 532 | } 533 | } 534 | } 535 | this.clearTriggerQueues() 536 | } 537 | 538 | /* Private */ 539 | Group.prototype.next = function(waypoint) { 540 | this.waypoints.sort(byTriggerPoint) 541 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 542 | var isLast = index === this.waypoints.length - 1 543 | return isLast ? null : this.waypoints[index + 1] 544 | } 545 | 546 | /* Private */ 547 | Group.prototype.previous = function(waypoint) { 548 | this.waypoints.sort(byTriggerPoint) 549 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 550 | return index ? this.waypoints[index - 1] : null 551 | } 552 | 553 | /* Private */ 554 | Group.prototype.queueTrigger = function(waypoint, direction) { 555 | this.triggerQueues[direction].push(waypoint) 556 | } 557 | 558 | /* Private */ 559 | Group.prototype.remove = function(waypoint) { 560 | var index = Waypoint.Adapter.inArray(waypoint, this.waypoints) 561 | if (index > -1) { 562 | this.waypoints.splice(index, 1) 563 | } 564 | } 565 | 566 | /* Public */ 567 | /* http://imakewebthings.com/waypoints/api/first */ 568 | Group.prototype.first = function() { 569 | return this.waypoints[0] 570 | } 571 | 572 | /* Public */ 573 | /* http://imakewebthings.com/waypoints/api/last */ 574 | Group.prototype.last = function() { 575 | return this.waypoints[this.waypoints.length - 1] 576 | } 577 | 578 | /* Private */ 579 | Group.findOrCreate = function(options) { 580 | return groups[options.axis][options.name] || new Group(options) 581 | } 582 | 583 | Waypoint.Group = Group 584 | }()) 585 | ;(function() { 586 | 'use strict' 587 | 588 | var Waypoint = window.Waypoint 589 | 590 | function isWindow(element) { 591 | return element === element.window 592 | } 593 | 594 | function getWindow(element) { 595 | if (isWindow(element)) { 596 | return element 597 | } 598 | return element.defaultView 599 | } 600 | 601 | function NoFrameworkAdapter(element) { 602 | this.element = element 603 | this.handlers = {} 604 | } 605 | 606 | NoFrameworkAdapter.prototype.innerHeight = function() { 607 | var isWin = isWindow(this.element) 608 | return isWin ? this.element.innerHeight : this.element.clientHeight 609 | } 610 | 611 | NoFrameworkAdapter.prototype.innerWidth = function() { 612 | var isWin = isWindow(this.element) 613 | return isWin ? this.element.innerWidth : this.element.clientWidth 614 | } 615 | 616 | NoFrameworkAdapter.prototype.off = function(event, handler) { 617 | function removeListeners(element, listeners, handler) { 618 | for (var i = 0, end = listeners.length - 1; i < end; i++) { 619 | var listener = listeners[i] 620 | if (!handler || handler === listener) { 621 | element.removeEventListener(listener) 622 | } 623 | } 624 | } 625 | 626 | var eventParts = event.split('.') 627 | var eventType = eventParts[0] 628 | var namespace = eventParts[1] 629 | var element = this.element 630 | 631 | if (namespace && this.handlers[namespace] && eventType) { 632 | removeListeners(element, this.handlers[namespace][eventType], handler) 633 | this.handlers[namespace][eventType] = [] 634 | } 635 | else if (eventType) { 636 | for (var ns in this.handlers) { 637 | removeListeners(element, this.handlers[ns][eventType] || [], handler) 638 | this.handlers[ns][eventType] = [] 639 | } 640 | } 641 | else if (namespace && this.handlers[namespace]) { 642 | for (var type in this.handlers[namespace]) { 643 | removeListeners(element, this.handlers[namespace][type], handler) 644 | } 645 | this.handlers[namespace] = {} 646 | } 647 | } 648 | 649 | /* Adapted from jQuery 1.x offset() */ 650 | NoFrameworkAdapter.prototype.offset = function() { 651 | if (!this.element.ownerDocument) { 652 | return null 653 | } 654 | 655 | var documentElement = this.element.ownerDocument.documentElement 656 | var win = getWindow(this.element.ownerDocument) 657 | var rect = { 658 | top: 0, 659 | left: 0 660 | } 661 | 662 | if (this.element.getBoundingClientRect) { 663 | rect = this.element.getBoundingClientRect() 664 | } 665 | 666 | return { 667 | top: rect.top + win.pageYOffset - documentElement.clientTop, 668 | left: rect.left + win.pageXOffset - documentElement.clientLeft 669 | } 670 | } 671 | 672 | NoFrameworkAdapter.prototype.on = function(event, handler) { 673 | var eventParts = event.split('.') 674 | var eventType = eventParts[0] 675 | var namespace = eventParts[1] || '__default' 676 | var nsHandlers = this.handlers[namespace] = this.handlers[namespace] || {} 677 | var nsTypeList = nsHandlers[eventType] = nsHandlers[eventType] || [] 678 | 679 | nsTypeList.push(handler) 680 | this.element.addEventListener(eventType, handler) 681 | } 682 | 683 | NoFrameworkAdapter.prototype.outerHeight = function(includeMargin) { 684 | var height = this.innerHeight() 685 | var computedStyle 686 | 687 | if (includeMargin && !isWindow(this.element)) { 688 | computedStyle = window.getComputedStyle(this.element) 689 | height += parseInt(computedStyle.marginTop, 10) 690 | height += parseInt(computedStyle.marginBottom, 10) 691 | } 692 | 693 | return height 694 | } 695 | 696 | NoFrameworkAdapter.prototype.outerWidth = function(includeMargin) { 697 | var width = this.innerWidth() 698 | var computedStyle 699 | 700 | if (includeMargin && !isWindow(this.element)) { 701 | computedStyle = window.getComputedStyle(this.element) 702 | width += parseInt(computedStyle.marginLeft, 10) 703 | width += parseInt(computedStyle.marginRight, 10) 704 | } 705 | 706 | return width 707 | } 708 | 709 | NoFrameworkAdapter.prototype.scrollLeft = function() { 710 | var win = getWindow(this.element) 711 | return win ? win.pageXOffset : this.element.scrollLeft 712 | } 713 | 714 | NoFrameworkAdapter.prototype.scrollTop = function() { 715 | var win = getWindow(this.element) 716 | return win ? win.pageYOffset : this.element.scrollTop 717 | } 718 | 719 | NoFrameworkAdapter.extend = function() { 720 | var args = Array.prototype.slice.call(arguments) 721 | 722 | function merge(target, obj) { 723 | if (typeof target === 'object' && typeof obj === 'object') { 724 | for (var key in obj) { 725 | if (obj.hasOwnProperty(key)) { 726 | target[key] = obj[key] 727 | } 728 | } 729 | } 730 | 731 | return target 732 | } 733 | 734 | for (var i = 1, end = args.length; i < end; i++) { 735 | merge(args[0], args[i]) 736 | } 737 | return args[0] 738 | } 739 | 740 | NoFrameworkAdapter.inArray = function(element, array, i) { 741 | return array == null ? -1 : array.indexOf(element, i) 742 | } 743 | 744 | NoFrameworkAdapter.isEmptyObject = function(obj) { 745 | /* eslint no-unused-vars: 0 */ 746 | for (var name in obj) { 747 | return false 748 | } 749 | return true 750 | } 751 | 752 | Waypoint.adapters.push({ 753 | name: 'noframework', 754 | Adapter: NoFrameworkAdapter 755 | }) 756 | Waypoint.Adapter = NoFrameworkAdapter 757 | }()) 758 | ; --------------------------------------------------------------------------------