├── .gitignore ├── .nuget ├── NuGet.Config ├── NuGet.exe └── NuGet.targets ├── README.md ├── ngPlaybook.sln └── ngPlaybook ├── Apps ├── common │ ├── js │ │ ├── directives │ │ │ ├── alerts.js │ │ │ └── workSpinner.js │ │ └── services │ │ │ ├── addToken.js │ │ │ ├── alerting.js │ │ │ ├── currentUser.js │ │ │ ├── exceptionHandler.js │ │ │ ├── formEncode.js │ │ │ ├── interpolateDebug.js │ │ │ ├── localStorage.js │ │ │ ├── log.js │ │ │ ├── loginRedirect.js │ │ │ ├── oauth.js │ │ │ └── requestCounter.js │ ├── module.js │ └── templates │ │ └── alerts.html ├── diagnostics │ ├── js │ │ └── controllers │ │ │ └── errorProneController.js │ ├── module.js │ ├── shell.html │ └── templates │ │ └── nav.html ├── forms │ ├── js │ │ ├── controllers │ │ │ ├── editProfileController.js │ │ │ └── resultController.js │ │ ├── directives │ │ │ ├── forminput.js │ │ │ ├── rating.js │ │ │ ├── startsWith.js │ │ │ └── username.js │ │ └── services │ │ │ └── user.js │ ├── module.js │ ├── shell.html │ └── templates │ │ ├── home.html │ │ ├── messages.html │ │ ├── nav.html │ │ ├── rating.html │ │ └── results.html ├── integration │ ├── js │ │ ├── controllers │ │ │ └── movingObjects.js │ │ ├── directives │ │ │ ├── knob.js │ │ │ ├── phsicsEdgeDetection.js │ │ │ ├── physicsBehavior.js │ │ │ ├── physicsBody.js │ │ │ ├── physicsCanvas.js │ │ │ └── tubular.js │ │ └── services │ │ │ └── physics.js │ ├── module.js │ ├── shell.html │ └── templates │ │ ├── nav.html │ │ └── physicsCanvas.html ├── security │ ├── js │ │ ├── controllers │ │ │ ├── loginController.js │ │ │ └── secretController.js │ │ └── services │ │ │ └── recipes.js │ ├── module.js │ ├── shell.html │ └── templates │ │ ├── ajax-loader.gif │ │ ├── home.html │ │ ├── login.html │ │ ├── nav.html │ │ └── secret.html └── ui │ ├── js │ ├── controllers │ │ ├── adminController.js │ │ ├── costController.js │ │ ├── customersController.js │ │ ├── injuriesController.js │ │ └── overallController.js │ ├── directives │ │ ├── calendar.js │ │ ├── navbar.js │ │ ├── rating.js │ │ └── rating2.js │ └── services │ │ ├── confirmPromotion.js │ │ ├── employee.js │ │ └── stateChangeErrors.js │ ├── module.js │ ├── shell.html │ └── templates │ ├── admin.html │ ├── confirmPromotion.html │ ├── costs.html │ ├── customers.html │ ├── dashboard.html │ ├── injuries.html │ ├── nav.html │ ├── overall.html │ └── rating2.html ├── Global.asax ├── Global.asax.cs ├── Js ├── angular │ ├── angular-animate.js │ ├── angular-aria.js │ ├── angular-cookies.js │ ├── angular-loader.js │ ├── angular-messages.js │ ├── angular-mocks.js │ ├── angular-resource.js │ ├── angular-route.js │ ├── angular-sanitize.js │ ├── angular-scenario.js │ ├── angular-touch.js │ └── angular.js ├── google-chart │ └── google-chart.js ├── jasmine │ ├── boot.js │ ├── console.js │ ├── jasmine-html.js │ ├── jasmine.css │ ├── jasmine.js │ └── jasmine_favicon.png ├── jquery.knob │ └── jquery.knob.js ├── jquery │ └── jquery-2.1.3.js ├── physicsjs │ └── physicsjs-full.js ├── tubular │ └── tubular.js ├── ui-bootstrap │ └── ui-bootstrap-tpls.js └── ui-router │ └── ui-router.js ├── Properties └── AssemblyInfo.cs ├── Protractor ├── pages │ ├── Config.js │ ├── DiagnosticsPage.js │ ├── HomePage.js │ ├── LoginPage.js │ └── SecretRecipePage.js ├── protractor.conf.js └── specs │ ├── diagnosticsSpecs.js │ ├── loginSpecs.js │ └── redirectSpecs.js ├── Server ├── Api │ ├── NameValidationController.cs │ └── SecretController.cs ├── Auth │ ├── OdeToFoodJwtOptions.cs │ ├── OdeToFoodJwtWriterFormat.cs │ ├── OdeToFoodOAuthOptions.cs │ └── OdeToFoodOAuthProvider.cs ├── Config │ └── AppConfiguration.cs ├── Models │ └── Recipe.cs └── Startup │ ├── OwinStartup.cs │ └── WebApiStartup.cs ├── Styles ├── animate.css ├── css │ └── bootstrap.css ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── js │ └── bootstrap.js └── site.css ├── Web.Debug.config ├── Web.Release.config ├── Web.config ├── default.html ├── ngPlaybook.csproj └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | *resharper.user 2 | [Dd]ebug/ 3 | [Rr]elease/ 4 | build/ 5 | [Bb]in/ 6 | [Oo]bj/ 7 | *.suo 8 | *.mdf 9 | *.ldf 10 | *.sln.cache 11 | _ReSharper.*/ 12 | *.resharper 13 | resharper.settings.xml 14 | *.user 15 | [Bb]uild* 16 | [Dd]ist 17 | junit-report 18 | junit 19 | ProfilerMessage.java 20 | 0 21 | *.g.csproj 22 | temp-war-deps 23 | /.gitversion.tmp 24 | /.gitversion.short.tmp 25 | *.vspscc 26 | *.bak 27 | *.scc 28 | *.xap 29 | MSSCCPRJ.SCC 30 | DebugLog.* 31 | *.orig 32 | *.log 33 | log.txt 34 | *.docstates 35 | *.mp4 36 | *.mp3 37 | *.mov 38 | .idea 39 | .DS_Store 40 | .sdf 41 | packages/ 42 | TestResults/ -------------------------------------------------------------------------------- /.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OdeToCode/ngplaybook/8e1299cdae87c860d2828c4477f6db235e0d289a/.nuget/NuGet.exe -------------------------------------------------------------------------------- /.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | 6 | 7 | false 8 | 9 | 10 | false 11 | 12 | 13 | true 14 | 15 | 16 | false 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 31 | 32 | 33 | 34 | 35 | $(SolutionDir).nuget 36 | 37 | 38 | 39 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config 40 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config 41 | 42 | 43 | 44 | $(MSBuildProjectDirectory)\packages.config 45 | $(PackagesProjectConfig) 46 | 47 | 48 | 49 | 50 | $(NuGetToolsPath)\NuGet.exe 51 | @(PackageSource) 52 | 53 | "$(NuGetExePath)" 54 | mono --runtime=v4.0.30319 "$(NuGetExePath)" 55 | 56 | $(TargetDir.Trim('\\')) 57 | 58 | -RequireConsent 59 | -NonInteractive 60 | 61 | "$(SolutionDir) " 62 | "$(SolutionDir)" 63 | 64 | 65 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) 66 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols 67 | 68 | 69 | 70 | RestorePackages; 71 | $(BuildDependsOn); 72 | 73 | 74 | 75 | 76 | $(BuildDependsOn); 77 | BuildPackage; 78 | 79 | 80 | 81 | 82 | 83 | 84 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 99 | 100 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ngplaybook 2 | ========== 3 | -------------------------------------------------------------------------------- /ngPlaybook.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ngPlaybook", "ngPlaybook\ngPlaybook.csproj", "{A5DFC2C8-8F18-4A5C-A187-13743E4E6B98}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{BCDB3875-538C-484B-A24E-075A9FBD16DF}" 9 | ProjectSection(SolutionItems) = preProject 10 | .nuget\NuGet.Config = .nuget\NuGet.Config 11 | .nuget\NuGet.exe = .nuget\NuGet.exe 12 | .nuget\NuGet.targets = .nuget\NuGet.targets 13 | EndProjectSection 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {A5DFC2C8-8F18-4A5C-A187-13743E4E6B98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {A5DFC2C8-8F18-4A5C-A187-13743E4E6B98}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {A5DFC2C8-8F18-4A5C-A187-13743E4E6B98}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {A5DFC2C8-8F18-4A5C-A187-13743E4E6B98}.Release|Any CPU.Build.0 = Release|Any CPU 25 | EndGlobalSection 26 | GlobalSection(SolutionProperties) = preSolution 27 | HideSolutionNode = FALSE 28 | EndGlobalSection 29 | EndGlobal 30 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/js/directives/alerts.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | var alerts = function(alerting) { 4 | return { 5 | restrict: "AE", 6 | templateUrl: "/apps/common/templates/alerts.html", 7 | scope: true, 8 | controller: function($scope) { 9 | $scope.removeAlert = function(alert) { 10 | alerting.removeAlert(alert); 11 | }; 12 | }, 13 | link: function(scope) { 14 | scope.currentAlerts = alerting.currentAlerts; 15 | } 16 | }; 17 | }; 18 | 19 | module.directive("alerts", alerts); 20 | 21 | }(angular.module("common"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/js/directives/workSpinner.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | var workSpinner = function (requestCounter) { 4 | return { 5 | restrict: "EAC", 6 | transclude: true, 7 | scope: {}, 8 | template: "", 9 | link: function (scope) { 10 | 11 | scope.$watch(function () { 12 | return requestCounter.getRequestCount(); 13 | }, function(requestCount) { 14 | scope.requestCount = requestCount; 15 | }); 16 | 17 | } 18 | }; 19 | }; 20 | 21 | module.directive("workSpinner", workSpinner); 22 | 23 | }(angular.module("common"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/js/services/addToken.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | var addToken = function(currentUser, $q) { 4 | 5 | return { 6 | request: function(config) { 7 | if (currentUser.profile.token) { 8 | config.headers.Authorization = "Bearer " + currentUser.profile.token; 9 | } 10 | return $q.when(config); 11 | } 12 | }; 13 | }; 14 | 15 | module.factory("addToken", addToken); 16 | module.config(function($httpProvider) { 17 | $httpProvider.interceptors.push("addToken"); 18 | }); 19 | 20 | })(angular.module("common")); -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/js/services/alerting.js: -------------------------------------------------------------------------------- 1 | (function(common) { 2 | 3 | var alerting = function($timeout) { 4 | 5 | var currentAlerts = []; 6 | var alertTypes = ["info", "warning", "success", "danger"]; 7 | 8 | var addWarning = function (message) { 9 | addAlert("warning", message); 10 | }; 11 | 12 | var addInfo = function(message) { 13 | addAlert("info", message); 14 | }; 15 | 16 | var addDanger = function(message) { 17 | addAlert("danger", message); 18 | }; 19 | 20 | var addSuccess = function(message) { 21 | addAlert("success", message); 22 | }; 23 | 24 | var addAlert = function(type, message) { 25 | var alert = { type: type, message: message }; 26 | currentAlerts.push(alert); 27 | 28 | $timeout(function() { 29 | removeAlert(alert); 30 | }, 10000); 31 | }; 32 | 33 | var removeAlert = function(alert) { 34 | for (var i = 0; i < currentAlerts.length; i++) { 35 | if (currentAlerts[i] == alert) { 36 | currentAlerts.splice(i, 1); 37 | break; 38 | } 39 | } 40 | }; 41 | 42 | var errorHandler = function(description) { 43 | return function() { 44 | addDanger(description); 45 | }; 46 | }; 47 | 48 | 49 | return { 50 | removeAlert: removeAlert, 51 | addAlert: addAlert, 52 | errorHandler: errorHandler, 53 | addInfo: addInfo, 54 | addWarning: addWarning, 55 | currentAlerts: currentAlerts, 56 | alertTypes: alertTypes, 57 | addSuccess: addSuccess, 58 | addDanger: addDanger 59 | }; 60 | 61 | }; 62 | 63 | common.factory("alerting", alerting); 64 | 65 | }(angular.module("common"))) -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/js/services/currentUser.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | var USERKEY = "utoken"; 4 | 5 | var currentUser = function (localStorage) { 6 | 7 | var saveUser = function () { 8 | localStorage.add(USERKEY, profile); 9 | }; 10 | 11 | var removeUser = function () { 12 | localStorage.remove(USERKEY); 13 | }; 14 | 15 | var initialize = function() { 16 | var user = { 17 | username: "", 18 | token: "", 19 | get loggedIn() { 20 | return this.token ? true : false; 21 | } 22 | }; 23 | 24 | var localUser = localStorage.get(USERKEY); 25 | if (localUser) { 26 | user.username = localUser.username; 27 | user.token = localUser.token; 28 | } 29 | return user; 30 | } 31 | 32 | var profile = initialize(); 33 | 34 | return { 35 | save: saveUser, 36 | remove: removeUser, 37 | profile: profile 38 | }; 39 | }; 40 | 41 | module.factory("currentUser", currentUser); 42 | 43 | }(angular.module("common"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/js/services/exceptionHandler.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | module.config(function($provide) { 4 | $provide.decorator("$exceptionHandler", function($delegate, $injector) { 5 | return function(exception, cause) { 6 | $delegate(exception, cause); 7 | var alerting = $injector.get("alerting"); 8 | alerting.addDanger(exception.message); 9 | }; 10 | }); 11 | }); 12 | 13 | }(angular.module("common"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/js/services/formEncode.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | var formEncode = function() { 4 | return function(data) { 5 | var pairs = []; 6 | for (var name in data) { 7 | pairs.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name])); 8 | } 9 | return pairs.join('&').replace(/%20/g, '+'); 10 | }; 11 | }; 12 | 13 | module.factory("formEncode", formEncode); 14 | 15 | }(angular.module("common"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/js/services/interpolateDebug.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | module.config(function ($provide) { 4 | $provide.decorator("$interpolate", function ($delegate, $log) { 5 | 6 | var serviceWrapper = function () { 7 | var bindingFn = $delegate.apply(this, arguments); 8 | if (angular.isFunction(bindingFn) && arguments[0]) { 9 | return bindingWrapper(bindingFn, arguments[0].trim()); 10 | } 11 | return bindingFn; 12 | }; 13 | 14 | var bindingWrapper = function (bindingFn, bindingExpression) { 15 | return function () { 16 | var result = bindingFn.apply(this, arguments); 17 | var trimmedResult = result.trim(); 18 | var log = trimmedResult ? $log.info : $log.warn; 19 | log.call($log, bindingExpression + " = " + trimmedResult); 20 | return result; 21 | }; 22 | }; 23 | 24 | angular.extend(serviceWrapper, $delegate); 25 | return serviceWrapper; 26 | 27 | }); 28 | }); 29 | 30 | }(angular.module("common"))); 31 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/js/services/localStorage.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | var localStorage = function($window) { 4 | 5 | var store = $window.localStorage; 6 | 7 | var add = function (key, value) { 8 | value = angular.toJson(value); 9 | store.setItem(key, value); 10 | }; 11 | 12 | var get = function(key) { 13 | var value = store.getItem(key); 14 | if (value) { 15 | value = angular.fromJson(value); 16 | } 17 | return value; 18 | }; 19 | 20 | var remove = function(key) { 21 | store.removeItem(key); 22 | }; 23 | 24 | return { 25 | add: add, 26 | get: get, 27 | remove: remove 28 | }; 29 | }; 30 | 31 | module.factory("localStorage", localStorage); 32 | 33 | }(angular.module("common"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/js/services/log.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | module.config(function($provide) { 4 | $provide.decorator("$log", function($delegate, $injector) { 5 | 6 | var log = function(message) { 7 | var alerting = $injector.get("alerting"); 8 | alerting.addInformation(message); 9 | return $delegate.log(message); 10 | }; 11 | 12 | var warn = function(message) { 13 | var alerting = $injector.get("alerting"); 14 | alerting.addWarning(message); 15 | return $delegate.info(message); 16 | }; 17 | 18 | var info = function(message) { 19 | var alerting = $injector.get("alerting"); 20 | alerting.addInformation(message); 21 | return $delegate.info(message); 22 | }; 23 | 24 | var error = function(message) { 25 | var alerting = $injector.get("alerting"); 26 | alerting.addDanger(message); 27 | return $delegate.info(message); 28 | }; 29 | 30 | return { 31 | log: log, 32 | warn: warn, 33 | info: info, 34 | error: error 35 | }; 36 | }); 37 | }); 38 | 39 | }(angular.module("common"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/js/services/loginRedirect.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | var loginRedirect = function () { 4 | 5 | var loginUrl = "/login"; 6 | var lastPath = ""; 7 | 8 | this.setLoginUrl = function (value) { 9 | loginUrl = value; 10 | }; 11 | 12 | this.$get = function ($q, $location) { 13 | 14 | return { 15 | 16 | responseError: function (response) { 17 | if (response.status == 401) { 18 | lastPath = $location.path(); 19 | $location.path(loginUrl); 20 | } 21 | return $q.reject(response); 22 | }, 23 | 24 | redirectPreLogin: function () { 25 | if (lastPath) { 26 | $location.path(lastPath); 27 | lastPath = ""; 28 | 29 | } else { 30 | $location.path("/"); 31 | } 32 | } 33 | }; 34 | }; 35 | }; 36 | 37 | module.provider("loginRedirect", loginRedirect); 38 | module.config(function($httpProvider) { 39 | $httpProvider.interceptors.push("loginRedirect"); 40 | }); 41 | 42 | }(angular.module("common"))) -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/js/services/oauth.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | var oauth = function () { 4 | 5 | var url = "/login"; 6 | 7 | this.setUrl = function (newUrl) { 8 | url = newUrl; 9 | }; 10 | 11 | this.$get = function ($http, formEncode, currentUser) { 12 | 13 | var processToken = function (username) { 14 | return function (response) { 15 | currentUser.profile.username = username; 16 | currentUser.profile.token = response.data.access_token; 17 | currentUser.save(); 18 | return username; 19 | } 20 | }; 21 | 22 | var login = function (username, password) { 23 | 24 | var configuration = { 25 | headers: { 26 | "Content-Type": "application/x-www-form-urlencoded" 27 | } 28 | }; 29 | 30 | var data = formEncode({ 31 | username: username, 32 | password: password, 33 | grant_type: "password" 34 | }); 35 | 36 | return $http.post(url, data, configuration).then(processToken(username)); 37 | }; 38 | 39 | var logout = function() { 40 | currentUser.profile.username = ""; 41 | currentUser.profile.token = ""; 42 | currentUser.remove(); 43 | }; 44 | 45 | return { 46 | login: login, 47 | logout: logout 48 | }; 49 | } 50 | }; 51 | 52 | module.config(function ($provide) { 53 | $provide.provider("oauth", oauth); 54 | }); 55 | 56 | }(angular.module("common"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/js/services/requestCounter.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | var requestCounter = function($q) { 4 | 5 | var requests = 0; 6 | 7 | var request = function(config) { 8 | requests += 1; 9 | return $q.when(config); 10 | }; 11 | 12 | var requestError = function(error) { 13 | requests -= 1; 14 | return $q.reject(error); 15 | }; 16 | 17 | var response = function(response) { 18 | requests -= 1; 19 | return $q.when(response); 20 | }; 21 | 22 | var responseError = function(error) { 23 | requests -= 1; 24 | return $q.reject(error); 25 | }; 26 | 27 | var getRequestCount = function() { 28 | return requests; 29 | }; 30 | 31 | return { 32 | request: request, 33 | response: response, 34 | requestError: requestError, 35 | responseError: responseError, 36 | getRequestCount: getRequestCount 37 | }; 38 | 39 | }; 40 | 41 | module.factory("requestCounter", requestCounter); 42 | 43 | module.config(function($httpProvider) { 44 | $httpProvider.interceptors.push("requestCounter"); 45 | }); 46 | 47 | }(angular.module("common"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | var module = angular.module("common", ["ngAnimate"]); 4 | 5 | }()); -------------------------------------------------------------------------------- /ngPlaybook/Apps/common/templates/alerts.html: -------------------------------------------------------------------------------- 1 | 
2 | {{ alert.message }} 3 |
4 | 5 |
6 |
-------------------------------------------------------------------------------- /ngPlaybook/Apps/diagnostics/js/controllers/errorProneController.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | var errorProneController = function(alerting) { 4 | var model = this; 5 | 6 | model.alertTypes = alerting.alertTypes; 7 | model.alertMessage = ""; 8 | model.alertType = model.alertTypes[0]; 9 | 10 | model.createAlert = function() { 11 | alerting.addAlert(model.alertType, model.alertMessage); 12 | model.alertMessage = ""; 13 | model.alertType = model.alertTypes[0]; 14 | }; 15 | 16 | model.createException = function() { 17 | throw new Error("Something has gone terribly wrong!"); 18 | }; 19 | }; 20 | 21 | module.controller("errorProneController", errorProneController); 22 | 23 | }(angular.module("diagnostics"))) -------------------------------------------------------------------------------- /ngPlaybook/Apps/diagnostics/module.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | var module = angular.module("diagnostics", ["common"]); 4 | 5 | }()); -------------------------------------------------------------------------------- /ngPlaybook/Apps/diagnostics/shell.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | Ode To Food 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 |
16 |
17 |
18 |
19 |

