From 99d39ec59489fb4eb045074bf99e0253319cea13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Beaulieu?= Date: Fri, 9 Apr 2021 17:30:52 -0400 Subject: [PATCH] Better event listener management to fix multiple events listners on messages events attached to the window object, occured when we close and reopen the form. --- lib/rxp-hpp.js | 217 +++++++++++++++++++++++++++---------------------- 1 file changed, 119 insertions(+), 98 deletions(-) diff --git a/lib/rxp-hpp.js b/lib/rxp-hpp.js index c569764..dcb798b 100644 --- a/lib/rxp-hpp.js +++ b/lib/rxp-hpp.js @@ -46,7 +46,25 @@ var RealexHpp = (function () { var redirectUrl; var internal = { - + evtMsg: [], + addEvtMsgListener: function(evtMsgFct) { + this.evtMsg.push({ fct: evtMsgFct, opt: false }); + if (window.addEventListener) { + window.addEventListener("message", evtMsgFct, false); + } else { + window.attachEvent('message', evtMsgFct); + } + }, + removeOldEvtMsgListener: function () { + if (this.evtMsg.length > 0) { + var evt = this.evtMsg.pop(); + if (window.addEventListener) { + window.removeEventListener("message", evt.fct, evt.opt); + } else { + window.detachEvent('message', evt.fct); + } + } + }, base64:{ encode:function(input) { var keyStr = "ABCDEFGHIJKLMNOP" + @@ -416,95 +434,93 @@ var RealexHpp = (function () { return internal.getHostnameFromUrl(origin) === internal.getHostnameFromUrl(hppUrl); }, - receiveMessage: function (lightboxInstance, merchantUrl, isEmbedded) { - return function (event) { - //Check the origin of the response comes from HPP - if (!internal.isMessageFromHpp(event.origin, hppUrl)) { - return; - } - // check for iframe resize values - var evtdata; - if (event.data && (evtdata=internal.decodeAnswer(event.data)).iframe) { - if (!isMobileNewTab()) { - var iframeWidth = evtdata.iframe.width; - var iframeHeight = evtdata.iframe.height; - - var iFrame; - var resized = false; - - if (isEmbedded) { - iFrame = lightboxInstance.getIframe(); - } else { - iFrame = document.getElementById("rxp-frame-" + randomId); - } - if(lightboxInstance.events && lightboxInstance.events.onResize) { - lightboxInstance.events.onResize(evtdata.iframe); - } + receiveMessage: function (e) { + //Check the origin of the response comes from HPP + if (!internal.isMessageFromHpp(e.event.origin, hppUrl)) { + return; + } + // check for iframe resize values + var evtdata; + if (e.event.data && (evtdata=internal.decodeAnswer(e.event.data)).iframe) { + if (!isMobileNewTab()) { + var iframeWidth = evtdata.iframe.width; + var iframeHeight = evtdata.iframe.height; + + var iFrame; + var resized = false; + + if (e.embedded) { + iFrame = e.instance.getIframe(); + } else { + iFrame = document.getElementById("rxp-frame-" + randomId); + } + if (e.instance.events && e.instance.events.onResize) { + e.instance.events.onResize(evtdata.iframe); + } - if (iframeWidth === "390px" && iframeHeight === "440px") { - iFrame.setAttribute("width", iframeWidth); - iFrame.setAttribute("height", iframeHeight); - resized = true; - } + if (iframeWidth === "390px" && iframeHeight === "440px") { + iFrame.setAttribute("width", iframeWidth); + iFrame.setAttribute("height", iframeHeight); + resized = true; + } - iFrame.style.backgroundColor="#ffffff"; - - if (isMobileIFrame) { - iFrame.style.marginLeft = "0px"; - iFrame.style.WebkitOverflowScrolling = "touch"; - iFrame.style.overflowX = "scroll"; - iFrame.style.overflowY = "scroll"; - - if (!isEmbedded) { - var overlay = document.getElementById("rxp-overlay-" + randomId); - overlay.style.overflowX = "scroll"; - overlay.style.overflowY = "scroll"; - } - } else if (!isEmbedded && resized) { - iFrame.style.marginLeft = (parseInt(iframeWidth.replace("px", ""), 10) / 2 * -1) + "px"; - } + iFrame.style.backgroundColor="#ffffff"; - if (!isEmbedded && resized) { - // wrap the below in a setTimeout to prevent a timing issue on a - // cache-miss load - setTimeout(function () { - var closeButton = document.getElementById("rxp-frame-close-" + randomId); - closeButton.style.marginLeft = ((parseInt(iframeWidth.replace("px", ""), 10) / 2) -7) + "px"; - }, 200); + if (isMobileIFrame) { + iFrame.style.marginLeft = "0px"; + iFrame.style.WebkitOverflowScrolling = "touch"; + iFrame.style.overflowX = "scroll"; + iFrame.style.overflowY = "scroll"; + + if (!e.embedded) { + var overlay = document.getElementById("rxp-overlay-" + randomId); + overlay.style.overflowX = "scroll"; + overlay.style.overflowY = "scroll"; } + } else if (!e.embedded && resized) { + iFrame.style.marginLeft = (parseInt(iframeWidth.replace("px", ""), 10) / 2 * -1) + "px"; } - } else { - var _close=function(){ - if (isMobileNewTab() && tabWindow) { - //Close the new window - tabWindow.close(); - } else { - //Close the lightbox - lightboxInstance.close(); - } - var overlay=document.getElementById("rxp-overlay-" + randomId); - if(overlay) { - overlay.remove(); - } - }; - var response = event.data; - //allow the script to intercept the answer, instead of redirecting to another page. (which is really a 90s thing) - if(typeof merchantUrl==='function'){ - var answer=internal.decodeAnswer(response); - merchantUrl(answer,_close); - return; + if (!e.embedded && resized) { + // wrap the below in a setTimeout to prevent a timing issue on a + // cache-miss load + setTimeout(function () { + var closeButton = document.getElementById("rxp-frame-close-" + randomId); + closeButton.style.marginLeft = ((parseInt(iframeWidth.replace("px", ""), 10) / 2) -7) + "px"; + }, 200); } - _close(); - //Create a form and submit the hpp response to the merchant's response url - var form = document.createElement("form"); - form.setAttribute("method", "POST"); - form.setAttribute("action", merchantUrl); - form.appendChild(internal.createFormHiddenInput("hppResponse", response)); - document.body.appendChild(form); - form.submit(); } - }; + } else { + var _close=function(){ + if (isMobileNewTab() && tabWindow) { + //Close the new window + tabWindow.close(); + } else { + //Close the lightbox + e.instance.close(); + } + var overlay=document.getElementById("rxp-overlay-" + randomId); + if(overlay) { + overlay.remove(); + } + + }; + var response = e.event.data; + //allow the script to intercept the answer, instead of redirecting to another page. (which is really a 90s thing) + if(typeof e.url==='function'){ + var answer=internal.decodeAnswer(response); + e.url(answer,_close); + return; + } + _close(); + //Create a form and submit the hpp response to the merchant's response url + var form = document.createElement("form"); + form.setAttribute("method", "POST"); + form.setAttribute("action", e.url); + form.appendChild(internal.createFormHiddenInput("hppResponse", response)); + document.body.appendChild(form); + form.submit(); + } } }; @@ -576,12 +592,13 @@ var RealexHpp = (function () { } else { document.getElementById(idOfLightboxButton).attachEvent('onclick', lightboxInstance.lightbox); } - - if (window.addEventListener) { - window.addEventListener("message", internal.receiveMessage(lightboxInstance, merchantUrl), false); - } else { - window.attachEvent('message', internal.receiveMessage(lightboxInstance, merchantUrl)); - } + //avoid multiple message event listener binded to the window object. + internal.removeOldEvtMsgListener(); + var evtMsgFct = function (event) { + return internal.receiveMessage({ event: event, instance: lightboxInstance, url: merchantUrl, embedded: false }); + }; + internal.evtMsg.push({ fct: evtMsgFct, opt: false }); + internal.addEvtMsgListener(evtMsgFct); } }; })(); @@ -654,11 +671,13 @@ var RealexHpp = (function () { document.getElementById(idOfEmbeddedButton).attachEvent('onclick', embeddedInstance.embedded); } - if (window.addEventListener) { - window.addEventListener("message", internal.receiveMessage(embeddedInstance, merchantUrl, true), false); - } else { - window.attachEvent('message', internal.receiveMessage(embeddedInstance, merchantUrl, true)); - } + //avoid multiple message event listener binded to the window object. + internal.removeOldEvtMsgListener(); + var evtMsgFct = function (event) { + return internal.receiveMessage({ event: event, instance: embeddedInstance, url: merchantUrl, embedded: true }); + }; + internal.evtMsg.push({ fct: evtMsgFct, opt: false }); + internal.addEvtMsgListener(evtMsgFct); } }; })(); @@ -718,11 +737,13 @@ var RealexHpp = (function () { document.getElementById(idOfButton).attachEvent('onclick', redirectInstance.redirect); } - if (window.addEventListener) { - window.addEventListener("message", internal.receiveMessage(redirectInstance, merchantUrl), false); - } else { - window.attachEvent('message', internal.receiveMessage(redirectInstance, merchantUrl)); - } + //avoid multiple message event listener binded to the window object. + internal.removeOldEvtMsgListener(); + var evtMsgFct = function (event) { + return internal.receiveMessage({ event: event, instance: redirectInstance, url: merchantUrl, embedded: false }); + }; + internal.evtMsg.push({ fct: evtMsgFct, opt: false }); + internal.addEvtMsgListener(evtMsgFct); } }; }());