Skip to content
This repository

notices paging using pjax #107

Merged
merged 1 commit into from over 2 years ago

3 participants

Marcin Ciunelis Nathan Broadbent Gerrit Riessen
Marcin Ciunelis
Collaborator

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

Nathan Broadbent ndbroadbent merged commit b264ce0 into from October 15, 2011
Nathan Broadbent ndbroadbent closed this October 15, 2011
Nathan Broadbent
Owner

Thanks, this is awesome!

Gerrit Riessen

@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

Showing 1 unique commit by 1 author.

Oct 15, 2011
Marcin Ciunelis notices paging using pjax e17caf0
This page is out of date. Refresh to see the latest.
4  app/controllers/errs_controller.rb
@@ -34,6 +34,10 @@ def show
34 34
     @notices  = @problem.notices.paginate(:page => page, :per_page => 1)
35 35
     @notice   = @notices.first
36 36
     @comment = Comment.new
  37
+    if request.headers['X-PJAX']
  38
+      params["_pjax"] = nil
  39
+      render :layout => false
  40
+    end
37 41
   end
38 42
 
39 43
   def create_issue
2  config/application.rb
@@ -39,7 +39,7 @@ class Application < Rails::Application
39 39
     # config.i18n.default_locale = :de
40 40
 
41 41
     # JavaScript files you want as :defaults (application.js is always included).
42  
-    config.action_view.javascript_expansions[:defaults] = %w(jquery underscore-1.1.6 rails form)
  42
+    config.action_view.javascript_expansions[:defaults] = %w(jquery underscore-1.1.6 rails form jquery.pjax)
43 43
 
44 44
     # > rails generate - config
45 45
     config.generators do |g|
19  public/javascripts/application.js
@@ -2,6 +2,8 @@
2 2
 
3 3
 $(function() {
4 4
   
  5
+  var currentTab = "summary";
  6
+  
5 7
   function init() {
6 8
     
7 9
     activateTabbedPanels();
@@ -31,6 +33,17 @@ $(function() {
31 33
     $('input[type=submit][data-action]').click(function() {
32 34
       $(this).closest('form').attr('action', $(this).attr('data-action'));
33 35
     });
  36
+    
  37
+    $('.notice-pagination').each(function() {
  38
+      $('.notice-pagination a').pjax('#content', { timeout: 2000});
  39
+      $('#content').bind('pjax:start',  function() {
  40
+        currentTab = $('.tab-bar ul li a.button.active').attr('rel');
  41
+      });
  42
+
  43
+      $('#content').bind('pjax:end',  function() {
  44
+        activateTabbedPanels();
  45
+      });
  46
+    });
34 47
   }
35 48
   
36 49
   function activateTabbedPanels() {
@@ -39,13 +52,13 @@ $(function() {
39 52
       var panel = $('#'+tab.attr('rel'));
40 53
       panel.addClass('panel');
41 54
       panel.find('h3').hide();
42  
-    })
  55
+    });
43 56
     
44 57
     $('.tab-bar a').click(function(){
45 58
       activateTab($(this));
46 59
       return(false);
47 60
     });
48  
-    activateTab($('.tab-bar a').first());
  61
+    activateTab($('.tab-bar ul li a.button[rel=' + currentTab + ']'));
49 62
   }
50 63
   
51 64
   function activateTab(tab) {
@@ -65,7 +78,7 @@ $(function() {
65 78
         var checkbox = $(this).find('input[name="problems[]"]');
66 79
         checkbox.attr('checked', !checkbox.is(':checked'));
67 80
       }
68  
-    })
  81
+    });
69 82
   }
70 83
   
71 84
   init();
264  public/javascripts/jquery.pjax.js
... ...
@@ -0,0 +1,264 @@
  1
+// jquery.pjax.js
  2
+// copyright chris wanstrath
  3
+// https://github.com/defunkt/jquery-pjax
  4
+
  5
