├── LICENSE.md ├── README.md ├── assets ├── app │ ├── beans │ │ └── render-context.js │ ├── controllers │ │ ├── app-controller.js │ │ ├── contact │ │ │ └── contact-controller.js │ │ ├── home │ │ │ └── home-controller.js │ │ ├── layouts │ │ │ ├── splash-controller.js │ │ │ └── standard-controller.js │ │ └── pets │ │ │ ├── categories-controller.js │ │ │ ├── detail │ │ │ ├── detail-controller.js │ │ │ └── random-controller.js │ │ │ ├── list-controller.js │ │ │ └── pets-controller.js │ ├── css │ │ └── main.css │ ├── img │ │ ├── header-splash.jpg │ │ └── header-standard.jpg │ ├── less │ │ ├── category-list.less │ │ ├── core.less │ │ ├── home-nav.less │ │ ├── loading.less │ │ ├── main.less │ │ ├── mixins.less │ │ ├── pet-header.less │ │ ├── pet-list-header.less │ │ ├── pet-properties.less │ │ ├── random-pet.less │ │ ├── splash.less │ │ ├── standard.less │ │ └── tabs.less │ ├── main.js │ ├── services │ │ ├── category-service.js │ │ ├── lodash.js │ │ ├── pet-service.js │ │ └── request-context.js │ └── views │ │ ├── contact │ │ └── index.htm │ │ ├── home │ │ └── index.htm │ │ ├── layouts │ │ ├── splash.htm │ │ └── standard.htm │ │ └── pets │ │ ├── categories.htm │ │ ├── detail │ │ ├── background.htm │ │ ├── diet.htm │ │ ├── index.htm │ │ ├── medical-history.htm │ │ └── random.htm │ │ ├── index.htm │ │ └── list.htm └── vendor │ ├── angularjs │ └── angular.min.js │ ├── jquery │ └── jquery-1.8.3.min.js │ └── lodash │ └── lodash.min.js └── index.htm /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | # The MIT License (MIT) 3 | 4 | Copyright (c) 2013 [Ben Nadel][1] 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | [1]: http://www.bennadel.com -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AngularJS - Deep Routing Example 2 | 3 | See demo at http://bennadel.github.io/AngularJS-Routing 4 | -------------------------------------------------------------------------------- /assets/app/beans/render-context.js: -------------------------------------------------------------------------------- 1 | (function( ng, app ) { 2 | 3 | "use strict"; 4 | 5 | // I provide information about the current route request, local to the given render path. 6 | app.value( 7 | "RenderContext", 8 | function( requestContext, actionPrefix, paramNames ) { 9 | 10 | 11 | // I return the next section after the location being watched. 12 | function getNextSection() { 13 | 14 | return( 15 | requestContext.getNextSection( actionPrefix ) 16 | ); 17 | 18 | } 19 | 20 | 21 | // I check to see if the action has changed (and is local to the current location). 22 | function isChangeLocal() { 23 | 24 | return( 25 | requestContext.startsWith( actionPrefix ) 26 | ); 27 | 28 | } 29 | 30 | 31 | // I determine if the last change in the request context is relevant to 32 | // the action and route params being observed in this render context. 33 | function isChangeRelevant() { 34 | 35 | // If the action is not local to the action prefix, then we don't even 36 | // want to bother checking the params. 37 | if ( ! requestContext.startsWith( actionPrefix ) ) { 38 | 39 | return( false ); 40 | 41 | } 42 | 43 | // If the action has changed, we don't need to bother checking the params. 44 | if ( requestContext.hasActionChanged() ) { 45 | 46 | return( true ) ; 47 | 48 | } 49 | 50 | // If we made it this far, we know that the action has not changed. As such, we''ll 51 | // have to make the change determination based on the observed parameters. 52 | return( 53 | paramNames.length && 54 | requestContext.haveParamsChanged( paramNames ) 55 | ); 56 | 57 | } 58 | 59 | 60 | // ---------------------------------------------- // 61 | // ---------------------------------------------- // 62 | 63 | 64 | // Private variables... 65 | 66 | 67 | // ---------------------------------------------- // 68 | // ---------------------------------------------- // 69 | 70 | 71 | // Return the public API. 72 | return({ 73 | getNextSection: getNextSection, 74 | isChangeLocal: isChangeLocal, 75 | isChangeRelevant: isChangeRelevant 76 | }); 77 | 78 | 79 | } 80 | ); 81 | 82 | })( angular, Demo ); 83 | -------------------------------------------------------------------------------- /assets/app/controllers/app-controller.js: -------------------------------------------------------------------------------- 1 | (function( ng, app ){ 2 | 3 | "use strict"; 4 | 5 | app.controller( 6 | "AppController", 7 | function( $scope, $route, $routeParams, $location, requestContext, _ ) { 8 | 9 | 10 | // --- Define Controller Methods. ------------------- // 11 | 12 | 13 | // I check to see if the given route is a valid route; or, is the route being 14 | // re-directed to the default route (due to failure to match pattern). 15 | function isRouteRedirect( route ) { 16 | 17 | // If there is no action, then the route is redirection from an unknown 18 | // route to a known route. 19 | return( ! route.current.action ); 20 | 21 | } 22 | 23 | 24 | // --- Define Scope Methods. ------------------------ // 25 | 26 | 27 | // I get the current time for use when display the time a controller was rendered. 28 | // This way, we can see the difference between when a controller was instantiated 29 | // and when it was re-populated with data. 30 | $scope.getInstanceTime = function() { 31 | 32 | var now = new Date(); 33 | var timeString = now.toTimeString(); 34 | var instanceTime = timeString.match( /\d+:\d+:\d+/i ); 35 | 36 | return( instanceTime[ 0 ] ); 37 | 38 | }; 39 | 40 | 41 | // TODO: Flesh this out - for now, just trying to create a wrapper for alert(). 42 | $scope.openModalWindow = function( modalType ) { 43 | 44 | alert( arguments[ 1 ] || "Opps: Something went wrong." ); 45 | 46 | }; 47 | 48 | 49 | // I update the title tag. 50 | $scope.setWindowTitle = function( title ) { 51 | 52 | $scope.windowTitle = title; 53 | 54 | }; 55 | 56 | 57 | // --- Define Controller Variables. ----------------- // 58 | 59 | 60 | // Get the render context local to this controller (and relevant params). 61 | var renderContext = requestContext.getRenderContext(); 62 | 63 | 64 | // --- Define Scope Variables. ---------------------- // 65 | 66 | 67 | // Set up the default window title. 68 | $scope.windowTitle = "Adopt-A-Pet"; 69 | 70 | // The subview indicates which view is going to be rendered on the page. 71 | $scope.subview = renderContext.getNextSection(); 72 | 73 | 74 | // --- Bind To Scope Events. ------------------------ // 75 | 76 | 77 | // I handle changes to the request context. 78 | $scope.$on( 79 | "requestContextChanged", 80 | function() { 81 | 82 | // Make sure this change is relevant to this controller. 83 | if ( ! renderContext.isChangeRelevant() ) { 84 | 85 | return; 86 | 87 | } 88 | 89 | // Update the view that is being rendered. 90 | $scope.subview = renderContext.getNextSection(); 91 | 92 | } 93 | ); 94 | 95 | 96 | // Listen for route changes so that we can trigger request-context change events. 97 | $scope.$on( 98 | "$routeChangeSuccess", 99 | function( event ) { 100 | 101 | // If this is a redirect directive, then there's no taction to be taken. 102 | if ( isRouteRedirect( $route ) ) { 103 | 104 | return; 105 | 106 | } 107 | 108 | // Update the current request action change. 109 | requestContext.setContext( $route.current.action, $routeParams ); 110 | 111 | // Announce the change in render conditions. 112 | $scope.$broadcast( "requestContextChanged", requestContext ); 113 | 114 | } 115 | ); 116 | 117 | 118 | // --- Initialize. ---------------------------------- // 119 | 120 | 121 | // ... 122 | 123 | 124 | } 125 | ); 126 | 127 | })( angular, Demo ); -------------------------------------------------------------------------------- /assets/app/controllers/contact/contact-controller.js: -------------------------------------------------------------------------------- 1 | (function( ng, app ){ 2 | 3 | "use strict"; 4 | 5 | app.controller( 6 | "contact.ContactController", 7 | function( $scope, requestContext, _ ) { 8 | 9 | 10 | // --- Define Controller Methods. ------------------- // 11 | 12 | 13 | // ... 14 | 15 | 16 | // --- Define Scope Methods. ------------------------ // 17 | 18 | 19 | // ... 20 | 21 | 22 | // --- Define Controller Variables. ----------------- // 23 | 24 | 25 | // Get the render context local to this controller (and relevant params). 26 | var renderContext = requestContext.getRenderContext( "standard.contact" ); 27 | 28 | 29 | // --- Define Scope Variables. ---------------------- // 30 | 31 | 32 | // The subview indicates which view is going to be rendered on the page. 33 | $scope.subview = renderContext.getNextSection(); 34 | 35 | 36 | // --- Bind To Scope Events. ------------------------ // 37 | 38 | 39 | // I handle changes to the request context. 40 | $scope.$on( 41 | "requestContextChanged", 42 | function() { 43 | 44 | // Make sure this change is relevant to this controller. 45 | if ( ! renderContext.isChangeRelevant() ) { 46 | 47 | return; 48 | 49 | } 50 | 51 | // Update the view that is being rendered. 52 | $scope.subview = renderContext.getNextSection(); 53 | 54 | } 55 | ); 56 | 57 | 58 | // --- Initialize. ---------------------------------- // 59 | 60 | 61 | $scope.setWindowTitle( "Contact Us" ); 62 | 63 | 64 | } 65 | ); 66 | 67 | })( angular, Demo ); -------------------------------------------------------------------------------- /assets/app/controllers/home/home-controller.js: -------------------------------------------------------------------------------- 1 | (function( ng, app ){ 2 | 3 | "use strict"; 4 | 5 | app.controller( 6 | "home.HomeController", 7 | function( $scope, requestContext, _ ) { 8 | 9 | 10 | // --- Define Controller Methods. ------------------- // 11 | 12 | 13 | // ... 14 | 15 | 16 | // --- Define Scope Methods. ------------------------ // 17 | 18 | 19 | // ... 20 | 21 | 22 | // --- Define Controller Variables. ----------------- // 23 | 24 | 25 | // Get the render context local to this controller (and relevant params). 26 | var renderContext = requestContext.getRenderContext( "splash.home" ) 27 | 28 | 29 | // --- Define Scope Variables. ---------------------- // 30 | 31 | 32 | // The subview indicates which view is going to be rendered on the page. 33 | $scope.subview = renderContext.getNextSection(); 34 | 35 | 36 | // --- Bind To Scope Events. ------------------------ // 37 | 38 | 39 | // I handle changes to the request context. 40 | $scope.$on( 41 | "requestContextChanged", 42 | function() { 43 | 44 | // Make sure this change is relevant to this controller. 45 | if ( ! renderContext.isChangeRelevant() ) { 46 | 47 | return; 48 | 49 | } 50 | 51 | // Update the view that is being rendered. 52 | $scope.subview = renderContext.getNextSection(); 53 | 54 | } 55 | ); 56 | 57 | 58 | // --- Initialize. ---------------------------------- // 59 | 60 | 61 | $scope.setWindowTitle( "Welcome to Adopt-A-Pet" ); 62 | 63 | 64 | } 65 | ); 66 | 67 | })( angular, Demo ); -------------------------------------------------------------------------------- /assets/app/controllers/layouts/splash-controller.js: -------------------------------------------------------------------------------- 1 | (function( ng, app ){ 2 | 3 | "use strict"; 4 | 5 | app.controller( 6 | "layouts.SplashController", 7 | function( $scope, requestContext, _ ) { 8 | 9 | 10 | // --- Define Controller Methods. ------------------- // 11 | 12 | 13 | // ... 14 | 15 | 16 | // --- Define Scope Methods. ------------------------ // 17 | 18 | 19 | // ... 20 | 21 | 22 | // --- Define Controller Variables. ----------------- // 23 | 24 | 25 | // Get the render context local to this controller (and relevant params). 26 | var renderContext = requestContext.getRenderContext( "splash" ); 27 | 28 | 29 | // --- Define Scope Variables. ---------------------- // 30 | 31 | 32 | // The subview indicates which view is going to be rendered on the page. 33 | $scope.subview = renderContext.getNextSection(); 34 | 35 | // Get the current year for copyright output. 36 | $scope.copyrightYear = ( new Date() ).getFullYear(); 37 | 38 | 39 | // --- Bind To Scope Events. ------------------------ // 40 | 41 | 42 | // I handle changes to the request context. 43 | $scope.$on( 44 | "requestContextChanged", 45 | function() { 46 | 47 | // Make sure this change is relevant to this controller. 48 | if ( ! renderContext.isChangeRelevant() ) { 49 | 50 | return; 51 | 52 | } 53 | 54 | // Update the view that is being rendered. 55 | $scope.subview = renderContext.getNextSection(); 56 | 57 | } 58 | ); 59 | 60 | 61 | // --- Initialize. ---------------------------------- // 62 | 63 | 64 | // ... 65 | 66 | 67 | } 68 | ); 69 | 70 | })( angular, Demo ); -------------------------------------------------------------------------------- /assets/app/controllers/layouts/standard-controller.js: -------------------------------------------------------------------------------- 1 | (function( ng, app ){ 2 | 3 | "use strict"; 4 | 5 | app.controller( 6 | "layouts.StandardController", 7 | function( $scope, requestContext, _ ) { 8 | 9 | 10 | // --- Define Controller Methods. ------------------- // 11 | 12 | 13 | // ... 14 | 15 | 16 | // --- Define Scope Methods. ------------------------ // 17 | 18 | 19 | // ... 20 | 21 | 22 | // --- Define Controller Variables. ----------------- // 23 | 24 | 25 | // Get the render context local to this controller (and relevant params). 26 | var renderContext = requestContext.getRenderContext( "standard" ); 27 | 28 | 29 | // --- Define Scope Variables. ---------------------- // 30 | 31 | 32 | // The subview indicates which view is going to be rendered on the page. 33 | $scope.subview = renderContext.getNextSection(); 34 | 35 | // Get the current year for copyright output. 36 | $scope.copyrightYear = ( new Date() ).getFullYear(); 37 | 38 | 39 | // --- Bind To Scope Events. ------------------------ // 40 | 41 | 42 | // I handle changes to the request context. 43 | $scope.$on( 44 | "requestContextChanged", 45 | function() { 46 | 47 | // Make sure this change is relevant to this controller. 48 | if ( ! renderContext.isChangeRelevant() ) { 49 | 50 | return; 51 | 52 | } 53 | 54 | // Update the view that is being rendered. 55 | $scope.subview = renderContext.getNextSection(); 56 | 57 | } 58 | ); 59 | 60 | 61 | // --- Initialize. ---------------------------------- // 62 | 63 | 64 | // ... 65 | 66 | 67 | } 68 | ); 69 | 70 | })( angular, Demo ); -------------------------------------------------------------------------------- /assets/app/controllers/pets/categories-controller.js: -------------------------------------------------------------------------------- 1 | (function( ng, app ){ 2 | 3 | "use strict"; 4 | 5 | app.controller( 6 | "pets.CategoriesController", 7 | function( $scope, requestContext, categoryService, _ ) { 8 | 9 | 10 | // --- Define Controller Methods. ------------------- // 11 | 12 | 13 | // I apply the remote data to the local view model. 14 | function applyRemoteData( categories ) { 15 | 16 | $scope.categories = _.sortOnProperty( categories, "name", "asc" ); 17 | 18 | } 19 | 20 | 21 | // I load the "remote" data from the server. 22 | function loadRemoteData() { 23 | 24 | $scope.isLoading = true; 25 | 26 | var promise = categoryService.getCategories(); 27 | 28 | promise.then( 29 | function( response ) { 30 | 31 | $scope.isLoading = false; 32 | 33 | applyRemoteData( response ); 34 | 35 | }, 36 | function( response ) { 37 | 38 | $scope.openModalWindow( "error", "For some reason we couldn't load the categories. Try refreshing your browser." ); 39 | 40 | } 41 | ); 42 | 43 | } 44 | 45 | 46 | // --- Define Scope Methods. ------------------------ // 47 | 48 | 49 | // ... 50 | 51 | 52 | // --- Define Controller Variables. ----------------- // 53 | 54 | 55 | // Get the render context local to this controller (and relevant params). 56 | var renderContext = requestContext.getRenderContext( "standard.pets.categories" ); 57 | 58 | 59 | // --- Define Scope Variables. ---------------------- // 60 | 61 | 62 | // I flag that data is being loaded. 63 | $scope.isLoading = true; 64 | 65 | // I hold the categories to render. 66 | $scope.categories = []; 67 | 68 | // The subview indicates which view is going to be rendered on the page. 69 | $scope.subview = renderContext.getNextSection(); 70 | 71 | 72 | // --- Bind To Scope Events. ------------------------ // 73 | 74 | 75 | // I handle changes to the request context. 76 | $scope.$on( 77 | "requestContextChanged", 78 | function() { 79 | 80 | // Make sure this change is relevant to this controller. 81 | if ( ! renderContext.isChangeRelevant() ) { 82 | 83 | return; 84 | 85 | } 86 | 87 | // Update the view that is being rendered. 88 | $scope.subview = renderContext.getNextSection(); 89 | 90 | } 91 | ); 92 | 93 | 94 | // --- Initialize. ---------------------------------- // 95 | 96 | 97 | // Set the window title. 98 | $scope.setWindowTitle( "Pets" ); 99 | 100 | // Load the "remote" data. 101 | loadRemoteData(); 102 | 103 | 104 | } 105 | ); 106 | 107 | })( angular, Demo ); -------------------------------------------------------------------------------- /assets/app/controllers/pets/detail/detail-controller.js: -------------------------------------------------------------------------------- 1 | (function( ng, app ){ 2 | 3 | "use strict"; 4 | 5 | app.controller( 6 | "pets.detail.DetailController", 7 | function( $scope, $location, $q, requestContext, categoryService, petService, _ ) { 8 | 9 | 10 | // --- Define Controller Methods. ------------------- // 11 | 12 | 13 | // I apply the remote data to the local view model. 14 | function applyRemoteData( category, pet ) { 15 | 16 | $scope.category = category; 17 | $scope.pet = pet; 18 | 19 | $scope.setWindowTitle( pet.name + " - " + pet.breed ); 20 | 21 | } 22 | 23 | 24 | // I load the "remote" data from the server. 25 | function loadRemoteData() { 26 | 27 | $scope.isLoading = true; 28 | 29 | var promise = $q.all( 30 | [ 31 | categoryService.getCategoryByID( $scope.categoryID ), 32 | petService.getPetByID( $scope.petID ) 33 | ] 34 | ); 35 | 36 | promise.then( 37 | function( response ) { 38 | 39 | $scope.isLoading = false; 40 | 41 | applyRemoteData( response[ 0 ], response[ 1 ] ); 42 | 43 | }, 44 | function( response ) { 45 | 46 | // The pet couldn't be loaded for some reason - possibly someone hacking with the URL. 47 | $location.path( "/pets/" + $scope.categoryID ); 48 | 49 | } 50 | ); 51 | 52 | } 53 | 54 | 55 | // --- Define Scope Methods. ------------------------ // 56 | 57 | 58 | // ... 59 | 60 | 61 | // --- Define Controller Variables. ----------------- // 62 | 63 | 64 | // Get the render context local to this controller (and relevant params). 65 | var renderContext = requestContext.getRenderContext( "standard.pets.detail", "petID" ); 66 | 67 | 68 | // --- Define Scope Variables. ---------------------- // 69 | 70 | 71 | // Get the relevant route IDs. 72 | $scope.categoryID = requestContext.getParam( "categoryID" ); 73 | $scope.petID = requestContext.getParamAsInt( "petID" ); 74 | 75 | // I flag that data is being loaded. 76 | $scope.isLoading = true; 77 | 78 | // I hold the category and pet to render. 79 | $scope.category = null; 80 | $scope.pet = null; 81 | 82 | // The subview indicates which view is going to be rendered on the page. 83 | $scope.subview = renderContext.getNextSection(); 84 | 85 | 86 | // --- Bind To Scope Events. ------------------------ // 87 | 88 | 89 | // I handle changes to the request context. 90 | $scope.$on( 91 | "requestContextChanged", 92 | function() { 93 | 94 | // Make sure this change is relevant to this controller. 95 | if ( ! renderContext.isChangeRelevant() ) { 96 | 97 | return; 98 | 99 | } 100 | 101 | // Get the relevant route IDs. 102 | $scope.categoryID = requestContext.getParam( "categoryID" ); 103 | $scope.petID = requestContext.getParamAsInt( "petID" ); 104 | 105 | // Update the view that is being rendered. 106 | $scope.subview = renderContext.getNextSection(); 107 | 108 | // If the relevant ID has changed, refresh the view. 109 | if ( requestContext.haveParamsChanged( [ "categoryID", "petID" ] ) ) { 110 | 111 | loadRemoteData(); 112 | 113 | } 114 | 115 | } 116 | ); 117 | 118 | 119 | // --- Initialize. ---------------------------------- // 120 | 121 | 122 | // Set the window title. 123 | $scope.setWindowTitle( "Loading Pet" ); 124 | 125 | // Load the "remote" data. 126 | loadRemoteData(); 127 | 128 | 129 | } 130 | ); 131 | 132 | })( angular, Demo ); -------------------------------------------------------------------------------- /assets/app/controllers/pets/detail/random-controller.js: -------------------------------------------------------------------------------- 1 | (function( ng, app ){ 2 | 3 | "use strict"; 4 | 5 | app.controller( 6 | "pets.detail.RandomController", 7 | function( $scope, requestContext, petService, _ ) { 8 | 9 | 10 | // --- Define Controller Methods. ------------------- // 11 | 12 | 13 | // I apply the remote data to the local view model. 14 | function applyRemoteData( pet ) { 15 | 16 | $scope.pet = pet; 17 | 18 | } 19 | 20 | 21 | // I load the "remote" data from the server. 22 | function loadRemoteData() { 23 | 24 | $scope.isLoading = true; 25 | 26 | var promise = petService.getRandomPetExcluding( $scope.categoryID, $scope.petID ); 27 | 28 | promise.then( 29 | function( response ) { 30 | 31 | $scope.isLoading = false; 32 | 33 | applyRemoteData( response ); 34 | 35 | }, 36 | function( response ) { 37 | 38 | $scope.openModalWindow( "error", "For some reason we couldn't load a random pet. Try refreshing your browser." ); 39 | 40 | } 41 | ); 42 | 43 | } 44 | 45 | 46 | // --- Define Scope Methods. ------------------------ // 47 | 48 | 49 | // ... 50 | 51 | 52 | // --- Define Controller Variables. ----------------- // 53 | 54 | 55 | // Get the render context local to this controller (and relevant params). 56 | var renderContext = requestContext.getRenderContext( "standard.pets.detail", [ "categoryID", "petID" ] ); 57 | 58 | 59 | // --- Define Scope Variables. ---------------------- // 60 | 61 | 62 | // Get the relevant route IDs. 63 | $scope.categoryID = requestContext.getParam( "categoryID" ); 64 | $scope.petID = requestContext.getParamAsInt( "petID" ); 65 | 66 | // I flag that data is being loaded. 67 | $scope.isLoading = true; 68 | 69 | // I hold the pet to render. 70 | $scope.pet = null; 71 | 72 | 73 | // --- Bind To Scope Events. ------------------------ // 74 | 75 | 76 | // I handle changes to the request context. 77 | $scope.$on( 78 | "requestContextChanged", 79 | function() { 80 | 81 | // Make sure this change is relevant to this controller. 82 | if ( ! renderContext.isChangeRelevant() ) { 83 | 84 | return; 85 | 86 | } 87 | 88 | // Get the relevant route IDs. 89 | $scope.categoryID = requestContext.getParam( "categoryID" ); 90 | $scope.petID = requestContext.getParamAsInt( "petID" ); 91 | 92 | // If the relevant ID has changed, refresh the view. 93 | if ( requestContext.haveParamsChanged( [ "categoryID", "petID" ] ) ) { 94 | 95 | loadRemoteData(); 96 | 97 | } 98 | 99 | } 100 | ); 101 | 102 | 103 | // --- Initialize. ---------------------------------- // 104 | 105 | 106 | // Load the "remote" data. 107 | loadRemoteData(); 108 | 109 | 110 | } 111 | ); 112 | 113 | })( angular, Demo ); -------------------------------------------------------------------------------- /assets/app/controllers/pets/list-controller.js: -------------------------------------------------------------------------------- 1 | (function( ng, app ){ 2 | 3 | "use strict"; 4 | 5 | app.controller( 6 | "pets.ListController", 7 | function( $scope, $location, $q, requestContext, categoryService, petService, _ ) { 8 | 9 | 10 | // --- Define Controller Methods. ------------------- // 11 | 12 | 13 | // I apply the remote data to the local view model. 14 | function applyRemoteData( category, pets ) { 15 | 16 | $scope.category = category; 17 | $scope.pets = _.sortOnProperty( pets, "name", "asc" ); 18 | 19 | $scope.setWindowTitle( category.name ); 20 | 21 | } 22 | 23 | 24 | // I load the remote data from the server. 25 | function loadRemoteData() { 26 | 27 | $scope.isLoading = true; 28 | 29 | var promise = $q.all( 30 | [ 31 | categoryService.getCategoryByID( $scope.categoryID ), 32 | petService.getPetsByCategoryID( $scope.categoryID ) 33 | ] 34 | ); 35 | 36 | promise.then( 37 | function( response ) { 38 | 39 | $scope.isLoading = false; 40 | 41 | applyRemoteData( response[ 0 ], response[ 1 ] ); 42 | 43 | }, 44 | function( response ) { 45 | 46 | // The category couldn't be loaded for some reason - possibly someone hacking with the URL. 47 | $location.path( "/pets" ); 48 | 49 | } 50 | ); 51 | 52 | } 53 | 54 | 55 | // --- Define Scope Methods. ------------------------ // 56 | 57 | 58 | // ... 59 | 60 | 61 | // --- Define Controller Variables. ----------------- // 62 | 63 | 64 | // Get the render context local to this controller (and relevant params). 65 | var renderContext = requestContext.getRenderContext( "standard.pets.list", "categoryID" ); 66 | 67 | 68 | // --- Define Scope Variables. ---------------------- // 69 | 70 | 71 | // Get the ID of the category. 72 | $scope.categoryID = requestContext.getParam( "categoryID" ); 73 | 74 | // I flag that data is being loaded. 75 | $scope.isLoading = true; 76 | 77 | // I am the category and the list of pets that are being viewed. 78 | $scope.category = null; 79 | $scope.pets = null; 80 | 81 | // The subview indicates which view is going to be rendered on the page. 82 | $scope.subview = renderContext.getNextSection(); 83 | 84 | 85 | // --- Bind To Scope Events. ------------------------ // 86 | 87 | 88 | // I handle changes to the request context. 89 | $scope.$on( 90 | "requestContextChanged", 91 | function() { 92 | 93 | // Make sure this change is relevant to this controller. 94 | if ( ! renderContext.isChangeRelevant() ) { 95 | 96 | return; 97 | 98 | } 99 | 100 | // Get the relevant route IDs. 101 | $scope.categoryID = requestContext.getParam( "categoryID" ); 102 | 103 | // Update the view that is being rendered. 104 | $scope.subview = renderContext.getNextSection(); 105 | 106 | // If the relevant IDs have changed, refresh the view. 107 | if ( requestContext.hasParamChanged( "categoryID" ) ) { 108 | 109 | loadRemoteData(); 110 | 111 | } 112 | 113 | } 114 | ); 115 | 116 | 117 | // --- Initialize. ---------------------------------- // 118 | 119 | 120 | // Set the interim title. 121 | $scope.setWindowTitle( "Loading Category" ); 122 | 123 | // Load the "remote" data. 124 | loadRemoteData(); 125 | 126 | 127 | } 128 | ); 129 | 130 | })( angular, Demo ); -------------------------------------------------------------------------------- /assets/app/controllers/pets/pets-controller.js: -------------------------------------------------------------------------------- 1 | (function( ng, app ){ 2 | 3 | "use strict"; 4 | 5 | app.controller( 6 | "pets.PetsController", 7 | function( $scope, requestContext, _ ) { 8 | 9 | 10 | // --- Define Controller Methods. ------------------- // 11 | 12 | 13 | // ... 14 | 15 | 16 | // --- Define Scope Methods. ------------------------ // 17 | 18 | 19 | // ... 20 | 21 | 22 | // --- Define Controller Variables. ----------------- // 23 | 24 | 25 | // Get the render context local to this controller (and relevant params). 26 | var renderContext = requestContext.getRenderContext( "standard.pets" ); 27 | 28 | 29 | // --- Define Scope Variables. ---------------------- // 30 | 31 | 32 | // The subview indicates which view is going to be rendered on the page. 33 | $scope.subview = renderContext.getNextSection(); 34 | 35 | 36 | // --- Bind To Scope Events. ------------------------ // 37 | 38 | 39 | // I handle changes to the request context. 40 | $scope.$on( 41 | "requestContextChanged", 42 | function() { 43 | 44 | // Make sure this change is relevant to this controller. 45 | if ( ! renderContext.isChangeRelevant() ) { 46 | 47 | return; 48 | 49 | } 50 | 51 | // Update the view that is being rendered. 52 | $scope.subview = renderContext.getNextSection(); 53 | 54 | } 55 | ); 56 | 57 | 58 | // --- Initialize. ---------------------------------- // 59 | 60 | 61 | $scope.setWindowTitle( "Pets" ); 62 | 63 | 64 | } 65 | ); 66 | 67 | })( angular, Demo ); -------------------------------------------------------------------------------- /assets/app/css/main.css: -------------------------------------------------------------------------------- 1 | .clearfix { 2 | *zoom: 1; 3 | } 4 | .clearfix:before, 5 | .clearfix:after { 6 | display: table; 7 | content: ""; 8 | } 9 | .clearfix:after { 10 | clear: both; 11 | } 12 | body { 13 | font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; 14 | font-size: 16px ; 15 | line-height: 1.6em ; 16 | } 17 | h1, 18 | h2, 19 | h3, 20 | h4 { 21 | font-family: Georgia, serif ; 22 | } 23 | h1 { 24 | font-size: 28px ; 25 | } 26 | h2 { 27 | font-size: 24px ; 28 | } 29 | h3 { 30 | font-size: 20px ; 31 | } 32 | h4 { 33 | font-size: 16px ; 34 | } 35 | a { 36 | color: #333333 ; 37 | } 38 | div.l-loading { 39 | background-color: #262626 ; 40 | bottom: 0px ; 41 | left: 0px ; 42 | position: fixed ; 43 | right: 0px ; 44 | top: 0px ; 45 | } 46 | div.l-loading p { 47 | color: #F0F0F0 ; 48 | font-size: 12px ; 49 | font-style: italic ; 50 | left: 0px ; 51 | position: absolute ; 52 | text-align: center ; 53 | top: 48% ; 54 | width: 100% ; 55 | } 56 | div.l-splash { 57 | margin: 30px auto 50px auto ; 58 | width: 600px ; 59 | } 60 | div.l-splash div.l-container { 61 | -webkit-border-radius: 7px 7px 7px 7px; 62 | -moz-border-radius: 7px 7px 7px 7px; 63 | border-radius: 7px 7px 7px 7px; 64 | -webkit-box-shadow: 0px 0px 5px 1px #666666; 65 | -moz-box-shadow: 0px 0px 5px 1px #666666; 66 | box-shadow: 0px 0px 5px 1px #666666; 67 | padding: 0px 0px 1px 0px ; 68 | } 69 | div.l-splash div.l-header { 70 | background: url("../img/header-splash.jpg") 0px 0px no-repeat; 71 | -webkit-border-radius: 6px 6px 0px 0px; 72 | -moz-border-radius: 6px 6px 0px 0px; 73 | border-radius: 6px 6px 0px 0px; 74 | height: 305px ; 75 | position: relative ; 76 | } 77 | div.l-splash div.l-header span.title { 78 | color: #FFFFFF ; 79 | font-family: Georgia, serif ; 80 | font-size: 50px ; 81 | font-weight: bold ; 82 | line-height: 65px ; 83 | position: absolute ; 84 | right: 0px ; 85 | text-align: center ; 86 | text-shadow: 1px 1px #000000 ; 87 | top: 53px ; 88 | width: 275px ; 89 | } 90 | div.l-splash div.l-body { 91 | margin: 20px 20px 20px 20px ; 92 | } 93 | div.l-splash div.l-footer { 94 | color: #999999 ; 95 | font-size: 11px ; 96 | line-height: 16px ; 97 | margin: 20px 20px 20px 20px ; 98 | } 99 | div.l-splash div.l-footer div.description { 100 | margin-bottom: 5px ; 101 | } 102 | div.l-splash div.l-footer div.author a { 103 | color: #999999 ; 104 | text-decoration: none ; 105 | } 106 | div.l-splash div.l-footer div.author a:hover { 107 | color: #333333 ; 108 | text-decoration: underline ; 109 | } 110 | div.l-standard { 111 | margin: 30px auto 50px auto ; 112 | width: 600px ; 113 | } 114 | div.l-standard div.l-container { 115 | -webkit-border-radius: 7px 7px 7px 7px; 116 | -moz-border-radius: 7px 7px 7px 7px; 117 | border-radius: 7px 7px 7px 7px; 118 | -webkit-box-shadow: 0px 0px 5px 1px #666666; 119 | -moz-box-shadow: 0px 0px 5px 1px #666666; 120 | box-shadow: 0px 0px 5px 1px #666666; 121 | padding: 0px 0px 1px 0px ; 122 | } 123 | div.l-standard div.l-header { 124 | background: url("../img/header-standard.jpg") 0px -30px no-repeat; 125 | -webkit-border-radius: 6px 6px 0px 0px; 126 | -moz-border-radius: 6px 6px 0px 0px; 127 | border-radius: 6px 6px 0px 0px; 128 | height: 157px ; 129 | position: relative ; 130 | } 131 | div.l-standard div.l-header span.title { 132 | color: #262626 ; 133 | font-family: Georgia, serif ; 134 | font-size: 46px ; 135 | font-weight: bold ; 136 | left: 20px ; 137 | line-height: 52px ; 138 | position: absolute ; 139 | text-shadow: 1px 1px rgba(255, 255, 255, 0.8); 140 | top: 28px ; 141 | } 142 | div.l-standard div.l-header ul { 143 | background-color: #F0F0F0 ; 144 | border: 1px solid #333333 ; 145 | border-width: 1px 0px 1px 0px ; 146 | bottom: 0px ; 147 | font-size: 16px ; 148 | height: 35px ; 149 | left: 0px ; 150 | list-style-type: none ; 151 | margin: 0px 0px 0px 0px ; 152 | padding: 0px 0px 0px 0px ; 153 | position: absolute ; 154 | right: 0px ; 155 | } 156 | div.l-standard div.l-header ul li { 157 | border-right: 1px dotted #CCCCCC ; 158 | float: left ; 159 | margin: 0px 0px 0px 0px ; 160 | padding: 0px 0px 0px 0px ; 161 | } 162 | div.l-standard div.l-header ul li a { 163 | color: #666666 ; 164 | display: block ; 165 | height: 35px ; 166 | line-height: 35px ; 167 | text-align: center ; 168 | text-decoration: none ; 169 | width: 100px ; 170 | } 171 | div.l-standard div.l-header ul li a:hover { 172 | text-decoration: underline ; 173 | } 174 | div.l-standard div.l-header ul li.on a { 175 | background-color: #262626 ; 176 | color: #FFFFFF ; 177 | font-weight: bold ; 178 | } 179 | div.l-standard div.l-header ul li.on a:hover { 180 | text-decoration: none ; 181 | } 182 | div.l-standard div.l-body { 183 | margin: 25px 20px 25px 20px ; 184 | } 185 | div.l-standard div.l-footer { 186 | color: #999999 ; 187 | font-size: 11px ; 188 | line-height: 16px ; 189 | margin: 20px 20px 20px 20px ; 190 | } 191 | div.l-standard div.l-footer div.description { 192 | margin-bottom: 5px ; 193 | } 194 | div.l-standard div.l-footer div.author a { 195 | color: #999999 ; 196 | text-decoration: none ; 197 | } 198 | div.l-standard div.l-footer div.author a:hover { 199 | color: #333333 ; 200 | text-decoration: underline ; 201 | } 202 | ul.m-category-list { 203 | list-style-type: none ; 204 | margin: 20px 0px 20px 0px ; 205 | padding: 0px 0px 0px 0px ; 206 | } 207 | ul.m-category-list li { 208 | margin: 0px 0px 13px 0px ; 209 | padding: 0px 0px 0px 0px ; 210 | } 211 | ul.m-category-list li a { 212 | background-color: #F0F0F0 ; 213 | border: 1px solid #CCCCCC ; 214 | -webkit-border-radius: 4px 4px 4px 4px; 215 | -moz-border-radius: 4px 4px 4px 4px; 216 | border-radius: 4px 4px 4px 4px; 217 | display: block ; 218 | height: 70px ; 219 | position: relative ; 220 | text-decoration: none ; 221 | } 222 | ul.m-category-list li a::after { 223 | background-color: #FFFFFF ; 224 | -webkit-border-radius: 40px 40px 40px 40px; 225 | -moz-border-radius: 40px 40px 40px 40px; 226 | border-radius: 40px 40px 40px 40px; 227 | color: #333333 ; 228 | content: "\00BB"; 229 | display: none ; 230 | font-family: Tahoma, Geneva, sans-serif; 231 | font-size: 30px ; 232 | height: 40px ; 233 | line-height: 35px ; 234 | margin-top: -20px; 235 | position: absolute ; 236 | right: 15px ; 237 | text-align: center ; 238 | text-index: 3px ; 239 | top: 50% ; 240 | width: 40px ; 241 | } 242 | ul.m-category-list li a span.name { 243 | display: block ; 244 | font-size: 18px ; 245 | font-weight: bold ; 246 | line-height: 23px ; 247 | padding: 12px 0px 3px 15px ; 248 | text-decoration: underline ; 249 | } 250 | ul.m-category-list li a span.description { 251 | display: block ; 252 | padding: 0px 0px 0px 15px ; 253 | } 254 | ul.m-category-list li a:hover::after { 255 | display: block ; 256 | } 257 | ul.m-home-nav { 258 | height: 102px ; 259 | list-style-type: none ; 260 | margin: 30px 0px 30px 0px ; 261 | padding: 0px 0px 0px 0px ; 262 | position: relative ; 263 | } 264 | ul.m-home-nav li { 265 | background-color: #F0F0F0 ; 266 | border: 1px solid #CCCCCC ; 267 | -webkit-border-radius: 4px 4px 4px 4px; 268 | -moz-border-radius: 4px 4px 4px 4px; 269 | border-radius: 4px 4px 4px 4px; 270 | float: left ; 271 | height: 100px ; 272 | position: absolute ; 273 | text-align: center ; 274 | top: 0px ; 275 | width: 140px ; 276 | } 277 | ul.m-home-nav li a { 278 | bottom: 0px ; 279 | color: #333333 ; 280 | left: 0px ; 281 | position: absolute ; 282 | right: 0px ; 283 | text-decoration: none ; 284 | top: 0px ; 285 | } 286 | ul.m-home-nav li span.declaration { 287 | display: block ; 288 | font-size: 12px ; 289 | line-height: 17px ; 290 | padding: 18px 0px 5px 0px ; 291 | text-transform: uppercase ; 292 | } 293 | ul.m-home-nav li span.category { 294 | display: block ; 295 | font-size: 32px ; 296 | line-height: 38px ; 297 | text-decoration: underline ; 298 | } 299 | ul.m-home-nav li.cats { 300 | left: 100px ; 301 | } 302 | ul.m-home-nav li.dogs { 303 | right: 100px ; 304 | } 305 | div.m-pet-header { 306 | position: relative ; 307 | } 308 | div.m-pet-header span.back { 309 | color: #999999 ; 310 | font-size: 16px ; 311 | line-height: 27px ; 312 | position: absolute ; 313 | right: 0px ; 314 | top: 0px ; 315 | } 316 | div.m-pet-header span.back a { 317 | border-bottom: 1px dotted #999999 ; 318 | color: #999999 ; 319 | text-decoration: none ; 320 | } 321 | div.m-pet-header span.back a:hover { 322 | border-color: #333333 ; 323 | color: #333333 ; 324 | } 325 | div.m-pet-list-header { 326 | position: relative ; 327 | } 328 | div.m-pet-list-header span.back { 329 | color: #999999 ; 330 | font-size: 16px ; 331 | line-height: 27px ; 332 | position: absolute ; 333 | right: 0px ; 334 | top: 0px ; 335 | } 336 | div.m-pet-list-header span.back a { 337 | border-bottom: 1px dotted #999999 ; 338 | color: #999999 ; 339 | text-decoration: none ; 340 | } 341 | div.m-pet-list-header span.back a:hover { 342 | border-color: #333333 ; 343 | color: #333333 ; 344 | } 345 | ul.m-pet-properties { 346 | *zoom: 1; 347 | margin-bottom: 30px ; 348 | } 349 | ul.m-pet-properties:before, 350 | ul.m-pet-properties:after { 351 | display: table; 352 | content: ""; 353 | } 354 | ul.m-pet-properties:after { 355 | clear: both; 356 | } 357 | ul.m-pet-properties li { 358 | float: left ; 359 | width: 50% ; 360 | } 361 | div.m-random-pet { 362 | border-top: 1px dashed #CCCCCC ; 363 | color: #999999 ; 364 | font-size: 12px ; 365 | font-style: italic ; 366 | line-height: 17px ; 367 | padding: 15px 0px 0px 0px ; 368 | } 369 | div.m-random-pet a { 370 | color: #999999 ; 371 | } 372 | div.m-random-pet a:hover { 373 | color: #333333 ; 374 | } 375 | div.m-tabs { 376 | border-bottom: 1px solid #999999 ; 377 | *zoom: 1; 378 | margin-bottom: 15px ; 379 | padding-left: 4px ; 380 | } 381 | div.m-tabs:before, 382 | div.m-tabs:after { 383 | display: table; 384 | content: ""; 385 | } 386 | div.m-tabs:after { 387 | clear: both; 388 | } 389 | div.m-tabs a { 390 | background-color: #FFFFFF ; 391 | border: 1px solid #CCCCCC ; 392 | border-bottom-width: 0px ; 393 | -webkit-border-radius: 3px 3px 0px 0px; 394 | -moz-border-radius: 3px 3px 0px 0px; 395 | border-radius: 3px 3px 0px 0px; 396 | color: #666666 ; 397 | float: left ; 398 | margin-right: 7px ; 399 | padding: 4px 15px 4px 15px ; 400 | position: relative ; 401 | text-decoration: none ; 402 | } 403 | div.m-tabs a:hover { 404 | text-decoration: underline ; 405 | } 406 | div.m-tabs a.on { 407 | border-color: #999999 ; 408 | color: #333333 ; 409 | font-weight: bold ; 410 | padding-bottom: 5px ; 411 | margin-top: -1px; 412 | top: 1px ; 413 | } 414 | div.m-tabs a.on:hover { 415 | text-decoration: none ; 416 | } 417 | -------------------------------------------------------------------------------- /assets/app/img/header-splash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bennadel/AngularJS-Routing/50056c74f908b419cb618ea48fa09fae894ed9c3/assets/app/img/header-splash.jpg -------------------------------------------------------------------------------- /assets/app/img/header-standard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bennadel/AngularJS-Routing/50056c74f908b419cb618ea48fa09fae894ed9c3/assets/app/img/header-standard.jpg -------------------------------------------------------------------------------- /assets/app/less/category-list.less: -------------------------------------------------------------------------------- 1 | 2 | ul.m-category-list { 3 | list-style-type: none ; 4 | margin: 20px 0px 20px 0px ; 5 | padding: 0px 0px 0px 0px ; 6 | 7 | li { 8 | margin: 0px 0px 13px 0px ; 9 | padding: 0px 0px 0px 0px ; 10 | 11 | a { 12 | background-color: #F0F0F0 ; 13 | border: 1px solid #CCCCCC ; 14 | .border-radius( 4px 4px 4px 4px ) ; 15 | display: block ; 16 | height: 70px ; 17 | position: relative ; 18 | text-decoration: none ; 19 | 20 | &::after { 21 | background-color: #FFFFFF ; 22 | .border-radius( 40px 40px 40px 40px ) ; 23 | color: #333333 ; 24 | content: "\00BB" ; 25 | display: none ; 26 | font-family: Tahoma, Geneva, sans-serif ; 27 | font-size: 30px ; 28 | height: 40px ; 29 | line-height: 35px ; 30 | margin-top: -20px ; 31 | position: absolute ; 32 | right: 15px ; 33 | text-align: center ; 34 | text-index: 3px ; 35 | top: 50% ; 36 | width: 40px ; 37 | } 38 | 39 | span.name { 40 | display: block ; 41 | font-size: 18px ; 42 | font-weight: bold ; 43 | line-height: 23px ; 44 | padding: 12px 0px 3px 15px ; 45 | text-decoration: underline ; 46 | } 47 | 48 | span.description { 49 | display: block ; 50 | padding: 0px 0px 0px 15px ; 51 | } 52 | 53 | // a -- variations. 54 | 55 | &:hover { 56 | &::after { 57 | display: block ; 58 | } 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /assets/app/less/core.less: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif ; 4 | font-size: 16px ; 5 | line-height: 1.6em ; 6 | } 7 | 8 | h1, 9 | h2, 10 | h3, 11 | h4 { 12 | font-family: Georgia, serif ; 13 | } 14 | 15 | h1 { 16 | font-size: 28px ; 17 | } 18 | 19 | h2 { 20 | font-size: 24px ; 21 | } 22 | 23 | h3 { 24 | font-size: 20px ; 25 | } 26 | 27 | h4 { 28 | font-size: 16px ; 29 | } 30 | 31 | a { 32 | color: #333333 ; 33 | } -------------------------------------------------------------------------------- /assets/app/less/home-nav.less: -------------------------------------------------------------------------------- 1 | 2 | ul.m-home-nav { 3 | height: 102px ; 4 | list-style-type: none ; 5 | margin: 30px 0px 30px 0px ; 6 | padding: 0px 0px 0px 0px ; 7 | position: relative ; 8 | 9 | li { 10 | background-color: #F0F0F0 ; 11 | border: 1px solid #CCCCCC ; 12 | .border-radius( 4px 4px 4px 4px ) ; 13 | float: left ; 14 | height: 100px ; 15 | position: absolute ; 16 | text-align: center ; 17 | top: 0px ; 18 | width: 140px ; 19 | 20 | a { 21 | bottom: 0px ; 22 | color: #333333 ; 23 | left: 0px ; 24 | position: absolute ; 25 | right: 0px ; 26 | text-decoration: none ; 27 | top: 0px ; 28 | } 29 | 30 | span.declaration { 31 | display: block ; 32 | font-size: 12px ; 33 | line-height: 17px ; 34 | padding: 18px 0px 5px 0px ; 35 | text-transform: uppercase ; 36 | } 37 | 38 | span.category { 39 | display: block ; 40 | font-size: 32px ; 41 | line-height: 38px ; 42 | text-decoration: underline ; 43 | } 44 | 45 | // li -- variations 46 | 47 | &.cats { 48 | left: 100px ; 49 | } 50 | 51 | &.dogs { 52 | right: 100px ; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /assets/app/less/loading.less: -------------------------------------------------------------------------------- 1 | 2 | div.l-loading { 3 | background-color: #262626 ; 4 | bottom: 0px ; 5 | left: 0px ; 6 | position: fixed ; 7 | right: 0px ; 8 | top: 0px ; 9 | 10 | p { 11 | color: #F0F0F0 ; 12 | font-size: 12px ; 13 | font-style: italic ; 14 | left: 0px ; 15 | position: absolute ; 16 | text-align: center ; 17 | top: 48% ; 18 | width: 100% ; 19 | } 20 | } -------------------------------------------------------------------------------- /assets/app/less/main.less: -------------------------------------------------------------------------------- 1 | 2 | @import "mixins.less" ; 3 | 4 | // Reset. 5 | @import "core.less" ; 6 | 7 | // Layouts. 8 | @import "loading.less" ; 9 | @import "splash.less" ; 10 | @import "standard.less" ; 11 | 12 | // Modules. 13 | @import "category-list.less" ; 14 | @import "home-nav.less" ; 15 | @import "pet-header.less" ; 16 | @import "pet-list-header.less" ; 17 | @import "pet-properties.less" ; 18 | @import "random-pet.less" ; 19 | @import "tabs.less" ; 20 | -------------------------------------------------------------------------------- /assets/app/less/mixins.less: -------------------------------------------------------------------------------- 1 | 2 | // -- 3 | // Borrowed from Twitter Bootstrap. 4 | // -- 5 | 6 | // Clearfix 7 | .clearfix { 8 | *zoom: 1; 9 | &:before, 10 | &:after { 11 | display: table; 12 | content: ""; 13 | } 14 | &:after { 15 | clear: both; 16 | } 17 | } 18 | 19 | // Border Radius 20 | .border-radius(@radius) { 21 | -webkit-border-radius: @radius; 22 | -moz-border-radius: @radius; 23 | border-radius: @radius; 24 | } 25 | 26 | // Drop shadows 27 | .box-shadow(@shadow) { 28 | -webkit-box-shadow: @shadow; 29 | -moz-box-shadow: @shadow; 30 | box-shadow: @shadow; 31 | } 32 | 33 | // Transitions 34 | .transition(@transition) { 35 | -webkit-transition: @transition; 36 | -moz-transition: @transition; 37 | -ms-transition: @transition; 38 | -o-transition: @transition; 39 | transition: @transition; 40 | } 41 | 42 | // User select 43 | // For selecting text on the page 44 | .user-select(@select) { 45 | -webkit-user-select: @select; 46 | -moz-user-select: @select; 47 | -ms-user-select: @select; 48 | -o-user-select: @select; 49 | user-select: @select; 50 | } 51 | 52 | // Opacity 53 | .opacity(@opacity) { 54 | opacity: @opacity / 100; 55 | filter: ~"alpha(opacity=@{opacity})"; 56 | } 57 | 58 | -------------------------------------------------------------------------------- /assets/app/less/pet-header.less: -------------------------------------------------------------------------------- 1 | 2 | div.m-pet-header { 3 | position: relative ; 4 | 5 | h1 {} 6 | 7 | span.back { 8 | color: #999999 ; 9 | font-size: 16px ; 10 | line-height: 27px ; 11 | position: absolute ; 12 | right: 0px ; 13 | top: 0px ; 14 | 15 | a { 16 | border-bottom: 1px dotted #999999 ; 17 | color: #999999 ; 18 | text-decoration: none ; 19 | 20 | // a -- variations. 21 | 22 | &:hover { 23 | border-color: #333333 ; 24 | color: #333333 ; 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /assets/app/less/pet-list-header.less: -------------------------------------------------------------------------------- 1 | 2 | div.m-pet-list-header { 3 | position: relative ; 4 | 5 | h1 {} 6 | 7 | span.back { 8 | color: #999999 ; 9 | font-size: 16px ; 10 | line-height: 27px ; 11 | position: absolute ; 12 | right: 0px ; 13 | top: 0px ; 14 | 15 | a { 16 | border-bottom: 1px dotted #999999 ; 17 | color: #999999 ; 18 | text-decoration: none ; 19 | 20 | // a -- variations. 21 | 22 | &:hover { 23 | border-color: #333333 ; 24 | color: #333333 ; 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /assets/app/less/pet-properties.less: -------------------------------------------------------------------------------- 1 | 2 | ul.m-pet-properties { 3 | .clearfix ; 4 | margin-bottom: 30px ; 5 | 6 | li { 7 | float: left ; 8 | width: 50% ; 9 | } 10 | } -------------------------------------------------------------------------------- /assets/app/less/random-pet.less: -------------------------------------------------------------------------------- 1 | 2 | div.m-random-pet { 3 | border-top: 1px dashed #CCCCCC ; 4 | color: #999999 ; 5 | font-size: 12px ; 6 | font-style: italic ; 7 | line-height: 17px ; 8 | padding: 15px 0px 0px 0px ; 9 | 10 | a { 11 | color: #999999 ; 12 | 13 | // a -- variations. 14 | 15 | &:hover { 16 | color: #333333 ; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /assets/app/less/splash.less: -------------------------------------------------------------------------------- 1 | 2 | div.l-splash { 3 | margin: 30px auto 50px auto ; 4 | width: 600px ; 5 | 6 | div.l-container { 7 | .border-radius( 7px 7px 7px 7px ); 8 | .box-shadow( 0px 0px 5px 1px #666666 ) ; 9 | padding: 0px 0px 1px 0px ; 10 | } 11 | 12 | div.l-header { 13 | background: url( "../img/header-splash.jpg" ) 0px 0px no-repeat ; 14 | .border-radius( 6px 6px 0px 0px ) ; 15 | height: 305px ; 16 | position: relative ; 17 | 18 | span.title { 19 | color: #FFFFFF ; 20 | font-family: Georgia, serif ; 21 | font-size: 50px ; 22 | font-weight: bold ; 23 | line-height: 65px ; 24 | position: absolute ; 25 | right: 0px ; 26 | text-align: center ; 27 | text-shadow: 1px 1px #000000 ; 28 | top: 53px ; 29 | width: 275px ; 30 | } 31 | } 32 | 33 | div.l-body { 34 | margin: 20px 20px 20px 20px ; 35 | } 36 | 37 | div.l-footer { 38 | color: #999999 ; 39 | font-size: 11px ; 40 | line-height: 16px ; 41 | margin: 20px 20px 20px 20px ; 42 | 43 | div.description { 44 | margin-bottom: 5px ; 45 | } 46 | 47 | div.author { 48 | a { 49 | color: #999999 ; 50 | text-decoration: none ; 51 | 52 | &:hover { 53 | color: #333333 ; 54 | text-decoration: underline ; 55 | } 56 | } 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /assets/app/less/standard.less: -------------------------------------------------------------------------------- 1 | 2 | div.l-standard { 3 | margin: 30px auto 50px auto ; 4 | width: 600px ; 5 | 6 | div.l-container { 7 | .border-radius( 7px 7px 7px 7px ); 8 | .box-shadow( 0px 0px 5px 1px #666666 ) ; 9 | padding: 0px 0px 1px 0px ; 10 | } 11 | 12 | div.l-header { 13 | background: url( "../img/header-standard.jpg" ) 0px -30px no-repeat ; 14 | .border-radius( 6px 6px 0px 0px ) ; 15 | height: 157px ; 16 | position: relative ; 17 | 18 | span.title { 19 | color: #262626 ; 20 | font-family: Georgia, serif ; 21 | font-size: 46px ; 22 | font-weight: bold ; 23 | left: 20px ; 24 | line-height: 52px ; 25 | position: absolute ; 26 | text-shadow: 1px 1px rgba( 255, 255, 255, .8 ) ; 27 | top: 28px ; 28 | } 29 | 30 | ul { 31 | background-color: #F0F0F0 ; 32 | border: 1px solid #333333 ; 33 | border-width: 1px 0px 1px 0px ; 34 | bottom: 0px ; 35 | font-size: 16px ; 36 | height: 35px ; 37 | left: 0px ; 38 | list-style-type: none ; 39 | margin: 0px 0px 0px 0px ; 40 | padding: 0px 0px 0px 0px ; 41 | position: absolute ; 42 | right: 0px ; 43 | 44 | li { 45 | border-right: 1px dotted #CCCCCC ; 46 | float: left ; 47 | margin: 0px 0px 0px 0px ; 48 | padding: 0px 0px 0px 0px ; 49 | 50 | a { 51 | color: #666666 ; 52 | display: block ; 53 | height: 35px ; 54 | line-height: 35px ; 55 | text-align: center ; 56 | text-decoration: none ; 57 | width: 100px ; 58 | 59 | // a -- variations. 60 | 61 | &:hover { 62 | text-decoration: underline ; 63 | } 64 | } 65 | 66 | // li -- variations. 67 | 68 | &.on { 69 | a { 70 | background-color: #262626 ; 71 | color: #FFFFFF ; 72 | font-weight: bold ; 73 | 74 | // a -- variations. 75 | 76 | &:hover { 77 | text-decoration: none ; 78 | } 79 | } 80 | } 81 | } 82 | } 83 | } 84 | 85 | div.l-body { 86 | margin: 25px 20px 25px 20px ; 87 | } 88 | 89 | div.l-footer { 90 | color: #999999 ; 91 | font-size: 11px ; 92 | line-height: 16px ; 93 | margin: 20px 20px 20px 20px ; 94 | 95 | div.description { 96 | margin-bottom: 5px ; 97 | } 98 | 99 | div.author { 100 | a { 101 | color: #999999 ; 102 | text-decoration: none ; 103 | 104 | &:hover { 105 | color: #333333 ; 106 | text-decoration: underline ; 107 | } 108 | } 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /assets/app/less/tabs.less: -------------------------------------------------------------------------------- 1 | 2 | div.m-tabs { 3 | border-bottom: 1px solid #999999 ; 4 | .clearfix ; 5 | margin-bottom: 15px ; 6 | padding-left: 4px ; 7 | 8 | a { 9 | background-color: #FFFFFF ; 10 | border: 1px solid #CCCCCC ; 11 | border-bottom-width: 0px ; 12 | .border-radius( 3px 3px 0px 0px ) ; 13 | color: #666666 ; 14 | float: left ; 15 | margin-right: 7px ; 16 | padding: 4px 15px 4px 15px ; 17 | position: relative ; 18 | text-decoration: none ; 19 | 20 | // a -- variations. 21 | 22 | &:hover { 23 | text-decoration: underline ; 24 | } 25 | 26 | &.on { 27 | border-color: #999999 ; 28 | color: #333333 ; 29 | font-weight: bold ; 30 | padding-bottom: 5px ; 31 | margin-top: -1px ; 32 | top: 1px ; 33 | 34 | // a.on -- variations. 35 | 36 | &:hover { 37 | text-decoration: none ; 38 | } 39 | } 40 | } 41 | } 42 | 43 | div.m-tab-pane {} -------------------------------------------------------------------------------- /assets/app/main.js: -------------------------------------------------------------------------------- 1 | 2 | // Create an application module for our demo. 3 | var Demo = angular.module( "Demo", [] ); 4 | 5 | // Configure the routing. The $routeProvider will be automatically injected into 6 | // the configurator. 7 | Demo.config( 8 | function( $routeProvider ){ 9 | 10 | // Typically, when defining routes, you will map the route to a Template to be 11 | // rendered; however, this only makes sense for simple web sites. When you are 12 | // building more complex applications, with nested navigation, you probably need 13 | // something more complex. In this case, we are mapping routes to render "Actions" 14 | // rather than a template. 15 | $routeProvider 16 | .when( 17 | "/home", 18 | { 19 | action: "splash.home" 20 | } 21 | ) 22 | .when( 23 | "/pets", 24 | { 25 | action: "standard.pets.categories" 26 | } 27 | ) 28 | .when( 29 | "/pets/:categoryID", 30 | { 31 | action: "standard.pets.list" 32 | } 33 | ) 34 | .when( 35 | "/pets/:categoryID/:petID", 36 | { 37 | action: "standard.pets.detail.background" 38 | } 39 | ) 40 | .when( 41 | "/pets/:categoryID/:petID/diet", 42 | { 43 | action: "standard.pets.detail.diet" 44 | } 45 | ) 46 | .when( 47 | "/pets/:categoryID/:petID/medical-history", 48 | { 49 | action: "standard.pets.detail.medicalHistory" 50 | } 51 | ) 52 | .when( 53 | "/contact", 54 | { 55 | action: "standard.contact" 56 | } 57 | ) 58 | .otherwise( 59 | { 60 | redirectTo: "/home" 61 | } 62 | ) 63 | ; 64 | 65 | } 66 | ); 67 | -------------------------------------------------------------------------------- /assets/app/services/category-service.js: -------------------------------------------------------------------------------- 1 | (function( ng, app ) { 2 | 3 | "use strict"; 4 | 5 | // I provide a repository for the categories. 6 | app.service( 7 | "categoryService", 8 | function( $q, _ ) { 9 | 10 | 11 | // I get all of the categories. 12 | function getCategories() { 13 | 14 | var deferred = $q.defer(); 15 | 16 | deferred.resolve( ng.copy( cache ) ); 17 | 18 | return( deferred.promise ); 19 | 20 | } 21 | 22 | 23 | // I get the category with the given ID. 24 | function getCategoryByID( id ) { 25 | 26 | var deferred = $q.defer(); 27 | var category = _.findWithProperty( cache, "id", id ); 28 | 29 | if ( category ) { 30 | 31 | deferred.resolve( ng.copy( category ) ); 32 | 33 | } else { 34 | 35 | deferred.reject(); 36 | 37 | } 38 | 39 | return( deferred.promise ); 40 | 41 | } 42 | 43 | 44 | // ---------------------------------------------- // 45 | // ---------------------------------------------- // 46 | 47 | 48 | // Set up the categories data cache. For this demo, we'll just use static data. 49 | var cache = [ 50 | { 51 | id: "cats", 52 | name: "Cats", 53 | description: "Cats are graceful and cunning." 54 | }, 55 | { 56 | id: "dogs", 57 | name: "Dogs", 58 | description: "Dogs are super awesome and adorable." 59 | } 60 | ]; 61 | 62 | 63 | // ---------------------------------------------- // 64 | // ---------------------------------------------- // 65 | 66 | 67 | // Return the public API. 68 | return({ 69 | getCategories: getCategories, 70 | getCategoryByID: getCategoryByID 71 | }); 72 | 73 | 74 | } 75 | ); 76 | 77 | })( angular, Demo ); -------------------------------------------------------------------------------- /assets/app/services/lodash.js: -------------------------------------------------------------------------------- 1 | (function( ng, app, _ ) { 2 | 3 | "use strict"; 4 | 5 | // I provide an augmented lodash library. 6 | app.factory( 7 | "_", 8 | function() { 9 | 10 | 11 | // I filter the collection down to items with the given property value. 12 | _.filterWithProperty = function( collection, name, value ) { 13 | 14 | var result = _.filter( 15 | collection, 16 | function( item ) { 17 | 18 | return( item[ name ] === value ); 19 | 20 | } 21 | ); 22 | 23 | return( result ); 24 | 25 | }; 26 | 27 | 28 | // I find the first collection item with the given property value. 29 | _.findWithProperty = function( collection, name, value ) { 30 | 31 | var result = _.find( 32 | collection, 33 | function( item ) { 34 | 35 | return( item[ name ] === value ); 36 | 37 | } 38 | ); 39 | 40 | return( result ); 41 | 42 | }; 43 | 44 | 45 | // I sort the collection on the given property. 46 | _.sortOnProperty = function( collection, name, direction ) { 47 | 48 | var indicator = ( ( direction.toLowerCase() === "asc" ) ? -1 : 1 ); 49 | 50 | collection.sort( 51 | function( a, b ) { 52 | 53 | if ( a[ name ] < b[ name ] ) { 54 | 55 | return( indicator ); 56 | 57 | } else if ( a[ name ] > b[ name ] ) { 58 | 59 | return( - indicator ); 60 | 61 | } 62 | 63 | return( 0 ); 64 | 65 | } 66 | ); 67 | 68 | return( collection ); 69 | 70 | }; 71 | 72 | 73 | // ---------------------------------------------- // 74 | // ---------------------------------------------- // 75 | 76 | 77 | // Return the public API. 78 | return( _ ); 79 | 80 | 81 | } 82 | ); 83 | 84 | })( angular, Demo, _.noConflict() ); 85 | // Release the global reference to the lodash library. This way, we make sure that everyone goes 86 | // through our service object in order to get to the utility library. -------------------------------------------------------------------------------- /assets/app/services/pet-service.js: -------------------------------------------------------------------------------- 1 | (function( ng, app ) { 2 | 3 | "use strict"; 4 | 5 | // I provide a repository for the pets. 6 | app.service( 7 | "petService", 8 | function( $q, _ ) { 9 | 10 | 11 | // I get the pet with the given ID. 12 | function getPetByID( id ) { 13 | 14 | var deferred = $q.defer(); 15 | var pet = _.findWithProperty( cache, "id", id ); 16 | 17 | if ( pet ) { 18 | 19 | deferred.resolve( ng.copy( pet ) ); 20 | 21 | } else { 22 | 23 | deferred.reject(); 24 | 25 | } 26 | 27 | return( deferred.promise ); 28 | 29 | } 30 | 31 | 32 | // I get the pets in the given category. 33 | function getPetsByCategoryID( categoryID ) { 34 | 35 | var deferred = $q.defer(); 36 | var pets = _.filterWithProperty( cache, "categoryID", categoryID ); 37 | 38 | if ( pets ) { 39 | 40 | deferred.resolve( ng.copy( pets ) ); 41 | 42 | } else { 43 | 44 | deferred.reject(); 45 | 46 | } 47 | 48 | return( deferred.promise ); 49 | 50 | } 51 | 52 | 53 | // I get a random pet in the given category, less the given pet. 54 | function getRandomPetExcluding( categoryID, excludePetID ) { 55 | 56 | var deferred = $q.defer(); 57 | var pets = _.filterWithProperty( cache, "categoryID", categoryID ); 58 | 59 | if ( pets ) { 60 | 61 | var index = _.random( 0, ( pets.length - 1 ) ); 62 | 63 | while ( pets[ index ].id === excludePetID ) { 64 | 65 | index = _.random( 0, ( pets.length - 1 ) ); 66 | 67 | } 68 | 69 | deferred.resolve( ng.copy( pets[ index ] ) ); 70 | 71 | } else { 72 | 73 | deferred.reject(); 74 | 75 | } 76 | 77 | return( deferred.promise ); 78 | 79 | } 80 | 81 | 82 | // ---------------------------------------------- // 83 | // ---------------------------------------------- // 84 | 85 | 86 | // Set up a collection of constants for our pet categories. Normally, this would be managed 87 | // by the server-side relational database; but, since we're using static data, this will 88 | // just make the code easier to read. 89 | var categories = { 90 | cats: "cats", 91 | dogs: "dogs" 92 | }; 93 | 94 | // Set up a collection of size constants. 95 | var sizes = { 96 | small: "Small, 25 lbs or less", 97 | medium: "Medium, 26 - 60 lbs", 98 | large: "Large, 61 - 100 lbs", 99 | huge: "Huge, more than 100 lbs" 100 | }; 101 | 102 | // Set up the pets data cache. For this demo, we'll just use static data. 103 | var cache = [ 104 | { 105 | id: 1, 106 | categoryID: categories.dogs, 107 | name: "Annie", 108 | breed: "Pit Bull Terrier", 109 | color: "Tricolor", 110 | sex: "F", 111 | size: sizes.small, 112 | description: "I love chewing on shoes.", 113 | background: "Annie was found in an abandoned house in Brooklyn.", 114 | diet: "Annie loves raw chicken necks.", 115 | medicalHistory: "Annie has all of her shots." 116 | }, 117 | { 118 | id: 2, 119 | categoryID: categories.dogs, 120 | name: "Voodoo", 121 | breed: "Chihuahua", 122 | color: "White With Black", 123 | sex: "F", 124 | size: sizes.small, 125 | description: "I am house-trained, but when I get excited, I sometimes tinkle.", 126 | background: "Voodoo was one of 17 dogs found in a hoarder's house.", 127 | diet: "Voodoo will eat just about anything.", 128 | medicalHistory: "Voodoo has all of his shots and is spayed." 129 | }, 130 | { 131 | id: 3, 132 | categoryID: categories.dogs, 133 | name: "Frodo", 134 | breed: "Yorkie", 135 | color: "Silver With Blue", 136 | sex: "F", 137 | size: sizes.small, 138 | description: "I want to lick your face ... a lot.", 139 | background: "Frodo went on a great adventure!", 140 | diet: "Frodo loves chicken and fish and peanut butter.", 141 | medicalHistory: "Frodo has all of his shots." 142 | }, 143 | { 144 | id: 4, 145 | categoryID: categories.dogs, 146 | name: "Brook", 147 | breed: "Labrador Retriever", 148 | color: "Yellow", 149 | sex: "M", 150 | size: sizes.large, 151 | description: "I'll eat anything, but newspaper makes me gassy.", 152 | background: "Brook was found walking along George Washington Bridge.", 153 | diet: "Brook loves any duck-based food.", 154 | medicalHistory: "Brook has all of her shots." 155 | }, 156 | { 157 | id: 5, 158 | categoryID: categories.dogs, 159 | name: "Henry", 160 | breed: "Bulldog", 161 | color: "Tricolor", 162 | sex: "M", 163 | size: sizes.medium, 164 | description: "I'm surprisingly active and can jump!", 165 | background: "Henry's owner recently passed and was left with no family.", 166 | diet: "Henry prefers dry food.", 167 | medicalHistory: "Henry has all of his shots and is fixed." 168 | }, 169 | { 170 | id: 6, 171 | categoryID: categories.cats, 172 | name: "Marley", 173 | breed: "Scottish Fold", 174 | color: "White", 175 | sex: "F", 176 | size: sizes.small, 177 | description: "I can climb walls like a ninja!", 178 | background: "Marley was found in an abandoned lot in Brooklyn.", 179 | diet: "Marley prefers wet food.", 180 | medicalHistory: "Marley has all of her shots and is spayed." 181 | }, 182 | { 183 | id: 7, 184 | categoryID: categories.cats, 185 | name: "Jamie", 186 | breed: "Calico", 187 | color: "Tricolor", 188 | sex: "F", 189 | size: sizes.small, 190 | description: "I'm extremely people friend, for a cat.", 191 | background: "Jamie was found under the porch.", 192 | diet: "Jamie can't stand wet food.", 193 | medicalHistory: "Jamie has all of her shots and need to be spayed." 194 | }, 195 | { 196 | id: 8, 197 | categoryID: categories.cats, 198 | name: "Bruno", 199 | breed: "Uknown", 200 | color: "Black", 201 | sex: "M", 202 | size: sizes.small, 203 | description: "I'm an escape artist.", 204 | background: "When found, Bruno was under-nourished.", 205 | diet: "Bruno loves milk and anything chicken-based.", 206 | medicalHistory: "Bruno has all of his shots and is fixed." 207 | }, 208 | { 209 | id: 9, 210 | categoryID: categories.cats, 211 | name: "Wiggles", 212 | breed: "Burmese", 213 | color: "Gray", 214 | sex: "M", 215 | size: sizes.small, 216 | description: "I love lasers and chasing my own tail.", 217 | background: "Wiggles was a feral cat known for his jumping.", 218 | diet: "Wiggles has no specific dietary information.", 219 | medicalHistory: "Wiggles has all of his shots." 220 | }, 221 | { 222 | id: 10, 223 | categoryID: categories.cats, 224 | name: "Cotton", 225 | breed: "Himalayan", 226 | color: "Tan With Black", 227 | sex: "F", 228 | size: sizes.small, 229 | description: "I love to cuddle at night.", 230 | background: "Cotton's owner recently passed.", 231 | diet: "Cotton will eat just about anything.", 232 | medicalHistory: "Cotton has all of her shots and needs to be fixed." 233 | } 234 | ]; 235 | 236 | 237 | // ---------------------------------------------- // 238 | // ---------------------------------------------- // 239 | 240 | 241 | // Return the public API. 242 | return({ 243 | getPetByID: getPetByID, 244 | getPetsByCategoryID: getPetsByCategoryID, 245 | getRandomPetExcluding: getRandomPetExcluding 246 | }); 247 | 248 | 249 | } 250 | ); 251 | 252 | })( angular, Demo ); -------------------------------------------------------------------------------- /assets/app/services/request-context.js: -------------------------------------------------------------------------------- 1 | (function( ng, app ) { 2 | 3 | "use strict"; 4 | 5 | // I provide information about the current route request. 6 | app.service( 7 | "requestContext", 8 | function( RenderContext ) { 9 | 10 | 11 | // I get the current action. 12 | function getAction() { 13 | 14 | return( action ); 15 | 16 | } 17 | 18 | 19 | // I get the next section at the given location on the action path. 20 | function getNextSection( prefix ) { 21 | 22 | // Make sure the prefix is actually in the current action. 23 | if ( ! startsWith( prefix ) ) { 24 | 25 | return( null ); 26 | 27 | } 28 | 29 | // If the prefix is empty, return the first section. 30 | if ( prefix === "" ) { 31 | 32 | return( sections[ 0 ] ); 33 | 34 | } 35 | 36 | // Now that we know the prefix is valid, lets figure out the depth 37 | // of the current path. 38 | var depth = prefix.split( "." ).length; 39 | 40 | // If the depth is out of bounds, meaning the current action doesn't 41 | // define sections to that path (they are equal), then return null. 42 | if ( depth === sections.length ) { 43 | 44 | return( null ); 45 | 46 | } 47 | 48 | // Return the section. 49 | return( sections[ depth ] ); 50 | 51 | } 52 | 53 | 54 | // I return the param with the given name, or the default value (or null). 55 | function getParam( name, defaultValue ) { 56 | 57 | if ( ng.isUndefined( defaultValue ) ) { 58 | 59 | defaultValue = null; 60 | 61 | } 62 | 63 | return( params[ name ] || defaultValue ); 64 | 65 | } 66 | 67 | 68 | // I return the param as an int. If the param cannot be returned as an 69 | // int, the given default value is returned. If no default value is 70 | // defined, the return will be zero. 71 | function getParamAsInt( name, defaultValue ) { 72 | 73 | // Try to parse the number. 74 | var valueAsInt = ( this.getParam( name, defaultValue || 0 ) * 1 ); 75 | 76 | // Check to see if the coersion failed. If so, return the default. 77 | if ( isNaN( valueAsInt ) ) { 78 | 79 | return( defaultValue || 0 ); 80 | 81 | } else { 82 | 83 | return( valueAsInt ); 84 | 85 | } 86 | 87 | } 88 | 89 | 90 | // I return the render context for the given action prefix and sub-set of 91 | // route params. 92 | function getRenderContext( requestActionLocation, paramNames ) { 93 | 94 | // Default the requestion action. 95 | requestActionLocation = ( requestActionLocation || "" ); 96 | 97 | // Default the param names. 98 | paramNames = ( paramNames || [] ); 99 | 100 | // The param names can be passed in as a single name; or, as an array 101 | // of names. If a single name was provided, let's convert it to the array. 102 | if ( ! ng.isArray( paramNames ) ) { 103 | 104 | paramNames = [ paramNames ]; 105 | 106 | } 107 | 108 | return( 109 | new RenderContext( this, requestActionLocation, paramNames ) 110 | ); 111 | 112 | } 113 | 114 | 115 | // I determine if the action has changed in this particular request context. 116 | function hasActionChanged() { 117 | 118 | return( action !== previousAction ); 119 | 120 | } 121 | 122 | 123 | // I determine if the given param has changed in this particular request 124 | // context. This change comparison can be made against a specific value 125 | // (paramValue); or, if only the param name is defined, the comparison will 126 | // be made agains the previous snapshot. 127 | function hasParamChanged( paramName, paramValue ) { 128 | 129 | // If the param value exists, then we simply want to use that to compare 130 | // against the current snapshot. 131 | if ( ! ng.isUndefined( paramValue ) ) { 132 | 133 | return( ! isParam( paramName, paramValue ) ); 134 | 135 | } 136 | 137 | // If the param was NOT in the previous snapshot, then we'll consider 138 | // it changing. 139 | if ( 140 | ! previousParams.hasOwnProperty( paramName ) && 141 | params.hasOwnProperty( paramName ) 142 | ) { 143 | 144 | return( true ); 145 | 146 | // If the param was in the previous snapshot, but NOT in the current, 147 | // we'll consider it to be changing. 148 | } else if ( 149 | previousParams.hasOwnProperty( paramName ) && 150 | ! params.hasOwnProperty( paramName ) 151 | ) { 152 | 153 | return( true ); 154 | 155 | } 156 | 157 | // If we made it this far, the param existence has not change; as such, 158 | // let's compare their actual values. 159 | return( previousParams[ paramName ] !== params[ paramName ] ); 160 | 161 | } 162 | 163 | 164 | // I determine if any of the given params have changed in this particular 165 | // request context. 166 | function haveParamsChanged( paramNames ) { 167 | 168 | for ( var i = 0, length = paramNames.length ; i < length ; i++ ) { 169 | 170 | if ( hasParamChanged( paramNames[ i ] ) ) { 171 | 172 | // If one of the params has changed, return true - no need to 173 | // continue checking the other parameters. 174 | return( true ); 175 | 176 | } 177 | 178 | } 179 | 180 | // If we made it this far then none of the params have changed. 181 | return( false ); 182 | 183 | } 184 | 185 | 186 | // I check to see if the given param is still the given value. 187 | function isParam( paramName, paramValue ) { 188 | 189 | // When comparing, using the coersive equals since we may be comparing 190 | // parsed value against non-parsed values. 191 | if ( 192 | params.hasOwnProperty( paramName ) && 193 | ( params[ paramName ] == paramValue ) 194 | ) { 195 | 196 | return( true ); 197 | 198 | } 199 | 200 | // If we made it this far then param is either a different value; or, 201 | // is no longer available in the route. 202 | return( false ); 203 | 204 | } 205 | 206 | 207 | // I set the new request context conditions. 208 | function setContext( newAction, newRouteParams ) { 209 | 210 | // Copy the current action and params into the previous snapshots. 211 | previousAction = action; 212 | previousParams = params; 213 | 214 | // Set the action. 215 | action = newAction; 216 | 217 | // Split the action to determine the sections. 218 | sections = action.split( "." ); 219 | 220 | // Update the params collection. 221 | params = ng.copy( newRouteParams ); 222 | 223 | } 224 | 225 | 226 | // I determine if the current action starts with the given path. 227 | function startsWith( prefix ) { 228 | 229 | // When checking, we want to make sure we don't match partial sections for false 230 | // positives. So, either it matches in entirety; or, it matches with an additional 231 | // dot at the end. 232 | if ( 233 | ! prefix.length || 234 | ( action === prefix ) || 235 | ( action.indexOf( prefix + "." ) === 0 ) 236 | ) { 237 | 238 | return( true ); 239 | 240 | } 241 | 242 | return( false ); 243 | 244 | } 245 | 246 | 247 | // ---------------------------------------------- // 248 | // ---------------------------------------------- // 249 | 250 | 251 | // Store the current action path. 252 | var action = ""; 253 | 254 | // Store the action as an array of parts so we can more easily examine 255 | // parts of it. 256 | var sections = []; 257 | 258 | // Store the current route params. 259 | var params = {}; 260 | 261 | // Store the previous action and route params. We'll use these to make 262 | // a comparison from one route change to the next. 263 | var previousAction = ""; 264 | var previousParams = {}; 265 | 266 | 267 | // ---------------------------------------------- // 268 | // ---------------------------------------------- // 269 | 270 | 271 | // Return the public API. 272 | return({ 273 | getNextSection: getNextSection, 274 | getParam: getParam, 275 | getParamAsInt: getParamAsInt, 276 | getRenderContext: getRenderContext, 277 | hasActionChanged: hasActionChanged, 278 | hasParamChanged: hasParamChanged, 279 | haveParamsChanged: haveParamsChanged, 280 | isParam: isParam, 281 | setContext: setContext, 282 | startsWith: startsWith 283 | }); 284 | 285 | 286 | } 287 | ); 288 | 289 | })( angular, Demo ); -------------------------------------------------------------------------------- /assets/app/views/contact/index.htm: -------------------------------------------------------------------------------- 1 | 2 |
10 | Praesent imperdiet nibh a tellus pharetra vitae blandit dui euismod. Donec arcu mauris, 11 | porta non lobortis id, ultrices eget metus. Curabitur pretium diam eget dui iaculis 12 | ullamcorper. Ut vitae tortor ligula. Morbi hendrerit arcu tempor mauris aliquam tincidunt. 13 | Nam vestibulum malesuada leo a rhoncus. Integer metus risus, accumsan eget congue quis, 14 | porttitor a sem. Quisque mollis elit eu nisi mollis ac porta nunc elementum. 15 |
16 | 17 | 18 |10 | We place needy, abused, and abandoned animals in safe homes with loving people. Some of 11 | these guys need a little extra love and a little extra care. But, in the end, you're 12 | guaranteed to find yourself with a brand-new best friend! 13 |
14 | 15 |35 | Every adoption changes a life! 36 |
37 | 38 | 39 |25 | There's no doubt that both cats and dogs are adorable, in their own right. 26 | But, you gotta find the one that's right for you! 27 |
28 | 29 | 30 |6 | {{ pet.background }} 7 | 8 | Cras porttitor lorem eu diam eleifend mollis. Ut aliquam suscipit tellus, sit amet tincidunt 9 | dui bibendum quis. Aenean molestie, nulla quis viverra sollicitudin, justo orci consectetur 10 | lectus, nec scelerisque magna erat ut mauris. 11 |
12 | 13 | 14 |6 | {{ pet.diet }} 7 | 8 | Nunc sapien neque, adipiscing eu tincidunt sit amet, venenatis sed libero. Cras dictum lacus 9 | in augue blandit hendrerit. Nulla quam mauris, viverra quis rhoncus aliquet, dapibus vitae 10 | orci. Pellentesque odio massa, scelerisque eu viverra nec, vulputate eget massa. 11 |
12 | 13 | 14 |33 | {{ pet.description }} 34 |
35 | 36 |6 | {{ pet.medicalHistory }} 7 | 8 | Quisque sit amet pretium nulla. Vestibulum at varius justo. Aenean sodales tristique luctus. 9 | Donec sollicitudin eros sagittis lacus pretium porta. 10 |
11 | 12 | 13 |33 | {{ category.description }} 34 |
35 | 36 |z.priority)break;if(Y=z.scope)M("isolated scope",C,z,y),L(Y)&&(q(y,"ng-isolate-scope"),C=z),q(y,"ng-scope"),s=s||z;H=z.name;if(Y=z.controller)t=t||{},M("'"+H+"' controller",t[H],z,y),t[H]=z;if(Y=z.transclude)M("transclusion",D,z,y),D=z,n=z.priority,Y=="element"?(X=u(b),y=c.$$element=u("<\!-- "+H+": "+c[H]+" --\>"),b=y[0],Ga(e,u(X[0]),b),v=w(X,d,n)):(X=u(cb(b)).contents(),y.html(""),v=w(X,d));if(Y=z.template)if(M("template",A,z,y),A=z,Y=Ha(Y),z.replace){X=u(""+R(Y)+"").contents(); 44 | b=X[0];if(X.length!=1||b.nodeType!==1)throw new B(g+Y);Ga(e,y,b);H={$attr:{}};a=a.concat(O(b,a.splice(E+1,a.length-(E+1)),H));K(c,H);G=a.length}else y.html(Y);if(z.templateUrl)M("template",A,z,y),A=z,j=W(a.splice(E,a.length-E),j,y,c,e,z.replace,v),G=a.length;else if(z.compile)try{x=z.compile(y,c,v),N(x)?f(null,x):x&&f(x.pre,x.post)}catch(I){k(I,pa(y))}if(z.terminal)j.terminal=!0,n=Math.max(n,z.priority)}j.scope=s&&s.scope;j.transclude=D&&v;return j}function A(d,e,g,h){var j=!1;if(a.hasOwnProperty(e))for(var n, 45 | e=b.get(e+c),o=0,l=e.length;on.priority)&&n.restrict.indexOf(g)!=-1)d.push(n),j=!0}catch(r){k(r)}return j}function K(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;m(a,function(d,e){e.charAt(0)!="$"&&(b[e]&&(d+=(e==="style"?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});m(b,function(b,f){f=="class"?(q(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):f=="style"?e.attr("style",e.attr("style")+";"+b):f.charAt(0)!="$"&&!a.hasOwnProperty(f)&&(a[f]=b,d[f]=c[f])})}function W(a,b,c,d,e, 46 | f,k){var h=[],n,o,r=c[0],q=a.shift(),w=x({},q,{controller:null,templateUrl:null,transclude:null,scope:null});c.html("");j.get(q.templateUrl,{cache:l}).success(function(j){var l,q,j=Ha(j);if(f){q=u(" "+R(j)+"").contents();l=q[0];if(q.length!=1||l.nodeType!==1)throw new B(g+j);j={$attr:{}};Ga(e,c,l);O(l,a,j);K(d,j)}else l=r,c.html(j);a.unshift(w);n=C(a,c,d,k);for(o=s(c.contents(),k);h.length;){var ba=h.pop(),j=h.pop();q=h.pop();var y=h.pop(),m=l;q!==r&&(m=cb(l),Ga(j,u(q),m));n(function(){b(o, 47 | y,m,e,ba)},y,m,e,ba)}h=null}).error(function(a,b,c,d){throw B("Failed to load template: "+d.url);});return function(a,c,d,e,f){h?(h.push(c),h.push(d),h.push(e),h.push(f)):n(function(){b(o,c,d,e,f)},c,d,e,f)}}function y(a,b){return b.priority-a.priority}function M(a,b,c,d){if(b)throw B("Multiple directives ["+b.name+", "+c.name+"] asking for "+a+" on: "+pa(d));}function H(a,b){var c=h(b,!0);c&&a.push({priority:0,compile:I(function(a,b){var d=b.parent(),e=d.data("$binding")||[];e.push(c);q(d.data("$binding", 48 | e),"ng-binding");a.$watch(c,function(a){b[0].nodeValue=a})})})}function X(a,b,c,d){var e=h(c,!0);e&&b.push({priority:100,compile:I(function(a,b,c){b=c.$$observers||(c.$$observers={});d==="class"&&(e=h(c[d],!0));c[d]=p;(b[d]||(b[d]=[])).$$inter=!0;(c.$$observers&&c.$$observers[d].$$scope||a).$watch(e,function(a){c.$set(d,a)})})})}function Ga(a,b,c){var d=b[0],e=d.parentNode,f,g;if(a){f=0;for(g=a.length;f0){var e=M[0],f=e.text;if(f==a||f==b||f==c||f==d||!a&&!b&&!c&&!d)return e}return!1}function f(b,c,d,f){return(b=i(b,c,d,f))?(a&&!b.json&&e("is not valid json",b),M.shift(),b):!1}function h(a){f(a)||e("is unexpected, expecting ["+a+"]",i())}function k(a,b){return function(c,d){return a(c,d,b)}}function j(a,b,c){return function(d,e){return b(d,e,a,c)}}function l(){for(var a=[];;)if(M.length>0&&!i("}",")",";","]")&&a.push(v()),!f(";"))return a.length==1?a[0]:function(b,c){for(var d, 67 | e=0;e ","<=",">="))a=j(a,b.fn,q());return a}function s(){for(var a=m(),b;b=f("*","/","%");)a=j(a,b.fn,m());return a}function m(){var a;return f("+")?C():(a=f("-"))?j(W,a.fn,m()):(a=f("!"))?k(a.fn,m()):C()}function C(){var a;if(f("("))a=v(),h(")");else if(f("["))a=A();else if(f("{"))a=K();else{var b=f();(a=b.fn)||e("not a primary expression",b)}for(var c;b=f("(","[",".");)b.text==="("?(a=u(a,c),c=null):b.text==="["?(c=a,a=ea(a)):b.text==="."?(c=a,a=t(a)):e("IMPOSSIBLE"); 69 | return a}function A(){var a=[];if(g().text!="]"){do a.push(H());while(f(","))}h("]");return function(b,c){for(var d=[],e=0;e 1;d++){var e=a.shift(),g= 72 | b[e];g||(g={},b[e]=g);b=g}return b[a.shift()]=c}function fb(b,a,c){if(!a)return b;for(var a=a.split("."),d,e=b,g=a.length,i=0;i 7),hasEvent:function(c){if(c=="input"&&aa==9)return!1;if(t(a[c])){var e=b.document.createElement("div");a[c]="on"+c in e}return a[c]},csp:!1}}]}function Uc(){this.$get=I(U)}function Mb(b){var a={},c,d,e;if(!b)return a;m(b.split("\n"),function(b){e=b.indexOf(":");c=E(R(b.substr(0, 90 | e)));d=R(b.substr(e+1));c&&(a[c]?a[c]+=", "+d:a[c]=d)});return a}function Nb(b){var a=L(b)?b:p;return function(c){a||(a=Mb(b));return c?a[E(c)]||null:a}}function Ob(b,a,c){if(N(c))return c(b,a);m(c,function(c){b=c(b,a)});return b}function Vc(){var b=/^\s*(\[|\{[^\{])/,a=/[\}\]]\s*$/,c=/^\)\]\}',?\n/,d=this.defaults={transformResponse:[function(d){F(d)&&(d=d.replace(c,""),b.test(d)&&a.test(d)&&(d=nb(d,!0)));return d}],transformRequest:[function(a){return L(a)&&Sa.apply(a)!=="[object File]"?da(a):a}], 91 | headers:{common:{Accept:"application/json, text/plain, */*","X-Requested-With":"XMLHttpRequest"},post:{"Content-Type":"application/json;charset=utf-8"},put:{"Content-Type":"application/json;charset=utf-8"}}},e=this.responseInterceptors=[];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(a,b,c,h,k,j){function l(a){function c(a){var b=x({},a,{data:Ob(a.data,a.headers,f)});return 200<=a.status&&a.status<300?b:k.reject(b)}a.method=la(a.method);var e=a.transformRequest|| 92 | d.transformRequest,f=a.transformResponse||d.transformResponse,h=d.headers,h=x({"X-XSRF-TOKEN":b.cookies()["XSRF-TOKEN"]},h.common,h[E(a.method)],a.headers),e=Ob(a.data,Nb(h),e),g;t(a.data)&&delete h["Content-Type"];g=o(a,e,h);g=g.then(c,c);m(w,function(a){g=a(g)});g.success=function(b){g.then(function(c){b(c.data,c.status,c.headers,a)});return g};g.error=function(b){g.then(null,function(c){b(c.data,c.status,c.headers,a)});return g};return g}function o(b,c,d){function e(a,b,c){m&&(200<=a&&a<300?m.put(w, 93 | [a,b,Mb(c)]):m.remove(w));f(b,a,c);h.$apply()}function f(a,c,d){c=Math.max(c,0);(200<=c&&c<300?j.resolve:j.reject)({data:a,status:c,headers:Nb(d),config:b})}function i(){var a=za(l.pendingRequests,b);a!==-1&&l.pendingRequests.splice(a,1)}var j=k.defer(),o=j.promise,m,p,w=r(b.url,b.params);l.pendingRequests.push(b);o.then(i,i);b.cache&&b.method=="GET"&&(m=L(b.cache)?b.cache:n);if(m)if(p=m.get(w))if(p.then)return p.then(i,i),p;else J(p)?f(p[1],p[0],V(p[2])):f(p,200,{});else m.put(w,o);p||a(b.method, 94 | w,c,e,d,b.timeout,b.withCredentials);return o}function r(a,b){if(!b)return a;var c=[];ec(b,function(a,b){a==null||a==p||(L(a)&&(a=da(a)),c.push(encodeURIComponent(b)+"="+encodeURIComponent(a)))});return a+(a.indexOf("?")==-1?"?":"&")+c.join("&")}var n=c("$http"),w=[];m(e,function(a){w.push(F(a)?j.get(a):j.invoke(a))});l.pendingRequests=[];(function(a){m(arguments,function(a){l[a]=function(b,c){return l(x(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){m(arguments,function(a){l[a]= 95 | function(b,c,d){return l(x(d||{},{method:a,url:b,data:c}))}})})("post","put");l.defaults=d;return l}]}function Wc(){this.$get=["$browser","$window","$document",function(b,a,c){return Xc(b,Yc,b.defer,a.angular.callbacks,c[0],a.location.protocol.replace(":",""))}]}function Xc(b,a,c,d,e,g){function i(a,b){var c=e.createElement("script"),d=function(){e.body.removeChild(c);b&&b()};c.type="text/javascript";c.src=a;aa?c.onreadystatechange=function(){/loaded|complete/.test(c.readyState)&&d()}:c.onload=c.onerror= 96 | d;e.body.appendChild(c)}return function(e,h,k,j,l,o,r){function n(a,c,d,e){c=(h.match(Fb)||["",g])[1]=="file"?d?200:404:c;a(c==1223?204:c,d,e);b.$$completeOutstandingRequest(D)}b.$$incOutstandingRequestCount();h=h||b.url();if(E(e)=="jsonp"){var p="_"+(d.counter++).toString(36);d[p]=function(a){d[p].data=a};i(h.replace("JSON_CALLBACK","angular.callbacks."+p),function(){d[p].data?n(j,200,d[p].data):n(j,-2);delete d[p]})}else{var q=new a;q.open(e,h,!0);m(l,function(a,b){a&&q.setRequestHeader(b,a)}); 97 | var s;q.onreadystatechange=function(){q.readyState==4&&n(j,s||q.status,q.responseText,q.getAllResponseHeaders())};if(r)q.withCredentials=!0;q.send(k||"");o>0&&c(function(){s=-1;q.abort()},o)}}}function Zc(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"}, 98 | DATETIME_FORMATS:{MONTH:"January,February,March,April,May,June,July,August,September,October,November,December".split(","),SHORTMONTH:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(","),DAY:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),SHORTDAY:"Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(","),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a", 99 | shortTime:"h:mm a"},pluralCat:function(b){return b===1?"one":"other"}}}}function $c(){this.$get=["$rootScope","$browser","$q","$exceptionHandler",function(b,a,c,d){function e(e,f,h){var k=c.defer(),j=k.promise,l=v(h)&&!h,f=a.defer(function(){try{k.resolve(e())}catch(a){k.reject(a),d(a)}l||b.$apply()},f),h=function(){delete g[j.$$timeoutId]};j.$$timeoutId=f;g[f]=k;j.then(h,h);return j}var g={};e.cancel=function(b){return b&&b.$$timeoutId in g?(g[b.$$timeoutId].reject("canceled"),a.defer.cancel(b.$$timeoutId)): 100 | !1};return e}]}function Pb(b){function a(a,e){return b.factory(a+c,e)}var c="Filter";this.register=a;this.$get=["$injector",function(a){return function(b){return a.get(b+c)}}];a("currency",Qb);a("date",Rb);a("filter",ad);a("json",bd);a("limitTo",cd);a("lowercase",dd);a("number",Sb);a("orderBy",Tb);a("uppercase",ed)}function ad(){return function(b,a){if(!(b instanceof Array))return b;var c=[];c.check=function(a){for(var b=0;b -1;case "object":for(var c in a)if(c.charAt(0)!=="$"&&d(a[c],b))return!0;return!1;case "array":for(c=0;c e+1?i="0":(f=i,k=!0)}if(!k){i=(i.split(Vb)[1]||"").length;t(e)&&(e=Math.min(Math.max(a.minFrac,i),a.maxFrac));var i=Math.pow(10,e),b=Math.round(b*i)/i,b=(""+b).split(Vb),i=b[0],b=b[1]||"",k=0,j=a.lgSize,l=a.gSize;if(i.length>=j+l)for(var k=i.length-j,o=0;o 0||e>-c)e+=c;e===0&&c==-12&&(e=12);return ib(e,a,d)}}function La(b,a){return function(c,d){var e=c["get"+b](),g=la(a?"SHORT"+b:b);return d[g][e]}}function Rb(b){function a(a){var b; 105 | if(b=a.match(c)){var a=new Date(0),g=0,i=0;b[9]&&(g=G(b[9]+b[10]),i=G(b[9]+b[11]));a.setUTCFullYear(G(b[1]),G(b[2])-1,G(b[3]));a.setUTCHours(G(b[4]||0)-g,G(b[5]||0)-i,G(b[6]||0),G(b[7]||0))}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e){var g="",i=[],f,h,e=e||"mediumDate",e=b.DATETIME_FORMATS[e]||e;F(c)&&(c=fd.test(c)?G(c):a(c));wa(c)&&(c=new Date(c));if(!na(c))return c;for(;e;)(h=gd.exec(e))?(i=i.concat(ia.call(h, 106 | 1)),e=i.pop()):(i.push(e),e=null);m(i,function(a){f=hd[a];g+=f?f(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function bd(){return function(b){return da(b,!0)}}function cd(){return function(b,a){if(!(b instanceof Array))return b;var a=G(a),c=[],d,e;if(!b||!(b instanceof Array))return c;a>b.length?a=b.length:a<-b.length&&(a=-b.length);a>0?(d=0,e=a):(d=b.length+a,e=b.length);for(;d l?(d.$setValidity("maxlength", 112 | !1),p):(d.$setValidity("maxlength",!0),a)};d.$parsers.push(c);d.$formatters.push(c)}}function jb(b,a){b="ngClass"+b;return S(function(c,d,e){function g(b,d){if(a===!0||c.$index%2===a)d&&b!==d&&i(d),f(b)}function i(a){L(a)&&!J(a)&&(a=Ta(a,function(a,b){if(a)return b}));d.removeClass(J(a)?a.join(" "):a)}function f(a){L(a)&&!J(a)&&(a=Ta(a,function(a,b){if(a)return b}));a&&d.addClass(J(a)?a.join(" "):a)}c.$watch(e[b],g,!0);e.$observe("class",function(){var a=c.$eval(e[b]);g(a,a)});b!=="ngClass"&&c.$watch("$index", 113 | function(d,g){var j=d%2;j!==g%2&&(j==a?f(c.$eval(e[b])):i(c.$eval(e[b])))})})}var E=function(b){return F(b)?b.toLowerCase():b},la=function(b){return F(b)?b.toUpperCase():b},B=U.Error,aa=G((/msie (\d+)/.exec(E(navigator.userAgent))||[])[1]),u,ja,ia=[].slice,Ra=[].push,Sa=Object.prototype.toString,Yb=U.angular||(U.angular={}),ta,Cb,Z=["0","0","0"];D.$inject=[];ma.$inject=[];Cb=aa<9?function(b){b=b.nodeName?b:b[0];return b.scopeName&&b.scopeName!="HTML"?la(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName? 114 | b.nodeName:b[0].nodeName};var kc=/[A-Z]/g,id={full:"1.0.3",major:1,minor:0,dot:3,codeName:"bouncy-thunder"},Ba=Q.cache={},Aa=Q.expando="ng-"+(new Date).getTime(),oc=1,Zb=U.document.addEventListener?function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},db=U.document.removeEventListener?function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)},mc=/([\:\-\_]+(.))/g,nc=/^moz([A-Z])/,ua=Q.prototype={ready:function(b){function a(){c||(c=!0,b())} 115 | var c=!1;this.bind("DOMContentLoaded",a);Q(U).bind("load",a)},toString:function(){var b=[];m(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return b>=0?u(this[b]):u(this[this.length+b])},length:0,push:Ra,sort:[].sort,splice:[].splice},Ea={};m("multiple,selected,checked,disabled,readOnly,required".split(","),function(b){Ea[E(b)]=b});var zb={};m("input,select,option,textarea,button,form".split(","),function(b){zb[la(b)]=!0});m({data:ub,inheritedData:Da,scope:function(b){return Da(b, 116 | "$scope")},controller:xb,injector:function(b){return Da(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Ca,css:function(b,a,c){a=rb(a);if(v(c))b.style[a]=c;else{var d;aa<=8&&(d=b.currentStyle&&b.currentStyle[a],d===""&&(d="auto"));d=d||b.style[a];aa<=8&&(d=d===""?p:d);return d}},attr:function(b,a,c){var d=E(a);if(Ea[d])if(v(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||D).specified?d:p;else if(v(c))b.setAttribute(a, 117 | c);else if(b.getAttribute)return b=b.getAttribute(a,2),b===null?p:b},prop:function(b,a,c){if(v(c))b[a]=c;else return b[a]},text:x(aa<9?function(b,a){if(b.nodeType==1){if(t(a))return b.innerText;b.innerText=a}else{if(t(a))return b.nodeValue;b.nodeValue=a}}:function(b,a){if(t(a))return b.textContent;b.textContent=a},{$dv:""}),val:function(b,a){if(t(a))return b.value;b.value=a},html:function(b,a){if(t(a))return b.innerHTML;for(var c=0,d=b.childNodes;c ":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a, 126 | c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Lc={n:"\n",f:"\u000c",r:"\r",t:"\t",v:"\u000b","'":"'",'"':'"'},hb={},Yc=U.XMLHttpRequest||function(){try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(c){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(d){}throw new B("This browser does not support XMLHttpRequest."); 127 | };Pb.$inject=["$provide"];Qb.$inject=["$locale"];Sb.$inject=["$locale"];var Vb=".",hd={yyyy:P("FullYear",4),yy:P("FullYear",2,0,!0),y:P("FullYear",1),MMMM:La("Month"),MMM:La("Month",!0),MM:P("Month",2,1),M:P("Month",1,1),dd:P("Date",2),d:P("Date",1),HH:P("Hours",2),H:P("Hours",1),hh:P("Hours",2,-12),h:P("Hours",1,-12),mm:P("Minutes",2),m:P("Minutes",1),ss:P("Seconds",2),s:P("Seconds",1),EEEE:La("Day"),EEE:La("Day",!0),a:function(a,c){return a.getHours()<12?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){a=a.getTimezoneOffset(); 128 | return ib(a/60,2)+ib(Math.abs(a%60),2)}},gd=/((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,fd=/^\d+$/;Rb.$inject=["$locale"];var dd=I(E),ed=I(la);Tb.$inject=["$parse"];var jd=I({restrict:"E",compile:function(a,c){c.href||c.$set("href","");return function(a,c){c.bind("click",function(a){if(!c.attr("href"))return a.preventDefault(),!1})}}}),kb={};m(Ea,function(a,c){var d=fa("ng-"+c);kb[d]=function(){return{priority:100,compile:function(){return function(a,g,i){a.$watch(i[d], 129 | function(a){i.$set(c,!!a)})}}}}});m(["src","href"],function(a){var c=fa("ng-"+a);kb[c]=function(){return{priority:99,link:function(d,e,g){g.$observe(c,function(c){c&&(g.$set(a,c),aa&&e.prop(a,c))})}}}});var Oa={$addControl:D,$removeControl:D,$setValidity:D,$setDirty:D};Wb.$inject=["$element","$attrs","$scope"];var Ra=function(a){return["$timeout",function(c){var d={name:"form",restrict:"E",controller:Wb,compile:function(){return{pre:function(a,d,i,f){if(!i.action){var h=function(a){a.preventDefault? 130 | a.preventDefault():a.returnValue=!1};Zb(d[0],"submit",h);d.bind("$destroy",function(){c(function(){db(d[0],"submit",h)},0,!1)})}var k=d.parent().controller("form"),j=i.name||i.ngForm;j&&(a[j]=f);k&&d.bind("$destroy",function(){k.$removeControl(f);j&&(a[j]=p);x(f,Oa)})}}}};return a?x(V(d),{restrict:"EAC"}):d}]},kd=Ra(),ld=Ra(!0),md=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,nd=/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/,od=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/, 131 | ac={text:Qa,number:function(a,c,d,e,g,i){Qa(a,c,d,e,g,i);e.$parsers.push(function(a){var c=T(a);return c||od.test(a)?(e.$setValidity("number",!0),a===""?null:c?a:parseFloat(a)):(e.$setValidity("number",!1),p)});e.$formatters.push(function(a){return T(a)?"":""+a});if(d.min){var f=parseFloat(d.min),a=function(a){return!T(a)&&a h?(e.$setValidity("max", 132 | !1),p):(e.$setValidity("max",!0),a)};e.$parsers.push(d);e.$formatters.push(d)}e.$formatters.push(function(a){return T(a)||wa(a)?(e.$setValidity("number",!0),a):(e.$setValidity("number",!1),p)})},url:function(a,c,d,e,g,i){Qa(a,c,d,e,g,i);a=function(a){return T(a)||md.test(a)?(e.$setValidity("url",!0),a):(e.$setValidity("url",!1),p)};e.$formatters.push(a);e.$parsers.push(a)},email:function(a,c,d,e,g,i){Qa(a,c,d,e,g,i);a=function(a){return T(a)||nd.test(a)?(e.$setValidity("email",!0),a):(e.$setValidity("email", 133 | !1),p)};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){t(d.name)&&c.attr("name",xa());c.bind("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a,c,d,e){var g=d.ngTrueValue,i=d.ngFalseValue;F(g)||(g=!0);F(i)||(i=!1);c.bind("click",function(){a.$apply(function(){e.$setViewValue(c[0].checked)})});e.$render=function(){c[0].checked=e.$viewValue};e.$formatters.push(function(a){return a=== 134 | g});e.$parsers.push(function(a){return a?g:i})},hidden:D,button:D,submit:D,reset:D},bc=["$browser","$sniffer",function(a,c){return{restrict:"E",require:"?ngModel",link:function(d,e,g,i){i&&(ac[E(g.type)]||ac.text)(d,e,g,i,c,a)}}}],Na="ng-valid",Ma="ng-invalid",Pa="ng-pristine",Xb="ng-dirty",pd=["$scope","$exceptionHandler","$attrs","$element","$parse",function(a,c,d,e,g){function i(a,c){c=c?"-"+$a(c,"-"):"";e.removeClass((a?Ma:Na)+c).addClass((a?Na:Ma)+c)}this.$modelValue=this.$viewValue=Number.NaN; 135 | this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name=d.name;var f=g(d.ngModel),h=f.assign;if(!h)throw B(Db+d.ngModel+" ("+pa(e)+")");this.$render=D;var k=e.inheritedData("$formController")||Oa,j=0,l=this.$error={};e.addClass(Pa);i(!0);this.$setValidity=function(a,c){if(l[a]!==!c){if(c){if(l[a]&&j--,!j)i(!0),this.$valid=!0,this.$invalid=!1}else i(!1),this.$invalid=!0,this.$valid=!1,j++;l[a]=!c;i(c,a);k.$setValidity(a, 136 | c,this)}};this.$setViewValue=function(d){this.$viewValue=d;if(this.$pristine)this.$dirty=!0,this.$pristine=!1,e.removeClass(Pa).addClass(Xb),k.$setDirty();m(this.$parsers,function(a){d=a(d)});if(this.$modelValue!==d)this.$modelValue=d,h(a,d),m(this.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}})};var o=this;a.$watch(function(){var c=f(a);if(o.$modelValue!==c){var d=o.$formatters,e=d.length;for(o.$modelValue=c;e--;)c=d[e](c);if(o.$viewValue!==c)o.$viewValue=c,o.$render()}})}],qd=function(){return{require:["ngModel", 137 | "^?form"],controller:pd,link:function(a,c,d,e){var g=e[0],i=e[1]||Oa;i.$addControl(g);c.bind("$destroy",function(){i.$removeControl(g)})}}},rd=I({require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),cc=function(){return{require:"?ngModel",link:function(a,c,d,e){if(e){d.required=!0;var g=function(a){if(d.required&&(T(a)||a===!1))e.$setValidity("required",!1);else return e.$setValidity("required",!0),a};e.$formatters.push(g);e.$parsers.unshift(g); 138 | d.$observe("required",function(){g(e.$viewValue)})}}}},sd=function(){return{require:"ngModel",link:function(a,c,d,e){var g=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||d.ngList||",";e.$parsers.push(function(a){var c=[];a&&m(a.split(g),function(a){a&&c.push(R(a))});return c});e.$formatters.push(function(a){return J(a)?a.join(", "):p})}}},td=/^(true|false|\d+)$/,ud=function(){return{priority:100,compile:function(a,c){return td.test(c.ngValue)?function(a,c,g){g.$set("value",a.$eval(g.ngValue))}:function(a, 139 | c,g){a.$watch(g.ngValue,function(a){g.$set("value",a,!1)})}}}},vd=S(function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBind);a.$watch(d.ngBind,function(a){c.text(a==p?"":a)})}),wd=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate));d.addClass("ng-binding").data("$binding",c);e.$observe("ngBindTemplate",function(a){d.text(a)})}}],xd=[function(){return function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBindHtmlUnsafe);a.$watch(d.ngBindHtmlUnsafe, 140 | function(a){c.html(a||"")})}}],yd=jb("",!0),zd=jb("Odd",0),Ad=jb("Even",1),Bd=S({compile:function(a,c){c.$set("ngCloak",p);a.removeClass("ng-cloak")}}),Cd=[function(){return{scope:!0,controller:"@"}}],Dd=["$sniffer",function(a){return{priority:1E3,compile:function(){a.csp=!0}}}],dc={};m("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave".split(" "),function(a){var c=fa("ng-"+a);dc[c]=["$parse",function(d){return function(e,g,i){var f=d(i[c]);g.bind(E(a),function(a){e.$apply(function(){f(e, 141 | {$event:a})})})}}]});var Ed=S(function(a,c,d){c.bind("submit",function(){a.$apply(d.ngSubmit)})}),Fd=["$http","$templateCache","$anchorScroll","$compile",function(a,c,d,e){return{restrict:"ECA",terminal:!0,compile:function(g,i){var f=i.ngInclude||i.src,h=i.onload||"",k=i.autoscroll;return function(g,i){var o=0,m,n=function(){m&&(m.$destroy(),m=null);i.html("")};g.$watch(f,function(f){var p=++o;f?a.get(f,{cache:c}).success(function(a){p===o&&(m&&m.$destroy(),m=g.$new(),i.html(a),e(i.contents())(m), 142 | v(k)&&(!k||g.$eval(k))&&d(),m.$emit("$includeContentLoaded"),g.$eval(h))}).error(function(){p===o&&n()}):n()})}}}}],Gd=S({compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),Hd=S({terminal:!0,priority:1E3}),Id=["$locale","$interpolate",function(a,c){var d=/{}/g;return{restrict:"EA",link:function(e,g,i){var f=i.count,h=g.attr(i.$attr.when),k=i.offset||0,j=e.$eval(h),l={},o=c.startSymbol(),r=c.endSymbol();m(j,function(a,e){l[e]=c(a.replace(d,o+f+"-"+k+r))});e.$watch(function(){var c= 143 | parseFloat(e.$eval(f));return isNaN(c)?"":(j[c]||(c=a.pluralCat(c-k)),l[c](e,g,!0))},function(a){g.text(a)})}}}],Jd=S({transclude:"element",priority:1E3,terminal:!0,compile:function(a,c,d){return function(a,c,i){var f=i.ngRepeat,i=f.match(/^\s*(.+)\s+in\s+(.*)\s*$/),h,k,j;if(!i)throw B("Expected ngRepeat in form of '_item_ in _collection_' but got '"+f+"'.");f=i[1];h=i[2];i=f.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!i)throw B("'item' in 'item in collection' should be identifier or (key, value) but got '"+ 144 | f+"'.");k=i[3]||i[1];j=i[2];var l=new eb;a.$watch(function(a){var e,f,i=a.$eval(h),m=gc(i,!0),p,u=new eb,C,A,v,t,y=c;if(J(i))v=i||[];else{v=[];for(C in i)i.hasOwnProperty(C)&&C.charAt(0)!="$"&&v.push(C);v.sort()}e=0;for(f=v.length;e x;)t.pop().element.remove()}for(;v.length>w;)v.pop()[0].element.remove()}var i;if(!(i=w.match(d)))throw B("Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '"+w+"'.");var j=c(i[2]||i[1]),k=i[4]|| 154 | i[6],l=i[5],m=c(i[3]||""),o=c(i[2]?i[1]:k),r=c(i[7]),v=[[{element:f,label:""}]];q&&(a(q)(e),q.removeClass("ng-scope"),q.remove());f.html("");f.bind("change",function(){e.$apply(function(){var a,c=r(e)||[],d={},h,i,j,m,q,s;if(n){i=[];m=0;for(s=v.length;m @charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\\:form{display:block;}'); 160 | -------------------------------------------------------------------------------- /assets/vendor/lodash/lodash.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Lo-Dash 1.0.0-rc.3 lodash.com/license 3 | Underscore.js 1.4.3 underscorejs.org/LICENSE 4 | */ 5 | ;(function(e,t){function n(e){if(e&&typeof e=="object"&&e.__wrapped__)return e;if(!(this instanceof n))return new n(e);this.__wrapped__=e}function r(e,t,n){t||(t=0);var r=e.length,i=r-t>=(n||tt);if(i)for(var s={},n=t-1;++nt||typeof e=="undefined")return 1;if( 6 | e i;i++)r+="i='"+e.j[i]+"';if(","constructor"==e.j[i]&&(r+="!(f&&f.prototype===l)&&"),r+="h.call(l,i)){"+e.g+"}"}if(e.b||e.h)r+="}";return r+=e.c+";return t" 9 | ,n("e,h,j,k,p,n,s","return function("+t+"){"+r+"}")(u,Et,v,N,nn,At,xt)}function f(e){return"\\"+rn[e]}function l(e){return hn[e]}function c(e){return typeof e.toString!="function"&&typeof (e+"")=="string"}function h(){}function p(e,t,n){t||(t=0),typeof n=="undefined"&&(n=e?e.length:0);for(var r=-1,n=n-t||0,i=Array(0>n?0:n);++r n?Ot(0,i+n):n)||0;return typeof i=="number"?s=-1<(N(e)?e.indexOf(t,n):R(e,t,n)):an(e,function(e){if(++r>=n)return!(s=e===t)}),s} 15 | function A(e,t,n){var r=!0,t=u(t,n);if(vn(e))for(var n=-1,i=e.length;++nr&&(r=n,a=e)});else for(;++s a&&(a=e[s]);return a}function H(e,t){return D(e,t+"")}function B(e,t,n,r){var i=3>arguments.length,t=u(t,r,et);if(vn(e)){var s=-1,o= 17 | e.length;for(i&&(n=e[++s]);++s arguments.length;if(typeof s!="number")var a=gn(e),s=a.length;else Gt&&N(e)&&(i=e.split(""));return t=u(t,r,et),_(e,function(e,r,u){r=a?a[--s]:--s,n=o?(o=!1,i[r]):t(n,i[r],r,u)}),n}function F(e,t,n){var r,t=u(t,n);if(vn(e))for(var n=-1,i=e.length;++nn?Ot(0,i+n):n||0)-1;else if(n)return r=z(e,t),e[r]===t?r:-1;for(;++r>>1,n(e[r]) R(a,c))(n||f)&&a.push(c),o.push(r)}return o}function X(e,t){return zt||Nt&&2 |{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/,it=/&(?:amp|lt|gt|quot|#x27);/g,st=/\b__p\+='';/g,ot=/\b(__p\+=)''\+/g,ut=/(__e\(.*?\)|\b__t\))\+'';/g,at=/\w*$/,ft=/(?:__e|__t=)\(\s*(?![\d\s"']|this\.)/g 21 | ,lt=RegExp("^"+(Y.valueOf+"").replace(/[.*+?^=!:${}()|[\]\/\\]/g,"\\$&").replace(/valueOf|for [^\]]+/g,".+?")+"$"),ct=/\$\{((?:(?=\\?)\\?[\s\S])*?)}/g,ht=/<%=([\s\S]+?)%>/g,pt=/($^)/,dt=/[&<>"']/g,vt=/['\n\r\t\u2028\u2029\\]/g,mt="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),gt=Math.ceil,yt=G.concat,bt=Math.floor,wt=lt.test(wt=Object.getPrototypeOf)&&wt,Et=Y.hasOwnProperty,St=G.push,xt=Y.propertyIsEnumerable,Tt=Y.toString,Nt=lt.test(Nt= 22 | p.bind)&&Nt,Ct=lt.test(Ct=Array.isArray)&&Ct,kt=e.isFinite,Lt=e.isNaN,At=lt.test(At=Object.keys)&&At,Ot=Math.max,Mt=Math.min,_t=Math.random,Dt="[object Arguments]",Pt="[object Array]",Ht="[object Boolean]",Bt="[object Date]",jt="[object Number]",Ft="[object Object]",It="[object RegExp]",qt="[object String]",Rt=!!e.attachEvent,Ut=Nt&&!/\n|true/.test(Nt+Rt),zt=Nt&&!Ut,Wt=At&&(Rt||Ut),Xt,Vt,$t=($t={0:1,length:1},G.splice.call($t,0,1),$t[0]),Jt=!0;(function(){function e(){this.x=1}var t=[];e.prototype= 23 | {valueOf:1,y:1};for(var n in new e)t.push(n);for(n in arguments)Jt=!n;Xt=!/valueOf/.test(t),Vt="x"!=t[0]})(1);var Kt=arguments.constructor==Object,Qt=!v(arguments),Gt="xx"!="x"[0]+Object("x")[0];try{var Yt=("[object Object]",Tt.call(document)==Ft)}catch(Zt){}var en={"[object Function]":!1};en[Dt]=en[Pt]=en[Ht]=en[Bt]=en[jt]=en[Ft]=en[It]=en[qt]=!0;var tn={};tn[Pt]=Array,tn[Ht]=Boolean,tn[Bt]=Date,tn[Ft]=Object,tn[jt]=Number,tn[It]=RegExp,tn[qt]=String;var nn={"boolean":!1,"function":!0,object:!0, 24 | number:!1,string:!1,"undefined":!1},rn={"\\":"\\","'":"'","\n":"n","\r":"r"," ":"t","\u2028":"u2028","\u2029":"u2029"};n.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:ht,variable:""};var sn={a:"o,v,g",k:"for(var a=1,b=typeof g=='number'?2:arguments.length;a":">",'"':""","'":"'"},pn=w(hn),dn=a(sn,{g:"if(t[i]==null)"+sn.g}),vn=Ct||function(e){return Kt&&e instanceof Array||Tt.call(e)==Pt};S(/x/)&&(S=function(e){return e instanceof Function||"[object Function]"==Tt.call(e)});var mn=wt?function(e){if(!e||typeof e!="object")return!1;var t=e.valueOf,n=typeof t=="function"&&(n=wt(t))&&wt(n);return n?e==n||wt(e)==n&&!v(e):m(e) 26 | }:m,gn=At?function(e){return typeof e=="function"&&xt.call(e,"prototype")?g(e):x(e)?At(e):[]}:g;n.after=function(e,t){return 1>e?t():function(){if(1>--e)return t.apply(this,arguments)}},n.assign=fn,n.bind=X,n.bindAll=function(e){for(var t=arguments,n=1 R(f,l)){u&&f.push(l);for(var h=n;--h;)if(!(i[h]||(i[h]=r(t[h],0,100)))(l))continue e;a.push(l)}}return a},n.invert=w,n.invoke=function(e,t){var n=p(arguments,2),r=typeof t=="function",i=[];return _(e,function(e){i.push((r?t:e[t]).apply(e,n))}),i},n.keys=gn,n.map=D, 30 | n.max=P,n.memoize=function(e,t){var n={};return function(){var r=t?t.apply(this,arguments):arguments[0];return Et.call(n,r)?n[r]:n[r]=e.apply(this,arguments)}},n.merge=C,n.min=function(e,t,n){var r=Infinity,s=-1,o=e?e.length:0,a=r;if(t||!vn(e))t=!t&&N(e)?i:u(t,n),an(e,function(e,n,i){n=t(e,n,i),n R(s,n,1))i[n]=e}),i},n.once=function(e){var t,n=!1;return function(){return n?t:(n=!0,t=e.apply(this,arguments),e=null,t)}},n.pairs=function(e){var t=[];return cn(e,function(e,n){t.push([n,e])}),t},n.partial=function(e){return o(e,p(arguments,1))},n.pick=function(e,t,n){var r={};if(typeof t!="function")for(var i=0,s=yt.apply(G,arguments),o=s.length;++i =f?(clearTimeout(o),o=null,u=a,i=e.apply(s,r)):o||(o=setTimeout(n,f)),i}},n.times=function(e,t,n){for(var e=+e||0,r=-1,i=Array(e);++r n?Ot(0,r+n):Mt(n,r-1))+1);r--;)if(e[r]===t)return r;return-1},n.mixin=$,n.noConflict=function(){return e._=nt,this},n.random=function(e,t){return null==e&&null==t&&(t=1),e=+e||0,null==t&&(t=e,e=0),e+bt(_t()*((+t||0)-e+1))},n.reduce=B,n.reduceRight=j,n.result=function(e,t){var n=e?e[t]:null;return S(n)?e[t]():n},n.size=function(e){var t=e?e.length:0; 38 | return typeof t=="number"?t:gn(e).length},n.some=F,n.sortedIndex=z,n.template=function(e,t,r){e||(e=""),r||(r={});var i,s,o=n.templateSettings,u=0,a=r.interpolate||o.interpolate||pt,l="__p+='",c=r.variable||o.variable,h=c;e.replace(RegExp((r.escape||o.escape||pt).source+"|"+a.source+"|"+(a===ht?ct:pt).source+"|"+(r.evaluate||o.evaluate||pt).source+"|$","g"),function(t,n,r,s,o,a){return r||(r=s),l+=e.slice(u,a).replace(vt,f),n&&(l+="'+__e("+n+")+'"),o&&(l+="';"+o+";__p+='"),r&&(l+="'+((__t=("+r+"))==null?'':__t)+'" 39 | ),i||(i=o||rt.test(n||r)),u=a+t.length,t}),l+="';\n",h||(c="obj",i?l="with("+c+"){"+l+"}":(r=RegExp("(\\(\\s*)"+c+"\\."+c+"\\b","g"),l=l.replace(ft,"$&"+c+".").replace(r,"$1__d"))),l=(i?l.replace(st,""):l).replace(ot,"$1").replace(ut,"$1;"),l="function("+c+"){"+(h?"":c+"||("+c+"={});")+"var __t,__p='',__e=_.escape"+(i?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":(h?"":",__d="+c+"."+c+"||"+c)+";")+l+"return __p}";try{s=Function("_","return "+l)(n)}catch(p){throw p.source= 40 | l,p}return t?s(t):(s.source=l,s)},n.unescape=function(e){return null==e?"":(e+"").replace(it,d)},n.uniqueId=function(e){return(null==e?"":e+"")+ ++Z},n.all=A,n.any=F,n.detect=M,n.foldl=B,n.foldr=j,n.include=L,n.inject=B,cn(n,function(e,t){n.prototype[t]||(n.prototype[t]=function(){var t=[this.__wrapped__];return St.apply(t,arguments),e.apply(n,t)})}),n.first=I,n.last=function(e,t,n){if(e){var r=e.length;return null==t||n?e[r-1]:p(e,Ot(0,r-t))}},n.take=I,n.head=I,cn(n,function(e,t){n.prototype[t]|| 41 | (n.prototype[t]=function(t,r){var i=e(this.__wrapped__,t,r);return null==t||r?i:new n(i)})}),n.VERSION="1.0.0-rc.3",n.prototype.toString=function(){return this.__wrapped__+""},n.prototype.value=J,n.prototype.valueOf=J,an(["join","pop","shift"],function(e){var t=G[e];n.prototype[e]=function(){return t.apply(this.__wrapped__,arguments)}}),an(["push","reverse","sort","unshift"],function(e){var t=G[e];n.prototype[e]=function(){return t.apply(this.__wrapped__,arguments),this}}),an(["concat","slice","splice" 42 | ],function(e){var t=G[e];n.prototype[e]=function(){var e=t.apply(this.__wrapped__,arguments);return new n(e)}}),$t&&an(["pop","shift","splice"],function(e){var t=G[e],r="splice"==e;n.prototype[e]=function(){var e=this.__wrapped__,i=t.apply(e,arguments);return 0===e.length&&delete e[0],r?new n(i):i}}),typeof define=="function"&&typeof define.amd=="object"&&define.amd?(e._=n,define(function(){return n})):K?typeof module=="object"&&module&&module.exports==K?(module.exports=n)._=n:K._=n:e._=n})(this); -------------------------------------------------------------------------------- /index.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adopt-A-Pet 8 | 9 | 10 | 11 | 12 | 13 |14 | 19 |31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | --------------------------------------------------------------------------------20 | 21 |26 | 27 | 28 | 29 | 30 |22 | Loading Application 23 |
24 | 25 |