diff options
Diffstat (limited to 'WebContent/VAADIN/jquery.atmosphere.js')
-rw-r--r-- | WebContent/VAADIN/jquery.atmosphere.js | 2748 |
1 files changed, 0 insertions, 2748 deletions
diff --git a/WebContent/VAADIN/jquery.atmosphere.js b/WebContent/VAADIN/jquery.atmosphere.js deleted file mode 100644 index 520e63d7cb..0000000000 --- a/WebContent/VAADIN/jquery.atmosphere.js +++ /dev/null @@ -1,2748 +0,0 @@ -/** - * Copyright 2012 Jeanfrancois Arcand - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * IE streaming/XDR supports is copied/highly inspired by http://code.google.com/p/jquery-stream/ - * - * Copyright 2011, Donghwan Kim - * Licensed under the Apache License, Version 2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * LocalStorage supports is copied/highly inspired by https://github.com/flowersinthesand/jquery-socket - * Copyright 2011, Donghwan Kim - * Licensed under the Apache License, Version 2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * */ -/** - * Official documentation of this library: https://github.com/Atmosphere/atmosphere/wiki/jQuery.atmosphere.js-API - */ -jQuery.atmosphere = function() { - jQuery(window).bind("unload.atmosphere", function() { - jQuery.atmosphere.unsubscribe(); - }); - - // Prevent ESC to kill the connection from Firefox. - jQuery(window).keypress(function(e){ - if(e.keyCode == 27){ - e.preventDefault(); - } - }); - - var parseHeaders = function(headerString) { - var match, rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, headers = {}; - while (match = rheaders.exec(headerString)) { - headers[match[1]] = match[2]; - } - return headers; - }; - - return { - // Keep the version number in sync with push/build.xml and other locations listed in that file - version : "1.0.14.vaadin4", - requests : [], - callbacks : [], - - onError : function(response) { - }, - onClose : function(response) { - }, - onOpen : function(response) { - }, - onMessage : function(response) { - }, - onReconnect : function(request, response) { - }, - onMessagePublished : function(response) { - }, - onTransportFailure : function (reason, request) { - }, - onLocalMessage : function (response) { - }, - - AtmosphereRequest : function(options) { - - /** - * {Object} Request parameters. - * @private - */ - var _request = { - timeout: 300000, - method: 'GET', - headers: {}, - contentType : '', - callback: null, - url : '', - data : '', - suspend : true, - maxRequest : -1, - reconnect : true, - maxStreamingLength : 10000000, - lastIndex : 0, - logLevel : 'info', - requestCount : 0, - fallbackMethod: 'GET', - fallbackTransport : 'streaming', - transport : 'long-polling', - webSocketImpl: null, - webSocketUrl: null, - webSocketPathDelimiter: "@@", - enableXDR : false, - rewriteURL : false, - attachHeadersAsQueryString : true, - executeCallbackBeforeReconnect : false, - readyState : 0, - lastTimestamp : 0, - withCredentials : false, - trackMessageLength : false , - messageDelimiter : '|', - connectTimeout : -1, - reconnectInterval : 0, - dropAtmosphereHeaders : true, - uuid : 0, - shared : false, - readResponsesHeaders : true, - maxReconnectOnClose: 5, - enableProtocol: false, - onError : function(response) { - }, - onClose : function(response) { - }, - onOpen : function(response) { - }, - onMessage : function(response) { - }, - onReconnect : function(request, response) { - }, - onMessagePublished : function(response) { - }, - onTransportFailure : function (reason, request) { - }, - onLocalMessage : function (request) { - } - }; - - /** - * {Object} Request's last response. - * @private - */ - var _response = { - status: 200, - reasonPhrase : "OK", - responseBody : '', - messages : [], - headers : [], - state : "messageReceived", - transport : "polling", - error: null, - request : null, - partialMessage : "", - errorHandled: false, - id : 0 - }; - - /** - * {websocket} Opened web socket. - * - * @private - */ - var _websocket = null; - - /** - * {SSE} Opened SSE. - * - * @private - */ - var _sse = null; - - /** - * {XMLHttpRequest, ActiveXObject} Opened ajax request (in case of - * http-streaming or long-polling) - * - * @private - */ - var _activeRequest = null; - - /** - * {Object} Object use for streaming with IE. - * - * @private - */ - var _ieStream = null; - - /** - * {Object} Object use for jsonp transport. - * - * @private - */ - var _jqxhr = null; - - /** - * {boolean} If request has been subscribed or not. - * - * @private - */ - var _subscribed = true; - - /** - * {number} Number of test reconnection. - * - * @private - */ - var _requestCount = 0; - - /** - * {boolean} If request is currently aborded. - * - * @private - */ - var _abordingConnection = false; - - /** - * A local "channel' of communication. - * @private - */ - var _localSocketF = null; - - /** - * The storage used. - * @private - */ - var _storageService; - - /** - * Local communication - * @private - */ - var _localStorageService = null; - - /** - * A Unique ID - * @private - */ - var guid = jQuery.now(); - - /** Trace time */ - var _traceTimer; - - // Automatic call to subscribe - _subscribe(options); - - /** - * Initialize atmosphere request object. - * - * @private - */ - function _init() { - _subscribed = true; - _abordingConnection = false; - _requestCount = 0; - - _websocket = null; - _sse = null; - _activeRequest = null; - _ieStream = null; - } - - /** - * Re-initialize atmosphere object. - * @private - */ - function _reinit() { - _clearState(); - _init(); - } - - /** - * Subscribe request using request transport. <br> - * If request is currently opened, this one will be closed. - * - * @param {Object} - * Request parameters. - * @private - */ - function _subscribe(options) { - _reinit(); - - _request = jQuery.extend(_request, options); - // Allow at least 1 request - _request.mrequest = _request.reconnect; - if (!_request.reconnect) { - _request.reconnect = true; - } - } - - /** - * Check if web socket is supported (check for custom implementation - * provided by request object or browser implementation). - * - * @returns {boolean} True if web socket is supported, false - * otherwise. - * @private - */ - function _supportWebsocket() { - return _request.webSocketImpl != null || window.WebSocket || window.MozWebSocket; - } - - /** - * Check if server side events (SSE) is supported (check for custom implementation - * provided by request object or browser implementation). - * - * @returns {boolean} True if web socket is supported, false - * otherwise. - * @private - */ - function _supportSSE() { - return window.EventSource; - } - - /** - * Open request using request transport. <br> - * If request transport is 'websocket' but websocket can't be - * opened, request will automatically reconnect using fallback - * transport. - * - * @private - */ - function _execute() { - // Shared across multiple tabs/windows. - if (_request.shared) { - _localStorageService = _local(_request); - if (_localStorageService != null) { - if (_request.logLevel == 'debug') { - jQuery.atmosphere.debug("Storage service available. All communication will be local"); - } - - if (_localStorageService.open(_request)) { - // Local connection. - return; - } - } - - if (_request.logLevel == 'debug') { - jQuery.atmosphere.debug("No Storage service available."); - } - // Wasn't local or an error occurred - _localStorageService = null; - } - - // Protocol - _request.firstMessage= true; - _request.ctime = jQuery.now(); - - if (_request.transport != 'websocket' && _request.transport != 'sse') { - _executeRequest(); - } else if (_request.transport == 'websocket') { - if (!_supportWebsocket()) { - _reconnectWithFallbackTransport("Websocket is not supported, using request.fallbackTransport (" + _request.fallbackTransport + ")"); - } else { - _executeWebSocket(false); - } - } else if (_request.transport == 'sse') { - if (!_supportSSE()) { - _reconnectWithFallbackTransport("Server Side Events(SSE) is not supported, using request.fallbackTransport (" + _request.fallbackTransport + ")"); - } else { - _executeSSE(false); - } - } - } - - function _local(request) { - var trace, connector, orphan, name = "atmosphere-" + request.url, connectors = { - storage: function() { - if (!jQuery.atmosphere.supportStorage()) { - return; - } - - var storage = window.localStorage, - get = function(key) { - return jQuery.parseJSON(storage.getItem(name + "-" + key)); - }, - set = function(key, value) { - storage.setItem(name + "-" + key, jQuery.stringifyJSON(value)); - }; - - return { - init: function() { - set("children", get("children").concat([guid])); - jQuery(window).on("storage.socket", function(event) { - event = event.originalEvent; - if (event.key === name && event.newValue) { - listener(event.newValue); - } - }); - return get("opened"); - }, - signal: function(type, data) { - storage.setItem(name, jQuery.stringifyJSON({target: "p", type: type, data: data})); - }, - close: function() { - var index, children = get("children"); - - jQuery(window).off("storage.socket"); - if (children) { - index = jQuery.inArray(request.id, children); - if (index > -1) { - children.splice(index, 1); - set("children", children); - } - } - } - }; - }, - windowref: function() { - var win = window.open("", name.replace(/\W/g, "")); - - if (!win || win.closed || !win.callbacks) { - return; - } - - return { - init: function() { - win.callbacks.push(listener); - win.children.push(guid); - return win.opened; - }, - signal: function(type, data) { - if (!win.closed && win.fire) { - win.fire(jQuery.stringifyJSON({target: "p", type: type, data: data})); - } - }, - close : function() { - function remove(array, e) { - var index = jQuery.inArray(e, array); - if (index > -1) { - array.splice(index, 1); - } - } - - // Removes traces only if the parent is alive - if (!orphan) { - remove(win.callbacks, listener); - remove(win.children, guid); - } - } - - }; - } - }; - - // Receives open, close and message command from the parent - function listener(string) { - var command = jQuery.parseJSON(string), data = command.data; - - if (command.target === "c") { - switch (command.type) { - case "open": - _open("opening", 'local', _request) - break; - case "close": - if (!orphan) { - orphan = true; - if (data.reason === "aborted") { - _close(); - } else { - // Gives the heir some time to reconnect - if (data.heir === guid) { - _execute(); - } else { - setTimeout(function() { - _execute(); - }, 100); - } - } - } - break; - case "message": - _prepareCallback(data, "messageReceived", 200, request.transport); - break; - case "localMessage": - _localMessage(data); - break; - } - } - } - - function findTrace() { - var matcher = new RegExp("(?:^|; )(" + encodeURIComponent(name) + ")=([^;]*)").exec(document.cookie); - if (matcher) { - return jQuery.parseJSON(decodeURIComponent(matcher[2])); - } - } - - // Finds and validates the parent socket's trace from the cookie - trace = findTrace(); - if (!trace || jQuery.now() - trace.ts > 1000) { - return; - } - - // Chooses a connector - connector = connectors.storage() || connectors.windowref(); - if (!connector) { - return; - } - - return { - open: function() { - var parentOpened; - - // Checks the shared one is alive - _traceTimer = setInterval(function() { - var oldTrace = trace; - trace = findTrace(); - if (!trace || oldTrace.ts === trace.ts) { - // Simulates a close signal - listener(jQuery.stringifyJSON({target: "c", type: "close", data: {reason: "error", heir: oldTrace.heir}})); - } - }, 1000); - - parentOpened = connector.init(); - if (parentOpened) { - // Firing the open event without delay robs the user of the opportunity to bind connecting event handlers - setTimeout(function() { - _open("opening", 'local', request) - }, 50); - } - return parentOpened; - }, - send: function(event) { - connector.signal("send", event); - }, - localSend: function(event) { - connector.signal("localSend", jQuery.stringifyJSON({id: guid , event: event})); - }, - close: function() { - // Do not signal the parent if this method is executed by the unload event handler - if (!_abordingConnection) { - clearInterval(_traceTimer); - connector.signal("close"); - connector.close(); - } - } - }; - }; - - function share() { - var storageService, name = "atmosphere-" + _request.url, servers = { - // Powered by the storage event and the localStorage - // http://www.w3.org/TR/webstorage/#event-storage - storage: function() { - if (!jQuery.atmosphere.supportStorage()) { - return; - } - - var storage = window.localStorage; - - return { - init: function() { - // Handles the storage event - jQuery(window).on("storage.socket", function(event) { - event = event.originalEvent; - // When a deletion, newValue initialized to null - if (event.key === name && event.newValue) { - listener(event.newValue); - } - }); - }, - signal: function(type, data) { - storage.setItem(name, jQuery.stringifyJSON({target: "c", type: type, data: data})); - }, - get: function(key) { - return jQuery.parseJSON(storage.getItem(name + "-" + key)); - }, - set: function(key, value) { - storage.setItem(name + "-" + key, jQuery.stringifyJSON(value)); - }, - close : function() { - jQuery(window).off("storage.socket"); - storage.removeItem(name); - storage.removeItem(name + "-opened"); - storage.removeItem(name + "-children"); - } - - }; - }, - // Powered by the window.open method - // https://developer.mozilla.org/en/DOM/window.open - windowref: function() { - // Internet Explorer raises an invalid argument error - // when calling the window.open method with the name containing non-word characters - var neim = name.replace(/\W/g, ""), win = (jQuery('iframe[name="' + neim + '"]')[0] - || jQuery('<iframe name="' + neim + '" />').hide().appendTo("body")[0]).contentWindow; - - return { - init: function() { - // Callbacks from different windows - win.callbacks = [listener]; - // In IE 8 and less, only string argument can be safely passed to the function in other window - win.fire = function(string) { - var i; - - for (i = 0; i < win.callbacks.length; i++) { - win.callbacks[i](string); - } - }; - }, - signal: function(type, data) { - if (!win.closed && win.fire) { - win.fire(jQuery.stringifyJSON({target: "c", type: type, data: data})); - } - }, - get: function(key) { - return !win.closed ? win[key] : null; - }, - set: function(key, value) { - if (!win.closed) { - win[key] = value; - } - }, - close : function() {} - }; - } - }; - - - // Receives send and close command from the children - function listener(string) { - var command = jQuery.parseJSON(string), data = command.data; - - if (command.target === "p") { - switch (command.type) { - case "send": - _push(data); - break; - case "localSend": - _localMessage(data); - break; - case "close": - _close(); - break; - } - } - } - - _localSocketF = function propagateMessageEvent(context) { - storageService.signal("message", context); - } - - function leaveTrace() { - document.cookie = encodeURIComponent(name) + "=" + - // Opera's JSON implementation ignores a number whose a last digit of 0 strangely - // but has no problem with a number whose a last digit of 9 + 1 - encodeURIComponent(jQuery.stringifyJSON({ts: jQuery.now() + 1, heir: (storageService.get("children") || [])[0]})); - } - - // Chooses a storageService - storageService = servers.storage() || servers.windowref(); - storageService.init(); - - if (_request.logLevel == 'debug') { - jQuery.atmosphere.debug("Installed StorageService " + storageService); - } - - // List of children sockets - storageService.set("children", []); - - if (storageService.get("opened") != null && !storageService.get("opened")) { - // Flag indicating the parent socket is opened - storageService.set("opened", false); - } - // Leaves traces - leaveTrace(); - _traceTimer = setInterval(leaveTrace, 1000); - - _storageService = storageService; - } - - /** - * @private - */ - function _open(state, transport, request) { - if (_request.shared && transport != 'local') { - share(); - } - - if (_storageService != null) { - _storageService.set("opened", true); - } - - request.close = function() { - _close(); - }; - - if (_response.error == null) { - _response.request = request; - var prevState = _response.state; - _response.state = state; - _response.status = 200; - var prevTransport = _response.transport; - _response.transport = transport; - - var _body = _response.responseBody; - _invokeCallback(); - _response.responseBody = _body; - - _response.state = prevState; - _response.transport = prevTransport; - } - } - - /** - * Execute request using jsonp transport. - * - * @param request - * {Object} request Request parameters, if - * undefined _request object will be used. - * @private - */ - function _jsonp(request) { - // When CORS is enabled, make sure we force the proper transport. - request.transport="jsonp"; - - var rq = _request; - if ((request != null) && (typeof(request) != 'undefined')) { - rq = request; - } - - var url = rq.url; - var data = rq.data; - if (rq.attachHeadersAsQueryString) { - url = _attachHeaders(rq); - if (data != '') { - url += "&X-Atmosphere-Post-Body=" + encodeURIComponent(data); - } - data = ''; - } - - _jqxhr = jQuery.ajax({ - url : url, - type : rq.method, - dataType: "jsonp", - error : function(jqXHR, textStatus, errorThrown) { - _response.error = true; - if (jqXHR.status < 300 && rq.reconnect && _requestCount++ < rq.maxReconnectOnClose) { - _reconnect(_jqxhr, rq); - } else { - _onError(jqXHR.status, errorThrown); - } - }, - jsonp : "jsonpTransport", - success: function(json) { - if (rq.reconnect) { - if (rq.maxRequest == -1 || rq.requestCount++ < rq.maxRequest) { - _readHeaders(_jqxhr, rq); - - if (!rq.executeCallbackBeforeReconnect) { - _reconnect(_jqxhr, rq); - } - - var msg = json.message; - if (msg != null && typeof msg != 'string') { - try { - msg = jQuery.stringifyJSON(msg); - } catch (err) { - // The message was partial - } - } - - if (_handleProtocol(rq, msg)) { - _prepareCallback(msg, "messageReceived", 200, rq.transport); - } - - if (rq.executeCallbackBeforeReconnect) { - _reconnect(_jqxhr, rq); - } - } else { - jQuery.atmosphere.log(_request.logLevel, ["JSONP reconnect maximum try reached " + _request.requestCount]); - _onError(0, "maxRequest reached"); - } - } - }, - data : rq.data, - beforeSend : function(jqXHR) { - _doRequest(jqXHR, rq, false); - } - }); - } - - /** - * Execute request using ajax transport. - * - * @param request - * {Object} request Request parameters, if - * undefined _request object will be used. - * @private - */ - function _ajax(request) { - var rq = _request; - if ((request != null) && (typeof(request) != 'undefined')) { - rq = request; - } - - var url = rq.url; - var data = rq.data; - if (rq.attachHeadersAsQueryString) { - url = _attachHeaders(rq); - if (data != '') { - url += "&X-Atmosphere-Post-Body=" + encodeURIComponent(data); - } - data = ''; - } - - var async = typeof(rq.async) != 'undefined' ? rq.async : true; - _jqxhr = jQuery.ajax({ - url : url, - type : rq.method, - error : function(jqXHR, textStatus, errorThrown) { - _response.error = true; - if (jqXHR.status < 300) { - _reconnect(_jqxhr, rq); - } else { - _onError(jqXHR.status, errorThrown); - } - }, - success: function(data, textStatus, jqXHR) { - - if (rq.reconnect) { - if (rq.maxRequest == -1 || rq.requestCount++ < rq.maxRequest) { - if (!rq.executeCallbackBeforeReconnect) { - _reconnect(_jqxhr, rq); - } - - if (_handleProtocol(rq, data)) { - _prepareCallback(data, "messageReceived", 200, rq.transport); - } - - if (rq.executeCallbackBeforeReconnect) { - _reconnect(_jqxhr, rq); - } - } else { - jQuery.atmosphere.log(_request.logLevel, ["AJAX reconnect maximum try reached " + _request.requestCount]); - _onError(0, "maxRequest reached"); - } - } - }, - beforeSend : function(jqXHR) { - _doRequest(jqXHR, rq, false); - }, - crossDomain : rq.enableXDR, - async: async - }); - } - - /** - * Build websocket object. - * - * @param location - * {string} Web socket url. - * @returns {websocket} Web socket object. - * @private - */ - function _getWebSocket(location) { - if (_request.webSocketImpl != null) { - return _request.webSocketImpl; - } else { - if (window.WebSocket) { - return new WebSocket(location); - } else { - return new MozWebSocket(location); - } - } - } - - /** - * Build web socket url from request url. - * - * @return {string} Web socket url (start with "ws" or "wss" for - * secure web socket). - * @private - */ - function _buildWebSocketUrl() { - var url = _attachHeaders(_request); - - return decodeURI(jQuery('<a href="' + url + '"/>')[0].href.replace(/^http/, "ws")); - } - - /** - * Build SSE url from request url. - * - * @return a url with Atmosphere's headers - * @private - */ - function _buildSSEUrl() { - var url = _attachHeaders(_request); - return url; - } - - /** - * Open SSE. <br> - * Automatically use fallback transport if SSE can't be - * opened. - * - * @private - */ - function _executeSSE(sseOpened) { - - _response.transport = "sse"; - - var location = _buildSSEUrl(_request.url); - - if (_request.logLevel == 'debug') { - jQuery.atmosphere.debug("Invoking executeSSE"); - jQuery.atmosphere.debug("Using URL: " + location); - } - - if (sseOpened) { - _open('re-opening', "sse", _request); - } - - if (_request.enableProtocol && sseOpened) { - var time = jQuery.now() - _request.ctime; - _request.lastTimestamp = Number(_request.stime) + Number(time); - } - - if (sseOpened && !_request.reconnect) { - if (_sse != null) { - _clearState(); - } - return; - } - - try { - _sse = new EventSource(location, {withCredentials: _request.withCredentials}); - } catch (e) { - _onError(0, e); - _reconnectWithFallbackTransport("SSE failed. Downgrading to fallback transport and resending"); - return; - } - - if (_request.connectTimeout > 0) { - _request.id = setTimeout(function() { - if (!sseOpened) { - _clearState(); - } - }, _request.connectTimeout); - } - - _sse.onopen = function(event) { - if (_request.logLevel == 'debug') { - jQuery.atmosphere.debug("SSE successfully opened"); - } - - if (!sseOpened) { - _open('opening', "sse", _request); - } - sseOpened = true; - - if (_request.method == 'POST') { - _response.state = "messageReceived"; - _sse.send(_request.data); - } - }; - - _sse.onmessage = function(message) { - if (message.origin != window.location.protocol + "//" + window.location.host) { - jQuery.atmosphere.log(_request.logLevel, ["Origin was not " + window.location.protocol + "//" + window.location.host]); - return; - } - - var data = message.data; - - if (!_handleProtocol(_request, data)) return; - - _response.state = 'messageReceived'; - _response.status = 200; - - var skipCallbackInvocation = _trackMessageSize(data, _request, _response); - if (!skipCallbackInvocation) { - _invokeCallback(); - _response.responseBody = ''; - _response.messages = []; - } - }; - - _sse.onerror = function(message) { - - clearTimeout(_request.id); - _invokeClose(sseOpened); - _clearState(); - - if (_abordingConnection) { - jQuery.atmosphere.log(_request.logLevel, ["SSE closed normally"]); - } else if (!sseOpened) { - _reconnectWithFallbackTransport("SSE failed. Downgrading to fallback transport and resending"); - } else if (_request.reconnect && (_response.transport == 'sse')) { - if (_requestCount++ < _request.maxReconnectOnClose) { - _request.id = setTimeout(function() { - _executeSSE(true); - }, _request.reconnectInterval); - _response.responseBody = ""; - _response.messages = []; - } else { - jQuery.atmosphere.log(_request.logLevel, ["SSE reconnect maximum try reached " + _requestCount]); - _onError(0, "maxReconnectOnClose reached"); - } - } - }; - } - - /** - * Open web socket. <br> - * Automatically use fallback transport if web socket can't be - * opened. - * - * @private - */ - function _executeWebSocket(webSocketOpened) { - - _response.transport = "websocket"; - - if (_request.enableProtocol && webSocketOpened) { - var time = jQuery.now() - _request.ctime; - _request.lastTimestamp = Number(_request.stime) + Number(time); - } - - var location = _buildWebSocketUrl(_request.url); - var closed = false; - - if (_request.logLevel == 'debug') { - jQuery.atmosphere.debug("Invoking executeWebSocket"); - jQuery.atmosphere.debug("Using URL: " + location); - } - - if (webSocketOpened && !_request.reconnect) { - if (_websocket != null) { - _clearState(); - } - return; - } - - _websocket = _getWebSocket(location); - if (_request.connectTimeout > 0) { - _request.id = setTimeout(function() { - if (!webSocketOpened) { - var _message = { - code : 1002, - reason : "", - wasClean : false - }; - _websocket.onclose(_message); - // Close it anyway - try { - _clearState(); - } catch (e) { - } - return; - } - - }, _request.connectTimeout); - } - - _request.id = setTimeout(function() { - setTimeout(function () { - _clearState(); - }, _request.reconnectInterval) - }, _request.timeout); - - _websocket.onopen = function(message) { - if (_request.logLevel == 'debug') { - jQuery.atmosphere.debug("Websocket successfully opened"); - } - - _open('opening', 'websocket', _request); - - webSocketOpened = true; - _websocket.webSocketOpened = webSocketOpened; - - if (_request.method == 'POST') { - _response.state = "messageReceived"; - _websocket.send(_request.data); - } - }; - - _websocket.onmessage = function(message) { - - clearTimeout(_request.id); - _request.id = setTimeout(function() { - setTimeout(function () { - _clearState(); - }, _request.reconnectInterval) - }, _request.timeout); - - var data = message.data; - - if (!_handleProtocol(_request, data)) return; - - _response.state = 'messageReceived'; - _response.status = 200; - - var skipCallbackInvocation = _trackMessageSize(data, _request, _response); - if (!skipCallbackInvocation) { - _invokeCallback(); - _response.responseBody = ''; - _response.messages = []; - } - }; - - _websocket.onerror = function(message) { - clearTimeout(_request.id) - }; - - _websocket.onclose = function(message) { - if (closed) return - clearTimeout(_request.id); - - var reason = message.reason; - if (reason === "") { - switch (message.code) { - case 1000: - reason = "Normal closure; the connection successfully completed whatever purpose for which " + - "it was created."; - break; - case 1001: - reason = "The endpoint is going away, either because of a server failure or because the " + - "browser is navigating away from the page that opened the connection."; - break; - case 1002: - reason = "The endpoint is terminating the connection due to a protocol error."; - break; - case 1003: - reason = "The connection is being terminated because the endpoint received data of a type it " + - "cannot accept (for example, a text-only endpoint received binary data)."; - break; - case 1004: - reason = "The endpoint is terminating the connection because a data frame was received that " + - "is too large."; - break; - case 1005: - reason = "Unknown: no status code was provided even though one was expected."; - break; - case 1006: - reason = "Connection was closed abnormally (that is, with no close frame being sent)."; - break; - } - } - - jQuery.atmosphere.warn("Websocket closed, reason: " + reason); - jQuery.atmosphere.warn("Websocket closed, wasClean: " + message.wasClean); - - _invokeClose(webSocketOpened); - closed = true; - - if (_abordingConnection) { - jQuery.atmosphere.log(_request.logLevel, ["Websocket closed normally"]); - } else if (!webSocketOpened) { - _reconnectWithFallbackTransport("Websocket failed. Downgrading to Comet and resending"); - - } else if (_request.reconnect && _response.transport == 'websocket') { - _clearState(); - if (_request.reconnect && _requestCount++ < _request.maxReconnectOnClose) { - _request.id = setTimeout(function() { - _response.responseBody = ""; - _response.messages = []; - _executeWebSocket(true); - }, _request.reconnectInterval); - } else { - jQuery.atmosphere.log(_request.logLevel, ["Websocket reconnect maximum try reached " + _requestCount]); - jQuery.atmosphere.warn("Websocket error, reason: " + message.reason); - _onError(0, "maxReconnectOnClose reached"); - } - } - }; - if (_websocket.url === undefined) { - // Android 4.1 does not really support websockets and fails silently - _websocket.onclose({reason:"Android 4.1 does not support websockets.", wasClean: false}); - } - } - - function _handleProtocol(request, message) { - // The first messages is always the uuid. - if (jQuery.trim(message) != 0 && request.enableProtocol && request.firstMessage) { - request.firstMessage = false; - var messages = message.split(request.messageDelimiter); - var pos = messages.length == 2 ? 0 : 1; - request.uuid = jQuery.trim(messages[pos]); - request.stime = jQuery.trim(messages[pos + 1]); - return false; - } - return true; - } - - function _onError(code, reason) { - _clearState(); - - _response.state = 'error'; - _response.reasonPhrase = reason; - _response.responseBody = ""; - _response.messages = []; - _response.status = code; - _invokeCallback(); - } - - /** - * Track received message and make sure callbacks/functions are only invoked when the complete message - * has been received. - * - * @param message - * @param request - * @param response - */ - function _trackMessageSize(message, request, response) { - if (message.length === 0) - return true; - - if (request.trackMessageLength) { - - // If we have found partial message, prepend them. - if (response.partialMessage.length != 0) { - message = response.partialMessage + message; - } - - var messages = []; - var messageStart = message.indexOf(request.messageDelimiter); - while (messageStart !== -1) { - var str = jQuery.trim(message.substring(0, messageStart)); - var messageLength = parseInt(str, 10); - if (isNaN(messageLength)) - throw 'message length "' + str + '" is not a number'; - messageStart += request.messageDelimiter.length; - if (messageStart + messageLength > message.length) { - // message not complete, so there is no trailing messageDelimiter - messageStart = -1; - } else { - // message complete, so add it - messages.push(message.substring(messageStart, messageStart + messageLength)); - // remove consumed characters - message = message.substring(messageStart + messageLength, message.length); - messageStart = message.indexOf(request.messageDelimiter); - } - } - - /* keep any remaining data */ - response.partialMessage = message; - - if (messages.length !== 0) { - response.responseBody = messages.join(request.messageDelimiter); - response.messages = messages; - return false; - } else { - response.responseBody = ""; - response.messages = []; - return true; - } - } else { - response.responseBody = message; - } - return false; - } - - /** - * Reconnect request with fallback transport. <br> - * Used in case websocket can't be opened. - * - * @private - */ - function _reconnectWithFallbackTransport(errorMessage) { - jQuery.atmosphere.log(_request.logLevel, [errorMessage]); - - if (typeof(_request.onTransportFailure) != 'undefined') { - _request.onTransportFailure(errorMessage, _request); - } else if (typeof(jQuery.atmosphere.onTransportFailure) != 'undefined') { - jQuery.atmosphere.onTransportFailure(errorMessage, _request); - } - - _request.transport = _request.fallbackTransport; - var reconnectInterval = _request.connectTimeout == -1 ? 0 : _request.connectTimeout; - if (_request.reconnect && _request.transport != 'none' || _request.transport == null) { - _request.method = _request.fallbackMethod; - _response.transport = _request.fallbackTransport; - _request.fallbackTransport = 'none'; - _request.id = setTimeout(function() { - _execute(); - }, reconnectInterval); - } else { - _onError(500, "Unable to reconnect with fallback transport"); - } - } - - /** - * Get url from request and attach headers to it. - * - * @param request - * {Object} request Request parameters, if - * undefined _request object will be used. - * - * @returns {Object} Request object, if undefined, - * _request object will be used. - * @private - */ - function _attachHeaders(request) { - var rq = _request; - if ((request != null) && (typeof(request) != 'undefined')) { - rq = request; - } - - var url = rq.url; - - // If not enabled - if (!rq.attachHeadersAsQueryString) return url; - - // If already added - if (url.indexOf("X-Atmosphere-Framework") != -1) { - return url; - } - - url += (url.indexOf('?') != -1) ? '&' : '?'; - url += "X-Atmosphere-tracking-id=" + rq.uuid; - url += "&X-Atmosphere-Framework=" + jQuery.atmosphere.version; - url += "&X-Atmosphere-Transport=" + rq.transport; - - if (rq.trackMessageLength) { - url += "&X-Atmosphere-TrackMessageSize=" + "true"; - } - - if (rq.lastTimestamp != undefined) { - url += "&X-Cache-Date=" + rq.lastTimestamp; - } else { - url += "&X-Cache-Date=" + 0; - } - - if (rq.contentType != '') { - url += "&Content-Type=" + rq.contentType; - } - - if (rq.enableProtocol) { - url += "&X-atmo-protocol=true"; - } - - jQuery.each(rq.headers, function(name, value) { - var h = jQuery.isFunction(value) ? value.call(this, rq, request, _response) : value; - if (h != null) { - url += "&" + encodeURIComponent(name) + "=" + encodeURIComponent(h); - } - }); - - return url; - } - - /** - * Build ajax request. <br> - * Ajax Request is an XMLHttpRequest object, except for IE6 where - * ajax request is an ActiveXObject. - * - * @return {XMLHttpRequest, ActiveXObject} Ajax request. - * @private - */ - function _buildAjaxRequest() { - if (jQuery.browser.msie) { - if (typeof XMLHttpRequest == "undefined") - XMLHttpRequest = function () { - try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } - catch (e) {} - try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } - catch (e) {} - try { return new ActiveXObject("Microsoft.XMLHTTP"); } - catch (e) {} - //Microsoft.XMLHTTP points to Msxml2.XMLHTTP and is redundant - throw new Error("This browser does not support XMLHttpRequest."); - }; - } - return new XMLHttpRequest(); - } - - /** - * Execute ajax request. <br> - * - * @param request - * {Object} request Request parameters, if - * undefined _request object will be used. - * @private - */ - function _executeRequest(request) { - var rq = _request; - if ((request != null) || (typeof(request) != 'undefined')) { - rq = request; - } - - rq.lastIndex = 0; - rq.readyState = 0; - - // CORS fake using JSONP - if ((rq.transport == 'jsonp') || ((rq.enableXDR) && (jQuery.atmosphere.checkCORSSupport()))) { - _jsonp(rq); - return; - } - - if (rq.transport == 'ajax') { - _ajax(request); - return; - } - - if (jQuery.browser.msie && jQuery.browser.version < 10) { - if ((rq.transport == 'streaming')) { - rq.enableXDR && window.XDomainRequest ? _ieXDR(rq) : _ieStreaming(rq); - return; - } - - if ((rq.enableXDR) && (window.XDomainRequest)) { - _ieXDR(rq); - return; - } - } - - var reconnectF = function() { - if (rq.reconnect && _requestCount++ < rq.maxReconnectOnClose) { - _reconnect(ajaxRequest, rq, true); - } else { - _onError(0, "maxReconnectOnClose reached"); - } - }; - - if (rq.reconnect && ( rq.maxRequest == -1 || rq.requestCount++ < rq.maxRequest)) { - var ajaxRequest = _buildAjaxRequest(); - _doRequest(ajaxRequest, rq, true); - - if (rq.suspend) { - _activeRequest = ajaxRequest; - } - - if (rq.transport != 'polling') { - _response.transport = rq.transport; - } - - ajaxRequest.onabort = function () { - _invokeClose(true); - }; - - ajaxRequest.onerror = function() { - _response.error = true; - try { - _response.status = XMLHttpRequest.status; - } catch(e) { - _response.status = 500; - } - - if (!_response.status) { - _response.status = 500; - } - _clearState(); - if (!_response.errorHandled) { - reconnectF(); - } - }; - - ajaxRequest.onreadystatechange = function() { - if (_abordingConnection) { - return; - } - - _response.error = null; - var skipCallbackInvocation = false; - var update = false; - - if (rq.transport == 'streaming' && ajaxRequest.readyState == 2) { - _open('opening', rq.transport, rq); - } - - // Opera doesn't call onerror if the server disconnect. - if (jQuery.browser.opera - && rq.transport == 'streaming' - && rq.readyState > 2 - && ajaxRequest.readyState == 4) { - - rq.readyState = 0; - rq.lastIndex = 0; - - reconnectF(); - return; - } - - rq.readyState = ajaxRequest.readyState; - - if (rq.transport == 'streaming' && ajaxRequest.readyState >= 3) { - update = true; - } else if (rq.transport == 'long-polling' && ajaxRequest.readyState === 4) { - update = true; - } - clearTimeout(rq.id); - - if (update) { - // MSIE 9 and lower status can be higher than 1000, Chrome can be 0 - var status = 0; - if (ajaxRequest.readyState != 0) { - status = ajaxRequest.status > 1000 ? 0 : ajaxRequest.status; - } - - if (status >= 300 || status == 0) { - // Prevent onerror callback to be called - _response.errorHandled = true; - _clearState(); - _invokeClose(true); - reconnectF(); - return; - } - var responseText = ajaxRequest.responseText; - - if (jQuery.trim(responseText.length) == 0 && rq.transport == 'long-polling') { - // For browser that aren't support onabort - if (!ajaxRequest.hasData) { - reconnectF(); - } else { - ajaxRequest.hasData = false; - } - return; - } - ajaxRequest.hasData = true; - - _readHeaders(ajaxRequest, _request); - - if (rq.transport == 'streaming') { - if (!jQuery.browser.opera) { - var message = responseText.substring(rq.lastIndex, responseText.length); - rq.lastIndex = responseText.length; - if (!_handleProtocol(_request, message)) { - return; - } - skipCallbackInvocation = _trackMessageSize(message, rq, _response); - } else { - jQuery.atmosphere.iterate(function () { - if (_response.status != 500 && ajaxRequest.responseText.length > rq.lastIndex) { - try { - _response.status = ajaxRequest.status; - } - catch (e) { - _response.status = 404; - } - _response.state = "messageReceived"; - - var message = ajaxRequest.responseText.substring(rq.lastIndex); - rq.lastIndex = ajaxRequest.responseText.length; - if (_handleProtocol(_request, message)) { - skipCallbackInvocation = _trackMessageSize(message, rq, _response); - if (!skipCallbackInvocation) { - _invokeCallback(); - } - - _verifyStreamingLength(ajaxRequest, rq); - } - } else if (_response.status > 400){ - rq.lastIndex = ajaxRequest.responseText.length; - return false; - } - }, 0); - } - } else { - if (!_handleProtocol( _request, responseText)) { - _reconnect(ajaxRequest, rq, false); - return; - } - - skipCallbackInvocation = _trackMessageSize(responseText, rq, _response); - rq.lastIndex = responseText.length; - } - - try { - _response.status = ajaxRequest.status; - _response.headers = parseHeaders(ajaxRequest.getAllResponseHeaders()); - - _readHeaders(ajaxRequest, rq); - } catch(e) { - _response.status = 404; - } - - if (rq.suspend) { - _response.state = _response.status == 0 ? "closed" : "messageReceived"; - } else { - _response.state = "messagePublished"; - } - - if (!rq.executeCallbackBeforeReconnect) { - _reconnect(ajaxRequest, rq, false); - } - - // For backward compatibility with Atmosphere < 0.8 - if (_response.responseBody.indexOf("parent.callback") != -1) { - jQuery.atmosphere.log(rq.logLevel, ["parent.callback no longer supported with 0.8 version and up. Please upgrade"]); - } - - if (!skipCallbackInvocation) { - _invokeCallback(); - } - - if (rq.executeCallbackBeforeReconnect) { - _reconnect(ajaxRequest, rq, false); - } - - _verifyStreamingLength(ajaxRequest, rq); - - if (rq.transport == 'streaming' && rq.readyState == 4) { - _invokeClose(true); - reconnectF(); - } - } - }; - ajaxRequest.send(rq.data); - - if (rq.suspend) { - rq.id = setTimeout(function() { - if (_subscribed) { - setTimeout(function () { - _clearState(); - _executeRequest(rq); - }, rq.reconnectInterval) - } - }, rq.timeout); - } - _subscribed = true; - - } else { - if (rq.logLevel == 'debug') { - jQuery.atmosphere.log(rq.logLevel, ["Max re-connection reached."]); - } - _onError(0, "maxRequest reached"); - } - } - - /** - * Do ajax request. - * @param ajaxRequest Ajax request. - * @param request Request parameters. - * @param create If ajax request has to be open. - */ - function _doRequest(ajaxRequest, request, create) { - // Prevent Android to cache request - var url = _attachHeaders(request); - url = jQuery.atmosphere.prepareURL(url); - - if (create) { - ajaxRequest.open(request.method, url, true); - if (request.connectTimeout > -1) { - request.id = setTimeout(function() { - if (request.requestCount == 0) { - _clearState(); - _prepareCallback("Connect timeout", "closed", 200, request.transport); - } - }, request.connectTimeout); - } - } - - if (_request.withCredentials) { - if ("withCredentials" in ajaxRequest) { - ajaxRequest.withCredentials = true; - } - } - - if (!_request.dropAtmosphereHeaders) { - ajaxRequest.setRequestHeader("X-Atmosphere-Framework", jQuery.atmosphere.version); - ajaxRequest.setRequestHeader("X-Atmosphere-Transport", request.transport); - if (request.lastTimestamp != undefined) { - ajaxRequest.setRequestHeader("X-Cache-Date", request.lastTimestamp); - } else { - ajaxRequest.setRequestHeader("X-Cache-Date", 0); - } - - if (request.trackMessageLength) { - ajaxRequest.setRequestHeader("X-Atmosphere-TrackMessageSize", "true") - } - ajaxRequest.setRequestHeader("X-Atmosphere-tracking-id", request.uuid); - } - - if (request.contentType != '') { - ajaxRequest.setRequestHeader("Content-Type", request.contentType); - } - - jQuery.each(request.headers, function(name, value) { - var h = jQuery.isFunction(value) ? value.call(this, ajaxRequest, request, create, _response) : value; - if (h != null) { - ajaxRequest.setRequestHeader(name, h); - } - }); - } - - function _reconnect(ajaxRequest, request, force) { - if (force || request.transport != 'streaming') { - if ( request.reconnect || (request.suspend && _subscribed)) { - var status = 0; - if (ajaxRequest.readyState != 0) { - status = ajaxRequest.status > 1000 ? 0 : ajaxRequest.status; - } - _response.status = status == 0 ? 204 : status; - _response.reason = status == 0 ? "Server resumed the connection or down." : "OK"; - - var reconnectInterval = request.reconnectInterval; - - // Reconnect immedialtely - request.id = setTimeout(function () { - _executeRequest(request); - }, reconnectInterval); - } - } - } - - // From jquery-stream, which is APL2 licensed as well. - function _ieXDR(request) { - if (request.transport != "polling") { - _ieStream = _configureXDR(request); - _ieStream.open(); - } else { - _configureXDR(request).open(); - } - } - - // From jquery-stream - function _configureXDR(request) { - var rq = _request; - if ((request != null) && (typeof(request) != 'undefined')) { - rq = request; - } - - var transport = rq.transport; - var lastIndex = 0; - var xdrCallback = function (xdr) { - var responseBody = xdr.responseText; - - if (!_handleProtocol(request, responseBody)) return; - - _prepareCallback(responseBody, "messageReceived", 200, transport); - }; - - var xdr = new window.XDomainRequest(); - var rewriteURL = rq.rewriteURL || function(url) { - // Maintaining session by rewriting URL - // http://stackoverflow.com/questions/6453779/maintaining-session-by-rewriting-url - var match = /(?:^|;\s*)(JSESSIONID|PHPSESSID)=([^;]*)/.exec(document.cookie); - - switch (match && match[1]) { - case "JSESSIONID": - return url.replace(/;jsessionid=[^\?]*|(\?)|$/, ";jsessionid=" + match[2] + "$1"); - case "PHPSESSID": - return url.replace(/\?PHPSESSID=[^&]*&?|\?|$/, "?PHPSESSID=" + match[2] + "&").replace(/&$/, ""); - } - return url; - }; - - // Handles open and message event - xdr.onprogress = function() { - handle(xdr); - }; - - // Handles error event - xdr.onerror = function() { - // If the server doesn't send anything back to XDR will fail with polling - if (rq.transport != 'polling') { - _reconnect(xdr, rq, false); - } - }; - - // Handles close event - xdr.onload = function() { - handle(xdr); - }; - - var handle = function (xdr) { - // XDomain loop forever on itself without this. - // TODO: Clearly I need to come with something better than that solution - if (rq.lastMessage == xdr.responseText) return; - - if (rq.executeCallbackBeforeReconnect) { - xdrCallback(xdr); - } - - if (rq.transport == "long-polling" && (rq.reconnect && (rq.maxRequest == -1 || rq.requestCount++ < rq.maxRequest))) { - xdr.status = 200; - _reconnect(xdr, rq, false); - } - - if (!rq.executeCallbackBeforeReconnect) { - xdrCallback(xdr); - } - rq.lastMessage = xdr.responseText; - }; - - return { - open: function() { - if (rq.method == 'POST') { - rq.attachHeadersAsQueryString = true; - } - var url = _attachHeaders(rq); - if (rq.method == 'POST') { - url += "&X-Atmosphere-Post-Body=" + encodeURIComponent(rq.data); - } - xdr.open(rq.method, rewriteURL(url)); - xdr.send(); - if (rq.connectTimeout > -1) { - rq.id = setTimeout(function() { - if (rq.requestCount == 0) { - _clearState(); - _prepareCallback("Connect timeout", "closed", 200, rq.transport); - } - }, rq.connectTimeout); - } - }, - close: function() { - xdr.abort(); - _prepareCallback(xdr.responseText, "closed", 200, transport); - } - }; - } - - // From jquery-stream, which is APL2 licensed as well. - function _ieStreaming(request) { - _ieStream = _configureIE(request); - _ieStream.open(); - } - - function _configureIE(request) { - var rq = _request; - if ((request != null) && (typeof(request) != 'undefined')) { - rq = request; - } - - var stop; - var doc = new window.ActiveXObject("htmlfile"); - - doc.open(); - doc.close(); - - var url = rq.url; - - if (rq.transport != 'polling') { - _response.transport = rq.transport; - } - - return { - open: function() { - var iframe = doc.createElement("iframe"); - - url = _attachHeaders(rq); - if (rq.data != '') { - url += "&X-Atmosphere-Post-Body=" + encodeURIComponent(rq.data); - } - - // Finally attach a timestamp to prevent Android and IE caching. - url = jQuery.atmosphere.prepareURL(url); - - iframe.src = url; - doc.body.appendChild(iframe); - - // For the server to respond in a consistent format regardless of user agent, we polls response text - var cdoc = iframe.contentDocument || iframe.contentWindow.document; - - stop = jQuery.atmosphere.iterate(function() { - try { - if (!cdoc.firstChild) { - return; - } - - // Detects connection failure - if (cdoc.readyState === "complete") { - try { - jQuery.noop(cdoc.fileSize); - } catch(e) { - _prepareCallback("Connection Failure", "error", 500, rq.transport); - return false; - } - } - - var res = cdoc.body ? cdoc.body.lastChild : cdoc; - var readResponse = function() { - // Clones the element not to disturb the original one - var clone = res.cloneNode(true); - - // If the last character is a carriage return or a line feed, IE ignores it in the innerText property - // therefore, we add another non-newline character to preserve it - clone.appendChild(cdoc.createTextNode(".")); - - var text = clone.innerText; - text = text.substring(0, text.length - 1); - return text; - - }; - - //To support text/html content type - if (!jQuery.nodeName(res, "pre")) { - // Injects a plaintext element which renders text without interpreting the HTML and cannot be stopped - // it is deprecated in HTML5, but still works - var head = cdoc.head || cdoc.getElementsByTagName("head")[0] || cdoc.documentElement || cdoc; - var script = cdoc.createElement("script"); - - script.text = "document.write('<plaintext>')"; - - head.insertBefore(script, head.firstChild); - head.removeChild(script); - - // The plaintext element will be the response container - res = cdoc.body.lastChild; - } - - // Handles open event - _prepareCallback(readResponse(), "opening", 200, rq.transport); - - // Handles message and close event - stop = jQuery.atmosphere.iterate(function() { - var text = readResponse(); - if (text.length > rq.lastIndex) { - _response.status = 200; - _response.error = null; - - var message = text; - if (message.length != 0 && _handleProtocol(rq, message)) { - // Empties response every time that it is handled - res.innerText = ""; - _prepareCallback(message, "messageReceived", 200, rq.transport); - } - rq.lastIndex = 0; - } - - if (cdoc.readyState === "complete") { - _prepareCallback("", "closed", 200, rq.transport); - _prepareCallback("", "re-opening", 200, rq.transport); - rq.id = setTimeout(function() { - _ieStreaming(rq); - }, rq.reconnectInterval); - return false; - } - }, null); - - return false; - } catch (err) { - _response.error = true; - if (_requestCount++ < rq.maxReconnectOnClose) { - rq.id = setTimeout(function() { - _ieStreaming(rq); - }, rq.reconnectInterval); - } else { - _onError(0, "maxReconnectOnClose reached"); - } - doc.execCommand("Stop"); - doc.close(); - return false; - } - }); - }, - - close: function() { - if (stop) { - stop(); - } - - doc.execCommand("Stop"); - _prepareCallback("", "closed", 200, rq.transport); - } - }; - } - - /* - * Send message. <br> - * Will be automatically dispatch to other connected. - * - * @param {Object,string} Message to send. - * @private - */ - function _push(message) { - - if (_response.status == 408) { - _pushOnClose(message); - } else if (_localStorageService != null) { - _pushLocal(message); - } else if (_activeRequest != null || _sse != null) { - _pushAjaxMessage(message); - } else if (_ieStream != null) { - _pushIE(message); - } else if (_jqxhr != null) { - _pushJsonp(message); - } else if (_websocket != null) { - _pushWebSocket(message); - } - } - - function _pushOnClose(message) { - var rq = _getPushRequest(message); - rq.transport = "ajax"; - rq.method = "GET"; - rq.async = false; - rq.reconnect = false; - _executeRequest(rq); - } - - function _pushLocal(message) { - _localStorageService.send(message); - } - - function _intraPush(message) { - // IE 9 will crash if not. - if (message.length == 0) return; - - try { - if (_localStorageService) { - _localStorageService.localSend(message); - } else if (_storageService) { - _storageService.signal("localMessage", jQuery.stringifyJSON({id: guid , event: message})); - } - } catch (err) { - jQuery.atmosphere.error(err); - } - } - - /** - * Send a message using currently opened ajax request (using - * http-streaming or long-polling). <br> - * - * @param {string, Object} Message to send. This is an object, string - * message is saved in data member. - * @private - */ - function _pushAjaxMessage(message) { - var rq = _getPushRequest(message); - _executeRequest(rq); - } - - /** - * Send a message using currently opened ie streaming (using - * http-streaming or long-polling). <br> - * - * @param {string, Object} Message to send. This is an object, string - * message is saved in data member. - * @private - */ - function _pushIE(message) { - if (_request.enableXDR && jQuery.atmosphere.checkCORSSupport()) { - var rq = _getPushRequest(message); - // Do not reconnect since we are pushing. - rq.reconnect = false; - _jsonp(rq); - } else { - _pushAjaxMessage(message); - } - } - - /** - * Send a message using jsonp transport. <br> - * - * @param {string, Object} Message to send. This is an object, string - * message is saved in data member. - * @private - */ - function _pushJsonp(message) { - _pushAjaxMessage(message); - } - - function _getStringMessage(message) { - var msg = message; - if (typeof(msg) == 'object') { - msg = message.data; - } - return msg; - } - - /** - * Build request use to push message using method 'POST' <br>. - * Transport is defined as 'polling' and 'suspend' is set to false. - * - * @return {Object} Request object use to push message. - * @private - */ - function _getPushRequest(message) { - var msg = _getStringMessage(message); - - var rq = { - connected: false, - timeout: 60000, - method: 'POST', - url: _request.url, - contentType : _request.contentType, - headers: {}, - reconnect : true, - callback: null, - data : msg, - suspend : false, - maxRequest : -1, - logLevel : 'info', - requestCount : 0, - withCredentials : _request.withCredentials, - transport: 'polling', - attachHeadersAsQueryString: true, - enableXDR: _request.enableXDR, - uuid : _request.uuid, - messageDelimiter : '|', - enableProtocol : false, - maxReconnectOnClose : _request.maxReconnectOnClose - }; - - if (typeof(message) == 'object') { - rq = jQuery.extend(rq, message); - } - - return rq; - } - - /** - * Send a message using currently opened websocket. <br> - * - */ - function _pushWebSocket(message) { - var msg = _getStringMessage(message); - var data; - try { - if (_request.webSocketUrl != null) { - data = _request.webSocketPathDelimiter - + _request.webSocketUrl - + _request.webSocketPathDelimiter - + msg; - } else { - data = msg; - } - - _websocket.send(data); - - } catch (e) { - _websocket.onclose = function(message) { - }; - _clearState(); - - _reconnectWithFallbackTransport("Websocket failed. Downgrading to Comet and resending " + data); - _pushAjaxMessage(message); - } - } - - function _localMessage(message) { - var m = jQuery.parseJSON(message); - if (m.id != guid) { - if (typeof(_request.onLocalMessage) != 'undefined') { - _request.onLocalMessage(m.event); - } else if (typeof(jQuery.atmosphere.onLocalMessage) != 'undefined') { - jQuery.atmosphere.onLocalMessage(m.event); - } - } - } - - function _prepareCallback(messageBody, state, errorCode, transport) { - - if (state == "messageReceived") { - if (_trackMessageSize(messageBody, _request, _response)) return; - } else { - _response.responseBody = messageBody; - } - - _response.transport = transport; - _response.status = errorCode; - _response.state = state; - - _invokeCallback(); - } - - function _readHeaders(xdr, request) { - if (!request.readResponsesHeaders && !request.enableProtocol) { - request.lastTimestamp = jQuery.now(); - request.uuid = jQuery.atmosphere.guid(); - return; - } - - try { - var tempDate = xdr.getResponseHeader('X-Cache-Date'); - if (tempDate && tempDate != null && tempDate.length > 0 ) { - request.lastTimestamp = tempDate.split(" ").pop(); - } - - var tempUUID = xdr.getResponseHeader('X-Atmosphere-tracking-id'); - if (tempUUID && tempUUID != null) { - request.uuid = tempUUID.split(" ").pop(); - } - - // HOTFIX for firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=608735 - if (request.headers) { - jQuery.each(_request.headers, function (name) { - var v = xdr.getResponseHeader(name); - if (v) { - _response.headers[name] = v; - } - }); - } - } catch (e) { - } - } - - function _invokeFunction(response) { - _f(response, _request); - // Global - _f(response, jQuery.atmosphere); - } - - function _f(response, f) { - switch (response.state) { - case "messageReceived" : - _requestCount = 0; - if (typeof(f.onMessage) != 'undefined') f.onMessage(response); - break; - case "error" : - if (typeof(f.onError) != 'undefined') f.onError(response); - break; - case "opening" : - _request.closed = false; - if (typeof(f.onOpen) != 'undefined') f.onOpen(response); - break; - case "messagePublished" : - if (typeof(f.onMessagePublished) != 'undefined') f.onMessagePublished(response); - break; - case "re-opening" : - if (typeof(f.onReconnect) != 'undefined') f.onReconnect(_request, response); - break; - case "unsubscribe" : - case "closed" : - var closed = typeof(_request.closed) != 'undefined' ? _request.closed : false; - if (typeof(f.onClose) != 'undefined' && !closed) f.onClose(response); - _request.closed = true; - break; - } - } - - function _invokeClose(wasOpen) { - _response.state = 'closed'; - _response.responseBody = ""; - _response.messages = []; - _response.status = !wasOpen ? 501 : 200; - _invokeCallback(); - } - - /** - * Invoke request callbacks. - * - * @private - */ - function _invokeCallback() { - var call = function (index, func) { - func(_response); - }; - - if (_localStorageService == null && _localSocketF != null) { - _localSocketF(_response.responseBody); - } - - _request.reconnect = _request.mrequest; - - var messages = (typeof(_response.responseBody) == 'string' && _request.trackMessageLength) ? - (_response.messages.length>0 ? _response.messages : ['']) : new Array(_response.responseBody); - for (var i = 0; i < messages.length; i++) { - - if (messages.length > 1 && messages[i].length == 0) { - continue; - } - _response.responseBody = jQuery.trim(messages[i]); - - if (_response.responseBody.length == 0 && _response.state == "messageReceived") { - continue; - } - - _invokeFunction(_response); - - // Invoke global callbacks - if (jQuery.atmosphere.callbacks.length > 0) { - if (_request.logLevel == 'debug') { - jQuery.atmosphere.debug("Invoking " + jQuery.atmosphere.callbacks.length + " global callbacks: " + _response.state); - } - try { - jQuery.each(jQuery.atmosphere.callbacks, call); - } catch (e) { - jQuery.atmosphere.log(_request.logLevel, ["Callback exception" + e]); - } - } - - // Invoke request callback - if (typeof(_request.callback) == 'function') { - if (_request.logLevel == 'debug') { - jQuery.atmosphere.debug("Invoking request callbacks"); - } - try { - _request.callback(_response); - } catch (e) { - jQuery.atmosphere.log(_request.logLevel, ["Callback exception" + e]); - } - } - } - - } - - /** - * - * @private - */ - function _verifyStreamingLength(ajaxRequest, rq){ - // Wait to be sure we have the full message before closing. - if (_response.partialMessage == "" && - (rq.transport == 'streaming') && - (ajaxRequest.responseText.length > rq.maxStreamingLength)) { - _response.messages = []; - _invokeClose(true); - _disconnect(); - _clearState(); - _reconnect(ajaxRequest, rq, true); - } - } - - /** - * Disconnect - * @private - */ - function _disconnect() { - if (_request.enableProtocol) { - var query = "X-Atmosphere-Transport=close&X-Atmosphere-tracking-id=" + _request.uuid; - var url = _request.url.replace(/([?&])_=[^&]*/, query); - url = url + (url === _request.url ? (/\?/.test(_request.url) ? "&" : "?") + query : ""); - - if (_request.connectTimeout > -1) { - jQuery.ajax({url: url, async: false, timeout: _request.connectTimeout}); - } else { - jQuery.ajax({url: url, async: false}); - } - } - } - - /** - * Close request. - * - * @private - */ - function _close() { - _request.reconnect = false; - _abordingConnection = true; - _response.request = _request; - _response.state = 'unsubscribe'; - _response.responseBody = ""; - _response.messages = []; - _response.status = 408; - _invokeCallback(); - - _clearState(); - } - - function _clearState() { - if (_ieStream != null) { - _ieStream.close(); - _ieStream = null; - } - if (_jqxhr != null) { - _jqxhr.abort(); - _jqxhr = null; - } - if (_activeRequest != null) { - _activeRequest.abort(); - _activeRequest = null; - } - if (_websocket != null) { - if (_websocket.webSocketOpened) { - _websocket.close(); - } - _websocket = null; - } - if (_sse != null) { - _sse.close(); - _sse = null; - } - _clearStorage(); - } - - function _clearStorage() { - // Stop sharing a connection - if (_storageService != null) { - // Clears trace timer - clearInterval(_traceTimer); - // Removes the trace - document.cookie = encodeURIComponent("atmosphere-" + _request.url) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT"; - // The heir is the parent unless unloading - _storageService.signal("close", {reason: "", heir: !_abordingConnection ? guid : (_storageService.get("children") || [])[0]}); - _storageService.close(); - } - if (_localStorageService != null) { - _localStorageService.close(); - } - }; - - this.subscribe = function(options) { - _subscribe(options); - _execute(); - }; - - this.execute = function() { - _execute(); - }; - - this.invokeCallback = function() { - _invokeCallback(); - }; - - this.close = function() { - _close(); - }; - - this.disconnect = function () { - _disconnect(); - }; - - this.getUrl = function() { - return _request.url; - }; - - this.getUUID = function() { - return _request.uuid; - }; - - this.push = function(message) { - _push(message); - }; - - this.pushLocal = function(message) { - _intraPush(message); - }; - - this.enableProtocol = function(message) { - return _request.enableProtocol; - }; - - this.response = _response; - }, - - subscribe: function(url, callback, request) { - if (typeof(callback) == 'function') { - jQuery.atmosphere.addCallback(callback); - } - - if (typeof(url) != "string") { - request = url; - } else { - request.url = url; - } - - var rq = new jQuery.atmosphere.AtmosphereRequest(request); - rq.execute(); - - jQuery.atmosphere.requests[jQuery.atmosphere.requests.length] = rq; - return rq; - }, - - addCallback: function(func) { - if (jQuery.inArray(func, jQuery.atmosphere.callbacks) == -1) { - jQuery.atmosphere.callbacks.push(func); - } - }, - - removeCallback: function(func) { - var index = jQuery.inArray(func, jQuery.atmosphere.callbacks); - if (index != -1) { - jQuery.atmosphere.callbacks.splice(index, 1); - } - }, - - unsubscribe : function() { - if (jQuery.atmosphere.requests.length > 0) { - var requestsClone = [].concat(jQuery.atmosphere.requests); - for (var i = 0; i < requestsClone.length; i++) { - var rq = requestsClone[i]; - rq.disconnect(); - rq.close(); - clearTimeout(rq.response.request.id); - } - } - jQuery.atmosphere.requests = []; - jQuery.atmosphere.callbacks = []; - }, - - unsubscribeUrl: function(url) { - var idx = -1; - if (jQuery.atmosphere.requests.length > 0) { - for (var i = 0; i < jQuery.atmosphere.requests.length; i++) { - var rq = jQuery.atmosphere.requests[i]; - - // Suppose you can subscribe once to an url - if (rq.getUrl() == url) { - rq.disconnect(); - rq.close(); - clearTimeout(rq.response.request.id); - idx = i; - break; - } - } - } - if (idx >= 0) { - jQuery.atmosphere.requests.splice(idx, 1); - } - }, - - publish: function(request) { - if (typeof(request.callback) == 'function') { - jQuery.atmosphere.addCallback(callback); - } - request.transport = "polling"; - - var rq = new jQuery.atmosphere.AtmosphereRequest(request); - jQuery.atmosphere.requests[jQuery.atmosphere.requests.length] = rq; - return rq; - }, - - checkCORSSupport : function() { - if (jQuery.browser.msie && !window.XDomainRequest) { - return true; - } else if (jQuery.browser.opera && jQuery.browser.version < 12.0) { - return true; - } - - // Force Android to use CORS as some version like 2.2.3 fail otherwise - var ua = navigator.userAgent.toLowerCase(); - var isAndroid = ua.indexOf("android") > -1; - if (isAndroid) { - return true; - } - return false; - }, - - S4 : function() { - return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); - }, - - guid : function() { - return (jQuery.atmosphere.S4() + jQuery.atmosphere.S4() + "-" + jQuery.atmosphere.S4() + "-" + jQuery.atmosphere.S4() + "-" + jQuery.atmosphere.S4() + "-" + jQuery.atmosphere.S4() + jQuery.atmosphere.S4() + jQuery.atmosphere.S4()); - }, - - // From jQuery-Stream - prepareURL: function(url) { - // Attaches a time stamp to prevent caching - var ts = jQuery.now(); - var ret = url.replace(/([?&])_=[^&]*/, "$1_=" + ts); - - return ret + (ret === url ? (/\?/.test(url) ? "&" : "?") + "_=" + ts : ""); - }, - - // From jQuery-Stream - param : function(data) { - return jQuery.param(data, jQuery.ajaxSettings.traditional); - }, - - supportStorage : function() { - var storage = window.localStorage; - if (storage) { - try { - storage.setItem("t", "t"); - storage.removeItem("t"); - // The storage event of Internet Explorer and Firefox 3 works strangely - return window.StorageEvent && !jQuery.browser.msie && !(jQuery.browser.mozilla && jQuery.browser.version.split(".")[0] === "1"); - } catch (e) { - } - } - - return false; - }, - - iterate : function (fn, interval) { - var timeoutId; - - // Though the interval is 0 for real-time application, there is a delay between setTimeout calls - // For detail, see https://developer.mozilla.org/en/window.setTimeout#Minimum_delay_and_timeout_nesting - interval = interval || 0; - - (function loop() { - timeoutId = setTimeout(function() { - if (fn() === false) { - return; - } - - loop(); - }, interval); - })(); - - return function() { - clearTimeout(timeoutId); - }; - }, - - log: function (level, args) { - if (window.console) { - var logger = window.console[level]; - if (typeof logger == 'function') { - logger.apply(window.console, args); - } - } - }, - - warn: function() { - jQuery.atmosphere.log('warn', arguments); - }, - - info :function() { - jQuery.atmosphere.log('info', arguments); - }, - - debug: function() { - jQuery.atmosphere.log('debug', arguments); - }, - - error: function() { - jQuery.atmosphere.log('error', arguments); - } - }; -}(); - -// http://stackoverflow.com/questions/9645803/whats-the-replacement-for-browser -// Limit scope pollution from any deprecated API -(function () { - - var matched, browser; - -// Use of jQuery.browser is frowned upon. -// More details: http://api.jquery.com/jQuery.browser -// jQuery.uaMatch maintained for back-compat - jQuery.uaMatch = function (ua) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || - /(webkit)[ \/]([\w.]+)/.exec(ua) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; - }; - - matched = jQuery.uaMatch(navigator.userAgent); - browser = {}; - - if (matched.browser) { - browser[ matched.browser ] = true; - browser.version = matched.version; - } - -// Chrome is Webkit, but Webkit is also Safari. - if (browser.chrome) { - browser.webkit = true; - } else if (browser.webkit) { - browser.safari = true; - } - - jQuery.browser = browser; - - jQuery.sub = function () { - function jQuerySub(selector, context) { - return new jQuerySub.fn.init(selector, context); - } - - jQuery.extend(true, jQuerySub, this); - jQuerySub.superclass = this; - jQuerySub.fn = jQuerySub.prototype = this(); - jQuerySub.fn.constructor = jQuerySub; - jQuerySub.sub = this.sub; - jQuerySub.fn.init = function init(selector, context) { - if (context && context instanceof jQuery && !(context instanceof jQuerySub)) { - context = jQuerySub(context); - } - - return jQuery.fn.init.call(this, selector, context, rootjQuerySub); - }; - jQuerySub.fn.init.prototype = jQuerySub.fn; - var rootjQuerySub = jQuerySub(document); - return jQuerySub; - }; - -})(); - -/* - * jQuery stringifyJSON - * http://github.com/flowersinthesand/jquery-stringifyJSON - * - * Copyright 2011, Donghwan Kim - * Licensed under the Apache License, Version 2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - */ -// This plugin is heavily based on Douglas Crockford's reference implementation -(function(jQuery) { - - var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, meta = { - '\b' : '\\b', - '\t' : '\\t', - '\n' : '\\n', - '\f' : '\\f', - '\r' : '\\r', - '"' : '\\"', - '\\' : '\\\\' - }; - - function quote(string) { - return '"' + string.replace(escapable, function(a) { - var c = meta[a]; - return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4); - }) + '"'; - } - - function f(n) { - return n < 10 ? "0" + n : n; - } - - function str(key, holder) { - var i, v, len, partial, value = holder[key], type = typeof value; - - if (value && typeof value === "object" && typeof value.toJSON === "function") { - value = value.toJSON(key); - type = typeof value; - } - - switch (type) { - case "string": - return quote(value); - case "number": - return isFinite(value) ? String(value) : "null"; - case "boolean": - return String(value); - case "object": - if (!value) { - return "null"; - } - - switch (Object.prototype.toString.call(value)) { - case "[object Date]": - return isFinite(value.valueOf()) ? '"' + value.getUTCFullYear() + "-" + f(value.getUTCMonth() + 1) + "-" + f(value.getUTCDate()) + "T" + - f(value.getUTCHours()) + ":" + f(value.getUTCMinutes()) + ":" + f(value.getUTCSeconds()) + "Z" + '"' : "null"; - case "[object Array]": - len = value.length; - partial = []; - for (i = 0; i < len; i++) { - partial.push(str(i, value) || "null"); - } - - return "[" + partial.join(",") + "]"; - default: - partial = []; - for (i in value) { - if (Object.prototype.hasOwnProperty.call(value, i)) { - v = str(i, value); - if (v) { - partial.push(quote(i) + ":" + v); - } - } - } - - return "{" + partial.join(",") + "}"; - } - } - } - - jQuery.stringifyJSON = function(value) { - if (window.JSON && window.JSON.stringify) { - return window.JSON.stringify(value); - } - - return str("", {"": value}); - }; - -}(jQuery)); |