+(function($){
  6
+
  7
+// When called on a link, fetches the href with ajax into the
  8
+// container specified as the first parameter or with the data-pjax
  9
+// attribute on the link itself.
  10
+//
  11
+// Tries to make sure the back button and ctrl+click work the way
  12
+// you'd expect.
  13
+//
  14
+// Accepts a jQuery ajax options object that may include these
  15
+// pjax specific options:
  16
+//
  17
+// container - Where to stick the response body. Usually a String selector.
  18
+//             $(container).html(xhr.responseBody)
  19
+//      push - Whether to pushState the URL. Defaults to true (of course).
  20
+//   replace - Want to use replaceState instead? That's cool.
  21
+//
  22
+// For convenience the first parameter can be either the container or
  23
+// the options object.
  24
+//
  25
+// Returns the jQuery object
  26
+$.fn.pjax = function( container, options ) {
  27
+  if ( options )
  28
+    options.container = container
  29
+  else
  30
+    options = $.isPlainObject(container) ? container : {container:container}
  31
+
  32
+  // We can't persist $objects using the history API so we must use
  33
+  // a String selector. Bail if we got anything else.
  34
+  if ( options.container && typeof options.container !== 'string' ) {
  35
+    throw "pjax container must be a string selector!"
  36
+    return false
  37
+  }
  38
+
  39
+  return this.live('click', function(event){
  40
+    // Middle click, cmd click, and ctrl click should open
  41
+    // links in a new tab as normal.
  42
+    if ( event.which > 1 || event.metaKey )
  43
+      return true
  44
+
  45
+    var defaults = {
  46
+      url: this.href,
  47
+      container: $(this).attr('data-pjax'),
  48
+      clickedElement: $(this),
  49
+      fragment: null
  50
+    }
  51
+
  52
+    $.pjax($.extend({}, defaults, options))
  53
+
  54
+    event.preventDefault()
  55
+  })
  56
+}
  57
+
  58
+
  59
+// Loads a URL with ajax, puts the response body inside a container,
  60
+// then pushState()'s the loaded URL.
  61
+//
  62
+// Works just like $.ajax in that it accepts a jQuery ajax
  63
+// settings object (with keys like url, type, data, etc).
  64
+//
  65
+// Accepts these extra keys:
  66
+//
  67
+// container - Where to stick the response body. Must be a String.
  68
+//             $(container).html(xhr.responseBody)
  69
+//      push - Whether to pushState the URL. Defaults to true (of course).
  70
+//   replace - Want to use replaceState instead? That's cool.
  71
+//
  72
+// Use it just like $.ajax:
  73
+//
  74
+//   var xhr = $.pjax({ url: this.href, container: '#main' })
  75
+//   console.log( xhr.readyState )
  76
+//
  77
+// Returns whatever $.ajax returns.
  78
+var pjax = $.pjax = function( options ) {
  79
+  var $container = $(options.container),
  80
+      success = options.success || $.noop
  81
+
  82
+  // We don't want to let anyone override our success handler.
  83
+  delete options.success
  84
+
  85
+  // We can't persist $objects using the history API so we must use
  86
+  // a String selector. Bail if we got anything else.
  87
+  if ( typeof options.container !== 'string' )
  88
+    throw "pjax container must be a string selector!"
  89
+
  90
+  options = $.extend(true, {}, pjax.defaults, options)
  91
+
  92
+  if ( $.isFunction(options.url) ) {
  93
+    options.url = options.url()
  94
+  }
  95
+
  96
+  options.context = $container
  97
+
  98
+  options.success = function(data){
  99
+    if ( options.fragment ) {
  100
+      // If they specified a fragment, look for it in the response
  101
+      // and pull it out.
  102
+      var $fragment = $(data).find(options.fragment)
  103
+      if ( $fragment.length )
  104
+        data = $fragment.children()
  105
+      else
  106
+        return window.location = options.url
  107
+    } else {
  108
+        // If we got no data or an entire web page, go directly
  109
+        // to the page and let normal error handling happen.
  110
+        if ( !$.trim(data) || /<html/i.test(data) )
  111
+          return window.location = options.url
  112
+    }
  113
+
  114
+    // Make it happen.
  115
+    this.html(data)
  116
+
  117
+    // If there's a <title> tag in the response, use it as
  118
+    // the page's title.
  119
+    var oldTitle = document.title,
  120
+        title = $.trim( this.find('title').remove().text() )
  121
+    if ( title ) document.title = title
  122
+
  123
+    // No <title>? Fragment? Look for data-title and title attributes.
  124
+    if ( !title && options.fragment ) {
  125
+      title = $fragment.attr('title') || $fragment.data('title')
  126
+    }
  127
+
  128
+    var state = {
  129
+      pjax: options.container,
  130
+      fragment: options.fragment,
  131
+      timeout: options.timeout
  132
+    }
  133
+
  134
+    // If there are extra params, save the complete URL in the state object
  135
+    var query = $.param(options.data)
  136
+    if ( query != "_pjax=true" )
  137
+      state.url = options.url + (/\?/.test(options.url) ? "&" : "?") + query
  138
+
  139
+    if ( options.replace ) {
  140
+      window.history.replaceState(state, document.title, options.url)
  141
+    } else if ( options.push ) {
  142
+      // this extra replaceState before first push ensures good back
  143
+      // button behavior
  144
+      if ( !pjax.active ) {
  145
+        window.history.replaceState($.extend({}, state, {url:null}), oldTitle)
  146
+        pjax.active = true
  147
+      }
  148
+
  149
+      window.history.pushState(state, document.title, options.url)
  150
+    }
  151
+
  152
+    // Google Analytics support
  153
+    if ( (options.replace || options.push) && window._gaq )
  154
+      _gaq.push(['_trackPageview'])
  155
+
  156
+    // If the URL has a hash in it, make sure the browser
  157
+    // knows to navigate to the hash.
  158
+    var hash = window.location.hash.toString()
  159
+    if ( hash !== '' ) {
  160
+      window.location.href = hash
  161
+    }
  162
+
  163
+    // Invoke their success handler if they gave us one.
  164
+    success.apply(this, arguments)
  165
+  }
  166
+
  167
+  // Cancel the current request if we're already pjaxing
  168
+  var xhr = pjax.xhr
  169
+  if ( xhr && xhr.readyState < 4) {
  170
+    xhr.onreadystatechange = $.noop
  171
+    xhr.abort()
  172
+  }
  173
+
  174
+  pjax.options = options
  175
+  pjax.xhr = $.ajax(options)
  176
+  $(document).trigger('pjax', [pjax.xhr, options])
  177
+
  178
+  return pjax.xhr
  179
+}
  180
+
  181
+
  182
+pjax.defaults = {
  183
+  timeout: 650,
  184
+  push: true,
  185
+  replace: false,
  186
+  // We want the browser to maintain two separate internal caches: one for
  187
+  // pjax'd partial page loads and one for normal page loads. Without
  188
+  // adding this secret parameter, some browsers will often confuse the two.
  189
+  data: { _pjax: true },
  190
+  type: 'GET',
  191
+  dataType: 'html',
  192
+  beforeSend: function(xhr){
  193
+    this.trigger('pjax:start', [xhr, pjax.options])
  194
+    // start.pjax is deprecated
  195
+    this.trigger('start.pjax', [xhr, pjax.options])
  196
+    xhr.setRequestHeader('X-PJAX', 'true')
  197
+  },
  198
+  error: function(xhr, textStatus, errorThrown){
  199
+    if ( textStatus !== 'abort' )
  200
+      window.location = pjax.options.url
  201
+  },
  202
+  complete: function(xhr){
  203
+    this.trigger('pjax:end', [xhr, pjax.options])
  204
+    // end.pjax is deprecated
  205
+    this.trigger('end.pjax', [xhr, pjax.options])
  206
+  }
  207
+}
  208
+
  209
+
  210
+// Used to detect initial (useless) popstate.
  211
+// If history.state exists, assume browser isn't going to fire initial popstate.
  212
+var popped = ('state' in window.history), initialURL = location.href
  213
+
  214
+
  215
+// popstate handler takes care of the back and forward buttons
  216
+//
  217
+// You probably shouldn't use pjax on pages with other pushState
  218
+// stuff yet.
  219
+$(window).bind('popstate', function(event){
  220
+  // Ignore inital popstate that some browsers fire on page load
  221
+  var initialPop = !popped && location.href == initialURL
  222
+  popped = true
  223
+  if ( initialPop ) return
  224
+
  225
+  var state = event.state
  226
+
  227
+  if ( state && state.pjax ) {
  228
+    var container = state.pjax
  229
+    if ( $(container+'').length )
  230
+      $.pjax({
  231
+        url: state.url || location.href,
  232
+        fragment: state.fragment,
  233
+        container: container,
  234
+        push: false,
  235
+        timeout: state.timeout
  236
+      })
  237
+    else
  238
+      window.location = location.href
  239
+  }
  240
+})
  241
+
  242
+
  243
+// Add the state property to jQuery's event object so we can use it in
  244
+// $(window).bind('popstate')
  245
+if ( $.inArray('state', $.event.props) < 0 )
  246
+  $.event.props.push('state')
  247
+
  248
+
  249
+// Is pjax supported by this browser?
  250
+$.support.pjax =
  251
+  window.history && window.history.pushState && window.history.replaceState
  252
+  // pushState isn't reliable on iOS yet.
  253
+  && !navigator.userAgent.match(/(iPod|iPhone|iPad|WebApps\/.+CFNetwork)/)
  254
+
  255
+
  256
+// Fall back to normalcy for older browsers.
  257
+if ( !$.support.pjax ) {
  258
+  $.pjax = function( options ) {
  259
+    window.location = $.isFunction(options.url) ? options.url() : options.url
  260
+  }
  261
+  $.fn.pjax = function() { return this }
  262
+}
  263
+
  264
+})(jQuery);
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.