assets/javascripts/bootstrap/affix.js
changeset 114 af15590802a4
equal deleted inserted replaced
113:d4ec02c51c91 114:af15590802a4
       
     1 /* ========================================================================
       
     2  * Bootstrap: affix.js v3.3.5
       
     3  * http://getbootstrap.com/javascript/#affix
       
     4  * ========================================================================
       
     5  * Copyright 2011-2015 Twitter, Inc.
       
     6  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
       
     7  * ======================================================================== */
       
     8 
       
     9 
       
    10 +function ($) {
       
    11   'use strict';
       
    12 
       
    13   // AFFIX CLASS DEFINITION
       
    14   // ======================
       
    15 
       
    16   var Affix = function (element, options) {
       
    17     this.options = $.extend({}, Affix.DEFAULTS, options)
       
    18 
       
    19     this.$target = $(this.options.target)
       
    20       .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
       
    21       .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
       
    22 
       
    23     this.$element     = $(element)
       
    24     this.affixed      = null
       
    25     this.unpin        = null
       
    26     this.pinnedOffset = null
       
    27 
       
    28     this.checkPosition()
       
    29   }
       
    30 
       
    31   Affix.VERSION  = '3.3.5'
       
    32 
       
    33   Affix.RESET    = 'affix affix-top affix-bottom'
       
    34 
       
    35   Affix.DEFAULTS = {
       
    36     offset: 0,
       
    37     target: window
       
    38   }
       
    39 
       
    40   Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
       
    41     var scrollTop    = this.$target.scrollTop()
       
    42     var position     = this.$element.offset()
       
    43     var targetHeight = this.$target.height()
       
    44 
       
    45     if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
       
    46 
       
    47     if (this.affixed == 'bottom') {
       
    48       if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
       
    49       return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
       
    50     }
       
    51 
       
    52     var initializing   = this.affixed == null
       
    53     var colliderTop    = initializing ? scrollTop : position.top
       
    54     var colliderHeight = initializing ? targetHeight : height
       
    55 
       
    56     if (offsetTop != null && scrollTop <= offsetTop) return 'top'
       
    57     if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
       
    58 
       
    59     return false
       
    60   }
       
    61 
       
    62   Affix.prototype.getPinnedOffset = function () {
       
    63     if (this.pinnedOffset) return this.pinnedOffset
       
    64     this.$element.removeClass(Affix.RESET).addClass('affix')
       
    65     var scrollTop = this.$target.scrollTop()
       
    66     var position  = this.$element.offset()
       
    67     return (this.pinnedOffset = position.top - scrollTop)
       
    68   }
       
    69 
       
    70   Affix.prototype.checkPositionWithEventLoop = function () {
       
    71     setTimeout($.proxy(this.checkPosition, this), 1)
       
    72   }
       
    73 
       
    74   Affix.prototype.checkPosition = function () {
       
    75     if (!this.$element.is(':visible')) return
       
    76 
       
    77     var height       = this.$element.height()
       
    78     var offset       = this.options.offset
       
    79     var offsetTop    = offset.top
       
    80     var offsetBottom = offset.bottom
       
    81     var scrollHeight = Math.max($(document).height(), $(document.body).height())
       
    82 
       
    83     if (typeof offset != 'object')         offsetBottom = offsetTop = offset
       
    84     if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
       
    85     if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
       
    86 
       
    87     var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
       
    88 
       
    89     if (this.affixed != affix) {
       
    90       if (this.unpin != null) this.$element.css('top', '')
       
    91 
       
    92       var affixType = 'affix' + (affix ? '-' + affix : '')
       
    93       var e         = $.Event(affixType + '.bs.affix')
       
    94 
       
    95       this.$element.trigger(e)
       
    96 
       
    97       if (e.isDefaultPrevented()) return
       
    98 
       
    99       this.affixed = affix
       
   100       this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
       
   101 
       
   102       this.$element
       
   103         .removeClass(Affix.RESET)
       
   104         .addClass(affixType)
       
   105         .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
       
   106     }
       
   107 
       
   108     if (affix == 'bottom') {
       
   109       this.$element.offset({
       
   110         top: scrollHeight - height - offsetBottom
       
   111       })
       
   112     }
       
   113   }
       
   114 
       
   115 
       
   116   // AFFIX PLUGIN DEFINITION
       
   117   // =======================
       
   118 
       
   119   function Plugin(option) {
       
   120     return this.each(function () {
       
   121       var $this   = $(this)
       
   122       var data    = $this.data('bs.affix')
       
   123       var options = typeof option == 'object' && option
       
   124 
       
   125       if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
       
   126       if (typeof option == 'string') data[option]()
       
   127     })
       
   128   }
       
   129 
       
   130   var old = $.fn.affix
       
   131 
       
   132   $.fn.affix             = Plugin
       
   133   $.fn.affix.Constructor = Affix
       
   134 
       
   135 
       
   136   // AFFIX NO CONFLICT
       
   137   // =================
       
   138 
       
   139   $.fn.affix.noConflict = function () {
       
   140     $.fn.affix = old
       
   141     return this
       
   142   }
       
   143 
       
   144 
       
   145   // AFFIX DATA-API
       
   146   // ==============
       
   147 
       
   148   $(window).on('load', function () {
       
   149     $('[data-spy="affix"]').each(function () {
       
   150       var $spy = $(this)
       
   151       var data = $spy.data()
       
   152 
       
   153       data.offset = data.offset || {}
       
   154 
       
   155       if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
       
   156       if (data.offsetTop    != null) data.offset.top    = data.offsetTop
       
   157 
       
   158       Plugin.call($spy, data)
       
   159     })
       
   160   })
       
   161 
       
   162 }(jQuery);