Skip to content
This repository
Browse code

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...
commit 97c984754f20bd6dda8c343983d679b8f65093c8 1 parent f6aa43b
Damian Edwards authored
1  SignalR.Client.JS/SignalR.Client.JS.csproj
@@ -59,6 +59,7 @@
59 59
     <Reference Include="System.EnterpriseServices" />
60 60
   </ItemGroup>
61 61
   <ItemGroup>
  62
+    <Content Include="jquery.signalR.hubs.js" />
62 63
     <Content Include="jquery.signalR.transports.common.js" />
63 64
     <Content Include="jquery.signalR.transports.webSockets.js" />
64 65
     <Content Include="jquery.signalR.transports.serverSentEvents.js" />
3  SignalR.Client.JS/build.ps1
@@ -5,7 +5,8 @@ $files =
5 5
     "jquery.signalR.transports.webSockets.js",
6 6
     "jquery.signalR.transports.serverSentEvents.js",
7 7
     "jquery.signalR.transports.foreverFrame.js",
8  
-    "jquery.signalR.transports.longPolling.js"
  8
+    "jquery.signalR.transports.longPolling.js",
  9
+	"jquery.signalR.hubs.js"
9 10
 
10 11
 # Run JSHint against files
11 12
 Write-Host "Running JSHint..." -ForegroundColor Yellow
178  SignalR.Client.JS/jquery.signalR.hubs.js
... ...
@@ -0,0 +1,178 @@
  1
+/*global window:false */
  2
+/// <reference path="jquery.signalR.core.js" />
  3
+
  4
+(function ($, window) {
  5
+    "use strict";
  6
+    
  7
+    // we use a global id for tracking callbacks so the server doesn't have to send extra info like hub name
  8
+    var callbackId = 0,
  9
+        callbacks = {};
  10
+
  11
+    // Array.prototype.map
  12
+    if (!Array.prototype.hasOwnProperty("map")) {
  13
+        Array.prototype.map = function (fun, thisp) {
  14
+            var arr = this,
  15
+                i,
  16
+                length = arr.length,
  17
+                result = [];
  18
+            for (i = 0; i < length; i += 1) {
  19
+                if (arr.hasOwnProperty(i)) {
  20
+                    result[i] = fun.call(thisp, arr[i], i, arr);
  21
+                }
  22
+            }
  23
+            return result;
  24
+        };
  25
+    }
  26
+
  27
+    function getArgValue(a) {
  28
+        return $.isFunction(a) ? null : ($.type(a) === "undefined" ? null : a);
  29
+    }
  30
+
  31
+    // hubProxy
  32
+    function hubProxy(hubConnection, hubName) {
  33
+        /// <summary>
  34
+        ///     Creates a new proxy object for the given hub connection that can be used to invoke
  35
+        ///     methods on server hubs and handle client method invocation requests from the server.
  36
+        /// </summary>
  37
+        return new hubProxy.fn.init(hubConnection, hubName);
  38
+    }
  39
+
  40
+    hubProxy.fn = hubProxy.prototype = {
  41
+        init: function (connection, hubName) {
  42
+            this.state = {};
  43
+            this.connection = connection;
  44
+            this.hubName = hubName;
  45
+        },
  46
+
  47
+        on: function (eventName, callback) {
  48
+            /// <summary>Wires up a callback to be invoked when a invocation request is received from the server hub.</summary>
  49
+            /// <param name="eventName" type="String">The name of the hub event to register the callback for.</param>
  50
+            /// <param name="callback" type="Function">The callback to be invoked.</param>
  51
+            var self = this;
  52
+            $(self).bind(eventName, function (e, data) {
  53
+                callback.apply(self, data);
  54
+            });
  55
+            return self;
  56
+        },
  57
+
  58
+        invoke: function (methodName) {
  59
+            /// <summary>Invokes a server hub method with the given arguments.</summary>
  60
+            /// <param name="methodName" type="String">The name of the server hub method.</param>
  61
+            
  62
+            var self = this,
  63
+                args = $.makeArray(arguments).slice(1),
  64
+                userCallback = args[args.length - 1], // last argument
  65
+                methodArgs = $.type(userCallback) === "function" ? args.slice(0, -1) /* all but last */ : args,
  66
+                argValues = methodArgs.map(getArgValue),
  67
+                data = { hub: self.hubName, method: methodName, args: argValues, state: self.state, id: callbackId },
  68
+                d = $.Deferred(),
  69
+                callback = function (result) {
  70
+                    $.extend(this.state, result.State);
  71
+
  72
+                    if (result.Error) {
  73
+                        // Server hub method threw an exception, log it & reject the deferred
  74
+                        if (result.StackTrace) {
  75
+                            self.connection.log(result.Error + "\n" + result.StackTrace);
  76
+                        }
  77
+                        d.rejectWith(self, [result.Error]);
  78
+                    } else {
  79
+                        // Server invocation succeeded, invoke any user callback & resolve the deferred
  80
+                        if ($.type(userCallback) === "function") {
  81
+                            userCallback.call(self, result.Result);
  82
+                        }
  83
+                        d.resolveWith(self, [result.Result]);
  84
+                    }
  85
+                };
  86
+
  87
+            callbacks[callbackId.toString()] = { scope: self, method: callback };
  88
+            callbackId += 1;
  89
+            self.connection.send(window.JSON.stringify(data));
  90
+
  91
+            return d.promise();
  92
+        }
  93
+    };
  94
+
  95
+    hubProxy.fn.init.prototype = hubProxy.fn;
  96
+
  97
+
  98
+    // hubConnection
  99
+    function hubConnection(url) {
  100
+        /// <summary>Creates a new hub connection.</summary>
  101
+        /// <param name="url" type="String">[Optional] The hub route url, defaults to "/signalr"</param>
  102
+        if (!url) {
  103
+            url = "/signalr";
  104
+        }
  105
+        return new hubConnection.fn.init(url);
  106
+    }
  107
+
  108
+    hubConnection.fn = hubConnection.prototype = $.connection();
  109
+
  110
+    hubConnection.fn.init = function (url, qs, logging) {
  111
+        var connection = this;
  112
+
  113
+        $.signalR.fn.init.call(connection, url, qs, logging);
  114
+
  115
+        // Object to store hub proxies for this connection
  116
+        connection.proxies = {};
  117
+
  118
+        // Wire up the sending handler
  119
+        connection.sending(function () {
  120
+            var clientHubs = [];
  121
+
  122
+            $.each(this.proxies, function (key) {
  123
+                clientHubs.push({ name: key });
  124
+            });
  125
+
  126
+            this.data = window.JSON.stringify(clientHubs);
  127
+        });
  128
+
  129
+        // Wire up the received handler
  130
+        connection.received(function (data) {
  131
+            var proxy, dataCallbackId, callback;
  132
+            if (!data) {
  133
+                return;
  134
+            }
  135
+
  136
+            if (typeof(data.Id) !== "undefined") {
  137
+                // We received the return value from a server method invocation, look up callback by id and call it
  138
+                dataCallbackId = data.Id.toString();
  139
+                callback = callbacks[dataCallbackId];
  140
+                if (callback) {
  141
+                    // Delete the callback from the proxy
  142
+                    callbacks[dataCallbackId] = null;
  143
+                    delete callbacks[dataCallbackId];
  144
+
  145
+                    // Invoke the callback
  146
+                    callback.method.call(callback.scope, data);
  147
+                }
  148
+            } else {
  149
+                // We received a client invocation request, i.e. broadcast from server hub
  150
+                // Trigger the local invocation event
  151
+                proxy = this.proxies[data.Hub];
  152
+                $.extend(proxy.state, data.State);
  153
+                $(proxy).trigger(data.Method, [data.Args]);
  154
+            }
  155
+        });
  156
+    };
  157
+
  158
+    hubConnection.fn.createProxy = function (hubName) {
  159
+        /// <summary>
  160
+        ///     Creates a new proxy object for the given hub connection that can be used to invoke
  161
+        ///     methods on server hubs and handle client method invocation requests from the server.
  162
+        /// </summary>
  163
+        /// <paramater name="hubName" type="String">
  164
+        ///     The name of the hub on the server to create the proxy for.
  165
+        /// </parameter>
  166
+        var proxy = this.proxies[hubName];
  167
+        if (!proxy) {
  168
+            proxy = hubProxy(this, hubName);
  169
+            this.proxies[hubName] = proxy;
  170
+        }
  171
+        return proxy;
  172
+    };
  173
+    
  174
+    hubConnection.fn.init.prototype = hubConnection.fn;
  175
+
  176
+    $.hubConnection = hubConnection;
  177
+
  178
+}(window.jQuery, window));
29  samples/SignalR.Hosting.AspNet.Samples/Hubs/MouseTracking/MouseTracking.js
... ...
@@ -1,13 +1,18 @@
1  
-$(function () {
  1
+/// <reference path="../../Scripts/jquery-1.6.2.js" />
  2
+/// <reference path="../../Scripts/jquery.signalR.js" />
  3
+
  4
+$(function () {
2 5
     // Pure client side hub
3  
-    var signalR = $.connection;
4  
-    signalR.mouseTracking.moveMouse = function (id, x, y) {
5  
-        if (id == this.id) {
  6
+    var hubConnection = $.hubConnection(),
  7
+        hub = hubConnection.createProxy('MouseTracking');
  8
+
  9
+    hub.on('moveMouse', function (id, x, y) {
  10
+        if (id == this.state.id) {
6 11
             return;
7 12
         }
8 13
 
9 14
         updateCursor(id, x, y);
10  
-    };
  15
+    });
11 16
 
12 17
     function updateCursor(id, x, y) {
13 18
         var e = document.getElementById(id);
@@ -22,14 +27,14 @@
22 27
         e.css('top', y);
23 28
     }
24 29
 
25  
-
26  
-    signalR.hub.start({ transport: activeTransport }, function () {
27  
-        signalR.mouseTracking.join(function () {
28  
-
  30
+    hubConnection.start({ transport: activeTransport })
  31
+        .done(function () {
  32
+            return hub.invoke('Join');
  33
+        })
  34
+        .done(function () {
29 35
             $(document).mousemove(function (e) {
30  
-                signalR.mouseTracking.move(e.pageX, e.pageY);
31  
-                updateCursor(signalR.mouseTracking.id, e.pageX, e.pageY);
  36
+                hub.invoke('Move', e.pageX, e.pageY);
  37
+                updateCursor(hub.state.id, e.pageX, e.pageY);
32 38
             });
33 39
         });
34  
-    });
35 40
 });
2  samples/SignalR.Hosting.AspNet.Samples/Hubs/MouseTracking/index.htm
@@ -8,7 +8,7 @@
8 8
     <script src="../../Scripts/jquery-1.6.2.min.js" type="text/javascript"></script>
9 9
     <script src="../../Scripts/json2.min.js" type="text/javascript"></script>
10 10
     <script src="../../Scripts/jquery.signalR.js" type="text/javascript"></script>
11  
-    <script src="../../signalr/hubs" type="text/javascript"></script>
  11
+    <!--<script src="../../signalr/hubs" type="text/javascript"></script>-->
12 12
     <script src="MouseTracking.js" type="text/javascript"></script>
13 13
 </head>
14 14
 <body>
12  samples/SignalR.Hosting.AspNet.Samples/Scripts/hubs.js
@@ -144,7 +144,7 @@
144 144
         callbacks[callbackId.toString()] = { scope: hub, callback: cb };
145 145
         callbackId += 1;
146 146
         hub._.connection().send(window.JSON.stringify(data));
147  
-        return d;
  147
+        return d.promise();
148 148
     }
149 149
 
150 150
     // Create hub signalR instance
@@ -171,7 +171,7 @@
171 171
         demo: {
172 172
             _: {
173 173
                 hubName: 'demo',
174  
-                ignoreMembers: ['addToGroups', 'complexArray', 'complexType', 'doSomethingAndCallError', 'dynamicTask', 'genericTaskTypedAsPlain', 'genericTaskWithException', 'getValue', 'multipleCalls', 'overload', 'passingDynamicComplex', 'plainTask', 'readStateValue', 'setStateValue', 'simpleArray', 'taskWithException', 'unsupportedOverload', 'namespace', 'ignoreMembers', 'callbacks'],
  174
+                ignoreMembers: ['addToGroups', 'complexArray', 'complexType', 'doSomethingAndCallError', 'dynamicInvoke', 'dynamicTask', 'genericTaskTypedAsPlain', 'genericTaskWithException', 'getValue', 'multipleCalls', 'overload', 'passingDynamicComplex', 'plainTask', 'readStateValue', 'setStateValue', 'simpleArray', 'taskWithException', 'testGuid', 'unsupportedOverload', 'namespace', 'ignoreMembers', 'callbacks'],
175 175
                 connection: function () { return signalR.hub; }
176 176
             },
177 177
 
@@ -241,6 +241,14 @@
241 241
 
242 242
             unsupportedOverload: function (x, callback) {
243 243
                 return serverCall(this, "UnsupportedOverload", $.makeArray(arguments));
  244
+            },
  245
+
  246
+            testGuid: function (callback) {
  247
+                return serverCall(this, "TestGuid", $.makeArray(arguments));
  248
+            },
  249
+
  250
+            dynamicInvoke: function (method, callback) {
  251
+                return serverCall(this, "DynamicInvoke", $.makeArray(arguments));
244 252
             }
245 253
         },
246 254
         drawingPad: {
184  samples/SignalR.Hosting.AspNet.Samples/Scripts/jquery.signalR.js
@@ -303,9 +303,8 @@
303 303
                                     transports.push($.type(transport) === "string" ? "" + transport : transport);
304 304
                                 }
305 305
                             });
306  
-                        } else if ($.type(config.transport) === "object" ||
307  
-                                       $.inArray(config.transport, supportedTransports) >= 0) {
308  
-                                // specific transport provided, as object or a named transport, e.g. "longPolling"
  306
+                        } else if ($.type(config.transport) === "object" || $.inArray(config.transport, supportedTransports) >= 0) {
  307
+                            // specific transport provided, as object or a named transport, e.g. "longPolling"
309 308
                             transports.push(config.transport);
310 309
                         } else { // default "auto"
311 310
                             transports = supportedTransports;
@@ -1284,3 +1283,182 @@
1284 1283
     };
1285 1284
 
1286 1285
 }(window.jQuery, window));
  1286
