Permalink
Browse files

Added hub events support to JavaScript client:

- API mimics the .NET client hub API (createProxy, on, invoke, etc.)
- Update MouseMove sample to use hub events
  • Loading branch information...
1 parent f6aa43b commit 97c984754f20bd6dda8c343983d679b8f65093c8 @DamianEdwards DamianEdwards committed Jul 4, 2012
@@ -59,6 +59,7 @@
<Reference Include="System.EnterpriseServices" />
</ItemGroup>
<ItemGroup>
+ <Content Include="jquery.signalR.hubs.js" />
<Content Include="jquery.signalR.transports.common.js" />
<Content Include="jquery.signalR.transports.webSockets.js" />
<Content Include="jquery.signalR.transports.serverSentEvents.js" />
@@ -5,7 +5,8 @@ $files =
"jquery.signalR.transports.webSockets.js",
"jquery.signalR.transports.serverSentEvents.js",
"jquery.signalR.transports.foreverFrame.js",
- "jquery.signalR.transports.longPolling.js"
+ "jquery.signalR.transports.longPolling.js",
+ "jquery.signalR.hubs.js"
# Run JSHint against files
Write-Host "Running JSHint..." -ForegroundColor Yellow
@@ -0,0 +1,178 @@
+/*global window:false */
+/// <reference path="jquery.signalR.core.js" />
+
+(function ($, window) {
+ "use strict";
+
+ // we use a global id for tracking callbacks so the server doesn't have to send extra info like hub name
+ var callbackId = 0,
+ callbacks = {};
+
+ // Array.prototype.map
+ if (!Array.prototype.hasOwnProperty("map")) {
+ Array.prototype.map = function (fun, thisp) {
+ var arr = this,
+ i,
+ length = arr.length,
+ result = [];
+ for (i = 0; i < length; i += 1) {
+ if (arr.hasOwnProperty(i)) {
+ result[i] = fun.call(thisp, arr[i], i, arr);
+ }
+ }
+ return result;
+ };
+ }
+
+ function getArgValue(a) {
+ return $.isFunction(a) ? null : ($.type(a) === "undefined" ? null : a);
+ }
+
+ // hubProxy
+ function hubProxy(hubConnection, hubName) {
+ /// <summary>
+ /// Creates a new proxy object for the given hub connection that can be used to invoke
+ /// methods on server hubs and handle client method invocation requests from the server.
+ /// </summary>
+ return new hubProxy.fn.init(hubConnection, hubName);
+ }
+
+ hubProxy.fn = hubProxy.prototype = {
+ init: function (connection, hubName) {
+ this.state = {};
+ this.connection = connection;
+ this.hubName = hubName;
+ },
+
+ on: function (eventName, callback) {
+ /// <summary>Wires up a callback to be invoked when a invocation request is received from the server hub.</summary>
+ /// <param name="eventName" type="String">The name of the hub event to register the callback for.</param>
+ /// <param name="callback" type="Function">The callback to be invoked.</param>
+ var self = this;
+ $(self).bind(eventName, function (e, data) {
+ callback.apply(self, data);
+ });
+ return self;
+ },
+
+ invoke: function (methodName) {
+ /// <summary>Invokes a server hub method with the given arguments.</summary>
+ /// <param name="methodName" type="String">The name of the server hub method.</param>
+
+ var self = this,
+ args = $.makeArray(arguments).slice(1),
+ userCallback = args[args.length - 1], // last argument
+ methodArgs = $.type(userCallback) === "function" ? args.slice(0, -1) /* all but last */ : args,
+ argValues = methodArgs.map(getArgValue),
+ data = { hub: self.hubName, method: methodName, args: argValues, state: self.state, id: callbackId },
+ d = $.Deferred(),
+ callback = function (result) {
+ $.extend(this.state, result.State);
+
+ if (result.Error) {
+ // Server hub method threw an exception, log it & reject the deferred
+ if (result.StackTrace) {
+ self.connection.log(result.Error + "\n" + result.StackTrace);
+ }
+ d.rejectWith(self, [result.Error]);
+ } else {
+ // Server invocation succeeded, invoke any user callback & resolve the deferred
+ if ($.type(userCallback) === "function") {
+ userCallback.call(self, result.Result);
+ }
+ d.resolveWith(self, [result.Result]);
+ }
+ };
+
+ callbacks[callbackId.toString()] = { scope: self, method: callback };
+ callbackId += 1;
+ self.connection.send(window.JSON.stringify(data));
+
+ return d.promise();
+ }
+ };
+
+ hubProxy.fn.init.prototype = hubProxy.fn;
+
+
+ // hubConnection
+ function hubConnection(url) {
+ /// <summary>Creates a new hub connection.</summary>
+ /// <param name="url" type="String">[Optional] The hub route url, defaults to "/signalr"</param>
+ if (!url) {
+ url = "/signalr";
+ }
+ return new hubConnection.fn.init(url);
+ }
+
+ hubConnection.fn = hubConnection.prototype = $.connection();
+
+ hubConnection.fn.init = function (url, qs, logging) {
+ var connection = this;
+
+ $.signalR.fn.init.call(connection, url, qs, logging);
+
+ // Object to store hub proxies for this connection
+ connection.proxies = {};
+
+ // Wire up the sending handler
+ connection.sending(function () {
+ var clientHubs = [];
+
+ $.each(this.proxies, function (key) {
+ clientHubs.push({ name: key });
+ });
+
+ this.data = window.JSON.stringify(clientHubs);
+ });
+
+ // Wire up the received handler
+ connection.received(function (data) {
+ var proxy, dataCallbackId, callback;
+ if (!data) {
+ return;
+ }
+
+ if (typeof(data.Id) !== "undefined") {
+ // We received the return value from a server method invocation, look up callback by id and call it
+ dataCallbackId = data.Id.toString();
+ callback = callbacks[dataCallbackId];
+ if (callback) {
+ // Delete the callback from the proxy
+ callbacks[dataCallbackId] = null;
+ delete callbacks[dataCallbackId];
+
+ // Invoke the callback
+ callback.method.call(callback.scope, data);
+ }
+ } else {
+ // We received a client invocation request, i.e. broadcast from server hub
+ // Trigger the local invocation event
+ proxy = this.proxies[data.Hub];
+ $.extend(proxy.state, data.State);
+ $(proxy).trigger(data.Method, [data.Args]);
+ }
+ });
+ };
+
+ hubConnection.fn.createProxy = function (hubName) {
+ /// <summary>
+ /// Creates a new proxy object for the given hub connection that can be used to invoke
+ /// methods on server hubs and handle client method invocation requests from the server.
+ /// </summary>
+ /// <paramater name="hubName" type="String">
+ /// The name of the hub on the server to create the proxy for.
+ /// </parameter>
+ var proxy = this.proxies[hubName];
+ if (!proxy) {
+ proxy = hubProxy(this, hubName);
+ this.proxies[hubName] = proxy;
+ }
+ return proxy;
+ };
+
+ hubConnection.fn.init.prototype = hubConnection.fn;
+
+ $.hubConnection = hubConnection;
+
+}(window.jQuery, window));
@@ -1,13 +1,18 @@
-$(function () {
+/// <reference path="../../Scripts/jquery-1.6.2.js" />
+/// <reference path="../../Scripts/jquery.signalR.js" />
+
+$(function () {
// Pure client side hub
- var signalR = $.connection;
- signalR.mouseTracking.moveMouse = function (id, x, y) {
- if (id == this.id) {
+ var hubConnection = $.hubConnection(),
+ hub = hubConnection.createProxy('MouseTracking');
+
+ hub.on('moveMouse', function (id, x, y) {
+ if (id == this.state.id) {
return;
}
updateCursor(id, x, y);
- };
+ });
function updateCursor(id, x, y) {
var e = document.getElementById(id);
@@ -22,14 +27,14 @@
e.css('top', y);
}
-
- signalR.hub.start({ transport: activeTransport }, function () {
- signalR.mouseTracking.join(function () {
-
+ hubConnection.start({ transport: activeTransport })
+ .done(function () {
+ return hub.invoke('Join');
+ })
+ .done(function () {
$(document).mousemove(function (e) {
- signalR.mouseTracking.move(e.pageX, e.pageY);
- updateCursor(signalR.mouseTracking.id, e.pageX, e.pageY);
+ hub.invoke('Move', e.pageX, e.pageY);
+ updateCursor(hub.state.id, e.pageX, e.pageY);
});
});
- });
});
@@ -8,7 +8,7 @@
<script src="../../Scripts/jquery-1.6.2.min.js" type="text/javascript"></script>
<script src="../../Scripts/json2.min.js" type="text/javascript"></script>
<script src="../../Scripts/jquery.signalR.js" type="text/javascript"></script>
- <script src="../../signalr/hubs" type="text/javascript"></script>
+ <!--<script src="../../signalr/hubs" type="text/javascript"></script>-->
<script src="MouseTracking.js" type="text/javascript"></script>
</head>
<body>
@@ -144,7 +144,7 @@
callbacks[callbackId.toString()] = { scope: hub, callback: cb };
callbackId += 1;
hub._.connection().send(window.JSON.stringify(data));
- return d;
+ return d.promise();
}
// Create hub signalR instance
@@ -171,7 +171,7 @@
demo: {
_: {
hubName: 'demo',
- ignoreMembers: ['addToGroups', 'complexArray', 'complexType', 'doSomethingAndCallError', 'dynamicTask', 'genericTaskTypedAsPlain', 'genericTaskWithException', 'getValue', 'multipleCalls', 'overload', 'passingDynamicComplex', 'plainTask', 'readStateValue', 'setStateValue', 'simpleArray', 'taskWithException', 'unsupportedOverload', 'namespace', 'ignoreMembers', 'callbacks'],
+ ignoreMembers: ['addToGroups', 'complexArray', 'complexType', 'doSomethingAndCallError', 'dynamicInvoke', 'dynamicTask', 'genericTaskTypedAsPlain', 'genericTaskWithException', 'getValue', 'multipleCalls', 'overload', 'passingDynamicComplex', 'plainTask', 'readStateValue', 'setStateValue', 'simpleArray', 'taskWithException', 'testGuid', 'unsupportedOverload', 'namespace', 'ignoreMembers', 'callbacks'],
connection: function () { return signalR.hub; }
},
@@ -241,6 +241,14 @@
unsupportedOverload: function (x, callback) {
return serverCall(this, "UnsupportedOverload", $.makeArray(arguments));
+ },
+
+ testGuid: function (callback) {
+ return serverCall(this, "TestGuid", $.makeArray(arguments));
+ },
+
+ dynamicInvoke: function (method, callback) {
+ return serverCall(this, "DynamicInvoke", $.makeArray(arguments));
}
},
drawingPad: {
Oops, something went wrong. Retry.

0 comments on commit 97c9847

Please sign in to comment.