×

Welcome to TagMyCode

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