UNPKG

gate.js

Version:

Gate — это библиотека для кросс-доменной или внутридоменной синхронизации данных между окнами и вкладками браузера.

345 lines (306 loc) 8.3 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.MyBundle = factory()); }(this, function () { 'use strict'; function CustomEventTarget() { this._events = {}; } CustomEventTarget.prototype = { constructor: CustomEventTarget, on: function (eventType, listener) { var events = this._events, listeners; if (eventType in events) { listeners = events[eventType]; if (listeners.indexOf(listener) == -1) { listeners.push(listener); } } else { events[eventType] = [listener]; } }, off: function (eventType, listener) { var events = this._events, listeners; if (eventType in events) { listeners = events[eventType]; var i; var pos = listeners.indexOf(listener); if (pos !== -1) { listeners.splice(pos, 1); } } }, _fire: function (eventType, detail) { var listeners = this._events[eventType]; if (listeners) { var event = { type: eventType, detail: detail }; listeners.forEach(function (listener) { listener.call(this, event); }, this); } } }; function Gate(options) { this.constructor.Super.call(this); /** * Type of exchange. * * @private * @type {boolean} */ this._crossDomain = options.crossDomain; /** * Attrubute src or iframe. * * @private * @type {string} */ this._src = options.serviceFile || 'about:blank'; /** * Local storage key. * @type {string} * @private */ this._keyStorage = options.keyLocalStorage; /** * Iframe element. * * @private * @type {Object} */ this._iframe = this._createIframe(); /** * Initialization functions. * * @private */ this._initializeEvents(); /** * Settings for frame.html. * * @private * @type {Object} this._settings - Settings. * @property {string} this._settings.sender - Sender. * @property {string} this._settings.type - Type. * @property {object} this._settings.settings - Settings. * @property {string} this._settings.settings.localStorageKey - Local storage key. */ this._settings = { sender: 'Gate.js', type: 'settings', settings: { localStorageKey: options.keyLocalStorage } }; } /** * The name of the message event. * * @constant * @type {string} */ Gate.EVENT_MESSAGE = 'message'; /** * The name of the ready event. * * @type {string} * @constant */ Gate.EVENT_READY = 'ready'; /** * The name of the error event. * @type {string} * @constant */ Gate.EVENT_ERROR = 'error'; /** * The text error if service file load failed. * * @type {string} * @constant */ Gate.ERROR_SERVICE_FILE_LOAD_FAILED = 'приемник еще не загружен для получения данных. Попробуйте позже либо выполняйте передачу данных по событию ready'; /** * The text error if local storage not available. * * @type {string} * @constant */ Gate.ERROR_LOCAL_STORAGE_NOT_AVAILABLE = 'local Storage не доступен'; Gate.prototype = Object.create(CustomEventTarget.prototype); Gate.prototype.constructor = Gate; Gate.Super = CustomEventTarget; /** * Defaulst data for frame.html. * * @private * @type {Object} this._data - Settings. * @property {string} this._data.sender - Sender. * @property {string} this._data.type - Type. * @property {Object} this._data.data - Data. */ Gate.prototype._data = { sender: 'Gate.js', type: 'message', data: null }; /** * Assigning handlers. * * @private * @this {Gate} */ Gate.prototype._initializeEvents = function () { /** * * * @private */ this._onCanPostMessage = this._onCanPostMessage.bind(this); /** * * * @private */ this._onMessage = this._onMessage.bind(this); /** * * * @private */ this._onStorage = this._onStorage.bind(this); this._iframe.addEventListener('load', this._onCanPostMessage); window.addEventListener("message", this._onMessage, false); window.addEventListener('storage', this._onStorage, false); }; /** * Create and hide iframe. * * @private * @this {Gate} * @return {Object} The iframe element. */ Gate.prototype._createIframe = function () { var iframe = document.createElement('iframe'); iframe.style.cssText = "position: fixed; \ top: -100px; \ left: -100px; \ width: 50px; \ height: 50px; \ "; iframe.src = this._src; document.body.appendChild(iframe); return iframe; }; /** * The event handler: 'load'. * * @private * @this {Gate} */ Gate.prototype._onCanPostMessage = function () { this._iframe.contentWindow.postMessage(this._settings, this._src); this._ready = true; this._fire(Gate.EVENT_READY, { result: true }); }; /** * Sends data. * * @this {Gate} * @param {Object} data The data to transfer. */ Gate.prototype.postMessage = function (data) { if (this._crossDomain && this._src != 'about:blank') { this._data.data = data; try { if (!this._ready) { throw new Error(Gate.ERROR_SERVICE_FILE_LOAD_FAILED); } this._iframe.contentWindow.postMessage(this._data, this._src); } catch (error) { this._fire(Gate.EVENT_ERROR, error); } return; } this._pushDataToStorage(data); }; /** * The event handler: 'message'. * * @private * @this {Gate} */ Gate.prototype._onMessage = function () { //if (event.origin != this._src) // return; this._pushDataToStorage(event.data); this._fire(Gate.EVENT_MESSAGE, event.data); }; /** * Puts data to local storage. * * @private * @this {Gate} * @param {Object} data The data to transfer. */ Gate.prototype._pushDataToStorage = function (data) { try { if (window.localStorage) { localStorage.setItem(this._keyStorage, JSON.stringify({ crossDomain: this._crossDomain, rnd: Math.random(), data: data })); } else { throw new Error(Gate.ERROR_LOCAL_STORAGE_NOT_AVAILABLE); } } catch (error) { this._fire(Gate.EVENT_ERROR, error); } }; /** * The event handler: 'storage'. * * @private * @this */ Gate.prototype._onStorage = function (event) { if (event.key == this._keyStorage) { try { var data = JSON.parse(event.newValue); // оповещаем this._fire(Gate.EVENT_MESSAGE, data.data); } catch (error) { this._fire(Gate.EVENT_ERROR, error); } } }; Gate.prototype.destroy = function () { /** * Remove iframe */ document.body.removeChild(this._iframe); /** * Remove iframe from memory */ this._iframe = null; /** * Remove event listener 'message' */ window.removeEventListener("message", this._onMessage, false); /** * Remove event listener 'storage' */ window.removeEventListener('storage', this._onMessage, false); /** * Remove event listener '_onCanPostMessage' */ this._iframe.removeEventListener('load', this._onCanPostMessage); }; return Gate; }));