Stripe token not generating when using a live Publiashable Key - javascript

I am building a custom checkout where Stripe is handling the payment information. I'm using the Stripe Elements Library. When I was using the test publishable key I was about to get an input with a token but once I switched to the live key that was no longer happening. I'm not sure if there something missing in my setup that's not allowing the token to be generated when the live key is active.
Here's my Javascript for the Stripe Elements integrations
<script src="https://js.stripe.com/v3/"></script>
<script>
// Create a Stripe client.
var stripe = Stripe('pk_live_xxxxxxxxxxxxxx');
// Create an instance of Elements.
var elements = stripe.elements();
// Custom styling can be passed to options when creating an Element.
// (Note that this demo uses a wider set of styles than the guide below.)
var style = {
base: {
color: '#32325d',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
},
':focus': {
color: '#333',
},
'::placeholder': {
color: '#333',
},
':focus::placeholder': {
color: '#333',
},
},
invalid: {
color: '#DC5B5B',
iconColor: '#DC5B5B',
':focus': {
color: '#DC5B5B',
},
'::placeholder': {
color: '#DC5B5B',
},
}
};
var elementClasses = {
focus: 'focus',
empty: 'empty',
invalid: 'invalid',
};
// Create an instance of the card Element.
var cardNumber = elements.create('cardNumber', {
style: style,
classes: elementClasses,
});
cardNumber.mount('#example3-card-number');
var cardExpiry = elements.create('cardExpiry', {
style: style,
classes: elementClasses,
});
cardExpiry.mount('#example3-card-expiry');
var cardCvc = elements.create('cardCvc', {
style: style,
classes: elementClasses,
});
cardCvc.mount('#example3-card-cvc');
registerElements([cardNumber, cardExpiry, cardCvc], 'example3');
function registerElements(elements, exampleName) {
var formClass = '.' + exampleName;
var example = document.querySelector(formClass);
var form = example.querySelector('form');
var resetButton = example.querySelector('a.reset');
var error = form.querySelector('.error');
var errorMessage = error.querySelector('.message');
function enableInputs() {
Array.prototype.forEach.call(
form.querySelectorAll(
"input[type='text'], input[type='email'], input[type='tel']"
),
function(input) {
input.removeAttribute('disabled');
}
);
}
function disableInputs() {
Array.prototype.forEach.call(
form.querySelectorAll(
"input[type='text'], input[type='email'], input[type='tel']"
),
function(input) {
input.setAttribute('disabled', 'true');
}
);
}
function triggerBrowserValidation() {
// The only way to trigger HTML5 form validation UI is to fake a user submit
// event.
var submit = document.createElement('input');
submit.type = 'submit';
submit.style.display = 'none';
form.appendChild(submit);
submit.click();
submit.remove();
}
// Listen for errors from each Element, and show error messages in the UI.
var savedErrors = {};
elements.forEach(function(element, idx) {
element.on('change', function(event) {
if (event.error) {
error.classList.add('visible');
savedErrors[idx] = event.error.message;
errorMessage.innerText = event.error.message;
} else {
savedErrors[idx] = null;
// Loop over the saved errors and find the first one, if any.
var nextError = Object.keys(savedErrors)
.sort()
.reduce(function(maybeFoundError, key) {
return maybeFoundError || savedErrors[key];
}, null);
error.classList.remove('visible');
if (nextError) {
// Now that they've fixed the current error, show another one.
errorMessage.innerText = nextError;
error.classList.add('visible');
} else {
// The user fixed the last error; no more errors.
error.classList.remove('visible');
}
}
});
});
// Listen on the form's 'submit' handler...
form.addEventListener('submit', function(e) {
e.preventDefault();
// Trigger HTML5 validation UI on the form if any of the inputs fail
// validation.
var plainInputsValid = true;
Array.prototype.forEach.call(form.querySelectorAll('input'), function(
input
) {
if (input.checkValidity && !input.checkValidity()) {
plainInputsValid = false;
return;
}
});
if (!plainInputsValid) {
triggerBrowserValidation();
return;
}
// Show a loading screen...
example.classList.add('submitting');
// Disable all inputs.
disableInputs();
// Gather additional customer data we may have collected in our form.
var name = form.querySelector('#' + exampleName + '-name');
var address1 = form.querySelector('#' + exampleName + '-address');
var city = form.querySelector('#' + exampleName + '-city');
var state = form.querySelector('#' + exampleName + '-state');
var zip = form.querySelector('#' + exampleName + '-zip');
var additionalData = {
name: name ? name.value : undefined,
address_line1: address1 ? address1.value : undefined,
address_city: city ? city.value : undefined,
address_state: state ? state.value : undefined,
address_zip: zip ? zip.value : undefined,
};
// Use Stripe.js to create a token. We only need to pass in one Element
// from the Element group in order to create a token. We can also pass
// in the additional customer data we collected in our form.
stripe.createToken(elements[0], additionalData).then(function(result) {
// Stop loading!
example.classList.remove('submitting');
if (result.token) {
stripeTokenHandler(result.token)
} else {
// Otherwise, un-disable inputs.
enableInputs();
}
});
});
}
// Submit the form with the token ID.
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
}
I only made minor changes to the Javascript code above to match my html when I first implemented it other than that the code is exactly what I found and used when I had the test key.
I'm not very familar with Stripe's Element Library so any help would be greatly appreciated.

