PageSourceSearch

https://www.elitis.com/_javascript/r2017/matchHeight.js

js elitis.com collected 2026-10-08 22:41:40 UTC 10,928 bytes, 364 lines download raw bytes

vendor: 10,928 bytes, lines 1-364
1/**
2* jquery.matchHeight.js master
3* http://brm.io/jquery-match-height/
4* License: MIT
5*/
6
7;(function($) {
8    /*
9    *  internal
10    */
11
12    var _previousResizeWidth = -1,
13        _updateTimeout = -1;
14
15    /*
16    *  _parse
17    *  value parse utility function
18    */
19
20    var _parse = function(value) {
21        // parse value and convert NaN to 0
22        return parseFloat(value) || 0;
23    };
24
25    /*
26    *  _rows
27    *  utility function returns array of jQuery selections representing each row
28    *  (as displayed after float wrapping applied by browser)
29    */
30
31    var _rows = function(elements) {
32        var tolerance = 1,
33            $elements = $(elements),
34            lastTop = null,
35            rows = [];
36
37        // group elements by their top position
38        $elements.each(function(){
39            var $that = $(this),
40                top = $that.offset().top - _parse($that.css('margin-top')),
41                lastRow = rows.length > 0 ? rows[rows.length - 1] : null;
42
43            if (lastRow === null) {
44                // first item on the row, so just push it
45                rows.push($that);
46            } else {
47                // if the row top is the same, add to the row group
48                if (Math.floor(Math.abs(lastTop - top)) <= tolerance) {
49                    rows[rows.length - 1] = lastRow.add($that);
50                } else {
51                    // otherwise start a new row group
52                    rows.push($that);
53                }
54            }
55
56            // keep track of the last row top
57            lastTop = top;
58        });
59
60        return rows;
61    };
62
63    /*
64    *  _parseOptions
65    *  handle plugin options
66    */
67
68    var _parseOptions = function(options) {
69        var opts = {
70            byRow: true,
71            property: 'height',
72            target: null,
73            remove: false
74        };
75
76        if (typeof options === 'object') {
77            return $.extend(opts, options);
78        }
79
80        if (typeof options === 'boolean') {
81            opts.byRow = options;
82        } else if (options === 'remove') {
83            opts.remove = true;
84        }
85
86        return opts;
87    };
88
89    /*
90    *  matchHeight
91    *  plugin definition
92    */
93
94    var matchHeight = $.fn.matchHeight = function(options) {
95        var opts = _parseOptions(options);
96
97        // handle remove
98        if (opts.remove) {
99            var that = this;
100
101            // remove fixed height from all selected elements
102            this.css(opts.property, '');
103
104            // remove selected elements from all groups
105            $.each(matchHeight._groups, function(key, group) {
106                group.elements = group.elements.not(that);
107            });
108
109            // TODO: cleanup empty groups
110
111            return this;
112        }
113
114        if (this.length <= 1 && !opts.target) {
115            return this;
116        }
117
118        // keep track of this group so we can re-apply later on load and resize events
119        matchHeight._groups.push({
120            elements: this,
121            options: opts
122        });
123
124        // match each element's height to the tallest element in the selection
125        matchHeight._apply(this, opts);
126
127        return this;
128    };
129
130    /*
131    *  plugin global options
132    */
133
134    matchHeight._groups = [];
135    matchHeight._throttle = 80;
136    matchHeight._maintainScroll = false;
137    matchHeight._beforeUpdate = null;
138    matchHeight._afterUpdate = null;
139    matchHeight._rows = _rows;
140
141    /*
142    *  matchHeight._apply
143    *  apply matchHeight to given elements
144    */
145
146    matchHeight._apply = function(elements, options) {
147        var opts = _parseOptions(options),
148            $elements = $(elements),
149            rows = [$elements];
150
151        // take note of scroll position
152        var scrollTop = $(window).scrollTop(),
153            htmlHeight = $('html').outerHeight(true);
154
155        // get hidden parents
156        var $hiddenParents = $elements.parents().filter(':hidden');
157
158        // cache the original inline style
159        $hiddenParents.each(function() {
160            var $that = $(this);
161            $that.data('style-cache', $that.attr('style'));
162        });
163
164        // temporarily must force hidden parents visible
165        $hiddenParents.css('display', 'block');
166
167        // get rows if using byRow, otherwise assume one row
168        if (opts.byRow && !opts.target) {
169
170            // must first force an arbitrary equal height so floating elements break evenly
171            $elements.each(function() {
172                var $that = $(this),
173                    display = $that.css('display');
174
175                // temporarily force a usable display value
176                if (display !== 'inline-block' && display !== 'inline-flex') {
177                    display = 'block';
178                }
179
180                // cache the original inline style
181                $that.data('style-cache', $that.attr('style'));
182
183                $that.css({
184                    'display': display,
185                    'padding-top': '0',
186                    'padding-bottom': '0',
187                    'margin-top': '0',
188                    'margin-bottom': '0',
189                    'border-top-width': '0',
190                    'border-bottom-width': '0',
191                    'height': '100px'
192                });
193            });
194
195            // get the array of rows (based on element top position)
196            rows = _rows($elements);
197
198            // revert original inline styles
199            $elements.each(function() {
200                var $that = $(this);
201                $that.attr('style', $that.data('style-cache') || '');
202            });
203        }
204
205        $.each(rows, function(key, row) {
206            var $row = $(row),
207                targetHeight = 0;
208
209            if (!opts.target) {
210                // skip apply to rows with only one item
211                if (opts.byRow && $row.length <= 1) {
212                    $row.css(opts.property, '');
213                    return;
214                }
215
216                // iterate the row and find the max height
217                $row.each(function(){
218                    var $that = $(this),
219                        display = $that.css('display');
220
221                    // temporarily force a usable display value
222                    if (display !== 'inline-block' && display !== 'inline-flex') {
223                        display = 'block';
224                    }
225
226                    // ensure we get the correct actual height (and not a previously set height value)
227                    var css = { 'display': display };
228                    css[opts.property] = '';
229                    $that.css(css);
230
231                    // find the max height (including padding, but not margin)
232                    if ($that.outerHeight(false) > targetHeight) {
233                        targetHeight = $that.outerHeight(false);
234                    }
235
236                    // revert display block
237                    $that.css('display', '');
238                });
239            } else {
240                // if target set, use the height of the target element
241                targetHeight = opts.target.outerHeight(false);
242            }
243
244            // iterate the row and apply the height to all elements
245            $row.each(function(){
246                var $that = $(this),
247                    verticalPadding = 0;
248
249                // don't apply to a target
250                if (opts.target && $that.is(opts.target)) {
251                    return;
252                }
253
254                // handle padding and border correctly (required when not using border-box)
255                if ($that.css('box-sizing') !== 'border-box') {
256                    verticalPadding += _parse($that.css('border-top-width')) + _parse($that.css('border-bottom-width'));
257                    verticalPadding += _parse($that.css('padding-top')) + _parse($that.css('padding-bottom'));
258                }
259
260                // set the height (accounting for padding and border)
261                $that.css(opts.property, (targetHeight - verticalPadding) + 'px');
262            });
263        });
264
265        // revert hidden parents
266        $hiddenParents.each(function() {
267            var $that = $(this);
268            $that.attr('style', $that.data('style-cache') || null);
269        });
270
271        // restore scroll position if enabled
272        if (matchHeight._maintainScroll) {
273            $(window).scrollTop((scrollTop / htmlHeight) * $('html').outerHeight(true));
274        }
275
276        return this;
277    };
278
279    /*
280    *  matchHeight._applyDataApi
281    *  applies matchHeight to all elements with a data-match-height attribute
282    */
283
284    matchHeight._applyDataApi = function() {
285        var groups = {};
286
287        // generate groups by their groupId set by elements using data-match-height
288        $('[data-match-height], [data-mh]').each(function() {
289            var $this = $(this),
290                groupId = $this.attr('data-mh') || $this.attr('data-match-height');
291
292            if (groupId in groups) {
293                groups[groupId] = groups[groupId].add($this);
294            } else {
295                groups[groupId] = $this;
296            }
297        });
298
299        // apply matchHeight to each group
300        $.each(groups, function() {
301            this.matchHeight(true);
302        });
303    };
304
305    /*
306    *  matchHeight._update
307    *  updates matchHeight on all current groups with their correct options
308    */
309
310    var _update = function(event) {
311        if (matchHeight._beforeUpdate) {
312            matchHeight._beforeUpdate(event, matchHeight._groups);
313        }
314
315        $.each(matchHeight._groups, function() {
316            matchHeight._apply(this.elements, this.options);
317        });
318
319        if (matchHeight._afterUpdate) {
320            matchHeight._afterUpdate(event, matchHeight._groups);
321        }
322    };
323
324    matchHeight._update = function(throttle, event) {
325        // prevent update if fired from a resize event
326        // where the viewport width hasn't actually changed
327        // fixes an event looping bug in IE8
328        if (event && event.type === 'resize') {
329            var windowWidth = $(window).width();
330            if (windowWidth === _previousResizeWidth) {
331                return;
332            }
333            _previousResizeWidth = windowWidth;
334        }
335
336        // throttle updates
337        if (!throttle) {
338            _update(event);
339        } else if (_updateTimeout === -1) {
340            _updateTimeout = setTimeout(function() {
341                _update(event);
342                _updateTimeout = -1;
343            }, matchHeight._throttle);
344        }
345    };
346
347    /*
348    *  bind events
349    */
350
351    // apply on DOM ready event
352    $(matchHeight._applyDataApi);
353
354    // update heights on load and resize events
355    $(window).bind('load', function(event) {
356        matchHeight._update(false, event);
357    });
358
359    // throttled update heights on resize events
360    $(window).bind('resize orientationchange', function(event) {
361        matchHeight._update(true, event);
362    });
363
364})(jQuery);

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.