Alerts

20 |
21 | 22 |
23 |
24 | 27 |
28 | 29 |
30 |
31 |
32 |

Exceptions

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 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/diagnostics/templates/nav.html: -------------------------------------------------------------------------------- 1 |  8 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/forms/js/controllers/editProfileController.js: -------------------------------------------------------------------------------- 1 |  2 | (function (module) { 3 | 4 | var editProfileController = function(user, $location) { 5 | this.user = user; 6 | 7 | this.submit = function(isValid) { 8 | if (isValid) { 9 | $location.path("/results"); 10 | } 11 | }; 12 | }; 13 | 14 | module.controller("editProfileController", editProfileController); 15 | 16 | }(angular.module("forms"))); 17 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/forms/js/controllers/resultController.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | var resultController = function (user) { 4 | this.user = user; 5 | }; 6 | 7 | module.controller("resultController", resultController); 8 | 9 | }(angular.module("forms"))); 10 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/forms/js/directives/forminput.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | var watcherFor = function (form, name) { 4 | return function () { 5 | if (name && form[name]) { 6 | return form[name].$invalid; 7 | } 8 | }; 9 | }; 10 | 11 | var updaterFor = function (element) { 12 | return function (hasError) { 13 | if (hasError) { 14 | element.removeClass("has-success") 15 | .addClass("has-error"); 16 | } else { 17 | element.addClass("has-success") 18 | .removeClass("has-error"); 19 | } 20 | }; 21 | }; 22 | 23 | var setupDom = function (element) { 24 | var input = element[0].querySelector("input, textarea, select, otf-rating"); 25 | var type = input.getAttribute("type"); 26 | var name = input.getAttribute("name"); 27 | if (type !== "checkbox" && type !== "radio") { 28 | input.classList.add("form-control"); 29 | } 30 | 31 | var label = element[0].querySelector("label"); 32 | label.classList.add("control-label"); 33 | return name; 34 | }; 35 | 36 | var addMessages = function(form, element, name, $compile, scope) { 37 | var messages = "
"; 40 | element.append($compile(messages)(scope)); 41 | }; 42 | 43 | var link = function ($compile) { 44 | return function(scope, element, attributes, form) { 45 | var name = setupDom(element); 46 | addMessages(form, element, name, $compile, scope); 47 | scope.$watch(watcherFor(form, name), updaterFor(element)); 48 | } 49 | }; 50 | 51 | var forminput = function ($compile) { 52 | 53 | return { 54 | restrict: "A", 55 | require: "^form", 56 | link: link($compile) 57 | }; 58 | 59 | }; 60 | 61 | module.directive("forminput", forminput); 62 | 63 | }(angular.module("forms"))); 64 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/forms/js/directives/rating.js: -------------------------------------------------------------------------------- 1 |  2 | (function (module) { 3 | 4 | var otfRatingController = function($scope) { 5 | 6 | var ngModel; 7 | 8 | this.initialize = function(min, max, modelController) { 9 | ngModel = modelController; 10 | ngModel.$render = this.render; 11 | 12 | $scope.stars = new Array(max - min + 1); 13 | }; 14 | 15 | this.render = function () { 16 | $scope.value = ngModel.$viewValue; 17 | }; 18 | 19 | $scope.mouseover = function($index) { 20 | $scope.preview = $index; 21 | }; 22 | 23 | $scope.mouseout = function() { 24 | $scope.preview = -1; 25 | }; 26 | 27 | $scope.click = function ($index) { 28 | ngModel.$setTouched(); 29 | ngModel.$setViewValue($index + 1); 30 | ngModel.$render(); 31 | }; 32 | 33 | $scope.styles = function($index) { 34 | return { 35 | "glyphicon": true, 36 | "glyphicon-star": $index < $scope.value, 37 | "glyphicon-star-empty": $index >= $scope.value, 38 | "starpreview": $index <= $scope.preview 39 | }; 40 | }; 41 | }; 42 | 43 | var otfRating = function () { 44 | 45 | return { 46 | require: ["otfRating", "ngModel"], 47 | scope: { 48 | 49 | }, 50 | templateUrl: "templates/rating.html", 51 | controller: "otfRatingController", 52 | link: function (scope, element, attributes, controllers) { 53 | var ratingController = controllers[0]; 54 | var modelController = controllers[1]; 55 | 56 | var min = parseInt(attributes.min || "1"); 57 | var max = parseInt(attributes.max || "10"); 58 | ratingController.initialize(min, max, modelController); 59 | } 60 | }; 61 | }; 62 | 63 | module.controller("otfRatingController", otfRatingController); 64 | module.directive("otfRating", otfRating); 65 | 66 | }(angular.module("forms"))); 67 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/forms/js/directives/startsWith.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | var startsWith = function () { 4 | 5 | return { 6 | restrict: "A", 7 | require: "ngModel", 8 | link: function (scope, element, attributes, ngModel) { 9 | 10 | var value = attributes.startsWith; 11 | 12 | ngModel.$validators.startsWith = function (modelValue) { 13 | if (value && modelValue[0] !== value) { 14 | return false; 15 | } 16 | return true; 17 | }; 18 | } 19 | }; 20 | 21 | }; 22 | 23 | module.directive("startsWith", startsWith); 24 | 25 | }(angular.module("forms"))); 26 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/forms/js/directives/username.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | var username = function ($http, alerting, $q, $compile) { 4 | 5 | var processResponse = function (response) { 6 | if (response.data) { 7 | return $q.when(true); 8 | } else { 9 | return $q.reject(false); 10 | } 11 | }; 12 | 13 | var validateUsername = function (value) { 14 | return $http.get("/api/namevalidation?name=" + encodeURI(value)) 15 | .catch(alerting.errorHandler("Could not validate the username on the server")) 16 | .then(processResponse); 17 | 18 | }; 19 | 20 | var setupDom = function(input, form, scope) { 21 | var inputName = input.attr("name"); 22 | var formName = form.$name; 23 | var pending = "
Checking name...
"; 24 | input.parent().append($compile(pending)(scope)); 25 | 26 | }; 27 | 28 | return { 29 | require: ["ngModel", "^form"], 30 | link: function (scope, element, attributes, controllers) { 31 | var ngModel = controllers[0]; 32 | var ngForm = controllers[1]; 33 | ngModel.$asyncValidators.username = validateUsername; 34 | setupDom(element, ngForm, scope); 35 | } 36 | }; 37 | 38 | }; 39 | 40 | module.directive("username", username); 41 | 42 | }(angular.module("forms"))); 43 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/forms/js/services/user.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | var user = function () { 4 | return { 5 | username: "", 6 | email: "", 7 | website: "", 8 | phone: "", 9 | birthdate: "", 10 | age: "", 11 | feelLike: "", 12 | color: "", 13 | cuisine: "", 14 | bio: "", 15 | terms: "", 16 | status: "", 17 | rating: 1 18 | }; 19 | }; 20 | 21 | module.factory("user", user); 22 | 23 | }(angular.module("forms"))); 24 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/forms/module.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | var app = angular.module("forms", ["common", "ngRoute", "ngAnimate", "ngMessages"]); 4 | 5 | var routes = [ 6 | { url: "/", settings: { templateUrl: "templates/home.html" } }, 7 | { url: "/results", settings: {templateUrl: "templates/results.html"}} 8 | ]; 9 | 10 | var registerRoutes = function($routeProvider) { 11 | routes.forEach(function(route) { 12 | $routeProvider.when(route.url, route.settings); 13 | }); 14 | $routeProvider.otherwise({ redirectTo: routes[0].url }); 15 | }; 16 | 17 | app.config(registerRoutes); 18 | 19 | }()); -------------------------------------------------------------------------------- /ngPlaybook/Apps/forms/shell.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | Ode To Food 4 | 5 | 6 | 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 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/forms/templates/home.html: -------------------------------------------------------------------------------- 1 | 
2 |
3 |
4 |
5 | 6 |

Sign Up Now!

7 | 8 |
9 | 10 | 12 |
13 | 14 |
15 | 16 | 18 |
19 | 20 |
21 | 22 | 24 |
25 | 26 |
27 | 28 | 29 |
30 | 31 |
32 | 33 | 35 |
36 | 37 |
38 | 39 | 40 |
41 | 42 |
43 | 44 | 46 |
47 | 48 |
49 | 50 | 52 |
53 | 54 |
55 | 56 | 57 |
58 | 59 |
60 | 61 | 68 |
69 | 70 |
71 | 72 | 73 |
74 | 75 |
76 |
77 | 82 |
83 |
84 | 89 |
90 |
91 | 96 |
97 |
98 | 99 |
100 | 105 |
106 | 107 | 108 |
109 |
110 |
111 |
{{ profileForm | json }}
112 |
113 |
114 |
-------------------------------------------------------------------------------- /ngPlaybook/Apps/forms/templates/messages.html: -------------------------------------------------------------------------------- 1 | This field is required 2 | Too small 3 | Too large 4 | Enter a valid email 5 | Incorrect start 6 | Username is unavailble -------------------------------------------------------------------------------- /ngPlaybook/Apps/forms/templates/nav.html: -------------------------------------------------------------------------------- 1 |  8 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/forms/templates/rating.html: -------------------------------------------------------------------------------- 1 | 
2 | 7 | 8 |
-------------------------------------------------------------------------------- /ngPlaybook/Apps/forms/templates/results.html: -------------------------------------------------------------------------------- 1 | 
2 |

Results

3 |
{{ result.user | json}}
4 |
-------------------------------------------------------------------------------- /ngPlaybook/Apps/integration/js/controllers/movingObjects.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | module.controller("movingObjectController", function (Physics) { 4 | var model = this; 5 | 6 | model.box1 = null; 7 | model.box2 = null; 8 | 9 | model.kick = function () { 10 | model.box1.applyForce({ x: 0.1, y: -0.2 }); 11 | model.box2.applyForce({ x: -0.1, y: -0.2 }); 12 | }; 13 | 14 | model.resize = function (value) { 15 | model.box1.geometry.width = value; 16 | model.box1.geometry.height = value; 17 | model.box1.view = null; 18 | model.box1.recalc(); 19 | }; 20 | }); 21 | 22 | }(angular.module("integration"))); 23 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/integration/js/directives/knob.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | var knob = function () { 4 | 5 | return { 6 | scope: { 7 | min: "@", 8 | max:"@", 9 | width:"@", 10 | change: "&" 11 | }, 12 | link: function (scope, element) { 13 | element.knob({ 14 | min: scope.min, 15 | max: scope.max, 16 | width: scope.width, 17 | change: function (value) { 18 | scope.change({ value: value }); 19 | } 20 | }); 21 | } 22 | }; 23 | 24 | }; 25 | 26 | module.directive("knob", [knob]); 27 | 28 | }(angular.module("integration"))); 29 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/integration/js/directives/phsicsEdgeDetection.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | module.directive("physicsEdgeDetection", function (Physics) { 4 | return { 5 | restrict: "E", 6 | require: "^physicsCanvas", 7 | scope: { 8 | minX: "@", 9 | minY: "@", 10 | maxX: "@", 11 | maxY: "@", 12 | restitution: "@" 13 | }, 14 | link: function (scope, element, attributes, canvas) { 15 | var bounds = Physics.aabb(parseInt(scope.minX), 16 | parseInt(scope.minY), 17 | parseInt(scope.maxX), 18 | parseInt(scope.maxY)); 19 | canvas.add(Physics.behavior('edge-collision-detection', { 20 | aabb: bounds, 21 | restitution: parseFloat(scope.restitution) 22 | })); 23 | } 24 | }; 25 | }); 26 | 27 | 28 | }(angular.module("integration"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/integration/js/directives/physicsBehavior.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | module.directive("physicsBehavior", function (Physics) { 4 | return { 5 | restrict: "E", 6 | require: "^physicsCanvas", 7 | scope: { 8 | name: "@" 9 | }, 10 | link: function (scope, element, attributes, canvas) { 11 | canvas.add(Physics.behavior(scope.name)); 12 | } 13 | }; 14 | }); 15 | 16 | }(angular.module("integration"))); 17 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/integration/js/directives/physicsBody.js: -------------------------------------------------------------------------------- 1 |  2 | (function (module) { 3 | 4 | module.directive("physicsBody", function (Physics) { 5 | return { 6 | restrict: "E", 7 | require: "^physicsCanvas", 8 | scope: { 9 | options: "=", 10 | body: "=", 11 | type: "@" 12 | }, 13 | link: function (scope, element, attributes, canvas) { 14 | scope.body = Physics.body(scope.type, scope.options); 15 | canvas.add(scope.body); 16 | } 17 | }; 18 | }); 19 | 20 | }(angular.module("integration"))); 21 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/integration/js/directives/physicsCanvas.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | module.directive("physicsCanvas", function (Physics) { 4 | 5 | var preLink = function (scope, element) { 6 | 7 | var canvas = element[0].querySelector("canvas"); 8 | var renderer = Physics.renderer("canvas", { 9 | el: canvas, 10 | width: scope.width, 11 | height: scope.height 12 | }); 13 | 14 | Physics(function (world) { 15 | scope.world = world; 16 | scope.world.add(renderer); 17 | }); 18 | }; 19 | 20 | var postLink = function (scope) { 21 | Physics.util.ticker.on(function (time) { 22 | scope.world.step(time); 23 | }); 24 | 25 | scope.world.on('step', function () { 26 | scope.world.render(); 27 | }); 28 | 29 | Physics.util.ticker.start(); 30 | }; 31 | 32 | return { 33 | restrict: "E", 34 | transclude: true, 35 | templateUrl: "templates/physicsCanvas.html", 36 | scope: { 37 | width: "@", 38 | height: "@" 39 | }, 40 | controller: function ($scope) { 41 | this.add = function(thing) { 42 | $scope.world.add(thing); 43 | } 44 | }, 45 | compile: function() { 46 | return { 47 | pre: preLink, 48 | post: postLink 49 | } 50 | } 51 | }; 52 | }); 53 | 54 | }(angular.module("integration"))); 55 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/integration/js/directives/tubular.js: -------------------------------------------------------------------------------- 1 |  2 | (function (module) { 3 | 4 | var tubular = function () { 5 | 6 | return { 7 | link: function (scope, element, attributes) { 8 | attributes.$observe("tubular", function(value) { 9 | if (value) { 10 | element.tubular({ videoId: "e-UpuP4_iYA" }); 11 | } 12 | }); 13 | 14 | } 15 | }; 16 | }; 17 | 18 | module.directive("tubular", tubular); 19 | 20 | }(angular.module("integration"))); 21 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/integration/js/services/physics.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | module.value("Physics", Physics); 4 | 5 | }(angular.module("integration"))); 6 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/integration/module.js: -------------------------------------------------------------------------------- 1 |  2 | (function () { 3 | 4 | var app = angular.module("integration", ["common", "ngRoute", "ngAnimate", "ngMessages"]); 5 | 6 | 7 | }()); -------------------------------------------------------------------------------- /ngPlaybook/Apps/integration/shell.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | Ode To Food 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 |
16 |
17 |
18 | 19 | 20 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 |
39 | 40 |
    41 |
  • 42 | 43 |
  • 44 |
  • 45 | 48 |
  • 49 |
