Woocommerce "Add to cart" ajax - javascript

On the product category page, when someone clicks "Add to cart", woocommerce adds "View cart" below this button through Ajax. I found that the script which handle this is /assets/js/frontend/add-to-cart.js
Now, I want to add also "Procceed to checkout", so someone can go to checkout immediately.
This is the output of the script:
jQuery( function( $ ) {
// wc_add_to_cart_params is required to continue, ensure the object exists
if ( typeof wc_add_to_cart_params === 'undefined' )
return false;
// Ajax add to cart
$( document ).on( 'click', '.add_to_cart_button', function(e) {
// AJAX add to cart request
var $thisbutton = $( this );
if ( $thisbutton.is( '.product_type_simple' ) ) {
if ( ! $thisbutton.attr( 'data-product_id' ) )
return true;
$thisbutton.removeClass( 'added' );
$thisbutton.addClass( 'loading' );
var data = {
action: 'woocommerce_add_to_cart',
};
$.each( $thisbutton.data(), function( key, value ) {
data[key] = value;
});
// Trigger event
$( 'body' ).trigger( 'adding_to_cart', [ $thisbutton, data ] );
// Ajax action
$.post( wc_add_to_cart_params.ajax_url, data, function( response ) {
if ( ! response )
return;
var this_page = window.location.toString();
this_page = this_page.replace( 'add-to-cart', 'added-to-cart' );
if ( response.error && response.product_url ) {
window.location = response.product_url;
return;
}
// Redirect to cart option
if ( wc_add_to_cart_params.cart_redirect_after_add === 'yes' ) {
window.location = wc_add_to_cart_params.cart_url;
return;
} else {
$thisbutton.removeClass( 'loading' );
fragments = response.fragments;
cart_hash = response.cart_hash;
// Block fragments class
if ( fragments ) {
$.each( fragments, function( key, value ) {
$( key ).addClass( 'updating' );
});
}
// Block widgets and fragments
$( '.shop_table.cart, .updating, .cart_totals' ).fadeTo( '400', '0.6' ).block({
message: null,
overlayCSS: {
opacity: 0.6
}
});
// Changes button classes
$thisbutton.addClass( 'added' );
// View cart text
if ( ! wc_add_to_cart_params.is_cart && $thisbutton.parent().find( '.added_to_cart' ).size() === 0 ) {
$thisbutton.after( ' <a href="' + wc_add_to_cart_params.cart_url + '" class="added_to_cart wc-forward" title="' +
wc_add_to_cart_params.i18n_view_cart + '">' + wc_add_to_cart_params.i18n_view_cart + '</a>' );
}
// Replace fragments
if ( fragments ) {
$.each( fragments, function( key, value ) {
$( key ).replaceWith( value );
});
}
// Unblock
$( '.widget_shopping_cart, .updating' ).stop( true ).css( 'opacity', '1' ).unblock();
// Cart page elements
$( '.shop_table.cart' ).load( this_page + ' .shop_table.cart:eq(0) > *', function() {
$( '.shop_table.cart' ).stop( true ).css( 'opacity', '1' ).unblock();
$( 'body' ).trigger( 'cart_page_refreshed' );
});
$( '.cart_totals' ).load( this_page + ' .cart_totals:eq(0) > *', function() {
$( '.cart_totals' ).stop( true ).css( 'opacity', '1' ).unblock();
});
// Trigger event so themes can refresh other areas
$( 'body' ).trigger( 'added_to_cart', [ fragments, cart_hash, $thisbutton ] );
}
});
return false;
}
return true;
});
Is there anybody who has done something similar?

If you look here from the Woocommerce repo, you can see that add-to-cart.js is localized from that class.
Unfortunately, there isn't a filter to just add your own link. What you could try is copying add-to-cart.js to your theme and set the new src of the registered add-to-cart.js to your new local copy, by using this method.
From there you can alter the this conditional found in Woocommerce repo.
So, technically yes, you could could this, but there are caveats:
You would need to repeat this process for variation products
If translation is a concern, you need to address that as well
Any time the plugin updates, you now have to comb through these files for any differences that could break functionality or cause a security issue.

Related

JQuery click event fires on second click but not on first

I've google for this but I could no find a solution for my issue. I have some events on a js function (Immediate function invocation). Therefore the click event is not working well. It fires only on the second invocation.
The first three fields (To, Cc, and Cco) should expand when you type a long text. The click event should collapse the "To", "Cc" and "Cco" fields when you click on "Subject" field. It works, but only on the second time I click in subject.
Heres my js (IIF)
function initTextareaEvents(){
$('section textarea').on({
focusin:function( ev ) {
if($( this ).closest( '.info-box' ).length > 0){
$( this ).elastic();
}
},
keypress:function( ev ) {
var key = ev.which;
if(key == 13 || key == 32){
ev.preventDefault();
var str = $( this ).val().trim();
str += ', ';
$( this ).val( str );
}
},
click:function ( ev ) {
if($( this ).closest( '.info-box' ).length === 0){
$( '#to, #cc, #cco' ).css( 'height', 'auto' );
}
}
});
}
Here is Codepen
The first click is acting as "Focus Out" I think. try adding something like
focusout:function( ev ) {
if($( this ).closest( '.info-box' ).length > 0){
$( this ).elastic();
}
},
This seems to get you closer to the behavior you want.

after # email address write [duplicate]

I need help, I am stuck with trying to make the following case scenario work:
You have email input field, you type: foo#y - it should pop up autocomplete box, offering yahoo.com (for example).
If you take this suggestion, the end value should become: foo#yahoo.com
I have wrote this code (modified off another jquery UI sample):
$( "#tags" )
// don't navigate away from the field on tab when selecting an item
.bind( "keydown", function( event ) {
if ( event.keyCode === $.ui.keyCode.TAB &&
$( this ).data( "autocomplete" ).menu.active ) {
event.preventDefault();
}
})
.autocomplete({
minLength: 3,
source: function( request, response ) {
var mail_regex = /^([\w.]+)#([\w.]+)$/;
var match = mail_regex.exec(request.term);
if (match)
var matcher = new RegExp( "^" + match[2], "i" );
response( $.grep( availableTags, function( item ){
return matcher.test( item );
}) );
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function( event, ui ) {
var terms = split( this.value );
// remove the current input
terms.pop();
// add the selected item
terms.push( ui.item.value );
// add placeholder to get the comma-and-space at the end
terms.push( "" );
this.value = terms.join( ", " );
return false;
}
});
Full working interactive sample:
http://jsfiddle.net/rRF2s/3/
However, it REPLACES the foo# with just yahoo.com - I can not for the life of me figure out how to override this behaviour...
Any Javascript/jQuery masters - help please! how to accomplish this goal?
I tried doing: return match[1]+matcher.test( item ), but that does not work.
The select function is assigning the resultant value with this.value =. However it is replacing the input value completely rather than appending it with the drop down value.
Without a great deal of testing the following, simplified function seems to work as required:
select: function( event, ui ) {
this.value = this.value.substring(0, this.value.indexOf('#') + 1) + ui.item.value;
return false;
}
This is taking the first part of the already entered value, for example foo# for the input foo#ya and then adding on the value of the selected item from the drop down.
You may want to trigger the dropdown when someone enters the # symbol (seems more intuitive to me) and if so, this function may also need modifying to correctly extract the user entered value.
Here is the complete code:
$(function() {
var availableTags = [
"Yahoo.com",
"Gmail.com"
];
function extractLast( val ) {
if (val.indexOf("#")!=-1){
var tmp=val.split("#");
console.log(tmp[tmp.length-1]);
return tmp[tmp.length-1];
}
console.log("returning empty");
return "";
}
$( "#tags" )
// don't navigate away from the field on tab when selecting an item
.bind( "keydown", function( event ) {
if ( event.keyCode === $.ui.keyCode.TAB &&
$( this ).data( "autocomplete" ).menu.active ) {
event.preventDefault();
}
})
.autocomplete({
minLength: 1,
source: function( request, response ) {
var mail = extractLast(request.term);
if(mail.length<1){return;}
var matcher = new RegExp( "^" + mail, "i" );
response( $.grep( availableTags, function( item ){
return matcher.test( item );
}));
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function( event, ui ) {
var terms = this.value.split(", ");
// remove the current input
var ml=terms[terms.length-1].split("#")[0];
terms.pop();
// add the selected item
terms.push( ml+"#"+ui.item.value );
// add placeholder to get the comma-and-space at the end
terms.push( "" );
this.value = terms.join( ", " );
return false;
}
});
});

WooCommerce event not triggering when using Select2 instead of actual select

I've built a custom website using Wordpress and WooCommerce and have installed Select2 to generate custom selects which is working fine. The issue I am having is with some of the selects on the WooCommerce pages, specifically those that trigger an event on change.
The custom selects successfully change the option selected, but the issue arises with selects that are meant to trigger an event. For example, the colour variation dropdown on the product page or the 'Sort By' select on the store page.
I've looked through the WooCommerce JS files and discovered some WooCommerce specific events that are triggered when a selection is made using the actual select box but I'm not sure how to implement this when using Select2 instead.
Here is a copy of the WooCommerce JS in relation to the event I'm talking about (in this case the change to the select for product variations):
.on( 'change', '.variations select', function() {
$form.find( 'input[name="variation_id"], input.variation_id' ).val( '' ).change();
$form.find( '.wc-no-matching-variations' ).remove();
if ( $use_ajax ) {
if ( $xhr ) {
$xhr.abort();
}
var all_attributes_chosen = true;
var some_attributes_chosen = false;
var data = {};
$form.find( '.variations select' ).each( function() {
var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' );
if ( $( this ).val().length === 0 ) {
all_attributes_chosen = false;
} else {
some_attributes_chosen = true;
}
data[ attribute_name ] = $( this ).val();
});
if ( all_attributes_chosen ) {
// Get a matchihng variation via ajax
data.product_id = $product_id;
$xhr = $.ajax( {
url: wc_cart_fragments_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'get_variation' ),
type: 'POST',
data: data,
success: function( variation ) {
if ( variation ) {
$form.find( 'input[name="variation_id"], input.variation_id' )
.val( variation.variation_id )
.change();
$form.trigger( 'found_variation', [ variation ] );
} else {
$form.trigger( 'reset_data' );
$form.find( '.single_variation_wrap' ).after( '<p class="wc-no-matching-variations woocommerce-info">' + wc_add_to_cart_variation_params.i18n_no_matching_variations_text + '</p>' );
$form.find( '.wc-no-matching-variations' ).slideDown( 200 );
}
}
} );
} else {
$form.trigger( 'reset_data' );
}
if ( some_attributes_chosen ) {
if ( $reset_variations.css( 'visibility' ) === 'hidden' ) {
$reset_variations.css( 'visibility', 'visible' ).hide().fadeIn();
}
} else {
$reset_variations.css( 'visibility', 'hidden' );
}
} else {
$form.trigger( 'woocommerce_variation_select_change' );
$form.trigger( 'check_variations', [ '', false ] );
$( this ).blur();
}
// Custom event for when variation selection has been changed
$form.trigger( 'woocommerce_variation_has_changed' );
} )
And then my own attempt to utilise this event:
$('#pa_colour').select2();
$('#pa_colour').on('change', function(){
var $form = $(this).parents('form');
$form.trigger( 'woocommerce_variation_select_change' );
$form.trigger( 'woocommerce_variation_has_changed' );
});
Unfortunately the site isn't live yet so I can't provide a link but hopefully you get the idea.
If someone can help me here I'd be so appreciative, I'm not exactly sure how Wordpress hooks (if this is what this is) work and I may be just missing something obvious.
Thanks,
Kathryn
This isn't a solution exactly, but I ended up replacing the Select2 plugin with the Selectric plugin and that works perfectly. Oh well! Thanks guys. http://lcdsantos.github.io/jQuery-Selectric/
I came across the same issue and found a solution in the last comment in this thread Select2 not showing selected value
The comment by Matt inspired by Kevin suggested wrapping the select2 call in $(window).bind("load", function() {...}); which worked for me.
Kudos to those guys.

Jquery Mobile 1.4 swipe demo in Chrome with mobile device

My question concerns the swipe event on a mobile device (I'm using a Nexus 7) with Chrome. I am working off the Jquery Mobile 1.4.2 demo which can be found here:
http://demos.jquerymobile.com/1.4.2/swipe-page/
I'll ask my question and copy the sample javascript below. I can get everything to work, both on my laptop (using Chrome) and on my tablet (using Firefox), but the swipe works maybe one out of ten times in Chrome with my tablet. Any advice? Thanks!
// Pagecreate will fire for each of the pages in this demo
// but we only need to bind once so we use "one()"
$( document ).one( "pagecreate", ".demo-page", function() {
// Initialize the external persistent header and footer
$( "#header" ).toolbar({ theme: "b" });
$( "#footer" ).toolbar({ theme: "b" });
// Handler for navigating to the next page
function navnext( next ) {
$( ":mobile-pagecontainer" ).pagecontainer( "change", next + ".html", {
transition: "slide"
});
}
// Handler for navigating to the previous page
function navprev( prev ) {
$( ":mobile-pagecontainer" ).pagecontainer( "change", prev + ".html", {
transition: "slide",
reverse: true
});
}
// Navigate to the next page on swipeleft
$( document ).on( "swipeleft", ".ui-page", function( event ) {
// Get the filename of the next page. We stored that in the data-next
// attribute in the original markup.
var next = $( this ).jqmData( "next" );
// Check if there is a next page and
// swipes may also happen when the user highlights text, so ignore those.
// We're only interested in swipes on the page.
if ( next && ( event.target === $( this )[ 0 ] ) ) {
navnext( next );
}
});
// Navigate to the next page when the "next" button in the footer is clicked
$( document ).on( "click", ".next", function() {
var next = $( ".ui-page-active" ).jqmData( "next" );
// Check if there is a next page
if ( next ) {
navnext( next );
}
});
// The same for the navigating to the previous page
$( document ).on( "swiperight", ".ui-page", function( event ) {
var prev = $( this ).jqmData( "prev" );
if ( prev && ( event.target === $( this )[ 0 ] ) ) {
navprev( prev );
}
});
$( document ).on( "click", ".prev", function() {
var prev = $( ".ui-page-active" ).jqmData( "prev" );
if ( prev ) {
navprev( prev );
}
});
});
$( document ).on( "pageshow", ".demo-page", function() {
var thePage = $( this ),
title = thePage.jqmData( "title" ),
next = thePage.jqmData( "next" ),
prev = thePage.jqmData( "prev" );
// Point the "Trivia" button to the popup for the current page.
$( "#trivia-button" ).attr( "href", "#" + thePage.find( ".trivia" ).attr( "id" ) );
// We use the same header on each page
// so we have to update the title
$( "#header h1" ).text( title );
// Prefetch the next page
// We added data-dom-cache="true" to the page so it won't be deleted
// so there is no need to prefetch it
if ( next ) {
$( ":mobile-pagecontainer" ).pagecontainer( "load", next + ".html" );
}
// We disable the next or previous buttons in the footer
// if there is no next or previous page
// We use the same footer on each page
// so first we remove the disabled class if it is there
$( ".next.ui-state-disabled, .prev.ui-state-disabled" ).removeClass( "ui-state-disabled" );
if ( ! next ) {
$( ".next" ).addClass( "ui-state-disabled" );
}
if ( ! prev ) {
$( ".prev" ).addClass( "ui-state-disabled" );
}
});
I've done the same experiment and I've observed similar results with my tablet (Nexus 7 - Google Chrome).
You should not use heavy frameworks like jQueryMobile if you are going to create a web app or a mobile website because even if these tools make your life easier at the end the result, especially on Android devices, will be slow and sluggish.
In other words you should create your own .css and .js.
If you need to manipulate the DOM very often you should also look for alternatives to jQuery.
I suggest that you use Zepto.js.
In the end, I decided to use the jQuery touchSwipe plugin and write my own code, works fine in different browsers and across devices. Some of this may not make sense without the HTML, but essentially I determine the direction of the swipe based on the variable that is passed into the method. Then, by getting various attributes and class names, I am turning on and off the display of the various divs that have previously loaded the JSON into them from another method. The way I do that is through substrings, where the last digit of the id is a number. If anyone has any comments about how this code could be more efficient, I'd be happy to hear your thoughts. Cheers.
function swipeLiterary() {
$("#read").swipe({
swipe:function(event, direction, distance, duration, fingerCount) {
switch (direction) {
case 'left':
var thisPage = $('.display').attr('id');
var nextPageNum = parseInt(thisPage.substring(8)) + 1;
var nextPage = thisPage.substring(0,8) + nextPageNum;
if (nextPageNum > 9) {
break
}
$('#' + thisPage).removeClass('display').addClass('nodisplay');
$('#' + nextPage).removeClass('nodisplay').addClass('display');
console.log(nextPage);
break;
case 'right':
var thisPage = $('.display').attr('id');
var prevPageNum = parseInt(thisPage.substring(8)) - 1;
var prevPage = thisPage.substring(0,8) + prevPageNum;
if (prevPageNum < 0){
break;
}
$('#' + thisPage).removeClass('display').addClass('nodisplay');
$('#' + prevPage).removeClass('nodisplay').addClass('display');
console.log(prevPage);
break;
case 'up':
console.log('up');
break;
}
//$(this).text("You swiped " + direction );
//console.log(this);
}
});
}

Hover on dynamic link generated

I want to create a hover similar to the example here in the jQuery. But the link is dynamically generated so I'm really having a hard time figuring this out.
I tried this:
$(document).ready( function() {
$('a.g-tabs').on('hover', 'a', function() {
$( this ).append( $('<i class="icon-clear-remove" onClick="tabRemove();"></i>') );
},
function() {
$( this ).find( ".icon-clear-remove:last" ).remove();
});
});
But its not working. Seems like my selector is the problem. How can I select it properly?
UPDATE:
This JS is handles for the view to not refresh if the tab is created:
$(document).on('submit','#pop-form', function(e) {
// make an ajax request
$.post('../admin/FLT_add_tab.do',
$('#pop-form').serialize(),
function( data ) {
// if data from the database is empty string
if( $.trim( data ).length != 0 ) {
// hide popover
$('#popover').popover('hide');
//append new tab and new tab content
var id = $(".nav-tabs").children().length - 1;
$('#popover').closest('li').before('<li>' + data + '</li>');
$('.tab-content').append('<div class="tab-pane" id="tab_' + id + '"> <c:import url="flt-pis.html"></c:import> </div>');
} else {
// error handling later here
}
}
);
e.preventDefault();
});
Not this one is the HTML that handles the tabs if the user goes to this page in first hand:
<!-- Other tabs from the database -->
<c:forEach var="tabNames" items="${ allTabs }">
<li> ${ tabNames.key }</li>
</c:forEach>
<!-- Add new tab -->
<li>New <i class="icon-plus-sign"></i></li>
As requested the server side code:
#ResponseBody
#RequestMapping( value = "/admin/FLT_add_tab", method = RequestMethod.POST )
public String createNewTab( #RequestParam
String newTab, HttpServletRequest request )
{
HttpSession session = request.getSession();
String returnVal = Credentials.checkSession( session );
if( returnVal != null )
{
return returnVal;
}
String tabName = null;
try
{
DataSource dataSource = DatabaseCommunication.getInstance().getDataSource();
QuestionnaireDAO qDAO = new QuestionnaireDAO( dataSource );
if( qDAO.getTabName( 0, newTab ) == null )
{
qDAO.insertQtab( newTab );
tabName = newTab;
}
}
catch( Exception e )
{
// no logger yet
e.printStackTrace();
}
return tabName;
}
If it is dynamically created the you have to use the delegate
$(document).on('mouseenter', 'a.g-tabs', function() {
$( this ).append( $('<i class="icon-clear-remove" onClick="tabRemove();"></i>') );
});
$(document).on('mouseleave', 'a.g-tabs', function() {
$( this ).find( ".icon-clear-remove:last" ).remove();
});
try this code
$('a.g-tabs').on({
mouseenter: function() {
$( this ).append( $('<i class="icon-clear-remove" onClick="tabRemove();"></i>') );
},
mouseleave: function() {
$( this ).find( ".icon-clear-remove:last" ).remove();
}
}, "a");
this code from Is it possible to use jQuery .on and hover
use CSS.
.g-tabs a>.icon-clear-remove
{
display:none;
}
.g-tabs a:hover>.icon-clear-remove
{
display:inline-block;
}
E > F Matches any F element that is a child of an element E.
E:hover Matches E during user hovers E.
So, E:hover>F means that while user hovers E, apply rule to F.
Try it here http://jsfiddle.net/7bVTj/

Categories

Resources