1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

trim core scripts

This commit is contained in:
Luke Pulverenti 2015-11-27 19:04:04 -05:00
parent d7fb3af903
commit 6acc4bf69d
13 changed files with 267 additions and 454 deletions

View file

@ -30,6 +30,6 @@
"commit": "14d2ca3df97da64c820829a8310f9198fbafbcfa"
},
"_source": "git://github.com/desandro/eventie.git",
"_target": "^1",
"_target": "~1.0.3",
"_originalSource": "eventie"
}

View file

@ -36,7 +36,7 @@
"tag": "v1.0.8",
"commit": "e9a66727f3da0446f04956d4e4f1dcd51cdec2ff"
},
"_source": "git://github.com/PolymerElements/iron-selector.git",
"_source": "git://github.com/polymerelements/iron-selector.git",
"_target": "^1.0.0",
"_originalSource": "PolymerElements/iron-selector"
"_originalSource": "polymerelements/iron-selector"
}

View file

@ -26,109 +26,6 @@
var capabilities = ConnectionManager.capabilities();
ApiClientBridge.init(AppInfo.appName, AppInfo.appVersion, AppInfo.deviceId, AppInfo.deviceName, JSON.stringify(capabilities));
//initAjax();
}
var baseAjaxMethod;
var currentId = 0;
function getNewRequestId() {
var id = currentId++;
return id.toString();
}
function initAjax() {
baseAjaxMethod = HttpClient.send;
HttpClient.send = sendRequest;
}
function sendRequest(request) {
// For now, we can only handle json responses
if (request.dataType) {
if (request.dataType != 'json') {
return baseAjaxMethod(request);
}
}
if (request.data) {
// For now, we can only handle request bodies that are strings
if (typeof (request.data) != 'string') {
return baseAjaxMethod(request);
}
}
var deferred = DeferredBuilder.Deferred();
var id = getNewRequestId();
request.headers = request.headers || {};
if (request.dataType == 'json') {
request.headers.accept = 'application/json';
}
var method = request.type || "GET";
var javaRequest = {
Method: method,
Url: request.url,
RequestHeaders: request.headers
};
if (request.timeout) {
javaRequest.Timeout = request.timeout;
}
if (request.data) {
javaRequest.RequestContent = request.data;
}
if (request.contentType) {
javaRequest.RequestContentType = request.contentType;
}
//Logger.log("Sending request: " + JSON.stringify(javaRequest));
ApiClientBridge.sendRequest(JSON.stringify(javaRequest), request.dataType, id);
Events.on(AndroidAjax, 'response' + id, function (e, isSuccess, response) {
Events.off(AndroidAjax, 'response' + id);
if (isSuccess) {
if (response) {
deferred.resolveWith(null, [response]);
} else {
deferred.resolve();
}
}
else {
// Need to mimic the jquery ajax error response
deferred.rejectWith(request, [getErrorResponse(response)]);
}
});
return deferred.promise();
}
function getErrorResponse(response) {
var error = {};
if (response.StatusCode) {
error.status = response.StatusCode;
}
error.ResponseHeaders = response.ResponseHeaders || {};
error.getResponseHeader = function (name) {
return error.ResponseHeaders[name];
};
return error;
}
function getDownloadSpeed(bytes, url) {

View file

@ -54,6 +54,14 @@
/* Now playing bar */
.nowPlayingBar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
/* Above everything, except for the video player and popup overlays */
z-index: 1097;
color: #fff;
background-color: rgba(26,26,26,.94);
border-top: 1px solid #444;
text-align: center;
/*box-shadow: 0 0 8px rgba(255,255,255,.4);*/

View file

@ -1340,8 +1340,6 @@
$('.hasrefreshtime').removeClass('hasrefreshtime').removeAttr('data-lastrefresh');
}
Dashboard.ready(function () {
if (window.ApiClient) {
initializeApiClient(window.ApiClient);
}
@ -1352,6 +1350,5 @@
Events.on(ConnectionManager, 'localusersignedin', clearRefreshTimes);
Events.on(ConnectionManager, 'localusersignedout', clearRefreshTimes);
});
})(jQuery, document, window);

View file