+/* jquery.signalR.hubs.js */
  1287
+/*global window:false */
  1288
+/// <reference path="jquery.signalR.core.js" />
  1289
+
  1290
+(function ($, window) {
  1291
+    "use strict";
  1292
+    
  1293
+    // we use a global id for tracking callbacks so the server doesn't have to send extra info like hub name
  1294
+    var callbackId = 0,
  1295
+        callbacks = {};
  1296
+
  1297
+    // Array.prototype.map
  1298
+    if (!Array.prototype.hasOwnProperty("map")) {
  1299
+        Array.prototype.map = function (fun, thisp) {
  1300
+            var arr = this,
  1301
+                i,
  1302
+                length = arr.length,
  1303
+                result = [];
  1304
+            for (i = 0; i < length; i += 1) {
  1305
+                if (arr.hasOwnProperty(i)) {
  1306
+                    result[i] = fun.call(thisp, arr[i], i, arr);
  1307
+                }
  1308
+            }
  1309
+            return result;
  1310
+        };
  1311
+    }
  1312
+
  1313
+    function getArgValue(a) {
  1314
+        return $.isFunction(a) ? null : ($.type(a) === "undefined" ? null : a);
  1315
+    }
  1316
+
  1317
+    // hubProxy
  1318
+    function hubProxy(hubConnection, hubName) {
  1319
+        /// <summary>
  1320
+        ///     Creates a new proxy object for the given hub connection that can be used to invoke
  1321
+        ///     methods on server hubs and handle client method invocation requests from the server.
  1322
+        /// </summary>
  1323
+        return new hubProxy.fn.init(hubConnection, hubName);
  1324
+    }
  1325
+
  1326
+    hubProxy.fn = hubProxy.prototype = {
  1327
+        init: function (connection, hubName) {
  1328
+            this.state = {};
  1329
+            this.connection = connection;
  1330
+            this.hubName = hubName;
  1331
+        },
  1332
+
  1333
+        on: function (eventName, callback) {
  1334
+            /// <summary>Wires up a callback to be invoked when a invocation request is received from the server hub.</summary>
  1335
+            /// <param name="eventName" type="String">The name of the hub event to register the callback for.</param>
  1336
+            /// <param name="callback" type="Function">The callback to be invoked.</param>
  1337
+            var self = this;
  1338
+            $(self).bind(eventName, function (e, data) {
  1339
+                callback.apply(self, data);
  1340
+            });
  1341
+            return self;
  1342
+        },
  1343
+
  1344
+        invoke: function (methodName) {
  1345
+            /// <summary>Invokes a server hub method with the given arguments.</summary>
  1346
+            /// <param name="methodName" type="String">The name of the server hub method.</param>
  1347
+            
  1348
+            var self = this,
  1349
+                args = $.makeArray(arguments).slice(1),
  1350
+                userCallback = args[args.length - 1], // last argument
  1351
+                methodArgs = $.type(userCallback) === "function" ? args.slice(0, -1) /* all but last */ : args,
  1352
+                argValues = methodArgs.map(getArgValue),
  1353
+                data = { hub: self.hubName, method: methodName, args: argValues, state: self.state, id: callbackId },
  1354
+                d = $.Deferred(),
  1355
+                callback = function (result) {
  1356
+                    $.extend(this.state, result.State);
  1357
+
  1358
+                    if (result.Error) {
  1359
+                        // Server hub method threw an exception, log it & reject the deferred
  1360
+                        if (result.StackTrace) {
  1361
+                            self.connection.log(result.Error + "\n" + result.StackTrace);
  1362
+                        }
  1363
+                        d.rejectWith(self, [result.Error]);
  1364
+                    } else {
  1365
+                        // Server invocation succeeded, invoke any user callback & resolve the deferred
  1366
+                        if ($.type(userCallback) === "function") {
  1367
+                            userCallback.call(self, result.Result);
  1368
+                        }
  1369
+                        d.resolveWith(self, [result.Result]);
  1370
+                    }
  1371
+                };
  1372
+
  1373
+            callbacks[callbackId.toString()] = { scope: self, method: callback };
  1374
+            callbackId += 1;
  1375
+            self.connection.send(window.JSON.stringify(data));
  1376
+
  1377
+            return d.promise();
  1378
+        }
  1379
+    };
  1380
+
  1381
+    hubProxy.fn.init.prototype = hubProxy.fn;
  1382
+
  1383
+
  1384
+    // hubConnection
  1385
+    function hubConnection(url) {
  1386
+        /// <summary>Creates a new hub connection.</summary>
  1387
+        /// <param name="url" type="String">[Optional] The hub route url, defaults to "/signalr"</param>
  1388
+        if (!url) {
  1389
+            url = "/signalr";
  1390
+        }
  1391
+        return new hubConnection.fn.init(url);
  1392
+    }
  1393
+
  1394
+    hubConnection.fn = hubConnection.prototype = $.connection();
  1395
+
  1396
+    hubConnection.fn.init = function (url, qs, logging) {
  1397
+        var connection = this;
  1398
+
  1399
+        $.signalR.fn.init.call(connection, url, qs, logging);
  1400
+
  1401
+        // Object to store hub proxies for this connection
  1402
+        connection.proxies = {};
  1403
+
  1404
+        // Wire up the sending handler
  1405
+        connection.sending(function () {
  1406
+            var clientHubs = [];
  1407
+
  1408
+            $.each(this.proxies, function (key) {
  1409
+                clientHubs.push({ name: key });
  1410
+            });
  1411
+
  1412
+            this.data = window.JSON.stringify(clientHubs);
  1413
+        });
  1414
+
  1415
+        // Wire up the received handler
  1416
+        connection.received(function (data) {
  1417
+            var proxy, dataCallbackId, callback;
  1418
+            if (!data) {
  1419
+                return;
  1420
+            }
  1421
+
  1422
+            if (typeof(data.Id) !== "undefined") {
  1423
+                // We received the return value from a server method invocation, look up callback by id and call it
  1424
+                dataCallbackId = data.Id.toString();
  1425
+                callback = callbacks[dataCallbackId];
  1426
+                if (callback) {
  1427
+                    // Delete the callback from the proxy
  1428
+                    callbacks[dataCallbackId] = null;
  1429
+                    delete callbacks[dataCallbackId];
  1430
+
  1431
+                    // Invoke the callback
  1432
+                    callback.method.call(callback.scope, data);
  1433
+                }
  1434
+            } else {
  1435
+                // We received a client invocation request, i.e. broadcast from server hub
  1436
+                // Trigger the local invocation event
  1437
+                proxy = this.proxies[data.Hub];
  1438
+                $.extend(proxy.state, data.State);
  1439
+                $(proxy).trigger(data.Method, [data.Args]);
  1440
+            }
  1441
+        });
  1442
+    };
  1443
+
  1444
+    hubConnection.fn.createProxy = function (hubName) {
  1445
+        /// <summary>
  1446
+        ///     Creates a new proxy object for the given hub connection that can be used to invoke
  1447
+        ///     methods on server hubs and handle client method invocation requests from the server.
  1448
+        /// </summary>
  1449
+        /// <paramater name="hubName" type="String">
  1450
+        ///     The name of the hub on the server to create the proxy for.
  1451
+        /// </parameter>
  1452
+        var proxy = this.proxies[hubName];
  1453
+        if (!proxy) {
  1454
+            proxy = hubProxy(this, hubName);
  1455
+            this.proxies[hubName] = proxy;
  1456
+        }
  1457
+        return proxy;
  1458
+    };
  1459
+    
  1460
+    hubConnection.fn.init.prototype = hubConnection.fn;
  1461
+
  1462
+    $.hubConnection = hubConnection;
  1463
+
  1464
+}(window.jQuery, window));
2  samples/SignalR.Hosting.AspNet.Samples/Scripts/jquery.signalR.min.js
@@ -6,4 +6,4 @@
6 6
  * Licensed under the MIT.
