2
\$\begingroup\$

I have a JavaScript (jQuery) 'init' file with various variables/event handlers and functions that are currently written in no particular order. I've read that it's good to organise these by declaring variables at the top of the file, using an init function and binding event handlers etc.

Here is the file in its full and here in codepen.

It would be useful to just have a few pointers on how to organise this file a little better.

var w = $(window).width(),
    h = $(window).height(),
    screenMedium = 780,
    screenLarge = 920;

//remove error on fields on keydown
$('.form .error').on('keydown', 'input, textarea', function(){
    $(this)
        .parent()
        .removeClass('error')
        .end()
        .next()
        .remove('small');
});

// sticky navigation
function stickyNavigation() {

    var browserWidth = $(window).width();

    if(browserWidth >= 920) {

        if ($(this).scrollTop() > 175){  
            $('body').addClass("sticky");
        } else {
            $('body').removeClass("sticky");
        }

    }

}


//homepage video
var $video = $('#thevideo');
var video = $('#thevideo')[0];
var loaded = false;

$('#play-video-2').on('click',function(e){
    e.preventDefault();
    $('#thevideo-wrap').addClass('show-video');
    $('.playbutton').addClass('playing');
    setTimeout(function(){
        video.play();
    }, 1000);
});

$('.playbutton').on('click', function(e){
    e.preventDefault();

    var $button = $(this);
    var $holder = $(this).parent();
    var state = $button.hasClass('paused') ? 'paused'   :
                $button.hasClass('playing') ? 'playing' : '';

    if( state === 'playing' ){
        video.pause();
        $button.addClass('paused');

        return;
    }

    if( state === 'paused' ){
        video.play();
        $button.removeClass('paused');

        return;
    }

});

$video.on('ended', function(){
    $('#thevideo-wrap').removeClass('show-video');
    $('.playbutton').removeClass('playing');
});


//off canvas nav toggle
$('.off-canvas-toggle').on('click', function(e) {
    e.preventDefault();

    var direction = $('.off-canvas__container').data('off-canvas-direction');

    if ( $('#mobile-search').hasClass('show-mobile-search') ) {
        $('#mobile-search').removeClass('show-mobile-search');
    }

    $('.off-canvas').toggleClass('off-canvas--' + direction);
    $('.mobile-nav').toggleClass('pushed');
    $(this).toggleClass('active');
});

//off canvas mobile nav
$('.off-canvas__content').on('click', '.nav-click', function(e) {
    e.preventDefault();

    $this = $(this);
    $item = $this.parent('.nav__item');
    $item.toggleClass('nav__item--open');
    $this.children('i').toggleClass('icon-minus').toggleClass('icon-plus');

    if($item.hasClass('nav__item--open')) {
      $item.siblings().removeClass('nav__item--open');
      $item.siblings().children('.nav-click').children().removeClass('icon-minus').addClass('icon-plus');
    }

});


//toggle search
function toggleSearch() {

    if ($('body').hasClass('sticky')) {

        $('html, body').animate({ scrollTop: 0 }, 600, function() {

            $('#mobile-search').addClass('show-mobile-search');
            $('#main-header').addClass('mobile-search-open');
            $('.show-mobile-search').find('#mobile-query').focus();

        });

    } else {

        $('#mobile-search').toggleClass('show-mobile-search');
        $('#main-header').toggleClass('mobile-search-open');
        $('.show-mobile-search').find('#mobile-query').focus();

    }


}

$('.search-link-mobile').on('click', function(e){
    e.preventDefault();

    toggleSearch();

});


//footer nav toggle
if (w < screenMedium) {

    $('.footer-list-title').on('click', function(e){
        e.preventDefault();

        $(this).children('span').toggleClass('icon-minus').toggleClass('icon-plus').end().next().slideToggle(200);

    });

}


//desktop navigation dropdown
$('.has-subnav').on({

    mouseenter: function () {

        if (!$('body').hasClass('sticky')) {
            var $this = $(this);
            $this.children('a').addClass('active');
            setTimeout(function(){
                $this.find('.main-nav-dropdown').addClass('main-nav-opened');
                $('.off-canvas').addClass('open');
            }, 300);
            setTimeout(function(){
                $this.find('.main-nav-dropdown-list').addClass('main-nav-list-opened');
            }, 400);
        }

    },

    mouseleave: function () {

        if (!$('body').hasClass('sticky')) {
            var $this = $(this);
            $this.children('a').removeClass('active');
            $this.find('.main-nav-dropdown-list').removeClass('main-nav-list-opened');
            setTimeout(function(){
                $this.find('.main-nav-dropdown').removeClass('main-nav-opened');
                $('.off-canvas').removeClass('open');
            }, 300);

        }

    }

});