Related

Detect if an element is deleted from Codemirror with backspace

When i delete the following "label" as a block using the backspace key, i would like to detect this event and do an ajax call, for example.
This part is deleted when i use backspace
Rendered
The problem is: there can be lots of labels (a tags) in textarea with different id's, i want to detect when any block is going to be deleted, save the id and remove.
Configuration
I'm using a custom configuration with a custom entity called annotation which represents the HTML above.
// Create CodeMirror (with lineWrapping on).
var codeMirror = CodeMirror(document.getElementById('firepad-container'), {lineWrapping: true});
// Create Firepad (with rich text toolbar and shortcuts enabled).
var firepad = Firepad.fromCodeMirror(firepadRef, codeMirror, {
richTextShortcuts: true,
richTextToolbar: true,
userId: userId,
userColor: userImage,
});
//// Create FirepadUserlist (with our userId, user name and avatar to display).
var firepadUserList = FirepadUserlist.fromDiv(firepadRef.child('users'),
document.getElementById('userlist'), userId, displayName, userImage);
firepad.registerEntity('annotation', {
render: function (info, entityHandler) {
var inputElement = document.createElement('a');
if(info.id) {
inputElement.setAttribute('id', info.id);
}
if(info.classList) {
inputElement.setAttribute('class', info.classList);
}
if(info.color || info.cursor) {
inputElement.setAttribute('style', 'color:' + info.color + '; cursor:' + info.cursor + ';');
}
inputElement.innerText = info.innerText;
inputElement.addEventListener('click', function(e){
editAnnotation(info.id, e);
entityHandler.remove();
});
return inputElement;
}.bind(this),
fromElement: function (element) {
var info = {};
if(element.hasAttribute('id')) {
info.id = element.id;
}
if(element.hasAttribute('class')) {
info.classList = element.classList;
}
info.color = element.style["color"];
info.cursor = element.style["cursor"];
info.innerText = element.innerText;
return info;
},
update: function (info, element, entityHandler) {
if(info.id) {
element.setAttribute('id', info.id);
}
if(info.classList) {
element.setAttribute('class', info.classList);
}
if(info.color || info.cursor) {
element.setAttribute('style', 'color:' + info.color + '; cursor:' + info.cursor + ';');
}
element.innerText = info.innerText;
},
export: function () {
var inputElement = document.createElement('a');
return inputElement;
}
});
If you want to add this new entity just use this:
firepad.insertEntity('annotation', { 'id': annotationId, 'color': color, 'cursor': 'pointer', 'innerText': 'whatever you want'});

How to simulate user typing in form

