Skip to content

Commit

Permalink
enabling pjax
Browse files Browse the repository at this point in the history
  • Loading branch information
scottwater committed May 23, 2011
1 parent 3b886df commit 80468f4
Show file tree
Hide file tree
Showing 12 changed files with 251 additions and 28 deletions.
34 changes: 18 additions & 16 deletions ameba.rb
Expand Up @@ -69,7 +69,7 @@
get '/login' do
set_title = 'Log In'
@user = User.new
slim :login
v :login
end

post '/login' do
Expand All @@ -79,7 +79,7 @@
redirect redirect_to
else
flash[:notice] = "Invalid email/password combination"
slim :login
v :login
end
end

Expand All @@ -92,61 +92,63 @@
end

get '/about' do
set_title "About"
textile :about, :layout_engine => :slim
v :about
end

get '/archive' do
set_title "Archive"
@posts = Post.archive
@robots = "noindex,follow"
slim :archive
v :archive
end

get '/queue' do
login_required!
set_title "Queue"
@posts = Post.queued
@robots = "noindex,nofollow"
slim :queue
v :queue
end

get %r{/(.+)} do |slug|
@post = Post.find_by_slug(slug)
if @post
@post.increment_views unless logged_in?
set_title @post.title
slim :post
v :post
else
404
end
end

get '/' do
set_title
@posts = Post.recent(10, params[:page] || 1)
slim :index
v :index
end

not_found do
set_title "You broke my site!"
@posts = Post.popular
slim :'404'
v :'404'
end

def set_title (text=nil)
@title = text ? "#{text} : #{@site.title}" : @site.title
pjax? ? "<title>#{@title}</title>" : ''
end

private

def editor_form(post)
@post = post
set_title post.title.present? ? post.title : 'Write Something'
slim :editor
v :editor
end

def date_from_form(date)
date = 'now' if date.blank?
Chronic.parse(date).ago(@site.timezone_offset.hours).utc
end

def pjax?
env['HTTP_X_PJAX']
end

def v(name)
slim name, :layout => !pjax?
end
2 changes: 1 addition & 1 deletion lib/models.rb
Expand Up @@ -168,7 +168,7 @@ def set_standard_values(&blog_validation)
# This is not ideal, but it makes it easier to read code in the editor
# and formats it much better for end users
def clean_up_pre_code_blocks(text)
r = Regexp.new('<pre><code( class=".{1,6}")?>\r?\n')
r = Regexp.new('<pre><code( class\s?=\s?".{1,10}")?>\r?\n')
text.gsub(r, '<pre><code>')
end

Expand Down
213 changes: 213 additions & 0 deletions public/js/jquery.pjax.js
@@ -0,0 +1,213 @@
// jquery.pjax.js
// copyright chris wanstrath
// https://github.com/defunkt/pjax

