';
@@ -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) {
- currentTimeElement.html('--:--');
+ 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;
diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js
index d5fd0684fb..188b4678e7 100644
--- a/dashboard-ui/scripts/mediaplayer.js
+++ b/dashboard-ui/scripts/mediaplayer.js
@@ -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);
- });
+ window.MediaController.registerPlayer(window.MediaPlayer);
+ window.MediaController.setActivePlayer(window.MediaPlayer, window.MediaPlayer.getTargets()[0]);
})(document, setTimeout, clearTimeout, screen, $, setInterval, window);
\ No newline at end of file
diff --git a/dashboard-ui/scripts/notifications.js b/dashboard-ui/scripts/notifications.js
index ffb0a2dac9..3d8c89fb01 100644
--- a/dashboard-ui/scripts/notifications.js
+++ b/dashboard-ui/scripts/notifications.js
@@ -184,29 +184,24 @@
});
});
- Dashboard.ready(function () {
+ if (window.ApiClient) {
+ initializeApiClient(window.ApiClient);
+ }
- if (window.ApiClient) {
- initializeApiClient(window.ApiClient);
- }
+ $(ConnectionManager).on('apiclientcreated', function (e, apiClient) {
+ initializeApiClient(apiClient);
+ });
- $(ConnectionManager).on('apiclientcreated', function (e, apiClient) {
- initializeApiClient(apiClient);
- });
+ Events.on(ConnectionManager, 'localusersignedin', function () {
+ needsRefresh = true;
+ });
- Events.on(ConnectionManager, 'localusersignedin', function () {
- needsRefresh = true;
- });
-
- Events.on(ConnectionManager, 'localusersignedout', function () {
- needsRefresh = true;
- });
+ Events.on(ConnectionManager, 'localusersignedout', function () {
+ needsRefresh = true;
});
pageClassOn('pageshow', "type-interior", function () {
- var page = $(this);
-
if (needsRefresh) {
Notifications.updateNotificationCount();
}
diff --git a/dashboard-ui/scripts/nowplayingbar.js b/dashboard-ui/scripts/nowplayingbar.js
index 15937cafde..a980386c18 100644
--- a/dashboard-ui/scripts/nowplayingbar.js
+++ b/dashboard-ui/scripts/nowplayingbar.js
@@ -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());
- });
+ Events.on(MediaController, 'playerchange', function () {
bindToPlayer(MediaController.getCurrentPlayer());
});
+ bindToPlayer(MediaController.getCurrentPlayer());
+
})(window, document, jQuery, setTimeout, clearTimeout);
\ No newline at end of file
diff --git a/dashboard-ui/scripts/remotecontrol.js b/dashboard-ui/scripts/remotecontrol.js
index 432e31674e..15e782b3bb 100644
--- a/dashboard-ui/scripts/remotecontrol.js
+++ b/dashboard-ui/scripts/remotecontrol.js
@@ -387,15 +387,12 @@
$(apiClient).on("websocketmessage", onWebSocketMessageReceived).on("websocketopen", onWebSocketConnectionChange);
}
- Dashboard.ready(function () {
+ if (window.ApiClient) {
+ initializeApiClient(window.ApiClient);
+ }
- if (window.ApiClient) {
- initializeApiClient(window.ApiClient);
- }
-
- $(ConnectionManager).on('apiclientcreated', function (e, apiClient) {
- initializeApiClient(apiClient);
- });
+ $(ConnectionManager).on('apiclientcreated', function (e, apiClient) {
+ initializeApiClient(apiClient);
});
})(window, document, jQuery);
\ No newline at end of file
diff --git a/dashboard-ui/scripts/site.js b/dashboard-ui/scripts/site.js
index 378d3f5ffc..d1d1eb0485 100644
--- a/dashboard-ui/scripts/site.js
+++ b/dashboard-ui/scripts/site.js
@@ -435,6 +435,17 @@ var Dashboard = {
options.id = options.id || "notification" + new Date().getTime() + parseInt(Math.random());
+ if (!$(".footer").length) {
+
+ var footerHtml = '';
+
+ $(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,36 +1890,36 @@ var AppInfo = {};
initializeApiClient(newApiClient);
});
- var deferred = DeferredBuilder.Deferred();
+ return new Promise(function (resolve, reject) {
- if (Dashboard.isConnectMode()) {
+ if (Dashboard.isConnectMode()) {
- var server = ConnectionManager.getLastUsedServer();
+ var server = ConnectionManager.getLastUsedServer();
- if (!Dashboard.isServerlessPage()) {
+ if (!Dashboard.isServerlessPage()) {
- if (server && server.UserId && server.AccessToken) {
- ConnectionManager.connectToServer(server).done(function (result) {
- if (result.State == MediaBrowser.ConnectionState.SignedIn) {
- window.ApiClient = result.ApiClient;
- }
- deferred.resolve();
- });
- return deferred.promise();
+ if (server && server.UserId && server.AccessToken) {
+ ConnectionManager.connectToServer(server).done(function (result) {
+ if (result.State == MediaBrowser.ConnectionState.SignedIn) {
+ window.ApiClient = result.ApiClient;
+ }
+ resolve();
+ });
+ return;
+ }
}
+ resolve();
+
+ } else {
+
+ var apiClient = new MediaBrowser.ApiClient(Logger, Dashboard.serverAddress(), AppInfo.appName, AppInfo.appVersion, AppInfo.deviceName, AppInfo.deviceId);
+ apiClient.enableAutomaticNetworking = false;
+ ConnectionManager.addApiClient(apiClient);
+ Dashboard.importCss(apiClient.getUrl('Branding/Css'));
+ window.ApiClient = apiClient;
+ resolve();
}
- deferred.resolve();
-
- } else {
-
- var apiClient = new MediaBrowser.ApiClient(Logger, Dashboard.serverAddress(), AppInfo.appName, AppInfo.appVersion, AppInfo.deviceName, AppInfo.deviceId);
- apiClient.enableAutomaticNetworking = false;
- ConnectionManager.addApiClient(apiClient);
- Dashboard.importCss(apiClient.getUrl('Branding/Css'));
- window.ApiClient = apiClient;
- deferred.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 = '';
-
- $(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,64 +2273,98 @@ var AppInfo = {};
}
capabilities.DeviceProfile = MediaPlayer.getDeviceProfile(Math.max(screen.height, screen.width));
- createConnectionManager(capabilities).done(function () { onConnectionManagerCreated(deferred); });
- //$(document.body).append('
');
- });
- }
+ 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');
+ document.title = Globalize.translateDocument(document.title, 'html');
- $(function () {
+ $(function () {
- var mainDrawerPanelContent = document.querySelector('.mainDrawerPanelContent');
+ var mainDrawerPanelContent = document.querySelector('.mainDrawerPanelContent');
- if (mainDrawerPanelContent) {
+ if (mainDrawerPanelContent) {
- var newHtml = mainDrawerPanelContent.innerHTML.substring(4);
- newHtml = newHtml.substring(0, newHtml.length - 3);
+ var newHtml = mainDrawerPanelContent.innerHTML.substring(4);
+ newHtml = newHtml.substring(0, newHtml.length - 3);
- var srch = 'data-require=';
- var index = newHtml.indexOf(srch);
- var depends;
+ var srch = 'data-require=';
+ var index = newHtml.indexOf(srch);
+ var depends;
- if (index != -1) {
+ if (index != -1) {
- var requireAttribute = newHtml.substring(index + srch.length + 1);
+ var requireAttribute = newHtml.substring(index + srch.length + 1);
- requireAttribute = requireAttribute.substring(0, requireAttribute.indexOf('"'));
- depends = requireAttribute.split(',');
+ requireAttribute = requireAttribute.substring(0, requireAttribute.indexOf('"'));
+ depends = requireAttribute.split(',');
+ }
+
+ depends = depends || [];
+
+ if (newHtml.indexOf('type-interior') != -1) {
+ depends.push('jqmpopup');
+ depends.push('jqmlistview');
+ depends.push('jqmcollapsible');
+ depends.push('jqmcontrolgroup');
+ depends.push('jqmcheckbox');
+ }
+
+ require(depends, function () {
+
+ // 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(promiseResolve);
+ });
+ return;
}
- depends = depends || [];
-
- if (newHtml.indexOf('type-interior') != -1) {
- depends.push('jqmpopup');
- depends.push('jqmlistview');
- depends.push('jqmcollapsible');
- depends.push('jqmcontrolgroup');
- depends.push('jqmcheckbox');
- }
-
- require(depends, function () {
-
- // 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);
- });
- 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,33 +2437,33 @@ var AppInfo = {};
}, false);
}
- var initDeferred = $.Deferred();
- Dashboard.initPromise = initDeferred.promise();
+ Dashboard.initPromise = new Promise(function (resolve, reject) {
- setAppInfo();
- setDocumentClasses();
+ setAppInfo();
+ setDocumentClasses();
- function onWebComponentsReady() {
- if (Dashboard.isRunningInCordova()) {
- initCordova(initDeferred);
- } else {
- init(initDeferred, Dashboard.capabilities());
+ function onWebComponentsReady() {
+ if (Dashboard.isRunningInCordova()) {
+ initCordova(resolve);
+ } else {
+ init(resolve, Dashboard.capabilities());
+ }
}
- }
- initRequire();
+ initRequire();
- if ('registerElement' in document && 'content' in document.createElement('template')) {
- onWebComponentsReady();
- } else {
+ if ('registerElement' in document && 'content' in document.createElement('template')) {
+ onWebComponentsReady();
+ } else {
- document.addEventListener('WebComponentsReady', function () {
+ document.addEventListener('WebComponentsReady', function () {
- var delay = $.browser.mobile ? 500 : 300;
- setTimeout(onWebComponentsReady, delay);
- });
- require(['bower_components/webcomponentsjs/webcomponents-lite.min.js']);
- }
+ var delay = $.browser.mobile ? 500 : 300;
+ setTimeout(onWebComponentsReady, delay);
+ });
+ 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();
\ No newline at end of file
diff --git a/dashboard-ui/thirdparty/jquerymobile-1.4.5/jquery.mobile.custom.js b/dashboard-ui/thirdparty/jquerymobile-1.4.5/jquery.mobile.custom.js
index 2263792d48..338113f8e0 100644
--- a/dashboard-ui/thirdparty/jquerymobile-1.4.5/jquery.mobile.custom.js
+++ b/dashboard-ui/thirdparty/jquerymobile-1.4.5/jquery.mobile.custom.js
@@ -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