I'm trying to make a chrome extension that fills out a form in a specific page. (You can think of it like LastPass filling the user and passwords)
Currently I'm trying to fill out a form for a credit card with Javascript, but the website just gets stucked loading when you submit the form if you insert the credit card or other information through Javascript.
I have currently tried adding the card with this document.querySelector("#cardNumber").value="5454545454545454"; and I have tried doing .focus() or .click() on that input, even adding the value digit by digit, but it doesn't seem to trigger the website events that save the credit card correctly.
So, what I'm currently trying to figure out is if there's any way I can simulate the user adding the form so the website events get triggered. (The website is Mercadolibre.com, but I don't know if that helps in any way).
Here's a snippet of the website's code that gets executed when the card number changes.
App.module("Checkout.Payments.Views", function(e, t, n, i, o) {
var s = {
cardNumber: "number",
ownerName: "name",
expirationDate: "expiration",
securityCode: "security",
brand: "brand"
};
e.CardContainer = i.ItemView.extend({
getTemplate: function() {
return t.Utils.getTemplate(t.Components.templates.card, '[data-js="card"]')
},
className: "new-card__container--view",
ui: {
card: ".ui-card"
},
initialize: function() {
var e = this;
this.on("refresh", this.onCardRefresh),
this.on("rotate", this.onRotate),
this.on("brandSet", this.onBrandSet),
this.on("showSecurityHint", this.onShowSecurityHint),
this.modelEvents = {},
this.model.keys().forEach(function(t) {
"binHelper" !== t && (e.modelEvents["change:" + t] = function() {
return e.onCardDataChanged({
key: t,
rotate: "securityCode" === t
})
})
}),
this.bindEntityEvents(this.model, this.modelEvents),
this.brandSet = !1
},
onBrandSet: function() {
this.brandSet = !0
},
onShow: function() {
this.cardComponent = new CardComponent,
o(this.cardComponent.cardElements.name).attr("data-title", this.model.get("ownerNamePlaceholder")),
this.trigger("refresh")
},
onCardRefresh: function() {
var e = this;
this.model.keys().forEach(function(t) {
e.model.trigger("change:" + t, {
rotate: !1
})
})
},
onCardDataChanged: function(e) {
var t = e.key + "Changed",
n = t.replace(/\w{1}/, function(e) {
return e.toUpperCase()
}),
i = "on" + n;
this.triggerMethod(this[i] instanceof Function ? t : "otherCardDataChanged", e.key)
},
onCardNumberChanged: function(e) {
var t = this.model.get(e);
this.cardComponent[s[e]] = this.model.get(e),
t.length < 6 && (this.model.set("brand", ""),
this.model.set("bin", ""),
this.brandSet = !1)
},
onCardOwnerNameChanged: function(e) {
var t = this.model.get(e) || this.model.get("ownerNamePlaceholder");
this.cardComponent[s[e]] = t
},
onOtherCardDataChanged: function(e) {
this.cardComponent[s[e]] = this.model.get(e),
"" !== this.model.get("brand") && this.trigger("brandSet")
},
onRotate: function(e) {
"front" === e ? (this.cardComponent.rotateFront(),
this.cardComponent.blur = "securityFront") : "back" === e && this.cardComponent.rotateBack()
},
onShowSecurityHint: function() {
this.cardComponent.focus = "securityFront"
}
})
}),
The solution for this issue is sending events that get triggered when the user is typing manually. For example the events (blur, change, and input).
I added the events as constants like so:
const EVENT_OPTIONS = {bubbles: true, cancelable: false, composed: true};
const EVENTS = {
BLUR: new Event("blur", EVENT_OPTIONS),
CHANGE: new Event("change", EVENT_OPTIONS),
INPUT: new Event("input", EVENT_OPTIONS),
};
Afterwards, depending on the website, you might only need to add some of them or all like this:
const inputElement = document.querySelector("#cardNumber");
inputElement.value = "5454545454545454";
inputElement.dispatchEvent(EVENTS.INPUT);
In other websites, you can simulate the events better sending the CHANGE event and then the BLUR. And for other websites that use React, you might need to use React's _valueTracker like so:
const inputElement = document.querySelector("#cardNumber");
inputElement.value = "5454545454545454";
const tracker = inputElement._valueTracker;
tracker && tracker.setValue("5454545454545454");
inputElement.dispatchEvent(EVENTS.INPUT);
inputElement.dispatchEvent(EVENTS.BLUR);

Modifying stripe checkout form from one input contains all the required data to multiple inputs

I enabled a payment using a credit card by stripe and was working fine, but it had only one input box requesting all info. I need to modify the form to show multiple inputs.
I did a new HTML form with 4 inputs and every input in a div with different id names.
What I understand from the stripe docs is to modify the javascript file with the new ids as the following:
The old one:
<script type="text/javascript" nonce=""> // Create a Stripe client.
var stripe = Stripe('pk_test_XIkEi7uiUwtCIjdXShReMZ1e00kRB6lXjg');
// Create an instance of Elements.
var elements = stripe.elements();
// Custom styling can be passed to options when creating an Element.
// (Note that this demo uses a wider set of styles than the guide below.)
var style = {
base: {
color: '#32325d',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
};
// Create an instance of the card Element.
var card = elements.create('card', {style: style});
// Add an instance of the card Element into the `card-element` <div>.
card.mount('#card-element');
// Handle real-time validation errors from the card Element.
card.addEventListener('change', function(event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
// Handle form submission.
var form = document.getElementById('stripe-form');
form.addEventListener('submit', function(event) {
event.preventDefault();
stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the user if there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
});
});
// Submit the form with the token ID.
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('stripe-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit the form
form.submit();
}
</script>
The modified one:
<script type="text/javascript" nonce="">
// Create a Stripe client.
var stripe = Stripe('pk_tes**************************');
// Create an instance of Elements. var elements =
stripe.elements();
// Custom styling can be passed to options when creating an Element.
// (Note that this demo uses a wider set of styles than the guide
below.) var style = {
base: {
color: '#32325d',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
};
// Create an instance of the card Element. //var card =
elements.create('card', {
style: style
});
var cardNumberElement =
elements.create('cardNumber');
var cardExpiryElement =
elements.create('cardExpiry');
var cardCvcElement =
elements.create('cardCvc');
var zipCodeElement =
elements.create('zipCode');
// Add an instance of the card Element into the `stripe-form` <div>.
cardNumberElement.mount('#cardNumber');
cardExpiryElement.mount('#cardExpiry');
cardCvcElement.mount('#cardCvc');
zipCodeElement.mount('#zipCode');
// Handle real-time validation errors from the card Element.
card.addEventListener('change', function (event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
// Handle form submission. var form =
document.getElementById('stripe-form');
form.addEventListener('submit', function (event) {
event.preventDefault();
stripe.createToken(card).then(function (result) {
if (result.error) {
// Inform the user if there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
});
});
// Submit the form with the token ID. function
stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('stripe-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
///
var submitButton = document.getElementById('submit');
submitButton.addEventListener('click', function (ev) {
stripe.confirmCardPayment(clientSecret, {
payment_method: {
card: card,
billing_details: {
name: 'Jenny Rosen'
}
}
}).then(function (result) {
if (result.error) {
// Show error to your customer (e.g., insufficient funds)
console.log(result.error.message);
} else {
// The payment has been processed!
if (result.paymentIntent.status === 'succeeded') {
// Show a success message to your customer
// There's a risk of the customer closing the window before callback
// execution. Set up a webhook or plugin to listen for the
// payment_intent.succeeded event that handles any business critical
// post-payment actions.
}
}
});
});
// Submit the form
form.submit();
}
</script>
I want to know what's wrong with that since payment does work anymore after the .
modification

How can i open a form always in Edit mode , for a particular model

I have a model say 'my.attendance' , also have a form view for this which contains some attendance details.What i need is when i open this form view it should always open in Edit mode.So i can directly enter the attendance without clicking Edit button each time.
You have to extend the ViewManager to achieve this.
odoo.define('my_module.view_manager', function (require) {
"use strict";
var ViewManager = require('web.ViewManager');
ViewManager.include({
custom_events: {
execute_action: function(event) {
var data = event.data;
this.do_execute_action(data.action_data, data.env, data.on_closed)
.then(data.on_success, data.on_fail);
},
search: function(event) {
var d = event.data;
_.extend(this.env, this._process_search_data(d.domains, d.contexts, d.groupbys));
this.active_view.controller.reload(_.extend({offset: 0}, this.env));
},
switch_view: function(event) {
if ('res_id' in event.data) {
this.env.currentId = event.data.res_id;
}
var options = {};
console.log(event.data)
if (event.data.view_type === 'form' && !this.env.currentId) {
options.mode = 'edit';
} else if (event.data.mode) {
options.mode = event.data.mode;
}
// Extra added code
if (event.data.model){
if (event.data.model == 'my.model'){ // Checking the particular model.
options.mode = 'edit';
}
}
this.switch_mode(event.data.view_type, options);
},
env_updated: function(event) {
_.extend(this.env, event.data);
},
push_state: function(event) {
this.do_push_state(event.data);
},
get_controller_context: '_onGetControllerContext',
switch_to_previous_view: '_onSwitchToPreviousView',
},
});
});

Clearing last JSON response

I am developing an iOS 6.1 app using Titanium Studio, build: 3.1.2.201307091805, I am testing on the iPhone simulator and iPad device. I have a search field that gets JSON results from a remote server. The screen I am having issues with has the search box at the top and a couple of messages below. When the user types in the search field and hits return, the messages are hidden and a table is placed ready to receive the results from the database. All of that is working fine. When the user types in something that is not in the database I have a message appear "No results found, please try again". I made a button to "Clear" the table or "Not Found" message. Here is the button code I have so far:
var clear = Ti.UI.createButton({
title: "Clear",
style:Titanium.UI.iPhone.SystemButtonStyle.BORDERED
});
clear.addEventListener("click", function() {
message.hide();
table.setData([]);
});
Ti.UI.currentWindow.setRightNavButton(clear);
This code does clear the message or the results in the table but when I do another search the previous result appears above the new result even if the searches were totally unrelated. Here is my code.
var win = Titanium.UI.currentWindow;
win.backgroundImage='images/background.png';
win.barColor='#28517A';
win.title='Product Search';
var message = Ti.UI.createLabel({
text: 'No results found, please try again',
top:'100dp',
left:'20dp',
right:'20dp'
});
var customSearchBar = Ti.UI.createView({
backgroundColor: '#28517A',
height: 42,
top: '0dp',
width: Ti.UI.FILL
});
var customSearchField = Ti.UI.createTextField({
autocorrect: false,
borderStyle: Ti.UI.INPUT_BORDERSTYLE_ROUNDED,
clearOnEdit: true,
height: 28,
hintText: 'Search For Product or Service',
textAlign: 'center',
width: '90%',
});
customSearchBar.add(customSearchField);
win.add(customSearchBar);
var nolist= Ti.UI.createLabel({
text: 'XXXXXX',
color: '#000',
font: {fontSize:'16dp', fontWeight:'bold'},
top:'50dp',
left:'20dp',
right:'20dp'
});
win.add(nolist);
var businessowner = Ti.UI.createLabel({
text: 'XXXXXX',
color: '#000',
font: {fontSize:'16dp', fontWeight:'bold'},
bottom:'10dp',
left:'20dp',
right:'20dp'
});
win.add(businessowner);
var view = Ti.UI.createView({
backgroundColor: 'transparent',
top: '100dp',
bottom:'60dp'
});
var table = Ti.UI.createTableView({
backgroundColor: 'transparent',
top: '0dp',
height:'auto',
bottom:'0dp'
});
view.add(table);
table.show();
var tableData = [];
function checkInternetConnection(){
return Ti.Network.online ? true : false;
}
customSearchField.addEventListener("return", function(e) {
if(checkInternetConnection()){
nolist.hide();
businessowner.hide();
getdata();
win.add(view);
function getdata(){
var url = "http://mydomain.com/filename.php?title="+e.value;
var xhr = Ti.Network.createHTTPClient({
onload: function() {
Ti.API.debug(this.responseText);
var json = JSON.parse(this.responseText);
if (json.cms_list.length< 1){
win.add(message);
}
for (i = 0; i < json.cms_list.length; i++) {
client = json.cms_list[i];
row = Ti.UI.createTableViewRow({
height:'44dp',
hasChild:true
});
var clientlist = Ti.UI.createLabel({
text:client.clientname,
font:{fontSize:'16dp', fontWeight:'bold'},
height:'auto',
left:'10dp',
color:'#000'
});
row.add(clientlist);
tableData.push(row);
}
table.addEventListener('click',function(e){
var row = e.row;
var clientlist = row.children[0];
var win = Ti.UI.createWindow({
url: 'clientdetail.js',
title: clientlist.text
});
var clientlist = clientlist.text;
win.clientlist = clientlist;
customSearchField.blur();
Titanium.UI.currentTab.open(win,{animated:true});});
table.setData(tableData);
},
onerror: function(e) {
Ti.API.debug("STATUS: " + this.status);
Ti.API.debug("TEXT: " + this.responseText);
Ti.API.debug("ERROR: " + e.error);
alert('There was an error retrieving the remote data. Try again.');
},
timeout:5000
});
xhr.open("GET", url);
xhr.send();
}
}
else{
alert('Your internet connection is not available');
}
});
var clear = Ti.UI.createButton({
title: "Clear",
style:Titanium.UI.iPhone.SystemButtonStyle.BORDERED
});
clear.addEventListener("click", function() {
message.hide();
table.setData([]);
});
Ti.UI.currentWindow.setRightNavButton(clear);
If I press my back button and then return to this screen, the search is fine. How can I completely clear the previous results without leaving the screen and then returning?
You are adding the table to the window every time you click "return". Change your event listener by removing win.add(view); from it, and replace that line with table.show(); like this:
customSearchField.addEventListener("return", function(e) {
if(checkInternetConnection()){
nolist.hide();
businessowner.hide();
getdata();
//win.add(view); dont do this!!!!
table.show();
.....
});
Then, change this:
var table = Ti.UI.createTableView({
backgroundColor: 'transparent',
top: '0dp',
height:'auto',
bottom:'0dp'
});
view.add(table);
//table.show();
win.add(table);
table.hide();
Now you will only have one instance of a table, and you can use setData inside the return listener every time you want to change all the rows.
You are not clearing data from var tabledata. It should be cleared when you are setting table.setData([]); . It is pushing the same data after setting the table as empty.
Your code should look like this:
clear.addEventListener("click", function() {
message.hide();
tableData = [];
table.setData([]);
});

Categories