Support NFC on modal

This commit is contained in:
Kukks 2023-06-02 11:21:21 +02:00 committed by Andrew Camilleri
parent 6d4918f0ab
commit a618f901fc
2 changed files with 77 additions and 4 deletions

View file

@ -22,7 +22,38 @@
</template>
</template>
<script type="text/javascript">
// https://developer.chrome.com/articles/nfc/
class NDEFReaderWrapper {
constructor() {
this.onreading = null;
this.onreadingerror = null;
}
async scan( opts) {
if (opts && opts.signal){
opts.signal.addEventListener("abort", () => {
window.parent.postMessage("abortNfc", "*");
});
}
window.parent.postMessage("startNfcScan", "*");
}
}
window.addEventListener("message", (event) => {
const { action, data } = event.data;
if (action === "nfcData") {
if (ndef.onreading) {
ndef.onreading({ message: { records: [{ data }] } });
}
} else if (action === "nfcError") {
if (ndef.onreadingerror) {
ndef.onreadingerror();
}
}
});
Vue.component("lnurl-withdraw-checkout", {
template: "#lnurl-withdraw-template",
props: {
@ -69,7 +100,7 @@ Vue.component("lnurl-withdraw-checkout", {
data () {
return {
url: @Safe.Json(Context.Request.GetAbsoluteUri(Url.Action("SubmitLNURLWithdrawForInvoice", "NFC"))),
supported: 'NDEFReader' in window && window.self === window.top,
supported: 'NDEFReader' in window ,
scanning: false,
submitting: false,
permissionGranted: false,
@ -135,7 +166,7 @@ Vue.component("lnurl-withdraw-checkout", {
this.submitting = false;
this.scanning = true;
try {
const ndef = new NDEFReader()
const ndef = window.self === window.top? new NDEFReader() : new NDEFReaderWrapper();
this.readerAbortController = new AbortController()
this.readerAbortController.signal.onabort = () => {
this.scanning = false;

View file

@ -48,7 +48,7 @@
var scriptMatch = thisScript.match(scriptSrcRegex)
if (scriptMatch) {
// We can't just take the domain as btcpay can run under a sub path with RootPath
origin = thisScript.substr(0, thisScript.length - scriptMatch[0].length);
origin = thisScript.slice(0, thisScript.length - scriptMatch[0].length);
}
// urlPrefix should be site root without trailing slash
function setApiUrlPrefix(urlPrefix) {
@ -62,6 +62,7 @@
var onModalWillLeaveMethod = function () { };
var onModalReceiveMessageMethod = function (event) { };
var nfcSupportAvailable = "NDEFReader" in window;
function showFrame() {
if (window.document.getElementsByName('btcpay').length === 0) {
window.document.body.appendChild(iframe);
@ -88,7 +89,40 @@
function onModalReceiveMessage(customOnModalReceiveMessage) {
onModalReceiveMessageMethod = customOnModalReceiveMessage;
}
var readerAbortController = null;
function startNfcScan() {
const ndef = new NDEFReader();
readerAbortController = new AbortController()
readerAbortController.signal.onabort = () => {
this.scanning = false;
};
ndef.scan({signal:readerAbortController.signal}).then(() => {
console.log("> Scan started successfully.");
ndef.onreading = (event) => {
const message = event.message;
const record = message.records[0];
const textDecoder = new TextDecoder('utf-8');
const lnurl = textDecoder.decode(record.data);
// Send NFC data back to the iframe
if (iframe) {
iframe.contentWindow.postMessage({ action: "nfcData", data: lnurl }, "*");
}
};
ndef.onerror = () => {
console.log("Error! Cannot read data from the NFC tag. Try another one.");
// Send error message back to the iframe
if (iframe) {
iframe.contentWindow.postMessage({ action: "nfcError" }, "*");
}
};
}).catch(error => {
console.log(`Argh! ${error}`);
});
}
function receiveMessage(event) {
var uri;
@ -99,6 +133,14 @@
hideFrame();
} else if (event.data === 'loaded') {
showFrame();
}
else if(event.data === "startNfcScan") {
startNfcScan();
}
else if(event.data === "abortNfc") {
if (readerAbortController) {
readerAbortController.abort()
}
} else if (event.data && event.data.open) {
uri = event.data.open;
if (uri.indexOf('bitcoin:') === 0) {