@ -133,13 +133,7 @@
var mainDrawerButton = document.querySelector('.mainDrawerButton');
if (mainDrawerButton) {
if (AppInfo.isTouchPreferred || $.browser.mobile) {
mainDrawerButton.addEventListener('click', openMainDrawer);
} else {
$(mainDrawerButton).createHoverTouch().on('hovertouch', openMainDrawer);
}
}
var headerBackButton = document.querySelector('.headerBackButton');
@ -312,7 +306,6 @@
var userHeader = drawer.querySelector('.userheader');
userHeader.innerHTML = html;
ImageLoader.fillImages(userHeader.getElementsByClassName('lazy'));
}
@ -341,10 +334,6 @@
drawer.querySelector('.dashboardDrawerContent').innerHTML = html;
}
function replaceAll(string, find, replace) {
return string.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}
function refreshBottomUserInfoInDrawer(user, drawer) {
var html = '';
@ -582,7 +571,7 @@
} else {
Dashboard.navigate(link.href);
}
}, 400);
}, 350);
}, 50);
}
@ -599,7 +588,7 @@
setTimeout(function () {
Dashboard.logout();
}, 400);
}, 350);
}
return false;
@ -807,7 +796,7 @@
}
}
pageClassOn('pagebeforeshow', 'page', function () {
pageClassOn('pageinit', 'page', function () {
var page = this;
@ -815,7 +804,7 @@
requiresDashboardDrawerRefresh = true;
}
onPageBeforeShowDocumentReady(page);
onPageBeforeShow(page);
});
@ -823,20 +812,15 @@
var page = this;
onPageShowDocumentReady(page);
if (!NavHelper.isBack()) {
// Scroll back up so in case vertical scroll was messed with
window.scrollTo(0, 0);
}
updateTabLinks(page);
});
//pageClassOn('pagebeforehide', 'page', function () {
// var headroomEnabled = document.querySelectorAll('.headroomEnabled');
// for (var i = 0, length = headroomEnabled.length; i < length; i++) {
// headroomEnabled[i].classList.add('headroomDisabled');
// }
//});
function onPageBeforeShowDocumentReady(page) {
function onPageBeforeShow(page) {
buildViewMenuBar(page);
@ -934,15 +918,6 @@
}
}
function onPageShowDocumentReady(page) {
if (!NavHelper.isBack()) {
// Scroll back up so in case vertical scroll was messed with
window.scrollTo(0, 0);
}
updateTabLinks(page);
}
function initHeadRoom(elem) {
if (!AppInfo.enableHeadRoom) {
@ -1006,59 +981,6 @@
})(window, document, jQuery, window.devicePixelRatio);
$.fn.createHoverTouch = function () {
var preventHover = false;
var timerId;
function startTimer(elem) {
stopTimer();
timerId = setTimeout(function () {
Events.trigger(elem, 'hovertouch');
}, 300);
}
function stopTimer(elem) {
if (timerId) {
clearTimeout(timerId);
timerId = null;
}
}
return $(this).on('mouseenter', function () {
if (preventHover === true) {
preventHover = false;
return;
}
startTimer(this);
}).on('mouseleave', function () {
stopTimer(this);
}).on('touchstart', function () {
preventHover = true;
}).on('click', function () {
preventHover = true;
if (preventHover) {
Events.trigger(this, 'hovertouch');
stopTimer(this);
preventHover = false;
}
});
};
(function () {
var isCurrentNavBack = false;

View file

@ -34,6 +34,10 @@
self.resetEnhancements = function () {
if (!initComplete) {
return;
}
fadeOut(document.querySelector('#mediaPlayer'));
$('#videoPlayer').removeClass('fullscreenVideo').removeClass('idlePlayer');
$('.hiddenOnIdle').removeClass("inactive");
@ -676,6 +680,9 @@
Dashboard.importCss('css/mediaplayer-video.css');
// TODO: remove dependency on this file
Dashboard.importCss('css/nowplayingbar.css');
var html = '<div id="mediaPlayer" style="display: none;">';
html += '<div class="videoBackdrop">';
@ -749,8 +756,15 @@
document.body.appendChild(div);
}
Dashboard.ready(function () {
var initComplete;
function initVideoElements() {
if (initComplete) {
return;
}
initComplete = true;
ensureVideoPlayerElements();
var parent = $("#mediaPlayer");
@ -783,7 +797,7 @@
updateVolumeButtons(vol);
self.setVolume(vol);
})[0];
});
}
var idleHandlerTimeout;
function idleHandler() {
@ -924,13 +938,17 @@
// Replace audio version
self.cleanup = function (mediaRenderer) {
if (currentTimeElement) {
currentTimeElement.html('--:--');
}
unbindEventsForPlayback(mediaRenderer);
};
self.playVideo = function (item, mediaSource, startPosition, callback) {
initVideoElements();
requirejs(['videorenderer'], function () {
self.createStreamInfo('Video', item, mediaSource, startPosition).done(function (streamInfo) {
@ -1127,6 +1145,11 @@
};
self.updatePlaylistUi = function () {
if (!initComplete) {
return;
}
var index = self.currentPlaylistIndex(null);
var length = self.playlist.length;

View file

@ -26,7 +26,7 @@
var targets = [{
name: Globalize.translate('MyDevice'),
id: ConnectionManager.deviceId(),
id: AppInfo.deviceId,
playerName: self.name,
playableMediaTypes: ['Audio', 'Video'],
isLocalPlayer: true,
@ -1049,7 +1049,7 @@
return deferred.promise();
};
self.lastBitrateDetect = 0;
self.lastBitrateDetections = {};
self.playInternal = function (item, startPosition, callback) {
@ -1071,14 +1071,16 @@
return;
}
if (item.MediaType == 'Video' && AppSettings.enableAutomaticBitrateDetection() && (new Date().getTime() - self.lastBitrateDetect) > 300000) {
var bitrateDetectionKey = ApiClient.serverAddress();
if (item.MediaType == 'Video' && AppSettings.enableAutomaticBitrateDetection() && (new Date().getTime() - (self.lastBitrateDetections[bitrateDetectionKey] || 0)) > 300000) {
Dashboard.showModalLoadingMsg();
ApiClient.detectBitrate().done(function (bitrate) {
Logger.log('Max bitrate auto detected to ' + bitrate);
self.lastBitrateDetect = new Date().getTime();
self.lastBitrateDetections[bitrateDetectionKey] = new Date().getTime();
AppSettings.maxStreamingBitrate(bitrate);
playOnDeviceProfileCreated(self.getDeviceProfile(), item, startPosition, callback);
@ -1997,17 +1999,8 @@
window.MediaPlayer = new mediaPlayer();
function onConnectionChange() {
window.MediaPlayer.lastBitrateDetect = 0;
}
Dashboard.ready(function () {
window.MediaController.registerPlayer(window.MediaPlayer);
window.MediaController.setActivePlayer(window.MediaPlayer, window.MediaPlayer.getTargets()[0]);
Events.on(ConnectionManager, 'localusersignedin', onConnectionChange);
Events.on(ConnectionManager, 'localusersignedout', onConnectionChange);
});
})(document, setTimeout, clearTimeout, screen, $, setInterval, window);

View file

@ -184,8 +184,6 @@
});
});
Dashboard.ready(function () {
if (window.ApiClient) {
initializeApiClient(window.ApiClient);
}
@ -201,12 +199,9 @@
Events.on(ConnectionManager, 'localusersignedout', function () {
needsRefresh = true;
});
});
pageClassOn('pageshow', "type-interior", function () {
var page = $(this);
if (needsRefresh) {
Notifications.updateNotificationCount();
}

View file

@ -201,7 +201,9 @@
return elem;
}
elem = $(getNowPlayingBarHtml()).insertBefore('#footerNotifications')[0];
Dashboard.importCss('css/nowplayingbar.css');
elem = $(getNowPlayingBarHtml()).appendTo(document.body)[0];
if (($.browser.safari || !AppInfo.isNativeApp) && $.browser.mobile) {
// Not handled well here. The wrong elements receive events, bar doesn't update quickly enough, etc.
@ -563,14 +565,11 @@
.on('positionchange', onStateChanged);
}
Dashboard.ready(function () {
Events.on(MediaController, 'playerchange', function () {
bindToPlayer(MediaController.getCurrentPlayer());
});
bindToPlayer(MediaController.getCurrentPlayer());
});
})(window, document, jQuery, setTimeout, clearTimeout);

View file

@ -387,8 +387,6 @@
$(apiClient).on("websocketmessage", onWebSocketMessageReceived).on("websocketopen", onWebSocketConnectionChange);
}
Dashboard.ready(function () {
if (window.ApiClient) {
initializeApiClient(window.ApiClient);
}
@ -396,6 +394,5 @@
$(ConnectionManager).on('apiclientcreated', function (e, apiClient) {
initializeApiClient(apiClient);
});
});
})(window, document, jQuery);

View file

@ -435,6 +435,17 @@ var Dashboard = {
options.id = options.id || "notification" + new Date().getTime() + parseInt(Math.random());
if (!$(".footer").length) {
var footerHtml = '<div id="footer" class="footer" data-theme="b" class="ui-bar-b">';
footerHtml += '<div id="footerNotifications"></div>';
footerHtml += '</div>';
$(document.body).append(footerHtml);
}
var footer = $(".footer").css("top", "initial").show();
var parentElem = $('#footerNotifications', footer);
@ -1688,12 +1699,7 @@ var Dashboard = {
ready: function (fn) {
if (Dashboard.initPromiseDone) {
fn();
return;
}
Dashboard.initPromise.done(fn);
Dashboard.initPromise.then(fn);
},
loadExternalPlayer: function () {
@ -1884,7 +1890,7 @@ var AppInfo = {};
initializeApiClient(newApiClient);
});
var deferred = DeferredBuilder.Deferred();
return new Promise(function (resolve, reject) {
if (Dashboard.isConnectMode()) {
@ -1897,12 +1903,12 @@ var AppInfo = {};
if (result.State == MediaBrowser.ConnectionState.SignedIn) {
window.ApiClient = result.ApiClient;
}
deferred.resolve();
resolve();
});
return deferred.promise();
return;
}
}
deferred.resolve();
resolve();
} else {
@ -1911,9 +1917,9 @@ var AppInfo = {};
ConnectionManager.addApiClient(apiClient);
Dashboard.importCss(apiClient.getUrl('Branding/Css'));
window.ApiClient = apiClient;
deferred.resolve();
resolve();
}
return deferred.promise();
});
}
function initFastClick() {
@ -2004,82 +2010,6 @@ var AppInfo = {};
}
}
function onDocumentReady() {
if ($.browser.msie) {
require(['devices/ie/ie']);
}
// Do these now to prevent a flash of content
if (AppInfo.isNativeApp && $.browser.android) {
Dashboard.importCss('devices/android/android.css');
} else if (AppInfo.isNativeApp && $.browser.safari) {
Dashboard.importCss('devices/ios/ios.css');
} else if (!$.browser.android) {
Dashboard.importCss('devices/android/android.css');
}
loadTheme();
if ($.browser.safari && $.browser.mobile) {
initFastClick();
}
var footerHtml = '<div id="footer" class="footer" data-theme="b" class="ui-bar-b">';
footerHtml += '<div id="footerNotifications"></div>';
footerHtml += '</div>';
$(document.body).append(footerHtml);
window.addEventListener("beforeunload", function () {
var apiClient = window.ApiClient;
// Close the connection gracefully when possible
if (apiClient && apiClient.isWebSocketOpen()) {
var localActivePlayers = MediaController.getPlayers().filter(function (p) {
return p.isLocalPlayer && p.isPlaying();
});
if (!localActivePlayers.length) {
Logger.log('Sending close web socket command');
apiClient.closeWebSocket();
}
}
});
if (Dashboard.isRunningInCordova()) {
require(['cordova/connectsdk', 'scripts/registrationservices', 'cordova/back']);
if ($.browser.android) {
require(['cordova/android/androidcredentials', 'cordova/android/immersive', 'cordova/android/mediasession']);
} else {
require(['cordova/volume']);
}
if ($.browser.safari) {
require(['cordova/ios/orientation']);
}
} else {
if ($.browser.chrome) {
require(['scripts/chromecast']);
}
}
if (AppInfo.enableNowPlayingBar) {
require(['scripts/nowplayingbar']);
Dashboard.importCss('css/nowplayingbar.css');
}
if (navigator.splashscreen) {
navigator.splashscreen.hide();
}
}
function initRequire() {
var urlArgs = "v=" + window.dashboardVersion;
@ -2115,7 +2045,7 @@ var AppInfo = {};
}
function init(deferred, capabilities, appName, appVersion, deviceId, deviceName) {
function init(promiseResolve, capabilities, appName, appVersion, deviceId, deviceName) {
// Required since jQuery is loaded before requireJs
define('jquery', [], function () {
@ -2290,11 +2220,11 @@ var AppInfo = {};
loadImageCache();
$.extend(AppInfo, Dashboard.getAppInfo(appName, appVersion, deviceId, deviceName));
initAfterDependencies(deferred, capabilities);
initAfterDependencies(promiseResolve, capabilities);
});
}
function initAfterDependencies(deferred, capabilities) {
function initAfterDependencies(promiseResolve, capabilities) {
var drawer = document.querySelector('.mainDrawerPanel');
drawer.classList.remove('mainDrawerPanelPreInit');
@ -2314,10 +2244,11 @@ var AppInfo = {};
var deps = [];
if (AppInfo.isNativeApp && $.browser.android) {
deps.push('cordova/android/logging');
require(['cordova/android/logging']);
}
deps.push('appstorage');
deps.push('scripts/mediaplayer');
require(deps, function () {
@ -2342,15 +2273,11 @@ var AppInfo = {};
}
capabilities.DeviceProfile = MediaPlayer.getDeviceProfile(Math.max(screen.height, screen.width));
createConnectionManager(capabilities).done(function () { onConnectionManagerCreated(deferred); });
//$(document.body).append('<div style="background:#00ACC1;position:fixed;z-index:999999;top:1px;left:1px;width:800px;height:450px;display:flex;align-items:center;justify-content:center;"><iron-icon icon="ondemand-video" style="width:320px;height:320px;color:#fff;"></iron-icon></div>');
});
}
var connectionManagerPromise = createConnectionManager(capabilities);
function onConnectionManagerCreated(deferred) {
Promise.all([Globalize.ensure(), connectionManagerPromise]).then(function () {
Globalize.ensure().then(function () {
document.title = Globalize.translateDocument(document.title, 'html');
$(function () {
@ -2388,18 +2315,56 @@ var AppInfo = {};
// Don't like having to use jQuery here, but it takes care of making sure that embedded script executes
$(mainDrawerPanelContent).html(Globalize.translateDocument(newHtml, 'html'));
onAppReady(deferred);
onAppReady(promiseResolve);
});
return;
}
onAppReady(deferred);
onAppReady(promiseResolve);
});
});
});
}
function onAppReady(deferred) {
onDocumentReady();
function onAppReady(promiseResolve) {
if ($.browser.msie) {
require(['devices/ie/ie']);
}
// Do these now to prevent a flash of content
if (AppInfo.isNativeApp && $.browser.android) {
Dashboard.importCss('devices/android/android.css');
} else if (AppInfo.isNativeApp && $.browser.safari) {
Dashboard.importCss('devices/ios/ios.css');
} else if (!$.browser.android) {
Dashboard.importCss('devices/android/android.css');
}
loadTheme();
if ($.browser.safari && $.browser.mobile) {
initFastClick();
}
if (Dashboard.isRunningInCordova()) {
require(['cordova/connectsdk', 'scripts/registrationservices', 'cordova/back']);
if ($.browser.android) {
require(['cordova/android/androidcredentials', 'cordova/android/immersive', 'cordova/android/mediasession']);
} else {
require(['cordova/volume']);
}
if ($.browser.safari) {
require(['cordova/ios/orientation']);
}
} else {
if ($.browser.chrome) {
require(['scripts/chromecast']);
}
}
var deps = [];
@ -2412,13 +2377,24 @@ var AppInfo = {};
deps.push('cordova/ios/tabbar');
}
deps.push('scripts/remotecontrol');
deps.push('scripts/search');
deps.push('scripts/librarylist');
deps.push('scripts/notifications');
require(deps, function () {
Dashboard.initPromiseDone = true;
$.mobile.initializePage();
deferred.resolve();
promiseResolve();
require(['scripts/mediaplayer-video']);
});
//require(['localsync']);
if (AppInfo.enableNowPlayingBar) {
require(['scripts/nowplayingbar']);
}
require(['scripts/alphapicker']);
require(['scripts/thememediaplayer']);
}
function loadImageCache() {
@ -2461,17 +2437,16 @@ var AppInfo = {};
}, false);
}
var initDeferred = $.Deferred();
Dashboard.initPromise = initDeferred.promise();
Dashboard.initPromise = new Promise(function (resolve, reject) {
setAppInfo();
setDocumentClasses();
function onWebComponentsReady() {
if (Dashboard.isRunningInCordova()) {
initCordova(initDeferred);
initCordova(resolve);
} else {
init(initDeferred, Dashboard.capabilities());
init(resolve, Dashboard.capabilities());
}
}
@ -2488,6 +2463,7 @@ var AppInfo = {};
});
require(['bower_components/webcomponentsjs/webcomponents-lite.min.js']);
}
});
})();
@ -2612,4 +2588,23 @@ pageClassOn('pageshow', "page", function () {
});
window.addEventListener("beforeunload", function () {
var apiClient = window.ApiClient;
// Close the connection gracefully when possible
if (apiClient && apiClient.isWebSocketOpen()) {
var localActivePlayers = MediaController.getPlayers().filter(function (p) {
return p.isLocalPlayer && p.isPlaying();
});
if (!localActivePlayers.length) {
Logger.log('Sending close web socket command');
apiClient.closeWebSocket();
}
}
});
Dashboard.jQueryMobileInit();

