Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add Javascript Lib and QUnit Test Files

  • Loading branch information...
commit ee1dfb2c1eb3f3a9dfab6a12bdfd51c205ce9d28 1 parent add57cb
@NicholasMurray authored
Showing with 28,238 additions and 27,052 deletions.
  1. +2 −0  CodeCamper.Model/SessionBrief.cs
  2. +58 −11 CodeCamper.Web/App_Start/RouteConfig.cs
  3. +104 −30 CodeCamper.Web/CodeCamper.Web.csproj
  4. +225 −0 CodeCamper.Web/Content/qunit.css
  5. BIN  CodeCamper.Web/Scripts/_references.js
  6. +23 −0 CodeCamper.Web/Scripts/app/binder.js
  7. +21 −0 CodeCamper.Web/Scripts/app/bootstrapper.js
  8. +109 −0 CodeCamper.Web/Scripts/app/config.js
  9. +370 −0 CodeCamper.Web/Scripts/app/datacontext.js
  10. +95 −0 CodeCamper.Web/Scripts/app/datacontext.speaker-sessions.js
  11. +63 −0 CodeCamper.Web/Scripts/app/dataprimer.js
  12. +95 −0 CodeCamper.Web/Scripts/app/dataservice.attendance.js
  13. +15 −0 CodeCamper.Web/Scripts/app/dataservice.js
  14. +76 −0 CodeCamper.Web/Scripts/app/dataservice.lookup.js
  15. +80 −0 CodeCamper.Web/Scripts/app/dataservice.person.js
  16. +79 −0 CodeCamper.Web/Scripts/app/dataservice.session.js
  17. +42 −0 CodeCamper.Web/Scripts/app/event.delegates.js
  18. +83 −0 CodeCamper.Web/Scripts/app/filter.sessions.js
  19. +35 −0 CodeCamper.Web/Scripts/app/filter.speakers.js
  20. +44 −0 CodeCamper.Web/Scripts/app/group.js
  21. +143 −0 CodeCamper.Web/Scripts/app/ko.bindingHandlers.js
  22. +22 −0 CodeCamper.Web/Scripts/app/ko.debug.helpers.js
  23. +27 −0 CodeCamper.Web/Scripts/app/messenger.js
  24. +20 −0 CodeCamper.Web/Scripts/app/mock/mock.dataservice.attendance.js
  25. +33 −0 CodeCamper.Web/Scripts/app/mock/mock.dataservice.lookup.js
  26. +27 −0 CodeCamper.Web/Scripts/app/mock/mock.dataservice.person.js
  27. +27 −0 CodeCamper.Web/Scripts/app/mock/mock.dataservice.session.js
  28. +138 −0 CodeCamper.Web/Scripts/app/mock/mock.generator.js
  29. +23 −0 CodeCamper.Web/Scripts/app/mock/mock.js
  30. +70 −0 CodeCamper.Web/Scripts/app/model.attendance.js
  31. +30 −0 CodeCamper.Web/Scripts/app/model.js
  32. +91 −0 CodeCamper.Web/Scripts/app/model.mapper.js
  33. +99 −0 CodeCamper.Web/Scripts/app/model.person.js
  34. +16 −0 CodeCamper.Web/Scripts/app/model.room.js
  35. +140 −0 CodeCamper.Web/Scripts/app/model.session.js
  36. +32 −0 CodeCamper.Web/Scripts/app/model.timeslot.js
  37. +16 −0 CodeCamper.Web/Scripts/app/model.track.js
  38. +77 −0 CodeCamper.Web/Scripts/app/presenter.js
  39. +88 −0 CodeCamper.Web/Scripts/app/route-config.js
  40. +38 −0 CodeCamper.Web/Scripts/app/route-mediator.js
  41. +119 −0 CodeCamper.Web/Scripts/app/router.js
  42. +40 −0 CodeCamper.Web/Scripts/app/sort.js
  43. +24 −0 CodeCamper.Web/Scripts/app/store.js
  44. +83 −0 CodeCamper.Web/Scripts/app/utils.js
  45. +156 −0 CodeCamper.Web/Scripts/app/vm.favorites.js
  46. +19 −0 CodeCamper.Web/Scripts/app/vm.js
  47. +198 −0 CodeCamper.Web/Scripts/app/vm.session.js
  48. +161 −0 CodeCamper.Web/Scripts/app/vm.sessions.js
  49. +24 −0 CodeCamper.Web/Scripts/app/vm.shell.js
  50. +108 −0 CodeCamper.Web/Scripts/app/vm.speaker.js
  51. +78 −0 CodeCamper.Web/Scripts/app/vm.speakers.js
  52. +0 −2,494 CodeCamper.Web/Scripts/jquery-1.8.1.intellisense.js
  53. +0 −2  CodeCamper.Web/Scripts/jquery-1.8.1.min.js
  54. +0 −12,515 CodeCamper.Web/Scripts/jquery-ui-1.8.11.js
  55. +0 −1,682 CodeCamper.Web/Scripts/jquery-ui-1.8.11.min.js
  56. +0 −163 CodeCamper.Web/Scripts/jquery.unobtrusive-ajax.js
  57. +0 −5 CodeCamper.Web/Scripts/jquery.unobtrusive-ajax.min.js
  58. +0 −1,323 CodeCamper.Web/Scripts/jquery.validate-vsdoc.js
  59. +0 −1,194 CodeCamper.Web/Scripts/jquery.validate.js
  60. +0 −79 CodeCamper.Web/Scripts/jquery.validate.min.js
  61. +0 −345 CodeCamper.Web/Scripts/jquery.validate.unobtrusive.js
  62. +0 −5 CodeCamper.Web/Scripts/jquery.validate.unobtrusive.min.js
  63. +0 −3,443 CodeCamper.Web/Scripts/knockout-2.1.0.debug.js
  64. +27 −0 CodeCamper.Web/Scripts/lib/TrafficCop.js
  65. +102 −0 CodeCamper.Web/Scripts/lib/amplify.core.js
  66. +384 −0 CodeCamper.Web/Scripts/lib/amplify.request.js
  67. +304 −0 CodeCamper.Web/Scripts/lib/amplify.store.js
  68. +188 −0 CodeCamper.Web/Scripts/lib/infuser.js
  69. +7,223 −0 CodeCamper.Web/Scripts/lib/jquery-1.7.2-vsdoc.js
  70. +3,522 −3,419 CodeCamper.Web/Scripts/{jquery-1.8.1.js → lib/jquery-1.7.2.js}
  71. +4 −0 CodeCamper.Web/Scripts/lib/jquery-1.7.2.min.js
  72. +234 −0 CodeCamper.Web/Scripts/lib/jquery.mockjson.js
  73. +487 −0 CodeCamper.Web/Scripts/lib/json2.js
  74. 0  CodeCamper.Web/Scripts/{ → lib}/knockout-2.1.0.js
  75. +381 −0 CodeCamper.Web/Scripts/lib/knockout.activity.js
  76. +65 −0 CodeCamper.Web/Scripts/lib/knockout.asyncCommand.js
  77. +59 −0 CodeCamper.Web/Scripts/lib/knockout.dirtyFlag.js
  78. +1,028 −0 CodeCamper.Web/Scripts/lib/knockout.validation.js
  79. +102 −0 CodeCamper.Web/Scripts/lib/koExternalTemplateEngine.js
  80. +446 −341 CodeCamper.Web/Scripts/{modernizr-2.0.6-development-only.js → lib/modernizr-2.5.3.js}
  81. +918 −0 CodeCamper.Web/Scripts/lib/moment.js
  82. +2,030 −0 CodeCamper.Web/Scripts/lib/require.js
  83. +1,828 −0 CodeCamper.Web/Scripts/lib/sammy.js
  84. +59 −0 CodeCamper.Web/Scripts/lib/sammy.title.js
  85. 0  CodeCamper.Web/Scripts/{ → lib}/toastr.js
  86. +1,072 −0 CodeCamper.Web/Scripts/lib/underscore.js
  87. +32 −0 CodeCamper.Web/Scripts/main.js
  88. +1,106 −0 CodeCamper.Web/Scripts/moment.js
  89. +6 −0 CodeCamper.Web/Scripts/moment.min.js
  90. +13 −0 CodeCamper.Web/Test/qunit/qunit-composite.css
  91. +102 −0 CodeCamper.Web/Test/qunit/qunit-composite.js
  92. +236 −0 CodeCamper.Web/Test/qunit/qunit.css
  93. +1,452 −0 CodeCamper.Web/Test/qunit/qunit.js
  94. +38 −0 CodeCamper.Web/Test/web api/qunit-utils.js
  95. +20 −0 CodeCamper.Web/Test/web api/webapi.attendance-cud.tests.html
  96. +186 −0 CodeCamper.Web/Test/web api/webapi.attendance-cud.tests.js
  97. +20 −0 CodeCamper.Web/Test/web api/webapi.endpoint.tests.html
  98. +71 −0 CodeCamper.Web/Test/web api/webapi.endpoint.tests.js
  99. +20 −0 CodeCamper.Web/Test/web api/webapi.get-result.tests.html
  100. +27 −0 CodeCamper.Web/Test/web api/webapi.get-result.tests.js
  101. +20 −0 CodeCamper.Web/Test/web api/webapi.person-cud.tests.html
  102. +123 −0 CodeCamper.Web/Test/web api/webapi.person-cud.tests.js
  103. +20 −0 CodeCamper.Web/Test/web api/webapi.session-cud-validation.tests.html
  104. +42 −0 CodeCamper.Web/Test/web api/webapi.session-cud-validation.tests.js
  105. +20 −0 CodeCamper.Web/Test/web api/webapi.session-cud.tests.html
  106. +176 −0 CodeCamper.Web/Test/web api/webapi.session-cud.tests.js
  107. +31 −0 CodeCamper.Web/Test/web api/webapi.testsuite.html
  108. +2 −1  CodeCamper.Web/Web.config
  109. +1 −0  CodeCamper.Web/packages.config
  110. BIN  packages/QUnit-MVC.1.6.2.0/QUnit-MVC.1.6.2.0.nupkg
  111. +225 −0 packages/QUnit-MVC.1.6.2.0/content/Content/qunit.css
