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.