简体   繁体   中英

jQuery mobile - close panel on history back

I have a jQuery mobile panel which slides in from the side, it works great. But lets say you have a login page, that redirects to a main page with a panel. Now if the user opens the panel, and then clicks the back button, he expects the panel to close. But instead the browser navigates back to the login page.

I´ve tried adding something to the url:

window.location.hash = "panelOpen";

But that just messes up the jQuery mobile history state pattern. I´ve also tried to listen to the navigate event, and prevent it if a panel is open:

$(window).on('navigate', function (e, hans) {
     var panels = $('[data-role="panel"].ui-panel-open');
     if (panels&&panels.length>0) {
         e.preventDefault();
         e.stopPropagation();
         $('#' + panels[0].id).panel('close');
           return false;
         }
});

This kind of works, except that the url is changed, and I cannot grab the event that changes the url. Furthermore, it also messes up the jQuery mobile history pattern.

So how does people achieve this expected 'app-like' behaviour with a jQuery mobile panel; open panel > history back > close panel. And thats it.

Thanks alot!

Updated

Instead of retrieving current URL from jQuery Mobile's history, It is safer to retrieve it from hashchange event event.originalEvent.newURL and then pass it to popstate event to be replaceState() with that URL.


Instead of listening to navigate , listen to popstate which fires before. The trick here is manipulate both browser's history and jQuery Mobile's history by replaceState() and reload same page without transition .

var newUrl;
$(window).on("hashchange", function (e) {
    /* retrieve URL */
    newUrl = e.originalEvent.newURL;
}).on("popstate", function (e) {
    var direction = e.historyState.direction == "back" ? true : false,
        activePanel = $(".ui-panel-open").length > 0 ? true : false,
        url = newUrl,
        title = document.title;
    if (direction && activePanel) {
        $(".ui-panel-open").panel("close");
        $(".ui-header .ui-btn-active").removeClass("ui-btn-active");
        /* reload same page to maintain jQM's history */
        $.mobile.pageContainer.pagecontainer("change", url, {
            allowSamePageTransition: true
        });
        /* replace state to maintain browsers history */
        window.history.replaceState({}, title, url);
        /* prevent navigating into history */
        return false;
    }
});

This part is meant to maintain same transition used previously as transition is set to none when reloading same page.

$(document).on("pagebeforechange", function (e, data) {
    if (data.options && data.options.allowSamePageTransition) {
        data.options.transition = "none";
    } else {
        data.options.transition = $.mobile.defaultPageTransition;
    }
});

Demo - Code

I am a little bit late on the party, but i had recently the same requirements and i would like to share how i did it. So, i extended the requirement in the original question to Panels , Popups and Pages :

...an expected 'app-like' behaviour, history back > close whaterver is open. And thats it.

In .on("panelopen") , .on("popupafteropen") and .on("pagecontainershow") i simply add another entry to the window history, by using the HTML5 API ( https://developer.mozilla.org/en-US/docs/Web/API/History_API ) (I believe there is no need to use the JQM navigate browser quirks for that):

window.history.pushState({}, window.document.title, window.location.href);

After that, i'm using more or less Omar's function to intercept the popstate event:

$(window).on("popstate", function (e) {
  var pageId = $(":mobile-pagecontainer").pagecontainer("getActivePage").prop("id");
  var pageOpen = (pageId != "page-home");
  var panelOpen = $(".ui-panel-open").length > 0;
  var popupOpen = $(".ui-popup-active").length > 0;

  if(pageOpen) {
    $.mobile.pageContainer.pagecontainer("change", "#page-home", {reverse: true});
    return false;
  }
  if(panelOpen) {
    $(".ui-panel-open").panel("close");
    return false;
  }
  if(popupOpen) {
    $(".ui-popup-active .ui-popup").popup("close")
    return false;
  }
});

As you see, the is just only one level to the home-page, but this can be easily extended by using JQM history implementation to get the previous page:

var activeId = $.mobile.navigate.history.activeIndex;
var jqmHistory = $.mobile.navigate.history.stack; // array of pages

and use pagecontainer to change to the active entry - 1.


As last note, this works well also by completely disabling the built-in JQM Ajax navigation system:

/* Completely disable navigation for mobile app */
$.mobile.ajaxEnabled = false;
$.mobile.loadingMessage = false;
$.mobile.pushStateEnabled = false;
$.mobile.hashListeningEnabled = false;
$.mobile.changePage.defaults.changeHash = false;
$.mobile.popup.prototype.options.history = false;

(Tested in Browser, on real Android and iOS devices)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM