[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /* 2 YUI 3.17.2 (build 9c3c78e) 3 Copyright 2014 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 // -- Lifecycle Methods ---------------------------------------------------- 88 initializer: function () { 89 this.publish(EVT_NAVIGATE, {defaultFn: this._defNavigateFn}); 90 91 // Pjax is all about progressively enhancing the navigation between 92 // "pages", so by default we only want to handle and route link clicks 93 // in HTML5 `pushState`-compatible browsers. 94 if (this.get('html5')) { 95 this._pjaxBindUI(); 96 } 97 }, 98 99 destructor: function () { 100 if (this._pjaxEvents) { 101 this._pjaxEvents.detach(); 102 } 103 }, 104 105 // -- Public Methods ------------------------------------------------------- 106 107 /** 108 Navigates to the specified URL if there is a route handler that matches. In 109 browsers capable of using HTML5 history, the navigation will be enhanced by 110 firing the `navigate` event and having the router handle the "request". 111 Non-HTML5 browsers will navigate to the new URL via manipulation of 112 `window.location`. 113 114 When there is a route handler for the specified URL and it is being 115 navigated to, this method will return `true`, otherwise it will return 116 `false`. 117 118 **Note:** The specified URL _must_ be of the same origin as the current URL, 119 otherwise an error will be logged and navigation will not occur. This is 120 intended as both a security constraint and a purposely imposed limitation as 121 it does not make sense to tell the router to navigate to a URL on a 122 different scheme, host, or port. 123 124 @method navigate 125 @param {String} url The URL to navigate to. This must be of the same origin 126 as the current URL. 127 @param {Object} [options] Additional options to configure the navigation. 128 These are mixed into the `navigate` event facade. 129 @param {Boolean} [options.replace] Whether or not the current history 130 entry will be replaced, or a new entry will be created. Will default 131 to `true` if the specified `url` is the same as the current URL. 132 @param {Boolean} [options.force=false] Whether the enhanced navigation 133 should occur even in browsers without HTML5 history. 134 @return {Boolean} `true` if the URL was navigated to, `false` otherwise. 135 @since 3.5.0 136 **/ 137 navigate: function (url, options) { 138 // The `_navigate()` method expects fully-resolved URLs. 139 url = this._resolveURL(url); 140 141 if (this._navigate(url, options)) { 142 return true; 143 } 144 145 if (!this._hasSameOrigin(url)) { 146 Y.error('Security error: The new URL must be of the same origin as the current URL.'); 147 } 148 149 return false; 150 }, 151 152 // -- Protected Methods ---------------------------------------------------- 153 154 /** 155 Utility method to test whether a specified link/anchor node's `href` is of 156 the same origin as the page's current location. 157 158 This normalize browser inconsistencies with how the `port` is reported for 159 anchor elements (IE reports a value for the default port, e.g. "80"). 160 161 @method _isLinkSameOrigin 162 @param {Node} link The anchor element to test whether its `href` is of the 163 same origin as the page's current location. 164 @return {Boolean} Whether or not the link's `href` is of the same origin as 165 the page's current location. 166 @protected 167 @since 3.6.0 168 **/ 169 _isLinkSameOrigin: function (link) { 170 var location = Y.getLocation(), 171 protocol = location.protocol, 172 hostname = location.hostname, 173 port = parseInt(location.port, 10) || null, 174 linkPort; 175 176 // Link must have the same `protocol` and `hostname` as the page's 177 // currrent location. 178 if (link.get('protocol') !== protocol || 179 link.get('hostname') !== hostname) { 180 181 return false; 182 } 183 184 linkPort = parseInt(link.get('port'), 10) || null; 185 186 // Normalize ports. In most cases browsers use an empty string when the 187 // port is the default port, but IE does weird things with anchor 188 // elements, so to be sure, this will re-assign the default ports before 189 // they are compared. 190 if (protocol === 'http:') { 191 port || (port = 80); 192 linkPort || (linkPort = 80); 193 } else if (protocol === 'https:') { 194 port || (port = 443); 195 linkPort || (linkPort = 443); 196 } 197 198 // Finally, to be from the same origin, the link's `port` must match the 199 // page's current `port`. 200 return linkPort === port; 201 }, 202 203 /** 204 Underlying implementation for `navigate()`. 205 206 @method _navigate 207 @param {String} url The fully-resolved URL that the router should dispatch 208 to its route handlers to fulfill the enhanced navigation "request", or use 209 to update `window.location` in non-HTML5 history capable browsers. 210 @param {Object} [options] Additional options to configure the navigation. 211 These are mixed into the `navigate` event facade. 212 @param {Boolean} [options.replace] Whether or not the current history 213 entry will be replaced, or a new entry will be created. Will default 214 to `true` if the specified `url` is the same as the current URL. 215 @param {Boolean} [options.force=false] Whether the enhanced navigation 216 should occur even in browsers without HTML5 history. 217 @return {Boolean} `true` if the URL was navigated to, `false` otherwise. 218 @protected 219 @since 3.5.0 220 **/ 221 _navigate: function (url, options) { 222 url = this._upgradeURL(url); 223 224 // Navigation can only be enhanced if there is a route-handler. 225 if (!this.hasRoute(url)) { 226 return false; 227 } 228 229 // Make a copy of `options` before modifying it. 230 options = Y.merge(options, {url: url}); 231 232 var currentURL = this._getURL(), 233 hash, hashlessURL; 234 235 // Captures the `url`'s hash and returns a URL without that hash. 236 hashlessURL = url.replace(/(#.*)$/, function (u, h, i) { 237 hash = h; 238 return u.substring(i); 239 }); 240 241 if (hash && hashlessURL === currentURL.replace(/#.*$/, '')) { 242 // When the specified `url` and current URL only differ by the hash, 243 // the browser should handle this in-page navigation normally. 244 if (!this.get('navigateOnHash')) { 245 return false; 246 } 247 248 options.hash = hash; 249 } 250 251 // When navigating to the same URL as the current URL, behave like a 252 // browser and replace the history entry instead of creating a new one. 253 'replace' in options || (options.replace = url === currentURL); 254 255 // The `navigate` event will only fire and therefore enhance the 256 // navigation to the new URL in HTML5 history enabled browsers or when 257 // forced. Otherwise it will fallback to assigning or replacing the URL 258 // on `window.location`. 259 if (this.get('html5') || options.force) { 260 this.fire(EVT_NAVIGATE, options); 261 } else if (win) { 262 if (options.replace) { 263 win.location.replace(url); 264 } else { 265 win.location = url; 266 } 267 } 268 269 return true; 270 }, 271 272 /** 273 Binds the delegation of link-click events that match the `linkSelector` to 274 the `_onLinkClick()` handler. 275 276 By default this method will only be called if the browser is capable of 277 using HTML5 history. 278 279 @method _pjaxBindUI 280 @protected 281 @since 3.5.0 282 **/ 283 _pjaxBindUI: function () { 284 // Only bind link if we haven't already. 285 if (!this._pjaxEvents) { 286 this._pjaxEvents = Y.one('body').delegate('click', 287 this._onLinkClick, this.get('linkSelector'), this); 288 } 289 }, 290 291 // -- Protected Event Handlers --------------------------------------------- 292 293 /** 294 Default handler for the `navigate` event. 295 296 Adds a new history entry or replaces the current entry for the specified URL 297 and will scroll the page to the top if configured to do so. 298 299 @method _defNavigateFn 300 @param {EventFacade} e 301 @protected 302 @since 3.5.0 303 **/ 304 _defNavigateFn: function (e) { 305 this[e.replace ? 'replace' : 'save'](e.url); 306 307 if (win && this.get('scrollToTop')) { 308 // Scroll to the top of the page. The timeout ensures that the 309 // scroll happens after navigation begins, so that the current 310 // scroll position will be restored if the user clicks the back 311 // button. 312 setTimeout(function () { 313 win.scroll(0, 0); 314 }, 1); 315 } 316 }, 317 318 /** 319 Handler for delegated link-click events which match the `linkSelector`. 320 321 This will attempt to enhance the navigation to the link element's `href` by 322 passing the URL to the `_navigate()` method. When the navigation is being 323 enhanced, the default action is prevented. 324 325 If the user clicks a link with the middle/right mouse buttons, or is holding 326 down the Ctrl or Command keys, this method's behavior is not applied and 327 allows the native behavior to occur. Similarly, if the router is not capable 328 or handling the URL because no route-handlers match, the link click will 329 behave natively. 330 331 @method _onLinkClick 332 @param {EventFacade} e 333 @protected 334 @since 3.5.0 335 **/ 336 _onLinkClick: function (e) { 337 var link, url, navigated; 338 339 // Allow the native behavior on middle/right-click, or when Ctrl or 340 // Command are pressed. 341 if (e.button !== 1 || e.ctrlKey || e.metaKey) { return; } 342 343 link = e.currentTarget; 344 345 // Only allow anchor elements because we need access to its `protocol`, 346 // `host`, and `href` attributes. 347 if (link.get('tagName').toUpperCase() !== 'A') { 348 Y.log('pjax link-click navigation requires an anchor element.', 'warn', 'PjaxBase'); 349 return; 350 } 351 352 // Same origin check to prevent trying to navigate to URLs from other 353 // sites or things like mailto links. 354 if (!this._isLinkSameOrigin(link)) { 355 return; 356 } 357 358 // All browsers fully resolve an anchor's `href` property. 359 url = link.get('href'); 360 361 // Try and navigate to the URL via the router, and prevent the default 362 // link-click action if we do. 363 if (url) { 364 navigated = this._navigate(url, {originEvent: e}); 365 366 if (navigated) { 367 e.preventDefault(); 368 } 369 } 370 } 371 }; 372 373 PjaxBase.ATTRS = { 374 /** 375 CSS selector string used to filter link click events so that only the links 376 which match it will have the enhanced navigation behavior of Pjax applied. 377 378 When a link is clicked and that link matches this selector, Pjax will 379 attempt to dispatch to any route handlers matching the link's `href` URL. If 380 HTML5 history is not supported or if no route handlers match, the link click 381 will be handled by the browser just like any old link. 382 383 @attribute linkSelector 384 @type String|Function 385 @default "a.yui3-pjax" 386 @initOnly 387 @since 3.5.0 388 **/ 389 linkSelector: { 390 value : 'a.' + CLASS_PJAX, 391 writeOnce: 'initOnly' 392 }, 393 394 /** 395 Whether navigating to a hash-fragment identifier on the current page should 396 be enhanced and cause the `navigate` event to fire. 397 398 By default Pjax allows the browser to perform its default action when a user 399 is navigating within a page by clicking in-page links 400 (e.g. `<a href="#top">Top of page</a>`) and does not attempt to interfere or 401 enhance in-page navigation. 402 403 @attribute navigateOnHash 404 @type Boolean 405 @default false 406 @since 3.5.0 407 **/ 408 navigateOnHash: { 409 value: false 410 }, 411 412 /** 413 Whether the page should be scrolled to the top after navigating to a URL. 414 415 When the user clicks the browser's back button, the previous scroll position 416 will be maintained. 417 418 @attribute scrollToTop 419 @type Boolean 420 @default true 421 @since 3.5.0 422 **/ 423 scrollToTop: { 424 value: true 425 } 426 }; 427 428 Y.PjaxBase = PjaxBase; 429 430 431 }, '3.17.2', {"requires": ["classnamemanager", "node-event-delegate", "router"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |