89 lines
3.7 KiB
JavaScript
89 lines
3.7 KiB
JavaScript
/*
|
|
* Square "Pay" button embed loader.
|
|
* ─────────────────────────────────
|
|
* A school drops ONE script tag onto their own website:
|
|
*
|
|
* <script src="https://app.hotlunches.net/square/embed.js"
|
|
* data-square-key="sqpk_xxxxxxxxxxxxxxxx"
|
|
* data-amount="25.00"
|
|
* data-currency="CAD"
|
|
* data-email="" (optional, prefill receipt email)
|
|
* data-success="" (optional, redirect URL after payment)
|
|
* async></script>
|
|
*
|
|
* It injects a responsive <iframe> (pay-frame.php) right where the script tag
|
|
* sits, so the Square card form renders inline on their page. The card data is
|
|
* tokenized by Square inside the iframe and never touches their site or ours.
|
|
*
|
|
* To place the button somewhere specific, give a target:
|
|
* data-target="#pay-here" → renders into that element instead of inline.
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
|
|
// The currently executing script tag (so we can read its data-* and the base
|
|
// URL it was served from). document.currentScript is reliable for sync loads;
|
|
// for async we fall back to the last script that points at embed.js.
|
|
var me = document.currentScript || (function () {
|
|
var all = document.getElementsByTagName('script');
|
|
for (var i = all.length - 1; i >= 0; i--) {
|
|
if ((all[i].src || '').indexOf('embed.js') !== -1) return all[i];
|
|
}
|
|
return null;
|
|
})();
|
|
if (!me) return;
|
|
|
|
var key = me.getAttribute('data-square-key') || '';
|
|
if (!key) {
|
|
console.error('[square-embed] missing data-square-key on the embed script tag.');
|
|
return;
|
|
}
|
|
|
|
// Derive the integration base URL (…/square/) from this script's own src so
|
|
// the school never has to configure a second URL.
|
|
var base = me.src.replace(/embed\.js(\?.*)?$/, '');
|
|
|
|
var amount = me.getAttribute('data-amount') || '';
|
|
var currency = me.getAttribute('data-currency') || '';
|
|
var email = me.getAttribute('data-email') || '';
|
|
var success = me.getAttribute('data-success') || '';
|
|
|
|
var qs = 'key=' + encodeURIComponent(key) + '&amount=' + encodeURIComponent(amount);
|
|
if (currency) qs += '¤cy=' + encodeURIComponent(currency);
|
|
if (email) qs += '&email=' + encodeURIComponent(email);
|
|
if (success) qs += '&success=' + encodeURIComponent(success);
|
|
|
|
var iframe = document.createElement('iframe');
|
|
iframe.src = base + 'pay-frame.php?' + qs;
|
|
iframe.setAttribute('title', 'Pay with Square');
|
|
iframe.setAttribute('scrolling', 'no');
|
|
iframe.setAttribute('allow', 'payment');
|
|
iframe.style.cssText =
|
|
'width:100%;max-width:520px;border:0;overflow:hidden;display:block;height:280px;' +
|
|
'transition:height .15s ease;';
|
|
|
|
// A stable name lets us match height messages to THIS iframe if a page has
|
|
// several embedded buttons.
|
|
var frameName = 'sqpayframe_' + Math.random().toString(36).slice(2);
|
|
iframe.name = frameName;
|
|
|
|
// Resize the iframe to its content height as reported by pay-frame.php.
|
|
window.addEventListener('message', function (ev) {
|
|
var d = ev.data;
|
|
if (!d || d.sqPayFrame !== true || d.type !== 'height') return;
|
|
// Only react to messages from our own frame's content window.
|
|
if (ev.source !== iframe.contentWindow) return;
|
|
var h = parseInt(d.height, 10);
|
|
if (h > 0) iframe.style.height = (h + 4) + 'px';
|
|
});
|
|
|
|
// Insert: into data-target if given, else right where the script tag is.
|
|
var targetSel = me.getAttribute('data-target');
|
|
if (targetSel) {
|
|
var target = document.querySelector(targetSel);
|
|
if (target) { target.appendChild(iframe); return; }
|
|
console.warn('[square-embed] data-target "' + targetSel + '" not found; inlining instead.');
|
|
}
|
|
(me.parentNode || document.body).insertBefore(iframe, me);
|
|
})();
|