UNPKG

cluedin-widget

Version:

This is the project for creating and managing widgets in CluedIn.

1,142 lines (930 loc) • 125 kB
/* jquery.signalR.core.js */ /*global window:false */ /*! * ASP.NET SignalR JavaScript Library v2.2.0 * http://signalr.net/ * * Copyright (C) Microsoft Corporation. All rights reserved. * */ /// <reference path="Scripts/jquery-1.6.4.js" /> /// <reference path="jquery.signalR.version.js" /> (function( $, window, undefined ) { var resources = { nojQuery: "jQuery was not found. Please ensure jQuery is referenced before the SignalR client JavaScript file.", noTransportOnInit: "No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.", errorOnNegotiate: "Error during negotiation request.", stoppedWhileLoading: "The connection was stopped during page load.", stoppedWhileNegotiating: "The connection was stopped during the negotiate request.", errorParsingNegotiateResponse: "Error parsing negotiate response.", errorDuringStartRequest: "Error during start request. Stopping the connection.", stoppedDuringStartRequest: "The connection was stopped during the start request.", errorParsingStartResponse: "Error parsing start response: '{0}'. Stopping the connection.", invalidStartResponse: "Invalid start response: '{0}'. Stopping the connection.", protocolIncompatible: "You are using a version of the client that isn't compatible with the server. Client version {0}, server version {1}.", sendFailed: "Send failed.", parseFailed: "Failed at parsing response: {0}", longPollFailed: "Long polling request failed.", eventSourceFailedToConnect: "EventSource failed to connect.", eventSourceError: "Error raised by EventSource", webSocketClosed: "WebSocket closed.", pingServerFailedInvalidResponse: "Invalid ping response when pinging server: '{0}'.", pingServerFailed: "Failed to ping server.", pingServerFailedStatusCode: "Failed to ping server. Server responded with status code {0}, stopping the connection.", pingServerFailedParse: "Failed to parse ping server response, stopping the connection.", noConnectionTransport: "Connection is in an invalid state, there is no transport active.", webSocketsInvalidState: "The Web Socket transport is in an invalid state, transitioning into reconnecting.", reconnectTimeout: "Couldn't reconnect within the configured timeout of {0} ms, disconnecting.", reconnectWindowTimeout: "The client has been inactive since {0} and it has exceeded the inactivity timeout of {1} ms. Stopping the connection." }; if ( typeof ($) !== "function" ) { // no jQuery! throw new Error( resources.nojQuery ); } var signalR, _connection, _pageLoaded = (window.document.readyState === "complete"), _pageWindow = $( window ), _negotiateAbortText = "__Negotiate Aborted__", events = { onStart: "onStart", onStarting: "onStarting", onReceived: "onReceived", onError: "onError", onConnectionSlow: "onConnectionSlow", onReconnecting: "onReconnecting", onReconnect: "onReconnect", onStateChanged: "onStateChanged", onDisconnect: "onDisconnect" }, ajaxDefaults = { processData: true, timeout: null, async: true, global: false, cache: false }, log = function( msg, logging ) { if ( logging === false ) { return; } var m; if ( typeof (window.console) === "undefined" ) { return; } m = "[" + new Date().toTimeString() + "] SignalR: " + msg; if ( window.console.debug ) { window.console.debug( m ); } else if ( window.console.log ) { window.console.log( m ); } }, changeState = function( connection, expectedState, newState ) { if ( expectedState === connection.state ) { connection.state = newState; $( connection ).triggerHandler( events.onStateChanged, [ { oldState: expectedState, newState: newState } ] ); return true; } return false; }, isDisconnecting = function( connection ) { return connection.state === signalR.connectionState.disconnected; }, supportsKeepAlive = function( connection ) { return connection._.keepAliveData.activated && connection.transport.supportsKeepAlive( connection ); }, configureStopReconnectingTimeout = function( connection ) { var stopReconnectingTimeout, onReconnectTimeout; // Check if this connection has already been configured to stop reconnecting after a specified timeout. // Without this check if a connection is stopped then started events will be bound multiple times. if ( !connection._.configuredStopReconnectingTimeout ) { onReconnectTimeout = function( connection ) { var message = signalR._.format( signalR.resources.reconnectTimeout, connection.disconnectTimeout ); connection.log( message ); $( connection ).triggerHandler( events.onError, [ signalR._.error( message, /* source */ "TimeoutException" ) ] ); connection.stop( /* async */ false, /* notifyServer */ false ); }; connection.reconnecting( function() { var connection = this; // Guard against state changing in a previous user defined even handler if ( connection.state === signalR.connectionState.reconnecting ) { stopReconnectingTimeout = window.setTimeout( function() { onReconnectTimeout( connection ); }, connection.disconnectTimeout ); } } ); connection.stateChanged( function( data ) { if ( data.oldState === signalR.connectionState.reconnecting ) { // Clear the pending reconnect timeout check window.clearTimeout( stopReconnectingTimeout ); } } ); connection._.configuredStopReconnectingTimeout = true; } }; signalR = function( url, qs, logging ) { /// <summary>Creates a new SignalR connection for the given url</summary> /// <param name="url" type="String">The URL of the long polling endpoint</param> /// <param name="qs" type="Object"> /// [Optional] Custom querystring parameters to add to the connection URL. /// If an object, every non-function member will be added to the querystring. /// If a string, it's added to the QS as specified. /// </param> /// <param name="logging" type="Boolean"> /// [Optional] A flag indicating whether connection logging is enabled to the browser /// console/log. Defaults to false. /// </param> return new signalR.fn.init( url, qs, logging ); }; signalR._ = { defaultContentType: "application/x-www-form-urlencoded; charset=UTF-8", ieVersion: (function() { var version, matches; if ( window.navigator.appName === 'Microsoft Internet Explorer' ) { // Check if the user agent has the pattern "MSIE (one or more numbers).(one or more numbers)"; matches = /MSIE ([0-9]+\.[0-9]+)/.exec( window.navigator.userAgent ); if ( matches ) { version = window.parseFloat( matches[ 1 ] ); } } // undefined value means not IE return version; })(), error: function( message, source, context ) { var e = new Error( message ); e.source = source; if ( typeof context !== "undefined" ) { e.context = context; } return e; }, transportError: function( message, transport, source, context ) { var e = this.error( message, source, context ); e.transport = transport ? transport.name : undefined; return e; }, format: function() { /// <summary>Usage: format("Hi {0}, you are {1}!", "Foo", 100) </summary> var s = arguments[ 0 ]; for( var i = 0; i < arguments.length - 1; i++ ) { s = s.replace( "{" + i + "}", arguments[ i + 1 ] ); } return s; }, firefoxMajorVersion: function( userAgent ) { // Firefox user agents: http://useragentstring.com/pages/Firefox/ var matches = userAgent.match( /Firefox\/(\d+)/ ); if ( !matches || !matches.length || matches.length < 2 ) { return 0; } return parseInt( matches[ 1 ], 10 /* radix */ ); }, configurePingInterval: function( connection ) { var config = connection._.config, onFail = function( error ) { $( connection ).triggerHandler( events.onError, [ error ] ); }; if ( config && !connection._.pingIntervalId && config.pingInterval ) { connection._.pingIntervalId = window.setInterval( function() { signalR.transports._logic.pingServer( connection ).fail( onFail ); }, config.pingInterval ); } } }; signalR.events = events; signalR.resources = resources; signalR.ajaxDefaults = ajaxDefaults; signalR.changeState = changeState; signalR.isDisconnecting = isDisconnecting; signalR.connectionState = { connecting: 0, connected: 1, reconnecting: 2, disconnected: 4 }; signalR.hub = { start: function() { // This will get replaced with the real hub connection start method when hubs is referenced correctly throw new Error( "SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. <script src='/signalr/js'></script>." ); } }; _pageWindow.load( function() { _pageLoaded = true; } ); function validateTransport( requestedTransport, connection ) { /// <summary>Validates the requested transport by cross checking it with the pre-defined signalR.transports</summary> /// <param name="requestedTransport" type="Object">The designated transports that the user has specified.</param> /// <param name="connection" type="signalR">The connection that will be using the requested transports. Used for logging purposes.</param> /// <returns type="Object" /> if ( $.isArray( requestedTransport ) ) { // Go through transport array and remove an "invalid" tranports for( var i = requestedTransport.length - 1; i >= 0; i-- ) { var transport = requestedTransport[ i ]; if ( $.type( transport ) !== "string" || !signalR.transports[ transport ] ) { connection.log( "Invalid transport: " + transport + ", removing it from the transports list." ); requestedTransport.splice( i, 1 ); } } // Verify we still have transports left, if we dont then we have invalid transports if ( requestedTransport.length === 0 ) { connection.log( "No transports remain within the specified transport array." ); requestedTransport = null; } } else if ( !signalR.transports[ requestedTransport ] && requestedTransport !== "auto" ) { connection.log( "Invalid transport: " + requestedTransport.toString() + "." ); requestedTransport = null; } else if ( requestedTransport === "auto" && signalR._.ieVersion <= 8 ) { // If we're doing an auto transport and we're IE8 then force longPolling, #1764 return [ "longPolling" ]; } return requestedTransport; } function getDefaultPort( protocol ) { if ( protocol === "http:" ) { return 80; } else if ( protocol === "https:" ) { return 443; } } function addDefaultPort( protocol, url ) { // Remove ports from url. We have to check if there's a / or end of line // following the port in order to avoid removing ports such as 8080. if ( url.match( /:\d+$/ ) ) { return url; } else { return url + ":" + getDefaultPort( protocol ); } } function ConnectingMessageBuffer( connection, drainCallback ) { var that = this, buffer = []; that.tryBuffer = function( message ) { if ( connection.state === $.signalR.connectionState.connecting ) { buffer.push( message ); return true; } return false; }; that.drain = function() { // Ensure that the connection is connected when we drain (do not want to drain while a connection is not active) if ( connection.state === $.signalR.connectionState.connected ) { while( buffer.length > 0 ) { drainCallback( buffer.shift() ); } } }; that.clear = function() { buffer = []; }; } signalR.fn = signalR.prototype = { init: function( url, qs, logging ) { var $connection = $( this ); this.url = url; this.qs = qs; this.lastError = null; this._ = { keepAliveData: {}, connectingMessageBuffer: new ConnectingMessageBuffer( this, function( message ) { $connection.triggerHandler( events.onReceived, [ message ] ); } ), lastMessageAt: new Date().getTime(), lastActiveAt: new Date().getTime(), beatInterval: 5000, // Default value, will only be overridden if keep alive is enabled, beatHandle: null, totalTransportConnectTimeout: 0 // This will be the sum of the TransportConnectTimeout sent in response to negotiate and connection.transportConnectTimeout }; if ( typeof (logging) === "boolean" ) { this.logging = logging; } }, _parseResponse: function( response ) { var that = this; if ( !response ) { return response; } else if ( typeof response === "string" ) { return that.json.parse( response ); } else { return response; } }, _originalJson: window.JSON, json: window.JSON, isCrossDomain: function( url, against ) { /// <summary>Checks if url is cross domain</summary> /// <param name="url" type="String">The base URL</param> /// <param name="against" type="Object"> /// An optional argument to compare the URL against, if not specified it will be set to window.location. /// If specified it must contain a protocol and a host property. /// </param> var link; url = $.trim( url ); against = against || window.location; if ( url.indexOf( "http" ) !== 0 ) { return false; } // Create an anchor tag. link = window.document.createElement( "a" ); link.href = url; // When checking for cross domain we have to special case port 80 because the window.location will remove the return link.protocol + addDefaultPort( link.protocol, link.host ) !== against.protocol + addDefaultPort( against.protocol, against.host ); }, ajaxDataType: "text", contentType: "application/json; charset=UTF-8", logging: false, state: signalR.connectionState.disconnected, clientProtocol: "1.5", reconnectDelay: 2000, transportConnectTimeout: 0, disconnectTimeout: 30000, // This should be set by the server in response to the negotiate request (30s default) reconnectWindow: 30000, // This should be set by the server in response to the negotiate request keepAliveWarnAt: 2 / 3, // Warn user of slow connection if we breach the X% mark of the keep alive timeout start: function( options, callback ) { /// <summary>Starts the connection</summary> /// <param name="options" type="Object">Options map</param> /// <param name="callback" type="Function">A callback function to execute when the connection has started</param> var connection = this, config = { pingInterval: 300000, waitForPageLoad: true, transport: "auto", jsonp: false }, initialize, 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 parser = window.document.createElement( "a" ); connection.lastError = null; // Persist the deferral so that if start is called multiple times the same deferral is used. connection._deferral = deferred; if ( !connection.json ) { // no JSON! 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." ); } if ( $.type( options ) === "function" ) { // Support calling with single callback parameter callback = options; } else if ( $.type( options ) === "object" ) { $.extend( config, options ); if ( $.type( config.callback ) === "function" ) { callback = config.callback; } } config.transport = validateTransport( config.transport, connection ); // If the transport is invalid throw an error and abort start if ( !config.transport ) { throw new Error( "SignalR: Invalid transport(s) specified, aborting start." ); } connection._.config = config; // Check to see if start is being called prior to page load // If waitForPageLoad is true we then want to re-direct function call to the window load event if ( !_pageLoaded && config.waitForPageLoad === true ) { connection._.deferredStartHandler = function() { connection.start( options, callback ); }; _pageWindow.bind( "load", connection._.deferredStartHandler ); return deferred.promise(); } // If we're already connecting just return the same deferral as the original connection start if ( connection.state === signalR.connectionState.connecting ) { return deferred.promise(); } else if ( changeState( connection, signalR.connectionState.disconnected, signalR.connectionState.connecting ) === false ) { // We're not connecting so try and transition into connecting. // If we fail to transition then we're either in connected or reconnecting. deferred.resolve( connection ); return deferred.promise(); } configureStopReconnectingTimeout( connection ); // Resolve the full url parser.href = connection.url; if ( !parser.protocol || parser.protocol === ":" ) { connection.protocol = window.document.location.protocol; connection.host = parser.host || window.document.location.host; } else { connection.protocol = parser.protocol; connection.host = parser.host; } connection.baseUrl = connection.protocol + "//" + connection.host; // Set the websocket protocol connection.wsProtocol = connection.protocol === "https:" ? "wss://" : "ws://"; // If jsonp with no/auto transport is specified, then set the transport to long polling // since that is the only transport for which jsonp really makes sense. // Some developers might actually choose to specify jsonp for same origin requests // as demonstrated by Issue #623. if ( config.transport === "auto" && config.jsonp === true ) { config.transport = "longPolling"; } // If the url is protocol relative, prepend the current windows protocol to the url. if ( connection.url.indexOf( "//" ) === 0 ) { connection.url = window.location.protocol + connection.url; connection.log( "Protocol relative URL detected, normalizing it to '" + connection.url + "'." ); } if ( this.isCrossDomain( connection.url ) ) { connection.log( "Auto detected cross domain url." ); if ( config.transport === "auto" ) { // TODO: Support XDM with foreverFrame config.transport = [ "webSockets", "serverSentEvents", "longPolling" ]; } if ( typeof (config.withCredentials) === "undefined" ) { config.withCredentials = true; } // Determine if jsonp is the only choice for negotiation, ajaxSend and ajaxAbort. // i.e. if the browser doesn't supports CORS // If it is, ignore any preference to the contrary, and switch to jsonp. if ( !config.jsonp ) { config.jsonp = !$.support.cors; if ( config.jsonp ) { connection.log( "Using jsonp because this browser doesn't support CORS." ); } } connection.contentType = signalR._.defaultContentType; } connection.withCredentials = config.withCredentials; connection.ajaxDataType = config.jsonp ? "jsonp" : "text"; $( connection ).bind( events.onStart, function( e, data ) { if ( $.type( callback ) === "function" ) { callback.call( connection ); } deferred.resolve( connection ); } ); connection._.initHandler = signalR.transports._logic.initHandler( connection ); initialize = function( transports, index ) { var noTransportError = signalR._.error( resources.noTransportOnInit ); index = index || 0; if ( index >= transports.length ) { if ( index === 0 ) { connection.log( "No transports supported by the server were selected." ); } else if ( index === 1 ) { connection.log( "No fallback transports were selected." ); } else { connection.log( "Fallback transports exhausted." ); } // No transport initialized successfully $( connection ).triggerHandler( events.onError, [ noTransportError ] ); deferred.reject( noTransportError ); // Stop the connection if it has connected and move it into the disconnected state connection.stop(); return; } // The connection was aborted if ( connection.state === signalR.connectionState.disconnected ) { return; } var transportName = transports[ index ], transport = signalR.transports[ transportName ], onFallback = function() { initialize( transports, index + 1 ); }; connection.transport = transport; try { connection._.initHandler.start( transport, function() { // success // Firefox 11+ doesn't allow sync XHR withCredentials: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#withCredentials var isFirefox11OrGreater = signalR._.firefoxMajorVersion( window.navigator.userAgent ) >= 11, asyncAbort = !!connection.withCredentials && isFirefox11OrGreater; connection.log( "The start request succeeded. Transitioning to the connected state." ); if ( supportsKeepAlive( connection ) ) { signalR.transports._logic.monitorKeepAlive( connection ); } signalR.transports._logic.startHeartbeat( connection ); // Used to ensure low activity clients maintain their authentication. // Must be configured once a transport has been decided to perform valid ping requests. signalR._.configurePingInterval( connection ); if ( !changeState( connection, signalR.connectionState.connecting, signalR.connectionState.connected ) ) { connection.log( "WARNING! The connection was not in the connecting state." ); } // Drain any incoming buffered messages (messages that came in prior to connect) connection._.connectingMessageBuffer.drain(); $( connection ).triggerHandler( events.onStart ); // wire the stop handler for when the user leaves the page _pageWindow.bind( "unload", function() { connection.log( "Window unloading, stopping the connection." ); connection.stop( asyncAbort ); } ); if ( isFirefox11OrGreater ) { // Firefox does not fire cross-domain XHRs in the normal unload handler on tab close. // #2400 _pageWindow.bind( "beforeunload", function() { // If connection.stop() runs runs in beforeunload and fails, it will also fail // in unload unless connection.stop() runs after a timeout. window.setTimeout( function() { connection.stop( asyncAbort ); }, 0 ); } ); } }, onFallback ); } catch( error ) { connection.log( transport.name + " transport threw '" + error.message + "' when attempting to start." ); onFallback(); } }; var url = connection.url + "/negotiate", onFailed = function( error, connection ) { var err = signalR._.error( resources.errorOnNegotiate, error, connection._.negotiateRequest ); $( connection ).triggerHandler( events.onError, err ); deferred.reject( err ); // Stop the connection if negotiate failed connection.stop(); }; $( connection ).triggerHandler( events.onStarting ); url = signalR.transports._logic.prepareQueryString( connection, url ); connection.log( "Negotiating with '" + url + "'." ); // Save the ajax negotiate request object so we can abort it if stop is called while the request is in flight. connection._.negotiateRequest = signalR.transports._logic.ajax( connection, { url: url, error: function( error, statusText ) { // We don't want to cause any errors if we're aborting our own negotiate request. if ( statusText !== _negotiateAbortText ) { onFailed( error, connection ); } else { // This rejection will noop if the deferred has already been resolved or rejected. deferred.reject( signalR._.error( resources.stoppedWhileNegotiating, null /* error */, connection._.negotiateRequest ) ); } }, success: function( result ) { var res, keepAliveData, protocolError, transports = [], supportedTransports = []; try { res = connection._parseResponse( result ); } catch( error ) { onFailed( signalR._.error( resources.errorParsingNegotiateResponse, error ), connection ); return; } keepAliveData = connection._.keepAliveData; connection.appRelativeUrl = res.Url; connection.id = res.ConnectionId; connection.token = res.ConnectionToken; connection.webSocketServerUrl = res.WebSocketServerUrl; // The long poll timeout is the ConnectionTimeout plus 10 seconds connection._.pollTimeout = res.ConnectionTimeout * 1000 + 10000; // in ms // Once the server has labeled the PersistentConnection as Disconnected, we should stop attempting to reconnect // after res.DisconnectTimeout seconds. connection.disconnectTimeout = res.DisconnectTimeout * 1000; // in ms // Add the TransportConnectTimeout from the response to the transportConnectTimeout from the client to calculate the total timeout connection._.totalTransportConnectTimeout = connection.transportConnectTimeout + res.TransportConnectTimeout * 1000; // If we have a keep alive if ( res.KeepAliveTimeout ) { // Register the keep alive data as activated keepAliveData.activated = true; // Timeout to designate when to force the connection into reconnecting converted to milliseconds keepAliveData.timeout = res.KeepAliveTimeout * 1000; // Timeout to designate when to warn the developer that the connection may be dead or is not responding. keepAliveData.timeoutWarning = keepAliveData.timeout * connection.keepAliveWarnAt; // Instantiate the frequency in which we check the keep alive. It must be short in order to not miss/pick up any changes connection._.beatInterval = (keepAliveData.timeout - keepAliveData.timeoutWarning) / 3; } else { keepAliveData.activated = false; } connection.reconnectWindow = connection.disconnectTimeout + (keepAliveData.timeout || 0); if ( !res.ProtocolVersion || res.ProtocolVersion !== connection.clientProtocol ) { protocolError = signalR._.error( signalR._.format( resources.protocolIncompatible, connection.clientProtocol, res.ProtocolVersion ) ); $( connection ).triggerHandler( events.onError, [ protocolError ] ); deferred.reject( protocolError ); return; } $.each( signalR.transports, function( key ) { if ( (key.indexOf( "_" ) === 0) || (key === "webSockets" && !res.TryWebSockets) ) { return true; } supportedTransports.push( key ); } ); if ( $.isArray( config.transport ) ) { $.each( config.transport, function( _, transport ) { if ( $.inArray( transport, supportedTransports ) >= 0 ) { transports.push( transport ); } } ); } else if ( config.transport === "auto" ) { transports = supportedTransports; } else if ( $.inArray( config.transport, supportedTransports ) >= 0 ) { transports.push( config.transport ); } initialize( transports ); } } ); return deferred.promise(); }, starting: function( callback ) { /// <summary>Adds a callback that will be invoked before anything is sent over the connection</summary> /// <param name="callback" type="Function">A callback function to execute before the connection is fully instantiated.</param> /// <returns type="signalR" /> var connection = this; $( connection ).bind( events.onStarting, function( e, data ) { callback.call( connection ); } ); return connection; }, send: function( data ) { /// <summary>Sends data over the connection</summary> /// <param name="data" type="String">The data to send over the connection</param> /// <returns type="signalR" /> var connection = this; if ( connection.state === signalR.connectionState.disconnected ) { // Connection hasn't been started yet throw new Error( "SignalR: Connection must be started before data can be sent. Call .start() before .send()" ); } if ( connection.state === signalR.connectionState.connecting ) { // Connection hasn't been started yet throw new Error( "SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started." ); } connection.transport.send( connection, data ); // REVIEW: Should we return deferred here? return connection; }, received: function( callback ) { /// <summary>Adds a callback that will be invoked after anything is received over the connection</summary> /// <param name="callback" type="Function">A callback function to execute when any data is received on the connection</param> /// <returns type="signalR" /> var connection = this; $( connection ).bind( events.onReceived, function( e, data ) { callback.call( connection, data ); } ); return connection; }, stateChanged: function( callback ) { /// <summary>Adds a callback that will be invoked when the connection state changes</summary> /// <param name="callback" type="Function">A callback function to execute when the connection state changes</param> /// <returns type="signalR" /> var connection = this; $( connection ).bind( events.onStateChanged, function( e, data ) { callback.call( connection, data ); } ); return connection; }, error: function( callback ) { /// <summary>Adds a callback that will be invoked after an error occurs with the connection</summary> /// <param name="callback" type="Function">A callback function to execute when an error occurs on the connection</param> /// <returns type="signalR" /> var connection = this; $( connection ).bind( events.onError, function( e, errorData, sendData ) { connection.lastError = errorData; // In practice 'errorData' is the SignalR built error object. // In practice 'sendData' is undefined for all error events except those triggered by // 'ajaxSend' and 'webSockets.send'.'sendData' is the original send payload. callback.call( connection, errorData, sendData ); } ); return connection; }, disconnected: function( callback ) { /// <summary>Adds a callback that will be invoked when the client disconnects</summary> /// <param name="callback" type="Function">A callback function to execute when the connection is broken</param> /// <returns type="signalR" /> var connection = this; $( connection ).bind( events.onDisconnect, function( e, data ) { callback.call( connection ); } ); return connection; }, connectionSlow: function( callback ) { /// <summary>Adds a callback that will be invoked when the client detects a slow connection</summary> /// <param name="callback" type="Function">A callback function to execute when the connection is slow</param> /// <returns type="signalR" /> var connection = this; $( connection ).bind( events.onConnectionSlow, function( e, data ) { callback.call( connection ); } ); return connection; }, reconnecting: function( callback ) { /// <summary>Adds a callback that will be invoked when the underlying transport begins reconnecting</summary> /// <param name="callback" type="Function">A callback function to execute when the connection enters a reconnecting state</param> /// <returns type="signalR" /> var connection = this; $( connection ).bind( events.onReconnecting, function( e, data ) { callback.call( connection ); } ); return connection; }, reconnected: function( callback ) { /// <summary>Adds a callback that will be invoked when the underlying transport reconnects</summary> /// <param name="callback" type="Function">A callback function to execute when the connection is restored</param> /// <returns type="signalR" /> var connection = this; $( connection ).bind( events.onReconnect, function( e, data ) { callback.call( connection ); } ); return connection; }, stop: function( async, notifyServer ) { /// <summary>Stops listening</summary> /// <param name="async" type="Boolean">Whether or not to asynchronously abort the connection</param> /// <param name="notifyServer" type="Boolean">Whether we want to notify the server that we are aborting the connection</param> /// <returns type="signalR" /> var connection = this, // Save deferral because this is always cleaned up deferral = connection._deferral; // Verify that we've bound a load event. if ( connection._.deferredStartHandler ) { // Unbind the event. _pageWindow.unbind( "load", connection._.deferredStartHandler ); } // Always clean up private non-timeout based state. delete connection._.config; delete connection._.deferredStartHandler; // This needs to be checked despite the connection state because a connection start can be deferred until page load. // If we've deferred the start due to a page load we need to unbind the "onLoad" -> start event. if ( !_pageLoaded && (!connection._.config || connection._.config.waitForPageLoad === true) ) { connection.log( "Stopping connection prior to negotiate." ); // If we have a deferral we should reject it if ( deferral ) { deferral.reject( signalR._.error( resources.stoppedWhileLoading ) ); } // Short-circuit because the start has not been fully started. return; } if ( connection.state === signalR.connectionState.disconnected ) { return; } connection.log( "Stopping connection." ); changeState( connection, connection.state, signalR.connectionState.disconnected ); // Clear this no matter what window.clearTimeout( connection._.beatHandle ); window.clearInterval( connection._.pingIntervalId ); if ( connection.transport ) { connection.transport.stop( connection ); if ( notifyServer !== false ) { connection.transport.abort( connection, async ); } if ( supportsKeepAlive( connection ) ) { signalR.transports._logic.stopMonitoringKeepAlive( connection ); } connection.transport = null; } if ( connection._.negotiateRequest ) { // If the negotiation request has already completed this will noop. connection._.negotiateRequest.abort( _negotiateAbortText ); delete connection._.negotiateRequest; } // Ensure that initHandler.stop() is called before connection._deferral is deleted if ( connection._.initHandler ) { connection._.initHandler.stop(); } // Trigger the disconnect event $( connection ).triggerHandler( events.onDisconnect ); delete connection._deferral; delete connection.messageId; delete connection.groupsToken; delete connection.id; delete connection._.pingIntervalId; delete connection._.lastMessageAt; delete connection._.lastActiveAt; // Clear out our message buffer connection._.connectingMessageBuffer.clear(); return connection; }, log: function( msg ) { log( msg, this.logging ); } }; signalR.fn.init.prototype = signalR.fn; signalR.noConflict = function() { /// <summary>Reinstates the original value of $.connection and returns the signalR object for manual assignment</summary> /// <returns type="signalR" /> if ( $.connection === signalR ) { $.connection = _connection; } return signalR; }; if ( $.connection ) { _connection = $.connection; } $.connection = $.signalR = signalR; }( window.jQuery, window )); /* jquery.signalR.transports.common.js */ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information. /*global window:false */ /// <reference path="jquery.signalR.core.js" /> (function( $, window, undefined ) { var signalR = $.signalR, events = $.signalR.events, changeState = $.signalR.changeState, startAbortText = "__Start Aborted__", transportLogic; signalR.transports = {}; function beat( connection ) { if ( connection._.keepAliveData.monitoring ) { checkIfAlive( connection ); } // Ensure that we successfully marked active before continuing the heartbeat. if ( transportLogic.markActive( connection ) ) { connection._.beatHandle = window.setTimeout( function() { beat( connection ); }, connection._.beatInterval ); } } function checkIfAlive( connection ) { var keepAliveData = connection._.keepAliveData, timeElapsed; // Only check if we're connected if ( connection.state === signalR.connectionState.connected ) { timeElapsed = new Date().getTime() - connection._.lastMessageAt; // Check if the keep alive has completely timed out if ( timeElapsed >= keepAliveData.timeout ) { connection.log( "Keep alive timed out. Notifying transport that connection has been lost." ); // Notify transport that the connection has been lost connection.transport.lostConnection( connection ); } else if ( timeElapsed >= keepAliveData.timeoutWarning ) { // This is to assure that the user only gets a single warning if ( !keepAliveData.userNotified ) { connection.log( "Keep alive has been missed, connection may be dead/slow." ); $( connection ).triggerHandler( events.onConnectionSlow ); keepAliveData.userNotified = true; } } else { keepAliveData.userNotified = false; } } } function getAjaxUrl( connection, path ) { var url = connection.url + path; if ( connection.transport ) { url += "?transport=" + connection.transport.name; } return transportLogic.prepareQueryString( connection, url ); } function InitHandler( connection ) { this.connection = connection; this.startRequested = false; this.startCompleted = false; this.connectionStopped = false; } InitHandler.prototype = { start: function( transport, onSuccess, onFallback ) { var that = this, connection = that.connection, failCalled = false; if ( that.startRequested || that.connectionStopped ) { connection.log( "WARNING! " + transport.name + " transport cannot be started. Initialization ongoing or completed." ); return; } connection.log( transport.name + " transport starting." ); that.transportTimeoutHandle = window.setTimeout( function() { if ( !failCalled ) { failCalled = true; connection.log( transport.name + " transport timed out when trying to connect." ); that.transportFailed( transport, undefined, onFallback ); } }, connection._.totalTransportConnectTimeout ); transport.start( connection, function() { if ( !failCalled ) { that.initReceived( transport, onSuccess ); } }, function( error ) { // Don't allow the same transport to cause onFallback to be called twice if ( !failCalled ) { failCalled = true; that.transportFailed( transport, error, onFallback ); } // Returns true if the transport should stop; // false if it should attempt to reconnect return !that.startCompleted || that.connectionStopped; } ); }, stop: function() { this.connectionStopped = true; window.clearTimeout( this.transportTimeoutHandle ); signalR.transports._logic.tryAbortStartRequest( this.connection ); }, initReceived: function( transport, onSuccess ) { var that = this, connection = that.connection; if ( that.startRequested ) { connection.log( "WARNING! The client received multiple init messages." ); return; } if ( that.connectionStopped ) { return; } that.startRequested = true; window.clearTimeout( that.transportTimeoutHandle ); connection.log( transport.name + " transport connected. Initiating start request." ); signalR.transports._logic.ajaxStart( connection, function() { that.startCompleted = true; onSuccess(); } ); }, transportFailed: function( transport, error, onFallback ) { var connection = this.connection, deferred = connection._deferral, wrappedError; if ( this.connectionStopped ) { return; } window.clearTimeout( this.transportTimeoutHandle ); if ( !this.startRequested ) { transport.stop( connection ); connection.log( transport.name + " transport failed to connect. Attempting to fall back." ); onFallback(); } else if ( !this.startCompleted ) {