PageSourceSearch

https://xn--34-dlc5auab3a.xn--p1ai/wp-content/themes/country/js/jquery.mosaicflow.js?ver=5.3.1

js xn--34-dlc5auab3a.xn--p1ai collected 2026-10-03 02:07:33 UTC 10,147 bytes, 365 lines download raw bytes

1/**
2 * Mosaic Flow
3 *
4 * Pinterest like responsive image grid that doesn’t sucks
5 *
6 * @requires jQuery
7 * @author Artem Sapegin
8 * @copyright 2012 Artem Sapegin, http://sapegin.me
9 * @license MIT
10 */
11
12/*jshint browser:true, jquery:true, white:false, smarttabs:true */
13/*global jQuery:false, define:false*/
14(function(factory) {  // Try to register as an anonymous AMD module
15	if (typeof define === 'function' && define.amd) {
16		define(['jquery'], factory);
17	}
18	else {
19		factory(jQuery);
20	}
21}(function($) {
22	'use strict';
23	var cnt = 0;
24
25	$.fn.mosaicflow = function(options) {
26		var args = Array.prototype.slice.call(arguments, 0);
27
28		return this.each(function() {
29			var elm = $(this);
30			var data = elm.data('mosaicflow');
31
32			if (!data) {
33				options = $.extend({}, $.fn.mosaicflow.defaults, options, dataToOptions(elm));
34				data = new Mosaicflow(elm, options);
35				elm.data('mosaicflow', data);
36			}
37			else if (typeof options === 'string') {
38				data[options](args[1]);
39			}
40		});
41	};
42
43	$.fn.mosaicflow.defaults = {
44		itemSelector: '> *',
45		columnClass: 'mosaicflow__column',
46		minItemWidth: 240,
47		minColumns: 2,
48		itemHeightCalculation: 'auto',
49		threshold: 40
50	};
51
52	function Mosaicflow(container, options) {
53		this.container = container;
54		this.options = options;
55
56		this.container.trigger('mosaicflow-start');
57		this.init();
58		this.container.trigger('mosaicflow-ready');
59	}
60
61	Mosaicflow.prototype = {
62		init: function() {
63			this.__uid = cnt++;
64			this.__uidItemCounter = 0;
65			this.items = this.container.find(this.options.itemSelector);
66			this.columns = $([]);
67			this.columnsHeights = [];
68			this.itemsHeights = {};
69			this.tempContainer = $('<div>').css({'visibility': 'hidden', 'width': '100%'});
70			this.workOnTemp = false;
71			this.autoCalculation = this.options.itemHeightCalculation === 'auto';
72
73			this.container.append(this.tempContainer);
74
75			var that = this;
76			this.items.each(function() {
77				var elm = $(this);
78				var id = elm.attr('id');
79				if (!id) {
80					// Generate an unique id
81					id = that.generateUniqueId();
82					elm.attr('id', id);
83				}
84			});
85
86			this.container.css('visibility', 'hidden');
87			if (this.autoCalculation) {
88				$(window).on('load', $.proxy(this.refill, this));
89			}
90			else {
91				this.refill();
92			}
93			$(window).resize($.proxy(this.refill, this));
94		},
95
96		refill: function() {
97			this.container.trigger('mosaicflow-fill');
98			this.numberOfColumns = Math.floor(this.container.width() / this.options.minItemWidth);
99			// Always keep min columns number
100			if (this.numberOfColumns < this.options.minColumns)
101				this.numberOfColumns = this.options.minColumns;
102
103			var needToRefill = this.ensureColumns();
104			if (needToRefill) {
105				this.fillColumns();
106
107				// Remove excess columns, only if there are visible columns remaining
108				if (this.columns.filter(':visible').length > 0) {
109					this.columns.filter(':hidden').remove();
110				}
111			}
112			this.container.css('visibility', 'visible');
113			this.container.trigger('mosaicflow-filled');
114		},
115
116		ensureColumns: function() {
117			var createdCnt = this.columns.filter(':visible').length;
118			var calculatedCnt = this.numberOfColumns;
119
120			this.workingContainer = createdCnt === 0 ? this.tempContainer : this.container;
121
122			if (calculatedCnt > createdCnt) {
123				var neededCnt = calculatedCnt - createdCnt;
124				for (var columnIdx = 0; columnIdx < neededCnt; columnIdx++) {
125					var column = $('<div>', {
126						'class': this.options.columnClass
127					});
128
129					this.workingContainer.append(column);
130				}
131			}
132			else if (calculatedCnt < createdCnt) {
133				var lastColumn = createdCnt;
134				while (calculatedCnt <= lastColumn) {
135					// We can't remove columns here becase it will remove items to. So we hide it and will remove later.
136					this.columns.eq(lastColumn).hide();
137					lastColumn--;
138				}
139
140				var diff = createdCnt - calculatedCnt;
141				this.columnsHeights.splice(this.columnsHeights.length - diff, diff);
142			}
143
144			if (calculatedCnt !== createdCnt) {
145				this.columns = this.workingContainer.find('.' + this.options.columnClass);
146				this.columns.css('width', (100 / calculatedCnt) + '%');
147				return true;
148			}
149
150			return false;
151		},
152
153		fillColumns: function() {
154			var columnsCnt = this.numberOfColumns;
155			var itemsCnt = this.items.length;
156
157			for (var columnIdx = 0; columnIdx < columnsCnt; columnIdx++) {
158				var column = this.columns.eq(columnIdx);
159				this.columnsHeights[columnIdx] = 0;
160				for (var itemIdx = columnIdx; itemIdx < itemsCnt; itemIdx += columnsCnt) {
161					var item = this.items.eq(itemIdx);
162					var height = 0;
163					column.append(item);
164
165					if (this.autoCalculation) {
166						// Check height after being placed in its column
167						height = item.outerHeight();
168					}
169					else {
170						// Read img height attribute
171						height = parseInt(item.find('img').attr('height'), 10);
172					}
173
174					this.itemsHeights[item.attr('id')] = height;
175					this.columnsHeights[columnIdx] += height;
176				}
177			}
178
179			this.levelBottomEdge(this.itemsHeights, this.columnsHeights);
180
181			if (this.workingContainer === this.tempContainer) {
182				this.container.append(this.tempContainer.children());
183			}
184			this.container.trigger('mosaicflow-layout');
185		},
186
187		levelBottomEdge: function(itemsHeights, columnsHeights) {
188			while (true) {
189				var lowestColumn = $.inArray(Math.min.apply(null, columnsHeights), columnsHeights);
190				var highestColumn = $.inArray(Math.max.apply(null, columnsHeights), columnsHeights);
191				if (lowestColumn === highestColumn) return;
192
193				var lastInHighestColumn = this.columns.eq(highestColumn).children().last();
194				var lastInHighestColumnHeight = itemsHeights[lastInHighestColumn.attr('id')];
195				var lowestHeight = columnsHeights[lowestColumn];
196				var highestHeight = columnsHeights[highestColumn];
197				var newLowestHeight = lowestHeight + lastInHighestColumnHeight;
198
199				if (newLowestHeight >= highestHeight) return;
200
201				if (highestHeight - newLowestHeight < this.options.threshold) return;
202
203				this.columns.eq(lowestColumn).append(lastInHighestColumn);
204				columnsHeights[highestColumn] -= lastInHighestColumnHeight;
205				columnsHeights[lowestColumn] += lastInHighestColumnHeight;
206			}
207		},
208
209		add: function(elm) {
210			this.container.trigger('mosaicflow-item-add', [elm]);
211			var lowestColumn = $.inArray(Math.min.apply(null, this.columnsHeights), this.columnsHeights);
212			var height = 0;
213
214			if (this.autoCalculation) {
215
216				// Get height of elm
217				elm.css({
218					position: 'static',
219					visibility: 'hidden',
220					display: 'block'
221				}).appendTo(this.columns.eq(lowestColumn));
222
223				height = elm.outerHeight();
224
225				var inlineImages = elm.find('img');
226				if (inlineImages.length !== 0) {
227					inlineImages.each(function() {
228						var image = $(this);
229						var imageSizes = getImageSizes(image);
230						var actualHeight = (image.width() * imageSizes.height) / imageSizes.width;
231
232						height += actualHeight;
233					});
234				}
235
236				elm.detach().css({
237					position: 'static',
238					visibility: 'visible'
239				});
240			}
241			else {
242				height = parseInt(elm.find('img').attr('height'), 10);
243			}
244
245			if (!elm.attr('id')) {
246				// Generate a unique id
247				elm.attr('id', this.generateUniqueId());
248			}
249
250			// Update item collection.
251			// Item needs to be placed at the end of this.items to keep order of elements
252			var itemsArr = this.items.toArray();
253			itemsArr.push(elm);
254			this.items = $(itemsArr);
255
256			this.itemsHeights[elm.attr('id')] = height;
257			this.columnsHeights[lowestColumn] += height;
258			this.columns.eq(lowestColumn).append(elm);
259
260			this.levelBottomEdge(this.itemsHeights, this.columnsHeights);
261			this.container.trigger('mosaicflow-layout');
262			this.container.trigger('mosaicflow-item-added', [elm]);
263		},
264
265		remove: function(elm) {
266			this.container.trigger('mosaicflow-item-remove', [elm]);
267			var column = elm.parents('.' + this.options.columnClass);
268
269			// Update column height
270			this.columnsHeights[column.index() - 1] -= this.itemsHeights[elm.attr('id')];
271
272			elm.detach();
273
274			// Update item collection
275			this.items = this.items.not(elm);
276			this.levelBottomEdge(this.itemsHeights, this.columnsHeights);
277			this.container.trigger('mosaicflow-layout');
278			this.container.trigger('mosaicflow-item-removed', [elm]);
279		},
280
281		empty: function() {
282			var columnsCnt = this.numberOfColumns;
283
284			this.items = $([]);
285			this.itemsHeights = {};
286
287			for (var columnIdx = 0; columnIdx < columnsCnt; columnIdx++) {
288				var column = this.columns.eq(columnIdx);
289				this.columnsHeights[columnIdx] = 0;
290				column.empty();
291			}
292			this.container.trigger('mosaicflow-layout');
293		},
294
295		recomputeHeights: function() {
296			function computeHeight(idx, item) {
297				item = $(item);
298				var height = 0;
299				if (that.autoCalculation) {
300					// Check height after being placed in its column
301					height = item.outerHeight();
302				}
303				else {
304					// Read img height attribute
305					height = parseInt(item.find('img').attr('height'), 10);
306				}
307
308				that.itemsHeights[item.attr('id')] = height;
309				that.columnsHeights[columnIdx] += height;
310			}
311
312			var that = this;
313			var columnsCnt = this.numberOfColumns;
314
315			for (var columnIdx = 0; columnIdx < columnsCnt; columnIdx++) {
316				var column = this.columns.eq(columnIdx);
317
318				this.columnsHeights[columnIdx] = 0;
319				column.children().each(computeHeight);
320			}
321		},
322
323		generateUniqueId: function() {
324			// Increment the counter
325			this.__uidItemCounter++;
326
327			// Return an unique ID
328			return 'mosaic-' + this.__uid + '-itemid-' + this.__uidItemCounter;
329		}
330	};
331
332	// Camelize data-attributes
333	function dataToOptions(elem) {
334		function upper(m, l) {
335			return l.toUpper();
336		}
337		var options = {};
338		var data = elem.data();
339		for (var key in data) {
340			options[key.replace(/-(\w)/g, upper)] = data[key];
341		}
342		return options;
343	}
344
345	function getImageSizes(image) {
346		var sizes = {};
347
348		sizes.height = parseInt(image.attr('height'), 10);
349		sizes.width = parseInt(image.attr('width'), 10);
350
351		if (sizes.height === 0 || sizes.width === 0) {
352			var utilImage = new Image();
353			utilImage.src = image.attr('src');
354
355			sizes.width = utilImage.width;
356			sizes.height = utilImage.height;
357		}
358
359		return sizes;
360	}
361
362	// Auto init
363	$(function() { $('.mosaicflow').mosaicflow(); });
364
365}));

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.