Project

General

Profile

1
/*! UIkit 2.27.5 | http://www.getuikit.com | (c) 2014 YOOtheme | MIT License */
2
(function(addon) {
3

    
4
    var component;
5

    
6
    if (window.UIkit2) {
7
        component = addon(UIkit2);
8
    }
9

    
10
    if (typeof define == 'function' && define.amd) {
11
        define('uikit-sticky', ['uikit'], function(){
12
            return component || addon(UIkit2);
13
        });
14
    }
15

    
16
})(function(UI){
17

    
18
    "use strict";
19

    
20
    var $win         = UI.$win,
21
        $doc         = UI.$doc,
22
        sticked      = [],
23
        direction    = 1;
24

    
25
    UI.component('sticky', {
26

    
27
        defaults: {
28
            top          : 0,
29
            bottom       : 0,
30
            animation    : '',
31
            clsinit      : 'uk-sticky-init',
32
            clsactive    : 'uk-active',
33
            clsinactive  : '',
34
            getWidthFrom : '',
35
            showup       : false,
36
            boundary     : false,
37
            media        : false,
38
            target       : false,
39
            disabled     : false
40
        },
41

    
42
        boot: function() {
43

    
44
            // should be more efficient than using $win.scroll(checkscrollposition):
45
            UI.$doc.on('scrolling.uk.document', function(e, data) {
46
                if (!data || !data.dir) return;
47
                direction = data.dir.y;
48
                checkscrollposition();
49
            });
50

    
51
            UI.$win.on('resize orientationchange', UI.Utils.debounce(function() {
52

    
53
                if (!sticked.length) return;
54

    
55
                for (var i = 0; i < sticked.length; i++) {
56
                    sticked[i].reset(true);
57
                    sticked[i].self.computeWrapper();
58
                }
59

    
60
                checkscrollposition();
61
            }, 100));
62

    
63
            // init code
64
            UI.ready(function(context) {
65

    
66
                setTimeout(function(){
67

    
68
                    UI.$('[data-uk-sticky]', context).each(function(){
69

    
70
                        var $ele = UI.$(this);
71

    
72
                        if (!$ele.data('sticky')) {
73
                            UI.sticky($ele, UI.Utils.options($ele.attr('data-uk-sticky')));
74
                        }
75
                    });
76

    
77
                    checkscrollposition();
78
                }, 0);
79
            });
80
        },
81

    
82
        init: function() {
83

    
84
            var boundary = this.options.boundary, boundtoparent;
85

    
86
            this.wrapper = this.element.wrap('<div class="uk-sticky-placeholder"></div>').parent();
87
            this.computeWrapper();
88
            this.wrapper.css({
89
                'margin-top'    : this.element.css('margin-top'),
90
                'margin-bottom' : this.element.css('margin-bottom'),
91
                'margin-left'   : this.element.css('margin-left'),
92
                'margin-right'  : this.element.css('margin-right')
93
            })
94
            this.element.css('margin', 0);
95

    
96
            if (boundary) {
97

    
98
                if (boundary === true || boundary[0] === '!') {
99

    
100
                    boundary      = boundary === true ? this.wrapper.parent() : this.wrapper.closest(boundary.substr(1));
101
                    boundtoparent = true;
102

    
103
                } else if (typeof boundary === "string") {
104
                    boundary = UI.$(boundary);
105
                }
106
            }
107

    
108
            this.sticky = {
109
                self          : this,
110
                options       : this.options,
111
                element       : this.element,
112
                currentTop    : null,
113
                wrapper       : this.wrapper,
114
                init          : false,
115
                getWidthFrom  : UI.$(this.options.getWidthFrom || this.wrapper),
116
                boundary      : boundary,
117
                boundtoparent : boundtoparent,
118
                top           : 0,
119
                calcTop       : function() {
120

    
121
                    var top = this.options.top;
122

    
123
                    // dynamic top parameter
124
                    if (this.options.top && typeof(this.options.top) == 'string') {
125

    
126
                        // e.g. 50vh
127
                        if (this.options.top.match(/^(-|)(\d+)vh$/)) {
128
                            top = window.innerHeight * parseInt(this.options.top, 10)/100;
129
                        // e.g. #elementId, or .class-1,class-2,.class-3 (first found is used)
130
                        } else {
131

    
132
                            var topElement = UI.$(this.options.top).first();
133

    
134
                            if (topElement.length && topElement.is(':visible')) {
135
                                top = -1 * ((topElement.offset().top + topElement.outerHeight()) - this.wrapper.offset().top);
136
                            }
137
                        }
138

    
139
                    }
140

    
141
                    this.top = top;
142
                },
143

    
144
                reset: function(force) {
145

    
146
                    this.calcTop();
147

    
148
                    var finalize = function() {
149
                        this.element.css({position:'', top:'', width:'', left:'', margin:'0'});
150
                        this.element.removeClass([this.options.animation, 'uk-animation-reverse', this.options.clsactive].join(' '));
151
                        this.element.addClass(this.options.clsinactive);
152
                        this.element.trigger('inactive.uk.sticky');
153

    
154
                        this.currentTop = null;
155
                        this.animate    = false;
156

    
157
                    }.bind(this);
158

    
159

    
160
                    if (!force && this.options.animation && UI.support.animation && !UI.Utils.isInView(this.wrapper)) {
161

    
162
                        this.animate = true;
163

    
164
                        this.element.removeClass(this.options.animation).one(UI.support.animation.end, function(){
165
                            finalize();
166
                        }).width(); // force redraw
167

    
168
                        this.element.addClass(this.options.animation+' '+'uk-animation-reverse');
169
                    } else {
170
                        finalize();
171
                    }
172
                },
173

    
174
                check: function() {
175

    
176
                    if (this.options.disabled) {
177
                        return false;
178
                    }
179

    
180
                    if (this.options.media) {
181

    
182
                        switch(typeof(this.options.media)) {
183
                            case 'number':
184
                                if (window.innerWidth < this.options.media) {
185
                                    return false;
186
                                }
187
                                break;
188
                            case 'string':
189
                                if (window.matchMedia && !window.matchMedia(this.options.media).matches) {
190
                                    return false;
191
                                }
192
                                break;
193
                        }
194
                    }
195

    
196
                    var scrollTop      = $win.scrollTop(),
197
                        documentHeight = $doc.height(),
198
                        dwh            = documentHeight - window.innerHeight,
199
                        extra          = (scrollTop > dwh) ? dwh - scrollTop : 0,
200
                        elementTop     = this.wrapper.offset().top,
201
                        etse           = elementTop - this.top - extra,
202
                        active         = (scrollTop  >= etse);
203

    
204
                    if (active && this.options.showup) {
205

    
206
                        // set inactiv if scrolling down
207
                        if (direction == 1) {
208
                            active = false;
209
                        }
210

    
211
                        // set inactive when wrapper is still in view
212
                        if (direction == -1 && !this.element.hasClass(this.options.clsactive) && UI.Utils.isInView(this.wrapper)) {
213
                            active = false;
214
                        }
215
                    }
216

    
217
                    return active;
218
                }
219
            };
220

    
221
            this.sticky.calcTop();
222

    
223
            sticked.push(this.sticky);
224
        },
225

    
226
        update: function() {
227
            checkscrollposition(this.sticky);
228
        },
229

    
230
        enable: function() {
231
            this.options.disabled = false;
232
            this.update();
233
        },
234

    
235
        disable: function(force) {
236
            this.options.disabled = true;
237
            this.sticky.reset(force);
238
        },
239

    
240
        computeWrapper: function() {
241

    
242
            this.wrapper.css({
243
                'height'        : ['absolute','fixed'].indexOf(this.element.css('position')) == -1 ? this.element.outerHeight() : '',
244
                'float'         : this.element.css('float') != 'none' ? this.element.css('float') : ''
245
            });
246

    
247
            if (this.element.css('position') == 'fixed') {
248
                this.element.css({
249
                    width: this.sticky.getWidthFrom.length ? this.sticky.getWidthFrom.width() : this.element.width()
250
                });
251
            }
252
        }
253
    });
254

    
255
    function checkscrollposition(direction) {
256

    
257
        var stickies = arguments.length ? arguments : sticked;
258

    
259
        if (!stickies.length || $win.scrollTop() < 0) return;
260

    
261
        var scrollTop       = $win.scrollTop(),
262
            documentHeight  = $doc.height(),
263
            windowHeight    = $win.height(),
264
            dwh             = documentHeight - windowHeight,
265
            extra           = (scrollTop > dwh) ? dwh - scrollTop : 0,
266
            newTop, containerBottom, stickyHeight, sticky;
267

    
268
        for (var i = 0; i < stickies.length; i++) {
269

    
270
            sticky = stickies[i];
271

    
272
            if (!sticky.element.is(':visible') || sticky.animate) {
273
                continue;
274
            }
275

    
276
            if (!sticky.check()) {
277

    
278
                if (sticky.currentTop !== null) {
279
                    sticky.reset();
280
                }
281

    
282
            } else {
283

    
284
                if (sticky.top < 0) {
285
                    newTop = 0;
286
                } else {
287
                    stickyHeight = sticky.element.outerHeight();
288
                    newTop = documentHeight - stickyHeight - sticky.top - sticky.options.bottom - scrollTop - extra;
289
                    newTop = newTop < 0 ? newTop + sticky.top : sticky.top;
290
                }
291

    
292
                if (sticky.boundary && sticky.boundary.length) {
293

    
294
                    var bTop = sticky.boundary.offset().top;
295

    
296
                    if (sticky.boundtoparent) {
297
                        containerBottom = documentHeight - (bTop + sticky.boundary.outerHeight()) + parseInt(sticky.boundary.css('padding-bottom'));
298
                    } else {
299
                        containerBottom = documentHeight - bTop;
300
                    }
301

    
302
                    newTop = (scrollTop + stickyHeight) > (documentHeight - containerBottom - (sticky.top < 0 ? 0 : sticky.top)) ? (documentHeight - containerBottom) - (scrollTop + stickyHeight) : newTop;
303
                }
304

    
305

    
306
                if (sticky.currentTop != newTop) {
307

    
308
                    sticky.element.css({
309
                        position : 'fixed',
310
                        top      : newTop,
311
                        width    : sticky.getWidthFrom.length ? sticky.getWidthFrom.width() : sticky.element.width()
312
                    });
313

    
314
                    if (!sticky.init) {
315

    
316
                        sticky.element.addClass(sticky.options.clsinit);
317

    
318
                        if (location.hash && scrollTop > 0 && sticky.options.target) {
319

    
320
                            var $target = UI.$(location.hash);
321

    
322
                            if ($target.length) {
323

    
324
                                setTimeout((function($target, sticky){
325

    
326
                                    return function() {
327

    
328
                                        sticky.element.width(); // force redraw
329

    
330
                                        var offset       = $target.offset(),
331
                                            maxoffset    = offset.top + $target.outerHeight(),
332
                                            stickyOffset = sticky.element.offset(),
333
                                            stickyHeight = sticky.element.outerHeight(),
334
                                            stickyMaxOffset = stickyOffset.top + stickyHeight;
335

    
336
                                        if (stickyOffset.top < maxoffset && offset.top < stickyMaxOffset) {
337
                                            scrollTop = offset.top - stickyHeight - sticky.options.target;
338
                                            window.scrollTo(0, scrollTop);
339
                                        }
340
                                    };
341

    
342
                                })($target, sticky), 0);
343
                            }
344
                        }
345
                    }
346

    
347
                    sticky.element.addClass(sticky.options.clsactive).removeClass(sticky.options.clsinactive);
348
                    sticky.element.trigger('active.uk.sticky');
349
                    sticky.element.css('margin', '');
350

    
351
                    if (sticky.options.animation && sticky.init && !UI.Utils.isInView(sticky.wrapper)) {
352
                        sticky.element.addClass(sticky.options.animation);
353
                    }
354

    
355
                    sticky.currentTop = newTop;
356
                }
357
            }
358

    
359
            sticky.init = true;
360
        }
361
    }
362

    
363
    return UI.sticky;
364
});
(39-39/46)