50 |
51 |
52 |
53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/integration/templates/nav.html: -------------------------------------------------------------------------------- 1 |  8 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/integration/templates/physicsCanvas.html: -------------------------------------------------------------------------------- 1 |  2 |
-------------------------------------------------------------------------------- /ngPlaybook/Apps/security/js/controllers/loginController.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | var loginController = function(oauth, currentUser, alerting, loginRedirect) { 4 | var model = this; 5 | 6 | model.username = ""; 7 | model.password = ""; 8 | model.user = currentUser.profile; 9 | 10 | model.login = function(form) { 11 | if (form.$valid) { 12 | oauth.login(model.username, model.password) 13 | .then(loginRedirect.redirectPreLogin) 14 | .catch(alerting.errorHandler("Could not login")); 15 | model.password = ""; 16 | } 17 | } 18 | 19 | model.signOut = function() { 20 | oauth.logout(); 21 | }; 22 | }; 23 | 24 | module.controller("loginController", loginController); 25 | 26 | }(angular.module("security"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/security/js/controllers/secretController.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | var secretController = function (recipes) { 4 | 5 | var model = this; 6 | 7 | model.recipe = null; 8 | 9 | recipes.getSecret().then(function(recipe) { 10 | model.recipe = recipe; 11 | }); 12 | 13 | }; 14 | 15 | module.controller("secretController", secretController); 16 | 17 | }(angular.module("security"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/security/js/services/recipes.js: -------------------------------------------------------------------------------- 1 | (function(module) { 2 | 3 | var recipes = function($http) { 4 | 5 | var getSecret = function() { 6 | return $http.get("/api/secret").then(function(response) { 7 | return response.data; 8 | }); 9 | }; 10 | 11 | return { 12 | getSecret: getSecret 13 | } 14 | }; 15 | 16 | module.factory("recipes", recipes); 17 | 18 | }(angular.module("security"))) -------------------------------------------------------------------------------- /ngPlaybook/Apps/security/module.js: -------------------------------------------------------------------------------- 1 |  2 | (function () { 3 | 4 | var app = angular.module("security", ["common", "ngRoute", "ngAnimate", "ngMessages"]); 5 | 6 | var routes = [ 7 | { 8 | url: "/", 9 | settings: { templateUrl: "templates/home.html" } 10 | }, { 11 | url: "/secret", 12 | settings: { templateUrl: "templates/secret.html"} 13 | }, { 14 | url: "/login", 15 | settings: { templateUrl: "templates/login.html" } 16 | } 17 | ]; 18 | 19 | var registerRoutes = function($routeProvider) { 20 | routes.forEach(function(route) { 21 | $routeProvider.when(route.url, route.settings); 22 | }); 23 | $routeProvider.otherwise({ redirectTo: routes[0].url }); 24 | }; 25 | 26 | app.config(registerRoutes); 27 | 28 | }()); -------------------------------------------------------------------------------- /ngPlaybook/Apps/security/shell.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | Ode To Food 4 | 5 | 6 | 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 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/security/templates/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OdeToCode/ngplaybook/8e1299cdae87c860d2828c4477f6db235e0d289a/ngPlaybook/Apps/security/templates/ajax-loader.gif -------------------------------------------------------------------------------- /ngPlaybook/Apps/security/templates/home.html: -------------------------------------------------------------------------------- 1 | 
2 |

Recipes!

3 |

OdeToFood is the place to go for all the greatest recipes.

4 |

See today's secret recipe!

5 |
-------------------------------------------------------------------------------- /ngPlaybook/Apps/security/templates/login.html: -------------------------------------------------------------------------------- 1 | 
2 |
3 |
4 | 5 | 6 |
7 |
8 | 9 | 10 |
11 | 12 |
13 |
-------------------------------------------------------------------------------- /ngPlaybook/Apps/security/templates/nav.html: -------------------------------------------------------------------------------- 1 |  27 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/security/templates/secret.html: -------------------------------------------------------------------------------- 1 | 
2 |

{{secret.recipe.title}}

3 | 4 |
    5 |
  • 6 | {{ingredient.name}} {{ingredient.quantity}} 7 |
  • 8 |
9 | 10 |
11 | {{secret.recipe.instructions}} 12 |
13 |
-------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/js/controllers/adminController.js: -------------------------------------------------------------------------------- 1 |  2 | (function (module) { 3 | 4 | var adminController = function (Employee, confirmPromotion, alerting) { 5 | var model = this; 6 | 7 | var removeEmployee = function(employee) { 8 | for (var i = 0; i < model.employees.length; i++) { 9 | if (employee === model.employees[i]) { 10 | model.employees.splice(i, 1); 11 | alerting.addInfo(employee.lastName + " promoted!"); 12 | break; 13 | } 14 | }; 15 | } 16 | 17 | model.employees = [ 18 | new Employee("Scott", "Allen", 1), 19 | new Employee("Alex", "Lifeson", 4), 20 | new Employee("Lawrence P.", "Waterhouse", 4), 21 | new Employee("Zoey", "Thibodale", 2), 22 | new Employee("Glory", "Altimira", 3) 23 | ]; 24 | 25 | model.promote = function(employee) { 26 | confirmPromotion(employee).then(removeEmployee); 27 | }; 28 | 29 | }; 30 | 31 | module.controller("adminController", adminController); 32 | 33 | }(angular.module("ui"))); 34 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/js/controllers/costController.js: -------------------------------------------------------------------------------- 1 |  2 | (function (module) { 3 | 4 | var createChart = function () { 5 | var chart = {}; 6 | chart.type = "PieChart"; 7 | 8 | chart.data = [ 9 | ["Type", "Amount"], 10 | ["Food", 34], 11 | ["Salaries", 12], 12 | ["Lawsuits", 20], 13 | ["Drinks", 23], 14 | ["Silverware", 12] 15 | ]; 16 | 17 | chart.options = { 18 | height: 300, 19 | width: 600, 20 | backgroundColor: "#222222", 21 | legend: {textStyle: {color: "white", fontSize: 16}}, 22 | animation: { 23 | duration: 500, 24 | easing: "out" 25 | } 26 | }; 27 | return chart; 28 | }; 29 | 30 | var addData = function (chart) { 31 | for (var i = 1; i < chart.data.length; i++) { 32 | chart.data[i][1] = Math.round(Math.random() * 50) + 5; 33 | } 34 | }; 35 | 36 | var costController = function ($timeout) { 37 | var self = this; 38 | self.chart = createChart(); 39 | $timeout(function () { 40 | self.showChart = true; 41 | addData(self.chart); 42 | }, 750); 43 | }; 44 | 45 | module.controller("costController", costController); 46 | 47 | }(angular.module("ui"))); 48 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/js/controllers/customersController.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | var customersController = function ($timeout) { 4 | var self = this; 5 | var data = []; 6 | for (var i = 1; i < 360; i++) { 7 | var date = new Date(2014, 0); 8 | var number = Math.round(Math.random() * 50) + 50; 9 | if (i % 7 === 4 || i % 7 === 5) { 10 | number += 50; 11 | } 12 | date.setDate(i); 13 | data.push([date, number]); 14 | }; 15 | 16 | $timeout(function() { 17 | self.showChart = true; 18 | }, 750); 19 | 20 | self.data = data; 21 | }; 22 | 23 | module.controller("customersController", customersController); 24 | 25 | }(angular.module("ui"))); 26 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/js/controllers/injuriesController.js: -------------------------------------------------------------------------------- 1 |  2 | (function (module) { 3 | 4 | var createChart = function () { 5 | var chart = {}; 6 | chart.type = "ColumnChart"; 7 | 8 | chart.data = [ 9 | ["Injuries", "Count", {role:"style"}], 10 | ["Major Burns", 0, ""], 11 | ["Toxic Inhalations", 0, ""], 12 | ["Lacerations", 0, ""], 13 | ["Discoball Contusions", 0, ""], 14 | ["Muscle Pulls", 0, ""], 15 | ["Food poisonings", 0, ""], 16 | ["Hallucinations", 0, ""] 17 | ]; 18 | 19 | chart.options = { 20 | hAxis: { textStyle: { color: "#ffffff"}}, 21 | vAxis: { title: "Injury Type", textStyle:{color:"#ffffff"} }, 22 | height: 400, 23 | backgroundColor: "#222222", 24 | legend: { textStyle: { color: "white", fontSize: 16 } }, 25 | animation: { 26 | duration: 500, 27 | easing: "out" 28 | } 29 | }; 30 | return chart; 31 | }; 32 | 33 | var addData = function (chart) { 34 | for (var i = 1; i < chart.data.length; i++) { 35 | chart.data[i][1] = Math.round(Math.random() * 50) + 5; 36 | if (chart.data[i][1] > 40) { 37 | chart.data[i][2] = "red"; 38 | } 39 | } 40 | }; 41 | 42 | var injuriesController = function ($timeout) { 43 | var self = this; 44 | self.chart = createChart(); 45 | $timeout(function () { 46 | self.showChart = true; 47 | addData(self.chart); 48 | }, 750); 49 | }; 50 | 51 | module.controller("injuriesController", injuriesController); 52 | 53 | }(angular.module("ui"))); 54 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/js/controllers/overallController.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | var createChart = function() { 4 | var chart = {}; 5 | chart.type = "Gauge"; 6 | 7 | chart.data = [ 8 | ["Label", "Value"], 9 | ["Turnover", 0], 10 | ["Fire Risk", 0], 11 | ["Complaints", 0], 12 | ["Staleness", 0], 13 | ["Advertising", 0], 14 | ["Returns", 0], 15 | ["Accidents", 0], 16 | ["Parking", 0], 17 | ["Waste", 0] 18 | ]; 19 | 20 | chart.options = { 21 | width: 500, height: 400, 22 | redFrom: 90, redTo: 100, 23 | yellowFrom: 75, yellowTo: 90, 24 | minorTicks: 5, 25 | animation: { 26 | duration: 2000, 27 | easing: "out" 28 | } 29 | }; 30 | return chart; 31 | }; 32 | 33 | var addData = function(chart) { 34 | var data = [85, 55, 99, 22, 50, 22, 23, 65, 19]; 35 | for (var i = 1; i < chart.data.length; i++) { 36 | chart.data[i][1] = data[i - 1]; 37 | } 38 | }; 39 | 40 | var overallController = function ($timeout) { 41 | var self = this; 42 | self.chart = createChart(); 43 | $timeout(function() { 44 | self.showChart = true; 45 | addData(self.chart); 46 | }, 750); 47 | }; 48 | 49 | module.controller("overallController", overallController); 50 | 51 | }(angular.module("ui"))); 52 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/js/directives/calendar.js: -------------------------------------------------------------------------------- 1 |  2 | (function (module) { 3 | 4 | var drawChart = function (element, values) { 5 | var data = new google.visualization.DataTable(); 6 | data.addColumn({ type: 'date', id: 'Date' }); 7 | data.addColumn({ type: 'number', id: 'Count' }); 8 | data.addRows(values); 9 | var chart = new google.visualization.ChartWrapper({ 10 | chartType: 'Calendar', 11 | dataTable: data, 12 | options: { 13 | title: "Customers By Day", 14 | height: 400 15 | } 16 | }); 17 | chart.draw(element); 18 | }; 19 | 20 | var calendar = function (googleChartApiPromise) { 21 | 22 | return { 23 | scope: { 24 | data: "=" 25 | }, 26 | link: function (scope, element) { 27 | scope.$watch("data", function () { 28 | googleChartApiPromise.then(function () { 29 | if (scope.data) { 30 | drawChart(element[0], scope.data); 31 | } 32 | }); 33 | }); 34 | } 35 | }; 36 | 37 | }; 38 | 39 | module.directive("calendar", calendar); 40 | 41 | }(angular.module("ui"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/js/directives/navbar.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | var navbar = function () { 4 | return { 5 | templateUrl: "/apps/ui/templates/nav.html" 6 | }; 7 | }; 8 | 9 | module.directive("navbar", navbar); 10 | 11 | }(angular.module("ui"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/js/directives/rating.js: -------------------------------------------------------------------------------- 1 |  2 | (function (module) { 3 | 4 | var otfRating = function () { 5 | 6 | return { 7 | scope: { 8 | value: "=" 9 | }, 10 | link: function (scope, element, attributes) { 11 | 12 | var min = parseInt(attributes.min || "1"); 13 | var max = parseInt(attributes.max || "10"); 14 | 15 | element.addClass("btn-group"); 16 | 17 | scope.$watch("value", function (newValue) { 18 | element.empty(); 19 | for (var i = 0; i < newValue; i++) { 20 | element.append(""); 21 | } 22 | }); 23 | 24 | element.on("click", function () { 25 | scope.$apply(function () { 26 | if (scope.value < max) { 27 | scope.value += 1; 28 | } else { 29 | scope.value = min; 30 | } 31 | }); 32 | }); 33 | 34 | scope.$on("destroy", function () { 35 | element.off("click"); 36 | }); 37 | } 38 | }; 39 | }; 40 | 41 | module.directive("otfRating", otfRating); 42 | 43 | }(angular.module("ui"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/js/directives/rating2.js: -------------------------------------------------------------------------------- 1 |  2 | (function (module) { 3 | 4 | var otfRating2Controller = function ($scope) { 5 | 6 | this.setRange = function (min, max) { 7 | $scope.stars = new Array(max - min + 1); 8 | }; 9 | 10 | $scope.mouseover = function ($index) { 11 | $scope.preview = $index; 12 | }; 13 | 14 | $scope.mouseout = function () { 15 | $scope.preview = -1; 16 | }; 17 | 18 | $scope.click = function ($index) { 19 | $scope.value = $index + 1; 20 | }; 21 | 22 | $scope.styles = function ($index) { 23 | return { 24 | "glyphicon": true, 25 | "glyphicon-star": $index < $scope.value, 26 | "glyphicon-star-empty": $index >= $scope.value, 27 | "starpreview": $index <= $scope.preview 28 | }; 29 | }; 30 | }; 31 | 32 | var otfRating2 = function () { 33 | 34 | return { 35 | require: "otfRating2", 36 | scope: { 37 | value: "=" 38 | }, 39 | templateUrl: "templates/rating2.html", 40 | controller: "otfRating2Controller", 41 | link: function (scope, element, attributes, controller) { 42 | var min = parseInt(attributes.min || "1"); 43 | var max = parseInt(attributes.max || "10"); 44 | controller.setRange(min, max); 45 | } 46 | }; 47 | }; 48 | 49 | module.controller("otfRating2Controller", otfRating2Controller); 50 | module.directive("otfRating2", otfRating2); 51 | 52 | }(angular.module("ui"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/js/services/confirmPromotion.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | var confirmPromotion = function ($modal) { 4 | return function (employee) { 5 | var options = { 6 | templateUrl: "templates/confirmPromotion.html", 7 | controller: function() { 8 | this.employee = employee; 9 | }, 10 | controllerAs: "model" 11 | }; 12 | 13 | return $modal.open(options).result; 14 | }; 15 | }; 16 | 17 | module.factory("confirmPromotion", confirmPromotion); 18 | 19 | }(angular.module("ui"))); 20 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/js/services/employee.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | var Employee = function (firstName, lastName, rating) { 4 | this.firstName = firstName; 5 | this.lastName = lastName; 6 | this.rating = rating; 7 | }; 8 | 9 | module.value("Employee", Employee); 10 | 11 | }(angular.module("ui"))); 12 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/js/services/stateChangeErrors.js: -------------------------------------------------------------------------------- 1 | (function (module) { 2 | 3 | module.run(function($rootScope, alerting){ 4 | $rootScope.$on("$stateChangeError", function (event, toState, toParams, fromState, fromParams, error) { 5 | alerting.addDanger("Could not load " + toState.name); 6 | }); 7 | }); 8 | 9 | }(angular.module("ui"))); -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/module.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | var module = angular.module("ui", ["common", "ngAnimate", "ui.router", 4 | "googlechart", "ui.bootstrap"]); 5 | 6 | module.config(function ($stateProvider, $urlRouterProvider) { 7 | 8 | $urlRouterProvider.otherwise("/dashboard/overall"); 9 | $stateProvider 10 | .state("dashboard", { url: "/dashboard", templateUrl: "templates/dashboard.html" }) 11 | .state("overall", { parent:"dashboard", url: "/overall", templateUrl: "templates/overall.html" }) 12 | .state("customers", { parent:"dashboard", url: "/customers", templateUrl: "templates/customers.html" }) 13 | .state("injuries", { parent: "dashboard", url: "/injuries", templateUrl: "templates/injuries.html" }) 14 | .state("costs", { parent:"dashboard", url: "/costs", templateUrl: "templates/costs.html" }) 15 | .state("admin", { url: "/admin", templateUrl: "templates/admin.html" }); 16 | }); 17 | 18 | module.run(function(googleChartApiConfig) { 19 | googleChartApiConfig.optionalSettings.packages.push("calendar"); 20 | }); 21 | 22 | }()); 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/shell.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | Ode To Food 4 | 5 | 6 | 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 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/templates/admin.html: -------------------------------------------------------------------------------- 1 | 
2 |

Employee Admin

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
First NameLast NameRating
{{employee.firstName}}{{employee.lastName}}
21 |
-------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/templates/confirmPromotion.html: -------------------------------------------------------------------------------- 1 |  4 | 9 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/templates/costs.html: -------------------------------------------------------------------------------- 1 | 
2 |
3 |
4 |
-------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/templates/customers.html: -------------------------------------------------------------------------------- 1 | 
2 |
3 |
-------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/templates/dashboard.html: -------------------------------------------------------------------------------- 1 | 
2 |

Restaurant Dashboard

3 |
4 |
5 |
6 | 12 |
13 |
14 |
15 |
16 |
17 |
18 |
-------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/templates/injuries.html: -------------------------------------------------------------------------------- 1 | 
2 |
3 |
4 |
-------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/templates/nav.html: -------------------------------------------------------------------------------- 1 |  12 | -------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/templates/overall.html: -------------------------------------------------------------------------------- 1 | 
2 |
3 |
4 |
-------------------------------------------------------------------------------- /ngPlaybook/Apps/ui/templates/rating2.html: -------------------------------------------------------------------------------- 1 | 
2 | 7 | 8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /ngPlaybook/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="NgPlaybook.Global" Language="C#" %> 2 | -------------------------------------------------------------------------------- /ngPlaybook/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web; 3 | using System.Web.Http; 4 | using NgPlaybook.Server.Startup; 5 | 6 | namespace NgPlaybook 7 | { 8 | public class Global : HttpApplication 9 | { 10 | 11 | protected void Application_Start(object sender, EventArgs e) 12 | { 13 | GlobalConfiguration.Configure(WebApiStartup.Configure); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /ngPlaybook/Js/angular/angular-aria.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license AngularJS v1.3.5 3 | * (c) 2010-2014 Google, Inc. http://angularjs.org 4 | * License: MIT 5 | */ 6 | (function(window, angular, undefined) {'use strict'; 7 | 8 | /** 9 | * @ngdoc module 10 | * @name ngAria 11 | * @description 12 | * 13 | * The `ngAria` module provides support for common 14 | * [ARIA](http://www.w3.org/TR/wai-aria/) 15 | * attributes that convey state or semantic information about the application for users 16 | * of assistive technologies, such as screen readers. 17 | * 18 | *
19 | * 20 | * ## Usage 21 | * 22 | * For ngAria to do its magic, simply include the module as a dependency. The directives supported 23 | * by ngAria are: 24 | * `ngModel`, `ngDisabled`, `ngShow`, `ngHide`, `ngClick`, `ngDblClick`, and `ngMessages`. 25 | * 26 | * Below is a more detailed breakdown of the attributes handled by ngAria: 27 | * 28 | * | Directive | Supported Attributes | 29 | * |---------------------------------------------|----------------------------------------------------------------------------------------| 30 | * | {@link ng.directive:ngModel ngModel} | aria-checked, aria-valuemin, aria-valuemax, aria-valuenow, aria-invalid, aria-required | 31 | * | {@link ng.directive:ngDisabled ngDisabled} | aria-disabled | 32 | * | {@link ng.directive:ngShow ngShow} | aria-hidden | 33 | * | {@link ng.directive:ngHide ngHide} | aria-hidden | 34 | * | {@link ng.directive:ngClick ngClick} | tabindex | 35 | * | {@link ng.directive:ngDblclick ngDblclick} | tabindex | 36 | * | {@link module:ngMessages ngMessages} | aria-live | 37 | * 38 | * Find out more information about each directive by reading the 39 | * {@link guide/accessibility ngAria Developer Guide}. 40 | * 41 | * ##Example 42 | * Using ngDisabled with ngAria: 43 | * ```html 44 | * 45 | * ``` 46 | * Becomes: 47 | * ```html 48 | * 49 | * ``` 50 | * 51 | * ##Disabling Attributes 52 | * It's possible to disable individual attributes added by ngAria with the 53 | * {@link ngAria.$ariaProvider#config config} method. For more details, see the 54 | * {@link guide/accessibility Developer Guide}. 55 | */ 56 | /* global -ngAriaModule */ 57 | var ngAriaModule = angular.module('ngAria', ['ng']). 58 | provider('$aria', $AriaProvider); 59 | 60 | /** 61 | * @ngdoc provider 62 | * @name $ariaProvider 63 | * 64 | * @description 65 | * 66 | * Used for configuring the ARIA attributes injected and managed by ngAria. 67 | * 68 | * ```js 69 | * angular.module('myApp', ['ngAria'], function config($ariaProvider) { 70 | * $ariaProvider.config({ 71 | * ariaValue: true, 72 | * tabindex: false 73 | * }); 74 | * }); 75 | *``` 76 | * 77 | * ## Dependencies 78 | * Requires the {@link ngAria} module to be installed. 79 | * 80 | */ 81 | function $AriaProvider() { 82 | var config = { 83 | ariaHidden: true, 84 | ariaChecked: true, 85 | ariaDisabled: true, 86 | ariaRequired: true, 87 | ariaInvalid: true, 88 | ariaMultiline: true, 89 | ariaValue: true, 90 | tabindex: true 91 | }; 92 | 93 | /** 94 | * @ngdoc method 95 | * @name $ariaProvider#config 96 | * 97 | * @param {object} config object to enable/disable specific ARIA attributes 98 | * 99 | * - **ariaHidden** – `{boolean}` – Enables/disables aria-hidden tags 100 | * - **ariaChecked** – `{boolean}` – Enables/disables aria-checked tags 101 | * - **ariaDisabled** – `{boolean}` – Enables/disables aria-disabled tags 102 | * - **ariaRequired** – `{boolean}` – Enables/disables aria-required tags 103 | * - **ariaInvalid** – `{boolean}` – Enables/disables aria-invalid tags 104 | * - **ariaMultiline** – `{boolean}` – Enables/disables aria-multiline tags 105 | * - **ariaValue** – `{boolean}` – Enables/disables aria-valuemin, aria-valuemax and aria-valuenow tags 106 | * - **tabindex** – `{boolean}` – Enables/disables tabindex tags 107 | * 108 | * @description 109 | * Enables/disables various ARIA attributes 110 | */ 111 | this.config = function(newConfig) { 112 | config = angular.extend(config, newConfig); 113 | }; 114 | 115 | function camelCase(input) { 116 | return input.replace(/-./g, function(letter, pos) { 117 | return letter[1].toUpperCase(); 118 | }); 119 | } 120 | 121 | 122 | function watchExpr(attrName, ariaAttr, negate) { 123 | var ariaCamelName = camelCase(ariaAttr); 124 | return function(scope, elem, attr) { 125 | if (config[ariaCamelName] && !attr[ariaCamelName]) { 126 | scope.$watch(attr[attrName], function(boolVal) { 127 | if (negate) { 128 | boolVal = !boolVal; 129 | } 130 | elem.attr(ariaAttr, boolVal); 131 | }); 132 | } 133 | }; 134 | } 135 | 136 | /** 137 | * @ngdoc service 138 | * @name $aria 139 | * 140 | * @description 141 | * 142 | * The $aria service contains helper methods for applying common 143 | * [ARIA](http://www.w3.org/TR/wai-aria/) attributes to HTML directives. 144 | * 145 | * ngAria injects common accessibility attributes that tell assistive technologies when HTML 146 | * elements are enabled, selected, hidden, and more. To see how this is performed with ngAria, 147 | * let's review a code snippet from ngAria itself: 148 | * 149 | *```js 150 | * ngAriaModule.directive('ngDisabled', ['$aria', function($aria) { 151 | * return $aria.$$watchExpr('ngDisabled', 'aria-disabled'); 152 | * }]) 153 | *``` 154 | * Shown above, the ngAria module creates a directive with the same signature as the 155 | * traditional `ng-disabled` directive. But this ngAria version is dedicated to 156 | * solely managing accessibility attributes. The internal `$aria` service is used to watch the 157 | * boolean attribute `ngDisabled`. If it has not been explicitly set by the developer, 158 | * `aria-disabled` is injected as an attribute with its value synchronized to the value in 159 | * `ngDisabled`. 160 | * 161 | * Because ngAria hooks into the `ng-disabled` directive, developers do not have to do 162 | * anything to enable this feature. The `aria-disabled` attribute is automatically managed 163 | * simply as a silent side-effect of using `ng-disabled` with the ngAria module. 164 | * 165 | * The full list of directives that interface with ngAria: 166 | * * **ngModel** 167 | * * **ngShow** 168 | * * **ngHide** 169 | * * **ngClick** 170 | * * **ngDblclick** 171 | * * **ngMessages** 172 | * * **ngDisabled** 173 | * 174 | * Read the {@link guide/accessibility ngAria Developer Guide} for a thorough explanation of each 175 | * directive. 176 | * 177 | * 178 | * ## Dependencies 179 | * Requires the {@link ngAria} module to be installed. 180 | */ 181 | this.$get = function() { 182 | return { 183 | config: function(key) { 184 | return config[camelCase(key)]; 185 | }, 186 | $$watchExpr: watchExpr 187 | }; 188 | }; 189 | } 190 | 191 | var ngAriaTabindex = ['$aria', function($aria) { 192 | return function(scope, elem, attr) { 193 | if ($aria.config('tabindex') && !elem.attr('tabindex')) { 194 | elem.attr('tabindex', 0); 195 | } 196 | }; 197 | }]; 198 | 199 | ngAriaModule.directive('ngShow', ['$aria', function($aria) { 200 | return $aria.$$watchExpr('ngShow', 'aria-hidden', true); 201 | }]) 202 | .directive('ngHide', ['$aria', function($aria) { 203 | return $aria.$$watchExpr('ngHide', 'aria-hidden', false); 204 | }]) 205 | .directive('ngModel', ['$aria', function($aria) { 206 | 207 | function shouldAttachAttr(attr, elem) { 208 | return $aria.config(attr) && !elem.attr(attr); 209 | } 210 | 211 | function getShape(attr, elem) { 212 | var type = attr.type, 213 | role = attr.role; 214 | 215 | return ((type || role) === 'checkbox' || role === 'menuitemcheckbox') ? 'checkbox' : 216 | ((type || role) === 'radio' || role === 'menuitemradio') ? 'radio' : 217 | (type === 'range' || role === 'progressbar' || role === 'slider') ? 'range' : 218 | (type || role) === 'textbox' || elem[0].nodeName === 'TEXTAREA' ? 'multiline' : ''; 219 | } 220 | 221 | return { 222 | restrict: 'A', 223 | require: '?ngModel', 224 | link: function(scope, elem, attr, ngModel) { 225 | var shape = getShape(attr, elem); 226 | var needsTabIndex = shouldAttachAttr('tabindex', elem); 227 | 228 | function ngAriaWatchModelValue() { 229 | return ngModel.$modelValue; 230 | } 231 | 232 | function getRadioReaction() { 233 | if (needsTabIndex) { 234 | needsTabIndex = false; 235 | return function ngAriaRadioReaction(newVal) { 236 | var boolVal = newVal === attr.value; 237 | elem.attr('aria-checked', boolVal); 238 | elem.attr('tabindex', 0 - !boolVal); 239 | }; 240 | } else { 241 | return function ngAriaRadioReaction(newVal) { 242 | elem.attr('aria-checked', newVal === attr.value); 243 | }; 244 | } 245 | } 246 | 247 | function ngAriaCheckboxReaction(newVal) { 248 | elem.attr('aria-checked', !!newVal); 249 | } 250 | 251 | switch (shape) { 252 | case 'radio': 253 | case 'checkbox': 254 | if (shouldAttachAttr('aria-checked', elem)) { 255 | scope.$watch(ngAriaWatchModelValue, shape === 'radio' ? 256 | getRadioReaction() : ngAriaCheckboxReaction); 257 | } 258 | break; 259 | case 'range': 260 | if ($aria.config('ariaValue')) { 261 | if (attr.min && !elem.attr('aria-valuemin')) { 262 | elem.attr('aria-valuemin', attr.min); 263 | } 264 | if (attr.max && !elem.attr('aria-valuemax')) { 265 | elem.attr('aria-valuemax', attr.max); 266 | } 267 | if (!elem.attr('aria-valuenow')) { 268 | scope.$watch(ngAriaWatchModelValue, function ngAriaValueNowReaction(newVal) { 269 | elem.attr('aria-valuenow', newVal); 270 | }); 271 | } 272 | } 273 | break; 274 | case 'multiline': 275 | if (shouldAttachAttr('aria-multiline', elem)) { 276 | elem.attr('aria-multiline', true); 277 | } 278 | break; 279 | } 280 | 281 | if (needsTabIndex) { 282 | elem.attr('tabindex', 0); 283 | } 284 | 285 | if (ngModel.$validators.required && shouldAttachAttr('aria-required', elem)) { 286 | scope.$watch(function ngAriaRequiredWatch() { 287 | return ngModel.$error.required; 288 | }, function ngAriaRequiredReaction(newVal) { 289 | elem.attr('aria-required', !!newVal); 290 | }); 291 | } 292 | 293 | if (shouldAttachAttr('aria-invalid', elem)) { 294 | scope.$watch(function ngAriaInvalidWatch() { 295 | return ngModel.$invalid; 296 | }, function ngAriaInvalidReaction(newVal) { 297 | elem.attr('aria-invalid', !!newVal); 298 | }); 299 | } 300 | } 301 | }; 302 | }]) 303 | .directive('ngDisabled', ['$aria', function($aria) { 304 | return $aria.$$watchExpr('ngDisabled', 'aria-disabled'); 305 | }]) 306 | .directive('ngMessages', function() { 307 | return { 308 | restrict: 'A', 309 | require: '?ngMessages', 310 | link: function(scope, elem, attr, ngMessages) { 311 | if (!elem.attr('aria-live')) { 312 | elem.attr('aria-live', 'assertive'); 313 | } 314 | } 315 | }; 316 | }) 317 | .directive('ngClick', ngAriaTabindex) 318 | .directive('ngDblclick', ngAriaTabindex); 319 | 320 | 321 | })(window, window.angular); 322 | -------------------------------------------------------------------------------- /ngPlaybook/Js/angular/angular-cookies.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license AngularJS v1.3.5 3 | * (c) 2010-2014 Google, Inc. http://angularjs.org 4 | * License: MIT 5 | */ 6 | (function(window, angular, undefined) {'use strict'; 7 | 8 | /** 9 | * @ngdoc module 10 | * @name ngCookies 11 | * @description 12 | * 13 | * # ngCookies 14 | * 15 | * The `ngCookies` module provides a convenient wrapper for reading and writing browser cookies. 16 | * 17 | * 18 | *
19 | * 20 | * See {@link ngCookies.$cookies `$cookies`} and 21 | * {@link ngCookies.$cookieStore `$cookieStore`} for usage. 22 | */ 23 | 24 | 25 | angular.module('ngCookies', ['ng']). 26 | /** 27 | * @ngdoc service 28 | * @name $cookies 29 | * 30 | * @description 31 | * Provides read/write access to browser's cookies. 32 | * 33 | * Only a simple Object is exposed and by adding or removing properties to/from this object, new 34 | * cookies are created/deleted at the end of current $eval. 35 | * The object's properties can only be strings. 36 | * 37 | * Requires the {@link ngCookies `ngCookies`} module to be installed. 38 | * 39 | * @example 40 | * 41 | * ```js 42 | * angular.module('cookiesExample', ['ngCookies']) 43 | * .controller('ExampleController', ['$cookies', function($cookies) { 44 | * // Retrieving a cookie 45 | * var favoriteCookie = $cookies.myFavorite; 46 | * // Setting a cookie 47 | * $cookies.myFavorite = 'oatmeal'; 48 | * }]); 49 | * ``` 50 | */ 51 | factory('$cookies', ['$rootScope', '$browser', function($rootScope, $browser) { 52 | var cookies = {}, 53 | lastCookies = {}, 54 | lastBrowserCookies, 55 | runEval = false, 56 | copy = angular.copy, 57 | isUndefined = angular.isUndefined; 58 | 59 | //creates a poller fn that copies all cookies from the $browser to service & inits the service 60 | $browser.addPollFn(function() { 61 | var currentCookies = $browser.cookies(); 62 | if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl 63 | lastBrowserCookies = currentCookies; 64 | copy(currentCookies, lastCookies); 65 | copy(currentCookies, cookies); 66 | if (runEval) $rootScope.$apply(); 67 | } 68 | })(); 69 | 70 | runEval = true; 71 | 72 | //at the end of each eval, push cookies 73 | //TODO: this should happen before the "delayed" watches fire, because if some cookies are not 74 | // strings or browser refuses to store some cookies, we update the model in the push fn. 75 | $rootScope.$watch(push); 76 | 77 | return cookies; 78 | 79 | 80 | /** 81 | * Pushes all the cookies from the service to the browser and verifies if all cookies were 82 | * stored. 83 | */ 84 | function push() { 85 | var name, 86 | value, 87 | browserCookies, 88 | updated; 89 | 90 | //delete any cookies deleted in $cookies 91 | for (name in lastCookies) { 92 | if (isUndefined(cookies[name])) { 93 | $browser.cookies(name, undefined); 94 | } 95 | } 96 | 97 | //update all cookies updated in $cookies 98 | for (name in cookies) { 99 | value = cookies[name]; 100 | if (!angular.isString(value)) { 101 | value = '' + value; 102 | cookies[name] = value; 103 | } 104 | if (value !== lastCookies[name]) { 105 | $browser.cookies(name, value); 106 | updated = true; 107 | } 108 | } 109 | 110 | //verify what was actually stored 111 | if (updated) { 112 | updated = false; 113 | browserCookies = $browser.cookies(); 114 | 115 | for (name in cookies) { 116 | if (cookies[name] !== browserCookies[name]) { 117 | //delete or reset all cookies that the browser dropped from $cookies 118 | if (isUndefined(browserCookies[name])) { 119 | delete cookies[name]; 120 | } else { 121 | cookies[name] = browserCookies[name]; 122 | } 123 | updated = true; 124 | } 125 | } 126 | } 127 | } 128 | }]). 129 | 130 | 131 | /** 132 | * @ngdoc service 133 | * @name $cookieStore 134 | * @requires $cookies 135 | * 136 | * @description 137 | * Provides a key-value (string-object) storage, that is backed by session cookies. 138 | * Objects put or retrieved from this storage are automatically serialized or 139 | * deserialized by angular's toJson/fromJson. 140 | * 141 | * Requires the {@link ngCookies `ngCookies`} module to be installed. 142 | * 143 | * @example 144 | * 145 | * ```js 146 | * angular.module('cookieStoreExample', ['ngCookies']) 147 | * .controller('ExampleController', ['$cookieStore', function($cookieStore) { 148 | * // Put cookie 149 | * $cookieStore.put('myFavorite','oatmeal'); 150 | * // Get cookie 151 | * var favoriteCookie = $cookieStore.get('myFavorite'); 152 | * // Removing a cookie 153 | * $cookieStore.remove('myFavorite'); 154 | * }]); 155 | * ``` 156 | */ 157 | factory('$cookieStore', ['$cookies', function($cookies) { 158 | 159 | return { 160 | /** 161 | * @ngdoc method 162 | * @name $cookieStore#get 163 | * 164 | * @description 165 | * Returns the value of given cookie key 166 | * 167 | * @param {string} key Id to use for lookup. 168 | * @returns {Object} Deserialized cookie value. 169 | */ 170 | get: function(key) { 171 | var value = $cookies[key]; 172 | return value ? angular.fromJson(value) : value; 173 | }, 174 | 175 | /** 176 | * @ngdoc method 177 | * @name $cookieStore#put 178 | * 179 | * @description 180 | * Sets a value for given cookie key 181 | * 182 | * @param {string} key Id for the `value`. 183 | * @param {Object} value Value to be stored. 184 | */ 185 | put: function(key, value) { 186 | $cookies[key] = angular.toJson(value); 187 | }, 188 | 189 | /** 190 | * @ngdoc method 191 | * @name $cookieStore#remove 192 | * 193 | * @description 194 | * Remove given cookie 195 | * 196 | * @param {string} key Id of the key-value pair to delete. 197 | */ 198 | remove: function(key) { 199 | delete $cookies[key]; 200 | } 201 | }; 202 | 203 | }]); 204 | 205 | 206 | })(window, window.angular); 207 | -------------------------------------------------------------------------------- /ngPlaybook/Js/angular/angular-loader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license AngularJS v1.3.0 3 | * (c) 2010-2014 Google, Inc. http://angularjs.org 4 | * License: MIT 5 | */ 6 | 7 | (function() {'use strict'; 8 | 9 | /** 10 | * @description 11 | * 12 | * This object provides a utility for producing rich Error messages within 13 | * Angular. It can be called as follows: 14 | * 15 | * var exampleMinErr = minErr('example'); 16 | * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); 17 | * 18 | * The above creates an instance of minErr in the example namespace. The 19 | * resulting error will have a namespaced error code of example.one. The 20 | * resulting error will replace {0} with the value of foo, and {1} with the 21 | * value of bar. The object is not restricted in the number of arguments it can 22 | * take. 23 | * 24 | * If fewer arguments are specified than necessary for interpolation, the extra 25 | * interpolation markers will be preserved in the final string. 26 | * 27 | * Since data will be parsed statically during a build step, some restrictions 28 | * are applied with respect to how minErr instances are created and called. 29 | * Instances should have names of the form namespaceMinErr for a minErr created 30 | * using minErr('namespace') . Error codes, namespaces and template strings 31 | * should all be static strings, not variables or general expressions. 32 | * 33 | * @param {string} module The namespace to use for the new minErr instance. 34 | * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning 35 | * error from returned function, for cases when a particular type of error is useful. 36 | * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance 37 | */ 38 | 39 | function minErr(module, ErrorConstructor) { 40 | ErrorConstructor = ErrorConstructor || Error; 41 | return function () { 42 | var code = arguments[0], 43 | prefix = '[' + (module ? module + ':' : '') + code + '] ', 44 | template = arguments[1], 45 | templateArgs = arguments, 46 | stringify = function (obj) { 47 | if (typeof obj === 'function') { 48 | return obj.toString().replace(/ \{[\s\S]*$/, ''); 49 | } else if (typeof obj === 'undefined') { 50 | return 'undefined'; 51 | } else if (typeof obj !== 'string') { 52 | return JSON.stringify(obj); 53 | } 54 | return obj; 55 | }, 56 | message, i; 57 | 58 | message = prefix + template.replace(/\{\d+\}/g, function (match) { 59 | var index = +match.slice(1, -1), arg; 60 | 61 | if (index + 2 < templateArgs.length) { 62 | arg = templateArgs[index + 2]; 63 | if (typeof arg === 'function') { 64 | return arg.toString().replace(/ ?\{[\s\S]*$/, ''); 65 | } else if (typeof arg === 'undefined') { 66 | return 'undefined'; 67 | } else if (typeof arg !== 'string') { 68 | return toJson(arg); 69 | } 70 | return arg; 71 | } 72 | return match; 73 | }); 74 | 75 | message = message + '\nhttp://errors.angularjs.org/1.3.0/' + 76 | (module ? module + '/' : '') + code; 77 | for (i = 2; i < arguments.length; i++) { 78 | message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' + 79 | encodeURIComponent(stringify(arguments[i])); 80 | } 81 | return new ErrorConstructor(message); 82 | }; 83 | } 84 | 85 | /** 86 | * @ngdoc type 87 | * @name angular.Module 88 | * @module ng 89 | * @description 90 | * 91 | * Interface for configuring angular {@link angular.module modules}. 92 | */ 93 | 94 | function setupModuleLoader(window) { 95 | 96 | var $injectorMinErr = minErr('$injector'); 97 | var ngMinErr = minErr('ng'); 98 | 99 | function ensure(obj, name, factory) { 100 | return obj[name] || (obj[name] = factory()); 101 | } 102 | 103 | var angular = ensure(window, 'angular', Object); 104 | 105 | // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap 106 | angular.$$minErr = angular.$$minErr || minErr; 107 | 108 | return ensure(angular, 'module', function() { 109 | /** @type {Object.} */ 110 | var modules = {}; 111 | 112 | /** 113 | * @ngdoc function 114 | * @name angular.module 115 | * @module ng 116 | * @description 117 | * 118 | * The `angular.module` is a global place for creating, registering and retrieving Angular 119 | * modules. 120 | * All modules (angular core or 3rd party) that should be available to an application must be 121 | * registered using this mechanism. 122 | * 123 | * When passed two or more arguments, a new module is created. If passed only one argument, an 124 | * existing module (the name passed as the first argument to `module`) is retrieved. 125 | * 126 | * 127 | * # Module 128 | * 129 | * A module is a collection of services, directives, controllers, filters, and configuration information. 130 | * `angular.module` is used to configure the {@link auto.$injector $injector}. 131 | * 132 | * ```js 133 | * // Create a new module 134 | * var myModule = angular.module('myModule', []); 135 | * 136 | * // register a new service 137 | * myModule.value('appName', 'MyCoolApp'); 138 | * 139 | * // configure existing services inside initialization blocks. 140 | * myModule.config(['$locationProvider', function($locationProvider) { 141 | * // Configure existing providers 142 | * $locationProvider.hashPrefix('!'); 143 | * }]); 144 | * ``` 145 | * 146 | * Then you can create an injector and load your modules like this: 147 | * 148 | * ```js 149 | * var injector = angular.injector(['ng', 'myModule']) 150 | * ``` 151 | * 152 | * However it's more likely that you'll just use 153 | * {@link ng.directive:ngApp ngApp} or 154 | * {@link angular.bootstrap} to simplify this process for you. 155 | * 156 | * @param {!string} name The name of the module to create or retrieve. 157 | * @param {!Array.=} requires If specified then new module is being created. If 158 | * unspecified then the module is being retrieved for further configuration. 159 | * @param {Function=} configFn Optional configuration function for the module. Same as 160 | * {@link angular.Module#config Module#config()}. 161 | * @returns {module} new module with the {@link angular.Module} api. 162 | */ 163 | return function module(name, requires, configFn) { 164 | var assertNotHasOwnProperty = function(name, context) { 165 | if (name === 'hasOwnProperty') { 166 | throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context); 167 | } 168 | }; 169 | 170 | assertNotHasOwnProperty(name, 'module'); 171 | if (requires && modules.hasOwnProperty(name)) { 172 | modules[name] = null; 173 | } 174 | return ensure(modules, name, function() { 175 | if (!requires) { 176 | throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " + 177 | "the module name or forgot to load it. If registering a module ensure that you " + 178 | "specify the dependencies as the second argument.", name); 179 | } 180 | 181 | /** @type {!Array.>} */ 182 | var invokeQueue = []; 183 | 184 | /** @type {!Array.} */ 185 | var configBlocks = []; 186 | 187 | /** @type {!Array.} */ 188 | var runBlocks = []; 189 | 190 | var config = invokeLater('$injector', 'invoke', 'push', configBlocks); 191 | 192 | /** @type {angular.Module} */ 193 | var moduleInstance = { 194 | // Private state 195 | _invokeQueue: invokeQueue, 196 | _configBlocks: configBlocks, 197 | _runBlocks: runBlocks, 198 | 199 | /** 200 | * @ngdoc property 201 | * @name angular.Module#requires 202 | * @module ng 203 | * 204 | * @description 205 | * Holds the list of modules which the injector will load before the current module is 206 | * loaded. 207 | */ 208 | requires: requires, 209 | 210 | /** 211 | * @ngdoc property 212 | * @name angular.Module#name 213 | * @module ng 214 | * 215 | * @description 216 | * Name of the module. 217 | */ 218 | name: name, 219 | 220 | 221 | /** 222 | * @ngdoc method 223 | * @name angular.Module#provider 224 | * @module ng 225 | * @param {string} name service name 226 | * @param {Function} providerType Construction function for creating new instance of the 227 | * service. 228 | * @description 229 | * See {@link auto.$provide#provider $provide.provider()}. 230 | */ 231 | provider: invokeLater('$provide', 'provider'), 232 | 233 | /** 234 | * @ngdoc method 235 | * @name angular.Module#factory 236 | * @module ng 237 | * @param {string} name service name 238 | * @param {Function} providerFunction Function for creating new instance of the service. 239 | * @description 240 | * See {@link auto.$provide#factory $provide.factory()}. 241 | */ 242 | factory: invokeLater('$provide', 'factory'), 243 | 244 | /** 245 | * @ngdoc method 246 | * @name angular.Module#service 247 | * @module ng 248 | * @param {string} name service name 249 | * @param {Function} constructor A constructor function that will be instantiated. 250 | * @description 251 | * See {@link auto.$provide#service $provide.service()}. 252 | */ 253 | service: invokeLater('$provide', 'service'), 254 | 255 | /** 256 | * @ngdoc method 257 | * @name angular.Module#value 258 | * @module ng 259 | * @param {string} name service name 260 | * @param {*} object Service instance object. 261 | * @description 262 | * See {@link auto.$provide#value $provide.value()}. 263 | */ 264 | value: invokeLater('$provide', 'value'), 265 | 266 | /** 267 | * @ngdoc method 268 | * @name angular.Module#constant 269 | * @module ng 270 | * @param {string} name constant name 271 | * @param {*} object Constant value. 272 | * @description 273 | * Because the constant are fixed, they get applied before other provide methods. 274 | * See {@link auto.$provide#constant $provide.constant()}. 275 | */ 276 | constant: invokeLater('$provide', 'constant', 'unshift'), 277 | 278 | /** 279 | * @ngdoc method 280 | * @name angular.Module#animation 281 | * @module ng 282 | * @param {string} name animation name 283 | * @param {Function} animationFactory Factory function for creating new instance of an 284 | * animation. 285 | * @description 286 | * 287 | * **NOTE**: animations take effect only if the **ngAnimate** module is loaded. 288 | * 289 | * 290 | * Defines an animation hook that can be later used with 291 | * {@link ngAnimate.$animate $animate} service and directives that use this service. 292 | * 293 | * ```js 294 | * module.animation('.animation-name', function($inject1, $inject2) { 295 | * return { 296 | * eventName : function(element, done) { 297 | * //code to run the animation 298 | * //once complete, then run done() 299 | * return function cancellationFunction(element) { 300 | * //code to cancel the animation 301 | * } 302 | * } 303 | * } 304 | * }) 305 | * ``` 306 | * 307 | * See {@link ng.$animateProvider#register $animateProvider.register()} and 308 | * {@link ngAnimate ngAnimate module} for more information. 309 | */ 310 | animation: invokeLater('$animateProvider', 'register'), 311 | 312 | /** 313 | * @ngdoc method 314 | * @name angular.Module#filter 315 | * @module ng 316 | * @param {string} name Filter name. 317 | * @param {Function} filterFactory Factory function for creating new instance of filter. 318 | * @description 319 | * See {@link ng.$filterProvider#register $filterProvider.register()}. 320 | */ 321 | filter: invokeLater('$filterProvider', 'register'), 322 | 323 | /** 324 | * @ngdoc method 325 | * @name angular.Module#controller 326 | * @module ng 327 | * @param {string|Object} name Controller name, or an object map of controllers where the 328 | * keys are the names and the values are the constructors. 329 | * @param {Function} constructor Controller constructor function. 330 | * @description 331 | * See {@link ng.$controllerProvider#register $controllerProvider.register()}. 332 | */ 333 | controller: invokeLater('$controllerProvider', 'register'), 334 | 335 | /** 336 | * @ngdoc method 337 | * @name angular.Module#directive 338 | * @module ng 339 | * @param {string|Object} name Directive name, or an object map of directives where the 340 | * keys are the names and the values are the factories. 341 | * @param {Function} directiveFactory Factory function for creating new instance of 342 | * directives. 343 | * @description 344 | * See {@link ng.$compileProvider#directive $compileProvider.directive()}. 345 | */ 346 | directive: invokeLater('$compileProvider', 'directive'), 347 | 348 | /** 349 | * @ngdoc method 350 | * @name angular.Module#config 351 | * @module ng 352 | * @param {Function} configFn Execute this function on module load. Useful for service 353 | * configuration. 354 | * @description 355 | * Use this method to register work which needs to be performed on module loading. 356 | * For more about how to configure services, see 357 | * {@link providers#provider-recipe Provider Recipe}. 358 | */ 359 | config: config, 360 | 361 | /** 362 | * @ngdoc method 363 | * @name angular.Module#run 364 | * @module ng 365 | * @param {Function} initializationFn Execute this function after injector creation. 366 | * Useful for application initialization. 367 | * @description 368 | * Use this method to register work which should be performed when the injector is done 369 | * loading all modules. 370 | */ 371 | run: function(block) { 372 | runBlocks.push(block); 373 | return this; 374 | } 375 | }; 376 | 377 | if (configFn) { 378 | config(configFn); 379 | } 380 | 381 | return moduleInstance; 382 | 383 | /** 384 | * @param {string} provider 385 | * @param {string} method 386 | * @param {String=} insertMethod 387 | * @returns {angular.Module} 388 | */ 389 | function invokeLater(provider, method, insertMethod, queue) { 390 | if (!queue) queue = invokeQueue; 391 | return function() { 392 | queue[insertMethod || 'push']([provider, method, arguments]); 393 | return moduleInstance; 394 | }; 395 | } 396 | }); 397 | }; 398 | }); 399 | 400 | } 401 | 402 | setupModuleLoader(window); 403 | })(window); 404 | 405 | /** 406 | * Closure compiler type information 407 | * 408 | * @typedef { { 409 | * requires: !Array., 410 | * invokeQueue: !Array.>, 411 | * 412 | * service: function(string, Function):angular.Module, 413 | * factory: function(string, Function):angular.Module, 414 | * value: function(string, *):angular.Module, 415 | * 416 | * filter: function(string, Function):angular.Module, 417 | * 418 | * init: function(Function):angular.Module 419 | * } } 420 | */ 421 | angular.Module; 422 | 423 | -------------------------------------------------------------------------------- /ngPlaybook/Js/angular/angular-messages.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license AngularJS v1.3.5 3 | * (c) 2010-2014 Google, Inc. http://angularjs.org 4 | * License: MIT 5 | */ 6 | (function(window, angular, undefined) {'use strict'; 7 | 8 | /** 9 | * @ngdoc module 10 | * @name ngMessages 11 | * @description 12 | * 13 | * The `ngMessages` module provides enhanced support for displaying messages within templates 14 | * (typically within forms or when rendering message objects that return key/value data). 15 | * Instead of relying on JavaScript code and/or complex ng-if statements within your form template to 16 | * show and hide error messages specific to the state of an input field, the `ngMessages` and 17 | * `ngMessage` directives are designed to handle the complexity, inheritance and priority 18 | * sequencing based on the order of how the messages are defined in the template. 19 | * 20 | * Currently, the ngMessages module only contains the code for the `ngMessages` 21 | * and `ngMessage` directives. 22 | * 23 | * # Usage 24 | * The `ngMessages` directive listens on a key/value collection which is set on the ngMessages attribute. 25 | * Since the {@link ngModel ngModel} directive exposes an `$error` object, this error object can be 26 | * used with `ngMessages` to display control error messages in an easier way than with just regular angular 27 | * template directives. 28 | * 29 | * ```html 30 | *
31 | * 32 | *
33 | *
You did not enter a field
34 | *
The value entered is too short
35 | *
36 | *
37 | * ``` 38 | * 39 | * Now whatever key/value entries are present within the provided object (in this case `$error`) then 40 | * the ngMessages directive will render the inner first ngMessage directive (depending if the key values 41 | * match the attribute value present on each ngMessage directive). In other words, if your errors 42 | * object contains the following data: 43 | * 44 | * ```javascript 45 | * 46 | * myField.$error = { minlength : true, required : false }; 47 | * ``` 48 | * 49 | * Then the `required` message will be displayed first. When required is false then the `minlength` message 50 | * will be displayed right after (since these messages are ordered this way in the template HTML code). 51 | * The prioritization of each message is determined by what order they're present in the DOM. 52 | * Therefore, instead of having custom JavaScript code determine the priority of what errors are 53 | * present before others, the presentation of the errors are handled within the template. 54 | * 55 | * By default, ngMessages will only display one error at a time. However, if you wish to display all 56 | * messages then the `ng-messages-multiple` attribute flag can be used on the element containing the 57 | * ngMessages directive to make this happen. 58 | * 59 | * ```html 60 | *
...
61 | * ``` 62 | * 63 | * ## Reusing and Overriding Messages 64 | * In addition to prioritization, ngMessages also allows for including messages from a remote or an inline 65 | * template. This allows for generic collection of messages to be reused across multiple parts of an 66 | * application. 67 | * 68 | * ```html 69 | * 73 | *
74 | * ``` 75 | * 76 | * However, including generic messages may not be useful enough to match all input fields, therefore, 77 | * `ngMessages` provides the ability to override messages defined in the remote template by redefining 78 | * then within the directive container. 79 | * 80 | * ```html 81 | * 82 | * 86 | * 87 | *
88 | * 94 | * 95 | *
96 | * 97 | *
You did not enter your email address
98 | * 99 | * 100 | *
Your email address is invalid
101 | *
102 | *
103 | * ``` 104 | * 105 | * In the example HTML code above the message that is set on required will override the corresponding 106 | * required message defined within the remote template. Therefore, with particular input fields (such 107 | * email addresses, date fields, autocomplete inputs, etc...), specialized error messages can be applied 108 | * while more generic messages can be used to handle other, more general input errors. 109 | * 110 | * ## Animations 111 | * If the `ngAnimate` module is active within the application then both the `ngMessages` and 112 | * `ngMessage` directives will trigger animations whenever any messages are added and removed 113 | * from the DOM by the `ngMessages` directive. 114 | * 115 | * Whenever the `ngMessages` directive contains one or more visible messages then the `.ng-active` CSS 116 | * class will be added to the element. The `.ng-inactive` CSS class will be applied when there are no 117 | * animations present. Therefore, CSS transitions and keyframes as well as JavaScript animations can 118 | * hook into the animations whenever these classes are added/removed. 119 | * 120 | * Let's say that our HTML code for our messages container looks like so: 121 | * 122 | * ```html 123 | *
124 | *
...
125 | *
...
126 | *
127 | * ``` 128 | * 129 | * Then the CSS animation code for the message container looks like so: 130 | * 131 | * ```css 132 | * .my-messages { 133 | * transition:1s linear all; 134 | * } 135 | * .my-messages.ng-active { 136 | * // messages are visible 137 | * } 138 | * .my-messages.ng-inactive { 139 | * // messages are hidden 140 | * } 141 | * ``` 142 | * 143 | * Whenever an inner message is attached (becomes visible) or removed (becomes hidden) then the enter 144 | * and leave animation is triggered for each particular element bound to the `ngMessage` directive. 145 | * 146 | * Therefore, the CSS code for the inner messages looks like so: 147 | * 148 | * ```css 149 | * .some-message { 150 | * transition:1s linear all; 151 | * } 152 | * 153 | * .some-message.ng-enter {} 154 | * .some-message.ng-enter.ng-enter-active {} 155 | * 156 | * .some-message.ng-leave {} 157 | * .some-message.ng-leave.ng-leave-active {} 158 | * ``` 159 | * 160 | * {@link ngAnimate Click here} to learn how to use JavaScript animations or to learn more about ngAnimate. 161 | */ 162 | angular.module('ngMessages', []) 163 | 164 | /** 165 | * @ngdoc directive 166 | * @module ngMessages 167 | * @name ngMessages 168 | * @restrict AE 169 | * 170 | * @description 171 | * `ngMessages` is a directive that is designed to show and hide messages based on the state 172 | * of a key/value object that it listens on. The directive itself compliments error message 173 | * reporting with the `ngModel` $error object (which stores a key/value state of validation errors). 174 | * 175 | * `ngMessages` manages the state of internal messages within its container element. The internal 176 | * messages use the `ngMessage` directive and will be inserted/removed from the page depending 177 | * on if they're present within the key/value object. By default, only one message will be displayed 178 | * at a time and this depends on the prioritization of the messages within the template. (This can 179 | * be changed by using the ng-messages-multiple on the directive container.) 180 | * 181 | * A remote template can also be used to promote message reuseability and messages can also be 182 | * overridden. 183 | * 184 | * {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`. 185 | * 186 | * @usage 187 | * ```html 188 | * 189 | * 190 | * ... 191 | * ... 192 | * ... 193 | * 194 | * 195 | * 196 | * 197 | * ... 198 | * ... 199 | * ... 200 | * 201 | * ``` 202 | * 203 | * @param {string} ngMessages an angular expression evaluating to a key/value object 204 | * (this is typically the $error object on an ngModel instance). 205 | * @param {string=} ngMessagesMultiple|multiple when set, all messages will be displayed with true 206 | * @param {string=} ngMessagesInclude|include when set, the specified template will be included into the ng-messages container 207 | * 208 | * @example 209 | * 212 | * 213 | *
214 | * 215 | * 221 | * 222 | *
myForm.myName.$error = {{ myForm.myName.$error | json }}
223 | * 224 | *
225 | *
You did not enter a field
226 | *
Your field is too short
227 | *
Your field is too long
228 | *
229 | *
230 | *
231 | * 232 | * angular.module('ngMessagesExample', ['ngMessages']); 233 | * 234 | *
235 | */ 236 | .directive('ngMessages', ['$compile', '$animate', '$templateRequest', 237 | function($compile, $animate, $templateRequest) { 238 | var ACTIVE_CLASS = 'ng-active'; 239 | var INACTIVE_CLASS = 'ng-inactive'; 240 | 241 | return { 242 | restrict: 'AE', 243 | controller: function() { 244 | this.$renderNgMessageClasses = angular.noop; 245 | 246 | var messages = []; 247 | this.registerMessage = function(index, message) { 248 | for (var i = 0; i < messages.length; i++) { 249 | if (messages[i].type == message.type) { 250 | if (index != i) { 251 | var temp = messages[index]; 252 | messages[index] = messages[i]; 253 | if (index < messages.length) { 254 | messages[i] = temp; 255 | } else { 256 | messages.splice(0, i); //remove the old one (and shift left) 257 | } 258 | } 259 | return; 260 | } 261 | } 262 | messages.splice(index, 0, message); //add the new one (and shift right) 263 | }; 264 | 265 | this.renderMessages = function(values, multiple) { 266 | values = values || {}; 267 | 268 | var found; 269 | angular.forEach(messages, function(message) { 270 | if ((!found || multiple) && truthyVal(values[message.type])) { 271 | message.attach(); 272 | found = true; 273 | } else { 274 | message.detach(); 275 | } 276 | }); 277 | 278 | this.renderElementClasses(found); 279 | 280 | function truthyVal(value) { 281 | return value !== null && value !== false && value; 282 | } 283 | }; 284 | }, 285 | require: 'ngMessages', 286 | link: function($scope, element, $attrs, ctrl) { 287 | ctrl.renderElementClasses = function(bool) { 288 | bool ? $animate.setClass(element, ACTIVE_CLASS, INACTIVE_CLASS) 289 | : $animate.setClass(element, INACTIVE_CLASS, ACTIVE_CLASS); 290 | }; 291 | 292 | //JavaScript treats empty strings as false, but ng-message-multiple by itself is an empty string 293 | var multiple = angular.isString($attrs.ngMessagesMultiple) || 294 | angular.isString($attrs.multiple); 295 | 296 | var cachedValues, watchAttr = $attrs.ngMessages || $attrs['for']; //for is a reserved keyword 297 | $scope.$watchCollection(watchAttr, function(values) { 298 | cachedValues = values; 299 | ctrl.renderMessages(values, multiple); 300 | }); 301 | 302 | var tpl = $attrs.ngMessagesInclude || $attrs.include; 303 | if (tpl) { 304 | $templateRequest(tpl) 305 | .then(function processTemplate(html) { 306 | var after, container = angular.element('
').html(html); 307 | angular.forEach(container.children(), function(elm) { 308 | elm = angular.element(elm); 309 | after ? after.after(elm) 310 | : element.prepend(elm); //start of the container 311 | after = elm; 312 | $compile(elm)($scope); 313 | }); 314 | ctrl.renderMessages(cachedValues, multiple); 315 | }); 316 | } 317 | } 318 | }; 319 | }]) 320 | 321 | 322 | /** 323 | * @ngdoc directive 324 | * @name ngMessage 325 | * @restrict AE 326 | * @scope 327 | * 328 | * @description 329 | * `ngMessage` is a directive with the purpose to show and hide a particular message. 330 | * For `ngMessage` to operate, a parent `ngMessages` directive on a parent DOM element 331 | * must be situated since it determines which messages are visible based on the state 332 | * of the provided key/value map that `ngMessages` listens on. 333 | * 334 | * @usage 335 | * ```html 336 | * 337 | * 338 | * ... 339 | * ... 340 | * ... 341 | * 342 | * 343 | * 344 | * 345 | * ... 346 | * ... 347 | * ... 348 | * 349 | * ``` 350 | * 351 | * {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`. 352 | * 353 | * @param {string} ngMessage a string value corresponding to the message key. 354 | */ 355 | .directive('ngMessage', ['$animate', function($animate) { 356 | var COMMENT_NODE = 8; 357 | return { 358 | require: '^ngMessages', 359 | transclude: 'element', 360 | terminal: true, 361 | restrict: 'AE', 362 | link: function($scope, $element, $attrs, ngMessages, $transclude) { 363 | var index, element; 364 | 365 | var commentNode = $element[0]; 366 | var parentNode = commentNode.parentNode; 367 | for (var i = 0, j = 0; i < parentNode.childNodes.length; i++) { 368 | var node = parentNode.childNodes[i]; 369 | if (node.nodeType == COMMENT_NODE && node.nodeValue.indexOf('ngMessage') >= 0) { 370 | if (node === commentNode) { 371 | index = j; 372 | break; 373 | } 374 | j++; 375 | } 376 | } 377 | 378 | ngMessages.registerMessage(index, { 379 | type: $attrs.ngMessage || $attrs.when, 380 | attach: function() { 381 | if (!element) { 382 | $transclude($scope, function(clone) { 383 | $animate.enter(clone, null, $element); 384 | element = clone; 385 | }); 386 | } 387 | }, 388 | detach: function(now) { 389 | if (element) { 390 | $animate.leave(element); 391 | element = null; 392 | } 393 | } 394 | }); 395 | } 396 | }; 397 | }]); 398 | 399 | 400 | })(window, window.angular); 401 | -------------------------------------------------------------------------------- /ngPlaybook/Js/google-chart/google-chart.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @description Google Chart Api Directive Module for AngularJS 3 | * @version 0.0.11 4 | * @author Nicolas Bouillon 5 | * @author GitHub contributors 6 | * @license MIT 7 | * @year 2013 8 | */ 9 | (function (document, window, angular) { 10 | 'use strict'; 11 | 12 | angular.module('googlechart', []) 13 | 14 | .value('googleChartApiConfig', { 15 | version: '1', 16 | optionalSettings: { 17 | packages: ['corechart'] 18 | } 19 | }) 20 | 21 | .provider('googleJsapiUrl', function () { 22 | var protocol = 'https:'; 23 | var url = '//www.google.com/jsapi'; 24 | 25 | this.setProtocol = function (newProtocol) { 26 | protocol = newProtocol; 27 | }; 28 | 29 | this.setUrl = function (newUrl) { 30 | url = newUrl; 31 | }; 32 | 33 | this.$get = function () { 34 | return (protocol ? protocol : '') + url; 35 | }; 36 | }) 37 | .factory('googleChartApiPromise', ['$rootScope', '$q', 'googleChartApiConfig', 'googleJsapiUrl', function ($rootScope, $q, apiConfig, googleJsapiUrl) { 38 | var apiReady = $q.defer(); 39 | var onLoad = function () { 40 | // override callback function 41 | var settings = { 42 | callback: function () { 43 | var oldCb = apiConfig.optionalSettings.callback; 44 | $rootScope.$apply(function () { 45 | apiReady.resolve(); 46 | }); 47 | 48 | if (angular.isFunction(oldCb)) { 49 | oldCb.call(this); 50 | } 51 | } 52 | }; 53 | 54 | settings = angular.extend({}, apiConfig.optionalSettings, settings); 55 | 56 | window.google.load('visualization', apiConfig.version, settings); 57 | }; 58 | var head = document.getElementsByTagName('head')[0]; 59 | var script = document.createElement('script'); 60 | 61 | script.setAttribute('type', 'text/javascript'); 62 | script.src = googleJsapiUrl; 63 | 64 | if (script.addEventListener) { // Standard browsers (including IE9+) 65 | script.addEventListener('load', onLoad, false); 66 | } else { // IE8 and below 67 | script.onreadystatechange = function () { 68 | if (script.readyState === 'loaded' || script.readyState === 'complete') { 69 | script.onreadystatechange = null; 70 | onLoad(); 71 | } 72 | }; 73 | } 74 | 75 | head.appendChild(script); 76 | 77 | return apiReady.promise; 78 | }]) 79 | .directive('googleChart', ['$timeout', '$window', '$rootScope', 'googleChartApiPromise', function ($timeout, $window, $rootScope, googleChartApiPromise) { 80 | return { 81 | restrict: 'A', 82 | scope: { 83 | beforeDraw: '&', 84 | chart: '=chart', 85 | onReady: '&', 86 | onSelect: '&', 87 | select: '&' 88 | }, 89 | link: function ($scope, $elm, $attrs) { 90 | /* Watches, to refresh the chart when its data, formatters, options, view, 91 | or type change. All other values intentionally disregarded to avoid double 92 | calls to the draw function. Please avoid making changes to these objects 93 | directly from this directive.*/ 94 | $scope.$watch(function () { 95 | if ($scope.chart) { 96 | return { 97 | customFormatters: $scope.chart.customFormatters, 98 | data: $scope.chart.data, 99 | formatters: $scope.chart.formatters, 100 | options: $scope.chart.options, 101 | type: $scope.chart.type, 102 | view: $scope.chart.view 103 | }; 104 | } 105 | return $scope.chart; 106 | }, function () { 107 | drawAsync(); 108 | }, true); // true is for deep object equality checking 109 | 110 | // Redraw the chart if the window is resized 111 | var resizeHandler = $rootScope.$on('resizeMsg', function () { 112 | $timeout(function () { 113 | // Not always defined yet in IE so check 114 | if ($scope.chartWrapper) { 115 | drawAsync(); 116 | } 117 | }); 118 | }); 119 | 120 | //Cleanup resize handler. 121 | $scope.$on('$destroy', function () { 122 | resizeHandler(); 123 | }); 124 | 125 | // Keeps old formatter configuration to compare against 126 | $scope.oldChartFormatters = {}; 127 | 128 | function applyFormat(formatType, formatClass, dataTable) { 129 | 130 | if (typeof ($scope.chart.formatters[formatType]) != 'undefined') { 131 | if (!angular.equals($scope.chart.formatters[formatType], $scope.oldChartFormatters[formatType])) { 132 | $scope.oldChartFormatters[formatType] = $scope.chart.formatters[formatType]; 133 | $scope.formatters[formatType] = []; 134 | 135 | if (formatType === 'color') { 136 | for (var cIdx = 0; cIdx < $scope.chart.formatters[formatType].length; cIdx++) { 137 | var colorFormat = new formatClass(); 138 | 139 | for (i = 0; i < $scope.chart.formatters[formatType][cIdx].formats.length; i++) { 140 | var data = $scope.chart.formatters[formatType][cIdx].formats[i]; 141 | 142 | if (typeof (data.fromBgColor) != 'undefined' && typeof (data.toBgColor) != 'undefined') 143 | colorFormat.addGradientRange(data.from, data.to, data.color, data.fromBgColor, data.toBgColor); 144 | else 145 | colorFormat.addRange(data.from, data.to, data.color, data.bgcolor); 146 | } 147 | 148 | $scope.formatters[formatType].push(colorFormat) 149 | } 150 | } else { 151 | 152 | for (var i = 0; i < $scope.chart.formatters[formatType].length; i++) { 153 | $scope.formatters[formatType].push(new formatClass( 154 | $scope.chart.formatters[formatType][i]) 155 | ); 156 | } 157 | } 158 | } 159 | 160 | 161 | //apply formats to dataTable 162 | for (i = 0; i < $scope.formatters[formatType].length; i++) { 163 | if ($scope.chart.formatters[formatType][i].columnNum < dataTable.getNumberOfColumns()) 164 | $scope.formatters[formatType][i].format(dataTable, $scope.chart.formatters[formatType][i].columnNum); 165 | } 166 | 167 | 168 | //Many formatters require HTML tags to display special formatting 169 | if (formatType === 'arrow' || formatType === 'bar' || formatType === 'color') 170 | $scope.chart.options.allowHtml = true; 171 | } 172 | } 173 | 174 | function draw() { 175 | if (!draw.triggered && ($scope.chart != undefined)) { 176 | draw.triggered = true; 177 | $timeout(function () { 178 | 179 | if (typeof ($scope.chartWrapper) == 'undefined') { 180 | var chartWrapperArgs = { 181 | chartType: $scope.chart.type, 182 | dataTable: $scope.chart.data, 183 | view: $scope.chart.view, 184 | options: $scope.chart.options, 185 | containerId: $elm[0] 186 | }; 187 | 188 | $scope.chartWrapper = new google.visualization.ChartWrapper(chartWrapperArgs); 189 | google.visualization.events.addListener($scope.chartWrapper, 'ready', function () { 190 | $scope.chart.displayed = true; 191 | $scope.$apply(function (scope) { 192 | scope.onReady({ chartWrapper: scope.chartWrapper }); 193 | }); 194 | }); 195 | google.visualization.events.addListener($scope.chartWrapper, 'error', function (err) { 196 | console.log("Chart not displayed due to error: " + err.message + ". Full error object follows."); 197 | console.log(err); 198 | }); 199 | google.visualization.events.addListener($scope.chartWrapper, 'select', function () { 200 | var selectEventRetParams = { selectedItems: $scope.chartWrapper.getChart().getSelection() }; 201 | // This is for backwards compatibility for people using 'selectedItem' that only wanted the first selection. 202 | selectEventRetParams['selectedItem'] = selectEventRetParams['selectedItems'][0]; 203 | $scope.$apply(function () { 204 | if ($attrs.select) { 205 | console.log('Angular-Google-Chart: The \'select\' attribute is deprecated and will be removed in a future release. Please use \'onSelect\'.'); 206 | $scope.select({ selectEventRetParams: selectEventRetParams }); 207 | } 208 | else { 209 | $scope.onSelect({ selectEventRetParams: selectEventRetParams }); 210 | } 211 | }); 212 | }); 213 | } 214 | else { 215 | $scope.chartWrapper.setChartType($scope.chart.type); 216 | $scope.chartWrapper.setDataTable($scope.chart.data); 217 | $scope.chartWrapper.setView($scope.chart.view); 218 | $scope.chartWrapper.setOptions($scope.chart.options); 219 | } 220 | 221 | if (typeof ($scope.formatters) === 'undefined') 222 | $scope.formatters = {}; 223 | 224 | if (typeof ($scope.chart.formatters) != 'undefined') { 225 | applyFormat("number", google.visualization.NumberFormat, $scope.chartWrapper.getDataTable()); 226 | applyFormat("arrow", google.visualization.ArrowFormat, $scope.chartWrapper.getDataTable()); 227 | applyFormat("date", google.visualization.DateFormat, $scope.chartWrapper.getDataTable()); 228 | applyFormat("bar", google.visualization.BarFormat, $scope.chartWrapper.getDataTable()); 229 | applyFormat("color", google.visualization.ColorFormat, $scope.chartWrapper.getDataTable()); 230 | } 231 | 232 | var customFormatters = $scope.chart.customFormatters; 233 | if (typeof (customFormatters) != 'undefined') { 234 | for (var name in customFormatters) { 235 | applyFormat(name, customFormatters[name], $scope.chartWrapper.getDataTable()); 236 | } 237 | } 238 | 239 | $timeout(function () { 240 | $scope.beforeDraw({ chartWrapper: $scope.chartWrapper }); 241 | $scope.chartWrapper.draw(); 242 | draw.triggered = false; 243 | }); 244 | }, 0, true); 245 | } 246 | } 247 | 248 | function drawAsync() { 249 | googleChartApiPromise.then(function () { 250 | draw(); 251 | }) 252 | } 253 | } 254 | }; 255 | }]) 256 | 257 | .run(['$rootScope', '$window', function ($rootScope, $window) { 258 | angular.element($window).bind('resize', function () { 259 | $rootScope.$emit('resizeMsg'); 260 | }); 261 | }]); 262 | 263 | })(document, window, window.angular); 264 | -------------------------------------------------------------------------------- /ngPlaybook/Js/jasmine/boot.js: -------------------------------------------------------------------------------- 1 | /** 2 | Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project. 3 | 4 | If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms. 5 | 6 | The location of `boot.js` can be specified and/or overridden in `jasmine.yml`. 7 | 8 | [jasmine-gem]: http://github.com/pivotal/jasmine-gem 9 | */ 10 | 11 | (function() { 12 | 13 | /** 14 | * ## Require & Instantiate 15 | * 16 | * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference. 17 | */ 18 | window.jasmine = jasmineRequire.core(jasmineRequire); 19 | 20 | /** 21 | * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference. 22 | */ 23 | jasmineRequire.html(jasmine); 24 | 25 | /** 26 | * Create the Jasmine environment. This is used to run all specs in a project. 27 | */ 28 | var env = jasmine.getEnv(); 29 | 30 | /** 31 | * ## The Global Interface 32 | * 33 | * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged. 34 | */ 35 | var jasmineInterface = jasmineRequire.interface(jasmine, env); 36 | 37 | /** 38 | * Add all of the Jasmine global/public interface to the proper global, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`. 39 | */ 40 | if (typeof window == "undefined" && typeof exports == "object") { 41 | extend(exports, jasmineInterface); 42 | } else { 43 | extend(window, jasmineInterface); 44 | } 45 | 46 | /** 47 | * ## Runner Parameters 48 | * 49 | * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface. 50 | */ 51 | 52 | var queryString = new jasmine.QueryString({ 53 | getWindowLocation: function() { return window.location; } 54 | }); 55 | 56 | var catchingExceptions = queryString.getParam("catch"); 57 | env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions); 58 | 59 | /** 60 | * ## Reporters 61 | * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any). 62 | */ 63 | var htmlReporter = new jasmine.HtmlReporter({ 64 | env: env, 65 | onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); }, 66 | getContainer: function() { return document.body; }, 67 | createElement: function() { return document.createElement.apply(document, arguments); }, 68 | createTextNode: function() { return document.createTextNode.apply(document, arguments); }, 69 | timer: new jasmine.Timer() 70 | }); 71 | 72 | /** 73 | * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript. 74 | */ 75 | env.addReporter(jasmineInterface.jsApiReporter); 76 | env.addReporter(htmlReporter); 77 | 78 | /** 79 | * Filter which specs will be run by matching the start of the full name against the `spec` query param. 80 | */ 81 | var specFilter = new jasmine.HtmlSpecFilter({ 82 | filterString: function() { return queryString.getParam("spec"); } 83 | }); 84 | 85 | env.specFilter = function(spec) { 86 | return specFilter.matches(spec.getFullName()); 87 | }; 88 | 89 | /** 90 | * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack. 91 | */ 92 | window.setTimeout = window.setTimeout; 93 | window.setInterval = window.setInterval; 94 | window.clearTimeout = window.clearTimeout; 95 | window.clearInterval = window.clearInterval; 96 | 97 | /** 98 | * ## Execution 99 | * 100 | * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded. 101 | */ 102 | var currentWindowOnload = window.onload; 103 | 104 | window.onload = function() { 105 | if (currentWindowOnload) { 106 | currentWindowOnload(); 107 | } 108 | htmlReporter.initialize(); 109 | env.execute(); 110 | }; 111 | 112 | /** 113 | * Helper function for readability above. 114 | */ 115 | function extend(destination, source) { 116 | for (var property in source) destination[property] = source[property]; 117 | return destination; 118 | } 119 | 120 | }()); 121 | -------------------------------------------------------------------------------- /ngPlaybook/Js/jasmine/console.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008-2014 Pivotal Labs 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | function getJasmineRequireObj() { 24 | if (typeof module !== 'undefined' && module.exports) { 25 | return exports; 26 | } else { 27 | window.jasmineRequire = window.jasmineRequire || {}; 28 | return window.jasmineRequire; 29 | } 30 | } 31 | 32 | getJasmineRequireObj().console = function(jRequire, j$) { 33 | j$.ConsoleReporter = jRequire.ConsoleReporter(); 34 | }; 35 | 36 | getJasmineRequireObj().ConsoleReporter = function() { 37 | 38 | var noopTimer = { 39 | start: function(){}, 40 | elapsed: function(){ return 0; } 41 | }; 42 | 43 | function ConsoleReporter(options) { 44 | var print = options.print, 45 | showColors = options.showColors || false, 46 | onComplete = options.onComplete || function() {}, 47 | timer = options.timer || noopTimer, 48 | specCount, 49 | failureCount, 50 | failedSpecs = [], 51 | pendingCount, 52 | ansi = { 53 | green: '\x1B[32m', 54 | red: '\x1B[31m', 55 | yellow: '\x1B[33m', 56 | none: '\x1B[0m' 57 | }; 58 | 59 | this.jasmineStarted = function() { 60 | specCount = 0; 61 | failureCount = 0; 62 | pendingCount = 0; 63 | print('Started'); 64 | printNewline(); 65 | timer.start(); 66 | }; 67 | 68 | this.jasmineDone = function() { 69 | printNewline(); 70 | for (var i = 0; i < failedSpecs.length; i++) { 71 | specFailureDetails(failedSpecs[i]); 72 | } 73 | 74 | if(specCount > 0) { 75 | printNewline(); 76 | 77 | var specCounts = specCount + ' ' + plural('spec', specCount) + ', ' + 78 | failureCount + ' ' + plural('failure', failureCount); 79 | 80 | if (pendingCount) { 81 | specCounts += ', ' + pendingCount + ' pending ' + plural('spec', pendingCount); 82 | } 83 | 84 | print(specCounts); 85 | } else { 86 | print('No specs found'); 87 | } 88 | 89 | printNewline(); 90 | var seconds = timer.elapsed() / 1000; 91 | print('Finished in ' + seconds + ' ' + plural('second', seconds)); 92 | 93 | printNewline(); 94 | 95 | onComplete(failureCount === 0); 96 | }; 97 | 98 | this.specDone = function(result) { 99 | specCount++; 100 | 101 | if (result.status == 'pending') { 102 | pendingCount++; 103 | print(colored('yellow', '*')); 104 | return; 105 | } 106 | 107 | if (result.status == 'passed') { 108 | print(colored('green', '.')); 109 | return; 110 | } 111 | 112 | if (result.status == 'failed') { 113 | failureCount++; 114 | failedSpecs.push(result); 115 | print(colored('red', 'F')); 116 | } 117 | }; 118 | 119 | return this; 120 | 121 | function printNewline() { 122 | print('\n'); 123 | } 124 | 125 | function colored(color, str) { 126 | return showColors ? (ansi[color] + str + ansi.none) : str; 127 | } 128 | 129 | function plural(str, count) { 130 | return count == 1 ? str : str + 's'; 131 | } 132 | 133 | function repeat(thing, times) { 134 | var arr = []; 135 | for (var i = 0; i < times; i++) { 136 | arr.push(thing); 137 | } 138 | return arr; 139 | } 140 | 141 | function indent(str, spaces) { 142 | var lines = (str || '').split('\n'); 143 | var newArr = []; 144 | for (var i = 0; i < lines.length; i++) { 145 | newArr.push(repeat(' ', spaces).join('') + lines[i]); 146 | } 147 | return newArr.join('\n'); 148 | } 149 | 150 | function specFailureDetails(result) { 151 | printNewline(); 152 | print(result.fullName); 153 | 154 | for (var i = 0; i < result.failedExpectations.length; i++) { 155 | var failedExpectation = result.failedExpectations[i]; 156 | printNewline(); 157 | print(indent(failedExpectation.message, 2)); 158 | print(indent(failedExpectation.stack, 2)); 159 | } 160 | 161 | printNewline(); 162 | } 163 | } 164 | 165 | return ConsoleReporter; 166 | }; 167 | -------------------------------------------------------------------------------- /ngPlaybook/Js/jasmine/jasmine-html.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008-2014 Pivotal Labs 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | jasmineRequire.html = function(j$) { 24 | j$.ResultsNode = jasmineRequire.ResultsNode(); 25 | j$.HtmlReporter = jasmineRequire.HtmlReporter(j$); 26 | j$.QueryString = jasmineRequire.QueryString(); 27 | j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter(); 28 | }; 29 | 30 | jasmineRequire.HtmlReporter = function(j$) { 31 | 32 | var noopTimer = { 33 | start: function() {}, 34 | elapsed: function() { return 0; } 35 | }; 36 | 37 | function HtmlReporter(options) { 38 | var env = options.env || {}, 39 | getContainer = options.getContainer, 40 | createElement = options.createElement, 41 | createTextNode = options.createTextNode, 42 | onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {}, 43 | timer = options.timer || noopTimer, 44 | results = [], 45 | specsExecuted = 0, 46 | failureCount = 0, 47 | pendingSpecCount = 0, 48 | htmlReporterMain, 49 | symbols; 50 | 51 | this.initialize = function() { 52 | clearPrior(); 53 | htmlReporterMain = createDom('div', {className: 'jasmine_html-reporter'}, 54 | createDom('div', {className: 'banner'}, 55 | createDom('a', {className: 'title', href: 'http://jasmine.github.io/', target: '_blank'}), 56 | createDom('span', {className: 'version'}, j$.version) 57 | ), 58 | createDom('ul', {className: 'symbol-summary'}), 59 | createDom('div', {className: 'alert'}), 60 | createDom('div', {className: 'results'}, 61 | createDom('div', {className: 'failures'}) 62 | ) 63 | ); 64 | getContainer().appendChild(htmlReporterMain); 65 | 66 | symbols = find('.symbol-summary'); 67 | }; 68 | 69 | var totalSpecsDefined; 70 | this.jasmineStarted = function(options) { 71 | totalSpecsDefined = options.totalSpecsDefined || 0; 72 | timer.start(); 73 | }; 74 | 75 | var summary = createDom('div', {className: 'summary'}); 76 | 77 | var topResults = new j$.ResultsNode({}, '', null), 78 | currentParent = topResults; 79 | 80 | this.suiteStarted = function(result) { 81 | currentParent.addChild(result, 'suite'); 82 | currentParent = currentParent.last(); 83 | }; 84 | 85 | this.suiteDone = function(result) { 86 | if (currentParent == topResults) { 87 | return; 88 | } 89 | 90 | currentParent = currentParent.parent; 91 | }; 92 | 93 | this.specStarted = function(result) { 94 | currentParent.addChild(result, 'spec'); 95 | }; 96 | 97 | var failures = []; 98 | this.specDone = function(result) { 99 | if(noExpectations(result) && console && console.error) { 100 | console.error('Spec \'' + result.fullName + '\' has no expectations.'); 101 | } 102 | 103 | if (result.status != 'disabled') { 104 | specsExecuted++; 105 | } 106 | 107 | symbols.appendChild(createDom('li', { 108 | className: noExpectations(result) ? 'empty' : result.status, 109 | id: 'spec_' + result.id, 110 | title: result.fullName 111 | } 112 | )); 113 | 114 | if (result.status == 'failed') { 115 | failureCount++; 116 | 117 | var failure = 118 | createDom('div', {className: 'spec-detail failed'}, 119 | createDom('div', {className: 'description'}, 120 | createDom('a', {title: result.fullName, href: specHref(result)}, result.fullName) 121 | ), 122 | createDom('div', {className: 'messages'}) 123 | ); 124 | var messages = failure.childNodes[1]; 125 | 126 | for (var i = 0; i < result.failedExpectations.length; i++) { 127 | var expectation = result.failedExpectations[i]; 128 | messages.appendChild(createDom('div', {className: 'result-message'}, expectation.message)); 129 | messages.appendChild(createDom('div', {className: 'stack-trace'}, expectation.stack)); 130 | } 131 | 132 | failures.push(failure); 133 | } 134 | 135 | if (result.status == 'pending') { 136 | pendingSpecCount++; 137 | } 138 | }; 139 | 140 | this.jasmineDone = function() { 141 | var banner = find('.banner'); 142 | banner.appendChild(createDom('span', {className: 'duration'}, 'finished in ' + timer.elapsed() / 1000 + 's')); 143 | 144 | var alert = find('.alert'); 145 | 146 | alert.appendChild(createDom('span', { className: 'exceptions' }, 147 | createDom('label', { className: 'label', 'for': 'raise-exceptions' }, 'raise exceptions'), 148 | createDom('input', { 149 | className: 'raise', 150 | id: 'raise-exceptions', 151 | type: 'checkbox' 152 | }) 153 | )); 154 | var checkbox = find('#raise-exceptions'); 155 | 156 | checkbox.checked = !env.catchingExceptions(); 157 | checkbox.onclick = onRaiseExceptionsClick; 158 | 159 | if (specsExecuted < totalSpecsDefined) { 160 | var skippedMessage = 'Ran ' + specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all'; 161 | alert.appendChild( 162 | createDom('span', {className: 'bar skipped'}, 163 | createDom('a', {href: '?', title: 'Run all specs'}, skippedMessage) 164 | ) 165 | ); 166 | } 167 | var statusBarMessage = ''; 168 | var statusBarClassName = 'bar '; 169 | 170 | if (totalSpecsDefined > 0) { 171 | statusBarMessage += pluralize('spec', specsExecuted) + ', ' + pluralize('failure', failureCount); 172 | if (pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', pendingSpecCount); } 173 | statusBarClassName += (failureCount > 0) ? 'failed' : 'passed'; 174 | } else { 175 | statusBarClassName += 'skipped'; 176 | statusBarMessage += 'No specs found'; 177 | } 178 | 179 | alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage)); 180 | 181 | var results = find('.results'); 182 | results.appendChild(summary); 183 | 184 | summaryList(topResults, summary); 185 | 186 | function summaryList(resultsTree, domParent) { 187 | var specListNode; 188 | for (var i = 0; i < resultsTree.children.length; i++) { 189 | var resultNode = resultsTree.children[i]; 190 | if (resultNode.type == 'suite') { 191 | var suiteListNode = createDom('ul', {className: 'suite', id: 'suite-' + resultNode.result.id}, 192 | createDom('li', {className: 'suite-detail'}, 193 | createDom('a', {href: specHref(resultNode.result)}, resultNode.result.description) 194 | ) 195 | ); 196 | 197 | summaryList(resultNode, suiteListNode); 198 | domParent.appendChild(suiteListNode); 199 | } 200 | if (resultNode.type == 'spec') { 201 | if (domParent.getAttribute('class') != 'specs') { 202 | specListNode = createDom('ul', {className: 'specs'}); 203 | domParent.appendChild(specListNode); 204 | } 205 | var specDescription = resultNode.result.description; 206 | if(noExpectations(resultNode.result)) { 207 | specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription; 208 | } 209 | specListNode.appendChild( 210 | createDom('li', { 211 | className: resultNode.result.status, 212 | id: 'spec-' + resultNode.result.id 213 | }, 214 | createDom('a', {href: specHref(resultNode.result)}, specDescription) 215 | ) 216 | ); 217 | } 218 | } 219 | } 220 | 221 | if (failures.length) { 222 | alert.appendChild( 223 | createDom('span', {className: 'menu bar spec-list'}, 224 | createDom('span', {}, 'Spec List | '), 225 | createDom('a', {className: 'failures-menu', href: '#'}, 'Failures'))); 226 | alert.appendChild( 227 | createDom('span', {className: 'menu bar failure-list'}, 228 | createDom('a', {className: 'spec-list-menu', href: '#'}, 'Spec List'), 229 | createDom('span', {}, ' | Failures '))); 230 | 231 | find('.failures-menu').onclick = function() { 232 | setMenuModeTo('failure-list'); 233 | }; 234 | find('.spec-list-menu').onclick = function() { 235 | setMenuModeTo('spec-list'); 236 | }; 237 | 238 | setMenuModeTo('failure-list'); 239 | 240 | var failureNode = find('.failures'); 241 | for (var i = 0; i < failures.length; i++) { 242 | failureNode.appendChild(failures[i]); 243 | } 244 | } 245 | }; 246 | 247 | return this; 248 | 249 | function find(selector) { 250 | return getContainer().querySelector('.jasmine_html-reporter ' + selector); 251 | } 252 | 253 | function clearPrior() { 254 | // return the reporter 255 | var oldReporter = find(''); 256 | 257 | if(oldReporter) { 258 | getContainer().removeChild(oldReporter); 259 | } 260 | } 261 | 262 | function createDom(type, attrs, childrenVarArgs) { 263 | var el = createElement(type); 264 | 265 | for (var i = 2; i < arguments.length; i++) { 266 | var child = arguments[i]; 267 | 268 | if (typeof child === 'string') { 269 | el.appendChild(createTextNode(child)); 270 | } else { 271 | if (child) { 272 | el.appendChild(child); 273 | } 274 | } 275 | } 276 | 277 | for (var attr in attrs) { 278 | if (attr == 'className') { 279 | el[attr] = attrs[attr]; 280 | } else { 281 | el.setAttribute(attr, attrs[attr]); 282 | } 283 | } 284 | 285 | return el; 286 | } 287 | 288 | function pluralize(singular, count) { 289 | var word = (count == 1 ? singular : singular + 's'); 290 | 291 | return '' + count + ' ' + word; 292 | } 293 | 294 | function specHref(result) { 295 | return '?spec=' + encodeURIComponent(result.fullName); 296 | } 297 | 298 | function setMenuModeTo(mode) { 299 | htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode); 300 | } 301 | 302 | function noExpectations(result) { 303 | return (result.failedExpectations.length + result.passedExpectations.length) === 0 && 304 | result.status === 'passed'; 305 | } 306 | } 307 | 308 | return HtmlReporter; 309 | }; 310 | 311 | jasmineRequire.HtmlSpecFilter = function() { 312 | function HtmlSpecFilter(options) { 313 | var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); 314 | var filterPattern = new RegExp(filterString); 315 | 316 | this.matches = function(specName) { 317 | return filterPattern.test(specName); 318 | }; 319 | } 320 | 321 | return HtmlSpecFilter; 322 | }; 323 | 324 | jasmineRequire.ResultsNode = function() { 325 | function ResultsNode(result, type, parent) { 326 | this.result = result; 327 | this.type = type; 328 | this.parent = parent; 329 | 330 | this.children = []; 331 | 332 | this.addChild = function(result, type) { 333 | this.children.push(new ResultsNode(result, type, this)); 334 | }; 335 | 336 | this.last = function() { 337 | return this.children[this.children.length - 1]; 338 | }; 339 | } 340 | 341 | return ResultsNode; 342 | }; 343 | 344 | jasmineRequire.QueryString = function() { 345 | function QueryString(options) { 346 | 347 | this.setParam = function(key, value) { 348 | var paramMap = queryStringToParamMap(); 349 | paramMap[key] = value; 350 | options.getWindowLocation().search = toQueryString(paramMap); 351 | }; 352 | 353 | this.getParam = function(key) { 354 | return queryStringToParamMap()[key]; 355 | }; 356 | 357 | return this; 358 | 359 | function toQueryString(paramMap) { 360 | var qStrPairs = []; 361 | for (var prop in paramMap) { 362 | qStrPairs.push(encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop])); 363 | } 364 | return '?' + qStrPairs.join('&'); 365 | } 366 | 367 | function queryStringToParamMap() { 368 | var paramStr = options.getWindowLocation().search.substring(1), 369 | params = [], 370 | paramMap = {}; 371 | 372 | if (paramStr.length > 0) { 373 | params = paramStr.split('&'); 374 | for (var i = 0; i < params.length; i++) { 375 | var p = params[i].split('='); 376 | var value = decodeURIComponent(p[1]); 377 | if (value === 'true' || value === 'false') { 378 | value = JSON.parse(value); 379 | } 380 | paramMap[decodeURIComponent(p[0])] = value; 381 | } 382 | } 383 | 384 | return paramMap; 385 | } 386 | 387 | } 388 | 389 | return QueryString; 390 | }; 391 | -------------------------------------------------------------------------------- /ngPlaybook/Js/jasmine/jasmine_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OdeToCode/ngplaybook/8e1299cdae87c860d2828c4477f6db235e0d289a/ngPlaybook/Js/jasmine/jasmine_favicon.png -------------------------------------------------------------------------------- /ngPlaybook/Js/tubular/tubular.js: -------------------------------------------------------------------------------- 1 | /* jQuery tubular plugin 2 | |* by Sean McCambridge 3 | |* http://www.seanmccambridge.com/tubular 4 | |* version: 1.0 5 | |* updated: October 1, 2012 6 | |* since 2010 7 | |* licensed under the MIT License 8 | |* Enjoy. 9 | |* 10 | |* Thanks, 11 | |* Sean */ 12 | 13 | ; (function ($, window) { 14 | 15 | // test for feature support and return if failure 16 | 17 | // defaults 18 | var defaults = { 19 | ratio: 16 / 9, // usually either 4/3 or 16/9 -- tweak as needed 20 | videoId: 'ZCAnLxRvNNc', // toy robot in space is a good default, no? 21 | mute: true, 22 | repeat: true, 23 | width: $(window).width(), 24 | wrapperZIndex: 99, 25 | playButtonClass: 'tubular-play', 26 | pauseButtonClass: 'tubular-pause', 27 | muteButtonClass: 'tubular-mute', 28 | volumeUpClass: 'tubular-volume-up', 29 | volumeDownClass: 'tubular-volume-down', 30 | increaseVolumeBy: 10, 31 | start: 0 32 | }; 33 | 34 | // methods 35 | 36 | var tubular = function (node, options) { // should be called on the wrapper div 37 | var options = $.extend({}, defaults, options), 38 | $body = $('body') // cache body node 39 | $node = $(node); // cache wrapper node 40 | 41 | // build container 42 | var tubularContainer = '
'; 43 | 44 | // set up css prereq's, inject tubular container and set up wrapper defaults 45 | $('html,body').css({ 'width': '100%', 'height': '100%' }); 46 | $body.prepend(tubularContainer); 47 | $node.css({ position: 'relative', 'z-index': options.wrapperZIndex }); 48 | 49 | // set up iframe player, use global scope so YT api can talk 50 | window.player; 51 | window.onYouTubeIframeAPIReady = function () { 52 | player = new YT.Player('tubular-player', { 53 | width: options.width, 54 | height: Math.ceil(options.width / options.ratio), 55 | videoId: options.videoId, 56 | playerVars: { 57 | controls: 0, 58 | showinfo: 0, 59 | modestbranding: 1, 60 | wmode: 'transparent' 61 | }, 62 | events: { 63 | 'onReady': onPlayerReady, 64 | 'onStateChange': onPlayerStateChange 65 | } 66 | }); 67 | } 68 | 69 | window.onPlayerReady = function (e) { 70 | resize(); 71 | if (options.mute) e.target.mute(); 72 | e.target.seekTo(options.start); 73 | e.target.playVideo(); 74 | } 75 | 76 | window.onPlayerStateChange = function (state) { 77 | if (state.data === 0 && options.repeat) { // video ended and repeat option is set true 78 | player.seekTo(options.start); // restart 79 | } 80 | } 81 | 82 | // resize handler updates width, height and offset of player after resize/init 83 | var resize = function () { 84 | var width = $(window).width(), 85 | pWidth, // player width, to be defined 86 | height = $(window).height(), 87 | pHeight, // player height, tbd 88 | $tubularPlayer = $('#tubular-player'); 89 | 90 | // when screen aspect ratio differs from video, video must center and underlay one dimension 91 | 92 | if (width / options.ratio < height) { // if new video height < window height (gap underneath) 93 | pWidth = Math.ceil(height * options.ratio); // get new player width 94 | $tubularPlayer.width(pWidth).height(height).css({ left: (width - pWidth) / 2, top: 0 }); // player width is greater, offset left; reset top 95 | } else { // new video width < window width (gap to right) 96 | pHeight = Math.ceil(width / options.ratio); // get new player height 97 | $tubularPlayer.width(width).height(pHeight).css({ left: 0, top: (height - pHeight) / 2 }); // player height is greater, offset top; reset left 98 | } 99 | 100 | } 101 | 102 | // events 103 | $(window).on('resize.tubular', function () { 104 | resize(); 105 | }) 106 | 107 | $('body').on('click', '.' + options.playButtonClass, function (e) { // play button 108 | e.preventDefault(); 109 | player.playVideo(); 110 | }).on('click', '.' + options.pauseButtonClass, function (e) { // pause button 111 | e.preventDefault(); 112 | player.pauseVideo(); 113 | }).on('click', '.' + options.muteButtonClass, function (e) { // mute button 114 | e.preventDefault(); 115 | (player.isMuted()) ? player.unMute() : player.mute(); 116 | }).on('click', '.' + options.volumeDownClass, function (e) { // volume down button 117 | e.preventDefault(); 118 | var currentVolume = player.getVolume(); 119 | if (currentVolume < options.increaseVolumeBy) currentVolume = options.increaseVolumeBy; 120 | player.setVolume(currentVolume - options.increaseVolumeBy); 121 | }).on('click', '.' + options.volumeUpClass, function (e) { // volume up button 122 | e.preventDefault(); 123 | if (player.isMuted()) player.unMute(); // if mute is on, unmute 124 | var currentVolume = player.getVolume(); 125 | if (currentVolume > 100 - options.increaseVolumeBy) currentVolume = 100 - options.increaseVolumeBy; 126 | player.setVolume(currentVolume + options.increaseVolumeBy); 127 | }) 128 | } 129 | 130 | // load yt iframe js api 131 | 132 | var tag = document.createElement('script'); 133 | tag.src = "//www.youtube.com/iframe_api"; 134 | var firstScriptTag = document.getElementsByTagName('script')[0]; 135 | firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 136 | 137 | // create plugin 138 | 139 | $.fn.tubular = function (options) { 140 | return this.each(function () { 141 | if (!$.data(this, 'tubular_instantiated')) { // let's only run one 142 | $.data(this, 'tubular_instantiated', 143 | tubular(this, options)); 144 | } 145 | }); 146 | } 147 | 148 | })(jQuery, window); 149 | -------------------------------------------------------------------------------- /ngPlaybook/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ngPlaybook")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ngPlaybook")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("f5340d3e-84ec-4735-8a64-1fbbdd0adc9a")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /ngPlaybook/Protractor/pages/Config.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | baseUrl: "http://localhost:17648/Apps/" 3 | }; 4 | 5 | module.exports = config; -------------------------------------------------------------------------------- /ngPlaybook/Protractor/pages/DiagnosticsPage.js: -------------------------------------------------------------------------------- 1 | var config = require("./config"); 2 | 3 | var DiagnosticsPage = function () { 4 | 5 | this.go = function () { 6 | browser.get(DiagnosticsPage.url); 7 | }; 8 | 9 | this.getBrand = function() { 10 | return element(by.css(".navbar-brand")).getText(); 11 | }; 12 | 13 | }; 14 | 15 | DiagnosticsPage.url = config.baseUrl + "diagnostics/shell.html#/"; 16 | 17 | module.exports = DiagnosticsPage; -------------------------------------------------------------------------------- /ngPlaybook/Protractor/pages/HomePage.js: -------------------------------------------------------------------------------- 1 | var config = require("./config"); 2 | 3 | var HomePage = function () { 4 | 5 | this.go = function() { 6 | browser.get(HomePage.url); 7 | }; 8 | 9 | this.login = function (username, password) { 10 | element(by.name("username")).sendKeys(username); 11 | element(by.name("password")).sendKeys(password); 12 | element(by.name("loginForm")).submit(); 13 | }; 14 | 15 | this.getUsername = function () { 16 | var username = element(by.binding("login.user.username")); 17 | return username.getText(); 18 | }; 19 | 20 | this.signOut = function() { 21 | element(by.buttonText("Sign Out")).click(); 22 | }; 23 | 24 | }; 25 | 26 | HomePage.url = config.baseUrl + "security/shell.html#/"; 27 | 28 | module.exports = HomePage; -------------------------------------------------------------------------------- /ngPlaybook/Protractor/pages/LoginPage.js: -------------------------------------------------------------------------------- 1 | var config = require("./config"); 2 | 3 | var LoginPage = function () { 4 | 5 | this.go = function() { 6 | browser.get(LoginPage.url); 7 | }; 8 | 9 | this.login = function(username, password) { 10 | $(".container [name=username]").sendKeys(username); 11 | $(".container [name=password]").sendKeys(password); 12 | $(".container [name=loginForm]").submit(); 13 | }; 14 | 15 | }; 16 | 17 | LoginPage.url = config.baseUrl + "security/shell.html#/login"; 18 | 19 | module.exports = LoginPage; -------------------------------------------------------------------------------- /ngPlaybook/Protractor/pages/SecretRecipePage.js: -------------------------------------------------------------------------------- 1 | var config = require("./config"); 2 | 3 | var SecretRecipePage = function () { 4 | 5 | this.go = function() { 6 | browser.get(SecretRecipePage.url); 7 | }; 8 | 9 | }; 10 | 11 | SecretRecipePage.url = config.baseUrl + "security/shell.html#/secret"; 12 | 13 | module.exports = SecretRecipePage; -------------------------------------------------------------------------------- /ngPlaybook/Protractor/protractor.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | seleniumAddress: 'http://localhost:4444/wd/hub', 3 | specs: ["specs/*Specs.js"] 4 | } -------------------------------------------------------------------------------- /ngPlaybook/Protractor/specs/diagnosticsSpecs.js: -------------------------------------------------------------------------------- 1 | var DiagnosticsPage = require("../pages/DiagnosticsPage"); 2 | 3 | describe("The diagnostics application", function () { 4 | 5 | var page = new DiagnosticsPage(); 6 | 7 | it("should launch without an error", function () { 8 | page.go(); 9 | expect(page.getBrand()).toBe("Ode To Food"); 10 | }); 11 | 12 | }); -------------------------------------------------------------------------------- /ngPlaybook/Protractor/specs/loginSpecs.js: -------------------------------------------------------------------------------- 1 | var HomePage = require("../pages/HomePage"); 2 | 3 | describe("The security application", function () { 4 | 5 | var page = new HomePage(); 6 | 7 | it("should start as an anonymous user", function () { 8 | page.go(); 9 | expect(page.getUsername()).toBe(""); 10 | }); 11 | 12 | it("should allow the user to login", function () { 13 | page.login("sallen", "sallen"); 14 | expect(page.getUsername()).toContain("sallen"); 15 | }); 16 | 17 | it("should allow the user to sign out", function() { 18 | page.signOut(); 19 | expect(page.getUsername()).toBe(""); 20 | }); 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /ngPlaybook/Protractor/specs/redirectSpecs.js: -------------------------------------------------------------------------------- 1 | var SecretPage = require("../pages/SecretRecipePage"); 2 | var LoginPage = require("../pages/LoginPage.js"); 3 | 4 | describe("The security application", function () { 5 | 6 | var secret = new SecretPage(); 7 | var login = new LoginPage(); 8 | 9 | it("should redirect to login page if trying to view a secret as anonymous user", function () { 10 | secret.go(); 11 | expect(browser.getCurrentUrl()).toBe(LoginPage.url); 12 | }); 13 | 14 | it("should go back to the secret after a login", function () { 15 | login.login("sallen", "sallen"); 16 | expect(browser.getCurrentUrl()).toBe(SecretPage.url); 17 | }); 18 | 19 | }); -------------------------------------------------------------------------------- /ngPlaybook/Server/Api/NameValidationController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Web.Http; 3 | 4 | namespace NgPlaybook.Server.Api 5 | { 6 | public class NameValidationController : ApiController 7 | { 8 | public IHttpActionResult Get(string name) 9 | { 10 | Thread.Sleep(2000); 11 | if (name.Length > 3) 12 | { 13 | return Ok(true); 14 | } 15 | return Ok(false); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ngPlaybook/Server/Api/SecretController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Web.Http; 3 | using NgPlaybook.Server.Models; 4 | 5 | namespace NgPlaybook.Server.Api 6 | { 7 | [Authorize] 8 | public class SecretController : ApiController 9 | { 10 | public IHttpActionResult Get() 11 | { 12 | return Ok(new Recipe 13 | { 14 | Id = 1, 15 | Title = "French Toast", 16 | Instructions = @"In a medium bowl, whisk together the eggs, milk, and cinnamon. 17 | Stir in the orange zest and/or Triple Sec if using. Whisk the mixture until well blended 18 | and pour into a shallow bowl, wide enough to place a slice of the bread you will be using. 19 | Melt some butter in a large skillet over medium high heat. Place each slice of bread into 20 | the milk egg mixture, allowing the bread to soak in some of it. Shake off the excess, 21 | and place the bread slices onto the hot skillet. Fry the French toast until browned on 22 | one side, then flip and brown the other side. Serve hot with butter, maple syrup, and if 23 | available, fresh berries.", 24 | Ingredients = new List 25 | { 26 | new Ingredient { Id = 1, Name="Eggs", Quantity="4"}, 27 | new Ingredient { Id = 2, Name="Milk", Quantity="2/3 Cup"}, 28 | new Ingredient { Id = 3, Name="Cinnamon", Quantity="2 teaspoons"}, 29 | new Ingredient { Id = 4, Name="Day Old Bread", Quantity="8 thick slices"} 30 | } 31 | }); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ngPlaybook/Server/Auth/OdeToFoodJwtOptions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Owin.Security.Jwt; 2 | using NgPlaybook.Server.Config; 3 | 4 | namespace NgPlaybook.Server.Auth 5 | { 6 | public class OdeToFoodJwtOptions : JwtBearerAuthenticationOptions 7 | { 8 | public OdeToFoodJwtOptions() 9 | { 10 | var config = AppConfiguration.Config; 11 | 12 | AllowedAudiences = new[] { config.JwtAudience }; 13 | IssuerSecurityTokenProviders = new[] 14 | { 15 | new SymmetricKeyIssuerSecurityTokenProvider(config.JwtIssuer, config.JwtKey) 16 | }; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /ngPlaybook/Server/Auth/OdeToFoodJwtWriterFormat.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IdentityModel.Tokens; 3 | using Microsoft.Owin.Security; 4 | using Microsoft.Owin.Security.OAuth; 5 | using NgPlaybook.Server.Config; 6 | 7 | namespace NgPlaybook.Server.Auth 8 | { 9 | public class OdeToFoodJwtWriterFormat : ISecureDataFormat 10 | { 11 | private readonly OAuthAuthorizationServerOptions _options; 12 | 13 | public OdeToFoodJwtWriterFormat(OAuthAuthorizationServerOptions options) 14 | { 15 | _options = options; 16 | } 17 | 18 | public string SignatureAlgorithm 19 | { 20 | get { return "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256"; } 21 | } 22 | 23 | public string DigestAlgorithm 24 | { 25 | get { return "http://www.w3.org/2001/04/xmlenc#sha256"; } 26 | } 27 | 28 | public string Protect(AuthenticationTicket data) 29 | { 30 | if (data == null) throw new ArgumentNullException("data"); 31 | 32 | var config = AppConfiguration.Config; 33 | var issuer = config.JwtIssuer; 34 | var audience = config.JwtAudience; 35 | var key = Convert.FromBase64String(config.JwtKey); 36 | var now = DateTime.UtcNow; 37 | var expires = now.AddMinutes(_options.AccessTokenExpireTimeSpan.TotalMinutes); 38 | var signingCredentials = new SigningCredentials( 39 | new InMemorySymmetricSecurityKey(key), 40 | SignatureAlgorithm, 41 | DigestAlgorithm); 42 | var token = new JwtSecurityToken(issuer, audience, data.Identity.Claims, 43 | now, expires, signingCredentials); 44 | return new JwtSecurityTokenHandler().WriteToken(token); 45 | } 46 | 47 | public AuthenticationTicket Unprotect(string protectedText) 48 | { 49 | throw new NotImplementedException(); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /ngPlaybook/Server/Auth/OdeToFoodOAuthOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Owin; 3 | using Microsoft.Owin.Security.OAuth; 4 | using NgPlaybook.Server.Config; 5 | 6 | namespace NgPlaybook.Server.Auth 7 | { 8 | public class OdeToFoodOAuthOptions : OAuthAuthorizationServerOptions 9 | { 10 | public OdeToFoodOAuthOptions() 11 | { 12 | var config = AppConfiguration.Config; 13 | 14 | TokenEndpointPath = new PathString(config.TokenPath); 15 | AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(config.ExpirationMinutes); 16 | AccessTokenFormat = new OdeToFoodJwtWriterFormat(this); 17 | Provider = new OdeToFoodOAuthProvider(); 18 | #if DEBUG 19 | AllowInsecureHttp = true; 20 | #endif 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /ngPlaybook/Server/Auth/OdeToFoodOAuthProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Claims; 2 | using System.Threading.Tasks; 3 | using Microsoft.Owin.Security.OAuth; 4 | 5 | namespace NgPlaybook.Server.Auth 6 | { 7 | public class OdeToFoodOAuthProvider : OAuthAuthorizationServerProvider 8 | { 9 | public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 10 | { 11 | var identity = new ClaimsIdentity("otf"); 12 | var username = context.OwinContext.Get("otf:username"); 13 | identity.AddClaim(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", username)); 14 | identity.AddClaim(new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "user")); 15 | context.Validated(identity); 16 | return Task.FromResult(0); 17 | } 18 | 19 | public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) 20 | { 21 | try 22 | { 23 | var username = context.Parameters["username"]; 24 | var password = context.Parameters["password"]; 25 | 26 | if (username == password) 27 | { 28 | context.OwinContext.Set("otf:username", username); 29 | context.Validated(); 30 | } 31 | else 32 | { 33 | context.SetError("Invalid credentials"); 34 | context.Rejected(); 35 | } 36 | } 37 | catch 38 | { 39 | context.SetError("Server error"); 40 | context.Rejected(); 41 | } 42 | return Task.FromResult(0); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /ngPlaybook/Server/Config/AppConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System.Configuration; 2 | 3 | namespace NgPlaybook.Server.Config 4 | { 5 | public class AppConfiguration : ConfigurationSection 6 | { 7 | [ConfigurationProperty("tokenPath", IsRequired = true)] 8 | public string TokenPath 9 | { 10 | get { return (string)this["tokenPath"]; } 11 | set { this["tokenPath"] = value; } 12 | } 13 | 14 | [ConfigurationProperty("expirationMinutes", IsRequired = true)] 15 | public int ExpirationMinutes 16 | { 17 | get { return (int)this["expirationMinutes"]; } 18 | set { this["expirationMinutes"] = value; } 19 | } 20 | 21 | [ConfigurationProperty("jwtKey")] 22 | public string JwtKey 23 | { 24 | get { return (string)this["jwtKey"]; } 25 | set { this["jwtKey"] = value; } 26 | } 27 | 28 | [ConfigurationProperty("jwtIssuer")] 29 | public string JwtIssuer 30 | { 31 | get { return (string)this["jwtIssuer"]; } 32 | set { this["jwtIssuer"] = value; } 33 | } 34 | 35 | [ConfigurationProperty("jwtAudience")] 36 | public string JwtAudience 37 | { 38 | get { return (string)this["jwtAudience"]; } 39 | set { this["jwtAudience"] = value; } 40 | } 41 | 42 | public static AppConfiguration Config 43 | { 44 | get { return ConfigurationManager.GetSection("appConfiguration") as AppConfiguration; } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /ngPlaybook/Server/Models/Recipe.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace NgPlaybook.Server.Models 4 | { 5 | public class Recipe 6 | { 7 | public int Id { get; set; } 8 | public string Title { get; set; } 9 | public IList Ingredients { get; set; } 10 | public string Instructions { get; set; } 11 | } 12 | 13 | public class Ingredient 14 | { 15 | public int Id { get; set; } 16 | public string Name { get; set; } 17 | public string Quantity { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /ngPlaybook/Server/Startup/OwinStartup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Owin; 2 | using NgPlaybook.Server.Auth; 3 | using NgPlaybook.Server.Startup; 4 | using Owin; 5 | 6 | [assembly: OwinStartup(typeof(OwinStartup))] 7 | namespace NgPlaybook.Server.Startup 8 | { 9 | 10 | public class OwinStartup 11 | { 12 | public void Configuration(IAppBuilder app) 13 | { 14 | app.UseOAuthAuthorizationServer(new OdeToFoodOAuthOptions()); 15 | app.UseJwtBearerAuthentication(new OdeToFoodJwtOptions()); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /ngPlaybook/Server/Startup/WebApiStartup.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Http; 2 | using Newtonsoft.Json.Serialization; 3 | 4 | namespace NgPlaybook.Server.Startup 5 | { 6 | public class WebApiStartup 7 | { 8 | public static void Configure(HttpConfiguration config) 9 | { 10 | config.Routes.MapHttpRoute("api", "api/{controller}"); 11 | config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /ngPlaybook/Styles/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OdeToCode/ngplaybook/8e1299cdae87c860d2828c4477f6db235e0d289a/ngPlaybook/Styles/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /ngPlaybook/Styles/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OdeToCode/ngplaybook/8e1299cdae87c860d2828c4477f6db235e0d289a/ngPlaybook/Styles/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /ngPlaybook/Styles/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OdeToCode/ngplaybook/8e1299cdae87c860d2828c4477f6db235e0d289a/ngPlaybook/Styles/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /ngPlaybook/Styles/site.css: -------------------------------------------------------------------------------- 1 | input.ng-touched.ng-invalid { 2 | border: 2px #ff0000 solid; 3 | } 4 | 5 | .ng-move { 6 | -webkit-animation: pulse 0.5s; 7 | -moz-animation: pulse 0.5s; 8 | -o-animation: pulse 0.5s; 9 | animation: pulse 0.5s; 10 | } 11 | 12 | .ng-enter { 13 | -webkit-animation: zoomIn 0.5s; 14 | -moz-animation: zoomIn 0.5s; 15 | -o-animation: zoomIn 0.5s; 16 | animation: zoomIn 0.5s; 17 | } 18 | 19 | .ng-hide-add { 20 | -webkit-animation: fadeOut 0.9s; 21 | -moz-animation: fadeOut 0.9s; 22 | -o-animation: fadeOut 0.9s; 23 | animation: fadeOut 0.9s; 24 | display: block !important; 25 | } 26 | 27 | .ng-hide-remove { 28 | -webkit-animation: fadeIn 0.9s; 29 | -moz-animation: fadeIn 0.9s; 30 | -o-animation: fadeIn 0.9s; 31 | animation: fadeIn 0.9s; 32 | display: block !important; 33 | } 34 | 35 | .work-spinner { 36 | position: fixed; 37 | z-index: 1; 38 | left: 45%; 39 | top: 65px; 40 | } 41 | 42 | work-spinner { 43 | position: fixed; 44 | z-index: 1; 45 | left: 45%; 46 | top: 65px; 47 | } 48 | 49 | table > tbody > tr { 50 | border-top: 1px solid black; 51 | } 52 | 53 | .starpreview { 54 | color: rgba(255, 255, 128, 128); 55 | } 56 | 57 | pre { 58 | font-size: smaller; 59 | } 60 | 61 | .has-success .help-block { 62 | display: none; 63 | } 64 | 65 | -------------------------------------------------------------------------------- /ngPlaybook/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /ngPlaybook/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /ngPlaybook/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ngPlaybook/default.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | Ode To Food 4 | 5 | 6 | 7 | 8 | 9 | 10 | 24 | 25 |
26 |
27 |
28 | 29 |
30 |
31 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /ngPlaybook/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | --------------------------------------------------------------------------------