(function($, window, document, undefined) { 'use strict'; var Diamonds = function(customOptions) { this.options = { itemSelector : ".item", size : 250, gap : 0.5, autoRedraw : true, hideIncompleteRow : false, scrollbarWidth : 0, minDiamondsPerRow : 2, eventPrefix : "diamonds:", itemWrap : $('
'), rowWrap : $('
'), rowUpperWrap : $('
'), rowLowerWrap : $('
'), diamondWrap : $('
'), overrideCss : '.diamonds-{{guid}} .diamond-box { border-width: {{gap}}px }', debugEnabled : false, debugEvent : function(event, data) { if(console && console.log) { console.log("Event: " + event, data) }}, debugMethod : function(method, args) { if(console && console.log) { console.log("Method: " + method, args) }} }; this.wrapElement = customOptions.wrapElement; if(this._triggerEvent("beforeInit")) return; this.setOptions(customOptions, false); this.itemElements = $(this.options.itemSelector, this.wrapElement); this.guid = this._createGuid(); // Create override css this.styleElement = this._createOverrideCss(); // Initial draw this.draw(); // Auto redraw this.startAutoRedraw(); this._triggerEvent("afterInit"); }; /** * Returns true if we should stop */ Diamonds.prototype._triggerEvent = function(event, data) { if(this.options.debugEnabled) this.options.debugEvent(event, data); var e = $.Event(this.options.eventPrefix + event); this.wrapElement.trigger(e, data); return e.isDefaultPrevented(); }; Diamonds.prototype._createGuid = function() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {var r = Math.random()*16|0,v=c=='x'?r:r&0x3|0x8;return v.toString(16);}); }; Diamonds.prototype.destroy = function() { if(this._triggerEvent("beforeDestroy")) return; this._removeOverrideCss(); this.stopAutoRedraw(); this._emptyElement(this.wrapElement); this.wrapElement.append(this.itemElements); this.wrapElement.removeData("diamonds"); this._triggerEvent("afterDestroy"); }; Diamonds.prototype._createOverrideCss = function() { var css = this.options.overrideCss; var data = { "size" : this.options.size, "gap" : this.options.gap, "guid" : this.guid } for(var key in data) { if(data.hasOwnProperty(key)) { css = css.replace(new RegExp("{{" + key + "}}", 'g'), data[key]); } } var style = $(''); style.html(css); $("head").append(style); return style; }; Diamonds.prototype._removeOverrideCss = function() { if(this.styleElement) this.styleElement.remove(); }; Diamonds.prototype._updateOverrideCss = function() { this._removeOverrideCss(); this._createOverrideCss(); }; Diamonds.prototype.stopAutoRedraw = function() { if(this._triggerEvent("beforeStopAutoRedraw")) return; window.clearInterval(this.redrawer); this._triggerEvent("afterStopAutoRedraw"); }; Diamonds.prototype.startAutoRedraw = function() { window.clearInterval(this.redrawer); // Stop previous var lastWidth = this.wrapElement.width(); if(this.options.autoRedraw) { if(this._triggerEvent("beforeStartAutoRedraw")) return; this.redrawer = window.setInterval(function() { var curWidth = this.wrapElement.width(); if(curWidth !== lastWidth) { if(this._triggerEvent("onAutoResize", {before: lastWidth, current: curWidth})) return; lastWidth = curWidth; this.draw(); } }.bind(this), 50); this._triggerEvent("afterStartAutoRedraw"); } }; Diamonds.prototype.setOptions = function(customOptions, redraw) { redraw = redraw === undefined ? true : redraw; if(customOptions !== null && typeof customOptions === "object") { if(this._triggerEvent("beforeSetOptions", customOptions)) return; // Stop or start redraw if(this.options.autoRedraw && !customOptions.autoRedraw) { this.stopAutoRedraw(); } else if(!this.options.autoRedraw && customOptions.autoRedraw) { this.startAutoRedraw(); } $.extend(true, this.options, customOptions); if(redraw) { this._updateOverrideCss(); this.draw(); } this._triggerEvent("afterSetOptions", customOptions); } }; Diamonds.prototype._getScrollbarWidth = function() { if($.isNumeric(this.options.scrollbarWidth) && this.options.scrollbarWidth >= 0) { return this.options.scrollbarWidth; } var $inner = $('
test
'), $outer = $('
').append($inner), inner = $inner[0], outer = $outer[0]; $('body').append(outer); var width1 = inner.offsetWidth; $outer.css('overflow', 'scroll'); var width2 = outer.clientWidth; $outer.remove(); return this.scrollbarWidth = (width1 - width2); }; Diamonds.prototype._emptyElement = function(element) { $("> *", element).detach(); }; Diamonds.prototype._groupIntoRows = function(items, maxDiamondsPerRow, hideIncompleteRow) { // Max number of diamonds per row maxDiamondsPerRow = Math.max(this.options.minDiamondsPerRow, 0 + maxDiamondsPerRow); // Draw rows var rows = new Array(); for(var i = 0; i < items.length; i++) { var item = items[i]; // Append or create new row? var max = rows.length % 2 === 0 ? maxDiamondsPerRow - 1 : maxDiamondsPerRow; if(!rows.hasOwnProperty(rows.length - 1) || rows[rows.length - 1].length == max) { rows.push(new Array()); } rows[rows.length - 1].push(item); } // Hide incomplete rows if(hideIncompleteRow) { if(rows.hasOwnProperty(rows.length - 1) && rows[rows.length - 1].length < rows.length % 2 === 0 ? maxDiamondsPerRow - 1 : maxDiamondsPerRow) { rows.pop(); } } return rows; }; Diamonds.prototype._renderHtml = function(rows) { var wrap = this.options.diamondWrap.clone(); wrap.addClass("diamonds-" + this.guid); for(var i = 0; i < rows.length; i += 2) { var row = this.options.rowWrap.clone(); var upper = this.options.rowUpperWrap.clone(); var lower = this.options.rowLowerWrap.clone(); row.append(upper).append(lower); wrap.append(row); for(var j = 0; j < rows[i].length; j++) { upper.append(rows[i][j]); $(rows[i][j]).wrap(this.options.itemWrap); } if(!rows.hasOwnProperty(i + 1)) break; for(var j = 0; j < rows[i + 1].length; j++) { lower.append(rows[i + 1][j]); $(rows[i + 1][j]).wrap(this.options.itemWrap); } } //wrap.css("min-width", this.options.minDiamondsPerRow * this.options.size); return wrap; }; Diamonds.prototype.draw = function() { if(this._triggerEvent("beforeDraw")) return; this._emptyElement(this.wrapElement); var width = this.options.wrapElement.width() - this._getScrollbarWidth(); var rows = this._groupIntoRows(this.itemElements, Math.floor(width / this.options.size), this.options.hideIncompleteRow); var html = this._renderHtml(rows); this.wrapElement.append(html); this._triggerEvent("afterDraw"); }; // jQuery stuff $.fn.diamonds = function(method) { // Initialize if(method === undefined || $.isPlainObject(method)) { method = method || {}; method.wrapElement = this; this.data("diamonds", new Diamonds(method)); return this; } // Call method var inst = this.data("diamonds"); if(inst == null) throw new Error("Diamonds not initialized on this element."); if(Diamonds.prototype.hasOwnProperty(method)) { var args = Array.prototype.slice.call(arguments); args.shift(); if(inst.options.debugEnabled) inst.options.debugMethod(method, args); var ret = Diamonds.prototype[method].apply(inst, args); return ret === undefined ? this : ret; } }; })(window.hasOwnProperty("Zepto") ? window.Zepto : window.jQuery, window, document);