PageSourceSearch

https://onclick9927.github.io/js/jquery.pjax.js?v=1.1.0

js onclick9927.github.io collected 2026-10-03 09:42:52 UTC 29,923 bytes, 916 lines download raw bytes

vendor: 29,734 bytes, lines 1-907
1/*!
2 * Copyright 2012, Chris Wanstrath
3 * Released under the MIT License
4 * https://github.com/defunkt/jquery-pjax
5 */
6
7(function($){
8
9// When called on a container with a selector, fetches the href with
10// ajax into the container or with the data-pjax attribute on the link
11// itself.
12//
13// Tries to make sure the back button and ctrl+click work the way
14// you'd expect.
15//
16// Exported as $.fn.pjax
17//
18// Accepts a jQuery ajax options object that may include these
19// pjax specific options:
20//
21//
22// container - String selector for the element where to place the response body.
23//      push - Whether to pushState the URL. Defaults to true (of course).
24//   replace - Want to use replaceState instead? That's cool.
25//
26// For convenience the second parameter can be either the container or
27// the options object.
28//
29// Returns the jQuery object
30    function fnPjax(selector, container, options) {
31        options = optionsFor(container, options)
32        return this.on('click.pjax', selector, function(event) {
33            var opts = options
34            if (!opts.container) {
35                opts = $.extend({}, options)
36                opts.container = $(this).attr('data-pjax')
37            }
38            handleClick(event, opts)
39        })
40    }
41
42// Public: pjax on click handler
43//
44// Exported as $.pjax.click.
45//
46// event   - "click" jQuery.Event
47// options - pjax options
48//
49// Examples
50//
51//   $(document).on('click', 'a', $.pjax.click)
52//   // is the same as
53//   $(document).pjax('a')
54//
55// Returns nothing.
56    function handleClick(event, container, options) {
57        options = optionsFor(container, options)
58
59        var link = event.currentTarget
60        var $link = $(link)
61
62        if (link.tagName.toUpperCase() !== 'A')
63            throw "$.fn.pjax or $.pjax.click requires an anchor element"
64
65        // Middle click, cmd click, and ctrl click should open
66        // links in a new tab as normal.
67        if ( event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey )
68            return
69
70        // Ignore cross origin links
71        if ( location.protocol !== link.protocol || location.hostname !== link.hostname )
72            return
73
74        // Ignore case when a hash is being tacked on the current URL
75        if ( link.href.indexOf('#') > -1 && stripHash(link) == stripHash(location) )
76            return
77
78        // Ignore event with default prevented
79        if (event.isDefaultPrevented())
80            return
81
82        var defaults = {
83            url: link.href,
84            container: $link.attr('data-pjax'),
85            target: link
86        }
87
88        var opts = $.extend({}, defaults, options)
89        var clickEvent = $.Event('pjax:click')
90        $link.trigger(clickEvent, [opts])
91
92        if (!clickEvent.isDefaultPrevented()) {
93            pjax(opts)
94            event.preventDefault()
95            $link.trigger('pjax:clicked', [opts])
96        }
97    }
98
99// Public: pjax on form submit handler
100//
101// Exported as $.pjax.submit
102//
103// event   - "click" jQuery.Event
104// options - pjax options
105//
106// Examples
107//
108//  $(document).on('submit', 'form', function(event) {
109//    $.pjax.submit(event, '[data-pjax-container]')
110//  })
111//
112// Returns nothing.
113    function handleSubmit(event, container, options) {
114        options = optionsFor(container, options)
115
116        var form = event.currentTarget
117        var $form = $(form)
118
119        if (form.tagName.toUpperCase() !== 'FORM')
120            throw "$.pjax.submit requires a form element"
121
122        var defaults = {
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()
141        }
142
143        pjax($.extend({}, defaults, options))
144
145        event.preventDefault()
146    }
147
148// Loads a URL with ajax, puts the response body inside a container,
149// then pushState()'s the loaded URL.
150//
151// Works just like $.ajax in that it accepts a jQuery ajax
152// settings object (with keys like url, type, data, etc).
153//
154// Accepts these extra keys:
155//
156// container - String selector for where to stick the response body.
157//      push - Whether to pushState the URL. Defaults to true (of course).
158//   replace - Want to use replaceState instead? That's cool.
159//
160// Use it just like $.ajax:
161//
162//   var xhr = $.pjax({ url: this.href, container: '#main' })
163//   console.log( xhr.readyState )
164//
165// Returns whatever $.ajax returns.
166    function pjax(options) {
167        options = $.extend(true, {}, $.ajaxSettings, pjax.defaults, options)
168
169        if ($.isFunction(options.url)) {
170            options.url = options.url()
171        }
172
173        var hash = parseURL(options.url).hash
174
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        }
183
184        // We want the browser to maintain two separate internal caches: one
185        // for pjax'd partial page loads and one for normal page loads.
186        // Without adding this secret parameter, some browsers will often
187        // confuse the two.
188        if (!options.data) 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        }
194
195        function fire(type, args, props) {
196            if (!props) props = {}
197            props.relatedTarget = options.target
198            var event = $.Event(type, props)
199            context.trigger(event, args)
200            return !event.isDefaultPrevented()
201        }
202
203        var timeoutTimer
204
205        options.beforeSend = function(xhr, settings) {
206            // No timeout for non-GET requests
207            // Its not safe to request the resource again with a fallback method.
208            if (settings.type !== 'GET') {
209                settings.timeout = 0
210            }
211
212            xhr.setRequestHeader('X-PJAX', 'true')
213            xhr.setRequestHeader('X-PJAX-Container', options.container)
214
215            if (!fire('pjax:beforeSend', [xhr, settings]))
216                return false
217
218            if (settings.timeout > 0) {
219                timeoutTimer = setTimeout(function() {
220                    if (fire('pjax:timeout', [xhr, options]))
221                        xhr.abort('timeout')
222                }, settings.timeout)
223
224                // Clear timeout setting so jquerys internal timeout isn't invoked
225                settings.timeout = 0
226            }
227
228            var url = parseURL(settings.url)
229            if (hash) url.hash = hash
230            options.requestUrl = stripInternalParams(url)
231        }
232
233        options.complete = function(xhr, textStatus) {
234            if (timeoutTimer)
235                clearTimeout(timeoutTimer)
236
237            fire('pjax:complete', [xhr, textStatus, options])
238
239            fire('pjax:end', [xhr, options])
240            // 修复 jsfiddle 兼容 pjax
241            $('head > script[src^="//jsfiddle.net"]').each(function () {
242                $('div[data-src="'+$(this).attr('src')+'"]').after($(this))
243            })
244        }
245
246        options.error = function(xhr, textStatus, errorThrown) {
247            var container = extractContainer("", xhr, options)
248
249            var allowed = fire('pjax:error', [xhr, textStatus, errorThrown, options])
250            if (options.type == 'GET' && textStatus !== 'abort' && allowed) {
251                locationReplace(container.url)
252            }
253        }
254
255        options.success = function(data, status, xhr) {
256            var previousState = pjax.state
257
258            // If $.pjax.defaults.version is a function, invoke it first.
259            // Otherwise it can be a static string.
260            var currentVersion = typeof $.pjax.defaults.version === 'function' ?
261                $.pjax.defaults.version() :
262                $.pjax.defaults.version
263
264            var latestVersion = xhr.getResponseHeader('X-PJAX-Version')
265
266            var container = extractContainer(data, xhr, options)
267
268            var url = parseURL(container.url)
269            if (hash) {
270                url.hash = hash
271                container.url = url.href
272            }
273
274            // If there is a layout version mismatch, hard load the new url
275            if (currentVersion && latestVersion && currentVersion !== latestVersion) {
276                locationReplace(container.url)
277                return
278            }
279
280            // If the new response is missing a body, hard load the page
281            if (!container.contents) {
282                locationReplace(container.url)
283                return
284            }
285
286            pjax.state = {
287                id: options.id || uniqueId(),
288                url: container.url,
289                title: container.title,
290                container: options.container,
291                fragment: options.fragment,
292                timeout: options.timeout
293            }
294
295            if (options.push || options.replace) {
296                window.history.replaceState(pjax.state, container.title, container.url)
297            }
298
299            // Only blur the focus if the focused element is within the container.
300            var blurFocus = $.contains(context, document.activeElement)
301
302            // Clear out any focused controls before inserting new page contents.
303            if (blurFocus) {
304                try {
305                    document.activeElement.blur()
306                } catch (e) { /* ignore */ }
307            }
308
309            if (container.title) document.title = container.title
310
311            fire('pjax:beforeReplace', [container.contents, options], {
312                state: pjax.state,
313                previousState: previousState
314            })
315            context.html(container.contents)
316
317            // FF bug: Won't autofocus fields that are inserted via JS.
318            // This behavior is incorrect. So if theres no current focus, autofocus
319            // the last field.
320            //
321            // http://www.w3.org/html/wg/drafts/html/master/forms.html
322            var autofocusEl = context.find('input[autofocus], textarea[autofocus]').last()[0]
323            if (autofocusEl && document.activeElement !== autofocusEl) {
324                autofocusEl.focus()
325            }
326
327            executeScriptTags(container.scripts)
328
329            var scrollTo = options.scrollTo
330
331            // Ensure browser scrolls to the element referenced by the URL anchor
332            if (hash) {
333                var name = decodeURIComponent(hash.slice(1))
334                var target = document.getElementById(name) || document.getElementsByName(name)[0]
335                if (target) scrollTo = $(target).offset().top
336            }
337
338            if (typeof scrollTo == 'number') $(window).scrollTop(scrollTo)
339
340            fire('pjax:success', [data, status, xhr, options])
341        }
342
343
344        // Initialize pjax.state for the initial page load. Assume we're
345        // using the container and options of the link we're loading for the
346        // back button to the initial page. This ensures good back button
347        // behavior.
348        if (!pjax.state) {
349            pjax.state = {
350                id: uniqueId(),
351                url: window.location.href,
352                title: document.title,
353                container: options.container,
354                fragment: options.fragment,
355                timeout: options.timeout
356            }
357            window.history.replaceState(pjax.state, document.title)
358        }
359
360        // Cancel the current request if we're already pjaxing
361        abortXHR(pjax.xhr)
362
363        pjax.options = options
364        var xhr = pjax.xhr = $.ajax(options)
365
366        if (xhr.readyState > 0) {
367            if (options.push && !options.replace) {
368                // Cache current container element before replacing it
369                cachePush(pjax.state.id, [options.container, cloneContents(context)])
370
371                window.history.pushState(null, "", options.requestUrl)
372            }
373
374            fire('pjax:start', [xhr, options])
375            fire('pjax:send', [xhr, options])
376        }
377
378        return pjax.xhr
379    }
380
381// Public: Reload current page with pjax.
382//
383// Returns whatever $.pjax returns.
384    function pjaxReload(container, options) {
385        var defaults = {
386            url: window.location.href,
387            push: false,
388            replace: true,
389            scrollTo: false
390        }
391
392        return pjax($.extend(defaults, optionsFor(container, options)))
393    }
394
395// Internal: Hard replace current state with url.
396//
397// Work for around WebKit
398//   https://bugs.webkit.org/show_bug.cgi?id=93506
399//
400// Returns nothing.
401    function locationReplace(url) {
402        window.history.replaceState(null, "", pjax.state.url)
403        window.location.replace(url)
404    }
405
406
407    var initialPop = true
408    var initialURL = window.location.href
409    var initialState = window.history.state
410
411// Initialize $.pjax.state if possible
412// Happens when reloading a page and coming forward from a different
413// session history.
414    if (initialState && initialState.container) {
415        pjax.state = initialState
416    }
417
418// Non-webkit browsers don't fire an initial popstate event
419    if ('state' in window.history) {
420        initialPop = false
421    }
422
423// popstate handler takes care of the back and forward buttons
424//
425// You probably shouldn't use pjax on pages with other pushState
426// stuff yet.
427    function onPjaxPopstate(event) {
428
429        // Hitting back or forward should override any pending PJAX request.
430        if (!initialPop) {
431            abortXHR(pjax.xhr)
432        }
433
434        var previousState = pjax.state
435        var state = event.state
436        var direction
437
438        if (state && state.container) {
439            // When coming forward from a separate history session, will get an
440            // initial pop with a state we are already at. Skip reloading the current
441            // page.
442            if (initialPop && initialURL == state.url) return
443
444            if (previousState) {
445                // If popping back to the same state, just skip.
446                // Could be clicking back from hashchange rather than a pushState.
447                if (previousState.id === state.id) return
448
449                // Since state IDs always increase, we can deduce the navigation direction
450                direction = previousState.id < state.id ? 'forward' : 'back'
451            }
452
453            var cache = cacheMapping[state.id] || []
454            var containerSelector = cache[0] || state.container
455            var container = $(containerSelector), contents = cache[1]
456
457            if (container.length) {
458                if (previousState) {
459                    // Cache current container before replacement and inform the
460                    // cache which direction the history shifted.
461                    cachePop(direction, previousState.id, [containerSelector, cloneContents(container)])
462                }
463
464                var popstateEvent = $.Event('pjax:popstate', {
465                    state: state,
466                    direction: direction
467                })
468                container.trigger(popstateEvent)
469
470                var options = {
471                    id: state.id,
472                    url: state.url,
473                    container: containerSelector,
474                    push: false,
475                    fragment: state.fragment,
476                    timeout: state.timeout,
477                    scrollTo: false
478                }
479
480                if (contents) {
481                    container.trigger('pjax:start', [null, options])
482
483                    pjax.state = state
484                    if (state.title) document.title = state.title
485                    var beforeReplaceEvent = $.Event('pjax:beforeReplace', {
486                        state: state,
487                        previousState: previousState
488                    })
489                    container.trigger(beforeReplaceEvent, [contents, options])
490                    container.html(contents)
491
492                    container.trigger('pjax:end', [null, options])
493                    // 修复 jsfiddle 兼容 pjax
494                    $('head > script[src^="//jsfiddle.net"]').each(function () {
495                        $('div[data-src="'+$(this).attr('src')+'"]').after($(this))
496                    })
497                } else {
498                    pjax(options)
499                }
500
501                // Force reflow/relayout before the browser tries to restore the
502                // scroll position.
503                container[0].offsetHeight // eslint-disable-line no-unused-expressions
504            } else {
505                locationReplace(location.href)
506            }
507        }
508        initialPop = false
509    }
510
511// Fallback version of main pjax function for browsers that don't
512// support pushState.
513//
514// Returns nothing since it retriggers a hard form submission.
515    function fallbackPjax(options) {
516        var url = $.isFunction(options.url) ? options.url() : options.url,
517            method = options.type ? options.type.toUpperCase() : 'GET'
518
519        var form = $('<form>', {
520            method: method === 'GET' ? 'GET' : 'POST',
521            action: url,
522            style: 'display:none'
523        })
524
525        if (method !== 'GET' && method !== 'POST') {
526            form.append($('<input>', {
527                type: 'hidden',
528                name: '_method',
529                value: method.toLowerCase()
530            }))
531        }
532
533        var data = options.data
534        if (typeof data === 'string') {
535            $.each(data.split('&'), function(index, value) {
536                var pair = value.split('=')
537                form.append($('<input>', {type: 'hidden', name: pair[0], value: pair[1]}))
538            })
539        } else if ($.isArray(data)) {
540            $.each(data, function(index, value) {
541                form.append($('<input>', {type: 'hidden', name: value.name, value: value.value}))
542            })
543        } else if (typeof data === 'object') {
544            var key
545            for (key in data)
546                form.append($('<input>', {type: 'hidden', name: key, value: data[key]}))
547        }
548
549        $(document.body).append(form)
550        form.submit()
551    }
552
553// Internal: Abort an XmlHttpRequest if it hasn't been completed,
554// also removing its event handlers.
555    function abortXHR(xhr) {
556        if ( xhr && xhr.readyState < 4) {
557            xhr.onreadystatechange = $.noop
558            xhr.abort()
559        }
560    }
561
562// Internal: Generate unique id for state object.
563//
564// Use a timestamp instead of a counter since ids should still be
565// unique across page loads.
566//
567// Returns Number.
568    function uniqueId() {
569        return (new Date).getTime()
570    }
571
572    function cloneContents(container) {
573        var cloned = container.clone()
574        // Unmark script tags as already being eval'd so they can get executed again
575        // when restored from cache. HAXX: Uses jQuery internal method.
576        cloned.find('script').each(function(){
577            if (!this.src) $._data(this, 'globalEval', false)
578        })
579        return cloned.contents()
580    }
581
582// Internal: Strip internal query params from parsed URL.
583//
584// Returns sanitized url.href String.
585    function stripInternalParams(url) {
586        url.search = url.search.replace(/([?&])(_pjax|_)=[^&]*/g, '').replace(/^&/, '')
587        return url.href.replace(/\?($|#)/, '$1')
588    }
589
590// Internal: Parse URL components and returns a Locationish object.
591//
592// url - String URL
593//
594// Returns HTMLAnchorElement that acts like Location.
595    function parseURL(url) {
596        var a = document.createElement('a')
597        a.href = url
598        return a
599    }
600
601// Internal: Return the `href` component of given URL object with the hash
602// portion removed.
603//
604// location - Location or HTMLAnchorElement
605//
606// Returns String
607    function stripHash(location) {
608        return location.href.replace(/#.*/, '')
609    }
610
611// Internal: Build options Object for arguments.
612//
613// For convenience the first parameter can be either the container or
614// the options object.
615//
616// Examples
617//
618//   optionsFor('#container')
619//   // => {container: '#container'}
620//
621//   optionsFor('#container', {push: true})
622//   // => {container: '#container', push: true}
623//
624//   optionsFor({container: '#container', push: true})
625//   // => {container: '#container', push: true}
626//
627// Returns options Object.
628    function optionsFor(container, options) {
629        if (container && options) {
630            options = $.extend({}, options)
631            options.container = container
632            return options
633        } else if ($.isPlainObject(container)) {
634            return container
635        } else {
636            return {container: container}
637        }
638    }
639
640// Internal: Filter and find all elements matching the selector.
641//
642// Where $.fn.find only matches descendants, findAll will test all the
643// top level elements in the jQuery object as well.
644//
645// elems    - jQuery object of Elements
646// selector - String selector to match
647//
648// Returns a jQuery object.
649    function findAll(elems, selector) {
650        return elems.filter(selector).add(elems.find(selector))
651    }
652
653    function parseHTML(html) {
654        return $.parseHTML(html, document, true)
655    }
656
657// Internal: Extracts container and metadata from response.
658//
659// 1. Extracts X-PJAX-URL header if set
660// 2. Extracts inline <title> tags
661// 3. Builds response Element and extracts fragment if set
662//
663// data    - String response data
664// xhr     - XHR response
665// options - pjax options Object
666//
667// Returns an Object with url, title, and contents keys.
668    function extractContainer(data, xhr, options) {
669        var obj = {}, fullDocument = /<html/i.test(data)
670
671        // Prefer X-PJAX-URL header if it was set, otherwise fallback to
672        // using the original requested url.
673        var serverUrl = xhr.getResponseHeader('X-PJAX-URL')
674        obj.url = serverUrl ? stripInternalParams(parseURL(serverUrl)) : options.requestUrl
675
676        var $head, $body
677        // Attempt to parse response html into elements
678        if (fullDocument) {
679            $body = $(parseHTML(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0]))
680            var head = data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)
681            $head = head != null ? $(parseHTML(head[0])) : $body
682        } else {
683            $head = $body = $(parseHTML(data))
684        }
685
686        // If response data is empty, return fast
687        if ($body.length === 0)
688            return obj
689
690        // If there's a <title> tag in the header, use it as
691        // the page's title.
692        obj.title = findAll($head, 'title').last().text()
693
694        if (options.fragment) {
695            var $fragment = $body
696            // If they specified a fragment, look for it in the response
697            // and pull it out.
698            if (options.fragment !== 'body') {
699                $fragment = findAll($fragment, options.fragment).first()
700            }
701
702            if ($fragment.length) {
703                obj.contents = options.fragment === 'body' ? $fragment : $fragment.contents()
704
705                // If there's no title, look for data-title and title attributes
706                // on the fragment
707                if (!obj.title)
708                    obj.title = $fragment.attr('title') || $fragment.data('title')
709            }
710
711        } else if (!fullDocument) {
712            obj.contents = $body
713        }
714
715        // Clean up any <title> tags
716        if (obj.contents) {
717            // Remove any parent title elements
718            obj.contents = obj.contents.not(function() { return $(this).is('title') })
719
720            // Then scrub any titles from their descendants
721            obj.contents.find('title').remove()
722
723            // Gather all script[src] elements
724            obj.scripts = findAll(obj.contents, 'script[src]')
725            obj.scripts.each(function () {
726                $(this).after('<div style="display: none" data-src="'+$(this).attr('src')+'"></div>')
727                $(this).remove()
728            })
729
730            obj.contents = obj.contents.not(obj.scripts)
731        }
732
733        // Trim any whitespace off the title
734        if (obj.title) obj.title = $.trim(obj.title)
735
736        return obj
737    }
738
739// Load an execute scripts using standard script request.
740//
741// Avoids jQuery's traditional $.getScript which does a XHR request and
742// globalEval.
743//
744// scripts - jQuery object of script Elements
745//
746// Returns nothing.
747    function executeScriptTags(scripts) {
748        if (!scripts) return
749
750        var existingScripts = $('script[src]')
751
752        scripts.each(function() {
753            var src = this.src
754            var matchedScripts = existingScripts.filter(function() {
755                return this.src === src
756            })
757            if (matchedScripts.length) return
758
759            var script = document.createElement('script')
760            var type = $(this).attr('type')
761            if (type) script.type = type
762            script.src = $(this).attr('src')
763            document.head.appendChild(script)
764        })
765    }
766
767// Internal: History DOM caching class.
768    var cacheMapping      = {}
769    var cacheForwardStack = []
770    var cacheBackStack    = []
771
772// Push previous state id and container contents into the history
773// cache. Should be called in conjunction with `pushState` to save the
774// previous container contents.
775//
776// id    - State ID Number
777// value - DOM Element to cache
778//
779// Returns nothing.
780    function cachePush(id, value) {
781        cacheMapping[id] = value
782        cacheBackStack.push(id)
783
784        // Remove all entries in forward history stack after pushing a new page.
785        trimCacheStack(cacheForwardStack, 0)
786
787        // Trim back history stack to max cache length.
788        trimCacheStack(cacheBackStack, pjax.defaults.maxCacheLength)
789    }
790
791// Shifts cache from directional history cache. Should be
792// called on `popstate` with the previous state id and container
793// contents.
794//
795// direction - "forward" or "back" String
796// id        - State ID Number
797// value     - DOM Element to cache
798//
799// Returns nothing.
800    function cachePop(direction, id, value) {
801        var pushStack, popStack
802        cacheMapping[id] = value
803
804        if (direction === 'forward') {
805            pushStack = cacheBackStack
806            popStack  = cacheForwardStack
807        } else {
808            pushStack = cacheForwardStack
809            popStack  = cacheBackStack
810        }
811
812        pushStack.push(id)
813        id = popStack.pop()
814        if (id) delete cacheMapping[id]
815
816        // Trim whichever stack we just pushed to to max cache length.
817        trimCacheStack(pushStack, pjax.defaults.maxCacheLength)
818    }
819
820// Trim a cache stack (either cacheBackStack or cacheForwardStack) to be no
821// longer than the specified length, deleting cached DOM elements as necessary.
822//
823// stack  - Array of state IDs
824// length - Maximum length to trim to
825//
826// Returns nothing.
827    function trimCacheStack(stack, length) {
828        while (stack.length > length)
829            delete cacheMapping[stack.shift()]
830    }
831
832// Public: Find version identifier for the initial page load.
833//
834// Returns String version or undefined.
835    function findVersion() {
836        return $('meta').filter(function() {
837            var name = $(this).attr('http-equiv')
838            return name && name.toUpperCase() === 'X-PJAX-VERSION'
839        }).attr('content')
840    }
841
842// Install pjax functions on $.pjax to enable pushState behavior.
843//
844// Does nothing if already enabled.
845//
846// Examples
847//
848//     $.pjax.enable()
849//
850// Returns nothing.
851    function enable() {
852        $.fn.pjax = fnPjax
853        $.pjax = pjax
854        $.pjax.enable = $.noop
855        $.pjax.disable = disable
856        $.pjax.click = handleClick
857        $.pjax.submit = handleSubmit
858        $.pjax.reload = pjaxReload
859        $.pjax.defaults = {
860            timeout: 650,
861            push: true,
862            replace: false,
863            type: 'GET',
864            dataType: 'html',
865            scrollTo: 0,
866            maxCacheLength: 20,
867            version: findVersion
868        }
869        $(window).on('popstate.pjax', onPjaxPopstate)
870    }
871
872// Disable pushState behavior.
873//
874// This is the case when a browser doesn't support pushState. It is
875// sometimes useful to disable pushState for debugging on a modern
876// browser.
877//
878// Examples
879//
880//     $.pjax.disable()
881//
882// Returns nothing.
883    function disable() {
884        $.fn.pjax = function() { return this }
885        $.pjax = fallbackPjax
886        $.pjax.enable = enable
887        $.pjax.disable = $.noop
888        $.pjax.click = $.noop
889        $.pjax.submit = $.noop
890        $.pjax.reload = function() { window.location.reload() }
891
892        $(window).off('popstate.pjax', onPjaxPopstate)
893    }
894
895
896// Add the state property to jQuery's event object so we can use it in
897// $(window).bind('popstate')
898    if ($.event.props && $.inArray('state', $.event.props) < 0) {
899        $.event.props.push('state')
900    } else if (!('state' in $.Event.prototype)) {
901        $.event.addProp('state')
902    }
903
904// Is pjax supported by this browser?
905    $.support.pjax =
906        window.history && window.history.pushState && window.history.replaceState &&
907        // pushState isn't reliable on iOS until 5.
908        !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/)
909
910    if ($.support.pjax) {
911        enable()
912    } else {
913        disable()
914    }
915
916})(jQuery)

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.