Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

notices paging using pjax #107

Merged
merged 1 commit into from

3 participants

@martinciu
Collaborator

It fixes #106 and gives faster notices switching on the error page.

@ndbroadbent ndbroadbent merged commit b264ce0 into errbit:master
@ndbroadbent
Owner

Thanks, this is awesome!

@gorenje

@ndbroadbent cool -- as long as it works :)

just tried out, fantastic -- thanks guys!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 15, 2011
  1. @martinciu

    notices paging using pjax

    martinciu authored
This page is out of date. Refresh to see the latest.
View
4 app/controllers/errs_controller.rb
@@ -34,6 +34,10 @@ def show
@notices = @problem.notices.paginate(:page => page, :per_page => 1)
@notice = @notices.first
@comment = Comment.new
+ if request.headers['X-PJAX']
+ params["_pjax"] = nil
+ render :layout => false
+ end
end
def create_issue
View
2  config/application.rb
@@ -39,7 +39,7 @@ class Application < Rails::Application
# config.i18n.default_locale = :de
# JavaScript files you want as :defaults (application.js is always included).
- config.action_view.javascript_expansions[:defaults] = %w(jquery underscore-1.1.6 rails form)
+ config.action_view.javascript_expansions[:defaults] = %w(jquery underscore-1.1.6 rails form jquery.pjax)
# > rails generate - config
config.generators do |g|
View
19 public/javascripts/application.js
@@ -2,6 +2,8 @@
$(function() {
+ var currentTab = "summary";
+
function init() {
activateTabbedPanels();
@@ -31,6 +33,17 @@ $(function() {
$('input[type=submit][data-action]').click(function() {
$(this).closest('form').attr('action', $(this).attr('data-action'));
});
+
+ $('.notice-pagination').each(function() {
+ $('.notice-pagination a').pjax('#content', { timeout: 2000});
+ $('#content').bind('pjax:start', function() {
+ currentTab = $('.tab-bar ul li a.button.active').attr('rel');
+ });
+
+ $('#content').bind('pjax:end', function() {
+ activateTabbedPanels();
+ });
+ });
}
function activateTabbedPanels() {
@@ -39,13 +52,13 @@ $(function() {
var panel = $('#'+tab.attr('rel'));
panel.addClass('panel');
panel.find('h3').hide();
- })
+ });
$('.tab-bar a').click(function(){
activateTab($(this));
return(false);
});
- activateTab($('.tab-bar a').first());
+ activateTab($('.tab-bar ul li a.button[rel=' + currentTab + ']'));
}
function activateTab(tab) {
@@ -65,7 +78,7 @@ $(function() {
var checkbox = $(this).find('input[name="problems[]"]');
checkbox.attr('checked', !checkbox.is(':checked'));
}
- })
+ });
}
init();
View
264 public/javascripts/jquery.pjax.js
@@ -0,0 +1,264 @@
+// jquery.pjax.js
+// copyright chris wanstrath
+// https://github.com/defunkt/jquery-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}
+
+ // We can't persist $objects using the history API so we must use
+ // a String selector. Bail if we got anything else.
+ if ( options.container && typeof options.container !== 'string' ) {
+ throw "pjax container must be a string selector!"
+ return false
+ }
+
+ 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'),
+ clickedElement: $(this),
+ fragment: null
+ }
+
+ $.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. Must be a String.
+// $(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.
+var pjax = $.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
+
+ // We can't persist $objects using the history API so we must use
+ // a String selector. Bail if we got anything else.
+ if ( typeof options.container !== 'string' )
+ throw "pjax container must be a string selector!"
+
+ options = $.extend(true, {}, pjax.defaults, options)
+
+ if ( $.isFunction(options.url) ) {
+ options.url = options.url()
+ }
+
+ options.context = $container
+
+ options.success = function(data){
+ if ( options.fragment ) {
+ // If they specified a fragment, look for it in the response
+ // and pull it out.
+ var $fragment = $(data).find(options.fragment)
+ if ( $fragment.length )
+ data = $fragment.children()
+ else
+ return window.location = options.url
+ } else {
+ // 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.
+ this.html(data)
+
+ // If there's a <title> tag in the response, use it as
+ // the page's title.
+ var oldTitle = document.title,
+ title = $.trim( this.find('title').remove().text() )
+ if ( title ) document.title = title
+
+ // No <title>? Fragment? Look for data-title and title attributes.
+ if ( !title && options.fragment ) {
+ title = $fragment.attr('title') || $fragment.data('title')
+ }
+
+ var state = {
+ pjax: options.container,
+ fragment: options.fragment,
+ timeout: options.timeout
+ }
+
+ // 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'])
+
+ // If the URL has a hash in it, make sure the browser
+ // knows to navigate to the hash.
+ var hash = window.location.hash.toString()
+ if ( hash !== '' ) {
+ window.location.href = hash
+ }
+
+ // Invoke their success handler if they gave us one.
+ success.apply(this, arguments)
+ }
+
+ // Cancel the current request if we're already pjaxing
+ var xhr = pjax.xhr
+ if ( xhr && xhr.readyState < 4) {
+ xhr.onreadystatechange = $.noop
+ xhr.abort()
+ }
+
+ pjax.options = options
+ pjax.xhr = $.ajax(options)
+ $(document).trigger('pjax', [pjax.xhr, options])
+
+ return pjax.xhr
+}
+
+
+pjax.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){
+ this.trigger('pjax:start', [xhr, pjax.options])
+ // start.pjax is deprecated
+ this.trigger('start.pjax', [xhr, pjax.options])
+ xhr.setRequestHeader('X-PJAX', 'true')
+ },
+ error: function(xhr, textStatus, errorThrown){
+ if ( textStatus !== 'abort' )
+ window.location = pjax.options.url
+ },
+ complete: function(xhr){
+ this.trigger('pjax:end', [xhr, pjax.options])
+ // end.pjax is deprecated
+ this.trigger('end.pjax', [xhr, pjax.options])
+ }
+}
+
+
+// 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,
+ fragment: state.fragment,
+ 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 ( $.inArray('state', $.event.props) < 0 )
+ $.event.props.push('state')
+
+
+// Is pjax supported by this browser?
+$.support.pjax =
+ window.history && window.history.pushState && window.history.replaceState
+ // pushState isn't reliable on iOS yet.
+ && !navigator.userAgent.match(/(iPod|iPhone|iPad|WebApps\/.+CFNetwork)/)
+
+
+// Fall back to normalcy for older browsers.
+if ( !$.support.pjax ) {
+ $.pjax = function( options ) {
+ window.location = $.isFunction(options.url) ? options.url() : options.url
+ }
+ $.fn.pjax = function() { return this }
+}
+
+})(jQuery);
Something went wrong with that request. Please try again.