Skip to content

Commit 645d678

Browse files
committed
added pjax
shortened URLs as much as possible
1 parent 321ced3 commit 645d678

File tree

13 files changed

+330
-45
lines changed

13 files changed

+330
-45
lines changed
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
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 || $(this).attr('data-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+
options.success = function(data){
98+
if ( options.fragment ) {
99+
// If they specified a fragment, look for it in the response
100+
// and pull it out.
101+
var $fragment = $(data).find(options.fragment)
102+
if ( $fragment.length )
103+
data = $fragment.children()
104+
else
105+
return window.location = options.url
106+
} else {
107+
// If we got no data or an entire web page, go directly
108+
// to the page and let normal error handling happen.
109+
if ( !$.trim(data) || /<html/i.test(data) )
110+
return window.location = options.url
111+
}
112+
113+
// Make it happen.
114+
this.html(data)
115+
116+
// If there's a <title> tag in the response, use it as
117+
// the page's title.
118+
var oldTitle = document.title,
119+
title = $.trim( this.find('title').remove().text() )
120+
if ( title ) document.title = title
121+
122+
// No <title>? Fragment? Look for data-title and title attributes.
123+
if ( !title && options.fragment ) {
124+
title = $fragment.attr('title') || $fragment.data('title')
125+
}
126+
127+
var state = {
128+
pjax: options.container,
129+
fragment: options.fragment,
130+
timeout: options.timeout
131+
}
132+
133+
// If there are extra params, save the complete URL in the state object
134+
var query = $.param(options.data)
135+
if ( query != "_pjax=true" )
136+
state.url = options.url + (/\?/.test(options.url) ? "&" : "?") + query
137+
138+
if ( options.replace ) {
139+
window.history.replaceState(state, document.title, options.url)
140+
} else if ( options.push ) {
141+
// this extra replaceState before first push ensures good back
142+
// button behavior
143+
if ( !pjax.active ) {
144+
window.history.replaceState($.extend({}, state, {url:null}), oldTitle)
145+
pjax.active = true
146+
}
147+
148+
window.history.pushState(state, document.title, options.url)
149+
}
150+
151+
// Google Analytics support
152+
if ( (options.replace || options.push) && window._gaq )
153+
_gaq.push(['_trackPageview'])
154+
155+
// If the URL has a hash in it, make sure the browser
156+
// knows to navigate to the hash.
157+
var hash = window.location.hash.toString()
158+
if ( hash !== '' ) {
159+
window.location.href = hash
160+
}
161+
162+
// Invoke their success handler if they gave us one.
163+
success.apply(this, arguments)
164+
}
165+
166+
// Cancel the current request if we're already pjaxing
167+
var xhr = pjax.xhr
168+
if ( xhr && xhr.readyState < 4) {
169+
xhr.onreadystatechange = $.noop
170+
xhr.abort()
171+
}
172+
173+
pjax.options = options
174+
pjax.xhr = $.ajax(options)
175+
$(document).trigger('pjax', [pjax.xhr, options])
176+
177+
return pjax.xhr
178+
}
179+
180+
181+
pjax.defaults = {
182+
timeout: 2000,
183+
push: true,
184+
replace: false,
185+
// We want the browser to maintain two separate internal caches: one for
186+
// pjax'd partial page loads and one for normal page loads. Without
187+
// adding this secret parameter, some browsers will often confuse the two.
188+
data: { _pjax: true },
189+
type: 'GET',
190+
dataType: 'html',
191+
beforeSend: function(xhr){
192+
this.trigger('pjax:start', [xhr, pjax.options])
193+
// start.pjax is deprecated
194+
this.trigger('start.pjax', [xhr, pjax.options])
195+
xhr.setRequestHeader('X-PJAX', 'true')
196+
},
197+
error: function(xhr, textStatus, errorThrown){
198+
if ( textStatus !== 'abort' ) {
199+
// console.log(xhr, textStatus, errorThrown)
200+
window.location = pjax.options.url
201+
}
202+
203+
},
204+
complete: function(xhr){
205+
this.trigger('pjax:end', [xhr, pjax.options])
206+
// end.pjax is deprecated
207+
this.trigger('end.pjax', [xhr, pjax.options])
208+
}
209+
}
210+
211+
212+
// Used to detect initial (useless) popstate.
213+
// If history.state exists, assume browser isn't going to fire initial popstate.
214+
var popped = ('state' in window.history), initialURL = location.href
215+
216+
217+
// popstate handler takes care of the back and forward buttons
218+
//
219+
// You probably shouldn't use pjax on pages with other pushState
220+
// stuff yet.
221+
$(window).bind('popstate', function(event){
222+
// Ignore inital popstate that some browsers fire on page load
223+
var initialPop = !popped && location.href == initialURL
224+
popped = true
225+
if ( initialPop ) return
226+
227+
var state = event.state
228+
229+
if ( state && state.pjax ) {
230+
var container = state.pjax
231+
if ( $(container+'').length )
232+
$.pjax({
233+
url: state.url || location.href,
234+
fragment: state.fragment,
235+
container: container,
236+
push: false,
237+
timeout: state.timeout
238+
})
239+
else
240+
window.location = location.href
241+
}
242+
})
243+
244+
245+
// Add the state property to jQuery's event object so we can use it in
246+
// $(window).bind('popstate')
247+
if ( $.inArray('state', $.event.props) < 0 )
248+
$.event.props.push('state')
249+
250+
251+
// Is pjax supported by this browser?
252+
$.support.pjax =
253+
window.history && window.history.pushState && window.history.replaceState
254+
// pushState isn't reliable on iOS yet.
255+
&& !navigator.userAgent.match(/(iPod|iPhone|iPad|WebApps\/.+CFNetwork)/)
256+
257+
258+
// Fall back to normalcy for older browsers.
259+
if ( !$.support.pjax ) {
260+
$.pjax = function( options ) {
261+
window.location = $.isFunction(options.url) ? options.url() : options.url
262+
}
263+
$.fn.pjax = function() { return this }
264+
}
265+
266+
})(jQuery);