(function($){

// When called on a link, fetches the href with ajax into the
// container specified as the first parameter or with the data-pjax
// attribute on the link itself.
//
// Tries to make sure the back button and ctrl+click work the way
// you'd expect.
//
// Accepts a jQuery ajax options object that may include these
// pjax specific options:
//
// container - Where to stick the response body. Usually a String selector.
// $(container).html(xhr.responseBody)
// push - Whether to pushState the URL. Defaults to true (of course).
// replace - Want to use replaceState instead? That's cool.
//
// For convenience the first parameter can be either the container or
// the options object.
//
// Returns the jQuery object
$.fn.pjax = function( container, options ) {
if ( options )
options.container = container
else
options = $.isPlainObject(container) ? container : {container:container}

return this.live('click', function(event){
// Middle click, cmd click, and ctrl click should open
// links in a new tab as normal.
if ( event.which > 1 || event.metaKey )
return true

var defaults = {
url: this.href,
container: $(this).attr('data-pjax')
}

$.pjax($.extend({}, defaults, options))

event.preventDefault()
})
}


// Loads a URL with ajax, puts the response body inside a container,
// then pushState()'s the loaded URL.
//
// Works just like $.ajax in that it accepts a jQuery ajax
// settings object (with keys like url, type, data, etc).
//
// Accepts these extra keys:
//
// container - Where to stick the response body.
// $(container).html(xhr.responseBody)
// push - Whether to pushState the URL. Defaults to true (of course).
// replace - Want to use replaceState instead? That's cool.
//
// Use it just like $.ajax:
//
// var xhr = $.pjax({ url: this.href, container: '#main' })
// console.log( xhr.readyState )
//
// Returns whatever $.ajax returns.
$.pjax = function( options ) {
var $container = $(options.container),
success = options.success || $.noop

// We don't want to let anyone override our success handler.
delete options.success

var defaults = {
timeout: 650,
push: true,
replace: false,
// We want the browser to maintain two separate internal caches: one for
// pjax'd partial page loads and one for normal page loads. Without
// adding this secret parameter, some browsers will often confuse the two.
data: { _pjax: true },
type: 'GET',
dataType: 'html',
beforeSend: function(xhr){
$container.trigger('start.pjax')
xhr.setRequestHeader('X-PJAX', 'true')
},
error: function(){
window.location = options.url
},
complete: function(){
$container.trigger('end.pjax')
},
success: function(data){
// If we got no data or an entire web page, go directly
// to the page and let normal error handling happen.
if ( !$.trim(data) || /<html/i.test(data) )
return window.location = options.url

// Make it happen.
$container.html(data)

// If there's a <title> tag in the response, use it as
// the page's title.
var oldTitle = document.title,
title = $.trim( $container.find('title').remove().text() )
if ( title ) document.title = title

var state = {
pjax: options.container,
timeout: options.timeout
}

// We can't persist $objects using the history API so we need to store
// the string selector.
if ( $.isPlainObject(state.pjax) )
state.pjax = state.pjax.selector

// If there are extra params, save the complete URL in the state object
var query = $.param(options.data)
if ( query != "_pjax=true" )
state.url = options.url + (/\?/.test(options.url) ? "&" : "?") + query

if ( options.replace ) {
window.history.replaceState(state, document.title, options.url)
} else if ( options.push ) {
// this extra replaceState before first push ensures good back
// button behavior
if ( !$.pjax.active ) {
window.history.replaceState($.extend({}, state, {url:null}), oldTitle)
$.pjax.active = true
}

window.history.pushState(state, document.title, options.url)
}

// Google Analytics support
if ( (options.replace || options.push) && window._gaq )
_gaq.push(['_trackPageview'])

// Invoke their success handler if they gave us one.
success.apply(this, arguments)
}
}

options = $.extend(true, {}, defaults, options)

if ( $.isFunction(options.url) ) {
options.url = options.url()
}

// Cancel the current request if we're already pjaxing
var xhr = $.pjax.xhr
if ( xhr && xhr.readyState < 4) {
xhr.onreadystatechange = $.noop
xhr.abort()
}

$.pjax.xhr = $.ajax(options)
$(document).trigger('pjax', $.pjax.xhr, options)

return $.pjax.xhr
}


// Used to detect initial (useless) popstate.
// If history.state exists, assume browser isn't going to fire initial popstate.
var popped = ('state' in window.history), initialURL = location.href


// popstate handler takes care of the back and forward buttons
//
// You probably shouldn't use pjax on pages with other pushState
// stuff yet.
$(window).bind('popstate', function(event) {
// Ignore inital popstate that some browsers fire on page load
var initialPop = !popped && location.href == initialURL
popped = true
if ( initialPop ) return

var state = event.state

if ( state && state.pjax ) {
var $container = $(state.pjax+'')
if ( $container.length )
$.pjax({
url: state.url || location.href,
container: $container,
push: false,
timeout: state.timeout
})
else
window.location = location.href
}
})


// Add the state property to jQuery's event object so we can use it in
// $(window).bind('popstate')
if ( $.event.props.indexOf('state') < 0 )
$.event.props.push('state')


// Fall back to normalcy for older browsers.
if ( !window.history || !window.history.pushState ) {
$.pjax = $.noop
$.fn.pjax = function() { return this }
}


})(jQuery);
1 change: 1 addition & 0 deletions views/404.slim
@@ -1,3 +1,4 @@
== set_title "You broke my site!"
article
header
h1 OMG! You broke my site!
Expand Down
8 changes: 8 additions & 0 deletions views/about.slim
@@ -0,0 +1,8 @@
== set_title 'About'
article
header
h1 About Scott Watermasysk

section.content
== textile :about

9 changes: 0 additions & 9 deletions views/about.textile
@@ -1,9 +1,3 @@
<article>
<header>
h1. About Scott Watermasysk
</header>
<section class="content">

Hello! Thanks for stopping by.

This is the personal site of Scott Watermasysk.
Expand All @@ -30,6 +24,3 @@ Want more? Have a question?
# "Picture poster":http://crinket.com

Want this site's code? See the "Ameba repository":http://github.com/scottwater/ameba

</section>
</article>
1 change: 1 addition & 0 deletions views/archive.slim
@@ -1,3 +1,4 @@
== set_title "Archive"
article
header
h1 Archive
Expand Down
2 changes: 1 addition & 1 deletion views/editor.slim
@@ -1,3 +1,4 @@
== set_title @post.title.present? ? @post.title : 'Write Something'
article
header
h1 Feel inspired & write something
Expand Down Expand Up @@ -27,7 +28,6 @@ form action=editor_action_link(@post) method="post" id="post"
fieldset
input.submit type="submit" id="post-button" value=editor_button_text(@post) tab="2"

script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"
script type="text/javascript" src="http://cachedcommons.org/cache/jquery-elastic-textarea/1.6.4/javascripts/jquery-elastic-textarea-min.js"
script type="text/javascript" src="/js/incrementable.js"

Expand Down
2 changes: 1 addition & 1 deletion views/index.slim
@@ -1,4 +1,4 @@

== set_title
- @posts.each do |post|
article
header
Expand Down
5 changes: 5 additions & 0 deletions views/layout.slim
Expand Up @@ -14,9 +14,14 @@ html lang="en"
link rel="stylesheet" href="/css/app.css" media="screen, projection"
link href=url_for_feed(@site.feed) type="application/atom+xml" rel="alternate" title=@site.title
link rel="shortcut icon" href="/favicon.ico"
script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"
script type="text/javascript" src="/js/jquery.pjax.js"
script type="text/javascript" src="http://use.typekit.com/qqx1qcd.js"
javascript:
try{Typekit.load();}catch(e){}
$(document).ready(function() {
$('a').pjax('#content');
});
|<!--[if lt IE 9]>
|<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
Expand Down
1 change: 1 addition & 0 deletions views/post.slim
@@ -1,3 +1,4 @@
== set_title @post.title
article
header
h1
Expand Down
1 change: 1 addition & 0 deletions views/queue.slim
@@ -1,3 +1,4 @@
== set_title "Queue"
article
header
h1 Queue
Expand Down

0 comments on commit 80468f4

Please sign in to comment.