7 7
  * https://github.com/SignalR/SignalR/blob/master/LICENSE.md
8 8
  */
9  
-(function(n,t){"use strict";if(typeof n!="function")throw"SignalR: jQuery not found. Please ensure jQuery is referenced before the SignalR.js file.";if(!t.JSON)throw"SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8.";var i,f,r={onStart:"onStart",onStarting:"onStarting",onSending:"onSending",onReceived:"onReceived",onError:"onError",onReconnect:"onReconnect",onStateChanged:"onStateChanged",onDisconnect:"onDisconnect"},o=function(n,i){if(i!==!1){var r;typeof t.console!="undefined"&&(r="["+(new Date).toTimeString()+"] SignalR: "+n,t.console.debug?t.console.debug(r):t.console.log&&t.console.log(r))}},s=function(i){var r;return(i=n.trim(i),i.indexOf("http")!==0)?!1:(r=t.document.createElement("a"),r.href=i,r.protocol+r.host!==t.location.protocol+t.location.host)},u=function(t,i,u){return i===t.state?(n(t).trigger(r.onStateChanged,[{oldState:t.state,newState:u}]),t.state=u,!0):!1},e=function(n){return n.state===i.connectionState.disconnected};i=function(n,t,r){return new i.fn.init(n,t,r)},i.events=r,i.changeState=u,i.isDisconnecting=e,i.connectionState={connecting:0,connected:1,reconnecting:2,disconnected:4},i.hub={start:function(){throw"SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. <script src='/signalr/hubs'><\/script>.";}},i.fn=i.prototype={init:function(n,t,i){this.url=n,this.qs=t,typeof i=="boolean"&&(this.logging=i)},ajaxDataType:"json",logging:!1,state:i.connectionState.disconnected,reconnectDelay:2e3,start:function(f,e){var o=this,h={transport:"auto",jsonp:!1},a,l=n.Deferred(),c=t.document.createElement("a");return u(o,i.connectionState.disconnected,i.connectionState.connecting)===!1?(l.resolve(o),l.promise()):(n.type(f)==="function"?e=f:n.type(f)==="object"&&(n.extend(h,f),n.type(h.callback)==="function"&&(e=h.callback)),c.href=o.url,c.protocol&&c.protocol!==":"?(o.protocol=c.protocol,o.host=c.host,o.baseUrl=c.protocol+"//"+c.host):(o.protocol=t.document.location.protocol,o.host=t.document.location.host,o.baseUrl=o.protocol+"//"+o.host),o.wsProtocol=o.protocol==="https:"?"wss://":"ws://",s(o.url)&&(o.log("Auto detected cross domain url."),h.transport==="auto"&&(h.jsonp||(h.jsonp=!n.support.cors,h.jsonp&&o.log("Using jsonp because this browser doesn't support CORS")),h.transport=h.jsonp===!0?"longPolling":["webSockets","longPolling"])),o.ajaxDataType=h.jsonp?"jsonp":"json",n(o).bind(r.onStart,function(){n.type(e)==="function"&&e.call(o),l.resolve(o)}),a=function(f,e){if(e=e||0,e>=f.length){o.transport||l.reject("SignalR: No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.");return}var s=f[e],h=n.type(s)==="object"?s:i.transports[s];if(s.indexOf("_")===0){a(f,e+1);return}h.start(o,function(){o.transport=h,u(o,i.connectionState.connecting,i.connectionState.connected),n(o).trigger(r.onStart),n(t).unload(function(){o.stop(!1)})},function(){a(f,e+1)})},t.setTimeout(function(){var t=o.url+"/negotiate";o.log("Negotiating with '"+t+"'."),n.ajax({url:t,global:!1,cache:!1,type:"GET",data:{},dataType:o.ajaxDataType,error:function(t){n(o).trigger(r.onError,[t.responseText]),l.reject("SignalR: Error during negotiation request: "+t.responseText),o.stop()},success:function(t){if(o.appRelativeUrl=t.Url,o.id=t.ConnectionId,o.webSocketServerUrl=t.WebSocketServerUrl,!t.ProtocolVersion||t.ProtocolVersion!=="1.0"){n(o).trigger(r.onError,"SignalR: Incompatible protocol version."),l.reject("SignalR: Incompatible protocol version.");return}n(o).trigger(r.onStarting);var f=[],u=[];n.each(i.transports,function(n){if(n==="webSockets"&&!t.TryWebSockets)return!0;u.push(n)}),n.isArray(h.transport)?n.each(h.transport,function(){var t=this;(n.type(t)==="object"||n.type(t)==="string"&&n.inArray(""+t,u)>=0)&&f.push(n.type(t)==="string"?""+t:t)}):n.type(h.transport)==="object"||n.inArray(h.transport,u)>=0?f.push(h.transport):f=u,a(f)}})},0),l.promise())},starting:function(t){var i=this,u=n(i);return u.bind(r.onStarting,function(){t.call(i),u.unbind(r.onStarting)}),i},send:function(n){var t=this;if(t.state===i.connectionState.disconnected)throw"SignalR: Connection must be started before data can be sent. Call .start() before .send()";if(t.state===i.connectionState.connecting)throw"SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.";return t.transport.send(t,n),t},sending:function(t){var i=this;return n(i).bind(r.onSending,function(){t.call(i)}),i},received:function(t){var i=this;return n(i).bind(r.onReceived,function(n,r){t.call(i,r)}),i},stateChanged:function(t){var i=this;return n(i).bind(r.onStateChanged,function(n,r){t.call(i,r)}),i},error:function(t){var i=this;return n(i).bind(r.onError,function(n,r){t.call(i,r)}),i},disconnected:function(t){var i=this;return n(i).bind(r.onDisconnect,function(){t.call(i)}),i},reconnected:function(t){var i=this;return n(i).bind(r.onReconnect,function(){t.call(i)}),i},stop:function(t){var f=this;if(f.state!==i.connectionState.disconnected){try{f.transport&&(f.transport.abort(f,t),f.transport.stop(f),f.transport=null),n(f).trigger(r.onDisconnect),delete f.messageId,delete f.groups}finally{u(f,f.state,i.connectionState.disconnected)}return f}},log:function(n){o(n,this.logging)}},i.fn.init.prototype=i.fn,i.noConflict=function(){return n.connection===i&&(n.connection=f),i},n.connection&&(f=n.connection),n.connection=n.signalR=i})(window.jQuery,window),function(n,t){"use strict";var r=n.signalR,i=n.signalR.events;r.transports={},r.transports._logic={addQs:function(i,r){return r.qs?typeof r.qs=="object"?i+"&"+n.param(r.qs):typeof r.qs=="string"?i+"&"+r.qs:i+"&"+t.escape(r.qs.toString()):i},getUrl:function(n,i,r,u){var o=i==="webSockets"?"":n.baseUrl,f=o+n.appRelativeUrl,e="transport="+i+"&connectionId="+t.escape(n.id);return n.data&&(e+="&connectionData="+t.escape(n.data)),r?(u&&(f=f+"/reconnect"),n.messageId&&(e+="&messageId="+n.messageId),n.groups&&(e+="&groups="+t.escape(JSON.stringify(n.groups)))):f=f+"/connect",f+="?"+e,f=this.addQs(f,n),f+="&tid="+Math.floor(Math.random()*11)},ajaxSend:function(r,u){var f=r.url+"/send?transport="+r.transport.name+"&connectionId="+t.escape(r.id);return f=this.addQs(f,r),n.ajax({url:f,global:!1,type:"POST",dataType:r.ajaxDataType,data:{data:u},success:function(t){t&&n(r).trigger(i.onReceived,[t])},error:function(t,u){u!=="abort"&&(u!=="parsererror"||r.ajaxDataType!=="jsonp")&&n(r).trigger(i.onError,[t])}})},ajaxAbort:function(i,r){if(typeof i.transport!="undefined"){r=typeof r=="undefined"?!0:r;var u=i.url+"/abort?transport="+i.transport.name+"&connectionId="+t.escape(i.id);u=this.addQs(u,i),n.ajax({url:u,async:r,timeout:1e3,global:!1,type:"POST",dataType:i.ajaxDataType,data:{}}),i.log("Fired ajax abort async = "+r)}},processMessages:function(t,r){var u=n(t);if(r){if(r.Disconnect){t.log("Disconnect command received from server"),t.stop();return}r.Messages&&n.each(r.Messages,function(){try{u.trigger(i.onReceived,[this])}catch(r){t.log("Error raising received "+r),n(t).trigger(i.onError,[r])}}),r.MessageId&&(t.messageId=r.MessageId),r.TransportData&&(t.groups=r.TransportData.Groups)}},foreverFrame:{count:0,connections:{}}}}(window.jQuery,window),function(n,t){"use strict";var i=n.signalR,r=n.signalR.events,f=n.signalR.changeState,u=i.transports._logic;i.transports.webSockets={name:"webSockets",send:function(n,t){n.socket.send(t)},start:function(e,o,s){var h,a=!1,l=this,c=!o,v=n(e);if(t.MozWebSocket&&(t.WebSocket=t.MozWebSocket),!t.WebSocket){s();return}e.socket||(h=e.webSocketServerUrl?e.webSocketServerUrl:e.wsProtocol+e.host,n(e).trigger(r.onSending),h+=u.getUrl(e,this.name,c),e.log("Connecting to websocket endpoint '"+h+"'"),e.socket=new t.WebSocket(h),e.socket.onopen=function(){a=!0,e.log("Websocket opened"),o?o():f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&v.trigger(r.onReconnect)},e.socket.onclose=function(t){if(a)typeof t.wasClean!="undefined"&&t.wasClean===!1?(n(e).trigger(r.onError,[t.reason]),e.log("Unclean disconnect from websocket."+t.reason)):e.log("Websocket closed");else{s?s():c&&l.reconnect(e);return}l.reconnect(e)},e.socket.onmessage=function(i){var f=t.JSON.parse(i.data),o;f&&(o=n(e),f.Messages?u.processMessages(e,f):o.trigger(r.onReceived,[f]))})},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("Websocket reconnecting"),r.start(n))},n.reconnectDelay)},stop:function(n){n.socket!==null&&(n.log("Closing the Websocket"),n.socket.close(),n.socket=null)},abort:function(){}}}(window.jQuery,window),function(n,t){"use strict";var i=n.signalR,u=n.signalR.events,f=n.signalR.changeState,r=i.transports._logic;i.transports.serverSentEvents={name:"serverSentEvents",timeOut:3e3,start:function(e,o,s){var c=this,a=!1,l=n(e),h=!o,y,v;if(e.eventSource&&(e.log("The connection already has an event source. Stopping it."),e.stop()),!t.EventSource){s&&(e.log("This browser doesn't support SSE."),s());return}l.trigger(u.onSending),y=r.getUrl(e,this.name,h);try{e.log("Attempting to connect to SSE endpoint '"+y+"'"),e.eventSource=new t.EventSource(y)}catch(p){e.log("EventSource failed trying to connect with error "+p.Message),s?s():(l.trigger(u.onError,[p]),h&&c.reconnect(e));return}v=t.setTimeout(function(){a===!1&&(e.log("EventSource timed out trying to connect"),e.log("EventSource readyState: "+e.eventSource.readyState),h||c.stop(e),h?e.eventSource.readyState!==t.EventSource.CONNECTING&&e.eventSource.readyState!==t.EventSource.OPEN&&c.reconnect(e):s&&s())},c.timeOut),e.eventSource.addEventListener("open",function(){e.log("EventSource connected"),v&&t.clearTimeout(v),a===!1&&(a=!0,o&&o(),h&&f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&l.trigger(u.onReconnect))},!1),e.eventSource.addEventListener("message",function(n){n.data!=="initialized"&&r.processMessages(e,t.JSON.parse(n.data))},!1),e.eventSource.addEventListener("error",function(n){if(!a){s&&s();return}e.log("EventSource readyState: "+e.eventSource.readyState),n.eventPhase===t.EventSource.CLOSED?(e.log("EventSource reconnecting due to the server connection ending"),c.reconnect(e)):(e.log("EventSource error"),l.trigger(u.onError))},!1)},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("EventSource reconnecting"),r.start(n))},n.reconnectDelay)},send:function(n,t){r.ajaxSend(n,t)},stop:function(n){n&&n.eventSource&&(n.log("EventSource calling close()"),n.eventSource.close(),n.eventSource=null,delete n.eventSource)},abort:function(n,t){r.ajaxAbort(n,t)}}}(window.jQuery,window),function(n,t){"use strict";var r=n.signalR,u=n.signalR.events,f=n.signalR.changeState,i=r.transports._logic;r.transports.foreverFrame={name:"foreverFrame",timeOut:3e3,start:function(r,f,e){var s=this,h=i.foreverFrame.count+=1,c,l,o=n("<iframe data-signalr-connection-id='"+r.id+"' style='position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;'></iframe>");if(t.EventSource){e&&(r.log("This brower supports SSE, skipping Forever Frame."),e());return}n(r).trigger(u.onSending),c=i.getUrl(r,this.name),c+="&frameId="+h,o.prop("src",c),i.foreverFrame.connections[h]=r,r.log("Binding to iframe's readystatechange event."),o.bind("readystatechange",function(){n.inArray(this.readyState,["loaded","complete"])>=0&&(r.log("Forever frame iframe readyState changed to "+this.readyState+", reconnecting"),s.reconnect(r))}),r.frame=o[0],r.frameId=h,f&&(r.onSuccess=f),n("body").append(o),l=t.setTimeout(function(){r.onSuccess&&(r.log("Failed to connect using forever frame source, it timed out after "+s.timeOut+"ms."),s.stop(r),e&&e())},s.timeOut)},reconnect:function(n){var u=this;t.setTimeout(function(){if(n.frame&&(n.state===r.connectionState.reconnecting||f(n,r.connectionState.connected,r.connectionState.reconnecting)===!0)){var e=n.frame,t=i.getUrl(n,u.name,!0)+"&frameId="+n.frameId;n.log("Upating iframe src to '"+t+"'."),e.src=t}},n.reconnectDelay)},send:function(n,t){i.ajaxSend(n,t)},receive:function(t,r){var u;i.processMessages(t,r),t.frameMessageCount=(t.frameMessageCount||0)+1,t.frameMessageCount>50&&(t.frameMessageCount=0,u=t.frame.contentWindow||t.frame.contentDocument,u&&u.document&&n("body",u.document).empty())},stop:function(t){var r=null;t.frame&&(t.frame.stop?t.frame.stop():(r=t.frame.contentWindow||t.frame.contentDocument,r.document&&r.document.execCommand&&r.document.execCommand("Stop")),n(t.frame).remove(),delete i.foreverFrame.connections[t.frameId],t.frame=null,t.frameId=null,delete t.frame,delete t.frameId,t.log("Stopping forever frame"))},abort:function(n,t){i.ajaxAbort(n,t)},getConnection:function(n){return i.foreverFrame.connections[n]},started:function(t){t.onSuccess?(t.onSuccess(),t.onSuccess=null,delete t.onSuccess):f(t,r.connectionState.reconnecting,r.connectionState.connected)===!0&&n(t).trigger(u.onReconnect)}}}(window.jQuery,window),function(n,t){"use strict";var i=n.signalR,u=n.signalR.events,f=n.signalR.changeState,e=n.signalR.isDisconnecting,r=i.transports._logic;i.transports.longPolling={name:"longPolling",reconnectDelay:3e3,start:function(o,s){var l=this,c=!1;o.pollXhr&&(o.log("Polling xhr requests already exists, aborting."),o.stop()),o.messageId=null,t.setTimeout(function(){(function h(a,v){n(a).trigger(u.onSending);var d=a.messageId,k=d===null,b=!k,w=r.getUrl(a,l.name,b,v),p=null,y=!1;(b!==!0||v!==!0||o.state===i.connectionState.reconnecting||f(o,i.connectionState.connected,i.connectionState.reconnecting)!==!1)&&(o.log("Attempting to connect to '"+w+"' using longPolling."),a.pollXhr=n.ajax({url:w,global:!1,cache:!1,type:"GET",dataType:o.ajaxDataType,success:function(l){var w=0,p=!1;(c===!1&&(s(),c=!0),v===!0&&y===!1&&(o.log("Raising the reconnect event"),f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(u.onReconnect),y=!0)),r.processMessages(a,l),l&&l.TransportData&&n.type(l.TransportData.LongPollDelay)==="number"&&(w=l.TransportData.LongPollDelay),l&&l.TimedOut&&(p=l.TimedOut),l&&l.Disconnect)||e(a)!==!0&&(w>0?t.setTimeout(function(){h(a,p)},w):h(a,p))},error:function(i,r){if(r==="abort"){o.log("Aborted xhr requst.");return}o.log("An error occurred using longPolling. Status = "+r+". "+i.responseText),p&&t.clearTimeout(p),n(a).trigger(u.onError,[i.responseText]),t.setTimeout(function(){e(a)===!1&&h(a,!0)},o.reconnectDelay)}}),v===!0&&(p=t.setTimeout(function(){y===!1&&f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(u.onReconnect),y=!0)},l.reconnectDelay)))})(o),t.setTimeout(function(){c===!1&&(s(),c=!0)},150)},250)},send:function(n,t){r.ajaxSend(n,t)},stop:function(n){n.pollXhr&&(n.pollXhr.abort(),n.pollXhr=null,delete n.pollXhr)},abort:function(n,t){r.ajaxAbort(n,t)}}}(window.jQuery,window)
  9
