app/assets/javascripts/iframe-phone.js
File `iframe-phone.js` has 321 lines of code (exceeds 250 allowed). Consider refactoring.//// version 1.3.1//// NOTE: once the files like interactive_iframe.js.coffee that exist outside of lara-typescript use iframe-phone// this file needs to stay in the build (referenced in application.js)//Function `1` has 108 lines of code (exceeds 25 allowed). Consider refactoring.
Similar blocks of code found in 2 locations. Consider refactoring.!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.iframePhone=e():"undefined"!=typeof global?global.iframePhone=e():"undefined"!=typeof self&&(self.iframePhone=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ var structuredClone = require('./structured-clone'); var HELLO_INTERVAL_LENGTH = 200; var HELLO_TIMEOUT_LENGTH = 60000; Function `IFrameEndpoint` has 96 lines of code (exceeds 25 allowed). Consider refactoring. function IFrameEndpoint() { var listeners = {}; var isInitialized = false; var connected = false; var postMessageQueue = []; var helloInterval; Identical blocks of code found in 2 locations. Consider refactoring. function postToParent(message) { // See http://dev.opera.com/articles/view/window-postmessage-messagechannel/#crossdoc // https://github.com/Modernizr/Modernizr/issues/388 // http://jsfiddle.net/ryanseddon/uZTgD/2/ if (structuredClone.supported()) { window.parent.postMessage(message, '*'); } else { window.parent.postMessage(JSON.stringify(message), '*'); } } Identical blocks of code found in 2 locations. Consider refactoring. function post(type, content) { var message; // Message object can be constructed from 'type' and 'content' arguments or it can be passed // as the first argument. if (arguments.length === 1 && typeof type === 'object' && typeof type.type === 'string') { message = type; } else { message = { type: type, content: content }; } if (connected) { postToParent(message); } else { postMessageQueue.push(message); } } function postHello() { postToParent({ type: 'hello' }); } function addListener(type, fn) { listeners[type] = fn; } function removeListener(type) { delete listeners[type]; } function removeAllListeners() { listeners = {}; } function getListenerNames() { return Object.keys(listeners); } Identical blocks of code found in 2 locations. Consider refactoring. function messageListener(message) { // Anyone can send us a message. Only pay attention to messages from parent. if (message.source !== window.parent) return; var messageData = message.data; if (typeof messageData === 'string') messageData = JSON.parse(messageData); if (!connected && messageData.type === 'hello') { connected = true; stopPostingHello(); while (postMessageQueue.length > 0) { post(postMessageQueue.shift()); } } if (connected && listeners[messageData.type]) { listeners[messageData.type](messageData.content); } } function disconnect() { connected = false; stopPostingHello(); removeAllListeners(); window.removeEventListener('message', messageListener); } /** Initialize communication with the parent frame. This should not be called until the app's custom listeners are registered (via our 'addListener' public method) because, once we open the communication, the parent window may send any messages it may have queued. Messages for which we don't have handlers will be silently ignored. */Similar blocks of code found in 2 locations. Consider refactoring. function initialize() { if (isInitialized) { return; } isInitialized = true; if (window.parent === window) return; // We kick off communication with the parent window by sending a "hello" message. Then we wait // for a handshake (another "hello" message) from the parent window. startPostingHello(); window.addEventListener('message', messageListener, false); } Identical blocks of code found in 2 locations. Consider refactoring. function startPostingHello() { if (helloInterval) { stopPostingHello(); } helloInterval = window.setInterval(postHello, HELLO_INTERVAL_LENGTH); window.setTimeout(stopPostingHello, HELLO_TIMEOUT_LENGTH); // Post the first msg immediately. postHello(); } function stopPostingHello() { window.clearInterval(helloInterval); helloInterval = null; } // Public API. return { initialize: initialize, getListenerNames: getListenerNames, addListener: addListener, removeListener: removeListener, removeAllListeners: removeAllListeners, disconnect: disconnect, post: post }; } var instance = null; // IFrameEndpoint is a singleton, as iframe can't have multiple parents anyway. module.exports = function getIFrameEndpoint() { if (!instance) { instance = new IFrameEndpoint(); } return instance; }; Function `2` has 72 lines of code (exceeds 25 allowed). Consider refactoring.
Identical blocks of code found in 2 locations. Consider refactoring. },{"./structured-clone":4}],2:[function(require,module,exports){ var ParentEndpoint = require('./parent-endpoint'); var getIFrameEndpoint = require('./iframe-endpoint'); // Not a real UUID as there's an RFC for that (needed for proper distributed computing). // But in this fairly parochial situation, we just need to be fairly sure to avoid repeats. function getPseudoUUID() { var chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; var len = chars.length; var ret = []; for (var i = 0; i < 10; i++) { ret.push(chars[Math.floor(Math.random() * len)]); } return ret.join(''); } Function `IframePhoneRpcEndpoint` has 59 lines of code (exceeds 25 allowed). Consider refactoring.
Function `exports` has 5 arguments (exceeds 4 allowed). Consider refactoring. module.exports = function IframePhoneRpcEndpoint(handler, namespace, targetWindow, targetOrigin, phone) { var pendingCallbacks = Object.create({}); // if it's a non-null object, rather than a function, 'handler' is really an options object if (handler && typeof handler === 'object') { namespace = handler.namespace; targetWindow = handler.targetWindow; targetOrigin = handler.targetOrigin; phone = handler.phone; handler = handler.handler; } if (!phone) { if (targetWindow === window.parent) { phone = getIFrameEndpoint(); phone.initialize(); } else { phone = new ParentEndpoint(targetWindow, targetOrigin); } } phone.addListener(namespace, function (message) { var callbackObj; if (message.messageType === 'call' && typeof this.handler === 'function') { this.handler.call(undefined, message.value, function (returnValue) { phone.post(namespace, { messageType: 'returnValue', uuid: message.uuid, value: returnValue }); }); } else if (message.messageType === 'returnValue') { callbackObj = pendingCallbacks[message.uuid]; if (callbackObj) { window.clearTimeout(callbackObj.timeout); if (callbackObj.callback) { callbackObj.callback.call(undefined, message.value); } pendingCallbacks[message.uuid] = null; } } }.bind(this)); function call(message, callback) { var uuid = getPseudoUUID(); pendingCallbacks[uuid] = { callback: callback, timeout: window.setTimeout(function () { if (callback) { callback(undefined, new Error("IframePhone timed out waiting for reply")); } }, 2000) }; phone.post(namespace, { messageType: 'call', uuid: uuid, value: message }); } function disconnect() { phone.disconnect(); } this.handler = handler; this.call = call.bind(this); this.disconnect = disconnect.bind(this); }; Function `3` has 107 lines of code (exceeds 25 allowed). Consider refactoring. },{"./iframe-endpoint":1,"./parent-endpoint":3}],3:[function(require,module,exports){ var structuredClone = require('./structured-clone'); /** Call as: new ParentEndpoint(targetWindow, targetOrigin, afterConnectedCallback) targetWindow is a WindowProxy object. (Messages will be sent to it) targetOrigin is the origin of the targetWindow. (Messages will be restricted to this origin) afterConnectedCallback is an optional callback function to be called when the connection is established. OR (less secure): new ParentEndpoint(targetIframe, afterConnectedCallback) targetIframe is a DOM object (HTMLIframeElement); messages will be sent to its contentWindow. afterConnectedCallback is an optional callback function In this latter case, targetOrigin will be inferred from the value of the src attribute of the provided DOM object at the time of the constructor invocation. This is less secure because the iframe might have been navigated to an unexpected domain before constructor invocation. Note that it is important to specify the expected origin of the iframe's content to safeguard against sending messages to an unexpected domain. This might happen if our iframe is navigated to a third-party URL unexpectedly. Furthermore, having a reference to Window object (as in the first form of the constructor) does not protect against sending a message to the wrong domain. The window object is actualy a WindowProxy which transparently proxies the Window object of the underlying iframe, so that when the iframe is navigated, the "same" WindowProxy now references a completely differeent Window object, possibly controlled by a hostile domain. See http://www.esdiscuss.org/topic/a-dom-use-case-that-can-t-be-emulated-with-direct-proxies for more about this weird behavior of WindowProxies (the type returned by <iframe>.contentWindow). */ Function `ParentEndpoint` has 104 lines of code (exceeds 25 allowed). Consider refactoring. module.exports = function ParentEndpoint(targetWindowOrIframeEl, targetOrigin, afterConnectedCallback) { var postMessageQueue = []; var connected = false; var handlers = {}; var targetWindowIsIframeElement; function getIframeOrigin(iframe) { return iframe.src.match(/(.*?\/\/.*?)\//)[1]; } Identical blocks of code found in 2 locations. Consider refactoring. function post(type, content) { var message; // Message object can be constructed from 'type' and 'content' arguments or it can be passed // as the first argument. if (arguments.length === 1 && typeof type === 'object' && typeof type.type === 'string') { message = type; } else { message = { type: type, content: content }; } if (connected) { var tWindow = getTargetWindow(); // if we are laready connected ... send the message // See http://dev.opera.com/articles/view/window-postmessage-messagechannel/#crossdoc // https://github.com/Modernizr/Modernizr/issues/388 // http://jsfiddle.net/ryanseddon/uZTgD/2/ if (structuredClone.supported()) { tWindow.postMessage(message, targetOrigin); } else { tWindow.postMessage(JSON.stringify(message), targetOrigin); } } else { // else queue up the messages to send after connection complete. postMessageQueue.push(message); } } function addListener(messageName, func) { handlers[messageName] = func; } function removeListener(messageName) { delete handlers[messageName]; } function removeAllListeners() { handlers = {}; } // Note that this function can't be used when IFrame element hasn't been added to DOM yet // (.contentWindow would be null). At the moment risk is purely theoretical, as the parent endpoint // only listens for an incoming 'hello' message and the first time we call this function // is in #receiveMessage handler (so iframe had to be initialized before, as it could send 'hello'). // It would become important when we decide to refactor the way how communication is initialized.Identical blocks of code found in 2 locations. Consider refactoring. function getTargetWindow() { if (targetWindowIsIframeElement) { var tWindow = targetWindowOrIframeEl.contentWindow; if (!tWindow) { throw "IFrame element needs to be added to DOM before communication " + "can be started (.contentWindow is not available)"; } return tWindow; } return targetWindowOrIframeEl; } Similar blocks of code found in 2 locations. Consider refactoring. function receiveMessage(message) { var messageData; if (message.source === getTargetWindow() && (targetOrigin === '*' || message.origin === targetOrigin)) { messageData = message.data; if (typeof messageData === 'string') { messageData = JSON.parse(messageData); } if (handlers[messageData.type]) { handlers[messageData.type](messageData.content); } else { console.log("cant handle type: " + messageData.type); } } } function disconnect() { connected = false; removeAllListeners(); window.removeEventListener('message', receiveMessage); } // handle the case that targetWindowOrIframeEl is actually an <iframe> rather than a Window(Proxy) object // Note that if it *is* a WindowProxy, this probe will throw a SecurityException, but in that case // we also don't need to do anything try { targetWindowIsIframeElement = targetWindowOrIframeEl.constructor === HTMLIFrameElement; } catch (e) { targetWindowIsIframeElement = false; } Identical blocks of code found in 2 locations. Consider refactoring. if (targetWindowIsIframeElement) { // Infer the origin ONLY if the user did not supply an explicit origin, i.e., if the second // argument is empty or is actually a callback (meaning it is supposed to be the // afterConnectionCallback) if (!targetOrigin || targetOrigin.constructor === Function) { afterConnectedCallback = targetOrigin; targetOrigin = getIframeOrigin(targetWindowOrIframeEl); } } // Handle pages served through file:// protocol. Behaviour varies in different browsers. Safari sets origin // to 'file://' and everything works fine, but Chrome and Safari set message.origin to null. // Also, https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage says: // > Lastly, posting a message to a page at a file: URL currently requires that the targetOrigin argument be "*". // > file:// cannot be used as a security restriction; this restriction may be modified in the future. // So, using '*' seems like the only possible solution. if (targetOrigin === 'file://') { targetOrigin = '*'; } // when we receive 'hello':Identical blocks of code found in 2 locations. Consider refactoring. addListener('hello', function () { connected = true; // send hello response post({ type: 'hello', // `origin` property isn't used by IframeEndpoint anymore (>= 1.2.0), but it's being sent to be // backward compatible with old IframeEndpoint versions (< v1.2.0). origin: window.location.href.match(/(.*?\/\/.*?)\//)[1] }); // give the user a chance to do things now that we are connected // note that is will happen before any queued messages if (afterConnectedCallback && typeof afterConnectedCallback === "function") { afterConnectedCallback(); } // Now send any messages that have been queued up ... while (postMessageQueue.length > 0) { post(postMessageQueue.shift()); } }); window.addEventListener('message', receiveMessage, false); // Public API. return { post: post, addListener: addListener, removeListener: removeListener, removeAllListeners: removeAllListeners, disconnect: disconnect, getTargetWindow: getTargetWindow, targetOrigin: targetOrigin }; }; Similar blocks of code found in 2 locations. Consider refactoring. },{"./structured-clone":4}],4:[function(require,module,exports){ var featureSupported = { 'structuredClones': 0 }; (function () { var result = 0; if (!!window.postMessage) { try { // Spec states you can't transmit DOM nodes and it will throw an error // postMessage implementations that support cloned data will throw. window.postMessage(document.createElement("a"), "*"); } catch (e) { // BBOS6 throws but doesn't pass through the correct exception // so check error message result = (e.DATA_CLONE_ERR || e.message === "Cannot post cyclic structures.") ? 1 : 0; featureSupported = { 'structuredClones': result }; } } }()); exports.supported = function supported() { return featureSupported && featureSupported.structuredClones > 0; }; Similar blocks of code found in 2 locations. Consider refactoring. },{}],5:[function(require,module,exports){ module.exports = { /** * Allows to communicate with an iframe. */ ParentEndpoint: require('./lib/parent-endpoint'), /** * Allows to communicate with a parent page. * IFrameEndpoint is a singleton, as iframe can't have multiple parents anyway. */ getIFrameEndpoint: require('./lib/iframe-endpoint'), structuredClone: require('./lib/structured-clone'), // TODO: May be misnamed IframePhoneRpcEndpoint: require('./lib/iframe-phone-rpc-endpoint') }; },{"./lib/iframe-endpoint":1,"./lib/iframe-phone-rpc-endpoint":2,"./lib/parent-endpoint":3,"./lib/structured-clone":4}]},{},[5]) (5) }); ;