vendor: 4,829 bytes, lines 1-105
1/* jquery.signalR.core.js */ 2/*global window:false */ 3/*! 4 * ASP.NET SignalR JavaScript Library v2.2.2 5 * http://signalr.net/ 6 * 7 * Copyright (c) .NET Foundation. All rights reserved. 8 * Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 9 * 10 */ 11 12/// <reference path="Scripts/jquery-1.6.4.js" /> 13/// <reference path="jquery.signalR.version.js" /> 14(function ($, window, undefined) { 15 16 var resources = { 17 nojQuery: "jQuery was not found. Please ensure jQuery is referenced before the SignalR client JavaScript file.", 18 noTransportOnInit: "No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.", 19 errorOnNegotiate: "Error during negotiation request.", 20 stoppedWhileLoading: "The connection was stopped during page load.", 21 stoppedWhileNegotiating: "The connection was stopped during the negotiate request.", 22 errorParsingNegotiateResponse: "Error parsing negotiate response.", 23 errorDuringStartRequest: "Error during start request. Stopping the connection.", 24 stoppedDuringStartRequest: "The connection was stopped during the start request.", 25 errorParsingStartResponse: "Error parsing start response: '{0}'. Stopping the connection.", 26 invalidStartResponse: "Invalid start response: '{0}'. Stopping the connection.", 27 protocolIncompatible: "You are using a version of the client that isn't compatible with the server. Client version {0}, server version {1}.", 28 sendFailed: "Send failed.", 29 parseFailed: "Failed at parsing response: {0}", 30 longPollFailed: "Long polling request failed.", 31 eventSourceFailedToConnect: "EventSource failed to connect.", 32 eventSourceError: "Error raised by EventSource", 33 webSocketClosed: "WebSocket closed.", 34 pingServerFailedInvalidResponse: "Invalid ping response when pinging server: '{0}'.", 35 pingServerFailed: "Failed to ping server.", 36 pingServerFailedStatusCode: "Failed to ping server. Server responded with status code {0}, stopping the connection.", 37 pingServerFailedParse: "Failed to parse ping server response, stopping the connection.", 38 noConnectionTransport: "Connection is in an invalid state, there is no transport active.", 39 webSocketsInvalidState: "The Web Socket transport is in an invalid state, transitioning into reconnecting.", 40 reconnectTimeout: "Couldn't reconnect within the configured timeout of {0} ms, disconnecting.", 41 reconnectWindowTimeout: "The client has been inactive since {0} and it has exceeded the inactivity timeout of {1} ms. Stopping the connection." 42 }; 43 44 if (typeof ($) !== "function") { 45 // no jQuery! 46 throw new Error(resources.nojQuery); 47 } 48 49 var signalR, 50 _connection, 51 _pageLoaded = (window.document.readyState === "complete"), 52 _pageWindow = $(window), 53 _negotiateAbortText = "__Negotiate Aborted__", 54 events = { 55 onStart: "onStart", 56 onStarting: "onStarting", 57 onReceived: "onReceived", 58 onError: "onError", 59 onConnectionSlow: "onConnectionSlow", 60 onReconnecting: "onReconnecting", 61 onReconnect: "onReconnect", 62 onStateChanged: "onStateChanged", 63 onDisconnect: "onDisconnect" 64 }, 65 ajaxDefaults = { 66 processData: true, 67 timeout: null, 68 async: true, 69 global: false, 70 cache: false 71 }, 72 log = function (msg, logging) { 73 if (logging === false) { 74 return; 75 } 76 var m; 77 if (typeof (window.console) === "undefined") { 78 return; 79 } 80 m = "[" + new Date().toTimeString() + "] SignalR: " + msg; 81 if (window.console.debug) { 82 window.console.debug(m); 83 } else if (window.console.log) { 84 window.console.log(m); 85 } 86 }, 87 88 changeState = function (connection, expectedState, newState) { 89 if (expectedState === connection.state) { 90 connection.state = newState; 91 92 $(connection).triggerHandler(events.onStateChanged, [{ oldState: expectedState, newState: newState }]); 93 return true; 94 } 95 96 return false; 97 }, 98 99 isDisconnecting = function (connection) { 100 return connection.state === signalR.connectionState.disconnected; 101 }, 102 103 supportsKeepAlive = function (connection) { 104 return connection._.keepAliveData.activated && 105
vendor: 6,071 bytes, lines 105-253
105 connection.transport.supportsKeepAlive(connection); 106 }, 107 108 configureStopReconnectingTimeout = function (connection) { 109 var stopReconnectingTimeout, 110 onReconnectTimeout; 111 112 // Check if this connection has already been configured to stop reconnecting after a specified timeout. 113 // Without this check if a connection is stopped then started events will be bound multiple times. 114 if (!connection._.configuredStopReconnectingTimeout) { 115 onReconnectTimeout = function (connection) { 116 var message = signalR._.format(signalR.resources.reconnectTimeout, connection.disconnectTimeout); 117 connection.log(message); 118 $(connection).triggerHandler(events.onError, [signalR._.error(message, /* source */ "TimeoutException")]); 119 connection.stop(/* async */ false, /* notifyServer */ false); 120 }; 121 122 connection.reconnecting(function () { 123 var connection = this; 124 125 // Guard against state changing in a previous user defined even handler 126 if (connection.state === signalR.connectionState.reconnecting) { 127 stopReconnectingTimeout = window.setTimeout(function () { onReconnectTimeout(connection); }, connection.disconnectTimeout); 128 } 129 }); 130 131 connection.stateChanged(function (data) { 132 if (data.oldState === signalR.connectionState.reconnecting) { 133 // Clear the pending reconnect timeout check 134 window.clearTimeout(stopReconnectingTimeout); 135 } 136 }); 137 138 connection._.configuredStopReconnectingTimeout = true; 139 } 140 }; 141 142 signalR = function (url, qs, logging) { 143 /// <summary>Creates a new SignalR connection for the given url</summary> 144 /// <param name="url" type="String">The URL of the long polling endpoint</param> 145 /// <param name="qs" type="Object"> 146 /// [Optional] Custom querystring parameters to add to the connection URL. 147 /// If an object, every non-function member will be added to the querystring. 148 /// If a string, it's added to the QS as specified. 149 /// </param> 150 /// <param name="logging" type="Boolean"> 151 /// [Optional] A flag indicating whether connection logging is enabled to the browser 152 /// console/log. Defaults to false. 153 /// </param> 154 155 return new signalR.fn.init(url, qs, logging); 156 }; 157 158 signalR._ = { 159 defaultContentType: "application/x-www-form-urlencoded; charset=UTF-8", 160 161 ieVersion: (function () { 162 var version, 163 matches; 164 165 if (window.navigator.appName === 'Microsoft Internet Explorer') { 166 // Check if the user agent has the pattern "MSIE (one or more numbers).(one or more numbers)"; 167 matches = /MSIE ([0-9]+\.[0-9]+)/.exec(window.navigator.userAgent); 168 169 if (matches) { 170 version = window.parseFloat(matches[1]); 171 } 172 } 173 174 // undefined value means not IE 175 return version; 176 })(), 177 178 error: function (message, source, context) { 179 var e = new Error(message); 180 e.source = source; 181 182 if (typeof context !== "undefined") { 183 e.context = context; 184 } 185 186 return e; 187 }, 188 189 transportError: function (message, transport, source, context) { 190 var e = this.error(message, source, context); 191 e.transport = transport ? transport.name : undefined; 192 return e; 193 }, 194 195 format: function () { 196 /// <summary>Usage: format("Hi {0}, you are {1}!", "Foo", 100) </summary> 197 var s = arguments[0]; 198 for (var i = 0; i < arguments.length - 1; i++) { 199 s = s.replace("{" + i + "}", arguments[i + 1]); 200 } 201 return s; 202 }, 203 204 firefoxMajorVersion: function (userAgent) { 205 // Firefox user agents: http://useragentstring.com/pages/Firefox/ 206 var matches = userAgent.match(/Firefox\/(\d+)/); 207 if (!matches || !matches.length || matches.length < 2) { 208 return 0; 209 } 210 return parseInt(matches[1], 10 /* radix */); 211 }, 212 213 configurePingInterval: function (connection) { 214 var config = connection._.config, 215 onFail = function (error) { 216 $(connection).triggerHandler(events.onError, [error]); 217 }; 218 219 if (config && !connection._.pingIntervalId && config.pingInterval) { 220 connection._.pingIntervalId = window.setInterval(function () { 221 signalR.transports._logic.pingServer(connection).fail(onFail); 222 }, config.pingInterval); 223 } 224 } 225 }; 226 227 signalR.events = events; 228 229 signalR.resources = resources; 230 231 signalR.ajaxDefaults = ajaxDefaults; 232 233 signalR.changeState = changeState; 234 235 signalR.isDisconnecting = isDisconnecting; 236 237 signalR.connectionState = { 238 connecting: 0, 239 connected: 1, 240 reconnecting: 2, 241 disconnected: 4 242 }; 243 244 signalR.hub = { 245 start: function () { 246 // This will get replaced with the real hub connection start method when hubs is referenced correctly 247 throw new Error("SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. <script src='/signalr/js'></script>."); 248 } 249 }; 250 251 // .on() was added in version 1.7.0, .load() was removed in version 3.0.0 so we fallback to .load() if .on() does 252 // not exist to not break existing applications 253 if (typeof _pageWindow.on ==
vendor: 32,824 bytes, lines 253-955
253 "function") { 254 _pageWindow.on("load", function () { _pageLoaded = true; }); 255 } 256 else { 257 _pageWindow.load(function () { _pageLoaded = true; }); 258 } 259 260 function validateTransport(requestedTransport, connection) { 261 /// <summary>Validates the requested transport by cross checking it with the pre-defined signalR.transports</summary> 262 /// <param name="requestedTransport" type="Object">The designated transports that the user has specified.</param> 263 /// <param name="connection" type="signalR">The connection that will be using the requested transports. Used for logging purposes.</param> 264 /// <returns type="Object" /> 265 266 if ($.isArray(requestedTransport)) { 267 // Go through transport array and remove an "invalid" tranports 268 for (var i = requestedTransport.length - 1; i >= 0; i--) { 269 var transport = requestedTransport[i]; 270 if ($.type(transport) !== "string" || !signalR.transports[transport]) { 271 connection.log("Invalid transport: " + transport + ", removing it from the transports list."); 272 requestedTransport.splice(i, 1); 273 } 274 } 275 276 // Verify we still have transports left, if we dont then we have invalid transports 277 if (requestedTransport.length === 0) { 278 connection.log("No transports remain within the specified transport array."); 279 requestedTransport = null; 280 } 281 } else if (!signalR.transports[requestedTransport] && requestedTransport !== "auto") { 282 connection.log("Invalid transport: " + requestedTransport.toString() + "."); 283 requestedTransport = null; 284 } else if (requestedTransport === "auto" && signalR._.ieVersion <= 8) { 285 // If we're doing an auto transport and we're IE8 then force longPolling, #1764 286 return ["longPolling"]; 287 288 } 289 290 return requestedTransport; 291 } 292 293 function getDefaultPort(protocol) { 294 if (protocol === "http:") { 295 return 80; 296 } else if (protocol === "https:") { 297 return 443; 298 } 299 } 300 301 function addDefaultPort(protocol, url) { 302 // Remove ports from url. We have to check if there's a / or end of line 303 // following the port in order to avoid removing ports such as 8080. 304 if (url.match(/:\d+$/)) { 305 return url; 306 } else { 307 return url + ":" + getDefaultPort(protocol); 308 } 309 } 310 311 function ConnectingMessageBuffer(connection, drainCallback) { 312 var that = this, 313 buffer = []; 314 315 that.tryBuffer = function (message) { 316 if (connection.state === $.signalR.connectionState.connecting) { 317 buffer.push(message); 318 319 return true; 320 } 321 322 return false; 323 }; 324 325 that.drain = function () { 326 // Ensure that the connection is connected when we drain (do not want to drain while a connection is not active) 327 if (connection.state === $.signalR.connectionState.connected) { 328 while (buffer.length > 0) { 329 drainCallback(buffer.shift()); 330 } 331 } 332 }; 333 334 that.clear = function () { 335 buffer = []; 336 }; 337 } 338 339 signalR.fn = signalR.prototype = { 340 init: function (url, qs, logging) { 341 var $connection = $(this); 342 343 this.url = url; 344 this.qs = qs; 345 this.lastError = null; 346 this._ = { 347 keepAliveData: {}, 348 connectingMessageBuffer: new ConnectingMessageBuffer(this, function (message) { 349 $connection.triggerHandler(events.onReceived, [message]); 350 }), 351 lastMessageAt: new Date().getTime(), 352 lastActiveAt: new Date().getTime(), 353 beatInterval: 5000, // Default value, will only be overridden if keep alive is enabled, 354 beatHandle: null, 355 totalTransportConnectTimeout: 0 // This will be the sum of the TransportConnectTimeout sent in response to negotiate and connection.transportConnectTimeout 356 }; 357 if (typeof (logging) === "boolean") { 358 this.logging = logging; 359 } 360 }, 361 362 _parseResponse: function (response) { 363 var that = this; 364 365 if (!response) { 366 return response; 367 } else if (typeof response === "string") { 368 return that.json.parse(response); 369 } else { 370 return response; 371 } 372 }, 373 374 _originalJson: window.JSON, 375 376 json: window.JSON, 377 378 isCrossDomain: function (url, against) { 379 /// <summary>Checks if url is cross domain</summary> 380 /// <param name="url" type="String">The base URL</param> 381 /// <param name="against" type="Object"> 382 /// An optional argument to compare the URL against, if not specified it will be set to window.location. 383 /// If specified it must contain a protocol and a host property. 384 /// </param> 385 var link; 386 387 url = $.trim(url); 388 389 against = against || window.location; 390 391 if (url.indexOf("http") !== 0) { 392 return false; 393 } 394 395 // Create an anchor tag. 396 link = window.document.createElement("a"); 397 link.href = url; 398 399 // When checking for cross domain we have to special case port 80 because the window.location will remove the 400 return link.protocol + addDefaultPort(link.protocol, link.host) !== against.protocol + addDefaultPort(against.protocol, against.host); 401 }, 402 403 ajaxDataType: "text", 404 405 contentType: "application/json; charset=UTF-8", 406 407 logging: false, 408 409 state: signalR.connectionState.disconnected, 410 411 clientProtocol: "1.5", 412 413 reconnectDelay: 2000, 414 415 transportConnectTimeout: 0, 416 417 disconnectTimeout: 30000, // This should be set by the server in response to the negotiate request (30s default) 418 419 reconnectWindow: 30000, // This should be set by the server in response to the negotiate request 420 421 keepAliveWarnAt: 2 / 3, // Warn user of slow connection if we breach the X% mark of the keep alive timeout 422 423 start: function (options, callback) { 424 /// <summary>Starts the connection</summary> 425 /// <param name="options" type="Object">Options map</param> 426 /// <param name="callback" type="Function">A callback function to execute when the connection has started</param> 427 var connection = this, 428 config = { 429 pingInterval: 300000, 430 waitForPageLoad: true, 431 transport: "auto", 432 jsonp: false 433 }, 434 initialize, 435 deferred = connection._deferral || $.Deferred(), // Check to see if there is a pre-existing deferral that's being built on, if so we want to keep using it 436 parser = window.document.createElement("a"); 437 438 connection.lastError = null; 439 440 // Persist the deferral so that if start is called multiple times the same deferral is used. 441 connection._deferral = deferred; 442 443 if (!connection.json) { 444 // no JSON! 445 throw new Error("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."); 446 } 447 448 if ($.type(options) === "function") { 449 // Support calling with single callback parameter 450 callback = options; 451 } else if ($.type(options) === "object") { 452 $.extend(config, options); 453 if ($.type(config.callback) === "function") { 454 callback = config.callback; 455 } 456 } 457 458 config.transport = validateTransport(config.transport, connection); 459 460 // If the transport is invalid throw an error and abort start 461 if (!config.transport) { 462 throw new Error("SignalR: Invalid transport(s) specified, aborting start."); 463 } 464 465 connection._.config = config; 466 467 // Check to see if start is being called prior to page load 468 // If waitForPageLoad is true we then want to re-direct function call to the window load event 469 if (!_pageLoaded && config.waitForPageLoad === true) { 470 connection._.deferredStartHandler = function () { 471 connection.start(options, callback); 472 }; 473 _pageWindow.bind("load", connection._.deferredStartHandler); 474 475 return deferred.promise(); 476 } 477 478 // If we're already connecting just return the same deferral as the original connection start 479 if (connection.state === signalR.connectionState.connecting) { 480 return deferred.promise(); 481 } else if (changeState(connection, 482 signalR.connectionState.disconnected, 483 signalR.connectionState.connecting) === false) { 484 // We're not connecting so try and transition into connecting. 485 // If we fail to transition then we're either in connected or reconnecting. 486 487 deferred.resolve(connection); 488 return deferred.promise(); 489 } 490 491 configureStopReconnectingTimeout(connection); 492 493 // Resolve the full url 494 parser.href = connection.url; 495 if (!parser.protocol || parser.protocol === ":") { 496 connection.protocol = window.document.location.protocol; 497 connection.host = parser.host || window.document.location.host; 498 } else { 499 connection.protocol = parser.protocol; 500 connection.host = parser.host; 501 } 502 503 connection.baseUrl = connection.protocol + "//" + connection.host; 504 505 // Set the websocket protocol 506 connection.wsProtocol = connection.protocol === "https:" ? "wss://" : "ws://"; 507 508 // If jsonp with no/auto transport is specified, then set the transport to long polling 509 // since that is the only transport for which jsonp really makes sense. 510 // Some developers might actually choose to specify jsonp for same origin requests 511 // as demonstrated by Issue #623. 512 if (config.transport === "auto" && config.jsonp === true) { 513 config.transport = "longPolling"; 514 } 515 516 // If the url is protocol relative, prepend the current windows protocol to the url. 517 if (connection.url.indexOf("//") === 0) { 518 connection.url = window.location.protocol + connection.url; 519 connection.log("Protocol relative URL detected, normalizing it to '" + connection.url + "'."); 520 } 521 522 if (this.isCrossDomain(connection.url)) { 523 connection.log("Auto detected cross domain url."); 524 525 if (config.transport === "auto") { 526 // TODO: Support XDM with foreverFrame 527 config.transport = ["webSockets", "serverSentEvents", "longPolling"]; 528 } 529 530 if (typeof (config.withCredentials) === "undefined") { 531 config.withCredentials = true; 532 } 533 534 // Determine if jsonp is the only choice for negotiation, ajaxSend and ajaxAbort. 535 // i.e. if the browser doesn't supports CORS 536 // If it is, ignore any preference to the contrary, and switch to jsonp. 537 if (!config.jsonp) { 538 config.jsonp = !$.support.cors; 539 540 if (config.jsonp) { 541 connection.log("Using jsonp because this browser doesn't support CORS."); 542 } 543 } 544 545 connection.contentType = signalR._.defaultContentType; 546 } 547 548 connection.withCredentials = config.withCredentials; 549 550 connection.ajaxDataType = config.jsonp ? "jsonp" : "text"; 551 552 $(connection).bind(events.onStart, function (e, data) { 553 if ($.type(callback) === "function") { 554 callback.call(connection); 555 } 556 deferred.resolve(connection); 557 }); 558 559 connection._.initHandler = signalR.transports._logic.initHandler(connection); 560 561 initialize = function (transports, index) { 562 var noTransportError = signalR._.error(resources.noTransportOnInit); 563 564 index = index || 0; 565 if (index >= transports.length) { 566 if (index === 0) { 567 connection.log("No transports supported by the server were selected."); 568 } else if (index === 1) { 569 connection.log("No fallback transports were selected."); 570 } else { 571 connection.log("Fallback transports exhausted."); 572 } 573 574 // No transport initialized successfully 575 $(connection).triggerHandler(events.onError, [noTransportError]); 576 deferred.reject(noTransportError); 577 // Stop the connection if it has connected and move it into the disconnected state 578 connection.stop(); 579 return; 580 } 581 582 // The connection was aborted 583 if (connection.state === signalR.connectionState.disconnected) { 584 return; 585 } 586 587 var transportName = transports[index], 588 transport = signalR.transports[transportName], 589 onFallback = function () { 590 initialize(transports, index + 1); 591 }; 592 593 connection.transport = transport; 594 595 try { 596 connection._.initHandler.start(transport, function () { // success 597 // Firefox 11+ doesn't allow sync XHR withCredentials: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#withCredentials 598 var isFirefox11OrGreater = signalR._.firefoxMajorVersion(window.navigator.userAgent) >= 11, 599 asyncAbort = !!connection.withCredentials && isFirefox11OrGreater; 600 601 connection.log("The start request succeeded. Transitioning to the connected state."); 602 603 if (supportsKeepAlive(connection)) { 604 signalR.transports._logic.monitorKeepAlive(connection); 605 } 606 607 signalR.transports._logic.startHeartbeat(connection); 608 609 // Used to ensure low activity clients maintain their authentication. 610 // Must be configured once a transport has been decided to perform valid ping requests. 611 signalR._.configurePingInterval(connection); 612 613 if (!changeState(connection, 614 signalR.connectionState.connecting, 615 signalR.connectionState.connected)) { 616 connection.log("WARNING! The connection was not in the connecting state."); 617 } 618 619 // Drain any incoming buffered messages (messages that came in prior to connect) 620 connection._.connectingMessageBuffer.drain(); 621 622 $(connection).triggerHandler(events.onStart); 623 624 // wire the stop handler for when the user leaves the page 625 _pageWindow.bind("unload", function () { 626 connection.log("Window unloading, stopping the connection."); 627 628 connection.stop(asyncAbort); 629 }); 630 631 if (isFirefox11OrGreater) { 632 // Firefox does not fire cross-domain XHRs in the normal unload handler on tab close. 633 // #2400 634 _pageWindow.bind("beforeunload", function () { 635 // If connection.stop() runs runs in beforeunload and fails, it will also fail 636 // in unload unless connection.stop() runs after a timeout. 637 window.setTimeout(function () { 638 connection.stop(asyncAbort); 639 }, 0); 640 }); 641 } 642 }, onFallback); 643 } 644 catch (error) { 645 connection.log(transport.name + " transport threw '" + error.message + "' when attempting to start."); 646 onFallback(); 647 } 648 }; 649 650 var url = connection.url + "/negotiate", 651 onFailed = function (error, connection) { 652 var err = signalR._.error(resources.errorOnNegotiate, error, connection._.negotiateRequest); 653 654 $(connection).triggerHandler(events.onError, err); 655 deferred.reject(err); 656 // Stop the connection if negotiate failed 657 connection.stop(); 658 }; 659 660 $(connection).triggerHandler(events.onStarting); 661 662 url = signalR.transports._logic.prepareQueryString(connection, url); 663 664 connection.log("Negotiating with '" + url + "'."); 665 666 // Save the ajax negotiate request object so we can abort it if stop is called while the request is in flight. 667 connection._.negotiateRequest = signalR.transports._logic.ajax(connection, { 668 url: url, 669 error: function (error, statusText) { 670 // We don't want to cause any errors if we're aborting our own negotiate request. 671 if (statusText !== _negotiateAbortText) { 672 onFailed(error, connection); 673 } else { 674 // This rejection will noop if the deferred has already been resolved or rejected. 675 deferred.reject(signalR._.error(resources.stoppedWhileNegotiating, null /* error */, connection._.negotiateRequest)); 676 } 677 }, 678 success: function (result) { 679 var res, 680 keepAliveData, 681 protocolError, 682 transports = [], 683 supportedTransports = []; 684 685 try { 686 res = connection._parseResponse(result); 687 } catch (error) { 688 onFailed(signalR._.error(resources.errorParsingNegotiateResponse, error), connection); 689 return; 690 } 691 692 keepAliveData = connection._.keepAliveData; 693 connection.appRelativeUrl = res.Url; 694 connection.id = res.ConnectionId; 695 connection.token = res.ConnectionToken; 696 connection.webSocketServerUrl = res.WebSocketServerUrl; 697 698 // The long poll timeout is the ConnectionTimeout plus 10 seconds 699 connection._.pollTimeout = res.ConnectionTimeout * 1000 + 10000; // in ms 700 701 // Once the server has labeled the PersistentConnection as Disconnected, we should stop attempting to reconnect 702 // after res.DisconnectTimeout seconds. 703 connection.disconnectTimeout = res.DisconnectTimeout * 1000; // in ms 704 705 // Add the TransportConnectTimeout from the response to the transportConnectTimeout from the client to calculate the total timeout 706 connection._.totalTransportConnectTimeout = connection.transportConnectTimeout + res.TransportConnectTimeout * 1000; 707 708 // If we have a keep alive 709 if (res.KeepAliveTimeout) { 710 // Register the keep alive data as activated 711 keepAliveData.activated = true; 712 713 // Timeout to designate when to force the connection into reconnecting converted to milliseconds 714 keepAliveData.timeout = res.KeepAliveTimeout * 1000; 715 716 // Timeout to designate when to warn the developer that the connection may be dead or is not responding. 717 keepAliveData.timeoutWarning = keepAliveData.timeout * connection.keepAliveWarnAt; 718 719 // Instantiate the frequency in which we check the keep alive. It must be short in order to not miss/pick up any changes 720 connection._.beatInterval = (keepAliveData.timeout - keepAliveData.timeoutWarning) / 3; 721 } else { 722 keepAliveData.activated = false; 723 } 724 725 connection.reconnectWindow = connection.disconnectTimeout + (keepAliveData.timeout || 0); 726 727 if (!res.ProtocolVersion || res.ProtocolVersion !== connection.clientProtocol) { 728 protocolError = signalR._.error(signalR._.format(resources.protocolIncompatible, connection.clientProtocol, res.ProtocolVersion)); 729 $(connection).triggerHandler(events.onError, [protocolError]); 730 deferred.reject(protocolError); 731 732 return; 733 } 734 735 $.each(signalR.transports, function (key) { 736 if ((key.indexOf("_") === 0) || (key === "webSockets" && !res.TryWebSockets)) { 737 return true; 738 } 739 supportedTransports.push(key); 740 }); 741 742 if ($.isArray(config.transport)) { 743 $.each(config.transport, function (_, transport) { 744 if ($.inArray(transport, supportedTransports) >= 0) { 745 transports.push(transport); 746 } 747 }); 748 } else if (config.transport === "auto") { 749 transports = supportedTransports; 750 } else if ($.inArray(config.transport, supportedTransports) >= 0) { 751 transports.push(config.transport); 752 } 753 754 initialize(transports); 755 } 756 }); 757 758 return deferred.promise(); 759 }, 760 761 starting: function (callback) { 762 /// <summary>Adds a callback that will be invoked before anything is sent over the connection</summary> 763 /// <param name="callback" type="Function">A callback function to execute before the connection is fully instantiated.</param> 764 /// <returns type="signalR" /> 765 var connection = this; 766 $(connection).bind(events.onStarting, function (e, data) { 767 callback.call(connection); 768 }); 769 return connection; 770 }, 771 772 send: function (data) { 773 /// <summary>Sends data over the connection</summary> 774 /// <param name="data" type="String">The data to send over the connection</param> 775 /// <returns type="signalR" /> 776 var connection = this; 777 778 if (connection.state === signalR.connectionState.disconnected) { 779 // Connection hasn't been started yet 780 throw new Error("SignalR: Connection must be started before data can be sent. Call .start() before .send()"); 781 } 782 783 if (connection.state === signalR.connectionState.connecting) { 784 // Connection hasn't been started yet 785 throw new Error("SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started."); 786 } 787 788 connection.transport.send(connection, data); 789 // REVIEW: Should we return deferred here? 790 return connection; 791 }, 792 793 received: function (callback) { 794 /// <summary>Adds a callback that will be invoked after anything is received over the connection</summary> 795 /// <param name="callback" type="Function">A callback function to execute when any data is received on the connection</param> 796 /// <returns type="signalR" /> 797 var connection = this; 798 $(connection).bind(events.onReceived, function (e, data) { 799 callback.call(connection, data); 800 }); 801 return connection; 802 }, 803 804 stateChanged: function (callback) { 805 /// <summary>Adds a callback that will be invoked when the connection state changes</summary> 806 /// <param name="callback" type="Function">A callback function to execute when the connection state changes</param> 807 /// <returns type="signalR" /> 808 var connection = this; 809 $(connection).bind(events.onStateChanged, function (e, data) { 810 callback.call(connection, data); 811 }); 812 return connection; 813 }, 814 815 error: function (callback) { 816 /// <summary>Adds a callback that will be invoked after an error occurs with the connection</summary> 817 /// <param name="callback" type="Function">A callback function to execute when an error occurs on the connection</param> 818 /// <returns type="signalR" /> 819 var connection = this; 820 $(connection).bind(events.onError, function (e, errorData, sendData) { 821 connection.lastError = errorData; 822 // In practice 'errorData' is the SignalR built error object. 823 // In practice 'sendData' is undefined for all error events except those triggered by 824 // 'ajaxSend' and 'webSockets.send'.'sendData' is the original send payload. 825 callback.call(connection, errorData, sendData); 826 }); 827 return connection; 828 }, 829 830 disconnected: function (callback) { 831 /// <summary>Adds a callback that will be invoked when the client disconnects</summary> 832 /// <param name="callback" type="Function">A callback function to execute when the connection is broken</param> 833 /// <returns type="signalR" /> 834 var connection = this; 835 $(connection).bind(events.onDisconnect, function (e, data) { 836 callback.call(connection); 837 }); 838 return connection; 839 }, 840 841 connectionSlow: function (callback) { 842 /// <summary>Adds a callback that will be invoked when the client detects a slow connection</summary> 843 /// <param name="callback" type="Function">A callback function to execute when the connection is slow</param> 844 /// <returns type="signalR" /> 845 var connection = this; 846 $(connection).bind(events.onConnectionSlow, function (e, data) { 847 callback.call(connection); 848 }); 849 850 return connection; 851 }, 852 853 reconnecting: function (callback) { 854 /// <summary>Adds a callback that will be invoked when the underlying transport begins reconnecting</summary> 855 /// <param name="callback" type="Function">A callback function to execute when the connection enters a reconnecting state</param> 856 /// <returns type="signalR" /> 857 var connection = this; 858 $(connection).bind(events.onReconnecting, function (e, data) { 859 callback.call(connection); 860 }); 861 return connection; 862 }, 863 864 reconnected: function (callback) { 865 /// <summary>Adds a callback that will be invoked when the underlying transport reconnects</summary> 866 /// <param name="callback" type="Function">A callback function to execute when the connection is restored</param> 867 /// <returns type="signalR" /> 868 var connection = this; 869 $(connection).bind(events.onReconnect, function (e, data) { 870 callback.call(connection); 871 }); 872 return connection; 873 }, 874 875 stop: function (async, notifyServer) { 876 /// <summary>Stops listening</summary> 877 /// <param name="async" type="Boolean">Whether or not to asynchronously abort the connection</param> 878 /// <param name="notifyServer" type="Boolean">Whether we want to notify the server that we are aborting the connection</param> 879 /// <returns type="signalR" /> 880 var connection = this, 881 // Save deferral because this is always cleaned up 882 deferral = connection._deferral; 883 884 // Verify that we've bound a load event. 885 if (connection._.deferredStartHandler) { 886 // Unbind the event. 887 _pageWindow.unbind("load", connection._.deferredStartHandler); 888 } 889 890 // Always clean up private non-timeout based state. 891 delete connection._.config; 892 delete connection._.deferredStartHandler; 893 894 // This needs to be checked despite the connection state because a connection start can be deferred until page load. 895 // If we've deferred the start due to a page load we need to unbind the "onLoad" -> start event. 896 if (!_pageLoaded && (!connection._.config || connection._.config.waitForPageLoad === true)) { 897 connection.log("Stopping connection prior to negotiate."); 898 899 // If we have a deferral we should reject it 900 if (deferral) { 901 deferral.reject(signalR._.error(resources.stoppedWhileLoading)); 902 } 903 904 // Short-circuit because the start has not been fully started. 905 return; 906 } 907 908 if (connection.state === signalR.connectionState.disconnected) { 909 return; 910 } 911 912 connection.log("Stopping connection."); 913 914 // Clear this no matter what 915 window.clearTimeout(connection._.beatHandle); 916 window.clearInterval(connection._.pingIntervalId); 917 918 if (connection.transport) { 919 connection.transport.stop(connection); 920 921 if (notifyServer !== false) { 922 connection.transport.abort(connection, async); 923 } 924 925 if (supportsKeepAlive(connection)) { 926 signalR.transports._logic.stopMonitoringKeepAlive(connection); 927 } 928 929 connection.transport = null; 930 } 931 932 if (connection._.negotiateRequest) { 933 // If the negotiation request has already completed this will noop. 934 connection._.negotiateRequest.abort(_negotiateAbortText); 935 delete connection._.negotiateRequest; 936 } 937 938 // Ensure that initHandler.stop() is called before connection._deferral is deleted 939 if (connection._.initHandler) { 940 connection._.initHandler.stop(); 941 } 942 943 delete connection._deferral; 944 delete connection.messageId; 945 delete connection.groupsToken; 946 delete connection.id; 947 delete connection._.pingIntervalId; 948 delete connection._.lastMessageAt; 949 delete connection._.lastActiveAt; 950 951 // Clear out our message buffer 952 connection._.connectingMessageBuffer.clear(); 953 954 // Clean up this event 955 $(connection).unbind(events.onStart)
vendor: 8,847 bytes, lines 955-1191
955; 956 957 // Trigger the disconnect event 958 changeState(connection, connection.state, signalR.connectionState.disconnected); 959 $(connection).triggerHandler(events.onDisconnect); 960 961 return connection; 962 }, 963 964 log: function (msg) { 965 log(msg, this.logging); 966 } 967 }; 968 969 signalR.fn.init.prototype = signalR.fn; 970 971 signalR.noConflict = function () { 972 /// <summary>Reinstates the original value of $.connection and returns the signalR object for manual assignment</summary> 973 /// <returns type="signalR" /> 974 if ($.connection === signalR) { 975 $.connection = _connection; 976 } 977 return signalR; 978 }; 979 980 if ($.connection) { 981 _connection = $.connection; 982 } 983 984 $.connection = $.signalR = signalR; 985 986}(window.jQuery, window)); 987/* jquery.signalR.transports.common.js */ 988// Copyright (c) .NET Foundation. All rights reserved. 989// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 990 991/*global window:false */ 992/// <reference path="jquery.signalR.core.js" /> 993 994(function ($, window, undefined) { 995 996 var signalR = $.signalR, 997 events = $.signalR.events, 998 changeState = $.signalR.changeState, 999 startAbortText = "__Start Aborted__", 1000 transportLogic; 1001 1002 signalR.transports = {}; 1003 1004 function beat(connection) { 1005 if (connection._.keepAliveData.monitoring) { 1006 checkIfAlive(connection); 1007 } 1008 1009 // Ensure that we successfully marked active before continuing the heartbeat. 1010 if (transportLogic.markActive(connection)) { 1011 connection._.beatHandle = window.setTimeout(function () { 1012 beat(connection); 1013 }, connection._.beatInterval); 1014 } 1015 } 1016 1017 function checkIfAlive(connection) { 1018 var keepAliveData = connection._.keepAliveData, 1019 timeElapsed; 1020 1021 // Only check if we're connected 1022 if (connection.state === signalR.connectionState.connected) { 1023 timeElapsed = new Date().getTime() - connection._.lastMessageAt; 1024 1025 // Check if the keep alive has completely timed out 1026 if (timeElapsed >= keepAliveData.timeout) { 1027 connection.log("Keep alive timed out. Notifying transport that connection has been lost."); 1028 1029 // Notify transport that the connection has been lost 1030 connection.transport.lostConnection(connection); 1031 } else if (timeElapsed >= keepAliveData.timeoutWarning) { 1032 // This is to assure that the user only gets a single warning 1033 if (!keepAliveData.userNotified) { 1034 connection.log("Keep alive has been missed, connection may be dead/slow."); 1035 $(connection).triggerHandler(events.onConnectionSlow); 1036 keepAliveData.userNotified = true; 1037 } 1038 } else { 1039 keepAliveData.userNotified = false; 1040 } 1041 } 1042 } 1043 1044 function getAjaxUrl(connection, path) { 1045 var url = connection.url + path; 1046 1047 if (connection.transport) { 1048 url += "?transport=" + connection.transport.name; 1049 } 1050 1051 return transportLogic.prepareQueryString(connection, url); 1052 } 1053 1054 function InitHandler(connection) { 1055 this.connection = connection; 1056 1057 this.startRequested = false; 1058 this.startCompleted = false; 1059 this.connectionStopped = false; 1060 } 1061 1062 InitHandler.prototype = { 1063 start: function (transport, onSuccess, onFallback) { 1064 var that = this, 1065 connection = that.connection, 1066 failCalled = false; 1067 1068 if (that.startRequested || that.connectionStopped) { 1069 connection.log("WARNING! " + transport.name + " transport cannot be started. Initialization ongoing or completed."); 1070 return; 1071 } 1072 1073 connection.log(transport.name + " transport starting."); 1074 1075 transport.start(connection, function () { 1076 if (!failCalled) { 1077 that.initReceived(transport, onSuccess); 1078 } 1079 }, function (error) { 1080 // Don't allow the same transport to cause onFallback to be called twice 1081 if (!failCalled) { 1082 failCalled = true; 1083 that.transportFailed(transport, error, onFallback); 1084 } 1085 1086 // Returns true if the transport should stop; 1087 // false if it should attempt to reconnect 1088 return !that.startCompleted || that.connectionStopped; 1089 }); 1090 1091 that.transportTimeoutHandle = window.setTimeout(function () { 1092 if (!failCalled) { 1093 failCalled = true; 1094 connection.log(transport.name + " transport timed out when trying to connect."); 1095 that.transportFailed(transport, undefined, onFallback); 1096 } 1097 }, connection._.totalTransportConnectTimeout); 1098 }, 1099 1100 stop: function () { 1101 this.connectionStopped = true; 1102 window.clearTimeout(this.transportTimeoutHandle); 1103 signalR.transports._logic.tryAbortStartRequest(this.connection); 1104 }, 1105 1106 initReceived: function (transport, onSuccess) { 1107 var that = this, 1108 connection = that.connection; 1109 1110 if (that.startRequested) { 1111 connection.log("WARNING! The client received multiple init messages."); 1112 return; 1113 } 1114 1115 if (that.connectionStopped) { 1116 return; 1117 } 1118 1119 that.startRequested = true; 1120 window.clearTimeout(that.transportTimeoutHandle); 1121 1122 connection.log(transport.name + " transport connected. Initiating start request."); 1123 signalR.transports._logic.ajaxStart(connection, function () { 1124 that.startCompleted = true; 1125 onSuccess(); 1126 }); 1127 }, 1128 1129 transportFailed: function (transport, error, onFallback) { 1130 var connection = this.connection, 1131 deferred = connection._deferral, 1132 wrappedError; 1133 1134 if (this.connectionStopped) { 1135 return; 1136 } 1137 1138 window.clearTimeout(this.transportTimeoutHandle); 1139 1140 if (!this.startRequested) { 1141 transport.stop(connection); 1142 1143 connection.log(transport.name + " transport failed to connect. Attempting to fall back."); 1144 onFallback(); 1145 } else if (!this.startCompleted) { 1146 // Do not attempt to fall back if a start request is ongoing during a transport failure. 1147 // Instead, trigger an error and stop the connection. 1148 wrappedError = signalR._.error(signalR.resources.errorDuringStartRequest, error); 1149 1150 connection.log(transport.name + " transport failed during the start request. Stopping the connection."); 1151 $(connection).triggerHandler(events.onError, [wrappedError]); 1152 if (deferred) { 1153 deferred.reject(wrappedError); 1154 } 1155 1156 connection.stop(); 1157 } else { 1158 // The start request has completed, but the connection has not stopped. 1159 // No need to do anything here. The transport should attempt its normal reconnect logic. 1160 } 1161 } 1162 }; 1163 1164 transportLogic = signalR.transports._logic = { 1165 ajax: function (connection, options) { 1166 return $.ajax( 1167 $.extend(/*deep copy*/ true, {}, $.signalR.ajaxDefaults, { 1168 type: "GET", 1169 data: {}, 1170 xhrFields: { withCredentials: connection.withCredentials }, 1171 contentType: connection.contentType, 1172 dataType: connection.ajaxDataType 1173 }, options)); 1174 }, 1175 1176 pingServer: function (connection) { 1177 /// <summary>Pings the server</summary> 1178 /// <param name="connection" type="signalr">Connection associated with the server ping</param> 1179 /// <returns type="signalR" /> 1180 var url, 1181 xhr, 1182 deferral = $.Deferred(); 1183 1184 if (connection.transport) { 1185 url = connection.url + "/ping"; 1186 1187 url = transportLogic.addQs(url, connection.qs); 1188 1189 xhr = transportLogic.ajax(connection, { 1190 url: url, 1191
1191success: function (result) { 1192 var data; 1193 1194 try { 1195 data = connection._parseResponse(result); 1196 } 1197 catch (error) { 1198 deferral.reject( 1199 signalR._.transportError( 1200 signalR.resources.pingServerFailedParse, 1201 connection.transport, 1202 error, 1203 xhr 1204 ) 1205 ); 1206 connection.stop(); 1207 return; 1208 } 1209 1210 if (data.Response === "pong") { 1211 deferral.resolve(); 1212 } 1213 else { 1214 deferral.reject( 1215 signalR._.transportError( 1216 signalR._.format(signalR.resources.pingServerFailedInvalidResponse, result), 1217 connection.transport, 1218 null /* error */, 1219 xhr 1220 ) 1221 ); 1222 } 1223 }, 1224 error: function (error) { 1225 if (error.status === 401 || error.status === 403) { 1226 deferral.reject( 1227 signalR._.transportError( 1228 signalR._.format(signalR.resources.pingServerFailedStatusCode, error.status), 1229 connection.transport, 1230 error, 1231 xhr 1232 ) 1233 ); 1234 connection.stop(); 1235 } 1236 else { 1237 deferral.reject( 1238 signalR._.transportError( 1239 signalR.resources.pingServerFailed, 1240 connection.transport,
vendor: 15,235 bytes, lines 1241-1622
1241 error, 1242 xhr 1243 ) 1244 ); 1245 } 1246 } 1247 }); 1248 } 1249 else { 1250 deferral.reject( 1251 signalR._.transportError( 1252 signalR.resources.noConnectionTransport, 1253 connection.transport 1254 ) 1255 ); 1256 } 1257 1258 return deferral.promise(); 1259 }, 1260 1261 prepareQueryString: function (connection, url) { 1262 var preparedUrl; 1263 1264 // Use addQs to start since it handles the ?/& prefix for us 1265 preparedUrl = transportLogic.addQs(url, "clientProtocol=" + connection.clientProtocol); 1266 1267 // Add the user-specified query string params if any 1268 preparedUrl = transportLogic.addQs(preparedUrl, connection.qs); 1269 1270 if (connection.token) { 1271 preparedUrl += "&connectionToken=" + window.encodeURIComponent(connection.token); 1272 } 1273 1274 if (connection.data) { 1275 preparedUrl += "&connectionData=" + window.encodeURIComponent(connection.data); 1276 } 1277 1278 return preparedUrl; 1279 }, 1280 1281 addQs: function (url, qs) { 1282 var appender = url.indexOf("?") !== -1 ? "&" : "?", 1283 firstChar; 1284 1285 if (!qs) { 1286 return url; 1287 } 1288 1289 if (typeof (qs) === "object") { 1290 return url + appender + $.param(qs); 1291 } 1292 1293 if (typeof (qs) === "string") { 1294 firstChar = qs.charAt(0); 1295 1296 if (firstChar === "?" || firstChar === "&") { 1297 appender = ""; 1298 } 1299 1300 return url + appender + qs; 1301 } 1302 1303 throw new Error("Query string property must be either a string or object."); 1304 }, 1305 1306 // BUG #2953: The url needs to be same otherwise it will cause a memory leak 1307 getUrl: function (connection, transport, reconnecting, poll, ajaxPost) { 1308 /// <summary>Gets the url for making a GET based connect request</summary> 1309 var baseUrl = transport === "webSockets" ? "" : connection.baseUrl, 1310 url = baseUrl + connection.appRelativeUrl, 1311 qs = "transport=" + transport; 1312 1313 if (!ajaxPost && connection.groupsToken) { 1314 qs += "&groupsToken=" + window.encodeURIComponent(connection.groupsToken); 1315 } 1316 1317 if (!reconnecting) { 1318 url += "/connect"; 1319 } else { 1320 if (poll) { 1321 // longPolling transport specific 1322 url += "/poll"; 1323 } else { 1324 url += "/reconnect"; 1325 } 1326 1327 if (!ajaxPost && connection.messageId) { 1328 qs += "&messageId=" + window.encodeURIComponent(connection.messageId); 1329 } 1330 } 1331 url += "?" + qs; 1332 url = transportLogic.prepareQueryString(connection, url); 1333 1334 if (!ajaxPost) { 1335 url += "&tid=" + Math.floor(Math.random() * 11); 1336 } 1337 1338 return url; 1339 }, 1340 1341 maximizePersistentResponse: function (minPersistentResponse) { 1342 return { 1343 MessageId: minPersistentResponse.C, 1344 Messages: minPersistentResponse.M, 1345 Initialized: typeof (minPersistentResponse.S) !== "undefined" ? true : false, 1346 ShouldReconnect: typeof (minPersistentResponse.T) !== "undefined" ? true : false, 1347 LongPollDelay: minPersistentResponse.L, 1348 GroupsToken: minPersistentResponse.G 1349 }; 1350 }, 1351 1352 updateGroups: function (connection, groupsToken) { 1353 if (groupsToken) { 1354 connection.groupsToken = groupsToken; 1355 } 1356 }, 1357 1358 stringifySend: function (connection, message) { 1359 if (typeof (message) === "string" || typeof (message) === "undefined" || message === null) { 1360 return message; 1361 } 1362 return connection.json.stringify(message); 1363 }, 1364 1365 ajaxSend: function (connection, data) { 1366 var payload = transportLogic.stringifySend(connection, data), 1367 url = getAjaxUrl(connection, "/send"), 1368 xhr, 1369 onFail = function (error, connection) { 1370 $(connection).triggerHandler(events.onError, [signalR._.transportError(signalR.resources.sendFailed, connection.transport, error, xhr), data]); 1371 }; 1372 1373 1374 xhr = transportLogic.ajax(connection, { 1375 url: url, 1376 type: connection.ajaxDataType === "jsonp" ? "GET" : "POST", 1377 contentType: signalR._.defaultContentType, 1378 data: { 1379 data: payload 1380 }, 1381 success: function (result) { 1382 var res; 1383 1384 if (result) { 1385 try { 1386 res = connection._parseResponse(result); 1387 } 1388 catch (error) { 1389 onFail(error, connection); 1390 connection.stop(); 1391 return; 1392 } 1393 1394 transportLogic.triggerReceived(connection, res); 1395 } 1396 }, 1397 error: function (error, textStatus) { 1398 if (textStatus === "abort" || textStatus === "parsererror") { 1399 // The parsererror happens for sends that don't return any data, and hence 1400 // don't write the jsonp callback to the response. This is harder to fix on the server 1401 // so just hack around it on the client for now. 1402 return; 1403 } 1404 1405 onFail(error, connection); 1406 } 1407 }); 1408 1409 return xhr; 1410 }, 1411 1412 ajaxAbort: function (connection, async) { 1413 if (typeof (connection.transport) === "undefined") { 1414 return; 1415 } 1416 1417 // Async by default unless explicitly overidden 1418 async = typeof async === "undefined" ? true : async; 1419 1420 var url = getAjaxUrl(connection, "/abort"); 1421 1422 transportLogic.ajax(connection, { 1423 url: url, 1424 async: async, 1425 timeout: 1000, 1426 type: "POST" 1427 }); 1428 1429 connection.log("Fired ajax abort async = " + async + "."); 1430 }, 1431 1432 ajaxStart: function (connection, onSuccess) { 1433 var rejectDeferred = function (error) { 1434 var deferred = connection._deferral; 1435 if (deferred) { 1436 deferred.reject(error); 1437 } 1438 }, 1439 triggerStartError = function (error) { 1440 connection.log("The start request failed. Stopping the connection."); 1441 $(connection).triggerHandler(events.onError, [error]); 1442 rejectDeferred(error); 1443 connection.stop(); 1444 }; 1445 1446 connection._.startRequest = transportLogic.ajax(connection, { 1447 url: getAjaxUrl(connection, "/start"), 1448 success: function (result, statusText, xhr) { 1449 var data; 1450 1451 try { 1452 data = connection._parseResponse(result); 1453 } catch (error) { 1454 triggerStartError(signalR._.error( 1455 signalR._.format(signalR.resources.errorParsingStartResponse, result), 1456 error, xhr)); 1457 return; 1458 } 1459 1460 if (data.Response === "started") { 1461 onSuccess(); 1462 } else { 1463 triggerStartError(signalR._.error( 1464 signalR._.format(signalR.resources.invalidStartResponse, result), 1465 null /* error */, xhr)); 1466 } 1467 }, 1468 error: function (xhr, statusText, error) { 1469 if (statusText !== startAbortText) { 1470 triggerStartError(signalR._.error( 1471 signalR.resources.errorDuringStartRequest, 1472 error, xhr)); 1473 } else { 1474 // Stop has been called, no need to trigger the error handler 1475 // or stop the connection again with onStartError 1476 connection.log("The start request aborted because connection.stop() was called."); 1477 rejectDeferred(signalR._.error( 1478 signalR.resources.stoppedDuringStartRequest, 1479 null /* error */, xhr)); 1480 } 1481 } 1482 }); 1483 }, 1484 1485 tryAbortStartRequest: function (connection) { 1486 if (connection._.startRequest) { 1487 // If the start request has already completed this will noop. 1488 connection._.startRequest.abort(startAbortText); 1489 delete connection._.startRequest; 1490 } 1491 }, 1492 1493 tryInitialize: function (connection, persistentResponse, onInitialized) { 1494 if (persistentResponse.Initialized && onInitialized) { 1495 onInitialized(); 1496 } else if (persistentResponse.Initialized) { 1497 connection.log("WARNING! The client received an init message after reconnecting."); 1498 } 1499 1500 }, 1501 1502 triggerReceived: function (connection, data) { 1503 if (!connection._.connectingMessageBuffer.tryBuffer(data)) { 1504 $(connection).triggerHandler(events.onReceived, [data]); 1505 } 1506 }, 1507 1508 processMessages: function (connection, minData, onInitialized) { 1509 var data; 1510 1511 // Update the last message time stamp 1512 transportLogic.markLastMessage(connection); 1513 1514 if (minData) { 1515 data = transportLogic.maximizePersistentResponse(minData); 1516 1517 transportLogic.updateGroups(connection, data.GroupsToken); 1518 1519 if (data.MessageId) { 1520 connection.messageId = data.MessageId; 1521 } 1522 1523 if (data.Messages) { 1524 $.each(data.Messages, function (index, message) { 1525 transportLogic.triggerReceived(connection, message); 1526 }); 1527 1528 transportLogic.tryInitialize(connection, data, onInitialized); 1529 } 1530 } 1531 }, 1532 1533 monitorKeepAlive: function (connection) { 1534 var keepAliveData = connection._.keepAliveData; 1535 1536 // If we haven't initiated the keep alive timeouts then we need to 1537 if (!keepAliveData.monitoring) { 1538 keepAliveData.monitoring = true; 1539 1540 transportLogic.markLastMessage(connection); 1541 1542 // Save the function so we can unbind it on stop 1543 connection._.keepAliveData.reconnectKeepAliveUpdate = function () { 1544 // Mark a new message so that keep alive doesn't time out connections 1545 transportLogic.markLastMessage(connection); 1546 }; 1547 1548 // Update Keep alive on reconnect 1549 $(connection).bind(events.onReconnect, connection._.keepAliveData.reconnectKeepAliveUpdate); 1550 1551 connection.log("Now monitoring keep alive with a warning timeout of " + keepAliveData.timeoutWarning + ", keep alive timeout of " + keepAliveData.timeout + " and disconnecting timeout of " + connection.disconnectTimeout); 1552 } else { 1553 connection.log("Tried to monitor keep alive but it's already being monitored."); 1554 } 1555 }, 1556 1557 stopMonitoringKeepAlive: function (connection) { 1558 var keepAliveData = connection._.keepAliveData; 1559 1560 // Only attempt to stop the keep alive monitoring if its being monitored 1561 if (keepAliveData.monitoring) { 1562 // Stop monitoring 1563 keepAliveData.monitoring = false; 1564 1565 // Remove the updateKeepAlive function from the reconnect event 1566 $(connection).unbind(events.onReconnect, connection._.keepAliveData.reconnectKeepAliveUpdate); 1567 1568 // Clear all the keep alive data 1569 connection._.keepAliveData = {}; 1570 connection.log("Stopping the monitoring of the keep alive."); 1571 } 1572 }, 1573 1574 startHeartbeat: function (connection) { 1575 connection._.lastActiveAt = new Date().getTime(); 1576 beat(connection); 1577 }, 1578 1579 markLastMessage: function (connection) { 1580 connection._.lastMessageAt = new Date().getTime(); 1581 }, 1582 1583 markActive: function (connection) { 1584 if (transportLogic.verifyLastActive(connection)) { 1585 connection._.lastActiveAt = new Date().getTime(); 1586 return true; 1587 } 1588 1589 return false; 1590 }, 1591 1592 isConnectedOrReconnecting: function (connection) { 1593 return connection.state === signalR.connectionState.connected || 1594 connection.state === signalR.connectionState.reconnecting; 1595 }, 1596 1597 ensureReconnectingState: function (connection) { 1598 if (changeState(connection, 1599 signalR.connectionState.connected, 1600 signalR.connectionState.reconnecting) === true) { 1601 $(connection).triggerHandler(events.onReconnecting); 1602 } 1603 return connection.state === signalR.connectionState.reconnecting; 1604 }, 1605 1606 clearReconnectTimeout: function (connection) { 1607 if (connection && connection._.reconnectTimeout) { 1608 window.clearTimeout(connection._.reconnectTimeout); 1609 delete connection._.reconnectTimeout; 1610 } 1611 }, 1612 1613 verifyLastActive: function (connection) { 1614 if (new Date().getTime() - connection._.lastActiveAt >= connection.reconnectWindow) { 1615 var message = signalR._.format(signalR.resources.reconnectWindowTimeout, new Date(connection._.lastActiveAt), connection.reconnectWindow); 1616 connection.log(message); 1617 $(connection).triggerHandler(events.onError, [signalR._.error(message, /* source */ "TimeoutException")]); 1618 connection.stop(/* async */ false, /* notifyServer */ false); 1619 return false; 1620 } 1621 1622 return tru
vendor: 6,932 bytes, lines 1622-1797
1622e; 1623 }, 1624 1625 reconnect: function (connection, transportName) { 1626 var transport = signalR.transports[transportName]; 1627 1628 // We should only set a reconnectTimeout if we are currently connected 1629 // and a reconnectTimeout isn't already set. 1630 if (transportLogic.isConnectedOrReconnecting(connection) && !connection._.reconnectTimeout) { 1631 // Need to verify before the setTimeout occurs because an application sleep could occur during the setTimeout duration. 1632 if (!transportLogic.verifyLastActive(connection)) { 1633 return; 1634 } 1635 1636 connection._.reconnectTimeout = window.setTimeout(function () { 1637 if (!transportLogic.verifyLastActive(connection)) { 1638 return; 1639 } 1640 1641 transport.stop(connection); 1642 1643 if (transportLogic.ensureReconnectingState(connection)) { 1644 connection.log(transportName + " reconnecting."); 1645 transport.start(connection); 1646 } 1647 }, connection.reconnectDelay); 1648 } 1649 }, 1650 1651 handleParseFailure: function (connection, result, error, onFailed, context) { 1652 var wrappedError = signalR._.transportError( 1653 signalR._.format(signalR.resources.parseFailed, result), 1654 connection.transport, 1655 error, 1656 context); 1657 1658 // If we're in the initialization phase trigger onFailed, otherwise stop the connection. 1659 if (onFailed && onFailed(wrappedError)) { 1660 connection.log("Failed to parse server response while attempting to connect."); 1661 } else { 1662 $(connection).triggerHandler(events.onError, [wrappedError]); 1663 connection.stop(); 1664 } 1665 }, 1666 1667 initHandler: function (connection) { 1668 return new InitHandler(connection); 1669 }, 1670 1671 foreverFrame: { 1672 count: 0, 1673 connections: {} 1674 } 1675 }; 1676 1677}(window.jQuery, window)); 1678/* jquery.signalR.transports.webSockets.js */ 1679// Copyright (c) .NET Foundation. All rights reserved. 1680// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 1681 1682 1683/*global window:false */ 1684/// <reference path="jquery.signalR.transports.common.js" /> 1685 1686(function ($, window, undefined) { 1687 1688 var signalR = $.signalR, 1689 events = $.signalR.events, 1690 changeState = $.signalR.changeState, 1691 transportLogic = signalR.transports._logic; 1692 1693 signalR.transports.webSockets = { 1694 name: "webSockets", 1695 1696 supportsKeepAlive: function () { 1697 return true; 1698 }, 1699 1700 send: function (connection, data) { 1701 var payload = transportLogic.stringifySend(connection, data); 1702 1703 try { 1704 connection.socket.send(payload); 1705 } catch (ex) { 1706 $(connection).triggerHandler(events.onError, 1707 [signalR._.transportError( 1708 signalR.resources.webSocketsInvalidState, 1709 connection.transport, 1710 ex, 1711 connection.socket 1712 ), 1713 data]); 1714 } 1715 }, 1716 1717 start: function (connection, onSuccess, onFailed) { 1718 var url, 1719 opened = false, 1720 that = this, 1721 reconnecting = !onSuccess, 1722 $connection = $(connection); 1723 1724 if (!window.WebSocket) { 1725 onFailed(); 1726 return; 1727 } 1728 1729 if (!connection.socket) { 1730 if (connection.webSocketServerUrl) { 1731 url = connection.webSocketServerUrl; 1732 } else { 1733 url = connection.wsProtocol + connection.host; 1734 } 1735 1736 url += transportLogic.getUrl(connection, this.name, reconnecting); 1737 1738 connection.log("Connecting to websocket endpoint '" + url + "'."); 1739 connection.socket = new window.WebSocket(url); 1740 1741 connection.socket.onopen = function () { 1742 opened = true; 1743 connection.log("Websocket opened."); 1744 1745 transportLogic.clearReconnectTimeout(connection); 1746 1747 if (changeState(connection, 1748 signalR.connectionState.reconnecting, 1749 signalR.connectionState.connected) === true) { 1750 $connection.triggerHandler(events.onReconnect); 1751 } 1752 }; 1753 1754 connection.socket.onclose = function (event) { 1755 var error; 1756 1757 // Only handle a socket close if the close is from the current socket. 1758 // Sometimes on disconnect the server will push down an onclose event 1759 // to an expired socket. 1760 1761 if (this === connection.socket) { 1762 if (opened && typeof event.wasClean !== "undefined" && event.wasClean === false) { 1763 // Ideally this would use the websocket.onerror handler (rather than checking wasClean in onclose) but 1764 // I found in some circumstances Chrome won't call onerror. This implementation seems to work on all browsers. 1765 error = signalR._.transportError( 1766 signalR.resources.webSocketClosed, 1767 connection.transport, 1768 event); 1769 1770 connection.log("Unclean disconnect from websocket: " + (event.reason || "[no reason given].")); 1771 } else { 1772 connection.log("Websocket closed."); 1773 } 1774 1775 if (!onFailed || !onFailed(error)) { 1776 if (error) { 1777 $(connection).triggerHandler(events.onError, [error]); 1778 } 1779 1780 that.reconnect(connection); 1781 } 1782 } 1783 }; 1784 1785 connection.socket.onmessage = function (event) { 1786 var data; 1787 1788 try { 1789 data = connection._parseResponse(event.data); 1790 } 1791 catch (error) { 1792 transportLogic.handleParseFailure(connection, event.data, error, onFailed, event); 1793 return; 1794 } 1795 1796 if (data) { 1797
1797// data.M is PersistentResponse.Messages 1798 if ($.isEmptyObject(data) || data.M) { 1799 transportLogic.processMessages(connection, data, onSuccess); 1800 } else { 1801 // For websockets we need to trigger onReceived 1802 // for callbacks to outgoing hub calls. 1803 transportLogic.triggerReceived(connection, data); 1804 }
vendor: 11,128 bytes, lines 1804-2090
1804 1805 } 1806 }; 1807 } 1808 }, 1809 1810 reconnect: function (connection) { 1811 transportLogic.reconnect(connection, this.name); 1812 }, 1813 1814 lostConnection: function (connection) { 1815 this.reconnect(connection); 1816 }, 1817 1818 stop: function (connection) { 1819 // Don't trigger a reconnect after stopping 1820 transportLogic.clearReconnectTimeout(connection); 1821 1822 if (connection.socket) { 1823 connection.log("Closing the Websocket."); 1824 connection.socket.close(); 1825 connection.socket = null; 1826 } 1827 }, 1828 1829 abort: function (connection, async) { 1830 transportLogic.ajaxAbort(connection, async); 1831 } 1832 }; 1833 1834}(window.jQuery, window)); 1835/* jquery.signalR.transports.serverSentEvents.js */ 1836// Copyright (c) .NET Foundation. All rights reserved. 1837// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 1838 1839 1840/*global window:false */ 1841/// <reference path="jquery.signalR.transports.common.js" /> 1842 1843(function ($, window, undefined) { 1844 1845 var signalR = $.signalR, 1846 events = $.signalR.events, 1847 changeState = $.signalR.changeState, 1848 transportLogic = signalR.transports._logic, 1849 clearReconnectAttemptTimeout = function (connection) { 1850 window.clearTimeout(connection._.reconnectAttemptTimeoutHandle); 1851 delete connection._.reconnectAttemptTimeoutHandle; 1852 }; 1853 1854 signalR.transports.serverSentEvents = { 1855 name: "serverSentEvents", 1856 1857 supportsKeepAlive: function () { 1858 return true; 1859 }, 1860 1861 timeOut: 3000, 1862 1863 start: function (connection, onSuccess, onFailed) { 1864 var that = this, 1865 opened = false, 1866 $connection = $(connection), 1867 reconnecting = !onSuccess, 1868 url; 1869 1870 if (connection.eventSource) { 1871 connection.log("The connection already has an event source. Stopping it."); 1872 connection.stop(); 1873 } 1874 1875 if (!window.EventSource) { 1876 if (onFailed) { 1877 connection.log("This browser doesn't support SSE."); 1878 onFailed(); 1879 } 1880 return; 1881 } 1882 1883 url = transportLogic.getUrl(connection, this.name, reconnecting); 1884 1885 try { 1886 connection.log("Attempting to connect to SSE endpoint '" + url + "'."); 1887 connection.eventSource = new window.EventSource(url, { withCredentials: connection.withCredentials }); 1888 } 1889 catch (e) { 1890 connection.log("EventSource failed trying to connect with error " + e.Message + "."); 1891 if (onFailed) { 1892 // The connection failed, call the failed callback 1893 onFailed(); 1894 } else { 1895 $connection.triggerHandler(events.onError, [signalR._.transportError(signalR.resources.eventSourceFailedToConnect, connection.transport, e)]); 1896 if (reconnecting) { 1897 // If we were reconnecting, rather than doing initial connect, then try reconnect again 1898 that.reconnect(connection); 1899 } 1900 } 1901 return; 1902 } 1903 1904 if (reconnecting) { 1905 connection._.reconnectAttemptTimeoutHandle = window.setTimeout(function () { 1906 if (opened === false) { 1907 // If we're reconnecting and the event source is attempting to connect, 1908 // don't keep retrying. This causes duplicate connections to spawn. 1909 if (connection.eventSource.readyState !== window.EventSource.OPEN) { 1910 // If we were reconnecting, rather than doing initial connect, then try reconnect again 1911 that.reconnect(connection); 1912 } 1913 } 1914 }, 1915 that.timeOut); 1916 } 1917 1918 connection.eventSource.addEventListener("open", function (e) { 1919 connection.log("EventSource connected."); 1920 1921 clearReconnectAttemptTimeout(connection); 1922 transportLogic.clearReconnectTimeout(connection); 1923 1924 if (opened === false) { 1925 opened = true; 1926 1927 if (changeState(connection, 1928 signalR.connectionState.reconnecting, 1929 signalR.connectionState.connected) === true) { 1930 $connection.triggerHandler(events.onReconnect); 1931 } 1932 } 1933 }, false); 1934 1935 connection.eventSource.addEventListener("message", function (e) { 1936 var res; 1937 1938 // process messages 1939 if (e.data === "initialized") { 1940 return; 1941 } 1942 1943 try { 1944 res = connection._parseResponse(e.data); 1945 } 1946 catch (error) { 1947 transportLogic.handleParseFailure(connection, e.data, error, onFailed, e); 1948 return; 1949 } 1950 1951 transportLogic.processMessages(connection, res, onSuccess); 1952 }, false); 1953 1954 connection.eventSource.addEventListener("error", function (e) { 1955 var error = signalR._.transportError( 1956 signalR.resources.eventSourceError, 1957 connection.transport, 1958 e); 1959 1960 // Only handle an error if the error is from the current Event Source. 1961 // Sometimes on disconnect the server will push down an error event 1962 // to an expired Event Source. 1963 if (this !== connection.eventSource) { 1964 return; 1965 } 1966 1967 if (onFailed && onFailed(error)) { 1968 return; 1969 } 1970 1971 connection.log("EventSource readyState: " + connection.eventSource.readyState + "."); 1972 1973 if (e.eventPhase === window.EventSource.CLOSED) { 1974 // We don't use the EventSource's native reconnect function as it 1975 // doesn't allow us to change the URL when reconnecting. We need 1976 // to change the URL to not include the /connect suffix, and pass 1977 // the last message id we received. 1978 connection.log("EventSource reconnecting due to the server connection ending."); 1979 that.reconnect(connection); 1980 } else { 1981 // connection error 1982 connection.log("EventSource error."); 1983 $connection.triggerHandler(events.onError, [error]); 1984 } 1985 }, false); 1986 }, 1987 1988 reconnect: function (connection) { 1989 transportLogic.reconnect(connection, this.name); 1990 }, 1991 1992 lostConnection: function (connection) { 1993 this.reconnect(connection); 1994 }, 1995 1996 send: function (connection, data) { 1997 transportLogic.ajaxSend(connection, data); 1998 }, 1999 2000 stop: function (connection) { 2001 // Don't trigger a reconnect after stopping 2002 clearReconnectAttemptTimeout(connection); 2003 transportLogic.clearReconnectTimeout(connection); 2004 2005 if (connection && connection.eventSource) { 2006 connection.log("EventSource calling close()."); 2007 connection.eventSource.close(); 2008 connection.eventSource = null; 2009 delete connection.eventSource; 2010 } 2011 }, 2012 2013 abort: function (connection, async) { 2014 transportLogic.ajaxAbort(connection, async); 2015 } 2016 }; 2017 2018}(window.jQuery, window)); 2019/* jquery.signalR.transports.foreverFrame.js */ 2020// Copyright (c) .NET Foundation. All rights reserved. 2021// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 2022 2023 2024/*global window:false */ 2025/// <reference path="jquery.signalR.transports.common.js" /> 2026 2027(function ($, window, undefined) { 2028 2029 var signalR = $.signalR, 2030 events = $.signalR.events, 2031 changeState = $.signalR.changeState, 2032 transportLogic = signalR.transports._logic, 2033 createFrame = function () { 2034 var frame = window.document.createElement("iframe"); 2035 frame.setAttribute("style", "position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;"); 2036 return frame; 2037 }, 2038 // Used to prevent infinite loading icon spins in older versions of ie 2039 // We build this object inside a closure so we don't pollute the rest of 2040 // the foreverFrame transport with unnecessary functions/utilities. 2041 loadPreventer = (function () { 2042 var loadingFixIntervalId = null, 2043 loadingFixInterval = 1000, 2044 attachedTo = 0; 2045 2046 return { 2047 prevent: function () { 2048 // Prevent additional iframe removal procedures from newer browsers 2049 if (signalR._.ieVersion <= 8) { 2050 // We only ever want to set the interval one time, so on the first attachedTo 2051 if (attachedTo === 0) { 2052 // Create and destroy iframe every 3 seconds to prevent loading icon, super hacky 2053 loadingFixIntervalId = window.setInterval(function () { 2054 var tempFrame = createFrame(); 2055 2056 window.document.body.appendChild(tempFrame); 2057 window.document.body.removeChild(tempFrame); 2058 2059 tempFrame = null; 2060 }, loadingFixInterval); 2061 } 2062 2063 attachedTo++; 2064 } 2065 }, 2066 cancel: function () { 2067 // Only clear the interval if there's only one more object that the loadPreventer is attachedTo 2068 if (attachedTo === 1) { 2069 window.clearInterval(loadingFixIntervalId); 2070 } 2071 2072 if (attachedTo > 0) { 2073 attachedTo--; 2074 } 2075 } 2076 }; 2077 })(); 2078 2079 signalR.transports.foreverFrame = { 2080 name: "foreverFrame", 2081 2082 supportsKeepAlive: function () { 2083 return true; 2084 }, 2085 2086 // Added as a value here so we can create tests to verify functionality 2087 iframeClearThreshold: 50, 2088 2089 start: function (connection, onSuccess, onFailed) { 2090
vendor: 11,868 bytes, lines 2090-2374
2090var that = this, 2091 frameId = (transportLogic.foreverFrame.count += 1), 2092 url, 2093 frame = createFrame(), 2094 frameLoadHandler = function () { 2095 connection.log("Forever frame iframe finished loading and is no longer receiving messages."); 2096 if (!onFailed || !onFailed()) { 2097 that.reconnect(connection); 2098 } 2099 }; 2100 2101 if (window.EventSource) { 2102 // If the browser supports SSE, don't use Forever Frame 2103 if (onFailed) { 2104 connection.log("Forever Frame is not supported by SignalR on browsers with SSE support."); 2105 onFailed(); 2106 } 2107 return; 2108 } 2109 2110 frame.setAttribute("data-signalr-connection-id", connection.id); 2111 2112 // Start preventing loading icon 2113 // This will only perform work if the loadPreventer is not attached to another connection. 2114 loadPreventer.prevent(); 2115 2116 // Build the url 2117 url = transportLogic.getUrl(connection, this.name); 2118 url += "&frameId=" + frameId; 2119 2120 // add frame to the document prior to setting URL to avoid caching issues. 2121 window.document.documentElement.appendChild(frame); 2122 2123 connection.log("Binding to iframe's load event."); 2124 2125 if (frame.addEventListener) { 2126 frame.addEventListener("load", frameLoadHandler, false); 2127 } else if (frame.attachEvent) { 2128 frame.attachEvent("onload", frameLoadHandler); 2129 } 2130 2131 frame.src = url; 2132 transportLogic.foreverFrame.connections[frameId] = connection; 2133 2134 connection.frame = frame; 2135 connection.frameId = frameId; 2136 2137 if (onSuccess) { 2138 connection.onSuccess = function () { 2139 connection.log("Iframe transport started."); 2140 onSuccess(); 2141 }; 2142 } 2143 }, 2144 2145 reconnect: function (connection) { 2146 var that = this; 2147 2148 // Need to verify connection state and verify before the setTimeout occurs because an application sleep could occur during the setTimeout duration. 2149 if (transportLogic.isConnectedOrReconnecting(connection) && transportLogic.verifyLastActive(connection)) { 2150 window.setTimeout(function () { 2151 // Verify that we're ok to reconnect. 2152 if (!transportLogic.verifyLastActive(connection)) { 2153 return; 2154 } 2155 2156 if (connection.frame && transportLogic.ensureReconnectingState(connection)) { 2157 var frame = connection.frame, 2158 src = transportLogic.getUrl(connection, that.name, true) + "&frameId=" + connection.frameId; 2159 connection.log("Updating iframe src to '" + src + "'."); 2160 frame.src = src; 2161 } 2162 }, connection.reconnectDelay); 2163 } 2164 }, 2165 2166 lostConnection: function (connection) { 2167 this.reconnect(connection); 2168 }, 2169 2170 send: function (connection, data) { 2171 transportLogic.ajaxSend(connection, data); 2172 }, 2173 2174 receive: function (connection, data) { 2175 var cw, 2176 body, 2177 response; 2178 2179 if (connection.json !== connection._originalJson) { 2180 // If there's a custom JSON parser configured then serialize the object 2181 // using the original (browser) JSON parser and then deserialize it using 2182 // the custom parser (connection._parseResponse does that). This is so we 2183 // can easily send the response from the server as "raw" JSON but still 2184 // support custom JSON deserialization in the browser. 2185 data = connection._originalJson.stringify(data); 2186 } 2187 2188 response = connection._parseResponse(data); 2189 2190 transportLogic.processMessages(connection, response, connection.onSuccess); 2191 2192 // Protect against connection stopping from a callback trigger within the processMessages above. 2193 if (connection.state === $.signalR.connectionState.connected) { 2194 // Delete the script & div elements 2195 connection.frameMessageCount = (connection.frameMessageCount || 0) + 1; 2196 if (connection.frameMessageCount > signalR.transports.foreverFrame.iframeClearThreshold) { 2197 connection.frameMessageCount = 0; 2198 cw = connection.frame.contentWindow || connection.frame.contentDocument; 2199 if (cw && cw.document && cw.document.body) { 2200 body = cw.document.body; 2201 2202 // Remove all the child elements from the iframe's body to conserver memory 2203 while (body.firstChild) { 2204 body.removeChild(body.firstChild); 2205 } 2206 } 2207 } 2208 } 2209 }, 2210 2211 stop: function (connection) { 2212 var cw = null; 2213 2214 // Stop attempting to prevent loading icon 2215 loadPreventer.cancel(); 2216 2217 if (connection.frame) { 2218 if (connection.frame.stop) { 2219 connection.frame.stop(); 2220 } else { 2221 try { 2222 cw = connection.frame.contentWindow || connection.frame.contentDocument; 2223 if (cw.document && cw.document.execCommand) { 2224 cw.document.execCommand("Stop"); 2225 } 2226 } 2227 catch (e) { 2228 connection.log("Error occurred when stopping foreverFrame transport. Message = " + e.message + "."); 2229 } 2230 } 2231 2232 // Ensure the iframe is where we left it 2233 if (connection.frame.parentNode === window.document.documentElement) { 2234 window.document.documentElement.removeChild(connection.frame); 2235 } 2236 2237 delete transportLogic.foreverFrame.connections[connection.frameId]; 2238 connection.frame = null; 2239 connection.frameId = null; 2240 delete connection.frame; 2241 delete connection.frameId; 2242 delete connection.onSuccess; 2243 delete connection.frameMessageCount; 2244 connection.log("Stopping forever frame."); 2245 } 2246 }, 2247 2248 abort: function (connection, async) { 2249 transportLogic.ajaxAbort(connection, async); 2250 }, 2251 2252 getConnection: function (id) { 2253 return transportLogic.foreverFrame.connections[id]; 2254 }, 2255 2256 started: function (connection) { 2257 if (changeState(connection, 2258 signalR.connectionState.reconnecting, 2259 signalR.connectionState.connected) === true) { 2260 2261 $(connection).triggerHandler(events.onReconnect); 2262 } 2263 } 2264 }; 2265 2266}(window.jQuery, window)); 2267/* jquery.signalR.transports.longPolling.js */ 2268// Copyright (c) .NET Foundation. All rights reserved. 2269// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 2270 2271 2272/*global window:false */ 2273/// <reference path="jquery.signalR.transports.common.js" /> 2274 2275(function ($, window, undefined) { 2276 2277 var signalR = $.signalR, 2278 events = $.signalR.events, 2279 changeState = $.signalR.changeState, 2280 isDisconnecting = $.signalR.isDisconnecting, 2281 transportLogic = signalR.transports._logic; 2282 2283 signalR.transports.longPolling = { 2284 name: "longPolling", 2285 2286 supportsKeepAlive: function () { 2287 return false; 2288 }, 2289 2290 reconnectDelay: 3000, 2291 2292 start: function (connection, onSuccess, onFailed) { 2293 /// <summary>Starts the long polling connection</summary> 2294 /// <param name="connection" type="signalR">The SignalR connection to start</param> 2295 var that = this, 2296 fireConnect = function () { 2297 fireConnect = $.noop; 2298 2299 connection.log("LongPolling connected."); 2300 2301 if (onSuccess) { 2302 onSuccess(); 2303 } else { 2304 connection.log("WARNING! The client received an init message after reconnecting."); 2305 } 2306 }, 2307 tryFailConnect = function (error) { 2308 if (onFailed(error)) { 2309 connection.log("LongPolling failed to connect."); 2310 return true; 2311 } 2312 2313 return false; 2314 }, 2315 privateData = connection._, 2316 reconnectErrors = 0, 2317 fireReconnected = function (instance) { 2318 window.clearTimeout(privateData.reconnectTimeoutId); 2319 privateData.reconnectTimeoutId = null; 2320 2321 if (changeState(instance, 2322 signalR.connectionState.reconnecting, 2323 signalR.connectionState.connected) === true) { 2324 // Successfully reconnected! 2325 instance.log("Raising the reconnect event"); 2326 $(instance).triggerHandler(events.onReconnect); 2327 } 2328 }, 2329 // 1 hour 2330 maxFireReconnectedTimeout = 3600000; 2331 2332 if (connection.pollXhr) { 2333 connection.log("Polling xhr requests already exists, aborting."); 2334 connection.stop(); 2335 } 2336 2337 connection.messageId = null; 2338 2339 privateData.reconnectTimeoutId = null; 2340 2341 privateData.pollTimeoutId = window.setTimeout(function () { 2342 (function poll(instance, raiseReconnect) { 2343 var messageId = instance.messageId, 2344 connect = (messageId === null), 2345 reconnecting = !connect, 2346 polling = !raiseReconnect, 2347 url = transportLogic.getUrl(instance, that.name, reconnecting, polling, true /* use Post for longPolling */), 2348 postData = {}; 2349 2350 if (instance.messageId) { 2351 postData.messageId = instance.messageId; 2352 } 2353 2354 if (instance.groupsToken) { 2355 postData.groupsToken = instance.groupsToken; 2356 } 2357 2358 // If we've disconnected during the time we've tried to re-instantiate the poll then stop. 2359 if (isDisconnecting(instance) === true) { 2360 return; 2361 } 2362 2363 connection.log("Opening long polling request to '" + url + "'."); 2364 instance.pollXhr = transportLogic.ajax(connection, { 2365 xhrFields: { 2366 onprogress: function () { 2367 transportLogic.markLastMessage(connection); 2368 } 2369 }, 2370 url: url, 2371 type: "POST", 2372 contentType: signalR._.defaultContentType, 2373 data: postData, 2374 timeout: connection._.pollTimeout
vendor: 8,663 bytes, lines 2374-2538
2374, 2375 success: function (result) { 2376 var minData, 2377 delay = 0, 2378 data, 2379 shouldReconnect; 2380 2381 connection.log("Long poll complete."); 2382 2383 // Reset our reconnect errors so if we transition into a reconnecting state again we trigger 2384 // reconnected quickly 2385 reconnectErrors = 0; 2386 2387 try { 2388 // Remove any keep-alives from the beginning of the result 2389 minData = connection._parseResponse(result); 2390 } 2391 catch (error) { 2392 transportLogic.handleParseFailure(instance, result, error, tryFailConnect, instance.pollXhr); 2393 return; 2394 } 2395 2396 // If there's currently a timeout to trigger reconnect, fire it now before processing messages 2397 if (privateData.reconnectTimeoutId !== null) { 2398 fireReconnected(instance); 2399 } 2400 2401 if (minData) { 2402 data = transportLogic.maximizePersistentResponse(minData); 2403 } 2404 2405 transportLogic.processMessages(instance, minData, fireConnect); 2406 2407 if (data && 2408 $.type(data.LongPollDelay) === "number") { 2409 delay = data.LongPollDelay; 2410 } 2411 2412 if (isDisconnecting(instance) === true) { 2413 return; 2414 } 2415 2416 shouldReconnect = data && data.ShouldReconnect; 2417 if (shouldReconnect) { 2418 // Transition into the reconnecting state 2419 // If this fails then that means that the user transitioned the connection into a invalid state in processMessages. 2420 if (!transportLogic.ensureReconnectingState(instance)) { 2421 return; 2422 } 2423 } 2424 2425 // We never want to pass a raiseReconnect flag after a successful poll. This is handled via the error function 2426 if (delay > 0) { 2427 privateData.pollTimeoutId = window.setTimeout(function () { 2428 poll(instance, shouldReconnect); 2429 }, delay); 2430 } else { 2431 poll(instance, shouldReconnect); 2432 } 2433 }, 2434 2435 error: function (data, textStatus) { 2436 var error = signalR._.transportError(signalR.resources.longPollFailed, connection.transport, data, instance.pollXhr); 2437 2438 // Stop trying to trigger reconnect, connection is in an error state 2439 // If we're not in the reconnect state this will noop 2440 window.clearTimeout(privateData.reconnectTimeoutId); 2441 privateData.reconnectTimeoutId = null; 2442 2443 if (textStatus === "abort") { 2444 connection.log("Aborted xhr request."); 2445 return; 2446 } 2447 2448 if (!tryFailConnect(error)) { 2449 2450 // Increment our reconnect errors, we assume all errors to be reconnect errors 2451 // In the case that it's our first error this will cause Reconnect to be fired 2452 // after 1 second due to reconnectErrors being = 1. 2453 reconnectErrors++; 2454 2455 if (connection.state !== signalR.connectionState.reconnecting) { 2456 connection.log("An error occurred using longPolling. Status = " + textStatus + ". Response = " + data.responseText + "."); 2457 $(instance).triggerHandler(events.onError, [error]); 2458 } 2459 2460 // We check the state here to verify that we're not in an invalid state prior to verifying Reconnect. 2461 // If we're not in connected or reconnecting then the next ensureReconnectingState check will fail and will return. 2462 // Therefore we don't want to change that failure code path. 2463 if ((connection.state === signalR.connectionState.connected || 2464 connection.state === signalR.connectionState.reconnecting) && 2465 !transportLogic.verifyLastActive(connection)) { 2466 return; 2467 } 2468 2469 // Transition into the reconnecting state 2470 // If this fails then that means that the user transitioned the connection into the disconnected or connecting state within the above error handler trigger. 2471 if (!transportLogic.ensureReconnectingState(instance)) { 2472 return; 2473 } 2474 2475 // Call poll with the raiseReconnect flag as true after the reconnect delay 2476 privateData.pollTimeoutId = window.setTimeout(function () { 2477 poll(instance, true); 2478 }, that.reconnectDelay); 2479 } 2480 } 2481 }); 2482 2483 // This will only ever pass after an error has occurred via the poll ajax procedure. 2484 if (reconnecting && raiseReconnect === true) { 2485 // We wait to reconnect depending on how many times we've failed to reconnect. 2486 // This is essentially a heuristic that will exponentially increase in wait time before 2487 // triggering reconnected. This depends on the "error" handler of Poll to cancel this 2488 // timeout if it triggers before the Reconnected event fires. 2489 // The Math.min at the end is to ensure that the reconnect timeout does not overflow. 2490 privateData.reconnectTimeoutId = window.setTimeout(function () { fireReconnected(instance); }, Math.min(1000 * (Math.pow(2, reconnectErrors) - 1), maxFireReconnectedTimeout)); 2491 } 2492 }(connection)); 2493 }, 250); // Have to delay initial poll so Chrome doesn't show loader spinner in tab 2494 }, 2495 2496 lostConnection: function (connection) { 2497 if (connection.pollXhr) { 2498 connection.pollXhr.abort("lostConnection"); 2499 } 2500 }, 2501 2502 send: function (connection, data) { 2503 transportLogic.ajaxSend(connection, data); 2504 }, 2505 2506 stop: function (connection) { 2507 /// <summary>Stops the long polling connection</summary> 2508 /// <param name="connection" type="signalR">The SignalR connection to stop</param> 2509 2510 window.clearTimeout(connection._.pollTimeoutId); 2511 window.clearTimeout(connection._.reconnectTimeoutId); 2512 2513 delete connection._.pollTimeoutId; 2514 delete connection._.reconnectTimeoutId; 2515 2516 if (connection.pollXhr) { 2517 connection.pollXhr.abort(); 2518 connection.pollXhr = null; 2519 delete connection.pollXhr; 2520 } 2521 }, 2522 2523 abort: function (connection, async) { 2524 transportLogic.ajaxAbort(connection, async); 2525 } 2526 }; 2527 2528}(window.jQuery, window)); 2529/* jquery.signalR.hubs.js */ 2530// Copyright (c) .NET Foundation. All rights reserved. 2531// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 2532 2533/*global window:false */ 2534/// <reference path="jquery.signalR.core.js" /> 2535 2536(function ($, window, undefined) { 2537 2538 var
vendor: 2,287 bytes, lines 2538-2601
2538eventNamespace = ".hubProxy", 2539 signalR = $.signalR; 2540 2541 function makeEventName(event) { 2542 return event + eventNamespace; 2543 } 2544 2545 // Equivalent to Array.prototype.map 2546 function map(arr, fun, thisp) { 2547 var i, 2548 length = arr.length, 2549 result = []; 2550 for (i = 0; i < length; i += 1) { 2551 if (arr.hasOwnProperty(i)) { 2552 result[i] = fun.call(thisp, arr[i], i, arr); 2553 } 2554 } 2555 return result; 2556 } 2557 2558 function getArgValue(a) { 2559 return $.isFunction(a) ? null : ($.type(a) === "undefined" ? null : a); 2560 } 2561 2562 function hasMembers(obj) { 2563 for (var key in obj) { 2564 // If we have any properties in our callback map then we have callbacks and can exit the loop via return 2565 if (obj.hasOwnProperty(key)) { 2566 return true; 2567 } 2568 } 2569 2570 return false; 2571 } 2572 2573 function clearInvocationCallbacks(connection, error) { 2574 /// <param name="connection" type="hubConnection" /> 2575 var callbacks = connection._.invocationCallbacks, 2576 callback; 2577 2578 if (hasMembers(callbacks)) { 2579 connection.log("Clearing hub invocation callbacks with error: " + error + "."); 2580 } 2581 2582 // Reset the callback cache now as we have a local var referencing it 2583 connection._.invocationCallbackId = 0; 2584 delete connection._.invocationCallbacks; 2585 connection._.invocationCallbacks = {}; 2586 2587 // Loop over the callbacks and invoke them. 2588 // We do this using a local var reference and *after* we've cleared the cache 2589 // so that if a fail callback itself tries to invoke another method we don't 2590 // end up with its callback in the list we're looping over. 2591 for (var callbackId in callbacks) { 2592 callback = callbacks[callbackId]; 2593 callback.method.call(callback.scope, { E: error }); 2594 } 2595 } 2596 2597 // hubProxy 2598 function hubProxy(hubConnection, hubName) { 2599 /// <summary> 2600 /// Creates a new proxy object for the given hub connection that can be used to invoke 2601 /// methods on server hubs and handle client method invocation requests from the server.
2602 /// </summary> 2603 return new hubProxy.fn.init(hubConnection, hubName); 2604 } 2605 2606 hubProxy.fn = hubProxy.prototype = { 2607 init: function (connection, hubName) { 2608 this.state = {}; 2609 this.connection = connection; 2610 this.hubName = hubName; 2611 this._ = { 2612 callbackMap: {} 2613 }; 2614 }, 2615 2616 constructor: hubProxy, 2617 2618 hasSubscriptions: function () { 2619 return hasMembers(this._.callbackMap); 2620 }, 2621 2622 on: function (eventName, callback) { 2623 /// <summary>Wires up a callback to be invoked when a invocation request is received from the server hub.</summary> 2624 /// <param name="eventName" type="String">The name of the hub event to register the callback for.</param> 2625 /// <param name="callback" type="Function">The callback to be invoked.</param> 2626 var that = this, 2627 callbackMap = that._.callbackMap; 2628 2629 // Normalize the event name to lowercase 2630 eventName = eventName.toLowerCase(); 2631 2632 // If there is not an event registered for this callback yet we want to create its event space in the callback map. 2633 if (!callbackMap[eventName]) { 2634 callbackMap[eventName] = {}; 2635 } 2636 2637 // Map the callback to our encompassed function 2638 callbackMap[eventName][callback] = function (e, data) { 2639 callback.apply(that, data); 2640 }; 2641 2642 $(that).bind(makeEventName(eventName), callbackMap[eventName][callback]); 2643 2644 return that; 2645 }, 2646 2647 off: function (eventName, callback) { 2648 /// <summary>Removes the callback invocation request from the server hub for the given event name.</summary> 2649 /// <param name="eventName" type="String">The name of the hub event to unregister the callback for.</param> 2650 /// <param name="callback" type="Function">The callback to be invoked.</param> 2651 var that = this, 2652 callbackMap = that._.callbackMap, 2653 callbackSpace; 2654 2655 // Normalize the event name to lowercase 2656 eventName = eventName.toLowerCase(); 2657 2658 callbackSpace = callbackMap[eventName]; 2659 2660 // Verify that there is an event space to unbind 2661 if (callbackSpace) { 2662 // Only unbind if there's an event bound with eventName and a callback with the specified callback 2663 if (callbackSpace[callback]) { 2664 $(that).unbind(makeEventName(eventName), callbackSpace[callback]); 2665 2666 // Remove the callback from the callback map 2667 delete callbackSpace[callback]; 2668 2669 // Check if there are any members left on the event, if not we need to destroy it. 2670 if (!hasMembers(callbackSpace)) { 2671 delete callbackMap[eventName]; 2672 } 2673 } else if (!callback) { // Check if we're removing the whole event and we didn't error because of an invalid callback 2674 $(that).unbind(makeEventName(eventName)); 2675 2676 delete callbackMap[eventName]; 2677 } 2678 } 2679 2680 return that; 2681 }, 2682 2683 invoke: function (methodName) { 2684 /// <summary>Invokes a server hub method with the given arguments.</summary> 2685 /// <param name="methodName" type="String">The name of the server hub method.</param> 2686 2687 var that = this, 2688 connection = that.connection, 2689 args = $.makeArray(arguments).slice(1), 2690 argValues = map(args, getArgValue), 2691 data = { H: that.hubName, M: methodName, A: argValues, I: connection._.invocationCallbackId }, 2692 d = $.Deferred(), 2693 callback = function (minResult) { 2694 var result = that._maximizeHubResponse(minResult), 2695 source, 2696 error; 2697 2698 // Update the hub state 2699 $.extend(that.state, result.State); 2700 2701 if (result.Progress) { 2702 if (d.notifyWith) {
vendor: 10,769 bytes, lines 2703-2958
2703 // Progress is only supported in jQuery 1.7+ 2704 d.notifyWith(that, [result.Progress.Data]); 2705 } else if(!connection._.progressjQueryVersionLogged) { 2706 connection.log("A hub method invocation progress update was received but the version of jQuery in use (" + $.prototype.jquery + ") does not support progress updates. Upgrade to jQuery 1.7+ to receive progress notifications."); 2707 connection._.progressjQueryVersionLogged = true; 2708 } 2709 } else if (result.Error) { 2710 // Server hub method threw an exception, log it & reject the deferred 2711 if (result.StackTrace) { 2712 connection.log(result.Error + "\n" + result.StackTrace + "."); 2713 } 2714 2715 // result.ErrorData is only set if a HubException was thrown 2716 source = result.IsHubException ? "HubException" : "Exception"; 2717 error = signalR._.error(result.Error, source); 2718 error.data = result.ErrorData; 2719 2720 connection.log(that.hubName + "." + methodName + " failed to execute. Error: " + error.message); 2721 d.rejectWith(that, [error]); 2722 } else { 2723 // Server invocation succeeded, resolve the deferred 2724 connection.log("Invoked " + that.hubName + "." + methodName); 2725 d.resolveWith(that, [result.Result]); 2726 } 2727 }; 2728 2729 connection._.invocationCallbacks[connection._.invocationCallbackId.toString()] = { scope: that, method: callback }; 2730 connection._.invocationCallbackId += 1; 2731 2732 if (!$.isEmptyObject(that.state)) { 2733 data.S = that.state; 2734 } 2735 2736 connection.log("Invoking " + that.hubName + "." + methodName); 2737 connection.send(data); 2738 2739 return d.promise(); 2740 }, 2741 2742 _maximizeHubResponse: function (minHubResponse) { 2743 return { 2744 State: minHubResponse.S, 2745 Result: minHubResponse.R, 2746 Progress: minHubResponse.P ? { 2747 Id: minHubResponse.P.I, 2748 Data: minHubResponse.P.D 2749 } : null, 2750 Id: minHubResponse.I, 2751 IsHubException: minHubResponse.H, 2752 Error: minHubResponse.E, 2753 StackTrace: minHubResponse.T, 2754 ErrorData: minHubResponse.D 2755 }; 2756 } 2757 }; 2758 2759 hubProxy.fn.init.prototype = hubProxy.fn; 2760 2761 // hubConnection 2762 function hubConnection(url, options) { 2763 /// <summary>Creates a new hub connection.</summary> 2764 /// <param name="url" type="String">[Optional] The hub route url, defaults to "/signalr".</param> 2765 /// <param name="options" type="Object">[Optional] Settings to use when creating the hubConnection.</param> 2766 var settings = { 2767 qs: null, 2768 logging: false, 2769 useDefaultPath: true 2770 }; 2771 2772 $.extend(settings, options); 2773 2774 if (!url || settings.useDefaultPath) { 2775 url = (url || "") + "/signalr"; 2776 } 2777 return new hubConnection.fn.init(url, settings); 2778 } 2779 2780 hubConnection.fn = hubConnection.prototype = $.connection(); 2781 2782 hubConnection.fn.init = function (url, options) { 2783 var settings = { 2784 qs: null, 2785 logging: false, 2786 useDefaultPath: true 2787 }, 2788 connection = this; 2789 2790 $.extend(settings, options); 2791 2792 // Call the base constructor 2793 $.signalR.fn.init.call(connection, url, settings.qs, settings.logging); 2794 2795 // Object to store hub proxies for this connection 2796 connection.proxies = {}; 2797 2798 connection._.invocationCallbackId = 0; 2799 connection._.invocationCallbacks = {}; 2800 2801 // Wire up the received handler 2802 connection.received(function (minData) { 2803 var data, proxy, dataCallbackId, callback, hubName, eventName; 2804 if (!minData) { 2805 return; 2806 } 2807 2808 // We have to handle progress updates first in order to ensure old clients that receive 2809 // progress updates enter the return value branch and then no-op when they can't find 2810 // the callback in the map (because the minData.I value will not be a valid callback ID) 2811 if (typeof (minData.P) !== "undefined") { 2812 // Process progress notification 2813 dataCallbackId = minData.P.I.toString(); 2814 callback = connection._.invocationCallbacks[dataCallbackId]; 2815 if (callback) { 2816 callback.method.call(callback.scope, minData); 2817 } 2818 } else if (typeof (minData.I) !== "undefined") { 2819 // We received the return value from a server method invocation, look up callback by id and call it 2820 dataCallbackId = minData.I.toString(); 2821 callback = connection._.invocationCallbacks[dataCallbackId]; 2822 if (callback) { 2823 // Delete the callback from the proxy 2824 connection._.invocationCallbacks[dataCallbackId] = null; 2825 delete connection._.invocationCallbacks[dataCallbackId]; 2826 2827 // Invoke the callback 2828 callback.method.call(callback.scope, minData); 2829 } 2830 } else { 2831 data = this._maximizeClientHubInvocation(minData); 2832 2833 // We received a client invocation request, i.e. broadcast from server hub 2834 connection.log("Triggering client hub event '" + data.Method + "' on hub '" + data.Hub + "'."); 2835 2836 // Normalize the names to lowercase 2837 hubName = data.Hub.toLowerCase(); 2838 eventName = data.Method.toLowerCase(); 2839 2840 // Trigger the local invocation event 2841 proxy = this.proxies[hubName]; 2842 2843 // Update the hub state 2844 $.extend(proxy.state, data.State); 2845 $(proxy).triggerHandler(makeEventName(eventName), [data.Args]); 2846 } 2847 }); 2848 2849 connection.error(function (errData, origData) { 2850 var callbackId, callback; 2851 2852 if (!origData) { 2853 // No original data passed so this is not a send error 2854 return; 2855 } 2856 2857 callbackId = origData.I; 2858 callback = connection._.invocationCallbacks[callbackId]; 2859 2860 // Verify that there is a callback bound (could have been cleared) 2861 if (callback) { 2862 // Delete the callback 2863 connection._.invocationCallbacks[callbackId] = null; 2864 delete connection._.invocationCallbacks[callbackId]; 2865 2866 // Invoke the callback with an error to reject the promise 2867 callback.method.call(callback.scope, { E: errData }); 2868 } 2869 }); 2870 2871 connection.reconnecting(function () { 2872 if (connection.transport && connection.transport.name === "webSockets") { 2873 clearInvocationCallbacks(connection, "Connection started reconnecting before invocation result was received."); 2874 } 2875 }); 2876 2877 connection.disconnected(function () { 2878 clearInvocationCallbacks(connection, "Connection was disconnected before invocation result was received."); 2879 }); 2880 }; 2881 2882 hubConnection.fn._maximizeClientHubInvocation = function (minClientHubInvocation) { 2883 return { 2884 Hub: minClientHubInvocation.H, 2885 Method: minClientHubInvocation.M, 2886 Args: minClientHubInvocation.A, 2887 State: minClientHubInvocation.S 2888 }; 2889 }; 2890 2891 hubConnection.fn._registerSubscribedHubs = function () { 2892 /// <summary> 2893 /// Sets the starting event to loop through the known hubs and register any new hubs 2894 /// that have been added to the proxy. 2895 /// </summary> 2896 var connection = this; 2897 2898 if (!connection._subscribedToHubs) { 2899 connection._subscribedToHubs = true; 2900 connection.starting(function () { 2901 // Set the connection's data object with all the hub proxies with active subscriptions. 2902 // These proxies will receive notifications from the server. 2903 var subscribedHubs = []; 2904 2905 $.each(connection.proxies, function (key) { 2906 if (this.hasSubscriptions()) { 2907 subscribedHubs.push({ name: key }); 2908 connection.log("Client subscribed to hub '" + key + "'."); 2909 } 2910 }); 2911 2912 if (subscribedHubs.length === 0) { 2913 connection.log("No hubs have been subscribed to. The client will not receive data from hubs. To fix, declare at least one client side function prior to connection start for each hub you wish to subscribe to."); 2914 } 2915 2916 connection.data = connection.json.stringify(subscribedHubs); 2917 }); 2918 } 2919 }; 2920 2921 hubConnection.fn.createHubProxy = function (hubName) { 2922 /// <summary> 2923 /// Creates a new proxy object for the given hub connection that can be used to invoke 2924 /// methods on server hubs and handle client method invocation requests from the server. 2925 /// </summary> 2926 /// <param name="hubName" type="String"> 2927 /// The name of the hub on the server to create the proxy for. 2928 /// </param> 2929 2930 // Normalize the name to lowercase 2931 hubName = hubName.toLowerCase(); 2932 2933 var proxy = this.proxies[hubName]; 2934 if (!proxy) { 2935 proxy = hubProxy(this, hubName); 2936 this.proxies[hubName] = proxy; 2937 } 2938 2939 this._registerSubscribedHubs(); 2940 2941 return proxy; 2942 }; 2943 2944 hubConnection.fn.init.prototype = hubConnection.fn; 2945 2946 $.hubConnection = hubConnection; 2947 2948}(window.jQuery, window)); 2949/* jquery.signalR.version.js */ 2950// Copyright (c) .NET Foundation. All rights reserved. 2951// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 2952 2953 2954/*global window:false */ 2955/// <reference path="jquery.signalR.core.js" /> 2956(function ($, undefined) { 2957 $.signalR.version = "2.2.2"; 2958}(window.jQuery));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.