annotate themes/contrib/mayo/js/mayo-columns.js @ 2:5311817fb629

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