Browse Source

Started the creation of an API and implemented infinite scroll. Closes issue #7.

tags/v0.2.0
Isaac Bythewood 12 years ago
parent
commit
f88a06aefa
13 changed files with 237 additions and 21 deletions
  1. +0
    -0
      pinry/api/__init__.py
  2. +6
    -0
      pinry/api/urls.py
  3. +21
    -0
      pinry/api/views.py
  4. +6
    -0
      pinry/core/static/core/css/pinry.css
  5. BIN
      pinry/core/static/core/img/loader.gif
  6. +79
    -5
      pinry/core/static/core/js/pinry.js
  7. +2
    -0
      pinry/core/templates/core/base.html
  8. +6
    -12
      pinry/pins/templates/pins/recent_pins.html
  9. +1
    -4
      pinry/pins/views.py
  10. +1
    -0
      pinry/settings/__init__.py
  11. +1
    -0
      pinry/urls.py
  12. +112
    -0
      pinry/vendor/static/vendor/imagesloaded/2.0.1/jquery.imagesloaded.js
  13. +2
    -0
      pinry/vendor/static/vendor/imagesloaded/2.0.1/jquery.imagesloaded.min.js

+ 0
- 0
pinry/api/__init__.py View File


+ 6
- 0
pinry/api/urls.py View File

@@ -0,0 +1,6 @@
from django.conf.urls import patterns, include, url


urlpatterns = patterns('',
url(r'^pins/recent/(?P<page>\d*)/$', 'pinry.api.views.pins_recent', name='pins-recent'),
)

+ 21
- 0
pinry/api/views.py View File

@@ -0,0 +1,21 @@
from django.utils import simplejson
from django.http import HttpResponse

from pinry.pins.models import Pin


def pins_recent(request, page=1):
start_pin = abs(int(page) - 1) * 25
end_pin = int(page) * 25

pins = Pin.objects.order_by('-id')[start_pin:end_pin]
recent_pins = []
for pin in pins:
recent_pins.append({
'id': pin.id,
'thumbnail': pin.image.url_200x1000,
'original': pin.image.url,
'description': pin.description,
})

return HttpResponse(simplejson.dumps(recent_pins), mimetype="application/json")

+ 6
- 0
pinry/core/static/core/css/pinry.css View File

@@ -29,6 +29,11 @@ body {
text-decoration: underline;
}

#loader {
margin-top: 70px;
text-align: center;
}

#pins {
top: 70px;
position: absolute;
@@ -41,6 +46,7 @@ body {
float: left;
border: 1px solid #ccc;
padding: 20px;
display: none;
}

