├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── app ├── animals │ ├── IAnimal.ts │ ├── otherAnimal.module.ts │ └── otherAnimalController.ts ├── app.module.ts ├── core │ ├── config.ts │ ├── constants.ts │ ├── core.module.ts │ └── roverPhotoDataService.ts ├── dogs │ ├── IDog.ts │ ├── dog.module.ts │ └── dogController.ts ├── domain │ ├── dogDomain.ts │ ├── dogDomainController.ts │ └── domain.module.ts ├── layout │ └── layoutHex.html ├── objects │ ├── dogObject.module.ts │ └── dogObject.ts ├── people │ ├── masterController.ts │ ├── people.module.ts │ └── peopleController.ts └── roverPhotos │ ├── roverPhotos.module.ts │ └── roverPhotosController.ts ├── bower.json ├── content ├── GOODDC__.TTF ├── PostmanZeus7s.gif ├── ZeusMouthLight.jpg ├── alleycat.jpg ├── app.css ├── fireplug.jpg ├── hexagons.css ├── selectArrow.png ├── zeusbackyard.jpg ├── zeusfrontyard.jpg ├── zeusinside.jpg ├── zeusmaster.jpg ├── zeuspark.jpg └── zeussmile.jpg ├── gulpfile.js ├── index.html ├── karma.conf.js ├── package.json ├── server └── tinyserv.ts ├── test ├── MIT.LICENSE ├── SpecRunner.html ├── roverTestData.ts └── spec │ ├── dogControllerSpec.ts │ └── dogObjectSpec.ts ├── tsconfig.json ├── tslint.json └── typings.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.js.map 2 | bower_components/ 3 | node_modules/ 4 | typings/ 5 | app/**/*.js 6 | server/**/*.js 7 | test/**/*.js 8 | .vscode/settings.json 9 | *.diff 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | // -------------------- for automation only ------------------------------ 4 | // Controls if suggestions should be accepted 'Enter' - in addition to 'Tab'. Helps to avoid ambiguity between inserting new lines or accepting suggestions. 5 | // "editor.acceptSuggestionOnEnter": false, 6 | // Controls if the editor should automatically close brackets after opening them 7 | // "editor.autoClosingBrackets": false, 8 | // Controls the delay in ms after which quick suggestions will show up 9 | //"editor.quickSuggestionsDelay": 5, 10 | // -------------------- for automation only ------------------------------ 11 | // -------------------- for presentation ------------------------------ 12 | //"editor.fontSize": 14, 13 | //"editor.rulers": [ 14 | // 80 15 | //], 16 | //"window.zoomLevel": 2, 17 | // -------------------- for presentation ------------------------------ 18 | "files.exclude": { 19 | "app/**/*.js": true, 20 | "test/**/*.js": true 21 | } 22 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Tony Curtis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VirtualDog 2 | ## An easy to grasp example for training on various web technologies 3 | 4 | ### Use the **feature/begin** and **feature/end** branches to follow along with the [Pluralsight course here](https://www.pluralsight.com/courses/javascript-jasmine-typescript) 5 | 6 | To get started go to your fork directory in a command prompt and do this: 7 | 8 | ``` 9 | npm install 10 | npm start 11 | ``` 12 | 13 | Uses **npm scripts to run locally installed packages** without the need to run from command line, so **everything is local to avoid versioning issues** with a plethora of globally installed versions on student’s ‘puters. 14 | Since you want to use the local version of stuff (e.g. typescript, typings, etc), you **don’t want to run command line directly (contrary to the course instructions)** since that will either: 15 | - Fail if you don’t have the node module installed globally, 16 | - Or if you do have it installed globally, it will run the global version which may be different than the local version used in this project. 17 | 18 | Instead do this (as needed): 19 | ``` 20 | npm run tsc 21 | npm run tsc -- -w 22 | npm run typings -- install dt~silly-node-module --global --save 23 | ``` 24 | 25 | The pertinent part being `npm run` and if you want to add command line parameters follow the module name with the double dash (`--`) then add your command line parameters. 26 | Right now only bower, tsc, and typings have scripts in the package.json file that will allow this, so if there are other command-line-ish things you want to add to package.json, then add them to the list of scripts 27 | 28 | Requires the following global installations: 29 | 30 | - npm 31 | 32 | Also globally installed: 33 | 34 | - tslint (used by VSCode) 35 | 36 | ### To bring up the Virtual Dog Blog in the browser simply navigate to localhost:8042 37 | 38 | ### To bring up the Jasmine tests in the browser simply navigate to the test/SpecRunner.html file in your browser 39 | 40 | No frills, super simple, just a dog and his blog. -------------------------------------------------------------------------------- /app/animals/IAnimal.ts: -------------------------------------------------------------------------------- 1 | namespace dogsrus.virtdog { 2 | export interface IAnimal { 3 | defaultAction: string; 4 | familiarName?: string; 5 | speciesName: string; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/animals/otherAnimal.module.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace dogsrus.virtdog { 3 | angular.module('app.otherAnimal', []); 4 | export function getModuleOtherAnimal(): ng.IModule { 5 | return angular.module('app.otherAnimal'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/animals/otherAnimalController.ts: -------------------------------------------------------------------------------- 1 | namespace dogsrus.virtdog { 2 | export class OtherAnimalController { 3 | public otherAnimals: IAnimal[] = []; 4 | public selectedAnimal: IAnimal; 5 | public lastAction: string = ''; 6 | 7 | static $inject = ['$rootScope', 'eventNames']; 8 | constructor(private $rootScope: ng.IRootScopeService, private eventNames: EventNames) { 9 | this.intializeAnimalList(eventNames); 10 | } 11 | 12 | public performAction() { 13 | // in future may keep track of last action so we can respond back and forth 14 | this.lastAction = this.selectedAnimal.defaultAction; 15 | this.$rootScope.$broadcast(this.selectedAnimal.defaultAction, this.selectedAnimal); 16 | } 17 | 18 | private intializeAnimalList(eventNames: EventNames) { 19 | this.otherAnimals.push( 20 | { 21 | defaultAction: eventNames.catHiss, 22 | familiarName: 'Alley Cat', 23 | speciesName: '' 24 | }); 25 | this.otherAnimals.push( 26 | { 27 | defaultAction: eventNames.decapitate, 28 | familiarName: 'No Ordinary Rabbit', 29 | speciesName: '' 30 | }); 31 | this.otherAnimals.push( 32 | { 33 | defaultAction: eventNames.dogBark, 34 | familiarName: 'Little Noisy Dog', 35 | speciesName: '' 36 | }); 37 | this.performAction = this.performAction.bind(this); 38 | } 39 | } 40 | getModuleOtherAnimal().controller('otherAnimalController', OtherAnimalController); 41 | } 42 | -------------------------------------------------------------------------------- /app/app.module.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 'use strict'; 3 | namespace dogsrus.virtdog { 4 | angular.module('app', [ 5 | // Everybody has access to these 6 | // so centralize registration here 7 | // so feature modules don't need to register them 8 | 9 | 'app.core', 10 | 11 | // Feature Modules 12 | 13 | 'app.dogObject', 14 | 'app.dog', 15 | 'app.people', 16 | 'app.roverPhotos', 17 | 'app.otherAnimal', 18 | 'app.dogDomain' 19 | ]); 20 | // we don't ever refer to the app module except in tests 21 | // but the other modules may be refered 2+ times 22 | export function getModuleApp(): ng.IModule { 23 | return angular.module('app'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/core/config.ts: -------------------------------------------------------------------------------- 1 | namespace dogsrus.virtdog { 2 | export var dogConfiguration = { 3 | appTitle: 'Virtual Dog Demo', 4 | version: '1.0.0', 5 | startDog: { 6 | age: 9, 7 | barkSound: 'bark', 8 | breed: 'Malamute', 9 | chewUrgeInterval: 1000 * 20 * 1 * 1, 10 | coatStyle: 'thick and coarse', 11 | defaultAction: 'lay around', 12 | dogLonelyDuration: 1000 * 60 * 60 * 1, 13 | dogLonelyEndurance: 1000 * 60 * 60 * .06, 14 | dogSleepDuration: 1000 * 60 * 60 * 6, 15 | dogTiredInterval: 1000 * 60 * 60 * 2, 16 | earState: 'relaxed', 17 | earStyle: 'pointed and super soft', 18 | familiarName: 'Zeus', 19 | motherNature1Interval: 1000 * 60 * 60 * 4, 20 | motherNature2Interval: 1000 * 60 * 60 * 8, 21 | speciesName: 'canis familiaris', 22 | squeakyOcdChewCount: 10, 23 | startupBlog: 'I laid down and knocked my tail on the floor twice.', 24 | tailState: DogTailState.elevated, 25 | tailStyle: 'curved and furry' 26 | }, 27 | otherDogs: [{ 28 | age: 0.1, 29 | barkSound: 'yip', 30 | breed: 'Mongrel', 31 | chewUrgeInterval: 1000 * 15, 32 | coatStyle: '', 33 | defaultAction: 'Lay around', 34 | dogLonelyDuration: 1000 * 60 * 60 * 6, 35 | dogLonelyEndurance: 1000 * 10, 36 | dogSleepDuration: 1000 * 60 * 4, 37 | dogTiredInterval: 1000 * 60 * 2, 38 | earState: '', 39 | earStyle: '', 40 | familiarName: 'Puppy Trouble', 41 | motherNature1Interval: 1000 * 60, 42 | motherNature2Interval: 1000 * 60 * 60 * 1, 43 | speciesName: 'Canis familiaris', 44 | squeakyOcdChewCount: 3, 45 | startupBlog: 'I wagged my tail, no I wagged my whole body! And while I did that I did my other favorite thing, I wet all over!', 46 | tailState: DogTailState.wagging, 47 | tailStyle: '' 48 | }, { 49 | age: 5, 50 | barkSound: 'ruf', 51 | breed: 'Labrador', 52 | chewUrgeInterval: 1000 * 60 * 60 * 6, 53 | coatStyle: '', 54 | defaultAction: 'Lay around', 55 | dogLonelyDuration: 1000 * 60 * 60 * 6, 56 | dogLonelyEndurance: 1000 * 60 * 60 * 6, 57 | dogSleepDuration: 1000 * 60 * 60 * 6, 58 | dogTiredInterval: 1000 * 60 * 60 * 6, 59 | earState: '', 60 | earStyle: '', 61 | familiarName: 'Rover', 62 | motherNature1Interval: 1000 * 60 * 60 * 6, 63 | motherNature2Interval: 1000 * 60 * 60 * 6, 64 | speciesName: 'Canis familiaris', 65 | squeakyOcdChewCount: 10, 66 | startupBlog: 'I ran up to my master wagging my tail!', 67 | tailState: DogTailState.wagging, 68 | tailStyle: '' 69 | }] 70 | }; 71 | export type DogConfiguration = typeof dogConfiguration; 72 | getModuleCore().value('dogConfig', dogConfiguration); 73 | } 74 | -------------------------------------------------------------------------------- /app/core/constants.ts: -------------------------------------------------------------------------------- 1 | namespace dogsrus.virtdog { 2 | export var eventNames = { 3 | dogBark: 'dogBark', 4 | dogChase: 'dogChase', 5 | catMeow: 'catMeow', 6 | catBO: 'catBO', 7 | catMove: 'catMove', 8 | catHiss: 'catHiss', 9 | decapitate: 'decapitate', 10 | masterCall: 'masterCall', 11 | masterThrow: 'masterThrow', 12 | masterFeed: 'masterFeed', 13 | masterTake: 'masterTake', 14 | motherNatureCalls1: 'motherNatureCalls1', 15 | motherNatureCalls2: 'motherNatureCalls2', 16 | hunger: 'hunger', 17 | chewUrge: 'chewUrge', 18 | exhaustion: 'exhaustion', 19 | loneliness: 'loneliness', 20 | excitement: 'excitement', 21 | layAround: 'layAround', 22 | animalRun: 'animalRun', 23 | personPet: 'personPet', 24 | personThreaten: 'personThreaten', 25 | commandSit: 'sit', 26 | commandLayDown: 'lay down', 27 | commandStay: 'stay', 28 | commandShake: 'shake', 29 | changeDomain: 'changeDomain' 30 | }; 31 | export type EventNames = typeof eventNames; 32 | 33 | export var roverConfig = { 34 | roverUrl: 'http://localhost:8200//mars-photos/api/v1/rovers/curiosity/photos', 35 | apiKey: 'DEMO_KEY', 36 | camera: 'FHAZ', 37 | earthDate: '2014-8-26', 38 | roverName: 'curiosity', 39 | alternateUrl: 'https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos' 40 | }; 41 | export type RoverConfig = typeof roverConfig; 42 | 43 | export var dogPlaces = { 44 | home: { name: 'home', imagePath: 'zeusinside.jpg', indoors: true, placeObjects: [] }, 45 | frontYard: { name: 'front yard', imagePath: 'zeusfrontyard.jpg', indoors: false, placeObjects: [] }, 46 | backYard: { name: 'back yard', imagePath: 'zeusbackyard.jpg', indoors: false, placeObjects: [] }, 47 | park: { name: 'park', imagePath: 'zeuspark.jpg', indoors: false, placeObjects: [] }, 48 | bathroom: { name: 'bathroom', imagePath: 'fireplug.jpg', indoors: false, placeObjects: [] } 49 | }; 50 | export type DogPlaces = typeof dogPlaces; 51 | 52 | getModuleCore().constant('eventNames', eventNames); 53 | getModuleCore().constant('roverConfig', roverConfig); 54 | getModuleCore().constant('dogPlaces', dogPlaces); 55 | } 56 | -------------------------------------------------------------------------------- /app/core/core.module.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace dogsrus.virtdog { 3 | angular.module('app.core', [ 4 | /* 5 | * Angular modules 6 | */ 7 | 'ngRoute' 8 | /* 9 | * Our reusable cross app code modules 10 | */ 11 | // e.g. exception service, logger service 12 | 13 | /* 14 | * 3rd Party modules 15 | */ 16 | 17 | ]); 18 | export function getModuleCore(): ng.IModule { 19 | return angular.module('app.core'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/core/roverPhotoDataService.ts: -------------------------------------------------------------------------------- 1 | namespace dogsrus.virtdog { 2 | export class RoverPhotoDataService { 3 | static $inject = ['$http', 'roverConfig']; 4 | constructor(private $http: ng.IHttpService, private roverConfig: RoverConfig) { } 5 | 6 | public getPhotos(earthDate: string = this.roverConfig.earthDate, camera: string = this.roverConfig.camera) { 7 | let roverHttpConfig: ng.IRequestConfig = { 8 | method: 'GET', 9 | params: { 10 | 'earth_date': earthDate, 11 | 'camera': camera, 12 | 'api_key': this.roverConfig.apiKey, 13 | 'preventIECache': new Date().getTime() 14 | }, 15 | url: this.roverConfig.roverUrl 16 | }; 17 | 18 | return this.$http(roverHttpConfig).then( 19 | (results) => { 20 | return results.data; 21 | }, (response) => { 22 | return response; 23 | }); 24 | } 25 | } 26 | getModuleCore().service('roverPhotoDataService', RoverPhotoDataService); 27 | } 28 | -------------------------------------------------------------------------------- /app/dogs/IDog.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace dogsrus.virtdog { 3 | export enum DogTailState { 4 | wagging, 5 | elevated, 6 | drooped, 7 | tucked 8 | } 9 | export interface IDog extends IAnimal{ 10 | age: number; 11 | barkSound: string; 12 | breed: string; 13 | chewUrgeInterval: number; 14 | coatStyle: string; 15 | dogLonelyDuration: number; 16 | dogLonelyEndurance: number; 17 | dogSleepDuration: number; 18 | dogTiredInterval: number; 19 | earState: string; 20 | earStyle: string; 21 | motherNature1Interval: number; 22 | motherNature2Interval: number; 23 | squeakyOcdChewCount: number; 24 | startupBlog: string; 25 | tailState: DogTailState; 26 | tailStyle: string; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/dogs/dog.module.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace dogsrus.virtdog { 3 | angular.module('app.dog', []); 4 | export function getModuleDog(): ng.IModule { 5 | return angular.module('app.dog'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/dogs/dogController.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace dogsrus.virtdog { 3 | export class DogController implements IDog { 4 | public blogContent = ''; 5 | public blogPreface: string[] = ['']; 6 | public chewObjects: DogObject[] = []; 7 | public chewPromise: ng.IPromise; 8 | public dogDomain: DogDomain = null; 9 | public dogList: IDog[] = []; 10 | 11 | // IDog 12 | public age = 0; 13 | public barkSound = ''; 14 | public breed = ''; 15 | public chewUrgeInterval = 1000 * 60 * 60 * 6; 16 | public coatStyle = ''; 17 | public dogLonelyDuration = 1000 * 60 * 60 * 6; 18 | public dogLonelyEndurance = 1000 * 60 * 60 * 6; 19 | public dogSleepDuration = 1000 * 60 * 60 * 6; 20 | public dogTiredInterval = 1000 * 60 * 60 * 6; 21 | public earState = ''; 22 | public earStyle = ''; 23 | public motherNature1Interval = 1000 * 60 * 60 * 6; 24 | public motherNature2Interval = 1000 * 60 * 60 * 6; 25 | public squeakyOcdChewCount = 1; 26 | public startupBlog = ''; 27 | public tailState = DogTailState.elevated; 28 | public tailStyle = ''; 29 | 30 | // IAnimal 31 | public defaultAction = ''; 32 | public familiarName = ''; 33 | public speciesName = 'Canis familiaris'; 34 | 35 | static $inject = ['$rootScope', '$interval', 'dogConfig', 'eventNames']; 36 | constructor( 37 | private $rootScope: ng.IRootScopeService, 38 | private $interval: ng.IIntervalService, 39 | private dogConfig: DogConfiguration, 40 | private eventNames: EventNames 41 | ) { 42 | this.initializeDog(this.dogConfig.startDog); 43 | this.initializeEvents(); 44 | this.initializeLists(); 45 | 46 | this.blog(this.startupBlog); 47 | } 48 | 49 | public testBark() { 50 | this.bark(3); 51 | } 52 | 53 | public getTailStateText() { 54 | return DogTailState[this.tailState]; 55 | } 56 | 57 | // --------------------- private stuff down here ------------------------------- 58 | private initializeDog(dogToCopy: IDog) { 59 | // todo: not all dog props are being transfered 60 | this.familiarName = dogToCopy.familiarName; 61 | this.barkSound = dogToCopy.barkSound; 62 | this.age = dogToCopy.age; 63 | this.startupBlog = dogToCopy.startupBlog; 64 | this.chewUrgeInterval = dogToCopy.chewUrgeInterval; 65 | } 66 | 67 | private initializeEvents() { 68 | this.chewPromise = this.$interval(this.chewOnSomething, this.chewUrgeInterval, 0, true); 69 | this.$rootScope.$on(this.eventNames.masterThrow, this.fetch); 70 | this.$rootScope.$on(this.eventNames.masterFeed, this.eat); 71 | this.$rootScope.$on(this.eventNames.decapitate, this.decapitateHandler); 72 | this.$rootScope.$on(this.eventNames.catHiss, (e, a) => this.bark(10)); 73 | this.$rootScope.$on(this.eventNames.personPet, this.getPetted); 74 | this.$rootScope.$on(this.eventNames.animalRun, (e, arg) => this.giveChase(arg)); 75 | this.$rootScope.$on(this.eventNames.changeDomain, (e, arg) => this.setDogDomain(arg)); 76 | this.$rootScope.$on(this.eventNames.commandStay, this.respondToCommand); 77 | this.$rootScope.$on(this.eventNames.commandShake, this.respondToCommand); 78 | this.$rootScope.$on(this.eventNames.dogBark, (e, a) => this.getExcited); 79 | } 80 | 81 | private initializeLists() { 82 | this.blogPreface.push('Guess what! '); 83 | this.blogPreface.push('Ha! '); 84 | this.blogPreface.push('Nice! '); 85 | this.blogPreface.push('You\'ll never believe this! '); 86 | this.blogPreface.push('OMG! '); 87 | this.blogPreface.push('So I\'m laying here. '); 88 | for (let x = 0; x < this.dogConfig.otherDogs.length; x++) { 89 | this.dogList.push(this.dogConfig.otherDogs[x]); 90 | } 91 | this.dogList.push(this.dogConfig.startDog); 92 | } 93 | 94 | private bark = (numberOfBarks: number) => { 95 | let totalBarkText = ''; 96 | for (let x = 0; x < numberOfBarks; x++) { 97 | totalBarkText += `${this.barkSound} `; 98 | } 99 | this.blog(totalBarkText, false); 100 | }; 101 | 102 | // todo: may not always want to add datestamp to blog 103 | // e.g. if want we want to blog multiple times on one event 104 | private blog(blogEntry: string, addPreface = true): void { 105 | if (blogEntry !== '') { 106 | if (addPreface) { 107 | blogEntry = this.blogPreface[Math.floor( 108 | (Math.random() * this.blogPreface.length))] + blogEntry; 109 | } 110 | blogEntry = `${new Date().toLocaleTimeString(navigator.language, 111 | { hour: '2-digit', minute: '2-digit' })}: ${blogEntry}`; 112 | this.blogContent = `${blogEntry}\r\n${this.blogContent}`; 113 | } 114 | } 115 | 116 | // todo: implement this with button, make public? 117 | private blogAboutMe() { 118 | this.blog(`Hi, my name is ${this.familiarName} and 119 | I am a ${this.breed}. I have a ${this.coatStyle} coat, 120 | ears that are ${this.earStyle} 121 | and a tail that is ${this.tailStyle}, 122 | I am ${this.age} years old, 123 | and when I bark it sounds like this: ${this.barkSound}. 124 | I get the urge to chew about every 125 | ${this.chewUrgeInterval / (1000)} seconds, 126 | but mostly I ${this.defaultAction}. I get lonely after 127 | ${this.dogLonelyEndurance / (1000 * 60 * 60)} hours, 128 | and I will complain loudly about it for 129 | ${this.dogLonelyDuration / (1000 * 60)} minutes. I get sleepy every 130 | ${this.dogTiredInterval / (1000 * 60 * 60)} hours 131 | and sleep for ${this.dogSleepDuration / (1000 * 60 * 60)}. 132 | Right now my ears are ${this.earState} 133 | and my tail is ${this.getTailStateText()}.` 134 | .replace(/\s+/g, ' ')); 135 | } 136 | 137 | private chewOnSomething = () => { 138 | if (this.chewObjects.length) { 139 | this.chewObjects.sort((chewObject1, chewObject2) => { 140 | return chewObject1.expensive > chewObject2.expensive 141 | ? -1 142 | : chewObject1.expensive < chewObject2.expensive 143 | ? 1 144 | : chewObject1.irreplaceable 145 | ? -1 146 | : 0; 147 | }); 148 | } 149 | for (let x = 0; x < this.chewObjects.length; x++) { 150 | if (this.chewObjects[x].chewy) { 151 | let description = ''; 152 | if (this.chewObjects[x].chewOn() === ChewExperience.squeaky) { 153 | this.chewOnSomethingSqueaky(description, this.chewObjects[x]); 154 | } else { 155 | description = `Suddenly I got an urge to chew! 156 | I happily chewed on the ${this.chewObjects[x].name}! 157 | The ${this.chewObjects[x].name} is now 158 | ${this.chewObjects[x].getSpitStateText()} and 159 | ${this.chewObjects[x].getStateText()} 160 | ${((this.chewObjects[x].monetaryValue < 1) 161 | ? '.' 162 | : (` and is now worth $ 163 | ${Math.round(this.chewObjects[x].monetaryValue)}.`))}` 164 | .replace(/\s+/g, ' '); 165 | } 166 | this.blog(description); 167 | return; 168 | } 169 | } 170 | }; 171 | 172 | private chewOnSomethingSqueaky(blogEntry: string, chewObject: DogObject) { 173 | blogEntry += ` I chewed on the ${chewObject.name} and heard it squeak!` + 174 | 'Ok this is way too much fun!!!'; 175 | for (let i = 0; i < this.squeakyOcdChewCount; i++) { 176 | if (chewObject.chewOn() === ChewExperience.squeaky) { 177 | blogEntry += ' Chomp, SQEAK!'; 178 | } else { 179 | blogEntry += ' Chomp... Hey it stopped squeaking, let me try again!'; 180 | } 181 | } 182 | } 183 | 184 | private decapitateHandler = (event: ng.IAngularEvent) => { 185 | this.stopChewing(); 186 | this.tailState = DogTailState.tucked; 187 | this.blog('Oh no! Not the rab...'); 188 | }; 189 | 190 | private displayConfusion(event: ng.IAngularEvent, args) { 191 | this.blog(`I tilt my head at ${event.name}, akward...`); 192 | } 193 | 194 | private eat = (event: ng.IAngularEvent, food: DogObject) => { 195 | let blogEntry = `My master just fed me ${food.name}`; 196 | if (food.edible) { 197 | if (food.name === 'dog food') { 198 | blogEntry += '! I ignored it for an hour, dumped it out on the floor, then ate the ' + 199 | `${food.name} one piece at a time!`; 200 | this.tailState = DogTailState.wagging; 201 | } else { 202 | blogEntry += `! I devoured the ${food.name} immediately ` + 203 | 'and looked back up at him with a hungry face.'; 204 | this.tailState = DogTailState.wagging; 205 | } 206 | } else { 207 | blogEntry += `? I sniffed the ${food.name} and tilted my head.`; 208 | this.tailState = DogTailState.elevated; 209 | } 210 | this.blog(blogEntry); 211 | }; 212 | 213 | private fetch = (event: ng.IAngularEvent, fetchObject: DogObject) => { 214 | let blogEntry = `My master just threw a ${fetchObject.name}. ` + 215 | `I ran like mad to grab the ${fetchObject.name}`; 216 | if (fetchObject.flies) { 217 | blogEntry += ' and leapt like Air Jordan, snatching in mid flight!'; 218 | } else { 219 | blogEntry += ' snapping it up far sooner than imaginable!'; 220 | } 221 | 222 | if (fetchObject.chewy && !this.chewObjects.some((chewObject) => { 223 | return chewObject.name === fetchObject.name; 224 | })) { 225 | this.chewObjects.push(fetchObject); 226 | } 227 | if (fetchObject.chewOn() === ChewExperience.squeaky) { 228 | this.chewOnSomethingSqueaky(blogEntry, fetchObject); 229 | } else { 230 | blogEntry += ` I gave the ${fetchObject.name} a good chew or two and dropped it.`; 231 | } 232 | 233 | this.blog(blogEntry); 234 | }; 235 | 236 | private getExcited = (someAnimal: IAnimal) => { 237 | let description = someAnimal.familiarName + 238 | ' wants to play with me!!! I wag my tail vigorously whine and jump up!!!'; 239 | this.blog(description, true); 240 | }; 241 | 242 | private getPetted = (event: ng.IAngularEvent, person: IAnimal) => { 243 | this.tailState = DogTailState.wagging; 244 | let description = person.familiarName + 245 | ' just gave me a good petting! I smile and look at ' + 246 | `${person.familiarName} with my big dog eyes look!`; 247 | this.blog(description, true); 248 | }; 249 | 250 | private giveChase = (someAnimal: IAnimal) => { 251 | this.tailState = DogTailState.wagging; 252 | let description = `I just chased ${someAnimal.familiarName} ` + 253 | `through the ${this.dogDomain.name}!!!`; 254 | this.blog(description, true); 255 | }; 256 | 257 | private respondToCommand = (event: ng.IAngularEvent, somePerson: IAnimal) => { 258 | let description = `${somePerson.familiarName} just told me to ${event.name}! `; 259 | if (somePerson.familiarName === 'The Mailman') { 260 | this.giveChase(somePerson); 261 | this.blog(description, false); 262 | return; 263 | } 264 | if (event.name === this.eventNames.commandStay) { 265 | if (somePerson.familiarName === 'The Alpha Male') { 266 | description += 'I stayed.'; 267 | } else { 268 | description += 'I ignored it.'; 269 | } 270 | } else { 271 | description += 'I did it.'; 272 | } 273 | this.blog(description, true); 274 | }; 275 | 276 | private setDogDomain = (dogDomain: DogDomain) => { 277 | this.dogDomain = dogDomain; 278 | }; 279 | 280 | private stopChewing() { 281 | this.$interval.cancel(this.chewPromise); 282 | } 283 | 284 | } 285 | getModuleDog().controller('dogController', DogController); 286 | } 287 | -------------------------------------------------------------------------------- /app/domain/dogDomain.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace dogsrus.virtdog { 3 | export class DogDomain { 4 | public name = ''; 5 | public indoors = true; 6 | public imagePath = ''; 7 | public placeObjects: DogObject[] = []; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app/domain/dogDomainController.ts: -------------------------------------------------------------------------------- 1 | namespace dogsrus.virtdog { 2 | export class DogDomainController { 3 | public placeObjects: DogObject[] = []; 4 | public place: DogDomain; 5 | public places: DogDomain[] = []; 6 | 7 | static $inject = ['$rootScope', 'dogPlaces', 'eventNames'] 8 | constructor(private $rootScope: ng.IRootScopeService, public dogPlaces: DogPlaces, private eventNames: EventNames) { 9 | this.initializeDomain(); 10 | } 11 | 12 | public domainSelected(domain: DogDomain) { 13 | this.$rootScope.$broadcast(this.eventNames.changeDomain, domain); 14 | } 15 | 16 | // default initialization is home 17 | private initializeDomain() { 18 | this.place = this.dogPlaces.home; 19 | this.places.push(this.dogPlaces.home); 20 | this.places.push(this.dogPlaces.backYard); 21 | this.places.push(this.dogPlaces.frontYard); 22 | this.places.push(this.dogPlaces.park); 23 | this.places.push(this.dogPlaces.bathroom); 24 | this.placeObjects.push( 25 | new DogObject('Really Nice Couch', true, false) 26 | ); 27 | this.placeObjects[0].expensive = true; 28 | this.placeObjects[0].monetaryValue = 2000; 29 | } 30 | } 31 | getModuleDogDomain().controller('dogDomainController', DogDomainController); 32 | } 33 | -------------------------------------------------------------------------------- /app/domain/domain.module.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace dogsrus.virtdog { 3 | angular.module('app.dogDomain', []); 4 | export function getModuleDogDomain(): ng.IModule { 5 | return angular.module('app.dogDomain'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/layout/layoutHex.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | Master: {{master.familiarName}} 14 | 15 | Object: 16 | 17 | Action: 18 | $nbspPerform Action 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | Doggie Domain 27 | 28 | Domain: 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 41 | Dog Blog 42 | 43 | 44 | Bark 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 56 | 57 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | Mars Rovers 71 | 72 | Camera: 73 |  Get Rover Photos 74 | 77 | 78 | 79 | 80 | 81 | 82 | 97 | 98 | 99 | 100 | 101 | Other People 102 | 103 | Person: 104 | 105 | Action: 106 | 107 | Perform Action 108 | 109 | 110 | 111 | 112 | 113 | 114 | Other Animals 115 | 116 | Animal: 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /app/objects/dogObject.module.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace dogsrus.virtdog { 3 | angular.module('app.dogObject', []); 4 | export function getModuleDogObject(): ng.IModule { 5 | return angular.module('app.dogObject'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/objects/dogObject.ts: -------------------------------------------------------------------------------- 1 | namespace dogsrus.virtdog { 2 | export enum DogSpitState { 3 | noSpit, 4 | someSpit, 5 | soggyAndSlimy 6 | } 7 | 8 | export enum ObjectState { 9 | mintCondition, 10 | littleBitChewed, 11 | veryChewed, 12 | structurallyDamaged, 13 | shredded 14 | } 15 | 16 | export enum ChewExperience { 17 | painful, 18 | fair, 19 | good, 20 | great, 21 | squeaky 22 | } 23 | 24 | export class DogObject { 25 | public expensive: boolean = false; 26 | public irreplaceable: boolean = false; 27 | public flies: boolean = false; 28 | public bounces: boolean = false; 29 | public monetaryValue: number = 0; 30 | public spitState: DogSpitState = DogSpitState.noSpit; 31 | public shredable: boolean = false; 32 | public impervious: boolean = false; 33 | public chewLimit: number = 0; 34 | public state: ObjectState = ObjectState.mintCondition; 35 | 36 | constructor( 37 | public name: string, 38 | public chewy: boolean, 39 | public edible: boolean, 40 | private chewExperience = ChewExperience.good 41 | ) { 42 | if (!chewy && chewExperience > ChewExperience.fair) { 43 | chewExperience = ChewExperience.fair; 44 | } 45 | } 46 | 47 | public getSpitStateText() { 48 | return DogSpitState[this.spitState]; 49 | } 50 | 51 | public getStateText() { 52 | return ObjectState[this.state]; 53 | } 54 | 55 | public chewOn() { 56 | if (this.spitState < DogSpitState.soggyAndSlimy) { 57 | this.spitState++; 58 | } 59 | if (this.impervious) { 60 | return this.chewExperience; 61 | } 62 | this.monetaryValue /= 2; 63 | this.expensive = this.monetaryValue > 100; 64 | if (this.chewLimit > 0) { 65 | this.chewLimit--; 66 | if (this.state === ObjectState.mintCondition) { 67 | this.state++; 68 | } else if (this.chewLimit < 10 && this.state === ObjectState.littleBitChewed) { 69 | this.state++; 70 | if (this.chewExperience !== ChewExperience.squeaky 71 | && this.chewExperience > ChewExperience.good) { 72 | this.chewExperience--; 73 | } 74 | } else if (this.chewLimit < 5 && this.state === ObjectState.veryChewed) { 75 | this.state++; 76 | if (this.chewExperience !== ChewExperience.squeaky 77 | && this.chewExperience > ChewExperience.fair) { 78 | this.chewExperience--; 79 | } else if (this.chewExperience === ChewExperience.squeaky 80 | && this.chewLimit === 0) { 81 | this.chewExperience = ChewExperience.fair; 82 | } 83 | } 84 | } 85 | if (this.state === ObjectState.veryChewed) { 86 | if (this.shredable) { 87 | this.state++; 88 | } else { 89 | this.state += 2; 90 | } 91 | } else if (this.state < ObjectState.structurallyDamaged) { 92 | this.state++; 93 | } 94 | return this.chewExperience; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/people/masterController.ts: -------------------------------------------------------------------------------- 1 | namespace dogsrus.virtdog { 2 | export class MasterAction { 3 | constructor( 4 | public actionName: string, 5 | public actionFunc: (actionObject: DogObject) => void 6 | ) { } 7 | } 8 | 9 | export class MasterController implements IAnimal { 10 | public speciesName: string = 'Homo Sapiens'; 11 | public familiarName: string; 12 | public defaultAction: string; 13 | 14 | public selectedAction: MasterAction; 15 | public masterActions: MasterAction[] = []; 16 | public selectedObject: DogObject; 17 | public masterObjects: DogObject[] = []; 18 | 19 | static $inject = ['$rootScope', 'eventNames']; 20 | constructor(private $rootScope: ng.IRootScopeService, private eventNames: EventNames) { 21 | this.familiarName = 'Dillon'; 22 | this.initializeLists(); 23 | } 24 | 25 | public throwSomething = (object) => 26 | this.$rootScope.$broadcast(this.eventNames.masterThrow, object); 27 | 28 | public feedTheDog = (food) => 29 | this.$rootScope.$broadcast(this.eventNames.masterFeed, food); 30 | 31 | // --------------------- private stuff down here ------------------------------- 32 | private initializeLists() { 33 | this.masterActions.push(new MasterAction('Throw Object', this.throwSomething)); 34 | this.masterActions.push(new MasterAction('Feed', this.feedTheDog)); 35 | 36 | let dogObject = new DogObject('Babe Ruth autographed baseball', true, false); 37 | dogObject.bounces = true; 38 | dogObject.expensive = true; 39 | dogObject.irreplaceable = true; 40 | dogObject.monetaryValue = 100000; 41 | dogObject.chewLimit = 15; 42 | this.masterObjects.push(dogObject); 43 | 44 | dogObject = new DogObject('ball', true, false); 45 | dogObject.bounces = true; 46 | dogObject.chewLimit = 100; 47 | this.masterObjects.push(dogObject); 48 | 49 | dogObject = new DogObject('Frisbee', true, false); 50 | dogObject.flies = true; 51 | dogObject.chewLimit = 20; 52 | this.masterObjects.push(dogObject); 53 | 54 | this.masterObjects.push(new DogObject('stick', true, false)); 55 | this.masterObjects.push(new DogObject('dog food', true, true)); 56 | this.masterObjects.push(new DogObject('table scraps', true, true)); 57 | } 58 | } 59 | getModulePeople().controller('masterController', MasterController); 60 | } 61 | -------------------------------------------------------------------------------- /app/people/people.module.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace dogsrus.virtdog { 3 | angular.module('app.people', []); 4 | export function getModulePeople(): ng.IModule { 5 | return angular.module('app.people'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/people/peopleController.ts: -------------------------------------------------------------------------------- 1 | namespace dogsrus.virtdog { 2 | export class PersonAction { 3 | constructor( 4 | public actionName: string, 5 | public actionFunc: (actionObject: DogObject) => void 6 | ) { } 7 | } 8 | 9 | export class PeopleController { 10 | public people: IAnimal[] = []; 11 | public selectedPerson: IAnimal; 12 | 13 | public selectedAction: PersonAction; 14 | public personActions: PersonAction[] = []; 15 | 16 | static $inject = ['$rootScope', 'eventNames']; 17 | constructor(private $rootScope: ng.IRootScopeService, private eventNames: EventNames) { 18 | this.initializeLists(); 19 | } 20 | 21 | public commandStay = (person) => 22 | this.$rootScope.$broadcast(this.eventNames.commandStay, person); 23 | 24 | public commandShake = (person) => 25 | this.$rootScope.$broadcast(this.eventNames.commandShake, person); 26 | 27 | public runAway = (person) => 28 | this.$rootScope.$broadcast(this.eventNames.animalRun, person); 29 | 30 | public pet = (person) => 31 | this.$rootScope.$broadcast(this.eventNames.personPet, person); 32 | 33 | // --------------------- private stuff down here ------------------------------- 34 | private initializeLists() { 35 | this.personActions.push(new PersonAction('Command Zeus to Stay', this.commandStay)); 36 | this.personActions.push(new PersonAction('Command Zeus to Shake', this.commandShake)); 37 | this.personActions.push(new PersonAction('Run Away', this.runAway)); 38 | this.personActions.push(new PersonAction('Pet Zeus', this.pet)); 39 | 40 | this.people.push( 41 | { 42 | defaultAction: this.eventNames.personPet, 43 | familiarName: 'The Alpha Male', 44 | speciesName: 'Homo Sapiens' 45 | } 46 | ); 47 | this.people.push( 48 | { 49 | defaultAction: this.eventNames.personPet, 50 | familiarName: 'The She Wolf', 51 | speciesName: 'Homo Sapiens' 52 | } 53 | ); 54 | this.people.push( 55 | { 56 | defaultAction: this.eventNames.animalRun, 57 | familiarName: 'The Mailman', 58 | speciesName: 'Homo Sapiens' 59 | } 60 | ); 61 | } 62 | } 63 | getModulePeople().controller('peopleController', PeopleController); 64 | } 65 | -------------------------------------------------------------------------------- /app/roverPhotos/roverPhotos.module.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace dogsrus.virtdog { 3 | angular.module('app.roverPhotos', []); 4 | export function getModuleRoverPhotos(): ng.IModule { 5 | return angular.module('app.roverPhotos'); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/roverPhotos/roverPhotosController.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace dogsrus.virtdog { 3 | export class RoverPhotosController { 4 | public data = {}; 5 | public photosToDroolOver = []; 6 | public roverError; 7 | public today = new Date(); 8 | public photoDate = this.today.getFullYear().toString() + '-' + this.today.getMonth().toString() + '-' + this.today.getDate().toString(); 9 | public roverCamera = ''; 10 | public roverPhotoUrl = ''; 11 | public cameras; 12 | 13 | static $inject = ['roverPhotoDataService', 'roverConfig']; 14 | constructor(private roverPhotoDataService: RoverPhotoDataService, private roverConfig: RoverConfig) { 15 | // since there is a lag on photo upload from Mars (imagine that) 16 | // get photos from a few weeks ago 17 | this.today.setTime(this.today.getTime() - ((24 * 60 * 60 * 1000) * 84)); 18 | this.photoDate = this.today.getFullYear().toString() + '-' + (this.today.getMonth() + 1) + '-' + this.today.getDate().toString(); 19 | this.roverCamera = this.roverConfig.camera; 20 | this.getPhotos(this.roverCamera); 21 | } 22 | // todo: interface out the photo object and other objects from rest call 23 | public getPhotos(currentCamera: string) { 24 | this.roverPhotoDataService.getPhotos(this.photoDate, currentCamera).then((data) => { 25 | this.photosToDroolOver = (data).photos; 26 | this.photosToDroolOver.forEach(photo => { 27 | this.roverPhotoUrl = photo.img_src; 28 | this.cameras = photo.rover.cameras; 29 | }); 30 | }, (reason) => { this.roverError = reason; }); 31 | } 32 | } 33 | getModuleRoverPhotos().controller('roverPhotosController', RoverPhotosController); 34 | } 35 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VitrualDog", 3 | "description": "App to demo AngularJs and associated techs", 4 | "version": "0.0.1", 5 | "private": true, 6 | "dependencies": { 7 | "angular": "1.3.x", 8 | "angular-route": "~1.3.15" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /content/GOODDC__.TTF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyCurtisLives/VirtualDog/4dae694d7072a269a39c2dabddac889c86521c93/content/GOODDC__.TTF -------------------------------------------------------------------------------- /content/PostmanZeus7s.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyCurtisLives/VirtualDog/4dae694d7072a269a39c2dabddac889c86521c93/content/PostmanZeus7s.gif -------------------------------------------------------------------------------- /content/ZeusMouthLight.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyCurtisLives/VirtualDog/4dae694d7072a269a39c2dabddac889c86521c93/content/ZeusMouthLight.jpg -------------------------------------------------------------------------------- /content/alleycat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyCurtisLives/VirtualDog/4dae694d7072a269a39c2dabddac889c86521c93/content/alleycat.jpg -------------------------------------------------------------------------------- /content/app.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'GoodDogCool'; 3 | src: url('GOODDC__.TTF'); 4 | } 5 | .pageTitle { 6 | font-family: 'GoodDogCool'; 7 | margin-left: 34%; 8 | font-size: 3em; 9 | } 10 | 11 | /*span { 12 | font-style: italic; 13 | }*/ 14 | 15 | td { 16 | border-width: 3px; 17 | border-style: outset; 18 | border-color: bisque; 19 | } 20 | 21 | .sliderParagraph { 22 | text-align: left; 23 | background-color: rgba(0, 128, 128, 0.1); 24 | } 25 | 26 | .selectStyle select { 27 | border: 0 !important; /*Removes border*/ 28 | -webkit-appearance: none; /*Removes default chrome and safari style*/ 29 | -moz-appearance: none; /* Removes Default Firefox style*/ 30 | appearance:none; 31 | background: ivory url(selectArrow.png) no-repeat 90% center; 32 | width: 100px; /*Width of select dropdown to give space for arrow image*/ 33 | text-indent: 0.01px; /* Removes default arrow from firefox*/ 34 | text-overflow: ""; /*Removes default arrow from firefox*/ /*My custom style for fonts*/ 35 | color: #000; 36 | border-radius: 15px; 37 | padding: 5px; 38 | box-shadow: inset 0 0 5px rgba(000,000,000, 0.5); 39 | font-weight: bold; 40 | } 41 | 42 | .selectStyle select option { 43 | font-weight: bold; 44 | } 45 | 46 | .selectStyle :focus { 47 | outline: none; 48 | } 49 | 50 | .dogButtonStyle { 51 | height: 24px; 52 | border-radius: 14px; 53 | font-weight: bold; 54 | outline: none; 55 | border: none; 56 | background-color: lightblue; 57 | box-shadow: 0 4px #999; 58 | } 59 | 60 | .dogButtonStyle:hover { 61 | background-color: ivory; 62 | } 63 | 64 | .dogButtonStyle:active { 65 | background-color: ivory; 66 | box-shadow: 0 1px #666; 67 | transform: translateY(3px); 68 | } 69 | 70 | #buttonMasterAction { 71 | width: 110px; 72 | margin-left: 70px; 73 | } 74 | 75 | #selectAction { 76 | width: 110px; 77 | background: ivory url(selectArrow.png) no-repeat 95% center; 78 | } 79 | 80 | #selectObject { 81 | width: 230px; 82 | background: ivory url(selectArrow.png) no-repeat 97% center; 83 | } 84 | 85 | #dogTextArea { 86 | height: 275px; 87 | width: 320px; 88 | background: url(ZeusMouthLight.jpg) center center no-repeat; 89 | font-weight: bold; 90 | } 91 | 92 | #tunesTable { 93 | height: 275px; 94 | width: 320px; 95 | background: url(HowlingLight2.jpg) center center no-repeat; 96 | font-weight: bold; 97 | } 98 | 99 | #tunesDimensions { 100 | height: 275px; 101 | width: 320px; 102 | } 103 | #tunesCell { 104 | width: 320px; 105 | } 106 | 107 | #barkButtonDiv { 108 | text-align: center; 109 | width: 100%; 110 | } 111 | 112 | #barkButton { 113 | margin-left: -42px; 114 | width: 80px; 115 | } 116 | 117 | #buttonGetPhotos { 118 | margin-left: 70px; 119 | width: 130px; 120 | } 121 | 122 | .column-layout { 123 | padding: 10px; 124 | } 125 | 126 | #selectPerson { 127 | width: 120px; 128 | background: ivory url(selectArrow.png) no-repeat 96% center; 129 | } 130 | 131 | #selectPersonAction { 132 | width: 190px; 133 | background: ivory url(selectArrow.png) no-repeat 96% center; 134 | } 135 | 136 | #selectCamera { 137 | width: 230px; 138 | background: ivory url(selectArrow.png) no-repeat 96% center; 139 | } 140 | 141 | #selectAnimal { 142 | width: 160px; 143 | background: ivory url(selectArrow.png) no-repeat 96% center; 144 | } 145 | 146 | #personActionButton { 147 | margin-left: 82px; 148 | height: 27px; 149 | width: 120px; 150 | border-radius: 15px; 151 | font-weight: bold; 152 | } 153 | -------------------------------------------------------------------------------- /content/fireplug.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyCurtisLives/VirtualDog/4dae694d7072a269a39c2dabddac889c86521c93/content/fireplug.jpg -------------------------------------------------------------------------------- /content/hexagons.css: -------------------------------------------------------------------------------- 1 | body{ 2 | font-family: 'Open Sans', arial, sans-serif; 3 | background:rgb(123, 158, 158); 4 | } 5 | 6 | *{ 7 | margin:0; 8 | padding:0; 9 | } 10 | #categories{ 11 | overflow:hidden; 12 | width:90%; 13 | margin:0 auto; 14 | } 15 | .clr:after{ 16 | content:""; 17 | display:block; 18 | clear:both; 19 | } 20 | #categories li{ 21 | position:relative; 22 | list-style-type:none; 23 | width:27.85714285714286%; /* = (100-2.5) / 3.5 */ 24 | padding-bottom: 32.16760145166612%; /* = width /0.866 */ 25 | float:left; 26 | overflow:hidden; 27 | visibility:hidden; 28 | 29 | -webkit-transform: translateX(50%) rotate(-60deg) skewY(30deg); 30 | -ms-transform: translateX(50%) rotate(-60deg) skewY(30deg); 31 | transform: translateX(50%) rotate(-60deg) skewY(30deg); 32 | } 33 | #categories li:nth-child(3n+2){ 34 | margin:0 1%; 35 | } 36 | #categories li:nth-child(6n-5){ 37 | margin-left:0.5%; 38 | } 39 | #categories li:nth-child(6n+4), #categories li:nth-child(6n+5), #categories li:nth-child(6n+6) { 40 | margin-top: -6.9285714285%; 41 | margin-bottom: -6.9285714285%; 42 | 43 | -webkit-transform: rotate(-60deg) skewY(30deg); 44 | -ms-transform: rotate(-60deg) skewY(30deg); 45 | transform: rotate(-60deg) skewY(30deg); 46 | } 47 | #categories li:nth-child(6n+4):last-child, #categories li:nth-child(6n+5):last-child, #categories li:nth-child(6n+6):last-child{ 48 | margin-bottom:0%; 49 | } 50 | #categories li *{ 51 | position:absolute; 52 | visibility:visible; 53 | } 54 | #categories li > div{ 55 | width:100%; 56 | height:100%; 57 | text-align:center; 58 | color:#fff; 59 | overflow:hidden; 60 | 61 | -webkit-transform: skewY(-30deg) rotate(60deg); 62 | -ms-transform: skewY(-30deg) rotate(60deg); 63 | transform: skewY(-30deg) rotate(60deg); 64 | 65 | -webkit-backface-visibility:hidden; 66 | } 67 | 68 | /* HEX CONTENT */ 69 | 70 | #categories li img{ 71 | left:-100%; right:-100%; 72 | width: auto; height:100%; 73 | margin:0 auto; 74 | } 75 | /*#categories li span{ 76 | left:-100%; right:-100%; 77 | width: auto; height:100%; 78 | margin:0 auto; 79 | }*/ 80 | #categories div h1, #categories div p{ 81 | width:90%; 82 | padding:0 5%; 83 | background-color:#008080; background-color: rgba(0, 128, 128, 0.8); 84 | font-family: 'Raleway', sans-serif; 85 | 86 | -webkit-transition: top .2s ease-out, bottom .2s ease-out, .2s padding .2s ease-out; 87 | -ms-transition: top .2s ease-out, bottom .2s ease-out, .2s padding .2s ease-out; 88 | transition: top .2s ease-out, bottom .2s ease-out, .2s padding .2s ease-out; 89 | } 90 | #categories li h1{ 91 | bottom:110%; 92 | font-style:italic; 93 | font-weight:normal; 94 | font-size:1.5em; 95 | padding-top:100%; 96 | padding-bottom:100%; 97 | } 98 | #categories li h1:after{ 99 | content:''; 100 | display:block; 101 | position:absolute; 102 | bottom:-1px; left:45%; 103 | width:10%; 104 | text-align:center; 105 | z-index:1; 106 | border-bottom:2px solid #fff; 107 | } 108 | #categories li p{ 109 | padding-top:50%; 110 | top:110%; 111 | padding-bottom:50%; 112 | } 113 | 114 | /* HOVER EFFECT */ 115 | 116 | #categories li div:hover h1 { 117 | bottom:50%; 118 | padding-bottom:10%; 119 | } 120 | #categories li div:hover p{ 121 | top:50%; 122 | padding-top:10%; 123 | } 124 | #fork{ 125 | position:fixed; 126 | top:0; 127 | left:0; 128 | color:#000; 129 | text-decoration:none; 130 | border:1px solid #000; 131 | padding:.5em .7em; 132 | margin:1%; 133 | transition: color .5s; 134 | overflow:hidden; 135 | } 136 | #fork:before { 137 | content: ''; 138 | position: absolute; 139 | top: 0; left: 0; 140 | width: 130%; height: 100%; 141 | background: #000; 142 | z-index: -1; 143 | transform-origin:0 0 ; 144 | transform:translateX(-100%) skewX(-45deg); 145 | transition: transform .5s; 146 | } 147 | #fork:hover { 148 | color: #fff; 149 | } 150 | #fork:hover:before { 151 | transform: translateX(0) skewX(-45deg); 152 | } -------------------------------------------------------------------------------- /content/selectArrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyCurtisLives/VirtualDog/4dae694d7072a269a39c2dabddac889c86521c93/content/selectArrow.png -------------------------------------------------------------------------------- /content/zeusbackyard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyCurtisLives/VirtualDog/4dae694d7072a269a39c2dabddac889c86521c93/content/zeusbackyard.jpg -------------------------------------------------------------------------------- /content/zeusfrontyard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyCurtisLives/VirtualDog/4dae694d7072a269a39c2dabddac889c86521c93/content/zeusfrontyard.jpg -------------------------------------------------------------------------------- /content/zeusinside.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyCurtisLives/VirtualDog/4dae694d7072a269a39c2dabddac889c86521c93/content/zeusinside.jpg -------------------------------------------------------------------------------- /content/zeusmaster.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyCurtisLives/VirtualDog/4dae694d7072a269a39c2dabddac889c86521c93/content/zeusmaster.jpg -------------------------------------------------------------------------------- /content/zeuspark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyCurtisLives/VirtualDog/4dae694d7072a269a39c2dabddac889c86521c93/content/zeuspark.jpg -------------------------------------------------------------------------------- /content/zeussmile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyCurtisLives/VirtualDog/4dae694d7072a269a39c2dabddac889c86521c93/content/zeussmile.jpg -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require("gulp"), 2 | Server = require('karma').Server; 3 | 4 | gulp.task('test', function (done) { 5 | return new Server({ 6 | configFile: __dirname + '/karma.conf.js', 7 | singleRun: true 8 | }, done).start(); 9 | }); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Virtual Dog Blog 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Virtual Dog Blog 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | frameworks: ['jasmine'], 4 | reporters: ['spec'], 5 | browsers: ['PhantomJS'], 6 | // list of files / patterns to load in the browser 7 | files: [ 8 | 'bower_components/angular/angular.min.js', 9 | 'bower_components/angular-route/angular-route.min.js', 10 | 'node_modules/angular-mocks/angular-mocks.js', 11 | 'app/core/core.module.js', 12 | 'app/dogs/idog.js', 13 | 'app/core/config.js', 14 | 'app/core/constants.js', 15 | 'app/objects/dogObject.module.js', 16 | 'app/objects/dogObject.js', 17 | 'app/dogs/dog.module.js', 18 | 'app/dogs/dogController.js', 19 | 'test/*.js', 20 | 'test/**/*Spec.js' 21 | ], 22 | plugins : ['karma-jasmine', 'karma-phantomjs-launcher', 'karma-spec-reporter'] 23 | }); 24 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VirtualDog", 3 | "version": "0.0.1", 4 | "description": "App to demo AngularJs, Jasmine, TypeScript, and associated techs", 5 | "main": "index.js", 6 | "devDependencies": { 7 | "angular-mocks": "~1.3.15", 8 | "bower": "^1.7.9", 9 | "http-server": "^0.6.1", 10 | "jasmine": "^2.4.1", 11 | "node-promise": "^0.5.12", 12 | "typescript": "1.8.9", 13 | "typings": "1.0.4" 14 | }, 15 | "dependencies": { 16 | "bluebird": "^3.3.5", 17 | "concurrently": "^2.0.0", 18 | "node-rest-client": "^1.8.0" 19 | }, 20 | "scripts": { 21 | "postinstall": "bower install && typings install && echo Typings Installation version && typings -v && tsc && echo TypeScript Compilation version && tsc -v", 22 | "start": "concurrently --prefix-length 16 --prefix command \"http-server -a 0.0.0.0 -p 8042\" \"node server/tinyserv\" \"tsc -w\" ", 23 | "bower-typings": "bower install && typings install && echo Typings Installation version && typings -v", 24 | "bower": "bower", 25 | "typings": "typings", 26 | "tsc": "tsc", 27 | "tinyserv": "node server/tinyserv" 28 | }, 29 | "author": "Tony Curtis", 30 | "license": "MIT" 31 | } 32 | -------------------------------------------------------------------------------- /server/tinyserv.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import Http = require('http'); 4 | 5 | namespace toeknee.cors { 6 | export class CorsPassthru { 7 | private Client = require('node-rest-client').Client; 8 | private Promise = require('bluebird'); 9 | private restClient = new this.Client(); 10 | private server: Http.Server; 11 | 12 | // todo: pass in destination url root and url validation (for if test below) 13 | constructor() { 14 | this.initiate(); 15 | } 16 | 17 | public startServer() { 18 | this.server.listen(8200); 19 | console.log('Server running at ' + this.server.localAddress + ':' + this.server.localPort); 20 | } 21 | 22 | private initiate() { 23 | this.server = Http.createServer((request, response) => this.passThrough(request, response)); 24 | } 25 | 26 | private passThrough(request: Http.IncomingMessage, response: Http.ServerResponse) { 27 | console.log(request.url); 28 | // todo: for now only redirect the nasa stuff 29 | // in future make this generic 30 | // maybe config so we can either do JSON or other data 31 | if ((request.url).indexOf('mars-photos') > 0) { 32 | this.getAsync(request.url).then(function (data) { 33 | response.writeHead(200, { 34 | 'Content-Type': 'application/json', 35 | 'Access-Control-Allow-Origin': '*', 36 | 'Access-Control-Allow-Headers': 'X-Requested-With' 37 | }); 38 | response.write(JSON.stringify(data)); 39 | response.end(); 40 | }) 41 | .catch(function (err) { 42 | response.statusCode = 500; 43 | response.end(); 44 | }); 45 | } else { 46 | response.end(); 47 | }; 48 | } 49 | 50 | private getAsync(url: string) { 51 | return new this.Promise((resolve, reject) => { 52 | let args = { 53 | requestConfig: { 54 | timeout: 10000 55 | }, 56 | responseConfig: { 57 | timeout: 10000 58 | } 59 | }; 60 | // todo: make this more generic 61 | let destinationUrl = 'https://api.nasa.gov' + url; 62 | console.log('Destination: ' + destinationUrl); 63 | let returnData = ''; 64 | let req = this.restClient.get(destinationUrl, function (data, response) { 65 | console.log('Destination resolved'); 66 | resolve(data); 67 | }); 68 | 69 | req.on('requestTimeout', function (req) { 70 | console.log('request has expired'); 71 | req.abort(); 72 | reject('request expired'); 73 | }); 74 | 75 | req.on('responseTimeout', function (res) { 76 | console.log('response has expired'); 77 | reject('response expired'); 78 | }); 79 | 80 | req.on('error', function (err) { 81 | console.log('request error', err); 82 | reject('request error' + err); 83 | }); 84 | }); 85 | } 86 | } 87 | } 88 | 89 | new toeknee.cors.CorsPassthru().startServer(); 90 | -------------------------------------------------------------------------------- /test/MIT.LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2014 Pivotal Labs 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /test/SpecRunner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Jasmine Spec Runner 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /test/roverTestData.ts: -------------------------------------------------------------------------------- 1 | var roverTestData = 2 | { 3 | "photos": 4 | [ 5 | { 6 | "id": 532545, 7 | "sol": 1210, 8 | "camera": { 9 | "id": 20, "name": "FHAZ", "rover_id": 5, "full_name": "Front Hazard Avoidance Camera" 10 | }, 11 | "img_src": "http://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/01210/opgs/edr/fcam/FLB_504906873EDR_F0520004FHAZ00323M_.JPG", 12 | "earth_date": "2016-01-01", 13 | "rover": { 14 | "id": 5, 15 | "name": "Curiosity", 16 | "landing_date": "2012-08-06", 17 | "max_sol": 1332, 18 | "max_date": "2016-05-05", 19 | "total_photos": 253217, 20 | "cameras": [ 21 | { "name": "FHAZ", "full_name": "Front Hazard Avoidance Camera" }, 22 | { "name": "NAVCAM", "full_name": "Navigation Camera" }, 23 | { "name": "MAST", "full_name": "Mast Camera" }, 24 | { "name": "CHEMCAM", "full_name": "Chemistry and Camera Complex" }, 25 | { "name": "MAHLI", "full_name": "Mars Hand Lens Imager" }, 26 | { "name": "MARDI", "full_name": "Mars Descent Imager" }, 27 | { "name": "RHAZ", "full_name": "Rear Hazard Avoidance Camera" } 28 | ] 29 | } 30 | }, 31 | { 32 | "id": 532546, 33 | "sol": 1210, 34 | "camera": { 35 | "id": 20, "name": "FHAZ", "rover_id": 5, "full_name": "Front Hazard Avoidance Camera" 36 | }, 37 | "img_src": "http://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/01210/opgs/edr/fcam/FRB_504906873EDR_F0520004FHAZ00323M_.JPG", 38 | "earth_date": "2016-01-01", 39 | "rover": { 40 | "id": 5, 41 | "name": "Curiosity", 42 | "landing_date": "2012-08-06", 43 | "max_sol": 1332, 44 | "max_date": 45 | "2016-05-05", 46 | "total_photos": 253217, 47 | "cameras": [ 48 | { "name": "FHAZ", "full_name": "Front Hazard Avoidance Camera" }, 49 | { "name": "NAVCAM", "full_name": "Navigation Camera" }, 50 | { "name": "MAST", "full_name": "Mast Camera" }, 51 | { "name": "CHEMCAM", "full_name": "Chemistry and Camera Complex" }, 52 | { "name": "MAHLI", "full_name": "Mars Hand Lens Imager" }, 53 | { "name": "MARDI", "full_name": "Mars Descent Imager" }, 54 | { "name": "RHAZ", "full_name": "Rear Hazard Avoidance Camera" } 55 | ] 56 | } 57 | } 58 | ] 59 | }; 60 | -------------------------------------------------------------------------------- /test/spec/dogControllerSpec.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import vdog = dogsrus.virtdog; 3 | 4 | // todo: major refactoring, add event tests 5 | describe('dogController test', () => { 6 | beforeEach(angular.mock.module('app.dog')); 7 | describe('the dogController', () => { 8 | 9 | let $rootScope: ng.IRootScopeService, 10 | $controller: ng.IControllerService, 11 | $interval: ng.IIntervalService, 12 | dogConfig: vdog.DogConfiguration, 13 | //eventNames: vdog.EventNames, 14 | dogConstructorParams: { 15 | $rootScope: ng.IRootScopeService; 16 | $interval: ng.IIntervalService; 17 | dogConfig: vdog.DogConfiguration; 18 | eventNames: vdog.EventNames; 19 | }; 20 | 21 | dogConfig = { 22 | appTitle: 'Virtual Dog Demo', 23 | otherDogs: [], 24 | startDog: {}, 25 | version: '0.0.1' 26 | }; 27 | //eventNames = vdog.eventNames; 28 | beforeEach(() => { 29 | angular.mock.module('app.dog'); 30 | inject(($injector: ng.auto.IInjectorService) => { 31 | // we need to construct every time so set up for that 32 | $controller = $injector.get('$controller'); 33 | $rootScope = $injector.get('$rootScope'); 34 | $interval = $injector.get('$interval'); 35 | 36 | dogConstructorParams = { 37 | $rootScope: $rootScope, 38 | $interval: $interval, 39 | dogConfig: dogConfig, 40 | // this was changed too 41 | eventNames: vdog.eventNames 42 | }; 43 | }); 44 | }); 45 | describe('new', () => { 46 | // todo: add a beforeEach and move startdog settings and instantiation here 47 | it('construction test', () => { 48 | dogConfig.startDog.age = 99; 49 | dogConfig.startDog.barkSound = 'testbark'; 50 | dogConfig.startDog.breed = 'testbreed'; 51 | dogConfig.startDog.chewUrgeInterval = 1000 * 1 * 1 * 1; 52 | dogConfig.startDog.coatStyle = 'testCoatStyle'; 53 | dogConfig.startDog.defaultAction = 'testDefaultAction'; 54 | dogConfig.startDog.dogLonelyDuration = 1000 * 2 * 1 * 1; 55 | dogConfig.startDog.dogLonelyEndurance = 1000 * 3 * 1 * 1; 56 | dogConfig.startDog.dogSleepDuration = 1000 * 4 * 1 * 1; 57 | dogConfig.startDog.dogTiredInterval = 1000 * 5 * 1 * 1; 58 | dogConfig.startDog.earState = 'testEarState'; 59 | dogConfig.startDog.earStyle = 'testEarStyle'; 60 | dogConfig.startDog.familiarName = 'testFamiliarName'; 61 | dogConfig.startDog.motherNature1Interval = 1000 * 6 * 1 * 1; 62 | dogConfig.startDog.motherNature2Interval = 1000 * 7 * 1 * 1; 63 | dogConfig.startDog.speciesName = 'testSpeciesName'; 64 | dogConfig.startDog.startupBlog = 'testStartupBlog'; 65 | dogConfig.startDog.tailState = dogsrus.virtdog.DogTailState.tucked; 66 | dogConfig.startDog.tailStyle = 'testTailStyle'; 67 | 68 | let sut: dogsrus.virtdog.DogController = $controller( 69 | 'dogController', dogConstructorParams) 70 | 71 | expect(sut.age).toEqual(dogConfig.startDog.age); 72 | expect(sut.barkSound).toEqual(dogConfig.startDog.barkSound); 73 | expect(sut.breed).toEqual(dogConfig.startDog.breed); 74 | expect(sut.chewUrgeInterval).toEqual(dogConfig.startDog.chewUrgeInterval); 75 | expect(sut.coatStyle).toEqual(dogConfig.startDog.coatStyle); 76 | expect(sut.defaultAction).toEqual(dogConfig.startDog.defaultAction); 77 | expect(sut.dogLonelyDuration).toEqual(dogConfig.startDog.dogLonelyDuration); 78 | expect(sut.dogLonelyEndurance).toEqual(dogConfig.startDog.dogLonelyEndurance); 79 | expect(sut.dogSleepDuration).toEqual(dogConfig.startDog.dogSleepDuration); 80 | expect(sut.dogTiredInterval).toEqual(dogConfig.startDog.dogTiredInterval); 81 | expect(sut.earState).toEqual(dogConfig.startDog.earState); 82 | expect(sut.earStyle).toEqual(dogConfig.startDog.earStyle); 83 | expect(sut.familiarName).toEqual(dogConfig.startDog.familiarName); 84 | expect(sut.motherNature1Interval).toEqual(dogConfig.startDog.motherNature1Interval); 85 | expect(sut.motherNature2Interval).toEqual(dogConfig.startDog.motherNature2Interval); 86 | expect(sut.speciesName).toEqual(dogConfig.startDog.speciesName); 87 | expect(sut.startupBlog).toEqual(dogConfig.startDog.startupBlog); 88 | expect(sut.tailState).toEqual(dogConfig.startDog.tailState); 89 | expect(sut.tailStyle).toEqual(dogConfig.startDog.tailStyle); 90 | }); 91 | it('other stuff happens when new', () => { 92 | pending('add other constructor tests'); 93 | }); 94 | }); 95 | // todo: need to test feed event 96 | 97 | // todo: need to test thow event 98 | }); 99 | }); 100 | 101 | -------------------------------------------------------------------------------- /test/spec/dogObjectSpec.ts: -------------------------------------------------------------------------------- 1 | describe('In the file dogObject.js', function () { 2 | describe('the dogObject\'s', function () { 3 | let sut: dogsrus.virtdog.DogObject; 4 | beforeEach(function () { 5 | sut = new dogsrus.virtdog.DogObject('test', true, false); 6 | }); 7 | describe('chewOn function', function () { 8 | describe('for an object with no dog spit', function () { 9 | it('should set spitState to someSpit', function () { 10 | expect(sut.spitState).toEqual( 11 | dogsrus.virtdog.DogSpitState.noSpit); 12 | 13 | sut.chewOn(); 14 | 15 | expect(sut.spitState).toEqual( 16 | dogsrus.virtdog.DogSpitState.someSpit); 17 | }); 18 | }); 19 | 20 | describe('for an impervious object', function () { 21 | it('should not change state', function () { 22 | sut.impervious = true; 23 | let expectedState = sut.state; 24 | 25 | sut.chewOn(); 26 | 27 | expect(sut.state).toEqual(expectedState); 28 | }); 29 | }); 30 | 31 | describe('for an expensive object of $150 value', function () { 32 | beforeEach(function () { 33 | sut.expensive = true; 34 | sut.monetaryValue = 150; 35 | }); 36 | it('should reduce the value by half', function () { 37 | 38 | sut.chewOn(); 39 | 40 | expect(sut.monetaryValue).toEqual(150 / 2); 41 | }); 42 | it('should set expensive to false', function () { 43 | 44 | sut.chewOn(); 45 | 46 | expect(sut.expensive).toBeFalsy(); 47 | }); 48 | }); 49 | 50 | describe('for an object in mint condition', function () { 51 | describe('with chewLimit of 0', function () { 52 | it('should degrade state', function () { 53 | sut.chewOn(); 54 | 55 | expect(sut.state).toEqual(dogsrus.virtdog.ObjectState.littleBitChewed); 56 | }); 57 | }); 58 | describe('with chewLimit of 10', function () { 59 | beforeEach(function () { 60 | sut.chewLimit = 10; 61 | }); 62 | it('should degrade state', function () { 63 | sut.chewOn(); 64 | 65 | expect(sut.state).toEqual(dogsrus.virtdog.ObjectState.littleBitChewed); 66 | }); 67 | it('should reduce chewLimit', function () { 68 | sut.chewOn(); 69 | 70 | expect(sut.chewLimit).toEqual(9); 71 | }); 72 | }); 73 | }); 74 | 75 | describe('for an object with state of littleBitChewed', function () { 76 | beforeEach(function () { 77 | sut.state = dogsrus.virtdog.ObjectState.littleBitChewed; 78 | }); 79 | describe('with chewLimit of 11', function () { 80 | beforeEach(function () { 81 | sut.chewLimit = 11; 82 | }); 83 | it('should not degrade state', function () { 84 | sut.chewOn(); 85 | 86 | expect(sut.state).toEqual(dogsrus.virtdog.ObjectState.littleBitChewed); 87 | }); 88 | it('should reduce chewLimit', function () { 89 | sut.chewOn(); 90 | 91 | expect(sut.chewLimit).toEqual(10); 92 | }); 93 | }); 94 | 95 | describe('with chewLimit of 10', function () { 96 | beforeEach(function () { 97 | sut.chewLimit = 10; 98 | }); 99 | it('should degrade state', function () { 100 | sut.chewOn(); 101 | 102 | expect(sut.state).toEqual(dogsrus.virtdog.ObjectState.veryChewed); 103 | }); 104 | it('should reduce chewLimit', function () { 105 | sut.chewOn(); 106 | 107 | expect(sut.chewLimit).toEqual(9); 108 | }); 109 | }); 110 | 111 | describe('with chewLimit of 0', function () { 112 | it('should degrade state', function () { 113 | sut.chewOn(); 114 | 115 | expect(sut.state).toEqual(dogsrus.virtdog.ObjectState.veryChewed); 116 | }); 117 | }); 118 | }); 119 | 120 | describe('for an object with state of veryChewed', function () { 121 | beforeEach(function () { 122 | sut.state = dogsrus.virtdog.ObjectState.veryChewed; 123 | }); 124 | describe('with chewLimit of 6', function () { 125 | beforeEach(function () { 126 | sut.chewLimit = 6; 127 | }); 128 | it('should not degrade state', function () { 129 | sut.chewOn(); 130 | 131 | expect(sut.state).toEqual(dogsrus.virtdog.ObjectState.veryChewed); 132 | }); 133 | it('should reduce chewLimit', function () { 134 | sut.chewOn(); 135 | 136 | expect(sut.chewLimit).toEqual(5); 137 | }); 138 | }); 139 | 140 | describe('with chewLimit of 5', function () { 141 | beforeEach(function () { 142 | sut.chewLimit = 5; 143 | }); 144 | it('should degrade state', function () { 145 | sut.chewOn(); 146 | 147 | expect(sut.state).toEqual(dogsrus.virtdog.ObjectState.structurallyDamaged); 148 | }); 149 | it('should reduce chewLimit', function () { 150 | sut.chewOn(); 151 | 152 | expect(sut.chewLimit).toEqual(4); 153 | }); 154 | }); 155 | 156 | describe('with chewLimit of 0', function () { 157 | describe('and not shredable', function () { 158 | it('should degrade state to structurallyDamaged', function () { 159 | sut.chewOn(); 160 | 161 | expect(sut.state).toEqual(dogsrus.virtdog.ObjectState.structurallyDamaged); 162 | }); 163 | }); 164 | describe('and shredable', function () { 165 | beforeEach(function () { 166 | sut.shredable = true; 167 | }); 168 | it('should degrade state to shredded', function () { 169 | sut.chewOn(); 170 | 171 | expect(sut.state).toEqual(dogsrus.virtdog.ObjectState.shredded); 172 | }); 173 | }); 174 | }); 175 | }); 176 | }); 177 | }); 178 | }); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "preserveConstEnums": true, 6 | "inlineSourceMap": true 7 | }, 8 | "exclude": [ 9 | "node_modules", 10 | "bower_components", 11 | "typings" 12 | ] 13 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "class-name": true, 4 | "comment-format": [true, "check-space"], 5 | "curly": true, 6 | "eofline": true, 7 | "forin": true, 8 | "indent": [true, "spaces"], 9 | "label-position": true, 10 | "label-undefined": true, 11 | "max-line-length": [true, 140], 12 | "member-access": true, 13 | "member-ordering": [true, 14 | "public-before-private", 15 | "static-before-instance", 16 | "variables-before-functions" 17 | ], 18 | "no-arg": true, 19 | "no-bitwise": true, 20 | "no-console": [true, 21 | "debug", 22 | "info", 23 | "time", 24 | "timeEnd", 25 | "trace" 26 | ], 27 | "no-construct": true, 28 | "no-debugger": true, 29 | "no-duplicate-key": true, 30 | "no-duplicate-variable": true, 31 | "no-empty": true, 32 | "no-eval": true, 33 | "no-inferrable-types": true, 34 | "no-shadowed-variable": true, 35 | "no-string-literal": true, 36 | "no-switch-case-fall-through": true, 37 | "no-trailing-whitespace": true, 38 | "no-unused-expression": true, 39 | "no-unused-variable": true, 40 | "no-unreachable": true, 41 | "no-use-before-declare": true, 42 | "no-var-keyword": true, 43 | "object-literal-sort-keys": true, 44 | "one-line": [true, 45 | "check-open-brace", 46 | "check-catch", 47 | "check-else", 48 | "check-finally", 49 | "check-whitespace" 50 | ], 51 | "quotemark": [true, "single", "avoid-escape"], 52 | "radix": true, 53 | "semicolon": true, 54 | "trailing-comma": [true, { 55 | "singleline": "never", 56 | "multiline": "never" 57 | }], 58 | "triple-equals": [true, "allow-null-check"], 59 | "typedef-whitespace": [true, { 60 | "call-signature": "nospace", 61 | "index-signature": "nospace", 62 | "parameter": "nospace", 63 | "property-declaration": "nospace", 64 | "variable-declaration": "nospace" 65 | }], 66 | "variable-name": false, 67 | "whitespace": [true, 68 | "check-branch", 69 | "check-decl", 70 | "check-operator", 71 | "check-separator", 72 | "check-type" 73 | ] 74 | } 75 | } -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VitrualDog", 3 | "dependencies": { 4 | "bluebird": "registry:npm/bluebird#3.3.4+20160515010139" 5 | }, 6 | "globalDevDependencies": { 7 | "angular-mocks": "registry:dt/angular-mocks#1.3.0+20160425155016", 8 | "jasmine": "registry:dt/jasmine#2.2.0+20160505161446" 9 | }, 10 | "globalDependencies": { 11 | "angular": "registry:dt/angular#1.5.0+20160517064839", 12 | "jquery": "registry:dt/jquery#1.10.0+20160417213236", 13 | "node": "registry:env/node#6.0.0+20160918225031" 14 | } 15 | } 16 | --------------------------------------------------------------------------------
15 | Object: 16 | 17 | Action: 18 | $nbspPerform Action 19 |
28 | Domain: 30 | 31 | 32 |
72 | Camera: 73 |  Get Rover Photos 74 | 77 | 78 |
103 | Person: 104 | 105 | Action: 106 | 107 | Perform Action 108 |
116 | Animal: 118 | 119 | 120 |