rails_admin 2.1.1 → 2.2.0
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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/rails_admin/jquery.migrate.js +3 -0
- data/app/assets/javascripts/rails_admin/ra.filter-box.js +1 -4
- data/app/assets/javascripts/rails_admin/ra.nested-form-hooks.js +3 -3
- data/app/assets/javascripts/rails_admin/ra.widgets.js +1 -1
- data/app/assets/javascripts/rails_admin/rails_admin.js +2 -1
- data/app/assets/javascripts/rails_admin/ui.js +2 -2
- data/app/helpers/rails_admin/form_builder.rb +2 -0
- data/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb +1 -1
- data/lib/rails_admin/version.rb +2 -2
- data/vendor/assets/javascripts/rails_admin/bootstrap-datetimepicker.js +317 -150
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-affix.js +50 -28
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-alert.js +10 -7
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-button.js +35 -20
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-carousel.js +48 -25
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-collapse.js +70 -28
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-dropdown.js +56 -42
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-modal.js +118 -40
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-popover.js +26 -16
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-scrollspy.js +29 -27
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-tab.js +46 -19
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-tooltip.js +280 -60
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-transition.js +5 -5
- data/vendor/assets/javascripts/rails_admin/jquery.pjax.js +317 -160
- data/vendor/assets/javascripts/rails_admin/moment-with-locales.js +11210 -9290
- metadata +3 -3
- data/config/initializers/devise_patch.rb +0 -9
@@ -1,8 +1,8 @@
|
|
1
1
|
/* ========================================================================
|
2
|
-
* Bootstrap: transition.js v3.
|
3
|
-
*
|
2
|
+
* Bootstrap: transition.js v3.4.1
|
3
|
+
* https://getbootstrap.com/docs/3.4/javascript/#transitions
|
4
4
|
* ========================================================================
|
5
|
-
* Copyright 2011-
|
5
|
+
* Copyright 2011-2019 Twitter, Inc.
|
6
6
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
7
7
|
* ======================================================================== */
|
8
8
|
|
@@ -10,7 +10,7 @@
|
|
10
10
|
+function ($) {
|
11
11
|
'use strict';
|
12
12
|
|
13
|
-
// CSS TRANSITION SUPPORT (Shoutout:
|
13
|
+
// CSS TRANSITION SUPPORT (Shoutout: https://modernizr.com/)
|
14
14
|
// ============================================================
|
15
15
|
|
16
16
|
function transitionEnd() {
|
@@ -32,7 +32,7 @@
|
|
32
32
|
return false // explicit for ie8 ( ._.)
|
33
33
|
}
|
34
34
|
|
35
|
-
//
|
35
|
+
// https://blog.alexmaccaw.com/css-transitions
|
36
36
|
$.fn.emulateTransitionEnd = function (duration) {
|
37
37
|
var called = false
|
38
38
|
var $el = this
|
@@ -1,6 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
/*!
|
2
|
+
* Copyright 2012, Chris Wanstrath
|
3
|
+
* Released under the MIT License
|
4
|
+
* https://github.com/defunkt/jquery-pjax
|
5
|
+
*/
|
4
6
|
|
5
7
|
(function($){
|
6
8
|
|
@@ -17,9 +19,7 @@
|
|
17
19
|
// pjax specific options:
|
18
20
|
//
|
19
21
|
//
|
20
|
-
// container -
|
21
|
-
// $(container).html(xhr.responseBody)
|
22
|
-
// (default: current jquery context)
|
22
|
+
// container - String selector for the element where to place the response body.
|
23
23
|
// push - Whether to pushState the URL. Defaults to true (of course).
|
24
24
|
// replace - Want to use replaceState instead? That's cool.
|
25
25
|
//
|
@@ -28,11 +28,13 @@
|
|
28
28
|
//
|
29
29
|
// Returns the jQuery object
|
30
30
|
function fnPjax(selector, container, options) {
|
31
|
-
|
31
|
+
options = optionsFor(container, options)
|
32
32
|
return this.on('click.pjax', selector, function(event) {
|
33
|
-
var opts =
|
34
|
-
if (!opts.container)
|
35
|
-
opts
|
33
|
+
var opts = options
|
34
|
+
if (!opts.container) {
|
35
|
+
opts = $.extend({}, options)
|
36
|
+
opts.container = $(this).attr('data-pjax')
|
37
|
+
}
|
36
38
|
handleClick(event, opts)
|
37
39
|
})
|
38
40
|
}
|
@@ -50,16 +52,12 @@ function fnPjax(selector, container, options) {
|
|
50
52
|
// // is the same as
|
51
53
|
// $(document).pjax('a')
|
52
54
|
//
|
53
|
-
// $(document).on('click', 'a', function(event) {
|
54
|
-
// var container = $(this).closest('[data-pjax-container]')
|
55
|
-
// $.pjax.click(event, container)
|
56
|
-
// })
|
57
|
-
//
|
58
55
|
// Returns nothing.
|
59
56
|
function handleClick(event, container, options) {
|
60
57
|
options = optionsFor(container, options)
|
61
58
|
|
62
59
|
var link = event.currentTarget
|
60
|
+
var $link = $(link)
|
63
61
|
|
64
62
|
if (link.tagName.toUpperCase() !== 'A')
|
65
63
|
throw "$.fn.pjax or $.pjax.click requires an anchor element"
|
@@ -70,28 +68,32 @@ function handleClick(event, container, options) {
|
|
70
68
|
return
|
71
69
|
|
72
70
|
// Ignore cross origin links
|
73
|
-
if ( location.protocol !== link.protocol || location.
|
71
|
+
if ( location.protocol !== link.protocol || location.hostname !== link.hostname )
|
74
72
|
return
|
75
73
|
|
76
|
-
// Ignore
|
77
|
-
if (
|
78
|
-
location.href.replace(location.hash, ''))
|
74
|
+
// Ignore case when a hash is being tacked on the current URL
|
75
|
+
if ( link.href.indexOf('#') > -1 && stripHash(link) == stripHash(location) )
|
79
76
|
return
|
80
77
|
|
81
|
-
// Ignore
|
82
|
-
if (
|
78
|
+
// Ignore event with default prevented
|
79
|
+
if (event.isDefaultPrevented())
|
83
80
|
return
|
84
81
|
|
85
82
|
var defaults = {
|
86
83
|
url: link.href,
|
87
|
-
container: $
|
88
|
-
target: link
|
89
|
-
fragment: null
|
84
|
+
container: $link.attr('data-pjax'),
|
85
|
+
target: link
|
90
86
|
}
|
91
87
|
|
92
|
-
|
88
|
+
var opts = $.extend({}, defaults, options)
|
89
|
+
var clickEvent = $.Event('pjax:click')
|
90
|
+
$link.trigger(clickEvent, [opts])
|
93
91
|
|
94
|
-
|
92
|
+
if (!clickEvent.isDefaultPrevented()) {
|
93
|
+
pjax(opts)
|
94
|
+
event.preventDefault()
|
95
|
+
$link.trigger('pjax:clicked', [opts])
|
96
|
+
}
|
95
97
|
}
|
96
98
|
|
97
99
|
// Public: pjax on form submit handler
|
@@ -104,8 +106,7 @@ function handleClick(event, container, options) {
|
|
104
106
|
// Examples
|
105
107
|
//
|
106
108
|
// $(document).on('submit', 'form', function(event) {
|
107
|
-
//
|
108
|
-
// $.pjax.submit(event, container)
|
109
|
+
// $.pjax.submit(event, '[data-pjax-container]')
|
109
110
|
// })
|
110
111
|
//
|
111
112
|
// Returns nothing.
|
@@ -113,17 +114,30 @@ function handleSubmit(event, container, options) {
|
|
113
114
|
options = optionsFor(container, options)
|
114
115
|
|
115
116
|
var form = event.currentTarget
|
117
|
+
var $form = $(form)
|
116
118
|
|
117
119
|
if (form.tagName.toUpperCase() !== 'FORM')
|
118
120
|
throw "$.pjax.submit requires a form element"
|
119
121
|
|
120
122
|
var defaults = {
|
121
|
-
type: form.method,
|
122
|
-
url: form.action,
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
123
|
+
type: ($form.attr('method') || 'GET').toUpperCase(),
|
124
|
+
url: $form.attr('action'),
|
125
|
+
container: $form.attr('data-pjax'),
|
126
|
+
target: form
|
127
|
+
}
|
128
|
+
|
129
|
+
if (defaults.type !== 'GET' && window.FormData !== undefined) {
|
130
|
+
defaults.data = new FormData(form)
|
131
|
+
defaults.processData = false
|
132
|
+
defaults.contentType = false
|
133
|
+
} else {
|
134
|
+
// Can't handle file uploads, exit
|
135
|
+
if ($form.find(':file').length) {
|
136
|
+
return
|
137
|
+
}
|
138
|
+
|
139
|
+
// Fallback to manually serializing the fields
|
140
|
+
defaults.data = $form.serializeArray()
|
127
141
|
}
|
128
142
|
|
129
143
|
pjax($.extend({}, defaults, options))
|
@@ -139,8 +153,7 @@ function handleSubmit(event, container, options) {
|
|
139
153
|
//
|
140
154
|
// Accepts these extra keys:
|
141
155
|
//
|
142
|
-
// container -
|
143
|
-
// $(container).html(xhr.responseBody)
|
156
|
+
// container - String selector for where to stick the response body.
|
144
157
|
// push - Whether to pushState the URL. Defaults to true (of course).
|
145
158
|
// replace - Want to use replaceState instead? That's cool.
|
146
159
|
//
|
@@ -157,21 +170,32 @@ function pjax(options) {
|
|
157
170
|
options.url = options.url()
|
158
171
|
}
|
159
172
|
|
160
|
-
var target = options.target
|
161
|
-
|
162
173
|
var hash = parseURL(options.url).hash
|
163
174
|
|
164
|
-
var
|
175
|
+
var containerType = $.type(options.container)
|
176
|
+
if (containerType !== 'string') {
|
177
|
+
throw "expected string value for 'container' option; got " + containerType
|
178
|
+
}
|
179
|
+
var context = options.context = $(options.container)
|
180
|
+
if (!context.length) {
|
181
|
+
throw "the container selector '" + options.container + "' did not match anything"
|
182
|
+
}
|
165
183
|
|
166
184
|
// We want the browser to maintain two separate internal caches: one
|
167
185
|
// for pjax'd partial page loads and one for normal page loads.
|
168
186
|
// Without adding this secret parameter, some browsers will often
|
169
187
|
// confuse the two.
|
170
188
|
if (!options.data) options.data = {}
|
171
|
-
options.data
|
189
|
+
if ($.isArray(options.data)) {
|
190
|
+
options.data.push({name: '_pjax', value: options.container})
|
191
|
+
} else {
|
192
|
+
options.data._pjax = options.container
|
193
|
+
}
|
172
194
|
|
173
|
-
function fire(type, args) {
|
174
|
-
|
195
|
+
function fire(type, args, props) {
|
196
|
+
if (!props) props = {}
|
197
|
+
props.relatedTarget = options.target
|
198
|
+
var event = $.Event(type, props)
|
175
199
|
context.trigger(event, args)
|
176
200
|
return !event.isDefaultPrevented()
|
177
201
|
}
|
@@ -186,7 +210,7 @@ function pjax(options) {
|
|
186
210
|
}
|
187
211
|
|
188
212
|
xhr.setRequestHeader('X-PJAX', 'true')
|
189
|
-
xhr.setRequestHeader('X-PJAX-Container',
|
213
|
+
xhr.setRequestHeader('X-PJAX-Container', options.container)
|
190
214
|
|
191
215
|
if (!fire('pjax:beforeSend', [xhr, settings]))
|
192
216
|
return false
|
@@ -201,7 +225,9 @@ function pjax(options) {
|
|
201
225
|
settings.timeout = 0
|
202
226
|
}
|
203
227
|
|
204
|
-
|
228
|
+
var url = parseURL(settings.url)
|
229
|
+
if (hash) url.hash = hash
|
230
|
+
options.requestUrl = stripInternalParams(url)
|
205
231
|
}
|
206
232
|
|
207
233
|
options.complete = function(xhr, textStatus) {
|
@@ -223,8 +249,31 @@ function pjax(options) {
|
|
223
249
|
}
|
224
250
|
|
225
251
|
options.success = function(data, status, xhr) {
|
252
|
+
var previousState = pjax.state
|
253
|
+
|
254
|
+
// If $.pjax.defaults.version is a function, invoke it first.
|
255
|
+
// Otherwise it can be a static string.
|
256
|
+
var currentVersion = (typeof $.pjax.defaults.version === 'function') ?
|
257
|
+
$.pjax.defaults.version() :
|
258
|
+
$.pjax.defaults.version
|
259
|
+
|
260
|
+
var latestVersion = xhr.getResponseHeader('X-PJAX-Version')
|
261
|
+
|
226
262
|
var container = extractContainer(data, xhr, options)
|
227
263
|
|
264
|
+
var url = parseURL(container.url)
|
265
|
+
if (hash) {
|
266
|
+
url.hash = hash
|
267
|
+
container.url = url.href
|
268
|
+
}
|
269
|
+
|
270
|
+
// If there is a layout version mismatch, hard load the new url
|
271
|
+
if (currentVersion && latestVersion && currentVersion !== latestVersion) {
|
272
|
+
locationReplace(container.url)
|
273
|
+
return
|
274
|
+
}
|
275
|
+
|
276
|
+
// If the new response is missing a body, hard load the page
|
228
277
|
if (!container.contents) {
|
229
278
|
locationReplace(container.url)
|
230
279
|
return
|
@@ -234,7 +283,7 @@ function pjax(options) {
|
|
234
283
|
id: options.id || uniqueId(),
|
235
284
|
url: container.url,
|
236
285
|
title: container.title,
|
237
|
-
container:
|
286
|
+
container: options.container,
|
238
287
|
fragment: options.fragment,
|
239
288
|
timeout: options.timeout
|
240
289
|
}
|
@@ -243,35 +292,47 @@ function pjax(options) {
|
|
243
292
|
window.history.replaceState(pjax.state, container.title, container.url)
|
244
293
|
}
|
245
294
|
|
295
|
+
// Only blur the focus if the focused element is within the container.
|
296
|
+
var blurFocus = $.contains(options.container, document.activeElement)
|
297
|
+
|
298
|
+
// Clear out any focused controls before inserting new page contents.
|
299
|
+
if (blurFocus) {
|
300
|
+
try {
|
301
|
+
document.activeElement.blur()
|
302
|
+
} catch (e) { }
|
303
|
+
}
|
304
|
+
|
246
305
|
if (container.title) document.title = container.title
|
306
|
+
|
307
|
+
fire('pjax:beforeReplace', [container.contents, options], {
|
308
|
+
state: pjax.state,
|
309
|
+
previousState: previousState
|
310
|
+
})
|
247
311
|
context.html(container.contents)
|
248
312
|
|
249
|
-
//
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
//
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
// Avoid using simple hash set here. Will add another history
|
261
|
-
// entry. Replace the url with replaceState and scroll to target
|
262
|
-
// by hand.
|
263
|
-
//
|
264
|
-
// window.location.hash = hash
|
265
|
-
var url = parseURL(container.url)
|
266
|
-
url.hash = hash
|
313
|
+
// FF bug: Won't autofocus fields that are inserted via JS.
|
314
|
+
// This behavior is incorrect. So if theres no current focus, autofocus
|
315
|
+
// the last field.
|
316
|
+
//
|
317
|
+
// http://www.w3.org/html/wg/drafts/html/master/forms.html
|
318
|
+
var autofocusEl = context.find('input[autofocus], textarea[autofocus]').last()[0]
|
319
|
+
if (autofocusEl && document.activeElement !== autofocusEl) {
|
320
|
+
autofocusEl.focus()
|
321
|
+
}
|
322
|
+
|
323
|
+
executeScriptTags(container.scripts)
|
267
324
|
|
268
|
-
|
269
|
-
window.history.replaceState(pjax.state, container.title, url.href)
|
325
|
+
var scrollTo = options.scrollTo
|
270
326
|
|
271
|
-
|
272
|
-
|
327
|
+
// Ensure browser scrolls to the element referenced by the URL anchor
|
328
|
+
if (hash) {
|
329
|
+
var name = decodeURIComponent(hash.slice(1))
|
330
|
+
var target = document.getElementById(name) || document.getElementsByName(name)[0]
|
331
|
+
if (target) scrollTo = $(target).offset().top
|
273
332
|
}
|
274
333
|
|
334
|
+
if (typeof scrollTo == 'number') $(window).scrollTop(scrollTo)
|
335
|
+
|
275
336
|
fire('pjax:success', [data, status, xhr, options])
|
276
337
|
}
|
277
338
|
|
@@ -285,7 +346,7 @@ function pjax(options) {
|
|
285
346
|
id: uniqueId(),
|
286
347
|
url: window.location.href,
|
287
348
|
title: document.title,
|
288
|
-
container:
|
349
|
+
container: options.container,
|
289
350
|
fragment: options.fragment,
|
290
351
|
timeout: options.timeout
|
291
352
|
}
|
@@ -293,11 +354,7 @@ function pjax(options) {
|
|
293
354
|
}
|
294
355
|
|
295
356
|
// Cancel the current request if we're already pjaxing
|
296
|
-
|
297
|
-
if ( xhr && xhr.readyState < 4) {
|
298
|
-
xhr.onreadystatechange = $.noop
|
299
|
-
xhr.abort()
|
300
|
-
}
|
357
|
+
abortXHR(pjax.xhr)
|
301
358
|
|
302
359
|
pjax.options = options
|
303
360
|
var xhr = pjax.xhr = $.ajax(options)
|
@@ -305,9 +362,9 @@ function pjax(options) {
|
|
305
362
|
if (xhr.readyState > 0) {
|
306
363
|
if (options.push && !options.replace) {
|
307
364
|
// Cache current container element before replacing it
|
308
|
-
cachePush(pjax.state.id,
|
365
|
+
cachePush(pjax.state.id, [options.container, cloneContents(context)])
|
309
366
|
|
310
|
-
window.history.pushState(null, "",
|
367
|
+
window.history.pushState(null, "", options.requestUrl)
|
311
368
|
}
|
312
369
|
|
313
370
|
fire('pjax:start', [xhr, options])
|
@@ -338,35 +395,66 @@ function pjaxReload(container, options) {
|
|
338
395
|
//
|
339
396
|
// Returns nothing.
|
340
397
|
function locationReplace(url) {
|
341
|
-
window.history.replaceState(null, "",
|
398
|
+
window.history.replaceState(null, "", pjax.state.url)
|
342
399
|
window.location.replace(url)
|
343
400
|
}
|
344
401
|
|
402
|
+
|
403
|
+
var initialPop = true
|
404
|
+
var initialURL = window.location.href
|
405
|
+
var initialState = window.history.state
|
406
|
+
|
407
|
+
// Initialize $.pjax.state if possible
|
408
|
+
// Happens when reloading a page and coming forward from a different
|
409
|
+
// session history.
|
410
|
+
if (initialState && initialState.container) {
|
411
|
+
pjax.state = initialState
|
412
|
+
}
|
413
|
+
|
414
|
+
// Non-webkit browsers don't fire an initial popstate event
|
415
|
+
if ('state' in window.history) {
|
416
|
+
initialPop = false
|
417
|
+
}
|
418
|
+
|
345
419
|
// popstate handler takes care of the back and forward buttons
|
346
420
|
//
|
347
421
|
// You probably shouldn't use pjax on pages with other pushState
|
348
422
|
// stuff yet.
|
349
423
|
function onPjaxPopstate(event) {
|
424
|
+
|
425
|
+
// Hitting back or forward should override any pending PJAX request.
|
426
|
+
if (!initialPop) {
|
427
|
+
abortXHR(pjax.xhr)
|
428
|
+
}
|
429
|
+
|
430
|
+
var previousState = pjax.state
|
350
431
|
var state = event.state
|
432
|
+
var direction
|
351
433
|
|
352
434
|
if (state && state.container) {
|
353
|
-
|
354
|
-
|
355
|
-
|
435
|
+
// When coming forward from a separate history session, will get an
|
436
|
+
// initial pop with a state we are already at. Skip reloading the current
|
437
|
+
// page.
|
438
|
+
if (initialPop && initialURL == state.url) return
|
439
|
+
|
440
|
+
if (previousState) {
|
441
|
+
// If popping back to the same state, just skip.
|
442
|
+
// Could be clicking back from hashchange rather than a pushState.
|
443
|
+
if (previousState.id === state.id) return
|
444
|
+
|
445
|
+
// Since state IDs always increase, we can deduce the navigation direction
|
446
|
+
direction = previousState.id < state.id ? 'forward' : 'back'
|
447
|
+
}
|
356
448
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
var direction = pjax.state.id < state.id ? 'forward' : 'back'
|
449
|
+
var cache = cacheMapping[state.id] || []
|
450
|
+
var containerSelector = cache[0] || state.container
|
451
|
+
var container = $(containerSelector), contents = cache[1]
|
361
452
|
|
453
|
+
if (container.length) {
|
454
|
+
if (previousState) {
|
362
455
|
// Cache current container before replacement and inform the
|
363
456
|
// cache which direction the history shifted.
|
364
|
-
cachePop(direction,
|
365
|
-
} else {
|
366
|
-
// Page was reloaded but we have an existing history entry.
|
367
|
-
// Set it to our initial state.
|
368
|
-
pjax.state = state;
|
369
|
-
return;
|
457
|
+
cachePop(direction, previousState.id, [containerSelector, cloneContents(container)])
|
370
458
|
}
|
371
459
|
|
372
460
|
var popstateEvent = $.Event('pjax:popstate', {
|
@@ -378,7 +466,7 @@ function onPjaxPopstate(event) {
|
|
378
466
|
var options = {
|
379
467
|
id: state.id,
|
380
468
|
url: state.url,
|
381
|
-
container:
|
469
|
+
container: containerSelector,
|
382
470
|
push: false,
|
383
471
|
fragment: state.fragment,
|
384
472
|
timeout: state.timeout,
|
@@ -388,9 +476,14 @@ function onPjaxPopstate(event) {
|
|
388
476
|
if (contents) {
|
389
477
|
container.trigger('pjax:start', [null, options])
|
390
478
|
|
479
|
+
pjax.state = state
|
391
480
|
if (state.title) document.title = state.title
|
481
|
+
var beforeReplaceEvent = $.Event('pjax:beforeReplace', {
|
482
|
+
state: state,
|
483
|
+
previousState: previousState
|
484
|
+
})
|
485
|
+
container.trigger(beforeReplaceEvent, [contents, options])
|
392
486
|
container.html(contents)
|
393
|
-
pjax.state = state
|
394
487
|
|
395
488
|
container.trigger('pjax:end', [null, options])
|
396
489
|
} else {
|
@@ -404,6 +497,7 @@ function onPjaxPopstate(event) {
|
|
404
497
|
locationReplace(location.href)
|
405
498
|
}
|
406
499
|
}
|
500
|
+
initialPop = false
|
407
501
|
}
|
408
502
|
|
409
503
|
// Fallback version of main pjax function for browsers that don't
|
@@ -434,8 +528,13 @@ function fallbackPjax(options) {
|
|
434
528
|
var pair = value.split('=')
|
435
529
|
form.append($('<input>', {type: 'hidden', name: pair[0], value: pair[1]}))
|
436
530
|
})
|
531
|
+
} else if ($.isArray(data)) {
|
532
|
+
$.each(data, function(index, value) {
|
533
|
+
form.append($('<input>', {type: 'hidden', name: value.name, value: value.value}))
|
534
|
+
})
|
437
535
|
} else if (typeof data === 'object') {
|
438
|
-
|
536
|
+
var key
|
537
|
+
for (key in data)
|
439
538
|
form.append($('<input>', {type: 'hidden', name: key, value: data[key]}))
|
440
539
|
}
|
441
540
|
|
@@ -443,6 +542,15 @@ function fallbackPjax(options) {
|
|
443
542
|
form.submit()
|
444
543
|
}
|
445
544
|
|
545
|
+
// Internal: Abort an XmlHttpRequest if it hasn't been completed,
|
546
|
+
// also removing its event handlers.
|
547
|
+
function abortXHR(xhr) {
|
548
|
+
if ( xhr && xhr.readyState < 4) {
|
549
|
+
xhr.onreadystatechange = $.noop
|
550
|
+
xhr.abort()
|
551
|
+
}
|
552
|
+
}
|
553
|
+
|
446
554
|
// Internal: Generate unique id for state object.
|
447
555
|
//
|
448
556
|
// Use a timestamp instead of a counter since ids should still be
|
@@ -453,16 +561,22 @@ function uniqueId() {
|
|
453
561
|
return (new Date).getTime()
|
454
562
|
}
|
455
563
|
|
456
|
-
|
457
|
-
|
458
|
-
//
|
564
|
+
function cloneContents(container) {
|
565
|
+
var cloned = container.clone()
|
566
|
+
// Unmark script tags as already being eval'd so they can get executed again
|
567
|
+
// when restored from cache. HAXX: Uses jQuery internal method.
|
568
|
+
cloned.find('script').each(function(){
|
569
|
+
if (!this.src) jQuery._data(this, 'globalEval', false)
|
570
|
+
})
|
571
|
+
return cloned.contents()
|
572
|
+
}
|
573
|
+
|
574
|
+
// Internal: Strip internal query params from parsed URL.
|
459
575
|
//
|
460
|
-
// Returns String.
|
461
|
-
function
|
462
|
-
|
463
|
-
|
464
|
-
.replace(/_pjax=[^&]+&?/, '')
|
465
|
-
.replace(/[\?&]$/, '')
|
576
|
+
// Returns sanitized url.href String.
|
577
|
+
function stripInternalParams(url) {
|
578
|
+
url.search = url.search.replace(/([?&])(_pjax|_)=[^&]*/g, '')
|
579
|
+
return url.href.replace(/\?($|#)/, '$1')
|
466
580
|
}
|
467
581
|
|
468
582
|
// Internal: Parse URL components and returns a Locationish object.
|
@@ -476,6 +590,16 @@ function parseURL(url) {
|
|
476
590
|
return a
|
477
591
|
}
|
478
592
|
|
593
|
+
// Internal: Return the `href` component of given URL object with the hash
|
594
|
+
// portion removed.
|
595
|
+
//
|
596
|
+
// location - Location or HTMLAnchorElement
|
597
|
+
//
|
598
|
+
// Returns String
|
599
|
+
function stripHash(location) {
|
600
|
+
return location.href.replace(/#.*/, '')
|
601
|
+
}
|
602
|
+
|
479
603
|
// Internal: Build options Object for arguments.
|
480
604
|
//
|
481
605
|
// For convenience the first parameter can be either the container or
|
@@ -494,44 +618,14 @@ function parseURL(url) {
|
|
494
618
|
//
|
495
619
|
// Returns options Object.
|
496
620
|
function optionsFor(container, options) {
|
497
|
-
|
498
|
-
|
621
|
+
if (container && options) {
|
622
|
+
options = $.extend({}, options)
|
499
623
|
options.container = container
|
500
|
-
|
501
|
-
|
502
|
-
else if ( $.isPlainObject(container) )
|
503
|
-
options = container
|
504
|
-
|
505
|
-
// Only container
|
506
|
-
else
|
507
|
-
options = {container: container}
|
508
|
-
|
509
|
-
// Find and validate container
|
510
|
-
if (options.container)
|
511
|
-
options.container = findContainerFor(options.container)
|
512
|
-
|
513
|
-
return options
|
514
|
-
}
|
515
|
-
|
516
|
-
// Internal: Find container element for a variety of inputs.
|
517
|
-
//
|
518
|
-
// Because we can't persist elements using the history API, we must be
|
519
|
-
// able to find a String selector that will consistently find the Element.
|
520
|
-
//
|
521
|
-
// container - A selector String, jQuery object, or DOM Element.
|
522
|
-
//
|
523
|
-
// Returns a jQuery object whose context is `document` and has a selector.
|
524
|
-
function findContainerFor(container) {
|
525
|
-
container = $(container)
|
526
|
-
|
527
|
-
if ( !container.length ) {
|
528
|
-
throw "no pjax container for " + container.selector
|
529
|
-
} else if ( container.selector !== '' && container.context === document ) {
|
624
|
+
return options
|
625
|
+
} else if ($.isPlainObject(container)) {
|
530
626
|
return container
|
531
|
-
} else if ( container.attr('id') ) {
|
532
|
-
return $('#' + container.attr('id'))
|
533
627
|
} else {
|
534
|
-
|
628
|
+
return {container: container}
|
535
629
|
}
|
536
630
|
}
|
537
631
|
|
@@ -545,7 +639,11 @@ function findContainerFor(container) {
|
|
545
639
|
//
|
546
640
|
// Returns a jQuery object.
|
547
641
|
function findAll(elems, selector) {
|
548
|
-
return elems.filter(selector).add(elems.find(selector))
|
642
|
+
return elems.filter(selector).add(elems.find(selector))
|
643
|
+
}
|
644
|
+
|
645
|
+
function parseHTML(html) {
|
646
|
+
return $.parseHTML(html, document, true)
|
549
647
|
}
|
550
648
|
|
551
649
|
// Internal: Extracts container and metadata from response.
|
@@ -560,18 +658,19 @@ function findAll(elems, selector) {
|
|
560
658
|
//
|
561
659
|
// Returns an Object with url, title, and contents keys.
|
562
660
|
function extractContainer(data, xhr, options) {
|
563
|
-
var obj = {}
|
661
|
+
var obj = {}, fullDocument = /<html/i.test(data)
|
564
662
|
|
565
663
|
// Prefer X-PJAX-URL header if it was set, otherwise fallback to
|
566
664
|
// using the original requested url.
|
567
|
-
|
665
|
+
var serverUrl = xhr.getResponseHeader('X-PJAX-URL')
|
666
|
+
obj.url = serverUrl ? stripInternalParams(parseURL(serverUrl)) : options.requestUrl
|
568
667
|
|
569
668
|
// Attempt to parse response html into elements
|
570
|
-
if (
|
571
|
-
var $head = $(data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0])
|
572
|
-
var $body = $(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0])
|
669
|
+
if (fullDocument) {
|
670
|
+
var $head = $(parseHTML(data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0]))
|
671
|
+
var $body = $(parseHTML(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0]))
|
573
672
|
} else {
|
574
|
-
var $head = $body = $(data)
|
673
|
+
var $head = $body = $(parseHTML(data))
|
575
674
|
}
|
576
675
|
|
577
676
|
// If response data is empty, return fast
|
@@ -592,7 +691,7 @@ function extractContainer(data, xhr, options) {
|
|
592
691
|
}
|
593
692
|
|
594
693
|
if ($fragment.length) {
|
595
|
-
obj.contents = $fragment.contents()
|
694
|
+
obj.contents = options.fragment === 'body' ? $fragment : $fragment.contents()
|
596
695
|
|
597
696
|
// If there's no title, look for data-title and title attributes
|
598
697
|
// on the fragment
|
@@ -600,17 +699,21 @@ function extractContainer(data, xhr, options) {
|
|
600
699
|
obj.title = $fragment.attr('title') || $fragment.data('title')
|
601
700
|
}
|
602
701
|
|
603
|
-
} else if (
|
702
|
+
} else if (!fullDocument) {
|
604
703
|
obj.contents = $body
|
605
704
|
}
|
606
705
|
|
607
706
|
// Clean up any <title> tags
|
608
707
|
if (obj.contents) {
|
609
708
|
// Remove any parent title elements
|
610
|
-
obj.contents = obj.contents.not('title')
|
709
|
+
obj.contents = obj.contents.not(function() { return $(this).is('title') })
|
611
710
|
|
612
|
-
// Then scrub any titles from their
|
711
|
+
// Then scrub any titles from their descendants
|
613
712
|
obj.contents.find('title').remove()
|
713
|
+
|
714
|
+
// Gather all script[src] elements
|
715
|
+
obj.scripts = findAll(obj.contents, 'script[src]').remove()
|
716
|
+
obj.contents = obj.contents.not(obj.scripts)
|
614
717
|
}
|
615
718
|
|
616
719
|
// Trim any whitespace off the title
|
@@ -619,6 +722,34 @@ function extractContainer(data, xhr, options) {
|
|
619
722
|
return obj
|
620
723
|
}
|
621
724
|
|
725
|
+
// Load an execute scripts using standard script request.
|
726
|
+
//
|
727
|
+
// Avoids jQuery's traditional $.getScript which does a XHR request and
|
728
|
+
// globalEval.
|
729
|
+
//
|
730
|
+
// scripts - jQuery object of script Elements
|
731
|
+
//
|
732
|
+
// Returns nothing.
|
733
|
+
function executeScriptTags(scripts) {
|
734
|
+
if (!scripts) return
|
735
|
+
|
736
|
+
var existingScripts = $('script[src]')
|
737
|
+
|
738
|
+
scripts.each(function() {
|
739
|
+
var src = this.src
|
740
|
+
var matchedScripts = existingScripts.filter(function() {
|
741
|
+
return this.src === src
|
742
|
+
})
|
743
|
+
if (matchedScripts.length) return
|
744
|
+
|
745
|
+
var script = document.createElement('script')
|
746
|
+
var type = $(this).attr('type')
|
747
|
+
if (type) script.type = type
|
748
|
+
script.src = $(this).attr('src')
|
749
|
+
document.head.appendChild(script)
|
750
|
+
})
|
751
|
+
}
|
752
|
+
|
622
753
|
// Internal: History DOM caching class.
|
623
754
|
var cacheMapping = {}
|
624
755
|
var cacheForwardStack = []
|
@@ -636,14 +767,11 @@ function cachePush(id, value) {
|
|
636
767
|
cacheMapping[id] = value
|
637
768
|
cacheBackStack.push(id)
|
638
769
|
|
639
|
-
// Remove all
|
640
|
-
|
641
|
-
while (cacheForwardStack.length)
|
642
|
-
delete cacheMapping[cacheForwardStack.shift()]
|
770
|
+
// Remove all entries in forward history stack after pushing a new page.
|
771
|
+
trimCacheStack(cacheForwardStack, 0)
|
643
772
|
|
644
773
|
// Trim back history stack to max cache length.
|
645
|
-
|
646
|
-
delete cacheMapping[cacheBackStack.shift()]
|
774
|
+
trimCacheStack(cacheBackStack, pjax.defaults.maxCacheLength)
|
647
775
|
}
|
648
776
|
|
649
777
|
// Shifts cache from directional history cache. Should be
|
@@ -670,6 +798,31 @@ function cachePop(direction, id, value) {
|
|
670
798
|
pushStack.push(id)
|
671
799
|
if (id = popStack.pop())
|
672
800
|
delete cacheMapping[id]
|
801
|
+
|
802
|
+
// Trim whichever stack we just pushed to to max cache length.
|
803
|
+
trimCacheStack(pushStack, pjax.defaults.maxCacheLength)
|
804
|
+
}
|
805
|
+
|
806
|
+
// Trim a cache stack (either cacheBackStack or cacheForwardStack) to be no
|
807
|
+
// longer than the specified length, deleting cached DOM elements as necessary.
|
808
|
+
//
|
809
|
+
// stack - Array of state IDs
|
810
|
+
// length - Maximum length to trim to
|
811
|
+
//
|
812
|
+
// Returns nothing.
|
813
|
+
function trimCacheStack(stack, length) {
|
814
|
+
while (stack.length > length)
|
815
|
+
delete cacheMapping[stack.shift()]
|
816
|
+
}
|
817
|
+
|
818
|
+
// Public: Find version identifier for the initial page load.
|
819
|
+
//
|
820
|
+
// Returns String version or undefined.
|
821
|
+
function findVersion() {
|
822
|
+
return $('meta').filter(function() {
|
823
|
+
var name = $(this).attr('http-equiv')
|
824
|
+
return name && name.toUpperCase() === 'X-PJAX-VERSION'
|
825
|
+
}).attr('content')
|
673
826
|
}
|
674
827
|
|
675
828
|
// Install pjax functions on $.pjax to enable pushState behavior.
|
@@ -696,9 +849,10 @@ function enable() {
|
|
696
849
|
type: 'GET',
|
697
850
|
dataType: 'html',
|
698
851
|
scrollTo: 0,
|
699
|
-
maxCacheLength: 20
|
852
|
+
maxCacheLength: 20,
|
853
|
+
version: findVersion
|
700
854
|
}
|
701
|
-
$(window).
|
855
|
+
$(window).on('popstate.pjax', onPjaxPopstate)
|
702
856
|
}
|
703
857
|
|
704
858
|
// Disable pushState behavior.
|
@@ -721,21 +875,24 @@ function disable() {
|
|
721
875
|
$.pjax.submit = $.noop
|
722
876
|
$.pjax.reload = function() { window.location.reload() }
|
723
877
|
|
724
|
-
$(window).
|
878
|
+
$(window).off('popstate.pjax', onPjaxPopstate)
|
725
879
|
}
|
726
880
|
|
727
881
|
|
728
882
|
// Add the state property to jQuery's event object so we can use it in
|
729
883
|
// $(window).bind('popstate')
|
730
|
-
if ( $.inArray('state', $.event.props) < 0
|
884
|
+
if ($.event.props && $.inArray('state', $.event.props) < 0) {
|
731
885
|
$.event.props.push('state')
|
886
|
+
} else if (!('state' in $.Event.prototype)) {
|
887
|
+
$.event.addProp('state')
|
888
|
+
}
|
732
889
|
|
733
|
-
|
890
|
+
// Is pjax supported by this browser?
|
734
891
|
$.support.pjax =
|
735
892
|
window.history && window.history.pushState && window.history.replaceState &&
|
736
893
|
// pushState isn't reliable on iOS until 5.
|
737
|
-
!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/)
|
894
|
+
!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/)
|
738
895
|
|
739
896
|
$.support.pjax ? enable() : disable()
|
740
897
|
|
741
|
-
})(jQuery)
|
898
|
+
})(jQuery)
|