~andreserl/maas/packaging_precise_rebase

« back to all changes in this revision

Viewing changes to debian/extras/jslibs/yui/pjax-base/pjax-base-debug.js

  • Committer: Andres Rodriguez
  • Date: 2013-03-20 18:12:30 UTC
  • mfrom: (145.2.22 precise.sru)
  • Revision ID: andreserl@ubuntu.com-20130320181230-6l5guc0nhlv2z4p7
Re-base againts latest quantal released branch towards SRU

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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-base', function(Y) {
 
8
 
 
9
/**
 
10
`Y.Router` extension that provides the core plumbing for enhanced navigation
 
11
implemented using the pjax technique (HTML5 pushState + Ajax).
 
12
 
 
13
@module pjax
 
14
@submodule pjax-base
 
15
@since 3.5.0
 
16
**/
 
17
 
 
18
var win = Y.config.win,
 
19
 
 
20
    Lang = Y.Lang,
 
21
 
 
22
    // The CSS class name used to filter link clicks from only the links which
 
23
    // the pjax enhanced navigation should be used.
 
24
    CLASS_PJAX = Y.ClassNameManager.getClassName('pjax'),
 
25
 
 
26
    /**
 
27
    Fired when navigating to a URL via Pjax.
 
28
 
 
29
    When the `navigate()` method is called or a pjax link is clicked, this event
 
30
    will be fired if the browser supports HTML5 history _and_ the router has a
 
31
    route handler for the specified URL.
 
32
 
 
33
    This is a useful event to listen to for adding a visual loading indicator
 
34
    while the route handlers are busy handling the URL change.
 
35
 
 
36
    @event navigate
 
37
    @param {String} url The URL that the router will dispatch to its route
 
38
      handlers in order to fulfill the enhanced navigation "request".
 
39
    @param {Boolean} [force=false] Whether the enhanced navigation should occur
 
40
      even in browsers without HTML5 history.
 
41
    @param {String} [hash] The hash-fragment (including "#") of the `url`. This
 
42
      will be present when the `url` differs from the current URL only by its
 
43
      hash and `navigateOnHash` has ben set to `true`.
 
44
    @param {Event} [originEvent] The event that caused the navigation. Usually
 
45
      this would be a click event from a "pjax" anchor element.
 
46
    @param {Boolean} [replace] Whether or not the current history entry will be
 
47
      replaced, or a new entry will be created. Will default to `true` if the
 
48
      specified `url` is the same as the current URL.
 
49
    @since 3.5.0
 
50
    **/
 
51
    EVT_NAVIGATE = 'navigate';
 
52
 
 
53
/**
 
54
`Y.Router` extension that provides the core plumbing for enhanced navigation
 
55
implemented using the pjax technique (HTML5 `pushState` + Ajax).
 
56
 
 
57
This makes it easy to enhance the navigation between the URLs of an application
 
58
in HTML5 history capable browsers by delegating to the router to fulfill the
 
59
"request" and seamlessly falling-back to using standard full-page reloads in
 
60
older, less-capable browsers.
 
61
 
 
62
The `PjaxBase` class isn't useful on its own, but can be mixed into a
 
63
`Router`-based class to add Pjax functionality to that Router. For a pre-made
 
64
standalone Pjax router, see the `Pjax` class.
 
65
 
 
66
    var MyRouter = Y.Base.create('myRouter', Y.Router, [Y.PjaxBase], {
 
67
        // ...
 
68
    });
 
69
 
 
70
@class PjaxBase
 
71
@extensionfor Router
 
72
@since 3.5.0
 
73
**/
 
74
function PjaxBase() {}
 
