PageSourceSearch

https://www.nutrisail.com/assets/js/nutrisail.js?v=1790481876

js nutrisail.com collected 2026-09-27 04:05:15 UTC 42,443 bytes, 1,732 lines download raw bytes

1
2/*
3 * Define console and console.log if not defined
4 */
5
6if (!window.console) window.console = {};
7if (!window.console.log) window.console.log = function () { };
8/*
9 * Events that require the window to be loaded first
10 */
11window.addEventListener("load", function(e) {
12    /*
13     * Wrap jquery event
14     */
15    (function($) {
16        /*
17         * Document ready functions
18         */
19        $(document).ready(function() {
20
21
22             // Init the mlMenu in the side bar
23             doMenuInit();
24
25             // Init the tooltip
26             doTooltipInit();
27
28             // Bind events regarding the page blocker
29             bindPageBlock();
30
31             // Bind shipping functions on order review page
32             bindShippingFunctions();
33
34             // Bind on click functions that use specific classes to trigger actions
35             bindGenericFunctions();
36
37        });
38        /*
39         * End document ready functions
40         */
41
42        $('#checkoutForm').submit(function(e) {
43            proceedToCheckout({ e: e });
44        });
45
46    })(jQuery);
47    /*
48     * End jquery functions
49     */
50});
51/*
52 * End events that require the window to be loaded first
53 */
54
55function ajax(data, callback) {
56    return new Promise(function(resolve, reject) {
57        getJson(data,callback);
58
59        resolve(true);
60    });
61}
62
63
64
65
66
67/******** DEBUG ********/
68//@header
69
70// Debug function to identify function usage for key functions
71function report() {
72    alert('nutrisail.js');
73    console.trace();
74}
75
76// Keeping for now to see if anything breaks
77/*
78function formatCurrency(amount) {
79    var i = parseFloat(amount);
80    if(isNaN(i)) { i = 0.00; }
81    var minus = '';
82    if(i < 0) { minus = '-'; }
83    i = Math.abs(i);
84    i = parseInt((i + .005) * 100);
85    i = i / 100;
86    s = new String(i);
87    if(s.indexOf('.') < 0) { s += '.00'; }
88    if(s.indexOf('.') == (s.length - 2)) { s += '0'; }
89    s = minus + s;
90    return '$' + s;
91}
92*/
93
94
95/******** DEBUG ********/
96
97
98/* START EVENTS */
99
100
101/******** Commonly Used Functions and callbacks ********/
102/*
103 * Standard replace content callback
104 * This function will place the content of the response into the content-block element
105 */
106function replaceContent(content, target) {
107    if (target === undefined) {
108        target = $('#content-block');
109    }
110
111    // convert to string if not already
112    if (typeof content == 'string') {
113        content = $.parseJSON(content);
114    }
115
116
117    target.html(content.content);
118}
119
120function appendContent(content, target) {
121    if (target === undefined)
122        target = $('#content-block');
123
124    if (typeof content == 'string')
125        content = $.parseJSON(content);
126
127    target.append(content.content);
128}
129
130
131
132
133
134// Function written to bridge the gap between existing ajaxLoader template
135// todo : refactor and remove
136function ajaxReplaceContent(content, target)
137{
138    target.replaceWith(content.content);
139
140    if (content.new_ajax == true)
141
142        for (var key in content)
143            $('#ajax-holder-' + key).append(content.key);
144}
145
146function loadMessages(content)
147{
148    $('#messages').html(content.messages);
149}
150
151function loadSpinner(el) {
152    $(el).html(getLoadingSpinner());
153}
154
155function displayModal(content) {
156    if ($('.modal-instance').length) {
157        displayStackModal(content);
158    } else {
159        $('#modal').html(content.content);
160        $('#modal').modal();
161    }
162}
163
164function displayStackModal(content) {
165    // convert to string if not already
166    if (typeof content == 'string') {
167        content = $.parseJSON(content);
168    }
169
170    if (content.content) {
171        $('.modal-container').last().html(content.content);
172        $('.modal-instance').find('.modal-trigger').click();
173    } else {
174        console.log('Request to display empty modal detected, but no content found. Please use Controller Ajax in the controller.');
175    }
176}
177
178function closeModal()
179{
180    $('#modal').modal('hide');
181    $('.modal-container').removeClass('modal-active');
182}
183
184function getURL(params)
185{
186    var replicatedSiteName = window.location.pathname.split('/')[1];
187    return window.location.origin + '/' + replicatedSiteName + '/' +  params.action.split('_').join('/');
188}
189
190/******** Commonly Used Functions and callbacks ********/
191
192/******** TREE FUNCTIONS ********/
193
194function viewUserDetails(elem, e)
195{
196    e.preventDefault();
197
198    blockPage();
199    getJSON({
200        url: elem.attr('data-path'),
201        data:{
202            user_id : elem.attr('user-id'),
203        }
204    }, function(results) {
205        displayStackModal($.parseJSON(results));
206        unblockPage();
207    });
208
209}
210
211
212function initTreeAction(elem, e) {
213    switch(elem.attr('data-control')) {
214        case 'bookmark':
215            addToTreeBookmarks(elem, e);
216            break;
217        case 'pin':
218            pinToTreeTop(elem, e);
219            break;
220        default:
221            alert('action not set!');
222    }
223}
224
225
226function pinToTreeTop(elem, e) {
227    e.preventDefault();
228
229    var top_level_user  = elem.closest('.tree-item').attr('user-name');
230
231    if (!top_level_user) {
232        var top_level_user  = elem.attr('user-name');
233    }
234
235    getJSON({
236        url: '/Bliteworks/Backoffice/Tree/TreeGrid',
237        data:{
238            top_level_user : top_level_user
239        }
240    }, function(results) {
241        replaceContent(
242            $.parseJSON(results)
243        );
244
245        getJson({
246            url     : '/Bliteworks/Backoffice/Tree/Buttons',
247            data    : {
248                user    : top_level_user
249            }
250        }, function(results) {
251            replaceContent(
252                results,
253                $('.binary-tree-buttons')
254            );
255        });
256    });
257}
258
259
260function addToTreeBookmarks(elem, e) {
261    e.preventDefault();
262
263    var user_id     = elem.closest('.tree-item').attr('user-id');
264    if (!user_id) {
265        user_id = elem.attr('user-id');
266    }
267
268    getJSON({
269        url: '/Bliteworks/Backoffice/Tree/AddToBookmarks',
270        data:{
271            user_id: user_id,
272        }
273    });
274}
275
276function toggleFavorite(elem, e) {
277    e.preventDefault();
278
279    if (elem.hasClass('in-favorite')) {
280        removeProductFromFavorites(elem, e);
281        elem.removeClass('in-favorite');
282    } else {
283        addProductToFavorites(elem, e);
284        elem.addClass('in-favorite');
285    }
286        
287}
288
289function addProductToFavorites(elem, e) {
290    e.preventDefault();
291
292    getJSON({
293        url: elem.attr('data-url'),
294        data: {
295            entity_id: elem.attr('data-id')
296        }
297    });
298
299
300}
301
302function removeProductFromFavorites(elem, e) {
303    e.preventDefault();
304
305    getJSON({
306        url: elem.attr('data-url-remove'),
307        data: {
308            entity_id: elem.attr('data-id')
309        }
310    });
311}
312
313function viewTreeFavorites(elem, e)
314{
315    e.preventDefault();
316    getJSON({
317        url: elem.attr('data-path'),
318        data: {
319            user_id: elem.attr('data-id')
320        }
321    }, function(results) {
322        launchSidebar($.parseJSON(results));
323    });
324}
325
326
327
328
329function initCharLimit() {
330
331    function checkChars() {
332        var elements = $('.char-limit');
333        $.each(elements, function(index,value){
334            var elem = elements.eq(index);
335            var parentBoxWidth = elem.parent()[0].clientWidth;
336            var text = elem.text();
337
338            elem.attr('data-original-string', text);
339            if (parentBoxWidth<250) {
340                if (!text.includes('..')) {
341                    text = text.substring(0,10) + '..';
342                    elem.text(text);
343                }
344            } else {
345                if (text.includes('..')) {
346                        elem.text(elem.attr('data-original-string'));
347                }
348            }
349        });
350    }
351
352    $( window ).resize(function() {
353        checkChars();
354    });
355    checkChars();
356
357}
358
359
360
361
362
363
364/* GET JSON */
365function getJSON(data, callback) {
366    return getJson(data, callback);
367}
368
369function getJson(data, callback) {
370    if (data.data instanceof FormData) {
371        $.ajax({
372          url: data.url,
373          data: data.data,
374          processData: false,
375          contentType: false,
376          type: 'POST',
377          success: function(results){
378            if (callback) {
379                callback(results);
380            } else {
381                processAjaxCallback(results);
382            }
383          }
384        });
385
386    } else {
387
388        $.post(data.url, data.data, function(results) {
389            if (callback) {
390                callback(results);
391            } else {
392                processAjaxCallback(results);
393            }
394        });
395
396    }
397
398
399
400}
401
402/* GET JSON */
403function processAjaxCallback(data) {
404    var data = $.parseJSON(data);
405
406    // redirect
407    if (data.redirect && data.redirect.url) {
408        window.location.assign(data.redirect.url);
409        return;
410    }
411
412    // callbacks
413    if (data.callback && data.callback.length > 0) {
414        data.callback.forEach(function(item){
415            $('body').append('<script>' + item.function + '</script>');
416        })
417    }
418
419    // reload
420    if (data.reload && data.reload.url) {
421        // update the content
422        loadContent(data.reload.url);
423    }
424
425    if (data.warning && data.warning.length > 0) {
426        data.warning.forEach(function(item) {
427            swal({
428                title   : item.header,
429                text    : item.message,
430                icon    : 'warning',
431                button  : 'Continue'
432            });
433        });
434    }
435
436
437    // display error
438    if (data.error && data.error.length > 0) {
439        data.error.forEach(function(item) {
440            swal({
441                title   : item.header,
442                text: item.message,
443                icon: "error",
444                button: "Continue",
445            });
446        });
447    }
448
449    // display success
450    if (data.success && data.success.length > 0) {
451        data.success.forEach(function(item) {
452            swal({
453                title   : item.header,
454                text: item.message,
455                icon: "success",
456                button: "Continue",
457            });
458        });
459    }
460}
461
462
463
464
465/* LOAD CONTENT */
466function loadContent(url)
467{
468    report();
469    // update address bar
470    history.pushState({}, {} , url.replace('/Ajax', '').toLowerCase());
471
472    getJSON({
473        url: url,
474    }, function(results) {
475        replaceContent(results, $('#view'));
476    });
477}
478
479
480/* GET JSON */
481function submitForm(elem, e, options) {
482    e.preventDefault();
483    var data = elem.serialize();
484
485    var postUrl = elem.attr('action');
486
487    elem.parent().prepend(getLoadingSpinner());
488    elem.hide();
489
490    getJson({
491        url: postUrl,
492        data: data,
493    }, function(results) {
494        elem.show();
495        getLoadingSpinner().remove();
496        processAjaxCallback(results);
497
498        // if the modal is in the DOM tree of this form, close it
499        closeModal();
500    });
501}
502
503function submitFormAndClear(elem, e) {
504    submitForm(elem, e);
505    elem.find('.form-control').val('');
506    $('html, body').animate({ scrollTop: 0 }, 'fast');
507}
508
509// New feature planned
510function viewNotificationsDetails(elem, e)
511{
512    e.preventDefault();
513    var notification_id = elem.closest('.notification-item').attr('data-id');
514    getJSON({
515        url: '/Bliteworks/Notifications/Details',
516        data: {
517            notification_id: notification_id
518        },
519    }, function(results){
520        launchModal(results);
521    });
522}
523
524/* FACEBOOK API */
525function getFacebookData(postUrl) {
526    FB.api('/me?fields=id,email,name', function(user) {
527
528        getJSON({
529            url: postUrl,
530            data: {
531                fb_action   : 'connect' ,
532                fb_data     : user
533            }
534        });
535    });
536}
537
538
539
540function loginWithFacebook(e) {
541    e.preventDefault();
542    FB.login(function(response) {
543        getFacebookData('/Bliteworks/User/Signup/Action/LoginWithFacebook');
544    }, { scope: 'public_profile,email' });
545}
546
547
548function launchBrandProWizard(el) {
549    getJson({
550        url : el.attr('data-url')
551    }, function(results) {
552        launchCodebaseModal(results);
553    });
554}
555
556function launchCodebaseModal(content) {
557    if (typeof content == 'string') {
558        content = $.parseJSON(content);
559    }
560
561    if (content.content) {
562        $('#modal-normal .modal-content').html(content.content);
563        $('#modal-normal').modal(true);
564    } else {
565        console.log('Request to display empty modal detected, but no content found. Please use Controller Ajax in the controller.');
566    }
567}
568
569function goUrl(el) {
570    var url = el.attr('data-url');
571
572    window.location.replace(url);
573}
574
575
576/*** Dealing with sticky menu when transparent ***/
577$.fn.isInViewport = function() {
578	var elementTop = $(this).offset().top;
579	var elementBottom = elementTop + $(this).outerHeight();
580	var viewportTop = $(window).scrollTop();
581	var viewportBottom = viewportTop + $(window).height();
582	return elementBottom > viewportTop && elementTop < viewportBottom;
583};
584
585$.fn.copyToClipboard = function() {
586    $(this).focus();
587    $(this).select()
588
589    document.execCommand('copy');
590
591    swal({
592        title   : 'Content copied',
593        text: $(this).val(),
594        icon: "success",
595        button: "Continue",
596    });
597};
598
599$.fn.loadContent = function() {
600    // Get ajax url
601    var url = $(this).attr('data-url');
602
603    // Get target to place content into
604    if ($(this).attr('data-target'))
605        var target = $($(this).attr('data-target'));
606    else
607        var target = $(this);
608
609    // Get target to show spinner in
610    if ($(this).attr('data-spinner-target'))
611        var spinnertarget = $($(this).attr('data-spinner-target'))
612    else
613        var spinnertarget = $(this);
614
615    // Option to not show spinner at all
616    if (!$(this).attr('data-spinner-dontshow'))
617        spinnertarget.html(getLoadingSpinner());
618
619    // Person json communication
620    getJson({
621        url : url
622    }, function(results) {
623        processAjaxCallback(results);
624        replaceContent(results, target);
625    });
626};
627
628$.fn.loadModal = function() {
629    var url = $(this).attr('data-url');
630
631    getJson({
632        url : url
633    }, function(results) {
634        processAjaxCallback(results);
635        launchModal(results);
636    });
637};
638
639$.fn.doAjax = function() {
640    var url = $(this).attr('data-url');
641
642    // Get target to place content into
643    if ($(this).attr('data-target'))
644        var target = $($(this).attr('data-target'));
645    else
646        var target = $(this);
647
648    // Get target to show spinner in
649    if ($(this).attr('data-spinner-target'))
650        var spinnertarget = $($(this).attr('data-spinner-target'))
651    else
652        var spinnertarget = $(this);
653
654    // Option to not show spinner at all
655    if (!$(this).attr('data-spinner-dontshow'))
656        spinnertarget.html(getLoadingSpinner());
657
658    // Person json communication
659    getJson({
660        url : url
661    }, function(results) {
662        processAjaxCallback(results);
663    });
664
665
666};
667
668
669$(window).on('resize scroll', function() {
670    if ($('body').hasClass('transparent-header') && $('.transparent-trigger').length) {
671        $('#page-header').toggleClass('transparent', $('.transparent-trigger').isInViewport());
672    }
673});
674/*** Dealing with sticky menu when transparent ***/
675
676function launchLoginSidebar()
677{
678    getJson({
679        url : '/Bliteworks/Home/Login'
680    }, function(results) {
681        processAjaxCallback(results);
682        launchSidebar(results);
683    });
684}
685
686function showFacebookForm(elem, e) {
687    
688    var status = $('.email-form').css('display');
689    
690    if (status == 'none') {
691        $('.facebook-form').slideDown();
692        $('.bf-information').slideUp();
693        elem.attr('data-status', 'open');
694        $('.facebook-btn').fadeOut();
695    } else {
696        $('.facebook-form').slideUp();
697        $('.bf-information').slideDown();
698        elem.attr('data-status', 'closed');
699        $('.facebook-btn').fadeIn();
700    }
701}
702
703
704function showEmailForm(elem, e) {
705    $('.email-form').slideToggle();
706    $('.bf-information').slideToggle();
707
708    var main = $('.email-signup-btn');
709    if (main.attr('data-toggle')=='true') {
710        $('.buttons .btn-facebook').fadeIn();
711        $('.go-back-btn').hide()
712
713        main.removeClass('hide');
714        main.attr('data-toggle', false);
715        main.attr('onclick', 'showEmailForm($(this), event)');
716        main.text('Signup with Email')
717    } else {
718        main.addClass('hide');
719        $('.bf-information').slideUp();
720        $('.buttons .btn-facebook').fadeOut();
721        $('.facebook-form').fadeOut();
722        $('.go-back-btn').fadeIn()
723        main.attr('data-toggle', true);
724        main.text('Continue')
725        main.attr('onclick','$(".brand-fan-form").submit()')	
726    }
727
728}
729
730
731function bindFormEvents()
732{
733    $('form.submitForm').on('submit.form', function(event) {
734        event.preventDefault();
735        submitForm($(this), event);
736    });
737}
738
739function unbindFormEvents()
740{
741    $('form.submitForm').off('submit.form');
742}
743
744function bindPasswordEvents() {
745
746    var strength = {
747        contains_number:    false,
748        contains_uppercase: false,
749        contains_min_max:   false,
750    };
751
752    $('.new-password').bind('input.password propertychange.password', function (e) {
753        // does password contain one number
754        strength.contains_number    = (/\d/.test($(this).val()) ? true : false );
755        strength.contains_uppercase = (($(this).val().match(/[a-z]/g) !== null && $(this).val().match(/[A-Z]/g) !== null) ? true : false );
756        strength.contains_min_max   = ($(this).val().length >= 8 && $(this).val().length <= 36 ? true : false );
757
758        if (strength.contains_number) {
759            $('.contains_number').addClass('text-success')
760                .find('i').attr('class', 'fa fa-check-square');
761        } else { 
762            $('.contains_number').removeClass('text-success')
763                .find('i').attr('class', 'fa fa-check-square-o');
764        }
765
766        if (strength.contains_uppercase) {
767            $('.contains_uppercase').addClass('text-success')
768                .find('i').attr('class', 'fa fa-check-square');
769        } else { 
770            $('.contains_uppercase').removeClass('text-success')
771                .find('i').attr('class', 'fa fa-check-square-o');
772        }
773
774        if (strength.contains_min_max) {
775            $('.contains_min_max').addClass('text-success')
776                .find('i').attr('class', 'fa fa-check-square');
777        } else { 
778            $('.contains_min_max').removeClass('text-success')
779                .find('i').attr('class', 'fa fa-check-square-o');
780        }
781    });
782
783    $('.new-password-confirm').bind('input.password propertychange.password', function (e) {
784        if ($(this).val() == $('.new-password').val()) {
785            $('.pw-match').addClass('text-success')
786                .find('i').attr('class', 'fa fa-check-square');
787        } else {
788            $('.pw-match').removeClass('text-success')
789                .find('i').attr('class', 'fa fa-check-square-o');
790        }
791    });
792}
793
794function unbindPasswordEvents() {
795    $('.new-password').off('input.password propertychange.password');
796
797    $('.new-password-confirm').off('input.password propertychange.password');
798}
799
800function checkPassword(elem, event) {
801    event.preventDefault();
802
803
804    if(elem.find('.password-strength li.check').not('.text-success').length) {
805        swal(
806            'Double check the password requirements'
807        );
808    } else {
809        submitForm(elem, event);
810    }
811}
812
813
814$(document).ajaxComplete(function() {
815    unbindFormEvents();
816    bindFormEvents();
817
818    unbindPasswordEvents();
819    bindPasswordEvents();
820
821    unbindSidebarEvents();
822    bindSidebarEvents();
823
824    unbindGenericFunctions();
825    bindGenericFunctions();
826    $('[data-toggle="tooltip"]').tooltip()
827
828});
829
830function bindSidebarEvents()
831{
832    $('#sidebar-close').on('click.sidebar', function(e) {
833        closeSidebar();
834    });
835}
836
837function unbindSidebarEvents()
838{
839    $('#sidebar-close').off('click.sidebar');
840}
841
842function closeSidebar()
843{
844    var sidebar = $('.main-sidebar');
845
846    sidebar.toggle(false)
847
848    $('body').removeClass('sidebar-open');
849}
850
851
852
853function goSidebar(elem, event) {
854    event.preventDefault();
855
856    var url = elem.attr('data-url');
857
858    getJson({
859        url : url
860    }, function(results) {
861        processAjaxCallback(results);
862        launchSidebar(results);
863    });
864}
865
866function blockPage() {
867    $('body').addClass('sidebar-open').addClass('show-loader');
868    $('body', window.parent.document).addClass('sidebar-open').addClass('show-loader');
869}
870
871function unblockPage() {
872    $('body').removeClass('sidebar-open').removeClass('show-loader');
873    $('body', window.parent.document).removeClass('sidebar-open').removeClass('show-loader');
874}
875
876
877bindFormEvents();
878bindPasswordEvents();
879bindSidebarEvents();
880
881
882
883// Moveable element
884// Make the DIV element draggable:
885
886if (document.getElementById('dragme'))
887    dragElement(document.getElementById("dragme"));
888
889function dragElement(elmnt) {
890  var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
891  if (document.getElementById(elmnt.id + "header")) {
892    // if present, the header is where you move the DIV from:
893    document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
894  } else {
895    // otherwise, move the DIV from anywhere inside the DIV:
896    elmnt.onmousedown = dragMouseDown;
897  }
898
899  function dragMouseDown(e) {
900    e = e || window.event;
901    e.preventDefault();
902    // get the mouse cursor position at startup:
903    pos3 = e.clientX;
904    pos4 = e.clientY;
905    document.onmouseup = closeDragElement;
906    // call a function whenever the cursor moves:
907    document.onmousemove = elementDrag;
908  }
909
910  function elementDrag(e) {
911    e = e || window.event;
912    e.preventDefault();
913    // calculate the new cursor position:
914    pos1 = pos3 - e.clientX;
915    pos2 = pos4 - e.clientY;
916    pos3 = e.clientX;
917    pos4 = e.clientY;
918    // set the element's new position:
919    elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
920    elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
921  }
922
923  function closeDragElement() {
924    // stop moving when mouse button is released:
925    document.onmouseup = null;
926    document.onmousemove = null;
927  }
928}
929
930/********* MLMENU ********/
931// @header
932/*
933 * Required menu initialization functions
934 */
935function doMenuInit() {
936    /* mlMenu declaration */
937    var menuEl = document.getElementById('ml-menu');
938
939    if (menuEl) {
940
941        mlmenu = new MLMenu(menuEl, {
942            // breadcrumbsCtrl : true, // show breadcrumbs
943            // initialBreadcrumb : 'all', // initial breadcrumb text
944            backCtrl : false, // show back button
945            // itemsDelayInterval : 60, // delay between each menu item sliding animation
946        });
947
948        // mobile menu toggle
949        var openMenuCtrl = document.querySelector('.action--open'),
950            closeMenuCtrl = document.querySelector('.action--close');
951
952        openMenuCtrl.addEventListener('click', openMenu);
953        closeMenuCtrl.addEventListener('click', closeMenu);
954
955        function openMenu() {
956            classie.add(menuEl, 'menu--open');
957        }
958
959        function closeMenu() {
960            classie.remove(menuEl, 'menu--open');
961        }
962    }
963}
964/********* MLMENU ********/
965
966
967
968
969
970/******** TOOLTIP ******/
971// @header
972function doTooltipInit() {
973    $('[data-toggle="tooltip"]').tooltip()
974}
975/******** TOOLTIP ******/
976
977
978
979
980
981
982
983
984
985/******** PAGE BLOCK ********/
986// @header
987function bindPageBlock() {
988
989    // If page is blocked and showing the sidebar, close the sidebar if the user attempts to get out of the block
990    $('.page-blocker').on('click', function(event) {
991        closeSidebar();
992    });
993
994}
995/******** PAGE BLOCK ********/
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015/******** Generic functions to bind to elements with specific classes ********/
1016// @header
1017function unbindGenericFunctions() {
1018    $('.swal-confirm').off('click.generic');
1019    $('.button-load').off('click.generic');
1020    $('form.ajax-submit button[type="submit"]').off('click.generic');
1021    $('.modal-load-ajax').off('click.generic');
1022}
1023function bindGenericFunctions() {
1024    $('.modal-load-ajax').on('click.generic', function() {
1025        blockPage();
1026
1027        var url = $(this).attr('data-url');
1028
1029        getJson({
1030            url : url
1031        }, function(results) {
1032            displayModal(results);
1033            unblockPage();
1034        });
1035    });
1036
1037    $('.swal-confirm').bind('click.generic', function(e) {
1038        var id  = $(this).attr('data-id');
1039        var url = $(this).attr('data-url');
1040
1041        Swal({
1042            title: 'Are you sure?',
1043            text: "You won't be able to revert this!",
1044            type: 'warning',
1045            showCancelButton: true,
1046            confirmButtonColor: '#3085d6',
1047            cancelButtonColor: '#d33',
1048            confirmButtonText: 'Contine'
1049        }).then(function(result) {
1050            if (result.value) {
1051                blockPage();
1052                getJson({
1053                    url     : url,
1054                    data    : {
1055                        id      : id
1056                    }
1057                }, function(results) {
1058                    unblockPage();
1059                    processAjaxCallback(results);
1060                });
1061            }
1062        })
1063    });
1064
1065
1066    /*
1067     * class        : button-load
1068     * data-group   : The group that will be used when searching for data to be posted
1069     * data-target  : Element to place returned content into, attempts to work for admin panel if this attribute does not exists
1070     *                Also works if no content is retunred
1071     * data-callback    : Will attemp to execute a callback and pass the results to the callback if this attribute exists
1072     * 
1073     *
1074     * Submits data in the same data-group to a url and replaces content
1075     */
1076    $('.button-load').bind('click.generic', function(e) {
1077        blockPage();
1078        var datagroup = $(this).attr('data-group');
1079        var data = $('input[data-group="' + datagroup + '"]*[name]');
1080        var ref = $(this);
1081
1082        if ($(this).is('[data-target]')) {
1083            var target = $($(this).attr('data-target'));
1084        } else {
1085            var target = $(this).closest('.portlet-body').find('.data-content');
1086        }
1087
1088
1089        getJson({
1090            url : $(this).attr('data-url'),
1091            data : data.serialize()
1092        }, function(results) {
1093
1094
1095            processAjaxCallback(results);
1096
1097
1098            if (ref.is('[data-callback]')) {
1099                var callback = ref.attr('data-callback');
1100                window[callback](results);
1101            }
1102            replaceContent(results, target);
1103            unblockPage();
1104        });
1105    });
1106
1107    /*
1108        * Ajax submit forms
1109        * Add class .ajax-submit to submit button
1110        * Define ajax-submit-url on parent form
1111        * Define callback function in ajax-submit-success on parent form
1112        */
1113    $('form.ajax-submit button[type="submit"]').on('click.generic', function(e) {
1114        e.preventDefault();
1115
1116        var ref = $(this);
1117
1118        $.ajax({
1119            url     : $(this).parents('form').attr('ajax-submit-url'),
1120            type    : 'post',
1121            data    : $(this).parents('form').serialize() + '&ajax=true'
1122        }).done(function(data) {
1123            processAjaxCallback(data);
1124            var d = $.parseJSON(data);
1125
1126            if (d.redirectnow)
1127                window.location.assign(d.redirectnow);
1128
1129            if (d.formKey)
1130                $('input[name="formKey"]').val(d.formKey);
1131
1132            if (d.error) {
1133                $('#message-wrapper').html(d.messages);
1134
1135                return;
1136            }
1137
1138
1139
1140
1141            func = ref.parents('form').attr('ajax-submit-success');
1142            eval(func);
1143        });
1144    });
1145    /*
1146        * End ajax submit function
1147        */
1148}
1149/******** Generic functions to bind to elements with specific classes ********/
1150
1151
1152
1153
1154
1155
1156/******** MODAL FUNCTIONS ********/
1157// @header
1158
1159// Launch a frontend modal with content
1160function launchModal(content) {
1161    displayStackModal(content);
1162}
1163
1164// Launch a full screen modal
1165// Under review
1166function launchFullScreenModal(content) {
1167    report();
1168
1169    var trigger = $('.modal-trigger');
1170    var container = trigger.closest('.modal-instance');
1171
1172    container.addClass('menu-fullscreen');
1173    trigger.click();
1174    displayStackModal(content);
1175}
1176
1177// Launch the sidebar 
1178function launchSidebar(content) {
1179    // convert to string if not already
1180    if (typeof content == 'string') {
1181        content = $.parseJSON(content);
1182    }
1183
1184    var sidebar = $('.main-sidebar');
1185    sidebar.toggle(true);
1186    sidebar.find('#sidebar-content').html(content.content);
1187
1188    $('body').addClass('sidebar-open');
1189}
1190
1191// Launch the top alert bar
1192function launchAlertBar(content) {
1193    var sidebar = $('.alertbar');
1194    sidebar.toggle()
1195    sidebar.find('.content').html(content.content);
1196}
1197
1198/******** MODAL FUNCTIONS ********/
1199
1200/******** PAGE BLOCKING AND LOADING FUNCTIONS ********/
1201// @header
1202// Room for improvement using theme element blocking
1203
1204
1205
1206
1207
1208// Show a loading spinner
1209// Use this for loading in the sidebar
1210function getLoadingSpinner() {
1211    if ($('.loading-spinner').length>0)
1212        return $('.loading-spinner');
1213
1214    return '<div class="loading-spinner clearfix"><i class="fa fa-spinner fa-spin"></i></div>';
1215}
1216
1217
1218
1219
1220/******** PAGE BLOCKING AND LOADING FUNCTIONS ********/
1221
1222/******** ECOMMERCE FUNCTIONS ********/
1223// @header
1224
1225
1226
1227// *** PRODUCT FUNCTIONS *** //
1228
1229// Add configurable product to cart
1230function addConfigurableToCart(elem, e) {
1231    e.preventDefault();
1232
1233    getJSON({
1234        url     : elem.attr('data-url'),
1235        data    : $('#addToCartForm').serialize()
1236    }, function(results) {
1237        content = $.parseJSON(results);
1238        updateCartElements(results);
1239        processAjaxCallback(results);
1240    });
1241}
1242
1243
1244
1245// Add simple product to cart
1246function addToCart(elem , e) {
1247    e.preventDefault();
1248
1249    if ($('#qty').length)
1250        quantity = $('#qty').val();
1251    else
1252        quantity = 1;
1253
1254    getJSON({
1255        url: elem.attr('data-url'),
1256        data: {
1257            product_id : elem.attr('data-id'),
1258            quantity    : quantity
1259        }
1260    }, function(results){
1261        content = $.parseJSON(results);
1262        updateCartElements(results);
1263        processAjaxCallback(results)
1264    });
1265}
1266
1267// Toggle product in autoship cart
1268function toggleAutoshipCart(elem, e) {
1269    e.preventDefault();
1270
1271    if (elem.hasClass('in-autoship')) {
1272        removeFromAutoshipCart(elem, e);
1273
1274        elem.removeClass('in-autoship');
1275    } else {
1276        addToAutoshipCart(elem, e);
1277
1278        elem.addClass('in-autoship');
1279    }
1280
1281    // Get the autoship cart and show in sidebar
1282
1283    getJson({
1284        url : elem.attr('data-autoship')
1285    }, function(results) {
1286        launchSidebar($.parseJSON(results));
1287    });
1288
1289}
1290
1291// Remove a product from autoship cart
1292function removeFromAutoshipCart(elem, e) {
1293    e.preventDefault();
1294
1295    getJson({
1296        url     : elem.attr('data-url-remove'),
1297        data    : {
1298            product_id  : elem.attr('data-id')
1299        }
1300    }, function(results) {
1301        processAjaxCallback(results);
1302    });
1303}
1304
1305// Add a product to autoship cart
1306function addToAutoshipCart(elem, e) {
1307    e.preventDefault();
1308
1309    getJSON({
1310        url     : elem.attr('data-url'),
1311        data    : {
1312            product_id : elem.attr('data-id')
1313        }
1314    }, function(results) {
1315        processAjaxCallback(results);
1316    });
1317
1318    getJson({
1319        url : elem.attr('data-autoship')
1320    }, function(results) {
1321        launchSidebar($.parseJSON(results));
1322    });
1323}
1324
1325// Remove product from cart
1326function removeProductFromCart(elem, e)
1327{
1328    e.preventDefault();
1329
1330    swal({
1331        title: 'Are you sure?',
1332        text: "You won't be able to revert this!",
1333        icon: 'warning',
1334        buttons: {
1335            cancel: {
1336            text: "Cancel",
1337            value: null,
1338            visible: false,
1339            className: "",
1340            closeModal: true,
1341            },
1342            confirm: {
1343            text: "Remove From Cart",
1344            value: true,
1345            visible: true,
1346            className: "",
1347            closeModal: true
1348            }
1349        }
1350    }).then(function(result) {
1351        if (result) {
1352
1353            getJSON({
1354                url: elem.attr('href')
1355            }, function(results){
1356                updateCartElements(results);
1357                processAjaxCallback(results);
1358            });
1359            elem.closest('.product').hide('fast');
1360
1361            swal(
1362            'Deleted!',
1363            'This product has been removed.',
1364            'success'
1365            )
1366
1367            //update the cart page
1368            getJson({
1369                url : getURL({
1370                    action  : 'Home_Checkout_OnePage_CartUpdate'
1371                })
1372            }, function (results) {
1373                replaceContent(results, $('#main-container'));
1374            });
1375        }
1376    });
1377}
1378
1379// *** PRODUCT FUNCTIONS *** //
1380
1381
1382
1383// *** CHECKOUT FLOW FUNCTIONS *** //
1384
1385// @review functionality in work here
1386function proceedToCheckout(data) {
1387
1388    var elem = $('#cart-checkout-form');
1389    if (data.e) {
1390        data.e.preventDefault();
1391    }
1392    if (data.redirect) {
1393        var append = '&redirect=' + data.redirect;
1394    } else {
1395        var append = '';
1396    }
1397    //var action = $('#checkoutForm input[name=action]').val();
1398    var url = elem.attr('action'); //+ '?action=' + action + append;
1399
1400
1401    window.location.href = url;
1402}
1403
1404
1405// Update the minicart
1406function updateCartElements(content) {
1407    getJson({
1408        url: getURL({
1409            action  : 'Home_Store_CartDropdown'
1410        })
1411    }, function(result) {
1412        replaceContent(result, $('#minicart'));
1413    });
1414
1415    content = $.parseJSON(content);
1416
1417    if (content.data.count==0) {
1418        window.location.assign(getURL({
1419            action:'Home_Store'
1420        }))
1421    }
1422}
1423
1424// Update product quantity from the cart page
1425function updateQuantity(elem, e)
1426{
1427    e.preventDefault();
1428    e.stopPropagation();
1429    var postUrl = getURL({
1430        action: 'Home_Checkout_Update_Product'
1431    }) + '/pid/' + elem.attr('name') + '/stocktag/'
1432        + elem.attr('data-stocktag')
1433        + '/qty/'
1434        + elem.val();
1435
1436    getJSON({
1437        url: postUrl
1438    }, function(results) {
1439        updateCartElements(results);
1440        processAjaxCallback(results);
1441
1442        getJson({
1443            url : getURL({
1444                action  : 'Home_Checkout_OnePage_CartUpdate'
1445            })
1446        }, function (results) {
1447            replaceContent(results, $('#main-container'));
1448        });
1449    });
1450
1451}
1452
1453// Update the cart total on order review
1454function updateCartTotal() {
1455  var shipMethod    = $("input[name=shipping-method]:checked").val();
1456
1457  var shipping = shippingJson[shipMethod];
1458
1459  var subTotal      = $('#subtotal').attr('data-subtotal');
1460  var discounts     = $('.discount');
1461
1462  var discountAmount = 0;
1463
1464
1465  discounts.each(function(index) {
1466    discountAmount = discountAmount + parseFloat($(this).attr('data-discount'));
1467  });
1468
1469
1470  var tax = 0;
1471  var orderTotal = ((subTotal*1) + (shipping*1) + (tax*1) + (discountAmount*1));
1472
1473  orderTotal = orderTotal.toFixed(2);
1474
1475  $('.orderTotal').html('$'+orderTotal);
1476  return true;
1477}
1478
1479// Update the shipping method used on the order review page
1480function updateShippingOption(value) {
1481    $('input[name="shipMethod"]').val(value);;
1482}
1483
1484/******** Shipping functions on order review page ********/
1485function bindShippingFunctions() {
1486    // Order review admin custom shipping
1487    // @todo correct documentation
1488    $('.shipping-options-item [for="admin_custom"] input[type="number"]').on('input', function() {
1489        var shipping    = $(this).val();
1490        var subTotal    = $('#subtotal').attr('data-subtotal');
1491        var discounts   = $('.discount');
1492
1493        var discountAmount = 0;
1494
1495        discounts.each(function(index) {
1496            discountAmount = discountAmount + parseFloat($(this).attr('data-discount'));
1497        });
1498
1499        var tax = 0;
1500        var orderTotal = ((subTotal*1) + (shipping*1) + (tax*1) + (discountAmount*1));
1501
1502        orderTotal = orderTotal.toFixed(2);
1503        $('#orderTotal').html('$'+orderTotal);
1504        return true;
1505    });
1506}
1507/******** Shipping functions on order review page ********/
1508
1509// Update values when shipping method is changed in checkout
1510function updateShippingValues(elem,e) {
1511    e.preventDefault();
1512    var addNewButton = '<i class="fa fa-plus"></i> Add New';
1513    var canelAddNew = '<i class="fa fa-caret-up"></i> Close';
1514    var formToggleButton = $('.add-new');
1515    /* detect type */
1516    var shippingID = elem.attr('shipping-profile-id');
1517
1518    clearAllCheckboxes(elem);
1519    updateCheckbox(elem, e);
1520
1521
1522    // remove active class from all
1523    $('.shipping-profile-item').removeClass('active');
1524
1525    if (shippingID=='new') {
1526        /* Update Form Toggle text */
1527        if (elem.attr('data-toggle')==='closed') {
1528            formToggleButton.find('.cta-text').html(canelAddNew);
1529            formToggleButton.attr('data-toggle','open');
1530        } else {
1531            formToggleButton.find('.cta-text').html(addNewButton);
1532            formToggleButton.attr('data-toggle','closed');
1533        }
1534
1535        // Set New Card Icon as Checked
1536        $('.card-panel').eq(1).find('.check i').addClass('fa-check-square-o').removeClass('fa-square-o');
1537
1538        /* Toggle Form */
1539        $('#newShipping').toggleClass('hide');
1540        $('.saved-item').slideToggle();
1541    } else {
1542
1543        // add active class
1544        elem.addClass('active');
1545
1546        /* Toggle Form */
1547        $('#newShipping').addClass('hide');
1548    }
1549
1550    /* update shipping value */
1551    $("#shippingProfileInput").val(shippingID);
1552}
1553
1554// Update values when payment method is changed in checkout
1555function updatePaymentValues(elem,e) {
1556    e.preventDefault();
1557
1558    var addNewButton = '<i class="fa fa-plus"></i> Add New';
1559    var canelAddNew = '<i class="fa fa-caret-up"></i> Close';
1560    var formToggleButton = $('.add-new');
1561    /* detect type */
1562    var paymentID = elem.attr('data-id');
1563    var paymentType = elem.attr('data-payment-type');
1564
1565    // console.log(paymentID);
1566
1567    $('.payment-method-item').removeClass('active');
1568    elem.addClass('active');
1569
1570
1571    clearAllCheckboxes(elem);
1572    updateCheckbox(elem, e);
1573
1574    if (paymentID=='cash') {
1575        $('#newShipping').addClass('hide');
1576        $('.saved-items').slideUp();
1577        $('.embedded-checkout').addClass('hide');
1578    }
1579
1580    // if (paymentID=='new') {
1581    //
1582    //     $('.embedded-checkout').toggleClass('hide');
1583    //
1584    //     /* TOGGLE the ADD NEW FORM */
1585    //     if (elem.attr('data-toggle')==='closed') {
1586    //         elem.find('.cta-text').html(canelAddNew);
1587    //         elem.attr('data-toggle','open');
1588    //     } else {
1589    //         elem.find('.cta-text').html(addNewButton);
1590    //         elem.attr('data-toggle','closed');
1591    //     }
1592    //     $('#newShipping').toggleClass('hide');
1593    //     $('.saved-items').slideToggle();
1594    // } else {
1595    //     $('#newShipping').addClass('hide');
1596    // }
1597
1598    if (paymentID == "paytrace-new") {
1599
1600        $('.paytrace-embedded').toggleClass('hide');
1601        $('.paytrace-vaulted-cards').toggleClass('hide');
1602        if (elem.attr('data-toggle') === 'closed') {
1603            $('.paytrace-vaulted-payment-methods .cta-text').html(canelAddNew);
1604            elem.attr('data-toggle', 'open');
1605        } else {
1606            $('.paytrace-vaulted-payment-methods .cta-text').html(addNewButton);
1607            elem.attr('data-toggle', 'closed');
1608        }
1609    }
1610
1611    $('#vaulted-payment-method').val(paymentID);
1612    $('#vaulted-payment-type').val(paymentType);
1613}
1614
1615function updateShippingMethod(elem, e) {
1616
1617    clearAllCheckboxes(elem);
1618    updateCheckbox(elem, e);
1619    updateCartTotal();
1620
1621}
1622
1623// Show additional credit card forms
1624// Bake in a way to redirect to an external service for completing payment
1625function toggleCreditCardForms() {
1626    var paymentMethod = $('input[name="payment-type"]:checked').val();
1627    if (paymentMethod in payment_config['urls'] && 'next' in payment_config['urls'][paymentMethod]){
1628        $('.checkout').checkout.nextUrl = payment_config['urls'][paymentMethod]['next'];
1629    }
1630}
1631
1632// Wrapper function for some reason
1633function selectShippingProfile(elem, e)
1634{
1635    updateShippingValues(elem, e)
1636}
1637
1638
1639
1640// *** CHECKOUT FLOW FUNCTIONS *** //
1641
1642
1643/******** ECOMMERCE FUNCTIONS ********/
1644
1645
1646
1647
1648/******** ELEMENT ACTIONS ********/
1649
1650// @header
1651
1652function jumpTo(el, offset) {
1653    $('html,body').unbind().animate({scrollTop: (el).offset().top - offset},'slow');
1654
1655}
1656
1657
1658// Update icon
1659// @review
1660function updateIcon(elem) {
1661    $('.checkbox-icon .fa').removeClass('fa-check-square-o');
1662    $('.checkbox-icon .fa').addClass('fa-square-o');
1663
1664    var thisButton = elem.find('.fa');
1665    thisButton.addClass('fa-check-square-o');
1666    thisButton.removeClass('fa-square-o');
1667    return elem;
1668}
1669
1670// Clear all the checkboxes in a container element
1671// @review
1672function clearAllCheckboxes(container_elem) {
1673    var classes = '';
1674
1675    // select all classes
1676    $.each(container_elem.attr('class').trim().split(' '), function(index, value){
1677        value = value.trim();
1678        if (value && value != '' && value !== null) {
1679            classes = classes + '.' + value;
1680        }
1681    });
1682
1683    // uncheck classes
1684    var allCheckboxes = $( classes + ' input');
1685    $.each(allCheckboxes, function(i, value){
1686        allCheckboxes.eq(i)[0].checked = false
1687    });
1688}
1689
1690// Clean form inputs
1691function cleanInputs() {
1692    var inputs = $('#brandfan-signup-form, #customer-signup-form');
1693    $.each(inputs,function(index, value){
1694        $.each($(value).find('.form-control'), function(i,input){
1695            var name =  $(input).attr('name');
1696            if (name    == 'firstname'
1697                || name == 'lastname'
1698                // || name == 'phone'
1699                || name == 'email'
1700                || name == 'username'
1701                || name == 'password')
1702            {
1703                // attach event handler
1704                $(this).keyup(function(){
1705                    var newValue =   $(this).val().replace(/\s+/g, '')
1706                    $(this).val(newValue);
1707                });
1708            } else {
1709            }
1710        });
1711    });
1712}
1713
1714function updateCheckbox(elem, e) {
1715    e.preventDefault();
1716    if (input = elem.find('input')) {
1717        if (input[0] !==undefined ) {
1718            if (!input[0].checked) {
1719                input[0].checked = true;
1720            } else {
1721                input[0].checked = false;
1722            }
1723        }
1724    } else {
1725        console.log('the attached function element does not have a checkbox inside of parent')
1726    }
1727}
1728/******** ELEMENT ACTIONS ********/
1729
1730$(function () {
1731  $('[data-toggle="tooltip"]').tooltip()
1732})

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.