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 var $form = $(form) 123 124 if (form.tagName.toUpperCase() !== 'FORM') 125 throw "$.pjax.submit requires a form element" 126 127 var defaults = { 128 type: ($form.attr('method') || 'GET').toUpperCase(), 129 url: $form.attr('action'), 130 container: $form.attr('data-pjax'), 131 target: form 132 } 133 134 if (defaults.type !== 'GET' && window.FormData !== undefined) { 135 defaults.data = new FormData(form); 136 defaults.processData = false; 137 defaults.contentType = false;
vendor: 9,684 bytes, lines 138-471
138 } else { 139 // Can't handle file uploads, exit 140 if ($(form).find(':file').length) { 141 return; 142 } 143 144 // Fallback to manually serializing the fields 145 defaults.data = $(form).serializeArray(); 146 } 147 148 pjax($.extend({}, defaults, options)) 149 150 event.preventDefault() 151} 152 153// Loads a URL with ajax, puts the response body inside a container, 154// then pushState()'s the loaded URL. 155// 156// Works just like $.ajax in that it accepts a jQuery ajax 157// settings object (with keys like url, type, data, etc). 158// 159// Accepts these extra keys: 160// 161// container - Where to stick the response body. 162// $(container).html(xhr.responseBody) 163// push - Whether to pushState the URL. Defaults to true (of course). 164// replace - Want to use replaceState instead? That's cool. 165// 166// Use it just like $.ajax: 167// 168// var xhr = $.pjax({ url: this.href, container: '#main' }) 169// console.log( xhr.readyState ) 170// 171// Returns whatever $.ajax returns. 172function pjax(options) { 173 options = $.extend(true, {}, $.ajaxSettings, pjax.defaults, options) 174 175 if ($.isFunction(options.url)) { 176 options.url = options.url() 177 } 178 179 var target = options.target 180 181 var hash = parseURL(options.url).hash 182 183 var context = options.context = findContainerFor(options.container) 184 185 // We want the browser to maintain two separate internal caches: one 186 // for pjax'd partial page loads and one for normal page loads. 187 // Without adding this secret parameter, some browsers will often 188 // confuse the two. 189 if (!options.data) options.data = {} 190 if ($.isArray(options.data)) { 191 options.data.push({name: '_pjax', value: context.selector}) 192 } else { 193 options.data._pjax = context.selector 194 } 195 196 function fire(type, args, props) { 197 if (!props) props = {} 198 props.relatedTarget = target 199 var event = $.Event(type, props) 200 context.trigger(event, args) 201 return !event.isDefaultPrevented() 202 } 203 204 var timeoutTimer 205 206 options.beforeSend = function(xhr, settings) { 207 // No timeout for non-GET requests 208 // Its not safe to request the resource again with a fallback method. 209 if (settings.type !== 'GET') { 210 settings.timeout = 0 211 } 212 213 xhr.setRequestHeader('X-PJAX', 'true') 214 xhr.setRequestHeader('X-PJAX-Container', context.selector) 215 216 if (!fire('pjax:beforeSend', [xhr, settings])) 217 return false 218 219 if (settings.timeout > 0) { 220 timeoutTimer = setTimeout(function() { 221 if (fire('pjax:timeout', [xhr, options])) 222 xhr.abort('timeout') 223 }, settings.timeout) 224 225 // Clear timeout setting so jquerys internal timeout isn't invoked 226 settings.timeout = 0 227 } 228 229 var url = parseURL(settings.url) 230 if (hash) url.hash = hash 231 options.requestUrl = stripInternalParams(url) 232 } 233 234 options.complete = function(xhr, textStatus) { 235 if (timeoutTimer) 236 clearTimeout(timeoutTimer) 237 238 fire('pjax:complete', [xhr, textStatus, options]) 239 240 fire('pjax:end', [xhr, options]) 241 } 242 243 options.error = function(xhr, textStatus, errorThrown) { 244 var container = extractContainer("", xhr, options) 245 246 var allowed = fire('pjax:error', [xhr, textStatus, errorThrown, options]) 247 if (options.type == 'GET' && textStatus !== 'abort' && allowed) { 248 locationReplace(container.url) 249 } 250 } 251 252 options.success = function(data, status, xhr) { 253 var previousState = pjax.state; 254 255 // If $.pjax.defaults.version is a function, invoke it first. 256 // Otherwise it can be a static string. 257 var currentVersion = (typeof $.pjax.defaults.version === 'function') ? 258 $.pjax.defaults.version() : 259 $.pjax.defaults.version 260 261 var latestVersion = xhr.getResponseHeader('X-PJAX-Version') 262 263 var container = extractContainer(data, xhr, options) 264 265 var url = parseURL(container.url) 266 if (hash) { 267 url.hash = hash 268 container.url = url.href 269 } 270 271 // If there is a layout version mismatch, hard load the new url 272 if (currentVersion && latestVersion && currentVersion !== latestVersion) { 273 locationReplace(container.url) 274 return 275 } 276 277 // If the new response is missing a body, hard load the page 278 if (!container.contents) { 279 locationReplace(container.url) 280 return 281 } 282 283 pjax.state = { 284 id: options.id || uniqueId(), 285 url: container.url, 286 title: container.title, 287 container: context.selector, 288 fragment: options.fragment, 289 timeout: options.timeout 290 } 291 292 if (options.push || options.replace) { 293 window.history.replaceState(pjax.state, container.title, container.url) 294 } 295 296 // Only blur the focus if the focused element is within the container. 297 var blurFocus = $.contains(options.container, document.activeElement) 298 299 // Clear out any focused controls before inserting new page contents. 300 if (blurFocus) { 301 try { 302 document.activeElement.blur() 303 } catch (e) { } 304 } 305 306 if (container.title) document.title = container.title 307 308 fire('pjax:beforeReplace', [container.contents, options], { 309 state: pjax.state, 310 previousState: previousState 311 }) 312 context.html(container.contents) 313 314 // FF bug: Won't autofocus fields that are inserted via JS. 315 // This behavior is incorrect. So if theres no current focus, autofocus 316 // the last field. 317 // 318 // http://www.w3.org/html/wg/drafts/html/master/forms.html 319 var autofocusEl = context.find('input[autofocus], textarea[autofocus]').last()[0] 320 if (autofocusEl && document.activeElement !== autofocusEl) { 321 autofocusEl.focus(); 322 } 323 324 executeScriptTags(container.scripts) 325 326 var scrollTo = options.scrollTo 327 328 // Ensure browser scrolls to the element referenced by the URL anchor 329 if (hash) { 330 var name = decodeURIComponent(hash.slice(1)) 331 var target = document.getElementById(name) || document.getElementsByName(name)[0] 332 if (target) scrollTo = $(target).offset().top 333 } 334 335 if (typeof scrollTo == 'number') $(window).scrollTop(scrollTo) 336 337 fire('pjax:success', [data, status, xhr, options]) 338 } 339 340 341 // Initialize pjax.state for the initial page load. Assume we're 342 // using the container and options of the link we're loading for the 343 // back button to the initial page. This ensures good back button 344 // behavior. 345 if (!pjax.state) { 346 pjax.state = { 347 id: uniqueId(), 348 url: window.location.href, 349 title: document.title, 350 container: context.selector, 351 fragment: options.fragment, 352 timeout: options.timeout 353 } 354 window.history.replaceState(pjax.state, document.title) 355 } 356 357 // Cancel the current request if we're already pjaxing 358 abortXHR(pjax.xhr) 359 360 pjax.options = options 361 var xhr = pjax.xhr = $.ajax(options) 362 363 if (xhr.readyState > 0) { 364 if (options.push && !options.replace) { 365 // Cache current container element before replacing it 366 cachePush(pjax.state.id, cloneContents(context)) 367 368 window.history.pushState(null, "", options.requestUrl) 369 } 370 371 fire('pjax:start', [xhr, options]) 372 fire('pjax:send', [xhr, options]) 373 } 374 375 return pjax.xhr 376} 377 378// Public: Reload current page with pjax. 379// 380// Returns whatever $.pjax returns. 381function pjaxReload(container, options) { 382 var defaults = { 383 url: window.location.href, 384 push: false, 385 replace: true, 386 scrollTo: false 387 } 388 389 return pjax($.extend(defaults, optionsFor(container, options))) 390} 391 392// Internal: Hard replace current state with url. 393// 394// Work for around WebKit 395// https://bugs.webkit.org/show_bug.cgi?id=93506 396// 397// Returns nothing. 398function locationReplace(url) { 399 window.history.replaceState(null, "", pjax.state.url) 400 window.location.replace(url) 401} 402 403 404var initialPop = true 405var initialURL = window.location.href 406var initialState = window.history.state 407 408// Initialize $.pjax.state if possible 409// Happens when reloading a page and coming forward from a different 410// session history. 411if (initialState && initialState.container) { 412 pjax.state = initialState 413} 414 415// Non-webkit browsers don't fire an initial popstate event 416if ('state' in window.history) { 417 initialPop = false 418} 419 420// popstate handler takes care of the back and forward buttons 421// 422// You probably shouldn't use pjax on pages with other pushState 423// stuff yet. 424function onPjaxPopstate(event) { 425 426 // Hitting back or forward should override any pending PJAX request. 427 if (!initialPop) { 428 abortXHR(pjax.xhr) 429 } 430 431 var previousState = pjax.state 432 var state = event.state 433 var direction 434 435 if (state && state.container) { 436 // When coming forward from a separate history session, will get an 437 // initial pop with a state we are already at. Skip reloading the current 438 // page. 439 if (initialPop && initialURL == state.url) return 440 441 if (previousState) { 442 // If popping back to the same state, just skip. 443 // Could be clicking back from hashchange rather than a pushState. 444 if (previousState.id === state.id) return 445 446 // Since state IDs always increase, we can deduce the navigation direction 447 direction = previousState.id < state.id ? 'forward' : 'back' 448 } 449 450 var cache = cacheMapping[state.id] || [] 451 var container = $(cache[0] || state.container), 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, 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: container, 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 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. 507function 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. 547function 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. 560function uniqueId() { 561 return (new Date).getTime() 562} 563 564function cloneContents(container) { 565 var cloned = container.clone() 566 // Unmark script tags as already being eval'd so they can get executed again 567 // when restored from cache. HAXX: Uses jQuery internal method. 568 cloned.find('script').each(function(){ 569 if (!this.src) jQuery._data(this, 'globalEval', false) 570 }) 571 return [container.selector, cloned.contents()] 572} 573 574// Internal: Strip internal query params from parsed URL. 575// 576// Returns sanitized url.href String. 577function stripInternalParams(url) { 578 url.search = url.search.replace(/([?&])(_pjax|_)=[^&]*/g, '') 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. 587function 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 599function 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. 620function optionsFor(container, options) { 621 // Both container and options 622 if ( container && options ) 623 options.container = container 624 625 // First argument is options Object 626 else if ( $.isPlainObject(container) ) 627 options = container 628 629 // Only container 630 else 631 options = {container: container} 632 633 // Find and validate container 634 if (options.container) 635 options.container = findContainerFor(options.container) 636 637 return options 638} 639 640// Internal: Find container element for a variety of inputs. 641// 642// Because we can't persist elements using the history API, we must be 643// able to find a String selector that will consistently find the Element. 644// 645// container - A selector String, jQuery object, or DOM Element. 646// 647// Returns a jQuery object whose context is `document` and has a selector. 648function findContainerFor(container) { 649 container = $(container) 650 651 if ( !container.length ) { 652 throw "no pjax container for " + container.selector 653 } else if ( container.selector !== '' && container.context === document ) { 654 return container 655 } else if ( container.attr('id') ) { 656 return $('#' + container.attr('id')) 657 } else { 658 throw "cant get selector for pjax container!" 659 } 660} 661 662// Internal: Filter and find all elements matching the selector. 663// 664// Where $.fn.find only matches descendants, findAll will test all the 665// top level elements in the jQuery object as well. 666// 667// elems - jQuery object of Elements 668// selector - String selector to match 669// 670// Returns a jQuery object. 671function findAll(elems, selector) { 672 return elems.filter(selector).add(elems.find(selector)); 673} 674 675function parseHTML(html) { 676 return $.parseHTML(html, document, true) 677} 678 679// Internal: Extracts container and metadata from response. 680// 681// 1. Extracts X-PJAX-URL header if set 682// 2. Extracts inline <title> tags 683// 3. Builds response Element and extracts fragment if set 684// 685// data - String response data 686// xhr - XHR response 687// options - pjax options Object 688// 689// Returns an Object with url, title, and contents keys. 690function extractContainer(data, xhr, options) { 691 var obj = {}, fullDocument = /<html/i.test(data) 692 693 // Prefer X-PJAX-URL header if it was set, otherwise fallback to 694 // using the original requested url. 695 var serverUrl = xhr.getResponseHeader('X-PJAX-URL')
vendor: 5,929 bytes, lines 696-917
696 obj.url = serverUrl ? stripInternalParams(parseURL(serverUrl)) : options.requestUrl 697 698 // Attempt to parse response html into elements 699 if (fullDocument) { 700 var $head = $(parseHTML(data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0])) 701 var $body = $(parseHTML(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0])) 702 } else { 703 var $head = $body = $(parseHTML(data)) 704 } 705 706 // If response data is empty, return fast 707 if ($body.length === 0) 708 return obj 709 710 // If there's a <title> tag in the header, use it as 711 // the page's title. 712 obj.title = findAll($head, 'title').last().text() 713 714 if (options.fragment) { 715 // If they specified a fragment, look for it in the response 716 // and pull it out. 717 if (options.fragment === 'body') { 718 var $fragment = $body 719 } else { 720 var $fragment = findAll($body, options.fragment).first() 721 } 722 723 if ($fragment.length) { 724 obj.contents = options.fragment === 'body' ? $fragment : $fragment.contents() 725 726 // If there's no title, look for data-title and title attributes 727 // on the fragment 728 if (!obj.title) 729 obj.title = $fragment.attr('title') || $fragment.data('title') 730 } 731 732 } else if (!fullDocument) { 733 obj.contents = $body 734 } 735 736 // Clean up any <title> tags 737 if (obj.contents) { 738 // Remove any parent title elements 739 obj.contents = obj.contents.not(function() { return $(this).is('title') }) 740 741 // Then scrub any titles from their descendants 742 obj.contents.find('title').remove() 743 744 // Gather all script[src] elements 745 obj.scripts = findAll(obj.contents, 'script[src]').remove() 746 obj.contents = obj.contents.not(obj.scripts) 747 } 748 749 // Trim any whitespace off the title 750 if (obj.title) obj.title = $.trim(obj.title) 751 752 return obj 753} 754 755// Load an execute scripts using standard script request. 756// 757// Avoids jQuery's traditional $.getScript which does a XHR request and 758// globalEval. 759// 760// scripts - jQuery object of script Elements 761// 762// Returns nothing. 763function executeScriptTags(scripts) { 764 if (!scripts) return 765 766 var existingScripts = $('script[src]') 767 768 scripts.each(function() { 769 var src = this.src 770 var matchedScripts = existingScripts.filter(function() { 771 return this.src === src 772 }) 773 if (matchedScripts.length) return 774 775 var script = document.createElement('script') 776 var type = $(this).attr('type') 777 if (type) script.type = type 778 script.src = $(this).attr('src') 779 document.head.appendChild(script) 780 }) 781} 782 783// Internal: History DOM caching class. 784var cacheMapping = {} 785var cacheForwardStack = [] 786var cacheBackStack = [] 787 788// Push previous state id and container contents into the history 789// cache. Should be called in conjunction with `pushState` to save the 790// previous container contents. 791// 792// id - State ID Number 793// value - DOM Element to cache 794// 795// Returns nothing. 796function cachePush(id, value) { 797 cacheMapping[id] = value 798 cacheBackStack.push(id) 799 800 // Remove all entries in forward history stack after pushing a new page. 801 trimCacheStack(cacheForwardStack, 0) 802 803 // Trim back history stack to max cache length. 804 trimCacheStack(cacheBackStack, pjax.defaults.maxCacheLength) 805} 806 807// Shifts cache from directional history cache. Should be 808// called on `popstate` with the previous state id and container 809// contents. 810// 811// direction - "forward" or "back" String 812// id - State ID Number 813// value - DOM Element to cache 814// 815// Returns nothing. 816function cachePop(direction, id, value) { 817 var pushStack, popStack 818 cacheMapping[id] = value 819 820 if (direction === 'forward') { 821 pushStack = cacheBackStack 822 popStack = cacheForwardStack 823 } else { 824 pushStack = cacheForwardStack 825 popStack = cacheBackStack 826 } 827 828 pushStack.push(id) 829 if (id = popStack.pop()) 830 delete cacheMapping[id] 831 832 // Trim whichever stack we just pushed to to max cache length. 833 trimCacheStack(pushStack, pjax.defaults.maxCacheLength) 834} 835 836// Trim a cache stack (either cacheBackStack or cacheForwardStack) to be no 837// longer than the specified length, deleting cached DOM elements as necessary. 838// 839// stack - Array of state IDs 840// length - Maximum length to trim to 841// 842// Returns nothing. 843function trimCacheStack(stack, length) { 844 while (stack.length > length) 845 delete cacheMapping[stack.shift()] 846} 847 848// Public: Find version identifier for the initial page load. 849// 850// Returns String version or undefined. 851function findVersion() { 852 return $('meta').filter(function() { 853 var name = $(this).attr('http-equiv') 854 return name && name.toUpperCase() === 'X-PJAX-VERSION' 855 }).attr('content') 856} 857 858// Install pjax functions on $.pjax to enable pushState behavior. 859// 860// Does nothing if already enabled. 861// 862// Examples 863// 864// $.pjax.enable() 865// 866// Returns nothing. 867function enable() { 868 $.fn.pjax = fnPjax 869 $.pjax = pjax 870 $.pjax.enable = $.noop 871 $.pjax.disable = disable 872 $.pjax.click = handleClick 873 $.pjax.submit = handleSubmit 874 $.pjax.reload = pjaxReload 875 $.pjax.defaults = { 876 timeout: 650, 877 push: true, 878 replace: false, 879 type: 'GET', 880 dataType: 'html', 881 scrollTo: 0, 882 maxCacheLength: 20, 883 version: findVersion 884 } 885 $(window).on('popstate.pjax', onPjaxPopstate) 886} 887 888// Disable pushState behavior. 889// 890// This is the case when a browser doesn't support pushState. It is 891// sometimes useful to disable pushState for debugging on a modern 892// browser. 893// 894// Examples 895// 896// $.pjax.disable() 897// 898// Returns nothing. 899function disable() { 900 $.fn.pjax = function() { return this } 901 $.pjax = fallbackPjax 902 $.pjax.enable = enable 903 $.pjax.disable = $.noop 904 $.pjax.click = $.noop 905 $.pjax.submit = $.noop 906 $.pjax.reload = function() { window.location.reload() } 907 908 $(window).off('popstate.pjax', onPjaxPopstate) 909} 910 911 912// Add the state property to jQuery's event object so we can use it in 913// $(window).bind('popstate') 914if ( $.inArray('state', $.event.props) < 0 ) 915 $.event.props.push('state') 916 917// Is pjax supported by this browser?
918$.support.pjax = 919 window.history && window.history.pushState && window.history.replaceState && 920 // pushState isn't reliable on iOS until 5. 921 !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/) 922 923$.support.pjax ? enable() : disable() 924 925})(jQuery); 926 927 928 929(function(){ 930 var cururl = window.location.href; 931 var bp = document.createElement('script'); 932 bp.src = '/baidu_push_api.php?url='+encodeURI(cururl); 933 var s = document.getElementsByTagName("script")[0]; 934 s.parentNode.insertBefore(bp, s); 935})();
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.