Reside-Menu for jQuery Mobile


There is no doubt that Panel Widget offered by jQuery Mobile is handy, especially that panels are accessible from many page when using External Panel. However, widgets keep your hands tied up when it comes to applying your own modifications. Modifying widgets is somehow hectic and time consuming and sometimes you don’t get them to work as expected.

I came through this question on stack overflow, where the OP is asking whether it is possible to create such a Reside-Menu (screenshot). Well, nothing is impossible, a bit of CSS, jQuery and a clear mind; anything is achievable. Conclusion…I came up with a Reside-Menu which acts as an External Panel.

1) Reside-Menu structure

The menu can be anything, buttons, listview, collapsible…etc. The important part is to manually enhancing menu container if any jQM widget is used.

<div id="content">
  <!-- elements -->
</div>

Second point, menu’s container position and z-index. The latter CSS property should be set to lowest possible – although it will be hidden – in order not to overlap with other elements in active page.

#content {
  height: 100%;
  width: 50%;
  position: absolute;
  top: 5px;
  left: 5px;
  z-index: -9999;
}

2) CSS3 Animation – transition, transform3d(x,y,z) & scale3d(x,y,z)

CSS3 transition is used in animating pages, dialogs, panels, toolbars and popups. They are safe and easy to maintain and debug; most importantly, CSS3 transition has callback event that you can listen to on any browser! These events give you more control over elements being animated to execute more functions after animation is done.

Three class should be created for, revealing, hiding and animating for both reveal/hide.

Reveal / open menu:

.panel-open {
    -webkit-transform: translate3d(60%, 0, 0) scale3d(0.6, 0.6, 1);
       -moz-transform: translate3d(60%, 0, 0) scale3d(0.6, 0.6, 1);
        -ms-transform: translate3d(60%, 0, 0) scale3d(0.6, 0.6, 1);
         -o-transform: translate3d(60%, 0, 0) scale3d(0.6, 0.6, 1);
            transform: translate3d(60%, 0, 0) scale3d(0.6, 0.6, 1);
}

Hide / close menu:

.panel-close {
    -webkit-transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
       -moz-transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
        -ms-transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
         -o-transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
            transform: translate3d(0, 0, 0) scale3d(1, 1, 1);
}

Animate open / close:

.panel-animate {
    -webkit-transition: all 500ms ease;
       -moz-transition: all 500ms ease;
        -ms-transition: all 500ms ease;
         -o-transition: all 500ms ease;
            transition: all 500ms ease;
}

3) Open / Close Reside-Menu

This step is simple yet tricky, it’s all about adding/removing classes for animation. However, to achieve a smooth transition, yet prevent page from scrolling, some additional steps are required.

  1. Opening Reside-Menu
    • In case any of jQuery Mobile widget is used in the menu, it should be initialized manually. Then the menu should be _hidden_.
      $("#content").enhanceWithin().hide();
      
    • In order not to cause scroll, body‘s _overflow_ should be set to hidden.
      $("body").css({ "overflow-y": "hidden" });
      
    • Retrieve viewport‘s height and update active page’s height .ui-page-active with that value. However, note that if page contains header or footer, 44px should be subtracted from viewport‘s height. In case both toolbars are presenet, 88px should be subtracted.
      $(".ui-page-active").height($(window).height() - 88);
      
    • Reveal Reside-Menu by adding panel-animate and panel-open to active page .ui-page-active. At the same time, hidden state of Reside-Menu should be removed. It won’t overlap with active page as its has higher z-index at this stage.
      $(".ui-page-active").addClass("panel-animate panel-open");
      $("#content").show();
      
  2. Closeing Reside-Menu
    • This is the easiest step in the whole process, just add panel-close, remove panel-open AND change Reside-Menu’s z-index to original value.
      $(".ui-page-active").addClass("panel-close").removeClass("panel-open");
      $("#content").css("z-index", "-9999");
      
  3. Most important part: Post-opening and Post-Closing.
    • Post-Opening: When animation is done, Reside-Menu can’t be accessed, because page’s z-index is higher than Reside-Menu’s one.
      $("#content").css("z-index", "-9999");
      

      However, this step cant be taken ahead of time, it should be done after page is fully animated, otherwise, Reside-Menu will be overlap with page and it will look urgly. To ensure that page is out of our way, we need to listen to a special event(s) webkitTransitionEnd, oTransitionEnd, otransitionend, transitionend, msTransitionEnd. Each browser fires its’ own event, so all should be included for best results. Once tranisionend event is fires, we update Reside-Menu’s z-index value to `9999`.

    • Post-Closing: At this step, all we need is to revert back all the changes we have made to active page and body.First, Reside-Menu should be hidden again, then remove CSS properties that we added to active page and body. That’s not all, we have messed up .ui-page-active‘s height! It should be returned to its’ original state…Well, a tiny function will take care of everything $.mobile.resetActivePageHeight().
              $("#content").hide();
              $("body, .ui-page-active").removeAttr("style");
              $(this).removeClass("panel-animate panel-close").css({ padding: "44px 0" });
              $.mobile.resetActivePageHeight();
      

Full code & Demo

$("#content").enhanceWithin().hide();

$(".panel").on("click", function () {
    $("body").css({
        "overflow-y": "hidden"
    });
    $(".ui-page-active").height($(window).height() - 88);
    $(".ui-page-active").addClass("panel-animate panel-open");
    $("#content").show();
});

$(".panel-close-btn").on("click", function () {
    $(".ui-page-active").addClass("panel-close").removeClass("panel-open");
    $("#content").css("z-index", "-9999");
});

$(document).on("webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd", ".panel-open, .panel-close", function (e) {
    if ($(this).hasClass("panel-open")) {
        $("#content").css("z-index", "9999");
    }
    if ($(this).hasClass("panel-close")) {
        $("#content").hide();
        $("body, .ui-page-active").removeAttr("style");
        $(this).removeClass("panel-animate panel-close").css({
            padding: "44px 0"
        });
        $.mobile.resetActivePageHeight();
    }
});
Advertisements

6 thoughts on “Reside-Menu for jQuery Mobile

  1. Pingback: Reside-Menu for jQuery Mobile – Part 2 | jQuery Mobile Tricks
  2. Omar, All I Can Say Is WOW! You Are An Absolute STAR! Please Email Me. I Wan To Offer You Something In Return. Best To You! Thank You Again!

  3. Dear Mr Omar, Would you please be so kind and take a look at your code modified by me. I am trying to link between pages but it does not seem to be working. More, I would like the menu to disappear after a new page is selected and the screen to come back to its original size. Is it possible to be done? Thank you so much for your help. Code: http://jsfiddle.net/flymen8888/NNQM4/

  4. Hi Yaro, thanks for passing by. I am glad you find the blog of help. Please free to use in your upcoming app. All I request is an attribution 🙂

    Good luck on your app!

  5. Thank You So Much For Your Help On Stockoverflow. Your help is much appreciated. You are an absolute genius. In relation to the outstanding content of this blog, can the code shown in those examples be used in commercial projects? Is there any license available? I would love to use this example to build a mobile template for sale. Please let me know.

    Best to you all.

Drop me a line or two ;)

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s