No announcement yet.

Mini Basket Slide Out Right

  • Filter
  • Time
  • Show
Clear All
new posts

  • Mini Basket Slide Out Right

    I'm trying to change the functionality of the Mini Basket and have it slide out from the right using the built in functions linked to the css classes .mobile-menu, .mobile-menu-right, and toggle-slide-right.

    I'm testing this on some custom CTGY and PROD page templates that can only be accessed by being assigned to a certain availability group so I do not break the live site.

    They are basically copies of the regular page templates.

    I copied the global header and mini basket code into the page templates and used some miva script to call in copies of the css and scripts so I can tweak everything while not screwing up the live site.

    Here is the code for the mini basket and part of the code that I used for the header.

    <!--[if lt IE 9]> <p class="message closable message-info browsehappy align-center"><a href="#" class="close">&times;</a>You are using an <strong>outdated</strong> browser.<br />Please <a href="" target="_blank" rel="nofollow">upgrade your browser</a> to improve your experience.</p> <![endif]-->
    <nav class="mobile-menu mobile-menu-left">
        <div class="row mobile-navigation-header bg-charcoal white">SHOP</div>
        <div id="js-mobile-navigation" class="mobile-navigation"></div>
    <div id="js-mini-basket-container" class="column whole small-half large-one-third mini-basket-container mobile-menu mobile-menu-right">
        <div class="row mini-basket-content" data-itemcount="&mvt:global_minibasket:basket_count;" data-subtotal="&mvt:global_minibasket:formatted_total;">
            <span class="column whole normal h3 np"><span class="inline-block">Shopping Cart</span></span>
            <mvt:if expr="l.settings:global_minibasket:empty">
                <div class="breaker clear"></div>
                <span class="column whole h5 align-center">Your cart is currently empty.</span>
                <div class="column whole mini-basket-table-wrap custom-scrolling">
                    <mvt:foreach iterator="item" array="global_minibasket:items">
                        <div class="row mini-basket-row">
                            <div class="column hide medium-show medium-one-fifth">
                                <mvt:if expr="NOT ISNULL l.settings:item:imagetypes:main">
                                    <img src="&mvte:item:imagetypes:main;" alt="&mvt:item:name;" title="&mvt:item:name;" />
                            <div class="column three-fourths medium-three-fifths small">
                                <a href="https://&mvt:global:domain:name;/&mvta:item:code;.html" title="&mvt:item:name;">&mvt:item:name;</a>
                                <mvt:if expr="l.settings:item:upsold">
                                    &nbsp;(Special Offer)
                                <br />
                                <mvt:foreach iterator="option" array="item:options">
                                    <mvt:if expr="l.settings:option:option_id">
                                        &mvt:option:attr_code;: <strong>&mvt:option:opt_code;</strong>
                                    <mvt:elseif expr="NOT ISNULL l.settings:option:data">
                                        &mvt:option:attr_code;: <strong>&mvt:option:data;</strong>
                                    <mvt:elseif expr="NOT ISNULL l.settings:option:data_long">
                                        &mvt:option:attr_code;: <strong>&mvt:option:data_long;</strong>
                                    <br />
                                <mvt:if expr="l.settings:item:subterm_id">
                                    Subscription: &mvte:item:productsubscriptionterm:descrip;<br />
                                Qty: &mvte:item:quantity;
                            <div class="column one-fourth medium-one-fifth align-right small np">
                                <strong>&mvt:item:formatted_subtotal;</strong><br />
                                <mvt:foreach iterator="option" array="item:options">
                                    <mvt:if expr="l.settings:option:subtotal_base_price OR l.settings:option:subtotal">
                                        &mvt:option:formatted_subtotal;<br />
                                        &nbsp;<br />
                <div class="breaker clear"></div>
                <h5 class="column whole align-right normal np">Estimated Total: <strong>&mvt:global_minibasket:formatted_total;</strong></h5>
        <mvt:if expr="NOT l.settings:global_minibasket:empty">
            <div class="row">
                <div class="column whole big np"><a href="&mvte:urls:BASK:auto;" title="View Cart and Checkout" class="button button-block button-medium button-square bg-sky charcoal">Review Cart & Checkout</a></div>
        <div class="row">
            <div class="column whole button button-square align-center bg-transparent" data-rt-icon="&#xf102;"></div>
    <!-- end mobile-navigation -->
    <div id="js-site-overlay" class="site-overlay"></div>
    <!-- end site-overlay -->
    <div id="js-site-wrapper" class="site-wrapper">
        <header id="header" class="header clearfix">
            <div class="pre-header clearfix bg-charcoal">
                <nav class="row wrap">
                    <ul class="align-center">
                        <li class="pre-header--promo"><mvt:item name="readytheme" param="banner( 'wholesale-promo-message' )" /><a class="plt1" href="tel:+16303931111"><span data-rt-icon="&#xf095;"></span> &mvt:global:store:phone;</a></li>
            <!-- end pre-header -->
            <div id="js-main-header" class="row wrap main-header vertical-align-parent">
                <ul class="medium-all-hidden no-list mobile-main-header">
                    <li class="column one-sixth x-small-one-fourth toggle-slide-left mobile-menu-button print-hide"><span data-rt-icon="&#xf0c9;"></span></li>
                    <li class="column two-thirds x-small-half">
                        <a href="https://&mvt:global:domain:name;/wholesale.html" title="&mvt:global:store:name;" class="align-center">
                            <mvt:if expr="l.settings:readytheme:logo_type EQ 'text'">
                                <span class="h1 show uppercase masthead--name">&mvt:readytheme:logo_name;</span>
                                <span class="h3 show italic nm masthead--tagline">&mvt:readytheme:logo_tagline;</span>
                            <mvt:elseif expr="l.settings:readytheme:logo_type EQ 'image'">
                                <img src="&mvte:readytheme:logo_image;" alt="&mvt:readytheme:logo_alt;" title="&mvt:readytheme:logo_alt;" />
                    <li class="column one-sixth x-small-one-fourth nlp mobile-basket-button toggle-slide-right print-hide"><span data-rt-icon="&#xf07a;" class="bg-sky white"><span class="notification bg-red white basket-count">&mvte:global_minibasket:basket_count;</span></span></li>
    I got it working properly on the CTGY page template but the PROD template is proving a bit more difficult and I believe the problem lies in the Ajax add to cart function.

    This was as far as I got with the scripts code but I kept getting the error in the console that the attribute for data-itemcount was undefined. I marked that snippet with a red X

            // ---- AJAX Add To Cart ---- //
            function addToCart () {
                $('#js-add-to-cart').on('click', function (e) {
                    var purchaseForm = $('#js-purchase-product');
                    // Check the form is not currently submitting
                    if ('formstatus') !== 'submitting') {
                        // Set up variables
                        var form = purchaseForm,
                            formData = form.serialize(),
                            randomNo = Math.ceil(Math.random() * 1000000), // IE Hack: Creating random number to refresh ajax call
                            formUrl = form.attr('action'),
                            formMethod = form.attr('method'),
                            responseMessage = $('#js-purchase-message'),
                            miniBasket = $('#js-mini-basket-container'),
                            processingImage = $('#js-processing-purchase'),
                            purchaseButton = $(this),
                            purchaseButtonText = purchaseButton.val();
                        if (/\?/.test(formUrl)) {
                            formUrl = formUrl + '&v=' + randomNo;
                        else {
                            formUrl = formUrl + '?v=' + randomNo;
                        // Add status data to form
              'formstatus', 'submitting');
                        // Show processing message
                        // Send data to server for validation
                            url: formUrl,
                            type: formMethod,
                            data: formData,
                            success: function(data, textStatus, jqXHR) {
                                if ("js-BASK"/i) != -1) {
                                    $('html, body').animate({scrollTop: '0px'}, 250);
                                    var responseMiniBasket = $(data).find('#js-mini-basket-container'),
                                        miniBasketCount = responseMiniBasket.contents()[1].getAttribute('data-itemcount'),X
                                        miniBasketSubtotal = ' ' + responseMiniBasket.contents()[1].getAttribute('data-subtotal'),
                                        miniBasketLinkCount = $('#js-mini-basket-count, #js-mobile-basket-button .notification'),
                                        miniBasketLinkSubtotal = $('#js-mini-basket-subtotal');
                                    miniBasketLinkCount.text(miniBasketCount); // Update basket quantity (display only)
                                    miniBasketLinkSubtotal.text(miniBasketSubtotal); // Update basket subtotal (display only)
                                    $('html, body').addClass('mobile-menu-active mobile-menu-right-open');
                                    setTimeout(function () {
                                        $('html, body').removeClass('mobile-menu-active mobile-menu-right-open');
                                        if ( $( "#family-tree" ).length ) {
                                                var url = "/family-tree-hearts-discs.html";
                                        if ( $( "#wholesale-family-tree" ).length ) {
                                                var url = "/wholesale-family-tree-hearts-discs.html";
                                    }, 3000);

    Here's the mobile navigation and mini basket functions in the plugins file just for reference in case there are conflicting functions.

    // ---- Mobile Navigation Functions ---- //
        (function(f){if(Array.prototype.forEach){var b=document.body;f=document.querySelector("#js-site-overlay");var g=document.querySelectorAll(".toggle-slide-top"),h=document.querySelectorAll(".toggle-slide-right"),a=document.querySelectorAll(".toggle-slide-bottom"),c=document.querySelectorAll(".toggle-slide-left");document.querySelector(".mobile-menu-top");document.querySelector(".mobile-menu-right");document.querySelector(".mobile-menu-bottom");document.querySelector(".mobile-menu-left");var d;[], c){a.addEventListener("click",function(e){e.stopPropagation();e.preventDefault();e.stopImmediatePropagation();b.className+=" mobile-menu-active mobile-menu-top-open";d="mobile-menu-active mobile-menu-top-open"})});[],c){a.addEventListener("click",function(e){e.stopPropagation();e.preventDefault();e.stopImmediatePropagation();b.className+=" mobile-menu-active mobile-menu-right-open";d="mobile-menu-active mobile-menu-right-open"})});[], c){a.addEventListener("click",function(a){a.stopPropagation();a.preventDefault();a.stopImmediatePropagation();b.className+=" mobile-menu-active mobile-menu-bottom-open";d="mobile-menu-active mobile-menu-bottom-open"})});[],c){a.addEventListener("click",function(a){a.stopPropagation();a.preventDefault();a.stopImmediatePropagation();b.className+=" mobile-menu-active mobile-menu-left-open";d="mobile-menu-active mobile-menu-left-open"})});f.addEventListener("click",function(a){a.stopPropagation(); a.preventDefault();a.stopImmediatePropagation();b.className=b.className.replace(" "+d,"").replace(d,"");d=""});[]".close-mobile-menu")).forEach(function(a,c){a.addEventListener("click",function(a){a.stopPropagation();a.preventDefault();a.stopImmediatePropagation();b.className=b.className.replace(" "+d,"").replace(d,"");d=""})})}})(window);
        function mobileNavigation(){function f(){959>=$(window).innerWidth()?0==$("#js-mobile-navigation ul").length&&(,$(b).append(h),$("#js-mobile-navigation ul li span").each(function(){if("0"!=$(this).next().length){$(this).addClass("parent");var a=$(this).children("a").text();$(this).parent("li").append('<span data-name="'+a+'" data-rt-icon="&#xf105;" class="next"></span>')}})):0==$("#js-navigation-bar ul").length&&(g.hide(),$("#js-mobile-navigation").find($(".clone").remove()),$("#js-navigation-bar").prepend(h.removeClass("hide")), $(".next").remove())}var b=$("#js-mobile-navigation"),g=$("#js-mobile-menu-button"),h=$("#js-navigation-set");$(window).on("load resize",function(){f()});b.on("click","",function(a){a.stopPropagation();a.preventDefault();a.stopImmediatePropagation();$(this).siblings("span").closest("ul").addClass("hide");$parent=$(this).text();$new=$(this).prev("ul").clone().addClass("clone").appendTo(b);a=$(this).attr("data-name");$('<li><span class="back"><a> Back</a></span></li>').prependTo($new); if($(".navigation-trail").length)c=$(this).parent("li").siblings(".navigation-trail").clone(),$(c).children("span").append(" / "+a),c.prependTo($new);else{var c=$('<li class="navigation-trail"><span>Home</span></li>').prependTo($new);$(c).children("span").append(" / "+a)}});b.on("click","span.back",function(a){a.stopPropagation();a.preventDefault();a.stopImmediatePropagation();$(this).closest("ul").prev("ul").removeClass("hide");breadcrumb=$("a.root").text();last=breadcrumb.substr(breadcrumb.lastIndexOf(" / ")+ 1);$old=$(this).closest("ul");$old.remove();$("a.root").html(function(a,b){return b.replace(last,"")})})}mobileNavigation=new mobileNavigation;
    // ---- Mini-Basket Functions ---- //
        $.fn.isOnScreen=function(){var a=$(window),b=a.scrollTop(),d=a.scrollLeft(),e,c=this.offset();e=d+a.width();a=b+a.height();c.right=c.left+this.outerWidth();;return!(e<c.left||d>c.right||a<||b>c.bottom)};
        function MiniBasket(){var a=$("#js-mini-basket, #js-mobile-basket-button, #js-mobile-footer-basket"),b=$("#js-mini-basket-container"),d=$("body");a&&b&&($(a).on("click",function(a){b.toggleClass("open");0!=d.scrollTop&&$("html, body").animate({scrollTop: '0px'}, 400);a.preventDefault()}),d.on("click","#js-continue-shopping",function(a){a.preventDefault();b.removeClass("open")}),d.on("click",function(){b.hasClass("open")&&b.isOnScreen()&&window.matchMedia&&b.removeClass("open")}),b.removeClass("open"))}var minibasket=new MiniBasket;
    I also tried removing the mini basket functions above which did not break anything on the CTGY page but it did not fix the issue with the ajax add to cart function on the PROD page.

    Thanks for any input or nudges in the right direction.
    Last edited by SidFeyDesigns; 04-30-19, 07:07 AM.

  • Since these are custom pages, is there more than one instance in the mini-basket code when you view source? If there is, that could be the cause of the error on the product page.
    Matt Zimmermann
    Director of UI/UX Standards and Theme Development
    / Miva, Inc.


    • Hmm I definitely did not look into that. I don't believe so but I should check to be sure.

      I will have to check again later this afternoon after we are done processing orders so I will get back to you on that.

      Just wanted to start a thread in case there was something obviously wrong in the code changes.

      Thanks Matt.


      • It was not being duplicated.

        What I did find interesting was if I moved the mini basket back to its original location, which is a div just after the Shopping cart/ mini basket link, the ajax add to cart will work.

        Unfortunately to set up the mobile-menu-right, the mini basket needs to be before this: <div id="js-site-overlay" class="site-overlay"></div>.

        So although the ajax add to cart problem gets solved, now the mobile menu right does not display properly.

        I'm thinking to get this to work I will need to tweak the scripts file a bit for the ajax add to cart.

        Maybe modify the targeting for this?: miniBasketCount = responseMiniBasket.contents()[1].getAttribute('data-itemcount')


        • The control of the mini-basket display should be controlled through CSS. You should be able to modify the top and right settings to get it to slide in from the right instead of from the top. The rest of the code would probably stay where it is by default.
          Matt Zimmermann
          Director of UI/UX Standards and Theme Development
          / Miva, Inc.


          • I have tried that and it does work but it doesn't include the site overlay functionality.

            I like the functionality of being able to close it by simply clicking/tapping outside of the mini basket or clicking the button to close it.

            Without the site overlay, you must click the button that closes it for it to actually close.

            Not the worst case scenario and if I can't figure it out with the mobile-menu-right / site overlay functionalities then I will most likely do it that way.

            Thanks for the input.


            • So after spending probably too much time trying to get the mobile-menu-right functionality to work properly with the ajax add to cart on the product page, I decided enough was enough and have altered the css to get it to slide out from the right and have a height of 100% of the screen/window and be fixed.

              I even was able to get a site overlay to work to help prevent accidentally clicking or tapping product links while trying to close the mini basket when tapping or clicking outside of the mini-basket-container. I was mistaken and didn't realize you could close the mini basket by clicking or tapping anywhere outside of the container.

              Still have a bit of tweaking to do with the css to make sure it looks how I want on all screen sizes but this route was much simpler for me.

              Should be able to get this finished and live on the whole site today. I will post a link in case anyone wants to check it out when its done.

              Thank you for that suggestion Matt.



              • Everything is dialed in and its working great! Check it out here:



                This website uses cookies to identify visitors, track visitors to our website, store login session information and to remember your user preferences. By continuing to use this site you agree to our use of cookies. Learn More.

                This website uses cookies. By continuing to use this site you agree to our use of cookies. Learn More.