Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

further changes to nancy demo

  • Loading branch information...
commit 636959df45854ce0ccbdf61153392c52cebdad66 1 parent dae8581
@nicholascloud authored
Showing with 552 additions and 54 deletions.
  1. +6 −2 kcdc12/nancyfx/demo/HamstringFX.RaceService/CliArgs.cs
  2. +4 −2 kcdc12/nancyfx/demo/HamstringFX.RaceService/HamstringFX.RaceService.csproj
  3. +2 −2 kcdc12/nancyfx/demo/HamstringFX.RaceService/Program.cs
  4. +6 −1 kcdc12/nancyfx/demo/HamstringFX.RaceService/RaceServiceBootstrapper.cs
  5. +3 −0  kcdc12/nancyfx/demo/HamstringFX.RaceService/app.config
  6. +5 −0 kcdc12/nancyfx/demo/HamstringFX.RaceService/cache/races.xml
  7. +11 −3 kcdc12/nancyfx/demo/HamstringFX.RaceService/data/RaceData.cs
  8. +4 −2 kcdc12/nancyfx/demo/HamstringFX/HamstringFX.csproj
  9. +15 −0 kcdc12/nancyfx/demo/HamstringFX/data/Announcement.cs
  10. +3 −1 kcdc12/nancyfx/demo/HamstringFX/data/HamstringData.cs
  11. +5 −1 kcdc12/nancyfx/demo/HamstringFX/{model → data}/Race.cs
  12. +2 −2 kcdc12/nancyfx/demo/HamstringFX/{model → data}/RaceServiceProxy.cs
  13. +1 −0  kcdc12/nancyfx/demo/HamstringFX/model/IRaceServiceProxy.cs
  14. +6 −2 kcdc12/nancyfx/demo/HamstringFX/model/MainModelFactory.cs
  15. +1 −1  kcdc12/nancyfx/demo/HamstringFX/model/Models.cs
  16. +15 −0 kcdc12/nancyfx/demo/HamstringFX/model/RunModel.cs
  17. +13 −0 kcdc12/nancyfx/demo/HamstringFX/modules/MainModule.cs
  18. +4 −1 kcdc12/nancyfx/demo/HamstringFX/modules/RunModule.cs
  19. BIN  kcdc12/nancyfx/demo/HamstringFX/public/img/runner.png
  20. +49 −14 kcdc12/nancyfx/demo/HamstringFX/public/scripts/hamstringfx.js
  21. +18 −0 kcdc12/nancyfx/demo/HamstringFX/public/scripts/lib/postal.diagnostics.js
  22. +347 −0 kcdc12/nancyfx/demo/HamstringFX/public/scripts/lib/postal.js
  23. +12 −4 kcdc12/nancyfx/demo/HamstringFX/public/styles/hamstringfx.css
  24. +1 −1  kcdc12/nancyfx/demo/HamstringFX/views/_addrun.sshtml
  25. +5 −7 kcdc12/nancyfx/demo/HamstringFX/views/_announcements.sshtml
  26. +1 −1  kcdc12/nancyfx/demo/HamstringFX/views/_races.sshtml
  27. +1 −1  kcdc12/nancyfx/demo/HamstringFX/views/hamstring.sshtml
  28. +3 −5 kcdc12/nancyfx/demo/HamstringFX/views/master.sshtml
  29. BIN  kcdc12/nancyfx/demo/gfx/runner-silhouette-transp.png
  30. +9 −1 kcdc12/nancyfx/demo/schema.sql
