vendor: 29,103 bytes, lines 1-894
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 } 241 242 options.error = function(xhr, textStatus, errorThrown) { 243 var container = extractContainer("", xhr, options) 244 245 var allowed = fire('pjax:error', [xhr, textStatus, errorThrown, options]) 246 if (options.type == 'GET' && textStatus !== 'abort' && allowed) { 247 locationReplace(container.url) 248 } 249 } 250 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 262 var container = extractContainer(data, xhr, options) 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 277 if (!container.contents) { 278 locationReplace(container.url) 279 return 280 } 281 282 pjax.state = { 283 id: options.id || uniqueId(), 284 url: container.url, 285 title: container.title, 286 container: options.container, 287 fragment: options.fragment, 288 timeout: options.timeout 289 } 290 291 if (options.push || options.replace) { 292 window.history.replaceState(pjax.state, container.title, container.url) 293 } 294 295 // Only blur the focus if the focused element is within the container. 296 var blurFocus = $.contains(context, 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) { /* ignore */ } 303 } 304 305 if (container.title) document.title = container.title 306 307 fire('pjax:beforeReplace', [container.contents, options], { 308 state: pjax.state, 309 previousState: previousState 310 }) 311 context.html(container.contents) 312 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) 324 325 var scrollTo = options.scrollTo 326 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 332 } 333 334 if (typeof scrollTo == 'number') $(window).scrollTop(scrollTo) 335 336 fire('pjax:success', [data, status, xhr, options]) 337 } 338 339 340 // Initialize pjax.state for the initial page load. Assume we're 341 // using the container and options of the link we're loading for the 342 // back button to the initial page. This ensures good back button 343 // behavior. 344 if (!pjax.state) { 345 pjax.state = { 346 id: uniqueId(), 347 url: window.location.href, 348 title: document.title, 349 container: options.container, 350 fragment: options.fragment, 351 timeout: options.timeout 352 } 353 window.history.replaceState(pjax.state, document.title) 354 } 355 356 // Cancel the current request if we're already pjaxing 357 abortXHR(pjax.xhr) 358 359 pjax.options = options 360 var xhr = pjax.xhr = $.ajax(options) 361 362 if (xhr.readyState > 0) { 363 if (options.push && !options.replace) { 364 // Cache current container element before replacing it 365 cachePush(pjax.state.id, [options.container, cloneContents(context)]) 366 367 window.history.pushState(null, "", options.requestUrl) 368 } 369 370 fire('pjax:start', [xhr, options]) 371 fire('pjax:send', [xhr, options]) 372 } 373 374 return pjax.xhr 375 } 376 377// Public: Reload current page with pjax. 378// 379// Returns whatever $.pjax returns. 380 function pjaxReload(container, options) { 381 var defaults = { 382 url: window.location.href, 383 push: false, 384 replace: true, 385 scrollTo: false 386 } 387 388 return pjax($.extend(defaults, optionsFor(container, options))) 389 } 390 391// Internal: Hard replace current state with url. 392// 393// Work for around WebKit 394// https://bugs.webkit.org/show_bug.cgi?id=93506 395// 396// Returns nothing. 397 function locationReplace(url) { 398 window.history.replaceState(null, "", pjax.state.url) 399 window.location.replace(url) 400 } 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 419// popstate handler takes care of the back and forward buttons 420// 421// You probably shouldn't use pjax on pages with other pushState 422// stuff yet. 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 431 var state = event.state 432 var direction 433 434 if (state && state.container) { 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 } 448 449 var cache = cacheMapping[state.id] || [] 450 var containerSelector = cache[0] || state.container 451 var container = $(containerSelector), contents = cache[1] 452 453 if (container.length) { 454 if (previousState) { 455 // Cache current container before replacement and inform the 456 // cache which direction the history shifted. 457 cachePop(direction, previousState.id, [containerSelector, cloneContents(container)]) 458 } 459 460 var popstateEvent = $.Event('pjax:popstate', { 461 state: state, 462 direction: direction 463 }) 464 container.trigger(popstateEvent) 465 466 var options = { 467 id: state.id, 468 url: state.url, 469 container: containerSelector, 470 push: false, 471 fragment: state.fragment, 472 timeout: state.timeout, 473 scrollTo: false 474 } 475 476 if (contents) { 477 container.trigger('pjax:start', [null, options]) 478 479 pjax.state = state 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]) 486 container.html(contents) 487 488 container.trigger('pjax:end', [null, options]) 489 } else { 490 pjax(options) 491 } 492 493 // Force reflow/relayout before the browser tries to restore the 494 // scroll position. 495 container[0].offsetHeight // eslint-disable-line no-unused-expressions 496 } else { 497 locationReplace(location.href) 498 } 499 } 500 initialPop = false 501 } 502 503// Fallback version of main pjax function for browsers that don't 504// support pushState. 505// 506// Returns nothing since it retriggers a hard form submission. 507 function fallbackPjax(options) { 508 var url = $.isFunction(options.url) ? options.url() : options.url, 509 method = options.type ? options.type.toUpperCase() : 'GET' 510 511 var form = $('<form>', { 512 method: method === 'GET' ? 'GET' : 'POST', 513 action: url, 514 style: 'display:none' 515 }) 516 517 if (method !== 'GET' && method !== 'POST') { 518 form.append($('<input>', { 519 type: 'hidden', 520 name: '_method', 521 value: method.toLowerCase() 522 })) 523 } 524 525 var data = options.data 526 if (typeof data === 'string') { 527 $.each(data.split('&'), function(index, value) { 528 var pair = value.split('=') 529 form.append($('<input>', {type: 'hidden', name: pair[0], value: pair[1]})) 530 }) 531 } else if ($.isArray(data)) { 532 $.each(data, function(index, value) { 533 form.append($('<input>', {type: 'hidden', name: value.name, value: value.value})) 534 }) 535 } else if (typeof data === 'object') { 536 var key 537 for (key in data) 538 form.append($('<input>', {type: 'hidden', name: key, value: data[key]})) 539 } 540 541 $(document.body).append(form) 542 form.submit() 543 } 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 554// Internal: Generate unique id for state object. 555// 556// Use a timestamp instead of a counter since ids should still be 557// unique across page loads. 558// 559// Returns Number. 560 function uniqueId() { 561 return (new Date).getTime() 562 } 563 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) $._data(this, 'globalEval', false) 570 }) 571 return cloned.contents() 572 } 573 574// Internal: Strip internal query params from parsed URL. 575// 576// Returns sanitized url.href String. 577 function stripInternalParams(url) { 578 url.search = url.search.replace(/([?&])(_pjax|_)=[^&]*/g, '').replace(/^&/, '') 579 return url.href.replace(/\?($|#)/, '$1') 580 } 581 582// Internal: Parse URL components and returns a Locationish object. 583// 584// url - String URL 585// 586// Returns HTMLAnchorElement that acts like Location. 587 function parseURL(url) { 588 var a = document.createElement('a') 589 a.href = url 590 return a 591 } 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 603// Internal: Build options Object for arguments. 604// 605// For convenience the first parameter can be either the container or 606// the options object. 607// 608// Examples 609// 610// optionsFor('#container') 611// // => {container: '#container'} 612// 613// optionsFor('#container', {push: true}) 614// // => {container: '#container', push: true} 615// 616// optionsFor({container: '#container', push: true}) 617// // => {container: '#container', push: true} 618// 619// Returns options Object. 620 function optionsFor(container, options) { 621 if (container && options) { 622 options = $.extend({}, options) 623 options.container = container 624 return options 625 } else if ($.isPlainObject(container)) { 626 return container 627 } else { 628 return {container: container} 629 } 630 } 631 632// Internal: Filter and find all elements matching the selector. 633// 634// Where $.fn.find only matches descendants, findAll will test all the 635// top level elements in the jQuery object as well. 636// 637// elems - jQuery object of Elements 638// selector - String selector to match 639// 640// Returns a jQuery object. 641 function findAll(elems, selector) { 642 return elems.filter(selector).add(elems.find(selector)) 643 } 644 645 function parseHTML(html) { 646 return $.parseHTML(html, document, true) 647 } 648 649// Internal: Extracts container and metadata from response. 650// 651// 1. Extracts X-PJAX-URL header if set 652// 2. Extracts inline <title> tags 653// 3. Builds response Element and extracts fragment if set 654// 655// data - String response data 656// xhr - XHR response 657// options - pjax options Object 658// 659// Returns an Object with url, title, and contents keys. 660 function extractContainer(data, xhr, options) { 661 var obj = {}, fullDocument = /<html/i.test(data) 662 663 // Prefer X-PJAX-URL header if it was set, otherwise fallback to 664 // using the original requested url. 665 var serverUrl = xhr.getResponseHeader('X-PJAX-URL') 666 obj.url = serverUrl ? stripInternalParams(parseURL(serverUrl)) : options.requestUrl 667 668 var $head, $body 669 // Attempt to parse response html into elements 670 if (fullDocument) { 671 $body = $(parseHTML(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0])) 672 var head = data.match(/<head[^>]*>([\s\S.]*)<\/head>/i) 673 $head = head != null ? $(parseHTML(head[0])) : $body 674 } else { 675 $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 var $fragment = $body 688 // If they specified a fragment, look for it in the response 689 // and pull it out. 690 if (options.fragment !== 'body') { 691 $fragment = findAll($fragment, options.fragment).first() 692 } 693 694 if ($fragment.length) { 695 obj.contents = options.fragment === 'body' ? $fragment : $fragment.contents() 696 697 // If there's no title, look for data-title and title attributes 698 // on the fragment 699 if (!obj.title) 700 obj.title = $fragment.attr('title') || $fragment.data('title') 701 } 702 703 } else if (!fullDocument) { 704 obj.contents = $body 705 } 706 707 // Clean up any <title> tags 708 if (obj.contents) { 709 // Remove any parent title elements 710 obj.contents = obj.contents.not(function() { return $(this).is('title') }) 711 712 // Then scrub any titles from their descendants 713 obj.contents.find('title').remove() 714 715 // Gather all script[src] elements 716 obj.scripts = findAll(obj.contents, 'script[src]').remove() 717 obj.contents = obj.contents.not(obj.scripts) 718 } 719 720 // Trim any whitespace off the title 721 if (obj.title) obj.title = $.trim(obj.title) 722 723 return obj 724 } 725 726// Load an execute scripts using standard script request. 727// 728// Avoids jQuery's traditional $.getScript which does a XHR request and 729// globalEval. 730// 731// scripts - jQuery object of script Elements 732// 733// Returns nothing. 734 function executeScriptTags(scripts) { 735 if (!scripts) return 736 737 var existingScripts = $('script[src]') 738 739 scripts.each(function() { 740 var src = this.src 741 var matchedScripts = existingScripts.filter(function() { 742 return this.src === src 743 }) 744 if (matchedScripts.length) return 745 746 var script = document.createElement('script') 747 var type = $(this).attr('type') 748 if (type) script.type = type 749 script.src = $(this).attr('src') 750 document.head.appendChild(script) 751 }) 752 } 753 754// Internal: History DOM caching class. 755 var cacheMapping = {} 756 var cacheForwardStack = [] 757 var cacheBackStack = [] 758 759// Push previous state id and container contents into the history 760// cache. Should be called in conjunction with `pushState` to save the 761// previous container contents. 762// 763// id - State ID Number 764// value - DOM Element to cache 765// 766// Returns nothing. 767 function cachePush(id, value) { 768 cacheMapping[id] = value 769 cacheBackStack.push(id) 770 771 // Remove all entries in forward history stack after pushing a new page. 772 trimCacheStack(cacheForwardStack, 0) 773 774 // Trim back history stack to max cache length. 775 trimCacheStack(cacheBackStack, pjax.defaults.maxCacheLength) 776 } 777 778// Shifts cache from directional history cache. Should be 779// called on `popstate` with the previous state id and container 780// contents. 781// 782// direction - "forward" or "back" String 783// id - State ID Number 784// value - DOM Element to cache 785// 786// Returns nothing. 787 function cachePop(direction, id, value) { 788 var pushStack, popStack 789 cacheMapping[id] = value 790 791 if (direction === 'forward') { 792 pushStack = cacheBackStack 793 popStack = cacheForwardStack 794 } else { 795 pushStack = cacheForwardStack 796 popStack = cacheBackStack 797 } 798 799 pushStack.push(id) 800 id = popStack.pop() 801 if (id) delete cacheMapping[id] 802 803 // Trim whichever stack we just pushed to to max cache length. 804 trimCacheStack(pushStack, pjax.defaults.maxCacheLength) 805 } 806 807// Trim a cache stack (either cacheBackStack or cacheForwardStack) to be no 808// longer than the specified length, deleting cached DOM elements as necessary. 809// 810// stack - Array of state IDs 811// length - Maximum length to trim to 812// 813// Returns nothing. 814 function trimCacheStack(stack, length) { 815 while (stack.length > length) 816 delete cacheMapping[stack.shift()] 817 } 818 819// Public: Find version identifier for the initial page load. 820// 821// Returns String version or undefined. 822 function findVersion() { 823 return $('meta').filter(function() { 824 var name = $(this).attr('http-equiv') 825 return name && name.toUpperCase() === 'X-PJAX-VERSION' 826 }).attr('content') 827 } 828 829// Install pjax functions on $.pjax to enable pushState behavior. 830// 831// Does nothing if already enabled. 832// 833// Examples 834// 835// $.pjax.enable() 836// 837// Returns nothing. 838 function enable() { 839 $.fn.pjax = fnPjax 840 $.pjax = pjax 841 $.pjax.enable = $.noop 842 $.pjax.disable = disable 843 $.pjax.click = handleClick 844 $.pjax.submit = handleSubmit 845 $.pjax.reload = pjaxReload 846 $.pjax.defaults = { 847 timeout: 650, 848 push: true, 849 replace: false, 850 type: 'GET', 851 dataType: 'html', 852 scrollTo: 0, 853 maxCacheLength: 20, 854 version: findVersion 855 } 856 $(window).on('popstate.pjax', onPjaxPopstate) 857 } 858 859// Disable pushState behavior. 860// 861// This is the case when a browser doesn't support pushState. It is 862// sometimes useful to disable pushState for debugging on a modern 863// browser. 864// 865// Examples 866// 867// $.pjax.disable() 868// 869// Returns nothing. 870 function disable() { 871 $.fn.pjax = function() { return this } 872 $.pjax = fallbackPjax 873 $.pjax.enable = enable 874 $.pjax.disable = $.noop 875 $.pjax.click = $.noop 876 $.pjax.submit = $.noop 877 $.pjax.reload = function() { window.location.reload() } 878 879 $(window).off('popstate.pjax', onPjaxPopstate) 880 } 881 882 883// Add the state property to jQuery's event object so we can use it in 884// $(window).bind('popstate') 885 if ($.event.props && $.inArray('state', $.event.props) < 0) { 886 $.event.props.push('state') 887 } else if (!('state' in $.Event.prototype)) { 888 $.event.addProp('state') 889 } 890 891// Is pjax supported by this browser? 892 $.support.pjax = 893 window.history && window.history.pushState && window.history.replaceState && 894 // pushState isn't reliable on iOS until 5.
895 !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/) 896 897 if ($.support.pjax) { 898 enable() 899 } else { 900 disable() 901 } 902 903})(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.