app/assets/javascripts/rails_admin/ra.filter-box.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
$.filters = filters = {
66
append: function(field_label, field_name, field_type, field_value, field_operator, field_options, multiple_values, index) {
7-
var value_name = 'filters[' + field_name + '][' + index + '][value]';
8-
var operator_name = 'filters[' + field_name + '][' + index + '][operator]';
7+
var value_name = 'f[' + field_name + '][' + index + '][v]';
8+
var operator_name = 'f[' + field_name + '][' + index + '][o]';
99
switch(field_type) {
1010
case 'boolean':
1111
var control = '<select class="span3 " name="' + value_name + '">' +
@@ -71,7 +71,7 @@
7171

7272
var content = '<div class="row filter clearfix">' +
7373
'<span class="span3">' +
74-
'<span data-original-title="Click to remove this filter" rel="twipsy" class="btn info delete" data-disabler-name="filters[' + field_name + '][' + index + '][disabled]">' + field_label + '</span>' +
74+
'<span data-original-title="Click to remove this filter" rel="twipsy" class="btn info delete" data-disabler-name="f[' + field_name + '][' + index + '][disabled]">' + field_label + '</span>' +
7575
'</span>' +
7676
'<span class="span3">'+
7777
control +
@@ -91,7 +91,7 @@
9191
$(this).data('field-operator'),
9292
$(this).data('field-options'),
9393
$(this).data('field-multiple_values'),
94-
$.now()
94+
$.now().toString().slice(7,11)
9595
);
9696
$("[rel=twipsy]").twipsy();
9797
});

app/assets/javascripts/rails_admin/rails_admin.js.erb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
theme = :default
33
require_asset 'rails_admin/jquery-1.6.4.min'
44
require_asset 'jquery_ujs'
5+
require_asset 'rails_admin/jquery.pjax'
56
require_asset 'jquery.remotipart'
67
require_asset 'rails_admin/jquery-ui-1.8.16.custom.js'
78
require_asset 'bootstrap'

app/assets/javascripts/rails_admin/ui.js.coffee

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,21 @@ $("#list input.checkbox.toggle").live "click", ->
1212
$("#list a, #list form").live "ajax:complete", (xhr, data, status) ->
1313
$("#list").replaceWith data.responseText
1414

15-
$("#list table th.header").live "click", ->
16-
$.ajax
17-
url: $(this).data("link")
18-
success: (data) ->
19-
$("#list").replaceWith data
20-
2115
$("table#history th.header").live "click", ->
2216
window.location = $(this).data("link")
2317

2418
$(document).ready ->
19+
$('.pjax').pjax('[data-pjax-container]')
20+
$('.pjax-form').live 'submit', (event) ->
21+
event.preventDefault()
22+
$.pjax
23+
container: '[data-pjax-container]'
24+
url: this.action + (if (this.action.indexOf('?') != -1) then '&' else '?') + $(this).serialize()
2525
$(".alert-message").alert()
2626
$("[rel=twipsy]").twipsy()
2727
$('.animate-width-to').each ->
2828
length = $(this).data("animate-length")
2929
width = $(this).data("animate-width-to")
3030
$(this).animate(width: width, length, 'easeOutQuad')
31+
32+

app/controllers/rails_admin/main_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ def get_collection(model_config, scope)
342342
options = options.merge(:page => (params[:page] || 1).to_i, :per => (params[:per] || model_config.list.items_per_page)) unless params[:associated_collection] || params[:all]
343343
options = options.merge(:include => associations) unless associations.blank?
344344
options = options.merge(get_sort_hash(model_config)) unless params[:associated_collection]
345-
options = options.merge(model_config.abstract_model.get_conditions_hash(model_config, params[:query], params[:filters])) if params[:query] || params[:filters]
345+
options = options.merge(model_config.abstract_model.get_conditions_hash(model_config, params[:query], params[:f])) if params[:query] || params[:f]
346346
options = options.merge(:bulk_ids => params[:bulk_ids]) if params[:bulk_ids]
347347

348348
objects = model_config.abstract_model.all(options, scope)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
- if current_page.last?
22
%li.next.disabled= link_to raw(t 'views.pagination.next'), '#'
33
- else
4-
%li.next= link_to raw(t 'views.pagination.next'), url, :remote => remote
4+
%li.next= link_to raw(t 'views.pagination.next'), url, :class => (remote ? 'pjax' : '')
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
- if page.current?
2-
%li.active= link_to page, url, :remote => remote
2+
%li.active= link_to page, url, :class => (remote ? 'pjax' : '')
33
- else
4-
%li= link_to page, url, :remote => remote
4+
%li= link_to page, url, :class => (remote ? 'pjax' : '')
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
- if current_page.first?
22
%li.prev.disabled= link_to raw(t 'views.pagination.previous'), '#'
33
- else
4-
%li.prev= link_to raw(t 'views.pagination.previous'), url, :remote => remote
4+
%li.prev= link_to raw(t 'views.pagination.previous'), url, :class => (remote ? 'pjax' : '')

0 commit comments

Comments
 (0)