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