Integrating Braintree Client token into braintree.client.create - javascript

I have limited experience working with JavaScript and am attempting to pass a client token generated on my server into the braintree client create of Braintree's javascript code. I do not know how to pass the ClientToken out of the jQuery post and into the authorization section of braintree.client.create. A portion of my code is below:
<script src="https://js.braintreegateway.com/web/3.34.0/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.34.0/js/hosted-fields.min.js"></script>
<script src="https://www.paypalobjects.com/api/checkout.js" data-version-4></script>
<script src="https://js.braintreegateway.com/web/3.34.0/js/paypal-checkout.min.js"></script>
<script>
var form = document.querySelector('#register-form');
var submit = document.querySelector('input[type="submit"]');
var ClientToken;
var authPosting = jQuery.post('/path/to/php_scripts/getClientToken.php');
authPosting.done(function( data ) {
ClientToken = data;
console.log(ClientToken);
});
braintree.client.create({
authorization: 'ClientToken'
}, function (clientErr, clientInstance) {
if (clientErr) {
console.error(clientErr);
return;
}
braintree.hostedFields.create({
client: clientInstance,
styles: {
'input': {
'font-size': '15px',
'font-family': 'roboto, verdana, sans-serif',
'font-weight': 'lighter',
'color': 'black'
},
':focus': {
'color': 'black'
},
'.valid': {
'color': 'black'
},
'.invalid': {
'color': 'black'
}
},
fields: {
number: {
selector: '#card-number',
placeholder: ''
},
cvv: {
selector: '#cvv',
placeholder: ''
},
expirationDate: {
selector: '#expiration-date',
placeholder: 'MM/YY'
},
postalCode: {
selector: '#postal-code',
placeholder: ''
}
}
}, function(err, hostedFieldsInstance) {
if (err) {
console.error(err);
return;
}
function findLabel(field) {
return jQuery('.hosted-field--label[for="' + field.container.id + '"]');
}
hostedFieldsInstance.on('focus', function (event) {
var field = event.fields[event.emittedBy];
findLabel(field).addClass('label-float').removeClass('filled');
jQuery(".error-msg").hide();
});
// Emulates floating label pattern
hostedFieldsInstance.on('blur', function (event) {
var field = event.fields[event.emittedBy];
var label = findLabel(field);
if (field.isEmpty) {
label.removeClass('label-float');
} else if (field.isValid) {
label.addClass('filled');
} else {
label.addClass('invalid');
}
});
hostedFieldsInstance.on('empty', function (event) {
var field = event.fields[event.emittedBy];
findLabel(field).removeClass('filled').removeClass('invalid');
});
hostedFieldsInstance.on('validityChange', function (event) {
var field = event.fields[event.emittedBy];
var label = findLabel(field);
if (field.isPotentiallyValid) {
label.removeClass('invalid');
} else {
label.addClass('invalid');
}
});
//Submit function
jQuery("#register-form").validate({
submitHandler: function(form) {
event.preventDefault();
hostedFieldsInstance.tokenize(function (err, payload) {
if (err) {
if (err.code === 'HOSTED_FIELDS_FIELDS_EMPTY') {
var msg = "All credit card fields are required.";
jQuery(".error-msg").text(msg);
jQuery(".error-msg").show();
} else if (err.code === 'HOSTED_FIELDS_FIELDS_INVALID') {
var invalidFields = err.details.invalidFieldKeys;
invalidFields.forEach(function (field) {
if (field == "number") {
var myid = "card-number";
var myobj = "credit card number";
} else if (field == "expirationDate") {
var myid = "expiration-date";
var myobj = "expiration date";
}
jQuery("#" + myid).append("<div class='error-msg'>Please enter a valid " + myobj + ".</div>");
});
} else {
var msg = "There was an error on the form."
alert (msg);
}
return;
}
vfirst = jQuery( "input#firstname" ).val(),
vlast = jQuery( "input#lastname" ).val(),
vemail = jQuery( "input#email" ).val(),
vproof = jQuery( "input[name='proof']" ).val(),
vprice = jQuery( "tr#total td.price" ).data('price'),
vcourse = 1950,
vnonce = 'fake-valid-nonce',
url = '/path/to/php_scripts/placeOrder.php';
// This is where you would submit payload.nonce to your server
// alert('Submit your cc nonce to your server here!');
});
//form.submit();
}
});
});
....more code below....
</script>
Any suggestions would be greatly appreciated.

Answering my own question:
CLIENT_AUTHORIZATION = jQuery.parseJSON(jQuery.ajax({
url: "/path/to/php_scripts/TokenScript.php",
dataType: "json",
async: false
}).responseText);
braintree.client.create({
authorization: CLIENT_AUTHORIZATION.token
}, function (clientErr, clientInstance) {
if (clientErr) {
console.error(clientErr);
return;
} code continues.....
The CLIENT_AUTHORIZATION.token is whatever the token was named on the client authorization script.

Related

How to select row in datatable (jquery datatables)

I'm using below code 1 to populate my datatable. However, when I tried to access my datatable using code 2, I dont get this response: alert( customerTable.row( this ).data() );
What am I doing wrong here?
Code 1
$(searchClientBtn).on("click", function () {
var clientLastName = $(clientLastNameTxt).val();
var clientFirstName = $(clientFirstNameTxt).val();
var clientMiddleName = $(clientMiddleNameTxt).val();
var clientDateOfBirth = $(clientDateOfBirthTxt).val();
if ( clientLastName.length == 0 && clientFirstName.length == 0 && clientMiddleName.length == 0 ) {
alert("Please enter search parameter/s to proceed.");
}
else {
var formData = new FormData();
formData.append("firstName", $("#clientFirstNameTxt").val());
formData.append("middleName", $("#clientMiddleNameTxt").val());
formData.append("lastName", $("#clientLastNameTxt").val());
formData.append("dateOfBirth", $("#clientDateOfBirthTxt").val());
//console.log(formData);
var booking = new booking();
booking.getListCustomer(formData, {
onSuccess: function (xdata) {
var customerTable = $("#customerTable").DataTable({
data: xdata.result,
processing: true,
columns: [
{ 'data': 'FirstName' },
{ 'data': 'MiddleName' },
{ 'data': 'LastName' },
{ 'data': 'Birthdate' }
]
});
},
onError: function (xdata) {
alert("An error occured");
}
});
$(clientSearchModal).modal("show");
}
});
Code 2
$("#customerTable").on("click", "tbody tr", function () {
alert("imclicked");
alert( customerTable.row( this ).data() );
});
Need to define variable.
$("#customerTable").on("click", "tbody tr", function () {
var customerTable = $('#customerTable').DataTable(); //Here need to define variable
alert("imclicked");
alert( customerTable.row( this ).data() );
});

Uninitialized constant Spree::Api::AramexAddressController::AramexAddressValidator

I am facing the following issue:
ActionController::RoutingError (uninitialized constant Spree::Api::AramexAddressController::AramexAddressValidator):
app/controllers/spree/api/aramex_address_controller.rb:2:in <class:AramexAddressController>
app/controllers/spree/api/aramex_address_controller.rb:1:in <top (required)>
I included the following in my controllers/spree/api/aramex_address_controller.rb:
class Spree::Api::AramexAddressController < ApplicationController
include AramexAddressValidator
# fetch cities from aramex api
def fetch_cities_from_aramex_address
response = []
zones = Spree::ShippingMethod.where(['LOWER(admin_name) like ?', '%aramex%']).map(&:zones).flatten
if zones.map(&:countries).flatten.map(&:iso).include?(params['country_code'])
response = JSON.parse(fetch_cities(params['country_code']))['Cities']
end
respond_to do |format|
format.json { render :json => response, :status => 200 }
end
end
# Validate address for aramex shipping
def validate_address_with_aramex
begin
zones = Spree::ShippingMethod.where(['LOWER(admin_name) like ?', '%aramex%']).map(&:zones).flatten
final_response = {}
if zones.map(&:countries).flatten.map(&:iso).include?(params[:b_country])
final_response[:b_errors] = confirm_address_validity(params[:b_city], params[:b_zipcode], params[:b_country])
end
if zones.map(&:countries).flatten.map(&:iso).include?(params[:s_country]) && params[:use_bill_address] == "false"
final_response[:s_errors] = confirm_address_validity(params[:s_city], params[:s_zipcode], params[:s_country])
end
rescue
return true
end
respond_to do |format|
format.json { render :json => final_response, :status => 200 }
end
end
# Confirm address validity with Aramex address validatio API
def confirm_address_validity(city, zipcode, country)
response = JSON.parse(validate_address(city, zipcode, country))
if response['HasErrors'] == true
if response['SuggestedAddresses'].present?
response['Notifications'].map{|data| data['Message']}.join(', ') + ', Suggested city name is - ' + response['SuggestedAddresses'].map{|data| data['City']}.join(', ')
else
if response['Notifications'].first['Code'] == 'ERR06'
response['Notifications'].map{|data| data['Message']}.join(', ')
else
cities_response = JSON.parse(fetch_cities(country, city[0..2]))
cities_response['Notifications'].map{|data| data['Message']}.join(', ') + ', Suggested city name is - ' + cities_response['Cities'].join(' ,')
end
end
end
end
end
In my route file I mentioned:
get 'validate_address_with_aramex', to: 'aramex_address#validate_address_with_aramex'
get 'fetch_cities_from_aramex_address', to: 'aramex_address#fetch_cities_from_aramex_address'
I included the following JS call for the submitted Aramex Ajax validation in assets/javascripts/spree/frontend/checkout/address.js:
Spree.ready(function($) {
Spree.onAddress = function() {
var call_aramex = true;
$("#checkout_form_address").on('submit', function(e) {
if ($('#checkout_form_address').valid()) {
var s_country = $("#order_ship_address_attributes_country_id").find('option:selected').attr('iso_code');
var s_zipcode = $("#order_ship_address_attributes_zipcode").val();
var s_city = $("#order_ship_address_attributes_city").val();
var b_country = $("#order_bill_address_attributes_country_id").find('option:selected').attr('iso_code');
var b_zipcode = $("#order_bill_address_attributes_zipcode").val();
var b_city = $("#order_bill_address_attributes_city").val();
if (call_aramex == true && (typeof aramex_countries !== 'undefined') && (aramex_countries.includes(b_country) || aramex_countries.includes(s_country))) {
e.preventDefault();
var error_id = $('#errorExplanation').is(':visible') ? '#errorExplanation' : '#manual_error'
$(error_id).html("").hide()
$.blockUI({
message: '<img src="/assets/ajax-loader.gif" />'
});
$.ajax({
url: "/api/validate_address_with_aramex",
type: 'GET',
dataType: "json",
data: {
s_country: s_country,
s_zipcode: s_zipcode,
s_city: s_city,
b_country: b_country,
b_zipcode: b_zipcode,
b_city: b_city,
use_bill_address: ($("#order_use_billing").is(":checked"))
},
success: function(result) {
$.unblockUI()
if (result.b_errors || result.s_errors) {
if (result.b_errors) {
$(error_id).append('<div>Billing Address ' + result.b_errors + ' </div>')
}
if (result.s_errors) {
$(error_id).append('<div>Shipping Address ' + result.s_errors + ' </div>')
}
if ((result.b_errors && !result.s_errors) && ($("#order_use_billing").is(":unchecked"))) {
$(".js-summary-edit").trigger("click")
}
$(error_id).show();
$('html, body').animate({
scrollTop: '0px'
}, 300);
} else {
call_aramex = false;
$('#checkout_form_address').submit()
}
},
error: function(xhr, status, error) {
$(error_id).append('Oops Something Went Wrong but you can process order')
$(error_id).show();
$.unblockUI()
$('html, body').animate({
scrollTop: '0px'
}, 300);
$('#checkout_form_address').submit()
}
});
}
}
})
var getCountryId, order_use_billing, update_shipping_form_state;
if (($('#checkout_form_address')).is('*')) {
($('#checkout_form_address')).validate({
rules: {
"order[bill_address_attributes][city]": {
required: true,
maxlength: function(element) {
return maxCharLimit($("#order_bill_address_attributes_country_id").val(), 22)
}
},
"order[bill_address_attributes][firstname]": {
required: true,
maxlength: function(element) {
return maxCharLimit($("#order_bill_address_attributes_country_id").val(), 15)
}
},
"order[bill_address_attributes][lastname]": {
required: true,
maxlength: function(element) {
return maxCharLimit($("#order_bill_address_attributes_country_id").val(), 17)
}
},
"order[bill_address_attributes][address1]": {
required: true,
maxlength: function(element) {
return maxCharLimit($("#order_bill_address_attributes_country_id").val(), 32)
}
},
"order[bill_address_attributes][address2]": {
maxlength: function(element) {
return maxCharLimit($("#order_bill_address_attributes_country_id").val(), 32)
}
},
"order[bill_address_attributes][zipcode]": {
maxlength: function(element) {
return maxCharLimit($("#order_bill_address_attributes_country_id").val(), 10)
}
},
"order[ship_address_attributes][city]": {
required: true,
maxlength: function(element) {
return maxCharLimit($("#order_ship_address_attributes_country_id").val(), 22)
}
},
"order[ship_address_attributes][firstname]": {
required: true,
maxlength: function(element) {
return maxCharLimit($("#order_ship_address_attributes_country_id").val(), 15)
}
},
"order[ship_address_attributes][lastname]": {
required: true,
maxlength: function(element) {
return maxCharLimit($("#order_ship_address_attributes_country_id").val(), 17)
}
},
"order[ship_address_attributes][address1]": {
required: true,
maxlength: function(element) {
return maxCharLimit($("#order_ship_address_attributes_country_id").val(), 32)
}
},
"order[ship_address_attributes][address2]": {
maxlength: function(element) {
return maxCharLimit($("#order_ship_address_attributes_country_id").val(), 32)
}
},
"order[ship_address_attributes][zipcode]": {
maxlength: function(element) {
return maxCharLimit($("#order_ship_address_attributes_country_id").val(), 10)
}
}
}
});
getCountryId = function(region) {
return $('#' + region + 'country select').val();
};
isCountryUsOrCa = function(country_id) {
return ["38", "232"].includes(country_id)
}
maxCharLimit = function(country_id, limit) {
if (["38", "232"].includes(country_id)) {
return limit;
} else {
return 255;
}
};
Spree.updateState = function(region) {
var countryId;
var cityId
countryId = getCountryId(region);
if (countryId != null) {
if (region == 'b') {
cityId = '#order_bill_address_attributes_city'
countryInputId = "#order_bill_address_attributes_country_id"
} else {
cityId = '#order_ship_address_attributes_city'
countryInputId = "#order_ship_address_attributes_country_id"
}
fill_cities($(countryInputId).find('option:selected').attr('iso_code'), cityId)
if (Spree.Checkout[countryId] == null) {
return $.get(Spree.routes.states_search, {
country_id: countryId
}, function(data) {
Spree.Checkout[countryId] = {
states: data.states,
states_required: data.states_required
};
return Spree.fillStates(Spree.Checkout[countryId], region);
});
} else {
return Spree.fillStates(Spree.Checkout[countryId], region);
}
}
};
fill_cities = function(country_code, cityId) {
$.ajax({
url: "/api/fetch_cities_from_aramex_address",
type: 'GET',
dataType: "json",
data: {
country_code: country_code
},
success: function(data) {
$(cityId).autocomplete({
source: data,
});
},
error: function() {}
});
}
Spree.fillStates = function(data, region) {
var selected, stateInput, statePara, stateSelect, stateSpanRequired, states, statesRequired, statesWithBlank;
statesRequired = data.states_required;
states = data.states;
statePara = $('#' + region + 'state');
stateSelect = statePara.find('select');
stateInput = statePara.find('input');
stateSpanRequired = statePara.find('[id$="state-required"]');
if (states.length > 0) {
selected = parseInt(stateSelect.val());
stateSelect.html('');
statesWithBlank = [{
name: '',
id: ''
}].concat(states);
$.each(statesWithBlank, function(idx, state) {
var opt;
opt = ($(document.createElement('option'))).attr('value', state.id).html(state.name);
if (selected === state.id) {
opt.prop('selected', true);
}
return stateSelect.append(opt);
});
stateSelect.prop('disabled', false).show();
stateInput.hide().prop('disabled', true);
statePara.show();
stateSpanRequired.show();
if (statesRequired) {
stateSelect.addClass('required');
}
stateSelect.removeClass('hidden');
return stateInput.removeClass('required');
} else {
stateSelect.hide().prop('disabled', true);
stateInput.show();
if (statesRequired) {
stateSpanRequired.show();
stateInput.addClass('required');
} else {
stateInput.val('');
stateSpanRequired.hide();
stateInput.removeClass('required');
}
statePara.toggle(!!statesRequired);
stateInput.prop('disabled', !statesRequired);
stateInput.removeClass('hidden');
return stateSelect.removeClass('required');
}
};
($('#bcountry select')).change(function() {
$('label.error').hide()
if (isCountryUsOrCa($("#order_bill_address_attributes_country_id").val())) {
$('#checkout_form_address').valid();
}
return Spree.updateState('b');
});
($('#scountry select')).change(function() {
$('label.error').hide()
if (isCountryUsOrCa($("#order_bill_address_attributes_country_id").val())) {
$('#checkout_form_address').valid();
}
return Spree.updateState('s');
});
Spree.updateState('b');
order_use_billing = $('input#order_use_billing');
order_use_billing.change(function() {
return update_shipping_form_state(order_use_billing);
});
update_shipping_form_state = function(order_use_billing) {
if (order_use_billing.is(':checked')) {
($('#shipping .inner')).hide();
return ($('#shipping .inner input, #shipping .inner select')).prop('disabled', true);
} else {
($('#shipping .inner')).show();
($('#shipping .inner input, #shipping .inner select')).prop('disabled', false);
return Spree.updateState('s');
}
};
return update_shipping_form_state(order_use_billing);
}
};
return Spree.onAddress();
});
Why am I am facing the issue mentioned at the top?
maybe you can try this:
namespace :spree do
namespace :api do
resources :aramex_address, only: [] do
get :validate_address_with_aramex
get :fetch_cities_from_aramex_address
end
end
end
words of advice I think it's better if you rename the fetch_cities_from_aramex_address with show method, so it still follow rails convenience
well here is the issue of constant lookup. Your constant that is AramexAddressValidator is missing because of the way you wrote class Spree::Api::AramexAddressController < ApplicationController
So if your module AramexAddressValidator is inside some scope use that scope also while including this module
For Ex. if its inside spree/aramex_address_validator use
include Spree::AramexAddressValidator

Calling toastr makes the webpage jump to top of page

I'm seeking a solution for the toastr.js "error" that causes the webpage, if scrolled down, to jump up again when a new toastr is displayed
GitHub page containing the script
I've tried to change the top to auto, but that wasn't an accepted parameter, because nothing showed up then.
Isn't there any way to make it appear where the mouse is at the moment?
.toast-top-center {
top: 12px;
margin: 0 auto;
left: 43%;
}
this has the calling code:
<p><span style="font-family:'Roboto','One Open Sans', 'Helvetica Neue', Helvetica, sans-serif;color:rgb(253,253,255); font-size:16px ">
xxxxxxxxxxxxx
</span></p>
This is the function code:
<script type='text/javascript'> function playclip() {
toastr.options = {
"debug": false,
"positionClass": "toast-top-center",
"onclick": null,
"fadeIn": 800,
"fadeOut": 1000,
"timeOut": 5000,
"extendedTimeOut": 1000
}
toastr["error"]("This link is pointing to a page that hasn't been written yet,</ br> sorry for the inconvenience?"); } </script>
And this is the script itself:
/*
* Toastr
* Copyright 2012-2015
* Authors: John Papa, Hans Fjällemark, and Tim Ferrell.
* All Rights Reserved.
* Use, reproduction, distribution, and modification of this code is subject to the terms and
* conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
*
* ARIA Support: Greta Krafsig
*
* Project: https://github.com/CodeSeven/toastr
*/
/* global define */
(function (define) {
define(['jquery'], function ($) {
return (function () {
var $container;
var listener;
var toastId = 0;
var toastType = {
error: 'error',
info: 'info',
success: 'success',
warning: 'warning'
};
var toastr = {
clear: clear,
remove: remove,
error: error,
getContainer: getContainer,
info: info,
options: {},
subscribe: subscribe,
success: success,
version: '2.1.3',
warning: warning
};
var previousToast;
return toastr;
////////////////
function error(message, title, optionsOverride) {
return notify({
type: toastType.error,
iconClass: getOptions().iconClasses.error,
message: message,
optionsOverride: optionsOverride,
title: title
});
}
function getContainer(options, create) {
if (!options) { options = getOptions(); }
$container = $('#' + options.containerId);
if ($container.length) {
return $container;
}
if (create) {
$container = createContainer(options);
}
return $container;
}
function info(message, title, optionsOverride) {
return notify({
type: toastType.info,
iconClass: getOptions().iconClasses.info,
message: message,
optionsOverride: optionsOverride,
title: title
});
}
function subscribe(callback) {
listener = callback;
}
function success(message, title, optionsOverride) {
return notify({
type: toastType.success,
iconClass: getOptions().iconClasses.success,
message: message,
optionsOverride: optionsOverride,
title: title
});
}
function warning(message, title, optionsOverride) {
return notify({
type: toastType.warning,
iconClass: getOptions().iconClasses.warning,
message: message,
optionsOverride: optionsOverride,
title: title
});
}
function clear($toastElement, clearOptions) {
var options = getOptions();
if (!$container) { getContainer(options); }
if (!clearToast($toastElement, options, clearOptions)) {
clearContainer(options);
}
}
function remove($toastElement) {
var options = getOptions();
if (!$container) { getContainer(options); }
if ($toastElement && $(':focus', $toastElement).length === 0) {
removeToast($toastElement);
return;
}
if ($container.children().length) {
$container.remove();
}
}
// internal functions
function clearContainer (options) {
var toastsToClear = $container.children();
for (var i = toastsToClear.length - 1; i >= 0; i--) {
clearToast($(toastsToClear[i]), options);
}
}
function clearToast ($toastElement, options, clearOptions) {
var force = clearOptions && clearOptions.force ? clearOptions.force : false;
if ($toastElement && (force || $(':focus', $toastElement).length === 0)) {
$toastElement[options.hideMethod]({
duration: options.hideDuration,
easing: options.hideEasing,
complete: function () { removeToast($toastElement); }
});
return true;
}
return false;
}
function createContainer(options) {
$container = $('<div/>')
.attr('id', options.containerId)
.addClass(options.positionClass);
$container.appendTo($(options.target));
return $container;
}
function getDefaults() {
return {
tapToDismiss: true,
toastClass: 'toast',
containerId: 'toast-container',
debug: false,
showMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery
showDuration: 300,
showEasing: 'swing', //swing and linear are built into jQuery
onShown: undefined,
hideMethod: 'fadeOut',
hideDuration: 1000,
hideEasing: 'swing',
onHidden: undefined,
closeMethod: false,
closeDuration: false,
closeEasing: false,
closeOnHover: true,
extendedTimeOut: 1000,
iconClasses: {
error: 'toast-error',
info: 'toast-info',
success: 'toast-success',
warning: 'toast-warning'
},
iconClass: 'toast-info',
positionClass: 'toast-top-right',
timeOut: 5000, // Set timeOut and extendedTimeOut to 0 to make it sticky
titleClass: 'toast-title',
messageClass: 'toast-message',
escapeHtml: false,
target: 'body',
closeHtml: '<button type="button">×</button>',
closeClass: 'toast-close-button',
newestOnTop: true,
preventDuplicates: false,
progressBar: false,
progressClass: 'toast-progress',
rtl: false
};
}
function publish(args) {
if (!listener) { return; }
listener(args);
}
function notify(map) {
var options = getOptions();
var iconClass = map.iconClass || options.iconClass;
if (typeof (map.optionsOverride) !== 'undefined') {
options = $.extend(options, map.optionsOverride);
iconClass = map.optionsOverride.iconClass || iconClass;
}
if (shouldExit(options, map)) { return; }
toastId++;
$container = getContainer(options, true);
var intervalId = null;
var $toastElement = $('<div/>');
var $titleElement = $('<div/>');
var $messageElement = $('<div/>');
var $progressElement = $('<div/>');
var $closeElement = $(options.closeHtml);
var progressBar = {
intervalId: null,
hideEta: null,
maxHideTime: null
};
var response = {
toastId: toastId,
state: 'visible',
startTime: new Date(),
options: options,
map: map
};
personalizeToast();
displayToast();
handleEvents();
publish(response);
if (options.debug && console) {
console.log(response);
}
return $toastElement;
function escapeHtml(source) {
if (source == null) {
source = '';
}
return source
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
}
function personalizeToast() {
setIcon();
setTitle();
setMessage();
setCloseButton();
setProgressBar();
setRTL();
setSequence();
setAria();
}
function setAria() {
var ariaValue = '';
switch (map.iconClass) {
case 'toast-success':
case 'toast-info':
ariaValue = 'polite';
break;
default:
ariaValue = 'assertive';
}
$toastElement.attr('aria-live', ariaValue);
}
function handleEvents() {
if (options.closeOnHover) {
$toastElement.hover(stickAround, delayedHideToast);
}
if (!options.onclick && options.tapToDismiss) {
$toastElement.click(hideToast);
}
if (options.closeButton && $closeElement) {
$closeElement.click(function (event) {
if (event.stopPropagation) {
event.stopPropagation();
} else if (event.cancelBubble !== undefined && event.cancelBubble !== true) {
event.cancelBubble = true;
}
if (options.onCloseClick) {
options.onCloseClick(event);
}
hideToast(true);
});
}
if (options.onclick) {
$toastElement.click(function (event) {
options.onclick(event);
hideToast();
});
}
}
function displayToast() {
$toastElement.hide();
$toastElement[options.showMethod](
{duration: options.showDuration, easing: options.showEasing, complete: options.onShown}
);
if (options.timeOut > 0) {
intervalId = setTimeout(hideToast, options.timeOut);
progressBar.maxHideTime = parseFloat(options.timeOut);
progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;
if (options.progressBar) {
progressBar.intervalId = setInterval(updateProgress, 10);
}
}
}
function setIcon() {
if (map.iconClass) {
$toastElement.addClass(options.toastClass).addClass(iconClass);
}
}
function setSequence() {
if (options.newestOnTop) {
$container.prepend($toastElement);
} else {
$container.append($toastElement);
}
}
function setTitle() {
if (map.title) {
var suffix = map.title;
if (options.escapeHtml) {
suffix = escapeHtml(map.title);
}
$titleElement.append(suffix).addClass(options.titleClass);
$toastElement.append($titleElement);
}
}
function setMessage() {
if (map.message) {
var suffix = map.message;
if (options.escapeHtml) {
suffix = escapeHtml(map.message);
}
$messageElement.append(suffix).addClass(options.messageClass);
$toastElement.append($messageElement);
}
}
function setCloseButton() {
if (options.closeButton) {
$closeElement.addClass(options.closeClass).attr('role', 'button');
$toastElement.prepend($closeElement);
}
}
function setProgressBar() {
if (options.progressBar) {
$progressElement.addClass(options.progressClass);
$toastElement.prepend($progressElement);
}
}
function setRTL() {
if (options.rtl) {
$toastElement.addClass('rtl');
}
}
function shouldExit(options, map) {
if (options.preventDuplicates) {
if (map.message === previousToast) {
return true;
} else {
previousToast = map.message;
}
}
return false;
}
function hideToast(override) {
var method = override && options.closeMethod !== false ? options.closeMethod : options.hideMethod;
var duration = override && options.closeDuration !== false ?
options.closeDuration : options.hideDuration;
var easing = override && options.closeEasing !== false ? options.closeEasing : options.hideEasing;
if ($(':focus', $toastElement).length && !override) {
return;
}
clearTimeout(progressBar.intervalId);
return $toastElement[method]({
duration: duration,
easing: easing,
complete: function () {
removeToast($toastElement);
clearTimeout(intervalId);
if (options.onHidden && response.state !== 'hidden') {
options.onHidden();
}
response.state = 'hidden';
response.endTime = new Date();
publish(response);
}
});
}
function delayedHideToast() {
if (options.timeOut > 0 || options.extendedTimeOut > 0) {
intervalId = setTimeout(hideToast, options.extendedTimeOut);
progressBar.maxHideTime = parseFloat(options.extendedTimeOut);
progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;
}
}
function stickAround() {
clearTimeout(intervalId);
progressBar.hideEta = 0;
$toastElement.stop(true, true)[options.showMethod](
{duration: options.showDuration, easing: options.showEasing}
);
}
function updateProgress() {
var percentage = ((progressBar.hideEta - (new Date().getTime())) / progressBar.maxHideTime) * 100;
$progressElement.width(percentage + '%');
}
}
function getOptions() {
return $.extend({}, getDefaults(), toastr.options);
}
function removeToast($toastElement) {
if (!$container) { $container = getContainer(); }
if ($toastElement.is(':visible')) {
return;
}
$toastElement.remove();
$toastElement = null;
if ($container.children().length === 0) {
$container.remove();
previousToast = undefined;
}
}
})();
});
}(typeof define === 'function' && define.amd ? define : function (deps, factory) {
if (typeof module !== 'undefined' && module.exports) { //Node
module.exports = factory(require('jquery'));
} else {
window.toastr = factory(window.jQuery);
}
}));
Change your code to be like this:
<a href="#" style="color: rgb(255,0,0,0)" onclick="playclip(); return false;" >xxxxxxxxxxxxx </a>
However, I would reconsider using this type of javascript invokation. Take a look at this "javascript:void(0);" vs "return false" vs "preventDefault()"

Vuejs + typeahead this - undefined

I am trying to do a form with autocomplete. When a user type a part of a name typeahead suggests people that are in our database. If the user selects one of the suggestion I want to the full form to be filled from the autosuggestion.
Everything works but all my attempts to assign to the data object the value from the suggestion. When I log the this.newReviewer I get this is undefined... here is my code:
var Vue = require('vue')
var validator = require('vue-validator')
var resource = require('vue-resource')
Vue.use(validator)
Vue.use(resource)
var token = $('#token').attr('value');
Vue.http.headers.common['X-CSRF-TOKEN'] = token;
new Vue({
el:'#invite',
data: {
newReviewer: {
title:'',
last_name:'',
first_name:'',
email:'',
ers_id:'null'
},
reviewers: {},
quantity: {},
submitted: false,
},
ready: function(){
this.fetchInvitedReviewers();
console.log(this.newReviewer);
var ersContacts = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: 'api/search/%QUERY',
wildcard: '%QUERY'
}
});
$('#last_name')
.typeahead({
minLength: 2,
highlight: true,
hint: true
},
{
displayKey: 'last_name',
templates: {
suggestion: function(ersContacts) {
return (
'<div>' +
'<h3>'
+ ersContacts.title + ' '
+ ersContacts.first_name + ' '
+ ersContacts.last_name
+ '</h3>'
+ '<p class="uk-text-muted">'
+ ersContacts.city + ' '
+ ersContacts.country
+ '</p>' +
'</div>'
)
}
},
source: ersContacts
})
.on('typeahead:select', function(e, suggestion){
console.log(this.newReviewer);
this.newReviewer.last_name.push(suggestion.last_name);
this.newReviewer.email.push(suggestion.email);
})
.bind(this);
},
computed:{
//errors: function() {
// for(var key in this.newReviewer) {
// if (! this.newReviewer[key]) return true;
// }
// return false;
//}
},
methods: {
fetchInvitedReviewers: function() {
this.$http.get('api', function(response) {
this.$set('reviewers', response.reviewers);
this.$set('quantity', response.quantity);
});
},
onSubmitForm: function(e){
e.preventDefault();
var reviewer = this.newReviewer;
//add new reviewer to reviewers array
this.reviewers.push(reviewer);
//reset input values
this.newReviewer = {title:'', last_name: '', first_name: '', email:'', ers_id:''}
//substract one to the quantity
this.quantity -= 1 ;
//sent post ajax request
this.$http.post('api/store', reviewer)
//show success and count how many left
if(this.quantity <= 0) {
this.submitted = true;
}
}
},
validator: {
validates: {
email: function (val) {
return /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(val)
}
}
}
});
found...
Sorry guys. this
})
.bind(this);
should have been
}
.bind(this));

