Koumbit.org

Pour un internet libre et solidaire

How to toggle a theme region using jQuery with either Omega or AdaptiveTheme

Recently two clients wanted to have a left-column navigation menu which the user could hide or display using a link in the primary menu, one on a site with a theme based on Omega, and another using a theme based on AdaptiveTheme. It wasn't enough to call the jQuery function .toggle(), however, since by the time the page has been loaded the Omega base theme has already determined that the Sidebar First region has content and the width of the rest of the page elements have been determined accordingly. Fortunately, the Omega and AdaptiveTheme base themes use CSS classes to indicate which theme regions are active, and set the width of each region based on those classes. So, all we had to do was to swap the appropriate classes each time the we toggled the display of the menu.

As it happens this is the first time I've had to insert random bits of jQuery into a theme (up until now, there was always a module for that), and I found that the necessary jQuery wrapper wasn't as well documented as it could have been, so here's a quick tutorial.

Put the following into MYTHEME.info:

scripts[] = js/toggle.js

In the file js/toggle.js, put the following for a theme based on Omega:

(function ($) {
  Drupal.behaviors.MY_OMEGA_SUBTHEME = {
    attach: function(context, settings) {
      // initialize
      var initialState = $.cookie('MYTHEME_toggle');
      if ( initialState == "1" ) {
        $('aside#region-sidebar-first').hide();
        $('div#region-content').toggleClass('grid-16 grid-11');
      }
      // attach to menu item "Show/Hide Menu"
      var showOrHideMenu = $('aside#region-sidebar-first').is(':hidden');
      $('.menu-12345 a').click(function(){
        if ( showOrHideMenu == true ) {
          // div#region-content.grid-11
          $('aside#region-sidebar-first').show();
          $('div#region-content').toggleClass('grid-11 grid-16');
          $.cookie('MYTHEME_toggle', 0, { path: settings.basePath });
          showOrHideMenu = false;
        }
        else if ( showOrHideMenu == false ) {
          // div#region-content.grid-16
          $('aside#region-sidebar-first').hide();
          $('div#region-content').toggleClass('grid-16 grid-11');
          $.cookie('MYTHEME_toggle', 1, { path: settings.basePath });
          showOrHideMenu = true;
        }
        return false;
      });
    }
  };
})(jQuery);

On our Omega based site, the central content region div#region-content has the class .grid-11 when the left sidebar is active, and .grid-16 otherwise (we have no right sidebar on this site). This means that when the page is loaded, the menu is displayed and the content region has class .grid-11. Clicking the menu item with ID 12345 will hide the menu, and change that class to .grid-16, which has the effect of making the content region wider. Clicking this menu item again will make the page return to its initial state.

You'll notice that this code snippet also sets a cookie to make sure that the menu toggle state is preserved when the user loads a new page, using a cookie called MYTHEME_toggle which is set to 1 if the menu should be hidden and 0 otherwise. When this file is first loaded, it checks this cookie to set the initial state of the block. All of this works beautifully, but there's a small catch -- Drupal 7 ships with jquery.cookie.js, but it's not loaded by default for all users. So, we need to make sure that happens by explicitly loading it in a module:

/**
 * Implements hook_init().
 */
function MYMODULE_init() {
  drupal_add_library('system', 'jquery.cookie');
}

The code for AdaptiveTheme is very similar, except that the magic CSS classes which list the active regions are on the body tag, and in this case we had to toggle the right sidebar:

(function ($) {
  Drupal.behaviors.MY_ADAPTIVETHEME_SUBTHEME = {
    attach: function(context, settings) {
      // initialize
      var initialState = $.cookie('MYTHEME_toggle');
      if ( initialState == "1" ) {
        $('.region-sidebar-second').hide();
        $('body.html').addClass('no-sidebars');
        $('body.html').removeClass('one-sidebar');
        $('body.html').removeClass('sidebar-second');
      }
      // attach to "Show/Hide Menu"
      var showOrHideMenu = $('.region-sidebar-second').is(':hidden');
      $('.menu-12345 a').click(function(){
        if ( showOrHideMenu == true ) {
          // body.one-sidebar.sidebar-second
          $('.region-sidebar-second').show();
          $('body.html').removeClass('no-sidebars');
          $('body.html').addClass('one-sidebar');
          $('body.html').addClass('sidebar-second');
          $.cookie('MYTHEME_toggle', 0, { path: settings.basePath });
          showOrHideMenu = false;
        }
        else if ( showOrHideMenu == false ) {
          // body.no-sidebars
          $('.region-sidebar-second').hide();
          $('body.html').addClass('no-sidebars');
          $('body.html').removeClass('one-sidebar');
          $('body.html').removeClass('sidebar-second');
          $.cookie('MYTHEME_toggle', 1, { path: settings.basePath });
          showOrHideMenu = true;
        }
        return false;
      });
    }
  };
})(jQuery);    

Since Drupal 7 menu items can normally only point towards external URLs or internal Drupal paths, we used the module Void Menu to allow us to create a menu item pointing to . Normally this would make the browser jump to the top of the page in addition to calling the attached function, but this can be avoided by returning false.

To use this on your own site, compare the HTML generated by your theme on pages with and without the region you want to toggle. (You can do this by manually setting the menu block in question to not display on one particular page to see how your theme sets the content region in order to take the full width of the page.) Next, tweak the above code snippet so that .toggleClass(), .removeClass(), and .addClass() switch the correct classes, and so that the function is attached to the correct menu ID.

Happy theming, and may your blocks always be toggled!

Ajouter un commentaire

Permanence téléphonique

☏ +1 514 907 9494
Lun: 10h à 12h et 13h à 16h
Mar: 10h à 12h
Mer: 10h à 12h et 13h à 16h
Jeu: 10h à 12h
Mon: 10am to 12pm and 1pm to 4pm
Tue: 10am to 12pm
Wed: 10am to 12pm and 1pm to 4pm
Thu: 10am to 12pm

Venez nous voir!

1883, rue Atateken,
Montréal (Québec) H2L 3L7, Canada
Veuillez noter que nos bureaux n'ont pas de stationnement attitré.
1883 Atateken Street,
Montreal, Quebec, H2L 3L7, Canada
Please note that you'll need to find on-street parking.

Écrivez-nous

Informations générales

Support technique

Pour une demande de devis, voir le formulaire à la page contact.

Nos clefs PGP

General inquiries

Technical support

For a free estimate, see the form on our contact page.

Our PGP keys

Suivez-nous

ktweb_menu_social