All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.resources.primefaces.socket.0-atmosphere.js Maven / Gradle / Ivy

Go to download

PrimeFaces is one of the most popular UI libraries in Java EE Ecosystem and widely used by software companies, world renowned brands, banks, financial institutions, insurance companies, universities and more.

There is a newer version: 14.0.0-RC3
Show newest version
/*
 * Copyright 2015 Async-IO.org
 *
 * 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.
 */
/**
 * Atmosphere.js
 * https://github.com/Atmosphere/atmosphere-javascript
 *
 * API reference
 * https://github.com/Atmosphere/atmosphere/wiki/jQuery.atmosphere.js-API
 *
 * Highly inspired by
 * - Portal by Donghwan Kim http://flowersinthesand.github.io/portal/
 */
(function (root, factory) {
    if (typeof define === "function" && define.amd) {
        // AMD
        define(factory);
    } else if(typeof exports !== 'undefined') {
        // CommonJS
        module.exports = factory();
    } else {
        // Browser globals, Window
        root.atmosphere = factory();
    }
}(this, function () {

    "use strict";

    var atmosphere = {},
        guid,
        offline = false,
        requests = [],
        callbacks = [],
        uuid = 0,
        hasOwn = Object.prototype.hasOwnProperty;

    atmosphere = {
        version: "2.3.3-javascript",
        onError: function (response) {
        },
        onClose: function (response) {
        },
        onOpen: function (response) {
        },
        onReopen: function (response) {
        },
        onMessage: function (response) {
        },
        onReconnect: function (request, response) {
        },
        onMessagePublished: function (response) {
        },
        onTransportFailure: function (errorMessage, _request) {
        },
        onLocalMessage: function (response) {
        },
        onFailureToReconnect: function (request, response) {
        },
        onClientTimeout: function (request) {
        },
        onOpenAfterResume: function (request) {
        },

        /**
         * Creates an object based on an atmosphere subscription that exposes functions defined by the Websocket interface.
         *
         * @class WebsocketApiAdapter
         * @param {Object} request the request object to build the underlying subscription
         * @constructor
         */
        WebsocketApiAdapter: function (request) {
            var _socket, _adapter;

            /**
             * Overrides the onMessage callback in given request.
             *
             * @method onMessage
             * @param {Object} e the event object
             */
            request.onMessage = function (e) {
                _adapter.onmessage({data: e.responseBody});
            };

            /**
             * Overrides the onMessagePublished callback in given request.
             *
             * @method onMessagePublished
             * @param {Object} e the event object
             */
            request.onMessagePublished = function (e) {
                _adapter.onmessage({data: e.responseBody});
            };

            /**
             * Overrides the onOpen callback in given request to proxy the event to the adapter.
             *
             * @method onOpen
             * @param {Object} e the event object
             */
            request.onOpen = function (e) {
                _adapter.onopen(e);
            };

            _adapter = {
                close: function () {
                    _socket.close();
                },

                send: function (data) {
                    _socket.push(data);
                },

                onmessage: function (e) {
                },

                onopen: function (e) {
                },

                onclose: function (e) {
                },

                onerror: function (e) {

                }
            };
            _socket = new atmosphere.subscribe(request);

            return _adapter;
        },

        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,
                webSocketBinaryType: null,
                dispatchUrl: null,
                webSocketPathDelimiter: "@@",
                enableXDR: false,
                rewriteURL: false,
                attachHeadersAsQueryString: true,
                executeCallbackBeforeReconnect: false,
                readyState: 0,
                withCredentials: false,
                trackMessageLength: false,
                messageDelimiter: '|',
                connectTimeout: -1,
                reconnectInterval: 0,
                dropHeaders: true,
                uuid: 0,
                async: true,
                shared: false,
                readResponsesHeaders: false,
                maxReconnectOnClose: 5,
                enableProtocol: true,
                disableDisconnect: false,
                pollingInterval: 0,
                heartbeat: {
                    client: null,
                    server: null
                },
                ackInterval: 0,
                closeAsync: false,
                reconnectOnServerError: true,
                handleOnlineOffline: true,
                onError: function (response) {
                },
                onClose: function (response) {
                },
                onOpen: function (response) {
                },
                onMessage: function (response) {
                },
                onReopen: function (request, response) {
                },
                onReconnect: function (request, response) {
                },
                onMessagePublished: function (response) {
                },
                onTransportFailure: function (reason, request) {
                },
                onLocalMessage: function (request) {
                },
                onFailureToReconnect: function (request, response) {
                },
                onClientTimeout: function (request) {
                },
                onOpenAfterResume: 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,
                closedByClientTimeout: false,
                ffTryingReconnect: false
            };

            /**
             * {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;

            /**
             * The Heartbeat interval send by the server.
             * @type {int}
             * @private
             */
            var _heartbeatInterval = 0;

            /**
             * The Heartbeat bytes send by the server.
             * @type {string}
             * @private
             */
            var _heartbeatPadding = 'X';

            /**
             * {boolean} If request is currently aborted.
             *
             * @private
             */
            var _abortingConnection = 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 = atmosphere.util.now();

            /** Trace time */
            var _traceTimer;

            /** Key for connection sharing */
            var _sharingKey;

            /**
             * {boolean} If window beforeUnload event has been called.
             * Flag will be reset after 5000 ms
             *
             * @private
             */
            var _beforeUnloadState = false;

            // Automatic call to subscribe
            _subscribe(options);

            /**
             * Initialize atmosphere request object.
             *
             * @private
             */
            function _init() {
                _subscribed = true;
                _abortingConnection = false;
                _requestCount = 0;

                _websocket = null;
                _sse = null;
                _activeRequest = null;
                _ieStream = null;
            }

            /**
             * Re-initialize atmosphere object.
             *
             * @private
             */
            function _reinit() {
                _clearState();
                _init();
            }

            /**
             * Returns true if the given level is equal or above the configured log level.
             *
             * @private
             */
            function _canLog(level) {
                if (level == 'debug') {
                    return _request.logLevel === 'debug';
                } else if (level == 'info') {
                    return _request.logLevel === 'info' || _request.logLevel === 'debug';
                } else if (level == 'warn') {
                    return _request.logLevel === 'warn' || _request.logLevel === 'info' || _request.logLevel === 'debug';
                } else if (level == 'error') {
                    return _request.logLevel === 'error' || _request.logLevel === 'warn' || _request.logLevel === 'info' || _request.logLevel === 'debug';
                } else {
                    return false;
                }
            }

            function _debug(msg) {
                if (_canLog('debug')) {
                    atmosphere.util.debug(new Date() + " Atmosphere: " + msg);
                }
            }

            /**
             *
             * @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)) {
                    return true;
                }
                return false;
            }

            /**
             * Disconnect
             *
             * @private
             */
            function _disconnect() {
                if (_request.enableProtocol && !_request.disableDisconnect && !_request.firstMessage) {
                    var query = "X-Atmosphere-Transport=close&X-Atmosphere-tracking-id=" + _request.uuid;

                    atmosphere.util.each(_request.headers, function (name, value) {
                        var h = atmosphere.util.isFunction(value) ? value.call(this, _request, _request, _response) : value;
                        if (h != null) {
                            query += "&" + encodeURIComponent(name) + "=" + encodeURIComponent(h);
                        }
                    });

                    var url = _request.url.replace(/([?&])_=[^&]*/, query);
                    url = url + (url === _request.url ? (/\?/.test(_request.url) ? "&" : "?") + query : "");

                    var rq = {
                        connected: false
                    };
                    var closeR = new atmosphere.AtmosphereRequest(rq);
                    closeR.connectTimeout = _request.connectTimeout;
                    closeR.attachHeadersAsQueryString = false;
                    closeR.dropHeaders = true;
                    closeR.url = url;
                    closeR.contentType = "text/plain";
                    closeR.transport = 'polling';
                    closeR.method = 'GET';
                    closeR.data = '';
                    closeR.heartbeat = null;
                    if (_request.enableXDR) {
                        closeR.enableXDR = _request.enableXDR
                    }
                    closeR.async = _request.closeAsync;
                    _pushOnClose("", closeR);
                }
            }

            /**
             * Close request.
             *
             * @private
             */
            function _close() {
                _debug("Closing (AtmosphereRequest._close() called)");

                _abortingConnection = true;
                if (_request.reconnectId) {
                    clearTimeout(_request.reconnectId);
                    delete _request.reconnectId;
                }

                if (_request.heartbeatTimer) {
                    clearTimeout(_request.heartbeatTimer);
                }

                _request.reconnect = false;
                _response.request = _request;
                _response.state = 'unsubscribe';
                _response.responseBody = "";
                _response.status = 408;
                _response.partialMessage = "";
                _invokeCallback();
                _disconnect();
                _clearState();
            }

            function _clearState() {
                _response.partialMessage = "";
                if (_request.id) {
                    clearTimeout(_request.id);
                }

                if (_request.heartbeatTimer) {
                    clearTimeout(_request.heartbeatTimer);
                }

                // https://github.com/Atmosphere/atmosphere/issues/1860#issuecomment-74707226
                if(_request.reconnectId) {
                    clearTimeout(_request.reconnectId);
                    delete _request.reconnectId;
                }

                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.canSendMessage) {
                        _debug("invoking .close() on WebSocket object");
                        _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 = _sharingKey + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
                    // The heir is the parent unless unloading
                    _storageService.signal("close", {
                        reason: "",
                        heir: !_abortingConnection ? guid : (_storageService.get("children") || [])[0]
                    });
                    _storageService.close();
                }
                if (_localStorageService != null) {
                    _localStorageService.close();
                }
            }

            /**
             * Subscribe request using request transport. 
* If request is currently opened, this one will be closed. * * @param {Object} Request parameters. * @private */ function _subscribe(options) { _reinit(); _request = atmosphere.util.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() { // Origin parts var url = atmosphere.util.getAbsoluteURL(_request.url.toLowerCase()); var parts = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/.exec(url); var crossOrigin = !!(parts && ( // protocol parts[1] != window.location.protocol || // hostname parts[2] != window.location.hostname || // port (parts[3] || (parts[1] === "http:" ? 80 : 443)) != (window.location.port || (window.location.protocol === "http:" ? 80 : 443)) )); return window.EventSource && (!crossOrigin || !atmosphere.util.browser.safari || atmosphere.util.browser.vmajor >= 7); } /** * Open request using request transport.
* 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 (_canLog('debug')) { atmosphere.util.debug("Storage service available. All communication will be local"); } if (_localStorageService.open(_request)) { // Local connection. return; } } if (_canLog('debug')) { atmosphere.util.debug("No Storage service available."); } // Wasn't local or an error occurred _localStorageService = null; } // Protocol _request.firstMessage = uuid == 0 ? true : false; _request.isOpen = false; _request.ctime = atmosphere.util.now(); // We carry any UUID set by the user or from a previous connection. if (_request.uuid === 0) { _request.uuid = uuid; } _response.closedByClientTimeout = false; if (_request.transport !== 'websocket' && _request.transport !== 'sse') { _executeRequest(_request); } 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 () { function onstorage(event) { if (event.key === name && event.newValue) { listener(event.newValue); } } if (!atmosphere.util.storage) { return; } var storage = window.localStorage, get = function (key) { var item = storage.getItem(name + "-" + key); return item === null ? [] : atmosphere.util.parseJSON(item); }, set = function (key, value) { storage.setItem(name + "-" + key, atmosphere.util.stringifyJSON(value)); }; return { init: function () { set("children", get("children").concat([guid])); atmosphere.util.on(window, "storage", onstorage); return get("opened"); }, signal: function (type, data) { storage.setItem(name, atmosphere.util.stringifyJSON({ target: "p", type: type, data: data })); }, close: function () { var children = get("children"); atmosphere.util.off(window, "storage", onstorage); if (children) { if (removeFromArray(children, request.id)) { 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(atmosphere.util.stringifyJSON({ target: "p", type: type, data: data })); } }, close: function () { // Removes traces only if the parent is alive if (!orphan) { removeFromArray(win.callbacks, listener); removeFromArray(win.children, guid); } } }; } }; function removeFromArray(array, val) { var i, length = array.length; for (i = 0; i < length; i++) { if (array[i] === val) { array.splice(i, 1); } } return length !== array.length; } // Receives open, close and message command from the parent function listener(string) { var command = atmosphere.util.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 atmosphere.util.parseJSON(decodeURIComponent(matcher[2])); } } // Finds and validates the parent socket's trace from the cookie trace = findTrace(); if (!trace || atmosphere.util.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(atmosphere.util.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", atmosphere.util.stringifyJSON({ id: guid, event: event })); }, close: function () { // Do not signal the parent if this method is executed by the unload event handler if (!_abortingConnection) { 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 () { function onstorage(event) { // When a deletion, newValue initialized to null if (event.key === name && event.newValue) { listener(event.newValue); } } if (!atmosphere.util.storage) { return; } var storage = window.localStorage; return { init: function () { // Handles the storage event atmosphere.util.on(window, "storage", onstorage); }, signal: function (type, data) { storage.setItem(name, atmosphere.util.stringifyJSON({ target: "c", type: type, data: data })); }, get: function (key) { return atmosphere.util.parseJSON(storage.getItem(name + "-" + key)); }, set: function (key, value) { storage.setItem(name + "-" + key, atmosphere.util.stringifyJSON(value)); }, close: function () { atmosphere.util.off(window, "storage", onstorage); 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, ""), container = document.getElementById(neim), win; if (!container) { container = document.createElement("div"); container.id = neim; container.style.display = "none"; container.innerHTML = '