+(function(n,t){"use strict";if(typeof n!="function")throw"SignalR: jQuery not found. Please ensure jQuery is referenced before the SignalR.js file.";if(!t.JSON)throw"SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8.";var i,f,r={onStart:"onStart",onStarting:"onStarting",onSending:"onSending",onReceived:"onReceived",onError:"onError",onReconnect:"onReconnect",onStateChanged:"onStateChanged",onDisconnect:"onDisconnect"},o=function(n,i){if(i!==!1){var r;typeof t.console!="undefined"&&(r="["+(new Date).toTimeString()+"] SignalR: "+n,t.console.debug?t.console.debug(r):t.console.log&&t.console.log(r))}},s=function(i){var r;return(i=n.trim(i),i.indexOf("http")!==0)?!1:(r=t.document.createElement("a"),r.href=i,r.protocol+r.host!==t.location.protocol+t.location.host)},u=function(t,i,u){return i===t.state?(n(t).trigger(r.onStateChanged,[{oldState:t.state,newState:u}]),t.state=u,!0):!1},e=function(n){return n.state===i.connectionState.disconnected};i=function(n,t,r){return new i.fn.init(n,t,r)},i.events=r,i.changeState=u,i.isDisconnecting=e,i.connectionState={connecting:0,connected:1,reconnecting:2,disconnected:4},i.hub={start:function(){throw"SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. <script src='/signalr/hubs'><\/script>.";}},i.fn=i.prototype={init:function(n,t,i){this.url=n,this.qs=t,typeof i=="boolean"&&(this.logging=i)},ajaxDataType:"json",logging:!1,state:i.connectionState.disconnected,reconnectDelay:2e3,start:function(f,e){var o=this,h={transport:"auto",jsonp:!1},a,l=n.Deferred(),c=t.document.createElement("a");return u(o,i.connectionState.disconnected,i.connectionState.connecting)===!1?(l.resolve(o),l.promise()):(n.type(f)==="function"?e=f:n.type(f)==="object"&&(n.extend(h,f),n.type(h.callback)==="function"&&(e=h.callback)),c.href=o.url,c.protocol&&c.protocol!==":"?(o.protocol=c.protocol,o.host=c.host,o.baseUrl=c.protocol+"//"+c.host):(o.protocol=t.document.location.protocol,o.host=t.document.location.host,o.baseUrl=o.protocol+"//"+o.host),o.wsProtocol=o.protocol==="https:"?"wss://":"ws://",s(o.url)&&(o.log("Auto detected cross domain url."),h.transport==="auto"&&(h.jsonp||(h.jsonp=!n.support.cors,h.jsonp&&o.log("Using jsonp because this browser doesn't support CORS")),h.transport=h.jsonp===!0?"longPolling":["webSockets","longPolling"])),o.ajaxDataType=h.jsonp?"jsonp":"json",n(o).bind(r.onStart,function(){n.type(e)==="function"&&e.call(o),l.resolve(o)}),a=function(f,e){if(e=e||0,e>=f.length){o.transport||l.reject("SignalR: No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.");return}var s=f[e],h=n.type(s)==="object"?s:i.transports[s];if(s.indexOf("_")===0){a(f,e+1);return}h.start(o,function(){o.transport=h,u(o,i.connectionState.connecting,i.connectionState.connected),n(o).trigger(r.onStart),n(t).unload(function(){o.stop(!1)})},function(){a(f,e+1)})},t.setTimeout(function(){var t=o.url+"/negotiate";o.log("Negotiating with '"+t+"'."),n.ajax({url:t,global:!1,cache:!1,type:"GET",data:{},dataType:o.ajaxDataType,error:function(t){n(o).trigger(r.onError,[t.responseText]),l.reject("SignalR: Error during negotiation request: "+t.responseText),o.stop()},success:function(t){if(o.appRelativeUrl=t.Url,o.id=t.ConnectionId,o.webSocketServerUrl=t.WebSocketServerUrl,!t.ProtocolVersion||t.ProtocolVersion!=="1.0"){n(o).trigger(r.onError,"SignalR: Incompatible protocol version."),l.reject("SignalR: Incompatible protocol version.");return}n(o).trigger(r.onStarting);var f=[],u=[];n.each(i.transports,function(n){if(n==="webSockets"&&!t.TryWebSockets)return!0;u.push(n)}),n.isArray(h.transport)?n.each(h.transport,function(){var t=this;(n.type(t)==="object"||n.type(t)==="string"&&n.inArray(""+t,u)>=0)&&f.push(n.type(t)==="string"?""+t:t)}):n.type(h.transport)==="object"||n.inArray(h.transport,u)>=0?f.push(h.transport):f=u,a(f)}})},0),l.promise())},starting:function(t){var i=this,u=n(i);return u.bind(r.onStarting,function(){t.call(i),u.unbind(r.onStarting)}),i},send:function(n){var t=this;if(t.state===i.connectionState.disconnected)throw"SignalR: Connection must be started before data can be sent. Call .start() before .send()";if(t.state===i.connectionState.connecting)throw"SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.";return t.transport.send(t,n),t},sending:function(t){var i=this;return n(i).bind(r.onSending,function(){t.call(i)}),i},received:function(t){var i=this;return n(i).bind(r.onReceived,function(n,r){t.call(i,r)}),i},stateChanged:function(t){var i=this;return n(i).bind(r.onStateChanged,function(n,r){t.call(i,r)}),i},error:function(t){var i=this;return n(i).bind(r.onError,function(n,r){t.call(i,r)}),i},disconnected:function(t){var i=this;return n(i).bind(r.onDisconnect,function(){t.call(i)}),i},reconnected:function(t){var i=this;return n(i).bind(r.onReconnect,function(){t.call(i)}),i},stop:function(t){var f=this;if(f.state!==i.connectionState.disconnected){try{f.transport&&(f.transport.abort(f,t),f.transport.stop(f),f.transport=null),n(f).trigger(r.onDisconnect),delete f.messageId,delete f.groups}finally{u(f,f.state,i.connectionState.disconnected)}return f}},log:function(n){o(n,this.logging)}},i.fn.init.prototype=i.fn,i.noConflict=function(){return n.connection===i&&(n.connection=f),i},n.connection&&(f=n.connection),n.connection=n.signalR=i})(window.jQuery,window),function(n,t){"use strict";var r=n.signalR,i=n.signalR.events;r.transports={},r.transports._logic={addQs:function(i,r){return r.qs?typeof r.qs=="object"?i+"&"+n.param(r.qs):typeof r.qs=="string"?i+"&"+r.qs:i+"&"+t.escape(r.qs.toString()):i},getUrl:function(n,i,r,u){var o=i==="webSockets"?"":n.baseUrl,f=o+n.appRelativeUrl,e="transport="+i+"&connectionId="+t.escape(n.id);return n.data&&(e+="&connectionData="+t.escape(n.data)),r?(u&&(f=f+"/reconnect"),n.messageId&&(e+="&messageId="+n.messageId),n.groups&&(e+="&groups="+t.escape(JSON.stringify(n.groups)))):f=f+"/connect",f+="?"+e,f=this.addQs(f,n),f+="&tid="+Math.floor(Math.random()*11)},ajaxSend:function(r,u){var f=r.url+"/send?transport="+r.transport.name+"&connectionId="+t.escape(r.id);return f=this.addQs(f,r),n.ajax({url:f,global:!1,type:"POST",dataType:r.ajaxDataType,data:{data:u},success:function(t){t&&n(r).trigger(i.onReceived,[t])},error:function(t,u){u!=="abort"&&(u!=="parsererror"||r.ajaxDataType!=="jsonp")&&n(r).trigger(i.onError,[t])}})},ajaxAbort:function(i,r){if(typeof i.transport!="undefined"){r=typeof r=="undefined"?!0:r;var u=i.url+"/abort?transport="+i.transport.name+"&connectionId="+t.escape(i.id);u=this.addQs(u,i),n.ajax({url:u,async:r,timeout:1e3,global:!1,type:"POST",dataType:i.ajaxDataType,data:{}}),i.log("Fired ajax abort async = "+r)}},processMessages:function(t,r){var u=n(t);if(r){if(r.Disconnect){t.log("Disconnect command received from server"),t.stop();return}r.Messages&&n.each(r.Messages,function(){try{u.trigger(i.onReceived,[this])}catch(r){t.log("Error raising received "+r),n(t).trigger(i.onError,[r])}}),r.MessageId&&(t.messageId=r.MessageId),r.TransportData&&(t.groups=r.TransportData.Groups)}},foreverFrame:{count:0,connections:{}}}}(window.jQuery,window),function(n,t){"use strict";var i=n.signalR,r=n.signalR.events,f=n.signalR.changeState,u=i.transports._logic;i.transports.webSockets={name:"webSockets",send:function(n,t){n.socket.send(t)},start:function(e,o,s){var h,a=!1,l=this,c=!o,v=n(e);if(t.MozWebSocket&&(t.WebSocket=t.MozWebSocket),!t.WebSocket){s();return}e.socket||(h=e.webSocketServerUrl?e.webSocketServerUrl:e.wsProtocol+e.host,n(e).trigger(r.onSending),h+=u.getUrl(e,this.name,c),e.log("Connecting to websocket endpoint '"+h+"'"),e.socket=new t.WebSocket(h),e.socket.onopen=function(){a=!0,e.log("Websocket opened"),o?o():f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&v.trigger(r.onReconnect)},e.socket.onclose=function(t){if(a)typeof t.wasClean!="undefined"&&t.wasClean===!1?(n(e).trigger(r.onError,[t.reason]),e.log("Unclean disconnect from websocket."+t.reason)):e.log("Websocket closed");else{s?s():c&&l.reconnect(e);return}l.reconnect(e)},e.socket.onmessage=function(i){var f=t.JSON.parse(i.data),o;f&&(o=n(e),f.Messages?u.processMessages(e,f):o.trigger(r.onReceived,[f]))})},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("Websocket reconnecting"),r.start(n))},n.reconnectDelay)},stop:function(n){n.socket!==null&&(n.log("Closing the Websocket"),n.socket.close(),n.socket=null)},abort:function(){}}}(window.jQuery,window),function(n,t){"use strict";var i=n.signalR,u=n.signalR.events,f=n.signalR.changeState,r=i.transports._logic;i.transports.serverSentEvents={name:"serverSentEvents",timeOut:3e3,start:function(e,o,s){var c=this,a=!1,l=n(e),h=!o,y,v;if(e.eventSource&&(e.log("The connection already has an event source. Stopping it."),e.stop()),!t.EventSource){s&&(e.log("This browser doesn't support SSE."),s());return}l.trigger(u.onSending),y=r.getUrl(e,this.name,h);try{e.log("Attempting to connect to SSE endpoint '"+y+"'"),e.eventSource=new t.EventSource(y)}catch(p){e.log("EventSource failed trying to connect with error "+p.Message),s?s():(l.trigger(u.onError,[p]),h&&c.reconnect(e));return}v=t.setTimeout(function(){a===!1&&(e.log("EventSource timed out trying to connect"),e.log("EventSource readyState: "+e.eventSource.readyState),h||c.stop(e),h?e.eventSource.readyState!==t.EventSource.CONNECTING&&e.eventSource.readyState!==t.EventSource.OPEN&&c.reconnect(e):s&&s())},c.timeOut),e.eventSource.addEventListener("open",function(){e.log("EventSource connected"),v&&t.clearTimeout(v),a===!1&&(a=!0,o&&o(),h&&f(e,i.connectionState.reconnecting,i.connectionState.connected)===!0&&l.trigger(u.onReconnect))},!1),e.eventSource.addEventListener("message",function(n){n.data!=="initialized"&&r.processMessages(e,t.JSON.parse(n.data))},!1),e.eventSource.addEventListener("error",function(n){if(!a){s&&s();return}e.log("EventSource readyState: "+e.eventSource.readyState),n.eventPhase===t.EventSource.CLOSED?(e.log("EventSource reconnecting due to the server connection ending"),c.reconnect(e)):(e.log("EventSource error"),l.trigger(u.onError))},!1)},reconnect:function(n){var r=this;t.setTimeout(function(){r.stop(n),(n.state===i.connectionState.reconnecting||f(n,i.connectionState.connected,i.connectionState.reconnecting)===!0)&&(n.log("EventSource reconnecting"),r.start(n))},n.reconnectDelay)},send:function(n,t){r.ajaxSend(n,t)},stop:function(n){n&&n.eventSource&&(n.log("EventSource calling close()"),n.eventSource.close(),n.eventSource=null,delete n.eventSource)},abort:function(n,t){r.ajaxAbort(n,t)}}}(window.jQuery,window),function(n,t){"use strict";var r=n.signalR,u=n.signalR.events,f=n.signalR.changeState,i=r.transports._logic;r.transports.foreverFrame={name:"foreverFrame",timeOut:3e3,start:function(r,f,e){var s=this,h=i.foreverFrame.count+=1,c,l,o=n("<iframe data-signalr-connection-id='"+r.id+"' style='position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;'></iframe>");if(t.EventSource){e&&(r.log("This brower supports SSE, skipping Forever Frame."),e());return}n(r).trigger(u.onSending),c=i.getUrl(r,this.name),c+="&frameId="+h,o.prop("src",c),i.foreverFrame.connections[h]=r,r.log("Binding to iframe's readystatechange event."),o.bind("readystatechange",function(){n.inArray(this.readyState,["loaded","complete"])>=0&&(r.log("Forever frame iframe readyState changed to "+this.readyState+", reconnecting"),s.reconnect(r))}),r.frame=o[0],r.frameId=h,f&&(r.onSuccess=f),n("body").append(o),l=t.setTimeout(function(){r.onSuccess&&(r.log("Failed to connect using forever frame source, it timed out after "+s.timeOut+"ms."),s.stop(r),e&&e())},s.timeOut)},reconnect:function(n){var u=this;t.setTimeout(function(){if(n.frame&&(n.state===r.connectionState.reconnecting||f(n,r.connectionState.connected,r.connectionState.reconnecting)===!0)){var e=n.frame,t=i.getUrl(n,u.name,!0)+"&frameId="+n.frameId;n.log("Upating iframe src to '"+t+"'."),e.src=t}},n.reconnectDelay)},send:function(n,t){i.ajaxSend(n,t)},receive:function(t,r){var u;i.processMessages(t,r),t.frameMessageCount=(t.frameMessageCount||0)+1,t.frameMessageCount>50&&(t.frameMessageCount=0,u=t.frame.contentWindow||t.frame.contentDocument,u&&u.document&&n("body",u.document).empty())},stop:function(t){var r=null;t.frame&&(t.frame.stop?t.frame.stop():(r=t.frame.contentWindow||t.frame.contentDocument,r.document&&r.document.execCommand&&r.document.execCommand("Stop")),n(t.frame).remove(),delete i.foreverFrame.connections[t.frameId],t.frame=null,t.frameId=null,delete t.frame,delete t.frameId,t.log("Stopping forever frame"))},abort:function(n,t){i.ajaxAbort(n,t)},getConnection:function(n){return i.foreverFrame.connections[n]},started:function(t){t.onSuccess?(t.onSuccess(),t.onSuccess=null,delete t.onSuccess):f(t,r.connectionState.reconnecting,r.connectionState.connected)===!0&&n(t).trigger(u.onReconnect)}}}(window.jQuery,window),function(n,t){"use strict";var i=n.signalR,u=n.signalR.events,f=n.signalR.changeState,e=n.signalR.isDisconnecting,r=i.transports._logic;i.transports.longPolling={name:"longPolling",reconnectDelay:3e3,start:function(o,s){var l=this,c=!1;o.pollXhr&&(o.log("Polling xhr requests already exists, aborting."),o.stop()),o.messageId=null,t.setTimeout(function(){(function h(a,v){n(a).trigger(u.onSending);var d=a.messageId,k=d===null,b=!k,w=r.getUrl(a,l.name,b,v),p=null,y=!1;(b!==!0||v!==!0||o.state===i.connectionState.reconnecting||f(o,i.connectionState.connected,i.connectionState.reconnecting)!==!1)&&(o.log("Attempting to connect to '"+w+"' using longPolling."),a.pollXhr=n.ajax({url:w,global:!1,cache:!1,type:"GET",dataType:o.ajaxDataType,success:function(l){var w=0,p=!1;(c===!1&&(s(),c=!0),v===!0&&y===!1&&(o.log("Raising the reconnect event"),f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(u.onReconnect),y=!0)),r.processMessages(a,l),l&&l.TransportData&&n.type(l.TransportData.LongPollDelay)==="number"&&(w=l.TransportData.LongPollDelay),l&&l.TimedOut&&(p=l.TimedOut),l&&l.Disconnect)||e(a)!==!0&&(w>0?t.setTimeout(function(){h(a,p)},w):h(a,p))},error:function(i,r){if(r==="abort"){o.log("Aborted xhr requst.");return}o.log("An error occurred using longPolling. Status = "+r+". "+i.responseText),p&&t.clearTimeout(p),n(a).trigger(u.onError,[i.responseText]),t.setTimeout(function(){e(a)===!1&&h(a,!0)},o.reconnectDelay)}}),v===!0&&(p=t.setTimeout(function(){y===!1&&f(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&(n(a).trigger(u.onReconnect),y=!0)},l.reconnectDelay)))})(o),t.setTimeout(function(){c===!1&&(s(),c=!0)},150)},250)},send:function(n,t){r.ajaxSend(n,t)},stop:function(n){n.pollXhr&&(n.pollXhr.abort(),n.pollXhr=null,delete n.pollXhr)},abort:function(n,t){r.ajaxAbort(n,t)}}}(window.jQuery,window),function(n,t){"use strict";function e(t){return n.isFunction(t)?null:n.type(t)==="undefined"?null:t}function r(n,t){return new r.fn.init(n,t)}function i(n){return n||(n="/signalr"),new i.fn.init(n)}var f=0,u={};Array.prototype.hasOwnProperty("map")||(Array.prototype.map=function(n,t){for(var r=this,f=r.length,u=[],i=0;i<f;i+=1)r.hasOwnProperty(i)&&(u[i]=n.call(t,r[i],i,r));return u}),r.fn=r.prototype={init:function(n,t){this.state={},this.connection=n,this.hubName=t},on:function(t,i){var r=this;return n(r).bind(t,function(n,t){i.apply(r,t)}),r},invoke:function(i){var r=this,o=n.makeArray(arguments).slice(1),h=o[o.length-1],a=n.type(h)==="function"?o.slice(0,-1):o,v=a.map(e),l={hub:r.hubName,method:i,args:v,state:r.state,id:f},s=n.Deferred(),c=function(t){n.extend(this.state,t.State),t.Error?(t.StackTrace&&r.connection.log(t.Error+"\n"+t.StackTrace),s.rejectWith(r,[t.Error])):(n.type(h)==="function"&&h.call(r,t.Result),s.resolveWith(r,[t.Result]))};return u[f.toString()]={scope:r,method:c},f+=1,r.connection.send(t.JSON.stringify(l)),s.promise()}},r.fn.init.prototype=r.fn,i.fn=i.prototype=n.connection(),i.fn.init=function(i,r,f){var e=this;n.signalR.fn.init.call(e,i,r,f),e.proxies={},e.sending(function(){var i=[];n.each(this.proxies,function(n){i.push({name:n})}),this.data=t.JSON.stringify(i)}),e.received(function(t){var f,i,r;t&&(typeof t.Id!="undefined"?(i=t.Id.toString(),r=u[i],r&&(u[i]=null,delete u[i],r.method.call(r.scope,t))):(f=this.proxies[t.Hub],n.extend(f.state,t.State),n(f).trigger(t.Method,[t.Args])))})},i.fn.createProxy=function(n){var t=this.proxies[n];return t||(t=r(this,n),this.proxies[n]=t),t},i.fn.init.prototype=i.fn,n.hubConnection=i}(window.jQuery,window)
1,274  samples/SignalR.Hosting.Owin.Samples/Content/Scripts/jquery.signalR.js
... ...
@@ -1,27 +1,28 @@
  1