//homepage desktop hero slider
var heroSlider = $('#hero-slider').bxSlider({
    pagerCustom: '#hero-pager',
    auto: true,
    mode: 'fade',
    speed: 800,
    pause: 8000,
    video: true,
    autoHover: true,
    onSliderLoad: function() {
        $('body').addClass('loaded');

        var browserWidth = $(window).width();

        if(browserWidth >= 920) {
            var current = 0;
            var themeID = $('#slide-index-'+current).find('.hero-inner').data('theme');
            if (themeID === 1) {
                $('body').addClass('slider-theme-light');
            } else {
                $('body').addClass('slider-theme-dark');
            }
        }
    },
    onSlideBefore: function() {

        var browserWidth = $(window).width();

        if(browserWidth >= 920) {
            var current = heroSlider.getCurrentSlide();
            var themeID = $('#slide-index-'+current).find('.hero-inner').data('theme');
            if (themeID === 1) {
                $('body').addClass('slider-theme-light').removeClass('slider-theme-dark');
            } else {
                $('body').addClass('slider-theme-dark').removeClass('slider-theme-light');
            }
        }
    },
});


//scroll to main content
$("#to-content").on('click', function(e) {
    e.preventDefault();
    $('html, body').animate({
        scrollTop: $("#main").offset().top
    }, 1000);
});


//featured shows slider
$('#featured-slider')
    .on('init', function(event, slick){
        $(this).addClass('loaded');
    })
    .slick({
        slidesToShow: 1,
        centerMode: true,
        mobileFirst: true,
        autoplaySpeed: 4000,
        dots: true,
        arrows: false,
        prevArrow: '<a href="#" data-role="none" class="slick-arrow slick-prev" aria-label="previous">Previous</a>',
        nextArrow: '<a href="#" data-role="none" class="slick-arrow slick-next" aria-label="next">Next</a>',
        customPaging : function(slider, i) {
            return '<span class="slick-dot"><span></span></span>';
        },
        responsive: [
        {
            breakpoint: 1600,
            settings: {
                slidesToShow: 5,
                slidesToScroll: 1,
                arrows: true
            }
        },
        {
            breakpoint: 1300,
            settings: {
                slidesToShow: 4,
                slidesToScroll: 1,
                arrows: true
            }
        },
        {
            breakpoint: 780,
            settings: {
                slidesToShow: 3,
                slidesToScroll: 1,
                arrows: true
            }
        },
        {
          breakpoint: 600,
          settings: {
            slidesToShow: 2
          }
        }
      ]
});



//journey wall
$('#journal-wall').mixitup({
    onMixStart: function() {
        $("#journal-wall .journal-item img").trigger("unveil");
    }
});

//lazy load journey all item images
$("#journal-wall .journal-item img").unveil(20, function() {
    $(this).load(function() {
        this.style.opacity = 1;
    });
});

//toggle journal nav
$('.journal-list-title').on('click', function(e){
    e.preventDefault();

    $(this).children('span').toggleClass('icon-minus').toggleClass('icon-plus').end().next().slideToggle(200);

});


//article fitvids
$('.article').fitVids();


$(window).scroll(function() {

    stickyNavigation();

});

$(window).load(function() {

    var w = $(window).width();

    if (w >= 600) {

        $('#journal-wall .journal-item').conformity();

    }

});


$(window).on("debouncedresize", function( event ) {

    var w = $(window).width();

    if (w < 920) {
        $('body').removeClass('sticky').removeClass('slider-theme-light').removeClass('slider-theme-dark');
        if ($('.bx-wrapper').length && $('body').hasClass('home')) {
            heroSlider.destroySlider();
        }
    } else {
        if (!$('.bx-wrapper').length && $('body').hasClass('home')) {
            heroSlider.reloadSlider();
        }
    }

    if (w >= 600) {

        $('#journal-wall .journal-item').conformity();

    } else {

        $('#journal-wall .journal-item').removeAttr('style');
    }   

});
\$\endgroup\$
  • \$\begingroup\$ It may be useful to split pieces of your code into reusable modules and then include them in separately where pages require them. \$\endgroup\$ – Jamesking56 Sep 1 '15 at 20:49
  • \$\begingroup\$ This sounds interesting, I've always checked to see if an element exists with .length in the past which seems clunky. Do you have any examples/tutorials I could use? \$\endgroup\$ – Rob Morris Sep 1 '15 at 20:53
  • \$\begingroup\$ If you added a certain module (or component) to a page which required it, that would imply the element already exists on the page, solving that issue. \$\endgroup\$ – Jamesking56 Sep 1 '15 at 20:54
  • \$\begingroup\$ For instance, Vue.js implements a components structure that has a template associated. The template creates the elements that component requires automatically. \$\endgroup\$ – Jamesking56 Sep 1 '15 at 20:54
  • \$\begingroup\$ Does this mean I'd have to split my 'init.js' file up into separate files? \$\endgroup\$ – Rob Morris Sep 1 '15 at 20:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.