<!DOCTYPE html>
<html ng-app="optional">

  <head>
    <script data-require="angular.js@1.3.1" data-semver="1.3.1" src="//code.angularjs.org/1.3.1/angular.js"></script>
    <script src="//unpkg.com/angular-ui-router/release/angular-ui-router.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="angular-ui-router.js"></script>
    <script src="script.js"></script>
  </head>

  <body>
    <h5>Squash settings:</h5>
    <pre>{{ href  | json }}</pre>
    <h5>Current state / params:</h5>
    <pre>{{ $state.current.name }} - 
{{$state.params | json }}</pre>
<!--     <h5>Current url:</h5>
<pre>{{ $location.url() }}</pre>
 -->    
    <ul>
      <li ui-sref-active="active" ui-sref="user({username: 'christopherthielen'})">user({username: 'christopherthielen'})</li>
      <li ui-sref-active="active" ui-sref="user({username: 'johndoe'})">user({username: 'johndoe'})</li>
      <li ui-sref="user({username: ''})">user({username: ''})</li>
      <li ui-sref="user({username: null})">user({username: null})</li>
      <li ui-sref="user" ui-sref-opts="{ inherit: false }">user(), { inherit: false}</li>
      <li ui-sref="user" ui-sref-opts="{ inherit: true }">user(), { inherit: true}</li>
    </ul>
    
    <div>
      <button type="button" ng-click="reload()">$state.reload()</button>
      <button type="button" ng-click="go()">$state.go('user')</button>
    </div>

    <div ui-view></div>

  </body>

</html>
// Code goes here

var app = angular.module("optional", ['ui.router']);

app.service("Session", function() { 
  return { username: 'christopherthielen' };
});

app.config(function($stateProvider, $urlRouterProvider, $urlMatcherFactoryProvider) {
  $urlRouterProvider.otherwise("/user/christopherthielen/gallery/favorites/photo/CN0ZRJw");
  $urlMatcherFactoryProvider.defaultSquashPolicy(false);
  // $urlMatcherFactoryProvider.defaultSquashPolicy("");
  // $urlMatcherFactoryProvider.defaultSquashPolicy(true);
  
  $stateProvider.decorator("url", function(state, urlFn) {
    var url = urlFn(state);
    url.$$format = function(squash, params) {
      var keys = url.params.$$keys();
      var original = keys.map(function(key) { return url.params[key].squash; });
      keys.forEach(function(key) { url.params[key].squash = squash; });
      var formatted = url.format(params);
      for (var i = 0; i < keys.length; i++) { url.params[keys[i]].squash = original[i]; }
      return formatted;
    }
    return url;
  });
  
  
  $stateProvider.state({ 
    name: 'top', url: "/", template: '<div ui-view/>',
    resolve: { 
      users: function($http) { 
        return $http.get("users.json").then(function(r) { return r.data; });
      },
      photos: function($http) { 
        return $http.get("photos.json").then(function(r) { return r.data; });
      }
    }
  });
  
  $stateProvider.state({
    name: "user",
    url: "user/:username",
    parent: 'top',
    params: { 
      username: { 
        value: function(Session) { return Session.username; }
      } 
    }, 
    resolve: { 
      user: function($stateParams, users) { return users[$stateParams.username]; }, 
      galleries: function($stateParams, photos) { return photos[$stateParams.username] }
    },
    templateUrl: 'user.html',
    controller: function($scope, $state, user, galleries) { $scope.user = user; $scope.galleries = galleries; }
  });
  
  $stateProvider.state({
    name: "user.gallery",
    url: "/gallery/:galleryid",
    resolve: { 
      photos: function($stateParams, galleries) { return galleries[$stateParams.galleryid]; } 
    },
    params: { galleryid: { value: "favorites" } }, 
    templateUrl: 'gallery.html',
    controller: function($scope, $state, $stateParams, photos) { 
      $scope.gallery = $stateParams.galleryid; 
      $scope.photos = photos; 
    }
  });
  
  $stateProvider.state({
    name: "user.gallery.photo",
    url: "/photo/:photoid",
    resolve: { 
      photo: function($stateParams, photos) { 
        return photos.filter(function(photo) { return photo.id === $stateParams.photoid; })[0];
      } 
    },
    templateUrl: 'photo.html',
    controller: function($scope, $state, $stateParams, photo) { 
      $scope.gallery = $stateParams.galleryid; 
      $scope.photo = photo; 
    }
  });

});

app.run(function($rootScope, $location, $state) { 
  $rootScope.$location = $location; 
  $rootScope.$state = $state;
  $rootScope.reload = function() { $state.reload(); };
  $rootScope.go = function() { $state.go('user'); };
});

