javascript ndefREADER doesn't load automatically - javascript

First of all, I have to say this is my first question on stack ;)
I am trying to implement a reading via NFC on my test web, but i dunno why, the ndefReader doesn't works on startup, i have to press any field on the web to get it loaded (or asked for permission).
BUT, if i wrote some alerts to check why it doen't reach the function on startup, it works!!! (of course, it show alerts before). I don't know if when I accept the alert, I am interacting with the web and that's why it works, but anyways, I dunno why this happens (I need to click anywhere before starting).
function iniciar() {
document.getElementById("input1").focus();
//alert("test before"); <--- IF i remove this, it doesnt works
document.getElementById("input1").addEventListener("blur", async () => {
try{
const ndef = new NDEFReader();
alert("before wait");
await ndef.scan();
alert("after wait");
ndef.addEventListener("readingerror", () => {
alert("Argh! Cannot read data from the NFC tag. Try another one?");
});
ndef.addEventListener("reading", ({ message, serialNumber }) => {
alert(`> Serial Number: ${serialNumber}`);
alert(`> Records: (${message.records.length})`);
});
} catch (error) {
alert("Argh! " + error);
}
},false);

To scan and write to NFC tags, you must first request the "nfc" permission while handling a user gesture (e.g a button click, or in your case the "alert" call). Once handled, the NDEFReader scan() and write() methods trigger a user prompt, if access was not previously granted.
Check out https://web.dev/nfc/#security-and-permissions to learn more.
Hopefully https://googlechrome.github.io/samples/web-nfc/ samples should help you as well.
scanButton.addEventListener("click", async () => {
console.log("User clicked scan button");
try {
const ndef = new NDEFReader();
await ndef.scan();
console.log("> Scan started");
ndef.addEventListener("readingerror", () => {
console.log("Argh! Cannot read data from the NFC tag. Try another one?");
});
ndef.addEventListener("reading", ({ message, serialNumber }) => {
console.log(`> Serial Number: ${serialNumber}`);
console.log(`> Records: (${message.records.length})`);
});
} catch (error) {
console.log("Argh! " + error);
}
});

Related

Can I emulate/provoke failure to copy to clipboard from JS in Chrome?

I have a web page with some JavaScript code that copies stuff to the clipboard similar to what this demo does: https://davidwalsh.name/demo/javascript-copy-clipboard.php
My code is something like this:
// Within a listener that is triggered by a click on some button:
var copiedText = "...something";
navigator.clipboard.writeText(copiedText).then(
function() {
console.log("Succesfully copied");
},
function() {
console.log("FAILED to copy!!!!!!");
}
);
This works fine, but it always succeeds. I need to test that the behavior is correct when copying fails for whatever reason.
How can I cause the copy to fail on purpose so that I can test the behavior of my code in that situation?
I never get a prompt asking me permission to write to the clipboard.
In Chrome, I have tried going to the site settings for the site, and under "Clipboard" selecting "Block", but it does nothing (I guess that's only for reading from the clipboard).
Sure, just provide an invalid argument which will throw an exception during the stringification algorithm:
Note that this demo will work in your own page, but the success case won't work in the Stack Overflow code snippet iframe sandbox (where there is no clipboard permission).
function copyThenLog (input) {
navigator.clipboard.writeText(input).then(
() => console.log({success: true}),
(ex) => {
console.log({success: false});
console.error(ex);
},
);
}
document.querySelector('.success').addEventListener('click', () => {
const input = 'hello world';
copyThenLog(input);
});
document.querySelector('.fail').addEventListener('click', () => {
const input = {
toString () {
throw new Error('Oops');
}
};
copyThenLog(input);
});
<div class="success">Click me to succeed</div>
<div class="fail">Click me to fail</div>

How to set Wix to do a HTTP request upon an event

I have a Wix site and I have this JS code in the site:
import { fetch } from 'wix-fetch';
$w("#button1").onClick( (event) => {
var link = $w("#link").id;
console.log(link)
fetch("https://my-new-app-xyz.herokuapp.com?link="+link, {"method": 'get'})
.then((httpResponse) => {
if (httpResponse.ok) {
return httpResponse;
} else {
return Promise.reject("Failed");
}
} )
.catch( (err) => {
console.log(err);
} );
})
However, upon the click of button1 nothing happens. Hopefully, the code explains what I want to do, but, upon clicking button1. I want to get the value of the text box element with id link and send a GET request to "https://my-new-app-xyz.herokuapp.com?link=" + the link from the text box. I don't know much JavaScript - this code is from reading the Wix API docs.

Why IFrame does not load on a single click on container div?

Background:
Working on Cybersource Credit Card integration with React app. Need to show Masked card number coming from API response upon tabbing out (onBlur) of field.
Flow
Created a container-div in which IFrame gets loaded and I enter CC number. On blur event, doing API calls for validation and getting the masked card number (if successfully validated).
Upon setting maskedCardNumber, component gets re-rendered and shows the maskedCardNumber in the container-div. At this point I see in Elements tab, IFrame is gone which is perfectly fine to me. Now in my container div there is no IFrame but a masked card number.
I want to change CC number
I click on input alike div and masked card number gets removed because of setMaskedCardNumber("");. ( Not each character one by one but all in once as we do not have that card number). Till this point everything is fine.
Problem
After removal, it should show new Iframe because I am calling loadIFrame(); like I did for initial Iframe loading but weirdly it does not show until I click AGAIN. YES!! you read it right. I need to click AGAIN to load and IFrame which is very weird for me.
Tried so far
useState(),
useReducer(),
to make <label>{maskedCardNumber}</label> inside container-div.
Changing conatiner-div <div> to <input>
Relevant code
useEffect(() => {
if (apiKey) {
loadIFrame();
}
}, [apiKey])
const loadIFrame = () => {
let flex;
flex = new Flex(apiKey);
let microform = flex.microform();
let number = microform.createField('number', {
placeholder: 'Enter card number'
});
number.on('load', () => {
number.focus();
});
number.on('blur', () => {
//transient token call
microform.createToken({}, function(err, token) {
if (err) {
console.error(err);
setCardError({
...error,
token: "Please enter valid CC number"
})
} else {
setCardError({
...error,
token: ""
});
//permenant token call
setMaskedCardNumber(JSON.parse(atob(token.split('.')[1]))["data"]["number"]);
dispatch({
type: orderActions.GET_CC_TOKEN,
transientToken: JSON.parse(atob(token.split('.')[1]))['jti'],
callbacks: {
success: (ccToken) => {
updateCardDetail({
type: "token",
token: ccToken
})
},
failure: (err) => {
console.error(err);
setCardError({
...error,
token: "Please enter valid CC number"
})
}
}
})
}
})
});
number.load('#number-container');
}
<div id="number-container" className="form-control" onClick={() => {
setMaskedCardNumber("");
loadIFrame();
}}>
{maskedCardNumber}
</div>
Problem I see here is basically the response to your setMaskedCardNumber() call returns after the iFrame is loaded due to its async nature.
Try putting this effect
useEffect(()=>{
if(maskedCardNumber === ""){
loadIFrame()
}
}, [maskedCardNumber])
and remove loadIFrame(); from onClick() handler
this will make sure whenever you empty the cardNumber state, iFrame is loaded when it is successfully emptied.
UPDATE:
We can make use of single useEffect.
useEffect(() => {
if (apiKey && !maskedCardNumber) {
loadIFrame();
}
}, [apiKey, maskedCardNumber])
With this we can make sure to load IFrame only if apiKey present otherwise do not try to load because IFrame is dependant on apiKey.

Handling a Windows confirm pop-up using Cypress

I am learning Cypress the hard way: on a legacy app with frames :(
I read that Cypress auto accepts alerts but here I have a Confirm pop-up that demands a user input. However, I am struggling to close this windows confirm pop ip asking to 'Cancel' or 'OK'.
The element which fires the pop-up is within a frame (not an iFrame) is as follows:
<a href="/tasksgui/manageScheduledJobs.do?userAction=runnow&userAction=select&selectedIndex=1&formContextKey=ListChunk[SchedulerJobsSearchResults]{1588676256461}1"
onclick="return(confirmRunNow())" ;>
RunJobs</a>
I know that the Cypress API exposes a way to handle these:
cy.on('window:confirm', (str) => {
//code here
}
But I'm unclear how to incorporate this into my test block"
it('gets the post', (done) => {
cy.visit('http://myapp.co.uk/mygui/index.jsp');
getLeftFrameBody().findByText('Manage Tasks').click();
cy.wait(2000)
getContentFrameBody().should('include.text', 'Scheduled Tasks')
getContentFrameBody().findByText('Task Name');
getContentFrameBody().find('input[name="jobName"]').type('Task one');
getContentFrameBody().findByText('Search').click();
cy.wait(2000)
cy.on('window:confirm', function(confirmText){
return true
});
getContentFrameBody().find('.resultrowone').find('a').eq(5).click();
})
By making the function async, you can await the window confirmation and then continue as seen in the example below.
it('gets the post', async (done) => {
cy.visit('http://companyapp.co.uk/mygui/index.jsp');
getLeftFrameBody().findByText('Manage Tasks').click();
cy.wait(2000)
getContentFrameBody().should('include.text', 'Scheduled Tasks')
getContentFrameBody().findByText('Job Name');
getContentFrameBody().find('input[name="jobName"]').type('runTasks');
getContentFrameBody().findByText('Search').click();
cy.wait(2000);
await new Promise(resolve => {
cy.on('window:confirm', (str) => {
resolve();
});
getContentFrameBody().find('.resultrowone').find('a').eq(5).click();
});
// Continue after window was confirmed
});

Twilio Client - Connection accepted event on caller site

I cannot find anthing in Twilio Docs about event fired up when called user answers the call. Connection.accept(handler) is fired up only on called user browser when he anwsers. Im doing connection between two browsers in Aurelia.js and I want to start the timer on moment when call is answered, but none of the events described in docs seems to fire up when called user answers. This is my client code.
setupTwilio() {
this.http.get("twilio/client/create").then(response => {
this.twilioData = JSON.parse(response.response);
Twilio.Device.setup(this.twilioData.token);
Twilio.Device.offline((device)=>{
Twilio.Device.destroy();
this.setupTwilio();
});
Twilio.Device.ready((device) => {
console.log("Ready");
});
Twilio.Device.error((error) => {
console.log("Error: " + error.message);
});
Twilio.Device.connect((conn) => {
this.call.startedAt = moment().unix();
});
Twilio.Device.disconnect((conn) => {
this.rejectCall();
});
Twilio.Device.cancel((conn) => {
this.rejectCall();
});
Twilio.Device.incoming((conn) => {
var userId = conn.parameters.From.split(":").pop().substring(4);
this.http.get('users/' + userId).then((response) => {
this.call.user = JSON.parse(response.response);
$('#incomingCall').modal({backdrop: 'static', keyboard: false});
}).catch(error => {
this.notification.error("Error fetching user");
});
});
});
}
Take a look at this article. https://www.twilio.com/blog/2015/05/introducing-call-progress-events-flexibly-track-and-control-your-outbound-calls.html It explains about call progress events: Initiated, Ringing, Answered, Completed.

Categories