How to get Email.send to send emails in the future (7 days, 14 days from now, etc)

I need to send email reminders to people in the future. I have implemented MomentJS and I can get dates I'd need my email to send, I just couldn't find anything in meteor docs for Email.send(options) to have anything there. Is there a different package you can recommend?
Here is some of my code as per #richsilv 's advice
createTransfer.js (client)
Template.createTransfer.events({
'submit form': function (event, template) {
event.preventDefault();
Transfers.insert(transfer, function (error, id) {
if (error) {
showError(error);
} else {
Session.set('files');
showAlert('Transfers sent!');
transfer._id = id;
Meteor.call('sendEmail', transfer);
scheduleEmail(transfer); // send reminder email
Router.go('viewTransfer', {_id: id});
}
});
// scheduleEmail(transfer);
console.log(transfer);
function scheduleEmail(transfer) {
if (transfer.invoice.due == "7 Days"){
console.log('its due in 7 days');
if (moment(transfer.date).add(7, 'days').calendar() == moment(new Date()).format("MM/DD/YYYY")) {
Meteor.call('sendMail',transfer);
}
} else if (transfer.invoice.due == "14 Days") {
if (moment(transfer.date).add(14, 'days').calendar() == moment(new Date()).format("MM/DD/YYYY")) {
Meteor.call('sendMail',transfer);
}
} else if (transfer.invoice.due == "30 Days") {
if (moment(transfer.date).add(30, 'days').calendar() == moment(new Date()).format("MM/DD/YYYY")) {
Meteor.call('sendMail',transfer);
}
} else if (transfer.invoice.due == "90 Days") {
if (moment(transfer.date).add(90, 'days').calendar() == moment(new Date()).format("MM/DD/YYYY")) {
Meteor.call('sendMail',transfer);
}
} else {
console.log('need to initiate cron!');
var thisId = FutureEmails.insert(transfer);
console.log('inserted into db');
Meteor.call('addCronMail',thisId, transfer);
}
}
methods.js (lib)
Meteor.methods({
sendMail: function(transfer) {
check([transfer.senderEmail,
transfer.recipientEmail,
transfer.message,
// transfer.invoice.total
], [String]);
// Let other method calls from the same client start running,
// without waiting for the email sending to complete.
this.unblock();
transfer.url = Meteor.absoluteUrl() +'transfer/' + transfer._id;
var template = 'invoice-due';
Email.send({
to: transfer.recipientEmail,
bcc: transfer.senderEmail,
from: transfer.senderEmail,
subject: transfer.senderEmail + ' sent you files!',
html: Handlebars.templates[template](transfer)
});
},
addCronMail: function(id, transfer) {
SyncedCron.add({
name: id,
schedule: function(parser) {
return parser.recur().on(transfer.date).fullDate();
},
job: function() {
sendMail(transfer);
FutureEmails.remove(id);
SyncedCron.remove(id);
return id;
}
});
}
});
cron.js (server)
Meteor.startup(function() {
FutureEmails.find().forEach(function(mail) {
if (moment(mail.date).format("MMM Do YY") == moment(new Date()).format("MMM Do YY")) {
sendMail(mail)
} else {
addCronMail(mail._id, mail);
}
});
SyncedCron.start();
});
As requested, although note that this is not tested, so you might have to play around with it.
$ meteor add percolatestudio:synced-cron
Then something like this on the server:
FutureEmails = new Meteor.Collection('future_emails'); // server-side only
// "details" should be an object containing a date, plus required e-mail details (recipient, content, etc.)
function sendMail(details) {
Email.send({
from: details.from,
to: details.to,
etc....
});
}
function addCronMail(id, details) {
SyncedCron.add({
name: id,
schedule: function(parser) {
return parser.recur().on(details.date).fullDate();
},
job: function() {
sendMail(details);
FutureEmails.remove(id);
SyncedCron.remove(id);
return id;
}
});
}
function scheduleEmail(details) {
if (details.date < new Date()) {
sendMail(details);
} else {
var thisId = FutureEmails.insert(details);
addCronMail(thisId, details);
}
}
Meteor.startup(function() {
FutureEmails.find().forEach(function(mail) {
if (mail.date < new Date()) {
sendMail(mail)
} else {
addCronMail(mail._id, mail);
}
});
SyncedCron.start();
});
Then just call scheduleEmail(details) whenever you want to schedule a new mail.
Hope that's helpful!

Categories

Resources