Project

General

Profile

1
// Native Javascript for Bootstrap 3 | Affix
2
// by dnp_theme
3

    
4
(function(factory){
5

    
6
  // CommonJS/RequireJS and "native" compatibility
7
  if(typeof module !== "undefined" && typeof exports == "object") {
8
    // A commonJS/RequireJS environment
9
    if(typeof window != "undefined") {
10
      // Window and document exist, so return the factory's return value.
11
      module.exports = factory();
12
    } else {
13
      // Let the user give the factory a Window and Document.
14
      module.exports = factory;
15
    }
16
  } else {
17
    // Assume a traditional browser.
18
    window.Affix = factory();
19
  }
20

    
21
})(function(){
22

    
23
  //AFFIX DEFINITION
24
  var Affix = function(element,options) {
25
    options = options || {};
26
    
27
    this.element = typeof element === 'object' ? element : document.querySelector(element);
28
    this.options = {};
29
    this.options.target = options.target ? ((typeof(options.target) === 'object') ? options.target : document.querySelector(options.target)) : null; // target is an object
30
    this.options.offsetTop = options.offsetTop && options.offsetTop ? ( options.offsetTop === 'function' ? options.offsetTop() : parseInt(options.offsetTop,0) ) : 0; // offset option is an integer number or function to determine that number
31
    this.options.offsetBottom = options.offsetBottom && options.offsetBottom ? ( options.offsetBottom === 'function' ? options.offsetBottom() : parseInt(options.offsetBottom,0) ) : null;
32

    
33
    if (this.element && (this.options.target || this.options.offsetTop || this.options.offsetBottom ) ) { this.init(); }
34
  }
35

    
36
  //AFFIX METHODS
37
  Affix.prototype = {
38
    init: function () {
39
      this.affixed = false;
40
      this.affixedBottom = false;
41
      this.getPinOffsetTop = 0;
42
      this.getPinOffsetBottom = null;
43

    
44
      //actions
45
      this.checkPosition();
46
      this.updateAffix();
47
      this.scrollEvent();
48
      this.resizeEvent()
49
    },
50
    processOffsetTop: function () {
51
      if ( this.options.target !== null ) {
52
        return this.targetRect().top + this.scrollOffset();
53
      } else if ( this.options.offsetTop !== null ) {
54
        return this.options.offsetTop
55
      }
56
    },
57
    processOffsetBottom: function () {
58
      if ( this.options.offsetBottom !== null ) {
59
        var maxScroll = this.getMaxScroll();
60
        return maxScroll - this.elementHeight() - this.options.offsetBottom
61
      }
62
    },
63
    offsetTop: function () {
64
      return this.processOffsetTop()
65
    },
66
    offsetBottom: function () {
67
      return this.processOffsetBottom()
68
    },
69
    checkPosition: function () {
70
      this.getPinOffsetTop = this.offsetTop
71
      this.getPinOffsetBottom = this.offsetBottom
72
    },
73
    scrollOffset: function () {
74
      return window.pageYOffset || document.documentElement.scrollTop
75
    },
76
    pinTop: function () {
77
      if ( !/affix/.test(this.element.className) ) {
78
        this.element.className += ' affix';
79
        this.affixed = true
80
      }
81
    },
82
    unPinTop: function () {
83
      if ( /affix/.test(this.element.className) ) {
84
        this.element.className = this.element.className.replace(' affix','');
85
        this.affixed = false
86
      }
87
    },
88
    pinBottom: function () {
89
      if ( !/'affix-bottom'/.test(this.element.className) ) {
90
        this.element.className += ' affix-bottom';
91
        this.affixedBottom = true
92
      }
93
    },
94
    unPinBottom: function () {
95
      if ( /'affix-bottom'/.test(this.element.className) ) { 
96
        this.element.className = this.element.className.replace(' affix-bottom','');
97
        this.affixedBottom = false
98
      }
99
    },
100
    updatePin: function () {
101
      if (this.affixed === false && (parseInt(this.offsetTop(),0) - parseInt(this.scrollOffset(),0) < 0)) {
102
        this.pinTop();
103
      } else if (this.affixed === true && (parseInt(this.scrollOffset(),0) <= parseInt(this.getPinOffsetTop(),0) )) {
104
        this.unPinTop()
105
      }
106

    
107
      if (this.affixedBottom === false && (parseInt(this.offsetBottom(),0) - parseInt(this.scrollOffset(),0) < 0)) {
108
        this.pinBottom();
109
      } else if (this.affixedBottom === true && (parseInt(this.scrollOffset(),0) <= parseInt(this.getPinOffsetBottom(),0) )) {
110
        this.unPinBottom()
111
      }
112
    },
113

    
114
    updateAffix : function () { // Unpin and check position again
115
      this.unPinTop();
116
      this.unPinBottom();
117
      this.checkPosition()
118

    
119
      this.updatePin() // If any case update values again
120
    },
121

    
122
    elementHeight : function(){
123
      return this.element.offsetHeight
124
    },
125

    
126
    targetRect : function(){
127
      return this.options.target.getBoundingClientRect()
128
    },
129

    
130
    getMaxScroll : function(){
131
      return Math.max( document.body.scrollHeight, document.body.offsetHeight, 
132
        document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight )
133
    },
134

    
135
    scrollEvent : function(){
136
      var self = this;
137
      window.addEventListener('scroll', function() {
138
        self.updatePin()
139
      }, false);
140

    
141
    },
142
    resizeEvent : function(){
143
      var self = this, 
144
        isIE = (new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})").exec(navigator.userAgent) != null) ? parseFloat( RegExp.$1 ) : false, 
145
        dl = (isIE && isIE < 10) ? 500 : 50;
146
      window.addEventListener('resize', function () {
147
        setTimeout(function(){
148
          self.updateAffix()
149
        },dl);
150
      }, false);
151

    
152
    }
153
  };
154

    
155
  // AFFIX DATA API
156
  // =================
157
  var Affixes = document.querySelectorAll('[data-spy="affix"]'), i = 0, afl = Affixes.length;
158
  for (i;i<afl;i++) {
159
    var item = Affixes[i], options = {};
160
      options.offsetTop    = item.getAttribute('data-offset-top');
161
      options.offsetBottom  = item.getAttribute('data-offset-bottom');
162
      options.target      = item.getAttribute('data-target');
163

    
164
    if ( item && (options.offsetTop !== null || options.offsetBottom !== null || options.target !== null) ) { //don't do anything unless we have something valid to pin
165
      new Affix(item, options);
166
    }
167
  }
168

    
169
  return Affix;
170
});
(1-1/17)