Instantly share code, notes, and snippets.
Created
July 1, 2014 07:51
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save frequent/cdefb7e9712137863ea5 to your computer and use it in GitHub Desktop.
JQM navigation gadget, which allows deeplinking and (uri encoded) query parameters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*jslint indent: 2, maxlen: 80, nomen: true */ | |
/*global console, window, document, rJS, RSVP, $ */ | |
(function (window, document, rJS) { | |
"use strict"; | |
rJS(window) | |
/** | |
* Override navigation of jQuery Mobile and allow deeplinking. Missing | |
* pages will now be loaded and added to the DOM as new page-gadgets - | |
* and removed again once the user leaves them. | |
* @method render | |
* @param {Object} gadget Gadget object | |
*/ | |
.declareMethod('render', function () { | |
var gadget = this; | |
// helper: render new gadget | |
function renderNewGadget(my_gadget, my_page_name, query) { | |
var page_list, page, data_url; | |
// render = create dynamic contents of page if applicable | |
if (my_gadget.render) { | |
my_gadget.render().fail(console.log); | |
} | |
// active page is last page | |
page_list = document.querySelectorAll("[data-role='page']"); | |
page = page_list[page_list.length - 1]; | |
// encode query parameters (Hello JQM!) | |
if (query) { | |
data_url = window.encodeURIComponent(my_page_name + "?" + query); | |
} | |
// go to the new page, overwrite page id with correct data_url | |
// so that pages can be based on a single "template" but have | |
// different urls | |
$.mobile.changePage("#" + page.id, {"dataUrl": data_url || null}); | |
page.setAttribute("data-external-page", true); | |
page.setAttribute("data-url", data_url); | |
} | |
// helper: create new page gadget and integrate it in application | |
// this will fetch an HTML file whose body contains the page | |
// template. | |
function createNewGadget(my_target_name, query) { | |
return gadget.declareGadget( | |
"./" + my_target_name + ".html", | |
{"element": gadget.__element, "scope": my_target_name} | |
) | |
.then(function (new_gadget) { | |
return renderNewGadget(new_gadget, my_target_name, query); | |
}) | |
.fail(console.log); | |
} | |
// helper: select page via data-url | |
function getElementByDataUrl(str) { | |
return document.querySelector("[data-url='" + str + "']"); | |
} | |
// helper: override default JQM navigation, allow deeplinks | |
// NOTE: a deeplink is a transition to a page that is already in the | |
// DOM. If it is not in the DOM, the transition will be halted, the | |
// page will be fetched/generated and inserted before the transition | |
// is triggered again with correct parameters (data_url). | |
// NOTE: in case of a deeplink, the initial page stays un-enhanced | |
// and the user starts on the deeplinked page. However the initial | |
// page is still set as firstPage! | |
function navigationHandler(e, data) { | |
var target, has_query, clean_url, parsed_url, to_page, decoded, page, | |
go_home, dist, encoded, data_url, deeplink; | |
if (e && data) { | |
dist = $.mobile.navigate.history.initialDst; | |
if (typeof data.toPage === "string") { | |
to_page = data.toPage.split("#")[1]; | |
decoded = decodeURIComponent(to_page || "documents").split("?"); | |
// NOTE: hmhm.... | |
encoded = window.location.hash.replace("#", "").replace("?", "%3F"); | |
target = decoded[0]; | |
has_query = decoded[1]; | |
// transition to first page (unenhanced if coming from deeplink) | |
go_home = $.mobile.firstPage[0].id === to_page; | |
page = document.getElementById(target) || | |
getElementByDataUrl(target) || | |
getElementByDataUrl(to_page); | |
// deeplink | |
} else if (dist && window.location.hash !== "") { | |
// enable deeplinking | |
clean_url = window.location.href.split("#")[0]; | |
parsed_url = $.mobile.path.parseUrl(clean_url); | |
decoded = decodeURIComponent(window.location.href).split("?"); | |
target = decoded[0].split("#")[1]; | |
has_query = decoded[1]; | |
page = document.getElementById(target) || | |
getElementByDataUrl(target); | |
deeplink = true; | |
// remove initialDist, otherwise closing popups | |
// will trigger double backward transition. | |
delete $.mobile.navigate.history.initialDst; | |
// correctly set index as first page in JQM history | |
$.mobile.navigate.history.stack[0].hash = ""; | |
$.mobile.navigate.history.stack[0].url = clean_url; | |
$.mobile.path.documentUrl = parsed_url; | |
$.mobile.path.documentBase = parsed_url; | |
} | |
} | |
if (target) { | |
// page does not exist > make it. Load underlying document, set | |
// url to encoded string including query param #foo?baz=bam and | |
// hierarchy (#foo/baz/bam) | |
if (!page) { | |
e.preventDefault(); | |
return createNewGadget(target, has_query) | |
.fail(console.log); | |
} | |
// page exists | |
if (has_query || go_home) { | |
if (deeplink) { | |
return; | |
} | |
if (has_query && to_page !== encoded) { | |
window.location.hash = to_page; | |
return; | |
} | |
if ((has_query && ($.mobile.activePage && | |
$.mobile.activePage[0].id !== target))) { | |
data_url = window.encodeURIComponent(target + "?" + has_query); | |
$.mobile.changePage("#" + target, {"dataUrl": data_url}); | |
} else { | |
return gadget.my_triggerEvent(page, "render") | |
.fail(console.log); | |
} | |
} | |
} | |
} | |
// helper: remove page and gadget when user leaves | |
function cleanupHandler(e) { | |
var page, is_enhanced, clean_scope, data_url; | |
page = e.target; | |
is_enhanced = $(page).data("mobilePage") || $(page).page("instance"); | |
data_url = page.getAttribute("data-url"); | |
clean_scope = window.decodeURIComponent(data_url).split("?")[0]; | |
if (page.getAttribute('data-external-page')) { | |
if (is_enhanced) { | |
$(this).page('destroy').remove(); | |
} | |
return gadget.dropGadget(clean_scope) | |
.fail(console.log); | |
} | |
} | |
// START: | |
$(document) | |
.on('pagebeforechange', navigationHandler) | |
.on('pagehide', 'div.ui-page', cleanupHandler); | |
}) | |
/* ======================== METHODS TO EXPOSE ========================= */ | |
/* ========================= METHODS NEEDED =========================== */ | |
.declareAcquiredMethod("my_triggerEvent", "util_triggerEvent"); | |
}(window, document, rJS)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment