lib/angular/js/ng/location.js
function $LocationProvider(){
  var hashPrefix = '',
      html5Mode = false;

  /**
   * @ngdoc method
   * @name $locationProvider#hashPrefix
   * @description
   * @param {string=} prefix Prefix for hash part (containing path and search)
   * @returns {*} current value if used as getter or itself (chaining) if used as setter
   */
  this.hashPrefix = function(prefix) {
    if (isDefined(prefix)) {
      hashPrefix = prefix;
      return this;
    } else {
      return hashPrefix;
    }
  };

  /**
   * @ngdoc method
   * @name $locationProvider#html5Mode
   * @description
   * @param {boolean=} mode Use HTML5 strategy if available.
   * @returns {*} current value if used as getter or itself (chaining) if used as setter
   */
  this.html5Mode = function(mode) {
    if (isDefined(mode)) {
      html5Mode = mode;
      return this;
    } else {
      return html5Mode;
    }
  };

  /**
   * @ngdoc event
   * @name $location#$locationChangeStart
   * @eventType broadcast on root scope
   * @description
   * Broadcasted before a URL will change. This change can be prevented by calling
   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
   * details about event object. Upon successful change
   * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
   *
   * @param {Object} angularEvent Synthetic event object.
   * @param {string} newUrl New URL
   * @param {string=} oldUrl URL that was before it was changed.
   */

  /**
   * @ngdoc event
   * @name $location#$locationChangeSuccess
   * @eventType broadcast on root scope
   * @description
   * Broadcasted after a URL was changed.
   *
   * @param {Object} angularEvent Synthetic event object.
   * @param {string} newUrl New URL
   * @param {string=} oldUrl URL that was before it was changed.
   */

  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
      function( $rootScope,   $browser,   $sniffer,   $rootElement) {
    var $location,
        LocationMode,
        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
        initialUrl = $browser.url(),
        appBase;

    if (html5Mode) {
      appBase = serverBase(initialUrl) + (baseHref || '/');
      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
    } else {
      appBase = stripHash(initialUrl);
      LocationMode = LocationHashbangUrl;
    }
    $location = new LocationMode(appBase, '#' + hashPrefix);
    $location.$$parse($location.$$rewrite(initialUrl));

    $rootElement.on('click', function(event) {
      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
      // currently we open nice url link and redirect then

      if (event.ctrlKey || event.metaKey || event.which == 2) return;

      var elm = jqLite(event.target);

      // traverse the DOM up to find first A tag
      while (nodeName_(elm[0]) !== 'a') {
        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
      }

      var absHref = elm.prop('href');

      if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
        // an animation.
        absHref = urlResolve(absHref.animVal).href;
      }

      // Make relative links work in HTML5 mode for legacy browsers (or at least IE8 & 9)
      // The href should be a regular url e.g. /link/somewhere or link/somewhere or ../somewhere or
      // somewhere#anchor or http://example.com/somewhere
      if (LocationMode === LocationHashbangInHtml5Url) {
        // get the actual href attribute - see
        // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
        var href = elm.attr('href') || elm.attr('xlink:href');

        if (href.indexOf('://') < 0) {         // Ignore absolute URLs
          var prefix = '#' + hashPrefix;
          if (href[0] == '/') {
            // absolute path - replace old path
            absHref = appBase + prefix + href;
          } else if (href[0] == '#') {
            // local anchor
            absHref = appBase + prefix + ($location.path() || '/') + href;
          } else {
            // relative path - join with current path
            var stack = $location.path().split("/"),
              parts = href.split("/");
            for (var i=0; i<parts.length; i++) {
              if (parts[i] == ".")
                continue;
              else if (parts[i] == "..")
                stack.pop();
              else if (parts[i].length)
                stack.push(parts[i]);
            }
            absHref = appBase + prefix + stack.join('/');
          }
        }
      }

      var rewrittenUrl = $location.$$rewrite(absHref);

      if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
        event.preventDefault();
        if (rewrittenUrl != $browser.url()) {
          // update location manually
          $location.$$parse(rewrittenUrl);
          $rootScope.$apply();
          // hack to work around FF6 bug 684208 when scenario runner clicks on links
          window.angular['ff-684208-preventDefault'] = true;
        }
      }
    });


    // rewrite hashbang url <> html5 url
    if ($location.absUrl() != initialUrl) {
      $browser.url($location.absUrl(), true);
    }

    // update $location when $browser url changes
    $browser.onUrlChange(function(newUrl) {
      if ($location.absUrl() != newUrl) {
        $rootScope.$evalAsync(function() {
          var oldUrl = $location.absUrl();

          $location.$$parse(newUrl);
          if ($rootScope.$broadcast('$locationChangeStart', newUrl,
                                    oldUrl).defaultPrevented) {
            $location.$$parse(oldUrl);
            $browser.url(oldUrl);
          } else {
            afterLocationChange(oldUrl);
          }
        });
        if (!$rootScope.$$phase) $rootScope.$digest();
      }
    });

    // update browser
    var changeCounter = 0;
    $rootScope.$watch(function $locationWatch() {
      var oldUrl = $browser.url();
      var currentReplace = $location.$$replace;

      if (!changeCounter || oldUrl != $location.absUrl()) {
        changeCounter++;
        $rootScope.$evalAsync(function() {
          if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
              defaultPrevented) {
            $location.$$parse(oldUrl);
          } else {
            $browser.url($location.absUrl(), currentReplace);
            afterLocationChange(oldUrl);
          }
        });
      }
      $location.$$replace = false;

      return changeCounter;
    });

    return $location;

    function afterLocationChange(oldUrl) {
      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
    }
}];
}
function $LocationProvider(){
  var hashPrefix = '',
      html5Mode = false;

  /**
   * @ngdoc method
   * @name $locationProvider#hashPrefix
   * @description
   * @param {string=} prefix Prefix for hash part (containing path and search)
   * @returns {*} current value if used as getter or itself (chaining) if used as setter
   */
  this.hashPrefix = function(prefix) {
    if (isDefined(prefix)) {
      hashPrefix = prefix;
      return this;
    } else {
      return hashPrefix;
    }
  };

  /**
   * @ngdoc method
   * @name $locationProvider#html5Mode
   * @description
   * @param {boolean=} mode Use HTML5 strategy if available.
   * @returns {*} current value if used as getter or itself (chaining) if used as setter
   */
  this.html5Mode = function(mode) {
    if (isDefined(mode)) {
      html5Mode = mode;
      return this;
    } else {
      return html5Mode;
    }
  };

  /**
   * @ngdoc event
   * @name $location#$locationChangeStart
   * @eventType broadcast on root scope
   * @description
   * Broadcasted before a URL will change. This change can be prevented by calling
   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
   * details about event object. Upon successful change
   * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
   *
   * @param {Object} angularEvent Synthetic event object.
   * @param {string} newUrl New URL
   * @param {string=} oldUrl URL that was before it was changed.
   */

  /**
   * @ngdoc event
   * @name $location#$locationChangeSuccess
   * @eventType broadcast on root scope
   * @description
   * Broadcasted after a URL was changed.
   *
   * @param {Object} angularEvent Synthetic event object.
   * @param {string} newUrl New URL
   * @param {string=} oldUrl URL that was before it was changed.
   */

  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
      function( $rootScope,   $browser,   $sniffer,   $rootElement) {
    var $location,
        LocationMode,
        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
        initialUrl = $browser.url(),
        appBase;

    if (html5Mode) {
      appBase = serverBase(initialUrl) + (baseHref || '/');
      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
    } else {
      appBase = stripHash(initialUrl);
      LocationMode = LocationHashbangUrl;
    }
    $location = new LocationMode(appBase, '#' + hashPrefix);
    $location.$$parse($location.$$rewrite(initialUrl));

    $rootElement.on('click', function(event) {
      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
      // currently we open nice url link and redirect then

      if (event.ctrlKey || event.metaKey || event.which == 2) return;

      var elm = jqLite(event.target);

      // traverse the DOM up to find first A tag
      while (nodeName_(elm[0]) !== 'a') {
        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
      }

      var absHref = elm.prop('href');

      if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
        // an animation.
        absHref = urlResolve(absHref.animVal).href;
      }

      // Make relative links work in HTML5 mode for legacy browsers (or at least IE8 & 9)
      // The href should be a regular url e.g. /link/somewhere or link/somewhere or ../somewhere or
      // somewhere#anchor or http://example.com/somewhere
      if (LocationMode === LocationHashbangInHtml5Url) {
        // get the actual href attribute - see
        // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
        var href = elm.attr('href') || elm.attr('xlink:href');

        if (href.indexOf('://') < 0) {         // Ignore absolute URLs
          var prefix = '#' + hashPrefix;
          if (href[0] == '/') {
            // absolute path - replace old path
            absHref = appBase + prefix + href;
          } else if (href[0] == '#') {
            // local anchor
            absHref = appBase + prefix + ($location.path() || '/') + href;
          } else {
            // relative path - join with current path
            var stack = $location.path().split("/"),
              parts = href.split("/");
            for (var i=0; i<parts.length; i++) {
              if (parts[i] == ".")
                continue;
              else if (parts[i] == "..")
                stack.pop();
              else if (parts[i].length)
                stack.push(parts[i]);
            }
            absHref = appBase + prefix + stack.join('/');
          }
        }
      }

      var rewrittenUrl = $location.$$rewrite(absHref);

      if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
        event.preventDefault();
        if (rewrittenUrl != $browser.url()) {
          // update location manually
          $location.$$parse(rewrittenUrl);
          $rootScope.$apply();
          // hack to work around FF6 bug 684208 when scenario runner clicks on links
          window.angular['ff-684208-preventDefault'] = true;
        }
      }
    });


    // rewrite hashbang url <> html5 url
    if ($location.absUrl() != initialUrl) {
      $browser.url($location.absUrl(), true);
    }

    // update $location when $browser url changes
    $browser.onUrlChange(function(newUrl) {
      if ($location.absUrl() != newUrl) {
        $rootScope.$evalAsync(function() {
          var oldUrl = $location.absUrl();

          $location.$$parse(newUrl);
          if ($rootScope.$broadcast('$locationChangeStart', newUrl,
                                    oldUrl).defaultPrevented) {
            $location.$$parse(oldUrl);
            $browser.url(oldUrl);
          } else {
            afterLocationChange(oldUrl);
          }
        });
        if (!$rootScope.$$phase) $rootScope.$digest();
      }
    });

    // update browser
    var changeCounter = 0;
    $rootScope.$watch(function $locationWatch() {
      var oldUrl = $browser.url();
      var currentReplace = $location.$$replace;

      if (!changeCounter || oldUrl != $location.absUrl()) {
        changeCounter++;
        $rootScope.$evalAsync(function() {
          if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
              defaultPrevented) {
            $location.$$parse(oldUrl);
          } else {
            $browser.url($location.absUrl(), currentReplace);
            afterLocationChange(oldUrl);
          }
        });
      }
      $location.$$replace = false;

      return changeCounter;
    });

    return $location;

    function afterLocationChange(oldUrl) {
      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
    }
}];
}
function $LocationProvider ( ) { var hashPrefix = '' , html5Mode = false ; /**
   * @ngdoc method
   * @name $locationProvider#hashPrefix
   * @description
   * @param {string=} prefix Prefix for hash part (containing path and search)
   * @returns {*} current value if used as getter or itself (chaining) if used as setter
   */ this . hashPrefix = function ( prefix ) { if ( isDefined ( prefix ) ) { hashPrefix = prefix ; return this ; } else { return hashPrefix ; } } ; /**
   * @ngdoc method
   * @name $locationProvider#html5Mode
   * @description
   * @param {boolean=} mode Use HTML5 strategy if available.
   * @returns {*} current value if used as getter or itself (chaining) if used as setter
   */ this . html5Mode = function ( mode ) { if ( isDefined ( mode ) ) { html5Mode = mode ; return this ; } else { return html5Mode ; } } ; /**
   * @ngdoc event
   * @name $location#$locationChangeStart
   * @eventType broadcast on root scope
   * @description
   * Broadcasted before a URL will change. This change can be prevented by calling
   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
   * details about event object. Upon successful change
   * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
   *
   * @param {Object} angularEvent Synthetic event object.
   * @param {string} newUrl New URL
   * @param {string=} oldUrl URL that was before it was changed.
   */ /**
   * @ngdoc event
   * @name $location#$locationChangeSuccess
   * @eventType broadcast on root scope
   * @description
   * Broadcasted after a URL was changed.
   *
   * @param {Object} angularEvent Synthetic event object.
   * @param {string} newUrl New URL
   * @param {string=} oldUrl URL that was before it was changed.
   */ this . $get = [ '$rootScope' , '$browser' , '$sniffer' , '$rootElement' , function ( $rootScope , $browser , $sniffer , $rootElement ) { var $location , LocationMode , baseHref = $browser . baseHref ( ) , // if base[href] is undefined, it defaults to '' initialUrl = $browser . url ( ) , appBase ; if ( html5Mode ) { appBase = serverBase ( initialUrl ) + ( baseHref || '/' ) ; LocationMode = $sniffer . history ? LocationHtml5Url : LocationHashbangInHtml5Url ; } else { appBase = stripHash ( initialUrl ) ; LocationMode = LocationHashbangUrl ; } $location = new LocationMode ( appBase , '#' + hashPrefix ) ; $location . $$parse ( $location . $$rewrite ( initialUrl ) ) ; $rootElement . on ( 'click' , function ( event ) { // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser) // currently we open nice url link and redirect then if ( event . ctrlKey || event . metaKey || event . which == 2 ) return ; var elm = jqLite ( event . target ) ; // traverse the DOM up to find first A tag while ( nodeName_ ( elm [ 0 ] ) !== 'a' ) { // ignore rewriting if no A tag (reached root element, or no parent - removed from document) if ( elm [ 0 ] === $rootElement [ 0 ] || ! ( elm = elm . parent ( ) ) [ 0 ] ) return ; } var absHref = elm . prop ( 'href' ) ; if ( isObject ( absHref ) && absHref . toString ( ) === '[object SVGAnimatedString]' ) { // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during // an animation. absHref = urlResolve ( absHref . animVal ) . href ; } // Make relative links work in HTML5 mode for legacy browsers (or at least IE8 & 9) // The href should be a regular url e.g. /link/somewhere or link/somewhere or ../somewhere or // somewhere#anchor or http://example.com/somewhere if ( LocationMode === LocationHashbangInHtml5Url ) { // get the actual href attribute - see // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx var href = elm . attr ( 'href' ) || elm . attr ( 'xlink:href' ) ; if ( href . indexOf ( '://' ) < 0 ) { // Ignore absolute URLs var prefix = '#' + hashPrefix ; if ( href [ 0 ] == '/' ) { // absolute path - replace old path absHref = appBase + prefix + href ; } else if ( href [ 0 ] == '#' ) { // local anchor absHref = appBase + prefix + ( $location . path ( ) || '/' ) + href ; } else { // relative path - join with current path var stack = $location . path ( ) . split ( "/" ) , parts = href . split ( "/" ) ; for ( var i = 0 ; i < parts . length ; i ++ ) { if ( parts [ i ] == "." ) continue ; else if ( parts [ i ] == ".." ) stack . pop ( ) ; else if ( parts [ i ] . length ) stack . push ( parts [ i ] ) ; } absHref = appBase + prefix + stack . join ( '/' ) ; } } } var rewrittenUrl = $location . $$rewrite ( absHref ) ; if ( absHref && ! elm . attr ( 'target' ) && rewrittenUrl && ! event . isDefaultPrevented ( ) ) { event . preventDefault ( ) ; if ( rewrittenUrl != $browser . url ( ) ) { // update location manually $location . $$parse ( rewrittenUrl ) ; $rootScope . $apply ( ) ; // hack to work around FF6 bug 684208 when scenario runner clicks on links window . angular [ 'ff-684208-preventDefault' ] = true ; } } } ) ; // rewrite hashbang url <> html5 url if ( $location . absUrl ( ) != initialUrl ) { $browser . url ( $location . absUrl ( ) , true ) ; } // update $location when $browser url changes $browser . onUrlChange ( function ( newUrl ) { if ( $location . absUrl ( ) != newUrl ) { $rootScope . $evalAsync ( function ( ) { var oldUrl = $location . absUrl ( ) ; $location . $$parse ( newUrl ) ; if ( $rootScope . $broadcast ( '$locationChangeStart' , newUrl , oldUrl ) . defaultPrevented ) { $location . $$parse ( oldUrl ) ; $browser . url ( oldUrl ) ; } else { afterLocationChange ( oldUrl ) ; } } ) ; if ( ! $rootScope . $$phase ) $rootScope . $digest ( ) ; } } ) ; // update browser var changeCounter = 0 ; $rootScope . $watch ( function $locationWatch ( ) { var oldUrl = $browser . url ( ) ; var currentReplace = $location . $$replace ; if ( ! changeCounter || oldUrl != $location . absUrl ( ) ) { changeCounter ++ ; $rootScope . $evalAsync ( function ( ) { if ( $rootScope . $broadcast ( '$locationChangeStart' , $location . absUrl ( ) , oldUrl ) . defaultPrevented ) { $location . $$parse ( oldUrl ) ; } else { $browser . url ( $location . absUrl ( ) , currentReplace ) ; afterLocationChange ( oldUrl ) ; } } ) ; } $location . $$replace = false ; return changeCounter ; } ) ; return $location ; function afterLocationChange ( oldUrl ) { $rootScope . $broadcast ( '$locationChangeSuccess' , $location . absUrl ( ) , oldUrl ) ; } } ] ; }
@ngdoc service
@name $location

@requires $rootElement

@description
The $location service parses the URL in the browser address bar (based on the
[window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
available to your application. Changes to the URL in the address bar are reflected into
$location service and changes to $location are reflected into the browser address bar.

**The $location service:**

- Exposes the current URL in the browser address bar, so you can
- Watch and observe the URL.
- Change the URL.
- Synchronizes the URL with the browser when the user
- Changes the address bar.
- Clicks the back or forward button (or clicks a History link).
- Clicks on a link.
- Represents the URL object as a set of methods (protocol, host, port, path, search, hash).

For more information see {@link guide/$location Developer Guide: Using $location}
 
@ngdoc provider
@name $locationProvider
@description
Use the `$locationProvider` to configure how the application deep linking paths are stored.
@ngdoc service @name $location