View
8 kcdc12/nancyfx/demo/HamstringFX.RaceService/CliArgs.cs
@@ -1,7 +1,7 @@
using System.Collections.Generic;
namespace HamstringFX.RaceService {
- class CliArgs {
+ public class CliArgs {
public CliArgs(IEnumerable<string> args) {
_args = new List<string>(args);
}
@@ -9,7 +9,11 @@ class CliArgs {
private readonly List<string> _args;
public bool LaunchBrowser {
- get { return _args.Contains("-b"); }
+ get { return _args.Contains("--browser"); }
+ }
+
+ public bool AlwaysUseCache {
+ get { return _args.Contains("--cached"); }
}
}
}
View
6 kcdc12/nancyfx/demo/HamstringFX.RaceService/HamstringFX.RaceService.csproj
@@ -9,9 +9,10 @@
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>HamstringFX.RaceService</RootNamespace>
- <AssemblyName>HamstringFX.RaceService</AssemblyName>
+ <AssemblyName>racesrv</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
- <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+ <TargetFrameworkProfile>
+ </TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
@@ -62,6 +63,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
+ <None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
View
4 kcdc12/nancyfx/demo/HamstringFX.RaceService/Program.cs
@@ -10,7 +10,7 @@ class Program {
//TODO: discuss self hosting in slideshow
var uri = new Uri("http://localhost:8087/");
- var host = new NancyHost(uri);
+ var host = new NancyHost(uri, new RaceServiceBootstrapper(cliargs));
host.Start();
Console.WriteLine(String.Format("HamstringFX.RaceService now listening on {0}", uri.OriginalString));
@@ -23,8 +23,8 @@ class Program {
Console.ReadKey();
host.Stop();
+ Console.WriteLine();
Console.WriteLine("HamstringFX.RaceService terminated");
-
}
}
}
View
7 kcdc12/nancyfx/demo/HamstringFX.RaceService/RaceServiceBootstrapper.cs
@@ -3,11 +3,16 @@
namespace HamstringFX.RaceService {
public class RaceServiceBootstrapper : DefaultNancyBootstrapper {
+ public RaceServiceBootstrapper(CliArgs args) {
+ _args = args;
+ }
+
+ private readonly CliArgs _args;
protected override void ConfigureApplicationContainer(TinyIoC.TinyIoCContainer container) {
base.ConfigureApplicationContainer(container);
- container.Register<IRaceData, RaceData>().AsSingleton();
+ container.Register<IRaceData>(new RaceData(_args.AlwaysUseCache));
}
}
}
View
3  kcdc12/nancyfx/demo/HamstringFX.RaceService/app.config
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<configuration>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
View
5 kcdc12/nancyfx/demo/HamstringFX.RaceService/cache/races.xml
@@ -97,5 +97,10 @@
<link>http://www.runningintheusa.com/Race/View.aspx?RaceID=53901</link>
<pubDate>4/3/2012 1:25:00 PM</pubDate>
</item>
+ <!-- dummy data for debugging -->
+ <item>
+ <title>Foo Race ~ Florissant, MO ~ Aug 13 2012</title>
+ <link>http://foorace.com</link>
+ </item>
</channel>
</rss>
View
14 kcdc12/nancyfx/demo/HamstringFX.RaceService/data/RaceData.cs
@@ -7,10 +7,18 @@
namespace HamstringFX.RaceService.data {
public class RaceData : IRaceData {
- readonly IDataStream _remote = new RemoteRaceStream();
- readonly IDataStream _cached = new CachedRaceStream();
-
+ public RaceData(bool alwaysUseCache) {
+ _alwaysUseCache = alwaysUseCache;
+ }
+
+ private readonly bool _alwaysUseCache = false;
+ private readonly IDataStream _remote = new RemoteRaceStream();
+ private readonly IDataStream _cached = new CachedRaceStream();
+
public ICollection<Race> UpcomingRaces() {
+ if (_alwaysUseCache) {
+ return ReadRaces(_cached);
+ }
try {
return ReadRaces(_remote);
View
6 kcdc12/nancyfx/demo/HamstringFX/HamstringFX.csproj
@@ -81,14 +81,16 @@
<Compile Include="data\HamstringData.cs" />
<Compile Include="data\HamstringUserIdentity.cs" />
<Compile Include="data\Member.cs" />
+ <Compile Include="data\Announcement.cs" />
<Compile Include="data\Playlist.cs" />
<Compile Include="data\Privilege.cs" />
<Compile Include="model\IRaceServiceProxy.cs" />
<Compile Include="model\MainModelFactory.cs" />
<Compile Include="model\PortalModelFactory.cs" />
<Compile Include="model\IModelFactory.cs" />
- <Compile Include="model\Race.cs" />
- <Compile Include="model\RaceServiceProxy.cs" />
+ <Compile Include="data\Race.cs" />
+ <Compile Include="data\RaceServiceProxy.cs" />
+ <Compile Include="model\RunModel.cs" />
<Compile Include="modules\MainModule.cs" />
<Compile Include="security\AuthenticationResult.cs" />
<Compile Include="security\IHashStrategy.cs" />
View
15 kcdc12/nancyfx/demo/HamstringFX/data/Announcement.cs
@@ -0,0 +1,15 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+
+namespace HamstringFX.data {
+ public class Announcement {
+ [Key]
+ public Guid Id { get; set; }
+ public DateTime ReportedAt { get; set; }
+ public String Content { get; set; }
+
+ public String FormattedDate {
+ get { return ReportedAt.ToString("dddd, MM/dd/yyyy"); }
+ }
+ }
+}
View
4 kcdc12/nancyfx/demo/HamstringFX/data/HamstringData.cs
@@ -9,7 +9,8 @@ public interface IHamstringData {
IDbSet<Run> Runs { get; set; }
IDbSet<Member> Members { get; set; }
IDbSet<Privilege> Privileges { get; set; }
- IDbSet<Playlist> Playlists { get; set; }
+ IDbSet<Playlist> Playlists { get; set; }
+ IDbSet<Announcement> Announcements { get; set; }
}
public class HamstringData : DbContext, IHamstringData {
@@ -18,5 +19,6 @@ public class HamstringData : DbContext, IHamstringData {
public IDbSet<Member> Members { get; set; }
public IDbSet<Privilege> Privileges { get; set; }
public IDbSet<Playlist> Playlists { get; set; }
+ public IDbSet<Announcement> Announcements { get; set; }
}
}
View
6 kcdc12/nancyfx/demo/HamstringFX/model/Race.cs → kcdc12/nancyfx/demo/HamstringFX/data/Race.cs
@@ -1,10 +1,14 @@
using System;
-namespace HamstringFX.model {
+namespace HamstringFX.data {
public class Race {
public String Name { get; set; }
public String Location { get; set; }
public DateTime ScheduledAt { get; set; }
public String URL { get; set; }
+
+ public String FormattedDate {
+ get { return ScheduledAt.ToString("MM/dd/yyyy"); }
+ }
}
}
View
4 ...ancyfx/demo/HamstringFX/model/RaceServiceProxy.cs → ...nancyfx/demo/HamstringFX/data/RaceServiceProxy.cs
@@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
using System.Net;
+using HamstringFX.model;
using Nancy.Json;
-namespace HamstringFX.model {
+namespace HamstringFX.data {
class RaceServiceProxy : IRaceServiceProxy {
public RaceServiceProxy(String endpoint) {
_endpoint = endpoint;
View
1  kcdc12/nancyfx/demo/HamstringFX/model/IRaceServiceProxy.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using HamstringFX.data;
namespace HamstringFX.model {
public interface IRaceServiceProxy {
View
8 kcdc12/nancyfx/demo/HamstringFX/model/MainModelFactory.cs
@@ -1,16 +1,20 @@
using System.Linq;
+using HamstringFX.data;
namespace HamstringFX.model {
public class MainModelFactory : IModelFactory {
- public MainModelFactory(IRaceServiceProxy proxy) {
+ public MainModelFactory(IHamstringData db, IRaceServiceProxy proxy) {
+ _db = db;
_proxy = proxy;
}
+ private readonly IHamstringData _db;
private readonly IRaceServiceProxy _proxy;
public dynamic Create() {
return new {
- UpcomingRaces = _proxy.UpcomingRaces()
+ UpcomingRaces = _proxy.UpcomingRaces(),
+ Announcements = _db.Announcements.OrderByDescending(n => n.ReportedAt).ToList()
};
}
}
View
2  kcdc12/nancyfx/demo/HamstringFX/model/Models.cs
@@ -12,7 +12,7 @@ public sealed class Models {
private readonly IRaceServiceProxy _proxy;
public IModelFactory MainModel () {
- return new MainModelFactory(_proxy);
+ return new MainModelFactory(_db, _proxy);
}
public IModelFactory PortalModel (Member member) {
View
15 kcdc12/nancyfx/demo/HamstringFX/model/RunModel.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace HamstringFX.model {
+ public class RunModel {
+ public DateTime When { get; set; }
+ public Guid Where { get; set; }
+ public Int32 Hour { get; set; }
+ public Int32 Min { get; set; }
+ public Int32 Sec { get; set; }
+
+ public String Time {
+ get { return String.Format("{0}:{1}:{2}", Hour, Min, Sec); }
+ }
+ }
+}
View
13 kcdc12/nancyfx/demo/HamstringFX/modules/MainModule.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using HamstringFX.model;
using HamstringFX.security;
using Nancy;
@@ -8,8 +9,12 @@
namespace HamstringFX.modules {
public class MainModule : NancyModule {
+ private readonly Dictionary<String, dynamic> _cache = new Dictionary<string, dynamic>();
+
public MainModule (IMemberAuthentication auth, Models models) {
+
+
Get["/"] = routeParams => {
var model = models.MainModel().Create();
return View["hamstring.sshtml", model];
@@ -40,6 +45,14 @@ public class MainModule : NancyModule {
};
Get["/logout"] = routeParams => this.LogoutAndRedirect("~/");
+
+ //
+
+ Before += ctx => {
+ return null;
+ };
}
+
+
}
}
View
5 kcdc12/nancyfx/demo/HamstringFX/modules/RunModule.cs
@@ -1,7 +1,9 @@
using System;
using System.Linq;
using HamstringFX.data;
+using HamstringFX.model;
using Nancy;
+using Nancy.ModelBinding;
using Nancy.Security;
namespace HamstringFX.modules {
@@ -19,7 +21,8 @@ public class RunModule : NancyModule {
Post["/run"] = p => {
try {
Guid newId = Guid.NewGuid();
-
+ var runModel = this.Bind<RunModel>();
+
return HttpStatusCode.OK;
} catch (Exception ex) {
View
BIN  kcdc12/nancyfx/demo/HamstringFX/public/img/runner.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
63 kcdc12/nancyfx/demo/HamstringFX/public/scripts/hamstringfx.js
@@ -1,3 +1,5 @@
+//global: postal, $
+
var Hamstring = {};
Hamstring.url = (function (location) {
@@ -28,7 +30,7 @@ Hamstring.ready = function (bodyid) {
for (var i = 0; i < this.modules.length; i++) {
var module = this.modules[i];
if (module.handles(bodyid)) {
- module.init();
+ module.init(postal);
}
}
};
@@ -36,7 +38,7 @@ Hamstring.ready = function (bodyid) {
/*
* Global operations for all pages
*/
-Hamstring.modules.push((function all () {
+Hamstring.modules.push(function all () {
var _init = function () {
$('.pickdate').datepicker();
@@ -48,12 +50,12 @@ Hamstring.modules.push((function all () {
},
init: _init
};
-})());
+}());
/*
* Login
*/
-Hamstring.modules.push((function login () {
+Hamstring.modules.push(function login () {
var setActionParams = function ($form) {
var returnUrl = Hamstring.url.param('returnUrl');
@@ -91,14 +93,22 @@ Hamstring.modules.push((function login () {
},
init: _init
};
-})());
+}());
/*
* Add run
*/
-Hamstring.modules.push((function myhamstring () {
+Hamstring.modules.push(function addRun () {
+
+ var fields = {
+ when: '[name=when]',
+ where: '[name=where]',
+ hour: '[name=hour]',
+ min: '[name=min]',
+ sec: '[name=sec]'
+ };
- var _init = function () {
+ var _init = function (bus) {
var $section = $('#addrun');
var submitForm = function (onSuccess, onError) {
@@ -106,21 +116,35 @@ Hamstring.modules.push((function myhamstring () {
onError = onError || function () {};
var formData = {
- when: $section.find('[name=when]').val(),
- where: $section.find('[name=where]').val(),
- hour: $section.find('[name=hour]').val(),
- min: $section.find('[name=min]').val(),
- sec: $section.find('[name=sec]').val()
+ when: $section.find(fields.when).val(),
+ where: $section.find(fields.where).val(),
+ hour: $section.find(fields.hour).val(),
+ min: $section.find(fields.min).val(),
+ sec: $section.find(fields.sec).val()
};
- $.post('', formData, function () {
+ $.post('/run', formData, function () {
onSuccess();
}).error(function () {
onError();
});
};
+ var resetForm = function () {
+ $section.find(fields.when).val('');
+ $section.find(fields.where)[0].selectedIndex = 0;
+ $section.find(fields.hour).val('0');
+ $section.find(fields.min).val('0');
+ $section.find(fields.sec).val('0');
+ };
+
$section.find('a.submit').click(function (evt) {
+ submitForm(function onSuccess () {
+ bus.publish('run-added', {});
+ resetForm();
+ }, function onError (message) {
+ bus.publish('display-error', message);
+ });
evt.stopPropagation();
evt.preventDefault();
return false;
@@ -133,7 +157,18 @@ Hamstring.modules.push((function myhamstring () {
},
init: _init
};
-})());
+}());
+
+Hamstring.modules.push(function runs () {
+
+ var _init = function (bus) {
+
+ };
+
+ return {
+ init: _init
+ };
+}());
/*
* Document is ready
View
18 kcdc12/nancyfx/demo/HamstringFX/public/scripts/lib/postal.diagnostics.js
@@ -0,0 +1,18 @@
+postal.addWireTap(function(data, envelope) {
+ var all = _.extend(envelope, { data: data });
+ if(!JSON) {
+ throw "This browser or environment does not provide JSON support";
+ }
+ try {
+ console.log(JSON.stringify(all));
+ }
+ catch(exception) {
+ try {
+ all.data = "ERROR: " + exception.message;
+ console.log(JSON.stringify(all));
+ }
+ catch(ex) {
+ console.log("Unable to parse data to JSON: " + exception);
+ }
+ }
+});
View
347 kcdc12/nancyfx/demo/HamstringFX/public/scripts/lib/postal.js
@@ -0,0 +1,347 @@
+(function(global, undefined) {
+/*
+ postal.js
+ Author: Jim Cowart
+ License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license)
+ Version 0.4.4
+*/
+
+var DEFAULT_EXCHANGE = "/",
+ DEFAULT_PRIORITY = 50,
+ DEFAULT_DISPOSEAFTER = 0,
+ SYSTEM_EXCHANGE = "postal",
+ NO_OP = function() { },
+ parsePublishArgs = function(args) {
+ var parsed = { envelope: { } }, env;
+ switch(args.length) {
+ case 3:
+ if(typeof args[1] === "Object" && typeof args[2] === "Object") {
+ parsed.envelope.exchange = DEFAULT_EXCHANGE;
+ parsed.envelope.topic = args[0];
+ parsed.payload = args[1];
+ env = parsed.envelope;
+ parsed.envelope = _.extend(env, args[2]);
+ }
+ else {
+ parsed.envelope.exchange = args[0];
+ parsed.envelope.topic = args[1];
+ parsed.payload = args[2];
+ }
+ break;
+ case 4:
+ parsed.envelope.exchange = args[0];
+ parsed.envelope.topic = args[1];
+ parsed.payload = args[2];
+ env = parsed.envelope;
+ parsed.envelope = _.extend(env, args[3]);
+ break;
+ default:
+ parsed.envelope.exchange = DEFAULT_EXCHANGE;
+ parsed.envelope.topic = args[0];
+ parsed.payload = args[1];
+ break;
+ }
+ return parsed;
+ };
+
+var DistinctPredicate = function() {
+ var previous;
+ return function(data) {
+ var eq = false;
+ if(_.isString(data)) {
+ eq = data === previous;
+ previous = data;
+ }
+ else {
+ eq = _.isEqual(data, previous);
+ previous = _.clone(data);
+ }
+ return !eq;
+ };
+};
+
+var ChannelDefinition = function(exchange, topic) {
+ this.exchange = exchange;
+ this.topic = topic;
+};
+
+ChannelDefinition.prototype = {
+ subscribe: function(callback) {
+ var subscription = new SubscriptionDefinition(this.exchange, this.topic, callback);
+ postal.configuration.bus.subscribe(subscription);
+ return subscription;
+ },
+
+ publish: function(data, envelope) {
+ var env = _.extend({
+ exchange: this.exchange,
+ timeStamp: new Date(),
+ topic: this.topic
+ }, envelope);
+ postal.configuration.bus.publish(data, env);
+ }
+};
+
+var SubscriptionDefinition = function(exchange, topic, callback) {
+ this.exchange = exchange;
+ this.topic = topic;
+ this.callback = callback;
+ this.priority = DEFAULT_PRIORITY;
+ this.constraints = [];
+ this.maxCalls = DEFAULT_DISPOSEAFTER;
+ this.onHandled = NO_OP;
+ this.context = null;
+
+ postal.publish(SYSTEM_EXCHANGE, "subscription.created",
+ {
+ event: "subscription.created",
+ exchange: exchange,
+ topic: topic
+ });
+};
+
+SubscriptionDefinition.prototype = {
+ unsubscribe: function() {
+ postal.configuration.bus.unsubscribe(this);
+ postal.publish(SYSTEM_EXCHANGE, "subscription.removed",
+ {
+ event: "subscription.removed",
+ exchange: this.exchange,
+ topic: this.topic
+ });
+ },
+
+ defer: function() {
+ var fn = this.callback;
+ this.callback = function(data) {
+ setTimeout(fn,0,data);
+ };
+ return this;
+ },
+
+ disposeAfter: function(maxCalls) {
+ if(_.isNaN(maxCalls) || maxCalls <= 0) {
+ throw "The value provided to disposeAfter (maxCalls) must be a number greater than zero.";
+ }
+
+ var fn = this.onHandled;
+ var dispose = _.after(maxCalls, _.bind(function() {
+ this.unsubscribe(this);
+ }, this));
+
+ this.onHandled = function() {
+ fn.apply(this.context, arguments);
+ dispose();
+ };
+ return this;
+ },
+
+ ignoreDuplicates: function() {
+ this.withConstraint(new DistinctPredicate());
+ return this;
+ },
+
+ whenHandledThenExecute: function(callback) {
+ if(! _.isFunction(callback)) {
+ throw "Value provided to 'whenHandledThenExecute' must be a function";
+ }
+ this.onHandled = callback;
+ return this;
+ },
+
+ withConstraint: function(predicate) {
+ if(! _.isFunction(predicate)) {
+ throw "Predicate constraint must be a function";
+ }
+ this.constraints.push(predicate);
+ return this;
+ },
+
+ withConstraints: function(predicates) {
+ var self = this;
+ if(_.isArray(predicates)) {
+ _.each(predicates, function(predicate) { self.withConstraint(predicate); } );
+ }
+ return self;
+ },
+
+ withContext: function(context) {
+ this.context = context;
+ return this;
+ },
+
+ withDebounce: function(milliseconds) {
+ if(_.isNaN(milliseconds)) {
+ throw "Milliseconds must be a number";
+ }
+ var fn = this.callback;
+ this.callback = _.debounce(fn, milliseconds);
+ return this;
+ },
+
+ withDelay: function(milliseconds) {
+ if(_.isNaN(milliseconds)) {
+ throw "Milliseconds must be a number";
+ }
+ var fn = this.callback;
+ this.callback = function(data) {
+ setTimeout(fn, milliseconds, data);
+ };
+ return this;
+ },
+
+ withPriority: function(priority) {
+ if(_.isNaN(priority)) {
+ throw "Priority must be a number";
+ }
+ this.priority = priority;
+ return this;
+ },
+
+ withThrottle: function(milliseconds) {
+ if(_.isNaN(milliseconds)) {
+ throw "Milliseconds must be a number";
+ }
+ var fn = this.callback;
+ this.callback = _.throttle(fn, milliseconds);
+ return this;
+ }
+};
+
+var bindingsResolver = {
+ cache: { },
+
+ compare: function(binding, topic) {
+ if(this.cache[topic] && this.cache[topic][binding]) {
+ return true;
+ }
+ var rgx = new RegExp("^" + this.regexify(binding) + "$"), // match from start to end of string
+ result = rgx.test(topic);
+ if(result) {
+ if(!this.cache[topic]) {
+ this.cache[topic] = {};
+ }
+ this.cache[topic][binding] = true;
+ }
+ return result;
+ },
+
+ regexify: function(binding) {
+ return binding.replace(/\./g,"\\.") // escape actual periods
+ .replace(/\*/g, ".*") // asterisks match any value
+ .replace(/#/g, "[A-Z,a-z,0-9]*"); // hash matches any alpha-numeric 'word'
+ }
+};
+
+var localBus = {
+
+ subscriptions: {},
+
+ wireTaps: [],
+
+ publish: function(data, envelope) {
+ this.notifyTaps(data, envelope);
+
+ _.each(this.subscriptions[envelope.exchange], function(topic) {
+ _.each(topic, function(binding){
+ if(postal.configuration.resolver.compare(binding.topic, envelope.topic)) {
+ if(_.all(binding.constraints, function(constraint) { return constraint(data); })) {
+ if(typeof binding.callback === 'function') {
+ binding.callback.apply(binding.context, [data, envelope]);
+ binding.onHandled();
+ }
+ }
+ }
+ });
+ });
+ },
+
+ subscribe: function(subDef) {
+ var idx, found, fn;
+
+ if(!this.subscriptions[subDef.exchange]) {
+ this.subscriptions[subDef.exchange] = {};
+ }
+ if(!this.subscriptions[subDef.exchange][subDef.topic]) {
+ this.subscriptions[subDef.exchange][subDef.topic] = [];
+ }
+
+ idx = this.subscriptions[subDef.exchange][subDef.topic].length - 1;
+ if(!_.any(this.subscriptions[subDef.exchange][subDef.topic], function(cfg) { return cfg === subDef; })) {
+ for(; idx >= 0; idx--) {
+ if(this.subscriptions[subDef.exchange][subDef.topic][idx].priority <= subDef.priority) {
+ this.subscriptions[subDef.exchange][subDef.topic].splice(idx + 1, 0, subDef);
+ found = true;
+ break;
+ }
+ }
+ if(!found) {
+ this.subscriptions[subDef.exchange][subDef.topic].unshift(subDef);
+ }
+ }
+
+ return _.bind(function() { this.unsubscribe(subDef); }, this);
+ },
+
+ notifyTaps: function(data, envelope) {
+ _.each(this.wireTaps,function(tap) {
+ tap(data, envelope);
+ });
+ },
+
+ unsubscribe: function(config) {
+ if(this.subscriptions[config.exchange][config.topic]) {
+ var len = this.subscriptions[config.exchange][config.topic].length,
+ idx = 0;
+ for ( ; idx < len; idx++ ) {
+ if (this.subscriptions[config.exchange][config.topic][idx] === config) {
+ this.subscriptions[config.exchange][config.topic].splice( idx, 1 );
+ break;
+ }
+ }
+ }
+ },
+
+ addWireTap: function(callback) {
+ this.wireTaps.push(callback);
+ return function() {
+ var idx = this.wireTaps.indexOf(callback);
+ if(idx !== -1) {
+ this.wireTaps.splice(idx,1);
+ }
+ };
+ }
+};
+
+var postal = {
+ configuration: {
+ bus: localBus,
+ resolver: bindingsResolver
+ },
+
+ channel: function(exchange, topic) {
+ var exch = arguments.length === 2 ? exchange : DEFAULT_EXCHANGE,
+ tpc = arguments.length === 2 ? topic : exchange;
+ return new ChannelDefinition(exch, tpc);
+ },
+
+ subscribe: function(exchange, topic, callback) {
+ var exch = arguments.length === 3 ? exchange : DEFAULT_EXCHANGE,
+ tpc = arguments.length === 3 ? topic : exchange,
+ callbk = arguments.length === 3 ? callback : topic;
+ var channel = this.channel(exch, tpc);
+ return channel.subscribe(callbk);
+ },
+
+ publish: function(exchange, topic, payload, envelopeOptions) {
+ var parsedArgs = parsePublishArgs([].slice.call(arguments,0));
+ var channel = this.channel(parsedArgs.envelope.exchange, parsedArgs.envelope.topic);
+ channel.publish(parsedArgs.payload, parsedArgs.envelope);
+ },
+
+ addWireTap: function(callback) {
+ return this.configuration.bus.addWireTap(callback);
+ }
+};
+
+global.postal = postal; })(window);
View
16 kcdc12/nancyfx/demo/HamstringFX/public/styles/hamstringfx.css
@@ -97,6 +97,11 @@ header h1 {
font-weight:bold;
}
+header img {
+ float:left;
+ padding-right:2em;
+}
+
#content {
width:100%;
padding-top:2%;
@@ -115,6 +120,10 @@ header h1 {
#quickactions {
width:30%;
float:left;
+ /*background-color:#fff;*/
+ padding:1em;
+ border-radius:0.5em;
+ box-shadow:0px 0px 5px #ccc;
}
#contentfocus {
@@ -125,7 +134,6 @@ header h1 {
footer {
clear:both;
text-align:center;
- font-size:0.6em;
padding-top:2em;
}
@@ -140,17 +148,17 @@ footer {
text-shadow:1px 1px 3px #ccc;
}
-#contentfocus #anouncements dl {
+#contentfocus #announcements dl {
margin:0;
padding:0;
}
-#contentfocus #anouncements dl dt {
+#contentfocus #announcements dl dt {
font-weight:bold;
margin:1em 0;
}
-#contentfocus #anouncements dl dd {
+#contentfocus #announcements dl dd {
padding-left:2%;
}
View
2  kcdc12/nancyfx/demo/HamstringFX/views/_addrun.sshtml
@@ -1,5 +1,5 @@
<section id="addrun">
- <form method="POST" action="">
+ <form>
<fieldset>
<div>
<label>When?</label>
View
12 kcdc12/nancyfx/demo/HamstringFX/views/_announcements.sshtml
@@ -1,11 +1,9 @@
-<article id="anouncements">
+<article id="announcements">
<h1>Announcements</h1>
<dl>
- <dt>Thursday, 4/5/2012</dt>
- <dd>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in metus nisi, id luctus dolor.</dd>
- <dt>Monday, 3/26/2012</dt>
- <dd>Praesent vulputate odio nisl, eu fermentum sapien.</dd>
- <dt>Friday, 3/16/2012</dt>
- <dd>Nullam et turpis eu mi interdum tincidunt. Integer in leo at mi commodo pulvinar. Integer ut sem sit amet quam luctus lacinia. Praesent est orci, ultrices et ornare a, fermentum non dolor.</dd>
+ @Each.Announcements
+ <dt>@Current.FormattedDate</dt>
+ <dd>@Current.Content</dd>
+ @EndEach
</dl>
</article>
View
2  kcdc12/nancyfx/demo/HamstringFX/views/_races.sshtml
@@ -3,7 +3,7 @@
<dl>
@Each.UpcomingRaces
<dt><a href="@Current.URL" target="_blank">@Current.Name</a></dt>
- <dd>@Current.Location</dd>
+ <dd>@Current.Location<br />@Current.FormattedDate</dd>
@EndEach
</dl>
</section>
View
2  kcdc12/nancyfx/demo/HamstringFX/views/hamstring.sshtml
@@ -11,6 +11,6 @@
@Section['contentfocus']
<h1>Welcome to HamstringFX</h1>
- @Partial['_announcements']
+ @Partial['_announcements', Model]
@EndSection
View
8 kcdc12/nancyfx/demo/HamstringFX/views/master.sshtml
@@ -9,6 +9,7 @@
</head>
<body id="@Section['bodyid']">
<header class="shiny">
+ <img src="/img/runner.png" alt="HamstringFX" />
<h1>HamstringFX</h1>
</header>
@@ -29,12 +30,9 @@
<script type="text/javascript" src="/scripts/lib/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="/scripts/lib/jquery-ui-1.8.18.custom.min.js"></script>
+ <script type="text/javascript" src="/scripts/lib/postal.diagnostics.js"></script>
+ <script type="text/javascript" src="/scripts/lib/postal.js"></script>
<script type="text/javascript" src="/scripts/hamstringfx.js"></script>
- <script type="text/javascript">
- $().ready(function () {
- $('.pickdate').datepicker();
- });
- </script>
@Section['scripts']
</body>
</html>
View
BIN  kcdc12/nancyfx/demo/gfx/runner-silhouette-transp.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
10 kcdc12/nancyfx/demo/schema.sql
@@ -79,7 +79,7 @@ if object_id('News') > 0
drop table News;
go
-create table News (
+create table Announcements (
Id uniqueidentifier not null primary key nonclustered,
ReportedAt datetime not null default getdate(),
Content nvarchar(max) not null default ''
@@ -118,4 +118,12 @@ insert into Playlists (Id, MemberId, Name, SongCount, Duration, [Image]) values
('CD4B070E-E0FC-46CA-9FF0-41111DD85F8B', '71ED18D9-DE5D-4DC5-9DCF-E9F143605E15', 'ours is the fury', 20, '1:14:33', 'playlist3.png'),
('69DC1930-FC3E-429F-B34C-BCBC16F7895D', '71ED18D9-DE5D-4DC5-9DCF-E9F143605E15', 'WAT', 45, '2:47:44', 'playlist4.png');
go
+
+insert into Announcements (Id, ReportedAt, Content) values
+ ('FCB89EB6-C972-480A-A506-1A9DEC726EFD', '2012-04-08', 'New members will be introduced at upcoming TriAth meeting on the 15th. If you haven''t joined but want to, please make sure you contact Gayle at g.bridges@u2fast.com.'),
+ ('757D5753-03B9-43CC-8B91-0B7C4824EC45', '2012-04-02', 'Due to the overwhelming positive response we have received from members who are interested in a custom HamstringFX podcast, we are looking to recruit a few members every month who would like to participate on an interview panel. We will be discussing topics important to runners, such as stretching, proper nutrition, customized routines, good running locations, etc. Doug will be recruiting at our next meeting!'),
+ ('62AAAB60-908A-41AC-B3DE-5A409F2BDD46', '2012-03-22', 'The STL Road Rage crew has a few exta slots open for their weekly biking excursion next week. If you want a break from running and would like to join up, contact Walt at 555-1212. Their website is http://stlroadrage.com if you would like more information.'),
+ ('90103E6E-E15C-4F01-9665-0480BC128688', '2012-03-22', 'For Paleo enthusiasts, an open forum on Paleo nutrition will be conducted on July 12 at WashU. This is a great opportunity to educate students on the benefits of Paleo!'),
+ ('5231ACCB-0C07-49B0-A2A4-049CAD3CE110', '2012-02-10', 'We have recieved a generous donation from the Fit and Fun Foundation that will allow us to reduce member fees this year by $15! This is a great opportunity to reach out to people in our community who might be thinking of joining -- friends and family for sure -- and convince them to join! Our new fee for 2012 is now $35 per person, per year.');
+go
Please sign in to comment.
Something went wrong with that request. Please try again.