Sorry, we could not display the entire diff because it was too big.
View
2  CodeCamper.Model/SessionBrief.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -9,6 +10,7 @@ namespace CodeCamper.Model
public class SessionBrief
{
public int Id { get; set; }
+ [Required(ErrorMessage = "Title is required")]
public string Title { get; set; }
public string Code { get; set; }
public int SpeakerId { get; set; }
View
69 CodeCamper.Web/App_Start/RouteConfig.cs
@@ -1,30 +1,77 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Web;
-using System.Web.Http;
+using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;
+// ReSharper disable RedundantArgumentName
+
namespace CodeCamper.Web
{
public class RouteConfig
{
+ public static string ControllerOnly = "ApiControllerOnly";
+ public static string ControllerAndId = "ApiControllerAndIntegerId";
+ public static string ControllerAction = "ApiControllerAction";
+
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
+ // This controller-per-type route is ideal for GetAll calls.
+ // It finds the method on the controller using WebAPI conventions
+ // The template has no parameters.
+ //
+ // ex: api/sessionbriefs
+ // ex: api/sessions
+ // ex: api/persons
+ routes.MapHttpRoute(
+ name: ControllerOnly,
+ routeTemplate: "api/{controller}"
+ );
+
+ // This is the default route that a "File | New MVC 4 " project creates.
+ // (I changed the name, removed the defaults, and added the constraints)
+ //
+ // This controller-per-type route lets us fetch a single resource by numeric id
+ // It finds the appropriate method GetById method
+ // on the controller using WebAPI conventions
+ // The {id} is not optional, must be an integer, and
+ // must match a method with a parameter named "id" (case insensitive)
+ //
+ // ex: api/sessions/1
+ // ex: api/persons/1
routes.MapHttpRoute(
- name: "DefaultApi",
+ name: ControllerAndId,
routeTemplate: "api/{controller}/{id}",
- defaults: new { id = RouteParameter.Optional }
+ defaults: null, //defaults: new { id = RouteParameter.Optional } //,
+ constraints: new { id = @"^\d+$" } // id must be all digits
);
- routes.MapRoute(
- name: "Default",
- url: "{controller}/{action}/{id}",
- defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
+ /********************************************************
+ * The integer id constraint is necessary to distinguish
+ * the {id} route above from the {action} route below.
+ * For example, the route above handles
+ * "api/sessions/1"
+ * whereas the route below handles
+ * "api/lookups/all"
+ ********************************************************/
+
+ // This RPC style route is great for lookups and custom calls
+ // It matches the {action} to a method on the controller
+ //
+ // ex: api/lookups/all
+ // ex: api/lookups/rooms
+ routes.MapHttpRoute(
+ name: ControllerAction,
+ routeTemplate: "api/{controller}/{action}"
);
+
+ //PAPA: Commented this out because we wont be using MVC views
+ //routes.MapRoute(
+ // name: "Default",
+ // url: "{controller}/{action}/{id}",
+ // defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
+ //);
+
}
}
}
View
134 CodeCamper.Web/CodeCamper.Web.csproj
@@ -133,7 +133,15 @@
<Compile Include="App_Start\NinjectDependencyScope.cs" />
<Compile Include="App_Start\RouteConfig.cs" />
<Compile Include="App_Start\ValidationActionFilter.cs" />
+ <Compile Include="Controllers\ApiBaseController.cs" />
+ <Compile Include="Controllers\AttendanceController.cs" />
+ <Compile Include="Controllers\FavoritesController.cs" />
<Compile Include="Controllers\HomeController.cs" />
+ <Compile Include="Controllers\LookupsController.cs" />
+ <Compile Include="Controllers\PersonsController.cs" />
+ <Compile Include="Controllers\SessionBriefsController.cs" />
+ <Compile Include="Controllers\SessionsController.cs" />
+ <Compile Include="Controllers\SpeakersController.cs" />
<Compile Include="Controllers\ValuesController.cs" />
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
@@ -141,6 +149,8 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
+ <Content Include="App_Data\CodeCamper.sdf" />
+ <Content Include="Content\qunit.css" />
<Content Include="Content\themes\base\images\ui-bg_flat_0_aaaaaa_40x100.png" />
<Content Include="Content\themes\base\images\ui-bg_flat_75_ffffff_40x100.png" />
<Content Include="Content\themes\base\images\ui-bg_glass_55_fbf9ee_1x400.png" />
@@ -172,34 +182,101 @@
<Content Include="Content\toastr.css" />
<Content Include="favicon.ico" />
<Content Include="Global.asax" />
- <None Include="Scripts\jquery.validate-vsdoc.js" />
- <None Include="Scripts\jquery-1.8.1.intellisense.js">
- <DependentUpon>jquery-1.8.1.js</DependentUpon>
- </None>
- <Content Include="Scripts\jquery-1.8.1.js" />
- <Content Include="Scripts\jquery-1.8.1.min.js">
- <DependentUpon>jquery-1.8.1.js</DependentUpon>
+ <Content Include="Scripts\app\binder.js" />
+ <Content Include="Scripts\app\bootstrapper.js" />
+ <Content Include="Scripts\app\config.js" />
+ <Content Include="Scripts\app\datacontext.js" />
+ <Content Include="Scripts\app\datacontext.speaker-sessions.js" />
+ <Content Include="Scripts\app\dataprimer.js" />
+ <Content Include="Scripts\app\dataservice.attendance.js" />
+ <Content Include="Scripts\app\dataservice.js" />
+ <Content Include="Scripts\app\dataservice.lookup.js" />
+ <Content Include="Scripts\app\dataservice.person.js" />
+ <Content Include="Scripts\app\dataservice.session.js" />
+ <Content Include="Scripts\app\event.delegates.js" />
+ <Content Include="Scripts\app\filter.sessions.js" />
+ <Content Include="Scripts\app\filter.speakers.js" />
+ <Content Include="Scripts\app\group.js" />
+ <Content Include="Scripts\app\ko.bindingHandlers.js" />
+ <Content Include="Scripts\app\ko.debug.helpers.js" />
+ <Content Include="Scripts\app\messenger.js" />
+ <Content Include="Scripts\app\mock\mock.dataservice.attendance.js" />
+ <Content Include="Scripts\app\mock\mock.dataservice.lookup.js" />
+ <Content Include="Scripts\app\mock\mock.dataservice.person.js" />
+ <Content Include="Scripts\app\mock\mock.dataservice.session.js" />
+ <Content Include="Scripts\app\mock\mock.generator.js" />
+ <Content Include="Scripts\app\mock\mock.js" />
+ <Content Include="Scripts\app\model.attendance.js" />
+ <Content Include="Scripts\app\model.js" />
+ <Content Include="Scripts\app\model.mapper.js" />
+ <Content Include="Scripts\app\model.person.js" />
+ <Content Include="Scripts\app\model.room.js" />
+ <Content Include="Scripts\app\model.session.js" />
+ <Content Include="Scripts\app\model.timeslot.js" />
+ <Content Include="Scripts\app\model.track.js" />
+ <Content Include="Scripts\app\presenter.js" />
+ <Content Include="Scripts\app\route-config.js" />
+ <Content Include="Scripts\app\route-mediator.js" />
+ <Content Include="Scripts\app\router.js" />
+ <Content Include="Scripts\app\sort.js" />
+ <Content Include="Scripts\app\store.js" />
+ <Content Include="Scripts\app\utils.js" />
+ <Content Include="Scripts\app\vm.favorites.js" />
+ <Content Include="Scripts\app\vm.js" />
+ <Content Include="Scripts\app\vm.session.js" />
+ <Content Include="Scripts\app\vm.sessions.js" />
+ <Content Include="Scripts\app\vm.shell.js" />
+ <Content Include="Scripts\app\vm.speaker.js" />
+ <Content Include="Scripts\app\vm.speakers.js" />
+ <Content Include="Scripts\lib\amplify.core.js" />
+ <Content Include="Scripts\lib\amplify.request.js" />
+ <Content Include="Scripts\lib\amplify.store.js" />
+ <Content Include="Scripts\lib\infuser.js" />
+ <None Include="Scripts\lib\jquery-1.7.2-vsdoc.js" />
+ <Content Include="Scripts\lib\jquery-1.7.2.js" />
+ <Content Include="Scripts\lib\jquery-1.7.2.min.js">
+ <DependentUpon>jquery-1.7.2.js</DependentUpon>
</Content>
- <Content Include="Scripts\jquery-ui-1.8.11.js" />
- <Content Include="Scripts\jquery-ui-1.8.11.min.js">
- <DependentUpon>jquery-ui-1.8.11.js</DependentUpon>
+ <Content Include="Scripts\lib\jquery.mockjson.js" />
+ <Content Include="Scripts\lib\json2.js" />
+ <Content Include="Scripts\lib\knockout-2.1.0.js" />
+ <Content Include="Scripts\lib\knockout.activity.js" />
+ <Content Include="Scripts\lib\knockout.asyncCommand.js" />
+ <Content Include="Scripts\lib\knockout.dirtyFlag.js" />
+ <Content Include="Scripts\lib\knockout.validation.js" />
+ <Content Include="Scripts\lib\koExternalTemplateEngine.js" />
+ <Content Include="Scripts\lib\modernizr-2.5.3.js" />
+ <Content Include="Scripts\lib\moment.js" />
+ <Content Include="Scripts\lib\require.js" />
+ <Content Include="Scripts\lib\sammy.js" />
+ <Content Include="Scripts\lib\sammy.title.js" />
+ <Content Include="Scripts\lib\toastr.js" />
+ <Content Include="Scripts\lib\TrafficCop.js" />
+ <Content Include="Scripts\lib\underscore.js" />
+ <Content Include="Scripts\main.js" />
+ <Content Include="Scripts\moment.js" />
+ <Content Include="Scripts\moment.min.js">
+ <DependentUpon>moment.js</DependentUpon>
</Content>
- <Content Include="Scripts\jquery.unobtrusive-ajax.js" />
- <Content Include="Scripts\jquery.unobtrusive-ajax.min.js">
- <DependentUpon>jquery.unobtrusive-ajax.js</DependentUpon>
- </Content>
- <Content Include="Scripts\jquery.validate.js" />
- <Content Include="Scripts\jquery.validate.min.js">
- <DependentUpon>jquery.validate.js</DependentUpon>
- </Content>
- <Content Include="Scripts\jquery.validate.unobtrusive.js" />
- <Content Include="Scripts\jquery.validate.unobtrusive.min.js">
- <DependentUpon>jquery.validate.unobtrusive.js</DependentUpon>
- </Content>
- <Content Include="Scripts\knockout-2.1.0.debug.js" />
- <Content Include="Scripts\knockout-2.1.0.js" />
- <Content Include="Scripts\modernizr-2.0.6-development-only.js" />
- <Content Include="Scripts\toastr.js" />
+ <Content Include="Scripts\_references.js" />
+ <Content Include="Test\qunit\qunit-composite.css" />
+ <Content Include="Test\qunit\qunit-composite.js" />
+ <Content Include="Test\qunit\qunit.css" />
+ <Content Include="Test\qunit\qunit.js" />
+ <Content Include="Test\web api\qunit-utils.js" />
+ <Content Include="Test\web api\webapi.attendance-cud.tests.html" />
+ <Content Include="Test\web api\webapi.attendance-cud.tests.js" />
+ <Content Include="Test\web api\webapi.endpoint.tests.html" />
+ <Content Include="Test\web api\webapi.endpoint.tests.js" />
+ <Content Include="Test\web api\webapi.get-result.tests.html" />
+ <Content Include="Test\web api\webapi.get-result.tests.js" />
+ <Content Include="Test\web api\webapi.person-cud.tests.html" />
+ <Content Include="Test\web api\webapi.person-cud.tests.js" />
+ <Content Include="Test\web api\webapi.session-cud-validation.tests.html" />
+ <Content Include="Test\web api\webapi.session-cud-validation.tests.js" />
+ <Content Include="Test\web api\webapi.session-cud.tests.html" />
+ <Content Include="Test\web api\webapi.session-cud.tests.js" />
+ <Content Include="Test\web api\webapi.testsuite.html" />
<Content Include="Web.config" />
<Content Include="Web.Debug.config">
<DependentUpon>Web.config</DependentUpon>
@@ -227,16 +304,13 @@
<Content Include="Images\orderedList9.png" />
<Content Include="Images\twitter.png" />
<Content Include="Images\windowsLive.png" />
- <Content Include="Scripts\_references.js" />
<Content Include="Views\Web.config" />
<Content Include="Views\_ViewStart.cshtml" />
<Content Include="Views\Home\Index.cshtml" />
<Content Include="Views\Shared\Error.cshtml" />
<Content Include="Views\Shared\_Layout.cshtml" />
</ItemGroup>
- <ItemGroup>
- <Folder Include="App_Data\" />
- </ItemGroup>
+ <ItemGroup />
<ItemGroup>
<Content Include="packages.config" />
</ItemGroup>
View
225 CodeCamper.Web/Content/qunit.css
@@ -0,0 +1,225 @@
+/**
+ * QUnit - A JavaScript Unit Testing Framework
+ *
+ * http://docs.jquery.com/QUnit
+ *
+ * Copyright (c) 2011 John Resig, Jörn Zaefferer
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * or GPL (GPL-LICENSE.txt) licenses.
+ */
+
+/** Font Family and Sizes */
+
+#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
+ font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
+}
+
+#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
+#qunit-tests { font-size: smaller; }
+
+
+/** Resets */
+
+#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
+ margin: 0;
+ padding: 0;
+}
+
+
+/** Header */
+
+#qunit-header {
+ padding: 0.5em 0 0.5em 1em;
+
+ color: #8699a4;
+ background-color: #0d3349;
+
+ font-size: 1.5em;
+ line-height: 1em;
+ font-weight: normal;
+
+ border-radius: 15px 15px 0 0;
+ -moz-border-radius: 15px 15px 0 0;
+ -webkit-border-top-right-radius: 15px;
+ -webkit-border-top-left-radius: 15px;
+}
+
+#qunit-header a {
+ text-decoration: none;
+ color: #c2ccd1;
+}
+
+#qunit-header a:hover,
+#qunit-header a:focus {
+ color: #fff;
+}
+
+#qunit-banner {
+ height: 5px;
+}
+
+#qunit-testrunner-toolbar {
+ padding: 0.5em 0 0.5em 2em;
+ color: #5E740B;
+ background-color: #eee;
+}
+
+#qunit-userAgent {
+ padding: 0.5em 0 0.5em 2.5em;
+ background-color: #2b81af;
+ color: #fff;
+ text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
+}
+
+
+/** Tests: Pass/Fail */
+
+#qunit-tests {
+ list-style-position: inside;
+}
+
+#qunit-tests li {
+ padding: 0.4em 0.5em 0.4em 2.5em;
+ border-bottom: 1px solid #fff;
+ list-style-position: inside;
+}
+
+#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
+ display: none;
+}
+
+#qunit-tests li strong {
+ cursor: pointer;
+}
+
+#qunit-tests li a {
+ padding: 0.5em;
+ color: #c2ccd1;
+ text-decoration: none;
+}
+#qunit-tests li a:hover,
+#qunit-tests li a:focus {
+ color: #000;
+}
+
+#qunit-tests ol {
+ margin-top: 0.5em;
+ padding: 0.5em;
+
+ background-color: #fff;
+
+ border-radius: 15px;
+ -moz-border-radius: 15px;
+ -webkit-border-radius: 15px;
+
+ box-shadow: inset 0px 2px 13px #999;
+ -moz-box-shadow: inset 0px 2px 13px #999;
+ -webkit-box-shadow: inset 0px 2px 13px #999;
+}
+
+#qunit-tests table {
+ border-collapse: collapse;
+ margin-top: .2em;
+}
+
+#qunit-tests th {
+ text-align: right;
+ vertical-align: top;
+ padding: 0 .5em 0 0;
+}
+
+#qunit-tests td {
+ vertical-align: top;
+}
+
+#qunit-tests pre {
+ margin: 0;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+#qunit-tests del {
+ background-color: #e0f2be;
+ color: #374e0c;
+ text-decoration: none;
+}
+
+#qunit-tests ins {
+ background-color: #ffcaca;
+ color: #500;
+ text-decoration: none;
+}
+
+/*** Test Counts */
+
+#qunit-tests b.counts { color: black; }
+#qunit-tests b.passed { color: #5E740B; }
+#qunit-tests b.failed { color: #710909; }
+
+#qunit-tests li li {
+ margin: 0.5em;
+ padding: 0.4em 0.5em 0.4em 0.5em;
+ background-color: #fff;
+ border-bottom: none;
+ list-style-position: inside;
+}
+
+/*** Passing Styles */
+
+#qunit-tests li li.pass {
+ color: #5E740B;
+ background-color: #fff;
+ border-left: 26px solid #C6E746;
+}
+
+#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
+#qunit-tests .pass .test-name { color: #366097; }
+
+#qunit-tests .pass .test-actual,
+#qunit-tests .pass .test-expected { color: #999999; }
+
+#qunit-banner.qunit-pass { background-color: #C6E746; }
+
+/*** Failing Styles */
+
+#qunit-tests li li.fail {
+ color: #710909;
+ background-color: #fff;
+ border-left: 26px solid #EE5757;
+}
+
+#qunit-tests > li:last-child {
+ border-radius: 0 0 15px 15px;
+ -moz-border-radius: 0 0 15px 15px;
+ -webkit-border-bottom-right-radius: 15px;
+ -webkit-border-bottom-left-radius: 15px;
+}
+
+#qunit-tests .fail { color: #000000; background-color: #EE5757; }
+#qunit-tests .fail .test-name,
+#qunit-tests .fail .module-name { color: #000000; }
+
+#qunit-tests .fail .test-actual { color: #EE5757; }
+#qunit-tests .fail .test-expected { color: green; }
+
+#qunit-banner.qunit-fail { background-color: #EE5757; }
+
+
+/** Result */
+
+#qunit-testresult {
+ padding: 0.5em 0.5em 0.5em 2.5em;
+
+ color: #2b81af;
+ background-color: #D2E0E6;
+
+ border-bottom: 1px solid white;
+}
+
+/** Fixture */
+
+#qunit-fixture {
+ position: absolute;
+ top: -10000px;
+ left: -10000px;
+}
View
BIN  CodeCamper.Web/Scripts/_references.js
Binary file not shown
View
23 CodeCamper.Web/Scripts/app/binder.js
@@ -0,0 +1,23 @@
+define('binder',
+ ['jquery', 'ko', 'config', 'vm'],
+ function ($, ko, config, vm) {
+ var
+ ids = config.viewIds,
+
+ bind = function () {
+ ko.applyBindings(vm.shell, getView(ids.shellTop));
+ ko.applyBindings(vm.favorites, getView(ids.favorites));
+ ko.applyBindings(vm.session, getView(ids.session));
+ ko.applyBindings(vm.sessions, getView(ids.sessions));
+ ko.applyBindings(vm.speaker, getView(ids.speaker));
+ ko.applyBindings(vm.speakers, getView(ids.speakers));
+ },
+
+ getView = function (viewName) {
+ return $(viewName).get(0);
+ };
+
+ return {
+ bind: bind
+ };
+ });
View
21 CodeCamper.Web/Scripts/app/bootstrapper.js
@@ -0,0 +1,21 @@
+define('bootstrapper',
+ ['jquery', 'config', 'route-config', 'presenter', 'dataprimer', 'binder'],
+ function ($, config, routeConfig, presenter, dataprimer, binder) {
+ var
+ run = function () {
+ presenter.toggleActivity(true);
+
+ config.dataserviceInit();
+
+ $.when(dataprimer.fetch())
+ .done(binder.bind)
+ .done(routeConfig.register)
+ .always(function () {
+ presenter.toggleActivity(false);
+ });
+ };
+
+ return {
+ run: run
+ };
+ });
View
109 CodeCamper.Web/Scripts/app/config.js
@@ -0,0 +1,109 @@
+define('config',
+ ['toastr', 'mock/mock', 'infuser', 'ko'],
+ function (toastr, mock, infuser, ko) {
+
+ var
+ // properties
+ //-----------------
+
+ currentUserId = 3, // John Papa
+ currentUser = ko.observable(),
+ hashes = {
+ favorites: '#/favorites',
+ favoritesByDate: '#/favorites/date',
+ sessions: '#/sessions',
+ speakers: '#/speakers'
+ },
+ logger = toastr, // use toastr for the logger
+ messages = {
+ viewModelActivated: 'viewmodel-activation'
+ },
+ stateKeys = {
+ lastView: 'state.active-hash'
+ },
+ storeExpirationMs = (1000 * 60 * 60 * 24), // 1 day
+ //storeExpirationMs = (1000 * 5), // 5 seconds
+ throttle = 400,
+ title = 'CodeCamper > ',
+ toastrTimeout = 2000,
+
+ _useMocks = false, // Set this to toggle mocks
+ useMocks = function (val) {
+ if(val) {
+ _useMocks = val;
+ init();
+ }
+ return _useMocks;
+ },
+
+ viewIds = {
+ favorites: '#favorites-view',
+ session: '#session-view',
+ sessions: '#sessions-view',
+ shellTop: '#shellTop-view',
+ speaker: '#speaker-view',
+ speakers: '#speakers-view'
+ },
+
+ toasts = {
+ changesPending: 'Please save or cancel your changes before leaving the page.',
+ errorSavingData: 'Data could not be saved. Please check the logs.',
+ errorGettingData: 'Could not retrieve data. Please check the logs.',
+ invalidRoute: 'Cannot navigate. Invalid route',
+ retreivedData: 'Data retrieved successfully',
+ savedData: 'Data saved successfully'
+ },
+
+ // methods
+ //-----------------
+
+ dataserviceInit = function () { },
+
+ validationInit = function () {
+ ko.validation.configure({
+ registerExtenders: true, //default is true
+ messagesOnModified: true, //default is true
+ insertMessages: true, //default is true
+ parseInputAttributes: true, //default is false
+ writeInputAttributes: true, //default is false
+ messageTemplate: null, //default is null
+ decorateElement: true //default is false. Applies the .validationElement CSS class
+ });
+ },
+
+ configureExternalTemplates = function () {
+ infuser.defaults.templatePrefix = "_";
+ infuser.defaults.templateSuffix = ".tmpl.html";
+ infuser.defaults.templateUrl = "/Tmpl";
+ },
+
+ init = function () {
+ if (_useMocks) {
+ dataserviceInit = mock.dataserviceInit;
+ }
+ dataserviceInit();
+
+ toastr.options.timeOut = toastrTimeout;
+ configureExternalTemplates();
+ validationInit();
+ };
+
+ init();
+
+ return {
+ currentUserId: currentUserId,
+ currentUser: currentUser,
+ dataserviceInit: dataserviceInit,
+ hashes: hashes,
+ logger: logger,
+ messages: messages,
+ stateKeys: stateKeys,
+ storeExpirationMs: storeExpirationMs,
+ throttle: throttle,
+ title: title,
+ toasts: toasts,
+ useMocks: useMocks,
+ viewIds: viewIds,
+ window: window
+ };
+ });
View
370 CodeCamper.Web/Scripts/app/datacontext.js
@@ -0,0 +1,370 @@
+define('datacontext',
+ ['jquery', 'underscore', 'ko', 'model', 'model.mapper', 'dataservice', 'config', 'utils', 'datacontext.speaker-sessions'],
+ function ($, _, ko, model, modelmapper, dataservice, config, utils, SpeakerSessions) {
+ var logger = config.logger,
+ getCurrentUserId = function() {
+ return config.currentUser().id();
+ },
+ itemsToArray = function (items, observableArray, filter, sortFunction) {
+ // Maps the memo to an observableArray,
+ // then returns the observableArray
+ if (!observableArray) return;
+
+ // Create an array from the memo object
+ var underlyingArray = utils.mapMemoToArray(items);
+
+ if (filter) {
+ underlyingArray = _.filter(underlyingArray, function(o) {
+ var match = filter.predicate(filter, o);
+ return match;
+ });
+ }
+ if (sortFunction) {
+ underlyingArray.sort(sortFunction);
+ }
+ //logger.info('Fetched, filtered and sorted ' + underlyingArray.length + ' records');
+ observableArray(underlyingArray);
+ },
+ mapToContext = function(dtoList, items, results, mapper, filter, sortFunction) {
+ // Loop through the raw dto list and populate a dictionary of the items
+ items = _.reduce(dtoList, function(memo, dto) {
+ var id = mapper.getDtoId(dto);
+ var existingItem = items[id];
+ memo[id] = mapper.fromDto(dto, existingItem);
+ return memo;
+ }, { });
+ itemsToArray(items, results, filter, sortFunction);
+ //logger.success('received with ' + dtoList.length + ' elements');
+ return items; // must return these
+ },
+ EntitySet = function(getFunction, mapper, nullo, updateFunction) {
+ var items = {},
+ // returns the model item produced by merging dto into context
+ mapDtoToContext = function(dto) {
+ var id = mapper.getDtoId(dto);
+ var existingItem = items[id];
+ items[id] = mapper.fromDto(dto, existingItem);
+ return items[id];
+ },
+ add = function(newObj) {
+ items[newObj.id()] = newObj;
+ },
+ removeById = function(id) {
+ delete items[id];
+ },
+ getLocalById = function(id) {
+ // This is the only place we set to NULLO
+ return !!id && !!items[id] ? items[id] : nullo;
+ },
+ getAllLocal = function() {
+ return utils.mapMemoToArray(items);
+ },
+ getData = function(options) {
+ return $.Deferred(function(def) {
+ var results = options && options.results,
+ sortFunction = options && options.sortFunction,
+ filter = options && options.filter,
+ forceRefresh = options && options.forceRefresh,
+ param = options && options.param,
+ getFunctionOverride = options && options.getFunctionOverride;
+
+ getFunction = getFunctionOverride || getFunction;
+
+ // If the internal items object doesnt exist,
+ // or it exists but has no properties,
+ // or we force a refresh
+ if (forceRefresh || !items || !utils.hasProperties(items)) {
+ getFunction({
+ success: function(dtoList) {
+ items = mapToContext(dtoList, items, results, mapper, filter, sortFunction);
+ def.resolve(results);
+ },
+ error: function (response) {
+ logger.error(config.toasts.errorGettingData);
+ def.reject();
+ }
+ }, param);
+ } else {
+ itemsToArray(items, results, filter, sortFunction);
+ def.resolve(results);
+ }
+ }).promise();
+ },
+ updateData = function(entity, callbacks) {
+
+ var entityJson = ko.toJSON(entity);
+
+ return $.Deferred(function(def) {
+ if (!updateFunction) {
+ logger.error('updateData method not implemented');
+ if (callbacks && callbacks.error) { callbacks.error(); }
+ def.reject();
+ return;
+ }
+
+ updateFunction({
+ success: function(response) {
+ logger.success(config.toasts.savedData);
+ entity.dirtyFlag().reset();
+ if (callbacks && callbacks.success) { callbacks.success(); }
+ def.resolve(response);
+ },
+ error: function(response) {
+ logger.error(config.toasts.errorSavingData);
+ if (callbacks && callbacks.error) { callbacks.error(); }
+ def.reject(response);
+ return;
+ }
+ }, entityJson);
+ }).promise();
+ };
+
+ return {
+ mapDtoToContext: mapDtoToContext,
+ add: add,
+ getAllLocal: getAllLocal,
+ getLocalById: getLocalById,
+ getData: getData,
+ removeById: removeById,
+ updateData: updateData
+ };
+ },
+
+ //----------------------------------
+ // Repositories
+ //
+ // Pass:
+ // dataservice's 'get' method
+ // model mapper
+ //----------------------------------
+ attendance = new EntitySet(dataservice.attendance.getAttendance, modelmapper.attendance, model.Attendance.Nullo),
+ rooms = new EntitySet(dataservice.lookup.getRooms, modelmapper.room, model.Room.Nullo),
+ sessions = new EntitySet(dataservice.session.getSessionBriefs, modelmapper.session, model.Session.Nullo, dataservice.session.updateSession),
+ persons = new EntitySet(dataservice.person.getPersons, modelmapper.person, model.Person.Nullo, dataservice.person.updatePerson),
+ timeslots = new EntitySet(dataservice.lookup.getTimeslots, modelmapper.timeSlot, model.TimeSlot.Nullo),
+ tracks = new EntitySet(dataservice.lookup.getTracks, modelmapper.track, model.Track.Nullo),
+ speakerSessions = new SpeakerSessions.SpeakerSessions(persons, sessions);
+
+ // Attendance extensions
+ attendance.addData = function (sessionModel, callbacks) {
+ var attendanceModel = new model.Attendance()
+ .sessionId(sessionModel.id())
+ .personId(getCurrentUserId()),
+ attendanceModelJson = ko.toJSON(attendanceModel);
+
+ return $.Deferred(function (def) {
+ dataservice.attendance.addAttendance({
+ success: function (dto) {
+ if (!dto) {
+ logger.error(config.toasts.errorSavingData);
+ if (callbacks && callbacks.error) { callbacks.error(); }
+ def.reject();
+ return;
+ }
+ var newAtt = modelmapper.attendance.fromDto(dto); // Map DTO to Model
+ attendance.add(newAtt); // Add to the datacontext
+ sessionModel.isFavoriteRefresh.valueHasMutated(); // Trigger re-evaluation of isFavorite
+ logger.success(config.toasts.savedData);
+ if (callbacks && callbacks.success) { callbacks.success(newAtt); }
+ def.resolve(dto);
+ },
+ error: function (response) {
+ logger.error(config.toasts.errorSavingData);
+ if (callbacks && callbacks.error) { callbacks.error(); }
+ def.reject(response);
+ return;
+ }
+ }, attendanceModelJson);
+ }).promise();
+ };
+
+ attendance.updateData = function (sessionModel, callbacks) {
+ var
+ attendanceModel = sessionModel.attendance(),
+ attendanceModelJson = ko.toJSON(attendanceModel);
+
+ return $.Deferred(function(def) {
+ dataservice.attendance.updateAttendance({
+ success: function(response) {
+ logger.success(config.toasts.savedData);
+ attendanceModel.dirtyFlag().reset();
+ if (callbacks && callbacks.success) { callbacks.success(); }
+ def.resolve(response);
+ },
+ error: function(response) {
+ logger.error(config.toasts.errorSavingData);
+ if (callbacks && callbacks.error) { callbacks.error(); }
+ def.reject(response);
+ return;
+ }
+ }, attendanceModelJson);
+ }).promise();
+ };
+
+ attendance.deleteData = function (sessionModel, callbacks) {
+ var attendanceModel = sessionModel.attendance();
+ return $.Deferred(function (def) {
+ dataservice.attendance.deleteAttendance({
+ success: function (response) {
+ attendance.removeById(attendanceModel.id());
+ sessionModel.isFavoriteRefresh.valueHasMutated(); // Trigger re-evaluation of isFavorite
+ logger.success(config.toasts.savedData);
+ if (callbacks && callbacks.success) { callbacks.success(); }
+ def.resolve(response);
+ },
+ error: function (response) {
+ logger.error(config.toasts.errorSavingData);
+ if (callbacks && callbacks.error) { callbacks.error(); }
+ def.reject(response);
+ return;
+ }
+ }, attendanceModel.personId(), attendanceModel.sessionId());
+ }).promise();
+ };
+
+ // Extend Attendance entityset with ability to get attendance for the current user (aka, the favorite)
+ // This is a "Local" method, so it gets it from the DC only, no promise returned, no callbacks.
+ attendance.getLocalSessionFavorite = function (sessionId) {
+ var
+ id = model.Attendance.makeId(getCurrentUserId(), sessionId),
+ att = attendance.getLocalById(id);
+ return att;
+ };
+
+ // Extend Attendance entityset with ability to get attendance for the current user (aka, the favorite)
+ attendance.getSessionFavorite = function (sessionId, callbacks, forceRefresh) {
+ return $.Deferred(function (def) {
+ var
+ id = model.Attendance.makeId(getCurrentUserId(), sessionId),
+ att = attendance.getLocalById(id);
+
+ if (att.isNullo || forceRefresh) {
+ // get fresh from database
+ dataservice.attendance.getAttendance(
+ {
+ success: function (dto) {
+ // updates the session returned from getLocalById() above
+ att = attendance.mapDtoToContext(dto);
+ if (callbacks && callbacks.success) { callbacks.success(att); }
+ def.resolve(dto);
+ },
+ error: function (response) {
+ logger.error('oops! could not retrieve attendance ' + sessionId);
+ if (callbacks && callbacks.error) { callbacks.error(response); }
+ def.reject(response);
+ }
+ },
+ getCurrentUserId(),
+ sessionId
+ );
+ } else {
+ if (callbacks && callbacks.success) { callbacks.success(att); }
+ def.resolve(att);
+ }
+ }).promise();
+ };
+
+ // extend Sessions enttityset
+ sessions.getFullSessionById = function(id, callbacks, forceRefresh) {
+ return $.Deferred(function (def) {
+ var session = sessions.getLocalById(id);
+ if (session.isNullo || session.isBrief() || forceRefresh) {
+ // if nullo or brief, get fresh from database
+ dataservice.session.getSession({
+ success: function (dto) {
+ // updates the session returned from getLocalById() above
+ session = sessions.mapDtoToContext(dto);
+ session.isBrief(false); // now a full session
+ if (callbacks && callbacks.success) { callbacks.success(session); }
+ def.resolve(dto);
+ },
+ error: function (response) {
+ logger.error('oops! could not retrieve session ' + id);
+ if (callbacks && callbacks.error) { callbacks.error(response); }
+ def.reject(response);
+ }
+ },
+ id);
+ }
+ else {
+ if (callbacks && callbacks.success) { callbacks.success(session); }
+ def.resolve(session);
+ }
+ }).promise();
+ };
+
+ sessions.getSessionsAndAttendance = function (options) {
+ return $.Deferred(function(def) {
+ $.when(
+ sessions.getData(options),
+ datacontext.attendance.getData(
+ {
+ param: options.currentUserId,
+ forceRefresh: options.forceRefresh
+ })
+ )
+ .done(function () { def.resolve(); })
+ .fail(function () { def.reject(); });
+ }).promise();
+ };
+
+ // extend Persons entitySet
+ persons.getSpeakers = function (options) {
+ return $.Deferred(function(def) {
+ _.extend(options, {
+ getFunctionOverride: dataservice.person.getSpeakers
+ });
+ $.when(persons.getData(options))
+ .done(function() { def.resolve(); })
+ .fail(function() { def.reject(); });
+ }).promise();
+ },
+
+ persons.getFullPersonById = function (id, callbacks, forceRefresh) {
+ return $.Deferred(function (def) {
+ var person = persons.getLocalById(id);
+ if (person.isNullo || person.isBrief() || forceRefresh) {
+ // if nullo or brief, get fresh from database
+ dataservice.person.getPerson({
+ success: function (dto) {
+ // updates the person returned from getLocalById() above
+ person = persons.mapDtoToContext(dto);
+ person.isBrief(false); // now a full person
+ callbacks.success(person);
+ def.resolve(dto);
+ },
+ error: function (response) {
+ logger.error('oops! could not retrieve person ' + id);
+ if (callbacks && callbacks.error) { callbacks.error(response); }
+ def.reject(response);
+ }
+ },
+ id);
+ } else {
+ callbacks.success(person);
+ def.resolve(person);
+ }
+ }).promise();
+ },
+
+ // Get the sessions in cache for which this person is
+ // a speaker from local data (no 'promise')
+ persons.getLocalSpeakerSessions = function (personId) {
+ return speakerSessions.getLocalSessionsBySpeakerId(personId);
+ };
+
+ var datacontext = {
+ attendance: attendance,
+ persons: persons,
+ rooms: rooms,
+ sessions: sessions,
+ speakerSessions: speakerSessions,
+ timeslots: timeslots,
+ tracks: tracks
+ };
+
+ // We did this so we can access the datacontext during its construction
+ model.setDataContext(datacontext);
+
+ return datacontext;
+});
View
95 CodeCamper.Web/Scripts/app/datacontext.speaker-sessions.js
@@ -0,0 +1,95 @@
+define('datacontext.speaker-sessions',
+ ['jquery', 'underscore', 'ko'],
+ function ($, _, ko) {
+ /*
+ * A data "view" of speakers in cache and their cached sessions
+ */
+ var SpeakerSessions = function (persons, sessions) {
+
+ var items,
+ crossMatchSpeakers = function (observableArray, filter, sortFunction) {
+
+ // clear out the results observableArray
+ observableArray([]);
+
+ var underlyingArray = observableArray();
+ // get an array of persons
+ for (var prop in items) {
+ if (items.hasOwnProperty(prop)) {
+ underlyingArray.push(persons.getLocalById(prop));
+ }
+ }
+ if (filter) {
+ underlyingArray = _.filter(underlyingArray, function (o) {
+ var match = filter.predicate(filter, o);
+ return match;
+ });
+ }
+ if (sortFunction) {
+ underlyingArray.sort(sortFunction);
+ }
+ observableArray(underlyingArray);
+ },
+
+ // Rebuild this data "view" from the current state of the cache
+ refreshLocal = function() {
+ items = _.reduce(sessions.getAllLocal(), function(memo, s) {
+ var speakerId = s.speakerId();
+ memo[speakerId] = memo[speakerId] || [];
+ memo[speakerId].push(s);
+ return memo;
+ }, { });
+ },
+
+ // Rebuild this data "view" from fresh server data.
+ // Returns a promise to get fresh session and person data and
+ // refresh this instance of SpeakerSessions.
+ // caller can hang its own actions on the returned promise.
+ forceDataRefresh = function () {
+ var self = this;
+ return $.when(
+ sessions.getData({ forceRefresh: true }),
+ persons.getSpeakers({ forceRefresh: true })
+ )
+ .done(self.refresh);
+ },
+
+ // Get an array of sessions, sorted by title,
+ // for the speakerId (a person.id)
+ getLocalSessionsBySpeakerId = function (speakerId) {
+ var speakerSessions,
+ results = !!speakerId && !!(speakerSessions = items[speakerId]) ? speakerSessions.slice() : [];
+
+ return results.sort(function(l, r) { return l.title() > r.title() ? 1 : -1; });
+ },
+
+ // Fills the 'results' observable array with speakers
+ // optionally filtered and/or sorted
+ getLocalSpeakers = function (results, options) {
+ if (!ko.isObservable(results) || results.length === undefined) {
+ throw new Error('must provide a results observable array');
+ }
+ var sortFunction = options && options.sortFunction,
+ filter = options && options.filter;
+
+ crossMatchSpeakers(results, filter, sortFunction);
+
+ },
+
+ init = function () {
+ refreshLocal();
+ };
+
+ init();
+
+ return {
+ getLocalSessionsBySpeakerId: getLocalSessionsBySpeakerId,
+ getLocalSpeakers: getLocalSpeakers,
+ refreshLocal: refreshLocal,
+ forceDataRefresh: forceDataRefresh
+ };
+ };
+ return {
+ SpeakerSessions: SpeakerSessions
+ };
+ });
View
63 CodeCamper.Web/Scripts/app/dataprimer.js
@@ -0,0 +1,63 @@
+define('dataprimer',
+ ['ko', 'datacontext', 'config'],
+ function (ko, datacontext, config) {
+
+ var logger = config.logger,
+
+ fetch = function () {
+
+ return $.Deferred(function (def) {
+
+ var data = {
+ rooms: ko.observable(),
+ tracks: ko.observable(),
+ timeslots: ko.observable(),
+ attendance: ko.observable(),
+ persons: ko.observable(),
+ sessions: ko.observable()
+ };
+
+ $.when(
+ datacontext.rooms.getData({ results: data.rooms }),
+ datacontext.timeslots.getData({ results: data.timeslots }),
+ datacontext.tracks.getData({ results: data.tracks }),
+ datacontext.attendance.getData({ param: config.currentUserId, results: data.attendance }),
+ datacontext.persons.getSpeakers({ results: data.persons }),
+ datacontext.sessions.getData({ results: data.sessions }),
+ datacontext.persons.getFullPersonById(config.currentUserId,
+ {
+ success: function(person) {
+ config.currentUser(person);
+ }
+ }, true)
+ )
+
+ .pipe(function () {
+ // Need sessions and speakers in cache before
+ // speakerSessions models can be made (client model only)
+ datacontext.speakerSessions.refreshLocal();
+ })
+
+ .pipe(function() {
+ logger.success('Fetched data for: '
+ + '<div>' + data.rooms().length + ' rooms </div>'
+ + '<div>' + data.tracks().length + ' tracks </div>'
+ + '<div>' + data.timeslots().length + ' timeslots </div>'
+ + '<div>' + data.attendance().length + ' attendance </div>'
+ + '<div>' + data.persons().length + ' persons </div>'
+ + '<div>' + data.sessions().length + ' sessions </div>'
+ + '<div>' + (config.currentUser().isNullo ? 0 : 1) + ' user profile </div>'
+ );
+ })
+
+ .fail(function () { def.reject(); })
+
+ .done(function () { def.resolve(); });
+
+ }).promise();
+ };
+
+ return {
+ fetch: fetch
+ };
+ });
View
95 CodeCamper.Web/Scripts/app/dataservice.attendance.js
@@ -0,0 +1,95 @@
+define('dataservice.attendance',
+ ['amplify'],
+ function (amplify) {
+ var
+ init = function () {
+
+ amplify.request.define('favorites', 'ajax', {
+ url: '/api/favorites/{personId}',
+ dataType: 'json',
+ type: 'GET'
+ //cache:
+ });
+
+ amplify.request.define('favorite', 'ajax', {
+ url: '/api/attendance/?pid={personId}&sid={sessionId}',
+ dataType: 'json',
+ type: 'GET'
+ //cache:
+ });
+
+ amplify.request.define('attendanceAdd', 'ajax', {
+ url: '/api/attendance',
+ dataType: 'json',
+ type: 'POST',
+ contentType: 'application/json; charset=utf-8'
+ });
+
+ amplify.request.define('attendanceUpdate', 'ajax', {
+ url: '/api/attendance',
+ dataType: 'json',
+ type: 'PUT',
+ contentType: 'application/json; charset=utf-8'
+ });
+
+ // DELETE /api/attendance/?pid=2&sid=1
+ amplify.request.define('attendanceDelete', 'ajax', {
+ url: '/api/attendance/?pid={personId}&sid={sessionId}',
+ dataType: 'json',
+ type: 'DELETE',
+ contentType: 'application/json; charset=utf-8'
+ });
+ },
+
+ getAttendance = function (callbacks, personId, sessionId) {
+ var
+ resourceId = sessionId ? 'favorite' : 'favorites',
+ data = sessionId ? { personId: personId, sessionId: sessionId } : {personId: personId};
+
+ return amplify.request({
+ resourceId: resourceId,
+ data: data,
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ },
+
+ addAttendance = function(callbacks, data) {
+ return amplify.request({
+ resourceId: 'attendanceAdd',
+ data: data,
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ },
+
+ updateAttendance = function(callbacks, data) {
+ return amplify.request({
+ resourceId: 'attendanceUpdate',
+ data: data,
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ },
+
+ deleteAttendance = function(callbacks, personId, sessionId) {
+ return amplify.request({
+ resourceId: 'attendanceDelete',
+ data: {
+ personId: personId,
+ sessionId: sessionId
+ },
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ };
+
+ init();
+
+ return {
+ getAttendance: getAttendance,
+ addAttendance: addAttendance,
+ deleteAttendance: deleteAttendance,
+ updateAttendance: updateAttendance
+ };
+});
View
15 CodeCamper.Web/Scripts/app/dataservice.js
@@ -0,0 +1,15 @@
+define('dataservice',
+ [
+ 'dataservice.attendance',
+ 'dataservice.lookup',
+ 'dataservice.person',
+ 'dataservice.session'
+ ],
+ function (attendance, lookup, person, session) {
+ return {
+ attendance: attendance,
+ lookup: lookup,
+ person: person,
+ session: session
+ };
+ });
View
76 CodeCamper.Web/Scripts/app/dataservice.lookup.js
@@ -0,0 +1,76 @@
+define('dataservice.lookup',
+ ['amplify'],
+ function (amplify) {
+ var
+ init = function () {
+
+ amplify.request.define('lookups', 'ajax', {
+ url: '/api/lookups/all',
+ dataType: 'json',
+ type: 'GET'
+ //cache:
+ }),
+
+ amplify.request.define('rooms', 'ajax', {
+ url: '/api/lookups/rooms',
+ dataType: 'json',
+ type: 'GET'
+ //cache:
+ }),
+
+ amplify.request.define('timeslots', 'ajax', {
+ url: '/api/lookups/timeslots',
+ dataType: 'json',
+ type: 'GET'
+ //cache:
+ }),
+
+ amplify.request.define('tracks', 'ajax', {
+ url: '/api/lookups/tracks',
+ dataType: 'json',
+ type: 'GET'
+ //cache:
+ });
+ },
+
+ getLookups = function (callbacks) {
+ return amplify.request({
+ resourceId: 'lookups',
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ },
+
+ getRooms = function (callbacks) {
+ return amplify.request({
+ resourceId: 'rooms',
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ },
+
+ getTimeslots = function (callbacks) {
+ return amplify.request({
+ resourceId: 'timeslots',
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ },
+
+ getTracks = function (callbacks) {
+ return amplify.request({
+ resourceId: 'tracks',
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ };
+
+ init();
+
+ return {
+ getLookups: getLookups,
+ getRooms: getRooms,
+ getTimeslots: getTimeslots,
+ getTracks: getTracks
+ };
+});
View
80 CodeCamper.Web/Scripts/app/dataservice.person.js
@@ -0,0 +1,80 @@
+define('dataservice.person',
+ ['amplify'],
+ function (amplify) {
+ var
+ init = function () {
+
+ amplify.request.define('speakers', 'ajax', {
+ url: '/api/speakers',
+ dataType: 'json',
+ type: 'GET'
+ //cache: true
+ }),
+
+ amplify.request.define('persons', 'ajax', {
+ url: '/api/persons',
+ dataType: 'json',
+ type: 'GET'
+ //cache:
+ });
+
+ amplify.request.define('person', 'ajax', {
+ url: '/api/persons/{id}',
+ dataType: 'json',
+ type: 'GET'
+ //cache:
+ });
+
+ amplify.request.define('personUpdate', 'ajax', {
+ url: '/api/persons',
+ dataType: 'json',
+ type: 'PUT',
+ contentType: 'application/json; charset=utf-8'
+ });
+ },
+
+ getSpeakers = function (callbacks) {
+ return amplify.request({
+ resourceId: 'speakers',
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ },
+
+ getPersons = function (callbacks) {
+ return amplify.request({
+ resourceId: 'persons',
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ },
+
+ getPerson = function (callbacks, id) {
+ return amplify.request({
+ resourceId: 'person',
+ data: { id: id },
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ };
+
+ updatePerson = function (callbacks, data) {
+ return amplify.request({
+ resourceId: 'personUpdate',
+ data: data,
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ };
+
+ init();
+
+ return {
+ getPerson: getPerson,
+ getPersons: getPersons,
+ getSpeakers: getSpeakers,
+ updatePerson: updatePerson
+ };
+});
+
+
View
79 CodeCamper.Web/Scripts/app/dataservice.session.js
@@ -0,0 +1,79 @@
+define('dataservice.session',
+ ['amplify'],
+ function (amplify) {
+ var
+ init = function () {
+
+ amplify.request.define('sessions', 'ajax', {
+ url: '/api/sessions',
+ dataType: 'json',
+ type: 'GET'
+ });
+
+ // Pass Resource Id, Request Type, and Settings
+ amplify.request.define('session-briefs', 'ajax', {
+ url: '/api/sessionbriefs',
+ dataType: 'json',
+ type: 'GET'
+ //cache: true
+ //cache: 60000 // 1 minute
+ //cache: 'persist'
+ });
+
+ amplify.request.define('session', 'ajax', {
+ url: '/api/sessions/{id}',
+ dataType: 'json',
+ type: 'GET'
+ });
+
+ amplify.request.define('sessionUpdate', 'ajax', {
+ url: '/api/sessions',
+ dataType: 'json',
+ type: 'PUT',
+ contentType: 'application/json; charset=utf-8'
+ });
+ },
+
+ getSessions = function (callbacks) {
+ return amplify.request({
+ resourceId: 'sessions',
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ },
+
+ getSessionBriefs = function (callbacks) {
+ return amplify.request({
+ resourceId: 'session-briefs',
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ },
+
+ getSession = function (callbacks, id) {
+ return amplify.request({
+ resourceId: 'session',
+ data: { id: id },
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ },
+
+ updateSession = function (callbacks, data) {
+ return amplify.request({
+ resourceId: 'sessionUpdate',
+ data: data,
+ success: callbacks.success,
+ error: callbacks.error
+ });
+ };
+
+ init();
+
+ return {
+ getSessions: getSessions,
+ getSessionBriefs: getSessionBriefs,
+ getSession: getSession,
+ updateSession: updateSession
+ };
+ });
View
42 CodeCamper.Web/Scripts/app/event.delegates.js
@@ -0,0 +1,42 @@
+define('event.delegates',
+ ['jquery', 'ko', 'config'],
+ function ($, ko, config) {
+ var
+ sessionBriefSelector = '.session-brief',
+ favoriteSelector = 'button.markfavorite',
+
+ bindEventToList = function (rootSelector, selector, callback, eventName) {
+ var eName = eventName || 'click';
+ $(rootSelector).on(eName, selector, function () {
+ //var context = ko.contextFor(this);
+ //var session = context.$data;
+ var session = ko.dataFor(this);
+ callback(session);
+ return false;
+ });
+ },
+
+ favoritesListItem = function (callback, eventName) {
+ bindEventToList(config.viewIds.favorites, sessionBriefSelector, callback, eventName);
+ },
+
+ sessionsListItem = function (callback, eventName) {
+ bindEventToList(config.viewIds.sessions, sessionBriefSelector, callback, eventName);
+ },
+
+ favoritesFavorite = function (callback, eventName) {
+ bindEventToList(config.viewIds.favorites, favoriteSelector, callback, eventName);
+ },
+
+ sessionsFavorite = function (callback, eventName) {
+ bindEventToList(config.viewIds.sessions, favoriteSelector, callback, eventName);
+ };
+
+ return {
+ favoritesListItem: favoritesListItem,
+ favoritesFavorite: favoritesFavorite,
+ sessionsListItem: sessionsListItem,
+ sessionsFavorite: sessionsFavorite
+ };
+ });
+
View
83 CodeCamper.Web/Scripts/app/filter.sessions.js
@@ -0,0 +1,83 @@
+define('filter.sessions',
+ ['ko', 'utils', 'config'],
+ function(ko, utils, config) {
+
+ var SessionFilter = function() {
+ var self = this;
+ self.favoriteOnly = ko.observable(false);
+ self.minDate = ko.observable();
+ self.maxDate = ko.observable();
+ self.searchText = ko.observable().extend({ throttle: config.throttle });
+ self.speaker = ko.observable(); // object
+ self.timeslot = ko.observable(); // object
+ self.track = ko.observable(); // object
+ return self;
+ };
+
+ SessionFilter.prototype = function () {
+ var tagDelimiter = '|',
+ escapedTagDelimiter = '\\|',
+ searchTest = function(searchText, session) {
+ if (!searchText) return true; // always succeeds if no search text
+ var srch = utils.regExEscape(searchText.toLowerCase());
+ if (session.title().toLowerCase().search(srch) !== -1) return true;
+ if (session.speaker().firstName().toLowerCase().search(srch) !== -1) return true;
+ if (session.speaker().lastName().toLowerCase().search(srch) !== -1) return true;
+ if (session.track().name().toLowerCase().search(srch) !== -1) return true;
+ if (session.room().name().toLowerCase().search(srch) !== -1) return true;
+ if ((tagDelimiter + session.tags().toLowerCase() + tagDelimiter)
+ .search(escapedTagDelimiter + srch + escapedTagDelimiter) !== -1) return true;
+ return false;
+ },
+ favoriteTest = function(favoriteOnly, session) {
+ if (favoriteOnly) {
+ var match = session.isFavorite();
+ return match;
+ } else {
+ return true; // don't care if favorite or not
+ }
+ },
+
+ timeSlotTest = function (minDate, maxDate, session) {
+ // Return true if it meets the filter criteria. Otherwise, return false
+ if (minDate && minDate > session.timeslot().start()) return false;
+ if (maxDate && maxDate < session.timeslot().start()) return false;
+ return true;
+ },
+
+ modelTest = function (timeslot, speaker, track, session) {
+ // Return true if it meets the filter criteria. Otherwise, return false
+ if (timeslot && timeslot.id() !== session.timeslot().id()) return false;
+ if (speaker && speaker.id() !== session.speaker().id()) return false;
+ if (track && track.id() !== session.track().id()) return false;
+ return true;
+ },
+
+ predicate = function (self, session) {
+ // Return true if all of these meet the filter criteria. Otherwise, return false
+ var match = searchTest(self.searchText(), session)
+ && favoriteTest(self.favoriteOnly(), session)
+ && timeSlotTest(self.minDate(), self.maxDate(), session)
+ && modelTest(self.timeslot(), self.speaker(), self.track(), session);
+ return match;
+
+ //PAPA: testing only.
+ //var matchSearch = searchTest(self.searchText(), session),
+ // matchFav = favoriteTest(self.favoriteOnly(), session),
+ // matchTime = timeSlotTest(self.minDate(), self.maxDate(), session),
+ // matchModels = modelTest(self.timeslot(), self.speaker(), self.track(), session);
+ //console.log('search filter matched: ' + matchSearch);
+ //console.log('favorites filter matched: ' + matchFav);
+ //console.log('time filter matched: ' + matchTime);
+ //console.log('models filter matched: ' + matchModels);
+ //console.log('MATCH === ' + matchSearch && matchFav && matchTime && matchModels);
+ //return matchSearch && matchFav && matchTime && matchModels;
+ };
+
+ return {
+ predicate: predicate
+ };
+ }();
+
+ return SessionFilter;
+ });
View
35 CodeCamper.Web/Scripts/app/filter.speakers.js
@@ -0,0 +1,35 @@
+define('filter.speakers',
+ ['ko', 'utils', 'config'],
+ function(ko, utils, config) {
+
+ var SpeakerFilter = function() {
+ var self = this;
+ self.searchText = ko.observable().extend({ throttle: config.throttle });
+ return self;
+ };
+
+ SpeakerFilter.prototype = function() {
+ var searchTest = function(searchText, speaker) {
+ try {
+ if (!searchText) return true; // always succeeds if no search text
+ var srch = utils.regExEscape(searchText.toLowerCase());
+ if (speaker.firstName().toLowerCase().search(srch) !== -1) return true;
+ if (speaker.lastName().toLowerCase().search(srch) !== -1) return true;
+ } catch(err) {
+ config.logger.error('filter failed for expression ' + searchText + '. ' + err.message);
+ }
+ return false;
+ },
+ predicate = function(self, speaker) {
+ // Return true if all of these meet the filter criteria. Otherwise, return false
+ var match = searchTest(self.searchText(), speaker);
+ return match;
+ };
+
+ return {
+ predicate: predicate
+ };
+ }();
+
+ return SpeakerFilter;
+ });
View
44 CodeCamper.Web/Scripts/app/group.js
@@ -0,0 +1,44 @@
+define('group',
+ ['underscore', 'ko', 'moment', 'config'],
+ function(_, ko, moment, config) {
+
+ var timeslotsToDays = function(timeslots) {
+
+ var
+ hash = config.hashes.favoritesByDate,
+
+ result = _.reduce(timeslots, function (memo, slot) {
+ var
+ slotStart = slot.start(),
+ date = moment(slotStart).format('MM-DD-YYYY'),
+ day = moment(slotStart).format('ddd MMM DD');
+
+ if (!memo.index[day.toString()]) {
+ // This is created so i dont have to loop through the array each time again
+ memo.index[day.toString()] = true;
+
+ // We will return an array of objects with
+ // the properties: date, day, isSelected
+ memo.slots.push({
+ date: date,
+ day: day,
+ hash: hash + '/' + date,
+ isSelected: ko.observable()
+ });
+
+ }
+ return memo;
+ }, { index: {}, slots: [] }),
+
+ sortedDays = result.slots.sort(function(a, b) {
+ return a.date > b.date ? 1 : -1;
+ });
+
+ return sortedDays;
+
+ };
+
+ return {
+ timeslotsToDays: timeslotsToDays
+ };
+ });
View
143 CodeCamper.Web/Scripts/app/ko.bindingHandlers.js
@@ -0,0 +1,143 @@
+define('ko.bindingHandlers',
+['jquery', 'ko'],
+function ($, ko) {
+ var unwrap = ko.utils.unwrapObservable;
+
+ // escape
+ //---------------------------
+ ko.bindingHandlers.escape = {
+ update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
+ var command = valueAccessor();
+ $(element).keyup(function (event) {
+ if (event.keyCode === 27) { // <ESC>
+ command.call(viewModel, viewModel, event);
+ }
+ });
+ }
+ };
+
+ // hidden
+ //---------------------------
+ ko.bindingHandlers.hidden = {
+ update: function (element, valueAccessor) {
+ var value = unwrap(valueAccessor());
+ ko.bindingHandlers.visible.update(element, function () { return !value; });
+ }
+ };
+
+ // checboxImage
+ //---------------------------
+ ko.bindingHandlers.checkboxImage = {
+ init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
+ var $el = $(element),
+ settings = valueAccessor();
+
+ $el.addClass('checkbox');
+
+ $el.click(function () {
+ if (settings.checked) {
+ settings.checked(!settings.checked());
+ }
+ });
+
+ ko.bindingHandlers.checkboxImage.update(
+ element, valueAccessor, allBindingsAccessor, viewModel);
+ },
+ update: function (element, valueAccessor) {
+ var $el = $(element),
+ settings = valueAccessor(),
+ enable = (settings.enable !== undefined) ? unwrap(settings.enable()) : true,
+ checked = (settings.checked !== undefined) ? unwrap(settings.checked()) : true;
+
+ $el.prop('disabled', !enable);
+
+ checked ? $el.addClass('selected') : $el.removeClass('selected');
+ }
+ };
+
+ // favoriteCheckbox
+ //---------------------------
+ ko.bindingHandlers.favoriteCheckbox = {
+ init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
+ var $el = $(element);
+
+ $el.addClass('markfavorite');
+
+ ko.bindingHandlers.favoriteCheckbox.update(
+ element, valueAccessor, allBindingsAccessor, viewModel);
+ },
+ update: function (element, valueAccessor) {
+ var $el = $(element),
+ valAccessor = valueAccessor(),
+ enable = (valAccessor.enable !== undefined) ? unwrap(valAccessor.enable()) : true,
+ checked = (valAccessor.checked !== undefined) ? unwrap(valAccessor.checked()) : true;
+
+ $el.prop('disabled', !enable);
+ if (checked) {
+ if (enable) {
+ $el.attr('title', 'remove favorite');
+ } else {
+ $el.attr('title', 'locked');
+ }
+ } else {
+ $el.attr('title', 'mark as favorite');
+ }
+
+ checked ? $el.addClass('selected') : $el.removeClass('selected');
+ enable ? $el.removeClass('locked') : $el.addClass('locked');
+ }
+ };
+
+ // starRating
+ //---------------------------
+ ko.bindingHandlers.starRating = {
+ init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
+ // Create the span's (only do in init)
+ for (var i = 0; i < 5; i++) {
+ $('<span>').appendTo(element);
+ }
+
+ ko.bindingHandlers.starRating.update(element, valueAccessor, allBindingsAccessor, viewModel);
+ },
+
+ update: function (element, valueAccessor, allBindingsAccessor) {
+ // Give the first x stars the 'chosen' class, where x <= rating
+ var ratingObservable = valueAccessor(),
+ allBindings = allBindingsAccessor(),
+ enable = (allBindings.enable !== undefined) ? unwrap(allBindings.enable) : true;
+
+ // Toggle the appropriate CSS classes
+ if (enable) {
+ $(element).addClass('starRating').removeClass('starRating-readonly');
+ }else {
+ $(element).removeClass('starRating').addClass('starRating-readonly');
+ }
+
+ // Wire up the event handlers, if enabled
+ if (enable) {
+ // Handle mouse events on the stars
+ $('span', element).each(function (index) {
+ var $star = $(this);
+
+ $star.hover(
+ function () {
+ $star.prevAll().add(this).addClass('hoverChosen');
+ },
+ function () {
+ $star.prevAll().add(this).removeClass('hoverChosen');
+ });
+
+ $star.click(function () {
+ //var ratingObservable = valueAccessor(); // Get the associated observable
+ ratingObservable(index + 1); // Write the new rating to it
+ });
+ });
+ }
+
+ // Toggle the chosen CSS class (fills in the stars for the rating)
+ $('span', element).each(function (index) {
+ $(this).toggleClass('chosen', index < ratingObservable());
+ });
+ }
+ };
+});
View
22 CodeCamper.Web/Scripts/app/ko.debug.helpers.js
@@ -0,0 +1,22 @@
+define('ko.debug.helpers',
+['ko'],
+function (ko) {
+
+ //track the number of re-evaluations for a computed observable
+ ko.observableArray.fn.trackReevaluations = function () {
+ var self = this;
+ self.reevaluationCount = ko.observable(0);
+ self.subscribe(function () {
+ this.reevaluationCount(this.reevaluationCount() + 1);
+ }, self);
+ return self;
+ };
+
+ ko.utils.debugInfo = function (items) {
+ return ko.computed(function () {
+ //new in KO 2.1. it used to be JSON.stringify(ko.toJS(timeslots), null, 2)
+ return ko.toJSON(items, null, 2);
+ });
+ };
+
+});
View
27 CodeCamper.Web/Scripts/app/messenger.js
@@ -0,0 +1,27 @@
+define('messenger',
+['amplify', 'config'],
+ function (amplify, config) {
+ var
+ priority = 1,
+
+ publish = function (topic, options) {
+ amplify.publish(topic, options);
+ },
+
+ subscribe = function (options) {
+ amplify.subscribe(
+ options.topic,
+ options.context,
+ options.callback,
+ priority);
+ };
+
+ publish.viewModelActivated = function(options) {
+ amplify.publish(config.messages.viewModelActivated, options);
+ };
+
+ return {
+ publish: publish,
+ subscribe: subscribe
+ };
+ });
View
20 CodeCamper.Web/Scripts/app/mock/mock.dataservice.attendance.js
@@ -0,0 +1,20 @@
+define('mock/mock.dataservice.attendance',
+ ['amplify'],
+ function (amplify) {
+ var
+ defineApi = function (model) {
+
+ amplify.request.define('favorites', function (settings) {
+ settings.success(model.generateAttendance().attendance);
+ });
+
+ amplify.request.define('favorite', function (settings) {
+ settings.success(model.generateAttendance().attendance[0]);
+ });
+
+ };
+
+ return {
+ defineApi: defineApi
+ };
+ });
View
33 CodeCamper.Web/Scripts/app/mock/mock.dataservice.lookup.js
@@ -0,0 +1,33 @@
+define('mock/mock.dataservice.lookup',
+ ['amplify'],
+ function (amplify) {
+ var
+ defineApi = function (model) {
+
+ amplify.request.define('lookups', function (settings) {
+ settings.success({
+ lookups: {
+ Rooms: model.generateRooms().rooms,
+ TimeSlots: model.generateTimeslots().timeslots,
+ Tracks: model.generateTracks().tracks
+ }
+ });
+ });
+
+ amplify.request.define('rooms', function (settings) {
+ settings.success(model.generateRooms().rooms);
+ });
+
+ amplify.request.define('timeslots', function (settings) {
+ settings.success(model.generateTimeslots().timeslots);
+ });
+
+ amplify.request.define('tracks', function (settings) {
+ settings.success(model.generateTracks().tracks);
+ });
+ };
+
+ return {
+ defineApi: defineApi
+ };
+ });
View
27 CodeCamper.Web/Scripts/app/mock/mock.dataservice.person.js
@@ -0,0 +1,27 @@
+define('mock/mock.dataservice.person',
+ ['amplify'],
+ function (amplify) {
+ var
+ defineApi = function (model) {
+
+ amplify.request.define('speakers', function (settings) {
+ settings.success(model.generatePersons().persons);
+ });
+
+ amplify.request.define('persons', function (settings) {
+ settings.success(model.generatePersons().persons);
+ });
+
+ amplify.request.define('person', function (settings) {
+ settings.success(model.generatePersons().persons[0]);
+ });
+
+ amplify.request.define('personUpdate', function (settings) {
+ settings.success();
+ });
+ };
+
+ return {
+ defineApi: defineApi
+ };
+ });
View
27 CodeCamper.Web/Scripts/app/mock/mock.dataservice.session.js
@@ -0,0 +1,27 @@
+define('mock/mock.dataservice.session',
+ ['amplify'],
+ function (amplify) {
+ var
+ defineApi = function (model) {
+
+ amplify.request.define('sessions', function (settings) {
+ settings.success(model.generateSessions().sessions);
+ });
+
+ amplify.request.define('session-briefs', function (settings) {
+ settings.success(model.generateSessions().sessions);
+ });
+
+ amplify.request.define('session', function (settings) {
+ settings.success(model.generateSessions().sessions[0]);
+ });
+
+ amplify.request.define('sessionUpdate', function (settings) {
+ settings.success();
+ });
+ };
+
+ return {
+ defineApi: defineApi
+ };
+ });
View
138 CodeCamper.Web/Scripts/app/mock/mock.generator.js
@@ -0,0 +1,138 @@
+define('mock/mock.generator',
+ ['jquery', 'moment'],
+ function($, moment) {
+ var
+ init = function () {
+ $.mockJSON.random = true;
+ $.mockJSON.log = false;
+ $.mockJSON.data.SPEAKER_FIRST_NAME = ['John', 'Dan', 'Scott', 'Hans', 'Ward', 'Jim', 'Ryan', 'Steve', 'Ella', 'Landon', 'Haley', 'Madelyn'];
+ $.mockJSON.data.SPEAKER_LAST_NAME = ['Papa', 'Wahlin', 'Guthrie', 'Fjällemark', 'Bell', 'Cowart', 'Niemeyer', 'Sanderson'];
+ $.mockJSON.data.IMAGE_SOURCE = ['john_papa.jpg', 'dan_wahlin.jpg', 'scott_guthrie.jpg', 'hans_fjallemark.jpg', 'ward_bell.jpg', 'jim_cowart.jpg', 'ryan_niemeyer.jpg', 'steve_sanderson.jpg'];
+ $.mockJSON.data.DATE_TODAY = [moment().format('MMMM DD YYYY')];
+ $.mockJSON.data.DATE_FULL = [new Date()];
+ $.mockJSON.data.TAG = ['JavaScript', 'Knockout', 'MVVM', 'HTML5', 'Keynote', 'SQL', 'CSS', 'Metro', 'UX'];
+ $.mockJSON.data.TRACK = ['Windows 8', 'JavaScript', 'ASP.NET', '.NET', 'Data', 'Mobile', 'Cloud', 'Practices', 'Design'];
+ $.mockJSON.data.TITLE = [
+ 'Building HTML/JavaScript Apps with Knockout and MVVM',
+ 'JsRender Fundamentals',
+ 'Introduction to Building Windows 8 Metro Applications',
+ 'Building ASP.NET MVC Apps with EF Code First, HTML5, and jQuery',
+ 'jQuery Fundamentals',
+ 'jQuery Tips and Tricks',
+ 'JavaScript for .NET Developers',
+ 'jQuery Mobile',
+ 'Bootstrap',
+ 'Responsive Web Design',
+ 'Structuring JavaScript Code',
+ 'Keynote'
+ ];
+ $.mockJSON.data.LEVEL = ["Beginner", "Intermediate", "Advanced"];
+ $.mockJSON.data.TWITTER = ['