3 Copyright 2012 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
7 YUI.add('pjax', function(Y) {
10 Provides seamless, gracefully degrading Pjax (pushState + Ajax) functionality,
11 which makes it easy to progressively enhance standard links on the page so that
12 they can be loaded normally in old browsers, or via Ajax (with HTML5 history
13 support) in newer browsers.
21 Provides seamless, gracefully degrading Pjax (pushState + Ajax) functionality,
22 which makes it easy to progressively enhance standard links on the page so that
23 they can be loaded normally in old browsers, or via Ajax (with HTML5 history
24 support) in newer browsers.
30 @param {Object} [config] Config attributes.
35 Fired when an error occurs while attempting to load a URL via Ajax.
38 @param {Object} content Content extracted from the response, if any.
39 @param {Node} content.node A `Y.Node` instance for a document fragment
40 containing the extracted HTML content.
41 @param {String} [content.title] The title of the HTML page, if any,
42 extracted using the `titleSelector` attribute. If `titleSelector` is not
43 set or if a title could not be found, this property will be `undefined`.
44 @param {String} responseText Raw Ajax response text.
45 @param {Number} status HTTP status code for the Ajax response.
46 @param {String} url The absolute URL that failed to load.
49 var EVT_ERROR = 'error',
52 Fired when a URL is successfully loaded via Ajax.
55 @param {Object} content Content extracted from the response, if any.
56 @param {Node} content.node A `Y.Node` instance for a document fragment
57 containing the extracted HTML content.
58 @param {String} [content.title] The title of the HTML page, if any,
59 extracted using the `titleSelector` attribute. If `titleSelector` is not
60 set or if a title could not be found, this property will be `undefined`.
61 @param {String} responseText Raw Ajax response text.
62 @param {Number} status HTTP status code for the Ajax response.
63 @param {String} url The absolute URL that was loaded.
68 Y.Pjax = Y.Base.create('pjax', Y.Router, [Y.PjaxBase], {
69 // -- Lifecycle Methods ----------------------------------------------------
70 initializer: function () {
71 this.publish(EVT_ERROR, {defaultFn: this._defCompleteFn});
72 this.publish(EVT_LOAD, {defaultFn: this._defCompleteFn});
75 // -- Public Methods -------------------------------------------------------
78 Extracts and returns the relevant HTML content from an Ajax response. The
79 content is extracted using the `contentSelector` attribute as a CSS
80 selector. If `contentSelector` is `null`, the entire response will be
83 The return value is an object containing two properties:
85 - **node**: A `Y.Node` instance for a document fragment containing the
86 extracted HTML content.
88 - **title**: The title of the HTML page, if any, extracted using the
89 `titleSelector` attribute (which defaults to looking for a `<title>`
90 element). If `titleSelector` is not set or if a title could not be
91 found, this property will be `undefined`.
94 @param {String} responseText Raw Ajax response text.
95 @return {Object} Content object with the properties described above.
98 getContent: function (responseText) {
100 contentSelector = this.get('contentSelector'),
101 frag = Y.Node.create(responseText || ''),
102 titleSelector = this.get('titleSelector'),
105 if (contentSelector) {
106 content.node = Y.one(frag.all(contentSelector).toFrag());
112 titleNode = frag.one(titleSelector);
115 content.title = titleNode.get('text');
122 // -- Protected Methods ----------------------------------------------------
125 Default Pjax route handler. Makes an Ajax request for the requested URL.
127 @method _defaultRoute
128 @param {Object} req Request object.
132 _defaultRoute: function (req) {
135 // If there's an outstanding request, abort it.
136 this._request && this._request.abort();
138 // Add a 'pjax=1' query parameter if enabled.
139 if (this.get('addPjaxParam')) {
140 // Captures the path with query, and hash parts of the URL. Then
141 // properly injects the "pjax=1" query param in the right place,
142 // before any hash fragment, and returns the updated URL.
143 url = url.replace(/([^#]*)(#.*)?$/, function (match, path, hash) {
144 path += (path.indexOf('?') > -1 ? '&' : '?') + 'pjax=1';
145 return path + (hash || '');
150 this._request = Y.io(url, {
151 arguments: {url: url},
153 headers : {'X-PJAX': 'true'},
154 timeout : this.get('timeout'),
157 end : this._onPjaxIOEnd,
158 failure: this._onPjaxIOFailure,
159 success: this._onPjaxIOSuccess
164 // -- Event Handlers -------------------------------------------------------
167 Default event handler for both the `error` and `load` events. Attempts to
168 insert the loaded content into the `container` node and update the page's
171 @method _defCompleteFn
172 @param {EventFacade} e
176 _defCompleteFn: function (e) {
177 var container = this.get('container'),
180 if (container && content.node) {
181 container.setContent(content.node);
184 if (content.title && Y.config.doc) {
185 Y.config.doc.title = content.title;
190 Handles IO end events.
196 _onPjaxIOEnd: function () {
197 this._request = null;
201 Handles IO failure events and fires our own `error` event.
203 @method _onPjaxIOFailure
207 _onPjaxIOFailure: function (id, res, details) {
208 var content = this.getContent(res.responseText);
210 this.fire(EVT_ERROR, {
212 responseText: res.responseText,
219 Handles IO success events and fires our own 'load' event.
221 @method _onPjaxIOSuccess
225 _onPjaxIOSuccess: function (id, res, details) {
226 var content = this.getContent(res.responseText);
228 this.fire(EVT_LOAD, {
230 responseText: res.responseText,
238 If `true`, a "pjax=1" query parameter will be appended to all URLs
241 Browsers ignore HTTP request headers when caching content, so if the
242 same URL is used to request a partial Pjax page and a full page, the
243 browser will cache them under the same key and may later load the
244 cached partial page when the user actually requests a full page (or vice
247 To prevent this, we can add a bogus query parameter to the URL so that
248 Pjax URLs will always be cached separately from non-Pjax URLs.
250 @attribute addPjaxParam
260 Node into which content should be inserted when a page is loaded via
261 Pjax. This node's existing contents will be removed to make way for the
264 If not set, loaded content will not be automatically inserted into the
275 setter: function (node) {
276 return node ? Y.one(node) : null;
281 CSS selector used to extract a specific portion of the content of a page
284 For example, if you wanted to load the page `example.html` but only use
285 the content within an element with the id "pjax-content", you'd set
286 `contentSelector` to "#pjax-content".
288 If not set, the entire page will be used.
290 @attribute contentSelector
299 // Inherited from Router and already documented there.
302 {path: '*', callback: '_defaultRoute'}
307 CSS selector used to extract a page title from the content of a page
310 By default this is set to extract the title from the `<title>` element,
311 but you could customize it to extract the title from an `<h1>`, or from
312 any other element, if that's more appropriate for the content you're
315 @attribute titleSelector
325 Time in milliseconds after which an Ajax request should time out. When a
326 timeout occurs, the `error` event will be fired.
340 }, '3.5.1' ,{requires:['pjax-base', 'io-base']});