+/* jquery.signalR.core.js */
  2
+/*global window:false */
1 3
 /*!
2  
-* SignalR JavaScript Library v0.5.2
3  
-* http://signalr.net/
4  
-*
5  
-* Copyright David Fowler and Damian Edwards 2012
6  
-* Licensed under the MIT.
7  
-* https://github.com/SignalR/SignalR/blob/master/LICENSE.md
8  
-*/
9  
-
10  
-/// <reference path="jquery-1.6.2.js" />
  4
+ * SignalR JavaScript Library v0.5.2
  5
+ * http://signalr.net/
  6
+ *
  7
+ * Copyright David Fowler and Damian Edwards 2012
  8
+ * Licensed under the MIT.
  9
+ * https://github.com/SignalR/SignalR/blob/master/LICENSE.md
  10
+ */
  11
+
  12
+/// <reference path="Scripts/jquery-1.6.2.js" />
11 13
 (function ($, window) {
12  
-    /// <param name="$" type="jQuery" />
13 14
     "use strict";
14  
-
  15
+    
15 16
     if (typeof ($) !== "function") {
16 17
         // no jQuery!
17 18
         throw "SignalR: jQuery not found. Please ensure jQuery is referenced before the SignalR.js file.";
18 19
     }
19  
-
  20
+    
20 21
     if (!window.JSON) {
21 22
         // no JSON!
22 23
         throw "SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8.";
23 24
     }
24  
-
  25
+    
25 26
     var signalR,
26 27
         _connection,
27 28
 
@@ -94,10 +95,15 @@
94 95
         ///     [Optional] A flag indicating whether connection logging is enabled to the browser
95 96
         ///     console/log. Defaults to false.
96 97
         /// </param>
97  
-        /// <returns type="signalR" />
98 98
 
99 99
         return new signalR.fn.init(url, qs, logging);
100 100
     };
  101
+    
  102
+    signalR.events = events;
  103
+
  104
+    signalR.changeState = changeState;
  105
+
  106
+    signalR.isDisconnecting = isDisconnecting;
101 107
 
102 108
     signalR.connectionState = {
103 109
         connecting: 0,
@@ -105,6 +111,13 @@
105 111
         reconnecting: 2,
106 112
         disconnected: 4
107 113
     };
  114
+    
  115
+    signalR.hub = {
  116
+        start: function () {
  117
+            // This will get replaced with the real hub connection start method when hubs is referenced correctly
  118
+            throw "SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. <script src='/signalr/hubs'></script>.";
  119
+        }
  120
+    };
108 121
 
109 122
     signalR.fn = signalR.prototype = {
110 123
         init: function (url, qs, logging) {
@@ -218,6 +231,12 @@
218 231
                 var transportName = transports[index],
219 232
                     transport = $.type(transportName) === "object" ? transportName : signalR.transports[transportName];
220 233
 
  234
+                if (transportName.indexOf("_") === 0) {
  235
+                    // Private member
  236
+                    initialize(transports, index + 1);
  237
+                    return;
  238
+                }
  239
+
221 240
                 transport.start(connection, function () { // success
222 241
                     connection.transport = transport;
223 242
 
@@ -284,8 +303,7 @@
284 303
                                     transports.push($.type(transport) === "string" ? "" + transport : transport);
285 304
                                 }
286 305
                             });
287  
-                        } else if ($.type(config.transport) === "object" ||
288  
-                                       $.inArray(config.transport, supportedTransports) >= 0) {
  306
+                        } else if ($.type(config.transport) === "object" || $.inArray(config.transport, supportedTransports) >= 0) {
289 307
                             // specific transport provided, as object or a named transport, e.g. "longPolling"
290 308
                             transports.push(config.transport);
291 309
                         } else { // default "auto"
@@ -438,10 +456,35 @@
438 456
 
439 457
     signalR.fn.init.prototype = signalR.fn;
440 458
 
  459
+    signalR.noConflict = function () {
  460
+        /// <summary>Reinstates the original value of $.connection and returns the signalR object for manual assignment</summary>
  461
+        /// <returns type="signalR" />
  462
+        if ($.connection === signalR) {
  463
+            $.connection = _connection;
  464
+        }
  465
+        return signalR;
  466
+    };
  467
+
  468
+    if ($.connection) {
  469
+        _connection = $.connection;
  470
+    }
  471
+
  472
+    $.connection = $.signalR = signalR;
  473
+
  474
+}(window.jQuery, window));
  475
