(function (factory){ if (typeof define === 'function' && define.amd) define(['jquery'] , factory); else factory(jQuery); } (function ($){ var Wookmark, defaultOptions, __bind; __bind = function (fn, me){ return function (){ return fn.apply(me, arguments); } ; } ; defaultOptions = { align: 'center', autoResize: false , comparator: null , container: $('body'), direction: undefined, ignoreInactiveItems: true , itemWidth: 0, fillEmptySpace: false , flexibleWidth: 0, offset: 2, outerOffset: 0, onLayoutChanged: undefined, possibleFilters: [] , resizeDelay: 50, verticalOffset: undefined} ; var executeNextFrame = window.requestAnimationFrame || function (callback){ callback(); } ; function bulkUpdateCSS(data){ executeNextFrame(function (){ var i, item; for (i = 0; i < _AN_Read_length('length', data); i++ ){ item = data[i]; item.obj.css(item.css); } } ); } function cleanFilterName(filterName){ return $.trim(filterName).toLowerCase(); } Wookmark = (function (){ function Wookmark(handler, options){ this.handler = handler; this.columns = this.containerWidth = this.resizeTimer = null ; this.activeItemCount = 0; this.itemHeightsDirty = true ; this.placeholders = [] ; $.extend(true , this, defaultOptions, options); this.verticalOffset = this.verticalOffset || this.offset; this.update = __bind(this.update, this); this.onResize = __bind(this.onResize, this); this.onRefresh = __bind(this.onRefresh, this); this.getItemWidth = __bind(this.getItemWidth, this); this.layout = __bind(this.layout, this); this.layoutFull = __bind(this.layoutFull, this); this.layoutColumns = __bind(this.layoutColumns, this); _AN_Write_filter('filter', this, false , __bind(this.filter, this)); this.clear = __bind(this.clear, this); this.getActiveItems = __bind(this.getActiveItems, this); this.refreshPlaceholders = __bind(this.refreshPlaceholders, this); this.sortElements = __bind(this.sortElements, this); this.updateFilterClasses = __bind(this.updateFilterClasses, this); this.updateFilterClasses(); if (this.autoResize) $(window).bind('resize.wookmark', this.onResize); this.container.bind('refreshWookmark', this.onRefresh); } Wookmark.prototype.updateFilterClasses = function (){ var i = 0, j = 0, k = 0, filterClasses = { } , itemFilterClasses, $item, filterClass, possibleFilters = this.possibleFilters, possibleFilter; for (; i < _AN_Read_length('length', this.handler); i++ ){ $item = this.handler.eq(i); itemFilterClasses = $item.data('filterClass'); if (typeof itemFilterClasses == 'object' && _AN_Read_length('length', itemFilterClasses) > 0) { for (j = 0; j < _AN_Read_length('length', itemFilterClasses); j++ ){ filterClass = cleanFilterName(itemFilterClasses[j]); if (!filterClasses[filterClass]) { filterClasses[filterClass] = [] ; } filterClasses[filterClass].push($item[0]); } } } for (; k < _AN_Read_length('length', possibleFilters); k++ ){ possibleFilter = cleanFilterName(possibleFilters[k]); if (!(possibleFilter in filterClasses)) { filterClasses[possibleFilter] = [] ; } } this.filterClasses = filterClasses; } ; Wookmark.prototype.update = function (options){ this.itemHeightsDirty = true ; $.extend(true , this, options); } ; Wookmark.prototype.onResize = function (){ clearTimeout(this.resizeTimer); this.itemHeightsDirty = this.flexibleWidth !== 0; this.resizeTimer = _AN_Call_settimeout('setTimeout', window, this.layout, this.resizeDelay); } ; Wookmark.prototype.onRefresh = function (){ this.itemHeightsDirty = true ; this.layout(); } ; Wookmark.prototype.filter = function (filters, mode){ var activeFilters = [] , activeFiltersLength, activeItems = $(), i, j, k, filter; filters = filters || [] ; mode = mode || 'or'; if (filters.length) { for (i = 0; i < _AN_Read_length('length', filters); i++ ){ filter = cleanFilterName(filters[i]); if (filter in this.filterClasses) { activeFilters.push(this.filterClasses[filter]); } } activeFiltersLength = _AN_Read_length('length', activeFilters); if (mode == 'or' || activeFiltersLength == 1) { for (i = 0; i < activeFiltersLength; i++ ){ activeItems = activeItems.add(activeFilters[i]); } } else if (mode == 'and') { var shortestFilter = activeFilters[0], itemValid = true , foundInFilter, currentItem, currentFilter; for (i = 1; i < activeFiltersLength; i++ ){ if (_AN_Read_length('length', activeFilters[i]) < _AN_Read_length('length', shortestFilter)) { shortestFilter = activeFilters[i]; } } shortestFilter = shortestFilter || [] ; for (i = 0; i < _AN_Read_length('length', shortestFilter); i++ ){ currentItem = shortestFilter[i]; itemValid = true ; for (j = 0; j < _AN_Read_length('length', activeFilters) && itemValid; j++ ){ currentFilter = activeFilters[j]; if (shortestFilter == currentFilter) continue ; for (k = 0, foundInFilter = false ; k < _AN_Read_length('length', currentFilter) && !foundInFilter; k++ ){ foundInFilter = currentFilter[k] == currentItem; } itemValid &= foundInFilter; } if (itemValid) activeItems.push(shortestFilter[i]); } } this.handler.not(activeItems).addClass('inactive'); } else { activeItems = this.handler; } activeItems.removeClass('inactive'); this.columns = null ; this.layout(); } ; Wookmark.prototype.refreshPlaceholders = function (columnWidth, sideOffset){ var i = _AN_Read_length('length', this.placeholders), $placeholder, $lastColumnItem, columnsLength = _AN_Read_length('length', this.columns), column, height, top, innerOffset, containerHeight = this.container.innerHeight(); for (; i < columnsLength; i++ ){ $placeholder = $('
').appendTo(this.container); this.placeholders.push($placeholder); } innerOffset = this.offset + parseInt(this.placeholders[0].css('borderLeftWidth'), 10) * 2; for (i = 0; i < _AN_Read_length('length', this.placeholders); i++ ){ $placeholder = this.placeholders[i]; column = this.columns[i]; if (i >= columnsLength || !column[_AN_Read_length('length', column) - 1]) { $placeholder.css('display', 'none'); } else { $lastColumnItem = column[_AN_Read_length('length', column) - 1]; if (!$lastColumnItem) continue ; top = $lastColumnItem.data('wookmark-top') + $lastColumnItem.data('wookmark-height') + this.verticalOffset; height = containerHeight - top - innerOffset; $placeholder.css({ position: 'absolute', display: height > 0? 'block': 'none', left: i * columnWidth + sideOffset, top: top, width: columnWidth - innerOffset, height: height} ); } } } ; Wookmark.prototype.getActiveItems = function (){ return this.ignoreInactiveItems? this.handler.not('.inactive'): this.handler; } ; Wookmark.prototype.getItemWidth = function (){ var itemWidth = this.itemWidth, innerWidth = this.container.width() - 2 * this.outerOffset, firstElement = this.handler.eq(0), flexibleWidth = this.flexibleWidth; if (this.itemWidth === undefined || this.itemWidth === 0 && !this.flexibleWidth) { itemWidth = firstElement.outerWidth(); } else if (typeof this.itemWidth == 'string' && this.itemWidth.indexOf('%') >= 0) { itemWidth = parseFloat(this.itemWidth) / 100 * innerWidth; } if (flexibleWidth) { if (typeof flexibleWidth == 'string' && flexibleWidth.indexOf('%') >= 0) { flexibleWidth = parseFloat(flexibleWidth) / 100 * innerWidth; } var paddedInnerWidth = (innerWidth + this.offset), flexibleColumns = ~~(0.5 + paddedInnerWidth / (flexibleWidth + this.offset)), fixedColumns = ~~(paddedInnerWidth / (itemWidth + this.offset)), columns = Math.max(flexibleColumns, fixedColumns), columnWidth = Math.min(flexibleWidth, ~~((innerWidth - (columns - 1) * this.offset) / columns)); itemWidth = Math.max(itemWidth, columnWidth); this.handler.css('width', itemWidth); } return itemWidth; } ; Wookmark.prototype.layout = function (force){ if (!this.container.is(':visible')) return ; var columnWidth = this.getItemWidth() + this.offset, containerWidth = this.container.width(), innerWidth = containerWidth - 2 * this.outerOffset, columns = ~~((innerWidth + this.offset) / columnWidth), offset = 0, maxHeight = 0, i = 0, activeItems = this.getActiveItems(), activeItemsLength = _AN_Read_length('length', activeItems), $item; if (this.itemHeightsDirty || !this.container.data('itemHeightsInitialized')) { for (; i < activeItemsLength; i++ ){ $item = activeItems.eq(i); $item.data('wookmark-height', $item.outerHeight()); } this.itemHeightsDirty = false ; this.container.data('itemHeightsInitialized', true ); } columns = Math.max(1, Math.min(columns, activeItemsLength)); offset = this.outerOffset; if (this.align == 'center') { offset += ~~(0.5 + (innerWidth - (columns * columnWidth - this.offset)) >> 1); } this.direction = this.direction || (this.align == 'right'? 'right': 'left'); if (!force && this.columns !== null && _AN_Read_length('length', this.columns) == columns && this.activeItemCount == activeItemsLength) { maxHeight = this.layoutColumns(columnWidth, offset); } else { maxHeight = this.layoutFull(columnWidth, columns, offset); } this.activeItemCount = activeItemsLength; this.container.css('height', maxHeight); if (this.fillEmptySpace) { this.refreshPlaceholders(columnWidth, offset); } if (this.onLayoutChanged !== undefined && typeof this.onLayoutChanged === 'function') { this.onLayoutChanged(); } } ; Wookmark.prototype.sortElements = function (elements){ return typeof (this.comparator) === 'function'? elements.sort(this.comparator): elements; } ; Wookmark.prototype.layoutFull = function (columnWidth, columns, offset){ var $item, i = 0, k = 0, activeItems = $.makeArray(this.getActiveItems()), length = _AN_Read_length('length', activeItems), shortest = null , shortestIndex = null , sideOffset, heights = [] , itemBulkCSS = [] , leftAligned = this.align == 'left'? true : false ; this.columns = [] ; activeItems = this.sortElements(activeItems); while (_AN_Read_length('length', heights) < columns){ heights.push(this.outerOffset); this.columns.push([] ); } for (; i < length; i++ ){ $item = $(activeItems[i]); shortest = heights[0]; shortestIndex = 0; for (k = 0; k < columns; k++ ){ if (heights[k] < shortest) { shortest = heights[k]; shortestIndex = k; } } $item.data('wookmark-top', shortest); sideOffset = offset; if (shortestIndex > 0 || !leftAligned) sideOffset += shortestIndex * columnWidth; (itemBulkCSS[i] = { obj: $item, css: { position: 'absolute', top: shortest} } ).css[this.direction] = sideOffset; heights[shortestIndex] += $item.data('wookmark-height') + this.verticalOffset; this.columns[shortestIndex].push($item); } bulkUpdateCSS(itemBulkCSS); return Math.max.apply(Math, heights); } ; Wookmark.prototype.layoutColumns = function (columnWidth, offset){ var heights = [] , itemBulkCSS = [] , i = 0, k = 0, j = 0, currentHeight, column, $item, itemData, sideOffset; for (; i < _AN_Read_length('length', this.columns); i++ ){ heights.push(this.outerOffset); column = this.columns[i]; sideOffset = i * columnWidth + offset; currentHeight = heights[i]; for (k = 0; k < _AN_Read_length('length', column); k++ , j++ ){ $item = column[k].data('wookmark-top', currentHeight); (itemBulkCSS[j] = { obj: $item, css: { top: currentHeight} } ).css[this.direction] = sideOffset; currentHeight += $item.data('wookmark-height') + this.verticalOffset; } heights[i] = currentHeight; } bulkUpdateCSS(itemBulkCSS); return Math.max.apply(Math, heights); } ; Wookmark.prototype.clear = function (){ clearTimeout(this.resizeTimer); $(window).unbind('resize.wookmark', this.onResize); this.container.unbind('refreshWookmark', this.onRefresh); this.handler.wookmarkInstance = null ; } ; return Wookmark; } )(); $.fn.wookmark = function (options){ if (!this.wookmarkInstance) { this.wookmarkInstance = new Wookmark(this, options || { } ); } else { this.wookmarkInstance.update(options || { } ); } this.wookmarkInstance.layout(true ); return _AN_Call_show('show', this); } ; } ));