PageSourceSearch

https://ifangler.com/assets/js/jquery.pjax.js

js ifangler.com collected 2026-10-09 22:07:43 UTC 25,031 bytes, 897 lines download raw bytes

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