+/* jquery.signalR.transports.common.js */
  476
+/*global window:false */
  477
+/// <reference path="jquery.signalR.core.js" />
  478
+
  479
+(function ($, window) {
  480
+    "use strict";
  481
+
  482
+    var signalR = $.signalR,
  483
+        events = $.signalR.events;
441 484
 
442  
-    // Transports
443  
-    var transportLogic = {
  485
+    signalR.transports = {};
444 486
 
  487
+    signalR.transports._logic = {
445 488
         addQs: function (url, connection) {
446 489
             if (!connection.qs) {
447 490
                 return url;
@@ -490,7 +533,7 @@
490 533
         ajaxSend: function (connection, data) {
491 534
             var url = connection.url + "/send" + "?transport=" + connection.transport.name + "&connectionId=" + window.escape(connection.id);
492 535
             url = this.addQs(url, connection);
493  
-            $.ajax({
  536
+            return $.ajax({
494 537
                 url: url,
495 538
                 global: false,
496 539
                 type: "POST",
@@ -581,628 +624,841 @@
581 624
         }
582 625
     };
583 626
 
584  
-    signalR.transports = {
  627
+}(window.jQuery, window));
  628
+/* jquery.signalR.transports.webSockets.js */
  629
+/*global window:false */
  630
+/// <reference path="jquery.signalR.transports.common.js" />
585 631
 
586  
-        webSockets: {
587  
-            name: "webSockets",
  632
+(function ($, window) {
  633
+    "use strict";
588 634
 
589  
-            send: function (connection, data) {
590  
-                connection.socket.send(data);
591  
-            },
  635
+    var signalR = $.signalR,
  636
+        events = $.signalR.events,
  637
+        changeState = $.signalR.changeState,
  638
+        transportLogic = signalR.transports._logic;
592 639
 
593  
-            start: function (connection, onSuccess, onFailed) {
594  
-                var url,
595  
-                    opened = false,
596  
-                    that = this,
597  
-                    reconnecting = !onSuccess,
598  
-                    protocol,
599  
-                    $connection = $(connection);
  640
+    signalR.transports.webSockets = {
  641
+        name: "webSockets",
600 642
 
601  
-                if (window.MozWebSocket) {
602  
-                    window.WebSocket = window.MozWebSocket;
603  
-                }
  643
+        send: function (connection, data) {
  644
+            connection.socket.send(data);
  645
+        },
604 646
 
605  
-                if (!window.WebSocket) {
606  
-                    onFailed();
607  
-                    return;
  647
+        start: function (connection, onSuccess, onFailed) {
  648
+            var url,
  649
+                opened = false,
  650
+                that = this,
  651
+                reconnecting = !onSuccess,
  652
+                $connection = $(connection);
  653
+
  654
+            if (window.MozWebSocket) {
  655
+                window.WebSocket = window.MozWebSocket;
  656
+            }
  657
+
  658
+            if (!window.WebSocket) {
  659
+                onFailed();
  660
+                return;
  661
+            }
  662
+
  663
+            if (!connection.socket) {
  664
+                if (connection.webSocketServerUrl) {
  665
+                    url = connection.webSocketServerUrl;
608 666
                 }
  667
+                else {
  668
+                    url = connection.wsProtocol + connection.host;
  669
+                }
  670
+
  671
+                // Build the url
  672
+                $(connection).trigger(events.onSending);
  673
+
  674
+                url += transportLogic.getUrl(connection, this.name, reconnecting);
609 675
 
610  
-                if (!connection.socket) {
611  
-                    if (connection.webSocketServerUrl) {
612  
-                        url = connection.webSocketServerUrl;
  676
+                connection.log("Connecting to websocket endpoint '" + url + "'");
  677
+                connection.socket = new window.WebSocket(url);
  678
+                connection.socket.onopen = function () {
  679
+                    opened = true;
  680
+                    connection.log("Websocket opened");
  681
+                    if (onSuccess) {
  682
+                        onSuccess();
613 683
                     }
614 684
                     else {
615  
-                        url = connection.wsProtocol + connection.host;
  685
+                        if (changeState(connection,
  686
+                                        signalR.connectionState.reconnecting,
  687
+                                        signalR.connectionState.connected) === true) {
  688
+                            $connection.trigger(events.onReconnect);
  689
+                        }
616 690
                     }
  691
+                };
617 692
 
618  
-                    // Build the url
619  
-                    $(connection).trigger(events.onSending);
620  
-
621  
-                    url += transportLogic.getUrl(connection, this.name, reconnecting);
622  
-
623  
-                    connection.log("Connecting to websocket endpoint '" + url + "'");
624  
-                    connection.socket = new window.WebSocket(url);
625  
-                    connection.socket.onopen = function () {
626  
-                        opened = true;
627  
-                        connection.log("Websocket opened");
628  
-                        if (onSuccess) {
629  
-                            onSuccess();
630  
-                        }
631  
-                        else {
632  
-                            if (changeState(connection,
633  
-                                            signalR.connectionState.reconnecting,
634  
-                                            signalR.connectionState.connected) === true) {
635  
-                                $connection.trigger(events.onReconnect);
636  
-                            }
  693
+                connection.socket.onclose = function (event) {
  694
+                    if (!opened) {
  695
+                        if (onFailed) {
  696
+                            onFailed();
637 697
                         }
638  
-                    };
639  
-
640  
-                    connection.socket.onclose = function (event) {
641  
-                        if (!opened) {
642  
-                            if (onFailed) {
643  
-                                onFailed();
644  
-                            }
645  
-                            else if(reconnecting) {
646  
-                                that.reconnect(connection);
647  
-                            }
648  
-                            return;
  698
+                        else if (reconnecting) {
  699
+                            that.reconnect(connection);
649 700
                         }
650  
-                        else if (typeof event.wasClean !== "undefined" && event.wasClean === false) {
  701
+                        return;
  702
+                    }
  703
+                    else if (typeof event.wasClean !== "undefined" && event.wasClean === false) {
651 704
                             // Ideally this would use the websocket.onerror handler (rather than checking wasClean in onclose) but
652 705
                             // I found in some circumstances Chrome won't call onerror. This implementation seems to work on all browsers.
653  
-                            $(connection).trigger(events.onError, [event.reason]);
654  
-                            connection.log("Unclean disconnect from websocket." + event.reason);
655  
-                        }
656  
-                        else {
657  
-                            connection.log("Websocket closed");
658  
-                        }
  706
+                        $(connection).trigger(events.onError, [event.reason]);
  707
+                        connection.log("Unclean disconnect from websocket." + event.reason);
  708
+                    }
  709
+                    else {
  710
+                        connection.log("Websocket closed");
  711
+                    }
659 712
 
660  
-                        that.reconnect(connection);
661  
-                    };
  713
+                    that.reconnect(connection);
  714
+                };
662 715
 
663  
-                    connection.socket.onmessage = function (event) {
664  
-                        var data = window.JSON.parse(event.data),
665  
-                            $connection;
666  
-                        if (data) {
667  
-                            $connection = $(connection);
  716
+                connection.socket.onmessage = function (event) {
  717
+                    var data = window.JSON.parse(event.data),
  718
+                        $connection;
  719
+                    if (data) {
  720
+                        $connection = $(connection);
668 721
 
669  
-                            if (data.Messages) {
670  
-                                transportLogic.processMessages(connection, data);
671  
-                            } else {
672  
-                                $connection.trigger(events.onReceived, [data]);
673  
-                            }
  722
+                        if (data.Messages) {
  723
+                            transportLogic.processMessages(connection, data);
  724
+                        } else {
  725
+                            $connection.trigger(events.onReceived, [data]);
674 726
                         }
675  
-                    };
676  
-                }
677  
-            },
678  
-
679  
-            reconnect: function (connection) {
680  
-                var that = this;
681  
-                window.setTimeout(function () {
682  
-                    that.stop(connection);
  727
+                    }
  728
+                };
  729
+            }
  730
+        },
683 731
 
684  
-                    if (connection.state === signalR.connectionState.reconnecting ||
685  
-                        changeState(connection,
686  
-                                    signalR.connectionState.connected,
687  
-                                    signalR.connectionState.reconnecting) === true) {
  732
+        reconnect: function (connection) {
  733
+            var that = this;
  734
+            window.setTimeout(function () {
  735
+                that.stop(connection);
688 736
 
689  
-                        connection.log("Websocket reconnecting");
690  
-                        that.start(connection);
691  
-                    }
692  
-                },
693  
-                connection.reconnectDelay);
694  
-            },
  737
+                if (connection.state === signalR.connectionState.reconnecting ||
  738
+                    changeState(connection,
  739
+                                signalR.connectionState.connected,
  740
+                                signalR.connectionState.reconnecting) === true) {
695 741
 
696  
-            stop: function (connection) {
697  
-                if (connection.socket !== null) {
698  
-                    connection.log("Closing the Websocket");
699  
-                    connection.socket.close();
700  
-                    connection.socket = null;
  742
+                    connection.log("Websocket reconnecting");
  743
+                    that.start(connection);
701 744
                 }
702 745
             },
  746
+            connection.reconnectDelay);
  747
+        },
703 748
 
704  
-            abort: function (connection) {
  749
+        stop: function (connection) {
  750
+            if (connection.socket !== null) {
  751
+                connection.log("Closing the Websocket");
  752
+                connection.socket.close();
  753
+                connection.socket = null;
705 754
             }
706 755
         },
707 756
 
708  
-        serverSentEvents: {
709  
-            name: "serverSentEvents",
  757
+        abort: function (connection) {
  758
+        }
  759
+    };
710 760
 
711  
-            timeOut: 3000,
  761
+}(window.jQuery, window));
  762
+/* jquery.signalR.transports.serverSentEvents.js */
  763
+/*global window:false */
  764
+/// <reference path="jquery.signalR.transports.common.js" />
712 765
 
713  
-            start: function (connection, onSuccess, onFailed) {
714  
-                var that = this,
715  
-                    opened = false,
716  
-                    $connection = $(connection),
717  
-                    reconnecting = !onSuccess,
718  
-                    url,
719  
-                    connectTimeOut;
  766
+(function ($, window) {
  767
+    "use strict";
720 768
 
721  
-                if (connection.eventSource) {
722  
-                    connection.log("The connection already has an event source. Stopping it.");
723  
-                    connection.stop();
724  
-                }
  769
+    var signalR = $.signalR,
  770
+        events = $.signalR.events,
  771
+        changeState = $.signalR.changeState,
  772
+        transportLogic = signalR.transports._logic;
725 773
 
726  
-                if (!window.EventSource) {
727  
-                    if (onFailed) {
728  
-                        connection.log("This browser doesn't support SSE.");
729  
-                        onFailed();
730  
-                    }
731  
-                    return;
  774
+    signalR.transports.serverSentEvents = {
  775
+        name: "serverSentEvents",
  776
+
  777
+        timeOut: 3000,
  778
+
  779
+        start: function (connection, onSuccess, onFailed) {
  780
+            var that = this,
  781
+                opened = false,
  782
+                $connection = $(connection),
  783
+                reconnecting = !onSuccess,
  784
+                url,
  785
+                connectTimeOut;
  786
+
  787
+            if (connection.eventSource) {
  788
+                connection.log("The connection already has an event source. Stopping it.");
  789
+                connection.stop();
  790
+            }
  791
+
  792
+            if (!window.EventSource) {
  793
+                if (onFailed) {
  794
+                    connection.log("This browser doesn't support SSE.");
  795
+                    onFailed();
732 796
                 }
  797
+                return;
  798
+            }
733 799
 
734  
-                $connection.trigger(events.onSending);
  800
+            $connection.trigger(events.onSending);
735 801
 
736  
-                url = transportLogic.getUrl(connection, this.name, reconnecting);
  802
+            url = transportLogic.getUrl(connection, this.name, reconnecting);
737 803
 
738  
-                try {
739  
-                    connection.log("Attempting to connect to SSE endpoint '" + url + "'");
740  
-                    connection.eventSource = new window.EventSource(url);
  804
+            try {
  805
+                connection.log("Attempting to connect to SSE endpoint '" + url + "'");
  806
+                connection.eventSource = new window.EventSource(url);
  807
+            }
  808
+            catch (e) {
  809
+                connection.log("EventSource failed trying to connect with error " + e.Message);
  810
+                if (onFailed) {
  811
+                    // The connection failed, call the failed callback
  812
+                    onFailed();
741 813
                 }
742  
-                catch (e) {
743  
-                    connection.log("EventSource failed trying to connect with error " + e.Message);
744  
-                    if (onFailed) {
745  
-                        // The connection failed, call the failed callback
746  
-                        onFailed();
747  
-                    }
748  
-                    else {
749  
-                        $connection.trigger(events.onError, [e]);
750  
-                        if (reconnecting) {
751  
-                            // If we were reconnecting, rather than doing initial connect, then try reconnect again
752  
-                            that.reconnect(connection);
753  
-                        }
  814
+                else {
  815
+                    $connection.trigger(events.onError, [e]);
  816
+                    if (reconnecting) {
  817
+                        // If we were reconnecting, rather than doing initial connect, then try reconnect again
  818
+                        that.reconnect(connection);
754 819
                     }
755  
-                    return;
756 820
                 }
  821
+                return;
  822
+            }
757 823
 
758  
-                // After connecting, if after the specified timeout there's no response stop the connection
759  
-                // and raise on failed
760  
-                connectTimeOut = window.setTimeout(function () {
761  
-                    if (opened === false) {
762  
-                        connection.log("EventSource timed out trying to connect");
763  
-                        connection.log("EventSource readyState: " + connection.eventSource.readyState);
764  
-
765  
-                        if (!reconnecting) {
766  
-                            that.stop(connection);
767  
-                        }
  824
+            // After connecting, if after the specified timeout there's no response stop the connection
  825
+            // and raise on failed