// Adds state change hooks; logs to console.
app.run(function($rootScope, $state, $stateParams, $urlMatcherFactory) {
  $rootScope.$state = $state;
  var umf = $urlMatcherFactory;
  $rootScope.href = {};
  $rootScope.$on("$stateChangeSuccess", function(evt, to, toP, from, fromP) { 
    [ false, "-", "~", "", true ].forEach(function(policy) { 
      $rootScope.href[policy] = $state.$current.url.$$format(policy, $stateParams);
    })
  });
  //   function setSquash(state, squash) { 
  //     var reset = {};
  //     var params = state.params;
  //     params.$$keys().forEach(function(key) {
  //       reset[key] = params[key].squash;
  //       params[key].squash = squash;
  //     });
  //     return function() { angular.forEach(reset, function(value, key) { params[key].squash = reset[key]}) }
  //   }
   
  //   $rootScope.href = {};
  //   angular.forEach( [ "nosquash", "value", "slash" ], function(policy) { 
  //     var resetFn = [];
  //     angular.forEach($state.$current.path, function(state) { 
  //       resetFn.push(setSquash(state, policy));
  //     })
  //     $rootScope.href[policy] = $state.$current.url.format($stateParams);
  //     resetFn.forEach(function(fn) { fn(); } );
  //   });
  // });

  function message(to, toP, from, fromP) { return from.name  + angular.toJson(fromP) + " -> " + to.name + angular.toJson(toP); }
  $rootScope.$on("$stateChangeStart", function(evt, to, toP, from, fromP) { console.log("Start:   " + message(to, toP, from, fromP)); });
  $rootScope.$on("$stateChangeSuccess", function(evt, to, toP, from, fromP) { console.log("Success: " + message(to, toP, from, fromP)); });
  $rootScope.$on("$stateChangeError", function(evt, to, toP, from, fromP, err) { console.log("Error:   " + message(to, toP, from, fromP), err); });

});


/* Styles go here */

ul li {
  display: inline-block;
  margin: 0.2em;
  padding: 0.1em 0.75em 0.1em 0.75em;
  
  border: 1px solid black;
  background-color: #DDDDff;
  border-radius: 4px;
  text-decoration: underline;
  cursor: pointer
}

ul li.active {
  background-color: #AAAAFF;
}
{
    "christopherthielen": { 
      "username": "christopherthielen", 
      "name": "Chris Thielen"
    },
    "johndoe": {
      "username": "johndoe", 
      "name": "John Doe" 
    }
}
<h3>User: {{ user.name || "no user" }}</h3>
<ul>
  <li ui-sref-active="active" 
      ui-sref="user.gallery({galleryid: gallery })"
      ng-repeat="(gallery, photos) in galleries">
    <a>{{gallery}}</a>
  </li>
</ul><div ui-view></div>
{
  "christopherthielen": {
    "favorites": [
      { "id": "CN0ZRJw", "name": "putin", "url": "http://i.imgur.com/CN0ZRJw.gif" },
      { "id": "TjjgkZW", "name": "homer", "url": "http://i.imgur.com/TjjgkZW.gif" }
    ],
    "skiing": [
      { "id": "BjWLA", "name": "spread eagle", "url": "http://i.imgur.com/BjWLA.jpg" },
      { "id": "uU2iY0X", "name": "faceplant", "url": "http://i.imgur.com/uU2iY0X.jpg" }
    ], 
    "dogs": [
      { "id": "yK3WE7P", "name": "weiner", "url": "http://i.imgur.com/yK3WE7P.jpg" },
      { "id": "n4V9UXT", "name": "Oliphaunt", "url": "http://i.imgur.com/n4V9UXT.jpg" }
    ]
  },
  "johndoe": { 
    "favorites": [
      { "id": "1WjYutp", "name": "fireworks", "url": "http://i.imgur.com/1WjYutp.jpg" },
      { "id": "USnLRR0", "name": "killer penguin", "url": "http://i.imgur.com/USnLRR0.jpg" }
    ],
    "fruit": [
      { "id": "NMLpcKj", "name": "strawberry", "url": "http://i.imgur.com/NMLpcKj.jpg" },
      { "id": "e4bnu7i", "name": "ananas", "url": "http://i.imgur.com/e4bnu7i.jpg" }
    ]
  }
}
<hr>
<div>Gallery: {{ gallery }}</div>
<ul>
  <li ui-sref=".photo({ photoid: photo.id })"
      ui-sref-active="active" 
      ng-repeat="photo in photos">
    <a>{{ photo.name }}</a>
  </li>
</ul>
<div ui-view></div>
<h3>img: {{ photo.name }}</h3>
<img style="max-width: 100%" src="{{ photo.url }} ">