1
+ // When called on a link, fetches the href with ajax into the
2
+ // container specified as the first parameter or with the data-pjax
3
+ // attribute on the link itself.
4
+ //
5
+ // Tries to make sure the back button and ctrl+click work the way
6
+ // you'd expect.
7
+ //
8
+ // Accepts a jQuery ajax options object that may include these
9
+ // pjax specific options:
10
+ //
11
+ // container - Where to stick the response body. Usually a String selector.
12
+ // $(container).html(xhr.responseBody)
13
+ // loading - A callback to fire after it's been too many ms and
14
+ // you want to ease the user's pain with a loading indicator.
15
+ // You can also bind to the 'loading.pjax' event on container.
16
+ // push - Whether to pushState the URL. Defaults to true (of course).
17
+ //
18
+ // For convenience the first parameter can be either the container or
19
+ // the options object.
20
+ //
21
+ // Returns the jQuery object
22
+ jQuery . fn . pjax = function ( container , options ) {
23
+ var $ = jQuery
24
+
25
+ if ( options )
26
+ options . container = container
27
+ else
28
+ options = container
29
+
30
+ $ ( this ) . live ( 'click' , function ( ) {
31
+ // Middle click, cmd click, and ctrl click should open
32
+ // links in a new tab as normal.
33
+ if ( event . which == 2 || event . metaKey )
34
+ return true
35
+
36
+ var defaults = {
37
+ url : this . href ,
38
+ container : $ ( this ) . attr ( 'data-pjax' )
39
+ }
40
+
41
+ $ . pjax ( $ . extend ( { } , defaults , options ) )
42
+
43
+ return false
44
+ } )
45
+ }
46
+
47
+
48
+ // Loads a URL with ajax, puts the response body inside a container,
49
+ // then pushState()'s the loaded URL. Also ensures the back button
50
+ // works the way you'd expect.
51
+ //
52
+ // Works just like $.ajax in that it accepts a jQuery ajax
53
+ // settings object (with keys like url, type, data, etc).
54
+ //
55
+ // Accepts these extra keys:
56
+ //
57
+ // container - Where to stick the response body.
58
+ // $(container).html(xhr.responseBody)
59
+ // loading - A callback to fire after it's been too many ms and
60
+ // you want to ease the user's pain with a loading indicator.
61
+ // You can also bind to the 'loading.pjax' event on container.
62
+ // push - Whether to pushState the URL. Defaults to true (of course).
63
+ //
64
+ // Use it just like $.ajax:
65
+ //
66
+ // var xhr = $.pjax({ url: this.href, container: '#main' })
67
+ // console.log( xhr.readyState )
68
+ //
69
+ // Returns whatever $.ajax returns.
70
+ jQuery . pjax = function ( options ) {
71
+ // Helper
72
+ var $ = jQuery
73
+
74
+ var defaults = {
75
+ data : { pjax : true } ,
76
+ type : 'GET' ,
77
+ dataType : 'html' ,
78
+ error : function ( ) { window . location = options . url } ,
79
+ success : function ( data ) {
80
+ // If we got no data or an entire web page, go directly
81
+ // to the page and let normal error handling happen.
82
+ if ( ! $ . trim ( data ) || / < h t m l / i. test ( data ) )
83
+ return window . location = options . url
84
+
85
+ // If there's a <title> tag in the response, use it as
86
+ // the page's title.
87
+ var title = $ . trim ( $ ( data ) . filter ( 'title' ) . remove ( ) . text ( ) )
88
+ if ( title ) document . title = title
89
+
90
+ // Make it happen.
91
+ $ ( options . container ) . html ( data )
92
+
93
+ // If they didn't explicitly disable `push`, call pushState()
94
+ if ( options . push !== false ) {
95
+ window . history . pushState ( { pjax : options . container } ,
96
+ document . title , options . url )
97
+ }
98
+
99
+ // Invoke their success handler if they gave us one.
100
+ success . apply ( this , arguments )
101
+ }
102
+ }
103
+
104
+ // We don't want to let anyone override our success handler.
105
+ var success = options . success || $ . noop
106
+ delete options . success
107
+
108
+ options = $ . extend ( true , { } , defaults , options )
109
+ var xhr = $ . ajax ( options )
110
+
111
+ // If we haven't found what we're looking for after a buncha ms
112
+ // you might want to show a 'Loading...' indicator.
113
+ setTimeout ( function ( ) {
114
+ if ( xhr . readyState == 4 ) return
115
+ $ ( options . container ) . trigger ( 'loading.pjax' )
116
+ if ( options . loading ) options . loading . call ( options . container )
117
+ } , 350 )
118
+
119
+ $ ( document ) . trigger ( 'pjax' , xhr , options )
120
+ return xhr
121
+ }
122
+
123
+ // Bind our popstate handler which takes care of the back and
124
+ // forward buttons, but only once we've called pjax()
125
+ jQuery ( document ) . one ( 'pjax' , function ( ) {
126
+ jQuery ( window ) . bind ( 'popstate' , function ( event ) {
127
+ var state = event . state
128
+ if ( state && state . pjax )
129
+ jQuery . pjax ( { url : location . href , container : state . pjax , push : false } )
130
+ else
131
+ window . location = location . href
132
+ } )
133
+ } )
134
+
135
+ // Add the state property to jQuery's event object so we can use it in
136
+ // $(window).bind('popstate')
137
+ jQuery . event . props . push ( 'state' )
138
+
139
+ // Fall back to normalcy for older browsers.
140
+ if ( ! window . history || ! window . history . pushState ) {
141
+ jQuery . pjax = jQuery . fn . pjax = $ . noop
142
+ }
0 commit comments