@@ -1,5 +1,6 @@ | |||
from tastypie.resources import ModelResource | |||
from tastypie import fields | |||
from tastypie.authorization import DjangoAuthorization | |||
from django.contrib.auth.models import User | |||
@@ -15,7 +16,7 @@ class UserResource(ModelResource): | |||
include_resource_uri = False | |||
class PinResource(ModelResource): # pylint: disable-msg=R0904 | |||
class PinResource(ModelResource): | |||
tags = fields.ListField() | |||
submitter = fields.ForeignKey(UserResource, 'submitter', full=True) | |||
@@ -27,6 +28,7 @@ class PinResource(ModelResource): # pylint: disable-msg=R0904 | |||
'published': ['gt'], | |||
'submitter': ['exact'] | |||
} | |||
authorization = DjangoAuthorization() | |||
def build_filters(self, filters=None): | |||
if filters is None: | |||
@@ -1,33 +1,40 @@ | |||
body { | |||
margin-top: 70px; | |||
background: url("/static/core/img/background.png"); | |||
background: #eee; | |||
} | |||
.navbar-inner { | |||
background-image: none; | |||
background: white; | |||
background: #222; | |||
filter: none; | |||
border-bottom: 1px solid #999; | |||
height: 48px; | |||
} | |||
.navbar .brand { | |||
margin-left: 0; | |||
color: #333; | |||
color: #fff; | |||
font-family: 'Monoton'; | |||
font-size: 30px; | |||
} | |||
.navbar .nav > li > a { | |||
color: #333; | |||
background: #ddd; | |||
text-shadow: none; | |||
border-left: 1px solid #ccc; | |||
padding: 14px 20px 15px; | |||
padding: 3px 13px; | |||
margin: 12px 7px; | |||
border-radius: 2px; | |||
-moz-border-radius: 2px; | |||
-webkit-border-radius: 2px; | |||
} | |||
.navbar .nav > li:last-child > a { | |||
margin-right: 14px; | |||
} | |||
.navbar .nav > li > a:hover { | |||
color: #333; | |||
text-decoration: underline; | |||
color: #ddd; | |||
background: #275173; | |||
} | |||
.messages { | |||
@@ -75,7 +82,7 @@ body { | |||
.pin { | |||
background: #fff; | |||
width: 200px; | |||
border: 1px solid #ccc; | |||
box-shadow: 0 1px 3px #bbb; | |||
padding: 20px; | |||
position: absolute; | |||
} | |||
@@ -1,82 +1,102 @@ | |||
$(window).load(function() { | |||
/** | |||
* tileLayout will simply tile/retile the block/pin container when run. This | |||
* was put into a function in order to adjust frequently on screen size | |||
* changes. | |||
*/ | |||
function tileLayout() { | |||
// Config | |||
// Defines our containers | |||
var blockContainer = $('#pins'); | |||
var blocks = blockContainer.children('.pin'); | |||
// Size of blocks/pins and the spacing between them | |||
var blockMargin = 20; | |||
var blockWidth = 240; | |||
// End Config | |||
var blockContainer = $('#pins'); | |||
var blocks = blockContainer.children('.pin'); | |||
var rowSize = Math.floor(blockContainer.width()/blockWidth); | |||
var blockWidth = (blockContainer.width()-blockMargin*(rowSize))/rowSize; | |||
var colHeights = [] | |||
// How many items we can fit in a row and our array for the row heights | |||
var rowSize = Math.floor(blockContainer.width()/(blockWidth+blockMargin)); | |||
var colHeights = []; | |||
// These are used for horizontal positioning | |||
var rowMargins = []; | |||
var marginLeft = 0; | |||
// Fill our colHeights array with 0 for each row we have | |||
for (var i=0; i < rowSize; i++) colHeights[i] = 0; | |||
// Fill out our rowMargins which will be static after this | |||
for (var i=0; i < rowSize; i++) { | |||
colHeights[i] = 0; | |||
// Our first item has a special margin to keep things centered | |||
if (i == 0) rowMargins[0] = (blockContainer.width()-rowSize*(blockWidth+blockMargin))/2; | |||
else rowMargins[i] = rowMargins[i-1]+(blockWidth+blockMargin); | |||
} | |||
// Loop through every block | |||
for (var b=0; b < blocks.length; b++) { | |||
// Get the jQuery object of the current block | |||
block = blocks.eq(b); | |||
var col = -1; | |||
var colHeight = 0; | |||
// Position our new pin in the shortest column | |||
var sCol = 0; | |||
for (var i=0; i < rowSize; i++) { | |||
if (col < 0) { | |||
col = 0; | |||
colHeight = colHeights[col]; | |||
} else { | |||
if (colHeight > colHeights[i]) { | |||
col = i; | |||
colHeight = colHeights[col]; | |||
} | |||
} | |||
if (colHeights[sCol] > colHeights[i]) sCol = i; | |||
} | |||
block.css({ | |||
'margin-left': blockWidth*col+col*blockMargin | |||
'margin-left': rowMargins[sCol], | |||
'margin-top': colHeights[sCol], | |||
'display': 'block' | |||
}); | |||
blockMarginTop = blockMargin; | |||
block.css({ | |||
'margin-top': colHeight+blockMarginTop | |||
}); | |||
colHeights[col] += block.height()+blockMarginTop; | |||
block.css('display', 'block'); | |||
colHeights[sCol] += block.height()+(blockMargin*3); | |||
} | |||
$('.spinner').css('display', 'none'); | |||
blockContainer.css('height', colHeights.sort().slice(-1)[0]); | |||
} | |||
var offset = 0; | |||
/** | |||
* Load our pins using the pins template into our UI, be sure to define a | |||
* offset outside the function to keep a running tally of your location. | |||
*/ | |||
function loadPins() { | |||
// Show our loading symbol | |||
$('.spinner').css('display', 'block'); | |||
// Fetch our pins from the api using our current offset | |||
$.get('/api/v1/pin/?format=json&offset='+String(offset), function(pins) { | |||
console.log(pins.objects[0]) | |||
var source = $('#pins-template').html(); | |||
var template = Handlebars.compile(source); | |||
var context = { | |||
pins: pins.objects | |||
} | |||
var html = template(context); | |||
// Use the fetched pins as our context for our pins template | |||
var template = Handlebars.compile($('#pins-template').html()); | |||
var html = template({pins: pins.objects}); | |||
// Append the newly compiled data to our container | |||
$('#pins').append(html); | |||
// We need to then wait for images to load in and then tile | |||
$('#pins').ajaxStop(function() { | |||
tileLayout(); | |||
$('img').load(function() { | |||
tileLayout(); | |||
}); | |||
}); | |||
// Up our offset, it's currently defined as 30 in our settings | |||
offset += 30; | |||
}); | |||
} | |||
// Set offset for loadPins and do our initial load | |||
var offset = 0; | |||
loadPins(); | |||
// If our window gets resized keep the tiles looking clean and in our window | |||
$(window).resize(function() { | |||
tileLayout(); | |||
}) | |||
// If we scroll to the bottom of the document load more pins | |||
$(window).scroll(function() { | |||
if($(window).scrollTop() + $(window).height() > $(document).height() - 100) { | |||
loadPins(); | |||
@@ -1,12 +1,13 @@ | |||
{% spaceless %} | |||
{% load new_pin %} | |||
{% load compress %} | |||
{% load verbatim %} | |||
<!DOCTYPE html> | |||
<html> | |||
<head> | |||
<title>{{ site_name }} - {% block title %}{% endblock %}</title> | |||
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Monoton"> | |||
{% compress css %} | |||
<link rel="stylesheet" href="/static/vendor/bootstrap/2.0.3/css/bootstrap.css"> | |||
<link rel="stylesheet" href="/static/vendor/fancybox/2.0.6/jquery.fancybox.css"> | |||
@@ -14,7 +15,6 @@ | |||
<link rel="stylesheet" href="/static/core/css/pinry.css"> | |||
{% endcompress %} | |||
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Monoton"> | |||
</head> | |||
<body> | |||
<div class="navbar navbar-fixed-top"> | |||
@@ -47,38 +47,23 @@ | |||
{% new_pin request %} | |||
{% verbatim %} | |||
<script id="pins-template" type="text/x-handlebars-template"> | |||
{{#each pins}} | |||
<div class="pin"> | |||
<img src="{{thumbnail}}"> | |||
{{#if description}} | |||
<p>{{description}}</p> | |||
{{/if}} | |||
{{#if tags}} | |||
<p> | |||
{{#each tags}} | |||
<span class="label">{{this}}</span> | |||
{{/each}} | |||
</p> | |||
{{/if}} | |||
</div> | |||
{{/each}} | |||
{% block templates %}{% endblock %} | |||
{% compress js inline %} | |||
<script> | |||
var username = "{{ user.username }}"; | |||
var isSuperuser = {{ user.is_superuser|lower }}; | |||
</script> | |||
{% endverbatim %} | |||
{% endcompress %} | |||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> | |||
{% compress js %} | |||
<script src="/static/vendor/jquery/1.7.2/jquery.js"></script> | |||
<script src="/static/vendor/bootstrap/2.0.3/js/bootstrap.js"></script> | |||
<script src="/static/vendor/handlebars/handlebars.js"></script> | |||
<script> | |||
var username = "{{ user.username }}"; | |||
var isSuperuser = {{ user.is_superuser|lower }}; | |||
</script> | |||
<script src="/static/vendor/handlebars/1.0.0/handlebars.js"></script> | |||
<script src="/static/core/js/pinry.js"></script> | |||
<script src="/static/core/js/messages.js"></script> | |||
{% endcompress %} | |||
</body> | |||
</html> | |||
{% endspaceless %} |
@@ -1,4 +1,5 @@ | |||
{% extends 'core/base.html' %} | |||
{% load verbatim %} | |||
{% block title %}Recent Pins{% endblock %} | |||
@@ -6,9 +7,34 @@ | |||
<div id="pins"></div> | |||
<div class="container spinner"> | |||
<div class="row"> | |||
<div class="span2 offset5"> | |||
<div class="span12" align="center"> | |||
<img src="/static/core/img/loader.gif" alt="Loader"> | |||
</div> | |||
</div> | |||
</div> | |||
{% endblock %} | |||
{% block templates %} | |||
{% verbatim %} | |||
<script id="pins-template" type="text/x-handlebars-template"> | |||
{{#each pins}} | |||
<div class="pin"> | |||
{{#if editable}} | |||
<i class="icon-white icon-pencil"></i> | |||
{{/if}} | |||
<img src="{{thumbnail}}" /> | |||
{{#if description}} | |||
<p>{{description}}</p> | |||
{{/if}} | |||
{{#if tags}} | |||
<p> | |||
{{#each tags}} | |||
<span class="label">{{this}}</span> | |||
{{/each}} | |||
</p> | |||
{{/if}} | |||
</div> | |||
{{/each}} | |||
</script> | |||
{% endverbatim %} | |||
{% endblock %} |
@@ -1,112 +0,0 @@ | |||
/*! | |||
* jQuery imagesLoaded plugin v2.0.1 | |||
* http://github.com/desandro/imagesloaded | |||
* | |||
* MIT License. by Paul Irish et al. | |||
*/ | |||
/*jshint curly: true, eqeqeq: true, noempty: true, strict: true, undef: true, browser: true */ | |||
/*global jQuery: false */ | |||
;(function($, undefined) { | |||
'use strict'; | |||
// blank image data-uri bypasses webkit log warning (thx doug jones) | |||
var BLANK = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=='; | |||
$.fn.imagesLoaded = function( callback ) { | |||
var $this = this, | |||
deferred = $.isFunction($.Deferred) ? $.Deferred() : 0, | |||
hasNotify = $.isFunction(deferred.notify), | |||
$images = $this.find('img').add( $this.filter('img') ), | |||
loaded = [], | |||
proper = [], | |||
broken = []; | |||
function doneLoading() { | |||
var $proper = $(proper), | |||
$broken = $(broken); | |||
if ( deferred ) { | |||
if ( broken.length ) { | |||
deferred.reject( $images, $proper, $broken ); | |||
} else { | |||
deferred.resolve( $images ); | |||
} | |||
} | |||
if ( $.isFunction( callback ) ) { | |||
callback.call( $this, $images, $proper, $broken ); | |||
} | |||
} | |||
function imgLoaded( img, isBroken ) { | |||
// don't proceed if BLANK image, or image is already loaded | |||
if ( img.src === BLANK || $.inArray( img, loaded ) !== -1 ) { | |||
return; | |||
} | |||
// store element in loaded images array | |||
loaded.push( img ); | |||
// keep track of broken and properly loaded images | |||
if ( isBroken ) { | |||
broken.push( img ); | |||
} else { | |||
proper.push( img ); | |||
} | |||
// cache image and its state for future calls | |||
$.data( img, 'imagesLoaded', { isBroken: isBroken, src: img.src } ); | |||
// trigger deferred progress method if present | |||
if ( hasNotify ) { | |||
deferred.notifyWith( $(img), [ isBroken, $images, $(proper), $(broken) ] ); | |||
} | |||
// call doneLoading and clean listeners if all images are loaded | |||
if ( $images.length === loaded.length ){ | |||
setTimeout( doneLoading ); | |||
$images.unbind( '.imagesLoaded' ); | |||
} | |||
} | |||
// if no images, trigger immediately | |||
if ( !$images.length ) { | |||
doneLoading(); | |||
} else { | |||
$images.bind( 'load.imagesLoaded error.imagesLoaded', function( event ){ | |||
// trigger imgLoaded | |||
imgLoaded( event.target, event.type === 'error' ); | |||
}).each( function( i, el ) { | |||
var src = el.src; | |||
// find out if this image has been already checked for status | |||
// if it was, and src has not changed, call imgLoaded on it | |||
var cached = $.data( el, 'imagesLoaded' ); | |||
if ( cached && cached.src === src ) { | |||
imgLoaded( el, cached.isBroken ); | |||
return; | |||
} | |||
// if complete is true and browser supports natural sizes, try | |||
// to check for image status manually | |||
if ( el.complete && el.naturalWidth !== undefined ) { | |||
imgLoaded( el, el.naturalWidth === 0 || el.naturalHeight === 0 ); | |||
return; | |||
} | |||
// cached images don't fire load sometimes, so we reset src, but only when | |||
// dealing with IE, or image is complete (loaded) and failed manual check | |||
// webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f | |||
if ( el.readyState || el.complete ) { | |||
el.src = BLANK; | |||
el.src = src; | |||
} | |||
}); | |||
} | |||
return deferred ? deferred.promise( $this ) : $this; | |||
}; | |||
})(jQuery); |
@@ -1,2 +0,0 @@ | |||
(function(c,n){var k="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";c.fn.imagesLoaded=function(l){function m(){var b=c(h),a=c(g);d&&(g.length?d.reject(e,b,a):d.resolve(e));c.isFunction(l)&&l.call(f,e,b,a)}function i(b,a){b.src===k||-1!==c.inArray(b,j)||(j.push(b),a?g.push(b):h.push(b),c.data(b,"imagesLoaded",{isBroken:a,src:b.src}),o&&d.notifyWith(c(b),[a,e,c(h),c(g)]),e.length===j.length&&(setTimeout(m),e.unbind(".imagesLoaded")))}var f=this,d=c.isFunction(c.Deferred)?c.Deferred(): | |||
0,o=c.isFunction(d.notify),e=f.find("img").add(f.filter("img")),j=[],h=[],g=[];e.length?e.bind("load.imagesLoaded error.imagesLoaded",function(b){i(b.target,"error"===b.type)}).each(function(b,a){var e=a.src,d=c.data(a,"imagesLoaded");if(d&&d.src===e)i(a,d.isBroken);else if(a.complete&&a.naturalWidth!==n)i(a,0===a.naturalWidth||0===a.naturalHeight);else if(a.readyState||a.complete)a.src=k,a.src=e}):m();return d?d.promise(f):f}})(jQuery); |
@@ -1,78 +0,0 @@ | |||
/****************************************** | |||
* Websanova.com | |||
* | |||
* Resources for web entrepreneurs | |||
* | |||
* @author Websanova | |||
* @copyright Copyright (c) 2012 Websanova. | |||
* @license This websanova JavaScript url is dual licensed under the MIT and GPL licenses. | |||
* @link http://www.websanova.com | |||
* @github http://github.com/websanova/js-url | |||
* @version 1.7.2 | |||
* | |||
******************************************/ | |||
window.url = (function() { | |||
function isNumeric(arg) { | |||
return !isNaN(parseFloat(arg)) && isFinite(arg); | |||
} | |||
return function url(arg, url) { | |||
var _ls = url || window.location.toString(); | |||
if(_ls.substring(0,2) === '//') _ls = 'http:' + _ls; | |||
else if(_ls.split('://').length === 1) _ls = 'http://' + _ls; | |||
url = _ls.split('/'); | |||
var _l = {auth:''}, host = url[2].split('@'); | |||
if(host.length === 1) host = host[0].split(':'); | |||
else{ _l.auth = host[0]; host = host[1].split(':'); } | |||
_l.protocol=url[0], _l.hostname=host[0], _l.port=(host[1]||'80'), _l.pathname='/' + url.slice(3, url.length).join('/').split('?')[0].split('#')[0]; | |||
var _p = _l.pathname; | |||
if(_p.split('.').length === 1 && _p[_p.length-1] !== '/') _p += '/'; | |||
var _h = _l.hostname, _hs = _h.split('.'), _ps = _p.split('/'); | |||
if(!arg) return _ls; | |||
else if(arg === 'hostname') return _h; | |||
else if(arg === 'domain') return _hs.slice(-2).join('.'); | |||
else if(arg === 'tld') return _hs.slice(-1).join('.'); | |||
else if(arg === 'sub') return _hs.slice(0, _hs.length - 2).join('.'); | |||
else if(arg === 'port') return _l.port || '80'; | |||
else if(arg === 'protocol') return _l.protocol.split(':')[0]; | |||
else if(arg === 'auth') return _l.auth; | |||
else if(arg === 'user') return _l.auth.split(':')[0]; | |||
else if(arg === 'pass') return _l.auth.split(':')[1] || ''; | |||
else if(arg === 'path') return _p; | |||
else if(arg[0] === '.') | |||
{ | |||
arg = arg.substring(1); | |||
if(isNumeric(arg)) {arg = parseInt(arg); return _hs[arg < 0 ? _hs.length + arg : arg-1] || ''; } | |||
} | |||
else if(isNumeric(arg)){ arg = parseInt(arg); return _ps[arg < 0 ? _ps.length - 1 + arg : arg] || ''; } | |||
else if(arg === 'file') return _ps.slice(-1)[0]; | |||
else if(arg === 'filename') return _ps.slice(-1)[0].split('.')[0]; | |||
else if(arg === 'fileext') return _ps.slice(-1)[0].split('.')[1] || ''; | |||
else if(arg[0] === '?' || arg[0] === '#') | |||
{ | |||
var params = _ls, param = null; | |||
if(arg[0] === '?') params = (params.split('?')[1] || '').split('#')[0]; | |||
else if(arg[0] === '#') params = (params.split('#')[1] || ''); | |||
if(!arg[1]) return params; | |||
arg = arg.substring(1); | |||
params = params.split('&'); | |||
for(var i=0,ii=params.length; i<ii; i++) | |||
{ | |||
param = params[i].split('='); | |||
if(param[0] === arg) return param[1]; | |||
} | |||
} | |||
return ''; | |||
} | |||
})(); |
@@ -1 +0,0 @@ | |||
/* url() v1.7.2 - http://github.com/websanova/js-url */window.url=(function(){function b(c){return !isNaN(parseFloat(c))&&isFinite(c)}return function a(p,d){var c=d||window.location.toString();if(c.substring(0,2)==="//"){c="http:"+c}else{if(c.split("://").length===1){c="http://"+c}}d=c.split("/");var g={auth:""},o=d[2].split("@");if(o.length===1){o=o[0].split(":")}else{g.auth=o[0];o=o[1].split(":")}g.protocol=d[0],g.hostname=o[0],g.port=(o[1]||"80"),g.pathname="/"+d.slice(3,d.length).join("/").split("?")[0].split("#")[0];var e=g.pathname;if(e.split(".").length===1&&e[e.length-1]!=="/"){e+="/"}var k=g.hostname,l=k.split("."),m=e.split("/");if(!p){return c}else{if(p==="hostname"){return k}else{if(p==="domain"){return l.slice(-2).join(".")}else{if(p==="tld"){return l.slice(-1).join(".")}else{if(p==="sub"){return l.slice(0,l.length-2).join(".")}else{if(p==="port"){return g.port||"80"}else{if(p==="protocol"){return g.protocol.split(":")[0]}else{if(p==="auth"){return g.auth}else{if(p==="user"){return g.auth.split(":")[0]}else{if(p==="pass"){return g.auth.split(":")[1]||""}else{if(p==="path"){return e}else{if(p[0]==="."){p=p.substring(1);if(b(p)){p=parseInt(p);return l[p<0?l.length+p:p-1]||""}}else{if(b(p)){p=parseInt(p);return m[p<0?m.length-1+p:p]||""}else{if(p==="file"){return m.slice(-1)[0]}else{if(p==="filename"){return m.slice(-1)[0].split(".")[0]}else{if(p==="fileext"){return m.slice(-1)[0].split(".")[1]||""}else{if(p[0]==="?"||p[0]==="#"){var h=c,f=null;if(p[0]==="?"){h=(h.split("?")[1]||"").split("#")[0]}else{if(p[0]==="#"){h=(h.split("#")[1]||"")}}if(!p[1]){return h}p=p.substring(1);h=h.split("&");for(var j=0,n=h.length;j<n;j++){f=h[j].split("=");if(f[0]===p){return f[1]}}}}}}}}}}}}}}}}}}}return""}})(); |
@@ -1,169 +0,0 @@ | |||
/*! | |||
jQuery Wookmark plugin 0.5 | |||
@name jquery.wookmark.js | |||
@author Christoph Ono (chri@sto.ph or @gbks) | |||
@version 0.5 | |||
@date 3/19/2012 | |||
@category jQuery plugin | |||
@copyright (c) 2009-2012 Christoph Ono (www.wookmark.com) | |||
@license Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. | |||
*/ | |||
$.fn.wookmark = function(options) { | |||
if(!this.wookmarkOptions) { | |||
this.wookmarkOptions = $.extend( { | |||
container: $('body'), | |||
offset: 2, | |||
autoResize: false, | |||
itemWidth: $(this[0]).outerWidth(), | |||
resizeDelay: 50 | |||
}, options); | |||
} else if(options) { | |||
this.wookmarkOptions = $.extend(this.wookmarkOptions, options); | |||
} | |||
// Layout variables. | |||
if(!this.wookmarkColumns) { | |||
this.wookmarkColumns = null; | |||
this.wookmarkContainerWidth = null; | |||
} | |||
// Main layout function. | |||
this.wookmarkLayout = function() { | |||
// Calculate basic layout parameters. | |||
var columnWidth = this.wookmarkOptions.itemWidth + this.wookmarkOptions.offset; | |||
var containerWidth = this.wookmarkOptions.container.width(); | |||
var columns = Math.floor((containerWidth+this.wookmarkOptions.offset)/columnWidth); | |||
var offset = Math.round((containerWidth - (columns*columnWidth-this.wookmarkOptions.offset))/2); | |||
// If container and column count hasn't changed, we can only update the columns. | |||
var bottom = 0; | |||
if(this.wookmarkColumns != null && this.wookmarkColumns.length == columns) { | |||
bottom = this.wookmarkLayoutColumns(columnWidth, offset); | |||
} else { | |||
bottom = this.wookmarkLayoutFull(columnWidth, columns, offset); | |||
} | |||
// Set container height to height of the grid. | |||
this.wookmarkOptions.container.css('height', bottom+'px'); | |||
}; | |||
/** | |||
* Perform a full layout update. | |||
*/ | |||
this.wookmarkLayoutFull = function(columnWidth, columns, offset) { | |||
// Prepare Array to store height of columns. | |||
var heights = []; | |||
while(heights.length < columns) { | |||
heights.push(0); | |||
} | |||
// Store column data. | |||
this.wookmarkColumns = []; | |||
while(this.wookmarkColumns.length < columns) { | |||
this.wookmarkColumns.push([]); | |||
} | |||
// Loop over items. | |||
var item, top, left, i=0, k=0, length=this.length, shortest=null, shortestIndex=null, bottom = 0; | |||
for(; i<length; i++ ) { | |||
item = $(this[i]); | |||
// Find the shortest column. | |||
shortest = null; | |||
shortestIndex = 0; | |||
for(k=0; k<columns; k++) { | |||
if(shortest == null || heights[k] < shortest) { | |||
shortest = heights[k]; | |||
shortestIndex = k; | |||
} | |||
} | |||
// Postion the item. | |||
item.css({ | |||
position: 'absolute', | |||
top: shortest+'px', | |||
left: (shortestIndex*columnWidth + offset)+'px' | |||
}); | |||
// Update column height. | |||
heights[shortestIndex] = shortest + item.outerHeight() + this.wookmarkOptions.offset; | |||
bottom = Math.max(bottom, heights[shortestIndex]); | |||
this.wookmarkColumns[shortestIndex].push(item); | |||
} | |||
return bottom; | |||
}; | |||
/** | |||
* This layout function only updates the vertical position of the | |||
* existing column assignments. | |||
*/ | |||
this.wookmarkLayoutColumns = function(columnWidth, offset) { | |||
var heights = []; | |||
while(heights.length < this.wookmarkColumns.length) { | |||
heights.push(0); | |||
} | |||
var i=0, length = this.wookmarkColumns.length, column; | |||
var k=0, kLength, item; | |||
var bottom = 0; | |||
for(; i<length; i++) { | |||
column = this.wookmarkColumns[i]; | |||
kLength = column.length; | |||
for(k=0; k<kLength; k++) { | |||
item = column[k]; | |||
item.css({ | |||
left: (i*columnWidth + offset)+'px', | |||
top: heights[i]+'px' | |||
}); | |||
heights[i] += item.outerHeight() + this.wookmarkOptions.offset; | |||
bottom = Math.max(bottom, heights[i]); | |||
} | |||
} | |||
return bottom; | |||
}; | |||
// Listen to resize event if requested. | |||
this.wookmarkResizeTimer = null; | |||
if(!this.wookmarkResizeMethod) { | |||
this.wookmarkResizeMethod = null; | |||
} | |||
if(this.wookmarkOptions.autoResize) { | |||
// This timer ensures that layout is not continuously called as window is being dragged. | |||
this.wookmarkOnResize = function(event) { | |||
if(this.wookmarkResizeTimer) { | |||
clearTimeout(this.wookmarkResizeTimer); | |||
} | |||
this.wookmarkResizeTimer = setTimeout($.proxy(this.wookmarkLayout, this), this.wookmarkOptions.resizeDelay) | |||
}; | |||
// Bind event listener. | |||
if(!this.wookmarkResizeMethod) { | |||
this.wookmarkResizeMethod = $.proxy(this.wookmarkOnResize, this); | |||
} | |||
$(window).resize(this.wookmarkResizeMethod); | |||
}; | |||
/** | |||
* Clear event listeners and time outs. | |||
*/ | |||
this.wookmarkClear = function() { | |||
if(this.wookmarkResizeTimer) { | |||
clearTimeout(this.wookmarkResizeTimer); | |||
this.wookmarkResizeTimer = null; | |||
} | |||
if(this.wookmarkResizeMethod) { | |||
$(window).unbind('resize', this.wookmarkResizeMethod); | |||
} | |||
}; | |||
// Apply layout | |||
this.wookmarkLayout(); | |||
// Display items (if hidden). | |||
this.show(); | |||
}; |
@@ -1,11 +0,0 @@ | |||
/*! | |||
jQuery Wookmark plugin 0.5 | |||
@name jquery.wookmark.js | |||
@author Christoph Ono (chri@sto.ph or @gbks) | |||
@version 0.5 | |||
@date 3/19/2012 | |||
@category jQuery plugin | |||
@copyright (c) 2009-2012 Christoph Ono (www.wookmark.com) | |||
@license Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. | |||
*/ | |||
$.fn.wookmark=function(a){if(!this.wookmarkOptions){this.wookmarkOptions=$.extend({container:$("body"),offset:2,autoResize:false,itemWidth:$(this[0]).outerWidth(),resizeDelay:50},a)}else if(a){this.wookmarkOptions=$.extend(this.wookmarkOptions,a)}if(!this.wookmarkColumns){this.wookmarkColumns=null;this.wookmarkContainerWidth=null}this.wookmarkLayout=function(){var a=this.wookmarkOptions.itemWidth+this.wookmarkOptions.offset;var b=this.wookmarkOptions.container.width();var c=Math.floor((b+this.wookmarkOptions.offset)/a);var d=Math.round((b-(c*a-this.wookmarkOptions.offset))/2);var e=0;if(this.wookmarkColumns!=null&&this.wookmarkColumns.length==c){e=this.wookmarkLayoutColumns(a,d)}else{e=this.wookmarkLayoutFull(a,c,d)}this.wookmarkOptions.container.css("height",e+"px")};this.wookmarkLayoutFull=function(a,b,c){var d=[];while(d.length<b){d.push(0)}this.wookmarkColumns=[];while(this.wookmarkColumns.length<b){this.wookmarkColumns.push([])}var e,f,g,h=0,i=0,j=this.length,k=null,l=null,m=0;for(;h<j;h++){e=$(this[h]);k=null;l=0;for(i=0;i<b;i++){if(k==null||d[i]<k){k=d[i];l=i}}e.css({position:"absolute",top:k+"px",left:l*a+c+"px"});d[l]=k+e.outerHeight()+this.wookmarkOptions.offset;m=Math.max(m,d[l]);this.wookmarkColumns[l].push(e)}return m};this.wookmarkLayoutColumns=function(a,b){var c=[];while(c.length<this.wookmarkColumns.length){c.push(0)}var d=0,e=this.wookmarkColumns.length,f;var g=0,h,i;var j=0;for(;d<e;d++){f=this.wookmarkColumns[d];h=f.length;for(g=0;g<h;g++){i=f[g];i.css({left:d*a+b+"px",top:c[d]+"px"});c[d]+=i.outerHeight()+this.wookmarkOptions.offset;j=Math.max(j,c[d])}}return j};this.wookmarkResizeTimer=null;if(!this.wookmarkResizeMethod){this.wookmarkResizeMethod=null}if(this.wookmarkOptions.autoResize){this.wookmarkOnResize=function(a){if(this.wookmarkResizeTimer){clearTimeout(this.wookmarkResizeTimer)}this.wookmarkResizeTimer=setTimeout($.proxy(this.wookmarkLayout,this),this.wookmarkOptions.resizeDelay)};if(!this.wookmarkResizeMethod){this.wookmarkResizeMethod=$.proxy(this.wookmarkOnResize,this)}$(window).resize(this.wookmarkResizeMethod)}this.wookmarkClear=function(){if(this.wookmarkResizeTimer){clearTimeout(this.wookmarkResizeTimer);this.wookmarkResizeTimer=null}if(this.wookmarkResizeMethod){$(window).unbind("resize",this.wookmarkResizeMethod)}};this.wookmarkLayout();this.show()} |