View file

@ -2365,11 +2365,7 @@
var link = parentWithTag(event.target, 'A');
var $link = $(link),
baseUrl, href,
useDefaultUrlHandling, isExternal,
reverse, role;
var $link = $(link);
// If there is no link associated with the click or its not a left
// click we want to ignore the click
@ -2385,10 +2381,10 @@
return false;
}
baseUrl = $.mobile.getClosestBaseUrl(link);
var baseUrl = $.mobile.getClosestBaseUrl(link);
//get href, if defined, otherwise default to empty hash
href = $.mobile.path.makeUrlAbsolute(link.getAttribute("href") || "#", baseUrl);
var href = $.mobile.path.makeUrlAbsolute(link.getAttribute("href") || "#", baseUrl);
// XXX_jblas: Ideally links to application pages should be specified as
// an url to the application document with a hash that is either
@ -2417,25 +2413,19 @@
}
// Should we handle this link, or let the browser deal with it?
useDefaultUrlHandling = link.getAttribute("rel") == "external" || link.getAttribute("data-ajax") == "false" || link.getAttribute('target');
//check for protocol or rel and its not an embedded page
//TODO overlap in logic from isExternal, rel=external check should be
// moved into more comprehensive isExternalLink
isExternal = useDefaultUrlHandling || ($.mobile.path.isExternal(href));
if (isExternal) {
if (link.getAttribute("rel") == "external" || link.getAttribute("data-ajax") == "false" || link.getAttribute('target') || ($.mobile.path.isExternal(href))) {
//use default click handling
return;
}
//use ajax
reverse = $link.data("direction") === "reverse" ||
// deprecated - remove by 1.0
$link.data("back");
var reverse = $link.data("direction") === "reverse";
//this may need to be more specific as we use data-rel more
role = link.getAttribute("data-rel") || undefined;
var role = link.getAttribute("data-rel") || undefined;
$.mobile.changePage(href, { reverse: reverse, role: role, link: $link });
event.preventDefault();
@ -2493,24 +2483,21 @@
initializePage: function () {
// find present pages
var path = $.mobile.path,
$pages = $(document.querySelectorAll("div[data-role='page']")),
firstPage = document.querySelector("div[data-role='page']"),
hash = path.stripHash(path.stripQueryParams(path.parseLocation().hash)),
theLocation = $.mobile.path.parseLocation(),
hashPage = hash ? document.getElementById(hash) : undefined;
// add dialogs, set data-url attrs
$pages.each(function () {
var $this = $(this);
if (firstPage) {
// unless the data url is already set set it to the pathname
if (!$this[0].getAttribute("data-url")) {
$this.attr("data-url", $this.attr("id") ||
path.convertUrlToDataUrl(theLocation.pathname + theLocation.search));
if (!firstPage.getAttribute("data-url")) {
firstPage.setAttribute("data-url", firstPage.getAttribute("id") || path.convertUrlToDataUrl(theLocation.pathname + theLocation.search));
}
}
});
// define first page in dom case one backs out to the directory root (not always the first page visited, but defined as fallback)
$.mobile.firstPage = $pages.first();
$.mobile.firstPage = $(firstPage);
// define page container
$.mobile.pageContainer = $.mobile.firstPage