rails_admin 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rails_admin might be problematic. Click here for more details.
- data/README.md +3 -1
- data/app/assets/javascripts/rails_admin/jquery.pjax.js +360 -160
- data/app/assets/javascripts/rails_admin/ra.filter-box.js +4 -4
- data/app/assets/javascripts/rails_admin/ra.nested-form-hooks.coffee +2 -2
- data/app/assets/javascripts/rails_admin/ra.remote-form.js +1 -1
- data/app/assets/javascripts/rails_admin/ra.widgets.coffee +2 -2
- data/app/assets/javascripts/rails_admin/ui.js.coffee +7 -7
- data/app/helpers/rails_admin/application_helper.rb +15 -4
- data/app/views/layouts/rails_admin/_secondary_navigation.html.haml +1 -1
- data/app/views/layouts/rails_admin/pjax.html.haml +0 -4
- data/app/views/rails_admin/main/_form_filtering_select.html.haml +2 -2
- data/lib/rails_admin/version.rb +1 -1
- data/spec/dummy_app/db/test.sqlite3 +0 -0
- data/spec/dummy_app/log/test.log +15222 -0
- data/spec/integration/rails_admin_spec.rb +6 -0
- metadata +2 -2
data/README.md
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
# RailsAdmin
|
2
|
+
[][gem]
|
2
3
|
[][travis]
|
3
4
|
[][gemnasium]
|
4
5
|
[][codeclimate]
|
5
|
-
[][pledgie]
|
6
7
|
[][flattr]
|
7
8
|
|
8
9
|
RailsAdmin is a Rails engine that provides an easy-to-use interface for managing your data.
|
9
10
|
|
11
|
+
[gem]: https://rubygems.org/gems/rails_admin
|
10
12
|
[travis]: http://travis-ci.org/sferik/rails_admin
|
11
13
|
[gemnasium]: https://gemnasium.com/sferik/rails_admin
|
12
14
|
[codeclimate]: https://codeclimate.com/github/sferik/rails_admin
|
@@ -4,28 +4,36 @@
|
|
4
4
|
|
5
5
|
(function($){
|
6
6
|
|
7
|
-
// When called on a
|
8
|
-
//
|
9
|
-
//
|
7
|
+
// When called on a container with a selector, fetches the href with
|
8
|
+
// ajax into the container or with the data-pjax attribute on the link
|
9
|
+
// itself.
|
10
10
|
//
|
11
11
|
// Tries to make sure the back button and ctrl+click work the way
|
12
12
|
// you'd expect.
|
13
13
|
//
|
14
|
+
// Exported as $.fn.pjax
|
15
|
+
//
|
14
16
|
// Accepts a jQuery ajax options object that may include these
|
15
17
|
// pjax specific options:
|
16
18
|
//
|
19
|
+
//
|
17
20
|
// container - Where to stick the response body. Usually a String selector.
|
18
21
|
// $(container).html(xhr.responseBody)
|
22
|
+
// (default: current jquery context)
|
19
23
|
// push - Whether to pushState the URL. Defaults to true (of course).
|
20
24
|
// replace - Want to use replaceState instead? That's cool.
|
21
25
|
//
|
22
|
-
// For convenience the
|
26
|
+
// For convenience the second parameter can be either the container or
|
23
27
|
// the options object.
|
24
28
|
//
|
25
29
|
// Returns the jQuery object
|
26
|
-
|
27
|
-
|
28
|
-
|
30
|
+
function fnPjax(selector, container, options) {
|
31
|
+
var context = this
|
32
|
+
return this.on('click.pjax', selector, function(event) {
|
33
|
+
var opts = $.extend({}, optionsFor(container, options))
|
34
|
+
if (!opts.container)
|
35
|
+
opts.container = $(this).attr('data-pjax') || context
|
36
|
+
handleClick(event, opts)
|
29
37
|
})
|
30
38
|
}
|
31
39
|
|
@@ -38,16 +46,16 @@ $.fn.pjax = function( container, options ) {
|
|
38
46
|
//
|
39
47
|
// Examples
|
40
48
|
//
|
41
|
-
// $(
|
49
|
+
// $(document).on('click', 'a', $.pjax.click)
|
42
50
|
// // is the same as
|
43
|
-
// $(
|
51
|
+
// $(document).pjax('a')
|
44
52
|
//
|
45
53
|
// $(document).on('click', 'a', function(event) {
|
46
54
|
// var container = $(this).closest('[data-pjax-container]')
|
47
|
-
//
|
55
|
+
// $.pjax.click(event, container)
|
48
56
|
// })
|
49
57
|
//
|
50
|
-
// Returns
|
58
|
+
// Returns nothing.
|
51
59
|
function handleClick(event, container, options) {
|
52
60
|
options = optionsFor(container, options)
|
53
61
|
|
@@ -58,7 +66,7 @@ function handleClick(event, container, options) {
|
|
58
66
|
|
59
67
|
// Middle click, cmd click, and ctrl click should open
|
60
68
|
// links in a new tab as normal.
|
61
|
-
if ( event.which > 1 || event.metaKey )
|
69
|
+
if ( event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey )
|
62
70
|
return
|
63
71
|
|
64
72
|
// Ignore cross origin links
|
@@ -66,24 +74,62 @@ function handleClick(event, container, options) {
|
|
66
74
|
return
|
67
75
|
|
68
76
|
// Ignore anchors on the same page
|
69
|
-
if (
|
70
|
-
location.href.replace(location.hash, '')
|
77
|
+
if (link.hash && link.href.replace(link.hash, '') ===
|
78
|
+
location.href.replace(location.hash, ''))
|
79
|
+
return
|
80
|
+
|
81
|
+
// Ignore empty anchor "foo.html#"
|
82
|
+
if (link.href === location.href + '#')
|
71
83
|
return
|
72
84
|
|
73
85
|
var defaults = {
|
74
86
|
url: link.href,
|
75
87
|
container: $(link).attr('data-pjax'),
|
76
88
|
target: link,
|
77
|
-
clickedElement: $(link), // DEPRECATED: use target
|
78
89
|
fragment: null
|
79
90
|
}
|
80
91
|
|
81
|
-
|
92
|
+
pjax($.extend({}, defaults, options))
|
82
93
|
|
83
94
|
event.preventDefault()
|
84
|
-
return false
|
85
95
|
}
|
86
96
|
|
97
|
+
// Public: pjax on form submit handler
|
98
|
+
//
|
99
|
+
// Exported as $.pjax.submit
|
100
|
+
//
|
101
|
+
// event - "click" jQuery.Event
|
102
|
+
// options - pjax options
|
103
|
+
//
|
104
|
+
// Examples
|
105
|
+
//
|
106
|
+
// $(document).on('submit', 'form', function(event) {
|
107
|
+
// var container = $(this).closest('[data-pjax-container]')
|
108
|
+
// $.pjax.submit(event, container)
|
109
|
+
// })
|
110
|
+
//
|
111
|
+
// Returns nothing.
|
112
|
+
function handleSubmit(event, container, options) {
|
113
|
+
options = optionsFor(container, options)
|
114
|
+
|
115
|
+
var form = event.currentTarget
|
116
|
+
|
117
|
+
if (form.tagName.toUpperCase() !== 'FORM')
|
118
|
+
throw "$.pjax.submit requires a form element"
|
119
|
+
|
120
|
+
var defaults = {
|
121
|
+
type: form.method,
|
122
|
+
url: form.action,
|
123
|
+
data: $(form).serializeArray(),
|
124
|
+
container: $(form).attr('data-pjax'),
|
125
|
+
target: form,
|
126
|
+
fragment: null
|
127
|
+
}
|
128
|
+
|
129
|
+
pjax($.extend({}, defaults, options))
|
130
|
+
|
131
|
+
event.preventDefault()
|
132
|
+
}
|
87
133
|
|
88
134
|
// Loads a URL with ajax, puts the response body inside a container,
|
89
135
|
// then pushState()'s the loaded URL.
|
@@ -104,7 +150,7 @@ function handleClick(event, container, options) {
|
|
104
150
|
// console.log( xhr.readyState )
|
105
151
|
//
|
106
152
|
// Returns whatever $.ajax returns.
|
107
|
-
|
153
|
+
function pjax(options) {
|
108
154
|
options = $.extend(true, {}, $.ajaxSettings, pjax.defaults, options)
|
109
155
|
|
110
156
|
if ($.isFunction(options.url)) {
|
@@ -113,18 +159,8 @@ var pjax = $.pjax = function( options ) {
|
|
113
159
|
|
114
160
|
var target = options.target
|
115
161
|
|
116
|
-
// DEPRECATED: use options.target
|
117
|
-
if (!target && options.clickedElement) target = options.clickedElement[0]
|
118
|
-
|
119
162
|
var hash = parseURL(options.url).hash
|
120
163
|
|
121
|
-
// DEPRECATED: Save references to original event callbacks. However,
|
122
|
-
// listening for custom pjax:* events is prefered.
|
123
|
-
var oldBeforeSend = options.beforeSend,
|
124
|
-
oldComplete = options.complete,
|
125
|
-
oldSuccess = options.success,
|
126
|
-
oldError = options.error
|
127
|
-
|
128
164
|
var context = options.context = findContainerFor(options.container)
|
129
165
|
|
130
166
|
// We want the browser to maintain two separate internal caches: one
|
@@ -143,13 +179,9 @@ var pjax = $.pjax = function( options ) {
|
|
143
179
|
var timeoutTimer
|
144
180
|
|
145
181
|
options.beforeSend = function(xhr, settings) {
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
xhr.abort('timeout')
|
150
|
-
}, settings.timeout)
|
151
|
-
|
152
|
-
// Clear timeout setting so jquerys internal timeout isn't invoked
|
182
|
+
// No timeout for non-GET requests
|
183
|
+
// Its not safe to request the resource again with a fallback method.
|
184
|
+
if (settings.type !== 'GET') {
|
153
185
|
settings.timeout = 0
|
154
186
|
}
|
155
187
|
|
@@ -158,68 +190,67 @@ var pjax = $.pjax = function( options ) {
|
|
158
190
|
|
159
191
|
var result
|
160
192
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
193
|
+
if (!fire('pjax:beforeSend', [xhr, settings]))
|
194
|
+
return false
|
195
|
+
|
196
|
+
if (settings.timeout > 0) {
|
197
|
+
timeoutTimer = setTimeout(function() {
|
198
|
+
if (fire('pjax:timeout', [xhr, options]))
|
199
|
+
xhr.abort('timeout')
|
200
|
+
}, settings.timeout)
|
166
201
|
|
167
|
-
|
202
|
+
// Clear timeout setting so jquerys internal timeout isn't invoked
|
203
|
+
settings.timeout = 0
|
204
|
+
}
|
168
205
|
|
169
|
-
|
170
|
-
// start.pjax is deprecated
|
171
|
-
fire('start.pjax', [xhr, options])
|
206
|
+
options.requestUrl = parseURL(settings.url).href
|
172
207
|
}
|
173
208
|
|
174
209
|
options.complete = function(xhr, textStatus) {
|
175
210
|
if (timeoutTimer)
|
176
211
|
clearTimeout(timeoutTimer)
|
177
212
|
|
178
|
-
// DEPRECATED: Invoke original `complete` handler
|
179
|
-
if (oldComplete) oldComplete.apply(this, arguments)
|
180
|
-
|
181
213
|
fire('pjax:complete', [xhr, textStatus, options])
|
182
214
|
|
183
215
|
fire('pjax:end', [xhr, options])
|
184
|
-
// end.pjax is deprecated
|
185
|
-
fire('end.pjax', [xhr, options])
|
186
216
|
}
|
187
217
|
|
188
218
|
options.error = function(xhr, textStatus, errorThrown) {
|
189
219
|
var container = extractContainer("", xhr, options)
|
190
220
|
|
191
|
-
// DEPRECATED: Invoke original `error` handler
|
192
|
-
if (oldError) oldError.apply(this, arguments)
|
193
|
-
|
194
221
|
var allowed = fire('pjax:error', [xhr, textStatus, errorThrown, options])
|
195
|
-
if (textStatus !== 'abort' && allowed)
|
196
|
-
|
222
|
+
if (options.type == 'GET' && textStatus !== 'abort' && allowed) {
|
223
|
+
locationReplace(container.url)
|
224
|
+
}
|
197
225
|
}
|
198
226
|
|
199
227
|
options.success = function(data, status, xhr) {
|
200
228
|
var container = extractContainer(data, xhr, options)
|
201
229
|
|
202
230
|
if (!container.contents) {
|
203
|
-
|
231
|
+
locationReplace(container.url)
|
204
232
|
return
|
205
233
|
}
|
206
234
|
|
207
235
|
pjax.state = {
|
208
236
|
id: options.id || uniqueId(),
|
209
237
|
url: container.url,
|
238
|
+
title: container.title,
|
210
239
|
container: context.selector,
|
211
240
|
fragment: options.fragment,
|
212
241
|
timeout: options.timeout
|
213
242
|
}
|
214
243
|
|
244
|
+
if (options.push || options.replace) {
|
245
|
+
window.history.replaceState(pjax.state, container.title, container.url)
|
246
|
+
}
|
247
|
+
|
215
248
|
if (container.title) document.title = container.title
|
216
249
|
context.html(container.contents)
|
217
250
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
window.history.pushState(pjax.state, container.title, container.url)
|
222
|
-
}
|
251
|
+
// Scroll to top by default
|
252
|
+
if (typeof options.scrollTo === 'number')
|
253
|
+
$(window).scrollTop(options.scrollTo)
|
223
254
|
|
224
255
|
// Google Analytics support
|
225
256
|
if ( (options.replace || options.push) && window._gaq )
|
@@ -228,12 +259,21 @@ var pjax = $.pjax = function( options ) {
|
|
228
259
|
// If the URL has a hash in it, make sure the browser
|
229
260
|
// knows to navigate to the hash.
|
230
261
|
if ( hash !== '' ) {
|
231
|
-
|
262
|
+
// Avoid using simple hash set here. Will add another history
|
263
|
+
// entry. Replace the url with replaceState and scroll to target
|
264
|
+
// by hand.
|
265
|
+
//
|
266
|
+
// window.location.hash = hash
|
267
|
+
var url = parseURL(container.url)
|
268
|
+
url.hash = hash
|
269
|
+
|
270
|
+
pjax.state.url = url.href
|
271
|
+
window.history.replaceState(pjax.state, container.title, url.href)
|
272
|
+
|
273
|
+
var target = $(url.hash)
|
274
|
+
if (target.length) $(window).scrollTop(target.offset().top)
|
232
275
|
}
|
233
276
|
|
234
|
-
// DEPRECATED: Invoke original `success` handler
|
235
|
-
if (oldSuccess) oldSuccess.apply(this, arguments)
|
236
|
-
|
237
277
|
fire('pjax:success', [data, status, xhr, options])
|
238
278
|
}
|
239
279
|
|
@@ -246,6 +286,7 @@ var pjax = $.pjax = function( options ) {
|
|
246
286
|
pjax.state = {
|
247
287
|
id: uniqueId(),
|
248
288
|
url: window.location.href,
|
289
|
+
title: document.title,
|
249
290
|
container: context.selector,
|
250
291
|
fragment: options.fragment,
|
251
292
|
timeout: options.timeout
|
@@ -261,12 +302,148 @@ var pjax = $.pjax = function( options ) {
|
|
261
302
|
}
|
262
303
|
|
263
304
|
pjax.options = options
|
264
|
-
pjax.xhr = $.ajax(options)
|
265
|
-
|
305
|
+
var xhr = pjax.xhr = $.ajax(options)
|
306
|
+
|
307
|
+
if (xhr.readyState > 0) {
|
308
|
+
if (options.push && !options.replace) {
|
309
|
+
// Cache current container element before replacing it
|
310
|
+
cachePush(pjax.state.id, context.clone().contents())
|
311
|
+
|
312
|
+
window.history.pushState(null, "", stripPjaxParam(options.requestUrl))
|
313
|
+
}
|
314
|
+
|
315
|
+
fire('pjax:start', [xhr, options])
|
316
|
+
fire('pjax:send', [xhr, options])
|
317
|
+
}
|
266
318
|
|
267
319
|
return pjax.xhr
|
268
320
|
}
|
269
321
|
|
322
|
+
// Public: Reload current page with pjax.
|
323
|
+
//
|
324
|
+
// Returns whatever $.pjax returns.
|
325
|
+
function pjaxReload(container, options) {
|
326
|
+
var defaults = {
|
327
|
+
url: window.location.href,
|
328
|
+
push: false,
|
329
|
+
replace: true,
|
330
|
+
scrollTo: false
|
331
|
+
}
|
332
|
+
|
333
|
+
return pjax($.extend(defaults, optionsFor(container, options)))
|
334
|
+
}
|
335
|
+
|
336
|
+
// Internal: Hard replace current state with url.
|
337
|
+
//
|
338
|
+
// Work for around WebKit
|
339
|
+
// https://bugs.webkit.org/show_bug.cgi?id=93506
|
340
|
+
//
|
341
|
+
// Returns nothing.
|
342
|
+
function locationReplace(url) {
|
343
|
+
window.history.replaceState(null, "", "#")
|
344
|
+
window.location.replace(url)
|
345
|
+
}
|
346
|
+
|
347
|
+
// popstate handler takes care of the back and forward buttons
|
348
|
+
//
|
349
|
+
// You probably shouldn't use pjax on pages with other pushState
|
350
|
+
// stuff yet.
|
351
|
+
function onPjaxPopstate(event) {
|
352
|
+
var state = event.state
|
353
|
+
|
354
|
+
if (state && state.container) {
|
355
|
+
var container = $(state.container)
|
356
|
+
if (container.length) {
|
357
|
+
var contents = cacheMapping[state.id]
|
358
|
+
|
359
|
+
if (pjax.state) {
|
360
|
+
// Since state ids always increase, we can deduce the history
|
361
|
+
// direction from the previous state.
|
362
|
+
var direction = pjax.state.id < state.id ? 'forward' : 'back'
|
363
|
+
|
364
|
+
// Cache current container before replacement and inform the
|
365
|
+
// cache which direction the history shifted.
|
366
|
+
cachePop(direction, pjax.state.id, container.clone().contents())
|
367
|
+
} else {
|
368
|
+
// Page was reloaded but we have an existing history entry.
|
369
|
+
// Set it to our initial state.
|
370
|
+
pjax.state = state;
|
371
|
+
return;
|
372
|
+
}
|
373
|
+
|
374
|
+
var popstateEvent = $.Event('pjax:popstate', {
|
375
|
+
state: state,
|
376
|
+
direction: direction
|
377
|
+
})
|
378
|
+
container.trigger(popstateEvent)
|
379
|
+
|
380
|
+
var options = {
|
381
|
+
id: state.id,
|
382
|
+
url: state.url,
|
383
|
+
container: container,
|
384
|
+
push: false,
|
385
|
+
fragment: state.fragment,
|
386
|
+
timeout: state.timeout,
|
387
|
+
scrollTo: false
|
388
|
+
}
|
389
|
+
|
390
|
+
if (contents) {
|
391
|
+
container.trigger('pjax:start', [null, options])
|
392
|
+
|
393
|
+
if (state.title) document.title = state.title
|
394
|
+
container.html(contents)
|
395
|
+
pjax.state = state
|
396
|
+
|
397
|
+
container.trigger('pjax:end', [null, options])
|
398
|
+
} else {
|
399
|
+
pjax(options)
|
400
|
+
}
|
401
|
+
|
402
|
+
// Force reflow/relayout before the browser tries to restore the
|
403
|
+
// scroll position.
|
404
|
+
container[0].offsetHeight
|
405
|
+
} else {
|
406
|
+
locationReplace(location.href)
|
407
|
+
}
|
408
|
+
}
|
409
|
+
}
|
410
|
+
|
411
|
+
// Fallback version of main pjax function for browsers that don't
|
412
|
+
// support pushState.
|
413
|
+
//
|
414
|
+
// Returns nothing since it retriggers a hard form submission.
|
415
|
+
function fallbackPjax(options) {
|
416
|
+
var url = $.isFunction(options.url) ? options.url() : options.url,
|
417
|
+
method = options.type ? options.type.toUpperCase() : 'GET'
|
418
|
+
|
419
|
+
var form = $('<form>', {
|
420
|
+
method: method === 'GET' ? 'GET' : 'POST',
|
421
|
+
action: url,
|
422
|
+
style: 'display:none'
|
423
|
+
})
|
424
|
+
|
425
|
+
if (method !== 'GET' && method !== 'POST') {
|
426
|
+
form.append($('<input>', {
|
427
|
+
type: 'hidden',
|
428
|
+
name: '_method',
|
429
|
+
value: method.toLowerCase()
|
430
|
+
}))
|
431
|
+
}
|
432
|
+
|
433
|
+
var data = options.data
|
434
|
+
if (typeof data === 'string') {
|
435
|
+
$.each(data.split('&'), function(index, value) {
|
436
|
+
var pair = value.split('=')
|
437
|
+
form.append($('<input>', {type: 'hidden', name: pair[0], value: pair[1]}))
|
438
|
+
})
|
439
|
+
} else if (typeof data === 'object') {
|
440
|
+
for (key in data)
|
441
|
+
form.append($('<input>', {type: 'hidden', name: key, value: data[key]}))
|
442
|
+
}
|
443
|
+
|
444
|
+
$(document.body).append(form)
|
445
|
+
form.submit()
|
446
|
+
}
|
270
447
|
|
271
448
|
// Internal: Generate unique id for state object.
|
272
449
|
//
|
@@ -370,13 +547,7 @@ function findContainerFor(container) {
|
|
370
547
|
//
|
371
548
|
// Returns a jQuery object.
|
372
549
|
function findAll(elems, selector) {
|
373
|
-
|
374
|
-
elems.each(function() {
|
375
|
-
if ($(this).is(selector))
|
376
|
-
results = results.add(this)
|
377
|
-
results = results.add(selector, this)
|
378
|
-
})
|
379
|
-
return results
|
550
|
+
return elems.filter(selector).add(elems.find(selector));
|
380
551
|
}
|
381
552
|
|
382
553
|
// Internal: Extracts container and metadata from response.
|
@@ -395,23 +566,32 @@ function extractContainer(data, xhr, options) {
|
|
395
566
|
|
396
567
|
// Prefer X-PJAX-URL header if it was set, otherwise fallback to
|
397
568
|
// using the original requested url.
|
398
|
-
obj.url = stripPjaxParam(xhr.getResponseHeader('X-PJAX-URL') || options.
|
569
|
+
obj.url = stripPjaxParam(xhr.getResponseHeader('X-PJAX-URL') || options.requestUrl)
|
399
570
|
|
400
571
|
// Attempt to parse response html into elements
|
401
|
-
|
572
|
+
if (/<html/i.test(data)) {
|
573
|
+
var $head = $(data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0])
|
574
|
+
var $body = $(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0])
|
575
|
+
} else {
|
576
|
+
var $head = $body = $(data)
|
577
|
+
}
|
402
578
|
|
403
579
|
// If response data is empty, return fast
|
404
|
-
if ($
|
580
|
+
if ($body.length === 0)
|
405
581
|
return obj
|
406
582
|
|
407
|
-
// If there's a <title> tag in the
|
583
|
+
// If there's a <title> tag in the header, use it as
|
408
584
|
// the page's title.
|
409
|
-
obj.title = findAll($
|
585
|
+
obj.title = findAll($head, 'title').last().text()
|
410
586
|
|
411
587
|
if (options.fragment) {
|
412
588
|
// If they specified a fragment, look for it in the response
|
413
589
|
// and pull it out.
|
414
|
-
|
590
|
+
if (options.fragment === 'body') {
|
591
|
+
var $fragment = $body
|
592
|
+
} else {
|
593
|
+
var $fragment = findAll($body, options.fragment).first()
|
594
|
+
}
|
415
595
|
|
416
596
|
if ($fragment.length) {
|
417
597
|
obj.contents = $fragment.contents()
|
@@ -423,7 +603,7 @@ function extractContainer(data, xhr, options) {
|
|
423
603
|
}
|
424
604
|
|
425
605
|
} else if (!/<html/i.test(data)) {
|
426
|
-
obj.contents = $
|
606
|
+
obj.contents = $body
|
427
607
|
}
|
428
608
|
|
429
609
|
// Clean up any <title> tags
|
@@ -441,52 +621,110 @@ function extractContainer(data, xhr, options) {
|
|
441
621
|
return obj
|
442
622
|
}
|
443
623
|
|
624
|
+
// Internal: History DOM caching class.
|
625
|
+
var cacheMapping = {}
|
626
|
+
var cacheForwardStack = []
|
627
|
+
var cacheBackStack = []
|
444
628
|
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
629
|
+
// Push previous state id and container contents into the history
|
630
|
+
// cache. Should be called in conjunction with `pushState` to save the
|
631
|
+
// previous container contents.
|
632
|
+
//
|
633
|
+
// id - State ID Number
|
634
|
+
// value - DOM Element to cache
|
635
|
+
//
|
636
|
+
// Returns nothing.
|
637
|
+
function cachePush(id, value) {
|
638
|
+
cacheMapping[id] = value
|
639
|
+
cacheBackStack.push(id)
|
640
|
+
|
641
|
+
// Remove all entires in forward history stack after pushing
|
642
|
+
// a new page.
|
643
|
+
while (cacheForwardStack.length)
|
644
|
+
delete cacheMapping[cacheForwardStack.shift()]
|
452
645
|
|
453
|
-
//
|
454
|
-
|
646
|
+
// Trim back history stack to max cache length.
|
647
|
+
while (cacheBackStack.length > pjax.defaults.maxCacheLength)
|
648
|
+
delete cacheMapping[cacheBackStack.shift()]
|
649
|
+
}
|
455
650
|
|
651
|
+
// Shifts cache from directional history cache. Should be
|
652
|
+
// called on `popstate` with the previous state id and container
|
653
|
+
// contents.
|
654
|
+
//
|
655
|
+
// direction - "forward" or "back" String
|
656
|
+
// id - State ID Number
|
657
|
+
// value - DOM Element to cache
|
658
|
+
//
|
659
|
+
// Returns nothing.
|
660
|
+
function cachePop(direction, id, value) {
|
661
|
+
var pushStack, popStack
|
662
|
+
cacheMapping[id] = value
|
456
663
|
|
457
|
-
|
458
|
-
|
459
|
-
|
664
|
+
if (direction === 'forward') {
|
665
|
+
pushStack = cacheBackStack
|
666
|
+
popStack = cacheForwardStack
|
667
|
+
} else {
|
668
|
+
pushStack = cacheForwardStack
|
669
|
+
popStack = cacheBackStack
|
670
|
+
}
|
460
671
|
|
672
|
+
pushStack.push(id)
|
673
|
+
if (id = popStack.pop())
|
674
|
+
delete cacheMapping[id]
|
675
|
+
}
|
461
676
|
|
462
|
-
//
|
677
|
+
// Install pjax functions on $.pjax to enable pushState behavior.
|
463
678
|
//
|
464
|
-
//
|
465
|
-
//
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
679
|
+
// Does nothing if already enabled.
|
680
|
+
//
|
681
|
+
// Examples
|
682
|
+
//
|
683
|
+
// $.pjax.enable()
|
684
|
+
//
|
685
|
+
// Returns nothing.
|
686
|
+
function enable() {
|
687
|
+
$.fn.pjax = fnPjax
|
688
|
+
$.pjax = pjax
|
689
|
+
$.pjax.enable = $.noop
|
690
|
+
$.pjax.disable = disable
|
691
|
+
$.pjax.click = handleClick
|
692
|
+
$.pjax.submit = handleSubmit
|
693
|
+
$.pjax.reload = pjaxReload
|
694
|
+
$.pjax.defaults = {
|
695
|
+
timeout: 650,
|
696
|
+
push: true,
|
697
|
+
replace: false,
|
698
|
+
type: 'GET',
|
699
|
+
dataType: 'html',
|
700
|
+
scrollTo: 0,
|
701
|
+
maxCacheLength: 20
|
702
|
+
}
|
703
|
+
$(window).bind('popstate.pjax', onPjaxPopstate)
|
704
|
+
}
|
471
705
|
|
472
|
-
|
706
|
+
// Disable pushState behavior.
|
707
|
+
//
|
708
|
+
// This is the case when a browser doesn't support pushState. It is
|
709
|
+
// sometimes useful to disable pushState for debugging on a modern
|
710
|
+
// browser.
|
711
|
+
//
|
712
|
+
// Examples
|
713
|
+
//
|
714
|
+
// $.pjax.disable()
|
715
|
+
//
|
716
|
+
// Returns nothing.
|
717
|
+
function disable() {
|
718
|
+
$.fn.pjax = function() { return this }
|
719
|
+
$.pjax = fallbackPjax
|
720
|
+
$.pjax.enable = enable
|
721
|
+
$.pjax.disable = $.noop
|
722
|
+
$.pjax.click = $.noop
|
723
|
+
$.pjax.submit = $.noop
|
724
|
+
$.pjax.reload = function() { window.location.reload() }
|
473
725
|
|
474
|
-
|
475
|
-
|
476
|
-
if (container.length) {
|
477
|
-
$.pjax({
|
478
|
-
id: state.id,
|
479
|
-
url: state.url,
|
480
|
-
container: container,
|
481
|
-
push: false,
|
482
|
-
fragment: state.fragment,
|
483
|
-
timeout: state.timeout
|
484
|
-
})
|
485
|
-
} else {
|
486
|
-
window.location = location.href
|
487
|
-
}
|
488
|
-
}
|
489
|
-
})
|
726
|
+
$(window).unbind('popstate.pjax', onPjaxPopstate)
|
727
|
+
}
|
490
728
|
|
491
729
|
|
492
730
|
// Add the state property to jQuery's event object so we can use it in
|
@@ -494,50 +732,12 @@ $(window).bind('popstate', function(event){
|
|
494
732
|
if ( $.inArray('state', $.event.props) < 0 )
|
495
733
|
$.event.props.push('state')
|
496
734
|
|
497
|
-
|
498
|
-
// Is pjax supported by this browser?
|
735
|
+
// Is pjax supported by this browser?
|
499
736
|
$.support.pjax =
|
500
|
-
window.history && window.history.pushState && window.history.replaceState
|
737
|
+
window.history && window.history.pushState && window.history.replaceState &&
|
501
738
|
// pushState isn't reliable on iOS until 5.
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
// Fall back to normalcy for older browsers.
|
506
|
-
if ( !$.support.pjax ) {
|
507
|
-
$.pjax = function( options ) {
|
508
|
-
var url = $.isFunction(options.url) ? options.url() : options.url,
|
509
|
-
method = options.type ? options.type.toUpperCase() : 'GET'
|
510
|
-
|
511
|
-
var form = $('<form>', {
|
512
|
-
method: method === 'GET' ? 'GET' : 'POST',
|
513
|
-
action: url,
|
514
|
-
style: 'display:none'
|
515
|
-
})
|
516
|
-
|
517
|
-
if (method !== 'GET' && method !== 'POST') {
|
518
|
-
form.append($('<input>', {
|
519
|
-
type: 'hidden',
|
520
|
-
name: '_method',
|
521
|
-
value: method.toLowerCase()
|
522
|
-
}))
|
523
|
-
}
|
524
|
-
|
525
|
-
var data = options.data
|
526
|
-
if (typeof data === 'string') {
|
527
|
-
$.each(data.split('&'), function(index, value) {
|
528
|
-
var pair = value.split('=')
|
529
|
-
form.append($('<input>', {type: 'hidden', name: pair[0], value: pair[1]}))
|
530
|
-
})
|
531
|
-
} else if (typeof data === 'object') {
|
532
|
-
for (key in data)
|
533
|
-
form.append($('<input>', {type: 'hidden', name: key, value: data[key]}))
|
534
|
-
}
|
739
|
+
!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/)
|
535
740
|
|
536
|
-
|
537
|
-
form.submit()
|
538
|
-
}
|
539
|
-
$.pjax.click = $.noop
|
540
|
-
$.fn.pjax = function() { return this }
|
541
|
-
}
|
741
|
+
$.support.pjax ? enable() : disable()
|
542
742
|
|
543
|
-
})(jQuery);
|
743
|
+
})(jQuery);
|