diff --git a/.gitignore b/.gitignore index 7bec9be..4f18d42 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ /node_modules/ yarn.lock package-lock.json +.DS_Store +_SpecRunner.html +.grunt/ diff --git a/dist/rxp-js.js b/dist/rxp-js.js index 54f0f1e..fe61875 100644 --- a/dist/rxp-js.js +++ b/dist/rxp-js.js @@ -1,4 +1,4 @@ -/*! rxp-js - v1.4.0 - 2021-03-29 +/*! rxp-js - v1.4.0 - 2021-05-18 * The official Realex Payments JS Library * https://github.com/realexpayments/rxp-js * Licensed MIT @@ -50,7 +50,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" + @@ -420,95 +438,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(); + } } }; @@ -580,12 +596,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); } }; })(); @@ -658,11 +675,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); } }; })(); @@ -722,11 +741,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); } }; }()); diff --git a/dist/rxp-js.min.js b/dist/rxp-js.min.js index c048d82..6273524 100644 --- a/dist/rxp-js.min.js +++ b/dist/rxp-js.min.js @@ -1,7 +1,7 @@ -/*! rxp-js - v1.4.0 - 2021-03-29 +/*! rxp-js - v1.4.0 - 2021-05-18 * The official Realex Payments JS Library * https://github.com/realexpayments/rxp-js * Licensed MIT */ -Element.prototype.remove=function(){this.parentElement.removeChild(this)},NodeList.prototype.remove=HTMLCollection.prototype.remove=function(){for(var e=this.length-1;0<=e;e--)this[e]&&this[e].parentElement&&this[e].parentElement.removeChild(this[e])};var RealexHpp=function(){"use strict";var h,d,n,i,A,C="https://pay.realexpayments.com/pay",E=E||Math.random().toString(16).substr(2,8),t=360,e=/Windows Phone|IEMobile/.test(navigator.userAgent),o=/Android|iPad|iPhone|iPod/.test(navigator.userAgent),u=e,m=function(){return!e&&(o||(0>2,o=(3&A)<<4|(n=e.charCodeAt(c++))>>4,r=(15&n)<<2|(d=e.charCodeAt(c++))>>6,s=63&d,isNaN(n)?r=s=64:isNaN(d)&&(s=64),a=a+t.charAt(i)+t.charAt(o)+t.charAt(r)+t.charAt(s),A=n=d="",i=o=r=s="",c