MDL-32843 import YUI 3.5.1
[moodle.git] / lib / yui / 3.5.1 / build / pjax / pjax.js
blob69b8c4e8de42ef690009e99233cd3eae86c655f0
1 /*
2 YUI 3.5.1 (build 22)
3 Copyright 2012 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
6 */
7 YUI.add('pjax', function(Y) {
9 /**
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.
15 @module pjax
16 @main
17 @since 3.5.0
18 **/
20 /**
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.
26 @class Pjax
27 @extends Router
28 @uses PjaxBase
29 @constructor
30 @param {Object} [config] Config attributes.
31 @since 3.5.0
32 **/
34 /**
35 Fired when an error occurs while attempting to load a URL via Ajax.
37 @event error
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.
47 @since 3.5.0
48 **/
49 var EVT_ERROR = 'error',
51 /**
52 Fired when a URL is successfully loaded via Ajax.
54 @event load
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.
64 @since 3.5.0
65 **/
66 EVT_LOAD = 'load';
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});
73     },
75     // -- Public Methods -------------------------------------------------------
77     /**
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
81     returned.
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`.
93     @method getContent
94     @param {String} responseText Raw Ajax response text.
95     @return {Object} Content object with the properties described above.
96     @since 3.5.0
97     **/
98     getContent: function (responseText) {
99         var content         = {},
100             contentSelector = this.get('contentSelector'),
101             frag            = Y.Node.create(responseText || ''),
102             titleSelector   = this.get('titleSelector'),
103             titleNode;
105         if (contentSelector) {
106             content.node = Y.one(frag.all(contentSelector).toFrag());
107         } else {
108             content.node = frag;
109         }
111         if (titleSelector) {
112             titleNode = frag.one(titleSelector);
114             if (titleNode) {
115                 content.title = titleNode.get('text');
116             }
117         }
119         return content;
120     },
122     // -- Protected Methods ----------------------------------------------------
124     /**
125     Default Pjax route handler. Makes an Ajax request for the requested URL.
127     @method _defaultRoute
128     @param {Object} req Request object.
129     @protected
130     @since 3.5.0
131     **/
132     _defaultRoute: function (req) {
133         var url = req.url;
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 || '');
146             });
147         }
149         // Send a request.
150         this._request = Y.io(url, {
151             arguments: {url: url},
152             context  : this,
153             headers  : {'X-PJAX': 'true'},
154             timeout  : this.get('timeout'),
156             on: {
157                 end    : this._onPjaxIOEnd,
158                 failure: this._onPjaxIOFailure,
159                 success: this._onPjaxIOSuccess
160             }
161         });
162     },
164     // -- Event Handlers -------------------------------------------------------
166     /**
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
169     title.
171     @method _defCompleteFn
172     @param {EventFacade} e
173     @protected
174     @since 3.5.0
175     **/
176     _defCompleteFn: function (e) {
177         var container = this.get('container'),
178             content   = e.content;
180         if (container && content.node) {
181             container.setContent(content.node);
182         }
184         if (content.title && Y.config.doc) {
185             Y.config.doc.title = content.title;
186         }
187     },
189     /**
190     Handles IO end events.
192     @method _onPjaxIOEnd
193     @protected
194     @since 3.5.0
195     **/
196     _onPjaxIOEnd: function () {
197         this._request = null;
198     },
200     /**
201     Handles IO failure events and fires our own `error` event.
203     @method _onPjaxIOFailure
204     @protected
205     @since 3.5.0
206     **/
207     _onPjaxIOFailure: function (id, res, details) {
208         var content = this.getContent(res.responseText);
210         this.fire(EVT_ERROR, {
211             content     : content,
212             responseText: res.responseText,
213             status      : res.status,
214             url         : details.url
215         });
216     },
218     /**
219     Handles IO success events and fires our own 'load' event.
221     @method _onPjaxIOSuccess
222     @protected
223     @since 3.5.0
224     **/
225     _onPjaxIOSuccess: function (id, res, details) {
226         var content = this.getContent(res.responseText);
228         this.fire(EVT_LOAD, {
229             content     : content,
230             responseText: res.responseText,
231             status      : res.status,
232             url         : details.url
233         });
234     }
235 }, {
236     ATTRS: {
237         /**
238         If `true`, a "pjax=1" query parameter will be appended to all URLs
239         requested via Pjax.
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
245         versa).
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
251         @type Boolean
252         @default true
253         @since 3.5.0
254         **/
255         addPjaxParam: {
256             value: true
257         },
259         /**
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
262         new content.
264         If not set, loaded content will not be automatically inserted into the
265         page.
267         @attribute container
268         @type Node
269         @default null
270         @since 3.5.0
271         **/
272         container: {
273             value: null,
275             setter: function (node) {
276                 return node ? Y.one(node) : null;
277             }
278         },
280         /**
281         CSS selector used to extract a specific portion of the content of a page
282         loaded via Pjax.
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
291         @type String
292         @default null
293         @since 3.5.0
294         **/
295         contentSelector: {
296             value: null
297         },
299         // Inherited from Router and already documented there.
300         routes: {
301             value: [
302                 {path: '*', callback: '_defaultRoute'}
303             ]
304         },
306         /**
307         CSS selector used to extract a page title from the content of a page
308         loaded via Pjax.
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
313         loading.
315         @attribute titleSelector
316         @type String
317         @default "title"
318         @since 3.5.0
319         **/
320         titleSelector: {
321             value: 'title'
322         },
324         /**
325         Time in milliseconds after which an Ajax request should time out. When a
326         timeout occurs, the `error` event will be fired.
328         @attribute timeout
329         @type Number
330         @default 30000
331         @since 3.5.0
332         **/
333         timeout: {
334             value: 30000
335         }
336     }
340 }, '3.5.1' ,{requires:['pjax-base', 'io-base']});