src/cm/media/js/lib/yui/yui_3.10.3/build/pjax-base/pjax-base-debug.js
changeset 525 89ef5ed3c48b
equal deleted inserted replaced
524:322d0feea350 525:89ef5ed3c48b
       
     1 /*
       
     2 YUI 3.10.3 (build 2fb5187)
       
     3 Copyright 2013 Yahoo! Inc. All rights reserved.
       
     4 Licensed under the BSD License.
       
     5 http://yuilibrary.com/license/
       
     6 */
       
     7 
       
     8 YUI.add('pjax-base', function (Y, NAME) {
       
     9 
       
    10 /**
       
    11 `Y.Router` extension that provides the core plumbing for enhanced navigation
       
    12 implemented using the pjax technique (HTML5 pushState + Ajax).
       
    13 
       
    14 @module pjax
       
    15 @submodule pjax-base
       
    16 @since 3.5.0
       
    17 **/
       
    18 
       
    19 var win = Y.config.win,
       
    20 
       
    21     // The CSS class name used to filter link clicks from only the links which
       
    22     // the pjax enhanced navigation should be used.
       
    23     CLASS_PJAX = Y.ClassNameManager.getClassName('pjax'),
       
    24 
       
    25     /**
       
    26     Fired when navigating to a URL via Pjax.
       
    27 
       
    28     When the `navigate()` method is called or a pjax link is clicked, this event
       
    29     will be fired if the browser supports HTML5 history _and_ the router has a
       
    30     route handler for the specified URL.
       
    31 
       
    32     This is a useful event to listen to for adding a visual loading indicator
       
    33     while the route handlers are busy handling the URL change.
       
    34 
       
    35     @event navigate
       
    36     @param {String} url The URL that the router will dispatch to its route
       
    37       handlers in order to fulfill the enhanced navigation "request".
       
    38     @param {Boolean} [force=false] Whether the enhanced navigation should occur
       
    39       even in browsers without HTML5 history.
       
    40     @param {String} [hash] The hash-fragment (including "#") of the `url`. This
       
    41       will be present when the `url` differs from the current URL only by its
       
    42       hash and `navigateOnHash` has been set to `true`.
       
    43     @param {Event} [originEvent] The event that caused the navigation. Usually
       
    44       this would be a click event from a "pjax" anchor element.
       
    45     @param {Boolean} [replace] Whether or not the current history entry will be
       
    46       replaced, or a new entry will be created. Will default to `true` if the
       
    47       specified `url` is the same as the current URL.
       
    48     @since 3.5.0
       
    49     **/
       
    50     EVT_NAVIGATE = 'navigate';
       
    51 
       
    52 /**
       
    53 `Y.Router` extension that provides the core plumbing for enhanced navigation
       
    54 implemented using the pjax technique (HTML5 `pushState` + Ajax).
       
    55 
       
    56 This makes it easy to enhance the navigation between the URLs of an application
       
    57 in HTML5 history capable browsers by delegating to the router to fulfill the
       
    58 "request" and seamlessly falling-back to using standard full-page reloads in
       
    59 older, less-capable browsers.
       
    60 
       
    61 The `PjaxBase` class isn't useful on its own, but can be mixed into a
       
    62 `Router`-based class to add Pjax functionality to that Router. For a pre-made
       
    63 standalone Pjax router, see the `Pjax` class.
       
    64 
       
    65     var MyRouter = Y.Base.create('myRouter', Y.Router, [Y.PjaxBase], {
       
    66         // ...
       
    67     });
       
    68 
       
    69 @class PjaxBase
       
    70 @extensionfor Router
       
    71 @since 3.5.0
       
    72 **/
       
    73 function PjaxBase() {}
       
    74 
       
    75 PjaxBase.prototype = {
       
    76     // -- Protected Properties -------------------------------------------------
       
    77 
       
    78     /**
       
    79     Holds the delegated pjax-link click handler.
       
    80 
       
    81     @property _pjaxEvents
       
    82     @type EventHandle
       
    83     @protected
       
    84     @since 3.5.0
       
    85     **/
       
    86 
       
    87     /**
       
    88     Regex used to break up a URL string around the URL's path.
       
    89 
       
    90     Subpattern captures:
       
    91 
       
    92       1. Origin, everything before the URL's path-part.
       
    93       2. The URL's path-part.
       
    94       3. Suffix, everything after the URL's path-part.
       
    95 
       
    96     @property _regexURL
       
    97     @type RegExp
       
    98     @protected
       
    99     @since 3.5.0
       
   100     **/
       
   101     _regexURL: /^((?:[^\/#?:]+:\/\/|\/\/)[^\/]*)?([^?#]*)(\?[^#]*)?(#.*)?$/,
       
   102 
       
   103     // -- Lifecycle Methods ----------------------------------------------------
       
   104     initializer: function () {
       
   105         this.publish(EVT_NAVIGATE, {defaultFn: this._defNavigateFn});
       
   106 
       
   107         // Pjax is all about progressively enhancing the navigation between
       
   108         // "pages", so by default we only want to handle and route link clicks
       
   109         // in HTML5 `pushState`-compatible browsers.
       
   110         if (this.get('html5')) {
       
   111             this._pjaxBindUI();
       
   112         }
       
   113     },
       
   114 
       
   115     destructor: function () {
       
   116         if (this._pjaxEvents) {
       
   117             this._pjaxEvents.detach();
       
   118         }
       
   119     },
       
   120 
       
   121     // -- Public Methods -------------------------------------------------------
       
   122 
       
   123     /**
       
   124     Navigates to the specified URL if there is a route handler that matches. In
       
   125     browsers capable of using HTML5 history, the navigation will be enhanced by
       
   126     firing the `navigate` event and having the router handle the "request".
       
   127     Non-HTML5 browsers will navigate to the new URL via manipulation of
       
   128     `window.location`.
       
   129 
       
   130     When there is a route handler for the specified URL and it is being
       
   131     navigated to, this method will return `true`, otherwise it will return
       
   132     `false`.
       
   133 
       
   134     **Note:** The specified URL _must_ be of the same origin as the current URL,
       
   135     otherwise an error will be logged and navigation will not occur. This is
       
   136     intended as both a security constraint and a purposely imposed limitation as
       
   137     it does not make sense to tell the router to navigate to a URL on a
       
   138     different scheme, host, or port.
       
   139 
       
   140     @method navigate
       
   141     @param {String} url The URL to navigate to. This must be of the same origin
       
   142       as the current URL.
       
   143     @param {Object} [options] Additional options to configure the navigation.
       
   144       These are mixed into the `navigate` event facade.
       
   145         @param {Boolean} [options.replace] Whether or not the current history
       
   146           entry will be replaced, or a new entry will be created. Will default
       
   147           to `true` if the specified `url` is the same as the current URL.
       
   148         @param {Boolean} [options.force=false] Whether the enhanced navigation
       
   149           should occur even in browsers without HTML5 history.
       
   150     @return {Boolean} `true` if the URL was navigated to, `false` otherwise.
       
   151     @since 3.5.0
       
   152     **/
       
   153     navigate: function (url, options) {
       
   154         // The `_navigate()` method expects fully-resolved URLs.
       
   155         url = this._resolveURL(url);
       
   156 
       
   157         if (this._navigate(url, options)) {
       
   158             return true;
       
   159         }
       
   160 
       
   161         if (!this._hasSameOrigin(url)) {
       
   162             Y.error('Security error: The new URL must be of the same origin as the current URL.');
       
   163         }
       
   164 
       
   165         return false;
       
   166     },
       
   167 
       
   168     // -- Protected Methods ----------------------------------------------------
       
   169 
       
   170     /**
       
   171     Utility method to test whether a specified link/anchor node's `href` is of
       
   172     the same origin as the page's current location.
       
   173 
       
   174     This normalize browser inconsistencies with how the `port` is reported for
       
   175     anchor elements (IE reports a value for the default port, e.g. "80").
       
   176 
       
   177     @method _isLinkSameOrigin
       
   178     @param {Node} link The anchor element to test whether its `href` is of the
       
   179         same origin as the page's current location.
       
   180     @return {Boolean} Whether or not the link's `href` is of the same origin as
       
   181         the page's current location.
       
   182     @protected
       
   183     @since 3.6.0
       
   184     **/
       
   185     _isLinkSameOrigin: function (link) {
       
   186         var location = Y.getLocation(),
       
   187             protocol = location.protocol,
       
   188             hostname = location.hostname,
       
   189             port     = parseInt(location.port, 10) || null,
       
   190             linkPort;
       
   191 
       
   192         // Link must have the same `protocol` and `hostname` as the page's
       
   193         // currrent location.
       
   194         if (link.get('protocol') !== protocol ||
       
   195                 link.get('hostname') !== hostname) {
       
   196 
       
   197             return false;
       
   198         }
       
   199 
       
   200         linkPort = parseInt(link.get('port'), 10) || null;
       
   201 
       
   202         // Normalize ports. In most cases browsers use an empty string when the
       
   203         // port is the default port, but IE does weird things with anchor
       
   204         // elements, so to be sure, this will re-assign the default ports before
       
   205         // they are compared.
       
   206         if (protocol === 'http:') {
       
   207             port     || (port     = 80);
       
   208             linkPort || (linkPort = 80);
       
   209         } else if (protocol === 'https:') {
       
   210             port     || (port     = 443);
       
   211             linkPort || (linkPort = 443);
       
   212         }
       
   213 
       
   214         // Finally, to be from the same origin, the link's `port` must match the
       
   215         // page's current `port`.
       
   216         return linkPort === port;
       
   217     },
       
   218 
       
   219     /**
       
   220     Underlying implementation for `navigate()`.
       
   221 
       
   222     @method _navigate
       
   223     @param {String} url The fully-resolved URL that the router should dispatch
       
   224       to its route handlers to fulfill the enhanced navigation "request", or use
       
   225       to update `window.location` in non-HTML5 history capable browsers.
       
   226     @param {Object} [options] Additional options to configure the navigation.
       
   227       These are mixed into the `navigate` event facade.
       
   228         @param {Boolean} [options.replace] Whether or not the current history
       
   229           entry will be replaced, or a new entry will be created. Will default
       
   230           to `true` if the specified `url` is the same as the current URL.
       
   231         @param {Boolean} [options.force=false] Whether the enhanced navigation
       
   232           should occur even in browsers without HTML5 history.
       
   233     @return {Boolean} `true` if the URL was navigated to, `false` otherwise.
       
   234     @protected
       
   235     @since 3.5.0
       
   236     **/
       
   237     _navigate: function (url, options) {
       
   238         url = this._upgradeURL(url);
       
   239 
       
   240         // Navigation can only be enhanced if there is a route-handler.
       
   241         if (!this.hasRoute(url)) {
       
   242             return false;
       
   243         }
       
   244 
       
   245         // Make a copy of `options` before modifying it.
       
   246         options = Y.merge(options, {url: url});
       
   247 
       
   248         var currentURL = this._getURL(),
       
   249             hash, hashlessURL;
       
   250 
       
   251         // Captures the `url`'s hash and returns a URL without that hash.
       
   252         hashlessURL = url.replace(/(#.*)$/, function (u, h, i) {
       
   253             hash = h;
       
   254             return u.substring(i);
       
   255         });
       
   256 
       
   257         if (hash && hashlessURL === currentURL.replace(/#.*$/, '')) {
       
   258             // When the specified `url` and current URL only differ by the hash,
       
   259             // the browser should handle this in-page navigation normally.
       
   260             if (!this.get('navigateOnHash')) {
       
   261                 return false;
       
   262             }
       
   263 
       
   264             options.hash = hash;
       
   265         }
       
   266 
       
   267         // When navigating to the same URL as the current URL, behave like a
       
   268         // browser and replace the history entry instead of creating a new one.
       
   269         'replace' in options || (options.replace = url === currentURL);
       
   270 
       
   271         // The `navigate` event will only fire and therefore enhance the
       
   272         // navigation to the new URL in HTML5 history enabled browsers or when
       
   273         // forced. Otherwise it will fallback to assigning or replacing the URL
       
   274         // on `window.location`.
       
   275         if (this.get('html5') || options.force) {
       
   276             this.fire(EVT_NAVIGATE, options);
       
   277         } else if (win) {
       
   278             if (options.replace) {
       
   279                 win.location.replace(url);
       
   280             } else {
       
   281                 win.location = url;
       
   282             }
       
   283         }
       
   284 
       
   285         return true;
       
   286     },
       
   287 
       
   288     /**
       
   289     Binds the delegation of link-click events that match the `linkSelector` to
       
   290     the `_onLinkClick()` handler.
       
   291 
       
   292     By default this method will only be called if the browser is capable of
       
   293     using HTML5 history.
       
   294 
       
   295     @method _pjaxBindUI
       
   296     @protected
       
   297     @since 3.5.0
       
   298     **/
       
   299     _pjaxBindUI: function () {
       
   300         // Only bind link if we haven't already.
       
   301         if (!this._pjaxEvents) {
       
   302             this._pjaxEvents = Y.one('body').delegate('click',
       
   303                 this._onLinkClick, this.get('linkSelector'), this);
       
   304         }
       
   305     },
       
   306 
       
   307     // -- Protected Event Handlers ---------------------------------------------
       
   308 
       
   309     /**
       
   310     Default handler for the `navigate` event.
       
   311 
       
   312     Adds a new history entry or replaces the current entry for the specified URL
       
   313     and will scroll the page to the top if configured to do so.
       
   314 
       
   315     @method _defNavigateFn
       
   316     @param {EventFacade} e
       
   317     @protected
       
   318     @since 3.5.0
       
   319     **/
       
   320     _defNavigateFn: function (e) {
       
   321         this[e.replace ? 'replace' : 'save'](e.url);
       
   322 
       
   323         if (win && this.get('scrollToTop')) {
       
   324             // Scroll to the top of the page. The timeout ensures that the
       
   325             // scroll happens after navigation begins, so that the current
       
   326             // scroll position will be restored if the user clicks the back
       
   327             // button.
       
   328             setTimeout(function () {
       
   329                 win.scroll(0, 0);
       
   330             }, 1);
       
   331         }
       
   332     },
       
   333 
       
   334     /**
       
   335     Handler for delegated link-click events which match the `linkSelector`.
       
   336 
       
   337     This will attempt to enhance the navigation to the link element's `href` by
       
   338     passing the URL to the `_navigate()` method. When the navigation is being
       
   339     enhanced, the default action is prevented.
       
   340 
       
   341     If the user clicks a link with the middle/right mouse buttons, or is holding
       
   342     down the Ctrl or Command keys, this method's behavior is not applied and
       
   343     allows the native behavior to occur. Similarly, if the router is not capable
       
   344     or handling the URL because no route-handlers match, the link click will
       
   345     behave natively.
       
   346 
       
   347     @method _onLinkClick
       
   348     @param {EventFacade} e
       
   349     @protected
       
   350     @since 3.5.0
       
   351     **/
       
   352     _onLinkClick: function (e) {
       
   353         var link, url, navigated;
       
   354 
       
   355         // Allow the native behavior on middle/right-click, or when Ctrl or
       
   356         // Command are pressed.
       
   357         if (e.button !== 1 || e.ctrlKey || e.metaKey) { return; }
       
   358 
       
   359         link = e.currentTarget;
       
   360 
       
   361         // Only allow anchor elements because we need access to its `protocol`,
       
   362         // `host`, and `href` attributes.
       
   363         if (link.get('tagName').toUpperCase() !== 'A') {
       
   364             Y.log('pjax link-click navigation requires an anchor element.', 'warn', 'PjaxBase');
       
   365             return;
       
   366         }
       
   367 
       
   368         // Same origin check to prevent trying to navigate to URLs from other
       
   369         // sites or things like mailto links.
       
   370         if (!this._isLinkSameOrigin(link)) {
       
   371             return;
       
   372         }
       
   373 
       
   374         // All browsers fully resolve an anchor's `href` property.
       
   375         url = link.get('href');
       
   376 
       
   377         // Try and navigate to the URL via the router, and prevent the default
       
   378         // link-click action if we do.
       
   379         if (url) {
       
   380             navigated = this._navigate(url, {originEvent: e});
       
   381 
       
   382             if (navigated) {
       
   383                 e.preventDefault();
       
   384             }
       
   385         }
       
   386     }
       
   387 };
       
   388 
       
   389 PjaxBase.ATTRS = {
       
   390     /**
       
   391     CSS selector string used to filter link click events so that only the links
       
   392     which match it will have the enhanced navigation behavior of Pjax applied.
       
   393 
       
   394     When a link is clicked and that link matches this selector, Pjax will
       
   395     attempt to dispatch to any route handlers matching the link's `href` URL. If
       
   396     HTML5 history is not supported or if no route handlers match, the link click
       
   397     will be handled by the browser just like any old link.
       
   398 
       
   399     @attribute linkSelector
       
   400     @type String|Function
       
   401     @default "a.yui3-pjax"
       
   402     @initOnly
       
   403     @since 3.5.0
       
   404     **/
       
   405     linkSelector: {
       
   406         value    : 'a.' + CLASS_PJAX,
       
   407         writeOnce: 'initOnly'
       
   408     },
       
   409 
       
   410     /**
       
   411     Whether navigating to a hash-fragment identifier on the current page should
       
   412     be enhanced and cause the `navigate` event to fire.
       
   413 
       
   414     By default Pjax allows the browser to perform its default action when a user
       
   415     is navigating within a page by clicking in-page links
       
   416     (e.g. `<a href="#top">Top of page</a>`) and does not attempt to interfere or
       
   417     enhance in-page navigation.
       
   418 
       
   419     @attribute navigateOnHash
       
   420     @type Boolean
       
   421     @default false
       
   422     @since 3.5.0
       
   423     **/
       
   424     navigateOnHash: {
       
   425         value: false
       
   426     },
       
   427 
       
   428     /**
       
   429     Whether the page should be scrolled to the top after navigating to a URL.
       
   430 
       
   431     When the user clicks the browser's back button, the previous scroll position
       
   432     will be maintained.
       
   433 
       
   434     @attribute scrollToTop
       
   435     @type Boolean
       
   436     @default true
       
   437     @since 3.5.0
       
   438     **/
       
   439     scrollToTop: {
       
   440         value: true
       
   441     }
       
   442 };
       
   443 
       
   444 Y.PjaxBase = PjaxBase;
       
   445 
       
   446 
       
   447 }, '3.10.3', {"requires": ["classnamemanager", "node-event-delegate", "router"]});