summaryrefslogtreecommitdiffstats
path: root/jquery.matchHeight.js
diff options
context:
space:
mode:
authorliabru <liabru@brm.io>2015-10-17 18:40:51 +0100
committerliabru <liabru@brm.io>2015-10-17 18:40:51 +0100
commitca926de04f830c401daf6d16db1359e982d3eda8 (patch)
treea4824ba1558964b9c10cf9ca11a706a51d0d5098 /jquery.matchHeight.js
parent91e50ad957b99dc30fab31e6aeb04f8669a63c10 (diff)
downloadjquery-match-height-ca926de04f830c401daf6d16db1359e982d3eda8.zip
jquery-match-height-ca926de04f830c401daf6d16db1359e982d3eda8.tar.gz
jquery-match-height-ca926de04f830c401daf6d16db1359e982d3eda8.tar.bz2
added gulpfile, jasmine test specs, browser test runner, selenium test runner
Diffstat (limited to 'jquery.matchHeight.js')
-rw-r--r--jquery.matchHeight.js727
1 files changed, 364 insertions, 363 deletions
diff --git a/jquery.matchHeight.js b/jquery.matchHeight.js
index 392bd1a..99310c3 100644
--- a/jquery.matchHeight.js
+++ b/jquery.matchHeight.js
@@ -1,363 +1,364 @@
-/**
-* jquery.matchHeight.js master
-* http://brm.io/jquery-match-height/
-* License: MIT
-*/
-
-;(function($) {
- /*
- * internal
- */
-
- var _previousResizeWidth = -1,
- _updateTimeout = -1;
-
- /*
- * _parse
- * value parse utility function
- */
-
- var _parse = function(value) {
- // parse value and convert NaN to 0
- return parseFloat(value) || 0;
- };
-
- /*
- * _rows
- * utility function returns array of jQuery selections representing each row
- * (as displayed after float wrapping applied by browser)
- */
-
- var _rows = function(elements) {
- var tolerance = 1,
- $elements = $(elements),
- lastTop = null,
- rows = [];
-
- // group elements by their top position
- $elements.each(function(){
- var $that = $(this),
- top = $that.offset().top - _parse($that.css('margin-top')),
- lastRow = rows.length > 0 ? rows[rows.length - 1] : null;
-
- if (lastRow === null) {
- // first item on the row, so just push it
- rows.push($that);
- } else {
- // if the row top is the same, add to the row group
- if (Math.floor(Math.abs(lastTop - top)) <= tolerance) {
- rows[rows.length - 1] = lastRow.add($that);
- } else {
- // otherwise start a new row group
- rows.push($that);
- }
- }
-
- // keep track of the last row top
- lastTop = top;
- });
-
- return rows;
- };
-
- /*
- * _parseOptions
- * handle plugin options
- */
-
- var _parseOptions = function(options) {
- var opts = {
- byRow: true,
- property: 'height',
- target: null,
- remove: false
- };
-
- if (typeof options === 'object') {
- return $.extend(opts, options);
- }
-
- if (typeof options === 'boolean') {
- opts.byRow = options;
- } else if (options === 'remove') {
- opts.remove = true;
- }
-
- return opts;
- };
-
- /*
- * matchHeight
- * plugin definition
- */
-
- var matchHeight = $.fn.matchHeight = function(options) {
- var opts = _parseOptions(options);
-
- // handle remove
- if (opts.remove) {
- var that = this;
-
- // remove fixed height from all selected elements
- this.css(opts.property, '');
-
- // remove selected elements from all groups
- $.each(matchHeight._groups, function(key, group) {
- group.elements = group.elements.not(that);
- });
-
- // TODO: cleanup empty groups
-
- return this;
- }
-
- if (this.length <= 1 && !opts.target) {
- return this;
- }
-
- // keep track of this group so we can re-apply later on load and resize events
- matchHeight._groups.push({
- elements: this,
- options: opts
- });
-
- // match each element's height to the tallest element in the selection
- matchHeight._apply(this, opts);
-
- return this;
- };
-
- /*
- * plugin global options
- */
-
- matchHeight._groups = [];
- matchHeight._throttle = 80;
- matchHeight._maintainScroll = false;
- matchHeight._beforeUpdate = null;
- matchHeight._afterUpdate = null;
-
- /*
- * matchHeight._apply
- * apply matchHeight to given elements
- */
-
- matchHeight._apply = function(elements, options) {
- var opts = _parseOptions(options),
- $elements = $(elements),
- rows = [$elements];
-
- // take note of scroll position
- var scrollTop = $(window).scrollTop(),
- htmlHeight = $('html').outerHeight(true);
-
- // get hidden parents
- var $hiddenParents = $elements.parents().filter(':hidden');
-
- // cache the original inline style
- $hiddenParents.each(function() {
- var $that = $(this);
- $that.data('style-cache', $that.attr('style'));
- });
-
- // temporarily must force hidden parents visible
- $hiddenParents.css('display', 'block');
-
- // get rows if using byRow, otherwise assume one row
- if (opts.byRow && !opts.target) {
-
- // must first force an arbitrary equal height so floating elements break evenly
- $elements.each(function() {
- var $that = $(this),
- display = $that.css('display');
-
- // temporarily force a usable display value
- if (display !== 'inline-block' && display !== 'inline-flex') {
- display = 'block';
- }
-
- // cache the original inline style
- $that.data('style-cache', $that.attr('style'));
-
- $that.css({
- 'display': display,
- 'padding-top': '0',
- 'padding-bottom': '0',
- 'margin-top': '0',
- 'margin-bottom': '0',
- 'border-top-width': '0',
- 'border-bottom-width': '0',
- 'height': '100px'
- });
- });
-
- // get the array of rows (based on element top position)
- rows = _rows($elements);
-
- // revert original inline styles
- $elements.each(function() {
- var $that = $(this);
- $that.attr('style', $that.data('style-cache') || '');
- });
- }
-
- $.each(rows, function(key, row) {
- var $row = $(row),
- targetHeight = 0;
-
- if (!opts.target) {
- // skip apply to rows with only one item
- if (opts.byRow && $row.length <= 1) {
- $row.css(opts.property, '');
- return;
- }
-
- // iterate the row and find the max height
- $row.each(function(){
- var $that = $(this),
- display = $that.css('display');
-
- // temporarily force a usable display value
- if (display !== 'inline-block' && display !== 'inline-flex') {
- display = 'block';
- }
-
- // ensure we get the correct actual height (and not a previously set height value)
- var css = { 'display': display };
- css[opts.property] = '';
- $that.css(css);
-
- // find the max height (including padding, but not margin)
- if ($that.outerHeight(false) > targetHeight) {
- targetHeight = $that.outerHeight(false);
- }
-
- // revert display block
- $that.css('display', '');
- });
- } else {
- // if target set, use the height of the target element
- targetHeight = opts.target.outerHeight(false);
- }
-
- // iterate the row and apply the height to all elements
- $row.each(function(){
- var $that = $(this),
- verticalPadding = 0;
-
- // don't apply to a target
- if (opts.target && $that.is(opts.target)) {
- return;
- }
-
- // handle padding and border correctly (required when not using border-box)
- if ($that.css('box-sizing') !== 'border-box') {
- verticalPadding += _parse($that.css('border-top-width')) + _parse($that.css('border-bottom-width'));
- verticalPadding += _parse($that.css('padding-top')) + _parse($that.css('padding-bottom'));
- }
-
- // set the height (accounting for padding and border)
- $that.css(opts.property, (targetHeight - verticalPadding) + 'px');
- });
- });
-
- // revert hidden parents
- $hiddenParents.each(function() {
- var $that = $(this);
- $that.attr('style', $that.data('style-cache') || null);
- });
-
- // restore scroll position if enabled
- if (matchHeight._maintainScroll) {
- $(window).scrollTop((scrollTop / htmlHeight) * $('html').outerHeight(true));
- }
-
- return this;
- };
-
- /*
- * matchHeight._applyDataApi
- * applies matchHeight to all elements with a data-match-height attribute
- */
-
- matchHeight._applyDataApi = function() {
- var groups = {};
-
- // generate groups by their groupId set by elements using data-match-height
- $('[data-match-height], [data-mh]').each(function() {
- var $this = $(this),
- groupId = $this.attr('data-mh') || $this.attr('data-match-height');
-
- if (groupId in groups) {
- groups[groupId] = groups[groupId].add($this);
- } else {
- groups[groupId] = $this;
- }
- });
-
- // apply matchHeight to each group
- $.each(groups, function() {
- this.matchHeight(true);
- });
- };
-
- /*
- * matchHeight._update
- * updates matchHeight on all current groups with their correct options
- */
-
- var _update = function(event) {
- if (matchHeight._beforeUpdate) {
- matchHeight._beforeUpdate(event, matchHeight._groups);
- }
-
- $.each(matchHeight._groups, function() {
- matchHeight._apply(this.elements, this.options);
- });
-
- if (matchHeight._afterUpdate) {
- matchHeight._afterUpdate(event, matchHeight._groups);
- }
- };
-
- matchHeight._update = function(throttle, event) {
- // prevent update if fired from a resize event
- // where the viewport width hasn't actually changed
- // fixes an event looping bug in IE8
- if (event && event.type === 'resize') {
- var windowWidth = $(window).width();
- if (windowWidth === _previousResizeWidth) {
- return;
- }
- _previousResizeWidth = windowWidth;
- }
-
- // throttle updates
- if (!throttle) {
- _update(event);
- } else if (_updateTimeout === -1) {
- _updateTimeout = setTimeout(function() {
- _update(event);
- _updateTimeout = -1;
- }, matchHeight._throttle);
- }
- };
-
- /*
- * bind events
- */
-
- // apply on DOM ready event
- $(matchHeight._applyDataApi);
-
- // update heights on load and resize events
- $(window).bind('load', function(event) {
- matchHeight._update(false, event);
- });
-
- // throttled update heights on resize events
- $(window).bind('resize orientationchange', function(event) {
- matchHeight._update(true, event);
- });
-
-})(jQuery);
+/**
+* jquery.matchHeight.js master
+* http://brm.io/jquery-match-height/
+* License: MIT
+*/
+
+;(function($) {
+ /*
+ * internal
+ */
+
+ var _previousResizeWidth = -1,
+ _updateTimeout = -1;
+
+ /*
+ * _parse
+ * value parse utility function
+ */
+
+ var _parse = function(value) {
+ // parse value and convert NaN to 0
+ return parseFloat(value) || 0;
+ };
+
+ /*
+ * _rows
+ * utility function returns array of jQuery selections representing each row
+ * (as displayed after float wrapping applied by browser)
+ */
+
+ var _rows = function(elements) {
+ var tolerance = 1,
+ $elements = $(elements),
+ lastTop = null,
+ rows = [];
+
+ // group elements by their top position
+ $elements.each(function(){
+ var $that = $(this),
+ top = $that.offset().top - _parse($that.css('margin-top')),
+ lastRow = rows.length > 0 ? rows[rows.length - 1] : null;
+
+ if (lastRow === null) {
+ // first item on the row, so just push it
+ rows.push($that);
+ } else {
+ // if the row top is the same, add to the row group
+ if (Math.floor(Math.abs(lastTop - top)) <= tolerance) {
+ rows[rows.length - 1] = lastRow.add($that);
+ } else {
+ // otherwise start a new row group
+ rows.push($that);
+ }
+ }
+
+ // keep track of the last row top
+ lastTop = top;
+ });
+
+ return rows;
+ };
+
+ /*
+ * _parseOptions
+ * handle plugin options
+ */
+
+ var _parseOptions = function(options) {
+ var opts = {
+ byRow: true,
+ property: 'height',
+ target: null,
+ remove: false
+ };
+
+ if (typeof options === 'object') {
+ return $.extend(opts, options);
+ }
+
+ if (typeof options === 'boolean') {
+ opts.byRow = options;
+ } else if (options === 'remove') {
+ opts.remove = true;
+ }
+
+ return opts;
+ };
+
+ /*
+ * matchHeight
+ * plugin definition
+ */
+
+ var matchHeight = $.fn.matchHeight = function(options) {
+ var opts = _parseOptions(options);
+
+ // handle remove
+ if (opts.remove) {
+ var that = this;
+
+ // remove fixed height from all selected elements
+ this.css(opts.property, '');
+
+ // remove selected elements from all groups
+ $.each(matchHeight._groups, function(key, group) {
+ group.elements = group.elements.not(that);
+ });
+
+ // TODO: cleanup empty groups
+
+ return this;
+ }
+
+ if (this.length <= 1 && !opts.target) {
+ return this;
+ }
+
+ // keep track of this group so we can re-apply later on load and resize events
+ matchHeight._groups.push({
+ elements: this,
+ options: opts
+ });
+
+ // match each element's height to the tallest element in the selection
+ matchHeight._apply(this, opts);
+
+ return this;
+ };
+
+ /*
+ * plugin global options
+ */
+
+ matchHeight._groups = [];
+ matchHeight._throttle = 80;
+ matchHeight._maintainScroll = false;
+ matchHeight._beforeUpdate = null;
+ matchHeight._afterUpdate = null;
+ matchHeight._rows = _rows;
+
+ /*
+ * matchHeight._apply
+ * apply matchHeight to given elements
+ */
+
+ matchHeight._apply = function(elements, options) {
+ var opts = _parseOptions(options),
+ $elements = $(elements),
+ rows = [$elements];
+
+ // take note of scroll position
+ var scrollTop = $(window).scrollTop(),
+ htmlHeight = $('html').outerHeight(true);
+
+ // get hidden parents
+ var $hiddenParents = $elements.parents().filter(':hidden');
+
+ // cache the original inline style
+ $hiddenParents.each(function() {
+ var $that = $(this);
+ $that.data('style-cache', $that.attr('style'));
+ });
+
+ // temporarily must force hidden parents visible
+ $hiddenParents.css('display', 'block');
+
+ // get rows if using byRow, otherwise assume one row
+ if (opts.byRow && !opts.target) {
+
+ // must first force an arbitrary equal height so floating elements break evenly
+ $elements.each(function() {
+ var $that = $(this),
+ display = $that.css('display');
+
+ // temporarily force a usable display value
+ if (display !== 'inline-block' && display !== 'inline-flex') {
+ display = 'block';
+ }
+
+ // cache the original inline style
+ $that.data('style-cache', $that.attr('style'));
+
+ $that.css({
+ 'display': display,
+ 'padding-top': '0',
+ 'padding-bottom': '0',
+ 'margin-top': '0',
+ 'margin-bottom': '0',
+ 'border-top-width': '0',
+ 'border-bottom-width': '0',
+ 'height': '100px'
+ });
+ });
+
+ // get the array of rows (based on element top position)
+ rows = _rows($elements);
+
+ // revert original inline styles
+ $elements.each(function() {
+ var $that = $(this);
+ $that.attr('style', $that.data('style-cache') || '');
+ });
+ }
+
+ $.each(rows, function(key, row) {
+ var $row = $(row),
+ targetHeight = 0;
+
+ if (!opts.target) {
+ // skip apply to rows with only one item
+ if (opts.byRow && $row.length <= 1) {
+ $row.css(opts.property, '');
+ return;
+ }
+
+ // iterate the row and find the max height
+ $row.each(function(){
+ var $that = $(this),
+ display = $that.css('display');
+
+ // temporarily force a usable display value
+ if (display !== 'inline-block' && display !== 'inline-flex') {
+ display = 'block';
+ }
+
+ // ensure we get the correct actual height (and not a previously set height value)
+ var css = { 'display': display };
+ css[opts.property] = '';
+ $that.css(css);
+
+ // find the max height (including padding, but not margin)
+ if ($that.outerHeight(false) > targetHeight) {
+ targetHeight = $that.outerHeight(false);
+ }
+
+ // revert display block
+ $that.css('display', '');
+ });
+ } else {
+ // if target set, use the height of the target element
+ targetHeight = opts.target.outerHeight(false);
+ }
+
+ // iterate the row and apply the height to all elements
+ $row.each(function(){
+ var $that = $(this),
+ verticalPadding = 0;
+
+ // don't apply to a target
+ if (opts.target && $that.is(opts.target)) {
+ return;
+ }
+
+ // handle padding and border correctly (required when not using border-box)
+ if ($that.css('box-sizing') !== 'border-box') {
+ verticalPadding += _parse($that.css('border-top-width')) + _parse($that.css('border-bottom-width'));
+ verticalPadding += _parse($that.css('padding-top')) + _parse($that.css('padding-bottom'));
+ }
+
+ // set the height (accounting for padding and border)
+ $that.css(opts.property, (targetHeight - verticalPadding) + 'px');
+ });
+ });
+
+ // revert hidden parents
+ $hiddenParents.each(function() {
+ var $that = $(this);
+ $that.attr('style', $that.data('style-cache') || null);
+ });
+
+ // restore scroll position if enabled
+ if (matchHeight._maintainScroll) {
+ $(window).scrollTop((scrollTop / htmlHeight) * $('html').outerHeight(true));
+ }
+
+ return this;
+ };
+
+ /*
+ * matchHeight._applyDataApi
+ * applies matchHeight to all elements with a data-match-height attribute
+ */
+
+ matchHeight._applyDataApi = function() {
+ var groups = {};
+
+ // generate groups by their groupId set by elements using data-match-height
+ $('[data-match-height], [data-mh]').each(function() {
+ var $this = $(this),
+ groupId = $this.attr('data-mh') || $this.attr('data-match-height');
+
+ if (groupId in groups) {
+ groups[groupId] = groups[groupId].add($this);
+ } else {
+ groups[groupId] = $this;
+ }
+ });
+
+ // apply matchHeight to each group
+ $.each(groups, function() {
+ this.matchHeight(true);
+ });
+ };
+
+ /*
+ * matchHeight._update
+ * updates matchHeight on all current groups with their correct options
+ */
+
+ var _update = function(event) {
+ if (matchHeight._beforeUpdate) {
+ matchHeight._beforeUpdate(event, matchHeight._groups);
+ }
+
+ $.each(matchHeight._groups, function() {
+ matchHeight._apply(this.elements, this.options);
+ });
+
+ if (matchHeight._afterUpdate) {
+ matchHeight._afterUpdate(event, matchHeight._groups);
+ }
+ };
+
+ matchHeight._update = function(throttle, event) {
+ // prevent update if fired from a resize event
+ // where the viewport width hasn't actually changed
+ // fixes an event looping bug in IE8
+ if (event && event.type === 'resize') {
+ var windowWidth = $(window).width();
+ if (windowWidth === _previousResizeWidth) {
+ return;
+ }
+ _previousResizeWidth = windowWidth;
+ }
+
+ // throttle updates
+ if (!throttle) {
+ _update(event);
+ } else if (_updateTimeout === -1) {
+ _updateTimeout = setTimeout(function() {
+ _update(event);
+ _updateTimeout = -1;
+ }, matchHeight._throttle);
+ }
+ };
+
+ /*
+ * bind events
+ */
+
+ // apply on DOM ready event
+ $(matchHeight._applyDataApi);
+
+ // update heights on load and resize events
+ $(window).bind('load', function(event) {
+ matchHeight._update(false, event);
+ });
+
+ // throttled update heights on resize events
+ $(window).bind('resize orientationchange', function(event) {
+ matchHeight._update(true, event);
+ });
+
+})(jQuery);