.pin img {


BIN
pinry/core/static/core/img/loader.gif View File

Before After
Width: 31  |  Height: 31  |  Size: 2.5 KiB

+ 79
- 5
pinry/core/static/core/js/pinry.js View File

@@ -1,10 +1,84 @@
$(window).bind('load', function() {
$('.pin').wookmark({
offset: 3,
itemWidth: 242,
autoResize: true
/**
* Based on Wookmark's endless scroll.
*/
$(window).ready(function () {
var apiURL = '/api/pins/recent/'
var page = 1;
var handler = null;
var isLoading = false;
/**
* When scrolled all the way to the bottom, add more tiles.
*/
function onScroll(event) {
if(!isLoading) {
var closeToBottom = ($(window).scrollTop() + $(window).height() > $(document).height() - 100);
if(closeToBottom) loadData();
}
};
function applyLayout() {
$('#pins').imagesLoaded(function() {
// Clear our previous layout handler.
if(handler) handler.wookmarkClear();
// Create a new layout handler.
handler = $('#pins .pin');
handler.wookmark({
autoResize: true,
offset: 3,
itemWidth: 242
});
});
};
/**
* Loads data from the API.
*/
function loadData() {
isLoading = true;
$('#loader').show();
$.ajax({
url: apiURL+page,
success: onLoadData
});
};
/**
* Receives data from the API, creates HTML for images and updates the layout
*/
function onLoadData(data) {
isLoading = false;
$('#loader').hide();
page++;
var html = '';
var i=0, length=data.length, image;
for(; i<length; i++) {
image = data[i];
html += '<div class="pin">';
html += '<a class="fancybox" rel="pins" href="'+image.original+'">';
html += '<img src="'+image.thumbnail+'" width="200" height="'+Math.round(image.height/image.width*200)+'">';
html += '</a>';
html += '<p>'+image.description+'</p>';
html += '</div>';
}
$('#pins').append(html);
applyLayout();
};
$(document).ready(new function() {
$(document).bind('scroll', onScroll);
loadData();
});

/**
* On clicking an image show fancybox original.
*/
$('.fancybox').fancybox({
openEffect: 'none',
closeEffect: 'none'


+ 2
- 0
pinry/core/templates/core/base.html View File

@@ -39,11 +39,13 @@
<script src="/static/vendor/bootstrap/2.0.3/js/bootstrap.js"></script>
<script src="/static/vendor/wookmark/0.5/jquery.wookmark.js"></script>
<script src="/static/vendor/fancybox/2.0.6/jquery.fancybox.js"></script>
<script src="/static/vendor/imagesloaded/2.0.1/jquery.imagesloaded.js"></script>
{% else %}
<script src="/static/vendor/jquery/1.7.2/jquery.min.js"></script>
<script src="/static/vendor/bootstrap/2.0.3/js/bootstrap.min.js"></script>
<script src="/static/vendor/wookmark/0.5/jquery.wookmark.min.js"></script>
<script src="/static/vendor/fancybox/2.0.6/jquery.fancybox.pack.js"></script>
<script src="/static/vendor/imagesloaded/2.0.1/jquery.imagesloaded.min.js"></script>
{% endif %}

<script src="/static/core/js/pinry.js"></script>


+ 6
- 12
pinry/pins/templates/pins/recent_pins.html View File

@@ -3,18 +3,12 @@
{% block title %}Recent Pins{% endblock %}

{% block yield %}
<div id="pins">
{% for pin in pins %}
<div class="pin">
{% if pin.image %}
<a class="fancybox" rel="pins" href="{{ pin.image.url }}">
<img src="{{ pin.image.url_200x1000 }}" alt="{{ pin.description }}">
</a>
{% endif %}
{% if pin.description %}
<p><strong>Description:</strong> {{ pin.description }}</p>
{% endif %}
<div id="pins"></div>
<div id="loader" class="container">
<div class="row">
<div class="span2 offset5">
<img src="/static/core/img/loader.gif" alt="Loader">
</div>
{% endfor %}
</div>
</div>
{% endblock %}

+ 1
- 4
pinry/pins/views.py View File

@@ -7,10 +7,7 @@ from .forms import PinForm


def recent_pins(request):
context = {
'pins': Pin.objects.order_by('-id')[:50],
}
return TemplateResponse(request, 'pins/recent_pins.html', context)
return TemplateResponse(request, 'pins/recent_pins.html', None)


def new_pin(request):


+ 1
- 0
pinry/settings/__init__.py View File

@@ -53,4 +53,5 @@ INSTALLED_APPS = (
'pinry.vendor',
'pinry.core',
'pinry.pins',
'pinry.api',
)

+ 1
- 0
pinry/urls.py View File

@@ -6,4 +6,5 @@ from django.conf import settings
urlpatterns = patterns('',
url(r'', include('pinry.core.urls', namespace='core')),
url(r'^pins/', include('pinry.pins.urls', namespace='pins')),
url(r'^api/', include('pinry.api.urls', namespace='api')),
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

+ 112
- 0
pinry/vendor/static/vendor/imagesloaded/2.0.1/jquery.imagesloaded.js View File

@@ -0,0 +1,112 @@
/*!
* 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);

+ 2
- 0
pinry/vendor/static/vendor/imagesloaded/2.0.1/jquery.imagesloaded.min.js View File

@@ -0,0 +1,2 @@
(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);

Loading…
Cancel
Save