PageSourceSearch

https://haber-brandner.de/metall/wp-content/themes/one-page-express/assets/js/libs/fixto.js?ver=1.3.20

js haber-brandner.de collected 2026-09-25 10:15:39 UTC 26,865 bytes, 781 lines download raw bytes

1var fixto = (function ($, window, document) {
2
3    // Start Computed Style. Please do not modify this module here. Modify it from its own repo. See address below.
4
5    /*! Computed Style - v0.1.0 - 2012-07-19
6     * https://github.com/bbarakaci/computed-style
7     * Copyright (c) 2012 Burak Barakaci; Licensed MIT */
8    var computedStyle = (function () {
9        var computedStyle = {
10            getAll: function (element) {
11                return document.defaultView.getComputedStyle(element);
12            },
13            get: function (element, name) {
14                return this.getAll(element)[name];
15            },
16            toFloat: function (value) {
17                return parseFloat(value, 10) || 0;
18            },
19            getFloat: function (element, name) {
20                return this.toFloat(this.get(element, name));
21            },
22            _getAllCurrentStyle: function (element) {
23                return element.currentStyle;
24            }
25        };
26
27        if (document.documentElement.currentStyle) {
28            computedStyle.getAll = computedStyle._getAllCurrentStyle;
29        }
30
31        return computedStyle;
32
33    }());
34
35    // End Computed Style. Modify whatever you want to.
36
37    var mimicNode = (function () {
38        /*
39        Class Mimic Node
40        Dependency : Computed Style
41        Tries to mimick a dom node taking his styles, dimensions. May go to his repo if gets mature.
42        */
43
44        function MimicNode(element) {
45            this.element = element;
46            this.replacer = document.createElement('div');
47            this.replacer.style.visibility = 'hidden';
48            this.hide();
49            element.parentNode.insertBefore(this.replacer, element);
50        }
51
52        MimicNode.prototype = {
53            replace: function () {
54                var rst = this.replacer.style;
55                var styles = computedStyle.getAll(this.element);
56
57                // rst.width = computedStyle.width(this.element) + 'px';
58                // rst.height = this.element.offsetHeight + 'px';
59
60                // Setting offsetWidth
61                rst.width = this._width();
62                rst.height = this._height();
63
64                // Adopt margins
65                rst.marginTop = styles.marginTop;
66                rst.marginBottom = styles.marginBottom;
67                rst.marginLeft = styles.marginLeft;
68                rst.marginRight = styles.marginRight;
69
70                // Adopt positioning
71                rst.cssFloat = styles.cssFloat;
72                rst.styleFloat = styles.styleFloat; //ie8;
73                rst.position = styles.position;
74                rst.top = styles.top;
75                rst.right = styles.right;
76                rst.bottom = styles.bottom;
77                rst.left = styles.left;
78                // rst.borderStyle = styles.borderStyle;
79
80                rst.display = styles.display;
81
82            },
83
84            hide: function () {
85                this.replacer.style.display = 'none';
86            },
87
88            _width: function () {
89                return this.element.getBoundingClientRect().width + 'px';
90            },
91
92            _widthOffset: function () {
93                return this.element.offsetWidth + 'px';
94            },
95
96            _height: function () {
97                return jQuery(this.element).outerHeight() + 'px';
98            },
99
100            _heightOffset: function () {
101                return this.element.offsetHeight + 'px';
102            },
103
104            destroy: function () {
105                $(this.replacer).remove();
106
107                // set properties to null to break references
108                for (var prop in this) {
109                    if (this.hasOwnProperty(prop)) {
110                        this[prop] = null;
111                    }
112                }
113            }
114        };
115
116        var bcr = document.documentElement.getBoundingClientRect();
117        if (!bcr.width) {
118            MimicNode.prototype._width = MimicNode.prototype._widthOffset;
119            MimicNode.prototype._height = MimicNode.prototype._heightOffset;
120        }
121
122        return {
123            MimicNode: MimicNode,
124            computedStyle: computedStyle
125        };
126    }());
127
128    // Class handles vendor prefixes
129    function Prefix() {
130        // Cached vendor will be stored when it is detected
131        this._vendor = null;
132
133        //this._dummy = document.createElement('div');
134    }
135
136    Prefix.prototype = {
137
138        _vendors: {
139            webkit: {
140                cssPrefix: '-webkit-',
141                jsPrefix: 'Webkit'
142            },
143            moz: {
144                cssPrefix: '-moz-',
145                jsPrefix: 'Moz'
146            },
147            ms: {
148                cssPrefix: '-ms-',
149                jsPrefix: 'ms'
150            },
151            opera: {
152                cssPrefix: '-o-',
153                jsPrefix: 'O'
154            }
155        },
156
157        _prefixJsProperty: function (vendor, prop) {
158            return vendor.jsPrefix + prop[0].toUpperCase() + prop.substr(1);
159        },
160
161        _prefixValue: function (vendor, value) {
162            return vendor.cssPrefix + value;
163        },
164
165        _valueSupported: function (prop, value, dummy) {
166            // IE8 will throw Illegal Argument when you attempt to set a not supported value.
167            try {
168                dummy.style[prop] = value;
169                return dummy.style[prop] === value;
170            } catch (er) {
171                return false;
172            }
173        },
174
175        /**
176         * Returns true if the property is supported
177         * @param {string} prop Property name
178         * @returns {boolean}
179         */
180        propertySupported: function (prop) {
181            // Supported property will return either inine style value or an empty string.
182            // Undefined means property is not supported.
183            return document.documentElement.style[prop] !== undefined;
184        },
185
186        /**
187         * Returns prefixed property name for js usage
188         * @param {string} prop Property name
189         * @returns {string|null}
190         */
191        getJsProperty: function (prop) {
192            // Try native property name first.
193            if (this.propertySupported(prop)) {
194                return prop;
195            }
196
197            // Prefix it if we know the vendor already
198            if (this._vendor) {
199                return this._prefixJsProperty(this._vendor, prop);
200            }
201
202            // We don't know the vendor, try all the possibilities
203            var prefixed;
204            for (var vendor in this._vendors) {
205                prefixed = this._prefixJsProperty(this._vendors[vendor], prop);
206                if (this.propertySupported(prefixed)) {
207                    // Vendor detected. Cache it.
208                    this._vendor = this._vendors[vendor];
209                    return prefixed;
210                }
211            }
212
213            // Nothing worked
214            return null;
215        },
216
217        /**
218         * Returns supported css value for css property. Could be used to check support or get prefixed value string.
219         * @param {string} prop Property
220         * @param {string} value Value name
221         * @returns {string|null}
222         */
223        getCssValue: function (prop, value) {
224            // Create dummy element to test value
225            var dummy = document.createElement('div');
226
227            // Get supported property name
228            var jsProperty = this.getJsProperty(prop);
229
230            // Try unprefixed value
231            if (this._valueSupported(jsProperty, value, dummy)) {
232                return value;
233            }
234
235            var prefixedValue;
236
237            // If we know the vendor already try prefixed value
238            if (this._vendor) {
239                prefixedValue = this._prefixValue(this._vendor, value);
240                if (this._valueSupported(jsProperty, prefixedValue, dummy)) {
241                    return prefixedValue;
242                }
243            }
244
245            // Try all vendors
246            for (var vendor in this._vendors) {
247                prefixedValue = this._prefixValue(this._vendors[vendor], value);
248                if (this._valueSupported(jsProperty, prefixedValue, dummy)) {
249                    // Vendor detected. Cache it.
250                    this._vendor = this._vendors[vendor];
251                    return prefixedValue;
252                }
253            }
254            // No support for value
255            return null;
256        }
257    };
258
259    var prefix = new Prefix();
260
261    // We will need this frequently. Lets have it as a global until we encapsulate properly.
262    var transformJsProperty = prefix.getJsProperty('transform');
263
264    // Will hold if browser creates a positioning context for fixed elements.
265    var fixedPositioningContext;
266
267    // Checks if browser creates a positioning context for fixed elements.
268    // Transform rule will create a positioning context on browsers who follow the spec.
269    // Ie for example will fix it according to documentElement
270    // TODO: Other css rules also effects. perspective creates at chrome but not in firefox. transform-style preserve3d effects.
271    function checkFixedPositioningContextSupport() {
272        var support = false;
273        var parent = document.createElement('div');
274        var child = document.createElement('div');
275        parent.appendChild(child);
276        parent.style[transformJsProperty] = 'translate(0)';
277        // Make sure there is space on top of parent
278        parent.style.marginTop = '10px';
279        parent.style.visibility = 'hidden';
280        child.style.position = 'fixed';
281        child.style.top = 0;
282        document.body.appendChild(parent);
283        var rect = child.getBoundingClientRect();
284        // If offset top is greater than 0 meand transformed element created a positioning context.
285        if (rect.top > 0) {
286            support = true;
287        }
288        // Remove dummy content
289        document.body.removeChild(parent);
290        return support;
291    }
292
293    // It will return null if position sticky is not supported
294    var nativeStickyValue = prefix.getCssValue('position', 'sticky');
295
296    // It will return null if position fixed is not supported
297    var fixedPositionValue = prefix.getCssValue('position', 'fixed');
298
299    // Dirty business
300    var ie = navigator.appName === 'Microsoft Internet Explorer';
301    var ieversion;
302
303    if (ie) {
304        ieversion = parseFloat(navigator.appVersion.split("MSIE")[1]);
305    }
306
307    function FixTo(child, parent, options) {
308        this.child = child;
309        this._$child = $(child);
310        this.parent = parent;
311        this.options = {
312            className: 'fixto-fixed',
313            top: 0
314        };
315        this._setOptions(options);
316    }
317
318    FixTo.prototype = {
319        // Returns the total outerHeight of the elements passed to mind option. Will return 0 if none.
320        _mindtop: function () {
321            var top = 0;
322            if (this._$mind) {
323                var el;
324                var rect;
325                var height;
326                for (var i = 0, l = this._$mind.length; i < l; i++) {
327                    el = this._$mind[i];
328                    rect = el.getBoundingClientRect();
329                    if (rect.height) {
330                        top += rect.height;
331                    } else {
332                        var styles = computedStyle.getAll(el);
333                        top += el.offsetHeight + computedStyle.toFloat(styles.marginTop) + computedStyle.toFloat(styles.marginBottom);
334                    }
335                }
336            }
337            return top;
338        },
339
340        // Public method to stop the behaviour of this instance.
341        stop: function () {
342            this._stop();
343            this._running = false;
344        },
345
346        // Public method starts the behaviour of this instance.
347        start: function () {
348
349            // Start only if it is not running not to attach event listeners multiple times.
350            if (!this._running) {
351                this._start();
352                this._running = true;
353            }
354        },
355
356        //Public method to destroy fixto behaviour
357        destroy: function () {
358            this.stop();
359
360            this._destroy();
361
362            // Remove jquery data from the element
363            this._$child.removeData('fixto-instance');
364
365            // set properties to null to break references
366            for (var prop in this) {
367                if (this.hasOwnProperty(prop)) {
368                    this[prop] = null;
369                }
370            }
371        },
372
373        _setOptions: function (options) {
374            $.extend(this.options, options);
375            if (this.options.mind) {
376                this._$mind = $(this.options.mind);
377            }
378            if (this.options.zIndex) {
379                this.child.style.zIndex = this.options.zIndex;
380            }
381        },
382
383        setOptions: function (options) {
384            this._setOptions(options);
385            this.refresh();
386        },
387
388        // Methods could be implemented by subclasses
389
390        _stop: function () {
391
392        },
393
394        _start: function () {
395
396        },
397
398        _destroy: function () {
399
400        },
401
402        refresh: function () {
403
404        }
405    };
406
407    // Class FixToContainer
408    function FixToContainer(child, parent, options) {
409        FixTo.call(this, child, parent, options);
410        this._replacer = new mimicNode.MimicNode(child);
411        this._ghostNode = this._replacer.replacer;
412
413        this._saveStyles();
414
415        this._saveViewportHeight();
416
417        // Create anonymous functions and keep references to register and unregister events.
418        this._proxied_onscroll = this._bind(this._onscroll, this);
419        this._proxied_onresize = this._bind(this._onresize, this);
420
421        this.start();
422    }
423
424    FixToContainer.prototype = new FixTo();
425
426    $.extend(FixToContainer.prototype, {
427
428        // Returns an anonymous function that will call the given function in the given context
429        _bind: function (fn, context) {
430            return function () {
431                return fn.call(context);
432            };
433        },
434
435        // at ie8 maybe only in vm window resize event fires everytime an element is resized.
436        _toresize: ieversion === 8 ? document.documentElement : window,
437
438        _onscroll: function _onscroll() {
439            this._scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
440            this._parentBottom = (this.parent.offsetHeight + this._fullOffset('offsetTop', this.parent));
441
442            // if (this.options.mindBottomPadding !== false) {
443            //     this._parentBottom -= computedStyle.getFloat(this.parent, 'paddingBottom');
444            // }
445
446
447            // if (this.options.toBottom) {
448            //     this._fix();
449            //     this._adjust();
450            //     return
451            // }
452
453            // if (this.options.toBottom) {
454            //     this.options.top = this._viewportHeight - computedStyle.toFloat(computedStyle.getAll(this.child).height) - this.options.topSpacing;
455            // }
456
457            if (!this.fixed) {
458
459                var childStyles = computedStyle.getAll(this.child);
460
461                if ((
462                    this._scrollTop < this._parentBottom &&
463                    this._scrollTop > (this._fullOffset('offsetTop', this.child) - this.options.top - this._mindtop()) &&
464                    this._viewportHeight > (this.child.offsetHeight + computedStyle.toFloat(childStyles.marginTop) + computedStyle.toFloat(childStyles.marginBottom))
465                ) || this.options.toBottom) {
466
467                    this._fix();
468                    this._adjust();
469                }
470            } else {
471                if (this.options.toBottom) {
472                    if (this._scrollTop >= this._fullOffset('offsetTop', this._ghostNode)) {
473                        this._unfix();
474                        return;
475                    }
476
477                } else {
478                    if (this._scrollTop > this._parentBottom || this._scrollTop <= (this._fullOffset('offsetTop', this._ghostNode) - this.options.top - this._mindtop())) {
479                        this._unfix();
480                        return;
481                    }
482                }
483                this._adjust();
484            }
485        },
486
487        _adjust: function _adjust() {
488            var top = 0;
489            var mindTop = this._mindtop();
490            var diff = 0;
491            var childStyles = computedStyle.getAll(this.child);
492            var context = null;
493
494            if (fixedPositioningContext) {
495                // Get positioning context.
496                context = this._getContext();
497                if (context) {
498                    // There is a positioning context. Top should be according to the context.
499                    top = Math.abs(context.getBoundingClientRect().top);
500                }
501            }
502
503            diff = (this._parentBottom - this._scrollTop) - (this.child.offsetHeight + computedStyle.toFloat(childStyles.marginBottom) + mindTop + this.options.top);
504
505            if (diff > 0) {
506                diff = 0;
507            }
508
509            if (this.options.toBottom) {
510                // this.child.style.top = (diff + mindTop + top + this.options.top) - computedStyle.toFloat(childStyles.marginTop) + 'px';
511            } else {
512                var _top = this.options.top;
513                if (_top === 0) {
514                    _top = $('body').offset().top;
515                }
516
517                this.child.style.top = (diff + mindTop + top + _top) - computedStyle.toFloat(childStyles.marginTop) + 'px';
518            }
519        },
520
521        // Calculate cumulative offset of the element.
522        // Optionally according to context
523        _fullOffset: function _fullOffset(offsetName, elm, context) {
524            var offset = elm[offsetName];
525            var offsetParent = elm.offsetParent;
526
527            // Add offset of the ascendent tree until we reach to the document root or to the given context
528            while (offsetParent !== null && offsetParent !== context) {
529                offset = offset + offsetParent[offsetName];
530                offsetParent = offsetParent.offsetParent;
531            }
532
533            return offset;
534        },
535
536        // Get positioning context of the element.
537        // We know that the closest parent that a transform rule applied will create a positioning context.
538        _getContext: function () {
539            var parent;
540            var element = this.child;
541            var context = null;
542            var styles;
543
544            // Climb up the treee until reaching the context
545            while (!context) {
546                parent = element.parentNode;
547                if (parent === document.documentElement) {
548                    return null;
549                }
550
551                styles = computedStyle.getAll(parent);
552                // Element has a transform rule
553                if (styles[transformJsProperty] !== 'none') {
554                    context = parent;
555                    break;
556                }
557                element = parent;
558            }
559            return context;
560        },
561
562        _fix: function _fix() {
563            var child = this.child;
564            var childStyle = child.style;
565            var childStyles = computedStyle.getAll(child);
566            var left = child.getBoundingClientRect().left;
567            var width = childStyles.width;
568            this.options._original
569
570            this._saveStyles();
571
572            if (document.documentElement.currentStyle) {
573                // Function for ie<9. When hasLayout is not triggered in ie7, he will report currentStyle as auto, clientWidth as 0. Thus using offsetWidth.
574                // Opera also falls here
575
576                width = (child.offsetWidth)
577                if (childStyles.boxSizing !== "border-box") {
578                    width = width - (computedStyle.toFloat(childStyles.paddingLeft) + computedStyle.toFloat(childStyles.paddingRight) + computedStyle.toFloat(childStyles.borderLeftWidth) + computedStyle.toFloat(childStyles.borderRightWidth));
579                }
580
581                width += "px";
582
583            }
584
585            // Ie still fixes the container according to the viewport.
586            if (fixedPositioningContext) {
587                var context = this._getContext();
588                // if(context) {
589                //     // There is a positioning context. Left should be according to the context.
590                //     left = child.getBoundingClientRect().left - context.getBoundingClientRect().left;
591                // } else {
592                left = this._$child.offset().left;
593                // }
594            }
595
596            this._replacer.replace();
597
598            childStyle.left = /*left + "px"; */ (left - computedStyle.toFloat(childStyles.marginLeft)) + 'px';
599            childStyle.width = width;
600
601            childStyle.position = 'fixed';
602            if (this.options.toBottom) {
603                childStyle.top = "";
604                childStyle.bottom = this.options.top + computedStyle.toFloat(childStyles.marginBottom) + 'px';
605            } else {
606                childStyle.bottom = "";
607                var _top = this.options.top;
608
609                if (_top === 0) {
610                    _top = $('body').offset().top;
611                }
612                childStyle.top = this._mindtop() + _top - computedStyle.toFloat(childStyles.marginTop) + 'px';
613
614            }
615            this._$child.addClass(this.options.className);
616            this.fixed = true;
617            this._$child.trigger('fixto-added');
618        },
619
620        _unfix: function _unfix() {
621            var childStyle = this.child.style;
622            this._replacer.hide();
623            childStyle.position = this._childOriginalPosition;
624            childStyle.top = this._childOriginalTop;
625            childStyle.bottom = this._childOriginalBottom;
626            childStyle.width = this._childOriginalWidth;
627            childStyle.left = this._childOriginalLeft;
628            this._$child.removeClass(this.options.className);
629            this._$child.trigger('fixto-removed');
630            this.fixed = false;
631        },
632
633        _saveStyles: function () {
634            var childStyle = this.child.style;
635            this._childOriginalPosition = childStyle.position;
636            if (this.options.toBottom) {
637                this._childOriginalTop = "";
638                this._childOriginalBottom = childStyle.bottom;
639            } else {
640                this._childOriginalTop = childStyle.top;
641                this._childOriginalBottom = "";
642            }
643            this._childOriginalWidth = childStyle.width;
644            this._childOriginalLeft = childStyle.left;
645        },
646
647        _onresize: function () {
648            this.refresh();
649        },
650
651        _saveViewportHeight: function () {
652            // ie8 doesn't support innerHeight
653            this._viewportHeight = window.innerHeight || document.documentElement.clientHeight;
654        },
655
656        _stop: function () {
657            // Unfix the container immediately.
658            this._unfix();
659            // remove event listeners
660            $(window).unbind('scroll.fixto mousewheel', this._proxied_onscroll);
661            $(this._toresize).unbind('resize.fixto', this._proxied_onresize);
662        },
663
664        _start: function () {
665            // Trigger onscroll to have the effect immediately.
666            this._onscroll();
667
668            // Attach event listeners
669            $(window).bind('scroll.fixto mousewheel', this._proxied_onscroll);
670            $(this._toresize).bind('resize.fixto', this._proxied_onresize);
671        },
672
673        _destroy: function () {
674            // Destroy mimic node instance
675            this._replacer.destroy();
676        },
677
678        refresh: function () {
679            this._saveViewportHeight();
680            this._unfix();
681            this._onscroll();
682        }
683    });
684
685    function NativeSticky(child, parent, options) {
686        FixTo.call(this, child, parent, options);
687        this.start();
688    }
689
690    NativeSticky.prototype = new FixTo();
691
692    $.extend(NativeSticky.prototype, {
693        _start: function () {
694
695            var childStyles = computedStyle.getAll(this.child);
696
697            this._childOriginalPosition = childStyles.position;
698            this._childOriginalTop = childStyles.top;
699
700            this.child.style.position = nativeStickyValue;
701            this.refresh();
702        },
703
704        _stop: function () {
705            this.child.style.position = this._childOriginalPosition;
706            this.child.style.top = this._childOriginalTop;
707        },
708
709        refresh: function () {
710            this.child.style.top = this._mindtop() + this.options.top + 'px';
711        }
712    });
713
714
715
716    var fixTo = function fixTo(childElement, parentElement, options) {
717        if ((nativeStickyValue && !options) || (nativeStickyValue && options && options.useNativeSticky !== false)) {
718            // Position sticky supported and user did not disabled the usage of it.
719            return new NativeSticky(childElement, parentElement, options);
720        } else if (fixedPositionValue) {
721            // Position fixed supported
722
723            if (fixedPositioningContext === undefined) {
724                // We don't know yet if browser creates fixed positioning contexts. Check it.
725                fixedPositioningContext = checkFixedPositioningContextSupport();
726            }
727
728            return new FixToContainer(childElement, parentElement, options);
729        } else {
730            return 'Neither fixed nor sticky positioning supported';
731        }
732    };
733
734    /*
735    No support for ie lt 8
736    */
737
738    if (ieversion < 8) {
739        fixTo = function () {
740            return 'not supported';
741        };
742    }
743
744    // Let it be a jQuery Plugin
745    $.fn.fixTo = function (targetSelector, options) {
746
747        var $targets = $(targetSelector);
748
749        var i = 0;
750        return this.each(function () {
751
752            // Check the data of the element.
753            var instance = $(this).data('fixto-instance');
754
755            // If the element is not bound to an instance, create the instance and save it to elements data.
756            if (!instance) {
757                $(this).data('fixto-instance', fixTo(this, $targets[i], options));
758            } else {
759                // If we already have the instance here, expect that targetSelector parameter will be a string
760                // equal to a public methods name. Run the method on the instance without checking if
761                // it exists or it is a public method or not. Cause nasty errors when necessary.
762                var method = targetSelector;
763                instance[method].call(instance, options);
764            }
765            i++;
766        });
767    };
768
769    /*
770        Expose
771    */
772
773    return {
774        FixToContainer: FixToContainer,
775        fixTo: fixTo,
776        computedStyle: computedStyle,
777        mimicNode: mimicNode
778    };
779
780
781}(window.jQuery, window, document));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.