UNPKG

jquery.fillwidth

Version:

A jQuery plugin that given a `ul` with images inside their `lis` will do some things to line them up so that everything fits inside their container nice and flush to the edges. Used throughout [Artsy](http://artsy.net) to make rows of images fit inside a

515 lines (480 loc) 14.8 kB
// Generated by CoffeeScript 1.7.1 (function() { var $, Li, Row, callQueue, debounce, methods, totalPlugins; $ = jQuery; totalPlugins = 0; callQueue = []; Li = (function() { function Li(el, settings) { var $el, $img; $el = $(el); this.originalWidth = this.width = $el.outerWidth(false); this.originalHeight = this.height = $el.height(); this.originalMargin = this.margin = $el.outerWidth(true) - $el.outerWidth(false); $img = $el.find('img'); this.imgRatio = $img.width() / $img.height(); this.$el = $el; this.settings = settings; } Li.prototype.setHeight = function(h) { this.width = Math.round(h * (this.width / this.height)); if (!this.settings.lockedHeight) { return this.height = h; } }; Li.prototype.setWidth = function(w) { this.height = Math.round(w * (this.height / this.width)); return this.width = w; }; Li.prototype.decWidth = function() { return this.setWidth(this.width - 1); }; Li.prototype.decHeight = function() { return this.setHeight(this.height - 1); }; Li.prototype.incWidth = function() { return this.setWidth(this.width + 1); }; Li.prototype.incHeight = function() { return this.setHeight(this.height + 1); }; Li.prototype.updateDOM = function() { this.$el.css({ width: this.width, height: this.height, 'margin-right': this.margin }); return this.$el.find('img').height('auto'); }; Li.prototype.reset = function() { this.width = this.originalWidth; this.height = this.originalHeight; this.margin = this.originalMargin; return this.$el.css({ width: this.width, height: this.height, 'margin-right': this.margin }); }; return Li; })(); Row = (function() { function Row(frameWidth, settings) { this.frameWidth = frameWidth; this.settings = settings; this.lis = []; } Row.prototype.width = function() { var li, width, _i, _len, _ref; width = 0; _ref = this.lis; for (_i = 0, _len = _ref.length; _i < _len; _i++) { li = _ref[_i]; width += li.width + li.margin; } return width; }; Row.prototype.updateDOM = function() { var li, _i, _len, _ref, _results; _ref = this.lis; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { li = _ref[_i]; _results.push(li.updateDOM()); } return _results; }; Row.prototype.reset = function() { var li, _i, _len, _ref, _results; _ref = this.lis; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { li = _ref[_i]; _results.push(li.reset()); } return _results; }; Row.prototype.landscapeGroups = function() { var i, landscapeGroups, landscapes, li, ratio, _ref; landscapeGroups = []; _ref = this.settings.landscapeRatios; for (i in _ref) { ratio = _ref[i]; landscapes = (function() { var _i, _len, _ref1, _results; _ref1 = this.lis; _results = []; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { li = _ref1[_i]; if (li.imgRatio >= ratio) { _results.push(li); } } return _results; }).call(this); landscapeGroups.push(landscapes); } return landscapeGroups; }; Row.prototype.resizeLandscapes = function() { var i, landscapes, li, _i, _j, _k, _len, _len1, _ref, _ref1; _ref = this.landscapeGroups(this.settings.landscapeRatios); for (_i = 0, _len = _ref.length; _i < _len; _i++) { landscapes = _ref[_i]; if (!(landscapes.length !== 0)) { continue; } for (i = _j = 0, _ref1 = this.settings.resizeLandscapesBy; 0 <= _ref1 ? _j <= _ref1 : _j >= _ref1; i = 0 <= _ref1 ? ++_j : --_j) { for (_k = 0, _len1 = landscapes.length; _k < _len1; _k++) { li = landscapes[_k]; li.decHeight(); } if (this.width() <= this.frameWidth) { break; } } if (this.width() <= this.frameWidth) { break; } } return this; }; Row.prototype.adjustMargins = function() { var i, li, _i, _j, _len, _ref, _ref1, _results; _results = []; for (i = _i = 0, _ref = this.settings.adjustMarginsBy; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) { _ref1 = this.lis.slice(0, +(this.lis.length - 2) + 1 || 9e9); for (_j = 0, _len = _ref1.length; _j < _len; _j++) { li = _ref1[_j]; li.margin--; if (this.width() <= this.frameWidth) { break; } } if (this.width() <= this.frameWidth) { break; } else { _results.push(void 0); } } return _results; }; Row.prototype.resizeHeight = function() { var i, li, _results; i = 0; _results = []; while (this.width() > this.frameWidth && i < this.settings.resizeRowBy) { i++; _results.push((function() { var _i, _len, _ref, _results1; _ref = this.lis; _results1 = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { li = _ref[_i]; _results1.push(li.decHeight()); } return _results1; }).call(this)); } return _results; }; Row.prototype.roundOff = function() { var li, _i, _len, _ref, _results; _ref = this.lis; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { li = _ref[_i]; _results.push(li.setWidth(Math.floor(li.width))); } return _results; }; Row.prototype.fillLeftoverPixels = function() { var diff, randIndex, _results; this.roundOff(); diff = (function(_this) { return function() { return _this.frameWidth - _this.width(); }; })(this); _results = []; while (diff() !== 0) { randIndex = Math.round(Math.random() * (this.lis.length - 1)); if (diff() < 0) { _results.push(this.lis[randIndex].decWidth()); } else { _results.push(this.lis[randIndex].incWidth()); } } return _results; }; Row.prototype.removeMargin = function() { var lastLi; lastLi = this.lis[this.lis.length - 1]; return lastLi.margin = 0; }; Row.prototype.lockHeight = function() { var li, tallestHeight, tallestLi, _i, _len, _ref, _results; tallestLi = (this.lis.sort(function(a, b) { return b.height - a.height; }))[0]; tallestHeight = Math.ceil(tallestLi.height); _ref = this.lis; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { li = _ref[_i]; _results.push(li.height = tallestHeight); } return _results; }; Row.prototype.hide = function() { var li, _i, _len, _ref, _results; _ref = this.lis; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { li = _ref[_i]; _results.push(li.$el.hide()); } return _results; }; Row.prototype.show = function() { var li, _i, _len, _ref, _results; _ref = this.lis; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { li = _ref[_i]; _results.push(li.$el.show()); } return _results; }; return Row; })(); debounce = function(func, wait) { var timeout; timeout = 0; return function() { var args, throttler; args = arguments; throttler = (function(_this) { return function() { timeout = null; return func(args); }; })(this); clearTimeout(timeout); return timeout = setTimeout(throttler, wait); }; }; methods = { init: function(settings) { var i, _defaults; _defaults = { resizeLandscapesBy: 200, resizeRowBy: 30, landscapeRatios: ((function() { var _i, _results; _results = []; for (i = _i = 10; _i <= 50; i = _i += 3) { _results.push(i / 10); } return _results; })()).reverse(), fillLastRow: false, beforeFillWidth: null, afterFillWidth: null }; this.settings = $.extend(_defaults, settings); return this.each((function(_this) { return function(i, el) { var $el, $imgs, imagesToLoad, initFillWidth; $el = $(el); methods.initStyling.call(_this, $el); initFillWidth = function() { methods.fillWidth.call(_this, $el); if (!(navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/MSIE 8\.0/i))) { $(window).bind('resize.fillwidth', debounce((function() { var fn, _i, _len; callQueue.push((function() { return methods.fillWidth.call(_this, $el); })); if (callQueue.length === totalPlugins) { for (_i = 0, _len = callQueue.length; _i < _len; _i++) { fn = callQueue[_i]; fn(); } return callQueue = []; } }), 300)); } return totalPlugins++; }; $imgs = $el.find('img'); if (_this.settings.imageDimensions != null) { return initFillWidth(); } else { imagesToLoad = $imgs.length; return $imgs.load(function() { imagesToLoad--; if (imagesToLoad === 0) { return initFillWidth(); } }); } }; })(this)); }, initStyling: function(el) { var $el; $el = $(el); $el.css({ 'list-style': 'none', padding: 0, margin: 0 }); if (this.settings.initStyling != null) { $el.css(this.settings.initStyling); } $el.find('> li').css({ 'display': 'inline-block', 'vertical-align': 'top', 'margin-left': 0 }); $el.find('img').css({ 'max-width': '100%', 'max-height': '100%' }); if (this.settings && (this.settings.imageDimensions != null)) { return $el.find('> li').each((function(_this) { return function(i, el) { var $img; $img = $(el).find('img').first(); $img.width(_this.settings.imageDimensions[i].width); return $img.height(_this.settings.imageDimensions[i].height); }; })(this)); } }, destroy: function() { $(window).unbind('resize.fillwidth'); return this.each(function() { var row, _i, _len, _ref; _ref = $(this).fillwidth('rowObjs'); for (_i = 0, _len = _ref.length; _i < _len; _i++) { row = _ref[_i]; row.reset(); } return $(this).removeData('fillwidth.rows'); }); }, fillWidth: function(el) { var $el, row, rows, _i, _j, _len, _len1, _ref; $el = $(el); $el.trigger('fillwidth.beforeFillWidth'); if (this.settings.beforeFillWidth != null) { this.settings.beforeFillWidth(); } if (this.fillwidthRows) { _ref = this.fillwidthRows; for (_i = 0, _len = _ref.length; _i < _len; _i++) { row = _ref[_i]; row.reset(); } } $el.width('auto'); $el.trigger('fillwidth.beforeNewRows'); if (this.settings.beforeNewRows != null) { this.settings.beforeNewRows(); } this.frameWidth = $el.width(); rows = methods.breakUpIntoRows.call(this, $el); this.fillwidthRows = rows; $el.width(this.frameWidth); $el.trigger('fillwidth.afterNewRows'); if (this.settings.afterNewRows != null) { this.settings.afterNewRows(); } for (_j = 0, _len1 = rows.length; _j < _len1; _j++) { row = rows[_j]; if (!(row.lis.length > 1)) { continue; } row.removeMargin(); row.resizeHeight(); if (this.settings.adjustMarginsBy != null) { row.adjustMargins(); } row.resizeLandscapes(); if (!(row === rows[rows.length - 1] && !this.settings.fillLastRow)) { row.fillLeftoverPixels(); } row.lockHeight(); row.updateDOM(); } $el.trigger('fillwidth.afterFillWidth'); if (this.settings.afterFillWidth != null) { return this.settings.afterFillWidth(); } }, rowObjs: function() { var arr, rows; arr = []; rows = this.fillwidthRows; this.each(function() { return arr.push(rows); }); if (arr.length === 1) { arr = arr[0]; } return arr; }, rows: function() { var arr, li, row, rows, _i, _len; rows = methods.rowObjs.call(this); arr = []; for (_i = 0, _len = rows.length; _i < _len; _i++) { row = rows[_i]; arr.push((function() { var _j, _len1, _ref, _results; _ref = row.lis; _results = []; for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { li = _ref[_j]; _results.push(li.$el); } return _results; })()); } if (arr.length === 1) { arr = arr[0]; } return arr; }, breakUpIntoRows: function(el) { var $el, i, rows; $el = $(el); i = 0; rows = [new Row(this.frameWidth, this.settings)]; $el.find('> li').each((function(_this) { return function(j, li) { if ($(li).is(':hidden')) { return; } rows[i].lis.push(new Li(li, _this.settings)); if (rows[i].width() >= $el.width() && j !== $el.find('> li').length - 1) { rows.push(new Row(_this.frameWidth, _this.settings)); return i++; } }; })(this)); return rows; } }; $.fn.fillwidth = function(method) { if (methods[method] != null) { return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof method === "object" || (method == null)) { return methods.init.apply(this, arguments); } else { return $.error("Method " + method + " does not exist on jQuery.fillwidth"); } }; }).call(this);