diff --git a/app/controllers/errs_controller.rb b/app/controllers/errs_controller.rb index 618db0e..b941d93 100644 --- a/app/controllers/errs_controller.rb +++ b/app/controllers/errs_controller.rb @@ -34,6 +34,10 @@ class ErrsController < ApplicationController @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 diff --git a/config/application.rb b/config/application.rb index a7656b5..d2270c2 100644 --- a/config/application.rb +++ b/config/application.rb @@ -39,7 +39,7 @@ module Errbit # 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| diff --git a/public/javascripts/application.js b/public/javascripts/application.js index fe792f2..e3bc0db 100644 --- a/public/javascripts/application.js +++ b/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(); diff --git a/public/javascripts/jquery.pjax.js b/public/javascripts/jquery.pjax.js new file mode 100644 index 0000000..6d2533a --- /dev/null +++ b/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) || / 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