75
 
 
76
PjaxBase.prototype = {
 
77
    // -- Protected Properties -------------------------------------------------
 
78
 
 
79
    /**
 
80
    Holds the delegated pjax-link click handler.
 
81
 
 
82
    @property _pjaxEvents
 
83
    @type EventHandle
 
84
    @protected
 
85
    @since 3.5.0
 
86
    **/
 
87
 
 
88
    /**
 
89
    Regex used to break up a URL string around the URL's path.
 
90
 
 
91
    Subpattern captures:
 
92
 
 
93
      1. Origin, everything before the URL's path-part.
 
94
      2. The URL's path-part.
 
95
      3. Suffix, everything after the URL's path-part.
 
96
 
 
97
    @property _regexURL
 
98
    @type RegExp
 
99
    @protected
 
100
    @since 3.5.0
 
101
    **/
 
102
    _regexURL: /^((?:[^\/#?:]+:\/\/|\/\/)[^\/]*)?([^?#]*)(\?[^#]*)?(#.*)?$/,
 
103
 
 
104
    // -- Lifecycle Methods ----------------------------------------------------
 
105
    initializer: function () {
 
106
        this.publish(EVT_NAVIGATE, {defaultFn: this._defNavigateFn});
 
107
 
 
108
        // Pjax is all about progressively enhancing the navigation between
 
109
        // "pages", so by default we only want to handle and route link clicks
 
110
        // in HTML5 `pushState`-compatible browsers.
 
111
        if (this.get('html5')) {
 
112
            this._pjaxBindUI();
 
113
        }
 
114
    },
 
115
 
 
116
    destructor: function () {
 
117
        this._pjaxEvents && this._pjaxEvents.detach();
 
118
    },
 
119
 
 
120
    // -- Public Methods -------------------------------------------------------
 
121
 
 
122
    /**
 
123
    Navigates to the specified URL if there is a route handler that matches. In
 
124
    browsers capable of using HTML5 history, the navigation will be enhanced by
 
125
    firing the `navigate` event and having the router handle the "request".
 
126
    Non-HTML5 browsers will navigate to the new URL via manipulation of
 
127
    `window.location`.
 
128
 
 
129
    When there is a route handler for the specified URL and it is being
 
130
    navigated to, this method will return `true`, otherwise it will return
 
131
    `false`.
 
132
 
 
133
    **Note:** The specified URL _must_ be of the same origin as the current URL,
 
134
    otherwise an error will be logged and navigation will not occur. This is
 
135
    intended as both a security constraint and a purposely imposed limitation as
 
136
    it does not make sense to tell the router to navigate to a URL on a
 
137
    different scheme, host, or port.
 
138
 
 
139
    @method navigate
 
140
    @param {String} url The URL to navigate to. This must be of the same origin
 
141
      as the current URL.
 
142
    @param {Object} [options] Additional options to configure the navigation.
 
143
      These are mixed into the `navigate` event facade.
 
144
        @param {Boolean} [options.replace] Whether or not the current history
 
145
          entry will be replaced, or a new entry will be created. Will default
 
146
          to `true` if the specified `url` is the same as the current URL.
 
147
        @param {Boolean} [options.force=false] Whether the enhanced navigation
 
148
          should occur even in browsers without HTML5 history.
 
149
    @return {Boolean} `true` if the URL was navigated to, `false` otherwise.
 
150
    @since 3.5.0
 
151
    **/
 
152
    navigate: function (url, options) {
 
153
        // The `_navigate()` method expects fully-resolved URLs.
 
154
        url = this._resolveURL(url);
 
155
 
 
156
        if (this._navigate(url, options)) {
 
157
            return true;
 
158
        }
 
159
 
 
160
        if (!this._hasSameOrigin(url)) {
 
161
            Y.error('Security error: The new URL must be of the same origin as the current URL.');
 
162
        }
 
163
 
 
164
        return false;
 
165
    },
 
166
 
 
167
    // -- Protected Methods ----------------------------------------------------
 
168
 
 
169
    /**
 
170
    Returns the current path root after popping off the last path segment,
 
171
    making it useful for resolving other URL paths against.
 
172
 
 
173
    The path root will always begin and end with a '/'.
 
174
 
 
175
    @method _getRoot
 
176
    @return {String} The URL's path root.
 
177
    @protected
 
178
    @since 3.5.0
 
179
    **/
 
180
    _getRoot: function () {
 
181
        var slash = '/',
 
182
            path  = Y.getLocation().pathname,
 
183
            segments;
 
184
 
 
185
        if (path.charAt(path.length - 1) === slash) {
 
186
            return path;
 
187
        }
 
188
 
 
189
        segments = path.split(slash);
 
190
        segments.pop();
 
191
 
 
192
        return segments.join(slash) + slash;
 
193
    },
 
194
 
 
195
    /**
 
196
    Underlying implementation for `navigate()`.
 
197
 
 
198
    @method _navigate
 
199
    @param {String} url The fully-resolved URL that the router should dispatch
 
200
      to its route handlers to fulfill the enhanced navigation "request", or use
 
201
      to update `window.location` in non-HTML5 history capable browsers.
 
202
    @param {Object} [options] Additional options to configure the navigation.
 
203
      These are mixed into the `navigate` event facade.
 
204
        @param {Boolean} [options.replace] Whether or not the current history
 
205
          entry will be replaced, or a new entry will be created. Will default
 
206
          to `true` if the specified `url` is the same as the current URL.
 
207
        @param {Boolean} [options.force=false] Whether the enhanced navigation
 
208
          should occur even in browsers without HTML5 history.
 
209
    @return {Boolean} `true` if the URL was navigated to, `false` otherwise.
 
210
    @protected
 
211
    @since 3.5.0
 
212
    **/
 
213
    _navigate: function (url, options) {
 
214
        // Navigation can only be enhanced if there is a route-handler.
 
215
        if (!this.hasRoute(url)) {
 
216
            return false;
 
217
        }
 
218
 
 
219
        options || (options = {});
 
220
        options.url = url;
 
221
 
 
222
        var currentURL = this._getURL(),
 
223
            hash, hashlessURL;
 
224
 
 
225
        // Captures the `url`'s hash and returns a URL without that hash.
 
226
        hashlessURL = url.replace(/(#.*)$/, function (u, h, i) {
 
227
            hash = h;
 
228
            return u.substring(i);
 
229
        });
 
230
 
 
231
        if (hash && hashlessURL === currentURL.replace(/#.*$/, '')) {
 
232
            // When the specified `url` and current URL only differ by the hash,
 
233
            // the browser should handle this in-page navigation normally.
 
234
            if (!this.get('navigateOnHash')) {
 
235
                return false;
 
236
            }
 
237
 
 
238
            options.hash = hash;
 
239
        }
 
240
 
 
241
        // When navigating to the same URL as the current URL, behave like a
 
242
        // browser and replace the history entry instead of creating a new one.
 
243
        'replace' in options || (options.replace = url === currentURL);
 
244
 
 
245
        // The `navigate` event will only fire and therefore enhance the
 
246
        // navigation to the new URL in HTML5 history enabled browsers or when
 
247
        // forced. Otherwise it will fallback to assigning or replacing the URL
 
248
        // on `window.location`.
 
249
        if (this.get('html5') || options.force) {
 
250
            this.fire(EVT_NAVIGATE, options);
 
251
        } else {
 
252
            if (options.replace) {
 
253
                win && win.location.replace(url);
 
254
            } else {
 
255
                win && (win.location = url);
 
256
            }
 
257
        }
 
258
 
 
259
        return true;
 
260
    },
 
261
 
 
262
    /**
 
263
    Returns a normalized path, ridding it of any '..' segments and properly
 
264
    handling leading and trailing slashes.
 
265
 
 
266
    @method _normalizePath
 
267
    @param {String} path URL path to normalize.
 
268
    @return {String} Normalized path.
 
269
    @protected
 
270
    @since 3.5.0
 
271
    **/
 
272
    _normalizePath: function (path) {
 
273
        var dots  = '..',
 
274
            slash = '/',
 
275
            i, len, normalized, segments, segment, stack;
 
276
 
 
277
        if (!path || path === slash) {
 
278
            return slash;
 
279
        }
 
280
 
 
281
        segments = path.split(slash);
 
282
        stack    = [];
 
283
 
 
284
        for (i = 0, len = segments.length; i < len; ++i) {
 
285
            segment = segments[i];
 
286
 
 
287
            if (segment === dots) {
 
288
                stack.pop();
 
289
            } else if (segment) {
 
290
                stack.push(segment);
 
291
            }
 
292
        }
 
293
 
 
294
        normalized = slash + stack.join(slash);
 
295
 
 
296
        // Append trailing slash if necessary.
 
297
        if (normalized !== slash && path.charAt(path.length - 1) === slash) {
 
298
            normalized += slash;
 
299
        }
 
300
 
 
301
        return normalized;
 
302
    },
 
303
 
 
304
    /**
 
305
    Binds the delegation of link-click events that match the `linkSelector` to
 
306
    the `_onLinkClick()` handler.
 
307
 
 
308
    By default this method will only be called if the browser is capable of
 
309
    using HTML5 history.
 
310
 
 
311
    @method _pjaxBindUI
 
312
    @protected
 
313
    @since 3.5.0
 
314
    **/
 
315
    _pjaxBindUI: function () {
 
316
        // Only bind link if we haven't already.
 
317
        if (!this._pjaxEvents) {
 
318
            this._pjaxEvents = Y.one('body').delegate('click',
 
319
                this._onLinkClick, this.get('linkSelector'), this);
 
320
        }
 
321
    },
 
322
 
 
323
    /**
 
324
    Returns the normalized result of resolving the `path` against the current
 
325
    path. Falsy values for `path` will return just the current path.
 
326
 
 
327
    @method _resolvePath
 
328
    @param {String} path URL path to resolve.
 
329
    @return {String} Resolved path.
 
330
    @protected
 
331
    @since 3.5.0
 
332
    **/
 
333
    _resolvePath: function (path) {
 
334
        if (!path) {
 
335
            return this._getPath();
 
336
        }
 
337
 
 
338
        // Path is host-relative and assumed to be resolved and normalized,
 
339
        // meaning silly paths like: '/foo/../bar/' will be returned as-is.
 
340
        if (path.charAt(0) === '/') {
 
341
            return this._normalizePath(path);
 
342
        }
 
343
 
 
344
        return this._normalizePath(this._getRoot() + path);
 
345
    },
 
346
 
 
347
    /**
 
348
    Resolves the specified URL against the current URL.
 
349
 
 
350
    This method resolves URLs like a browser does and will always return an
 
351
    absolute URL. When the specified URL is already absolute, it is assumed to
 
352
    be fully resolved and is simply returned as is. Scheme-relative URLs are
 
353
    prefixed with the current protocol. Relative URLs are giving the current
 
354
    URL's origin and are resolved and normalized against the current path root.
 
355
 
 
356
    @method _resolveURL
 
357
    @param {String} url URL to resolve.
 
358
    @return {String} Resolved URL.
 
359
    @protected
 
360
    @since 3.5.0
 
361
    **/
 
362
    _resolveURL: function (url) {
 
363
        var parts    = url && url.match(this._regexURL),
 
364
            origin, path, query, hash, resolved;
 
365
 
 
366
        if (!parts) {
 
367
            return this._getURL();
 
368
        }
 
369
 
 
370
        origin = parts[1];
 
371
        path   = parts[2];
 
372
        query  = parts[3];
 
373
        hash   = parts[4];
 
374
 
 
375
        // Absolute and scheme-relative URLs are assumed to be fully-resolved.
 
376
        if (origin) {
 
377
            // Prepend the current scheme for scheme-relative URLs.
 
378
            if (origin.indexOf('//') === 0) {
 
379
                origin = Y.getLocation().protocol + origin;
 
380
            }
 
381
 
 
382
            return origin + (path || '/') + (query || '') + (hash || '');
 
383
        }
 
384
 
 
385
        // Will default to the current origin and current path.
 
386
        resolved = this._getOrigin() + this._resolvePath(path);
 
387
 
 
388
        // A path or query for the specified URL trumps the current URL's.
 
389
        if (path || query) {
 
390
            return resolved + (query || '') + (hash || '');
 
391
        }
 
392
 
 
393
        query = this._getQuery();
 
394
 
 
395
        return resolved + (query ? ('?' + query) : '') + (hash || '');
 
396
    },
 
397
 
 
398
    // -- Protected Event Handlers ---------------------------------------------
 
399
 
 
400
    /**
 
401
    Default handler for the `navigate` event.
 
402
 
 
403
    Adds a new history entry or replaces the current entry for the specified URL
 
404
    and will scroll the page to the top if configured to do so.
 
405
 
 
406
    @method _defNavigateFn
 
407
    @param {EventFacade} e
 
408
    @protected
 
409
    @since 3.5.0
 
410
    **/
 
411
    _defNavigateFn: function (e) {
 
412
        this[e.replace ? 'replace' : 'save'](e.url);
 
413
 
 
414
        if (win && this.get('scrollToTop')) {
 
415
            // Scroll to the top of the page. The timeout ensures that the
 
416
            // scroll happens after navigation begins, so that the current
 
417
            // scroll position will be restored if the user clicks the back
 
418
            // button.
 
419
            setTimeout(function () {
 
420
                win.scroll(0, 0);
 
421
            }, 1);
 
422
        }
 
423
    },
 
424
 
 
425
    /**
 
426
    Handler for delegated link-click events which match the `linkSelector`.
 
427
 
 
428
    This will attempt to enhance the navigation to the link element's `href` by
 
429
    passing the URL to the `_navigate()` method. When the navigation is being
 
430
    enhanced, the default action is prevented.
 
431
 
 
432
    If the user clicks a link with the middle/right mouse buttons, or is holding
 
433
    down the Ctrl or Command keys, this method's behavior is not applied and
 
434
    allows the native behavior to occur. Similarly, if the router is not capable
 
435
    or handling the URL because no route-handlers match, the link click will
 
436
    behave natively.
 
437
 
 
438
    @method _onLinkClick
 
439
    @param {EventFacade} e
 
440
    @protected
 
441
    @since 3.5.0
 
442
    **/
 
443
    _onLinkClick: function (e) {
 
444
        var url;
 
445
 
 
446
        // Allow the native behavior on middle/right-click, or when Ctrl or
 
447
        // Command are pressed.
 
448
        if (e.button !== 1 || e.ctrlKey || e.metaKey) { return; }
 
449
 
 
450
        // All browsers fully resolve an anchor's `href` property.
 
451
        url = e.currentTarget.get('href');
 
452
 
 
453
        // Try and navigate to the URL via the router, and prevent the default
 
454
        // link-click action if we do.
 
455
        url && this._navigate(url, {originEvent: e}) && e.preventDefault();
 
456
    }
 
457
};
 
458
 
 
459
PjaxBase.ATTRS = {
 
460
    /**
 
461
    CSS selector string used to filter link click events so that only the links
 
462
    which match it will have the enhanced navigation behavior of Pjax applied.
 
463
 
 
464
    When a link is clicked and that link matches this selector, Pjax will
 
465
    attempt to dispatch to any route handlers matching the link's `href` URL. If
 
466
    HTML5 history is not supported or if no route handlers match, the link click
 
467
    will be handled by the browser just like any old link.
 
468
 
 
469
    @attribute linkSelector
 
470
    @type String|Function
 
471
    @default "a.pjax"
 
472
    @initOnly
 
473
    @since 3.5.0
 
474
    **/
 
475
    linkSelector: {
 
476
        value    : 'a.' + CLASS_PJAX,
 
477
        writeOnce: 'initOnly'
 
478
    },
 
479
 
 
480
    /**
 
481
    Whether navigating to a hash-fragment identifier on the current page should
 
482
    be enhanced and cause the `navigate` event to fire.
 
483
 
 
484
    By default Pjax allows the browser to perform its default action when a user
 
485
    is navigating within a page by clicking in-page links
 
486
    (e.g. `<a href="#top">Top of page</a>`) and does not attempt to interfere or
 
487
    enhance in-page navigation.
 
488
 
 
489
    @attribute navigateOnHash
 
490
    @type Boolean
 
491
    @default false
 
492
    @since 3.5.0
 
493
    **/
 
494
    navigateOnHash: {
 
495
        value: false
 
496
    },
 
497
 
 
498
    /**
 
499
    Whether the page should be scrolled to the top after navigating to a URL.
 
500
 
 
501
    When the user clicks the browser's back button, the previous scroll position
 
502
    will be maintained.
 
503
 
 
504
    @attribute scrollToTop
 
505
    @type Boolean
 
506
    @default true
 
507
    @since 3.5.0
 
508
    **/
 
509
    scrollToTop: {
 
510
        value: true
 
511
    }
 
512
};
 
513
 
 
514
Y.PjaxBase = PjaxBase;
 
515
 
 
516
 
 
517
}, '3.5.1' ,{requires:['classnamemanager', 'node-event-delegate', 'router']});